| 18 | |
| 19 | template <class T, size_t N> |
| 20 | class buffer_vector |
| 21 | { |
| 22 | private: |
| 23 | enum |
| 24 | { |
| 25 | USE_DYNAMIC = N + 1 |
| 26 | }; |
| 27 | // TODO (@gmoryes) consider std::aligned_storage |
| 28 | T m_static[N]; |
| 29 | size_t m_size; |
| 30 | std::vector<T> m_dynamic; |
| 31 | |
| 32 | bool IsDynamic() const { return m_size == USE_DYNAMIC; } |
| 33 | |
| 34 | void MoveStatic(buffer_vector & rhs) noexcept |
| 35 | { |
| 36 | static_assert(std::is_nothrow_move_assignable<T>::value); |
| 37 | |
| 38 | std::move(rhs.m_static, rhs.m_static + rhs.m_size, m_static); |
| 39 | } |
| 40 | |
| 41 | void SetStaticSize(size_t newSize) |
| 42 | { |
| 43 | if constexpr (std::is_destructible<T>::value) |
| 44 | { |
| 45 | // Call destructors for old elements. |
| 46 | for (size_t i = newSize; i < m_size; ++i) |
| 47 | m_static[i] = T(); |
| 48 | } |
| 49 | m_size = newSize; |
| 50 | } |
| 51 | |
| 52 | static constexpr size_t SwitchCapacity() { return 3 * N / 2 + 1; } |
| 53 | |
| 54 | public: |
| 55 | typedef T value_type; |
| 56 | typedef T const & const_reference; |
| 57 | typedef T & reference; |
| 58 | typedef size_t size_type; |
| 59 | typedef T const * const_iterator; |
| 60 | typedef T * iterator; |
| 61 | |
| 62 | buffer_vector() : m_size(0) {} |
| 63 | explicit buffer_vector(size_t n) : m_size(0) { resize(n); } |
| 64 | |
| 65 | buffer_vector(std::initializer_list<T> init) : m_size(0) |
| 66 | { |
| 67 | assign(std::make_move_iterator(init.begin()), std::make_move_iterator(init.end())); |
| 68 | } |
| 69 | |
| 70 | template <typename TIt> |
| 71 | buffer_vector(TIt beg, TIt end) : m_size(0) |
| 72 | { |
| 73 | assign(beg, end); |
| 74 | } |
| 75 | |
| 76 | buffer_vector(buffer_vector const &) = default; |
| 77 | |