1 // Copyright 2019 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "absl/container/inlined_vector.h"
16 
17 #include <algorithm>
18 #include <forward_list>
19 #include <list>
20 #include <memory>
21 #include <scoped_allocator>
22 #include <sstream>
23 #include <stdexcept>
24 #include <string>
25 #include <vector>
26 
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
29 #include "absl/base/attributes.h"
30 #include "absl/base/internal/exception_testing.h"
31 #include "absl/base/internal/raw_logging.h"
32 #include "absl/base/macros.h"
33 #include "absl/container/internal/counting_allocator.h"
34 #include "absl/container/internal/test_instance_tracker.h"
35 #include "absl/hash/hash_testing.h"
36 #include "absl/memory/memory.h"
37 #include "absl/strings/str_cat.h"
38 
39 namespace {
40 
41 using absl::container_internal::CountingAllocator;
42 using absl::test_internal::CopyableMovableInstance;
43 using absl::test_internal::CopyableOnlyInstance;
44 using absl::test_internal::InstanceTracker;
45 using testing::AllOf;
46 using testing::Each;
47 using testing::ElementsAre;
48 using testing::ElementsAreArray;
49 using testing::Eq;
50 using testing::Gt;
51 using testing::PrintToString;
52 
53 using IntVec = absl::InlinedVector<int, 8>;
54 
55 MATCHER_P(SizeIs, n, "") {
56   return testing::ExplainMatchResult(n, arg.size(), result_listener);
57 }
58 
59 MATCHER_P(CapacityIs, n, "") {
60   return testing::ExplainMatchResult(n, arg.capacity(), result_listener);
61 }
62 
63 MATCHER_P(ValueIs, e, "") {
64   return testing::ExplainMatchResult(e, arg.value(), result_listener);
65 }
66 
67 // TODO(bsamwel): Add support for movable-only types.
68 
69 // Test fixture for typed tests on BaseCountedInstance derived classes, see
70 // test_instance_tracker.h.
71 template <typename T>
72 class InstanceTest : public ::testing::Test {};
73 TYPED_TEST_SUITE_P(InstanceTest);
74 
75 // A simple reference counted class to make sure that the proper elements are
76 // destroyed in the erase(begin, end) test.
77 class RefCounted {
78  public:
RefCounted(int value,int * count)79   RefCounted(int value, int* count) : value_(value), count_(count) { Ref(); }
80 
RefCounted(const RefCounted & v)81   RefCounted(const RefCounted& v) : value_(v.value_), count_(v.count_) {
82     Ref();
83   }
84 
~RefCounted()85   ~RefCounted() {
86     Unref();
87     count_ = nullptr;
88   }
89 
swap(RefCounted & a,RefCounted & b)90   friend void swap(RefCounted& a, RefCounted& b) {
91     using std::swap;
92     swap(a.value_, b.value_);
93     swap(a.count_, b.count_);
94   }
95 
operator =(RefCounted v)96   RefCounted& operator=(RefCounted v) {
97     using std::swap;
98     swap(*this, v);
99     return *this;
100   }
101 
Ref() const102   void Ref() const {
103     ABSL_RAW_CHECK(count_ != nullptr, "");
104     ++(*count_);
105   }
106 
Unref() const107   void Unref() const {
108     --(*count_);
109     ABSL_RAW_CHECK(*count_ >= 0, "");
110   }
111 
112   int value_;
113   int* count_;
114 };
115 
116 using RefCountedVec = absl::InlinedVector<RefCounted, 8>;
117 
118 // A class with a vtable pointer
119 class Dynamic {
120  public:
~Dynamic()121   virtual ~Dynamic() {}
122 };
123 
124 using DynamicVec = absl::InlinedVector<Dynamic, 8>;
125 
126 // Append 0..len-1 to *v
127 template <typename Container>
Fill(Container * v,int len,int offset=0)128 static void Fill(Container* v, int len, int offset = 0) {
129   for (int i = 0; i < len; i++) {
130     v->push_back(i + offset);
131   }
132 }
133 
Fill(int len,int offset=0)134 static IntVec Fill(int len, int offset = 0) {
135   IntVec v;
136   Fill(&v, len, offset);
137   return v;
138 }
139 
TEST(IntVec,SimpleOps)140 TEST(IntVec, SimpleOps) {
141   for (int len = 0; len < 20; len++) {
142     IntVec v;
143     const IntVec& cv = v;  // const alias
144 
145     Fill(&v, len);
146     EXPECT_EQ(len, v.size());
147     EXPECT_LE(len, v.capacity());
148 
149     for (int i = 0; i < len; i++) {
150       EXPECT_EQ(i, v[i]);
151       EXPECT_EQ(i, v.at(i));
152     }
153     EXPECT_EQ(v.begin(), v.data());
154     EXPECT_EQ(cv.begin(), cv.data());
155 
156     int counter = 0;
157     for (IntVec::iterator iter = v.begin(); iter != v.end(); ++iter) {
158       EXPECT_EQ(counter, *iter);
159       counter++;
160     }
161     EXPECT_EQ(counter, len);
162 
163     counter = 0;
164     for (IntVec::const_iterator iter = v.begin(); iter != v.end(); ++iter) {
165       EXPECT_EQ(counter, *iter);
166       counter++;
167     }
168     EXPECT_EQ(counter, len);
169 
170     counter = 0;
171     for (IntVec::const_iterator iter = v.cbegin(); iter != v.cend(); ++iter) {
172       EXPECT_EQ(counter, *iter);
173       counter++;
174     }
175     EXPECT_EQ(counter, len);
176 
177     if (len > 0) {
178       EXPECT_EQ(0, v.front());
179       EXPECT_EQ(len - 1, v.back());
180       v.pop_back();
181       EXPECT_EQ(len - 1, v.size());
182       for (int i = 0; i < v.size(); ++i) {
183         EXPECT_EQ(i, v[i]);
184         EXPECT_EQ(i, v.at(i));
185       }
186     }
187   }
188 }
189 
TEST(IntVec,PopBackNoOverflow)190 TEST(IntVec, PopBackNoOverflow) {
191   IntVec v = {1};
192   v.pop_back();
193   EXPECT_EQ(v.size(), 0);
194 }
195 
TEST(IntVec,AtThrows)196 TEST(IntVec, AtThrows) {
197   IntVec v = {1, 2, 3};
198   EXPECT_EQ(v.at(2), 3);
199   ABSL_BASE_INTERNAL_EXPECT_FAIL(v.at(3), std::out_of_range,
200                                  "failed bounds check");
201 }
202 
TEST(IntVec,ReverseIterator)203 TEST(IntVec, ReverseIterator) {
204   for (int len = 0; len < 20; len++) {
205     IntVec v;
206     Fill(&v, len);
207 
208     int counter = len;
209     for (IntVec::reverse_iterator iter = v.rbegin(); iter != v.rend(); ++iter) {
210       counter--;
211       EXPECT_EQ(counter, *iter);
212     }
213     EXPECT_EQ(counter, 0);
214 
215     counter = len;
216     for (IntVec::const_reverse_iterator iter = v.rbegin(); iter != v.rend();
217          ++iter) {
218       counter--;
219       EXPECT_EQ(counter, *iter);
220     }
221     EXPECT_EQ(counter, 0);
222 
223     counter = len;
224     for (IntVec::const_reverse_iterator iter = v.crbegin(); iter != v.crend();
225          ++iter) {
226       counter--;
227       EXPECT_EQ(counter, *iter);
228     }
229     EXPECT_EQ(counter, 0);
230   }
231 }
232 
TEST(IntVec,Erase)233 TEST(IntVec, Erase) {
234   for (int len = 1; len < 20; len++) {
235     for (int i = 0; i < len; ++i) {
236       IntVec v;
237       Fill(&v, len);
238       v.erase(v.begin() + i);
239       EXPECT_EQ(len - 1, v.size());
240       for (int j = 0; j < i; ++j) {
241         EXPECT_EQ(j, v[j]);
242       }
243       for (int j = i; j < len - 1; ++j) {
244         EXPECT_EQ(j + 1, v[j]);
245       }
246     }
247   }
248 }
249 
250 // At the end of this test loop, the elements between [erase_begin, erase_end)
251 // should have reference counts == 0, and all others elements should have
252 // reference counts == 1.
TEST(RefCountedVec,EraseBeginEnd)253 TEST(RefCountedVec, EraseBeginEnd) {
254   for (int len = 1; len < 20; ++len) {
255     for (int erase_begin = 0; erase_begin < len; ++erase_begin) {
256       for (int erase_end = erase_begin; erase_end <= len; ++erase_end) {
257         std::vector<int> counts(len, 0);
258         RefCountedVec v;
259         for (int i = 0; i < len; ++i) {
260           v.push_back(RefCounted(i, &counts[i]));
261         }
262 
263         int erase_len = erase_end - erase_begin;
264 
265         v.erase(v.begin() + erase_begin, v.begin() + erase_end);
266 
267         EXPECT_EQ(len - erase_len, v.size());
268 
269         // Check the elements before the first element erased.
270         for (int i = 0; i < erase_begin; ++i) {
271           EXPECT_EQ(i, v[i].value_);
272         }
273 
274         // Check the elements after the first element erased.
275         for (int i = erase_begin; i < v.size(); ++i) {
276           EXPECT_EQ(i + erase_len, v[i].value_);
277         }
278 
279         // Check that the elements at the beginning are preserved.
280         for (int i = 0; i < erase_begin; ++i) {
281           EXPECT_EQ(1, counts[i]);
282         }
283 
284         // Check that the erased elements are destroyed
285         for (int i = erase_begin; i < erase_end; ++i) {
286           EXPECT_EQ(0, counts[i]);
287         }
288 
289         // Check that the elements at the end are preserved.
290         for (int i = erase_end; i < len; ++i) {
291           EXPECT_EQ(1, counts[i]);
292         }
293       }
294     }
295   }
296 }
297 
298 struct NoDefaultCtor {
NoDefaultCtor__anon5fdbec6b0111::NoDefaultCtor299   explicit NoDefaultCtor(int) {}
300 };
301 struct NoCopy {
NoCopy__anon5fdbec6b0111::NoCopy302   NoCopy() {}
303   NoCopy(const NoCopy&) = delete;
304 };
305 struct NoAssign {
NoAssign__anon5fdbec6b0111::NoAssign306   NoAssign() {}
307   NoAssign& operator=(const NoAssign&) = delete;
308 };
309 struct MoveOnly {
MoveOnly__anon5fdbec6b0111::MoveOnly310   MoveOnly() {}
311   MoveOnly(MoveOnly&&) = default;
312   MoveOnly& operator=(MoveOnly&&) = default;
313 };
TEST(InlinedVectorTest,NoDefaultCtor)314 TEST(InlinedVectorTest, NoDefaultCtor) {
315   absl::InlinedVector<NoDefaultCtor, 1> v(10, NoDefaultCtor(2));
316   (void)v;
317 }
TEST(InlinedVectorTest,NoCopy)318 TEST(InlinedVectorTest, NoCopy) {
319   absl::InlinedVector<NoCopy, 1> v(10);
320   (void)v;
321 }
TEST(InlinedVectorTest,NoAssign)322 TEST(InlinedVectorTest, NoAssign) {
323   absl::InlinedVector<NoAssign, 1> v(10);
324   (void)v;
325 }
TEST(InlinedVectorTest,MoveOnly)326 TEST(InlinedVectorTest, MoveOnly) {
327   absl::InlinedVector<MoveOnly, 2> v;
328   v.push_back(MoveOnly{});
329   v.push_back(MoveOnly{});
330   v.push_back(MoveOnly{});
331   v.erase(v.begin());
332   v.push_back(MoveOnly{});
333   v.erase(v.begin(), v.begin() + 1);
334   v.insert(v.begin(), MoveOnly{});
335   v.emplace(v.begin());
336   v.emplace(v.begin(), MoveOnly{});
337 }
TEST(InlinedVectorTest,Noexcept)338 TEST(InlinedVectorTest, Noexcept) {
339   EXPECT_TRUE(std::is_nothrow_move_constructible<IntVec>::value);
340   EXPECT_TRUE((std::is_nothrow_move_constructible<
341                absl::InlinedVector<MoveOnly, 2>>::value));
342 
343   struct MoveCanThrow {
344     MoveCanThrow(MoveCanThrow&&) {}
345   };
346   EXPECT_EQ(absl::default_allocator_is_nothrow::value,
347             (std::is_nothrow_move_constructible<
348                 absl::InlinedVector<MoveCanThrow, 2>>::value));
349 }
350 
TEST(InlinedVectorTest,EmplaceBack)351 TEST(InlinedVectorTest, EmplaceBack) {
352   absl::InlinedVector<std::pair<std::string, int>, 1> v;
353 
354   auto& inlined_element = v.emplace_back("answer", 42);
355   EXPECT_EQ(&inlined_element, &v[0]);
356   EXPECT_EQ(inlined_element.first, "answer");
357   EXPECT_EQ(inlined_element.second, 42);
358 
359   auto& allocated_element = v.emplace_back("taxicab", 1729);
360   EXPECT_EQ(&allocated_element, &v[1]);
361   EXPECT_EQ(allocated_element.first, "taxicab");
362   EXPECT_EQ(allocated_element.second, 1729);
363 }
364 
TEST(InlinedVectorTest,ShrinkToFitGrowingVector)365 TEST(InlinedVectorTest, ShrinkToFitGrowingVector) {
366   absl::InlinedVector<std::pair<std::string, int>, 1> v;
367 
368   v.shrink_to_fit();
369   EXPECT_EQ(v.capacity(), 1);
370 
371   v.emplace_back("answer", 42);
372   v.shrink_to_fit();
373   EXPECT_EQ(v.capacity(), 1);
374 
375   v.emplace_back("taxicab", 1729);
376   EXPECT_GE(v.capacity(), 2);
377   v.shrink_to_fit();
378   EXPECT_EQ(v.capacity(), 2);
379 
380   v.reserve(100);
381   EXPECT_GE(v.capacity(), 100);
382   v.shrink_to_fit();
383   EXPECT_EQ(v.capacity(), 2);
384 }
385 
TEST(InlinedVectorTest,ShrinkToFitEdgeCases)386 TEST(InlinedVectorTest, ShrinkToFitEdgeCases) {
387   {
388     absl::InlinedVector<std::pair<std::string, int>, 1> v;
389     v.emplace_back("answer", 42);
390     v.emplace_back("taxicab", 1729);
391     EXPECT_GE(v.capacity(), 2);
392     v.pop_back();
393     v.shrink_to_fit();
394     EXPECT_EQ(v.capacity(), 1);
395     EXPECT_EQ(v[0].first, "answer");
396     EXPECT_EQ(v[0].second, 42);
397   }
398 
399   {
400     absl::InlinedVector<std::string, 2> v(100);
401     v.resize(0);
402     v.shrink_to_fit();
403     EXPECT_EQ(v.capacity(), 2);  // inlined capacity
404   }
405 
406   {
407     absl::InlinedVector<std::string, 2> v(100);
408     v.resize(1);
409     v.shrink_to_fit();
410     EXPECT_EQ(v.capacity(), 2);  // inlined capacity
411   }
412 
413   {
414     absl::InlinedVector<std::string, 2> v(100);
415     v.resize(2);
416     v.shrink_to_fit();
417     EXPECT_EQ(v.capacity(), 2);
418   }
419 
420   {
421     absl::InlinedVector<std::string, 2> v(100);
422     v.resize(3);
423     v.shrink_to_fit();
424     EXPECT_EQ(v.capacity(), 3);
425   }
426 }
427 
TEST(IntVec,Insert)428 TEST(IntVec, Insert) {
429   for (int len = 0; len < 20; len++) {
430     for (int pos = 0; pos <= len; pos++) {
431       {
432         // Single element
433         std::vector<int> std_v;
434         Fill(&std_v, len);
435         IntVec v;
436         Fill(&v, len);
437 
438         std_v.insert(std_v.begin() + pos, 9999);
439         IntVec::iterator it = v.insert(v.cbegin() + pos, 9999);
440         EXPECT_THAT(v, ElementsAreArray(std_v));
441         EXPECT_EQ(it, v.cbegin() + pos);
442       }
443       {
444         // n elements
445         std::vector<int> std_v;
446         Fill(&std_v, len);
447         IntVec v;
448         Fill(&v, len);
449 
450         IntVec::size_type n = 5;
451         std_v.insert(std_v.begin() + pos, n, 9999);
452         IntVec::iterator it = v.insert(v.cbegin() + pos, n, 9999);
453         EXPECT_THAT(v, ElementsAreArray(std_v));
454         EXPECT_EQ(it, v.cbegin() + pos);
455       }
456       {
457         // Iterator range (random access iterator)
458         std::vector<int> std_v;
459         Fill(&std_v, len);
460         IntVec v;
461         Fill(&v, len);
462 
463         const std::vector<int> input = {9999, 8888, 7777};
464         std_v.insert(std_v.begin() + pos, input.cbegin(), input.cend());
465         IntVec::iterator it =
466             v.insert(v.cbegin() + pos, input.cbegin(), input.cend());
467         EXPECT_THAT(v, ElementsAreArray(std_v));
468         EXPECT_EQ(it, v.cbegin() + pos);
469       }
470       {
471         // Iterator range (forward iterator)
472         std::vector<int> std_v;
473         Fill(&std_v, len);
474         IntVec v;
475         Fill(&v, len);
476 
477         const std::forward_list<int> input = {9999, 8888, 7777};
478         std_v.insert(std_v.begin() + pos, input.cbegin(), input.cend());
479         IntVec::iterator it =
480             v.insert(v.cbegin() + pos, input.cbegin(), input.cend());
481         EXPECT_THAT(v, ElementsAreArray(std_v));
482         EXPECT_EQ(it, v.cbegin() + pos);
483       }
484       {
485         // Iterator range (input iterator)
486         std::vector<int> std_v;
487         Fill(&std_v, len);
488         IntVec v;
489         Fill(&v, len);
490 
491         std_v.insert(std_v.begin() + pos, {9999, 8888, 7777});
492         std::istringstream input("9999 8888 7777");
493         IntVec::iterator it =
494             v.insert(v.cbegin() + pos, std::istream_iterator<int>(input),
495                      std::istream_iterator<int>());
496         EXPECT_THAT(v, ElementsAreArray(std_v));
497         EXPECT_EQ(it, v.cbegin() + pos);
498       }
499       {
500         // Initializer list
501         std::vector<int> std_v;
502         Fill(&std_v, len);
503         IntVec v;
504         Fill(&v, len);
505 
506         std_v.insert(std_v.begin() + pos, {9999, 8888});
507         IntVec::iterator it = v.insert(v.cbegin() + pos, {9999, 8888});
508         EXPECT_THAT(v, ElementsAreArray(std_v));
509         EXPECT_EQ(it, v.cbegin() + pos);
510       }
511     }
512   }
513 }
514 
TEST(RefCountedVec,InsertConstructorDestructor)515 TEST(RefCountedVec, InsertConstructorDestructor) {
516   // Make sure the proper construction/destruction happen during insert
517   // operations.
518   for (int len = 0; len < 20; len++) {
519     SCOPED_TRACE(len);
520     for (int pos = 0; pos <= len; pos++) {
521       SCOPED_TRACE(pos);
522       std::vector<int> counts(len, 0);
523       int inserted_count = 0;
524       RefCountedVec v;
525       for (int i = 0; i < len; ++i) {
526         SCOPED_TRACE(i);
527         v.push_back(RefCounted(i, &counts[i]));
528       }
529 
530       EXPECT_THAT(counts, Each(Eq(1)));
531 
532       RefCounted insert_element(9999, &inserted_count);
533       EXPECT_EQ(1, inserted_count);
534       v.insert(v.begin() + pos, insert_element);
535       EXPECT_EQ(2, inserted_count);
536       // Check that the elements at the end are preserved.
537       EXPECT_THAT(counts, Each(Eq(1)));
538       EXPECT_EQ(2, inserted_count);
539     }
540   }
541 }
542 
TEST(IntVec,Resize)543 TEST(IntVec, Resize) {
544   for (int len = 0; len < 20; len++) {
545     IntVec v;
546     Fill(&v, len);
547 
548     // Try resizing up and down by k elements
549     static const int kResizeElem = 1000000;
550     for (int k = 0; k < 10; k++) {
551       // Enlarging resize
552       v.resize(len + k, kResizeElem);
553       EXPECT_EQ(len + k, v.size());
554       EXPECT_LE(len + k, v.capacity());
555       for (int i = 0; i < len + k; i++) {
556         if (i < len) {
557           EXPECT_EQ(i, v[i]);
558         } else {
559           EXPECT_EQ(kResizeElem, v[i]);
560         }
561       }
562 
563       // Shrinking resize
564       v.resize(len, kResizeElem);
565       EXPECT_EQ(len, v.size());
566       EXPECT_LE(len, v.capacity());
567       for (int i = 0; i < len; i++) {
568         EXPECT_EQ(i, v[i]);
569       }
570     }
571   }
572 }
573 
TEST(IntVec,InitWithLength)574 TEST(IntVec, InitWithLength) {
575   for (int len = 0; len < 20; len++) {
576     IntVec v(len, 7);
577     EXPECT_EQ(len, v.size());
578     EXPECT_LE(len, v.capacity());
579     for (int i = 0; i < len; i++) {
580       EXPECT_EQ(7, v[i]);
581     }
582   }
583 }
584 
TEST(IntVec,CopyConstructorAndAssignment)585 TEST(IntVec, CopyConstructorAndAssignment) {
586   for (int len = 0; len < 20; len++) {
587     IntVec v;
588     Fill(&v, len);
589     EXPECT_EQ(len, v.size());
590     EXPECT_LE(len, v.capacity());
591 
592     IntVec v2(v);
593     EXPECT_TRUE(v == v2) << PrintToString(v) << PrintToString(v2);
594 
595     for (int start_len = 0; start_len < 20; start_len++) {
596       IntVec v3;
597       Fill(&v3, start_len, 99);  // Add dummy elements that should go away
598       v3 = v;
599       EXPECT_TRUE(v == v3) << PrintToString(v) << PrintToString(v3);
600     }
601   }
602 }
603 
TEST(IntVec,AliasingCopyAssignment)604 TEST(IntVec, AliasingCopyAssignment) {
605   for (int len = 0; len < 20; ++len) {
606     IntVec original;
607     Fill(&original, len);
608     IntVec dup = original;
609     dup = *&dup;
610     EXPECT_EQ(dup, original);
611   }
612 }
613 
TEST(IntVec,MoveConstructorAndAssignment)614 TEST(IntVec, MoveConstructorAndAssignment) {
615   for (int len = 0; len < 20; len++) {
616     IntVec v_in;
617     const int inlined_capacity = v_in.capacity();
618     Fill(&v_in, len);
619     EXPECT_EQ(len, v_in.size());
620     EXPECT_LE(len, v_in.capacity());
621 
622     {
623       IntVec v_temp(v_in);
624       auto* old_data = v_temp.data();
625       IntVec v_out(std::move(v_temp));
626       EXPECT_TRUE(v_in == v_out) << PrintToString(v_in) << PrintToString(v_out);
627       if (v_in.size() > inlined_capacity) {
628         // Allocation is moved as a whole, data stays in place.
629         EXPECT_TRUE(v_out.data() == old_data);
630       } else {
631         EXPECT_FALSE(v_out.data() == old_data);
632       }
633     }
634     for (int start_len = 0; start_len < 20; start_len++) {
635       IntVec v_out;
636       Fill(&v_out, start_len, 99);  // Add dummy elements that should go away
637       IntVec v_temp(v_in);
638       auto* old_data = v_temp.data();
639       v_out = std::move(v_temp);
640       EXPECT_TRUE(v_in == v_out) << PrintToString(v_in) << PrintToString(v_out);
641       if (v_in.size() > inlined_capacity) {
642         // Allocation is moved as a whole, data stays in place.
643         EXPECT_TRUE(v_out.data() == old_data);
644       } else {
645         EXPECT_FALSE(v_out.data() == old_data);
646       }
647     }
648   }
649 }
650 
651 class NotTriviallyDestructible {
652  public:
NotTriviallyDestructible()653   NotTriviallyDestructible() : p_(new int(1)) {}
NotTriviallyDestructible(int i)654   explicit NotTriviallyDestructible(int i) : p_(new int(i)) {}
655 
NotTriviallyDestructible(const NotTriviallyDestructible & other)656   NotTriviallyDestructible(const NotTriviallyDestructible& other)
657       : p_(new int(*other.p_)) {}
658 
operator =(const NotTriviallyDestructible & other)659   NotTriviallyDestructible& operator=(const NotTriviallyDestructible& other) {
660     p_ = absl::make_unique<int>(*other.p_);
661     return *this;
662   }
663 
operator ==(const NotTriviallyDestructible & other) const664   bool operator==(const NotTriviallyDestructible& other) const {
665     return *p_ == *other.p_;
666   }
667 
668  private:
669   std::unique_ptr<int> p_;
670 };
671 
TEST(AliasingTest,Emplace)672 TEST(AliasingTest, Emplace) {
673   for (int i = 2; i < 20; ++i) {
674     absl::InlinedVector<NotTriviallyDestructible, 10> vec;
675     for (int j = 0; j < i; ++j) {
676       vec.push_back(NotTriviallyDestructible(j));
677     }
678     vec.emplace(vec.begin(), vec[0]);
679     EXPECT_EQ(vec[0], vec[1]);
680     vec.emplace(vec.begin() + i / 2, vec[i / 2]);
681     EXPECT_EQ(vec[i / 2], vec[i / 2 + 1]);
682     vec.emplace(vec.end() - 1, vec.back());
683     EXPECT_EQ(vec[vec.size() - 2], vec.back());
684   }
685 }
686 
TEST(AliasingTest,InsertWithCount)687 TEST(AliasingTest, InsertWithCount) {
688   for (int i = 1; i < 20; ++i) {
689     absl::InlinedVector<NotTriviallyDestructible, 10> vec;
690     for (int j = 0; j < i; ++j) {
691       vec.push_back(NotTriviallyDestructible(j));
692     }
693     for (int n = 0; n < 5; ++n) {
694       // We use back where we can because it's guaranteed to become invalidated
695       vec.insert(vec.begin(), n, vec.back());
696       auto b = vec.begin();
697       EXPECT_TRUE(
698           std::all_of(b, b + n, [&vec](const NotTriviallyDestructible& x) {
699             return x == vec.back();
700           }));
701 
702       auto m_idx = vec.size() / 2;
703       vec.insert(vec.begin() + m_idx, n, vec.back());
704       auto m = vec.begin() + m_idx;
705       EXPECT_TRUE(
706           std::all_of(m, m + n, [&vec](const NotTriviallyDestructible& x) {
707             return x == vec.back();
708           }));
709 
710       // We want distinct values so the equality test is meaningful,
711       // vec[vec.size() - 1] is also almost always invalidated.
712       auto old_e = vec.size() - 1;
713       auto val = vec[old_e];
714       vec.insert(vec.end(), n, vec[old_e]);
715       auto e = vec.begin() + old_e;
716       EXPECT_TRUE(std::all_of(
717           e, e + n,
718           [&val](const NotTriviallyDestructible& x) { return x == val; }));
719     }
720   }
721 }
722 
TEST(OverheadTest,Storage)723 TEST(OverheadTest, Storage) {
724   // Check for size overhead.
725   // In particular, ensure that std::allocator doesn't cost anything to store.
726   // The union should be absorbing some of the allocation bookkeeping overhead
727   // in the larger vectors, leaving only the size_ field as overhead.
728   EXPECT_EQ(2 * sizeof(int*),
729             sizeof(absl::InlinedVector<int*, 1>) - 1 * sizeof(int*));
730   EXPECT_EQ(1 * sizeof(int*),
731             sizeof(absl::InlinedVector<int*, 2>) - 2 * sizeof(int*));
732   EXPECT_EQ(1 * sizeof(int*),
733             sizeof(absl::InlinedVector<int*, 3>) - 3 * sizeof(int*));
734   EXPECT_EQ(1 * sizeof(int*),
735             sizeof(absl::InlinedVector<int*, 4>) - 4 * sizeof(int*));
736   EXPECT_EQ(1 * sizeof(int*),
737             sizeof(absl::InlinedVector<int*, 5>) - 5 * sizeof(int*));
738   EXPECT_EQ(1 * sizeof(int*),
739             sizeof(absl::InlinedVector<int*, 6>) - 6 * sizeof(int*));
740   EXPECT_EQ(1 * sizeof(int*),
741             sizeof(absl::InlinedVector<int*, 7>) - 7 * sizeof(int*));
742   EXPECT_EQ(1 * sizeof(int*),
743             sizeof(absl::InlinedVector<int*, 8>) - 8 * sizeof(int*));
744 }
745 
TEST(IntVec,Clear)746 TEST(IntVec, Clear) {
747   for (int len = 0; len < 20; len++) {
748     SCOPED_TRACE(len);
749     IntVec v;
750     Fill(&v, len);
751     v.clear();
752     EXPECT_EQ(0, v.size());
753     EXPECT_EQ(v.begin(), v.end());
754   }
755 }
756 
TEST(IntVec,Reserve)757 TEST(IntVec, Reserve) {
758   for (int len = 0; len < 20; len++) {
759     IntVec v;
760     Fill(&v, len);
761 
762     for (int newlen = 0; newlen < 100; newlen++) {
763       const int* start_rep = v.data();
764       v.reserve(newlen);
765       const int* final_rep = v.data();
766       if (newlen <= len) {
767         EXPECT_EQ(start_rep, final_rep);
768       }
769       EXPECT_LE(newlen, v.capacity());
770 
771       // Filling up to newlen should not change rep
772       while (v.size() < newlen) {
773         v.push_back(0);
774       }
775       EXPECT_EQ(final_rep, v.data());
776     }
777   }
778 }
779 
TEST(StringVec,SelfRefPushBack)780 TEST(StringVec, SelfRefPushBack) {
781   std::vector<std::string> std_v;
782   absl::InlinedVector<std::string, 4> v;
783   const std::string s = "A quite long std::string to ensure heap.";
784   std_v.push_back(s);
785   v.push_back(s);
786   for (int i = 0; i < 20; ++i) {
787     EXPECT_THAT(v, ElementsAreArray(std_v));
788 
789     v.push_back(v.back());
790     std_v.push_back(std_v.back());
791   }
792   EXPECT_THAT(v, ElementsAreArray(std_v));
793 }
794 
TEST(StringVec,SelfRefPushBackWithMove)795 TEST(StringVec, SelfRefPushBackWithMove) {
796   std::vector<std::string> std_v;
797   absl::InlinedVector<std::string, 4> v;
798   const std::string s = "A quite long std::string to ensure heap.";
799   std_v.push_back(s);
800   v.push_back(s);
801   for (int i = 0; i < 20; ++i) {
802     EXPECT_EQ(v.back(), std_v.back());
803 
804     v.push_back(std::move(v.back()));
805     std_v.push_back(std::move(std_v.back()));
806   }
807   EXPECT_EQ(v.back(), std_v.back());
808 }
809 
TEST(StringVec,SelfMove)810 TEST(StringVec, SelfMove) {
811   const std::string s = "A quite long std::string to ensure heap.";
812   for (int len = 0; len < 20; len++) {
813     SCOPED_TRACE(len);
814     absl::InlinedVector<std::string, 8> v;
815     for (int i = 0; i < len; ++i) {
816       SCOPED_TRACE(i);
817       v.push_back(s);
818     }
819     // Indirection necessary to avoid compiler warning.
820     v = std::move(*(&v));
821     // Ensure that the inlined vector is still in a valid state by copying it.
822     // We don't expect specific contents since a self-move results in an
823     // unspecified valid state.
824     std::vector<std::string> copy(v.begin(), v.end());
825   }
826 }
827 
TEST(IntVec,Swap)828 TEST(IntVec, Swap) {
829   for (int l1 = 0; l1 < 20; l1++) {
830     SCOPED_TRACE(l1);
831     for (int l2 = 0; l2 < 20; l2++) {
832       SCOPED_TRACE(l2);
833       IntVec a = Fill(l1, 0);
834       IntVec b = Fill(l2, 100);
835       {
836         using std::swap;
837         swap(a, b);
838       }
839       EXPECT_EQ(l1, b.size());
840       EXPECT_EQ(l2, a.size());
841       for (int i = 0; i < l1; i++) {
842         SCOPED_TRACE(i);
843         EXPECT_EQ(i, b[i]);
844       }
845       for (int i = 0; i < l2; i++) {
846         SCOPED_TRACE(i);
847         EXPECT_EQ(100 + i, a[i]);
848       }
849     }
850   }
851 }
852 
TYPED_TEST_P(InstanceTest,Swap)853 TYPED_TEST_P(InstanceTest, Swap) {
854   using Instance = TypeParam;
855   using InstanceVec = absl::InlinedVector<Instance, 8>;
856   for (int l1 = 0; l1 < 20; l1++) {
857     SCOPED_TRACE(l1);
858     for (int l2 = 0; l2 < 20; l2++) {
859       SCOPED_TRACE(l2);
860       InstanceTracker tracker;
861       InstanceVec a, b;
862       const size_t inlined_capacity = a.capacity();
863       auto min_len = std::min(l1, l2);
864       auto max_len = std::max(l1, l2);
865       for (int i = 0; i < l1; i++) a.push_back(Instance(i));
866       for (int i = 0; i < l2; i++) b.push_back(Instance(100 + i));
867       EXPECT_EQ(tracker.instances(), l1 + l2);
868       tracker.ResetCopiesMovesSwaps();
869       {
870         using std::swap;
871         swap(a, b);
872       }
873       EXPECT_EQ(tracker.instances(), l1 + l2);
874       if (a.size() > inlined_capacity && b.size() > inlined_capacity) {
875         EXPECT_EQ(tracker.swaps(), 0);  // Allocations are swapped.
876         EXPECT_EQ(tracker.moves(), 0);
877       } else if (a.size() <= inlined_capacity && b.size() <= inlined_capacity) {
878         EXPECT_EQ(tracker.swaps(), min_len);
879         EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()),
880                   max_len - min_len);
881       } else {
882         // One is allocated and the other isn't. The allocation is transferred
883         // without copying elements, and the inlined instances are copied/moved.
884         EXPECT_EQ(tracker.swaps(), 0);
885         EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()),
886                   min_len);
887       }
888 
889       EXPECT_EQ(l1, b.size());
890       EXPECT_EQ(l2, a.size());
891       for (int i = 0; i < l1; i++) {
892         EXPECT_EQ(i, b[i].value());
893       }
894       for (int i = 0; i < l2; i++) {
895         EXPECT_EQ(100 + i, a[i].value());
896       }
897     }
898   }
899 }
900 
TEST(IntVec,EqualAndNotEqual)901 TEST(IntVec, EqualAndNotEqual) {
902   IntVec a, b;
903   EXPECT_TRUE(a == b);
904   EXPECT_FALSE(a != b);
905 
906   a.push_back(3);
907   EXPECT_FALSE(a == b);
908   EXPECT_TRUE(a != b);
909 
910   b.push_back(3);
911   EXPECT_TRUE(a == b);
912   EXPECT_FALSE(a != b);
913 
914   b.push_back(7);
915   EXPECT_FALSE(a == b);
916   EXPECT_TRUE(a != b);
917 
918   a.push_back(6);
919   EXPECT_FALSE(a == b);
920   EXPECT_TRUE(a != b);
921 
922   a.clear();
923   b.clear();
924   for (int i = 0; i < 100; i++) {
925     a.push_back(i);
926     b.push_back(i);
927     EXPECT_TRUE(a == b);
928     EXPECT_FALSE(a != b);
929 
930     b[i] = b[i] + 1;
931     EXPECT_FALSE(a == b);
932     EXPECT_TRUE(a != b);
933 
934     b[i] = b[i] - 1;  // Back to before
935     EXPECT_TRUE(a == b);
936     EXPECT_FALSE(a != b);
937   }
938 }
939 
TEST(IntVec,RelationalOps)940 TEST(IntVec, RelationalOps) {
941   IntVec a, b;
942   EXPECT_FALSE(a < b);
943   EXPECT_FALSE(b < a);
944   EXPECT_FALSE(a > b);
945   EXPECT_FALSE(b > a);
946   EXPECT_TRUE(a <= b);
947   EXPECT_TRUE(b <= a);
948   EXPECT_TRUE(a >= b);
949   EXPECT_TRUE(b >= a);
950   b.push_back(3);
951   EXPECT_TRUE(a < b);
952   EXPECT_FALSE(b < a);
953   EXPECT_FALSE(a > b);
954   EXPECT_TRUE(b > a);
955   EXPECT_TRUE(a <= b);
956   EXPECT_FALSE(b <= a);
957   EXPECT_FALSE(a >= b);
958   EXPECT_TRUE(b >= a);
959 }
960 
TYPED_TEST_P(InstanceTest,CountConstructorsDestructors)961 TYPED_TEST_P(InstanceTest, CountConstructorsDestructors) {
962   using Instance = TypeParam;
963   using InstanceVec = absl::InlinedVector<Instance, 8>;
964   InstanceTracker tracker;
965   for (int len = 0; len < 20; len++) {
966     SCOPED_TRACE(len);
967     tracker.ResetCopiesMovesSwaps();
968 
969     InstanceVec v;
970     const size_t inlined_capacity = v.capacity();
971     for (int i = 0; i < len; i++) {
972       v.push_back(Instance(i));
973     }
974     EXPECT_EQ(tracker.instances(), len);
975     EXPECT_GE(tracker.copies() + tracker.moves(),
976               len);  // More due to reallocation.
977     tracker.ResetCopiesMovesSwaps();
978 
979     // Enlarging resize() must construct some objects
980     tracker.ResetCopiesMovesSwaps();
981     v.resize(len + 10, Instance(100));
982     EXPECT_EQ(tracker.instances(), len + 10);
983     if (len <= inlined_capacity && len + 10 > inlined_capacity) {
984       EXPECT_EQ(tracker.copies() + tracker.moves(), 10 + len);
985     } else {
986       // Only specify a minimum number of copies + moves. We don't want to
987       // depend on the reallocation policy here.
988       EXPECT_GE(tracker.copies() + tracker.moves(),
989                 10);  // More due to reallocation.
990     }
991 
992     // Shrinking resize() must destroy some objects
993     tracker.ResetCopiesMovesSwaps();
994     v.resize(len, Instance(100));
995     EXPECT_EQ(tracker.instances(), len);
996     EXPECT_EQ(tracker.copies(), 0);
997     EXPECT_EQ(tracker.moves(), 0);
998 
999     // reserve() must not increase the number of initialized objects
1000     SCOPED_TRACE("reserve");
1001     v.reserve(len + 1000);
1002     EXPECT_EQ(tracker.instances(), len);
1003     EXPECT_EQ(tracker.copies() + tracker.moves(), len);
1004 
1005     // pop_back() and erase() must destroy one object
1006     if (len > 0) {
1007       tracker.ResetCopiesMovesSwaps();
1008       v.pop_back();
1009       EXPECT_EQ(tracker.instances(), len - 1);
1010       EXPECT_EQ(tracker.copies(), 0);
1011       EXPECT_EQ(tracker.moves(), 0);
1012 
1013       if (!v.empty()) {
1014         tracker.ResetCopiesMovesSwaps();
1015         v.erase(v.begin());
1016         EXPECT_EQ(tracker.instances(), len - 2);
1017         EXPECT_EQ(tracker.copies() + tracker.moves(), len - 2);
1018       }
1019     }
1020 
1021     tracker.ResetCopiesMovesSwaps();
1022     int instances_before_empty_erase = tracker.instances();
1023     v.erase(v.begin(), v.begin());
1024     EXPECT_EQ(tracker.instances(), instances_before_empty_erase);
1025     EXPECT_EQ(tracker.copies() + tracker.moves(), 0);
1026   }
1027 }
1028 
TYPED_TEST_P(InstanceTest,CountConstructorsDestructorsOnCopyConstruction)1029 TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnCopyConstruction) {
1030   using Instance = TypeParam;
1031   using InstanceVec = absl::InlinedVector<Instance, 8>;
1032   InstanceTracker tracker;
1033   for (int len = 0; len < 20; len++) {
1034     SCOPED_TRACE(len);
1035     tracker.ResetCopiesMovesSwaps();
1036 
1037     InstanceVec v;
1038     for (int i = 0; i < len; i++) {
1039       v.push_back(Instance(i));
1040     }
1041     EXPECT_EQ(tracker.instances(), len);
1042     EXPECT_GE(tracker.copies() + tracker.moves(),
1043               len);  // More due to reallocation.
1044     tracker.ResetCopiesMovesSwaps();
1045     {  // Copy constructor should create 'len' more instances.
1046       InstanceVec v_copy(v);
1047       EXPECT_EQ(tracker.instances(), len + len);
1048       EXPECT_EQ(tracker.copies(), len);
1049       EXPECT_EQ(tracker.moves(), 0);
1050     }
1051     EXPECT_EQ(tracker.instances(), len);
1052   }
1053 }
1054 
TYPED_TEST_P(InstanceTest,CountConstructorsDestructorsOnMoveConstruction)1055 TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveConstruction) {
1056   using Instance = TypeParam;
1057   using InstanceVec = absl::InlinedVector<Instance, 8>;
1058   InstanceTracker tracker;
1059   for (int len = 0; len < 20; len++) {
1060     SCOPED_TRACE(len);
1061     tracker.ResetCopiesMovesSwaps();
1062 
1063     InstanceVec v;
1064     const size_t inlined_capacity = v.capacity();
1065     for (int i = 0; i < len; i++) {
1066       v.push_back(Instance(i));
1067     }
1068     EXPECT_EQ(tracker.instances(), len);
1069     EXPECT_GE(tracker.copies() + tracker.moves(),
1070               len);  // More due to reallocation.
1071     tracker.ResetCopiesMovesSwaps();
1072     {
1073       InstanceVec v_copy(std::move(v));
1074       if (len > inlined_capacity) {
1075         // Allocation is moved as a whole.
1076         EXPECT_EQ(tracker.instances(), len);
1077         EXPECT_EQ(tracker.live_instances(), len);
1078         // Tests an implementation detail, don't rely on this in your code.
1079         EXPECT_EQ(v.size(), 0);  // NOLINT misc-use-after-move
1080         EXPECT_EQ(tracker.copies(), 0);
1081         EXPECT_EQ(tracker.moves(), 0);
1082       } else {
1083         EXPECT_EQ(tracker.instances(), len + len);
1084         if (Instance::supports_move()) {
1085           EXPECT_EQ(tracker.live_instances(), len);
1086           EXPECT_EQ(tracker.copies(), 0);
1087           EXPECT_EQ(tracker.moves(), len);
1088         } else {
1089           EXPECT_EQ(tracker.live_instances(), len + len);
1090           EXPECT_EQ(tracker.copies(), len);
1091           EXPECT_EQ(tracker.moves(), 0);
1092         }
1093       }
1094       EXPECT_EQ(tracker.swaps(), 0);
1095     }
1096   }
1097 }
1098 
TYPED_TEST_P(InstanceTest,CountConstructorsDestructorsOnAssignment)1099 TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnAssignment) {
1100   using Instance = TypeParam;
1101   using InstanceVec = absl::InlinedVector<Instance, 8>;
1102   InstanceTracker tracker;
1103   for (int len = 0; len < 20; len++) {
1104     SCOPED_TRACE(len);
1105     for (int longorshort = 0; longorshort <= 1; ++longorshort) {
1106       SCOPED_TRACE(longorshort);
1107       tracker.ResetCopiesMovesSwaps();
1108 
1109       InstanceVec longer, shorter;
1110       for (int i = 0; i < len; i++) {
1111         longer.push_back(Instance(i));
1112         shorter.push_back(Instance(i));
1113       }
1114       longer.push_back(Instance(len));
1115       EXPECT_EQ(tracker.instances(), len + len + 1);
1116       EXPECT_GE(tracker.copies() + tracker.moves(),
1117                 len + len + 1);  // More due to reallocation.
1118 
1119       tracker.ResetCopiesMovesSwaps();
1120       if (longorshort) {
1121         shorter = longer;
1122         EXPECT_EQ(tracker.instances(), (len + 1) + (len + 1));
1123         EXPECT_GE(tracker.copies() + tracker.moves(),
1124                   len + 1);  // More due to reallocation.
1125       } else {
1126         longer = shorter;
1127         EXPECT_EQ(tracker.instances(), len + len);
1128         EXPECT_EQ(tracker.copies() + tracker.moves(), len);
1129       }
1130     }
1131   }
1132 }
1133 
TYPED_TEST_P(InstanceTest,CountConstructorsDestructorsOnMoveAssignment)1134 TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveAssignment) {
1135   using Instance = TypeParam;
1136   using InstanceVec = absl::InlinedVector<Instance, 8>;
1137   InstanceTracker tracker;
1138   for (int len = 0; len < 20; len++) {
1139     SCOPED_TRACE(len);
1140     for (int longorshort = 0; longorshort <= 1; ++longorshort) {
1141       SCOPED_TRACE(longorshort);
1142       tracker.ResetCopiesMovesSwaps();
1143 
1144       InstanceVec longer, shorter;
1145       const int inlined_capacity = longer.capacity();
1146       for (int i = 0; i < len; i++) {
1147         longer.push_back(Instance(i));
1148         shorter.push_back(Instance(i));
1149       }
1150       longer.push_back(Instance(len));
1151       EXPECT_EQ(tracker.instances(), len + len + 1);
1152       EXPECT_GE(tracker.copies() + tracker.moves(),
1153                 len + len + 1);  // More due to reallocation.
1154 
1155       tracker.ResetCopiesMovesSwaps();
1156       int src_len;
1157       if (longorshort) {
1158         src_len = len + 1;
1159         shorter = std::move(longer);
1160       } else {
1161         src_len = len;
1162         longer = std::move(shorter);
1163       }
1164       if (src_len > inlined_capacity) {
1165         // Allocation moved as a whole.
1166         EXPECT_EQ(tracker.instances(), src_len);
1167         EXPECT_EQ(tracker.live_instances(), src_len);
1168         EXPECT_EQ(tracker.copies(), 0);
1169         EXPECT_EQ(tracker.moves(), 0);
1170       } else {
1171         // Elements are all copied.
1172         EXPECT_EQ(tracker.instances(), src_len + src_len);
1173         if (Instance::supports_move()) {
1174           EXPECT_EQ(tracker.copies(), 0);
1175           EXPECT_EQ(tracker.moves(), src_len);
1176           EXPECT_EQ(tracker.live_instances(), src_len);
1177         } else {
1178           EXPECT_EQ(tracker.copies(), src_len);
1179           EXPECT_EQ(tracker.moves(), 0);
1180           EXPECT_EQ(tracker.live_instances(), src_len + src_len);
1181         }
1182       }
1183       EXPECT_EQ(tracker.swaps(), 0);
1184     }
1185   }
1186 }
1187 
TEST(CountElemAssign,SimpleTypeWithInlineBacking)1188 TEST(CountElemAssign, SimpleTypeWithInlineBacking) {
1189   for (size_t original_size = 0; original_size <= 5; ++original_size) {
1190     SCOPED_TRACE(original_size);
1191     // Original contents are [12345, 12345, ...]
1192     std::vector<int> original_contents(original_size, 12345);
1193 
1194     absl::InlinedVector<int, 2> v(original_contents.begin(),
1195                                   original_contents.end());
1196     v.assign(2, 123);
1197     EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(123, 123)));
1198     if (original_size <= 2) {
1199       // If the original had inline backing, it should stay inline.
1200       EXPECT_EQ(2, v.capacity());
1201     }
1202   }
1203 }
1204 
TEST(CountElemAssign,SimpleTypeWithAllocation)1205 TEST(CountElemAssign, SimpleTypeWithAllocation) {
1206   for (size_t original_size = 0; original_size <= 5; ++original_size) {
1207     SCOPED_TRACE(original_size);
1208     // Original contents are [12345, 12345, ...]
1209     std::vector<int> original_contents(original_size, 12345);
1210 
1211     absl::InlinedVector<int, 2> v(original_contents.begin(),
1212                                   original_contents.end());
1213     v.assign(3, 123);
1214     EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(123, 123, 123)));
1215     EXPECT_LE(v.size(), v.capacity());
1216   }
1217 }
1218 
TYPED_TEST_P(InstanceTest,CountElemAssignInlineBacking)1219 TYPED_TEST_P(InstanceTest, CountElemAssignInlineBacking) {
1220   using Instance = TypeParam;
1221   for (size_t original_size = 0; original_size <= 5; ++original_size) {
1222     SCOPED_TRACE(original_size);
1223     // Original contents are [12345, 12345, ...]
1224     std::vector<Instance> original_contents(original_size, Instance(12345));
1225 
1226     absl::InlinedVector<Instance, 2> v(original_contents.begin(),
1227                                        original_contents.end());
1228     v.assign(2, Instance(123));
1229     EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(ValueIs(123), ValueIs(123))));
1230     if (original_size <= 2) {
1231       // If the original had inline backing, it should stay inline.
1232       EXPECT_EQ(2, v.capacity());
1233     }
1234   }
1235 }
1236 
1237 template <typename Instance>
InstanceCountElemAssignWithAllocationTest()1238 void InstanceCountElemAssignWithAllocationTest() {
1239   for (size_t original_size = 0; original_size <= 5; ++original_size) {
1240     SCOPED_TRACE(original_size);
1241     // Original contents are [12345, 12345, ...]
1242     std::vector<Instance> original_contents(original_size, Instance(12345));
1243 
1244     absl::InlinedVector<Instance, 2> v(original_contents.begin(),
1245                                        original_contents.end());
1246     v.assign(3, Instance(123));
1247     EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(ValueIs(123), ValueIs(123),
1248                                                 ValueIs(123))));
1249     EXPECT_LE(v.size(), v.capacity());
1250   }
1251 }
TEST(CountElemAssign,WithAllocationCopyableInstance)1252 TEST(CountElemAssign, WithAllocationCopyableInstance) {
1253   InstanceCountElemAssignWithAllocationTest<CopyableOnlyInstance>();
1254 }
TEST(CountElemAssign,WithAllocationCopyableMovableInstance)1255 TEST(CountElemAssign, WithAllocationCopyableMovableInstance) {
1256   InstanceCountElemAssignWithAllocationTest<CopyableMovableInstance>();
1257 }
1258 
TEST(RangedConstructor,SimpleType)1259 TEST(RangedConstructor, SimpleType) {
1260   std::vector<int> source_v = {4, 5, 6};
1261   // First try to fit in inline backing
1262   absl::InlinedVector<int, 4> v(source_v.begin(), source_v.end());
1263   EXPECT_EQ(3, v.size());
1264   EXPECT_EQ(4, v.capacity());  // Indication that we're still on inlined storage
1265   EXPECT_EQ(4, v[0]);
1266   EXPECT_EQ(5, v[1]);
1267   EXPECT_EQ(6, v[2]);
1268 
1269   // Now, force a re-allocate
1270   absl::InlinedVector<int, 2> realloc_v(source_v.begin(), source_v.end());
1271   EXPECT_EQ(3, realloc_v.size());
1272   EXPECT_LT(2, realloc_v.capacity());
1273   EXPECT_EQ(4, realloc_v[0]);
1274   EXPECT_EQ(5, realloc_v[1]);
1275   EXPECT_EQ(6, realloc_v[2]);
1276 }
1277 
1278 // Test for ranged constructors using Instance as the element type and
1279 // SourceContainer as the source container type.
1280 template <typename Instance, typename SourceContainer, int inlined_capacity>
InstanceRangedConstructorTestForContainer()1281 void InstanceRangedConstructorTestForContainer() {
1282   InstanceTracker tracker;
1283   SourceContainer source_v = {Instance(0), Instance(1)};
1284   tracker.ResetCopiesMovesSwaps();
1285   absl::InlinedVector<Instance, inlined_capacity> v(source_v.begin(),
1286                                                     source_v.end());
1287   EXPECT_EQ(2, v.size());
1288   EXPECT_LT(1, v.capacity());
1289   EXPECT_EQ(0, v[0].value());
1290   EXPECT_EQ(1, v[1].value());
1291   EXPECT_EQ(tracker.copies(), 2);
1292   EXPECT_EQ(tracker.moves(), 0);
1293 }
1294 
1295 template <typename Instance, int inlined_capacity>
InstanceRangedConstructorTestWithCapacity()1296 void InstanceRangedConstructorTestWithCapacity() {
1297   // Test with const and non-const, random access and non-random-access sources.
1298   // TODO(bsamwel): Test with an input iterator source.
1299   {
1300     SCOPED_TRACE("std::list");
1301     InstanceRangedConstructorTestForContainer<Instance, std::list<Instance>,
1302                                               inlined_capacity>();
1303     {
1304       SCOPED_TRACE("const std::list");
1305       InstanceRangedConstructorTestForContainer<
1306           Instance, const std::list<Instance>, inlined_capacity>();
1307     }
1308     {
1309       SCOPED_TRACE("std::vector");
1310       InstanceRangedConstructorTestForContainer<Instance, std::vector<Instance>,
1311                                                 inlined_capacity>();
1312     }
1313     {
1314       SCOPED_TRACE("const std::vector");
1315       InstanceRangedConstructorTestForContainer<
1316           Instance, const std::vector<Instance>, inlined_capacity>();
1317     }
1318   }
1319 }
1320 
TYPED_TEST_P(InstanceTest,RangedConstructor)1321 TYPED_TEST_P(InstanceTest, RangedConstructor) {
1322   using Instance = TypeParam;
1323   SCOPED_TRACE("capacity=1");
1324   InstanceRangedConstructorTestWithCapacity<Instance, 1>();
1325   SCOPED_TRACE("capacity=2");
1326   InstanceRangedConstructorTestWithCapacity<Instance, 2>();
1327 }
1328 
TEST(RangedConstructor,ElementsAreConstructed)1329 TEST(RangedConstructor, ElementsAreConstructed) {
1330   std::vector<std::string> source_v = {"cat", "dog"};
1331 
1332   // Force expansion and re-allocation of v.  Ensures that when the vector is
1333   // expanded that new elements are constructed.
1334   absl::InlinedVector<std::string, 1> v(source_v.begin(), source_v.end());
1335   EXPECT_EQ("cat", v[0]);
1336   EXPECT_EQ("dog", v[1]);
1337 }
1338 
TEST(RangedAssign,SimpleType)1339 TEST(RangedAssign, SimpleType) {
1340   // Test for all combinations of original sizes (empty and non-empty inline,
1341   // and out of line) and target sizes.
1342   for (size_t original_size = 0; original_size <= 5; ++original_size) {
1343     SCOPED_TRACE(original_size);
1344     // Original contents are [12345, 12345, ...]
1345     std::vector<int> original_contents(original_size, 12345);
1346 
1347     for (size_t target_size = 0; target_size <= 5; ++target_size) {
1348       SCOPED_TRACE(target_size);
1349 
1350       // New contents are [3, 4, ...]
1351       std::vector<int> new_contents;
1352       for (size_t i = 0; i < target_size; ++i) {
1353         new_contents.push_back(i + 3);
1354       }
1355 
1356       absl::InlinedVector<int, 3> v(original_contents.begin(),
1357                                     original_contents.end());
1358       v.assign(new_contents.begin(), new_contents.end());
1359 
1360       EXPECT_EQ(new_contents.size(), v.size());
1361       EXPECT_LE(new_contents.size(), v.capacity());
1362       if (target_size <= 3 && original_size <= 3) {
1363         // Storage should stay inline when target size is small.
1364         EXPECT_EQ(3, v.capacity());
1365       }
1366       EXPECT_THAT(v, ElementsAreArray(new_contents));
1367     }
1368   }
1369 }
1370 
1371 // Returns true if lhs and rhs have the same value.
1372 template <typename Instance>
InstanceValuesEqual(const Instance & lhs,const Instance & rhs)1373 static bool InstanceValuesEqual(const Instance& lhs, const Instance& rhs) {
1374   return lhs.value() == rhs.value();
1375 }
1376 
1377 // Test for ranged assign() using Instance as the element type and
1378 // SourceContainer as the source container type.
1379 template <typename Instance, typename SourceContainer>
InstanceRangedAssignTestForContainer()1380 void InstanceRangedAssignTestForContainer() {
1381   // Test for all combinations of original sizes (empty and non-empty inline,
1382   // and out of line) and target sizes.
1383   for (size_t original_size = 0; original_size <= 5; ++original_size) {
1384     SCOPED_TRACE(original_size);
1385     // Original contents are [12345, 12345, ...]
1386     std::vector<Instance> original_contents(original_size, Instance(12345));
1387 
1388     for (size_t target_size = 0; target_size <= 5; ++target_size) {
1389       SCOPED_TRACE(target_size);
1390 
1391       // New contents are [3, 4, ...]
1392       // Generate data using a non-const container, because SourceContainer
1393       // itself may be const.
1394       // TODO(bsamwel): Test with an input iterator.
1395       std::vector<Instance> new_contents_in;
1396       for (size_t i = 0; i < target_size; ++i) {
1397         new_contents_in.push_back(Instance(i + 3));
1398       }
1399       SourceContainer new_contents(new_contents_in.begin(),
1400                                    new_contents_in.end());
1401 
1402       absl::InlinedVector<Instance, 3> v(original_contents.begin(),
1403                                          original_contents.end());
1404       v.assign(new_contents.begin(), new_contents.end());
1405 
1406       EXPECT_EQ(new_contents.size(), v.size());
1407       EXPECT_LE(new_contents.size(), v.capacity());
1408       if (target_size <= 3 && original_size <= 3) {
1409         // Storage should stay inline when target size is small.
1410         EXPECT_EQ(3, v.capacity());
1411       }
1412       EXPECT_TRUE(std::equal(v.begin(), v.end(), new_contents.begin(),
1413                              InstanceValuesEqual<Instance>));
1414     }
1415   }
1416 }
1417 
TYPED_TEST_P(InstanceTest,RangedAssign)1418 TYPED_TEST_P(InstanceTest, RangedAssign) {
1419   using Instance = TypeParam;
1420   // Test with const and non-const, random access and non-random-access sources.
1421   // TODO(bsamwel): Test with an input iterator source.
1422   SCOPED_TRACE("std::list");
1423   InstanceRangedAssignTestForContainer<Instance, std::list<Instance>>();
1424   SCOPED_TRACE("const std::list");
1425   InstanceRangedAssignTestForContainer<Instance, const std::list<Instance>>();
1426   SCOPED_TRACE("std::vector");
1427   InstanceRangedAssignTestForContainer<Instance, std::vector<Instance>>();
1428   SCOPED_TRACE("const std::vector");
1429   InstanceRangedAssignTestForContainer<Instance, const std::vector<Instance>>();
1430 }
1431 
TEST(InitializerListConstructor,SimpleTypeWithInlineBacking)1432 TEST(InitializerListConstructor, SimpleTypeWithInlineBacking) {
1433   EXPECT_THAT((absl::InlinedVector<int, 4>{4, 5, 6}),
1434               AllOf(SizeIs(3), CapacityIs(4), ElementsAre(4, 5, 6)));
1435 }
1436 
TEST(InitializerListConstructor,SimpleTypeWithReallocationRequired)1437 TEST(InitializerListConstructor, SimpleTypeWithReallocationRequired) {
1438   EXPECT_THAT((absl::InlinedVector<int, 2>{4, 5, 6}),
1439               AllOf(SizeIs(3), CapacityIs(Gt(2)), ElementsAre(4, 5, 6)));
1440 }
1441 
TEST(InitializerListConstructor,DisparateTypesInList)1442 TEST(InitializerListConstructor, DisparateTypesInList) {
1443   EXPECT_THAT((absl::InlinedVector<int, 2>{-7, 8ULL}), ElementsAre(-7, 8));
1444 
1445   EXPECT_THAT((absl::InlinedVector<std::string, 2>{"foo", std::string("bar")}),
1446               ElementsAre("foo", "bar"));
1447 }
1448 
TEST(InitializerListConstructor,ComplexTypeWithInlineBacking)1449 TEST(InitializerListConstructor, ComplexTypeWithInlineBacking) {
1450   EXPECT_THAT((absl::InlinedVector<CopyableMovableInstance, 1>{
1451                   CopyableMovableInstance(0)}),
1452               AllOf(SizeIs(1), CapacityIs(1), ElementsAre(ValueIs(0))));
1453 }
1454 
TEST(InitializerListConstructor,ComplexTypeWithReallocationRequired)1455 TEST(InitializerListConstructor, ComplexTypeWithReallocationRequired) {
1456   EXPECT_THAT(
1457       (absl::InlinedVector<CopyableMovableInstance, 1>{
1458           CopyableMovableInstance(0), CopyableMovableInstance(1)}),
1459       AllOf(SizeIs(2), CapacityIs(Gt(1)), ElementsAre(ValueIs(0), ValueIs(1))));
1460 }
1461 
TEST(InitializerListAssign,SimpleTypeFitsInlineBacking)1462 TEST(InitializerListAssign, SimpleTypeFitsInlineBacking) {
1463   for (size_t original_size = 0; original_size <= 4; ++original_size) {
1464     SCOPED_TRACE(original_size);
1465 
1466     absl::InlinedVector<int, 2> v1(original_size, 12345);
1467     const size_t original_capacity_v1 = v1.capacity();
1468     v1.assign({3});
1469     EXPECT_THAT(
1470         v1, AllOf(SizeIs(1), CapacityIs(original_capacity_v1), ElementsAre(3)));
1471 
1472     absl::InlinedVector<int, 2> v2(original_size, 12345);
1473     const size_t original_capacity_v2 = v2.capacity();
1474     v2 = {3};
1475     EXPECT_THAT(
1476         v2, AllOf(SizeIs(1), CapacityIs(original_capacity_v2), ElementsAre(3)));
1477   }
1478 }
1479 
TEST(InitializerListAssign,SimpleTypeDoesNotFitInlineBacking)1480 TEST(InitializerListAssign, SimpleTypeDoesNotFitInlineBacking) {
1481   for (size_t original_size = 0; original_size <= 4; ++original_size) {
1482     SCOPED_TRACE(original_size);
1483     absl::InlinedVector<int, 2> v1(original_size, 12345);
1484     v1.assign({3, 4, 5});
1485     EXPECT_THAT(v1, AllOf(SizeIs(3), ElementsAre(3, 4, 5)));
1486     EXPECT_LE(3, v1.capacity());
1487 
1488     absl::InlinedVector<int, 2> v2(original_size, 12345);
1489     v2 = {3, 4, 5};
1490     EXPECT_THAT(v2, AllOf(SizeIs(3), ElementsAre(3, 4, 5)));
1491     EXPECT_LE(3, v2.capacity());
1492   }
1493 }
1494 
TEST(InitializerListAssign,DisparateTypesInList)1495 TEST(InitializerListAssign, DisparateTypesInList) {
1496   absl::InlinedVector<int, 2> v_int1;
1497   v_int1.assign({-7, 8ULL});
1498   EXPECT_THAT(v_int1, ElementsAre(-7, 8));
1499 
1500   absl::InlinedVector<int, 2> v_int2;
1501   v_int2 = {-7, 8ULL};
1502   EXPECT_THAT(v_int2, ElementsAre(-7, 8));
1503 
1504   absl::InlinedVector<std::string, 2> v_string1;
1505   v_string1.assign({"foo", std::string("bar")});
1506   EXPECT_THAT(v_string1, ElementsAre("foo", "bar"));
1507 
1508   absl::InlinedVector<std::string, 2> v_string2;
1509   v_string2 = {"foo", std::string("bar")};
1510   EXPECT_THAT(v_string2, ElementsAre("foo", "bar"));
1511 }
1512 
TYPED_TEST_P(InstanceTest,InitializerListAssign)1513 TYPED_TEST_P(InstanceTest, InitializerListAssign) {
1514   using Instance = TypeParam;
1515   for (size_t original_size = 0; original_size <= 4; ++original_size) {
1516     SCOPED_TRACE(original_size);
1517     absl::InlinedVector<Instance, 2> v(original_size, Instance(12345));
1518     const size_t original_capacity = v.capacity();
1519     v.assign({Instance(3)});
1520     EXPECT_THAT(v, AllOf(SizeIs(1), CapacityIs(original_capacity),
1521                          ElementsAre(ValueIs(3))));
1522   }
1523   for (size_t original_size = 0; original_size <= 4; ++original_size) {
1524     SCOPED_TRACE(original_size);
1525     absl::InlinedVector<Instance, 2> v(original_size, Instance(12345));
1526     v.assign({Instance(3), Instance(4), Instance(5)});
1527     EXPECT_THAT(
1528         v, AllOf(SizeIs(3), ElementsAre(ValueIs(3), ValueIs(4), ValueIs(5))));
1529     EXPECT_LE(3, v.capacity());
1530   }
1531 }
1532 
1533 REGISTER_TYPED_TEST_CASE_P(InstanceTest, Swap, CountConstructorsDestructors,
1534                            CountConstructorsDestructorsOnCopyConstruction,
1535                            CountConstructorsDestructorsOnMoveConstruction,
1536                            CountConstructorsDestructorsOnAssignment,
1537                            CountConstructorsDestructorsOnMoveAssignment,
1538                            CountElemAssignInlineBacking, RangedConstructor,
1539                            RangedAssign, InitializerListAssign);
1540 
1541 using InstanceTypes =
1542     ::testing::Types<CopyableOnlyInstance, CopyableMovableInstance>;
1543 INSTANTIATE_TYPED_TEST_CASE_P(InstanceTestOnTypes, InstanceTest, InstanceTypes);
1544 
TEST(DynamicVec,DynamicVecCompiles)1545 TEST(DynamicVec, DynamicVecCompiles) {
1546   DynamicVec v;
1547   (void)v;
1548 }
1549 
TEST(AllocatorSupportTest,Constructors)1550 TEST(AllocatorSupportTest, Constructors) {
1551   using MyAlloc = CountingAllocator<int>;
1552   using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
1553   const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
1554   int64_t allocated = 0;
1555   MyAlloc alloc(&allocated);
1556   { AllocVec ABSL_ATTRIBUTE_UNUSED v; }
1557   { AllocVec ABSL_ATTRIBUTE_UNUSED v(alloc); }
1558   { AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc); }
1559   { AllocVec ABSL_ATTRIBUTE_UNUSED v({1, 2, 3}, alloc); }
1560 
1561   AllocVec v2;
1562   { AllocVec ABSL_ATTRIBUTE_UNUSED v(v2, alloc); }
1563   { AllocVec ABSL_ATTRIBUTE_UNUSED v(std::move(v2), alloc); }
1564 }
1565 
TEST(AllocatorSupportTest,CountAllocations)1566 TEST(AllocatorSupportTest, CountAllocations) {
1567   using MyAlloc = CountingAllocator<int>;
1568   using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
1569   const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
1570   int64_t allocated = 0;
1571   MyAlloc alloc(&allocated);
1572   {
1573     AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + 4, alloc);
1574     EXPECT_THAT(allocated, 0);
1575   }
1576   EXPECT_THAT(allocated, 0);
1577   {
1578     AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc);
1579     EXPECT_THAT(allocated, v.size() * sizeof(int));
1580   }
1581   EXPECT_THAT(allocated, 0);
1582   {
1583     AllocVec v(4, 1, alloc);
1584     EXPECT_THAT(allocated, 0);
1585 
1586     int64_t allocated2 = 0;
1587     MyAlloc alloc2(&allocated2);
1588     AllocVec v2(v, alloc2);
1589     EXPECT_THAT(allocated2, 0);
1590 
1591     int64_t allocated3 = 0;
1592     MyAlloc alloc3(&allocated3);
1593     AllocVec v3(std::move(v), alloc3);
1594     EXPECT_THAT(allocated3, 0);
1595   }
1596   EXPECT_THAT(allocated, 0);
1597   {
1598     AllocVec v(8, 2, alloc);
1599     EXPECT_THAT(allocated, v.size() * sizeof(int));
1600 
1601     int64_t allocated2 = 0;
1602     MyAlloc alloc2(&allocated2);
1603     AllocVec v2(v, alloc2);
1604     EXPECT_THAT(allocated2, v2.size() * sizeof(int));
1605 
1606     int64_t allocated3 = 0;
1607     MyAlloc alloc3(&allocated3);
1608     AllocVec v3(std::move(v), alloc3);
1609     EXPECT_THAT(allocated3, v3.size() * sizeof(int));
1610   }
1611   EXPECT_EQ(allocated, 0);
1612   {
1613     // Test shrink_to_fit deallocations.
1614     AllocVec v(8, 2, alloc);
1615     EXPECT_EQ(allocated, 8 * sizeof(int));
1616     v.resize(5);
1617     EXPECT_EQ(allocated, 8 * sizeof(int));
1618     v.shrink_to_fit();
1619     EXPECT_EQ(allocated, 5 * sizeof(int));
1620     v.resize(4);
1621     EXPECT_EQ(allocated, 5 * sizeof(int));
1622     v.shrink_to_fit();
1623     EXPECT_EQ(allocated, 0);
1624   }
1625 }
1626 
TEST(AllocatorSupportTest,SwapBothAllocated)1627 TEST(AllocatorSupportTest, SwapBothAllocated) {
1628   using MyAlloc = CountingAllocator<int>;
1629   using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
1630   int64_t allocated1 = 0;
1631   int64_t allocated2 = 0;
1632   {
1633     const int ia1[] = {0, 1, 2, 3, 4, 5, 6, 7};
1634     const int ia2[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
1635     MyAlloc a1(&allocated1);
1636     MyAlloc a2(&allocated2);
1637     AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1);
1638     AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2);
1639     EXPECT_LT(v1.capacity(), v2.capacity());
1640     EXPECT_THAT(allocated1, v1.capacity() * sizeof(int));
1641     EXPECT_THAT(allocated2, v2.capacity() * sizeof(int));
1642     v1.swap(v2);
1643     EXPECT_THAT(v1, ElementsAreArray(ia2));
1644     EXPECT_THAT(v2, ElementsAreArray(ia1));
1645     EXPECT_THAT(allocated1, v2.capacity() * sizeof(int));
1646     EXPECT_THAT(allocated2, v1.capacity() * sizeof(int));
1647   }
1648   EXPECT_THAT(allocated1, 0);
1649   EXPECT_THAT(allocated2, 0);
1650 }
1651 
TEST(AllocatorSupportTest,SwapOneAllocated)1652 TEST(AllocatorSupportTest, SwapOneAllocated) {
1653   using MyAlloc = CountingAllocator<int>;
1654   using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
1655   int64_t allocated1 = 0;
1656   int64_t allocated2 = 0;
1657   {
1658     const int ia1[] = {0, 1, 2, 3, 4, 5, 6, 7};
1659     const int ia2[] = {0, 1, 2, 3};
1660     MyAlloc a1(&allocated1);
1661     MyAlloc a2(&allocated2);
1662     AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1);
1663     AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2);
1664     EXPECT_THAT(allocated1, v1.capacity() * sizeof(int));
1665     EXPECT_THAT(allocated2, 0);
1666     v1.swap(v2);
1667     EXPECT_THAT(v1, ElementsAreArray(ia2));
1668     EXPECT_THAT(v2, ElementsAreArray(ia1));
1669     EXPECT_THAT(allocated1, v2.capacity() * sizeof(int));
1670     EXPECT_THAT(allocated2, 0);
1671     EXPECT_TRUE(v2.get_allocator() == a1);
1672     EXPECT_TRUE(v1.get_allocator() == a2);
1673   }
1674   EXPECT_THAT(allocated1, 0);
1675   EXPECT_THAT(allocated2, 0);
1676 }
1677 
TEST(AllocatorSupportTest,ScopedAllocatorWorksInlined)1678 TEST(AllocatorSupportTest, ScopedAllocatorWorksInlined) {
1679   using StdVector = std::vector<int, CountingAllocator<int>>;
1680   using Alloc = CountingAllocator<StdVector>;
1681   using ScopedAlloc = std::scoped_allocator_adaptor<Alloc>;
1682   using AllocVec = absl::InlinedVector<StdVector, 1, ScopedAlloc>;
1683 
1684   int64_t total_allocated_byte_count = 0;
1685 
1686   AllocVec inlined_case(ScopedAlloc(Alloc(+&total_allocated_byte_count)));
1687 
1688   // Called only once to remain inlined
1689   inlined_case.emplace_back();
1690 
1691   int64_t absl_responsible_for_count = total_allocated_byte_count;
1692 
1693   // MSVC's allocator preemptively allocates in debug mode
1694 #if !defined(_MSC_VER)
1695   EXPECT_EQ(absl_responsible_for_count, 0);
1696 #endif  // !defined(_MSC_VER)
1697 
1698   inlined_case[0].emplace_back();
1699   EXPECT_GT(total_allocated_byte_count, absl_responsible_for_count);
1700 
1701   inlined_case.clear();
1702   inlined_case.shrink_to_fit();
1703   EXPECT_EQ(total_allocated_byte_count, 0);
1704 }
1705 
TEST(AllocatorSupportTest,ScopedAllocatorWorksAllocated)1706 TEST(AllocatorSupportTest, ScopedAllocatorWorksAllocated) {
1707   using StdVector = std::vector<int, CountingAllocator<int>>;
1708   using Alloc = CountingAllocator<StdVector>;
1709   using ScopedAlloc = std::scoped_allocator_adaptor<Alloc>;
1710   using AllocVec = absl::InlinedVector<StdVector, 1, ScopedAlloc>;
1711 
1712   int64_t total_allocated_byte_count = 0;
1713 
1714   AllocVec allocated_case(ScopedAlloc(Alloc(+&total_allocated_byte_count)));
1715 
1716   // Called twice to force into being allocated
1717   allocated_case.emplace_back();
1718   allocated_case.emplace_back();
1719 
1720   int64_t absl_responsible_for_count = total_allocated_byte_count;
1721   EXPECT_GT(absl_responsible_for_count, 0);
1722 
1723   allocated_case[1].emplace_back();
1724   EXPECT_GT(total_allocated_byte_count, absl_responsible_for_count);
1725 
1726   allocated_case.clear();
1727   allocated_case.shrink_to_fit();
1728   EXPECT_EQ(total_allocated_byte_count, 0);
1729 }
1730 
TEST(AllocatorSupportTest,SizeAllocConstructor)1731 TEST(AllocatorSupportTest, SizeAllocConstructor) {
1732   constexpr int inlined_size = 4;
1733   using Alloc = CountingAllocator<int>;
1734   using AllocVec = absl::InlinedVector<int, inlined_size, Alloc>;
1735 
1736   {
1737     auto len = inlined_size / 2;
1738     int64_t allocated = 0;
1739     auto v = AllocVec(len, Alloc(&allocated));
1740 
1741     // Inline storage used; allocator should not be invoked
1742     EXPECT_THAT(allocated, 0);
1743     EXPECT_THAT(v, AllOf(SizeIs(len), Each(0)));
1744   }
1745 
1746   {
1747     auto len = inlined_size * 2;
1748     int64_t allocated = 0;
1749     auto v = AllocVec(len, Alloc(&allocated));
1750 
1751     // Out of line storage used; allocation of 8 elements expected
1752     EXPECT_THAT(allocated, len * sizeof(int));
1753     EXPECT_THAT(v, AllOf(SizeIs(len), Each(0)));
1754   }
1755 }
1756 
TEST(InlinedVectorTest,MinimumAllocatorCompilesUsingTraits)1757 TEST(InlinedVectorTest, MinimumAllocatorCompilesUsingTraits) {
1758   using T = int;
1759   using A = std::allocator<T>;
1760   using ATraits = absl::allocator_traits<A>;
1761 
1762   struct MinimumAllocator {
1763     using value_type = T;
1764 
1765     value_type* allocate(size_t n) {
1766       A a;
1767       return ATraits::allocate(a, n);
1768     }
1769 
1770     void deallocate(value_type* p, size_t n) {
1771       A a;
1772       ATraits::deallocate(a, p, n);
1773     }
1774   };
1775 
1776   absl::InlinedVector<T, 1, MinimumAllocator> vec;
1777   vec.emplace_back();
1778   vec.resize(0);
1779 }
1780 
TEST(InlinedVectorTest,AbslHashValueWorks)1781 TEST(InlinedVectorTest, AbslHashValueWorks) {
1782   using V = absl::InlinedVector<int, 4>;
1783   std::vector<V> cases;
1784 
1785   // Generate a variety of vectors some of these are small enough for the inline
1786   // space but are stored out of line.
1787   for (int i = 0; i < 10; ++i) {
1788     V v;
1789     for (int j = 0; j < i; ++j) {
1790       v.push_back(j);
1791     }
1792     cases.push_back(v);
1793     v.resize(i % 4);
1794     cases.push_back(v);
1795   }
1796 
1797   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases));
1798 }
1799 
1800 }  // anonymous namespace
1801