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__anon591d2c9d0111::NoDefaultCtor310 explicit NoDefaultCtor(int) {}
311 };
312 struct NoCopy {
NoCopy__anon591d2c9d0111::NoCopy313 NoCopy() {}
314 NoCopy(const NoCopy&) = delete;
315 };
316 struct NoAssign {
NoAssign__anon591d2c9d0111::NoAssign317 NoAssign() {}
318 NoAssign& operator=(const NoAssign&) = delete;
319 };
320 struct MoveOnly {
MoveOnly__anon591d2c9d0111::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 EXPECT_EQ(2 * sizeof(int*),
740 sizeof(absl::InlinedVector<int*, 1>) - 1 * sizeof(int*));
741 EXPECT_EQ(1 * sizeof(int*),
742 sizeof(absl::InlinedVector<int*, 2>) - 2 * sizeof(int*));
743 EXPECT_EQ(1 * sizeof(int*),
744 sizeof(absl::InlinedVector<int*, 3>) - 3 * sizeof(int*));
745 EXPECT_EQ(1 * sizeof(int*),
746 sizeof(absl::InlinedVector<int*, 4>) - 4 * sizeof(int*));
747 EXPECT_EQ(1 * sizeof(int*),
748 sizeof(absl::InlinedVector<int*, 5>) - 5 * sizeof(int*));
749 EXPECT_EQ(1 * sizeof(int*),
750 sizeof(absl::InlinedVector<int*, 6>) - 6 * sizeof(int*));
751 EXPECT_EQ(1 * sizeof(int*),
752 sizeof(absl::InlinedVector<int*, 7>) - 7 * sizeof(int*));
753 EXPECT_EQ(1 * sizeof(int*),
754 sizeof(absl::InlinedVector<int*, 8>) - 8 * sizeof(int*));
755 }
756
TEST(IntVec,Clear)757 TEST(IntVec, Clear) {
758 for (int len = 0; len < 20; len++) {
759 SCOPED_TRACE(len);
760 IntVec v;
761 Fill(&v, len);
762 v.clear();
763 EXPECT_EQ(0, v.size());
764 EXPECT_EQ(v.begin(), v.end());
765 }
766 }
767
TEST(IntVec,Reserve)768 TEST(IntVec, Reserve) {
769 for (int len = 0; len < 20; len++) {
770 IntVec v;
771 Fill(&v, len);
772
773 for (int newlen = 0; newlen < 100; newlen++) {
774 const int* start_rep = v.data();
775 v.reserve(newlen);
776 const int* final_rep = v.data();
777 if (newlen <= len) {
778 EXPECT_EQ(start_rep, final_rep);
779 }
780 EXPECT_LE(newlen, v.capacity());
781
782 // Filling up to newlen should not change rep
783 while (v.size() < newlen) {
784 v.push_back(0);
785 }
786 EXPECT_EQ(final_rep, v.data());
787 }
788 }
789 }
790
TEST(StringVec,SelfRefPushBack)791 TEST(StringVec, SelfRefPushBack) {
792 std::vector<std::string> std_v;
793 absl::InlinedVector<std::string, 4> v;
794 const std::string s = "A quite long string to ensure heap.";
795 std_v.push_back(s);
796 v.push_back(s);
797 for (int i = 0; i < 20; ++i) {
798 EXPECT_THAT(v, ElementsAreArray(std_v));
799
800 v.push_back(v.back());
801 std_v.push_back(std_v.back());
802 }
803 EXPECT_THAT(v, ElementsAreArray(std_v));
804 }
805
TEST(StringVec,SelfRefPushBackWithMove)806 TEST(StringVec, SelfRefPushBackWithMove) {
807 std::vector<std::string> std_v;
808 absl::InlinedVector<std::string, 4> v;
809 const std::string s = "A quite long string to ensure heap.";
810 std_v.push_back(s);
811 v.push_back(s);
812 for (int i = 0; i < 20; ++i) {
813 EXPECT_EQ(v.back(), std_v.back());
814
815 v.push_back(std::move(v.back()));
816 std_v.push_back(std::move(std_v.back()));
817 }
818 EXPECT_EQ(v.back(), std_v.back());
819 }
820
TEST(StringVec,SelfMove)821 TEST(StringVec, SelfMove) {
822 const std::string s = "A quite long string to ensure heap.";
823 for (int len = 0; len < 20; len++) {
824 SCOPED_TRACE(len);
825 absl::InlinedVector<std::string, 8> v;
826 for (int i = 0; i < len; ++i) {
827 SCOPED_TRACE(i);
828 v.push_back(s);
829 }
830 // Indirection necessary to avoid compiler warning.
831 v = std::move(*(&v));
832 // Ensure that the inlined vector is still in a valid state by copying it.
833 // We don't expect specific contents since a self-move results in an
834 // unspecified valid state.
835 std::vector<std::string> copy(v.begin(), v.end());
836 }
837 }
838
TEST(IntVec,Swap)839 TEST(IntVec, Swap) {
840 for (int l1 = 0; l1 < 20; l1++) {
841 SCOPED_TRACE(l1);
842 for (int l2 = 0; l2 < 20; l2++) {
843 SCOPED_TRACE(l2);
844 IntVec a = Fill(l1, 0);
845 IntVec b = Fill(l2, 100);
846 {
847 using std::swap;
848 swap(a, b);
849 }
850 EXPECT_EQ(l1, b.size());
851 EXPECT_EQ(l2, a.size());
852 for (int i = 0; i < l1; i++) {
853 SCOPED_TRACE(i);
854 EXPECT_EQ(i, b[i]);
855 }
856 for (int i = 0; i < l2; i++) {
857 SCOPED_TRACE(i);
858 EXPECT_EQ(100 + i, a[i]);
859 }
860 }
861 }
862 }
863
TYPED_TEST_P(InstanceTest,Swap)864 TYPED_TEST_P(InstanceTest, Swap) {
865 using Instance = TypeParam;
866 using InstanceVec = absl::InlinedVector<Instance, 8>;
867 for (int l1 = 0; l1 < 20; l1++) {
868 SCOPED_TRACE(l1);
869 for (int l2 = 0; l2 < 20; l2++) {
870 SCOPED_TRACE(l2);
871 InstanceTracker tracker;
872 InstanceVec a, b;
873 const size_t inlined_capacity = a.capacity();
874 auto min_len = std::min(l1, l2);
875 auto max_len = std::max(l1, l2);
876 for (int i = 0; i < l1; i++) a.push_back(Instance(i));
877 for (int i = 0; i < l2; i++) b.push_back(Instance(100 + i));
878 EXPECT_EQ(tracker.instances(), l1 + l2);
879 tracker.ResetCopiesMovesSwaps();
880 {
881 using std::swap;
882 swap(a, b);
883 }
884 EXPECT_EQ(tracker.instances(), l1 + l2);
885 if (a.size() > inlined_capacity && b.size() > inlined_capacity) {
886 EXPECT_EQ(tracker.swaps(), 0); // Allocations are swapped.
887 EXPECT_EQ(tracker.moves(), 0);
888 } else if (a.size() <= inlined_capacity && b.size() <= inlined_capacity) {
889 EXPECT_EQ(tracker.swaps(), min_len);
890 EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()),
891 max_len - min_len);
892 } else {
893 // One is allocated and the other isn't. The allocation is transferred
894 // without copying elements, and the inlined instances are copied/moved.
895 EXPECT_EQ(tracker.swaps(), 0);
896 EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()),
897 min_len);
898 }
899
900 EXPECT_EQ(l1, b.size());
901 EXPECT_EQ(l2, a.size());
902 for (int i = 0; i < l1; i++) {
903 EXPECT_EQ(i, b[i].value());
904 }
905 for (int i = 0; i < l2; i++) {
906 EXPECT_EQ(100 + i, a[i].value());
907 }
908 }
909 }
910 }
911
TEST(IntVec,EqualAndNotEqual)912 TEST(IntVec, EqualAndNotEqual) {
913 IntVec a, b;
914 EXPECT_TRUE(a == b);
915 EXPECT_FALSE(a != b);
916
917 a.push_back(3);
918 EXPECT_FALSE(a == b);
919 EXPECT_TRUE(a != b);
920
921 b.push_back(3);
922 EXPECT_TRUE(a == b);
923 EXPECT_FALSE(a != b);
924
925 b.push_back(7);
926 EXPECT_FALSE(a == b);
927 EXPECT_TRUE(a != b);
928
929 a.push_back(6);
930 EXPECT_FALSE(a == b);
931 EXPECT_TRUE(a != b);
932
933 a.clear();
934 b.clear();
935 for (int i = 0; i < 100; i++) {
936 a.push_back(i);
937 b.push_back(i);
938 EXPECT_TRUE(a == b);
939 EXPECT_FALSE(a != b);
940
941 b[i] = b[i] + 1;
942 EXPECT_FALSE(a == b);
943 EXPECT_TRUE(a != b);
944
945 b[i] = b[i] - 1; // Back to before
946 EXPECT_TRUE(a == b);
947 EXPECT_FALSE(a != b);
948 }
949 }
950
TEST(IntVec,RelationalOps)951 TEST(IntVec, RelationalOps) {
952 IntVec a, b;
953 EXPECT_FALSE(a < b);
954 EXPECT_FALSE(b < a);
955 EXPECT_FALSE(a > b);
956 EXPECT_FALSE(b > a);
957 EXPECT_TRUE(a <= b);
958 EXPECT_TRUE(b <= a);
959 EXPECT_TRUE(a >= b);
960 EXPECT_TRUE(b >= a);
961 b.push_back(3);
962 EXPECT_TRUE(a < b);
963 EXPECT_FALSE(b < a);
964 EXPECT_FALSE(a > b);
965 EXPECT_TRUE(b > a);
966 EXPECT_TRUE(a <= b);
967 EXPECT_FALSE(b <= a);
968 EXPECT_FALSE(a >= b);
969 EXPECT_TRUE(b >= a);
970 }
971
TYPED_TEST_P(InstanceTest,CountConstructorsDestructors)972 TYPED_TEST_P(InstanceTest, CountConstructorsDestructors) {
973 using Instance = TypeParam;
974 using InstanceVec = absl::InlinedVector<Instance, 8>;
975 InstanceTracker tracker;
976 for (int len = 0; len < 20; len++) {
977 SCOPED_TRACE(len);
978 tracker.ResetCopiesMovesSwaps();
979
980 InstanceVec v;
981 const size_t inlined_capacity = v.capacity();
982 for (int i = 0; i < len; i++) {
983 v.push_back(Instance(i));
984 }
985 EXPECT_EQ(tracker.instances(), len);
986 EXPECT_GE(tracker.copies() + tracker.moves(),
987 len); // More due to reallocation.
988 tracker.ResetCopiesMovesSwaps();
989
990 // Enlarging resize() must construct some objects
991 tracker.ResetCopiesMovesSwaps();
992 v.resize(len + 10, Instance(100));
993 EXPECT_EQ(tracker.instances(), len + 10);
994 if (len <= inlined_capacity && len + 10 > inlined_capacity) {
995 EXPECT_EQ(tracker.copies() + tracker.moves(), 10 + len);
996 } else {
997 // Only specify a minimum number of copies + moves. We don't want to
998 // depend on the reallocation policy here.
999 EXPECT_GE(tracker.copies() + tracker.moves(),
1000 10); // More due to reallocation.
1001 }
1002
1003 // Shrinking resize() must destroy some objects
1004 tracker.ResetCopiesMovesSwaps();
1005 v.resize(len, Instance(100));
1006 EXPECT_EQ(tracker.instances(), len);
1007 EXPECT_EQ(tracker.copies(), 0);
1008 EXPECT_EQ(tracker.moves(), 0);
1009
1010 // reserve() must not increase the number of initialized objects
1011 SCOPED_TRACE("reserve");
1012 v.reserve(len + 1000);
1013 EXPECT_EQ(tracker.instances(), len);
1014 EXPECT_EQ(tracker.copies() + tracker.moves(), len);
1015
1016 // pop_back() and erase() must destroy one object
1017 if (len > 0) {
1018 tracker.ResetCopiesMovesSwaps();
1019 v.pop_back();
1020 EXPECT_EQ(tracker.instances(), len - 1);
1021 EXPECT_EQ(tracker.copies(), 0);
1022 EXPECT_EQ(tracker.moves(), 0);
1023
1024 if (!v.empty()) {
1025 tracker.ResetCopiesMovesSwaps();
1026 v.erase(v.begin());
1027 EXPECT_EQ(tracker.instances(), len - 2);
1028 EXPECT_EQ(tracker.copies() + tracker.moves(), len - 2);
1029 }
1030 }
1031
1032 tracker.ResetCopiesMovesSwaps();
1033 int instances_before_empty_erase = tracker.instances();
1034 v.erase(v.begin(), v.begin());
1035 EXPECT_EQ(tracker.instances(), instances_before_empty_erase);
1036 EXPECT_EQ(tracker.copies() + tracker.moves(), 0);
1037 }
1038 }
1039
TYPED_TEST_P(InstanceTest,CountConstructorsDestructorsOnCopyConstruction)1040 TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnCopyConstruction) {
1041 using Instance = TypeParam;
1042 using InstanceVec = absl::InlinedVector<Instance, 8>;
1043 InstanceTracker tracker;
1044 for (int len = 0; len < 20; len++) {
1045 SCOPED_TRACE(len);
1046 tracker.ResetCopiesMovesSwaps();
1047
1048 InstanceVec v;
1049 for (int i = 0; i < len; i++) {
1050 v.push_back(Instance(i));
1051 }
1052 EXPECT_EQ(tracker.instances(), len);
1053 EXPECT_GE(tracker.copies() + tracker.moves(),
1054 len); // More due to reallocation.
1055 tracker.ResetCopiesMovesSwaps();
1056 { // Copy constructor should create 'len' more instances.
1057 InstanceVec v_copy(v);
1058 EXPECT_EQ(tracker.instances(), len + len);
1059 EXPECT_EQ(tracker.copies(), len);
1060 EXPECT_EQ(tracker.moves(), 0);
1061 }
1062 EXPECT_EQ(tracker.instances(), len);
1063 }
1064 }
1065
TYPED_TEST_P(InstanceTest,CountConstructorsDestructorsOnMoveConstruction)1066 TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveConstruction) {
1067 using Instance = TypeParam;
1068 using InstanceVec = absl::InlinedVector<Instance, 8>;
1069 InstanceTracker tracker;
1070 for (int len = 0; len < 20; len++) {
1071 SCOPED_TRACE(len);
1072 tracker.ResetCopiesMovesSwaps();
1073
1074 InstanceVec v;
1075 const size_t inlined_capacity = v.capacity();
1076 for (int i = 0; i < len; i++) {
1077 v.push_back(Instance(i));
1078 }
1079 EXPECT_EQ(tracker.instances(), len);
1080 EXPECT_GE(tracker.copies() + tracker.moves(),
1081 len); // More due to reallocation.
1082 tracker.ResetCopiesMovesSwaps();
1083 {
1084 InstanceVec v_copy(std::move(v));
1085 if (len > inlined_capacity) {
1086 // Allocation is moved as a whole.
1087 EXPECT_EQ(tracker.instances(), len);
1088 EXPECT_EQ(tracker.live_instances(), len);
1089 // Tests an implementation detail, don't rely on this in your code.
1090 EXPECT_EQ(v.size(), 0); // NOLINT misc-use-after-move
1091 EXPECT_EQ(tracker.copies(), 0);
1092 EXPECT_EQ(tracker.moves(), 0);
1093 } else {
1094 EXPECT_EQ(tracker.instances(), len + len);
1095 if (Instance::supports_move()) {
1096 EXPECT_EQ(tracker.live_instances(), len);
1097 EXPECT_EQ(tracker.copies(), 0);
1098 EXPECT_EQ(tracker.moves(), len);
1099 } else {
1100 EXPECT_EQ(tracker.live_instances(), len + len);
1101 EXPECT_EQ(tracker.copies(), len);
1102 EXPECT_EQ(tracker.moves(), 0);
1103 }
1104 }
1105 EXPECT_EQ(tracker.swaps(), 0);
1106 }
1107 }
1108 }
1109
TYPED_TEST_P(InstanceTest,CountConstructorsDestructorsOnAssignment)1110 TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnAssignment) {
1111 using Instance = TypeParam;
1112 using InstanceVec = absl::InlinedVector<Instance, 8>;
1113 InstanceTracker tracker;
1114 for (int len = 0; len < 20; len++) {
1115 SCOPED_TRACE(len);
1116 for (int longorshort = 0; longorshort <= 1; ++longorshort) {
1117 SCOPED_TRACE(longorshort);
1118 tracker.ResetCopiesMovesSwaps();
1119
1120 InstanceVec longer, shorter;
1121 for (int i = 0; i < len; i++) {
1122 longer.push_back(Instance(i));
1123 shorter.push_back(Instance(i));
1124 }
1125 longer.push_back(Instance(len));
1126 EXPECT_EQ(tracker.instances(), len + len + 1);
1127 EXPECT_GE(tracker.copies() + tracker.moves(),
1128 len + len + 1); // More due to reallocation.
1129
1130 tracker.ResetCopiesMovesSwaps();
1131 if (longorshort) {
1132 shorter = longer;
1133 EXPECT_EQ(tracker.instances(), (len + 1) + (len + 1));
1134 EXPECT_GE(tracker.copies() + tracker.moves(),
1135 len + 1); // More due to reallocation.
1136 } else {
1137 longer = shorter;
1138 EXPECT_EQ(tracker.instances(), len + len);
1139 EXPECT_EQ(tracker.copies() + tracker.moves(), len);
1140 }
1141 }
1142 }
1143 }
1144
TYPED_TEST_P(InstanceTest,CountConstructorsDestructorsOnMoveAssignment)1145 TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveAssignment) {
1146 using Instance = TypeParam;
1147 using InstanceVec = absl::InlinedVector<Instance, 8>;
1148 InstanceTracker tracker;
1149 for (int len = 0; len < 20; len++) {
1150 SCOPED_TRACE(len);
1151 for (int longorshort = 0; longorshort <= 1; ++longorshort) {
1152 SCOPED_TRACE(longorshort);
1153 tracker.ResetCopiesMovesSwaps();
1154
1155 InstanceVec longer, shorter;
1156 const int inlined_capacity = longer.capacity();
1157 for (int i = 0; i < len; i++) {
1158 longer.push_back(Instance(i));
1159 shorter.push_back(Instance(i));
1160 }
1161 longer.push_back(Instance(len));
1162 EXPECT_EQ(tracker.instances(), len + len + 1);
1163 EXPECT_GE(tracker.copies() + tracker.moves(),
1164 len + len + 1); // More due to reallocation.
1165
1166 tracker.ResetCopiesMovesSwaps();
1167 int src_len;
1168 if (longorshort) {
1169 src_len = len + 1;
1170 shorter = std::move(longer);
1171 } else {
1172 src_len = len;
1173 longer = std::move(shorter);
1174 }
1175 if (src_len > inlined_capacity) {
1176 // Allocation moved as a whole.
1177 EXPECT_EQ(tracker.instances(), src_len);
1178 EXPECT_EQ(tracker.live_instances(), src_len);
1179 EXPECT_EQ(tracker.copies(), 0);
1180 EXPECT_EQ(tracker.moves(), 0);
1181 } else {
1182 // Elements are all copied.
1183 EXPECT_EQ(tracker.instances(), src_len + src_len);
1184 if (Instance::supports_move()) {
1185 EXPECT_EQ(tracker.copies(), 0);
1186 EXPECT_EQ(tracker.moves(), src_len);
1187 EXPECT_EQ(tracker.live_instances(), src_len);
1188 } else {
1189 EXPECT_EQ(tracker.copies(), src_len);
1190 EXPECT_EQ(tracker.moves(), 0);
1191 EXPECT_EQ(tracker.live_instances(), src_len + src_len);
1192 }
1193 }
1194 EXPECT_EQ(tracker.swaps(), 0);
1195 }
1196 }
1197 }
1198
TEST(CountElemAssign,SimpleTypeWithInlineBacking)1199 TEST(CountElemAssign, SimpleTypeWithInlineBacking) {
1200 for (size_t original_size = 0; original_size <= 5; ++original_size) {
1201 SCOPED_TRACE(original_size);
1202 // Original contents are [12345, 12345, ...]
1203 std::vector<int> original_contents(original_size, 12345);
1204
1205 absl::InlinedVector<int, 2> v(original_contents.begin(),
1206 original_contents.end());
1207 v.assign(2, 123);
1208 EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(123, 123)));
1209 if (original_size <= 2) {
1210 // If the original had inline backing, it should stay inline.
1211 EXPECT_EQ(2, v.capacity());
1212 }
1213 }
1214 }
1215
TEST(CountElemAssign,SimpleTypeWithAllocation)1216 TEST(CountElemAssign, SimpleTypeWithAllocation) {
1217 for (size_t original_size = 0; original_size <= 5; ++original_size) {
1218 SCOPED_TRACE(original_size);
1219 // Original contents are [12345, 12345, ...]
1220 std::vector<int> original_contents(original_size, 12345);
1221
1222 absl::InlinedVector<int, 2> v(original_contents.begin(),
1223 original_contents.end());
1224 v.assign(3, 123);
1225 EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(123, 123, 123)));
1226 EXPECT_LE(v.size(), v.capacity());
1227 }
1228 }
1229
TYPED_TEST_P(InstanceTest,CountElemAssignInlineBacking)1230 TYPED_TEST_P(InstanceTest, CountElemAssignInlineBacking) {
1231 using Instance = TypeParam;
1232 for (size_t original_size = 0; original_size <= 5; ++original_size) {
1233 SCOPED_TRACE(original_size);
1234 // Original contents are [12345, 12345, ...]
1235 std::vector<Instance> original_contents(original_size, Instance(12345));
1236
1237 absl::InlinedVector<Instance, 2> v(original_contents.begin(),
1238 original_contents.end());
1239 v.assign(2, Instance(123));
1240 EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(ValueIs(123), ValueIs(123))));
1241 if (original_size <= 2) {
1242 // If the original had inline backing, it should stay inline.
1243 EXPECT_EQ(2, v.capacity());
1244 }
1245 }
1246 }
1247
1248 template <typename Instance>
InstanceCountElemAssignWithAllocationTest()1249 void InstanceCountElemAssignWithAllocationTest() {
1250 for (size_t original_size = 0; original_size <= 5; ++original_size) {
1251 SCOPED_TRACE(original_size);
1252 // Original contents are [12345, 12345, ...]
1253 std::vector<Instance> original_contents(original_size, Instance(12345));
1254
1255 absl::InlinedVector<Instance, 2> v(original_contents.begin(),
1256 original_contents.end());
1257 v.assign(3, Instance(123));
1258 EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(ValueIs(123), ValueIs(123),
1259 ValueIs(123))));
1260 EXPECT_LE(v.size(), v.capacity());
1261 }
1262 }
TEST(CountElemAssign,WithAllocationCopyableInstance)1263 TEST(CountElemAssign, WithAllocationCopyableInstance) {
1264 InstanceCountElemAssignWithAllocationTest<CopyableOnlyInstance>();
1265 }
TEST(CountElemAssign,WithAllocationCopyableMovableInstance)1266 TEST(CountElemAssign, WithAllocationCopyableMovableInstance) {
1267 InstanceCountElemAssignWithAllocationTest<CopyableMovableInstance>();
1268 }
1269
TEST(RangedConstructor,SimpleType)1270 TEST(RangedConstructor, SimpleType) {
1271 std::vector<int> source_v = {4, 5, 6};
1272 // First try to fit in inline backing
1273 absl::InlinedVector<int, 4> v(source_v.begin(), source_v.end());
1274 EXPECT_EQ(3, v.size());
1275 EXPECT_EQ(4, v.capacity()); // Indication that we're still on inlined storage
1276 EXPECT_EQ(4, v[0]);
1277 EXPECT_EQ(5, v[1]);
1278 EXPECT_EQ(6, v[2]);
1279
1280 // Now, force a re-allocate
1281 absl::InlinedVector<int, 2> realloc_v(source_v.begin(), source_v.end());
1282 EXPECT_EQ(3, realloc_v.size());
1283 EXPECT_LT(2, realloc_v.capacity());
1284 EXPECT_EQ(4, realloc_v[0]);
1285 EXPECT_EQ(5, realloc_v[1]);
1286 EXPECT_EQ(6, realloc_v[2]);
1287 }
1288
1289 // Test for ranged constructors using Instance as the element type and
1290 // SourceContainer as the source container type.
1291 template <typename Instance, typename SourceContainer, int inlined_capacity>
InstanceRangedConstructorTestForContainer()1292 void InstanceRangedConstructorTestForContainer() {
1293 InstanceTracker tracker;
1294 SourceContainer source_v = {Instance(0), Instance(1)};
1295 tracker.ResetCopiesMovesSwaps();
1296 absl::InlinedVector<Instance, inlined_capacity> v(source_v.begin(),
1297 source_v.end());
1298 EXPECT_EQ(2, v.size());
1299 EXPECT_LT(1, v.capacity());
1300 EXPECT_EQ(0, v[0].value());
1301 EXPECT_EQ(1, v[1].value());
1302 EXPECT_EQ(tracker.copies(), 2);
1303 EXPECT_EQ(tracker.moves(), 0);
1304 }
1305
1306 template <typename Instance, int inlined_capacity>
InstanceRangedConstructorTestWithCapacity()1307 void InstanceRangedConstructorTestWithCapacity() {
1308 // Test with const and non-const, random access and non-random-access sources.
1309 // TODO(bsamwel): Test with an input iterator source.
1310 {
1311 SCOPED_TRACE("std::list");
1312 InstanceRangedConstructorTestForContainer<Instance, std::list<Instance>,
1313 inlined_capacity>();
1314 {
1315 SCOPED_TRACE("const std::list");
1316 InstanceRangedConstructorTestForContainer<
1317 Instance, const std::list<Instance>, inlined_capacity>();
1318 }
1319 {
1320 SCOPED_TRACE("std::vector");
1321 InstanceRangedConstructorTestForContainer<Instance, std::vector<Instance>,
1322 inlined_capacity>();
1323 }
1324 {
1325 SCOPED_TRACE("const std::vector");
1326 InstanceRangedConstructorTestForContainer<
1327 Instance, const std::vector<Instance>, inlined_capacity>();
1328 }
1329 }
1330 }
1331
TYPED_TEST_P(InstanceTest,RangedConstructor)1332 TYPED_TEST_P(InstanceTest, RangedConstructor) {
1333 using Instance = TypeParam;
1334 SCOPED_TRACE("capacity=1");
1335 InstanceRangedConstructorTestWithCapacity<Instance, 1>();
1336 SCOPED_TRACE("capacity=2");
1337 InstanceRangedConstructorTestWithCapacity<Instance, 2>();
1338 }
1339
TEST(RangedConstructor,ElementsAreConstructed)1340 TEST(RangedConstructor, ElementsAreConstructed) {
1341 std::vector<std::string> source_v = {"cat", "dog"};
1342
1343 // Force expansion and re-allocation of v. Ensures that when the vector is
1344 // expanded that new elements are constructed.
1345 absl::InlinedVector<std::string, 1> v(source_v.begin(), source_v.end());
1346 EXPECT_EQ("cat", v[0]);
1347 EXPECT_EQ("dog", v[1]);
1348 }
1349
TEST(RangedAssign,SimpleType)1350 TEST(RangedAssign, SimpleType) {
1351 // Test for all combinations of original sizes (empty and non-empty inline,
1352 // and out of line) and target sizes.
1353 for (size_t original_size = 0; original_size <= 5; ++original_size) {
1354 SCOPED_TRACE(original_size);
1355 // Original contents are [12345, 12345, ...]
1356 std::vector<int> original_contents(original_size, 12345);
1357
1358 for (size_t target_size = 0; target_size <= 5; ++target_size) {
1359 SCOPED_TRACE(target_size);
1360
1361 // New contents are [3, 4, ...]
1362 std::vector<int> new_contents;
1363 for (size_t i = 0; i < target_size; ++i) {
1364 new_contents.push_back(i + 3);
1365 }
1366
1367 absl::InlinedVector<int, 3> v(original_contents.begin(),
1368 original_contents.end());
1369 v.assign(new_contents.begin(), new_contents.end());
1370
1371 EXPECT_EQ(new_contents.size(), v.size());
1372 EXPECT_LE(new_contents.size(), v.capacity());
1373 if (target_size <= 3 && original_size <= 3) {
1374 // Storage should stay inline when target size is small.
1375 EXPECT_EQ(3, v.capacity());
1376 }
1377 EXPECT_THAT(v, ElementsAreArray(new_contents));
1378 }
1379 }
1380 }
1381
1382 // Returns true if lhs and rhs have the same value.
1383 template <typename Instance>
InstanceValuesEqual(const Instance & lhs,const Instance & rhs)1384 static bool InstanceValuesEqual(const Instance& lhs, const Instance& rhs) {
1385 return lhs.value() == rhs.value();
1386 }
1387
1388 // Test for ranged assign() using Instance as the element type and
1389 // SourceContainer as the source container type.
1390 template <typename Instance, typename SourceContainer>
InstanceRangedAssignTestForContainer()1391 void InstanceRangedAssignTestForContainer() {
1392 // Test for all combinations of original sizes (empty and non-empty inline,
1393 // and out of line) and target sizes.
1394 for (size_t original_size = 0; original_size <= 5; ++original_size) {
1395 SCOPED_TRACE(original_size);
1396 // Original contents are [12345, 12345, ...]
1397 std::vector<Instance> original_contents(original_size, Instance(12345));
1398
1399 for (size_t target_size = 0; target_size <= 5; ++target_size) {
1400 SCOPED_TRACE(target_size);
1401
1402 // New contents are [3, 4, ...]
1403 // Generate data using a non-const container, because SourceContainer
1404 // itself may be const.
1405 // TODO(bsamwel): Test with an input iterator.
1406 std::vector<Instance> new_contents_in;
1407 for (size_t i = 0; i < target_size; ++i) {
1408 new_contents_in.push_back(Instance(i + 3));
1409 }
1410 SourceContainer new_contents(new_contents_in.begin(),
1411 new_contents_in.end());
1412
1413 absl::InlinedVector<Instance, 3> v(original_contents.begin(),
1414 original_contents.end());
1415 v.assign(new_contents.begin(), new_contents.end());
1416
1417 EXPECT_EQ(new_contents.size(), v.size());
1418 EXPECT_LE(new_contents.size(), v.capacity());
1419 if (target_size <= 3 && original_size <= 3) {
1420 // Storage should stay inline when target size is small.
1421 EXPECT_EQ(3, v.capacity());
1422 }
1423 EXPECT_TRUE(std::equal(v.begin(), v.end(), new_contents.begin(),
1424 InstanceValuesEqual<Instance>));
1425 }
1426 }
1427 }
1428
TYPED_TEST_P(InstanceTest,RangedAssign)1429 TYPED_TEST_P(InstanceTest, RangedAssign) {
1430 using Instance = TypeParam;
1431 // Test with const and non-const, random access and non-random-access sources.
1432 // TODO(bsamwel): Test with an input iterator source.
1433 SCOPED_TRACE("std::list");
1434 InstanceRangedAssignTestForContainer<Instance, std::list<Instance>>();
1435 SCOPED_TRACE("const std::list");
1436 InstanceRangedAssignTestForContainer<Instance, const std::list<Instance>>();
1437 SCOPED_TRACE("std::vector");
1438 InstanceRangedAssignTestForContainer<Instance, std::vector<Instance>>();
1439 SCOPED_TRACE("const std::vector");
1440 InstanceRangedAssignTestForContainer<Instance, const std::vector<Instance>>();
1441 }
1442
TEST(InitializerListConstructor,SimpleTypeWithInlineBacking)1443 TEST(InitializerListConstructor, SimpleTypeWithInlineBacking) {
1444 EXPECT_THAT((absl::InlinedVector<int, 4>{4, 5, 6}),
1445 AllOf(SizeIs(3), CapacityIs(4), ElementsAre(4, 5, 6)));
1446 }
1447
TEST(InitializerListConstructor,SimpleTypeWithReallocationRequired)1448 TEST(InitializerListConstructor, SimpleTypeWithReallocationRequired) {
1449 EXPECT_THAT((absl::InlinedVector<int, 2>{4, 5, 6}),
1450 AllOf(SizeIs(3), CapacityIs(Gt(2)), ElementsAre(4, 5, 6)));
1451 }
1452
TEST(InitializerListConstructor,DisparateTypesInList)1453 TEST(InitializerListConstructor, DisparateTypesInList) {
1454 EXPECT_THAT((absl::InlinedVector<int, 2>{-7, 8ULL}), ElementsAre(-7, 8));
1455
1456 EXPECT_THAT((absl::InlinedVector<std::string, 2>{"foo", std::string("bar")}),
1457 ElementsAre("foo", "bar"));
1458 }
1459
TEST(InitializerListConstructor,ComplexTypeWithInlineBacking)1460 TEST(InitializerListConstructor, ComplexTypeWithInlineBacking) {
1461 EXPECT_THAT((absl::InlinedVector<CopyableMovableInstance, 1>{
1462 CopyableMovableInstance(0)}),
1463 AllOf(SizeIs(1), CapacityIs(1), ElementsAre(ValueIs(0))));
1464 }
1465
TEST(InitializerListConstructor,ComplexTypeWithReallocationRequired)1466 TEST(InitializerListConstructor, ComplexTypeWithReallocationRequired) {
1467 EXPECT_THAT(
1468 (absl::InlinedVector<CopyableMovableInstance, 1>{
1469 CopyableMovableInstance(0), CopyableMovableInstance(1)}),
1470 AllOf(SizeIs(2), CapacityIs(Gt(1)), ElementsAre(ValueIs(0), ValueIs(1))));
1471 }
1472
TEST(InitializerListAssign,SimpleTypeFitsInlineBacking)1473 TEST(InitializerListAssign, SimpleTypeFitsInlineBacking) {
1474 for (size_t original_size = 0; original_size <= 4; ++original_size) {
1475 SCOPED_TRACE(original_size);
1476
1477 absl::InlinedVector<int, 2> v1(original_size, 12345);
1478 const size_t original_capacity_v1 = v1.capacity();
1479 v1.assign({3});
1480 EXPECT_THAT(
1481 v1, AllOf(SizeIs(1), CapacityIs(original_capacity_v1), ElementsAre(3)));
1482
1483 absl::InlinedVector<int, 2> v2(original_size, 12345);
1484 const size_t original_capacity_v2 = v2.capacity();
1485 v2 = {3};
1486 EXPECT_THAT(
1487 v2, AllOf(SizeIs(1), CapacityIs(original_capacity_v2), ElementsAre(3)));
1488 }
1489 }
1490
TEST(InitializerListAssign,SimpleTypeDoesNotFitInlineBacking)1491 TEST(InitializerListAssign, SimpleTypeDoesNotFitInlineBacking) {
1492 for (size_t original_size = 0; original_size <= 4; ++original_size) {
1493 SCOPED_TRACE(original_size);
1494 absl::InlinedVector<int, 2> v1(original_size, 12345);
1495 v1.assign({3, 4, 5});
1496 EXPECT_THAT(v1, AllOf(SizeIs(3), ElementsAre(3, 4, 5)));
1497 EXPECT_LE(3, v1.capacity());
1498
1499 absl::InlinedVector<int, 2> v2(original_size, 12345);
1500 v2 = {3, 4, 5};
1501 EXPECT_THAT(v2, AllOf(SizeIs(3), ElementsAre(3, 4, 5)));
1502 EXPECT_LE(3, v2.capacity());
1503 }
1504 }
1505
TEST(InitializerListAssign,DisparateTypesInList)1506 TEST(InitializerListAssign, DisparateTypesInList) {
1507 absl::InlinedVector<int, 2> v_int1;
1508 v_int1.assign({-7, 8ULL});
1509 EXPECT_THAT(v_int1, ElementsAre(-7, 8));
1510
1511 absl::InlinedVector<int, 2> v_int2;
1512 v_int2 = {-7, 8ULL};
1513 EXPECT_THAT(v_int2, ElementsAre(-7, 8));
1514
1515 absl::InlinedVector<std::string, 2> v_string1;
1516 v_string1.assign({"foo", std::string("bar")});
1517 EXPECT_THAT(v_string1, ElementsAre("foo", "bar"));
1518
1519 absl::InlinedVector<std::string, 2> v_string2;
1520 v_string2 = {"foo", std::string("bar")};
1521 EXPECT_THAT(v_string2, ElementsAre("foo", "bar"));
1522 }
1523
TYPED_TEST_P(InstanceTest,InitializerListAssign)1524 TYPED_TEST_P(InstanceTest, InitializerListAssign) {
1525 using Instance = TypeParam;
1526 for (size_t original_size = 0; original_size <= 4; ++original_size) {
1527 SCOPED_TRACE(original_size);
1528 absl::InlinedVector<Instance, 2> v(original_size, Instance(12345));
1529 const size_t original_capacity = v.capacity();
1530 v.assign({Instance(3)});
1531 EXPECT_THAT(v, AllOf(SizeIs(1), CapacityIs(original_capacity),
1532 ElementsAre(ValueIs(3))));
1533 }
1534 for (size_t original_size = 0; original_size <= 4; ++original_size) {
1535 SCOPED_TRACE(original_size);
1536 absl::InlinedVector<Instance, 2> v(original_size, Instance(12345));
1537 v.assign({Instance(3), Instance(4), Instance(5)});
1538 EXPECT_THAT(
1539 v, AllOf(SizeIs(3), ElementsAre(ValueIs(3), ValueIs(4), ValueIs(5))));
1540 EXPECT_LE(3, v.capacity());
1541 }
1542 }
1543
1544 REGISTER_TYPED_TEST_CASE_P(InstanceTest, Swap, CountConstructorsDestructors,
1545 CountConstructorsDestructorsOnCopyConstruction,
1546 CountConstructorsDestructorsOnMoveConstruction,
1547 CountConstructorsDestructorsOnAssignment,
1548 CountConstructorsDestructorsOnMoveAssignment,
1549 CountElemAssignInlineBacking, RangedConstructor,
1550 RangedAssign, InitializerListAssign);
1551
1552 using InstanceTypes =
1553 ::testing::Types<CopyableOnlyInstance, CopyableMovableInstance>;
1554 INSTANTIATE_TYPED_TEST_CASE_P(InstanceTestOnTypes, InstanceTest, InstanceTypes);
1555
TEST(DynamicVec,DynamicVecCompiles)1556 TEST(DynamicVec, DynamicVecCompiles) {
1557 DynamicVec v;
1558 (void)v;
1559 }
1560
TEST(AllocatorSupportTest,Constructors)1561 TEST(AllocatorSupportTest, Constructors) {
1562 using MyAlloc = CountingAllocator<int>;
1563 using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
1564 const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
1565 int64_t allocated = 0;
1566 MyAlloc alloc(&allocated);
1567 { AllocVec ABSL_ATTRIBUTE_UNUSED v; }
1568 { AllocVec ABSL_ATTRIBUTE_UNUSED v(alloc); }
1569 { AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc); }
1570 { AllocVec ABSL_ATTRIBUTE_UNUSED v({1, 2, 3}, alloc); }
1571
1572 AllocVec v2;
1573 { AllocVec ABSL_ATTRIBUTE_UNUSED v(v2, alloc); }
1574 { AllocVec ABSL_ATTRIBUTE_UNUSED v(std::move(v2), alloc); }
1575 }
1576
TEST(AllocatorSupportTest,CountAllocations)1577 TEST(AllocatorSupportTest, CountAllocations) {
1578 using MyAlloc = CountingAllocator<int>;
1579 using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
1580 const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
1581 int64_t allocated = 0;
1582 MyAlloc alloc(&allocated);
1583 {
1584 AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + 4, alloc);
1585 EXPECT_THAT(allocated, 0);
1586 }
1587 EXPECT_THAT(allocated, 0);
1588 {
1589 AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc);
1590 EXPECT_THAT(allocated, v.size() * sizeof(int));
1591 }
1592 EXPECT_THAT(allocated, 0);
1593 {
1594 AllocVec v(4, 1, alloc);
1595 EXPECT_THAT(allocated, 0);
1596
1597 int64_t allocated2 = 0;
1598 MyAlloc alloc2(&allocated2);
1599 AllocVec v2(v, alloc2);
1600 EXPECT_THAT(allocated2, 0);
1601
1602 int64_t allocated3 = 0;
1603 MyAlloc alloc3(&allocated3);
1604 AllocVec v3(std::move(v), alloc3);
1605 EXPECT_THAT(allocated3, 0);
1606 }
1607 EXPECT_THAT(allocated, 0);
1608 {
1609 AllocVec v(8, 2, alloc);
1610 EXPECT_THAT(allocated, v.size() * sizeof(int));
1611
1612 int64_t allocated2 = 0;
1613 MyAlloc alloc2(&allocated2);
1614 AllocVec v2(v, alloc2);
1615 EXPECT_THAT(allocated2, v2.size() * sizeof(int));
1616
1617 int64_t allocated3 = 0;
1618 MyAlloc alloc3(&allocated3);
1619 AllocVec v3(std::move(v), alloc3);
1620 EXPECT_THAT(allocated3, v3.size() * sizeof(int));
1621 }
1622 EXPECT_EQ(allocated, 0);
1623 {
1624 // Test shrink_to_fit deallocations.
1625 AllocVec v(8, 2, alloc);
1626 EXPECT_EQ(allocated, 8 * sizeof(int));
1627 v.resize(5);
1628 EXPECT_EQ(allocated, 8 * sizeof(int));
1629 v.shrink_to_fit();
1630 EXPECT_EQ(allocated, 5 * sizeof(int));
1631 v.resize(4);
1632 EXPECT_EQ(allocated, 5 * sizeof(int));
1633 v.shrink_to_fit();
1634 EXPECT_EQ(allocated, 0);
1635 }
1636 }
1637
TEST(AllocatorSupportTest,SwapBothAllocated)1638 TEST(AllocatorSupportTest, SwapBothAllocated) {
1639 using MyAlloc = CountingAllocator<int>;
1640 using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
1641 int64_t allocated1 = 0;
1642 int64_t allocated2 = 0;
1643 {
1644 const int ia1[] = {0, 1, 2, 3, 4, 5, 6, 7};
1645 const int ia2[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
1646 MyAlloc a1(&allocated1);
1647 MyAlloc a2(&allocated2);
1648 AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1);
1649 AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2);
1650 EXPECT_LT(v1.capacity(), v2.capacity());
1651 EXPECT_THAT(allocated1, v1.capacity() * sizeof(int));
1652 EXPECT_THAT(allocated2, v2.capacity() * sizeof(int));
1653 v1.swap(v2);
1654 EXPECT_THAT(v1, ElementsAreArray(ia2));
1655 EXPECT_THAT(v2, ElementsAreArray(ia1));
1656 EXPECT_THAT(allocated1, v2.capacity() * sizeof(int));
1657 EXPECT_THAT(allocated2, v1.capacity() * sizeof(int));
1658 }
1659 EXPECT_THAT(allocated1, 0);
1660 EXPECT_THAT(allocated2, 0);
1661 }
1662
TEST(AllocatorSupportTest,SwapOneAllocated)1663 TEST(AllocatorSupportTest, SwapOneAllocated) {
1664 using MyAlloc = CountingAllocator<int>;
1665 using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
1666 int64_t allocated1 = 0;
1667 int64_t allocated2 = 0;
1668 {
1669 const int ia1[] = {0, 1, 2, 3, 4, 5, 6, 7};
1670 const int ia2[] = {0, 1, 2, 3};
1671 MyAlloc a1(&allocated1);
1672 MyAlloc a2(&allocated2);
1673 AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1);
1674 AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2);
1675 EXPECT_THAT(allocated1, v1.capacity() * sizeof(int));
1676 EXPECT_THAT(allocated2, 0);
1677 v1.swap(v2);
1678 EXPECT_THAT(v1, ElementsAreArray(ia2));
1679 EXPECT_THAT(v2, ElementsAreArray(ia1));
1680 EXPECT_THAT(allocated1, v2.capacity() * sizeof(int));
1681 EXPECT_THAT(allocated2, 0);
1682 EXPECT_TRUE(v2.get_allocator() == a1);
1683 EXPECT_TRUE(v1.get_allocator() == a2);
1684 }
1685 EXPECT_THAT(allocated1, 0);
1686 EXPECT_THAT(allocated2, 0);
1687 }
1688
TEST(AllocatorSupportTest,ScopedAllocatorWorksInlined)1689 TEST(AllocatorSupportTest, ScopedAllocatorWorksInlined) {
1690 using StdVector = std::vector<int, CountingAllocator<int>>;
1691 using Alloc = CountingAllocator<StdVector>;
1692 using ScopedAlloc = std::scoped_allocator_adaptor<Alloc>;
1693 using AllocVec = absl::InlinedVector<StdVector, 1, ScopedAlloc>;
1694
1695 int64_t total_allocated_byte_count = 0;
1696
1697 AllocVec inlined_case(ScopedAlloc(Alloc(+&total_allocated_byte_count)));
1698
1699 // Called only once to remain inlined
1700 inlined_case.emplace_back();
1701
1702 int64_t absl_responsible_for_count = total_allocated_byte_count;
1703
1704 // MSVC's allocator preemptively allocates in debug mode
1705 #if !defined(_MSC_VER)
1706 EXPECT_EQ(absl_responsible_for_count, 0);
1707 #endif // !defined(_MSC_VER)
1708
1709 inlined_case[0].emplace_back();
1710 EXPECT_GT(total_allocated_byte_count, absl_responsible_for_count);
1711
1712 inlined_case.clear();
1713 inlined_case.shrink_to_fit();
1714 EXPECT_EQ(total_allocated_byte_count, 0);
1715 }
1716
TEST(AllocatorSupportTest,ScopedAllocatorWorksAllocated)1717 TEST(AllocatorSupportTest, ScopedAllocatorWorksAllocated) {
1718 using StdVector = std::vector<int, CountingAllocator<int>>;
1719 using Alloc = CountingAllocator<StdVector>;
1720 using ScopedAlloc = std::scoped_allocator_adaptor<Alloc>;
1721 using AllocVec = absl::InlinedVector<StdVector, 1, ScopedAlloc>;
1722
1723 int64_t total_allocated_byte_count = 0;
1724
1725 AllocVec allocated_case(ScopedAlloc(Alloc(+&total_allocated_byte_count)));
1726
1727 // Called twice to force into being allocated
1728 allocated_case.emplace_back();
1729 allocated_case.emplace_back();
1730
1731 int64_t absl_responsible_for_count = total_allocated_byte_count;
1732 EXPECT_GT(absl_responsible_for_count, 0);
1733
1734 allocated_case[1].emplace_back();
1735 EXPECT_GT(total_allocated_byte_count, absl_responsible_for_count);
1736
1737 allocated_case.clear();
1738 allocated_case.shrink_to_fit();
1739 EXPECT_EQ(total_allocated_byte_count, 0);
1740 }
1741
TEST(AllocatorSupportTest,SizeAllocConstructor)1742 TEST(AllocatorSupportTest, SizeAllocConstructor) {
1743 constexpr int inlined_size = 4;
1744 using Alloc = CountingAllocator<int>;
1745 using AllocVec = absl::InlinedVector<int, inlined_size, Alloc>;
1746
1747 {
1748 auto len = inlined_size / 2;
1749 int64_t allocated = 0;
1750 auto v = AllocVec(len, Alloc(&allocated));
1751
1752 // Inline storage used; allocator should not be invoked
1753 EXPECT_THAT(allocated, 0);
1754 EXPECT_THAT(v, AllOf(SizeIs(len), Each(0)));
1755 }
1756
1757 {
1758 auto len = inlined_size * 2;
1759 int64_t allocated = 0;
1760 auto v = AllocVec(len, Alloc(&allocated));
1761
1762 // Out of line storage used; allocation of 8 elements expected
1763 EXPECT_THAT(allocated, len * sizeof(int));
1764 EXPECT_THAT(v, AllOf(SizeIs(len), Each(0)));
1765 }
1766 }
1767
TEST(InlinedVectorTest,MinimumAllocatorCompilesUsingTraits)1768 TEST(InlinedVectorTest, MinimumAllocatorCompilesUsingTraits) {
1769 using T = int;
1770 using A = std::allocator<T>;
1771 using ATraits = absl::allocator_traits<A>;
1772
1773 struct MinimumAllocator {
1774 using value_type = T;
1775
1776 value_type* allocate(size_t n) {
1777 A a;
1778 return ATraits::allocate(a, n);
1779 }
1780
1781 void deallocate(value_type* p, size_t n) {
1782 A a;
1783 ATraits::deallocate(a, p, n);
1784 }
1785 };
1786
1787 absl::InlinedVector<T, 1, MinimumAllocator> vec;
1788 vec.emplace_back();
1789 vec.resize(0);
1790 }
1791
TEST(InlinedVectorTest,AbslHashValueWorks)1792 TEST(InlinedVectorTest, AbslHashValueWorks) {
1793 using V = absl::InlinedVector<int, 4>;
1794 std::vector<V> cases;
1795
1796 // Generate a variety of vectors some of these are small enough for the inline
1797 // space but are stored out of line.
1798 for (int i = 0; i < 10; ++i) {
1799 V v;
1800 for (int j = 0; j < i; ++j) {
1801 v.push_back(j);
1802 }
1803 cases.push_back(v);
1804 v.resize(i % 4);
1805 cases.push_back(v);
1806 }
1807
1808 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases));
1809 }
1810
1811 } // anonymous namespace
1812