LCOV - code coverage report
Current view: top level - Src/Utils - small_vector.hpp (source / functions) Hit Total Coverage
Test: Coverage example Lines: 205 280 73.2 %
Date: 2021-12-02 17:21:05 Functions: 508 567 89.6 %

          Line data    Source code
       1             : /*
       2             :  * Implementation of a vector optimized for the case where only a small number of elements
       3             :  * are stored.
       4             :  * The vector starts out storing elements in an inline storage buffer of size N. If the vector size
       5             :  * grows beyond N elements, the vector stores the elements in a dynamically allocated buffer.
       6             :  * The implementation of small_vector is largely inspired by the SmallVector class implementation from 
       7             :  * the LLVM framework codebase.
       8             :  * Link to the implementation of SmallVector in the LLVM codebase :
       9             :  * https://github.com/llvm/llvm-project/blob/master/llvm/include/llvm/ADT/SmallVector.h
      10             :  * The implementation of the function nextPowerOfTwo has been largely inspired by the implementation of
      11             :  * the function NextPowerOf2 from the LLVM codebase :
      12             :  * Link to the implementation of NextPowerOf2 in the LLVM codebase:
      13             :  * https://github.com/llvm/llvm-project/blob/master/llvm/include/llvm/Support/MathExtras.h
      14             :  */
      15             : 
      16             : #ifndef SMALL_VECTOR_HPP
      17             : #define SMALL_VECTOR_HPP
      18             : 
      19             : #include <cstddef>
      20             : #include <cstdlib>
      21             : #include <iterator>
      22             : #include <limits>
      23             : #include <cassert>
      24             : #include <memory>
      25             : #include <stdexcept>
      26             : #include <iostream>
      27             : #include <algorithm>
      28             : 
      29             : inline uint64_t nextPowerOfTwo(uint64_t n);
      30             : 
      31             : class small_vector_common_base {
      32             : protected:
      33             :     size_t capacity_;
      34             :     size_t originalCapacity_;
      35             :     size_t size_;
      36             :     void *beginPtr_;
      37             :     
      38             :     small_vector_common_base() = delete;
      39       16353 :     small_vector_common_base(size_t originalCapacity, void *beginPtr)
      40       16353 :         : capacity_(originalCapacity), originalCapacity_(originalCapacity), size_(0), beginPtr_(beginPtr) {}
      41             : };
      42             : 
      43             : template <typename T>
      44             : struct small_vector_internal_storage_offset_computation_structure {
      45             :     alignas(small_vector_common_base) char base[sizeof(small_vector_common_base)];
      46             :     alignas(T) char firstElt[sizeof(T)];
      47             : };
      48             : 
      49             : template <typename T>
      50             : class small_vector_base : public small_vector_common_base {
      51             : public:
      52             : 
      53             :     using size_type = size_t;
      54             :     using difference_type = ptrdiff_t;
      55             :     using value_type = T;
      56             :     using iterator = T *;
      57             :     using const_iterator = const T *;
      58             :     
      59             :     using reverse_iterator = std::reverse_iterator<iterator>;
      60             :     using const_reverse_iterator = std::reverse_iterator<const_iterator>;
      61             :     
      62             :     using reference =  T &;
      63             :     using const_reference = const T &;
      64             :     using pointer = T *;
      65             :     using const_pointer = const T *;
      66             : 
      67             : private:
      68          29 :      void grow_capacity_to_a_minimum_of(size_type minCapacity) {
      69          29 :         assert(minCapacity <= UINT32_MAX);
      70             :         
      71          29 :         size_type newCapacity = std::min(std::max(minCapacity, size_t(nextPowerOfTwo(capacity()))), size_t(UINT32_MAX));
      72             :         
      73          29 :         void *p = std::malloc(newCapacity*sizeof(T));
      74             :         
      75          29 :         std::uninitialized_copy(std::move_iterator<iterator>(begin()), std::move_iterator<iterator>(end()), static_cast<iterator>(p));
      76             :         
      77          29 :         std::destroy(rbegin(), rend());
      78             :         
      79          29 :         if(!is_small()) {
      80           0 :             std::free(beginPtr_);
      81             :         }
      82             :         
      83          29 :         beginPtr_ = p;
      84          29 :         capacity_ = newCapacity;
      85          29 :     }
      86             : 
      87             : protected:
      88             :     small_vector_base() = delete;
      89       16372 :     small_vector_base(size_t originalCapacity)
      90       16372 :         : small_vector_common_base(originalCapacity, getPointerToInternalStorage()) {}
      91             : 
      92             : public:
      93             :     template<typename InputItTy,
      94             :              typename = typename std::enable_if<std::is_convertible<
      95             :              typename std::iterator_traits<InputItTy>::iterator_category,
      96             :              std::input_iterator_tag>::value>::type>
      97        3404 :     void assign(InputItTy first, InputItTy last) {
      98        3404 :         size_t nbEltsInRange = std::distance(first, last);
      99             :         
     100        3404 :         if(capacity() >= nbEltsInRange) {
     101        3404 :             if(nbEltsInRange <= size()) {
     102           0 :                 std::copy(first, last, begin());
     103             :                 
     104           0 :                 if(nbEltsInRange < size()) {
     105           0 :                     std::destroy(rbegin(), reverse_iterator(begin() + nbEltsInRange));
     106             :                 }
     107             :             }else {
     108        3404 :                 iterator i2 = begin();
     109        3404 :                 InputItTy i = first;
     110             :                 
     111        3404 :                 for(size_t nb = size(); nb > 0; --nb, ++i, ++i2) {
     112           0 :                     *i2 = *i;
     113             :                 }
     114             :                 
     115        6963 :                 for(; i != last; ++i2, ++i) {
     116        3559 :                     new (static_cast<void *>(std::addressof(*i2))) T(*i);
     117             :                 }
     118             :             }
     119             :         }else {
     120           0 :             clear();
     121           0 :             grow_capacity_to_a_minimum_of(nbEltsInRange);
     122           0 :             std::uninitialized_copy(first, last, begin());
     123             :         }
     124             :         
     125        3404 :         set_size(nbEltsInRange);
     126        3404 :     }
     127             :     
     128        1106 :     void assign(size_type count, const T &value) {
     129             :         
     130        1106 :         if(capacity() >= count) {
     131        1078 :             if(count <= size()) {
     132         957 :                 std::fill_n(begin(), count, value);
     133             :                 
     134         957 :                 if(count < size()) {
     135           0 :                     std::destroy(rbegin(), reverse_iterator(begin() + count));
     136             :                 }
     137             :             }else {
     138         121 :                 std::fill_n(begin(), size(), value);
     139         121 :                 std::uninitialized_fill(end(), begin() + count, value);
     140             :             }
     141             :             
     142             :         } else {
     143          28 :             clear();
     144          28 :             grow_capacity_to_a_minimum_of(count);
     145          28 :             std::uninitialized_fill_n(begin(), count, value);
     146             :         }
     147             :         
     148        1106 :         set_size(count);
     149        1106 :     }
     150             :     
     151        3404 :     void assign(std::initializer_list<T> il) {
     152        3404 :         assign(il.begin(), il.end());
     153        3404 :     }
     154             :     
     155         696 :     small_vector_base &operator=(const small_vector_base &rhs) {
     156         696 :         if(this == std::addressof(rhs)) {
     157           0 :             return *this;
     158             :         }
     159             :         
     160         696 :         size_type rhsSize = rhs.size();
     161             :         
     162         696 :         if(size() >= rhsSize) {
     163           0 :             if(rhsSize > 0) {
     164           0 :                 std::copy(rhs.begin(), rhs.end(), begin());
     165             :             }
     166             :             
     167           0 :             std::destroy(rbegin(), reverse_iterator(begin() + rhsSize));
     168             :             
     169           0 :             set_size(rhsSize);
     170           0 :             return *this;
     171             :         }
     172             :         
     173         696 :         if(capacity() < rhsSize) {
     174           0 :             clear();
     175           0 :             grow_capacity_to_a_minimum_of(rhsSize);
     176         696 :         }else if(size() > 0) {
     177           0 :             std::copy(rhs.begin(), rhs.begin() + size(), begin());
     178             :         }
     179             :         
     180         696 :         std::uninitialized_copy(rhs.begin() + size(), rhs.end(), begin() + size());
     181         696 :         set_size(rhsSize);
     182         696 :         return *this;
     183             :     }
     184             :     
     185         161 :     small_vector_base &operator=(small_vector_base &&rhs) {
     186         161 :         if(this == std::addressof(rhs)) {
     187           0 :             return *this;
     188             :         }
     189             :         
     190         161 :         if(!rhs.is_small()) {
     191           0 :             clear();
     192             :             
     193           0 :             if(!is_small()) {
     194           0 :                 std::free(beginPtr_);
     195             :             }
     196             :             
     197           0 :             beginPtr_ = rhs.begin();
     198           0 :             size_ = rhs.size();
     199           0 :             capacity_ = rhs.capacity();
     200           0 :             rhs.reset_to_small();
     201             :             
     202           0 :             return *this;
     203             :         }
     204             :         
     205         161 :         size_type rhsSize = rhs.size();
     206             :         
     207         161 :         if(size() >= rhsSize) {
     208           0 :             if(rhsSize > 0) {
     209           0 :                 std::move(rhs.begin(), rhs.end(), begin());
     210             :             }
     211             :             
     212           0 :             std::destroy(rbegin(), reverse_iterator(begin() + rhsSize));
     213           0 :             set_size(rhsSize);
     214           0 :             rhs.clear();
     215           0 :             return *this;
     216             :         }
     217             :         
     218         161 :         if(capacity() < rhsSize) {
     219           0 :             clear();
     220           0 :             grow_capacity_to_a_minimum_of(rhsSize);
     221         161 :         }else if(size() > 0) {
     222           0 :             std::move(rhs.begin(), rhs.begin() + size(), begin());
     223             :         }
     224             :         
     225         161 :         std::uninitialized_copy(std::move_iterator<iterator>(rhs.begin() + size()),
     226             :                                 std::move_iterator<iterator>(rhs.end()),
     227         161 :                                 begin() + size());
     228         161 :         set_size(rhsSize);
     229         161 :         rhs.clear();
     230         161 :         return *this;
     231             :     }
     232             :     
     233             :     reference at(size_type index) {
     234             :         if(index < size()) {
     235             :             return begin()[index];
     236             :         } else {
     237             :             throw std::out_of_range("small_vector::at(size_type index) std::out_or_range exception");
     238             :         }
     239             :     }
     240             :     
     241       52836 :     reference operator[](size_type index) {
     242       52836 :         return begin()[index];
     243             :     }
     244             :     
     245       99630 :     const_reference operator[](size_type index) const {
     246       99630 :         return begin()[index];
     247             :     }
     248             :     
     249             :     reference front() {
     250             :         assert(!empty());
     251             :         return begin()[0];
     252             :     }
     253             :     
     254        1073 :     const_reference front() const {
     255        1073 :         assert(!empty());
     256        1073 :         return begin()[0];
     257             :     }
     258             :     
     259        8284 :     reference back() {
     260        8284 :         assert(!empty());
     261        8284 :         return end()[-1];
     262             :     }
     263             :     
     264             :     const_reference back() const {
     265             :         assert(!empty());
     266             :         return end()[-1];
     267             :     }
     268             :     
     269             :     pointer data() {
     270             :         return pointer(begin());
     271             :     }
     272             :     
     273             :     const_pointer data() const { 
     274             :         return const_pointer(begin());
     275             :     }
     276             :     
     277      143945 :     iterator begin() { return static_cast<iterator>(beginPtr_); }
     278      125855 :     const_iterator begin() const { return static_cast<const_iterator>(beginPtr_); }
     279             :     const_iterator cbegin() const { return static_cast<const_iterator>(beginPtr_); }
     280             :     
     281       55662 :     iterator end() { return begin() + size(); }
     282       16044 :     const_iterator end() const { return begin() + size(); }
     283             :     const_iterator cend() const { return begin() + size(); }
     284             :     
     285       18295 :     reverse_iterator rbegin() { return reverse_iterator(end()); }
     286             :     const_reverse_iterator rbegin() const { return  const_reverse_iterator(end()); }
     287             :     const_reverse_iterator crbegin() const { return  const_reverse_iterator(end()); }
     288             :     
     289       18089 :     reverse_iterator rend() { return reverse_iterator(begin()); }
     290             :     const_reverse_iterator rend() const { return reverse_iterator(begin()); }
     291             :     const_reverse_iterator crend() const { return reverse_iterator(begin()); }
     292             :     
     293       12694 :     bool empty() const {
     294       12694 :         return size_ == 0;
     295             :     }
     296             :     
     297      182166 :     size_type size() const {
     298      182166 :         return size_;
     299             :     }
     300             :     
     301             :     size_type max_size() const {
     302             :         return size_type(-1) / sizeof(T);
     303             :     }
     304             :     
     305        1057 :     void reserve(size_type capacity) {
     306        1057 :         if(capacity > capacity_) {
     307           0 :             grow_capacity_to_a_minimum_of(capacity);
     308             :         }
     309        1057 :     }
     310             :     
     311       41703 :     size_type capacity() const {
     312       41703 :         return capacity_;
     313             :     }
     314             :     
     315       22428 :     void set_size(size_type size) {
     316       22428 :         assert(size <= capacity());
     317       22427 :         size_ = size;
     318       22427 :     }
     319             :     
     320        1688 :     void clear() {
     321        1688 :         std::destroy(rbegin(), rend());
     322        1688 :         set_size(0);
     323        1688 :     }
     324             :     
     325           1 :     iterator insert(const_iterator pos, T &&value) {
     326           1 :         iterator it = const_cast<iterator>(pos);
     327           1 :         if(it == end()) {
     328           0 :             push_back(value);
     329           0 :             return end()-1;
     330             :         }
     331             :         
     332           1 :         assert(it >= begin() && it <= end() && "small_vector::insert iterator is out of bounds.");
     333             :         
     334           1 :         if(size() == capacity()) {
     335           0 :             size_t index = std::distance(begin(), it);
     336           0 :             grow_capacity_to_a_minimum_of(size()+1);
     337           0 :             it = begin() + index;
     338             :         }
     339             :         
     340           1 :         new (static_cast<void *>(end())) T(std::move(back()));
     341           1 :         std::move_backward(it, end()-1, end());
     342             :         
     343           1 :         const_iterator itElt = std::addressof(value);
     344             :         
     345           1 :         if(itElt >= it && itElt < end()) {
     346           0 :             ++itElt;
     347             :         }
     348             :         
     349           1 :         *it = std::move(*itElt);
     350             :         
     351           1 :         set_size(size()+1);
     352             :         
     353           1 :         return it;
     354             :     }
     355             :     
     356          41 :     iterator insert(const_iterator pos, const T &value) {
     357          41 :         iterator it = const_cast<iterator>(pos);
     358          41 :         if(it == end()) {
     359           0 :             push_back(value);
     360           0 :             return end()-1;
     361             :         }
     362             :         
     363          41 :         assert(it >= begin() && it <= end() && "small_vector::insert iterator is out of bounds.");
     364             :         
     365          41 :         if(size() == capacity()) {
     366           0 :             size_t index = std::distance(begin(), it);
     367           0 :             grow_capacity_to_a_minimum_of(size()+1);
     368           0 :             it = begin() + index;
     369             :         }
     370             :         
     371          41 :         new (static_cast<void *>(end())) T(std::move(back()));
     372          41 :         std::move_backward(it, end()-1, end());
     373             :         
     374          41 :         const_iterator itElt = std::addressof(value);
     375             :         
     376          41 :         if(itElt >= it && itElt < end()) {
     377          41 :             ++itElt;
     378             :         }
     379             :         
     380          41 :         *it = *itElt;
     381             :         
     382          41 :         set_size(size()+1);
     383             :         
     384          41 :         return it;
     385             :     }
     386             :     
     387             :     iterator insert(const_iterator pos, size_type count, const T &value) {
     388             :         iterator it = const_cast<iterator>(pos);
     389             :         size_t index = std::distance(begin(), it);
     390             :         
     391             :         if(it == end()) {
     392             :             reserve(size() + count);
     393             :             std::uninitialized_fill_n(end(), count, value);
     394             :             set_size(size()+count);
     395             :             return begin() + index;
     396             :         }
     397             :         
     398             :         assert(it >= begin() && it <= end() && "small_vector::insert iterator is out of bounds.");
     399             :         
     400             :         reserve(size() + count);
     401             :         
     402             :         it = begin() + index;
     403             :         
     404             :         size_t nbEltsInRange = std::distance(it, end());
     405             :         
     406             :         if(count <= nbEltsInRange) {
     407             :             std::uninitialized_copy(std::move_iterator<iterator>(end() - count),
     408             :                                     std::move_iterator<iterator>(end()), end());
     409             :             std::move_backward(it, end() - count, end());
     410             :             set_size(size()+count);
     411             :             std::fill_n(it, count, value);
     412             :             return it;
     413             :         }
     414             :         
     415             :         iterator oldEnd = end();
     416             :         set_size(size() + count);
     417             :         size_t nbOverwrittenElts = std::distance(it, oldEnd);
     418             :         std::uninitialized_copy(std::move_iterator<iterator>(it), std::move_iterator<iterator>(oldEnd), end() - nbOverwrittenElts);
     419             :         
     420             :         std::fill_n(it, nbOverwrittenElts, value);
     421             :         
     422             :         std::uninitialized_fill_n(oldEnd, count - nbOverwrittenElts, value);
     423             :         
     424             :         return it;
     425             :     }
     426             :     
     427             :     template<typename InputItTy,
     428             :              typename = typename std::enable_if<std::is_convertible<
     429             :              typename std::iterator_traits<InputItTy>::iterator_category,
     430             :              std::input_iterator_tag>::value>::type>
     431         109 :     iterator insert(const_iterator pos, InputItTy first, InputItTy last) {
     432         109 :         iterator it = const_cast<iterator>(pos);
     433             :         
     434         109 :         size_t index = std::distance(begin(), it);
     435         109 :         size_t nbEltsInInputRange = std::distance(first, last);
     436             :         
     437         109 :         if(it == end()) {
     438         109 :             reserve(size() + nbEltsInInputRange);
     439         109 :             std::uninitialized_copy(first, last, end());
     440         109 :             set_size(size() + nbEltsInInputRange);
     441         109 :             return begin() + index;
     442             :         }
     443             :         
     444           0 :         assert(it >= begin() && it <= end() && "small_vector::insert iterator is out of bounds.");
     445             :         
     446           0 :         reserve(size() + nbEltsInInputRange);
     447             :         
     448           0 :         it = begin() + index;
     449             :         
     450           0 :         size_t nbEltsInRangeItToEnd = std::distance(it, end());
     451             :         
     452           0 :         if(nbEltsInInputRange <= nbEltsInRangeItToEnd) {
     453           0 :             std::uninitialized_copy(std::move_iterator<iterator>(end() - nbEltsInInputRange),
     454             :                                     std::move_iterator<iterator>(end()), end());
     455           0 :             std::move_backward(it, end() - nbEltsInInputRange, end());
     456           0 :             std::copy(first, last, it);
     457           0 :             set_size(size() + nbEltsInInputRange);
     458           0 :             return it;
     459             :         }
     460             :         
     461           0 :         size_t rangeSizeDifference = nbEltsInInputRange - nbEltsInRangeItToEnd;
     462             :         
     463           0 :         std::uninitialized_move(it, end(), end() + rangeSizeDifference);
     464             :         
     465           0 :         for(iterator i = it; i != it + nbEltsInRangeItToEnd; ++it, ++first) {
     466           0 :             *i = *first;
     467             :         }
     468             :         
     469           0 :         std::uninitialized_copy(first, last, end());
     470             :         
     471           0 :         set_size(size() + nbEltsInInputRange);
     472             :         
     473           0 :         return it;
     474             :     }
     475             :     
     476        8165 :     void push_back(const T &value) {
     477        8165 :         if(size() >= capacity()) {
     478           0 :             grow_capacity_to_a_minimum_of(capacity()+1);
     479             :         }
     480             :         
     481        8165 :         new (static_cast<void *>(end())) T(value);
     482             :         
     483        8165 :         set_size(size()+1);
     484        8165 :     }
     485             :     
     486           2 :     iterator erase(const_iterator pos) {
     487           2 :         iterator it = const_cast<iterator>(pos);
     488             : 
     489           2 :         assert(it >= this->begin() && it < this->end() && "small_vector::erase iterator to erase from is out of bounds.");
     490             :         
     491           2 :         std::move(it+1, end(), it);
     492           2 :         pop_back();
     493             :         
     494           2 :         return it;
     495             :     }
     496             :     
     497         206 :     iterator erase(const_iterator first, const_iterator last) {
     498         206 :         iterator itFirst = const_cast<iterator>(first);
     499         206 :         iterator itLast = const_cast<iterator>(last);
     500             :         
     501         206 :         assert(itFirst <= itLast && "small_vector::erase trying to erase invalid range.");
     502         206 :         assert(itFirst >= this->begin() && itLast <= this->end() && "small_vector::erase range to erase is out of bounds.");
     503             : 
     504         206 :         iterator it = std::move(itLast, end(), itFirst);
     505         206 :         std::destroy(rbegin(), reverse_iterator(it));
     506         206 :         this->set_size(std::distance(begin(), it));
     507             :         
     508         206 :         return itFirst;
     509             :     }
     510             :     
     511         779 :     void push_back(T &&value) {
     512         779 :         if(size() >= capacity()) {
     513           0 :             grow_capacity_to_a_minimum_of(capacity()+1);
     514             :         }
     515             :         
     516         779 :         new (static_cast<void *>(end())) T(std::move(value));
     517             :         
     518         779 :         set_size(size()+1);
     519         779 :     }
     520             :     
     521             :     template <typename... Args>
     522        4891 :     reference emplace_back(Args &&... args) {
     523        4891 :         if(size() >= capacity()) {
     524           1 :             grow_capacity_to_a_minimum_of(capacity()+1);
     525             :         }
     526             :         
     527        4891 :         new (static_cast<void *>(end())) T(std::forward<Args>(args)...);
     528             :         
     529        4891 :         set_size(size()+1);
     530             :         
     531        4891 :         return back();
     532             :     }
     533             :     
     534        1179 :     void pop_back() {
     535        1179 :         assert(!empty());
     536        1179 :         set_size(size()-1);
     537        1179 :         end()->~T();
     538        1179 :     }
     539             :     
     540           2 :     void resize(size_type count) {
     541           2 :         if(count < size()) {
     542           0 :             std::destroy(rbegin(), reverse_iterator(begin() + count));
     543           2 :         }else if(count > size()) {
     544           2 :             if(capacity() < count) {
     545           0 :                 grow_capacity_to_a_minimum_of(count);
     546             :             }
     547           2 :             std::uninitialized_value_construct(end(), begin() + count);
     548             :         }
     549           2 :         set_size(count);
     550           2 :     }
     551             :     
     552             :     void resize(size_type count, const value_type &value) {
     553             :         if(count < size()) {
     554             :             std::destroy(rbegin(), reverse_iterator(begin() + count));
     555             :         }else if(count > size()) {
     556             :             if(capacity() < count) {
     557             :                 grow_capacity_to_a_minimum_of(count);
     558             :             }
     559             :             std::uninitialized_fill(end(), begin() + count, value);
     560             :         }
     561             :         set_size(count);
     562             :     }
     563             :     
     564             :     void swap(small_vector_base &rhs) {
     565             :         if(this == std::addressof(rhs)) {
     566             :             return;
     567             :         }
     568             :         
     569             :         if(!is_small() && !rhs.is_small()) {
     570             :             std::swap(capacity_, rhs.capacity_);
     571             :             std::swap(size_, rhs.size_);
     572             :             std::swap(beginPtr_, rhs.beginPtr_);
     573             :             return;
     574             :         }
     575             :         
     576             :         if(rhs.capacity() < size()) {
     577             :             rhs.grow_capacity_to_a_minimum_of(size());
     578             :         }
     579             :         
     580             :         if(capacity() < rhs.size()) {
     581             :             grow_capacity_to_a_minimum_of(rhs.size());
     582             :         }
     583             :         
     584             :         size_type minSize = std::min(size(), rhs.size());
     585             :         
     586             :         std::swap_ranges(begin(), begin() + minSize, rhs.begin()); 
     587             :         
     588             :         if(size() > rhs.size()) {
     589             :             size_type nbEltsDiff = size() - rhs.size();
     590             :             std::uninitialized_copy(begin() + minSize, end(), rhs.end());
     591             :             rhs.set_size(rhs.size() + nbEltsDiff);
     592             :             set_size(minSize);
     593             :         }else if(rhs.size() > size()) {
     594             :             size_type nbEltsDiff = rhs.size() - size();
     595             :             std::uninitialized_copy(rhs.begin() + minSize, rhs.end(), end());
     596             :             set_size(size() + nbEltsDiff);
     597             :             rhs.set_size(minSize);
     598             :         }
     599             :     }
     600             :     
     601             :     bool operator==(const small_vector_base &rhs) {
     602             :         return size() == rhs.size() && std::equal(begin(), end(), rhs.begin());
     603             :     }
     604             :     
     605       16562 :     bool is_small() const {
     606       16562 :         return beginPtr_ == getPointerToInternalStorage();
     607             :     }
     608             :     
     609       32934 :     void *getPointerToInternalStorage() const {
     610             :         return const_cast<void *>(reinterpret_cast<const void *>(reinterpret_cast<const char *>(this) +
     611       32934 :                offsetof(small_vector_internal_storage_offset_computation_structure<T>, firstElt)));
     612             :     }
     613             :     
     614           0 :     void reset_to_small() {
     615           0 :         beginPtr_ = getPointerToInternalStorage();
     616           0 :         capacity_ = originalCapacity_;
     617           0 :         size_ = 0;
     618           0 :     }
     619             : };
     620             : 
     621             : template <typename T, size_t N>
     622             : struct small_vector_storage {
     623             :     alignas(T) char smallBuffer_[sizeof(T)*N];
     624             : };
     625             : 
     626             : template <typename T>
     627             : struct alignas(T) small_vector_storage<T, 0> { };
     628             : 
     629             : template <typename T, size_t N = 64>
     630             : class small_vector : public small_vector_base<T>, public small_vector_storage<T, N> {
     631             : public:
     632             :     using typename small_vector_base<T>::size_type;
     633             :     using typename small_vector_base<T>::difference_type;
     634             :     using typename small_vector_base<T>::value_type;
     635             :     using typename small_vector_base<T>::iterator;
     636             :     using typename small_vector_base<T>::const_iterator;
     637             :     
     638             :     using typename small_vector_base<T>::reverse_iterator;
     639             :     using typename small_vector_base<T>::const_reverse_iterator;
     640             :     
     641             :     using typename small_vector_base<T>::reference;
     642             :     using typename small_vector_base<T>::const_reference;
     643             :     using typename small_vector_base<T>::pointer;
     644             :     using typename small_vector_base<T>::const_pointer;
     645             :     
     646       16372 :     small_vector() : small_vector_base<T>(N) {}
     647             :     
     648        1106 :     explicit small_vector(size_t count, const T &value = T()) : small_vector() {
     649        1106 :         this->assign(count, value);
     650        1106 :     }
     651             :     
     652         696 :     small_vector(const small_vector &rhs) : small_vector() {
     653         696 :         if(!rhs.empty()) {
     654         696 :             small_vector_base<T>::operator=(rhs);
     655             :         }
     656         696 :     }
     657             :     
     658          64 :     small_vector(small_vector &&rhs) : small_vector() {
     659          64 :         if(!rhs.empty()) {
     660           0 :             small_vector_base<T>::operator=(std::move(rhs));
     661             :         }
     662          64 :     }
     663             :     
     664             :     template<typename InputItTy,
     665             :              typename = typename std::enable_if<std::is_convertible<
     666             :              typename std::iterator_traits<InputItTy>::iterator_category,
     667             :              std::input_iterator_tag>::value>::type>
     668             :     small_vector(InputItTy first, InputItTy last) : small_vector() {
     669             :         this->assign(first, last);
     670             :     }
     671             :     
     672        3404 :     small_vector(std::initializer_list<T> il) : small_vector() {
     673        3404 :         this->assign(il);
     674        3404 :     }
     675             :     
     676       16372 :     ~small_vector() {
     677       16372 :         std::destroy(this->rbegin(), this->rend());
     678       16372 :         if(!this->is_small()) {
     679          29 :             std::free(this->begin());
     680             :         }
     681       16372 :     }
     682             :     
     683             :     small_vector &operator=(const small_vector &rhs) {
     684             :         small_vector_base<T>::operator=(rhs);
     685             :         return *this;
     686             :     }
     687             :     
     688             :     small_vector &operator=(const small_vector_base<T> &rhs) {
     689             :         small_vector_base<T>::operator=(rhs);
     690             :         return *this;
     691             :     }
     692             :     
     693             :     small_vector &operator=(small_vector &&rhs) {
     694             :         small_vector_base<T>::operator=(std::move(rhs));
     695             :         return *this;
     696             :     }
     697             :     
     698         161 :     small_vector &operator=(small_vector_base<T> &&rhs) {
     699         161 :         small_vector_base<T>::operator=(std::move(rhs));
     700         161 :         return *this;
     701             :     }
     702             :     
     703             :     small_vector &operator=(std::initializer_list<T> il) {
     704             :         this->assign(il);
     705             :         return *this;
     706             :     }
     707             : };
     708             : 
     709          29 : inline uint64_t nextPowerOfTwo(uint64_t n) {
     710          29 :     n |= (n >> 1);
     711          29 :     n |= (n >> 2);
     712          29 :     n |= (n >> 4);
     713          29 :     n |= (n >> 8);
     714          29 :     n |= (n >> 16);
     715          29 :     n |= (n >> 32);
     716             :     
     717          29 :     return n + 1;
     718             : }
     719             : 
     720             : namespace std {
     721             :     template <typename T, size_t N>
     722             :     inline void swap(small_vector<T, N> &lhs, small_vector<T, N> &rhs) {
     723             :         lhs.swap(rhs);
     724             :     }
     725             :     
     726             :     template <typename T>
     727             :     inline void swap(small_vector_base<T> &lhs, small_vector_base<T> &rhs) {
     728             :         lhs.swap(rhs);
     729             :     }
     730             : }
     731             : 
     732             : template <typename T>
     733             : struct is_instantiation_of_small_vector : std::false_type {};
     734             : 
     735             : template <typename T, size_t N>
     736             : struct is_instantiation_of_small_vector<small_vector<T, N>> : std::true_type {};
     737             : 
     738             : #endif

Generated by: LCOV version 1.14