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