1 //===- llvm/unittest/ADT/SmallVectorTest.cpp ------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // SmallVector unit tests.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "llvm/ADT/SmallVector.h"
14 #include "llvm/ADT/ArrayRef.h"
15 #include "llvm/Support/Compiler.h"
16 #include "gtest/gtest.h"
17 #include <list>
18 #include <stdarg.h>
19
20 using namespace llvm;
21
22 namespace {
23
24 /// A helper class that counts the total number of constructor and
25 /// destructor calls.
26 class Constructable {
27 private:
28 static int numConstructorCalls;
29 static int numMoveConstructorCalls;
30 static int numCopyConstructorCalls;
31 static int numDestructorCalls;
32 static int numAssignmentCalls;
33 static int numMoveAssignmentCalls;
34 static int numCopyAssignmentCalls;
35
36 bool constructed;
37 int value;
38
39 public:
Constructable()40 Constructable() : constructed(true), value(0) {
41 ++numConstructorCalls;
42 }
43
Constructable(int val)44 Constructable(int val) : constructed(true), value(val) {
45 ++numConstructorCalls;
46 }
47
Constructable(const Constructable & src)48 Constructable(const Constructable & src) : constructed(true) {
49 value = src.value;
50 ++numConstructorCalls;
51 ++numCopyConstructorCalls;
52 }
53
Constructable(Constructable && src)54 Constructable(Constructable && src) : constructed(true) {
55 value = src.value;
56 src.value = 0;
57 ++numConstructorCalls;
58 ++numMoveConstructorCalls;
59 }
60
~Constructable()61 ~Constructable() {
62 EXPECT_TRUE(constructed);
63 ++numDestructorCalls;
64 constructed = false;
65 }
66
operator =(const Constructable & src)67 Constructable & operator=(const Constructable & src) {
68 EXPECT_TRUE(constructed);
69 value = src.value;
70 ++numAssignmentCalls;
71 ++numCopyAssignmentCalls;
72 return *this;
73 }
74
operator =(Constructable && src)75 Constructable & operator=(Constructable && src) {
76 EXPECT_TRUE(constructed);
77 value = src.value;
78 src.value = 0;
79 ++numAssignmentCalls;
80 ++numMoveAssignmentCalls;
81 return *this;
82 }
83
getValue() const84 int getValue() const {
85 return abs(value);
86 }
87
reset()88 static void reset() {
89 numConstructorCalls = 0;
90 numMoveConstructorCalls = 0;
91 numCopyConstructorCalls = 0;
92 numDestructorCalls = 0;
93 numAssignmentCalls = 0;
94 numMoveAssignmentCalls = 0;
95 numCopyAssignmentCalls = 0;
96 }
97
getNumConstructorCalls()98 static int getNumConstructorCalls() {
99 return numConstructorCalls;
100 }
101
getNumMoveConstructorCalls()102 static int getNumMoveConstructorCalls() {
103 return numMoveConstructorCalls;
104 }
105
getNumCopyConstructorCalls()106 static int getNumCopyConstructorCalls() {
107 return numCopyConstructorCalls;
108 }
109
getNumDestructorCalls()110 static int getNumDestructorCalls() {
111 return numDestructorCalls;
112 }
113
getNumAssignmentCalls()114 static int getNumAssignmentCalls() {
115 return numAssignmentCalls;
116 }
117
getNumMoveAssignmentCalls()118 static int getNumMoveAssignmentCalls() {
119 return numMoveAssignmentCalls;
120 }
121
getNumCopyAssignmentCalls()122 static int getNumCopyAssignmentCalls() {
123 return numCopyAssignmentCalls;
124 }
125
operator ==(const Constructable & c0,const Constructable & c1)126 friend bool operator==(const Constructable &c0, const Constructable &c1) {
127 return c0.getValue() == c1.getValue();
128 }
129
operator !=(const Constructable & c0,const Constructable & c1)130 friend bool LLVM_ATTRIBUTE_UNUSED operator!=(const Constructable &c0,
131 const Constructable &c1) {
132 return c0.getValue() != c1.getValue();
133 }
134
operator <(const Constructable & c0,const Constructable & c1)135 friend bool operator<(const Constructable &c0, const Constructable &c1) {
136 return c0.getValue() < c1.getValue();
137 }
operator <=(const Constructable & c0,const Constructable & c1)138 friend bool LLVM_ATTRIBUTE_UNUSED operator<=(const Constructable &c0,
139 const Constructable &c1) {
140 return c0.getValue() <= c1.getValue();
141 }
operator >(const Constructable & c0,const Constructable & c1)142 friend bool LLVM_ATTRIBUTE_UNUSED operator>(const Constructable &c0,
143 const Constructable &c1) {
144 return c0.getValue() > c1.getValue();
145 }
operator >=(const Constructable & c0,const Constructable & c1)146 friend bool LLVM_ATTRIBUTE_UNUSED operator>=(const Constructable &c0,
147 const Constructable &c1) {
148 return c0.getValue() >= c1.getValue();
149 }
150 };
151
152 int Constructable::numConstructorCalls;
153 int Constructable::numCopyConstructorCalls;
154 int Constructable::numMoveConstructorCalls;
155 int Constructable::numDestructorCalls;
156 int Constructable::numAssignmentCalls;
157 int Constructable::numCopyAssignmentCalls;
158 int Constructable::numMoveAssignmentCalls;
159
160 struct NonCopyable {
NonCopyable__anon4a72bbf00111::NonCopyable161 NonCopyable() {}
NonCopyable__anon4a72bbf00111::NonCopyable162 NonCopyable(NonCopyable &&) {}
operator =__anon4a72bbf00111::NonCopyable163 NonCopyable &operator=(NonCopyable &&) { return *this; }
164 private:
165 NonCopyable(const NonCopyable &) = delete;
166 NonCopyable &operator=(const NonCopyable &) = delete;
167 };
168
CompileTest()169 LLVM_ATTRIBUTE_USED void CompileTest() {
170 SmallVector<NonCopyable, 0> V;
171 V.resize(42);
172 }
173
174 class SmallVectorTestBase : public testing::Test {
175 protected:
SetUp()176 void SetUp() override { Constructable::reset(); }
177
178 template <typename VectorT>
assertEmpty(VectorT & v)179 void assertEmpty(VectorT & v) {
180 // Size tests
181 EXPECT_EQ(0u, v.size());
182 EXPECT_TRUE(v.empty());
183
184 // Iterator tests
185 EXPECT_TRUE(v.begin() == v.end());
186 }
187
188 // Assert that v contains the specified values, in order.
189 template <typename VectorT>
assertValuesInOrder(VectorT & v,size_t size,...)190 void assertValuesInOrder(VectorT & v, size_t size, ...) {
191 EXPECT_EQ(size, v.size());
192
193 va_list ap;
194 va_start(ap, size);
195 for (size_t i = 0; i < size; ++i) {
196 int value = va_arg(ap, int);
197 EXPECT_EQ(value, v[i].getValue());
198 }
199
200 va_end(ap);
201 }
202
203 // Generate a sequence of values to initialize the vector.
204 template <typename VectorT>
makeSequence(VectorT & v,int start,int end)205 void makeSequence(VectorT & v, int start, int end) {
206 for (int i = start; i <= end; ++i) {
207 v.push_back(Constructable(i));
208 }
209 }
210 };
211
212 // Test fixture class
213 template <typename VectorT>
214 class SmallVectorTest : public SmallVectorTestBase {
215 protected:
216 VectorT theVector;
217 VectorT otherVector;
218 };
219
220
221 typedef ::testing::Types<SmallVector<Constructable, 0>,
222 SmallVector<Constructable, 1>,
223 SmallVector<Constructable, 2>,
224 SmallVector<Constructable, 4>,
225 SmallVector<Constructable, 5>
226 > SmallVectorTestTypes;
227 TYPED_TEST_SUITE(SmallVectorTest, SmallVectorTestTypes, );
228
229 // Constructor test.
TYPED_TEST(SmallVectorTest,ConstructorNonIterTest)230 TYPED_TEST(SmallVectorTest, ConstructorNonIterTest) {
231 SCOPED_TRACE("ConstructorTest");
232 this->theVector = SmallVector<Constructable, 2>(2, 2);
233 this->assertValuesInOrder(this->theVector, 2u, 2, 2);
234 }
235
236 // Constructor test.
TYPED_TEST(SmallVectorTest,ConstructorIterTest)237 TYPED_TEST(SmallVectorTest, ConstructorIterTest) {
238 SCOPED_TRACE("ConstructorTest");
239 int arr[] = {1, 2, 3};
240 this->theVector =
241 SmallVector<Constructable, 4>(std::begin(arr), std::end(arr));
242 this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3);
243 }
244
245 // New vector test.
TYPED_TEST(SmallVectorTest,EmptyVectorTest)246 TYPED_TEST(SmallVectorTest, EmptyVectorTest) {
247 SCOPED_TRACE("EmptyVectorTest");
248 this->assertEmpty(this->theVector);
249 EXPECT_TRUE(this->theVector.rbegin() == this->theVector.rend());
250 EXPECT_EQ(0, Constructable::getNumConstructorCalls());
251 EXPECT_EQ(0, Constructable::getNumDestructorCalls());
252 }
253
254 // Simple insertions and deletions.
TYPED_TEST(SmallVectorTest,PushPopTest)255 TYPED_TEST(SmallVectorTest, PushPopTest) {
256 SCOPED_TRACE("PushPopTest");
257
258 // Track whether the vector will potentially have to grow.
259 bool RequiresGrowth = this->theVector.capacity() < 3;
260
261 // Push an element
262 this->theVector.push_back(Constructable(1));
263
264 // Size tests
265 this->assertValuesInOrder(this->theVector, 1u, 1);
266 EXPECT_FALSE(this->theVector.begin() == this->theVector.end());
267 EXPECT_FALSE(this->theVector.empty());
268
269 // Push another element
270 this->theVector.push_back(Constructable(2));
271 this->assertValuesInOrder(this->theVector, 2u, 1, 2);
272
273 // Insert at beginning. Reserve space to avoid reference invalidation from
274 // this->theVector[1].
275 this->theVector.reserve(this->theVector.size() + 1);
276 this->theVector.insert(this->theVector.begin(), this->theVector[1]);
277 this->assertValuesInOrder(this->theVector, 3u, 2, 1, 2);
278
279 // Pop one element
280 this->theVector.pop_back();
281 this->assertValuesInOrder(this->theVector, 2u, 2, 1);
282
283 // Pop remaining elements
284 this->theVector.pop_back_n(2);
285 this->assertEmpty(this->theVector);
286
287 // Check number of constructor calls. Should be 2 for each list element,
288 // one for the argument to push_back, one for the argument to insert,
289 // and one for the list element itself.
290 if (!RequiresGrowth) {
291 EXPECT_EQ(5, Constructable::getNumConstructorCalls());
292 EXPECT_EQ(5, Constructable::getNumDestructorCalls());
293 } else {
294 // If we had to grow the vector, these only have a lower bound, but should
295 // always be equal.
296 EXPECT_LE(5, Constructable::getNumConstructorCalls());
297 EXPECT_EQ(Constructable::getNumConstructorCalls(),
298 Constructable::getNumDestructorCalls());
299 }
300 }
301
302 // Clear test.
TYPED_TEST(SmallVectorTest,ClearTest)303 TYPED_TEST(SmallVectorTest, ClearTest) {
304 SCOPED_TRACE("ClearTest");
305
306 this->theVector.reserve(2);
307 this->makeSequence(this->theVector, 1, 2);
308 this->theVector.clear();
309
310 this->assertEmpty(this->theVector);
311 EXPECT_EQ(4, Constructable::getNumConstructorCalls());
312 EXPECT_EQ(4, Constructable::getNumDestructorCalls());
313 }
314
315 // Resize smaller test.
TYPED_TEST(SmallVectorTest,ResizeShrinkTest)316 TYPED_TEST(SmallVectorTest, ResizeShrinkTest) {
317 SCOPED_TRACE("ResizeShrinkTest");
318
319 this->theVector.reserve(3);
320 this->makeSequence(this->theVector, 1, 3);
321 this->theVector.resize(1);
322
323 this->assertValuesInOrder(this->theVector, 1u, 1);
324 EXPECT_EQ(6, Constructable::getNumConstructorCalls());
325 EXPECT_EQ(5, Constructable::getNumDestructorCalls());
326 }
327
328 // Truncate test.
TYPED_TEST(SmallVectorTest,TruncateTest)329 TYPED_TEST(SmallVectorTest, TruncateTest) {
330 SCOPED_TRACE("TruncateTest");
331
332 this->theVector.reserve(3);
333 this->makeSequence(this->theVector, 1, 3);
334 this->theVector.truncate(1);
335
336 this->assertValuesInOrder(this->theVector, 1u, 1);
337 EXPECT_EQ(6, Constructable::getNumConstructorCalls());
338 EXPECT_EQ(5, Constructable::getNumDestructorCalls());
339
340 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
341 EXPECT_DEATH(this->theVector.truncate(2), "Cannot increase size");
342 #endif
343 this->theVector.truncate(1);
344 this->assertValuesInOrder(this->theVector, 1u, 1);
345 EXPECT_EQ(6, Constructable::getNumConstructorCalls());
346 EXPECT_EQ(5, Constructable::getNumDestructorCalls());
347
348 this->theVector.truncate(0);
349 this->assertEmpty(this->theVector);
350 EXPECT_EQ(6, Constructable::getNumConstructorCalls());
351 EXPECT_EQ(6, Constructable::getNumDestructorCalls());
352 }
353
354 // Resize bigger test.
TYPED_TEST(SmallVectorTest,ResizeGrowTest)355 TYPED_TEST(SmallVectorTest, ResizeGrowTest) {
356 SCOPED_TRACE("ResizeGrowTest");
357
358 this->theVector.resize(2);
359
360 EXPECT_EQ(2, Constructable::getNumConstructorCalls());
361 EXPECT_EQ(0, Constructable::getNumDestructorCalls());
362 EXPECT_EQ(2u, this->theVector.size());
363 }
364
TYPED_TEST(SmallVectorTest,ResizeWithElementsTest)365 TYPED_TEST(SmallVectorTest, ResizeWithElementsTest) {
366 this->theVector.resize(2);
367
368 Constructable::reset();
369
370 this->theVector.resize(4);
371
372 size_t Ctors = Constructable::getNumConstructorCalls();
373 EXPECT_TRUE(Ctors == 2 || Ctors == 4);
374 size_t MoveCtors = Constructable::getNumMoveConstructorCalls();
375 EXPECT_TRUE(MoveCtors == 0 || MoveCtors == 2);
376 size_t Dtors = Constructable::getNumDestructorCalls();
377 EXPECT_TRUE(Dtors == 0 || Dtors == 2);
378 }
379
380 // Resize with fill value.
TYPED_TEST(SmallVectorTest,ResizeFillTest)381 TYPED_TEST(SmallVectorTest, ResizeFillTest) {
382 SCOPED_TRACE("ResizeFillTest");
383
384 this->theVector.resize(3, Constructable(77));
385 this->assertValuesInOrder(this->theVector, 3u, 77, 77, 77);
386 }
387
TEST(SmallVectorTest,ResizeForOverwrite)388 TEST(SmallVectorTest, ResizeForOverwrite) {
389 {
390 // Heap allocated storage.
391 SmallVector<unsigned, 0> V;
392 V.push_back(5U);
393 V.pop_back();
394 V.resize_for_overwrite(V.size() + 1U);
395 EXPECT_EQ(5U, V.back());
396 V.pop_back();
397 V.resize(V.size() + 1);
398 EXPECT_EQ(0U, V.back());
399 }
400 {
401 // Inline storage.
402 SmallVector<unsigned, 2> V;
403 V.push_back(5U);
404 V.pop_back();
405 V.resize_for_overwrite(V.size() + 1U);
406 EXPECT_EQ(5U, V.back());
407 V.pop_back();
408 V.resize(V.size() + 1);
409 EXPECT_EQ(0U, V.back());
410 }
411 }
412
413 // Overflow past fixed size.
TYPED_TEST(SmallVectorTest,OverflowTest)414 TYPED_TEST(SmallVectorTest, OverflowTest) {
415 SCOPED_TRACE("OverflowTest");
416
417 // Push more elements than the fixed size.
418 this->makeSequence(this->theVector, 1, 10);
419
420 // Test size and values.
421 EXPECT_EQ(10u, this->theVector.size());
422 for (int i = 0; i < 10; ++i) {
423 EXPECT_EQ(i+1, this->theVector[i].getValue());
424 }
425
426 // Now resize back to fixed size.
427 this->theVector.resize(1);
428
429 this->assertValuesInOrder(this->theVector, 1u, 1);
430 }
431
432 // Iteration tests.
TYPED_TEST(SmallVectorTest,IterationTest)433 TYPED_TEST(SmallVectorTest, IterationTest) {
434 this->makeSequence(this->theVector, 1, 2);
435
436 // Forward Iteration
437 typename TypeParam::iterator it = this->theVector.begin();
438 EXPECT_TRUE(*it == this->theVector.front());
439 EXPECT_TRUE(*it == this->theVector[0]);
440 EXPECT_EQ(1, it->getValue());
441 ++it;
442 EXPECT_TRUE(*it == this->theVector[1]);
443 EXPECT_TRUE(*it == this->theVector.back());
444 EXPECT_EQ(2, it->getValue());
445 ++it;
446 EXPECT_TRUE(it == this->theVector.end());
447 --it;
448 EXPECT_TRUE(*it == this->theVector[1]);
449 EXPECT_EQ(2, it->getValue());
450 --it;
451 EXPECT_TRUE(*it == this->theVector[0]);
452 EXPECT_EQ(1, it->getValue());
453
454 // Reverse Iteration
455 typename TypeParam::reverse_iterator rit = this->theVector.rbegin();
456 EXPECT_TRUE(*rit == this->theVector[1]);
457 EXPECT_EQ(2, rit->getValue());
458 ++rit;
459 EXPECT_TRUE(*rit == this->theVector[0]);
460 EXPECT_EQ(1, rit->getValue());
461 ++rit;
462 EXPECT_TRUE(rit == this->theVector.rend());
463 --rit;
464 EXPECT_TRUE(*rit == this->theVector[0]);
465 EXPECT_EQ(1, rit->getValue());
466 --rit;
467 EXPECT_TRUE(*rit == this->theVector[1]);
468 EXPECT_EQ(2, rit->getValue());
469 }
470
471 // Swap test.
TYPED_TEST(SmallVectorTest,SwapTest)472 TYPED_TEST(SmallVectorTest, SwapTest) {
473 SCOPED_TRACE("SwapTest");
474
475 this->makeSequence(this->theVector, 1, 2);
476 std::swap(this->theVector, this->otherVector);
477
478 this->assertEmpty(this->theVector);
479 this->assertValuesInOrder(this->otherVector, 2u, 1, 2);
480 }
481
482 // Append test
TYPED_TEST(SmallVectorTest,AppendTest)483 TYPED_TEST(SmallVectorTest, AppendTest) {
484 SCOPED_TRACE("AppendTest");
485
486 this->makeSequence(this->otherVector, 2, 3);
487
488 this->theVector.push_back(Constructable(1));
489 this->theVector.append(this->otherVector.begin(), this->otherVector.end());
490
491 this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3);
492 }
493
494 // Append repeated test
TYPED_TEST(SmallVectorTest,AppendRepeatedTest)495 TYPED_TEST(SmallVectorTest, AppendRepeatedTest) {
496 SCOPED_TRACE("AppendRepeatedTest");
497
498 this->theVector.push_back(Constructable(1));
499 this->theVector.append(2, Constructable(77));
500 this->assertValuesInOrder(this->theVector, 3u, 1, 77, 77);
501 }
502
503 // Append test
TYPED_TEST(SmallVectorTest,AppendNonIterTest)504 TYPED_TEST(SmallVectorTest, AppendNonIterTest) {
505 SCOPED_TRACE("AppendRepeatedTest");
506
507 this->theVector.push_back(Constructable(1));
508 this->theVector.append(2, 7);
509 this->assertValuesInOrder(this->theVector, 3u, 1, 7, 7);
510 }
511
512 struct output_iterator {
513 typedef std::output_iterator_tag iterator_category;
514 typedef int value_type;
515 typedef int difference_type;
516 typedef value_type *pointer;
517 typedef value_type &reference;
operator int__anon4a72bbf00111::output_iterator518 operator int() { return 2; }
operator Constructable__anon4a72bbf00111::output_iterator519 operator Constructable() { return 7; }
520 };
521
TYPED_TEST(SmallVectorTest,AppendRepeatedNonForwardIterator)522 TYPED_TEST(SmallVectorTest, AppendRepeatedNonForwardIterator) {
523 SCOPED_TRACE("AppendRepeatedTest");
524
525 this->theVector.push_back(Constructable(1));
526 this->theVector.append(output_iterator(), output_iterator());
527 this->assertValuesInOrder(this->theVector, 3u, 1, 7, 7);
528 }
529
TYPED_TEST(SmallVectorTest,AppendSmallVector)530 TYPED_TEST(SmallVectorTest, AppendSmallVector) {
531 SCOPED_TRACE("AppendSmallVector");
532
533 SmallVector<Constructable, 3> otherVector = {7, 7};
534 this->theVector.push_back(Constructable(1));
535 this->theVector.append(otherVector);
536 this->assertValuesInOrder(this->theVector, 3u, 1, 7, 7);
537 }
538
539 // Assign test
TYPED_TEST(SmallVectorTest,AssignTest)540 TYPED_TEST(SmallVectorTest, AssignTest) {
541 SCOPED_TRACE("AssignTest");
542
543 this->theVector.push_back(Constructable(1));
544 this->theVector.assign(2, Constructable(77));
545 this->assertValuesInOrder(this->theVector, 2u, 77, 77);
546 }
547
548 // Assign test
TYPED_TEST(SmallVectorTest,AssignRangeTest)549 TYPED_TEST(SmallVectorTest, AssignRangeTest) {
550 SCOPED_TRACE("AssignTest");
551
552 this->theVector.push_back(Constructable(1));
553 int arr[] = {1, 2, 3};
554 this->theVector.assign(std::begin(arr), std::end(arr));
555 this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3);
556 }
557
558 // Assign test
TYPED_TEST(SmallVectorTest,AssignNonIterTest)559 TYPED_TEST(SmallVectorTest, AssignNonIterTest) {
560 SCOPED_TRACE("AssignTest");
561
562 this->theVector.push_back(Constructable(1));
563 this->theVector.assign(2, 7);
564 this->assertValuesInOrder(this->theVector, 2u, 7, 7);
565 }
566
TYPED_TEST(SmallVectorTest,AssignSmallVector)567 TYPED_TEST(SmallVectorTest, AssignSmallVector) {
568 SCOPED_TRACE("AssignSmallVector");
569
570 SmallVector<Constructable, 3> otherVector = {7, 7};
571 this->theVector.push_back(Constructable(1));
572 this->theVector.assign(otherVector);
573 this->assertValuesInOrder(this->theVector, 2u, 7, 7);
574 }
575
576 // Move-assign test
TYPED_TEST(SmallVectorTest,MoveAssignTest)577 TYPED_TEST(SmallVectorTest, MoveAssignTest) {
578 SCOPED_TRACE("MoveAssignTest");
579
580 // Set up our vector with a single element, but enough capacity for 4.
581 this->theVector.reserve(4);
582 this->theVector.push_back(Constructable(1));
583
584 // Set up the other vector with 2 elements.
585 this->otherVector.push_back(Constructable(2));
586 this->otherVector.push_back(Constructable(3));
587
588 // Move-assign from the other vector.
589 this->theVector = std::move(this->otherVector);
590
591 // Make sure we have the right result.
592 this->assertValuesInOrder(this->theVector, 2u, 2, 3);
593
594 // Make sure the # of constructor/destructor calls line up. There
595 // are two live objects after clearing the other vector.
596 this->otherVector.clear();
597 EXPECT_EQ(Constructable::getNumConstructorCalls()-2,
598 Constructable::getNumDestructorCalls());
599
600 // There shouldn't be any live objects any more.
601 this->theVector.clear();
602 EXPECT_EQ(Constructable::getNumConstructorCalls(),
603 Constructable::getNumDestructorCalls());
604 }
605
606 // Erase a single element
TYPED_TEST(SmallVectorTest,EraseTest)607 TYPED_TEST(SmallVectorTest, EraseTest) {
608 SCOPED_TRACE("EraseTest");
609
610 this->makeSequence(this->theVector, 1, 3);
611 const auto &theConstVector = this->theVector;
612 this->theVector.erase(theConstVector.begin());
613 this->assertValuesInOrder(this->theVector, 2u, 2, 3);
614 }
615
616 // Erase a range of elements
TYPED_TEST(SmallVectorTest,EraseRangeTest)617 TYPED_TEST(SmallVectorTest, EraseRangeTest) {
618 SCOPED_TRACE("EraseRangeTest");
619
620 this->makeSequence(this->theVector, 1, 3);
621 const auto &theConstVector = this->theVector;
622 this->theVector.erase(theConstVector.begin(), theConstVector.begin() + 2);
623 this->assertValuesInOrder(this->theVector, 1u, 3);
624 }
625
626 // Insert a single element.
TYPED_TEST(SmallVectorTest,InsertTest)627 TYPED_TEST(SmallVectorTest, InsertTest) {
628 SCOPED_TRACE("InsertTest");
629
630 this->makeSequence(this->theVector, 1, 3);
631 typename TypeParam::iterator I =
632 this->theVector.insert(this->theVector.begin() + 1, Constructable(77));
633 EXPECT_EQ(this->theVector.begin() + 1, I);
634 this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3);
635 }
636
637 // Insert a copy of a single element.
TYPED_TEST(SmallVectorTest,InsertCopy)638 TYPED_TEST(SmallVectorTest, InsertCopy) {
639 SCOPED_TRACE("InsertTest");
640
641 this->makeSequence(this->theVector, 1, 3);
642 Constructable C(77);
643 typename TypeParam::iterator I =
644 this->theVector.insert(this->theVector.begin() + 1, C);
645 EXPECT_EQ(this->theVector.begin() + 1, I);
646 this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3);
647 }
648
649 // Insert repeated elements.
TYPED_TEST(SmallVectorTest,InsertRepeatedTest)650 TYPED_TEST(SmallVectorTest, InsertRepeatedTest) {
651 SCOPED_TRACE("InsertRepeatedTest");
652
653 this->makeSequence(this->theVector, 1, 4);
654 Constructable::reset();
655 auto I =
656 this->theVector.insert(this->theVector.begin() + 1, 2, Constructable(16));
657 // Move construct the top element into newly allocated space, and optionally
658 // reallocate the whole buffer, move constructing into it.
659 // FIXME: This is inefficient, we shouldn't move things into newly allocated
660 // space, then move them up/around, there should only be 2 or 4 move
661 // constructions here.
662 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 ||
663 Constructable::getNumMoveConstructorCalls() == 6);
664 // Move assign the next two to shift them up and make a gap.
665 EXPECT_EQ(1, Constructable::getNumMoveAssignmentCalls());
666 // Copy construct the two new elements from the parameter.
667 EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls());
668 // All without any copy construction.
669 EXPECT_EQ(0, Constructable::getNumCopyConstructorCalls());
670 EXPECT_EQ(this->theVector.begin() + 1, I);
671 this->assertValuesInOrder(this->theVector, 6u, 1, 16, 16, 2, 3, 4);
672 }
673
TYPED_TEST(SmallVectorTest,InsertRepeatedNonIterTest)674 TYPED_TEST(SmallVectorTest, InsertRepeatedNonIterTest) {
675 SCOPED_TRACE("InsertRepeatedTest");
676
677 this->makeSequence(this->theVector, 1, 4);
678 Constructable::reset();
679 auto I = this->theVector.insert(this->theVector.begin() + 1, 2, 7);
680 EXPECT_EQ(this->theVector.begin() + 1, I);
681 this->assertValuesInOrder(this->theVector, 6u, 1, 7, 7, 2, 3, 4);
682 }
683
TYPED_TEST(SmallVectorTest,InsertRepeatedAtEndTest)684 TYPED_TEST(SmallVectorTest, InsertRepeatedAtEndTest) {
685 SCOPED_TRACE("InsertRepeatedTest");
686
687 this->makeSequence(this->theVector, 1, 4);
688 Constructable::reset();
689 auto I = this->theVector.insert(this->theVector.end(), 2, Constructable(16));
690 // Just copy construct them into newly allocated space
691 EXPECT_EQ(2, Constructable::getNumCopyConstructorCalls());
692 // Move everything across if reallocation is needed.
693 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 ||
694 Constructable::getNumMoveConstructorCalls() == 4);
695 // Without ever moving or copying anything else.
696 EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls());
697 EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls());
698
699 EXPECT_EQ(this->theVector.begin() + 4, I);
700 this->assertValuesInOrder(this->theVector, 6u, 1, 2, 3, 4, 16, 16);
701 }
702
TYPED_TEST(SmallVectorTest,InsertRepeatedEmptyTest)703 TYPED_TEST(SmallVectorTest, InsertRepeatedEmptyTest) {
704 SCOPED_TRACE("InsertRepeatedTest");
705
706 this->makeSequence(this->theVector, 10, 15);
707
708 // Empty insert.
709 EXPECT_EQ(this->theVector.end(),
710 this->theVector.insert(this->theVector.end(),
711 0, Constructable(42)));
712 EXPECT_EQ(this->theVector.begin() + 1,
713 this->theVector.insert(this->theVector.begin() + 1,
714 0, Constructable(42)));
715 }
716
717 // Insert range.
TYPED_TEST(SmallVectorTest,InsertRangeTest)718 TYPED_TEST(SmallVectorTest, InsertRangeTest) {
719 SCOPED_TRACE("InsertRangeTest");
720
721 Constructable Arr[3] =
722 { Constructable(77), Constructable(77), Constructable(77) };
723
724 this->makeSequence(this->theVector, 1, 3);
725 Constructable::reset();
726 auto I = this->theVector.insert(this->theVector.begin() + 1, Arr, Arr + 3);
727 // Move construct the top 3 elements into newly allocated space.
728 // Possibly move the whole sequence into new space first.
729 // FIXME: This is inefficient, we shouldn't move things into newly allocated
730 // space, then move them up/around, there should only be 2 or 3 move
731 // constructions here.
732 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 ||
733 Constructable::getNumMoveConstructorCalls() == 5);
734 // Copy assign the lower 2 new elements into existing space.
735 EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls());
736 // Copy construct the third element into newly allocated space.
737 EXPECT_EQ(1, Constructable::getNumCopyConstructorCalls());
738 EXPECT_EQ(this->theVector.begin() + 1, I);
739 this->assertValuesInOrder(this->theVector, 6u, 1, 77, 77, 77, 2, 3);
740 }
741
742
TYPED_TEST(SmallVectorTest,InsertRangeAtEndTest)743 TYPED_TEST(SmallVectorTest, InsertRangeAtEndTest) {
744 SCOPED_TRACE("InsertRangeTest");
745
746 Constructable Arr[3] =
747 { Constructable(77), Constructable(77), Constructable(77) };
748
749 this->makeSequence(this->theVector, 1, 3);
750
751 // Insert at end.
752 Constructable::reset();
753 auto I = this->theVector.insert(this->theVector.end(), Arr, Arr+3);
754 // Copy construct the 3 elements into new space at the top.
755 EXPECT_EQ(3, Constructable::getNumCopyConstructorCalls());
756 // Don't copy/move anything else.
757 EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls());
758 // Reallocation might occur, causing all elements to be moved into the new
759 // buffer.
760 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 ||
761 Constructable::getNumMoveConstructorCalls() == 3);
762 EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls());
763 EXPECT_EQ(this->theVector.begin() + 3, I);
764 this->assertValuesInOrder(this->theVector, 6u,
765 1, 2, 3, 77, 77, 77);
766 }
767
TYPED_TEST(SmallVectorTest,InsertEmptyRangeTest)768 TYPED_TEST(SmallVectorTest, InsertEmptyRangeTest) {
769 SCOPED_TRACE("InsertRangeTest");
770
771 this->makeSequence(this->theVector, 1, 3);
772
773 // Empty insert.
774 EXPECT_EQ(this->theVector.end(),
775 this->theVector.insert(this->theVector.end(),
776 this->theVector.begin(),
777 this->theVector.begin()));
778 EXPECT_EQ(this->theVector.begin() + 1,
779 this->theVector.insert(this->theVector.begin() + 1,
780 this->theVector.begin(),
781 this->theVector.begin()));
782 }
783
784 // Comparison tests.
TYPED_TEST(SmallVectorTest,ComparisonEqualityTest)785 TYPED_TEST(SmallVectorTest, ComparisonEqualityTest) {
786 SCOPED_TRACE("ComparisonEqualityTest");
787
788 this->makeSequence(this->theVector, 1, 3);
789 this->makeSequence(this->otherVector, 1, 3);
790
791 EXPECT_TRUE(this->theVector == this->otherVector);
792 EXPECT_FALSE(this->theVector != this->otherVector);
793
794 this->otherVector.clear();
795 this->makeSequence(this->otherVector, 2, 4);
796
797 EXPECT_FALSE(this->theVector == this->otherVector);
798 EXPECT_TRUE(this->theVector != this->otherVector);
799 }
800
801 // Comparison tests.
TYPED_TEST(SmallVectorTest,ComparisonLessThanTest)802 TYPED_TEST(SmallVectorTest, ComparisonLessThanTest) {
803 SCOPED_TRACE("ComparisonLessThanTest");
804
805 this->theVector = {1, 2, 4};
806 this->otherVector = {1, 4};
807
808 EXPECT_TRUE(this->theVector < this->otherVector);
809 EXPECT_TRUE(this->theVector <= this->otherVector);
810 EXPECT_FALSE(this->theVector > this->otherVector);
811 EXPECT_FALSE(this->theVector >= this->otherVector);
812
813 EXPECT_FALSE(this->otherVector < this->theVector);
814 EXPECT_FALSE(this->otherVector <= this->theVector);
815 EXPECT_TRUE(this->otherVector > this->theVector);
816 EXPECT_TRUE(this->otherVector >= this->theVector);
817
818 this->otherVector = {1, 2, 4};
819
820 EXPECT_FALSE(this->theVector < this->otherVector);
821 EXPECT_TRUE(this->theVector <= this->otherVector);
822 EXPECT_FALSE(this->theVector > this->otherVector);
823 EXPECT_TRUE(this->theVector >= this->otherVector);
824
825 EXPECT_FALSE(this->otherVector < this->theVector);
826 EXPECT_TRUE(this->otherVector <= this->theVector);
827 EXPECT_FALSE(this->otherVector > this->theVector);
828 EXPECT_TRUE(this->otherVector >= this->theVector);
829 }
830
831 // Constant vector tests.
TYPED_TEST(SmallVectorTest,ConstVectorTest)832 TYPED_TEST(SmallVectorTest, ConstVectorTest) {
833 const TypeParam constVector;
834
835 EXPECT_EQ(0u, constVector.size());
836 EXPECT_TRUE(constVector.empty());
837 EXPECT_TRUE(constVector.begin() == constVector.end());
838 }
839
840 // Direct array access.
TYPED_TEST(SmallVectorTest,DirectVectorTest)841 TYPED_TEST(SmallVectorTest, DirectVectorTest) {
842 EXPECT_EQ(0u, this->theVector.size());
843 this->theVector.reserve(4);
844 EXPECT_LE(4u, this->theVector.capacity());
845 EXPECT_EQ(0, Constructable::getNumConstructorCalls());
846 this->theVector.push_back(1);
847 this->theVector.push_back(2);
848 this->theVector.push_back(3);
849 this->theVector.push_back(4);
850 EXPECT_EQ(4u, this->theVector.size());
851 EXPECT_EQ(8, Constructable::getNumConstructorCalls());
852 EXPECT_EQ(1, this->theVector[0].getValue());
853 EXPECT_EQ(2, this->theVector[1].getValue());
854 EXPECT_EQ(3, this->theVector[2].getValue());
855 EXPECT_EQ(4, this->theVector[3].getValue());
856 }
857
TYPED_TEST(SmallVectorTest,IteratorTest)858 TYPED_TEST(SmallVectorTest, IteratorTest) {
859 std::list<int> L;
860 this->theVector.insert(this->theVector.end(), L.begin(), L.end());
861 }
862
863 template <typename InvalidType> class DualSmallVectorsTest;
864
865 template <typename VectorT1, typename VectorT2>
866 class DualSmallVectorsTest<std::pair<VectorT1, VectorT2>> : public SmallVectorTestBase {
867 protected:
868 VectorT1 theVector;
869 VectorT2 otherVector;
870
871 template <typename T, unsigned N>
NumBuiltinElts(const SmallVector<T,N> &)872 static unsigned NumBuiltinElts(const SmallVector<T, N>&) { return N; }
873 };
874
875 typedef ::testing::Types<
876 // Small mode -> Small mode.
877 std::pair<SmallVector<Constructable, 4>, SmallVector<Constructable, 4>>,
878 // Small mode -> Big mode.
879 std::pair<SmallVector<Constructable, 4>, SmallVector<Constructable, 2>>,
880 // Big mode -> Small mode.
881 std::pair<SmallVector<Constructable, 2>, SmallVector<Constructable, 4>>,
882 // Big mode -> Big mode.
883 std::pair<SmallVector<Constructable, 2>, SmallVector<Constructable, 2>>
884 > DualSmallVectorTestTypes;
885
886 TYPED_TEST_SUITE(DualSmallVectorsTest, DualSmallVectorTestTypes, );
887
TYPED_TEST(DualSmallVectorsTest,MoveAssignment)888 TYPED_TEST(DualSmallVectorsTest, MoveAssignment) {
889 SCOPED_TRACE("MoveAssignTest-DualVectorTypes");
890
891 // Set up our vector with four elements.
892 for (unsigned I = 0; I < 4; ++I)
893 this->otherVector.push_back(Constructable(I));
894
895 const Constructable *OrigDataPtr = this->otherVector.data();
896
897 // Move-assign from the other vector.
898 this->theVector =
899 std::move(static_cast<SmallVectorImpl<Constructable>&>(this->otherVector));
900
901 // Make sure we have the right result.
902 this->assertValuesInOrder(this->theVector, 4u, 0, 1, 2, 3);
903
904 // Make sure the # of constructor/destructor calls line up. There
905 // are two live objects after clearing the other vector.
906 this->otherVector.clear();
907 EXPECT_EQ(Constructable::getNumConstructorCalls()-4,
908 Constructable::getNumDestructorCalls());
909
910 // If the source vector (otherVector) was in small-mode, assert that we just
911 // moved the data pointer over.
912 EXPECT_TRUE(this->NumBuiltinElts(this->otherVector) == 4 ||
913 this->theVector.data() == OrigDataPtr);
914
915 // There shouldn't be any live objects any more.
916 this->theVector.clear();
917 EXPECT_EQ(Constructable::getNumConstructorCalls(),
918 Constructable::getNumDestructorCalls());
919
920 // We shouldn't have copied anything in this whole process.
921 EXPECT_EQ(Constructable::getNumCopyConstructorCalls(), 0);
922 }
923
924 struct notassignable {
925 int &x;
notassignable__anon4a72bbf00111::notassignable926 notassignable(int &x) : x(x) {}
927 };
928
TEST(SmallVectorCustomTest,NoAssignTest)929 TEST(SmallVectorCustomTest, NoAssignTest) {
930 int x = 0;
931 SmallVector<notassignable, 2> vec;
932 vec.push_back(notassignable(x));
933 x = 42;
934 EXPECT_EQ(42, vec.pop_back_val().x);
935 }
936
937 struct MovedFrom {
938 bool hasValue;
MovedFrom__anon4a72bbf00111::MovedFrom939 MovedFrom() : hasValue(true) {
940 }
MovedFrom__anon4a72bbf00111::MovedFrom941 MovedFrom(MovedFrom&& m) : hasValue(m.hasValue) {
942 m.hasValue = false;
943 }
operator =__anon4a72bbf00111::MovedFrom944 MovedFrom &operator=(MovedFrom&& m) {
945 hasValue = m.hasValue;
946 m.hasValue = false;
947 return *this;
948 }
949 };
950
TEST(SmallVectorTest,MidInsert)951 TEST(SmallVectorTest, MidInsert) {
952 SmallVector<MovedFrom, 3> v;
953 v.push_back(MovedFrom());
954 v.insert(v.begin(), MovedFrom());
955 for (MovedFrom &m : v)
956 EXPECT_TRUE(m.hasValue);
957 }
958
959 enum EmplaceableArgState {
960 EAS_Defaulted,
961 EAS_Arg,
962 EAS_LValue,
963 EAS_RValue,
964 EAS_Failure
965 };
966 template <int I> struct EmplaceableArg {
967 EmplaceableArgState State;
EmplaceableArg__anon4a72bbf00111::EmplaceableArg968 EmplaceableArg() : State(EAS_Defaulted) {}
EmplaceableArg__anon4a72bbf00111::EmplaceableArg969 EmplaceableArg(EmplaceableArg &&X)
970 : State(X.State == EAS_Arg ? EAS_RValue : EAS_Failure) {}
EmplaceableArg__anon4a72bbf00111::EmplaceableArg971 EmplaceableArg(EmplaceableArg &X)
972 : State(X.State == EAS_Arg ? EAS_LValue : EAS_Failure) {}
973
EmplaceableArg__anon4a72bbf00111::EmplaceableArg974 explicit EmplaceableArg(bool) : State(EAS_Arg) {}
975
976 private:
977 EmplaceableArg &operator=(EmplaceableArg &&) = delete;
978 EmplaceableArg &operator=(const EmplaceableArg &) = delete;
979 };
980
981 enum EmplaceableState { ES_Emplaced, ES_Moved };
982 struct Emplaceable {
983 EmplaceableArg<0> A0;
984 EmplaceableArg<1> A1;
985 EmplaceableArg<2> A2;
986 EmplaceableArg<3> A3;
987 EmplaceableState State;
988
Emplaceable__anon4a72bbf00111::Emplaceable989 Emplaceable() : State(ES_Emplaced) {}
990
991 template <class A0Ty>
Emplaceable__anon4a72bbf00111::Emplaceable992 explicit Emplaceable(A0Ty &&A0)
993 : A0(std::forward<A0Ty>(A0)), State(ES_Emplaced) {}
994
995 template <class A0Ty, class A1Ty>
Emplaceable__anon4a72bbf00111::Emplaceable996 Emplaceable(A0Ty &&A0, A1Ty &&A1)
997 : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)),
998 State(ES_Emplaced) {}
999
1000 template <class A0Ty, class A1Ty, class A2Ty>
Emplaceable__anon4a72bbf00111::Emplaceable1001 Emplaceable(A0Ty &&A0, A1Ty &&A1, A2Ty &&A2)
1002 : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)),
1003 A2(std::forward<A2Ty>(A2)), State(ES_Emplaced) {}
1004
1005 template <class A0Ty, class A1Ty, class A2Ty, class A3Ty>
Emplaceable__anon4a72bbf00111::Emplaceable1006 Emplaceable(A0Ty &&A0, A1Ty &&A1, A2Ty &&A2, A3Ty &&A3)
1007 : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)),
1008 A2(std::forward<A2Ty>(A2)), A3(std::forward<A3Ty>(A3)),
1009 State(ES_Emplaced) {}
1010
Emplaceable__anon4a72bbf00111::Emplaceable1011 Emplaceable(Emplaceable &&) : State(ES_Moved) {}
operator =__anon4a72bbf00111::Emplaceable1012 Emplaceable &operator=(Emplaceable &&) {
1013 State = ES_Moved;
1014 return *this;
1015 }
1016
1017 private:
1018 Emplaceable(const Emplaceable &) = delete;
1019 Emplaceable &operator=(const Emplaceable &) = delete;
1020 };
1021
TEST(SmallVectorTest,EmplaceBack)1022 TEST(SmallVectorTest, EmplaceBack) {
1023 EmplaceableArg<0> A0(true);
1024 EmplaceableArg<1> A1(true);
1025 EmplaceableArg<2> A2(true);
1026 EmplaceableArg<3> A3(true);
1027 {
1028 SmallVector<Emplaceable, 3> V;
1029 Emplaceable &back = V.emplace_back();
1030 EXPECT_TRUE(&back == &V.back());
1031 EXPECT_TRUE(V.size() == 1);
1032 EXPECT_TRUE(back.State == ES_Emplaced);
1033 EXPECT_TRUE(back.A0.State == EAS_Defaulted);
1034 EXPECT_TRUE(back.A1.State == EAS_Defaulted);
1035 EXPECT_TRUE(back.A2.State == EAS_Defaulted);
1036 EXPECT_TRUE(back.A3.State == EAS_Defaulted);
1037 }
1038 {
1039 SmallVector<Emplaceable, 3> V;
1040 Emplaceable &back = V.emplace_back(std::move(A0));
1041 EXPECT_TRUE(&back == &V.back());
1042 EXPECT_TRUE(V.size() == 1);
1043 EXPECT_TRUE(back.State == ES_Emplaced);
1044 EXPECT_TRUE(back.A0.State == EAS_RValue);
1045 EXPECT_TRUE(back.A1.State == EAS_Defaulted);
1046 EXPECT_TRUE(back.A2.State == EAS_Defaulted);
1047 EXPECT_TRUE(back.A3.State == EAS_Defaulted);
1048 }
1049 {
1050 SmallVector<Emplaceable, 3> V;
1051 Emplaceable &back = V.emplace_back(A0);
1052 EXPECT_TRUE(&back == &V.back());
1053 EXPECT_TRUE(V.size() == 1);
1054 EXPECT_TRUE(back.State == ES_Emplaced);
1055 EXPECT_TRUE(back.A0.State == EAS_LValue);
1056 EXPECT_TRUE(back.A1.State == EAS_Defaulted);
1057 EXPECT_TRUE(back.A2.State == EAS_Defaulted);
1058 EXPECT_TRUE(back.A3.State == EAS_Defaulted);
1059 }
1060 {
1061 SmallVector<Emplaceable, 3> V;
1062 Emplaceable &back = V.emplace_back(A0, A1);
1063 EXPECT_TRUE(&back == &V.back());
1064 EXPECT_TRUE(V.size() == 1);
1065 EXPECT_TRUE(back.State == ES_Emplaced);
1066 EXPECT_TRUE(back.A0.State == EAS_LValue);
1067 EXPECT_TRUE(back.A1.State == EAS_LValue);
1068 EXPECT_TRUE(back.A2.State == EAS_Defaulted);
1069 EXPECT_TRUE(back.A3.State == EAS_Defaulted);
1070 }
1071 {
1072 SmallVector<Emplaceable, 3> V;
1073 Emplaceable &back = V.emplace_back(std::move(A0), std::move(A1));
1074 EXPECT_TRUE(&back == &V.back());
1075 EXPECT_TRUE(V.size() == 1);
1076 EXPECT_TRUE(back.State == ES_Emplaced);
1077 EXPECT_TRUE(back.A0.State == EAS_RValue);
1078 EXPECT_TRUE(back.A1.State == EAS_RValue);
1079 EXPECT_TRUE(back.A2.State == EAS_Defaulted);
1080 EXPECT_TRUE(back.A3.State == EAS_Defaulted);
1081 }
1082 {
1083 SmallVector<Emplaceable, 3> V;
1084 Emplaceable &back = V.emplace_back(std::move(A0), A1, std::move(A2), A3);
1085 EXPECT_TRUE(&back == &V.back());
1086 EXPECT_TRUE(V.size() == 1);
1087 EXPECT_TRUE(back.State == ES_Emplaced);
1088 EXPECT_TRUE(back.A0.State == EAS_RValue);
1089 EXPECT_TRUE(back.A1.State == EAS_LValue);
1090 EXPECT_TRUE(back.A2.State == EAS_RValue);
1091 EXPECT_TRUE(back.A3.State == EAS_LValue);
1092 }
1093 {
1094 SmallVector<int, 1> V;
1095 V.emplace_back();
1096 V.emplace_back(42);
1097 EXPECT_EQ(2U, V.size());
1098 EXPECT_EQ(0, V[0]);
1099 EXPECT_EQ(42, V[1]);
1100 }
1101 }
1102
TEST(SmallVectorTest,DefaultInlinedElements)1103 TEST(SmallVectorTest, DefaultInlinedElements) {
1104 SmallVector<int> V;
1105 EXPECT_TRUE(V.empty());
1106 V.push_back(7);
1107 EXPECT_EQ(V[0], 7);
1108
1109 // Check that at least a couple layers of nested SmallVector<T>'s are allowed
1110 // by the default inline elements policy. This pattern happens in practice
1111 // with some frequency, and it seems fairly harmless even though each layer of
1112 // SmallVector's will grow the total sizeof by a vector header beyond the
1113 // "preferred" maximum sizeof.
1114 SmallVector<SmallVector<SmallVector<int>>> NestedV;
1115 NestedV.emplace_back().emplace_back().emplace_back(42);
1116 EXPECT_EQ(NestedV[0][0][0], 42);
1117 }
1118
TEST(SmallVectorTest,InitializerList)1119 TEST(SmallVectorTest, InitializerList) {
1120 SmallVector<int, 2> V1 = {};
1121 EXPECT_TRUE(V1.empty());
1122 V1 = {0, 0};
1123 EXPECT_TRUE(makeArrayRef(V1).equals({0, 0}));
1124 V1 = {-1, -1};
1125 EXPECT_TRUE(makeArrayRef(V1).equals({-1, -1}));
1126
1127 SmallVector<int, 2> V2 = {1, 2, 3, 4};
1128 EXPECT_TRUE(makeArrayRef(V2).equals({1, 2, 3, 4}));
1129 V2.assign({4});
1130 EXPECT_TRUE(makeArrayRef(V2).equals({4}));
1131 V2.append({3, 2});
1132 EXPECT_TRUE(makeArrayRef(V2).equals({4, 3, 2}));
1133 V2.insert(V2.begin() + 1, 5);
1134 EXPECT_TRUE(makeArrayRef(V2).equals({4, 5, 3, 2}));
1135 }
1136
1137 template <class VectorT>
1138 class SmallVectorReferenceInvalidationTest : public SmallVectorTestBase {
1139 protected:
1140 const char *AssertionMessage =
1141 "Attempting to reference an element of the vector in an operation \" "
1142 "\"that invalidates it";
1143
1144 VectorT V;
1145
1146 template <typename T, unsigned N>
NumBuiltinElts(const SmallVector<T,N> &)1147 static unsigned NumBuiltinElts(const SmallVector<T, N> &) {
1148 return N;
1149 }
1150
isValueType()1151 template <class T> static bool isValueType() {
1152 return std::is_same<T, typename VectorT::value_type>::value;
1153 }
1154
SetUp()1155 void SetUp() override {
1156 SmallVectorTestBase::SetUp();
1157
1158 // Fill up the small size so that insertions move the elements.
1159 for (int I = 0, E = NumBuiltinElts(V); I != E; ++I)
1160 V.emplace_back(I + 1);
1161 }
1162 };
1163
1164 // Test one type that's trivially copyable (int) and one that isn't
1165 // (Constructable) since reference invalidation may be fixed differently for
1166 // each.
1167 using SmallVectorReferenceInvalidationTestTypes =
1168 ::testing::Types<SmallVector<int, 3>, SmallVector<Constructable, 3>>;
1169
1170 TYPED_TEST_SUITE(SmallVectorReferenceInvalidationTest,
1171 SmallVectorReferenceInvalidationTestTypes, );
1172
TYPED_TEST(SmallVectorReferenceInvalidationTest,PushBack)1173 TYPED_TEST(SmallVectorReferenceInvalidationTest, PushBack) {
1174 // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode.
1175 auto &V = this->V;
1176 int N = this->NumBuiltinElts(V);
1177
1178 // Push back a reference to last element when growing from small storage.
1179 V.push_back(V.back());
1180 EXPECT_EQ(N, V.back());
1181
1182 // Check that the old value is still there (not moved away).
1183 EXPECT_EQ(N, V[V.size() - 2]);
1184
1185 // Fill storage again.
1186 V.back() = V.size();
1187 while (V.size() < V.capacity())
1188 V.push_back(V.size() + 1);
1189
1190 // Push back a reference to last element when growing from large storage.
1191 V.push_back(V.back());
1192 EXPECT_EQ(int(V.size()) - 1, V.back());
1193 }
1194
TYPED_TEST(SmallVectorReferenceInvalidationTest,PushBackMoved)1195 TYPED_TEST(SmallVectorReferenceInvalidationTest, PushBackMoved) {
1196 // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode.
1197 auto &V = this->V;
1198 int N = this->NumBuiltinElts(V);
1199
1200 // Push back a reference to last element when growing from small storage.
1201 V.push_back(std::move(V.back()));
1202 EXPECT_EQ(N, V.back());
1203 if (this->template isValueType<Constructable>()) {
1204 // Check that the value was moved (not copied).
1205 EXPECT_EQ(0, V[V.size() - 2]);
1206 }
1207
1208 // Fill storage again.
1209 V.back() = V.size();
1210 while (V.size() < V.capacity())
1211 V.push_back(V.size() + 1);
1212
1213 // Push back a reference to last element when growing from large storage.
1214 V.push_back(std::move(V.back()));
1215
1216 // Check the values.
1217 EXPECT_EQ(int(V.size()) - 1, V.back());
1218 if (this->template isValueType<Constructable>()) {
1219 // Check the value got moved out.
1220 EXPECT_EQ(0, V[V.size() - 2]);
1221 }
1222 }
1223
TYPED_TEST(SmallVectorReferenceInvalidationTest,Resize)1224 TYPED_TEST(SmallVectorReferenceInvalidationTest, Resize) {
1225 auto &V = this->V;
1226 (void)V;
1227 int N = this->NumBuiltinElts(V);
1228 V.resize(N + 1, V.back());
1229 EXPECT_EQ(N, V.back());
1230
1231 // Resize to add enough elements that V will grow again. If reference
1232 // invalidation breaks in the future, sanitizers should be able to catch a
1233 // use-after-free here.
1234 V.resize(V.capacity() + 1, V.front());
1235 EXPECT_EQ(1, V.back());
1236 }
1237
TYPED_TEST(SmallVectorReferenceInvalidationTest,Append)1238 TYPED_TEST(SmallVectorReferenceInvalidationTest, Append) {
1239 auto &V = this->V;
1240 (void)V;
1241 V.append(1, V.back());
1242 int N = this->NumBuiltinElts(V);
1243 EXPECT_EQ(N, V[N - 1]);
1244
1245 // Append enough more elements that V will grow again. This tests growing
1246 // when already in large mode.
1247 //
1248 // If reference invalidation breaks in the future, sanitizers should be able
1249 // to catch a use-after-free here.
1250 V.append(V.capacity() - V.size() + 1, V.front());
1251 EXPECT_EQ(1, V.back());
1252 }
1253
TYPED_TEST(SmallVectorReferenceInvalidationTest,AppendRange)1254 TYPED_TEST(SmallVectorReferenceInvalidationTest, AppendRange) {
1255 auto &V = this->V;
1256 (void)V;
1257 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
1258 EXPECT_DEATH(V.append(V.begin(), V.begin() + 1), this->AssertionMessage);
1259
1260 ASSERT_EQ(3u, this->NumBuiltinElts(V));
1261 ASSERT_EQ(3u, V.size());
1262 V.pop_back();
1263 ASSERT_EQ(2u, V.size());
1264
1265 // Confirm this checks for growth when there's more than one element
1266 // appended.
1267 EXPECT_DEATH(V.append(V.begin(), V.end()), this->AssertionMessage);
1268 #endif
1269 }
1270
TYPED_TEST(SmallVectorReferenceInvalidationTest,Assign)1271 TYPED_TEST(SmallVectorReferenceInvalidationTest, Assign) {
1272 // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode.
1273 auto &V = this->V;
1274 (void)V;
1275 int N = this->NumBuiltinElts(V);
1276 ASSERT_EQ(unsigned(N), V.size());
1277 ASSERT_EQ(unsigned(N), V.capacity());
1278
1279 // Check assign that shrinks in small mode.
1280 V.assign(1, V.back());
1281 EXPECT_EQ(1u, V.size());
1282 EXPECT_EQ(N, V[0]);
1283
1284 // Check assign that grows within small mode.
1285 ASSERT_LT(V.size(), V.capacity());
1286 V.assign(V.capacity(), V.back());
1287 for (int I = 0, E = V.size(); I != E; ++I) {
1288 EXPECT_EQ(N, V[I]);
1289
1290 // Reset to [1, 2, ...].
1291 V[I] = I + 1;
1292 }
1293
1294 // Check assign that grows to large mode.
1295 ASSERT_EQ(2, V[1]);
1296 V.assign(V.capacity() + 1, V[1]);
1297 for (int I = 0, E = V.size(); I != E; ++I) {
1298 EXPECT_EQ(2, V[I]);
1299
1300 // Reset to [1, 2, ...].
1301 V[I] = I + 1;
1302 }
1303
1304 // Check assign that shrinks in large mode.
1305 V.assign(1, V[1]);
1306 EXPECT_EQ(2, V[0]);
1307 }
1308
TYPED_TEST(SmallVectorReferenceInvalidationTest,AssignRange)1309 TYPED_TEST(SmallVectorReferenceInvalidationTest, AssignRange) {
1310 auto &V = this->V;
1311 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
1312 EXPECT_DEATH(V.assign(V.begin(), V.end()), this->AssertionMessage);
1313 EXPECT_DEATH(V.assign(V.begin(), V.end() - 1), this->AssertionMessage);
1314 #endif
1315 V.assign(V.begin(), V.begin());
1316 EXPECT_TRUE(V.empty());
1317 }
1318
TYPED_TEST(SmallVectorReferenceInvalidationTest,Insert)1319 TYPED_TEST(SmallVectorReferenceInvalidationTest, Insert) {
1320 // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode.
1321 auto &V = this->V;
1322 (void)V;
1323
1324 // Insert a reference to the back (not at end() or else insert delegates to
1325 // push_back()), growing out of small mode. Confirm the value was copied out
1326 // (moving out Constructable sets it to 0).
1327 V.insert(V.begin(), V.back());
1328 EXPECT_EQ(int(V.size() - 1), V.front());
1329 EXPECT_EQ(int(V.size() - 1), V.back());
1330
1331 // Fill up the vector again.
1332 while (V.size() < V.capacity())
1333 V.push_back(V.size() + 1);
1334
1335 // Grow again from large storage to large storage.
1336 V.insert(V.begin(), V.back());
1337 EXPECT_EQ(int(V.size() - 1), V.front());
1338 EXPECT_EQ(int(V.size() - 1), V.back());
1339 }
1340
TYPED_TEST(SmallVectorReferenceInvalidationTest,InsertMoved)1341 TYPED_TEST(SmallVectorReferenceInvalidationTest, InsertMoved) {
1342 // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode.
1343 auto &V = this->V;
1344 (void)V;
1345
1346 // Insert a reference to the back (not at end() or else insert delegates to
1347 // push_back()), growing out of small mode. Confirm the value was copied out
1348 // (moving out Constructable sets it to 0).
1349 V.insert(V.begin(), std::move(V.back()));
1350 EXPECT_EQ(int(V.size() - 1), V.front());
1351 if (this->template isValueType<Constructable>()) {
1352 // Check the value got moved out.
1353 EXPECT_EQ(0, V.back());
1354 }
1355
1356 // Fill up the vector again.
1357 while (V.size() < V.capacity())
1358 V.push_back(V.size() + 1);
1359
1360 // Grow again from large storage to large storage.
1361 V.insert(V.begin(), std::move(V.back()));
1362 EXPECT_EQ(int(V.size() - 1), V.front());
1363 if (this->template isValueType<Constructable>()) {
1364 // Check the value got moved out.
1365 EXPECT_EQ(0, V.back());
1366 }
1367 }
1368
TYPED_TEST(SmallVectorReferenceInvalidationTest,InsertN)1369 TYPED_TEST(SmallVectorReferenceInvalidationTest, InsertN) {
1370 auto &V = this->V;
1371 (void)V;
1372
1373 // Cover NumToInsert <= this->end() - I.
1374 V.insert(V.begin() + 1, 1, V.back());
1375 int N = this->NumBuiltinElts(V);
1376 EXPECT_EQ(N, V[1]);
1377
1378 // Cover NumToInsert > this->end() - I, inserting enough elements that V will
1379 // also grow again; V.capacity() will be more elements than necessary but
1380 // it's a simple way to cover both conditions.
1381 //
1382 // If reference invalidation breaks in the future, sanitizers should be able
1383 // to catch a use-after-free here.
1384 V.insert(V.begin(), V.capacity(), V.front());
1385 EXPECT_EQ(1, V.front());
1386 }
1387
TYPED_TEST(SmallVectorReferenceInvalidationTest,InsertRange)1388 TYPED_TEST(SmallVectorReferenceInvalidationTest, InsertRange) {
1389 auto &V = this->V;
1390 (void)V;
1391 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
1392 EXPECT_DEATH(V.insert(V.begin(), V.begin(), V.begin() + 1),
1393 this->AssertionMessage);
1394
1395 ASSERT_EQ(3u, this->NumBuiltinElts(V));
1396 ASSERT_EQ(3u, V.size());
1397 V.pop_back();
1398 ASSERT_EQ(2u, V.size());
1399
1400 // Confirm this checks for growth when there's more than one element
1401 // inserted.
1402 EXPECT_DEATH(V.insert(V.begin(), V.begin(), V.end()), this->AssertionMessage);
1403 #endif
1404 }
1405
TYPED_TEST(SmallVectorReferenceInvalidationTest,EmplaceBack)1406 TYPED_TEST(SmallVectorReferenceInvalidationTest, EmplaceBack) {
1407 // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode.
1408 auto &V = this->V;
1409 int N = this->NumBuiltinElts(V);
1410
1411 // Push back a reference to last element when growing from small storage.
1412 V.emplace_back(V.back());
1413 EXPECT_EQ(N, V.back());
1414
1415 // Check that the old value is still there (not moved away).
1416 EXPECT_EQ(N, V[V.size() - 2]);
1417
1418 // Fill storage again.
1419 V.back() = V.size();
1420 while (V.size() < V.capacity())
1421 V.push_back(V.size() + 1);
1422
1423 // Push back a reference to last element when growing from large storage.
1424 V.emplace_back(V.back());
1425 EXPECT_EQ(int(V.size()) - 1, V.back());
1426 }
1427
1428 template <class VectorT>
1429 class SmallVectorInternalReferenceInvalidationTest
1430 : public SmallVectorTestBase {
1431 protected:
1432 const char *AssertionMessage =
1433 "Attempting to reference an element of the vector in an operation \" "
1434 "\"that invalidates it";
1435
1436 VectorT V;
1437
1438 template <typename T, unsigned N>
NumBuiltinElts(const SmallVector<T,N> &)1439 static unsigned NumBuiltinElts(const SmallVector<T, N> &) {
1440 return N;
1441 }
1442
SetUp()1443 void SetUp() override {
1444 SmallVectorTestBase::SetUp();
1445
1446 // Fill up the small size so that insertions move the elements.
1447 for (int I = 0, E = NumBuiltinElts(V); I != E; ++I)
1448 V.emplace_back(I + 1, I + 1);
1449 }
1450 };
1451
1452 // Test pairs of the same types from SmallVectorReferenceInvalidationTestTypes.
1453 using SmallVectorInternalReferenceInvalidationTestTypes =
1454 ::testing::Types<SmallVector<std::pair<int, int>, 3>,
1455 SmallVector<std::pair<Constructable, Constructable>, 3>>;
1456
1457 TYPED_TEST_SUITE(SmallVectorInternalReferenceInvalidationTest,
1458 SmallVectorInternalReferenceInvalidationTestTypes, );
1459
TYPED_TEST(SmallVectorInternalReferenceInvalidationTest,EmplaceBack)1460 TYPED_TEST(SmallVectorInternalReferenceInvalidationTest, EmplaceBack) {
1461 // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode.
1462 auto &V = this->V;
1463 int N = this->NumBuiltinElts(V);
1464
1465 // Push back a reference to last element when growing from small storage.
1466 V.emplace_back(V.back().first, V.back().second);
1467 EXPECT_EQ(N, V.back().first);
1468 EXPECT_EQ(N, V.back().second);
1469
1470 // Check that the old value is still there (not moved away).
1471 EXPECT_EQ(N, V[V.size() - 2].first);
1472 EXPECT_EQ(N, V[V.size() - 2].second);
1473
1474 // Fill storage again.
1475 V.back().first = V.back().second = V.size();
1476 while (V.size() < V.capacity())
1477 V.emplace_back(V.size() + 1, V.size() + 1);
1478
1479 // Push back a reference to last element when growing from large storage.
1480 V.emplace_back(V.back().first, V.back().second);
1481 EXPECT_EQ(int(V.size()) - 1, V.back().first);
1482 EXPECT_EQ(int(V.size()) - 1, V.back().second);
1483 }
1484
1485 } // end namespace
1486