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).
9 #include <initializer_list>
14 #include "port/lang.h"
15 #include "rocksdb/rocksdb_namespace.h"
17 namespace ROCKSDB_NAMESPACE
{
20 template <class T
, size_t kSize
= 8>
21 class autovector
: public std::vector
<T
> {
22 using std::vector
<T
>::vector
;
26 // Make sure the initial vector has space for kSize elements
27 std::vector
<T
>::reserve(kSize
);
31 // A vector that leverages pre-allocated stack-based array to achieve better
32 // performance for array with small amount of items.
34 // The interface resembles that of vector, but with less features since we aim
35 // to solve the problem that we have in hand, rather than implementing a
36 // full-fledged generic container.
38 // Currently we don't support:
40 // If used correctly, in most cases, people should not touch the
41 // underlying vector at all.
42 // * random insert()/erase(), please only use push_back()/pop_back().
43 // * No move/swap operations. Each autovector instance has a
44 // stack-allocated array and if we want support move/swap operations, we
45 // need to copy the arrays other than just swapping the pointers. In this
46 // case we'll just explicitly forbid these operations since they may
47 // lead users to make false assumption by thinking they are inexpensive
50 // Naming style of public methods almost follows that of the STL's.
51 template <class T
, size_t kSize
= 8>
54 // General STL-style container member types.
56 using difference_type
= typename
std::vector
<T
>::difference_type
;
57 using size_type
= typename
std::vector
<T
>::size_type
;
58 using reference
= value_type
&;
59 using const_reference
= const value_type
&;
60 using pointer
= value_type
*;
61 using const_pointer
= const value_type
*;
63 // This class is the base for regular/const iterator
64 template <class TAutoVector
, class TValueType
>
68 using self_type
= iterator_impl
<TAutoVector
, TValueType
>;
69 using value_type
= TValueType
;
70 using reference
= TValueType
&;
71 using pointer
= TValueType
*;
72 using difference_type
= typename
TAutoVector::difference_type
;
73 using iterator_category
= std::random_access_iterator_tag
;
75 iterator_impl(TAutoVector
* vect
, size_t index
)
76 : vect_(vect
), index_(index
){};
77 iterator_impl(const iterator_impl
&) = default;
79 iterator_impl
& operator=(const iterator_impl
&) = default;
83 self_type
& operator++() {
89 self_type
operator++(int) {
96 self_type
& operator--() {
102 self_type
operator--(int) {
108 self_type
operator-(difference_type len
) const {
109 return self_type(vect_
, index_
- len
);
112 difference_type
operator-(const self_type
& other
) const {
113 assert(vect_
== other
.vect_
);
114 return index_
- other
.index_
;
117 self_type
operator+(difference_type len
) const {
118 return self_type(vect_
, index_
+ len
);
121 self_type
& operator+=(difference_type len
) {
126 self_type
& operator-=(difference_type len
) {
132 reference
operator*() const {
133 assert(vect_
->size() >= index_
);
134 return (*vect_
)[index_
];
137 pointer
operator->() const {
138 assert(vect_
->size() >= index_
);
139 return &(*vect_
)[index_
];
142 reference
operator[](difference_type len
) const { return *(*this + len
); }
144 // -- Logical Operators
145 bool operator==(const self_type
& other
) const {
146 assert(vect_
== other
.vect_
);
147 return index_
== other
.index_
;
150 bool operator!=(const self_type
& other
) const { return !(*this == other
); }
152 bool operator>(const self_type
& other
) const {
153 assert(vect_
== other
.vect_
);
154 return index_
> other
.index_
;
157 bool operator<(const self_type
& other
) const {
158 assert(vect_
== other
.vect_
);
159 return index_
< other
.index_
;
162 bool operator>=(const self_type
& other
) const {
163 assert(vect_
== other
.vect_
);
164 return index_
>= other
.index_
;
167 bool operator<=(const self_type
& other
) const {
168 assert(vect_
== other
.vect_
);
169 return index_
<= other
.index_
;
173 TAutoVector
* vect_
= nullptr;
177 using iterator
= iterator_impl
<autovector
, value_type
>;
178 using const_iterator
= iterator_impl
<const autovector
, const value_type
>;
179 using reverse_iterator
= std::reverse_iterator
<iterator
>;
180 using const_reverse_iterator
= std::reverse_iterator
<const_iterator
>;
182 autovector() : values_(reinterpret_cast<pointer
>(buf_
)) {}
184 autovector(std::initializer_list
<T
> init_list
)
185 : values_(reinterpret_cast<pointer
>(buf_
)) {
186 for (const T
& item
: init_list
) {
191 ~autovector() { clear(); }
193 // -- Immutable operations
194 // Indicate if all data resides in in-stack data structure.
195 bool only_in_stack() const {
196 // If no element was inserted at all, the vector's capacity will be `0`.
197 return vect_
.capacity() == 0;
200 size_type
size() const { return num_stack_items_
+ vect_
.size(); }
202 // resize does not guarantee anything about the contents of the newly
203 // available elements
204 void resize(size_type n
) {
206 vect_
.resize(n
- kSize
);
207 while (num_stack_items_
< kSize
) {
208 new ((void*)(&values_
[num_stack_items_
++])) value_type();
210 num_stack_items_
= kSize
;
213 while (num_stack_items_
< n
) {
214 new ((void*)(&values_
[num_stack_items_
++])) value_type();
216 while (num_stack_items_
> n
) {
217 values_
[--num_stack_items_
].~value_type();
222 bool empty() const { return size() == 0; }
224 size_type
capacity() const { return kSize
+ vect_
.capacity(); }
226 void reserve(size_t cap
) {
228 vect_
.reserve(cap
- kSize
);
231 assert(cap
<= capacity());
234 const_reference
operator[](size_type n
) const {
239 return vect_
[n
- kSize
];
242 reference
operator[](size_type n
) {
247 return vect_
[n
- kSize
];
250 const_reference
at(size_type n
) const {
255 reference
at(size_type n
) {
265 const_reference
front() const {
275 const_reference
back() const {
280 // -- Mutable Operations
281 void push_back(T
&& item
) {
282 if (num_stack_items_
< kSize
) {
283 new ((void*)(&values_
[num_stack_items_
])) value_type();
284 values_
[num_stack_items_
++] = std::move(item
);
286 vect_
.push_back(item
);
290 void push_back(const T
& item
) {
291 if (num_stack_items_
< kSize
) {
292 new ((void*)(&values_
[num_stack_items_
])) value_type();
293 values_
[num_stack_items_
++] = item
;
295 vect_
.push_back(item
);
299 template <class... Args
>
300 #if _LIBCPP_STD_VER > 14
301 reference
emplace_back(Args
&&... args
) {
302 if (num_stack_items_
< kSize
) {
303 return *(new ((void*)(&values_
[num_stack_items_
++]))
304 value_type(std::forward
<Args
>(args
)...));
306 return vect_
.emplace_back(std::forward
<Args
>(args
)...);
310 void emplace_back(Args
&&... args
) {
311 if (num_stack_items_
< kSize
) {
312 new ((void*)(&values_
[num_stack_items_
++]))
313 value_type(std::forward
<Args
>(args
)...);
315 vect_
.emplace_back(std::forward
<Args
>(args
)...);
322 if (!vect_
.empty()) {
325 values_
[--num_stack_items_
].~value_type();
330 while (num_stack_items_
> 0) {
331 values_
[--num_stack_items_
].~value_type();
336 // -- Copy and Assignment
337 autovector
& assign(const autovector
& other
);
339 autovector(const autovector
& other
) { assign(other
); }
341 autovector
& operator=(const autovector
& other
) { return assign(other
); }
343 autovector(autovector
&& other
) noexcept
{ *this = std::move(other
); }
344 autovector
& operator=(autovector
&& other
);
346 // -- Iterator Operations
347 iterator
begin() { return iterator(this, 0); }
349 const_iterator
begin() const { return const_iterator(this, 0); }
351 iterator
end() { return iterator(this, this->size()); }
353 const_iterator
end() const { return const_iterator(this, this->size()); }
355 reverse_iterator
rbegin() { return reverse_iterator(end()); }
357 const_reverse_iterator
rbegin() const {
358 return const_reverse_iterator(end());
361 reverse_iterator
rend() { return reverse_iterator(begin()); }
363 const_reverse_iterator
rend() const {
364 return const_reverse_iterator(begin());
368 size_type num_stack_items_
= 0; // current number of items
370 value_type
)) char buf_
[kSize
*
371 sizeof(value_type
)]; // the first `kSize` items
373 // used only if there are more than `kSize` items.
374 std::vector
<T
> vect_
;
377 template <class T
, size_t kSize
>
378 autovector
<T
, kSize
>& autovector
<T
, kSize
>::assign(
379 const autovector
<T
, kSize
>& other
) {
380 values_
= reinterpret_cast<pointer
>(buf_
);
381 // copy the internal vector
382 vect_
.assign(other
.vect_
.begin(), other
.vect_
.end());
385 num_stack_items_
= other
.num_stack_items_
;
386 std::copy(other
.values_
, other
.values_
+ num_stack_items_
, values_
);
391 template <class T
, size_t kSize
>
392 autovector
<T
, kSize
>& autovector
<T
, kSize
>::operator=(
393 autovector
<T
, kSize
>&& other
) {
394 values_
= reinterpret_cast<pointer
>(buf_
);
395 vect_
= std::move(other
.vect_
);
396 size_t n
= other
.num_stack_items_
;
397 num_stack_items_
= n
;
398 other
.num_stack_items_
= 0;
399 for (size_t i
= 0; i
< n
; ++i
) {
400 values_
[i
] = std::move(other
.values_
[i
]);
405 #endif // ROCKSDB_LITE
406 } // namespace ROCKSDB_NAMESPACE