1 /*
2 *
3 * Copyright 2017 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 #include "src/core/lib/gprpp/inlined_vector.h"
20 #include <grpc/support/log.h>
21 #include <gtest/gtest.h>
22 #include "src/core/lib/gprpp/memory.h"
23 #include "test/core/util/test_config.h"
24
25 namespace grpc_core {
26 namespace testing {
27 namespace {
28
29 template <typename Vector>
FillVector(Vector * v,int len,int start=0)30 static void FillVector(Vector* v, int len, int start = 0) {
31 for (int i = 0; i < len; i++) {
32 v->push_back(i + start);
33 EXPECT_EQ(i + 1UL, v->size());
34 }
35 EXPECT_EQ(static_cast<size_t>(len), v->size());
36 EXPECT_LE(static_cast<size_t>(len), v->capacity());
37 }
38
39 } // namespace
40
TEST(InlinedVectorTest,CreateAndIterate)41 TEST(InlinedVectorTest, CreateAndIterate) {
42 const int kNumElements = 9;
43 InlinedVector<int, 2> v;
44 EXPECT_TRUE(v.empty());
45 FillVector(&v, kNumElements);
46 EXPECT_EQ(static_cast<size_t>(kNumElements), v.size());
47 EXPECT_FALSE(v.empty());
48 for (int i = 0; i < kNumElements; ++i) {
49 EXPECT_EQ(i, v[i]);
50 EXPECT_EQ(i, &v[i] - &v[0]); // Ensure contiguous allocation.
51 }
52 }
53
TEST(InlinedVectorTest,ValuesAreInlined)54 TEST(InlinedVectorTest, ValuesAreInlined) {
55 const int kNumElements = 5;
56 InlinedVector<int, 10> v;
57 FillVector(&v, kNumElements);
58 EXPECT_EQ(static_cast<size_t>(kNumElements), v.size());
59 for (int i = 0; i < kNumElements; ++i) {
60 EXPECT_EQ(i, v[i]);
61 }
62 }
63
TEST(InlinedVectorTest,PushBackWithMove)64 TEST(InlinedVectorTest, PushBackWithMove) {
65 InlinedVector<UniquePtr<int>, 1> v;
66 UniquePtr<int> i = MakeUnique<int>(3);
67 v.push_back(std::move(i));
68 EXPECT_EQ(nullptr, i.get());
69 EXPECT_EQ(1UL, v.size());
70 EXPECT_EQ(3, *v[0]);
71 }
72
TEST(InlinedVectorTest,EmplaceBack)73 TEST(InlinedVectorTest, EmplaceBack) {
74 InlinedVector<UniquePtr<int>, 1> v;
75 v.emplace_back(New<int>(3));
76 EXPECT_EQ(1UL, v.size());
77 EXPECT_EQ(3, *v[0]);
78 }
79
TEST(InlinedVectorTest,ClearAndRepopulate)80 TEST(InlinedVectorTest, ClearAndRepopulate) {
81 const int kNumElements = 10;
82 InlinedVector<int, 5> v;
83 EXPECT_EQ(0UL, v.size());
84 FillVector(&v, kNumElements);
85 for (int i = 0; i < kNumElements; ++i) {
86 EXPECT_EQ(i, v[i]);
87 }
88 v.clear();
89 EXPECT_EQ(0UL, v.size());
90 FillVector(&v, kNumElements, kNumElements);
91 for (int i = 0; i < kNumElements; ++i) {
92 EXPECT_EQ(kNumElements + i, v[i]);
93 }
94 }
95
TEST(InlinedVectorTest,ConstIndexOperator)96 TEST(InlinedVectorTest, ConstIndexOperator) {
97 constexpr int kNumElements = 10;
98 InlinedVector<int, 5> v;
99 EXPECT_EQ(0UL, v.size());
100 FillVector(&v, kNumElements);
101 // The following lambda function is exceptionally allowed to use an anonymous
102 // capture due to the erroneous behavior of the MSVC compiler, that refuses to
103 // capture the kNumElements constexpr, something allowed by the standard.
104 auto const_func = [&](const InlinedVector<int, 5>& v) {
105 for (int i = 0; i < kNumElements; ++i) {
106 EXPECT_EQ(i, v[i]);
107 }
108 };
109 const_func(v);
110 }
111
112 // the following constants and typedefs are used for copy/move
113 // construction/assignment
114 const size_t kInlinedLength = 8;
115 typedef InlinedVector<int, kInlinedLength> IntVec8;
116 const size_t kInlinedFillSize = kInlinedLength - 1;
117 const size_t kAllocatedFillSize = kInlinedLength + 1;
118
TEST(InlinedVectorTest,CopyConstructerInlined)119 TEST(InlinedVectorTest, CopyConstructerInlined) {
120 IntVec8 original;
121 FillVector(&original, kInlinedFillSize);
122 IntVec8 copy_constructed(original);
123 for (size_t i = 0; i < original.size(); ++i) {
124 EXPECT_EQ(original[i], copy_constructed[i]);
125 }
126 }
127
TEST(InlinedVectorTest,CopyConstructerAllocated)128 TEST(InlinedVectorTest, CopyConstructerAllocated) {
129 IntVec8 original;
130 FillVector(&original, kAllocatedFillSize);
131 IntVec8 copy_constructed(original);
132 for (size_t i = 0; i < original.size(); ++i) {
133 EXPECT_EQ(original[i], copy_constructed[i]);
134 }
135 }
136
TEST(InlinedVectorTest,CopyAssignementInlinedInlined)137 TEST(InlinedVectorTest, CopyAssignementInlinedInlined) {
138 IntVec8 original;
139 FillVector(&original, kInlinedFillSize);
140 IntVec8 copy_assigned;
141 FillVector(©_assigned, kInlinedFillSize, 99);
142 copy_assigned = original;
143 for (size_t i = 0; i < original.size(); ++i) {
144 EXPECT_EQ(original[i], copy_assigned[i]);
145 }
146 }
147
TEST(InlinedVectorTest,CopyAssignementInlinedAllocated)148 TEST(InlinedVectorTest, CopyAssignementInlinedAllocated) {
149 IntVec8 original;
150 FillVector(&original, kInlinedFillSize);
151 IntVec8 copy_assigned;
152 FillVector(©_assigned, kAllocatedFillSize, 99);
153 copy_assigned = original;
154 for (size_t i = 0; i < original.size(); ++i) {
155 EXPECT_EQ(original[i], copy_assigned[i]);
156 }
157 }
158
TEST(InlinedVectorTest,CopyAssignementAllocatedInlined)159 TEST(InlinedVectorTest, CopyAssignementAllocatedInlined) {
160 IntVec8 original;
161 FillVector(&original, kAllocatedFillSize);
162 IntVec8 copy_assigned;
163 FillVector(©_assigned, kInlinedFillSize, 99);
164 copy_assigned = original;
165 for (size_t i = 0; i < original.size(); ++i) {
166 EXPECT_EQ(original[i], copy_assigned[i]);
167 }
168 }
169
TEST(InlinedVectorTest,CopyAssignementAllocatedAllocated)170 TEST(InlinedVectorTest, CopyAssignementAllocatedAllocated) {
171 IntVec8 original;
172 FillVector(&original, kAllocatedFillSize);
173 IntVec8 copy_assigned;
174 FillVector(©_assigned, kAllocatedFillSize, 99);
175 copy_assigned = original;
176 for (size_t i = 0; i < original.size(); ++i) {
177 EXPECT_EQ(original[i], copy_assigned[i]);
178 }
179 }
180
TEST(InlinedVectorTest,MoveConstructorInlined)181 TEST(InlinedVectorTest, MoveConstructorInlined) {
182 IntVec8 original;
183 FillVector(&original, kInlinedFillSize);
184 IntVec8 tmp(original);
185 auto* old_data = tmp.data();
186 IntVec8 move_constructed(std::move(tmp));
187 for (size_t i = 0; i < original.size(); ++i) {
188 EXPECT_EQ(original[i], move_constructed[i]);
189 }
190 // original data was inlined so it should have been copied, not moved.
191 EXPECT_NE(move_constructed.data(), old_data);
192 }
193
TEST(InlinedVectorTest,MoveConstructorAllocated)194 TEST(InlinedVectorTest, MoveConstructorAllocated) {
195 IntVec8 original;
196 FillVector(&original, kAllocatedFillSize);
197 IntVec8 tmp(original);
198 auto* old_data = tmp.data();
199 IntVec8 move_constructed(std::move(tmp));
200 for (size_t i = 0; i < original.size(); ++i) {
201 EXPECT_EQ(original[i], move_constructed[i]);
202 }
203 // original data was allocated, so it should been moved, not copied
204 EXPECT_EQ(move_constructed.data(), old_data);
205 }
206
TEST(InlinedVectorTest,MoveAssignmentInlinedInlined)207 TEST(InlinedVectorTest, MoveAssignmentInlinedInlined) {
208 IntVec8 original;
209 FillVector(&original, kInlinedFillSize);
210 IntVec8 move_assigned;
211 FillVector(&move_assigned, kInlinedFillSize, 99); // Add dummy elements
212 IntVec8 tmp(original);
213 auto* old_data = tmp.data();
214 move_assigned = std::move(tmp);
215 for (size_t i = 0; i < original.size(); ++i) {
216 EXPECT_EQ(original[i], move_assigned[i]);
217 }
218 // original data was inlined so it should have been copied, not moved.
219 EXPECT_NE(move_assigned.data(), old_data);
220 }
221
TEST(InlinedVectorTest,MoveAssignmentInlinedAllocated)222 TEST(InlinedVectorTest, MoveAssignmentInlinedAllocated) {
223 IntVec8 original;
224 FillVector(&original, kInlinedFillSize);
225 IntVec8 move_assigned;
226 FillVector(&move_assigned, kAllocatedFillSize, 99); // Add dummy elements
227 IntVec8 tmp(original);
228 auto* old_data = tmp.data();
229 move_assigned = std::move(tmp);
230 for (size_t i = 0; i < original.size(); ++i) {
231 EXPECT_EQ(original[i], move_assigned[i]);
232 }
233 // original data was inlined so it should have been copied, not moved.
234 EXPECT_NE(move_assigned.data(), old_data);
235 }
236
TEST(InlinedVectorTest,MoveAssignmentAllocatedInlined)237 TEST(InlinedVectorTest, MoveAssignmentAllocatedInlined) {
238 IntVec8 original;
239 FillVector(&original, kAllocatedFillSize);
240 IntVec8 move_assigned;
241 FillVector(&move_assigned, kInlinedFillSize, 99); // Add dummy elements
242 IntVec8 tmp(original);
243 auto* old_data = tmp.data();
244 move_assigned = std::move(tmp);
245 for (size_t i = 0; i < original.size(); ++i) {
246 EXPECT_EQ(original[i], move_assigned[i]);
247 }
248 // original data was allocated so it should have been moved, not copied.
249 EXPECT_EQ(move_assigned.data(), old_data);
250 }
251
TEST(InlinedVectorTest,MoveAssignmentAllocatedAllocated)252 TEST(InlinedVectorTest, MoveAssignmentAllocatedAllocated) {
253 IntVec8 original;
254 FillVector(&original, kAllocatedFillSize);
255 IntVec8 move_assigned;
256 FillVector(&move_assigned, kAllocatedFillSize, 99); // Add dummy elements
257 IntVec8 tmp(original);
258 auto* old_data = tmp.data();
259 move_assigned = std::move(tmp);
260 for (size_t i = 0; i < original.size(); ++i) {
261 EXPECT_EQ(original[i], move_assigned[i]);
262 }
263 // original data was allocated so it should have been moved, not copied.
264 EXPECT_EQ(move_assigned.data(), old_data);
265 }
266
267 } // namespace testing
268 } // namespace grpc_core
269
main(int argc,char ** argv)270 int main(int argc, char** argv) {
271 grpc_test_init(argc, argv);
272 ::testing::InitGoogleTest(&argc, argv);
273 return RUN_ALL_TESTS();
274 }
275