proxygen
small_vector.h
Go to the documentation of this file.
1 /*
2  * Copyright 2011-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*
18  * For high-level documentation and usage examples see
19  * folly/docs/small_vector.md
20  *
21  * @author Jordan DeLong <delong.j@fb.com>
22  */
23 
24 #pragma once
25 
26 #include <algorithm>
27 #include <cassert>
28 #include <cstdlib>
29 #include <cstring>
30 #include <iterator>
31 #include <stdexcept>
32 #include <type_traits>
33 #include <utility>
34 
35 #include <boost/mpl/count.hpp>
36 #include <boost/mpl/empty.hpp>
37 #include <boost/mpl/eval_if.hpp>
38 #include <boost/mpl/filter_view.hpp>
39 #include <boost/mpl/front.hpp>
40 #include <boost/mpl/identity.hpp>
41 #include <boost/mpl/if.hpp>
42 #include <boost/mpl/placeholders.hpp>
43 #include <boost/mpl/size.hpp>
44 #include <boost/mpl/vector.hpp>
45 #include <boost/operators.hpp>
46 
47 #include <folly/ConstexprMath.h>
48 #include <folly/FormatTraits.h>
49 #include <folly/Likely.h>
50 #include <folly/Portability.h>
51 #include <folly/Traits.h>
52 #include <folly/lang/Assume.h>
53 #include <folly/lang/Exception.h>
54 #include <folly/memory/Malloc.h>
56 
57 #if (FOLLY_X64 || FOLLY_PPC64)
58 #define FOLLY_SV_PACK_ATTR FOLLY_PACK_ATTR
59 #define FOLLY_SV_PACK_PUSH FOLLY_PACK_PUSH
60 #define FOLLY_SV_PACK_POP FOLLY_PACK_POP
61 #else
62 #define FOLLY_SV_PACK_ATTR
63 #define FOLLY_SV_PACK_PUSH
64 #define FOLLY_SV_PACK_POP
65 #endif
66 
67 // Ignore shadowing warnings within this file, so includers can use -Wshadow.
69 FOLLY_GNU_DISABLE_WARNING("-Wshadow")
70 
71 namespace folly {
72 
74 
75 namespace small_vector_policy {
76 
78 
79 /*
80  * A flag which makes us refuse to use the heap at all. If we
81  * overflow the in situ capacity we throw an exception.
82  */
83 struct NoHeap;
84 
86 
87 } // namespace small_vector_policy
88 
90 
91 template <class T, std::size_t M, class A, class B, class C>
93 
95 
96 namespace detail {
97 
98 /*
99  * Move objects in memory to the right into some uninitialized
100  * memory, where the region overlaps. This doesn't just use
101  * std::move_backward because move_backward only works if all the
102  * memory is initialized to type T already.
103  */
104 template <class T>
105 typename std::enable_if<
108 moveObjectsRight(T* first, T* lastConstructed, T* realLast) {
109  if (lastConstructed == realLast) {
110  return;
111  }
112 
113  T* end = first - 1; // Past the end going backwards.
114  T* out = realLast - 1;
115  T* in = lastConstructed - 1;
116  try {
117  for (; in != end && out >= lastConstructed; --in, --out) {
118  new (out) T(std::move(*in));
119  }
120  for (; in != end; --in, --out) {
121  *out = std::move(*in);
122  }
123  for (; out >= lastConstructed; --out) {
124  new (out) T();
125  }
126  } catch (...) {
127  // We want to make sure the same stuff is uninitialized memory
128  // if we exit via an exception (this is to make sure we provide
129  // the basic exception safety guarantee for insert functions).
130  if (out < lastConstructed) {
131  out = lastConstructed - 1;
132  }
133  for (auto it = out + 1; it != realLast; ++it) {
134  it->~T();
135  }
136  throw;
137  }
138 }
139 
140 // Specialization for trivially copyable types. The call to
141 // std::move_backward here will just turn into a memmove. (TODO:
142 // change to std::is_trivially_copyable when that works.)
143 template <class T>
144 typename std::enable_if<
147 moveObjectsRight(T* first, T* lastConstructed, T* realLast) {
148  std::move_backward(first, lastConstructed, realLast);
149 }
150 
151 /*
152  * Populate a region of memory using `op' to construct elements. If
153  * anything throws, undo what we did.
154  */
155 template <class T, class Function>
156 void populateMemForward(T* mem, std::size_t n, Function const& op) {
157  std::size_t idx = 0;
158  try {
159  for (size_t i = 0; i < n; ++i) {
160  op(&mem[idx]);
161  ++idx;
162  }
163  } catch (...) {
164  for (std::size_t i = 0; i < idx; ++i) {
165  mem[i].~T();
166  }
167  throw;
168  }
169 }
170 
171 template <class SizeType, bool ShouldUseHeap>
173  typedef SizeType InternalSizeType;
174 
175  IntegralSizePolicyBase() : size_(0) {}
176 
177  protected:
178  static constexpr std::size_t policyMaxSize() {
179  return SizeType(~kExternMask);
180  }
181 
182  std::size_t doSize() const {
183  return size_ & ~kExternMask;
184  }
185 
186  std::size_t isExtern() const {
187  return kExternMask & size_;
188  }
189 
190  void setExtern(bool b) {
191  if (b) {
192  size_ |= kExternMask;
193  } else {
194  size_ &= ~kExternMask;
195  }
196  }
197 
198  void setSize(std::size_t sz) {
199  assert(sz <= policyMaxSize());
200  size_ = (kExternMask & size_) | SizeType(sz);
201  }
202 
204  std::swap(size_, o.size_);
205  }
206 
207  protected:
208  static bool constexpr kShouldUseHeap = ShouldUseHeap;
209 
210  private:
211  static SizeType constexpr kExternMask =
212  kShouldUseHeap ? SizeType(1) << (sizeof(SizeType) * 8 - 1) : 0;
213 
214  SizeType size_;
215 };
216 
217 template <class SizeType, bool ShouldUseHeap>
219 
220 template <class SizeType>
221 struct IntegralSizePolicy<SizeType, true>
222  : public IntegralSizePolicyBase<SizeType, true> {
223  public:
224  /*
225  * Move a range to a range of uninitialized memory. Assumes the
226  * ranges don't overlap.
227  */
228  template <class T>
230  moveToUninitialized(T* first, T* last, T* out) {
231  std::size_t idx = 0;
232  try {
233  for (; first != last; ++first, ++idx) {
234  new (&out[idx]) T(std::move(*first));
235  }
236  } catch (...) {
237  // Even for callers trying to give the strong guarantee
238  // (e.g. push_back) it's ok to assume here that we don't have to
239  // move things back and that it was a copy constructor that
240  // threw: if someone throws from a move constructor the effects
241  // are unspecified.
242  for (std::size_t i = 0; i < idx; ++i) {
243  out[i].~T();
244  }
245  throw;
246  }
247  }
248 
249  // Specialization for trivially copyable types.
250  template <class T>
252  moveToUninitialized(T* first, T* last, T* out) {
253  std::memmove(out, first, (last - first) * sizeof *first);
254  }
255 
256  /*
257  * Move a range to a range of uninitialized memory. Assumes the
258  * ranges don't overlap. Inserts an element at out + pos using
259  * emplaceFunc(). out will contain (end - begin) + 1 elements on success and
260  * none on failure. If emplaceFunc() throws [begin, end) is unmodified.
261  */
262  template <class T, class EmplaceFunc>
264  T* begin,
265  T* end,
266  T* out,
267  SizeType pos,
268  EmplaceFunc&& emplaceFunc) {
269  // Must be called first so that if it throws [begin, end) is unmodified.
270  // We have to support the strong exception guarantee for emplace_back().
271  emplaceFunc(out + pos);
272  // move old elements to the left of the new one
273  try {
274  this->moveToUninitialized(begin, begin + pos, out);
275  } catch (...) {
276  out[pos].~T();
277  throw;
278  }
279  // move old elements to the right of the new one
280  try {
281  if (begin + pos < end) {
282  this->moveToUninitialized(begin + pos, end, out + pos + 1);
283  }
284  } catch (...) {
285  for (SizeType i = 0; i <= pos; ++i) {
286  out[i].~T();
287  }
288  throw;
289  }
290  }
291 };
292 
293 template <class SizeType>
294 struct IntegralSizePolicy<SizeType, false>
295  : public IntegralSizePolicyBase<SizeType, false> {
296  public:
297  template <class T>
298  void moveToUninitialized(T* /*first*/, T* /*last*/, T* /*out*/) {
300  }
301  template <class T, class EmplaceFunc>
303  T* /* begin */,
304  T* /* end */,
305  T* /* out */,
306  SizeType /* pos */,
307  EmplaceFunc&& /* emplaceFunc */) {
309  }
310 };
311 
312 /*
313  * If you're just trying to use this class, ignore everything about
314  * this next small_vector_base class thing.
315  *
316  * The purpose of this junk is to minimize sizeof(small_vector<>)
317  * and allow specifying the template parameters in whatever order is
318  * convenient for the user. There's a few extra steps here to try
319  * to keep the error messages at least semi-reasonable.
320  *
321  * Apologies for all the black magic.
322  */
323 namespace mpl = boost::mpl;
324 template <
325  class Value,
326  std::size_t RequestedMaxInline,
327  class InPolicyA,
328  class InPolicyB,
329  class InPolicyC>
331  typedef mpl::vector<InPolicyA, InPolicyB, InPolicyC> PolicyList;
332 
333  /*
334  * Determine the size type
335  */
336  typedef typename mpl::filter_view<
337  PolicyList,
338  std::is_integral<mpl::placeholders::_1>>::type Integrals;
339  typedef typename mpl::eval_if<
340  mpl::empty<Integrals>,
341  mpl::identity<std::size_t>,
342  mpl::front<Integrals>>::type SizeType;
343 
344  static_assert(
346  "Size type should be an unsigned integral type");
347  static_assert(
349  "Multiple size types specified in small_vector<>");
350 
351  /*
352  * Determine whether we should allow spilling to the heap or not.
353  */
355  HasNoHeap;
356 
357  static_assert(
358  HasNoHeap::value == 0 || HasNoHeap::value == 1,
359  "Multiple copies of small_vector_policy::NoHeap "
360  "supplied; this is probably a mistake");
361 
362  /*
363  * Make the real policy base classes.
364  */
366 
367  /*
368  * Now inherit from them all. This is done in such a convoluted
369  * way to make sure we get the empty base optimizaton on all these
370  * types to keep sizeof(small_vector<>) minimal.
371  */
372  typedef boost::totally_ordered1<
374  ActualSizePolicy>
376 };
377 
378 template <class T>
380  return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(p) | 1);
381 }
382 template <class T>
383 bool pointerFlagGet(T* p) {
384  return reinterpret_cast<uintptr_t>(p) & 1;
385 }
386 template <class T>
388  return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(p) & ~uintptr_t(1));
389 }
390 inline void* shiftPointer(void* p, size_t sizeBytes) {
391  return static_cast<char*>(p) + sizeBytes;
392 }
393 } // namespace detail
394 
397 template <
398  class Value,
399  std::size_t RequestedMaxInline = 1,
400  class PolicyA = void,
401  class PolicyB = void,
402  class PolicyC = void>
404  Value,
405  RequestedMaxInline,
406  PolicyA,
407  PolicyB,
408  PolicyC>::type {
409  typedef typename detail::
412  typedef typename BaseType::InternalSizeType InternalSizeType;
413 
414  /*
415  * Figure out the max number of elements we should inline. (If
416  * the user asks for less inlined elements than we can fit unioned
417  * into our value_type*, we will inline more than they asked.)
418  */
419  static constexpr std::size_t MaxInline{
420  constexpr_max(sizeof(Value*) / sizeof(Value), RequestedMaxInline)};
421 
422  public:
423  typedef std::size_t size_type;
424  typedef Value value_type;
425  typedef value_type& reference;
426  typedef value_type const& const_reference;
427  typedef value_type* iterator;
428  typedef value_type* pointer;
429  typedef value_type const* const_iterator;
430  typedef value_type const* const_pointer;
431  typedef std::ptrdiff_t difference_type;
432 
433  typedef std::reverse_iterator<iterator> reverse_iterator;
434  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
435 
436  small_vector() = default;
437  // Allocator is unused here. It is taken in for compatibility with std::vector
438  // interface, but it will be ignored.
439  small_vector(const std::allocator<Value>&) {}
440 
442  auto n = o.size();
443  makeSize(n);
444  try {
445  std::uninitialized_copy(o.begin(), o.end(), begin());
446  } catch (...) {
447  if (this->isExtern()) {
448  u.freeHeap();
449  }
450  throw;
451  }
452  this->setSize(n);
453  }
454 
456  std::is_nothrow_move_constructible<Value>::value) {
457  if (o.isExtern()) {
458  swap(o);
459  } else {
460  std::uninitialized_copy(
461  std::make_move_iterator(o.begin()),
462  std::make_move_iterator(o.end()),
463  begin());
464  this->setSize(o.size());
465  }
466  }
467 
468  small_vector(std::initializer_list<value_type> il) {
469  constructImpl(il.begin(), il.end(), std::false_type());
470  }
471 
472  explicit small_vector(size_type n) {
473  doConstruct(n, [&](void* p) { new (p) value_type(); });
474  }
475 
476  small_vector(size_type n, value_type const& t) {
477  doConstruct(n, [&](void* p) { new (p) value_type(t); });
478  }
479 
480  template <class Arg>
481  explicit small_vector(Arg arg1, Arg arg2) {
482  // Forward using std::is_arithmetic to get to the proper
483  // implementation; this disambiguates between the iterators and
484  // (size_t, value_type) meaning for this constructor.
485  constructImpl(arg1, arg2, std::is_arithmetic<Arg>());
486  }
487 
489  for (auto& t : *this) {
490  (&t)->~value_type();
491  }
492  if (this->isExtern()) {
493  u.freeHeap();
494  }
495  }
496 
498  if (FOLLY_LIKELY(this != &o)) {
499  assign(o.begin(), o.end());
500  }
501  return *this;
502  }
503 
505  // TODO: optimization:
506  // if both are internal, use move assignment where possible
507  if (FOLLY_LIKELY(this != &o)) {
508  clear();
509  swap(o);
510  }
511  return *this;
512  }
513 
514  bool operator==(small_vector const& o) const {
515  return size() == o.size() && std::equal(begin(), end(), o.begin());
516  }
517 
518  bool operator<(small_vector const& o) const {
519  return std::lexicographical_compare(begin(), end(), o.begin(), o.end());
520  }
521 
522  static constexpr size_type max_size() {
523  return !BaseType::kShouldUseHeap ? static_cast<size_type>(MaxInline)
524  : BaseType::policyMaxSize();
525  }
526 
527  size_type size() const {
528  return this->doSize();
529  }
530  bool empty() const {
531  return !size();
532  }
533 
534  iterator begin() {
535  return data();
536  }
537  iterator end() {
538  return data() + size();
539  }
540  const_iterator begin() const {
541  return data();
542  }
543  const_iterator end() const {
544  return data() + size();
545  }
546  const_iterator cbegin() const {
547  return begin();
548  }
549  const_iterator cend() const {
550  return end();
551  }
552 
553  reverse_iterator rbegin() {
554  return reverse_iterator(end());
555  }
556  reverse_iterator rend() {
557  return reverse_iterator(begin());
558  }
559 
560  const_reverse_iterator rbegin() const {
561  return const_reverse_iterator(end());
562  }
563 
564  const_reverse_iterator rend() const {
565  return const_reverse_iterator(begin());
566  }
567 
568  const_reverse_iterator crbegin() const {
569  return rbegin();
570  }
571  const_reverse_iterator crend() const {
572  return rend();
573  }
574 
575  /*
576  * Usually one of the simplest functions in a Container-like class
577  * but a bit more complex here. We have to handle all combinations
578  * of in-place vs. heap between this and o.
579  *
580  * Basic guarantee only. Provides the nothrow guarantee iff our
581  * value_type has a nothrow move or copy constructor.
582  */
583  void swap(small_vector& o) {
584  using std::swap; // Allow ADL on swap for our value_type.
585 
586  if (this->isExtern() && o.isExtern()) {
587  this->swapSizePolicy(o);
588 
589  auto thisCapacity = this->capacity();
590  auto oCapacity = o.capacity();
591 
592  auto* tmp = u.pdata_.heap_;
593  u.pdata_.heap_ = o.u.pdata_.heap_;
594  o.u.pdata_.heap_ = tmp;
595 
596  this->setCapacity(oCapacity);
597  o.setCapacity(thisCapacity);
598 
599  return;
600  }
601 
602  if (!this->isExtern() && !o.isExtern()) {
603  auto& oldSmall = size() < o.size() ? *this : o;
604  auto& oldLarge = size() < o.size() ? o : *this;
605 
606  for (size_type i = 0; i < oldSmall.size(); ++i) {
607  swap(oldSmall[i], oldLarge[i]);
608  }
609 
610  size_type i = oldSmall.size();
611  const size_type ci = i;
612  try {
613  for (; i < oldLarge.size(); ++i) {
614  auto addr = oldSmall.begin() + i;
615  new (addr) value_type(std::move(oldLarge[i]));
616  oldLarge[i].~value_type();
617  }
618  } catch (...) {
619  oldSmall.setSize(i);
620  for (; i < oldLarge.size(); ++i) {
621  oldLarge[i].~value_type();
622  }
623  oldLarge.setSize(ci);
624  throw;
625  }
626  oldSmall.setSize(i);
627  oldLarge.setSize(ci);
628  return;
629  }
630 
631  // isExtern != o.isExtern()
632  auto& oldExtern = o.isExtern() ? o : *this;
633  auto& oldIntern = o.isExtern() ? *this : o;
634 
635  auto oldExternCapacity = oldExtern.capacity();
636  auto oldExternHeap = oldExtern.u.pdata_.heap_;
637 
638  auto buff = oldExtern.u.buffer();
639  size_type i = 0;
640  try {
641  for (; i < oldIntern.size(); ++i) {
642  new (&buff[i]) value_type(std::move(oldIntern[i]));
643  oldIntern[i].~value_type();
644  }
645  } catch (...) {
646  for (size_type kill = 0; kill < i; ++kill) {
647  buff[kill].~value_type();
648  }
649  for (; i < oldIntern.size(); ++i) {
650  oldIntern[i].~value_type();
651  }
652  oldIntern.setSize(0);
653  oldExtern.u.pdata_.heap_ = oldExternHeap;
654  oldExtern.setCapacity(oldExternCapacity);
655  throw;
656  }
657  oldIntern.u.pdata_.heap_ = oldExternHeap;
658  this->swapSizePolicy(o);
659  oldIntern.setCapacity(oldExternCapacity);
660  }
661 
662  void resize(size_type sz) {
663  if (sz < size()) {
664  erase(begin() + sz, end());
665  return;
666  }
667  makeSize(sz);
669  begin() + size(), sz - size(), [&](void* p) { new (p) value_type(); });
670  this->setSize(sz);
671  }
672 
673  void resize(size_type sz, value_type const& v) {
674  if (sz < size()) {
675  erase(begin() + sz, end());
676  return;
677  }
678  makeSize(sz);
680  begin() + size(), sz - size(), [&](void* p) { new (p) value_type(v); });
681  this->setSize(sz);
682  }
683 
684  value_type* data() noexcept {
685  return this->isExtern() ? u.heap() : u.buffer();
686  }
687 
688  value_type const* data() const noexcept {
689  return this->isExtern() ? u.heap() : u.buffer();
690  }
691 
692  template <class... Args>
693  iterator emplace(const_iterator p, Args&&... args) {
694  if (p == cend()) {
695  emplace_back(std::forward<Args>(args)...);
696  return end() - 1;
697  }
698 
699  /*
700  * We implement emplace at places other than at the back with a
701  * temporary for exception safety reasons. It is possible to
702  * avoid having to do this, but it becomes hard to maintain the
703  * basic exception safety guarantee (unless you respond to a copy
704  * constructor throwing by clearing the whole vector).
705  *
706  * The reason for this is that otherwise you have to destruct an
707  * element before constructing this one in its place---if the
708  * constructor throws, you either need a nothrow default
709  * constructor or a nothrow copy/move to get something back in the
710  * "gap", and the vector requirements don't guarantee we have any
711  * of these. Clearing the whole vector is a legal response in
712  * this situation, but it seems like this implementation is easy
713  * enough and probably better.
714  */
715  return insert(p, value_type(std::forward<Args>(args)...));
716  }
717 
718  void reserve(size_type sz) {
719  makeSize(sz);
720  }
721 
722  size_type capacity() const {
723  if (this->isExtern()) {
724  if (u.hasCapacity()) {
725  return u.getCapacity();
726  }
727  return malloc_usable_size(u.pdata_.heap_) / sizeof(value_type);
728  }
729  return MaxInline;
730  }
731 
732  void shrink_to_fit() {
733  if (!this->isExtern()) {
734  return;
735  }
736 
737  small_vector tmp(begin(), end());
738  tmp.swap(*this);
739  }
740 
741  template <class... Args>
742  void emplace_back(Args&&... args) {
743  if (capacity() == size()) {
744  // Any of args may be references into the vector.
745  // When we are reallocating, we have to be careful to construct the new
746  // element before modifying the data in the old buffer.
747  makeSize(
748  size() + 1,
749  [&](void* p) { new (p) value_type(std::forward<Args>(args)...); },
750  size());
751  } else {
752  new (end()) value_type(std::forward<Args>(args)...);
753  }
754  this->setSize(size() + 1);
755  }
756 
757  void push_back(value_type&& t) {
758  return emplace_back(std::move(t));
759  }
760 
761  void push_back(value_type const& t) {
762  emplace_back(t);
763  }
764 
765  void pop_back() {
766  erase(end() - 1);
767  }
768 
769  iterator insert(const_iterator constp, value_type&& t) {
770  iterator p = unconst(constp);
771 
772  if (p == end()) {
774  return end() - 1;
775  }
776 
777  auto offset = p - begin();
778 
779  if (capacity() == size()) {
780  makeSize(
781  size() + 1,
782  [&t](void* ptr) { new (ptr) value_type(std::move(t)); },
783  offset);
784  this->setSize(this->size() + 1);
785  } else {
787  data() + offset, data() + size(), data() + size() + 1);
788  this->setSize(size() + 1);
789  data()[offset] = std::move(t);
790  }
791  return begin() + offset;
792  }
793 
794  iterator insert(const_iterator p, value_type const& t) {
795  // Make a copy and forward to the rvalue value_type&& overload
796  // above.
797  return insert(p, value_type(t));
798  }
799 
800  iterator insert(const_iterator pos, size_type n, value_type const& val) {
801  auto offset = pos - begin();
802  makeSize(size() + n);
804  data() + offset, data() + size(), data() + size() + n);
805  this->setSize(size() + n);
806  std::generate_n(begin() + offset, n, [&] { return val; });
807  return begin() + offset;
808  }
809 
810  template <class Arg>
811  iterator insert(const_iterator p, Arg arg1, Arg arg2) {
812  // Forward using std::is_arithmetic to get to the proper
813  // implementation; this disambiguates between the iterators and
814  // (size_t, value_type) meaning for this function.
815  return insertImpl(unconst(p), arg1, arg2, std::is_arithmetic<Arg>());
816  }
817 
818  iterator insert(const_iterator p, std::initializer_list<value_type> il) {
819  return insert(p, il.begin(), il.end());
820  }
821 
822  iterator erase(const_iterator q) {
823  std::move(unconst(q) + 1, end(), unconst(q));
824  (data() + size() - 1)->~value_type();
825  this->setSize(size() - 1);
826  return unconst(q);
827  }
828 
829  iterator erase(const_iterator q1, const_iterator q2) {
830  if (q1 == q2) {
831  return unconst(q1);
832  }
833  std::move(unconst(q2), end(), unconst(q1));
834  for (auto it = (end() - std::distance(q1, q2)); it != end(); ++it) {
835  it->~value_type();
836  }
837  this->setSize(size() - (q2 - q1));
838  return unconst(q1);
839  }
840 
841  void clear() {
842  erase(begin(), end());
843  }
844 
845  template <class Arg>
846  void assign(Arg first, Arg last) {
847  clear();
848  insert(end(), first, last);
849  }
850 
851  void assign(std::initializer_list<value_type> il) {
852  assign(il.begin(), il.end());
853  }
854 
855  void assign(size_type n, const value_type& t) {
856  clear();
857  insert(end(), n, t);
858  }
859 
860  reference front() {
861  assert(!empty());
862  return *begin();
863  }
864  reference back() {
865  assert(!empty());
866  return *(end() - 1);
867  }
868  const_reference front() const {
869  assert(!empty());
870  return *begin();
871  }
872  const_reference back() const {
873  assert(!empty());
874  return *(end() - 1);
875  }
876 
877  reference operator[](size_type i) {
878  assert(i < size());
879  return *(begin() + i);
880  }
881 
882  const_reference operator[](size_type i) const {
883  assert(i < size());
884  return *(begin() + i);
885  }
886 
887  reference at(size_type i) {
888  if (i >= size()) {
889  throw_exception<std::out_of_range>("index out of range");
890  }
891  return (*this)[i];
892  }
893 
894  const_reference at(size_type i) const {
895  if (i >= size()) {
896  throw_exception<std::out_of_range>("index out of range");
897  }
898  return (*this)[i];
899  }
900 
901  private:
902  static iterator unconst(const_iterator it) {
903  return const_cast<iterator>(it);
904  }
905 
906  // The std::false_type argument is part of disambiguating the
907  // iterator insert functions from integral types (see insert().)
908  template <class It>
909  iterator insertImpl(iterator pos, It first, It last, std::false_type) {
910  typedef typename std::iterator_traits<It>::iterator_category categ;
912  auto offset = pos - begin();
913  while (first != last) {
914  pos = insert(pos, *first++);
915  ++pos;
916  }
917  return begin() + offset;
918  }
919 
920  auto distance = std::distance(first, last);
921  auto offset = pos - begin();
922  makeSize(size() + distance);
924  data() + offset, data() + size(), data() + size() + distance);
925  this->setSize(size() + distance);
926  std::copy_n(first, distance, begin() + offset);
927  return begin() + offset;
928  }
929 
930  iterator
931  insertImpl(iterator pos, size_type n, const value_type& val, std::true_type) {
932  // The true_type means this should call the size_t,value_type
933  // overload. (See insert().)
934  return insert(pos, n, val);
935  }
936 
937  // The std::false_type argument came from std::is_arithmetic as part
938  // of disambiguating an overload (see the comment in the
939  // constructor).
940  template <class It>
941  void constructImpl(It first, It last, std::false_type) {
942  typedef typename std::iterator_traits<It>::iterator_category categ;
944  // With iterators that only allow a single pass, we can't really
945  // do anything sane here.
946  while (first != last) {
947  emplace_back(*first++);
948  }
949  return;
950  }
951 
952  auto distance = std::distance(first, last);
953  makeSize(distance);
954  this->setSize(distance);
955  try {
957  data(), distance, [&](void* p) { new (p) value_type(*first++); });
958  } catch (...) {
959  if (this->isExtern()) {
960  u.freeHeap();
961  }
962  throw;
963  }
964  }
965 
966  template <typename InitFunc>
967  void doConstruct(size_type n, InitFunc&& func) {
968  makeSize(n);
969  this->setSize(n);
970  try {
971  detail::populateMemForward(data(), n, std::forward<InitFunc>(func));
972  } catch (...) {
973  if (this->isExtern()) {
974  u.freeHeap();
975  }
976  throw;
977  }
978  }
979 
980  // The true_type means we should forward to the size_t,value_type
981  // overload.
982  void constructImpl(size_type n, value_type const& val, std::true_type) {
983  doConstruct(n, [&](void* p) { new (p) value_type(val); });
984  }
985 
986  /*
987  * Compute the size after growth.
988  */
989  size_type computeNewSize() const {
990  return std::min((3 * capacity()) / 2 + 1, max_size());
991  }
992 
993  void makeSize(size_type newSize) {
994  makeSizeInternal(newSize, false, [](void*) { assume_unreachable(); }, 0);
995  }
996 
997  template <typename EmplaceFunc>
998  void makeSize(size_type newSize, EmplaceFunc&& emplaceFunc, size_type pos) {
999  assert(size() == capacity());
1000  makeSizeInternal(
1001  newSize, true, std::forward<EmplaceFunc>(emplaceFunc), pos);
1002  }
1003 
1004  /*
1005  * Ensure we have a large enough memory region to be size `newSize'.
1006  * Will move/copy elements if we are spilling to heap_ or needed to
1007  * allocate a new region, but if resized in place doesn't initialize
1008  * anything in the new region. In any case doesn't change size().
1009  * Supports insertion of new element during reallocation by given
1010  * pointer to new element and position of new element.
1011  * NOTE: If reallocation is not needed, insert must be false,
1012  * because we only know how to emplace elements into new memory.
1013  */
1014  template <typename EmplaceFunc>
1016  size_type newSize,
1017  bool insert,
1018  EmplaceFunc&& emplaceFunc,
1019  size_type pos) {
1020  if (newSize > max_size()) {
1021  throw std::length_error("max_size exceeded in small_vector");
1022  }
1023  if (newSize <= capacity()) {
1024  assert(!insert);
1025  return;
1026  }
1027 
1028  assert(this->kShouldUseHeap);
1029  // This branch isn't needed for correctness, but allows the optimizer to
1030  // skip generating code for the rest of this function in NoHeap
1031  // small_vectors.
1032  if (!this->kShouldUseHeap) {
1033  return;
1034  }
1035 
1036  newSize = std::max(newSize, computeNewSize());
1037 
1038  auto needBytes = newSize * sizeof(value_type);
1039  // If the capacity isn't explicitly stored inline, but the heap
1040  // allocation is grown to over some threshold, we should store
1041  // a capacity at the front of the heap allocation.
1042  bool heapifyCapacity =
1043  !kHasInlineCapacity && needBytes > kHeapifyCapacityThreshold;
1044  if (heapifyCapacity) {
1045  needBytes += kHeapifyCapacitySize;
1046  }
1047  auto const sizeBytes = goodMallocSize(needBytes);
1048  void* newh = checkedMalloc(sizeBytes);
1049  // We expect newh to be at least 2-aligned, because we want to
1050  // use its least significant bit as a flag.
1051  assert(!detail::pointerFlagGet(newh));
1052 
1053  value_type* newp = static_cast<value_type*>(
1054  heapifyCapacity ? detail::shiftPointer(newh, kHeapifyCapacitySize)
1055  : newh);
1056 
1057  try {
1058  if (insert) {
1059  // move and insert the new element
1060  this->moveToUninitializedEmplace(
1061  begin(), end(), newp, pos, std::forward<EmplaceFunc>(emplaceFunc));
1062  } else {
1063  // move without inserting new element
1064  this->moveToUninitialized(begin(), end(), newp);
1065  }
1066  } catch (...) {
1067  free(newh);
1068  throw;
1069  }
1070  for (auto& val : *this) {
1071  val.~value_type();
1072  }
1073 
1074  if (this->isExtern()) {
1075  u.freeHeap();
1076  }
1077  auto availableSizeBytes = sizeBytes;
1078  if (heapifyCapacity) {
1079  u.pdata_.heap_ = detail::pointerFlagSet(newh);
1080  availableSizeBytes -= kHeapifyCapacitySize;
1081  } else {
1082  u.pdata_.heap_ = newh;
1083  }
1084  this->setExtern(true);
1085  this->setCapacity(availableSizeBytes / sizeof(value_type));
1086  }
1087 
1088  /*
1089  * This will set the capacity field, stored inline in the storage_ field
1090  * if there is sufficient room to store it.
1091  */
1092  void setCapacity(size_type newCapacity) {
1093  assert(this->isExtern());
1094  if (u.hasCapacity()) {
1095  assert(newCapacity < std::numeric_limits<InternalSizeType>::max());
1096  u.setCapacity(newCapacity);
1097  }
1098  }
1099 
1100  private:
1102  void* heap_;
1103  InternalSizeType capacity_;
1104 
1105  InternalSizeType getCapacity() const {
1106  return capacity_;
1107  }
1108  void setCapacity(InternalSizeType c) {
1109  capacity_ = c;
1110  }
1112 
1113  struct HeapPtr {
1114  // Lower order bit of heap_ is used as flag to indicate whether capacity is
1115  // stored at the front of the heap allocation.
1116  void* heap_;
1117 
1118  InternalSizeType getCapacity() const {
1119  assert(detail::pointerFlagGet(heap_));
1120  return *static_cast<InternalSizeType*>(detail::pointerFlagClear(heap_));
1121  }
1122  void setCapacity(InternalSizeType c) {
1123  *static_cast<InternalSizeType*>(detail::pointerFlagClear(heap_)) = c;
1124  }
1126 
1127  typedef typename std::aligned_storage<
1128  sizeof(value_type) * MaxInline,
1129  alignof(value_type)>::type InlineStorageDataType;
1130 
1131  typedef typename std::conditional<
1132  sizeof(value_type) * MaxInline != 0,
1133  InlineStorageDataType,
1135 
1136  static bool constexpr kHasInlineCapacity =
1137  sizeof(HeapPtrWithCapacity) < sizeof(InlineStorageType);
1138 
1139  // This value should we multiple of word size.
1140  static size_t constexpr kHeapifyCapacitySize = sizeof(
1141  typename std::
1143 
1144  // Threshold to control capacity heapifying.
1145  static size_t constexpr kHeapifyCapacityThreshold =
1146  100 * kHeapifyCapacitySize;
1147 
1148  typedef typename std::
1151 
1152  union Data {
1153  explicit Data() {
1154  pdata_.heap_ = nullptr;
1155  }
1156 
1159 
1160  value_type* buffer() noexcept {
1161  void* vp = &storage_;
1162  return static_cast<value_type*>(vp);
1163  }
1164  value_type const* buffer() const noexcept {
1165  return const_cast<Data*>(this)->buffer();
1166  }
1167  value_type* heap() noexcept {
1168  if (kHasInlineCapacity || !detail::pointerFlagGet(pdata_.heap_)) {
1169  return static_cast<value_type*>(pdata_.heap_);
1170  } else {
1171  return static_cast<value_type*>(detail::shiftPointer(
1172  detail::pointerFlagClear(pdata_.heap_), kHeapifyCapacitySize));
1173  }
1174  }
1175  value_type const* heap() const noexcept {
1176  return const_cast<Data*>(this)->heap();
1177  }
1178 
1179  bool hasCapacity() const {
1180  return kHasInlineCapacity || detail::pointerFlagGet(pdata_.heap_);
1181  }
1182  InternalSizeType getCapacity() const {
1183  return pdata_.getCapacity();
1184  }
1185  void setCapacity(InternalSizeType c) {
1186  pdata_.setCapacity(c);
1187  }
1188 
1189  void freeHeap() {
1190  auto vp = detail::pointerFlagClear(pdata_.heap_);
1191  free(vp);
1192  }
1193  } u;
1194 };
1196 
1198 
1199 // Basic guarantee only, or provides the nothrow guarantee iff T has a
1200 // nothrow move or copy constructor.
1201 template <class T, std::size_t MaxInline, class A, class B, class C>
1202 void swap(
1205  a.swap(b);
1206 }
1207 
1209 
1210 namespace detail {
1211 
1212 // Format support.
1213 template <class T, size_t M, class A, class B, class C>
1215  : public IndexableTraitsSeq<small_vector<T, M, A, B, C>> {};
1216 
1217 } // namespace detail
1218 
1219 } // namespace folly
1220 
1222 
1223 #undef FOLLY_SV_PACK_ATTR
1224 #undef FOLLY_SV_PACK_PUSH
1225 #undef FOLLY_SV_PACK_POP
void reserve(size_type sz)
Definition: small_vector.h:718
iterator emplace(const_iterator p, Args &&...args)
Definition: small_vector.h:693
T * pointerFlagClear(T *p)
Definition: small_vector.h:387
void * ptr
iterator insert(const_iterator p, std::initializer_list< value_type > il)
Definition: small_vector.h:818
std::vector< uint8_t > buffer(kBufferSize+16)
iterator insertImpl(iterator pos, It first, It last, std::false_type)
Definition: small_vector.h:909
small_vector(std::initializer_list< value_type > il)
Definition: small_vector.h:468
#define T(v)
Definition: http_parser.c:233
value_type & reference
Definition: small_vector.h:425
std::size_t size_type
Definition: small_vector.h:423
const_reference at(size_type i) const
Definition: small_vector.h:894
#define FOLLY_GNU_DISABLE_WARNING(warningName)
Definition: Portability.h:180
iterator insertImpl(iterator pos, size_type n, const value_type &val, std::true_type)
Definition: small_vector.h:931
#define FOLLY_POP_WARNING
Definition: Portability.h:179
iterator insert(const_iterator p, value_type const &t)
Definition: small_vector.h:794
void * checkedMalloc(size_t size)
Definition: Malloc.h:227
bool operator<(small_vector const &o) const
Definition: small_vector.h:518
std::unique_ptr< int > A
void swap(small_vector< T, MaxInline, A, B, C > &a, small_vector< T, MaxInline, A, B, C > &b)
reference operator[](size_type i)
Definition: small_vector.h:877
T * pointerFlagSet(T *p)
Definition: small_vector.h:379
iterator insert(const_iterator pos, size_type n, value_type const &val)
Definition: small_vector.h:800
#define FOLLY_PUSH_WARNING
Definition: Portability.h:178
reverse_iterator rbegin()
Definition: small_vector.h:553
char b
LogLevel max
Definition: LogLevel.cpp:31
void emplace_back(Args &&...args)
Definition: small_vector.h:742
iterator insert(const_iterator p, Arg arg1, Arg arg2)
Definition: small_vector.h:811
small_vector(small_vector const &o)
Definition: small_vector.h:441
PskType type
static iterator unconst(const_iterator it)
Definition: small_vector.h:902
const_reverse_iterator crbegin() const
Definition: small_vector.h:568
small_vector & operator=(small_vector &&o)
Definition: small_vector.h:504
#define FOLLY_SV_PACK_POP
Definition: small_vector.h:64
std::conditional< sizeof(value_type)*MaxInline!=0, InlineStorageDataType, void * >::type InlineStorageType
static constexpr std::size_t policyMaxSize()
Definition: small_vector.h:178
void setCapacity(InternalSizeType c)
small_vector(const std::allocator< Value > &)
Definition: small_vector.h:439
mpl::vector< InPolicyA, InPolicyB, InPolicyC > PolicyList
Definition: small_vector.h:331
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
union folly::small_vector::Data u
value_type const & const_reference
Definition: small_vector.h:426
const_reference operator[](size_type i) const
Definition: small_vector.h:882
void populateMemForward(T *mem, std::size_t n, Function const &op)
Definition: small_vector.h:156
static constexpr size_type max_size()
Definition: small_vector.h:522
STL namespace.
std::enable_if<!folly::is_trivially_copyable< T >::value >::type moveToUninitialized(T *first, T *last, T *out)
Definition: small_vector.h:230
auto begin(TestAdlIterable &instance)
Definition: ForeachTest.cpp:56
double val
Definition: String.cpp:273
size_type size() const
Definition: small_vector.h:527
iterator erase(const_iterator q1, const_iterator q2)
Definition: small_vector.h:829
void resize(size_type sz, value_type const &v)
Definition: small_vector.h:673
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
#define FOLLY_SV_PACK_PUSH
Definition: small_vector.h:63
small_vector & operator=(small_vector const &o)
Definition: small_vector.h:497
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
value_type const * heap() const noexcept
void constructImpl(size_type n, value_type const &val, std::true_type)
Definition: small_vector.h:982
requires E e noexcept(noexcept(s.error(std::move(e))))
const_reverse_iterator rend() const
Definition: small_vector.h:564
std::enable_if< folly::is_trivially_copyable< T >::value >::type moveToUninitialized(T *first, T *last, T *out)
Definition: small_vector.h:252
reverse_iterator rend()
Definition: small_vector.h:556
std::conditional< kHasInlineCapacity, HeapPtrWithCapacity, HeapPtr >::type PointerType
value_type * data() noexcept
Definition: small_vector.h:684
value_type const * data() const noexcept
Definition: small_vector.h:688
bool_constant< true > true_type
Definition: gtest-port.h:2210
InlineStorageType storage_
small_vector(size_type n, value_type const &t)
Definition: small_vector.h:476
constexpr T constexpr_max(T a)
Definition: ConstexprMath.h:68
std::reverse_iterator< iterator > reverse_iterator
Definition: small_vector.h:433
const_reference back() const
Definition: small_vector.h:872
void assign(size_type n, const value_type &t)
Definition: small_vector.h:855
iterator insert(const_iterator constp, value_type &&t)
Definition: small_vector.h:769
void swap(small_vector &o)
Definition: small_vector.h:583
void BENCHFUN() push_back(size_t iters, size_t arg)
const_reverse_iterator rbegin() const
Definition: small_vector.h:560
void setCapacity(InternalSizeType c)
small_vector(size_type n)
Definition: small_vector.h:472
void assign(Arg first, Arg last)
Definition: small_vector.h:846
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
const_iterator begin() const
Definition: small_vector.h:540
value_type const * buffer() const noexcept
void doConstruct(size_type n, InitFunc &&func)
Definition: small_vector.h:967
value_type * pointer
Definition: small_vector.h:428
constexpr auto empty(C const &c) -> decltype(c.empty())
Definition: Access.h:55
void push_back(value_type const &t)
Definition: small_vector.h:761
LogLevel min
Definition: LogLevel.cpp:30
void setCapacity(InternalSizeType c)
bool Value(const T &value, M matcher)
mpl::filter_view< PolicyList, std::is_integral< mpl::placeholders::_1 > >::type Integrals
Definition: small_vector.h:338
void push_back(value_type &&t)
Definition: small_vector.h:757
reference at(size_type i)
Definition: small_vector.h:887
void makeSizeInternal(size_type newSize, bool insert, EmplaceFunc &&emplaceFunc, size_type pos)
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
std::ptrdiff_t difference_type
Definition: small_vector.h:431
small_vector(Arg arg1, Arg arg2)
Definition: small_vector.h:481
size_type computeNewSize() const
Definition: small_vector.h:989
void constructImpl(It first, It last, std::false_type)
Definition: small_vector.h:941
void swapSizePolicy(IntegralSizePolicyBase &o)
Definition: small_vector.h:203
char a
std::is_trivially_copyable< T > is_trivially_copyable
Definition: Traits.h:313
value_type * iterator
Definition: small_vector.h:427
boost::totally_ordered1< small_vector< Value, RequestedMaxInline, InPolicyA, InPolicyB, InPolicyC >, ActualSizePolicy > type
Definition: small_vector.h:375
#define C(name, bit)
Definition: CpuId.h:204
static const char *const value
Definition: Conv.cpp:50
void * shiftPointer(void *p, size_t sizeBytes)
Definition: small_vector.h:390
void resize(size_type sz)
Definition: small_vector.h:662
void free()
void makeSize(size_type newSize)
Definition: small_vector.h:993
**Optimized Holders **The template hazptr_array< M > provides most of the functionality *of M hazptr_holder s but with faster construction destruction *for M
Definition: Hazptr.h:104
InternalSizeType getCapacity() const
value_type * buffer() noexcept
small_vector(small_vector &&o) noexcept(std::is_nothrow_move_constructible< Value >::value)
Definition: small_vector.h:455
const_reference front() const
Definition: small_vector.h:868
#define FOLLY_SV_PACK_ATTR
Definition: small_vector.h:62
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: small_vector.h:434
#define FOLLY_LIKELY(x)
Definition: Likely.h:35
std::pair< InIt, OutIt > copy_n(InIt b, typename std::iterator_traits< InIt >::difference_type n, OutIt d)
Definition: FBString.h:130
bool operator==(small_vector const &o) const
Definition: small_vector.h:514
std::enable_if< !std::is_default_constructible< T >::value||folly::is_trivially_copyable< T >::value >::type moveObjectsRight(T *first, T *lastConstructed, T *realLast)
Definition: small_vector.h:147
void moveToUninitializedEmplace(T *, T *, T *, SizeType, EmplaceFunc &&)
Definition: small_vector.h:302
const_reverse_iterator crend() const
Definition: small_vector.h:571
iterator erase(const_iterator q)
Definition: small_vector.h:822
void moveToUninitializedEmplace(T *begin, T *end, T *out, SizeType pos, EmplaceFunc &&emplaceFunc)
Definition: small_vector.h:263
const
Definition: upload.py:398
bool_constant< false > false_type
Definition: gtest-port.h:2209
std::aligned_storage< sizeof(value_type)*MaxInline, alignof(value_type)>::type InlineStorageDataType
mpl::count< PolicyList, small_vector_policy::NoHeap >::type HasNoHeap
Definition: small_vector.h:346
mpl::eval_if< mpl::empty< Integrals >, mpl::identity< std::size_t >, mpl::front< Integrals > >::type SizeType
Definition: small_vector.h:342
const_iterator cbegin() const
Definition: small_vector.h:546
const_iterator end() const
Definition: small_vector.h:543
value_type const * const_iterator
Definition: small_vector.h:429
void makeSize(size_type newSize, EmplaceFunc &&emplaceFunc, size_type pos)
Definition: small_vector.h:998
const_iterator cend() const
Definition: small_vector.h:549
IntegralSizePolicy< SizeType,!HasNoHeap::value > ActualSizePolicy
Definition: small_vector.h:360
BaseType::InternalSizeType InternalSizeType
Definition: small_vector.h:412
char c
static constexpr uint64_t data[1]
Definition: Fingerprint.cpp:43
ThreadPoolListHook * addr
value_type const * const_pointer
Definition: small_vector.h:430
InternalSizeType getCapacity() const
InternalSizeType getCapacity() const
bool pointerFlagGet(T *p)
Definition: small_vector.h:383
void assign(std::initializer_list< value_type > il)
Definition: small_vector.h:851
void setCapacity(size_type newCapacity)
Iterator< typename Container::const_iterator > cend(const Container &c)
Definition: Padded.h:324
detail::small_vector_base< Value, RequestedMaxInline, PolicyA, PolicyB, PolicyC >::type BaseType
Definition: small_vector.h:411
constexpr detail::First first
Definition: Base-inl.h:2553
size_t goodMallocSize(size_t minSize) noexcept
Definition: Malloc.h:201
value_type * heap() noexcept
size_type capacity() const
Definition: small_vector.h:722
bool empty() const
Definition: small_vector.h:530