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 numDestructorCalls;
30 static int numAssignmentCalls;
36 Constructable() : constructed(true), value(0) {
37 ++numConstructorCalls;
40 Constructable(int val) : constructed(true), value(val) {
41 ++numConstructorCalls;
44 Constructable(const Constructable & src) : constructed(true) {
45 EXPECT_TRUE(src.constructed);
47 ++numConstructorCalls;
50 Constructable(Constructable && src) : constructed(true) {
51 EXPECT_TRUE(src.constructed);
54 ++numConstructorCalls;
58 EXPECT_TRUE(constructed);
63 Constructable & operator=(const Constructable & src) {
64 EXPECT_TRUE(constructed);
65 EXPECT_TRUE(src.constructed);
71 Constructable & operator=(Constructable && src) {
72 EXPECT_TRUE(constructed);
73 EXPECT_TRUE(src.constructed);
80 int getValue() const {
85 numConstructorCalls = 0;
86 numDestructorCalls = 0;
87 numAssignmentCalls = 0;
90 static int getNumConstructorCalls() {
91 return numConstructorCalls;
94 static int getNumDestructorCalls() {
95 return numDestructorCalls;
98 friend bool operator==(const Constructable & c0, const Constructable & c1) {
99 return c0.getValue() == c1.getValue();
102 friend bool LLVM_ATTRIBUTE_UNUSED
103 operator!=(const Constructable & c0, const Constructable & c1) {
104 return c0.getValue() != c1.getValue();
108 int Constructable::numConstructorCalls;
109 int Constructable::numDestructorCalls;
110 int Constructable::numAssignmentCalls;
112 // Test fixture class
113 template <typename VectorT>
114 class SmallVectorTest : public testing::Test {
120 Constructable::reset();
123 void assertEmpty(VectorT & v) {
125 EXPECT_EQ(0u, v.size());
126 EXPECT_TRUE(v.empty());
129 EXPECT_TRUE(v.begin() == v.end());
132 // Assert that theVector contains the specified values, in order.
133 void assertValuesInOrder(VectorT & v, size_t size, ...) {
134 EXPECT_EQ(size, v.size());
138 for (size_t i = 0; i < size; ++i) {
139 int value = va_arg(ap, int);
140 EXPECT_EQ(value, v[i].getValue());
146 // Generate a sequence of values to initialize the vector.
147 void makeSequence(VectorT & v, int start, int end) {
148 for (int i = start; i <= end; ++i) {
149 v.push_back(Constructable(i));
154 typedef ::testing::Types<SmallVector<Constructable, 0>,
155 SmallVector<Constructable, 1>,
156 SmallVector<Constructable, 2>,
157 SmallVector<Constructable, 4>
158 > SmallVectorTestTypes;
159 TYPED_TEST_CASE(SmallVectorTest, SmallVectorTestTypes);
162 TYPED_TEST(SmallVectorTest, EmptyVectorTest) {
163 SCOPED_TRACE("EmptyVectorTest");
164 this->assertEmpty(this->theVector);
165 EXPECT_TRUE(this->theVector.rbegin() == this->theVector.rend());
166 EXPECT_EQ(0, Constructable::getNumConstructorCalls());
167 EXPECT_EQ(0, Constructable::getNumDestructorCalls());
170 // Simple insertions and deletions.
171 TYPED_TEST(SmallVectorTest, PushPopTest) {
172 SCOPED_TRACE("PushPopTest");
174 // Track whether the vector will potentially have to grow.
175 bool RequiresGrowth = this->theVector.capacity() < 3;
178 this->theVector.push_back(Constructable(1));
181 this->assertValuesInOrder(this->theVector, 1u, 1);
182 EXPECT_FALSE(this->theVector.begin() == this->theVector.end());
183 EXPECT_FALSE(this->theVector.empty());
185 // Push another element
186 this->theVector.push_back(Constructable(2));
187 this->assertValuesInOrder(this->theVector, 2u, 1, 2);
189 // Insert at beginning
190 this->theVector.insert(this->theVector.begin(), this->theVector[1]);
191 this->assertValuesInOrder(this->theVector, 3u, 2, 1, 2);
194 this->theVector.pop_back();
195 this->assertValuesInOrder(this->theVector, 2u, 2, 1);
197 // Pop remaining elements
198 this->theVector.pop_back();
199 this->theVector.pop_back();
200 this->assertEmpty(this->theVector);
202 // Check number of constructor calls. Should be 2 for each list element,
203 // one for the argument to push_back, one for the argument to insert,
204 // and one for the list element itself.
205 if (!RequiresGrowth) {
206 EXPECT_EQ(5, Constructable::getNumConstructorCalls());
207 EXPECT_EQ(5, Constructable::getNumDestructorCalls());
209 // If we had to grow the vector, these only have a lower bound, but should
211 EXPECT_LE(5, Constructable::getNumConstructorCalls());
212 EXPECT_EQ(Constructable::getNumConstructorCalls(),
213 Constructable::getNumDestructorCalls());
218 TYPED_TEST(SmallVectorTest, ClearTest) {
219 SCOPED_TRACE("ClearTest");
221 this->theVector.reserve(2);
222 this->makeSequence(this->theVector, 1, 2);
223 this->theVector.clear();
225 this->assertEmpty(this->theVector);
226 EXPECT_EQ(4, Constructable::getNumConstructorCalls());
227 EXPECT_EQ(4, Constructable::getNumDestructorCalls());
230 // Resize smaller test.
231 TYPED_TEST(SmallVectorTest, ResizeShrinkTest) {
232 SCOPED_TRACE("ResizeShrinkTest");
234 this->theVector.reserve(3);
235 this->makeSequence(this->theVector, 1, 3);
236 this->theVector.resize(1);
238 this->assertValuesInOrder(this->theVector, 1u, 1);
239 EXPECT_EQ(6, Constructable::getNumConstructorCalls());
240 EXPECT_EQ(5, Constructable::getNumDestructorCalls());
243 // Resize bigger test.
244 TYPED_TEST(SmallVectorTest, ResizeGrowTest) {
245 SCOPED_TRACE("ResizeGrowTest");
247 this->theVector.resize(2);
249 // The extra constructor/destructor calls come from the temporary object used
250 // to initialize the contents of the resized array (via copy construction).
251 EXPECT_EQ(3, Constructable::getNumConstructorCalls());
252 EXPECT_EQ(1, Constructable::getNumDestructorCalls());
253 EXPECT_EQ(2u, this->theVector.size());
256 // Resize with fill value.
257 TYPED_TEST(SmallVectorTest, ResizeFillTest) {
258 SCOPED_TRACE("ResizeFillTest");
260 this->theVector.resize(3, Constructable(77));
261 this->assertValuesInOrder(this->theVector, 3u, 77, 77, 77);
264 // Overflow past fixed size.
265 TYPED_TEST(SmallVectorTest, OverflowTest) {
266 SCOPED_TRACE("OverflowTest");
268 // Push more elements than the fixed size.
269 this->makeSequence(this->theVector, 1, 10);
271 // Test size and values.
272 EXPECT_EQ(10u, this->theVector.size());
273 for (int i = 0; i < 10; ++i) {
274 EXPECT_EQ(i+1, this->theVector[i].getValue());
277 // Now resize back to fixed size.
278 this->theVector.resize(1);
280 this->assertValuesInOrder(this->theVector, 1u, 1);
284 TYPED_TEST(SmallVectorTest, IterationTest) {
285 this->makeSequence(this->theVector, 1, 2);
288 typename TypeParam::iterator it = this->theVector.begin();
289 EXPECT_TRUE(*it == this->theVector.front());
290 EXPECT_TRUE(*it == this->theVector[0]);
291 EXPECT_EQ(1, it->getValue());
293 EXPECT_TRUE(*it == this->theVector[1]);
294 EXPECT_TRUE(*it == this->theVector.back());
295 EXPECT_EQ(2, it->getValue());
297 EXPECT_TRUE(it == this->theVector.end());
299 EXPECT_TRUE(*it == this->theVector[1]);
300 EXPECT_EQ(2, it->getValue());
302 EXPECT_TRUE(*it == this->theVector[0]);
303 EXPECT_EQ(1, it->getValue());
306 typename TypeParam::reverse_iterator rit = this->theVector.rbegin();
307 EXPECT_TRUE(*rit == this->theVector[1]);
308 EXPECT_EQ(2, rit->getValue());
310 EXPECT_TRUE(*rit == this->theVector[0]);
311 EXPECT_EQ(1, rit->getValue());
313 EXPECT_TRUE(rit == this->theVector.rend());
315 EXPECT_TRUE(*rit == this->theVector[0]);
316 EXPECT_EQ(1, rit->getValue());
318 EXPECT_TRUE(*rit == this->theVector[1]);
319 EXPECT_EQ(2, rit->getValue());
323 TYPED_TEST(SmallVectorTest, SwapTest) {
324 SCOPED_TRACE("SwapTest");
326 this->makeSequence(this->theVector, 1, 2);
327 std::swap(this->theVector, this->otherVector);
329 this->assertEmpty(this->theVector);
330 this->assertValuesInOrder(this->otherVector, 2u, 1, 2);
334 TYPED_TEST(SmallVectorTest, AppendTest) {
335 SCOPED_TRACE("AppendTest");
337 this->makeSequence(this->otherVector, 2, 3);
339 this->theVector.push_back(Constructable(1));
340 this->theVector.append(this->otherVector.begin(), this->otherVector.end());
342 this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3);
345 // Append repeated test
346 TYPED_TEST(SmallVectorTest, AppendRepeatedTest) {
347 SCOPED_TRACE("AppendRepeatedTest");
349 this->theVector.push_back(Constructable(1));
350 this->theVector.append(2, Constructable(77));
351 this->assertValuesInOrder(this->theVector, 3u, 1, 77, 77);
355 TYPED_TEST(SmallVectorTest, AssignTest) {
356 SCOPED_TRACE("AssignTest");
358 this->theVector.push_back(Constructable(1));
359 this->theVector.assign(2, Constructable(77));
360 this->assertValuesInOrder(this->theVector, 2u, 77, 77);
364 TYPED_TEST(SmallVectorTest, MoveAssignTest) {
365 SCOPED_TRACE("MoveAssignTest");
367 // Set up our vector with a single element, but enough capacity for 4.
368 this->theVector.reserve(4);
369 this->theVector.push_back(Constructable(1));
371 // Set up the other vector with 2 elements.
372 this->otherVector.push_back(Constructable(2));
373 this->otherVector.push_back(Constructable(3));
375 // Move-assign from the other vector.
376 this->theVector = std::move(this->otherVector);
378 // Make sure we have the right result.
379 this->assertValuesInOrder(this->theVector, 2u, 2, 3);
381 // Make sure the # of constructor/destructor calls line up. There
382 // are two live objects after clearing the other vector.
383 this->otherVector.clear();
384 EXPECT_EQ(Constructable::getNumConstructorCalls()-2,
385 Constructable::getNumDestructorCalls());
387 // There shouldn't be any live objects any more.
388 this->theVector.clear();
389 EXPECT_EQ(Constructable::getNumConstructorCalls(),
390 Constructable::getNumDestructorCalls());
393 // Erase a single element
394 TYPED_TEST(SmallVectorTest, EraseTest) {
395 SCOPED_TRACE("EraseTest");
397 this->makeSequence(this->theVector, 1, 3);
398 this->theVector.erase(this->theVector.begin());
399 this->assertValuesInOrder(this->theVector, 2u, 2, 3);
402 // Erase a range of elements
403 TYPED_TEST(SmallVectorTest, EraseRangeTest) {
404 SCOPED_TRACE("EraseRangeTest");
406 this->makeSequence(this->theVector, 1, 3);
407 this->theVector.erase(this->theVector.begin(), this->theVector.begin() + 2);
408 this->assertValuesInOrder(this->theVector, 1u, 3);
411 // Insert a single element.
412 TYPED_TEST(SmallVectorTest, InsertTest) {
413 SCOPED_TRACE("InsertTest");
415 this->makeSequence(this->theVector, 1, 3);
416 typename TypeParam::iterator I =
417 this->theVector.insert(this->theVector.begin() + 1, Constructable(77));
418 EXPECT_EQ(this->theVector.begin() + 1, I);
419 this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3);
422 // Insert a copy of a single element.
423 TYPED_TEST(SmallVectorTest, InsertCopy) {
424 SCOPED_TRACE("InsertTest");
426 this->makeSequence(this->theVector, 1, 3);
428 typename TypeParam::iterator I =
429 this->theVector.insert(this->theVector.begin() + 1, C);
430 EXPECT_EQ(this->theVector.begin() + 1, I);
431 this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3);
434 // Insert repeated elements.
435 TYPED_TEST(SmallVectorTest, InsertRepeatedTest) {
436 SCOPED_TRACE("InsertRepeatedTest");
438 this->makeSequence(this->theVector, 10, 15);
439 typename TypeParam::iterator I =
440 this->theVector.insert(this->theVector.begin() + 1, 2, Constructable(16));
441 EXPECT_EQ(this->theVector.begin() + 1, I);
442 this->assertValuesInOrder(this->theVector, 8u,
443 10, 16, 16, 11, 12, 13, 14, 15);
446 I = this->theVector.insert(this->theVector.end(), 2, Constructable(16));
447 EXPECT_EQ(this->theVector.begin() + 8, I);
448 this->assertValuesInOrder(this->theVector, 10u,
449 10, 16, 16, 11, 12, 13, 14, 15, 16, 16);
452 EXPECT_EQ(this->theVector.end(),
453 this->theVector.insert(this->theVector.end(),
454 0, Constructable(42)));
455 EXPECT_EQ(this->theVector.begin() + 1,
456 this->theVector.insert(this->theVector.begin() + 1,
457 0, Constructable(42)));
461 TYPED_TEST(SmallVectorTest, InsertRangeTest) {
462 SCOPED_TRACE("InsertRangeTest");
464 Constructable Arr[3] =
465 { Constructable(77), Constructable(77), Constructable(77) };
467 this->makeSequence(this->theVector, 1, 3);
468 typename TypeParam::iterator I =
469 this->theVector.insert(this->theVector.begin() + 1, Arr, Arr+3);
470 EXPECT_EQ(this->theVector.begin() + 1, I);
471 this->assertValuesInOrder(this->theVector, 6u, 1, 77, 77, 77, 2, 3);
474 I = this->theVector.insert(this->theVector.end(), Arr, Arr+3);
475 EXPECT_EQ(this->theVector.begin() + 6, I);
476 this->assertValuesInOrder(this->theVector, 9u,
477 1, 77, 77, 77, 2, 3, 77, 77, 77);
480 EXPECT_EQ(this->theVector.end(),
481 this->theVector.insert(this->theVector.end(),
482 this->theVector.begin(),
483 this->theVector.begin()));
484 EXPECT_EQ(this->theVector.begin() + 1,
485 this->theVector.insert(this->theVector.begin() + 1,
486 this->theVector.begin(),
487 this->theVector.begin()));
491 TYPED_TEST(SmallVectorTest, ComparisonTest) {
492 SCOPED_TRACE("ComparisonTest");
494 this->makeSequence(this->theVector, 1, 3);
495 this->makeSequence(this->otherVector, 1, 3);
497 EXPECT_TRUE(this->theVector == this->otherVector);
498 EXPECT_FALSE(this->theVector != this->otherVector);
500 this->otherVector.clear();
501 this->makeSequence(this->otherVector, 2, 4);
503 EXPECT_FALSE(this->theVector == this->otherVector);
504 EXPECT_TRUE(this->theVector != this->otherVector);
507 // Constant vector tests.
508 TYPED_TEST(SmallVectorTest, ConstVectorTest) {
509 const TypeParam constVector;
511 EXPECT_EQ(0u, constVector.size());
512 EXPECT_TRUE(constVector.empty());
513 EXPECT_TRUE(constVector.begin() == constVector.end());
516 // Direct array access.
517 TYPED_TEST(SmallVectorTest, DirectVectorTest) {
518 EXPECT_EQ(0u, this->theVector.size());
519 this->theVector.reserve(4);
520 EXPECT_LE(4u, this->theVector.capacity());
521 EXPECT_EQ(0, Constructable::getNumConstructorCalls());
522 this->theVector.push_back(1);
523 this->theVector.push_back(2);
524 this->theVector.push_back(3);
525 this->theVector.push_back(4);
526 EXPECT_EQ(4u, this->theVector.size());
527 EXPECT_EQ(8, Constructable::getNumConstructorCalls());
528 EXPECT_EQ(1, this->theVector[0].getValue());
529 EXPECT_EQ(2, this->theVector[1].getValue());
530 EXPECT_EQ(3, this->theVector[2].getValue());
531 EXPECT_EQ(4, this->theVector[3].getValue());
534 TYPED_TEST(SmallVectorTest, IteratorTest) {
536 this->theVector.insert(this->theVector.end(), L.begin(), L.end());
539 struct notassignable {
541 notassignable(int &x) : x(x) {}
544 TEST(SmallVectorCustomTest, NoAssignTest) {
546 SmallVector<notassignable, 2> vec;
547 vec.push_back(notassignable(x));
549 EXPECT_EQ(42, vec.pop_back_val().x);
554 MovedFrom() : hasValue(true) {
556 MovedFrom(MovedFrom&& m) : hasValue(m.hasValue) {
559 MovedFrom &operator=(MovedFrom&& m) {
560 hasValue = m.hasValue;
566 TEST(SmallVectorTest, MidInsert) {
567 SmallVector<MovedFrom, 3> v;
568 v.push_back(MovedFrom());
569 v.insert(v.begin(), MovedFrom());
570 for (MovedFrom &m : v)
571 EXPECT_TRUE(m.hasValue);