1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/containers/vector_buffer.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/memory/raw_ptr.h"
9 #include "base/test/copy_only_int.h"
10 #include "base/test/move_only_int.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12
13 namespace base::internal {
14
15 namespace {
16
17 class TRIVIAL_ABI TrivialAbiWithCountingOperations {
18 public:
TrivialAbiWithCountingOperations(int * destruction_counter,int * move_counter)19 TrivialAbiWithCountingOperations(int* destruction_counter, int* move_counter)
20 : destruction_counter_(destruction_counter),
21 move_counter_(move_counter) {}
22
~TrivialAbiWithCountingOperations()23 ~TrivialAbiWithCountingOperations() { ++*destruction_counter_; }
24
25 // Copy construction and assignment should not be used.
26 TrivialAbiWithCountingOperations(const TrivialAbiWithCountingOperations&) =
27 delete;
28 TrivialAbiWithCountingOperations& operator=(
29 const TrivialAbiWithCountingOperations&) = delete;
30
31 // Count how many times the move constructor is used.
TrivialAbiWithCountingOperations(TrivialAbiWithCountingOperations && rhs)32 TrivialAbiWithCountingOperations(TrivialAbiWithCountingOperations&& rhs)
33 : destruction_counter_(rhs.destruction_counter_),
34 move_counter_(rhs.move_counter_) {
35 ++*move_counter_;
36 }
37
38 // Move assignment should not be used.
39 TrivialAbiWithCountingOperations& operator=(
40 TrivialAbiWithCountingOperations&&) = delete;
41
42 private:
43 raw_ptr<int> destruction_counter_;
44 raw_ptr<int> move_counter_;
45 };
46
47 } // namespace
48
TEST(VectorBuffer,DeletePOD)49 TEST(VectorBuffer, DeletePOD) {
50 constexpr int size = 10;
51 VectorBuffer<int> buffer(size);
52 for (int i = 0; i < size; i++)
53 buffer.begin()[i] = i + 1;
54
55 buffer.DestructRange(buffer.begin(), buffer.end());
56
57 // Delete should do nothing.
58 for (int i = 0; i < size; i++)
59 EXPECT_EQ(i + 1, buffer.begin()[i]);
60 }
61
TEST(VectorBuffer,DeleteMoveOnly)62 TEST(VectorBuffer, DeleteMoveOnly) {
63 constexpr int size = 10;
64 VectorBuffer<MoveOnlyInt> buffer(size);
65 for (int i = 0; i < size; i++)
66 new (buffer.begin() + i) MoveOnlyInt(i + 1);
67
68 buffer.DestructRange(buffer.begin(), buffer.end());
69
70 // Delete should have reset all of the values to 0.
71 for (int i = 0; i < size; i++)
72 EXPECT_EQ(0, buffer.begin()[i].data());
73 }
74
TEST(VectorBuffer,PODMove)75 TEST(VectorBuffer, PODMove) {
76 constexpr int size = 10;
77 VectorBuffer<int> dest(size);
78
79 VectorBuffer<int> original(size);
80 for (int i = 0; i < size; i++)
81 original.begin()[i] = i + 1;
82
83 original.MoveRange(original.begin(), original.end(), dest.begin());
84 for (int i = 0; i < size; i++)
85 EXPECT_EQ(i + 1, dest.begin()[i]);
86 }
87
TEST(VectorBuffer,MovableMove)88 TEST(VectorBuffer, MovableMove) {
89 constexpr int size = 10;
90 VectorBuffer<MoveOnlyInt> dest(size);
91
92 VectorBuffer<MoveOnlyInt> original(size);
93 for (int i = 0; i < size; i++)
94 new (original.begin() + i) MoveOnlyInt(i + 1);
95
96 original.MoveRange(original.begin(), original.end(), dest.begin());
97
98 // Moving from a MoveOnlyInt resets to 0.
99 for (int i = 0; i < size; i++) {
100 EXPECT_EQ(0, original.begin()[i].data());
101 EXPECT_EQ(i + 1, dest.begin()[i].data());
102 }
103 }
104
TEST(VectorBuffer,CopyToMove)105 TEST(VectorBuffer, CopyToMove) {
106 constexpr int size = 10;
107 VectorBuffer<CopyOnlyInt> dest(size);
108
109 VectorBuffer<CopyOnlyInt> original(size);
110 for (int i = 0; i < size; i++)
111 new (original.begin() + i) CopyOnlyInt(i + 1);
112
113 original.MoveRange(original.begin(), original.end(), dest.begin());
114
115 // The original should have been destructed, which should reset the value to
116 // 0. Technically this dereferences the destructed object.
117 for (int i = 0; i < size; i++) {
118 EXPECT_EQ(0, original.begin()[i].data());
119 EXPECT_EQ(i + 1, dest.begin()[i].data());
120 }
121 }
122
TEST(VectorBuffer,TrivialAbiMove)123 TEST(VectorBuffer, TrivialAbiMove) {
124 // Currently trivial relocation doesn't work on Windows for some reason, so
125 // the test needs to handle both cases.
126 constexpr bool kHaveTrivialRelocation =
127 IS_TRIVIALLY_RELOCATABLE(TrivialAbiWithCountingOperations);
128 constexpr int size = 10;
129 VectorBuffer<TrivialAbiWithCountingOperations> dest(size);
130
131 int destruction_count = 0;
132 int move_count = 0;
133 VectorBuffer<TrivialAbiWithCountingOperations> original(size);
134 for (int i = 0; i < size; i++) {
135 new (original.begin() + i)
136 TrivialAbiWithCountingOperations(&destruction_count, &move_count);
137 }
138
139 original.MoveRange(original.begin(), original.end(), dest.begin());
140
141 // We expect the move to have been performed via memcpy, without calling move
142 // constructors or destructors.
143 EXPECT_EQ(destruction_count, kHaveTrivialRelocation ? 0 : size);
144 EXPECT_EQ(move_count, kHaveTrivialRelocation ? 0 : size);
145
146 dest.DestructRange(dest.begin(), dest.end());
147 EXPECT_EQ(destruction_count, kHaveTrivialRelocation ? size : size * 2);
148 EXPECT_EQ(move_count, kHaveTrivialRelocation ? 0 : size);
149 }
150
151 } // namespace base::internal
152