1 //===- llvm/unittest/ADT/SmallVectorTest.cpp ------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // SmallVector unit tests.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/Support/Compiler.h"
16 #include "gtest/gtest.h"
24 /// A helper class that counts the total number of constructor and
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;
40 Constructable() : constructed(true), value(0) {
41 ++numConstructorCalls;
44 Constructable(int val) : constructed(true), value(val) {
45 ++numConstructorCalls;
48 Constructable(const Constructable & src) : constructed(true) {
50 ++numConstructorCalls;
51 ++numCopyConstructorCalls;
54 Constructable(Constructable && src) : constructed(true) {
56 ++numConstructorCalls;
57 ++numMoveConstructorCalls;
61 EXPECT_TRUE(constructed);
66 Constructable & operator=(const Constructable & src) {
67 EXPECT_TRUE(constructed);
70 ++numCopyAssignmentCalls;
74 Constructable & operator=(Constructable && src) {
75 EXPECT_TRUE(constructed);
78 ++numMoveAssignmentCalls;
82 int getValue() const {
87 numConstructorCalls = 0;
88 numMoveConstructorCalls = 0;
89 numCopyConstructorCalls = 0;
90 numDestructorCalls = 0;
91 numAssignmentCalls = 0;
92 numMoveAssignmentCalls = 0;
93 numCopyAssignmentCalls = 0;
96 static int getNumConstructorCalls() {
97 return numConstructorCalls;
100 static int getNumMoveConstructorCalls() {
101 return numMoveConstructorCalls;
104 static int getNumCopyConstructorCalls() {
105 return numCopyConstructorCalls;
108 static int getNumDestructorCalls() {
109 return numDestructorCalls;
112 static int getNumAssignmentCalls() {
113 return numAssignmentCalls;
116 static int getNumMoveAssignmentCalls() {
117 return numMoveAssignmentCalls;
120 static int getNumCopyAssignmentCalls() {
121 return numCopyAssignmentCalls;
124 friend bool operator==(const Constructable & c0, const Constructable & c1) {
125 return c0.getValue() == c1.getValue();
128 friend bool LLVM_ATTRIBUTE_UNUSED
129 operator!=(const Constructable & c0, const Constructable & c1) {
130 return c0.getValue() != c1.getValue();
134 int Constructable::numConstructorCalls;
135 int Constructable::numCopyConstructorCalls;
136 int Constructable::numMoveConstructorCalls;
137 int Constructable::numDestructorCalls;
138 int Constructable::numAssignmentCalls;
139 int Constructable::numCopyAssignmentCalls;
140 int Constructable::numMoveAssignmentCalls;
142 // Test fixture class
143 template <typename VectorT>
144 class SmallVectorTest : public testing::Test {
150 Constructable::reset();
153 void assertEmpty(VectorT & v) {
155 EXPECT_EQ(0u, v.size());
156 EXPECT_TRUE(v.empty());
159 EXPECT_TRUE(v.begin() == v.end());
162 // Assert that theVector contains the specified values, in order.
163 void assertValuesInOrder(VectorT & v, size_t size, ...) {
164 EXPECT_EQ(size, v.size());
168 for (size_t i = 0; i < size; ++i) {
169 int value = va_arg(ap, int);
170 EXPECT_EQ(value, v[i].getValue());
176 // Generate a sequence of values to initialize the vector.
177 void makeSequence(VectorT & v, int start, int end) {
178 for (int i = start; i <= end; ++i) {
179 v.push_back(Constructable(i));
184 typedef ::testing::Types<SmallVector<Constructable, 0>,
185 SmallVector<Constructable, 1>,
186 SmallVector<Constructable, 2>,
187 SmallVector<Constructable, 4>,
188 SmallVector<Constructable, 5>
189 > SmallVectorTestTypes;
190 TYPED_TEST_CASE(SmallVectorTest, SmallVectorTestTypes);
193 TYPED_TEST(SmallVectorTest, EmptyVectorTest) {
194 SCOPED_TRACE("EmptyVectorTest");
195 this->assertEmpty(this->theVector);
196 EXPECT_TRUE(this->theVector.rbegin() == this->theVector.rend());
197 EXPECT_EQ(0, Constructable::getNumConstructorCalls());
198 EXPECT_EQ(0, Constructable::getNumDestructorCalls());
201 // Simple insertions and deletions.
202 TYPED_TEST(SmallVectorTest, PushPopTest) {
203 SCOPED_TRACE("PushPopTest");
205 // Track whether the vector will potentially have to grow.
206 bool RequiresGrowth = this->theVector.capacity() < 3;
209 this->theVector.push_back(Constructable(1));
212 this->assertValuesInOrder(this->theVector, 1u, 1);
213 EXPECT_FALSE(this->theVector.begin() == this->theVector.end());
214 EXPECT_FALSE(this->theVector.empty());
216 // Push another element
217 this->theVector.push_back(Constructable(2));
218 this->assertValuesInOrder(this->theVector, 2u, 1, 2);
220 // Insert at beginning
221 this->theVector.insert(this->theVector.begin(), this->theVector[1]);
222 this->assertValuesInOrder(this->theVector, 3u, 2, 1, 2);
225 this->theVector.pop_back();
226 this->assertValuesInOrder(this->theVector, 2u, 2, 1);
228 // Pop remaining elements
229 this->theVector.pop_back();
230 this->theVector.pop_back();
231 this->assertEmpty(this->theVector);
233 // Check number of constructor calls. Should be 2 for each list element,
234 // one for the argument to push_back, one for the argument to insert,
235 // and one for the list element itself.
236 if (!RequiresGrowth) {
237 EXPECT_EQ(5, Constructable::getNumConstructorCalls());
238 EXPECT_EQ(5, Constructable::getNumDestructorCalls());
240 // If we had to grow the vector, these only have a lower bound, but should
242 EXPECT_LE(5, Constructable::getNumConstructorCalls());
243 EXPECT_EQ(Constructable::getNumConstructorCalls(),
244 Constructable::getNumDestructorCalls());
249 TYPED_TEST(SmallVectorTest, ClearTest) {
250 SCOPED_TRACE("ClearTest");
252 this->theVector.reserve(2);
253 this->makeSequence(this->theVector, 1, 2);
254 this->theVector.clear();
256 this->assertEmpty(this->theVector);
257 EXPECT_EQ(4, Constructable::getNumConstructorCalls());
258 EXPECT_EQ(4, Constructable::getNumDestructorCalls());
261 // Resize smaller test.
262 TYPED_TEST(SmallVectorTest, ResizeShrinkTest) {
263 SCOPED_TRACE("ResizeShrinkTest");
265 this->theVector.reserve(3);
266 this->makeSequence(this->theVector, 1, 3);
267 this->theVector.resize(1);
269 this->assertValuesInOrder(this->theVector, 1u, 1);
270 EXPECT_EQ(6, Constructable::getNumConstructorCalls());
271 EXPECT_EQ(5, Constructable::getNumDestructorCalls());
274 // Resize bigger test.
275 TYPED_TEST(SmallVectorTest, ResizeGrowTest) {
276 SCOPED_TRACE("ResizeGrowTest");
278 this->theVector.resize(2);
280 // The extra constructor/destructor calls come from the temporary object used
281 // to initialize the contents of the resized array (via copy construction).
282 EXPECT_EQ(3, Constructable::getNumConstructorCalls());
283 EXPECT_EQ(1, Constructable::getNumDestructorCalls());
284 EXPECT_EQ(2u, this->theVector.size());
287 // Resize with fill value.
288 TYPED_TEST(SmallVectorTest, ResizeFillTest) {
289 SCOPED_TRACE("ResizeFillTest");
291 this->theVector.resize(3, Constructable(77));
292 this->assertValuesInOrder(this->theVector, 3u, 77, 77, 77);
295 // Overflow past fixed size.
296 TYPED_TEST(SmallVectorTest, OverflowTest) {
297 SCOPED_TRACE("OverflowTest");
299 // Push more elements than the fixed size.
300 this->makeSequence(this->theVector, 1, 10);
302 // Test size and values.
303 EXPECT_EQ(10u, this->theVector.size());
304 for (int i = 0; i < 10; ++i) {
305 EXPECT_EQ(i+1, this->theVector[i].getValue());
308 // Now resize back to fixed size.
309 this->theVector.resize(1);
311 this->assertValuesInOrder(this->theVector, 1u, 1);
315 TYPED_TEST(SmallVectorTest, IterationTest) {
316 this->makeSequence(this->theVector, 1, 2);
319 typename TypeParam::iterator it = this->theVector.begin();
320 EXPECT_TRUE(*it == this->theVector.front());
321 EXPECT_TRUE(*it == this->theVector[0]);
322 EXPECT_EQ(1, it->getValue());
324 EXPECT_TRUE(*it == this->theVector[1]);
325 EXPECT_TRUE(*it == this->theVector.back());
326 EXPECT_EQ(2, it->getValue());
328 EXPECT_TRUE(it == this->theVector.end());
330 EXPECT_TRUE(*it == this->theVector[1]);
331 EXPECT_EQ(2, it->getValue());
333 EXPECT_TRUE(*it == this->theVector[0]);
334 EXPECT_EQ(1, it->getValue());
337 typename TypeParam::reverse_iterator rit = this->theVector.rbegin();
338 EXPECT_TRUE(*rit == this->theVector[1]);
339 EXPECT_EQ(2, rit->getValue());
341 EXPECT_TRUE(*rit == this->theVector[0]);
342 EXPECT_EQ(1, rit->getValue());
344 EXPECT_TRUE(rit == this->theVector.rend());
346 EXPECT_TRUE(*rit == this->theVector[0]);
347 EXPECT_EQ(1, rit->getValue());
349 EXPECT_TRUE(*rit == this->theVector[1]);
350 EXPECT_EQ(2, rit->getValue());
354 TYPED_TEST(SmallVectorTest, SwapTest) {
355 SCOPED_TRACE("SwapTest");
357 this->makeSequence(this->theVector, 1, 2);
358 std::swap(this->theVector, this->otherVector);
360 this->assertEmpty(this->theVector);
361 this->assertValuesInOrder(this->otherVector, 2u, 1, 2);
365 TYPED_TEST(SmallVectorTest, AppendTest) {
366 SCOPED_TRACE("AppendTest");
368 this->makeSequence(this->otherVector, 2, 3);
370 this->theVector.push_back(Constructable(1));
371 this->theVector.append(this->otherVector.begin(), this->otherVector.end());
373 this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3);
376 // Append repeated test
377 TYPED_TEST(SmallVectorTest, AppendRepeatedTest) {
378 SCOPED_TRACE("AppendRepeatedTest");
380 this->theVector.push_back(Constructable(1));
381 this->theVector.append(2, Constructable(77));
382 this->assertValuesInOrder(this->theVector, 3u, 1, 77, 77);
386 TYPED_TEST(SmallVectorTest, AssignTest) {
387 SCOPED_TRACE("AssignTest");
389 this->theVector.push_back(Constructable(1));
390 this->theVector.assign(2, Constructable(77));
391 this->assertValuesInOrder(this->theVector, 2u, 77, 77);
395 TYPED_TEST(SmallVectorTest, MoveAssignTest) {
396 SCOPED_TRACE("MoveAssignTest");
398 // Set up our vector with a single element, but enough capacity for 4.
399 this->theVector.reserve(4);
400 this->theVector.push_back(Constructable(1));
402 // Set up the other vector with 2 elements.
403 this->otherVector.push_back(Constructable(2));
404 this->otherVector.push_back(Constructable(3));
406 // Move-assign from the other vector.
407 this->theVector = std::move(this->otherVector);
409 // Make sure we have the right result.
410 this->assertValuesInOrder(this->theVector, 2u, 2, 3);
412 // Make sure the # of constructor/destructor calls line up. There
413 // are two live objects after clearing the other vector.
414 this->otherVector.clear();
415 EXPECT_EQ(Constructable::getNumConstructorCalls()-2,
416 Constructable::getNumDestructorCalls());
418 // There shouldn't be any live objects any more.
419 this->theVector.clear();
420 EXPECT_EQ(Constructable::getNumConstructorCalls(),
421 Constructable::getNumDestructorCalls());
424 // Erase a single element
425 TYPED_TEST(SmallVectorTest, EraseTest) {
426 SCOPED_TRACE("EraseTest");
428 this->makeSequence(this->theVector, 1, 3);
429 this->theVector.erase(this->theVector.begin());
430 this->assertValuesInOrder(this->theVector, 2u, 2, 3);
433 // Erase a range of elements
434 TYPED_TEST(SmallVectorTest, EraseRangeTest) {
435 SCOPED_TRACE("EraseRangeTest");
437 this->makeSequence(this->theVector, 1, 3);
438 this->theVector.erase(this->theVector.begin(), this->theVector.begin() + 2);
439 this->assertValuesInOrder(this->theVector, 1u, 3);
442 // Insert a single element.
443 TYPED_TEST(SmallVectorTest, InsertTest) {
444 SCOPED_TRACE("InsertTest");
446 this->makeSequence(this->theVector, 1, 3);
447 typename TypeParam::iterator I =
448 this->theVector.insert(this->theVector.begin() + 1, Constructable(77));
449 EXPECT_EQ(this->theVector.begin() + 1, I);
450 this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3);
453 // Insert a copy of a single element.
454 TYPED_TEST(SmallVectorTest, InsertCopy) {
455 SCOPED_TRACE("InsertTest");
457 this->makeSequence(this->theVector, 1, 3);
459 typename TypeParam::iterator I =
460 this->theVector.insert(this->theVector.begin() + 1, C);
461 EXPECT_EQ(this->theVector.begin() + 1, I);
462 this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3);
465 // Insert repeated elements.
466 TYPED_TEST(SmallVectorTest, InsertRepeatedTest) {
467 SCOPED_TRACE("InsertRepeatedTest");
469 this->makeSequence(this->theVector, 1, 4);
470 Constructable::reset();
472 this->theVector.insert(this->theVector.begin() + 1, 2, Constructable(16));
473 // Move construct the top element into newly allocated space, and optionally
474 // reallocate the whole buffer, move constructing into it.
475 // FIXME: This is inefficient, we shouldn't move things into newly allocated
476 // space, then move them up/around, there should only be 2 or 4 move
477 // constructions here.
478 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 ||
479 Constructable::getNumMoveConstructorCalls() == 6);
480 // Move assign the next two to shift them up and make a gap.
481 EXPECT_EQ(1, Constructable::getNumMoveAssignmentCalls());
482 // Copy construct the two new elements from the parameter.
483 EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls());
484 // All without any copy construction.
485 EXPECT_EQ(0, Constructable::getNumCopyConstructorCalls());
486 EXPECT_EQ(this->theVector.begin() + 1, I);
487 this->assertValuesInOrder(this->theVector, 6u, 1, 16, 16, 2, 3, 4);
491 TYPED_TEST(SmallVectorTest, InsertRepeatedAtEndTest) {
492 SCOPED_TRACE("InsertRepeatedTest");
494 this->makeSequence(this->theVector, 1, 4);
495 Constructable::reset();
496 auto I = this->theVector.insert(this->theVector.end(), 2, Constructable(16));
497 // Just copy construct them into newly allocated space
498 EXPECT_EQ(2, Constructable::getNumCopyConstructorCalls());
499 // Move everything across if reallocation is needed.
500 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 ||
501 Constructable::getNumMoveConstructorCalls() == 4);
502 // Without ever moving or copying anything else.
503 EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls());
504 EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls());
506 EXPECT_EQ(this->theVector.begin() + 4, I);
507 this->assertValuesInOrder(this->theVector, 6u, 1, 2, 3, 4, 16, 16);
510 TYPED_TEST(SmallVectorTest, InsertRepeatedEmptyTest) {
511 SCOPED_TRACE("InsertRepeatedTest");
513 this->makeSequence(this->theVector, 10, 15);
516 EXPECT_EQ(this->theVector.end(),
517 this->theVector.insert(this->theVector.end(),
518 0, Constructable(42)));
519 EXPECT_EQ(this->theVector.begin() + 1,
520 this->theVector.insert(this->theVector.begin() + 1,
521 0, Constructable(42)));
525 TYPED_TEST(SmallVectorTest, InsertRangeTest) {
526 SCOPED_TRACE("InsertRangeTest");
528 Constructable Arr[3] =
529 { Constructable(77), Constructable(77), Constructable(77) };
531 this->makeSequence(this->theVector, 1, 3);
532 Constructable::reset();
533 auto I = this->theVector.insert(this->theVector.begin() + 1, Arr, Arr + 3);
534 // Move construct the top 3 elements into newly allocated space.
535 // Possibly move the whole sequence into new space first.
536 // FIXME: This is inefficient, we shouldn't move things into newly allocated
537 // space, then move them up/around, there should only be 2 or 3 move
538 // constructions here.
539 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 ||
540 Constructable::getNumMoveConstructorCalls() == 5);
541 // Copy assign the lower 2 new elements into existing space.
542 EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls());
543 // Copy construct the third element into newly allocated space.
544 EXPECT_EQ(1, Constructable::getNumCopyConstructorCalls());
545 EXPECT_EQ(this->theVector.begin() + 1, I);
546 this->assertValuesInOrder(this->theVector, 6u, 1, 77, 77, 77, 2, 3);
550 TYPED_TEST(SmallVectorTest, InsertRangeAtEndTest) {
551 SCOPED_TRACE("InsertRangeTest");
553 Constructable Arr[3] =
554 { Constructable(77), Constructable(77), Constructable(77) };
556 this->makeSequence(this->theVector, 1, 3);
559 Constructable::reset();
560 auto I = this->theVector.insert(this->theVector.end(), Arr, Arr+3);
561 // Copy construct the 3 elements into new space at the top.
562 EXPECT_EQ(3, Constructable::getNumCopyConstructorCalls());
563 // Don't copy/move anything else.
564 EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls());
565 // Reallocation might occur, causing all elements to be moved into the new
567 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 ||
568 Constructable::getNumMoveConstructorCalls() == 3);
569 EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls());
570 EXPECT_EQ(this->theVector.begin() + 3, I);
571 this->assertValuesInOrder(this->theVector, 6u,
572 1, 2, 3, 77, 77, 77);
575 TYPED_TEST(SmallVectorTest, InsertEmptyRangeTest) {
576 SCOPED_TRACE("InsertRangeTest");
578 this->makeSequence(this->theVector, 1, 3);
581 EXPECT_EQ(this->theVector.end(),
582 this->theVector.insert(this->theVector.end(),
583 this->theVector.begin(),
584 this->theVector.begin()));
585 EXPECT_EQ(this->theVector.begin() + 1,
586 this->theVector.insert(this->theVector.begin() + 1,
587 this->theVector.begin(),
588 this->theVector.begin()));
592 TYPED_TEST(SmallVectorTest, ComparisonTest) {
593 SCOPED_TRACE("ComparisonTest");
595 this->makeSequence(this->theVector, 1, 3);
596 this->makeSequence(this->otherVector, 1, 3);
598 EXPECT_TRUE(this->theVector == this->otherVector);
599 EXPECT_FALSE(this->theVector != this->otherVector);
601 this->otherVector.clear();
602 this->makeSequence(this->otherVector, 2, 4);
604 EXPECT_FALSE(this->theVector == this->otherVector);
605 EXPECT_TRUE(this->theVector != this->otherVector);
608 // Constant vector tests.
609 TYPED_TEST(SmallVectorTest, ConstVectorTest) {
610 const TypeParam constVector;
612 EXPECT_EQ(0u, constVector.size());
613 EXPECT_TRUE(constVector.empty());
614 EXPECT_TRUE(constVector.begin() == constVector.end());
617 // Direct array access.
618 TYPED_TEST(SmallVectorTest, DirectVectorTest) {
619 EXPECT_EQ(0u, this->theVector.size());
620 this->theVector.reserve(4);
621 EXPECT_LE(4u, this->theVector.capacity());
622 EXPECT_EQ(0, Constructable::getNumConstructorCalls());
623 this->theVector.push_back(1);
624 this->theVector.push_back(2);
625 this->theVector.push_back(3);
626 this->theVector.push_back(4);
627 EXPECT_EQ(4u, this->theVector.size());
628 EXPECT_EQ(8, Constructable::getNumConstructorCalls());
629 EXPECT_EQ(1, this->theVector[0].getValue());
630 EXPECT_EQ(2, this->theVector[1].getValue());
631 EXPECT_EQ(3, this->theVector[2].getValue());
632 EXPECT_EQ(4, this->theVector[3].getValue());
635 TYPED_TEST(SmallVectorTest, IteratorTest) {
637 this->theVector.insert(this->theVector.end(), L.begin(), L.end());
640 struct notassignable {
642 notassignable(int &x) : x(x) {}
645 TEST(SmallVectorCustomTest, NoAssignTest) {
647 SmallVector<notassignable, 2> vec;
648 vec.push_back(notassignable(x));
650 EXPECT_EQ(42, vec.pop_back_val().x);
655 MovedFrom() : hasValue(true) {
657 MovedFrom(MovedFrom&& m) : hasValue(m.hasValue) {
660 MovedFrom &operator=(MovedFrom&& m) {
661 hasValue = m.hasValue;
667 TEST(SmallVectorTest, MidInsert) {
668 SmallVector<MovedFrom, 3> v;
669 v.push_back(MovedFrom());
670 v.insert(v.begin(), MovedFrom());
671 for (MovedFrom &m : v)
672 EXPECT_TRUE(m.hasValue);