autovector.h 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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 "rocksdb/rocksdb_namespace.h"
  13. namespace ROCKSDB_NAMESPACE {
  14. #ifdef ROCKSDB_LITE
  15. template <class T, size_t kSize = 8>
  16. class autovector : public std::vector<T> {
  17. using std::vector<T>::vector;
  18. };
  19. #else
  20. // A vector that leverages pre-allocated stack-based array to achieve better
  21. // performance for array with small amount of items.
  22. //
  23. // The interface resembles that of vector, but with less features since we aim
  24. // to solve the problem that we have in hand, rather than implementing a
  25. // full-fledged generic container.
  26. //
  27. // Currently we don't support:
  28. // * reserve()/shrink_to_fit()
  29. // If used correctly, in most cases, people should not touch the
  30. // underlying vector at all.
  31. // * random insert()/erase(), please only use push_back()/pop_back().
  32. // * No move/swap operations. Each autovector instance has a
  33. // stack-allocated array and if we want support move/swap operations, we
  34. // need to copy the arrays other than just swapping the pointers. In this
  35. // case we'll just explicitly forbid these operations since they may
  36. // lead users to make false assumption by thinking they are inexpensive
  37. // operations.
  38. //
  39. // Naming style of public methods almost follows that of the STL's.
  40. template <class T, size_t kSize = 8>
  41. class autovector {
  42. public:
  43. // General STL-style container member types.
  44. typedef T value_type;
  45. typedef typename std::vector<T>::difference_type difference_type;
  46. typedef typename std::vector<T>::size_type size_type;
  47. typedef value_type& reference;
  48. typedef const value_type& const_reference;
  49. typedef value_type* pointer;
  50. typedef const value_type* const_pointer;
  51. // This class is the base for regular/const iterator
  52. template <class TAutoVector, class TValueType>
  53. class iterator_impl {
  54. public:
  55. // -- iterator traits
  56. typedef iterator_impl<TAutoVector, TValueType> self_type;
  57. typedef TValueType value_type;
  58. typedef TValueType& reference;
  59. typedef TValueType* pointer;
  60. typedef typename TAutoVector::difference_type difference_type;
  61. typedef std::random_access_iterator_tag iterator_category;
  62. iterator_impl(TAutoVector* vect, size_t index)
  63. : vect_(vect), index_(index) {};
  64. iterator_impl(const iterator_impl&) = default;
  65. ~iterator_impl() {}
  66. iterator_impl& operator=(const iterator_impl&) = default;
  67. // -- Advancement
  68. // ++iterator
  69. self_type& operator++() {
  70. ++index_;
  71. return *this;
  72. }
  73. // iterator++
  74. self_type operator++(int) {
  75. auto old = *this;
  76. ++index_;
  77. return old;
  78. }
  79. // --iterator
  80. self_type& operator--() {
  81. --index_;
  82. return *this;
  83. }
  84. // iterator--
  85. self_type operator--(int) {
  86. auto old = *this;
  87. --index_;
  88. return old;
  89. }
  90. self_type operator-(difference_type len) const {
  91. return self_type(vect_, index_ - len);
  92. }
  93. difference_type operator-(const self_type& other) const {
  94. assert(vect_ == other.vect_);
  95. return index_ - other.index_;
  96. }
  97. self_type operator+(difference_type len) const {
  98. return self_type(vect_, index_ + len);
  99. }
  100. self_type& operator+=(difference_type len) {
  101. index_ += len;
  102. return *this;
  103. }
  104. self_type& operator-=(difference_type len) {
  105. index_ -= len;
  106. return *this;
  107. }
  108. // -- Reference
  109. reference operator*() const {
  110. assert(vect_->size() >= index_);
  111. return (*vect_)[index_];
  112. }
  113. pointer operator->() const {
  114. assert(vect_->size() >= index_);
  115. return &(*vect_)[index_];
  116. }
  117. reference operator[](difference_type len) const {
  118. return *(*this + len);
  119. }
  120. // -- Logical Operators
  121. bool operator==(const self_type& other) const {
  122. assert(vect_ == other.vect_);
  123. return index_ == other.index_;
  124. }
  125. bool operator!=(const self_type& other) const { return !(*this == other); }
  126. bool operator>(const self_type& other) const {
  127. assert(vect_ == other.vect_);
  128. return index_ > other.index_;
  129. }
  130. bool operator<(const self_type& other) const {
  131. assert(vect_ == other.vect_);
  132. return index_ < other.index_;
  133. }
  134. bool operator>=(const self_type& other) const {
  135. assert(vect_ == other.vect_);
  136. return index_ >= other.index_;
  137. }
  138. bool operator<=(const self_type& other) const {
  139. assert(vect_ == other.vect_);
  140. return index_ <= other.index_;
  141. }
  142. private:
  143. TAutoVector* vect_ = nullptr;
  144. size_t index_ = 0;
  145. };
  146. typedef iterator_impl<autovector, value_type> iterator;
  147. typedef iterator_impl<const autovector, const value_type> const_iterator;
  148. typedef std::reverse_iterator<iterator> reverse_iterator;
  149. typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  150. autovector() : values_(reinterpret_cast<pointer>(buf_)) {}
  151. autovector(std::initializer_list<T> init_list)
  152. : values_(reinterpret_cast<pointer>(buf_)) {
  153. for (const T& item : init_list) {
  154. push_back(item);
  155. }
  156. }
  157. ~autovector() { clear(); }
  158. // -- Immutable operations
  159. // Indicate if all data resides in in-stack data structure.
  160. bool only_in_stack() const {
  161. // If no element was inserted at all, the vector's capacity will be `0`.
  162. return vect_.capacity() == 0;
  163. }
  164. size_type size() const { return num_stack_items_ + vect_.size(); }
  165. // resize does not guarantee anything about the contents of the newly
  166. // available elements
  167. void resize(size_type n) {
  168. if (n > kSize) {
  169. vect_.resize(n - kSize);
  170. while (num_stack_items_ < kSize) {
  171. new ((void*)(&values_[num_stack_items_++])) value_type();
  172. }
  173. num_stack_items_ = kSize;
  174. } else {
  175. vect_.clear();
  176. while (num_stack_items_ < n) {
  177. new ((void*)(&values_[num_stack_items_++])) value_type();
  178. }
  179. while (num_stack_items_ > n) {
  180. values_[--num_stack_items_].~value_type();
  181. }
  182. }
  183. }
  184. bool empty() const { return size() == 0; }
  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. void emplace_back(Args&&... args) {
  242. if (num_stack_items_ < kSize) {
  243. new ((void*)(&values_[num_stack_items_++]))
  244. value_type(std::forward<Args>(args)...);
  245. } else {
  246. vect_.emplace_back(std::forward<Args>(args)...);
  247. }
  248. }
  249. void pop_back() {
  250. assert(!empty());
  251. if (!vect_.empty()) {
  252. vect_.pop_back();
  253. } else {
  254. values_[--num_stack_items_].~value_type();
  255. }
  256. }
  257. void clear() {
  258. while (num_stack_items_ > 0) {
  259. values_[--num_stack_items_].~value_type();
  260. }
  261. vect_.clear();
  262. }
  263. // -- Copy and Assignment
  264. autovector& assign(const autovector& other);
  265. autovector(const autovector& other) { assign(other); }
  266. autovector& operator=(const autovector& other) { return assign(other); }
  267. // -- Iterator Operations
  268. iterator begin() { return iterator(this, 0); }
  269. const_iterator begin() const { return const_iterator(this, 0); }
  270. iterator end() { return iterator(this, this->size()); }
  271. const_iterator end() const { return const_iterator(this, this->size()); }
  272. reverse_iterator rbegin() { return reverse_iterator(end()); }
  273. const_reverse_iterator rbegin() const {
  274. return const_reverse_iterator(end());
  275. }
  276. reverse_iterator rend() { return reverse_iterator(begin()); }
  277. const_reverse_iterator rend() const {
  278. return const_reverse_iterator(begin());
  279. }
  280. private:
  281. size_type num_stack_items_ = 0; // current number of items
  282. alignas(alignof(
  283. value_type)) char buf_[kSize *
  284. sizeof(value_type)]; // the first `kSize` items
  285. pointer values_;
  286. // used only if there are more than `kSize` items.
  287. std::vector<T> vect_;
  288. };
  289. template <class T, size_t kSize>
  290. autovector<T, kSize>& autovector<T, kSize>::assign(const autovector& other) {
  291. values_ = reinterpret_cast<pointer>(buf_);
  292. // copy the internal vector
  293. vect_.assign(other.vect_.begin(), other.vect_.end());
  294. // copy array
  295. num_stack_items_ = other.num_stack_items_;
  296. std::copy(other.values_, other.values_ + num_stack_items_, values_);
  297. return *this;
  298. }
  299. #endif // ROCKSDB_LITE
  300. } // namespace ROCKSDB_NAMESPACE