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: 40 Constructable() : constructed(true), value(0) { 41 ++numConstructorCalls; 42 } 43 44 Constructable(int val) : constructed(true), value(val) { 45 ++numConstructorCalls; 46 } 47 48 Constructable(const Constructable & src) : constructed(true) { 49 value = src.value; 50 ++numConstructorCalls; 51 ++numCopyConstructorCalls; 52 } 53 54 Constructable(Constructable && src) : constructed(true) { 55 value = src.value; 56 ++numConstructorCalls; 57 ++numMoveConstructorCalls; 58 } 59 60 ~Constructable() { 61 EXPECT_TRUE(constructed); 62 ++numDestructorCalls; 63 constructed = false; 64 } 65 66 Constructable & operator=(const Constructable & src) { 67 EXPECT_TRUE(constructed); 68 value = src.value; 69 ++numAssignmentCalls; 70 ++numCopyAssignmentCalls; 71 return *this; 72 } 73 74 Constructable & operator=(Constructable && src) { 75 EXPECT_TRUE(constructed); 76 value = src.value; 77 ++numAssignmentCalls; 78 ++numMoveAssignmentCalls; 79 return *this; 80 } 81 82 int getValue() const { 83 return abs(value); 84 } 85 86 static void reset() { 87 numConstructorCalls = 0; 88 numMoveConstructorCalls = 0; 89 numCopyConstructorCalls = 0; 90 numDestructorCalls = 0; 91 numAssignmentCalls = 0; 92 numMoveAssignmentCalls = 0; 93 numCopyAssignmentCalls = 0; 94 } 95 96 static int getNumConstructorCalls() { 97 return numConstructorCalls; 98 } 99 100 static int getNumMoveConstructorCalls() { 101 return numMoveConstructorCalls; 102 } 103 104 static int getNumCopyConstructorCalls() { 105 return numCopyConstructorCalls; 106 } 107 108 static int getNumDestructorCalls() { 109 return numDestructorCalls; 110 } 111 112 static int getNumAssignmentCalls() { 113 return numAssignmentCalls; 114 } 115 116 static int getNumMoveAssignmentCalls() { 117 return numMoveAssignmentCalls; 118 } 119 120 static int getNumCopyAssignmentCalls() { 121 return numCopyAssignmentCalls; 122 } 123 124 friend bool operator==(const Constructable & c0, const Constructable & c1) { 125 return c0.getValue() == c1.getValue(); 126 } 127 128 friend bool LLVM_ATTRIBUTE_UNUSED 129 operator!=(const Constructable & c0, const Constructable & c1) { 130 return c0.getValue() != c1.getValue(); 131 } 132 }; 133 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; 141 142 struct NonCopyable { 143 NonCopyable() {} 144 NonCopyable(NonCopyable &&) {} 145 NonCopyable &operator=(NonCopyable &&) { return *this; } 146 private: 147 NonCopyable(const NonCopyable &) = delete; 148 NonCopyable &operator=(const NonCopyable &) = delete; 149 }; 150 151 LLVM_ATTRIBUTE_USED void CompileTest() { 152 SmallVector<NonCopyable, 0> V; 153 V.resize(42); 154 } 155 156 class SmallVectorTestBase : public testing::Test { 157 protected: 158 void SetUp() override { Constructable::reset(); } 159 160 template <typename VectorT> 161 void assertEmpty(VectorT & v) { 162 // Size tests 163 EXPECT_EQ(0u, v.size()); 164 EXPECT_TRUE(v.empty()); 165 166 // Iterator tests 167 EXPECT_TRUE(v.begin() == v.end()); 168 } 169 170 // Assert that v contains the specified values, in order. 171 template <typename VectorT> 172 void assertValuesInOrder(VectorT & v, size_t size, ...) { 173 EXPECT_EQ(size, v.size()); 174 175 va_list ap; 176 va_start(ap, size); 177 for (size_t i = 0; i < size; ++i) { 178 int value = va_arg(ap, int); 179 EXPECT_EQ(value, v[i].getValue()); 180 } 181 182 va_end(ap); 183 } 184 185 // Generate a sequence of values to initialize the vector. 186 template <typename VectorT> 187 void makeSequence(VectorT & v, int start, int end) { 188 for (int i = start; i <= end; ++i) { 189 v.push_back(Constructable(i)); 190 } 191 } 192 }; 193 194 // Test fixture class 195 template <typename VectorT> 196 class SmallVectorTest : public SmallVectorTestBase { 197 protected: 198 VectorT theVector; 199 VectorT otherVector; 200 }; 201 202 203 typedef ::testing::Types<SmallVector<Constructable, 0>, 204 SmallVector<Constructable, 1>, 205 SmallVector<Constructable, 2>, 206 SmallVector<Constructable, 4>, 207 SmallVector<Constructable, 5> 208 > SmallVectorTestTypes; 209 TYPED_TEST_CASE(SmallVectorTest, SmallVectorTestTypes); 210 211 // Constructor test. 212 TYPED_TEST(SmallVectorTest, ConstructorNonIterTest) { 213 SCOPED_TRACE("ConstructorTest"); 214 this->theVector = SmallVector<Constructable, 2>(2, 2); 215 this->assertValuesInOrder(this->theVector, 2u, 2, 2); 216 } 217 218 // Constructor test. 219 TYPED_TEST(SmallVectorTest, ConstructorIterTest) { 220 SCOPED_TRACE("ConstructorTest"); 221 int arr[] = {1, 2, 3}; 222 this->theVector = 223 SmallVector<Constructable, 4>(std::begin(arr), std::end(arr)); 224 this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3); 225 } 226 227 // New vector test. 228 TYPED_TEST(SmallVectorTest, EmptyVectorTest) { 229 SCOPED_TRACE("EmptyVectorTest"); 230 this->assertEmpty(this->theVector); 231 EXPECT_TRUE(this->theVector.rbegin() == this->theVector.rend()); 232 EXPECT_EQ(0, Constructable::getNumConstructorCalls()); 233 EXPECT_EQ(0, Constructable::getNumDestructorCalls()); 234 } 235 236 // Simple insertions and deletions. 237 TYPED_TEST(SmallVectorTest, PushPopTest) { 238 SCOPED_TRACE("PushPopTest"); 239 240 // Track whether the vector will potentially have to grow. 241 bool RequiresGrowth = this->theVector.capacity() < 3; 242 243 // Push an element 244 this->theVector.push_back(Constructable(1)); 245 246 // Size tests 247 this->assertValuesInOrder(this->theVector, 1u, 1); 248 EXPECT_FALSE(this->theVector.begin() == this->theVector.end()); 249 EXPECT_FALSE(this->theVector.empty()); 250 251 // Push another element 252 this->theVector.push_back(Constructable(2)); 253 this->assertValuesInOrder(this->theVector, 2u, 1, 2); 254 255 // Insert at beginning 256 this->theVector.insert(this->theVector.begin(), this->theVector[1]); 257 this->assertValuesInOrder(this->theVector, 3u, 2, 1, 2); 258 259 // Pop one element 260 this->theVector.pop_back(); 261 this->assertValuesInOrder(this->theVector, 2u, 2, 1); 262 263 // Pop remaining elements 264 this->theVector.pop_back_n(2); 265 this->assertEmpty(this->theVector); 266 267 // Check number of constructor calls. Should be 2 for each list element, 268 // one for the argument to push_back, one for the argument to insert, 269 // and one for the list element itself. 270 if (!RequiresGrowth) { 271 EXPECT_EQ(5, Constructable::getNumConstructorCalls()); 272 EXPECT_EQ(5, Constructable::getNumDestructorCalls()); 273 } else { 274 // If we had to grow the vector, these only have a lower bound, but should 275 // always be equal. 276 EXPECT_LE(5, Constructable::getNumConstructorCalls()); 277 EXPECT_EQ(Constructable::getNumConstructorCalls(), 278 Constructable::getNumDestructorCalls()); 279 } 280 } 281 282 // Clear test. 283 TYPED_TEST(SmallVectorTest, ClearTest) { 284 SCOPED_TRACE("ClearTest"); 285 286 this->theVector.reserve(2); 287 this->makeSequence(this->theVector, 1, 2); 288 this->theVector.clear(); 289 290 this->assertEmpty(this->theVector); 291 EXPECT_EQ(4, Constructable::getNumConstructorCalls()); 292 EXPECT_EQ(4, Constructable::getNumDestructorCalls()); 293 } 294 295 // Resize smaller test. 296 TYPED_TEST(SmallVectorTest, ResizeShrinkTest) { 297 SCOPED_TRACE("ResizeShrinkTest"); 298 299 this->theVector.reserve(3); 300 this->makeSequence(this->theVector, 1, 3); 301 this->theVector.resize(1); 302 303 this->assertValuesInOrder(this->theVector, 1u, 1); 304 EXPECT_EQ(6, Constructable::getNumConstructorCalls()); 305 EXPECT_EQ(5, Constructable::getNumDestructorCalls()); 306 } 307 308 // Resize bigger test. 309 TYPED_TEST(SmallVectorTest, ResizeGrowTest) { 310 SCOPED_TRACE("ResizeGrowTest"); 311 312 this->theVector.resize(2); 313 314 EXPECT_EQ(2, Constructable::getNumConstructorCalls()); 315 EXPECT_EQ(0, Constructable::getNumDestructorCalls()); 316 EXPECT_EQ(2u, this->theVector.size()); 317 } 318 319 TYPED_TEST(SmallVectorTest, ResizeWithElementsTest) { 320 this->theVector.resize(2); 321 322 Constructable::reset(); 323 324 this->theVector.resize(4); 325 326 size_t Ctors = Constructable::getNumConstructorCalls(); 327 EXPECT_TRUE(Ctors == 2 || Ctors == 4); 328 size_t MoveCtors = Constructable::getNumMoveConstructorCalls(); 329 EXPECT_TRUE(MoveCtors == 0 || MoveCtors == 2); 330 size_t Dtors = Constructable::getNumDestructorCalls(); 331 EXPECT_TRUE(Dtors == 0 || Dtors == 2); 332 } 333 334 // Resize with fill value. 335 TYPED_TEST(SmallVectorTest, ResizeFillTest) { 336 SCOPED_TRACE("ResizeFillTest"); 337 338 this->theVector.resize(3, Constructable(77)); 339 this->assertValuesInOrder(this->theVector, 3u, 77, 77, 77); 340 } 341 342 // Overflow past fixed size. 343 TYPED_TEST(SmallVectorTest, OverflowTest) { 344 SCOPED_TRACE("OverflowTest"); 345 346 // Push more elements than the fixed size. 347 this->makeSequence(this->theVector, 1, 10); 348 349 // Test size and values. 350 EXPECT_EQ(10u, this->theVector.size()); 351 for (int i = 0; i < 10; ++i) { 352 EXPECT_EQ(i+1, this->theVector[i].getValue()); 353 } 354 355 // Now resize back to fixed size. 356 this->theVector.resize(1); 357 358 this->assertValuesInOrder(this->theVector, 1u, 1); 359 } 360 361 // Iteration tests. 362 TYPED_TEST(SmallVectorTest, IterationTest) { 363 this->makeSequence(this->theVector, 1, 2); 364 365 // Forward Iteration 366 typename TypeParam::iterator it = this->theVector.begin(); 367 EXPECT_TRUE(*it == this->theVector.front()); 368 EXPECT_TRUE(*it == this->theVector[0]); 369 EXPECT_EQ(1, it->getValue()); 370 ++it; 371 EXPECT_TRUE(*it == this->theVector[1]); 372 EXPECT_TRUE(*it == this->theVector.back()); 373 EXPECT_EQ(2, it->getValue()); 374 ++it; 375 EXPECT_TRUE(it == this->theVector.end()); 376 --it; 377 EXPECT_TRUE(*it == this->theVector[1]); 378 EXPECT_EQ(2, it->getValue()); 379 --it; 380 EXPECT_TRUE(*it == this->theVector[0]); 381 EXPECT_EQ(1, it->getValue()); 382 383 // Reverse Iteration 384 typename TypeParam::reverse_iterator rit = this->theVector.rbegin(); 385 EXPECT_TRUE(*rit == this->theVector[1]); 386 EXPECT_EQ(2, rit->getValue()); 387 ++rit; 388 EXPECT_TRUE(*rit == this->theVector[0]); 389 EXPECT_EQ(1, rit->getValue()); 390 ++rit; 391 EXPECT_TRUE(rit == this->theVector.rend()); 392 --rit; 393 EXPECT_TRUE(*rit == this->theVector[0]); 394 EXPECT_EQ(1, rit->getValue()); 395 --rit; 396 EXPECT_TRUE(*rit == this->theVector[1]); 397 EXPECT_EQ(2, rit->getValue()); 398 } 399 400 // Swap test. 401 TYPED_TEST(SmallVectorTest, SwapTest) { 402 SCOPED_TRACE("SwapTest"); 403 404 this->makeSequence(this->theVector, 1, 2); 405 std::swap(this->theVector, this->otherVector); 406 407 this->assertEmpty(this->theVector); 408 this->assertValuesInOrder(this->otherVector, 2u, 1, 2); 409 } 410 411 // Append test 412 TYPED_TEST(SmallVectorTest, AppendTest) { 413 SCOPED_TRACE("AppendTest"); 414 415 this->makeSequence(this->otherVector, 2, 3); 416 417 this->theVector.push_back(Constructable(1)); 418 this->theVector.append(this->otherVector.begin(), this->otherVector.end()); 419 420 this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3); 421 } 422 423 // Append repeated test 424 TYPED_TEST(SmallVectorTest, AppendRepeatedTest) { 425 SCOPED_TRACE("AppendRepeatedTest"); 426 427 this->theVector.push_back(Constructable(1)); 428 this->theVector.append(2, Constructable(77)); 429 this->assertValuesInOrder(this->theVector, 3u, 1, 77, 77); 430 } 431 432 // Append test 433 TYPED_TEST(SmallVectorTest, AppendNonIterTest) { 434 SCOPED_TRACE("AppendRepeatedTest"); 435 436 this->theVector.push_back(Constructable(1)); 437 this->theVector.append(2, 7); 438 this->assertValuesInOrder(this->theVector, 3u, 1, 7, 7); 439 } 440 441 struct output_iterator { 442 typedef std::output_iterator_tag iterator_category; 443 typedef int value_type; 444 typedef int difference_type; 445 typedef value_type *pointer; 446 typedef value_type &reference; 447 operator int() { return 2; } 448 operator Constructable() { return 7; } 449 }; 450 451 TYPED_TEST(SmallVectorTest, AppendRepeatedNonForwardIterator) { 452 SCOPED_TRACE("AppendRepeatedTest"); 453 454 this->theVector.push_back(Constructable(1)); 455 this->theVector.append(output_iterator(), output_iterator()); 456 this->assertValuesInOrder(this->theVector, 3u, 1, 7, 7); 457 } 458 459 // Assign test 460 TYPED_TEST(SmallVectorTest, AssignTest) { 461 SCOPED_TRACE("AssignTest"); 462 463 this->theVector.push_back(Constructable(1)); 464 this->theVector.assign(2, Constructable(77)); 465 this->assertValuesInOrder(this->theVector, 2u, 77, 77); 466 } 467 468 // Assign test 469 TYPED_TEST(SmallVectorTest, AssignRangeTest) { 470 SCOPED_TRACE("AssignTest"); 471 472 this->theVector.push_back(Constructable(1)); 473 int arr[] = {1, 2, 3}; 474 this->theVector.assign(std::begin(arr), std::end(arr)); 475 this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3); 476 } 477 478 // Assign test 479 TYPED_TEST(SmallVectorTest, AssignNonIterTest) { 480 SCOPED_TRACE("AssignTest"); 481 482 this->theVector.push_back(Constructable(1)); 483 this->theVector.assign(2, 7); 484 this->assertValuesInOrder(this->theVector, 2u, 7, 7); 485 } 486 487 // Move-assign test 488 TYPED_TEST(SmallVectorTest, MoveAssignTest) { 489 SCOPED_TRACE("MoveAssignTest"); 490 491 // Set up our vector with a single element, but enough capacity for 4. 492 this->theVector.reserve(4); 493 this->theVector.push_back(Constructable(1)); 494 495 // Set up the other vector with 2 elements. 496 this->otherVector.push_back(Constructable(2)); 497 this->otherVector.push_back(Constructable(3)); 498 499 // Move-assign from the other vector. 500 this->theVector = std::move(this->otherVector); 501 502 // Make sure we have the right result. 503 this->assertValuesInOrder(this->theVector, 2u, 2, 3); 504 505 // Make sure the # of constructor/destructor calls line up. There 506 // are two live objects after clearing the other vector. 507 this->otherVector.clear(); 508 EXPECT_EQ(Constructable::getNumConstructorCalls()-2, 509 Constructable::getNumDestructorCalls()); 510 511 // There shouldn't be any live objects any more. 512 this->theVector.clear(); 513 EXPECT_EQ(Constructable::getNumConstructorCalls(), 514 Constructable::getNumDestructorCalls()); 515 } 516 517 // Erase a single element 518 TYPED_TEST(SmallVectorTest, EraseTest) { 519 SCOPED_TRACE("EraseTest"); 520 521 this->makeSequence(this->theVector, 1, 3); 522 const auto &theConstVector = this->theVector; 523 this->theVector.erase(theConstVector.begin()); 524 this->assertValuesInOrder(this->theVector, 2u, 2, 3); 525 } 526 527 // Erase a range of elements 528 TYPED_TEST(SmallVectorTest, EraseRangeTest) { 529 SCOPED_TRACE("EraseRangeTest"); 530 531 this->makeSequence(this->theVector, 1, 3); 532 const auto &theConstVector = this->theVector; 533 this->theVector.erase(theConstVector.begin(), theConstVector.begin() + 2); 534 this->assertValuesInOrder(this->theVector, 1u, 3); 535 } 536 537 // Insert a single element. 538 TYPED_TEST(SmallVectorTest, InsertTest) { 539 SCOPED_TRACE("InsertTest"); 540 541 this->makeSequence(this->theVector, 1, 3); 542 typename TypeParam::iterator I = 543 this->theVector.insert(this->theVector.begin() + 1, Constructable(77)); 544 EXPECT_EQ(this->theVector.begin() + 1, I); 545 this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3); 546 } 547 548 // Insert a copy of a single element. 549 TYPED_TEST(SmallVectorTest, InsertCopy) { 550 SCOPED_TRACE("InsertTest"); 551 552 this->makeSequence(this->theVector, 1, 3); 553 Constructable C(77); 554 typename TypeParam::iterator I = 555 this->theVector.insert(this->theVector.begin() + 1, C); 556 EXPECT_EQ(this->theVector.begin() + 1, I); 557 this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3); 558 } 559 560 // Insert repeated elements. 561 TYPED_TEST(SmallVectorTest, InsertRepeatedTest) { 562 SCOPED_TRACE("InsertRepeatedTest"); 563 564 this->makeSequence(this->theVector, 1, 4); 565 Constructable::reset(); 566 auto I = 567 this->theVector.insert(this->theVector.begin() + 1, 2, Constructable(16)); 568 // Move construct the top element into newly allocated space, and optionally 569 // reallocate the whole buffer, move constructing into it. 570 // FIXME: This is inefficient, we shouldn't move things into newly allocated 571 // space, then move them up/around, there should only be 2 or 4 move 572 // constructions here. 573 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 || 574 Constructable::getNumMoveConstructorCalls() == 6); 575 // Move assign the next two to shift them up and make a gap. 576 EXPECT_EQ(1, Constructable::getNumMoveAssignmentCalls()); 577 // Copy construct the two new elements from the parameter. 578 EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls()); 579 // All without any copy construction. 580 EXPECT_EQ(0, Constructable::getNumCopyConstructorCalls()); 581 EXPECT_EQ(this->theVector.begin() + 1, I); 582 this->assertValuesInOrder(this->theVector, 6u, 1, 16, 16, 2, 3, 4); 583 } 584 585 TYPED_TEST(SmallVectorTest, InsertRepeatedNonIterTest) { 586 SCOPED_TRACE("InsertRepeatedTest"); 587 588 this->makeSequence(this->theVector, 1, 4); 589 Constructable::reset(); 590 auto I = this->theVector.insert(this->theVector.begin() + 1, 2, 7); 591 EXPECT_EQ(this->theVector.begin() + 1, I); 592 this->assertValuesInOrder(this->theVector, 6u, 1, 7, 7, 2, 3, 4); 593 } 594 595 TYPED_TEST(SmallVectorTest, InsertRepeatedAtEndTest) { 596 SCOPED_TRACE("InsertRepeatedTest"); 597 598 this->makeSequence(this->theVector, 1, 4); 599 Constructable::reset(); 600 auto I = this->theVector.insert(this->theVector.end(), 2, Constructable(16)); 601 // Just copy construct them into newly allocated space 602 EXPECT_EQ(2, Constructable::getNumCopyConstructorCalls()); 603 // Move everything across if reallocation is needed. 604 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 || 605 Constructable::getNumMoveConstructorCalls() == 4); 606 // Without ever moving or copying anything else. 607 EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls()); 608 EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls()); 609 610 EXPECT_EQ(this->theVector.begin() + 4, I); 611 this->assertValuesInOrder(this->theVector, 6u, 1, 2, 3, 4, 16, 16); 612 } 613 614 TYPED_TEST(SmallVectorTest, InsertRepeatedEmptyTest) { 615 SCOPED_TRACE("InsertRepeatedTest"); 616 617 this->makeSequence(this->theVector, 10, 15); 618 619 // Empty insert. 620 EXPECT_EQ(this->theVector.end(), 621 this->theVector.insert(this->theVector.end(), 622 0, Constructable(42))); 623 EXPECT_EQ(this->theVector.begin() + 1, 624 this->theVector.insert(this->theVector.begin() + 1, 625 0, Constructable(42))); 626 } 627 628 // Insert range. 629 TYPED_TEST(SmallVectorTest, InsertRangeTest) { 630 SCOPED_TRACE("InsertRangeTest"); 631 632 Constructable Arr[3] = 633 { Constructable(77), Constructable(77), Constructable(77) }; 634 635 this->makeSequence(this->theVector, 1, 3); 636 Constructable::reset(); 637 auto I = this->theVector.insert(this->theVector.begin() + 1, Arr, Arr + 3); 638 // Move construct the top 3 elements into newly allocated space. 639 // Possibly move the whole sequence into new space first. 640 // FIXME: This is inefficient, we shouldn't move things into newly allocated 641 // space, then move them up/around, there should only be 2 or 3 move 642 // constructions here. 643 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 || 644 Constructable::getNumMoveConstructorCalls() == 5); 645 // Copy assign the lower 2 new elements into existing space. 646 EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls()); 647 // Copy construct the third element into newly allocated space. 648 EXPECT_EQ(1, Constructable::getNumCopyConstructorCalls()); 649 EXPECT_EQ(this->theVector.begin() + 1, I); 650 this->assertValuesInOrder(this->theVector, 6u, 1, 77, 77, 77, 2, 3); 651 } 652 653 654 TYPED_TEST(SmallVectorTest, InsertRangeAtEndTest) { 655 SCOPED_TRACE("InsertRangeTest"); 656 657 Constructable Arr[3] = 658 { Constructable(77), Constructable(77), Constructable(77) }; 659 660 this->makeSequence(this->theVector, 1, 3); 661 662 // Insert at end. 663 Constructable::reset(); 664 auto I = this->theVector.insert(this->theVector.end(), Arr, Arr+3); 665 // Copy construct the 3 elements into new space at the top. 666 EXPECT_EQ(3, Constructable::getNumCopyConstructorCalls()); 667 // Don't copy/move anything else. 668 EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls()); 669 // Reallocation might occur, causing all elements to be moved into the new 670 // buffer. 671 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 || 672 Constructable::getNumMoveConstructorCalls() == 3); 673 EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls()); 674 EXPECT_EQ(this->theVector.begin() + 3, I); 675 this->assertValuesInOrder(this->theVector, 6u, 676 1, 2, 3, 77, 77, 77); 677 } 678 679 TYPED_TEST(SmallVectorTest, InsertEmptyRangeTest) { 680 SCOPED_TRACE("InsertRangeTest"); 681 682 this->makeSequence(this->theVector, 1, 3); 683 684 // Empty insert. 685 EXPECT_EQ(this->theVector.end(), 686 this->theVector.insert(this->theVector.end(), 687 this->theVector.begin(), 688 this->theVector.begin())); 689 EXPECT_EQ(this->theVector.begin() + 1, 690 this->theVector.insert(this->theVector.begin() + 1, 691 this->theVector.begin(), 692 this->theVector.begin())); 693 } 694 695 // Comparison tests. 696 TYPED_TEST(SmallVectorTest, ComparisonTest) { 697 SCOPED_TRACE("ComparisonTest"); 698 699 this->makeSequence(this->theVector, 1, 3); 700 this->makeSequence(this->otherVector, 1, 3); 701 702 EXPECT_TRUE(this->theVector == this->otherVector); 703 EXPECT_FALSE(this->theVector != this->otherVector); 704 705 this->otherVector.clear(); 706 this->makeSequence(this->otherVector, 2, 4); 707 708 EXPECT_FALSE(this->theVector == this->otherVector); 709 EXPECT_TRUE(this->theVector != this->otherVector); 710 } 711 712 // Constant vector tests. 713 TYPED_TEST(SmallVectorTest, ConstVectorTest) { 714 const TypeParam constVector; 715 716 EXPECT_EQ(0u, constVector.size()); 717 EXPECT_TRUE(constVector.empty()); 718 EXPECT_TRUE(constVector.begin() == constVector.end()); 719 } 720 721 // Direct array access. 722 TYPED_TEST(SmallVectorTest, DirectVectorTest) { 723 EXPECT_EQ(0u, this->theVector.size()); 724 this->theVector.reserve(4); 725 EXPECT_LE(4u, this->theVector.capacity()); 726 EXPECT_EQ(0, Constructable::getNumConstructorCalls()); 727 this->theVector.push_back(1); 728 this->theVector.push_back(2); 729 this->theVector.push_back(3); 730 this->theVector.push_back(4); 731 EXPECT_EQ(4u, this->theVector.size()); 732 EXPECT_EQ(8, Constructable::getNumConstructorCalls()); 733 EXPECT_EQ(1, this->theVector[0].getValue()); 734 EXPECT_EQ(2, this->theVector[1].getValue()); 735 EXPECT_EQ(3, this->theVector[2].getValue()); 736 EXPECT_EQ(4, this->theVector[3].getValue()); 737 } 738 739 TYPED_TEST(SmallVectorTest, IteratorTest) { 740 std::list<int> L; 741 this->theVector.insert(this->theVector.end(), L.begin(), L.end()); 742 } 743 744 template <typename InvalidType> class DualSmallVectorsTest; 745 746 template <typename VectorT1, typename VectorT2> 747 class DualSmallVectorsTest<std::pair<VectorT1, VectorT2>> : public SmallVectorTestBase { 748 protected: 749 VectorT1 theVector; 750 VectorT2 otherVector; 751 752 template <typename T, unsigned N> 753 static unsigned NumBuiltinElts(const SmallVector<T, N>&) { return N; } 754 }; 755 756 typedef ::testing::Types< 757 // Small mode -> Small mode. 758 std::pair<SmallVector<Constructable, 4>, SmallVector<Constructable, 4>>, 759 // Small mode -> Big mode. 760 std::pair<SmallVector<Constructable, 4>, SmallVector<Constructable, 2>>, 761 // Big mode -> Small mode. 762 std::pair<SmallVector<Constructable, 2>, SmallVector<Constructable, 4>>, 763 // Big mode -> Big mode. 764 std::pair<SmallVector<Constructable, 2>, SmallVector<Constructable, 2>> 765 > DualSmallVectorTestTypes; 766 767 TYPED_TEST_CASE(DualSmallVectorsTest, DualSmallVectorTestTypes); 768 769 TYPED_TEST(DualSmallVectorsTest, MoveAssignment) { 770 SCOPED_TRACE("MoveAssignTest-DualVectorTypes"); 771 772 // Set up our vector with four elements. 773 for (unsigned I = 0; I < 4; ++I) 774 this->otherVector.push_back(Constructable(I)); 775 776 const Constructable *OrigDataPtr = this->otherVector.data(); 777 778 // Move-assign from the other vector. 779 this->theVector = 780 std::move(static_cast<SmallVectorImpl<Constructable>&>(this->otherVector)); 781 782 // Make sure we have the right result. 783 this->assertValuesInOrder(this->theVector, 4u, 0, 1, 2, 3); 784 785 // Make sure the # of constructor/destructor calls line up. There 786 // are two live objects after clearing the other vector. 787 this->otherVector.clear(); 788 EXPECT_EQ(Constructable::getNumConstructorCalls()-4, 789 Constructable::getNumDestructorCalls()); 790 791 // If the source vector (otherVector) was in small-mode, assert that we just 792 // moved the data pointer over. 793 EXPECT_TRUE(this->NumBuiltinElts(this->otherVector) == 4 || 794 this->theVector.data() == OrigDataPtr); 795 796 // There shouldn't be any live objects any more. 797 this->theVector.clear(); 798 EXPECT_EQ(Constructable::getNumConstructorCalls(), 799 Constructable::getNumDestructorCalls()); 800 801 // We shouldn't have copied anything in this whole process. 802 EXPECT_EQ(Constructable::getNumCopyConstructorCalls(), 0); 803 } 804 805 struct notassignable { 806 int &x; 807 notassignable(int &x) : x(x) {} 808 }; 809 810 TEST(SmallVectorCustomTest, NoAssignTest) { 811 int x = 0; 812 SmallVector<notassignable, 2> vec; 813 vec.push_back(notassignable(x)); 814 x = 42; 815 EXPECT_EQ(42, vec.pop_back_val().x); 816 } 817 818 struct MovedFrom { 819 bool hasValue; 820 MovedFrom() : hasValue(true) { 821 } 822 MovedFrom(MovedFrom&& m) : hasValue(m.hasValue) { 823 m.hasValue = false; 824 } 825 MovedFrom &operator=(MovedFrom&& m) { 826 hasValue = m.hasValue; 827 m.hasValue = false; 828 return *this; 829 } 830 }; 831 832 TEST(SmallVectorTest, MidInsert) { 833 SmallVector<MovedFrom, 3> v; 834 v.push_back(MovedFrom()); 835 v.insert(v.begin(), MovedFrom()); 836 for (MovedFrom &m : v) 837 EXPECT_TRUE(m.hasValue); 838 } 839 840 enum EmplaceableArgState { 841 EAS_Defaulted, 842 EAS_Arg, 843 EAS_LValue, 844 EAS_RValue, 845 EAS_Failure 846 }; 847 template <int I> struct EmplaceableArg { 848 EmplaceableArgState State; 849 EmplaceableArg() : State(EAS_Defaulted) {} 850 EmplaceableArg(EmplaceableArg &&X) 851 : State(X.State == EAS_Arg ? EAS_RValue : EAS_Failure) {} 852 EmplaceableArg(EmplaceableArg &X) 853 : State(X.State == EAS_Arg ? EAS_LValue : EAS_Failure) {} 854 855 explicit EmplaceableArg(bool) : State(EAS_Arg) {} 856 857 private: 858 EmplaceableArg &operator=(EmplaceableArg &&) = delete; 859 EmplaceableArg &operator=(const EmplaceableArg &) = delete; 860 }; 861 862 enum EmplaceableState { ES_Emplaced, ES_Moved }; 863 struct Emplaceable { 864 EmplaceableArg<0> A0; 865 EmplaceableArg<1> A1; 866 EmplaceableArg<2> A2; 867 EmplaceableArg<3> A3; 868 EmplaceableState State; 869 870 Emplaceable() : State(ES_Emplaced) {} 871 872 template <class A0Ty> 873 explicit Emplaceable(A0Ty &&A0) 874 : A0(std::forward<A0Ty>(A0)), State(ES_Emplaced) {} 875 876 template <class A0Ty, class A1Ty> 877 Emplaceable(A0Ty &&A0, A1Ty &&A1) 878 : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)), 879 State(ES_Emplaced) {} 880 881 template <class A0Ty, class A1Ty, class A2Ty> 882 Emplaceable(A0Ty &&A0, A1Ty &&A1, A2Ty &&A2) 883 : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)), 884 A2(std::forward<A2Ty>(A2)), State(ES_Emplaced) {} 885 886 template <class A0Ty, class A1Ty, class A2Ty, class A3Ty> 887 Emplaceable(A0Ty &&A0, A1Ty &&A1, A2Ty &&A2, A3Ty &&A3) 888 : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)), 889 A2(std::forward<A2Ty>(A2)), A3(std::forward<A3Ty>(A3)), 890 State(ES_Emplaced) {} 891 892 Emplaceable(Emplaceable &&) : State(ES_Moved) {} 893 Emplaceable &operator=(Emplaceable &&) { 894 State = ES_Moved; 895 return *this; 896 } 897 898 private: 899 Emplaceable(const Emplaceable &) = delete; 900 Emplaceable &operator=(const Emplaceable &) = delete; 901 }; 902 903 TEST(SmallVectorTest, EmplaceBack) { 904 EmplaceableArg<0> A0(true); 905 EmplaceableArg<1> A1(true); 906 EmplaceableArg<2> A2(true); 907 EmplaceableArg<3> A3(true); 908 { 909 SmallVector<Emplaceable, 3> V; 910 Emplaceable &back = V.emplace_back(); 911 EXPECT_TRUE(&back == &V.back()); 912 EXPECT_TRUE(V.size() == 1); 913 EXPECT_TRUE(back.State == ES_Emplaced); 914 EXPECT_TRUE(back.A0.State == EAS_Defaulted); 915 EXPECT_TRUE(back.A1.State == EAS_Defaulted); 916 EXPECT_TRUE(back.A2.State == EAS_Defaulted); 917 EXPECT_TRUE(back.A3.State == EAS_Defaulted); 918 } 919 { 920 SmallVector<Emplaceable, 3> V; 921 Emplaceable &back = V.emplace_back(std::move(A0)); 922 EXPECT_TRUE(&back == &V.back()); 923 EXPECT_TRUE(V.size() == 1); 924 EXPECT_TRUE(back.State == ES_Emplaced); 925 EXPECT_TRUE(back.A0.State == EAS_RValue); 926 EXPECT_TRUE(back.A1.State == EAS_Defaulted); 927 EXPECT_TRUE(back.A2.State == EAS_Defaulted); 928 EXPECT_TRUE(back.A3.State == EAS_Defaulted); 929 } 930 { 931 SmallVector<Emplaceable, 3> V; 932 Emplaceable &back = V.emplace_back(A0); 933 EXPECT_TRUE(&back == &V.back()); 934 EXPECT_TRUE(V.size() == 1); 935 EXPECT_TRUE(back.State == ES_Emplaced); 936 EXPECT_TRUE(back.A0.State == EAS_LValue); 937 EXPECT_TRUE(back.A1.State == EAS_Defaulted); 938 EXPECT_TRUE(back.A2.State == EAS_Defaulted); 939 EXPECT_TRUE(back.A3.State == EAS_Defaulted); 940 } 941 { 942 SmallVector<Emplaceable, 3> V; 943 Emplaceable &back = V.emplace_back(A0, A1); 944 EXPECT_TRUE(&back == &V.back()); 945 EXPECT_TRUE(V.size() == 1); 946 EXPECT_TRUE(back.State == ES_Emplaced); 947 EXPECT_TRUE(back.A0.State == EAS_LValue); 948 EXPECT_TRUE(back.A1.State == EAS_LValue); 949 EXPECT_TRUE(back.A2.State == EAS_Defaulted); 950 EXPECT_TRUE(back.A3.State == EAS_Defaulted); 951 } 952 { 953 SmallVector<Emplaceable, 3> V; 954 Emplaceable &back = V.emplace_back(std::move(A0), std::move(A1)); 955 EXPECT_TRUE(&back == &V.back()); 956 EXPECT_TRUE(V.size() == 1); 957 EXPECT_TRUE(back.State == ES_Emplaced); 958 EXPECT_TRUE(back.A0.State == EAS_RValue); 959 EXPECT_TRUE(back.A1.State == EAS_RValue); 960 EXPECT_TRUE(back.A2.State == EAS_Defaulted); 961 EXPECT_TRUE(back.A3.State == EAS_Defaulted); 962 } 963 { 964 SmallVector<Emplaceable, 3> V; 965 Emplaceable &back = V.emplace_back(std::move(A0), A1, std::move(A2), A3); 966 EXPECT_TRUE(&back == &V.back()); 967 EXPECT_TRUE(V.size() == 1); 968 EXPECT_TRUE(back.State == ES_Emplaced); 969 EXPECT_TRUE(back.A0.State == EAS_RValue); 970 EXPECT_TRUE(back.A1.State == EAS_LValue); 971 EXPECT_TRUE(back.A2.State == EAS_RValue); 972 EXPECT_TRUE(back.A3.State == EAS_LValue); 973 } 974 { 975 SmallVector<int, 1> V; 976 V.emplace_back(); 977 V.emplace_back(42); 978 EXPECT_EQ(2U, V.size()); 979 EXPECT_EQ(0, V[0]); 980 EXPECT_EQ(42, V[1]); 981 } 982 } 983 984 TEST(SmallVectorTest, InitializerList) { 985 SmallVector<int, 2> V1 = {}; 986 EXPECT_TRUE(V1.empty()); 987 V1 = {0, 0}; 988 EXPECT_TRUE(makeArrayRef(V1).equals({0, 0})); 989 V1 = {-1, -1}; 990 EXPECT_TRUE(makeArrayRef(V1).equals({-1, -1})); 991 992 SmallVector<int, 2> V2 = {1, 2, 3, 4}; 993 EXPECT_TRUE(makeArrayRef(V2).equals({1, 2, 3, 4})); 994 V2.assign({4}); 995 EXPECT_TRUE(makeArrayRef(V2).equals({4})); 996 V2.append({3, 2}); 997 EXPECT_TRUE(makeArrayRef(V2).equals({4, 3, 2})); 998 V2.insert(V2.begin() + 1, 5); 999 EXPECT_TRUE(makeArrayRef(V2).equals({4, 5, 3, 2})); 1000 } 1001 1002 } // end namespace 1003