compact_vector.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #pragma once
  2. #include <util/system/defaults.h>
  3. #include <cstdint>
  4. #include <iterator>
  5. #include <limits>
  6. namespace NYT {
  7. ////////////////////////////////////////////////////////////////////////////////
  8. template <class T>
  9. struct TCompactVectorOnHeapStorage;
  10. //! A vector-like structure optimized for storing elements inline
  11. //! and with little memory overhead.
  12. /*!
  13. * Stores up to #N (<= 254) elements inline.
  14. *
  15. * When capacity starts exceeding #N, moves all elements to heap;
  16. * \see #TCompactVectorOnHeapStorage.
  17. *
  18. * When linked with YTAlloc, employs its API to adjust the on-heap capacity in accordance
  19. * to the actual size of the allocated region.
  20. *
  21. * Assuming the entropy and the alignment constraints, yields a seemingly optimal memory overhead.
  22. * E.g. TCompactVector<uint8_t, 7> takes 8 bytes and TCompactVector<uint32_t, 3> takes 16 bytes.
  23. * \see #ByteSize.
  24. *
  25. * Assumes (and asserts) the following:
  26. * 1) the platform is 64 bit;
  27. * 2) the highest 8 bits of pointers returned by |malloc| are zeroes;
  28. * 3) the platform is little-endian.
  29. */
  30. template <class T, size_t N>
  31. class TCompactVector
  32. {
  33. public:
  34. static_assert(N < std::numeric_limits<uint8_t>::max());
  35. using size_type = size_t;
  36. using difference_type = ptrdiff_t;
  37. using value_type = T;
  38. using iterator = T*;
  39. using const_iterator = const T*;
  40. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  41. using reverse_iterator = std::reverse_iterator<iterator>;
  42. using reference = T&;
  43. using const_reference = const T&;
  44. using pointer = T*;
  45. using const_pointer = const T*;
  46. TCompactVector() noexcept;
  47. TCompactVector(const TCompactVector& other);
  48. template <size_t OtherN>
  49. TCompactVector(const TCompactVector<T, OtherN>& other);
  50. TCompactVector(TCompactVector&& other) noexcept(std::is_nothrow_move_constructible_v<T>);
  51. template <size_t OtherN>
  52. TCompactVector(TCompactVector<T, OtherN>&& other);
  53. explicit TCompactVector(size_type count);
  54. TCompactVector(size_type count, const T& value);
  55. template <class TIterator>
  56. TCompactVector(TIterator first, TIterator last);
  57. TCompactVector(std::initializer_list<T> list);
  58. ~TCompactVector();
  59. [[nodiscard]] bool empty() const;
  60. iterator begin();
  61. const_iterator begin() const;
  62. iterator end();
  63. const_iterator end() const;
  64. reverse_iterator rbegin();
  65. const_reverse_iterator rbegin() const;
  66. reverse_iterator rend();
  67. const_reverse_iterator rend() const;
  68. size_type size() const;
  69. size_type capacity() const;
  70. size_type max_size() const;
  71. pointer data();
  72. const_pointer data() const;
  73. reference operator[](size_type index);
  74. const_reference operator[](size_type index) const;
  75. reference front();
  76. const_reference front() const;
  77. reference back();
  78. const_reference back() const;
  79. void push_back(const T& value);
  80. void push_back(T&& value);
  81. template <class... TArgs>
  82. iterator emplace(const_iterator pos, TArgs&&... args);
  83. template <class... TArgs>
  84. reference emplace_back(TArgs&&... args);
  85. void pop_back();
  86. iterator erase(const_iterator pos);
  87. iterator erase(const_iterator first, const_iterator last);
  88. void clear();
  89. void resize(size_type newSize);
  90. void resize(size_type newSize, const T& value);
  91. void reserve(size_type newCapacity);
  92. void swap(TCompactVector& other);
  93. void assign(size_type count, const T& value);
  94. template <class TIterator>
  95. void assign(TIterator first, TIterator last);
  96. void assign(std::initializer_list<T> list);
  97. template <size_t OtherN>
  98. void assign(const TCompactVector<T, OtherN>& other);
  99. template <size_t OtherN>
  100. void assign(TCompactVector<T, OtherN>&& other);
  101. TCompactVector& operator=(const TCompactVector& other);
  102. template <size_t OtherN>
  103. TCompactVector& operator=(const TCompactVector<T, OtherN>& other);
  104. TCompactVector& operator=(TCompactVector&& other);
  105. template <size_t OtherN>
  106. TCompactVector& operator=(TCompactVector<T, OtherN>&& other);
  107. TCompactVector& operator=(std::initializer_list<T> list);
  108. iterator insert(const_iterator pos, const T& value);
  109. iterator insert(const_iterator pos, T&& value);
  110. iterator insert(const_iterator pos, size_type count, const T& value);
  111. template <class TIterator>
  112. iterator insert(const_iterator pos, TIterator first, TIterator last);
  113. iterator insert(const_iterator pos, std::initializer_list<T> list);
  114. void shrink_to_small();
  115. private:
  116. template <class OtherT, size_t OtherN>
  117. friend class TCompactVector;
  118. using TOnHeapStorage = TCompactVectorOnHeapStorage<T>;
  119. static constexpr size_t ByteSize =
  120. (sizeof(T) * N + alignof(T) + sizeof(uintptr_t) - 1) &
  121. ~(sizeof(uintptr_t) - 1);
  122. struct TInlineMeta
  123. {
  124. char Padding[ByteSize - sizeof(uint8_t)];
  125. // > 0 indicates inline storage
  126. // == 0 indicates on-heap storage
  127. uint8_t SizePlusOne;
  128. } alias_hack;
  129. // TODO(aleexfi): Use [[no_unique_address]] when clang will support it on windows.
  130. template <class = void>
  131. struct TOnHeapMeta
  132. {
  133. char Padding[ByteSize - sizeof(uintptr_t)];
  134. TOnHeapStorage* Storage;
  135. } alias_hack;
  136. template <class _>
  137. requires (ByteSize == sizeof(uintptr_t))
  138. struct TOnHeapMeta<_>
  139. {
  140. TOnHeapStorage* Storage;
  141. } alias_hack;
  142. static_assert(sizeof(TOnHeapMeta<>) == ByteSize);
  143. union
  144. {
  145. T InlineElements_[N];
  146. TInlineMeta InlineMeta_;
  147. TOnHeapMeta<> OnHeapMeta_;
  148. };
  149. bool IsInline() const;
  150. void SetSize(size_t newSize);
  151. void EnsureOnHeapCapacity(size_t newCapacity, bool incremental);
  152. template <class TPtr, class F>
  153. reference PushBackImpl(TPtr valuePtr, F&& func);
  154. template <class F>
  155. void ResizeImpl(size_t newSize, F&& func);
  156. template <class TPtr, class UninitializedF, class InitializedF>
  157. iterator InsertOneImpl(const_iterator pos, TPtr valuePtr, UninitializedF&& uninitializedFunc, InitializedF&& initializedFunc);
  158. template <class UninitializedF, class InitializedF>
  159. iterator InsertManyImpl(const_iterator pos, size_t insertCount, UninitializedF&& uninitializedFunc, InitializedF&& initializedFunc);
  160. static void Destroy(T* first, T* last);
  161. template <class T1, class T2>
  162. static void Copy(const T1* srcFirst, const T1* srcLast, T2* dst);
  163. template <class T1, class T2>
  164. static void UninitializedCopy(const T1* srcFirst, const T1* srcLast, T2* dst);
  165. static void Move(T* srcFirst, T* srcLast, T* dst);
  166. static void MoveBackward(T* srcFirst, T* srcLast, T* dst);
  167. static void UninitializedMove(T* srcFirst, T* srcLast, T* dst);
  168. };
  169. ////////////////////////////////////////////////////////////////////////////////
  170. template <class T, size_t LhsN, size_t RhsN>
  171. bool operator==(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs);
  172. template <class T, size_t LhsN, size_t RhsN>
  173. bool operator!=(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs);
  174. template <class T, size_t LhsN, size_t RhsN>
  175. bool operator<(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs);
  176. ////////////////////////////////////////////////////////////////////////////////
  177. } // namespace NYT
  178. #define COMPACT_VECTOR_INL_H_
  179. #include "compact_vector-inl.h"
  180. #undef COMPACT_VECTOR_INL_H_