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