compact_vector.h 6.4 KB

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