57b84a4efa345fccbc72c7156d0d736d359fd7ad
[folly.git] / folly / test / small_vector_test.cpp
1 /*
2  * Copyright 2014 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 #include "folly/small_vector.h"
18
19 #include <gtest/gtest.h>
20 #include <string>
21 #include <memory>
22 #include <iostream>
23 #include <limits>
24
25 #include <boost/algorithm/string.hpp>
26
27 #include "folly/Conv.h"
28
29 using folly::small_vector;
30 using namespace folly::small_vector_policy;
31
32 #if defined(__x86_64__)
33
34 static_assert(sizeof(small_vector<int>) == 16,
35               "Object size is not what we expect for small_vector<int>");
36 static_assert(sizeof(small_vector<int32_t,2>) == 16,
37               "Object size is not what we expect for "
38               "small_vector<int32_t,2>");
39 static_assert(sizeof(small_vector<int,10>) ==
40                 10 * sizeof(int) + sizeof(std::size_t),
41               "Object size is not what we expect for small_vector<int,10>");
42
43 static_assert(sizeof(small_vector<int32_t,1,uint32_t>) ==
44                 8 + 4,
45               "small_vector<int32_t,1,uint32_t> is wrong size");
46 static_assert(sizeof(small_vector<int32_t,1,uint16_t>) ==
47                 8 + 2,
48               "small_vector<int32_t,1,uint32_t> is wrong size");
49 static_assert(sizeof(small_vector<int32_t,1,uint8_t>) ==
50                 8 + 1,
51               "small_vector<int32_t,1,uint32_t> is wrong size");
52
53 static_assert(sizeof(small_vector<int32_t,1,OneBitMutex>) == 16,
54               "OneBitMutex took more space than expected");
55
56 static_assert(sizeof(small_vector<int16_t,4,uint16_t>) == 10,
57               "Sizeof unexpectedly large");
58 static_assert(sizeof(small_vector<int16_t,4,uint16_t,OneBitMutex>) == 10,
59               "Sizeof unexpectedly large");
60 static_assert(sizeof(small_vector<int16_t,4,NoHeap,uint16_t,
61                                   OneBitMutex>) == 10,
62               "Sizeof unexpectedly large");
63
64 #endif
65
66 static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(std::unique_ptr<int>),
67               "std::unique_ptr<> is trivially copyable");
68
69 namespace {
70
71 struct NontrivialType {
72   static int ctored;
73   explicit NontrivialType() : a(0) {}
74
75   /* implicit */ NontrivialType(int a) : a(a) {
76     ++ctored;
77   }
78
79   NontrivialType(NontrivialType const& s) {
80     ++ctored;
81   }
82
83   NontrivialType& operator=(NontrivialType const& o) {
84     a = o.a;
85     return *this;
86   }
87
88   int32_t a;
89 };
90 static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(NontrivialType),
91               "NontrivialType is trivially copyable");
92
93 int NontrivialType::ctored = 0;
94
95 struct TestException {};
96
97 int throwCounter = 1;
98 void MaybeThrow() {
99   if (!--throwCounter) {
100     throw TestException();
101   }
102 }
103
104 const int kMagic = 0xdeadbeef;
105 struct Thrower {
106   static int alive;
107
108   Thrower() : magic(kMagic) {
109     EXPECT_EQ(magic, kMagic);
110     MaybeThrow();
111     ++alive;
112   }
113   Thrower(Thrower const& other) : magic(other.magic) {
114     EXPECT_EQ(magic, kMagic);
115     MaybeThrow();
116     ++alive;
117   }
118   ~Thrower() noexcept {
119     EXPECT_EQ(magic, kMagic);
120     magic = 0;
121     --alive;
122   }
123
124   Thrower& operator=(Thrower const& other) {
125     EXPECT_EQ(magic, kMagic);
126     MaybeThrow();
127     return *this;
128   }
129
130   // This is just to try to make sure we don't get our member
131   // functions called on uninitialized memory.
132   int magic;
133 };
134
135 int Thrower::alive = 0;
136
137 // Type that counts how many exist and doesn't support copy
138 // construction.
139 struct NoncopyableCounter {
140   static int alive;
141   NoncopyableCounter() {
142     ++alive;
143   }
144   ~NoncopyableCounter() {
145     --alive;
146   }
147   NoncopyableCounter(NoncopyableCounter&&) { ++alive; }
148   NoncopyableCounter(NoncopyableCounter const&) = delete;
149   NoncopyableCounter& operator=(NoncopyableCounter const&) const = delete;
150   NoncopyableCounter& operator=(NoncopyableCounter&&) { return *this; }
151 };
152 int NoncopyableCounter::alive = 0;
153
154 static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(NoncopyableCounter),
155               "NoncopyableCounter is trivially copyable");
156
157 // Check that throws don't break the basic guarantee for some cases.
158 // Uses the method for testing exception safety described at
159 // http://www.boost.org/community/exception_safety.html, to force all
160 // throwing code paths to occur.
161 struct TestBasicGuarantee {
162   folly::small_vector<Thrower,3> vec;
163   int const prepopulate;
164
165   explicit TestBasicGuarantee(int prepopulate)
166     : prepopulate(prepopulate)
167   {
168     throwCounter = 1000;
169     for (int i = 0; i < prepopulate; ++i) {
170       vec.push_back(Thrower());
171     }
172   }
173
174   ~TestBasicGuarantee() {
175     throwCounter = 1000;
176   }
177
178   template<class Operation>
179   void operator()(int insertCount, Operation const& op) {
180     bool done = false;
181
182     std::unique_ptr<folly::small_vector<Thrower,3> > workingVec;
183     for (int counter = 1; !done; ++counter) {
184       throwCounter = 1000;
185       workingVec.reset(new folly::small_vector<Thrower,3>(vec));
186       throwCounter = counter;
187       EXPECT_EQ(Thrower::alive, prepopulate * 2);
188       try {
189         op(*workingVec);
190         done = true;
191       } catch (...) {
192         // Note that the size of the vector can change if we were
193         // inserting somewhere other than the end (it's a basic only
194         // guarantee).  All we're testing here is that we have the
195         // right amount of uninitialized vs initialized memory.
196         EXPECT_EQ(Thrower::alive, workingVec->size() + vec.size());
197         continue;
198       }
199
200       // If things succeeded.
201       EXPECT_EQ(workingVec->size(), prepopulate + insertCount);
202       EXPECT_EQ(Thrower::alive, prepopulate * 2 + insertCount);
203     }
204   }
205 };
206
207 }
208
209 TEST(small_vector, BasicGuarantee) {
210   for (int prepop = 1; prepop < 30; ++prepop) {
211     (TestBasicGuarantee(prepop))( // parens or a mildly vexing parse :(
212       1,
213       [&] (folly::small_vector<Thrower,3>& v) {
214         v.push_back(Thrower());
215       }
216     );
217
218     EXPECT_EQ(Thrower::alive, 0);
219
220     (TestBasicGuarantee(prepop))(
221       1,
222       [&] (folly::small_vector<Thrower,3>& v) {
223         v.insert(v.begin(), Thrower());
224       }
225     );
226
227     EXPECT_EQ(Thrower::alive, 0);
228
229     (TestBasicGuarantee(prepop))(
230       1,
231       [&] (folly::small_vector<Thrower,3>& v) {
232         v.insert(v.begin() + 1, Thrower());
233       }
234     );
235
236     EXPECT_EQ(Thrower::alive, 0);
237   }
238
239   TestBasicGuarantee(4)(
240     3,
241     [&] (folly::small_vector<Thrower,3>& v) {
242       std::vector<Thrower> b;
243       b.push_back(Thrower());
244       b.push_back(Thrower());
245       b.push_back(Thrower());
246
247       /*
248        * Apparently if you do the following initializer_list instead
249        * of the above push_back's, and one of the Throwers throws,
250        * g++4.6 doesn't destruct the previous ones.  Heh.
251        */
252       //b = { Thrower(), Thrower(), Thrower() };
253       v.insert(v.begin() + 1, b.begin(), b.end());
254     }
255   );
256
257   TestBasicGuarantee(2)(
258     6,
259     [&] (folly::small_vector<Thrower,3>& v) {
260       std::vector<Thrower> b;
261       for (int i = 0; i < 6; ++i) {
262         b.push_back(Thrower());
263       }
264
265       v.insert(v.begin() + 1, b.begin(), b.end());
266     }
267   );
268
269   EXPECT_EQ(Thrower::alive, 0);
270   try {
271     throwCounter = 4;
272     folly::small_vector<Thrower,1> p(14, Thrower());
273   } catch (...) {
274   }
275   EXPECT_EQ(Thrower::alive, 0);
276 }
277
278 // Run this with.
279 // MALLOC_CONF=prof_leak:true
280 // LD_PRELOAD=${JEMALLOC_PATH}/lib/libjemalloc.so.1
281 // LD_PRELOAD="$LD_PRELOAD:"${UNWIND_PATH}/lib/libunwind.so.7
282 TEST(small_vector, leak_test) {
283   for (int j = 0; j < 1000; ++j) {
284     folly::small_vector<int, 10> someVec(300);
285     for (int i = 0; i < 10000; ++i) {
286       someVec.push_back(12);
287     }
288   }
289 }
290
291 TEST(small_vector, Insert) {
292   folly::small_vector<int> someVec(3, 3);
293   someVec.insert(someVec.begin(), 12, 12);
294   EXPECT_EQ(someVec.size(), 15);
295   for (int i = 0; i < someVec.size(); ++i) {
296     if (i < 12) {
297       EXPECT_EQ(someVec[i], 12);
298     } else {
299       EXPECT_EQ(someVec[i], 3);
300     }
301   }
302
303   auto oldSize = someVec.size();
304   someVec.insert(someVec.begin() + 1, 12, 12);
305   EXPECT_EQ(someVec.size(), oldSize + 12);
306
307   folly::small_vector<std::string> v1(6, "asd"), v2(7, "wat");
308   v1.insert(v1.begin() + 1, v2.begin(), v2.end());
309   EXPECT_TRUE(v1.size() == 6 + 7);
310   EXPECT_EQ(v1.front(), "asd");
311   EXPECT_EQ(v1[1], "wat");
312 }
313
314 TEST(small_vector, Swap) {
315   folly::small_vector<int,10> somethingVec, emptyVec;
316   somethingVec.push_back(1);
317   somethingVec.push_back(2);
318   somethingVec.push_back(3);
319   somethingVec.push_back(4);
320
321   // Swapping intern'd with intern'd.
322   auto vec = somethingVec;
323   EXPECT_TRUE(vec == somethingVec);
324   EXPECT_FALSE(vec == emptyVec);
325   EXPECT_FALSE(somethingVec == emptyVec);
326
327   // Swapping a heap vector with an intern vector.
328   folly::small_vector<int,10> junkVec;
329   junkVec.assign(12, 12);
330   EXPECT_EQ(junkVec.size(), 12);
331   for (auto i : junkVec) {
332     EXPECT_EQ(i, 12);
333   }
334   swap(junkVec, vec);
335   EXPECT_TRUE(junkVec == somethingVec);
336   EXPECT_EQ(vec.size(), 12);
337   for (auto i : vec) {
338     EXPECT_EQ(i, 12);
339   }
340
341   // Swapping two heap vectors.
342   folly::small_vector<int,10> moreJunk(15, 15);
343   EXPECT_EQ(moreJunk.size(), 15);
344   for (auto i : moreJunk) {
345     EXPECT_EQ(i, 15);
346   }
347   swap(vec, moreJunk);
348   EXPECT_EQ(moreJunk.size(), 12);
349   for (auto i : moreJunk) {
350     EXPECT_EQ(i, 12);
351   }
352   EXPECT_EQ(vec.size(), 15);
353   for (auto i : vec) {
354     EXPECT_EQ(i, 15);
355   }
356
357   // Making a vector heap, then smaller than another non-heap vector,
358   // then swapping.
359   folly::small_vector<int,5> shrinker, other(4, 10);
360   shrinker = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
361   shrinker.erase(shrinker.begin() + 2, shrinker.end());
362   EXPECT_LT(shrinker.size(), other.size());
363   swap(shrinker, other);
364   EXPECT_EQ(shrinker.size(), 4);
365   EXPECT_TRUE(boost::all(shrinker, boost::is_any_of(std::vector<int>{10})));
366   EXPECT_TRUE((other == small_vector<int,5>{ 0, 1 }));
367 }
368
369 TEST(small_vector, Emplace) {
370   NontrivialType::ctored = 0;
371
372   folly::small_vector<NontrivialType> vec;
373   vec.reserve(1024);
374   vec.emplace_back(12);
375   EXPECT_EQ(NontrivialType::ctored, 1);
376   EXPECT_EQ(vec.front().a, 12);
377   vec.emplace_back(13);
378   EXPECT_EQ(vec.front().a, 12);
379   EXPECT_EQ(vec.back().a, 13);
380   EXPECT_EQ(NontrivialType::ctored, 2);
381
382   NontrivialType::ctored = 0;
383   for (int i = 0; i < 120; ++i) {
384     vec.emplace_back(i);
385   }
386   EXPECT_EQ(NontrivialType::ctored, 120);
387   EXPECT_EQ(vec[0].a, 12);
388   EXPECT_EQ(vec[1].a, 13);
389   EXPECT_EQ(vec.back().a, 119);
390
391   // We implement emplace() with a temporary (see the implementation
392   // for a comment about why), so this should make 2 ctor calls.
393   NontrivialType::ctored = 0;
394   vec.emplace(vec.begin(), 12);
395   EXPECT_EQ(NontrivialType::ctored, 2);
396 }
397
398 TEST(small_vector, Erase) {
399   folly::small_vector<int,4> notherVec = { 1, 2, 3, 4, 5 };
400   EXPECT_EQ(notherVec.front(), 1);
401   EXPECT_EQ(notherVec.size(), 5);
402   notherVec.erase(notherVec.begin());
403   EXPECT_EQ(notherVec.front(), 2);
404   EXPECT_EQ(notherVec.size(), 4);
405   EXPECT_EQ(notherVec[2], 4);
406   EXPECT_EQ(notherVec[3], 5);
407   notherVec.erase(notherVec.begin() + 2);
408   EXPECT_EQ(notherVec.size(), 3);
409   EXPECT_EQ(notherVec[2], 5);
410
411   folly::small_vector<int,2> vec2 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
412   vec2.erase(vec2.begin() + 1, vec2.end() - 1);
413   folly::small_vector<int,2> expected = { 1, 10 };
414   EXPECT_TRUE(vec2 == expected);
415
416   folly::small_vector<std::string,3> v(102, "ASD");
417   v.resize(1024, "D");
418   EXPECT_EQ(v.size(), 1024);
419   EXPECT_EQ(v.back(), "D");
420   EXPECT_EQ(v.front(), "ASD");
421   v.resize(1);
422   EXPECT_EQ(v.front(), "ASD");
423   EXPECT_EQ(v.size(), 1);
424   v.resize(0);
425   EXPECT_TRUE(v.empty());
426 }
427
428 TEST(small_vector, GrowShrinkGrow) {
429   folly::small_vector<NontrivialType,7> vec = { 1, 2, 3, 4, 5 };
430   std::generate_n(std::back_inserter(vec), 102, std::rand);
431
432   auto capacity = vec.capacity();
433
434   auto oldSize = vec.size();
435   for (int i = 0; i < oldSize; ++i) {
436     vec.erase(vec.begin() + (std::rand() % vec.size()));
437     EXPECT_EQ(vec.capacity(), capacity);
438   }
439   EXPECT_TRUE(vec.empty());
440
441   EXPECT_EQ(vec.capacity(), capacity);
442   std::generate_n(std::back_inserter(vec), 102, std::rand);
443   EXPECT_EQ(vec.capacity(), capacity);
444
445   std::generate_n(std::back_inserter(vec), 4096, std::rand);
446   EXPECT_GT(vec.capacity(), capacity);
447
448   vec.resize(10);
449   vec.shrink_to_fit();
450   EXPECT_LT(vec.capacity(), capacity);
451   vec.resize(4);
452   vec.shrink_to_fit();
453   EXPECT_EQ(vec.capacity(), 7); // in situ size
454 }
455
456 TEST(small_vector, Iteration) {
457   folly::small_vector<std::string,3> vec = { "foo", "bar" };
458   vec.push_back("blah");
459   vec.push_back("blah2");
460   vec.push_back("blah3");
461   vec.erase(vec.begin() + 2);
462
463   std::vector<std::string> otherVec;
464   for (auto& s : vec) {
465     otherVec.push_back(s);
466   }
467   EXPECT_EQ(otherVec.size(), vec.size());
468   if (otherVec.size() == vec.size()) {
469     EXPECT_TRUE(std::equal(otherVec.begin(), otherVec.end(), vec.begin()));
470   }
471
472   std::reverse(otherVec.begin(), otherVec.end());
473   auto oit = otherVec.begin();
474   auto rit = vec.crbegin();
475   for (; rit != vec.crend(); ++oit, ++rit) {
476     EXPECT_EQ(*oit, *rit);
477   }
478 }
479
480 TEST(small_vector, NonCopyableType) {
481   folly::small_vector<NontrivialType,2> vec;
482
483   for (int i = 0; i < 10; ++i) {
484     vec.emplace(vec.begin(), 13);
485   }
486   EXPECT_EQ(vec.size(), 10);
487   auto vec2 = std::move(vec);
488   EXPECT_EQ(vec.size(), 0);
489   EXPECT_EQ(vec2.size(), 10);
490   vec2.clear();
491
492   folly::small_vector<NoncopyableCounter,3> vec3;
493   for (int i = 0; i < 10; ++i) {
494     EXPECT_EQ(vec3.size(), i);
495     EXPECT_EQ(NoncopyableCounter::alive, i);
496     vec3.insert(vec3.begin(), NoncopyableCounter());
497   }
498   EXPECT_EQ(vec3.size(), 10);
499   EXPECT_EQ(NoncopyableCounter::alive, 10);
500
501   vec3.insert(vec3.begin() + 3, NoncopyableCounter());
502   EXPECT_EQ(NoncopyableCounter::alive, 11);
503   auto vec4 = std::move(vec3);
504   EXPECT_EQ(NoncopyableCounter::alive, 11);
505   vec4.resize(30);
506   EXPECT_EQ(NoncopyableCounter::alive, 30);
507   vec4.erase(vec4.begin(), vec4.end());
508   EXPECT_EQ(vec4.size(), 0);
509   EXPECT_EQ(NoncopyableCounter::alive, 0);
510 }
511
512 TEST(small_vector, MoveConstructor) {
513   folly::small_vector<std::string,10> v1;
514   v1.push_back("asd");
515   v1.push_back("bsd");
516   auto v2 = std::move(v1);
517   EXPECT_EQ(v2.size(), 2);
518   EXPECT_EQ(v2[0], "asd");
519   EXPECT_EQ(v2[1], "bsd");
520
521   v1 = std::move(v2);
522   EXPECT_EQ(v1.size(), 2);
523   EXPECT_EQ(v1[0], "asd");
524   EXPECT_EQ(v1[1], "bsd");
525 }
526
527 TEST(small_vector, NoHeap) {
528   typedef folly::small_vector<std::string,10,
529     std::size_t,folly::small_vector_policy::NoHeap> Vector;
530
531   Vector v;
532   static_assert(v.max_size() == 10, "max_size is incorrect");
533
534   for (int i = 0; i < 10; ++i) {
535     v.push_back(folly::to<std::string>(i));
536     EXPECT_EQ(v.size(), i + 1);
537   }
538
539   bool caught = false;
540   try {
541     v.insert(v.begin(), "ha");
542   } catch (const std::length_error&) {
543     caught = true;
544   }
545   EXPECT_TRUE(caught);
546
547   // Check max_size works right with various policy combinations.
548   folly::small_vector<std::string,32,uint32_t,NoHeap,OneBitMutex> v2;
549   static_assert(v2.max_size() == 32, "max_size is incorrect");
550   folly::small_vector<std::string,32,uint32_t,OneBitMutex> v3;
551   EXPECT_EQ(v3.max_size(), (1ul << 30) - 1);
552   folly::small_vector<std::string,32,uint32_t> v4;
553   EXPECT_EQ(v4.max_size(), (1ul << 31) - 1);
554
555   /*
556    * Test that even when we ask for a small number inlined it'll still
557    * inline at least as much as it takes to store the value_type
558    * pointer.
559    */
560   folly::small_vector<char,1,NoHeap> notsosmall;
561   static_assert(notsosmall.max_size() == sizeof(char*),
562                 "max_size is incorrect");
563   caught = false;
564   try {
565     notsosmall.push_back(12);
566     notsosmall.push_back(13);
567     notsosmall.push_back(14);
568   } catch (const std::length_error&) {
569     caught = true;
570   }
571   EXPECT_FALSE(caught);
572 }
573
574 TEST(small_vector, MaxSize) {
575   folly::small_vector<int,2,uint8_t> vec;
576   EXPECT_EQ(vec.max_size(), 127);
577   folly::small_vector<int,2,uint16_t> vec2;
578   EXPECT_EQ(vec2.max_size(), (1 << 15) - 1);
579   folly::small_vector<int,2,uint16_t,OneBitMutex> vec3;
580   EXPECT_EQ(vec3.max_size(), (1 << 14) - 1);
581 }
582
583 TEST(small_vector, AllHeap) {
584   // Use something bigger than the pointer so it can't get inlined.
585   struct SomeObj {
586     double a, b, c, d, e; int val;
587     SomeObj(int val) : val(val) {}
588     bool operator==(SomeObj const& o) const {
589       return o.val == val;
590     }
591   };
592
593   folly::small_vector<SomeObj,0> vec = { 1 };
594   EXPECT_EQ(vec.size(), 1);
595   if (!vec.empty()) {
596     EXPECT_TRUE(vec[0] == 1);
597   }
598   vec.insert(vec.begin(), { 0, 1, 2, 3 });
599   EXPECT_EQ(vec.size(), 5);
600   EXPECT_TRUE((vec == folly::small_vector<SomeObj,0>{ 0, 1, 2, 3, 1 }));
601 }
602
603 TEST(small_vector, Basic) {
604   typedef folly::small_vector<int,3,uint32_t
605 #ifdef __x86_64__
606     ,OneBitMutex
607 #endif
608   > Vector;
609
610   Vector a;
611
612 #ifdef __x86_64__
613   a.lock();
614   a.unlock();
615 #endif
616
617   a.push_back(12);
618   EXPECT_EQ(a.front(), 12);
619   EXPECT_EQ(a.size(), 1);
620   a.push_back(13);
621   EXPECT_EQ(a.size(), 2);
622   EXPECT_EQ(a.front(), 12);
623   EXPECT_EQ(a.back(), 13);
624
625   a.emplace(a.end(), 32);
626   EXPECT_EQ(a.back(), 32);
627
628   a.emplace(a.begin(), 12);
629   EXPECT_EQ(a.front(), 12);
630   EXPECT_EQ(a.back(), 32);
631   a.erase(a.end() - 1);
632   EXPECT_EQ(a.back(), 13);
633
634   a.push_back(12);
635   EXPECT_EQ(a.back(), 12);
636   a.pop_back();
637   EXPECT_EQ(a.back(), 13);
638
639   const int s = 12;
640   a.push_back(s); // lvalue reference
641
642   Vector b, c;
643   b = a;
644   EXPECT_TRUE(b == a);
645   c = std::move(b);
646   EXPECT_TRUE(c == a);
647   EXPECT_TRUE(c != b && b != a);
648
649   EXPECT_GT(c.size(), 0);
650   c.resize(1);
651   EXPECT_EQ(c.size(), 1);
652
653   Vector intCtor(12);
654 }
655
656 TEST(small_vector, Capacity) {
657   folly::small_vector<unsigned long, 1> vec;
658   EXPECT_EQ(vec.size(), 0);
659   EXPECT_EQ(vec.capacity(), 1);
660
661   vec.push_back(0);
662   EXPECT_EQ(vec.size(), 1);
663   EXPECT_EQ(vec.capacity(), 1);
664
665   vec.push_back(1);
666   EXPECT_EQ(vec.size(), 2);
667   EXPECT_GT(vec.capacity(), 1);
668
669
670   folly::small_vector<unsigned long, 2> vec2;
671   EXPECT_EQ(vec2.size(), 0);
672   EXPECT_EQ(vec2.capacity(), 2);
673
674   vec2.push_back(0);
675   vec2.push_back(1);
676   EXPECT_EQ(vec2.size(), 2);
677   EXPECT_EQ(vec2.capacity(), 2);
678
679   vec2.push_back(2);
680   EXPECT_EQ(vec2.size(), 3);
681   EXPECT_GT(vec2.capacity(), 2);
682
683   // Test capacity heapifying logic
684   folly::small_vector<unsigned char, 1> vec3;
685   const size_t hc_size = 1000000;
686   for (size_t i = 0; i < hc_size; ++i) {
687     auto v = (unsigned char)i;
688     vec3.push_back(v);
689     EXPECT_EQ(vec3[i], v);
690     EXPECT_EQ(vec3.size(), i + 1);
691     EXPECT_GT(vec3.capacity(), i);
692   }
693   for (auto i = hc_size; i > 0; --i) {
694     auto v = (unsigned char)(i - 1);
695     EXPECT_EQ(vec3.back(), v);
696     vec3.pop_back();
697     EXPECT_EQ(vec3.size(), i - 1);
698   }
699 }
700
701 TEST(small_vector, SelfPushBack) {
702   for (int i = 1; i < 33; ++i) {
703     folly::small_vector<std::string> vec;
704     for (int j = 0; j < i; ++j) {
705       vec.push_back("abc");
706     }
707     EXPECT_EQ(vec.size(), i);
708     vec.push_back(std::move(vec[0]));
709     EXPECT_EQ(vec.size(), i + 1);
710
711     EXPECT_EQ(vec[i], "abc");
712   }
713 }
714
715 TEST(small_vector, SelfEmplaceBack) {
716   for (int i = 1; i < 33; ++i) {
717     folly::small_vector<std::string> vec;
718     for (int j = 0; j < i; ++j) {
719       vec.emplace_back("abc");
720     }
721     EXPECT_EQ(vec.size(), i);
722     vec.emplace_back(std::move(vec[0]));
723     EXPECT_EQ(vec.size(), i + 1);
724
725     EXPECT_EQ(vec[i], "abc");
726   }
727 }
728
729 TEST(small_vector, SelfInsert) {
730   // end insert
731   for (int i = 1; i < 33; ++i) {
732     folly::small_vector<std::string> vec;
733     for (int j = 0; j < i; ++j) {
734       vec.push_back("abc");
735     }
736     EXPECT_EQ(vec.size(), i);
737     vec.insert(vec.end(), std::move(vec[0]));
738     EXPECT_EQ(vec.size(), i + 1);
739
740     EXPECT_EQ(vec[i], "abc");
741     EXPECT_EQ(vec[vec.size() - 1], "abc");
742   }
743
744   // middle insert
745   for (int i = 2; i < 33; ++i) {
746     folly::small_vector<std::string> vec;
747     for (int j = 0; j < i; ++j) {
748       vec.push_back("abc");
749     }
750     EXPECT_EQ(vec.size(), i);
751     vec.insert(vec.end()-1, std::move(vec[0]));
752     EXPECT_EQ(vec.size(), i + 1);
753
754     EXPECT_EQ(vec[i-1], "abc");
755     EXPECT_EQ(vec[i], "abc");
756   }
757 }