1 #ifndef _SMALL_VECTOR_H_
2 #define _SMALL_VECTOR_H_
9 #include "ndb_type_traits.h"
12 * References are not guaranteed to be stable across mutation
14 * XXX(stephentu): allow custom allocator
16 template <typename T, size_t SmallSize = SMALL_SIZE_VEC>
18 typedef std::vector<T> large_vector_type;
20 static const bool is_trivially_destructible =
21 private_::is_trivially_destructible<T>::value;
23 // std::is_trivially_copyable not supported in g++-4.7
24 static const bool is_trivially_copyable = std::is_scalar<T>::value;
29 typedef T & reference;
30 typedef const T & const_reference;
31 typedef size_t size_type;
33 small_vector() : n(0), large_elems(0) {}
39 small_vector(const small_vector &that)
40 : n(0), large_elems(0)
45 // not efficient, don't use in performance critical parts
46 small_vector(std::initializer_list<T> l)
47 : n(0), large_elems(nullptr)
49 if (l.size() > SmallSize) {
50 large_elems = new large_vector_type(l);
58 operator=(const small_vector &that)
67 if (unlikely(large_elems))
68 return large_elems->size();
81 if (unlikely(large_elems))
82 return large_elems->front();
84 INVARIANT(n <= SmallSize);
88 inline const_reference
91 return const_cast<small_vector *>(this)->front();
97 if (unlikely(large_elems))
98 return large_elems->back();
100 INVARIANT(n <= SmallSize);
104 inline const_reference
107 return const_cast<small_vector *>(this)->back();
113 if (unlikely(large_elems)) {
114 large_elems->pop_back();
118 if (!is_trivially_destructible)
124 push_back(const T &obj)
132 emplace_back(std::move(obj));
135 // C++11 goodness- a strange syntax this is
137 template <class... Args>
139 emplace_back(Args &&... args)
141 if (unlikely(large_elems)) {
143 large_elems->emplace_back(std::forward<Args>(args)...);
146 if (unlikely(n == SmallSize)) {
147 large_elems = new large_vector_type(ptr(), ptr() + n);
148 large_elems->emplace_back(std::forward<Args>(args)...);
152 INVARIANT(n < SmallSize);
153 new (&(ptr()[n++])) T(std::forward<Args>(args)...);
159 if (unlikely(large_elems))
160 return large_elems->operator[](i);
164 inline const_reference
165 operator[](int i) const
167 return const_cast<small_vector *>(this)->operator[](i);
173 if (unlikely(large_elems)) {
175 large_elems->clear();
178 if (!is_trivially_destructible)
179 for (size_t i = 0; i < n; i++)
187 if (unlikely(large_elems))
188 large_elems->reserve(n);
192 inline bool is_small_type() const { return !large_elems; }
194 template <typename Compare = std::less<T>>
196 sort(Compare c = Compare())
198 if (unlikely(large_elems))
199 std::sort(large_elems->begin(), large_elems->end(), c);
201 std::sort(small_begin(), small_end(), c);
209 if (unlikely(large_elems)) {
215 if (!is_trivially_destructible)
216 for (size_t i = 0; i < n; i++)
221 template <typename ObjType>
222 class small_iterator_ : public std::iterator<std::bidirectional_iterator_tag, ObjType> {
223 friend class small_vector;
225 inline small_iterator_() : p(0) {}
227 template <typename O>
228 inline small_iterator_(const small_iterator_<O> &other)
245 operator==(const small_iterator_ &o) const
251 operator!=(const small_iterator_ &o) const
253 return !operator==(o);
257 operator<(const small_iterator_ &o) const
263 operator>=(const small_iterator_ &o) const
265 return !operator<(o);
269 operator>(const small_iterator_ &o) const
275 operator<=(const small_iterator_ &o) const
277 return !operator>(o);
280 inline small_iterator_ &
287 inline small_iterator_ &
294 inline small_iterator_
295 operator+(int n) const
297 small_iterator_ cpy = *this;
301 inline small_iterator_
302 operator-(int n) const
304 small_iterator_ cpy = *this;
309 operator-(const small_iterator_ &o) const
314 inline small_iterator_ &
321 inline small_iterator_
324 small_iterator_ cur = *this;
329 inline small_iterator_ &
336 inline small_iterator_
339 small_iterator_ cur = *this;
345 inline small_iterator_(ObjType *p) : p(p) {}
351 template <typename ObjType, typename SmallTypeIter, typename LargeTypeIter>
352 class iterator_ : public std::iterator<std::bidirectional_iterator_tag, ObjType> {
353 friend class small_vector;
355 inline iterator_() : large(false) {}
357 template <typename O, typename S, typename L>
358 inline iterator_(const iterator_<O, S, L> &other)
359 : large(other.large),
360 small_it(other.small_it),
361 large_it(other.large_it)
381 operator==(const iterator_ &o) const
384 return large_it == o.large_it;
385 return small_it == o.small_it;
389 operator!=(const iterator_ &o) const
391 return !operator==(o);
395 operator<(const iterator_ &o) const
398 return large_it < o.large_it;
399 return small_it < o.small_it;
403 operator>=(const iterator_ &o) const
405 return !operator<(o);
409 operator>(const iterator_ &o) const
412 return large_it > o.large_it;
413 return small_it > o.small_it;
417 operator<=(const iterator_ &o) const
419 return !operator>(o);
443 operator+(int n) const
445 iterator_ cpy = *this;
450 operator-(int n) const
452 iterator_ cpy = *this;
457 operator-(const iterator_ &o) const
460 return large_it - o.large_it;
462 return small_it - o.small_it;
478 iterator_ cur = *this;
496 iterator_ cur = *this;
502 iterator_(SmallTypeIter small_it)
503 : large(false), small_it(small_it), large_it() {}
504 iterator_(LargeTypeIter large_it)
505 : large(true), small_it(), large_it(large_it) {}
509 SmallTypeIter small_it;
510 LargeTypeIter large_it;
513 typedef small_iterator_<T> small_iterator;
514 typedef small_iterator_<const T> const_small_iterator;
515 typedef typename large_vector_type::iterator large_iterator;
516 typedef typename large_vector_type::const_iterator const_large_iterator;
518 inline small_iterator
521 INVARIANT(!large_elems);
522 return small_iterator(ptr());
525 inline const_small_iterator
528 INVARIANT(!large_elems);
529 return const_small_iterator(ptr());
532 inline small_iterator
535 INVARIANT(!large_elems);
536 return small_iterator(ptr() + n);
539 inline const_small_iterator
542 INVARIANT(!large_elems);
543 return const_small_iterator(ptr() + n);
548 typedef iterator_<T, small_iterator, large_iterator> iterator;
549 typedef iterator_<const T, const_small_iterator, const_large_iterator> const_iterator;
551 typedef std::reverse_iterator<iterator> reverse_iterator;
552 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
557 if (unlikely(large_elems))
558 return iterator(large_elems->begin());
559 return iterator(small_begin());
562 inline const_iterator
565 if (unlikely(large_elems))
566 return const_iterator(large_elems->begin());
567 return const_iterator(small_begin());
573 if (unlikely(large_elems))
574 return iterator(large_elems->end());
575 return iterator(small_end());
578 inline const_iterator
581 if (unlikely(large_elems))
582 return const_iterator(large_elems->end());
583 return const_iterator(small_end());
586 inline reverse_iterator
589 return reverse_iterator(end());
592 inline const_reverse_iterator
595 return const_reverse_iterator(end());
598 inline reverse_iterator
601 return reverse_iterator(begin());
604 inline const_reverse_iterator
607 return const_reverse_iterator(begin());
612 assignFrom(const small_vector &that)
614 if (unlikely(this == &that))
617 if (unlikely(that.large_elems)) {
618 large_elems = new large_vector_type(*that.large_elems);
620 INVARIANT(that.n <= SmallSize);
621 if (is_trivially_copyable) {
622 NDB_MEMCPY(ptr(), that.ptr(), that.n * sizeof(T));
624 for (size_t i = 0; i < that.n; i++)
625 new (&(ptr()[i])) T(that.ptr()[i]);
631 inline ALWAYS_INLINE T *
634 return reinterpret_cast<T *>(&small_elems_buf[0]);
637 inline ALWAYS_INLINE const T *
640 return reinterpret_cast<const T *>(&small_elems_buf[0]);
644 char small_elems_buf[sizeof(T) * SmallSize];
645 large_vector_type *large_elems;
648 #endif /* _SMALL_VECTOR_H_ */