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) {
46 ++numConstructorCalls;
49 Constructable(Constructable && src) : constructed(true) {
51 ++numConstructorCalls;
55 EXPECT_TRUE(constructed);
60 Constructable & operator=(const Constructable & src) {
61 EXPECT_TRUE(constructed);
67 Constructable & operator=(Constructable && src) {
68 EXPECT_TRUE(constructed);
74 int getValue() const {
79 numConstructorCalls = 0;
80 numDestructorCalls = 0;
81 numAssignmentCalls = 0;
84 static int getNumConstructorCalls() {
85 return numConstructorCalls;
88 static int getNumDestructorCalls() {
89 return numDestructorCalls;
92 friend bool operator==(const Constructable & c0, const Constructable & c1) {
93 return c0.getValue() == c1.getValue();
96 friend bool LLVM_ATTRIBUTE_UNUSED
97 operator!=(const Constructable & c0, const Constructable & c1) {
98 return c0.getValue() != c1.getValue();
102 int Constructable::numConstructorCalls;
103 int Constructable::numDestructorCalls;
104 int Constructable::numAssignmentCalls;
106 // Test fixture class
107 template <typename VectorT>
108 class SmallVectorTest : public testing::Test {
114 Constructable::reset();
117 void assertEmpty(VectorT & v) {
119 EXPECT_EQ(0u, v.size());
120 EXPECT_TRUE(v.empty());
123 EXPECT_TRUE(v.begin() == v.end());
126 // Assert that theVector contains the specified values, in order.
127 void assertValuesInOrder(VectorT & v, size_t size, ...) {
128 EXPECT_EQ(size, v.size());
132 for (size_t i = 0; i < size; ++i) {
133 int value = va_arg(ap, int);
134 EXPECT_EQ(value, v[i].getValue());
140 // Generate a sequence of values to initialize the vector.
141 void makeSequence(VectorT & v, int start, int end) {
142 for (int i = start; i <= end; ++i) {
143 v.push_back(Constructable(i));
148 typedef ::testing::Types<SmallVector<Constructable, 0>,
149 SmallVector<Constructable, 1>,
150 SmallVector<Constructable, 2>,
151 SmallVector<Constructable, 4>
152 > SmallVectorTestTypes;
153 TYPED_TEST_CASE(SmallVectorTest, SmallVectorTestTypes);
156 TYPED_TEST(SmallVectorTest, EmptyVectorTest) {
157 SCOPED_TRACE("EmptyVectorTest");
158 this->assertEmpty(this->theVector);
159 EXPECT_TRUE(this->theVector.rbegin() == this->theVector.rend());
160 EXPECT_EQ(0, Constructable::getNumConstructorCalls());
161 EXPECT_EQ(0, Constructable::getNumDestructorCalls());
164 // Simple insertions and deletions.
165 TYPED_TEST(SmallVectorTest, PushPopTest) {
166 SCOPED_TRACE("PushPopTest");
168 // Track whether the vector will potentially have to grow.
169 bool RequiresGrowth = this->theVector.capacity() < 3;
172 this->theVector.push_back(Constructable(1));
175 this->assertValuesInOrder(this->theVector, 1u, 1);
176 EXPECT_FALSE(this->theVector.begin() == this->theVector.end());
177 EXPECT_FALSE(this->theVector.empty());
179 // Push another element
180 this->theVector.push_back(Constructable(2));
181 this->assertValuesInOrder(this->theVector, 2u, 1, 2);
183 // Insert at beginning
184 this->theVector.insert(this->theVector.begin(), this->theVector[1]);
185 this->assertValuesInOrder(this->theVector, 3u, 2, 1, 2);
188 this->theVector.pop_back();
189 this->assertValuesInOrder(this->theVector, 2u, 2, 1);
191 // Pop remaining elements
192 this->theVector.pop_back();
193 this->theVector.pop_back();
194 this->assertEmpty(this->theVector);
196 // Check number of constructor calls. Should be 2 for each list element,
197 // one for the argument to push_back, one for the argument to insert,
198 // and one for the list element itself.
199 if (!RequiresGrowth) {
200 EXPECT_EQ(5, Constructable::getNumConstructorCalls());
201 EXPECT_EQ(5, Constructable::getNumDestructorCalls());
203 // If we had to grow the vector, these only have a lower bound, but should
205 EXPECT_LE(5, Constructable::getNumConstructorCalls());
206 EXPECT_EQ(Constructable::getNumConstructorCalls(),
207 Constructable::getNumDestructorCalls());
212 TYPED_TEST(SmallVectorTest, ClearTest) {
213 SCOPED_TRACE("ClearTest");
215 this->theVector.reserve(2);
216 this->makeSequence(this->theVector, 1, 2);
217 this->theVector.clear();
219 this->assertEmpty(this->theVector);
220 EXPECT_EQ(4, Constructable::getNumConstructorCalls());
221 EXPECT_EQ(4, Constructable::getNumDestructorCalls());
224 // Resize smaller test.
225 TYPED_TEST(SmallVectorTest, ResizeShrinkTest) {
226 SCOPED_TRACE("ResizeShrinkTest");
228 this->theVector.reserve(3);
229 this->makeSequence(this->theVector, 1, 3);
230 this->theVector.resize(1);
232 this->assertValuesInOrder(this->theVector, 1u, 1);
233 EXPECT_EQ(6, Constructable::getNumConstructorCalls());
234 EXPECT_EQ(5, Constructable::getNumDestructorCalls());
237 // Resize bigger test.
238 TYPED_TEST(SmallVectorTest, ResizeGrowTest) {
239 SCOPED_TRACE("ResizeGrowTest");
241 this->theVector.resize(2);
243 // The extra constructor/destructor calls come from the temporary object used
244 // to initialize the contents of the resized array (via copy construction).
245 EXPECT_EQ(3, Constructable::getNumConstructorCalls());
246 EXPECT_EQ(1, Constructable::getNumDestructorCalls());
247 EXPECT_EQ(2u, this->theVector.size());
250 // Resize with fill value.
251 TYPED_TEST(SmallVectorTest, ResizeFillTest) {
252 SCOPED_TRACE("ResizeFillTest");
254 this->theVector.resize(3, Constructable(77));
255 this->assertValuesInOrder(this->theVector, 3u, 77, 77, 77);
258 // Overflow past fixed size.
259 TYPED_TEST(SmallVectorTest, OverflowTest) {
260 SCOPED_TRACE("OverflowTest");
262 // Push more elements than the fixed size.
263 this->makeSequence(this->theVector, 1, 10);
265 // Test size and values.
266 EXPECT_EQ(10u, this->theVector.size());
267 for (int i = 0; i < 10; ++i) {
268 EXPECT_EQ(i+1, this->theVector[i].getValue());
271 // Now resize back to fixed size.
272 this->theVector.resize(1);
274 this->assertValuesInOrder(this->theVector, 1u, 1);
278 TYPED_TEST(SmallVectorTest, IterationTest) {
279 this->makeSequence(this->theVector, 1, 2);
282 typename TypeParam::iterator it = this->theVector.begin();
283 EXPECT_TRUE(*it == this->theVector.front());
284 EXPECT_TRUE(*it == this->theVector[0]);
285 EXPECT_EQ(1, it->getValue());
287 EXPECT_TRUE(*it == this->theVector[1]);
288 EXPECT_TRUE(*it == this->theVector.back());
289 EXPECT_EQ(2, it->getValue());
291 EXPECT_TRUE(it == this->theVector.end());
293 EXPECT_TRUE(*it == this->theVector[1]);
294 EXPECT_EQ(2, it->getValue());
296 EXPECT_TRUE(*it == this->theVector[0]);
297 EXPECT_EQ(1, it->getValue());
300 typename TypeParam::reverse_iterator rit = this->theVector.rbegin();
301 EXPECT_TRUE(*rit == this->theVector[1]);
302 EXPECT_EQ(2, rit->getValue());
304 EXPECT_TRUE(*rit == this->theVector[0]);
305 EXPECT_EQ(1, rit->getValue());
307 EXPECT_TRUE(rit == this->theVector.rend());
309 EXPECT_TRUE(*rit == this->theVector[0]);
310 EXPECT_EQ(1, rit->getValue());
312 EXPECT_TRUE(*rit == this->theVector[1]);
313 EXPECT_EQ(2, rit->getValue());
317 TYPED_TEST(SmallVectorTest, SwapTest) {
318 SCOPED_TRACE("SwapTest");
320 this->makeSequence(this->theVector, 1, 2);
321 std::swap(this->theVector, this->otherVector);
323 this->assertEmpty(this->theVector);
324 this->assertValuesInOrder(this->otherVector, 2u, 1, 2);
328 TYPED_TEST(SmallVectorTest, AppendTest) {
329 SCOPED_TRACE("AppendTest");
331 this->makeSequence(this->otherVector, 2, 3);
333 this->theVector.push_back(Constructable(1));
334 this->theVector.append(this->otherVector.begin(), this->otherVector.end());
336 this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3);
339 // Append repeated test
340 TYPED_TEST(SmallVectorTest, AppendRepeatedTest) {
341 SCOPED_TRACE("AppendRepeatedTest");
343 this->theVector.push_back(Constructable(1));
344 this->theVector.append(2, Constructable(77));
345 this->assertValuesInOrder(this->theVector, 3u, 1, 77, 77);
349 TYPED_TEST(SmallVectorTest, AssignTest) {
350 SCOPED_TRACE("AssignTest");
352 this->theVector.push_back(Constructable(1));
353 this->theVector.assign(2, Constructable(77));
354 this->assertValuesInOrder(this->theVector, 2u, 77, 77);
358 TYPED_TEST(SmallVectorTest, MoveAssignTest) {
359 SCOPED_TRACE("MoveAssignTest");
361 // Set up our vector with a single element, but enough capacity for 4.
362 this->theVector.reserve(4);
363 this->theVector.push_back(Constructable(1));
365 // Set up the other vector with 2 elements.
366 this->otherVector.push_back(Constructable(2));
367 this->otherVector.push_back(Constructable(3));
369 // Move-assign from the other vector.
370 this->theVector = std::move(this->otherVector);
372 // Make sure we have the right result.
373 this->assertValuesInOrder(this->theVector, 2u, 2, 3);
375 // Make sure the # of constructor/destructor calls line up. There
376 // are two live objects after clearing the other vector.
377 this->otherVector.clear();
378 EXPECT_EQ(Constructable::getNumConstructorCalls()-2,
379 Constructable::getNumDestructorCalls());
381 // There shouldn't be any live objects any more.
382 this->theVector.clear();
383 EXPECT_EQ(Constructable::getNumConstructorCalls(),
384 Constructable::getNumDestructorCalls());
387 // Erase a single element
388 TYPED_TEST(SmallVectorTest, EraseTest) {
389 SCOPED_TRACE("EraseTest");
391 this->makeSequence(this->theVector, 1, 3);
392 this->theVector.erase(this->theVector.begin());
393 this->assertValuesInOrder(this->theVector, 2u, 2, 3);
396 // Erase a range of elements
397 TYPED_TEST(SmallVectorTest, EraseRangeTest) {
398 SCOPED_TRACE("EraseRangeTest");
400 this->makeSequence(this->theVector, 1, 3);
401 this->theVector.erase(this->theVector.begin(), this->theVector.begin() + 2);
402 this->assertValuesInOrder(this->theVector, 1u, 3);
405 // Insert a single element.
406 TYPED_TEST(SmallVectorTest, InsertTest) {
407 SCOPED_TRACE("InsertTest");
409 this->makeSequence(this->theVector, 1, 3);
410 typename TypeParam::iterator I =
411 this->theVector.insert(this->theVector.begin() + 1, Constructable(77));
412 EXPECT_EQ(this->theVector.begin() + 1, I);
413 this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3);
416 // Insert repeated elements.
417 TYPED_TEST(SmallVectorTest, InsertRepeatedTest) {
418 SCOPED_TRACE("InsertRepeatedTest");
420 this->makeSequence(this->theVector, 10, 15);
421 typename TypeParam::iterator I =
422 this->theVector.insert(this->theVector.begin() + 1, 2, Constructable(16));
423 EXPECT_EQ(this->theVector.begin() + 1, I);
424 this->assertValuesInOrder(this->theVector, 8u,
425 10, 16, 16, 11, 12, 13, 14, 15);
428 I = this->theVector.insert(this->theVector.end(), 2, Constructable(16));
429 EXPECT_EQ(this->theVector.begin() + 8, I);
430 this->assertValuesInOrder(this->theVector, 10u,
431 10, 16, 16, 11, 12, 13, 14, 15, 16, 16);
434 EXPECT_EQ(this->theVector.end(),
435 this->theVector.insert(this->theVector.end(),
436 0, Constructable(42)));
437 EXPECT_EQ(this->theVector.begin() + 1,
438 this->theVector.insert(this->theVector.begin() + 1,
439 0, Constructable(42)));
443 TYPED_TEST(SmallVectorTest, InsertRangeTest) {
444 SCOPED_TRACE("InsertRangeTest");
446 Constructable Arr[3] =
447 { Constructable(77), Constructable(77), Constructable(77) };
449 this->makeSequence(this->theVector, 1, 3);
450 typename TypeParam::iterator I =
451 this->theVector.insert(this->theVector.begin() + 1, Arr, Arr+3);
452 EXPECT_EQ(this->theVector.begin() + 1, I);
453 this->assertValuesInOrder(this->theVector, 6u, 1, 77, 77, 77, 2, 3);
456 I = this->theVector.insert(this->theVector.end(), Arr, Arr+3);
457 EXPECT_EQ(this->theVector.begin() + 6, I);
458 this->assertValuesInOrder(this->theVector, 9u,
459 1, 77, 77, 77, 2, 3, 77, 77, 77);
462 EXPECT_EQ(this->theVector.end(),
463 this->theVector.insert(this->theVector.end(),
464 this->theVector.begin(),
465 this->theVector.begin()));
466 EXPECT_EQ(this->theVector.begin() + 1,
467 this->theVector.insert(this->theVector.begin() + 1,
468 this->theVector.begin(),
469 this->theVector.begin()));
473 TYPED_TEST(SmallVectorTest, ComparisonTest) {
474 SCOPED_TRACE("ComparisonTest");
476 this->makeSequence(this->theVector, 1, 3);
477 this->makeSequence(this->otherVector, 1, 3);
479 EXPECT_TRUE(this->theVector == this->otherVector);
480 EXPECT_FALSE(this->theVector != this->otherVector);
482 this->otherVector.clear();
483 this->makeSequence(this->otherVector, 2, 4);
485 EXPECT_FALSE(this->theVector == this->otherVector);
486 EXPECT_TRUE(this->theVector != this->otherVector);
489 // Constant vector tests.
490 TYPED_TEST(SmallVectorTest, ConstVectorTest) {
491 const TypeParam constVector;
493 EXPECT_EQ(0u, constVector.size());
494 EXPECT_TRUE(constVector.empty());
495 EXPECT_TRUE(constVector.begin() == constVector.end());
498 // Direct array access.
499 TYPED_TEST(SmallVectorTest, DirectVectorTest) {
500 EXPECT_EQ(0u, this->theVector.size());
501 this->theVector.reserve(4);
502 EXPECT_LE(4u, this->theVector.capacity());
503 EXPECT_EQ(0, Constructable::getNumConstructorCalls());
504 this->theVector.push_back(1);
505 this->theVector.push_back(2);
506 this->theVector.push_back(3);
507 this->theVector.push_back(4);
508 EXPECT_EQ(4u, this->theVector.size());
509 EXPECT_EQ(8, Constructable::getNumConstructorCalls());
510 EXPECT_EQ(1, this->theVector[0].getValue());
511 EXPECT_EQ(2, this->theVector[1].getValue());
512 EXPECT_EQ(3, this->theVector[2].getValue());
513 EXPECT_EQ(4, this->theVector[3].getValue());
516 TYPED_TEST(SmallVectorTest, IteratorTest) {
518 this->theVector.insert(this->theVector.end(), L.begin(), L.end());
521 struct notassignable {
523 notassignable(int &x) : x(x) {}
526 TEST(SmallVectorCustomTest, NoAssignTest) {
528 SmallVector<notassignable, 2> vec;
529 vec.push_back(notassignable(x));
531 EXPECT_EQ(42, vec.pop_back_val().x);
536 MovedFrom() : hasValue(true) {
538 MovedFrom(MovedFrom&& m) : hasValue(m.hasValue) {
541 MovedFrom &operator=(MovedFrom&& m) {
542 hasValue = m.hasValue;
548 TEST(SmallVectorTest, MidInsert) {
549 SmallVector<MovedFrom, 3> v;
550 v.push_back(MovedFrom());
551 v.insert(v.begin(), MovedFrom());
552 for (MovedFrom &m : v)
553 EXPECT_TRUE(m.hasValue);