1 //===- llvm/unittest/ADT/SmallVectorTest.cpp ------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // SmallVector unit tests. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ADT/SmallVector.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 numDestructorCalls; 30 static int numAssignmentCalls; 31 32 int value; 33 34 public: 35 Constructable() : value(0) { 36 ++numConstructorCalls; 37 } 38 39 Constructable(int val) : value(val) { 40 ++numConstructorCalls; 41 } 42 43 Constructable(const Constructable & src) { 44 value = src.value; 45 ++numConstructorCalls; 46 } 47 48 ~Constructable() { 49 ++numDestructorCalls; 50 } 51 52 Constructable & operator=(const Constructable & src) { 53 value = src.value; 54 ++numAssignmentCalls; 55 return *this; 56 } 57 58 int getValue() const { 59 return abs(value); 60 } 61 62 static void reset() { 63 numConstructorCalls = 0; 64 numDestructorCalls = 0; 65 numAssignmentCalls = 0; 66 } 67 68 static int getNumConstructorCalls() { 69 return numConstructorCalls; 70 } 71 72 static int getNumDestructorCalls() { 73 return numDestructorCalls; 74 } 75 76 friend bool operator==(const Constructable & c0, const Constructable & c1) { 77 return c0.getValue() == c1.getValue(); 78 } 79 80 friend bool LLVM_ATTRIBUTE_UNUSED 81 operator!=(const Constructable & c0, const Constructable & c1) { 82 return c0.getValue() != c1.getValue(); 83 } 84 }; 85 86 int Constructable::numConstructorCalls; 87 int Constructable::numDestructorCalls; 88 int Constructable::numAssignmentCalls; 89 90 // Test fixture class 91 template <typename VectorT> 92 class SmallVectorTest : public testing::Test { 93 protected: 94 VectorT theVector; 95 VectorT otherVector; 96 97 void SetUp() { 98 Constructable::reset(); 99 } 100 101 void assertEmpty(VectorT & v) { 102 // Size tests 103 EXPECT_EQ(0u, v.size()); 104 EXPECT_TRUE(v.empty()); 105 106 // Iterator tests 107 EXPECT_TRUE(v.begin() == v.end()); 108 } 109 110 // Assert that theVector contains the specified values, in order. 111 void assertValuesInOrder(VectorT & v, size_t size, ...) { 112 EXPECT_EQ(size, v.size()); 113 114 va_list ap; 115 va_start(ap, size); 116 for (size_t i = 0; i < size; ++i) { 117 int value = va_arg(ap, int); 118 EXPECT_EQ(value, v[i].getValue()); 119 } 120 121 va_end(ap); 122 } 123 124 // Generate a sequence of values to initialize the vector. 125 void makeSequence(VectorT & v, int start, int end) { 126 for (int i = start; i <= end; ++i) { 127 v.push_back(Constructable(i)); 128 } 129 } 130 }; 131 132 typedef ::testing::Types<SmallVector<Constructable, 0>, 133 SmallVector<Constructable, 1>, 134 SmallVector<Constructable, 2>, 135 SmallVector<Constructable, 4> 136 > SmallVectorTestTypes; 137 TYPED_TEST_CASE(SmallVectorTest, SmallVectorTestTypes); 138 139 // New vector test. 140 TYPED_TEST(SmallVectorTest, EmptyVectorTest) { 141 SCOPED_TRACE("EmptyVectorTest"); 142 this->assertEmpty(this->theVector); 143 EXPECT_TRUE(this->theVector.rbegin() == this->theVector.rend()); 144 EXPECT_EQ(0, Constructable::getNumConstructorCalls()); 145 EXPECT_EQ(0, Constructable::getNumDestructorCalls()); 146 } 147 148 // Simple insertions and deletions. 149 TYPED_TEST(SmallVectorTest, PushPopTest) { 150 SCOPED_TRACE("PushPopTest"); 151 152 // Track whether the vector will potentially have to grow. 153 bool RequiresGrowth = this->theVector.capacity() < 3; 154 155 // Push an element 156 this->theVector.push_back(Constructable(1)); 157 158 // Size tests 159 this->assertValuesInOrder(this->theVector, 1u, 1); 160 EXPECT_FALSE(this->theVector.begin() == this->theVector.end()); 161 EXPECT_FALSE(this->theVector.empty()); 162 163 // Push another element 164 this->theVector.push_back(Constructable(2)); 165 this->assertValuesInOrder(this->theVector, 2u, 1, 2); 166 167 // Insert at beginning 168 this->theVector.insert(this->theVector.begin(), this->theVector[1]); 169 this->assertValuesInOrder(this->theVector, 3u, 2, 1, 2); 170 171 // Pop one element 172 this->theVector.pop_back(); 173 this->assertValuesInOrder(this->theVector, 2u, 2, 1); 174 175 // Pop remaining elements 176 this->theVector.pop_back(); 177 this->theVector.pop_back(); 178 this->assertEmpty(this->theVector); 179 180 // Check number of constructor calls. Should be 2 for each list element, 181 // one for the argument to push_back, one for the argument to insert, 182 // and one for the list element itself. 183 if (!RequiresGrowth) { 184 EXPECT_EQ(5, Constructable::getNumConstructorCalls()); 185 EXPECT_EQ(5, Constructable::getNumDestructorCalls()); 186 } else { 187 // If we had to grow the vector, these only have a lower bound, but should 188 // always be equal. 189 EXPECT_LE(5, Constructable::getNumConstructorCalls()); 190 EXPECT_EQ(Constructable::getNumConstructorCalls(), 191 Constructable::getNumDestructorCalls()); 192 } 193 } 194 195 // Clear test. 196 TYPED_TEST(SmallVectorTest, ClearTest) { 197 SCOPED_TRACE("ClearTest"); 198 199 this->theVector.reserve(2); 200 this->makeSequence(this->theVector, 1, 2); 201 this->theVector.clear(); 202 203 this->assertEmpty(this->theVector); 204 EXPECT_EQ(4, Constructable::getNumConstructorCalls()); 205 EXPECT_EQ(4, Constructable::getNumDestructorCalls()); 206 } 207 208 // Resize smaller test. 209 TYPED_TEST(SmallVectorTest, ResizeShrinkTest) { 210 SCOPED_TRACE("ResizeShrinkTest"); 211 212 this->theVector.reserve(3); 213 this->makeSequence(this->theVector, 1, 3); 214 this->theVector.resize(1); 215 216 this->assertValuesInOrder(this->theVector, 1u, 1); 217 EXPECT_EQ(6, Constructable::getNumConstructorCalls()); 218 EXPECT_EQ(5, Constructable::getNumDestructorCalls()); 219 } 220 221 // Resize bigger test. 222 TYPED_TEST(SmallVectorTest, ResizeGrowTest) { 223 SCOPED_TRACE("ResizeGrowTest"); 224 225 this->theVector.resize(2); 226 227 // The extra constructor/destructor calls come from the temporary object used 228 // to initialize the contents of the resized array (via copy construction). 229 EXPECT_EQ(3, Constructable::getNumConstructorCalls()); 230 EXPECT_EQ(1, Constructable::getNumDestructorCalls()); 231 EXPECT_EQ(2u, this->theVector.size()); 232 } 233 234 // Resize with fill value. 235 TYPED_TEST(SmallVectorTest, ResizeFillTest) { 236 SCOPED_TRACE("ResizeFillTest"); 237 238 this->theVector.resize(3, Constructable(77)); 239 this->assertValuesInOrder(this->theVector, 3u, 77, 77, 77); 240 } 241 242 // Overflow past fixed size. 243 TYPED_TEST(SmallVectorTest, OverflowTest) { 244 SCOPED_TRACE("OverflowTest"); 245 246 // Push more elements than the fixed size. 247 this->makeSequence(this->theVector, 1, 10); 248 249 // Test size and values. 250 EXPECT_EQ(10u, this->theVector.size()); 251 for (int i = 0; i < 10; ++i) { 252 EXPECT_EQ(i+1, this->theVector[i].getValue()); 253 } 254 255 // Now resize back to fixed size. 256 this->theVector.resize(1); 257 258 this->assertValuesInOrder(this->theVector, 1u, 1); 259 } 260 261 // Iteration tests. 262 TYPED_TEST(SmallVectorTest, IterationTest) { 263 this->makeSequence(this->theVector, 1, 2); 264 265 // Forward Iteration 266 typename TypeParam::iterator it = this->theVector.begin(); 267 EXPECT_TRUE(*it == this->theVector.front()); 268 EXPECT_TRUE(*it == this->theVector[0]); 269 EXPECT_EQ(1, it->getValue()); 270 ++it; 271 EXPECT_TRUE(*it == this->theVector[1]); 272 EXPECT_TRUE(*it == this->theVector.back()); 273 EXPECT_EQ(2, it->getValue()); 274 ++it; 275 EXPECT_TRUE(it == this->theVector.end()); 276 --it; 277 EXPECT_TRUE(*it == this->theVector[1]); 278 EXPECT_EQ(2, it->getValue()); 279 --it; 280 EXPECT_TRUE(*it == this->theVector[0]); 281 EXPECT_EQ(1, it->getValue()); 282 283 // Reverse Iteration 284 typename TypeParam::reverse_iterator rit = this->theVector.rbegin(); 285 EXPECT_TRUE(*rit == this->theVector[1]); 286 EXPECT_EQ(2, rit->getValue()); 287 ++rit; 288 EXPECT_TRUE(*rit == this->theVector[0]); 289 EXPECT_EQ(1, rit->getValue()); 290 ++rit; 291 EXPECT_TRUE(rit == this->theVector.rend()); 292 --rit; 293 EXPECT_TRUE(*rit == this->theVector[0]); 294 EXPECT_EQ(1, rit->getValue()); 295 --rit; 296 EXPECT_TRUE(*rit == this->theVector[1]); 297 EXPECT_EQ(2, rit->getValue()); 298 } 299 300 // Swap test. 301 TYPED_TEST(SmallVectorTest, SwapTest) { 302 SCOPED_TRACE("SwapTest"); 303 304 this->makeSequence(this->theVector, 1, 2); 305 std::swap(this->theVector, this->otherVector); 306 307 this->assertEmpty(this->theVector); 308 this->assertValuesInOrder(this->otherVector, 2u, 1, 2); 309 } 310 311 // Append test 312 TYPED_TEST(SmallVectorTest, AppendTest) { 313 SCOPED_TRACE("AppendTest"); 314 315 this->makeSequence(this->otherVector, 2, 3); 316 317 this->theVector.push_back(Constructable(1)); 318 this->theVector.append(this->otherVector.begin(), this->otherVector.end()); 319 320 this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3); 321 } 322 323 // Append repeated test 324 TYPED_TEST(SmallVectorTest, AppendRepeatedTest) { 325 SCOPED_TRACE("AppendRepeatedTest"); 326 327 this->theVector.push_back(Constructable(1)); 328 this->theVector.append(2, Constructable(77)); 329 this->assertValuesInOrder(this->theVector, 3u, 1, 77, 77); 330 } 331 332 // Assign test 333 TYPED_TEST(SmallVectorTest, AssignTest) { 334 SCOPED_TRACE("AssignTest"); 335 336 this->theVector.push_back(Constructable(1)); 337 this->theVector.assign(2, Constructable(77)); 338 this->assertValuesInOrder(this->theVector, 2u, 77, 77); 339 } 340 341 // Erase a single element 342 TYPED_TEST(SmallVectorTest, EraseTest) { 343 SCOPED_TRACE("EraseTest"); 344 345 this->makeSequence(this->theVector, 1, 3); 346 this->theVector.erase(this->theVector.begin()); 347 this->assertValuesInOrder(this->theVector, 2u, 2, 3); 348 } 349 350 // Erase a range of elements 351 TYPED_TEST(SmallVectorTest, EraseRangeTest) { 352 SCOPED_TRACE("EraseRangeTest"); 353 354 this->makeSequence(this->theVector, 1, 3); 355 this->theVector.erase(this->theVector.begin(), this->theVector.begin() + 2); 356 this->assertValuesInOrder(this->theVector, 1u, 3); 357 } 358 359 // Insert a single element. 360 TYPED_TEST(SmallVectorTest, InsertTest) { 361 SCOPED_TRACE("InsertTest"); 362 363 this->makeSequence(this->theVector, 1, 3); 364 typename TypeParam::iterator I = 365 this->theVector.insert(this->theVector.begin() + 1, Constructable(77)); 366 EXPECT_EQ(this->theVector.begin() + 1, I); 367 this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3); 368 } 369 370 // Insert repeated elements. 371 TYPED_TEST(SmallVectorTest, InsertRepeatedTest) { 372 SCOPED_TRACE("InsertRepeatedTest"); 373 374 this->makeSequence(this->theVector, 10, 15); 375 typename TypeParam::iterator I = 376 this->theVector.insert(this->theVector.begin() + 1, 2, Constructable(16)); 377 EXPECT_EQ(this->theVector.begin() + 1, I); 378 this->assertValuesInOrder(this->theVector, 8u, 379 10, 16, 16, 11, 12, 13, 14, 15); 380 381 // Insert at end. 382 I = this->theVector.insert(this->theVector.end(), 2, Constructable(16)); 383 EXPECT_EQ(this->theVector.begin() + 8, I); 384 this->assertValuesInOrder(this->theVector, 10u, 385 10, 16, 16, 11, 12, 13, 14, 15, 16, 16); 386 387 // Empty insert. 388 EXPECT_EQ(this->theVector.end(), 389 this->theVector.insert(this->theVector.end(), 390 0, Constructable(42))); 391 EXPECT_EQ(this->theVector.begin() + 1, 392 this->theVector.insert(this->theVector.begin() + 1, 393 0, Constructable(42))); 394 } 395 396 // Insert range. 397 TYPED_TEST(SmallVectorTest, InsertRangeTest) { 398 SCOPED_TRACE("InsertRangeTest"); 399 400 Constructable Arr[3] = 401 { Constructable(77), Constructable(77), Constructable(77) }; 402 403 this->makeSequence(this->theVector, 1, 3); 404 typename TypeParam::iterator I = 405 this->theVector.insert(this->theVector.begin() + 1, Arr, Arr+3); 406 EXPECT_EQ(this->theVector.begin() + 1, I); 407 this->assertValuesInOrder(this->theVector, 6u, 1, 77, 77, 77, 2, 3); 408 409 // Insert at end. 410 I = this->theVector.insert(this->theVector.end(), Arr, Arr+3); 411 EXPECT_EQ(this->theVector.begin() + 6, I); 412 this->assertValuesInOrder(this->theVector, 9u, 413 1, 77, 77, 77, 2, 3, 77, 77, 77); 414 415 // Empty insert. 416 EXPECT_EQ(this->theVector.end(), 417 this->theVector.insert(this->theVector.end(), 418 this->theVector.begin(), 419 this->theVector.begin())); 420 EXPECT_EQ(this->theVector.begin() + 1, 421 this->theVector.insert(this->theVector.begin() + 1, 422 this->theVector.begin(), 423 this->theVector.begin())); 424 } 425 426 // Comparison tests. 427 TYPED_TEST(SmallVectorTest, ComparisonTest) { 428 SCOPED_TRACE("ComparisonTest"); 429 430 this->makeSequence(this->theVector, 1, 3); 431 this->makeSequence(this->otherVector, 1, 3); 432 433 EXPECT_TRUE(this->theVector == this->otherVector); 434 EXPECT_FALSE(this->theVector != this->otherVector); 435 436 this->otherVector.clear(); 437 this->makeSequence(this->otherVector, 2, 4); 438 439 EXPECT_FALSE(this->theVector == this->otherVector); 440 EXPECT_TRUE(this->theVector != this->otherVector); 441 } 442 443 // Constant vector tests. 444 TYPED_TEST(SmallVectorTest, ConstVectorTest) { 445 const TypeParam constVector; 446 447 EXPECT_EQ(0u, constVector.size()); 448 EXPECT_TRUE(constVector.empty()); 449 EXPECT_TRUE(constVector.begin() == constVector.end()); 450 } 451 452 // Direct array access. 453 TYPED_TEST(SmallVectorTest, DirectVectorTest) { 454 EXPECT_EQ(0u, this->theVector.size()); 455 this->theVector.reserve(4); 456 EXPECT_LE(4u, this->theVector.capacity()); 457 EXPECT_EQ(0, Constructable::getNumConstructorCalls()); 458 this->theVector.end()[0] = 1; 459 this->theVector.end()[1] = 2; 460 this->theVector.end()[2] = 3; 461 this->theVector.end()[3] = 4; 462 this->theVector.set_size(4); 463 EXPECT_EQ(4u, this->theVector.size()); 464 EXPECT_EQ(4, Constructable::getNumConstructorCalls()); 465 EXPECT_EQ(1, this->theVector[0].getValue()); 466 EXPECT_EQ(2, this->theVector[1].getValue()); 467 EXPECT_EQ(3, this->theVector[2].getValue()); 468 EXPECT_EQ(4, this->theVector[3].getValue()); 469 } 470 471 TYPED_TEST(SmallVectorTest, IteratorTest) { 472 std::list<int> L; 473 this->theVector.insert(this->theVector.end(), L.begin(), L.end()); 474 } 475 476 struct notassignable { 477 int &x; 478 notassignable(int &x) : x(x) {} 479 }; 480 481 TEST(SmallVectorCustomTest, NoAssignTest) { 482 int x = 0; 483 SmallVector<notassignable, 2> vec; 484 vec.push_back(notassignable(x)); 485 x = 42; 486 EXPECT_EQ(42, vec.pop_back_val().x); 487 } 488 489 } 490