aboutsummaryrefslogtreecommitdiff
path: root/absl/container/inlined_vector_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/container/inlined_vector_test.cc')
-rw-r--r--absl/container/inlined_vector_test.cc294
1 files changed, 208 insertions, 86 deletions
diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc
index 65ddbab6..898b40db 100644
--- a/absl/container/inlined_vector_test.cc
+++ b/absl/container/inlined_vector_test.cc
@@ -1208,6 +1208,8 @@ TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveAssignment) {
}
TEST(CountElemAssign, SimpleTypeWithInlineBacking) {
+ const size_t inlined_capacity = absl::InlinedVector<int, 2>().capacity();
+
for (size_t original_size = 0; original_size <= 5; ++original_size) {
SCOPED_TRACE(original_size);
// Original contents are [12345, 12345, ...]
@@ -1217,9 +1219,9 @@ TEST(CountElemAssign, SimpleTypeWithInlineBacking) {
original_contents.end());
v.assign(2, 123);
EXPECT_THAT(v, AllOf(SizeIs(2u), ElementsAre(123, 123)));
- if (original_size <= 2) {
+ if (original_size <= inlined_capacity) {
// If the original had inline backing, it should stay inline.
- EXPECT_EQ(2u, v.capacity());
+ EXPECT_EQ(v.capacity(), inlined_capacity);
}
}
}
@@ -1360,6 +1362,8 @@ TEST(RangedConstructor, ElementsAreConstructed) {
}
TEST(RangedAssign, SimpleType) {
+ const size_t inlined_capacity = absl::InlinedVector<int, 3>().capacity();
+
// Test for all combinations of original sizes (empty and non-empty inline,
// and out of line) and target sizes.
for (size_t original_size = 0; original_size <= 5; ++original_size) {
@@ -1367,13 +1371,13 @@ TEST(RangedAssign, SimpleType) {
// Original contents are [12345, 12345, ...]
std::vector<int> original_contents(original_size, 12345);
- for (int target_size = 0; target_size <= 5; ++target_size) {
+ for (size_t target_size = 0; target_size <= 5; ++target_size) {
SCOPED_TRACE(target_size);
// New contents are [3, 4, ...]
std::vector<int> new_contents;
- for (int i = 0; i < target_size; ++i) {
- new_contents.push_back(i + 3);
+ for (size_t i = 0; i < target_size; ++i) {
+ new_contents.push_back(static_cast<int>(i + 3));
}
absl::InlinedVector<int, 3> v(original_contents.begin(),
@@ -1382,9 +1386,10 @@ TEST(RangedAssign, SimpleType) {
EXPECT_EQ(new_contents.size(), v.size());
EXPECT_LE(new_contents.size(), v.capacity());
- if (target_size <= 3 && original_size <= 3) {
+ if (target_size <= inlined_capacity &&
+ original_size <= inlined_capacity) {
// Storage should stay inline when target size is small.
- EXPECT_EQ(3u, v.capacity());
+ EXPECT_EQ(v.capacity(), inlined_capacity);
}
EXPECT_THAT(v, ElementsAreArray(new_contents));
}
@@ -1470,9 +1475,12 @@ TEST(InitializerListConstructor, DisparateTypesInList) {
}
TEST(InitializerListConstructor, ComplexTypeWithInlineBacking) {
- EXPECT_THAT((absl::InlinedVector<CopyableMovableInstance, 1>{
- CopyableMovableInstance(0)}),
- AllOf(SizeIs(1u), CapacityIs(1u), ElementsAre(ValueIs(0))));
+ const size_t inlined_capacity =
+ absl::InlinedVector<CopyableMovableInstance, 1>().capacity();
+ EXPECT_THAT(
+ (absl::InlinedVector<CopyableMovableInstance, 1>{
+ CopyableMovableInstance(0)}),
+ AllOf(SizeIs(1u), CapacityIs(inlined_capacity), ElementsAre(ValueIs(0))));
}
TEST(InitializerListConstructor, ComplexTypeWithReallocationRequired) {
@@ -1841,98 +1849,212 @@ MATCHER(HasValue, "") {
return ::testing::get<0>(arg).value() == ::testing::get<1>(arg);
}
-TEST(MoveAssignment, NonAssignable) {
+TEST(NonAssignableMoveAssignmentTest, AllocatedToInline) {
using X = MoveConstructibleOnlyInstance;
- {
- InstanceTracker tracker;
- absl::InlinedVector<X, 2> inlined;
- inlined.emplace_back(1);
- absl::InlinedVector<X, 2> allocated;
- allocated.emplace_back(1);
- allocated.emplace_back(2);
- allocated.emplace_back(3);
- tracker.ResetCopiesMovesSwaps();
+ InstanceTracker tracker;
+ absl::InlinedVector<X, 2> inlined;
+ inlined.emplace_back(1);
+ absl::InlinedVector<X, 2> allocated;
+ allocated.emplace_back(1);
+ allocated.emplace_back(2);
+ allocated.emplace_back(3);
+ tracker.ResetCopiesMovesSwaps();
- inlined = std::move(allocated);
- // passed ownership of the allocated storage
- EXPECT_EQ(tracker.moves(), 0);
- EXPECT_EQ(tracker.live_instances(), 3);
+ inlined = std::move(allocated);
+ // passed ownership of the allocated storage
+ EXPECT_EQ(tracker.moves(), 0);
+ EXPECT_EQ(tracker.live_instances(), 3);
- EXPECT_THAT(inlined, Pointwise(HasValue(), {1, 2, 3}));
- }
+ EXPECT_THAT(inlined, Pointwise(HasValue(), {1, 2, 3}));
+}
- {
- InstanceTracker tracker;
- absl::InlinedVector<X, 2> inlined;
- inlined.emplace_back(1);
- absl::InlinedVector<X, 2> allocated;
- allocated.emplace_back(1);
- allocated.emplace_back(2);
- allocated.emplace_back(3);
- tracker.ResetCopiesMovesSwaps();
+TEST(NonAssignableMoveAssignmentTest, InlineToAllocated) {
+ using X = MoveConstructibleOnlyInstance;
+ InstanceTracker tracker;
+ absl::InlinedVector<X, 2> inlined;
+ inlined.emplace_back(1);
+ absl::InlinedVector<X, 2> allocated;
+ allocated.emplace_back(1);
+ allocated.emplace_back(2);
+ allocated.emplace_back(3);
+ tracker.ResetCopiesMovesSwaps();
- allocated = std::move(inlined);
- // Moved elements
- EXPECT_EQ(tracker.moves(), 1);
- EXPECT_EQ(tracker.live_instances(), 1);
+ allocated = std::move(inlined);
+ // Moved elements
+ EXPECT_EQ(tracker.moves(), 1);
+ EXPECT_EQ(tracker.live_instances(), 1);
- EXPECT_THAT(allocated, Pointwise(HasValue(), {1}));
- }
+ EXPECT_THAT(allocated, Pointwise(HasValue(), {1}));
+}
- {
- InstanceTracker tracker;
- absl::InlinedVector<X, 2> inlined_a;
- inlined_a.emplace_back(1);
- absl::InlinedVector<X, 2> inlined_b;
- inlined_b.emplace_back(1);
- tracker.ResetCopiesMovesSwaps();
+TEST(NonAssignableMoveAssignmentTest, InlineToInline) {
+ using X = MoveConstructibleOnlyInstance;
+ InstanceTracker tracker;
+ absl::InlinedVector<X, 2> inlined_a;
+ inlined_a.emplace_back(1);
+ absl::InlinedVector<X, 2> inlined_b;
+ inlined_b.emplace_back(1);
+ tracker.ResetCopiesMovesSwaps();
- inlined_a = std::move(inlined_b);
- // Moved elements
- EXPECT_EQ(tracker.moves(), 1);
- EXPECT_EQ(tracker.live_instances(), 1);
+ inlined_a = std::move(inlined_b);
+ // Moved elements
+ EXPECT_EQ(tracker.moves(), 1);
+ EXPECT_EQ(tracker.live_instances(), 1);
- EXPECT_THAT(inlined_a, Pointwise(HasValue(), {1}));
- }
+ EXPECT_THAT(inlined_a, Pointwise(HasValue(), {1}));
+}
- {
- InstanceTracker tracker;
- absl::InlinedVector<X, 2> allocated_a;
- allocated_a.emplace_back(1);
- allocated_a.emplace_back(2);
- allocated_a.emplace_back(3);
- absl::InlinedVector<X, 2> allocated_b;
- allocated_b.emplace_back(4);
- allocated_b.emplace_back(5);
- allocated_b.emplace_back(6);
- allocated_b.emplace_back(7);
- tracker.ResetCopiesMovesSwaps();
+TEST(NonAssignableMoveAssignmentTest, AllocatedToAllocated) {
+ using X = MoveConstructibleOnlyInstance;
+ InstanceTracker tracker;
+ absl::InlinedVector<X, 2> allocated_a;
+ allocated_a.emplace_back(1);
+ allocated_a.emplace_back(2);
+ allocated_a.emplace_back(3);
+ absl::InlinedVector<X, 2> allocated_b;
+ allocated_b.emplace_back(4);
+ allocated_b.emplace_back(5);
+ allocated_b.emplace_back(6);
+ allocated_b.emplace_back(7);
+ tracker.ResetCopiesMovesSwaps();
- allocated_a = std::move(allocated_b);
- // passed ownership of the allocated storage
- EXPECT_EQ(tracker.moves(), 0);
- EXPECT_EQ(tracker.live_instances(), 4);
+ allocated_a = std::move(allocated_b);
+ // passed ownership of the allocated storage
+ EXPECT_EQ(tracker.moves(), 0);
+ EXPECT_EQ(tracker.live_instances(), 4);
- EXPECT_THAT(allocated_a, Pointwise(HasValue(), {4, 5, 6, 7}));
- }
+ EXPECT_THAT(allocated_a, Pointwise(HasValue(), {4, 5, 6, 7}));
+}
- {
- InstanceTracker tracker;
- absl::InlinedVector<X, 2> v;
- v.emplace_back(1);
- v.emplace_back(2);
- v.emplace_back(3);
+TEST(NonAssignableMoveAssignmentTest, AssignThis) {
+ using X = MoveConstructibleOnlyInstance;
+ InstanceTracker tracker;
+ absl::InlinedVector<X, 2> v;
+ v.emplace_back(1);
+ v.emplace_back(2);
+ v.emplace_back(3);
- tracker.ResetCopiesMovesSwaps();
+ tracker.ResetCopiesMovesSwaps();
- // Obfuscated in order to pass -Wself-move.
- v = std::move(*std::addressof(v));
- // nothing happens
- EXPECT_EQ(tracker.moves(), 0);
- EXPECT_EQ(tracker.live_instances(), 3);
+ // Obfuscated in order to pass -Wself-move.
+ v = std::move(*std::addressof(v));
+ // nothing happens
+ EXPECT_EQ(tracker.moves(), 0);
+ EXPECT_EQ(tracker.live_instances(), 3);
- EXPECT_THAT(v, Pointwise(HasValue(), {1, 2, 3}));
- }
+ EXPECT_THAT(v, Pointwise(HasValue(), {1, 2, 3}));
+}
+
+class NonSwappableInstance : public absl::test_internal::BaseCountedInstance {
+ public:
+ explicit NonSwappableInstance(int x) : BaseCountedInstance(x) {}
+ NonSwappableInstance(const NonSwappableInstance& other) = default;
+ NonSwappableInstance& operator=(const NonSwappableInstance& other) = default;
+ NonSwappableInstance(NonSwappableInstance&& other) = default;
+ NonSwappableInstance& operator=(NonSwappableInstance&& other) = default;
+};
+
+void swap(NonSwappableInstance&, NonSwappableInstance&) = delete;
+
+TEST(NonSwappableSwapTest, InlineAndAllocatedTransferStorageAndMove) {
+ using X = NonSwappableInstance;
+ InstanceTracker tracker;
+ absl::InlinedVector<X, 2> inlined;
+ inlined.emplace_back(1);
+ absl::InlinedVector<X, 2> allocated;
+ allocated.emplace_back(1);
+ allocated.emplace_back(2);
+ allocated.emplace_back(3);
+ tracker.ResetCopiesMovesSwaps();
+
+ inlined.swap(allocated);
+ EXPECT_EQ(tracker.moves(), 1);
+ EXPECT_EQ(tracker.live_instances(), 4);
+
+ EXPECT_THAT(inlined, Pointwise(HasValue(), {1, 2, 3}));
+}
+
+TEST(NonSwappableSwapTest, InlineAndInlineMoveIndividualElements) {
+ using X = NonSwappableInstance;
+ InstanceTracker tracker;
+ absl::InlinedVector<X, 2> inlined_a;
+ inlined_a.emplace_back(1);
+ absl::InlinedVector<X, 2> inlined_b;
+ inlined_b.emplace_back(2);
+ tracker.ResetCopiesMovesSwaps();
+
+ inlined_a.swap(inlined_b);
+ EXPECT_EQ(tracker.moves(), 3);
+ EXPECT_EQ(tracker.live_instances(), 2);
+
+ EXPECT_THAT(inlined_a, Pointwise(HasValue(), {2}));
+ EXPECT_THAT(inlined_b, Pointwise(HasValue(), {1}));
+}
+
+TEST(NonSwappableSwapTest, AllocatedAndAllocatedOnlyTransferStorage) {
+ using X = NonSwappableInstance;
+ InstanceTracker tracker;
+ absl::InlinedVector<X, 2> allocated_a;
+ allocated_a.emplace_back(1);
+ allocated_a.emplace_back(2);
+ allocated_a.emplace_back(3);
+ absl::InlinedVector<X, 2> allocated_b;
+ allocated_b.emplace_back(4);
+ allocated_b.emplace_back(5);
+ allocated_b.emplace_back(6);
+ allocated_b.emplace_back(7);
+ tracker.ResetCopiesMovesSwaps();
+
+ allocated_a.swap(allocated_b);
+ EXPECT_EQ(tracker.moves(), 0);
+ EXPECT_EQ(tracker.live_instances(), 7);
+
+ EXPECT_THAT(allocated_a, Pointwise(HasValue(), {4, 5, 6, 7}));
+ EXPECT_THAT(allocated_b, Pointwise(HasValue(), {1, 2, 3}));
+}
+
+TEST(NonSwappableSwapTest, SwapThis) {
+ using X = NonSwappableInstance;
+ InstanceTracker tracker;
+ absl::InlinedVector<X, 2> v;
+ v.emplace_back(1);
+ v.emplace_back(2);
+ v.emplace_back(3);
+
+ tracker.ResetCopiesMovesSwaps();
+
+ v.swap(v);
+ EXPECT_EQ(tracker.moves(), 0);
+ EXPECT_EQ(tracker.live_instances(), 3);
+
+ EXPECT_THAT(v, Pointwise(HasValue(), {1, 2, 3}));
+}
+
+template <size_t N>
+using CharVec = absl::InlinedVector<char, N>;
+
+// Warning: This struct "simulates" the type `InlinedVector::Storage::Allocated`
+// to make reasonable expectations for inlined storage capacity optimization. If
+// implementation changes `Allocated`, then `MySpan` and tests that use it need
+// to be updated accordingly.
+template <typename T>
+struct MySpan {
+ T* data;
+ size_t size;
+};
+
+TEST(StorageTest, InlinedCapacityAutoIncrease) {
+ // The requested capacity is auto increased to `sizeof(MySpan<char>)`.
+ EXPECT_GT(CharVec<1>().capacity(), 1);
+ EXPECT_EQ(CharVec<1>().capacity(), sizeof(MySpan<char>));
+ EXPECT_EQ(CharVec<1>().capacity(), CharVec<2>().capacity());
+ EXPECT_EQ(sizeof(CharVec<1>), sizeof(CharVec<2>));
+
+ // The requested capacity is auto increased to
+ // `sizeof(MySpan<int>) / sizeof(int)`.
+ EXPECT_GT((absl::InlinedVector<int, 1>().capacity()), 1);
+ EXPECT_EQ((absl::InlinedVector<int, 1>().capacity()),
+ sizeof(MySpan<int>) / sizeof(int));
}
} // anonymous namespace