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