compact_vector.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. #pragma once
  2. #include <util/generic/bitops.h>
  3. #include <util/generic/yexception.h>
  4. #include <util/system/sys_alloc.h>
  5. // vector that is 8 bytes when empty (TVector is 24 bytes)
  6. template <typename T>
  7. class TCompactVector {
  8. private:
  9. typedef TCompactVector<T> TThis;
  10. // XXX: make header independent on T and introduce nullptr
  11. struct THeader {
  12. size_t Size;
  13. size_t Capacity;
  14. };
  15. T* Ptr;
  16. THeader* Header() {
  17. return ((THeader*)Ptr) - 1;
  18. }
  19. const THeader* Header() const {
  20. return ((THeader*)Ptr) - 1;
  21. }
  22. void destruct_at(size_t pos) {
  23. (*this)[pos].~T();
  24. }
  25. public:
  26. using value_type = T;
  27. using TIterator = T*;
  28. using TConstIterator = const T*;
  29. using iterator = TIterator ;
  30. using const_iterator = TConstIterator;
  31. using reverse_iterator = std::reverse_iterator<iterator>;
  32. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  33. TCompactVector()
  34. : Ptr(nullptr)
  35. {
  36. }
  37. TCompactVector(const TThis& that)
  38. : Ptr(nullptr)
  39. {
  40. Reserve(that.Size());
  41. for (TConstIterator i = that.Begin(); i != that.End(); ++i) {
  42. PushBack(*i);
  43. }
  44. }
  45. TCompactVector(TThis&& that) noexcept
  46. : Ptr(nullptr)
  47. {
  48. Swap(that);
  49. }
  50. TCompactVector(std::initializer_list<T> init)
  51. : Ptr(nullptr)
  52. {
  53. Reserve(init.size());
  54. for (const T& val : init) {
  55. PushBack(val);
  56. }
  57. }
  58. template <class InputIterator>
  59. TCompactVector(InputIterator begin, InputIterator end)
  60. : Ptr(nullptr)
  61. {
  62. Reserve(std::distance(begin, end));
  63. for (auto it = begin; it != end; ++it) {
  64. push_back(*it);
  65. }
  66. }
  67. ~TCompactVector() {
  68. for (size_t i = 0; i < Size(); ++i) {
  69. try {
  70. destruct_at(i);
  71. } catch (...) {
  72. }
  73. }
  74. if (Ptr)
  75. y_deallocate(Header());
  76. }
  77. TThis& operator = (TThis&& that) noexcept {
  78. Swap(that);
  79. return *this;
  80. }
  81. TThis& operator = (const TThis& that) {
  82. if (Y_LIKELY(this != &that)) {
  83. TThis tmp(that);
  84. Swap(tmp);
  85. }
  86. return *this;
  87. }
  88. TThis& operator = (std::initializer_list<T> init) {
  89. TThis data(init);
  90. Swap(data);
  91. return *this;
  92. }
  93. TIterator Begin() {
  94. return Ptr;
  95. }
  96. TIterator End() {
  97. return Ptr + Size();
  98. }
  99. TConstIterator Begin() const {
  100. return Ptr;
  101. }
  102. TConstIterator End() const {
  103. return Ptr + Size();
  104. }
  105. iterator begin() {
  106. return Begin();
  107. }
  108. const_iterator begin() const {
  109. return Begin();
  110. }
  111. iterator end() {
  112. return End();
  113. }
  114. const_iterator end() const {
  115. return End();
  116. }
  117. reverse_iterator rbegin() {
  118. return std::make_reverse_iterator(end());
  119. }
  120. const_reverse_iterator rbegin() const {
  121. return std::make_reverse_iterator(end());
  122. }
  123. reverse_iterator rend() {
  124. return std::make_reverse_iterator(begin());
  125. }
  126. const_reverse_iterator rend() const {
  127. return std::make_reverse_iterator(begin());
  128. }
  129. void Swap(TThis& that) noexcept {
  130. DoSwap(Ptr, that.Ptr);
  131. }
  132. void Reserve(size_t newCapacity) {
  133. if (newCapacity <= Capacity()) {
  134. } else if (Ptr == nullptr) {
  135. constexpr size_t maxBlockSize = static_cast<size_t>(1) << (sizeof(size_t) * 8 - 1);
  136. constexpr size_t maxCapacity = (maxBlockSize - sizeof(THeader)) / sizeof(T);
  137. Y_ENSURE(newCapacity <= maxCapacity);
  138. const size_t requiredMemSize = sizeof(THeader) + newCapacity * sizeof(T);
  139. // most allocators operates pow-of-two memory blocks,
  140. // so we try to allocate such memory block to fully utilize its capacity
  141. const size_t memSizePowOf2 = FastClp2(requiredMemSize);
  142. const size_t realNewCapacity = (memSizePowOf2 - sizeof(THeader)) / sizeof(T);
  143. Y_ASSERT(realNewCapacity >= newCapacity);
  144. void* mem = ::y_allocate(memSizePowOf2);
  145. Ptr = (T*)(((THeader*)mem) + 1);
  146. Header()->Size = 0;
  147. Header()->Capacity = realNewCapacity;
  148. } else {
  149. TThis copy;
  150. copy.Reserve(newCapacity);
  151. for (TConstIterator it = Begin(); it != End(); ++it) {
  152. copy.PushBack(*it);
  153. }
  154. Swap(copy);
  155. }
  156. }
  157. void reserve(size_t newCapacity) {
  158. Reserve(newCapacity);
  159. }
  160. size_t Size() const {
  161. return Ptr ? Header()->Size : 0;
  162. }
  163. size_t size() const {
  164. return Size();
  165. }
  166. bool Empty() const {
  167. return Size() == 0;
  168. }
  169. bool empty() const {
  170. return Empty();
  171. }
  172. size_t Capacity() const {
  173. return Ptr ? Header()->Capacity : 0;
  174. }
  175. void PushBack(const T& elem) {
  176. Reserve(Size() + 1);
  177. new (Ptr + Size()) T(elem);
  178. ++(Header()->Size);
  179. }
  180. void push_back(const T& elem) {
  181. PushBack(elem);
  182. }
  183. T& Back() {
  184. return *(End() - 1);
  185. }
  186. const T& Back() const {
  187. return *(End() - 1);
  188. }
  189. T& back() {
  190. return Back();
  191. }
  192. const T& back() const {
  193. return Back();
  194. }
  195. TIterator Insert(TIterator pos, const T& elem) {
  196. Y_ASSERT(pos >= Begin());
  197. Y_ASSERT(pos <= End());
  198. size_t posn = pos - Begin();
  199. if (pos == End()) {
  200. PushBack(elem);
  201. } else {
  202. Y_ASSERT(Size() > 0);
  203. Reserve(Size() + 1);
  204. PushBack(*(End() - 1));
  205. for (size_t i = Size() - 2; i + 1 > posn; --i) {
  206. (*this)[i + 1] = (*this)[i];
  207. }
  208. (*this)[posn] = elem;
  209. }
  210. return Begin() + posn;
  211. }
  212. iterator insert(iterator pos, const T& elem) {
  213. return Insert(pos, elem);
  214. }
  215. void Clear() {
  216. TThis clean;
  217. Swap(clean);
  218. }
  219. void clear() {
  220. Clear();
  221. }
  222. void erase(iterator position) {
  223. Y_ENSURE(position >= begin() && position < end());
  224. std::move(position + 1, end(), position);
  225. destruct_at(Size() - 1);
  226. Header()->Size -= 1;
  227. }
  228. T& operator[](size_t index) {
  229. Y_ASSERT(index < Size());
  230. return Ptr[index];
  231. }
  232. const T& operator[](size_t index) const {
  233. Y_ASSERT(index < Size());
  234. return Ptr[index];
  235. }
  236. };