autovector.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. #pragma once
  6. #include <algorithm>
  7. #include <cassert>
  8. #include <initializer_list>
  9. #include <iterator>
  10. #include <stdexcept>
  11. #include <vector>
  12. #include "port/lang.h"
  13. #include "rocksdb/rocksdb_namespace.h"
  14. namespace ROCKSDB_NAMESPACE {
  15. // A vector that leverages pre-allocated stack-based array to achieve better
  16. // performance for array with small amount of items.
  17. //
  18. // The interface resembles that of vector, but with less features since we aim
  19. // to solve the problem that we have in hand, rather than implementing a
  20. // full-fledged generic container.
  21. //
  22. // Currently we don't support:
  23. // * shrink_to_fit()
  24. // If used correctly, in most cases, people should not touch the
  25. // underlying vector at all.
  26. // * random insert()/erase(), please only use push_back()/pop_back().
  27. // * No move/swap operations. Each autovector instance has a
  28. // stack-allocated array and if we want support move/swap operations, we
  29. // need to copy the arrays other than just swapping the pointers. In this
  30. // case we'll just explicitly forbid these operations since they may
  31. // lead users to make false assumption by thinking they are inexpensive
  32. // operations.
  33. //
  34. // Naming style of public methods almost follows that of the STL's.
  35. template <class T, size_t kSize = 8>
  36. class autovector {
  37. public:
  38. // General STL-style container member types.
  39. using value_type = T;
  40. using difference_type = typename std::vector<T>::difference_type;
  41. using size_type = typename std::vector<T>::size_type;
  42. using reference = value_type&;
  43. using const_reference = const value_type&;
  44. using pointer = value_type*;
  45. using const_pointer = const value_type*;
  46. // This class is the base for regular/const iterator
  47. template <class TAutoVector, class TValueType>
  48. class iterator_impl {
  49. public:
  50. // -- iterator traits
  51. using self_type = iterator_impl<TAutoVector, TValueType>;
  52. using value_type = TValueType;
  53. using reference = TValueType&;
  54. using pointer = TValueType*;
  55. using difference_type = typename TAutoVector::difference_type;
  56. using iterator_category = std::random_access_iterator_tag;
  57. iterator_impl(TAutoVector* vect, size_t index)
  58. : vect_(vect), index_(index) {}
  59. iterator_impl(const iterator_impl&) = default;
  60. ~iterator_impl() {}
  61. iterator_impl& operator=(const iterator_impl&) = default;
  62. // -- Advancement
  63. // ++iterator
  64. self_type& operator++() {
  65. ++index_;
  66. return *this;
  67. }
  68. // iterator++
  69. self_type operator++(int) {
  70. auto old = *this;
  71. ++index_;
  72. return old;
  73. }
  74. // --iterator
  75. self_type& operator--() {
  76. --index_;
  77. return *this;
  78. }
  79. // iterator--
  80. self_type operator--(int) {
  81. auto old = *this;
  82. --index_;
  83. return old;
  84. }
  85. self_type operator-(difference_type len) const {
  86. return self_type(vect_, index_ - len);
  87. }
  88. difference_type operator-(const self_type& other) const {
  89. assert(vect_ == other.vect_);
  90. return index_ - other.index_;
  91. }
  92. self_type operator+(difference_type len) const {
  93. return self_type(vect_, index_ + len);
  94. }
  95. self_type& operator+=(difference_type len) {
  96. index_ += len;
  97. return *this;
  98. }
  99. self_type& operator-=(difference_type len) {
  100. index_ -= len;
  101. return *this;
  102. }
  103. // -- Reference
  104. reference operator*() const {
  105. assert(vect_->size() >= index_);
  106. return (*vect_)[index_];
  107. }
  108. pointer operator->() const {
  109. assert(vect_->size() >= index_);
  110. return &(*vect_)[index_];
  111. }
  112. reference operator[](difference_type len) const { return *(*this + len); }
  113. // -- Logical Operators
  114. bool operator==(const self_type& other) const {
  115. assert(vect_ == other.vect_);
  116. return index_ == other.index_;
  117. }
  118. bool operator!=(const self_type& other) const { return !(*this == other); }
  119. bool operator>(const self_type& other) const {
  120. assert(vect_ == other.vect_);
  121. return index_ > other.index_;
  122. }
  123. bool operator<(const self_type& other) const {
  124. assert(vect_ == other.vect_);
  125. return index_ < other.index_;
  126. }
  127. bool operator>=(const self_type& other) const {
  128. assert(vect_ == other.vect_);
  129. return index_ >= other.index_;
  130. }
  131. bool operator<=(const self_type& other) const {
  132. assert(vect_ == other.vect_);
  133. return index_ <= other.index_;
  134. }
  135. private:
  136. TAutoVector* vect_ = nullptr;
  137. size_t index_ = 0;
  138. };
  139. using iterator = iterator_impl<autovector, value_type>;
  140. using const_iterator = iterator_impl<const autovector, const value_type>;
  141. using reverse_iterator = std::reverse_iterator<iterator>;
  142. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  143. autovector() : values_(reinterpret_cast<pointer>(buf_)) {}
  144. autovector(std::initializer_list<T> init_list)
  145. : values_(reinterpret_cast<pointer>(buf_)) {
  146. for (const T& item : init_list) {
  147. push_back(item);
  148. }
  149. }
  150. ~autovector() { clear(); }
  151. // -- Immutable operations
  152. // Indicate if all data resides in in-stack data structure.
  153. bool only_in_stack() const {
  154. // If no element was inserted at all, the vector's capacity will be `0`.
  155. return vect_.capacity() == 0;
  156. }
  157. size_type size() const { return num_stack_items_ + vect_.size(); }
  158. // resize does not guarantee anything about the contents of the newly
  159. // available elements
  160. void resize(size_type n) {
  161. if (n > kSize) {
  162. vect_.resize(n - kSize);
  163. while (num_stack_items_ < kSize) {
  164. new ((void*)(&values_[num_stack_items_++])) value_type();
  165. }
  166. num_stack_items_ = kSize;
  167. } else {
  168. vect_.clear();
  169. while (num_stack_items_ < n) {
  170. new ((void*)(&values_[num_stack_items_++])) value_type();
  171. }
  172. while (num_stack_items_ > n) {
  173. values_[--num_stack_items_].~value_type();
  174. }
  175. }
  176. }
  177. bool empty() const { return size() == 0; }
  178. size_type capacity() const { return kSize + vect_.capacity(); }
  179. void reserve(size_t cap) {
  180. if (cap > kSize) {
  181. vect_.reserve(cap - kSize);
  182. }
  183. assert(cap <= capacity());
  184. }
  185. const_reference operator[](size_type n) const {
  186. assert(n < size());
  187. if (n < kSize) {
  188. return values_[n];
  189. }
  190. return vect_[n - kSize];
  191. }
  192. reference operator[](size_type n) {
  193. assert(n < size());
  194. if (n < kSize) {
  195. return values_[n];
  196. }
  197. return vect_[n - kSize];
  198. }
  199. const_reference at(size_type n) const {
  200. assert(n < size());
  201. return (*this)[n];
  202. }
  203. reference at(size_type n) {
  204. assert(n < size());
  205. return (*this)[n];
  206. }
  207. reference front() {
  208. assert(!empty());
  209. return *begin();
  210. }
  211. const_reference front() const {
  212. assert(!empty());
  213. return *begin();
  214. }
  215. reference back() {
  216. assert(!empty());
  217. return *(end() - 1);
  218. }
  219. const_reference back() const {
  220. assert(!empty());
  221. return *(end() - 1);
  222. }
  223. // -- Mutable Operations
  224. void push_back(T&& item) {
  225. if (num_stack_items_ < kSize) {
  226. new ((void*)(&values_[num_stack_items_])) value_type();
  227. values_[num_stack_items_++] = std::move(item);
  228. } else {
  229. vect_.push_back(item);
  230. }
  231. }
  232. void push_back(const T& item) {
  233. if (num_stack_items_ < kSize) {
  234. new ((void*)(&values_[num_stack_items_])) value_type();
  235. values_[num_stack_items_++] = item;
  236. } else {
  237. vect_.push_back(item);
  238. }
  239. }
  240. template <class... Args>
  241. #if _LIBCPP_STD_VER > 14
  242. reference emplace_back(Args&&... args) {
  243. if (num_stack_items_ < kSize) {
  244. return *(new ((void*)(&values_[num_stack_items_++]))
  245. value_type(std::forward<Args>(args)...));
  246. } else {
  247. return vect_.emplace_back(std::forward<Args>(args)...);
  248. }
  249. }
  250. #else
  251. void emplace_back(Args&&... args) {
  252. if (num_stack_items_ < kSize) {
  253. new ((void*)(&values_[num_stack_items_++]))
  254. value_type(std::forward<Args>(args)...);
  255. } else {
  256. vect_.emplace_back(std::forward<Args>(args)...);
  257. }
  258. }
  259. #endif
  260. void pop_back() {
  261. assert(!empty());
  262. if (!vect_.empty()) {
  263. vect_.pop_back();
  264. } else {
  265. values_[--num_stack_items_].~value_type();
  266. }
  267. }
  268. void clear() {
  269. while (num_stack_items_ > 0) {
  270. values_[--num_stack_items_].~value_type();
  271. }
  272. vect_.clear();
  273. }
  274. // -- Copy and Assignment
  275. autovector& assign(const autovector& other);
  276. autovector(const autovector& other) { assign(other); }
  277. autovector& operator=(const autovector& other) { return assign(other); }
  278. autovector(autovector&& other) noexcept { *this = std::move(other); }
  279. autovector& operator=(autovector&& other);
  280. // -- Iterator Operations
  281. iterator begin() { return iterator(this, 0); }
  282. const_iterator begin() const { return const_iterator(this, 0); }
  283. iterator end() { return iterator(this, this->size()); }
  284. const_iterator end() const { return const_iterator(this, this->size()); }
  285. reverse_iterator rbegin() { return reverse_iterator(end()); }
  286. const_reverse_iterator rbegin() const {
  287. return const_reverse_iterator(end());
  288. }
  289. reverse_iterator rend() { return reverse_iterator(begin()); }
  290. const_reverse_iterator rend() const {
  291. return const_reverse_iterator(begin());
  292. }
  293. private:
  294. size_type num_stack_items_ = 0; // current number of items
  295. alignas(alignof(
  296. value_type)) char buf_[kSize *
  297. sizeof(value_type)]; // the first `kSize` items
  298. pointer values_;
  299. // used only if there are more than `kSize` items.
  300. std::vector<T> vect_;
  301. };
  302. template <class T, size_t kSize>
  303. autovector<T, kSize>& autovector<T, kSize>::assign(
  304. const autovector<T, kSize>& other) {
  305. values_ = reinterpret_cast<pointer>(buf_);
  306. // copy the internal vector
  307. vect_.assign(other.vect_.begin(), other.vect_.end());
  308. // copy array
  309. num_stack_items_ = other.num_stack_items_;
  310. for (size_t i = 0; i < num_stack_items_; ++i) {
  311. new ((void*)(&values_[i])) value_type();
  312. }
  313. std::copy(other.values_, other.values_ + num_stack_items_, values_);
  314. return *this;
  315. }
  316. template <class T, size_t kSize>
  317. autovector<T, kSize>& autovector<T, kSize>::operator=(
  318. autovector<T, kSize>&& other) {
  319. values_ = reinterpret_cast<pointer>(buf_);
  320. vect_ = std::move(other.vect_);
  321. size_t n = other.num_stack_items_;
  322. num_stack_items_ = n;
  323. other.num_stack_items_ = 0;
  324. for (size_t i = 0; i < n; ++i) {
  325. new ((void*)(&values_[i])) value_type();
  326. values_[i] = std::move(other.values_[i]);
  327. }
  328. return *this;
  329. }
  330. } // namespace ROCKSDB_NAMESPACE