blob: 98aff33498b2f939045e1d98bea64c5139cb60cb [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001// 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"
Austin Schuhb4691e92020-12-31 12:37:18 -080033#include "absl/base/options.h"
Austin Schuh36244a12019-09-21 17:52:38 -070034#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
40namespace {
41
42using absl::container_internal::CountingAllocator;
43using absl::test_internal::CopyableMovableInstance;
44using absl::test_internal::CopyableOnlyInstance;
45using absl::test_internal::InstanceTracker;
46using testing::AllOf;
47using testing::Each;
48using testing::ElementsAre;
49using testing::ElementsAreArray;
50using testing::Eq;
51using testing::Gt;
52using testing::PrintToString;
53
54using IntVec = absl::InlinedVector<int, 8>;
55
56MATCHER_P(SizeIs, n, "") {
57 return testing::ExplainMatchResult(n, arg.size(), result_listener);
58}
59
60MATCHER_P(CapacityIs, n, "") {
61 return testing::ExplainMatchResult(n, arg.capacity(), result_listener);
62}
63
64MATCHER_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.
72template <typename T>
73class InstanceTest : public ::testing::Test {};
74TYPED_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.
78class RefCounted {
79 public:
80 RefCounted(int value, int* count) : value_(value), count_(count) { Ref(); }
81
82 RefCounted(const RefCounted& v) : value_(v.value_), count_(v.count_) {
83 Ref();
84 }
85
86 ~RefCounted() {
87 Unref();
88 count_ = nullptr;
89 }
90
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
97 RefCounted& operator=(RefCounted v) {
98 using std::swap;
99 swap(*this, v);
100 return *this;
101 }
102
103 void Ref() const {
104 ABSL_RAW_CHECK(count_ != nullptr, "");
105 ++(*count_);
106 }
107
108 void Unref() const {
109 --(*count_);
110 ABSL_RAW_CHECK(*count_ >= 0, "");
111 }
112
113 int value_;
114 int* count_;
115};
116
117using RefCountedVec = absl::InlinedVector<RefCounted, 8>;
118
119// A class with a vtable pointer
120class Dynamic {
121 public:
122 virtual ~Dynamic() {}
123};
124
125using DynamicVec = absl::InlinedVector<Dynamic, 8>;
126
127// Append 0..len-1 to *v
128template <typename Container>
129static 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
135static IntVec Fill(int len, int offset = 0) {
136 IntVec v;
137 Fill(&v, len, offset);
138 return v;
139}
140
141TEST(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
191TEST(IntVec, PopBackNoOverflow) {
192 IntVec v = {1};
193 v.pop_back();
194 EXPECT_EQ(v.size(), 0);
195}
196
197TEST(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
204TEST(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
234TEST(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
Austin Schuhb4691e92020-12-31 12:37:18 -0800251TEST(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
Austin Schuh36244a12019-09-21 17:52:38 -0700261// 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.
264TEST(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
309struct NoDefaultCtor {
310 explicit NoDefaultCtor(int) {}
311};
312struct NoCopy {
313 NoCopy() {}
314 NoCopy(const NoCopy&) = delete;
315};
316struct NoAssign {
317 NoAssign() {}
318 NoAssign& operator=(const NoAssign&) = delete;
319};
320struct MoveOnly {
321 MoveOnly() {}
322 MoveOnly(MoveOnly&&) = default;
323 MoveOnly& operator=(MoveOnly&&) = default;
324};
325TEST(InlinedVectorTest, NoDefaultCtor) {
326 absl::InlinedVector<NoDefaultCtor, 1> v(10, NoDefaultCtor(2));
327 (void)v;
328}
329TEST(InlinedVectorTest, NoCopy) {
330 absl::InlinedVector<NoCopy, 1> v(10);
331 (void)v;
332}
333TEST(InlinedVectorTest, NoAssign) {
334 absl::InlinedVector<NoAssign, 1> v(10);
335 (void)v;
336}
337TEST(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}
349TEST(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
362TEST(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
376TEST(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
397TEST(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
439TEST(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
526TEST(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
554TEST(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
585TEST(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
596TEST(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
615TEST(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
625TEST(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
662class NotTriviallyDestructible {
663 public:
664 NotTriviallyDestructible() : p_(new int(1)) {}
665 explicit NotTriviallyDestructible(int i) : p_(new int(i)) {}
666
667 NotTriviallyDestructible(const NotTriviallyDestructible& other)
668 : p_(new int(*other.p_)) {}
669
670 NotTriviallyDestructible& operator=(const NotTriviallyDestructible& other) {
671 p_ = absl::make_unique<int>(*other.p_);
672 return *this;
673 }
674
675 bool operator==(const NotTriviallyDestructible& other) const {
676 return *p_ == *other.p_;
677 }
678
679 private:
680 std::unique_ptr<int> p_;
681};
682
683TEST(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
698TEST(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
734TEST(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.
Austin Schuhb4691e92020-12-31 12:37:18 -0800739
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]));
Austin Schuh36244a12019-09-21 17:52:38 -0700759}
760
761TEST(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
772TEST(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
795TEST(StringVec, SelfRefPushBack) {
796 std::vector<std::string> std_v;
797 absl::InlinedVector<std::string, 4> v;
Austin Schuhb4691e92020-12-31 12:37:18 -0800798 const std::string s = "A quite long string to ensure heap.";
Austin Schuh36244a12019-09-21 17:52:38 -0700799 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
810TEST(StringVec, SelfRefPushBackWithMove) {
811 std::vector<std::string> std_v;
812 absl::InlinedVector<std::string, 4> v;
Austin Schuhb4691e92020-12-31 12:37:18 -0800813 const std::string s = "A quite long string to ensure heap.";
Austin Schuh36244a12019-09-21 17:52:38 -0700814 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
825TEST(StringVec, SelfMove) {
Austin Schuhb4691e92020-12-31 12:37:18 -0800826 const std::string s = "A quite long string to ensure heap.";
Austin Schuh36244a12019-09-21 17:52:38 -0700827 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
843TEST(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
868TYPED_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
916TEST(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
955TEST(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
976TYPED_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
1044TYPED_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
1070TYPED_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
1114TYPED_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
1149TYPED_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
1203TEST(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
1220TEST(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
1234TYPED_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
1252template <typename Instance>
1253void 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}
1267TEST(CountElemAssign, WithAllocationCopyableInstance) {
1268 InstanceCountElemAssignWithAllocationTest<CopyableOnlyInstance>();
1269}
1270TEST(CountElemAssign, WithAllocationCopyableMovableInstance) {
1271 InstanceCountElemAssignWithAllocationTest<CopyableMovableInstance>();
1272}
1273
1274TEST(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.
1295template <typename Instance, typename SourceContainer, int inlined_capacity>
1296void 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
1310template <typename Instance, int inlined_capacity>
1311void 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
1336TYPED_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
1344TEST(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
1354TEST(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.
1387template <typename Instance>
1388static 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.
1394template <typename Instance, typename SourceContainer>
1395void 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
1433TYPED_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
1447TEST(InitializerListConstructor, SimpleTypeWithInlineBacking) {
1448 EXPECT_THAT((absl::InlinedVector<int, 4>{4, 5, 6}),
1449 AllOf(SizeIs(3), CapacityIs(4), ElementsAre(4, 5, 6)));
1450}
1451
1452TEST(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
1457TEST(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
1464TEST(InitializerListConstructor, ComplexTypeWithInlineBacking) {
1465 EXPECT_THAT((absl::InlinedVector<CopyableMovableInstance, 1>{
1466 CopyableMovableInstance(0)}),
1467 AllOf(SizeIs(1), CapacityIs(1), ElementsAre(ValueIs(0))));
1468}
1469
1470TEST(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
1477TEST(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
1495TEST(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
1510TEST(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
1528TYPED_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
1548REGISTER_TYPED_TEST_CASE_P(InstanceTest, Swap, CountConstructorsDestructors,
1549 CountConstructorsDestructorsOnCopyConstruction,
1550 CountConstructorsDestructorsOnMoveConstruction,
1551 CountConstructorsDestructorsOnAssignment,
1552 CountConstructorsDestructorsOnMoveAssignment,
1553 CountElemAssignInlineBacking, RangedConstructor,
1554 RangedAssign, InitializerListAssign);
1555
1556using InstanceTypes =
1557 ::testing::Types<CopyableOnlyInstance, CopyableMovableInstance>;
1558INSTANTIATE_TYPED_TEST_CASE_P(InstanceTestOnTypes, InstanceTest, InstanceTypes);
1559
1560TEST(DynamicVec, DynamicVecCompiles) {
1561 DynamicVec v;
1562 (void)v;
1563}
1564
1565TEST(AllocatorSupportTest, Constructors) {
1566 using MyAlloc = CountingAllocator<int>;
1567 using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
1568 const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
1569 int64_t allocated = 0;
1570 MyAlloc alloc(&allocated);
1571 { AllocVec ABSL_ATTRIBUTE_UNUSED v; }
1572 { AllocVec ABSL_ATTRIBUTE_UNUSED v(alloc); }
1573 { AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc); }
1574 { AllocVec ABSL_ATTRIBUTE_UNUSED v({1, 2, 3}, alloc); }
1575
1576 AllocVec v2;
1577 { AllocVec ABSL_ATTRIBUTE_UNUSED v(v2, alloc); }
1578 { AllocVec ABSL_ATTRIBUTE_UNUSED v(std::move(v2), alloc); }
1579}
1580
1581TEST(AllocatorSupportTest, CountAllocations) {
1582 using MyAlloc = CountingAllocator<int>;
1583 using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
1584 const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
1585 int64_t allocated = 0;
1586 MyAlloc alloc(&allocated);
1587 {
1588 AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + 4, alloc);
1589 EXPECT_THAT(allocated, 0);
1590 }
1591 EXPECT_THAT(allocated, 0);
1592 {
1593 AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc);
1594 EXPECT_THAT(allocated, v.size() * sizeof(int));
1595 }
1596 EXPECT_THAT(allocated, 0);
1597 {
1598 AllocVec v(4, 1, alloc);
1599 EXPECT_THAT(allocated, 0);
1600
1601 int64_t allocated2 = 0;
1602 MyAlloc alloc2(&allocated2);
1603 AllocVec v2(v, alloc2);
1604 EXPECT_THAT(allocated2, 0);
1605
1606 int64_t allocated3 = 0;
1607 MyAlloc alloc3(&allocated3);
1608 AllocVec v3(std::move(v), alloc3);
1609 EXPECT_THAT(allocated3, 0);
1610 }
1611 EXPECT_THAT(allocated, 0);
1612 {
1613 AllocVec v(8, 2, alloc);
1614 EXPECT_THAT(allocated, v.size() * sizeof(int));
1615
1616 int64_t allocated2 = 0;
1617 MyAlloc alloc2(&allocated2);
1618 AllocVec v2(v, alloc2);
1619 EXPECT_THAT(allocated2, v2.size() * sizeof(int));
1620
1621 int64_t allocated3 = 0;
1622 MyAlloc alloc3(&allocated3);
1623 AllocVec v3(std::move(v), alloc3);
1624 EXPECT_THAT(allocated3, v3.size() * sizeof(int));
1625 }
1626 EXPECT_EQ(allocated, 0);
1627 {
1628 // Test shrink_to_fit deallocations.
1629 AllocVec v(8, 2, alloc);
1630 EXPECT_EQ(allocated, 8 * sizeof(int));
1631 v.resize(5);
1632 EXPECT_EQ(allocated, 8 * sizeof(int));
1633 v.shrink_to_fit();
1634 EXPECT_EQ(allocated, 5 * sizeof(int));
1635 v.resize(4);
1636 EXPECT_EQ(allocated, 5 * sizeof(int));
1637 v.shrink_to_fit();
1638 EXPECT_EQ(allocated, 0);
1639 }
1640}
1641
1642TEST(AllocatorSupportTest, SwapBothAllocated) {
1643 using MyAlloc = CountingAllocator<int>;
1644 using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
1645 int64_t allocated1 = 0;
1646 int64_t allocated2 = 0;
1647 {
1648 const int ia1[] = {0, 1, 2, 3, 4, 5, 6, 7};
1649 const int ia2[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
1650 MyAlloc a1(&allocated1);
1651 MyAlloc a2(&allocated2);
1652 AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1);
1653 AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2);
1654 EXPECT_LT(v1.capacity(), v2.capacity());
1655 EXPECT_THAT(allocated1, v1.capacity() * sizeof(int));
1656 EXPECT_THAT(allocated2, v2.capacity() * sizeof(int));
1657 v1.swap(v2);
1658 EXPECT_THAT(v1, ElementsAreArray(ia2));
1659 EXPECT_THAT(v2, ElementsAreArray(ia1));
1660 EXPECT_THAT(allocated1, v2.capacity() * sizeof(int));
1661 EXPECT_THAT(allocated2, v1.capacity() * sizeof(int));
1662 }
1663 EXPECT_THAT(allocated1, 0);
1664 EXPECT_THAT(allocated2, 0);
1665}
1666
1667TEST(AllocatorSupportTest, SwapOneAllocated) {
1668 using MyAlloc = CountingAllocator<int>;
1669 using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
1670 int64_t allocated1 = 0;
1671 int64_t allocated2 = 0;
1672 {
1673 const int ia1[] = {0, 1, 2, 3, 4, 5, 6, 7};
1674 const int ia2[] = {0, 1, 2, 3};
1675 MyAlloc a1(&allocated1);
1676 MyAlloc a2(&allocated2);
1677 AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1);
1678 AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2);
1679 EXPECT_THAT(allocated1, v1.capacity() * sizeof(int));
1680 EXPECT_THAT(allocated2, 0);
1681 v1.swap(v2);
1682 EXPECT_THAT(v1, ElementsAreArray(ia2));
1683 EXPECT_THAT(v2, ElementsAreArray(ia1));
1684 EXPECT_THAT(allocated1, v2.capacity() * sizeof(int));
1685 EXPECT_THAT(allocated2, 0);
1686 EXPECT_TRUE(v2.get_allocator() == a1);
1687 EXPECT_TRUE(v1.get_allocator() == a2);
1688 }
1689 EXPECT_THAT(allocated1, 0);
1690 EXPECT_THAT(allocated2, 0);
1691}
1692
1693TEST(AllocatorSupportTest, ScopedAllocatorWorksInlined) {
1694 using StdVector = std::vector<int, CountingAllocator<int>>;
1695 using Alloc = CountingAllocator<StdVector>;
1696 using ScopedAlloc = std::scoped_allocator_adaptor<Alloc>;
1697 using AllocVec = absl::InlinedVector<StdVector, 1, ScopedAlloc>;
1698
1699 int64_t total_allocated_byte_count = 0;
1700
1701 AllocVec inlined_case(ScopedAlloc(Alloc(+&total_allocated_byte_count)));
1702
1703 // Called only once to remain inlined
1704 inlined_case.emplace_back();
1705
1706 int64_t absl_responsible_for_count = total_allocated_byte_count;
1707
1708 // MSVC's allocator preemptively allocates in debug mode
1709#if !defined(_MSC_VER)
1710 EXPECT_EQ(absl_responsible_for_count, 0);
1711#endif // !defined(_MSC_VER)
1712
1713 inlined_case[0].emplace_back();
1714 EXPECT_GT(total_allocated_byte_count, absl_responsible_for_count);
1715
1716 inlined_case.clear();
1717 inlined_case.shrink_to_fit();
1718 EXPECT_EQ(total_allocated_byte_count, 0);
1719}
1720
1721TEST(AllocatorSupportTest, ScopedAllocatorWorksAllocated) {
1722 using StdVector = std::vector<int, CountingAllocator<int>>;
1723 using Alloc = CountingAllocator<StdVector>;
1724 using ScopedAlloc = std::scoped_allocator_adaptor<Alloc>;
1725 using AllocVec = absl::InlinedVector<StdVector, 1, ScopedAlloc>;
1726
1727 int64_t total_allocated_byte_count = 0;
1728
1729 AllocVec allocated_case(ScopedAlloc(Alloc(+&total_allocated_byte_count)));
1730
1731 // Called twice to force into being allocated
1732 allocated_case.emplace_back();
1733 allocated_case.emplace_back();
1734
1735 int64_t absl_responsible_for_count = total_allocated_byte_count;
1736 EXPECT_GT(absl_responsible_for_count, 0);
1737
1738 allocated_case[1].emplace_back();
1739 EXPECT_GT(total_allocated_byte_count, absl_responsible_for_count);
1740
1741 allocated_case.clear();
1742 allocated_case.shrink_to_fit();
1743 EXPECT_EQ(total_allocated_byte_count, 0);
1744}
1745
1746TEST(AllocatorSupportTest, SizeAllocConstructor) {
1747 constexpr int inlined_size = 4;
1748 using Alloc = CountingAllocator<int>;
1749 using AllocVec = absl::InlinedVector<int, inlined_size, Alloc>;
1750
1751 {
1752 auto len = inlined_size / 2;
1753 int64_t allocated = 0;
1754 auto v = AllocVec(len, Alloc(&allocated));
1755
1756 // Inline storage used; allocator should not be invoked
1757 EXPECT_THAT(allocated, 0);
1758 EXPECT_THAT(v, AllOf(SizeIs(len), Each(0)));
1759 }
1760
1761 {
1762 auto len = inlined_size * 2;
1763 int64_t allocated = 0;
1764 auto v = AllocVec(len, Alloc(&allocated));
1765
1766 // Out of line storage used; allocation of 8 elements expected
1767 EXPECT_THAT(allocated, len * sizeof(int));
1768 EXPECT_THAT(v, AllOf(SizeIs(len), Each(0)));
1769 }
1770}
1771
Austin Schuhb4691e92020-12-31 12:37:18 -08001772TEST(InlinedVectorTest, MinimumAllocatorCompilesUsingTraits) {
1773 using T = int;
1774 using A = std::allocator<T>;
1775 using ATraits = absl::allocator_traits<A>;
1776
1777 struct MinimumAllocator {
1778 using value_type = T;
1779
1780 value_type* allocate(size_t n) {
1781 A a;
1782 return ATraits::allocate(a, n);
1783 }
1784
1785 void deallocate(value_type* p, size_t n) {
1786 A a;
1787 ATraits::deallocate(a, p, n);
1788 }
1789 };
1790
1791 absl::InlinedVector<T, 1, MinimumAllocator> vec;
1792 vec.emplace_back();
1793 vec.resize(0);
1794}
1795
Austin Schuh36244a12019-09-21 17:52:38 -07001796TEST(InlinedVectorTest, AbslHashValueWorks) {
1797 using V = absl::InlinedVector<int, 4>;
1798 std::vector<V> cases;
1799
1800 // Generate a variety of vectors some of these are small enough for the inline
1801 // space but are stored out of line.
1802 for (int i = 0; i < 10; ++i) {
1803 V v;
1804 for (int j = 0; j < i; ++j) {
1805 v.push_back(j);
1806 }
1807 cases.push_back(v);
1808 v.resize(i % 4);
1809 cases.push_back(v);
1810 }
1811
1812 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases));
1813}
1814
1815} // anonymous namespace