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 src.value = 0; 57 ++numConstructorCalls; 58 ++numMoveConstructorCalls; 59 } 60 61 ~Constructable() { 62 EXPECT_TRUE(constructed); 63 ++numDestructorCalls; 64 constructed = false; 65 } 66 67 Constructable & operator=(const Constructable & src) { 68 EXPECT_TRUE(constructed); 69 value = src.value; 70 ++numAssignmentCalls; 71 ++numCopyAssignmentCalls; 72 return *this; 73 } 74 75 Constructable & operator=(Constructable && src) { 76 EXPECT_TRUE(constructed); 77 value = src.value; 78 src.value = 0; 79 ++numAssignmentCalls; 80 ++numMoveAssignmentCalls; 81 return *this; 82 } 83 84 int getValue() const { 85 return abs(value); 86 } 87 88 static void reset() { 89 numConstructorCalls = 0; 90 numMoveConstructorCalls = 0; 91 numCopyConstructorCalls = 0; 92 numDestructorCalls = 0; 93 numAssignmentCalls = 0; 94 numMoveAssignmentCalls = 0; 95 numCopyAssignmentCalls = 0; 96 } 97 98 static int getNumConstructorCalls() { 99 return numConstructorCalls; 100 } 101 102 static int getNumMoveConstructorCalls() { 103 return numMoveConstructorCalls; 104 } 105 106 static int getNumCopyConstructorCalls() { 107 return numCopyConstructorCalls; 108 } 109 110 static int getNumDestructorCalls() { 111 return numDestructorCalls; 112 } 113 114 static int getNumAssignmentCalls() { 115 return numAssignmentCalls; 116 } 117 118 static int getNumMoveAssignmentCalls() { 119 return numMoveAssignmentCalls; 120 } 121 122 static int getNumCopyAssignmentCalls() { 123 return numCopyAssignmentCalls; 124 } 125 126 friend bool operator==(const Constructable &c0, const Constructable &c1) { 127 return c0.getValue() == c1.getValue(); 128 } 129 130 friend bool LLVM_ATTRIBUTE_UNUSED operator!=(const Constructable &c0, 131 const Constructable &c1) { 132 return c0.getValue() != c1.getValue(); 133 } 134 135 friend bool operator<(const Constructable &c0, const Constructable &c1) { 136 return c0.getValue() < c1.getValue(); 137 } 138 friend bool LLVM_ATTRIBUTE_UNUSED operator<=(const Constructable &c0, 139 const Constructable &c1) { 140 return c0.getValue() <= c1.getValue(); 141 } 142 friend bool LLVM_ATTRIBUTE_UNUSED operator>(const Constructable &c0, 143 const Constructable &c1) { 144 return c0.getValue() > c1.getValue(); 145 } 146 friend bool LLVM_ATTRIBUTE_UNUSED operator>=(const Constructable &c0, 147 const Constructable &c1) { 148 return c0.getValue() >= c1.getValue(); 149 } 150 }; 151 152 int Constructable::numConstructorCalls; 153 int Constructable::numCopyConstructorCalls; 154 int Constructable::numMoveConstructorCalls; 155 int Constructable::numDestructorCalls; 156 int Constructable::numAssignmentCalls; 157 int Constructable::numCopyAssignmentCalls; 158 int Constructable::numMoveAssignmentCalls; 159 160 struct NonCopyable { 161 NonCopyable() {} 162 NonCopyable(NonCopyable &&) {} 163 NonCopyable &operator=(NonCopyable &&) { return *this; } 164 private: 165 NonCopyable(const NonCopyable &) = delete; 166 NonCopyable &operator=(const NonCopyable &) = delete; 167 }; 168 169 LLVM_ATTRIBUTE_USED void CompileTest() { 170 SmallVector<NonCopyable, 0> V; 171 V.resize(42); 172 } 173 174 class SmallVectorTestBase : public testing::Test { 175 protected: 176 void SetUp() override { Constructable::reset(); } 177 178 template <typename VectorT> 179 void assertEmpty(VectorT & v) { 180 // Size tests 181 EXPECT_EQ(0u, v.size()); 182 EXPECT_TRUE(v.empty()); 183 184 // Iterator tests 185 EXPECT_TRUE(v.begin() == v.end()); 186 } 187 188 // Assert that v contains the specified values, in order. 189 template <typename VectorT> 190 void assertValuesInOrder(VectorT & v, size_t size, ...) { 191 EXPECT_EQ(size, v.size()); 192 193 va_list ap; 194 va_start(ap, size); 195 for (size_t i = 0; i < size; ++i) { 196 int value = va_arg(ap, int); 197 EXPECT_EQ(value, v[i].getValue()); 198 } 199 200 va_end(ap); 201 } 202 203 // Generate a sequence of values to initialize the vector. 204 template <typename VectorT> 205 void makeSequence(VectorT & v, int start, int end) { 206 for (int i = start; i <= end; ++i) { 207 v.push_back(Constructable(i)); 208 } 209 } 210 }; 211 212 // Test fixture class 213 template <typename VectorT> 214 class SmallVectorTest : public SmallVectorTestBase { 215 protected: 216 VectorT theVector; 217 VectorT otherVector; 218 }; 219 220 221 typedef ::testing::Types<SmallVector<Constructable, 0>, 222 SmallVector<Constructable, 1>, 223 SmallVector<Constructable, 2>, 224 SmallVector<Constructable, 4>, 225 SmallVector<Constructable, 5> 226 > SmallVectorTestTypes; 227 TYPED_TEST_SUITE(SmallVectorTest, SmallVectorTestTypes, ); 228 229 // Constructor test. 230 TYPED_TEST(SmallVectorTest, ConstructorNonIterTest) { 231 SCOPED_TRACE("ConstructorTest"); 232 this->theVector = SmallVector<Constructable, 2>(2, 2); 233 this->assertValuesInOrder(this->theVector, 2u, 2, 2); 234 } 235 236 // Constructor test. 237 TYPED_TEST(SmallVectorTest, ConstructorIterTest) { 238 SCOPED_TRACE("ConstructorTest"); 239 int arr[] = {1, 2, 3}; 240 this->theVector = 241 SmallVector<Constructable, 4>(std::begin(arr), std::end(arr)); 242 this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3); 243 } 244 245 // New vector test. 246 TYPED_TEST(SmallVectorTest, EmptyVectorTest) { 247 SCOPED_TRACE("EmptyVectorTest"); 248 this->assertEmpty(this->theVector); 249 EXPECT_TRUE(this->theVector.rbegin() == this->theVector.rend()); 250 EXPECT_EQ(0, Constructable::getNumConstructorCalls()); 251 EXPECT_EQ(0, Constructable::getNumDestructorCalls()); 252 } 253 254 // Simple insertions and deletions. 255 TYPED_TEST(SmallVectorTest, PushPopTest) { 256 SCOPED_TRACE("PushPopTest"); 257 258 // Track whether the vector will potentially have to grow. 259 bool RequiresGrowth = this->theVector.capacity() < 3; 260 261 // Push an element 262 this->theVector.push_back(Constructable(1)); 263 264 // Size tests 265 this->assertValuesInOrder(this->theVector, 1u, 1); 266 EXPECT_FALSE(this->theVector.begin() == this->theVector.end()); 267 EXPECT_FALSE(this->theVector.empty()); 268 269 // Push another element 270 this->theVector.push_back(Constructable(2)); 271 this->assertValuesInOrder(this->theVector, 2u, 1, 2); 272 273 // Insert at beginning. Reserve space to avoid reference invalidation from 274 // this->theVector[1]. 275 this->theVector.reserve(this->theVector.size() + 1); 276 this->theVector.insert(this->theVector.begin(), this->theVector[1]); 277 this->assertValuesInOrder(this->theVector, 3u, 2, 1, 2); 278 279 // Pop one element 280 this->theVector.pop_back(); 281 this->assertValuesInOrder(this->theVector, 2u, 2, 1); 282 283 // Pop remaining elements 284 this->theVector.pop_back_n(2); 285 this->assertEmpty(this->theVector); 286 287 // Check number of constructor calls. Should be 2 for each list element, 288 // one for the argument to push_back, one for the argument to insert, 289 // and one for the list element itself. 290 if (!RequiresGrowth) { 291 EXPECT_EQ(5, Constructable::getNumConstructorCalls()); 292 EXPECT_EQ(5, Constructable::getNumDestructorCalls()); 293 } else { 294 // If we had to grow the vector, these only have a lower bound, but should 295 // always be equal. 296 EXPECT_LE(5, Constructable::getNumConstructorCalls()); 297 EXPECT_EQ(Constructable::getNumConstructorCalls(), 298 Constructable::getNumDestructorCalls()); 299 } 300 } 301 302 // Clear test. 303 TYPED_TEST(SmallVectorTest, ClearTest) { 304 SCOPED_TRACE("ClearTest"); 305 306 this->theVector.reserve(2); 307 this->makeSequence(this->theVector, 1, 2); 308 this->theVector.clear(); 309 310 this->assertEmpty(this->theVector); 311 EXPECT_EQ(4, Constructable::getNumConstructorCalls()); 312 EXPECT_EQ(4, Constructable::getNumDestructorCalls()); 313 } 314 315 // Resize smaller test. 316 TYPED_TEST(SmallVectorTest, ResizeShrinkTest) { 317 SCOPED_TRACE("ResizeShrinkTest"); 318 319 this->theVector.reserve(3); 320 this->makeSequence(this->theVector, 1, 3); 321 this->theVector.resize(1); 322 323 this->assertValuesInOrder(this->theVector, 1u, 1); 324 EXPECT_EQ(6, Constructable::getNumConstructorCalls()); 325 EXPECT_EQ(5, Constructable::getNumDestructorCalls()); 326 } 327 328 // Truncate test. 329 TYPED_TEST(SmallVectorTest, TruncateTest) { 330 SCOPED_TRACE("TruncateTest"); 331 332 this->theVector.reserve(3); 333 this->makeSequence(this->theVector, 1, 3); 334 this->theVector.truncate(1); 335 336 this->assertValuesInOrder(this->theVector, 1u, 1); 337 EXPECT_EQ(6, Constructable::getNumConstructorCalls()); 338 EXPECT_EQ(5, Constructable::getNumDestructorCalls()); 339 340 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST 341 EXPECT_DEATH(this->theVector.truncate(2), "Cannot increase size"); 342 #endif 343 this->theVector.truncate(1); 344 this->assertValuesInOrder(this->theVector, 1u, 1); 345 EXPECT_EQ(6, Constructable::getNumConstructorCalls()); 346 EXPECT_EQ(5, Constructable::getNumDestructorCalls()); 347 348 this->theVector.truncate(0); 349 this->assertEmpty(this->theVector); 350 EXPECT_EQ(6, Constructable::getNumConstructorCalls()); 351 EXPECT_EQ(6, Constructable::getNumDestructorCalls()); 352 } 353 354 // Resize bigger test. 355 TYPED_TEST(SmallVectorTest, ResizeGrowTest) { 356 SCOPED_TRACE("ResizeGrowTest"); 357 358 this->theVector.resize(2); 359 360 EXPECT_EQ(2, Constructable::getNumConstructorCalls()); 361 EXPECT_EQ(0, Constructable::getNumDestructorCalls()); 362 EXPECT_EQ(2u, this->theVector.size()); 363 } 364 365 TYPED_TEST(SmallVectorTest, ResizeWithElementsTest) { 366 this->theVector.resize(2); 367 368 Constructable::reset(); 369 370 this->theVector.resize(4); 371 372 size_t Ctors = Constructable::getNumConstructorCalls(); 373 EXPECT_TRUE(Ctors == 2 || Ctors == 4); 374 size_t MoveCtors = Constructable::getNumMoveConstructorCalls(); 375 EXPECT_TRUE(MoveCtors == 0 || MoveCtors == 2); 376 size_t Dtors = Constructable::getNumDestructorCalls(); 377 EXPECT_TRUE(Dtors == 0 || Dtors == 2); 378 } 379 380 // Resize with fill value. 381 TYPED_TEST(SmallVectorTest, ResizeFillTest) { 382 SCOPED_TRACE("ResizeFillTest"); 383 384 this->theVector.resize(3, Constructable(77)); 385 this->assertValuesInOrder(this->theVector, 3u, 77, 77, 77); 386 } 387 388 TEST(SmallVectorTest, ResizeForOverwrite) { 389 { 390 // Heap allocated storage. 391 SmallVector<unsigned, 0> V; 392 V.push_back(5U); 393 V.pop_back(); 394 V.resize_for_overwrite(V.size() + 1U); 395 EXPECT_EQ(5U, V.back()); 396 V.pop_back(); 397 V.resize(V.size() + 1); 398 EXPECT_EQ(0U, V.back()); 399 } 400 { 401 // Inline storage. 402 SmallVector<unsigned, 2> V; 403 V.push_back(5U); 404 V.pop_back(); 405 V.resize_for_overwrite(V.size() + 1U); 406 EXPECT_EQ(5U, V.back()); 407 V.pop_back(); 408 V.resize(V.size() + 1); 409 EXPECT_EQ(0U, V.back()); 410 } 411 } 412 413 // Overflow past fixed size. 414 TYPED_TEST(SmallVectorTest, OverflowTest) { 415 SCOPED_TRACE("OverflowTest"); 416 417 // Push more elements than the fixed size. 418 this->makeSequence(this->theVector, 1, 10); 419 420 // Test size and values. 421 EXPECT_EQ(10u, this->theVector.size()); 422 for (int i = 0; i < 10; ++i) { 423 EXPECT_EQ(i+1, this->theVector[i].getValue()); 424 } 425 426 // Now resize back to fixed size. 427 this->theVector.resize(1); 428 429 this->assertValuesInOrder(this->theVector, 1u, 1); 430 } 431 432 // Iteration tests. 433 TYPED_TEST(SmallVectorTest, IterationTest) { 434 this->makeSequence(this->theVector, 1, 2); 435 436 // Forward Iteration 437 typename TypeParam::iterator it = this->theVector.begin(); 438 EXPECT_TRUE(*it == this->theVector.front()); 439 EXPECT_TRUE(*it == this->theVector[0]); 440 EXPECT_EQ(1, it->getValue()); 441 ++it; 442 EXPECT_TRUE(*it == this->theVector[1]); 443 EXPECT_TRUE(*it == this->theVector.back()); 444 EXPECT_EQ(2, it->getValue()); 445 ++it; 446 EXPECT_TRUE(it == this->theVector.end()); 447 --it; 448 EXPECT_TRUE(*it == this->theVector[1]); 449 EXPECT_EQ(2, it->getValue()); 450 --it; 451 EXPECT_TRUE(*it == this->theVector[0]); 452 EXPECT_EQ(1, it->getValue()); 453 454 // Reverse Iteration 455 typename TypeParam::reverse_iterator rit = this->theVector.rbegin(); 456 EXPECT_TRUE(*rit == this->theVector[1]); 457 EXPECT_EQ(2, rit->getValue()); 458 ++rit; 459 EXPECT_TRUE(*rit == this->theVector[0]); 460 EXPECT_EQ(1, rit->getValue()); 461 ++rit; 462 EXPECT_TRUE(rit == this->theVector.rend()); 463 --rit; 464 EXPECT_TRUE(*rit == this->theVector[0]); 465 EXPECT_EQ(1, rit->getValue()); 466 --rit; 467 EXPECT_TRUE(*rit == this->theVector[1]); 468 EXPECT_EQ(2, rit->getValue()); 469 } 470 471 // Swap test. 472 TYPED_TEST(SmallVectorTest, SwapTest) { 473 SCOPED_TRACE("SwapTest"); 474 475 this->makeSequence(this->theVector, 1, 2); 476 std::swap(this->theVector, this->otherVector); 477 478 this->assertEmpty(this->theVector); 479 this->assertValuesInOrder(this->otherVector, 2u, 1, 2); 480 } 481 482 // Append test 483 TYPED_TEST(SmallVectorTest, AppendTest) { 484 SCOPED_TRACE("AppendTest"); 485 486 this->makeSequence(this->otherVector, 2, 3); 487 488 this->theVector.push_back(Constructable(1)); 489 this->theVector.append(this->otherVector.begin(), this->otherVector.end()); 490 491 this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3); 492 } 493 494 // Append repeated test 495 TYPED_TEST(SmallVectorTest, AppendRepeatedTest) { 496 SCOPED_TRACE("AppendRepeatedTest"); 497 498 this->theVector.push_back(Constructable(1)); 499 this->theVector.append(2, Constructable(77)); 500 this->assertValuesInOrder(this->theVector, 3u, 1, 77, 77); 501 } 502 503 // Append test 504 TYPED_TEST(SmallVectorTest, AppendNonIterTest) { 505 SCOPED_TRACE("AppendRepeatedTest"); 506 507 this->theVector.push_back(Constructable(1)); 508 this->theVector.append(2, 7); 509 this->assertValuesInOrder(this->theVector, 3u, 1, 7, 7); 510 } 511 512 struct output_iterator { 513 typedef std::output_iterator_tag iterator_category; 514 typedef int value_type; 515 typedef int difference_type; 516 typedef value_type *pointer; 517 typedef value_type &reference; 518 operator int() { return 2; } 519 operator Constructable() { return 7; } 520 }; 521 522 TYPED_TEST(SmallVectorTest, AppendRepeatedNonForwardIterator) { 523 SCOPED_TRACE("AppendRepeatedTest"); 524 525 this->theVector.push_back(Constructable(1)); 526 this->theVector.append(output_iterator(), output_iterator()); 527 this->assertValuesInOrder(this->theVector, 3u, 1, 7, 7); 528 } 529 530 TYPED_TEST(SmallVectorTest, AppendSmallVector) { 531 SCOPED_TRACE("AppendSmallVector"); 532 533 SmallVector<Constructable, 3> otherVector = {7, 7}; 534 this->theVector.push_back(Constructable(1)); 535 this->theVector.append(otherVector); 536 this->assertValuesInOrder(this->theVector, 3u, 1, 7, 7); 537 } 538 539 // Assign test 540 TYPED_TEST(SmallVectorTest, AssignTest) { 541 SCOPED_TRACE("AssignTest"); 542 543 this->theVector.push_back(Constructable(1)); 544 this->theVector.assign(2, Constructable(77)); 545 this->assertValuesInOrder(this->theVector, 2u, 77, 77); 546 } 547 548 // Assign test 549 TYPED_TEST(SmallVectorTest, AssignRangeTest) { 550 SCOPED_TRACE("AssignTest"); 551 552 this->theVector.push_back(Constructable(1)); 553 int arr[] = {1, 2, 3}; 554 this->theVector.assign(std::begin(arr), std::end(arr)); 555 this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3); 556 } 557 558 // Assign test 559 TYPED_TEST(SmallVectorTest, AssignNonIterTest) { 560 SCOPED_TRACE("AssignTest"); 561 562 this->theVector.push_back(Constructable(1)); 563 this->theVector.assign(2, 7); 564 this->assertValuesInOrder(this->theVector, 2u, 7, 7); 565 } 566 567 TYPED_TEST(SmallVectorTest, AssignSmallVector) { 568 SCOPED_TRACE("AssignSmallVector"); 569 570 SmallVector<Constructable, 3> otherVector = {7, 7}; 571 this->theVector.push_back(Constructable(1)); 572 this->theVector.assign(otherVector); 573 this->assertValuesInOrder(this->theVector, 2u, 7, 7); 574 } 575 576 // Move-assign test 577 TYPED_TEST(SmallVectorTest, MoveAssignTest) { 578 SCOPED_TRACE("MoveAssignTest"); 579 580 // Set up our vector with a single element, but enough capacity for 4. 581 this->theVector.reserve(4); 582 this->theVector.push_back(Constructable(1)); 583 584 // Set up the other vector with 2 elements. 585 this->otherVector.push_back(Constructable(2)); 586 this->otherVector.push_back(Constructable(3)); 587 588 // Move-assign from the other vector. 589 this->theVector = std::move(this->otherVector); 590 591 // Make sure we have the right result. 592 this->assertValuesInOrder(this->theVector, 2u, 2, 3); 593 594 // Make sure the # of constructor/destructor calls line up. There 595 // are two live objects after clearing the other vector. 596 this->otherVector.clear(); 597 EXPECT_EQ(Constructable::getNumConstructorCalls()-2, 598 Constructable::getNumDestructorCalls()); 599 600 // There shouldn't be any live objects any more. 601 this->theVector.clear(); 602 EXPECT_EQ(Constructable::getNumConstructorCalls(), 603 Constructable::getNumDestructorCalls()); 604 } 605 606 // Erase a single element 607 TYPED_TEST(SmallVectorTest, EraseTest) { 608 SCOPED_TRACE("EraseTest"); 609 610 this->makeSequence(this->theVector, 1, 3); 611 const auto &theConstVector = this->theVector; 612 this->theVector.erase(theConstVector.begin()); 613 this->assertValuesInOrder(this->theVector, 2u, 2, 3); 614 } 615 616 // Erase a range of elements 617 TYPED_TEST(SmallVectorTest, EraseRangeTest) { 618 SCOPED_TRACE("EraseRangeTest"); 619 620 this->makeSequence(this->theVector, 1, 3); 621 const auto &theConstVector = this->theVector; 622 this->theVector.erase(theConstVector.begin(), theConstVector.begin() + 2); 623 this->assertValuesInOrder(this->theVector, 1u, 3); 624 } 625 626 // Insert a single element. 627 TYPED_TEST(SmallVectorTest, InsertTest) { 628 SCOPED_TRACE("InsertTest"); 629 630 this->makeSequence(this->theVector, 1, 3); 631 typename TypeParam::iterator I = 632 this->theVector.insert(this->theVector.begin() + 1, Constructable(77)); 633 EXPECT_EQ(this->theVector.begin() + 1, I); 634 this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3); 635 } 636 637 // Insert a copy of a single element. 638 TYPED_TEST(SmallVectorTest, InsertCopy) { 639 SCOPED_TRACE("InsertTest"); 640 641 this->makeSequence(this->theVector, 1, 3); 642 Constructable C(77); 643 typename TypeParam::iterator I = 644 this->theVector.insert(this->theVector.begin() + 1, C); 645 EXPECT_EQ(this->theVector.begin() + 1, I); 646 this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3); 647 } 648 649 // Insert repeated elements. 650 TYPED_TEST(SmallVectorTest, InsertRepeatedTest) { 651 SCOPED_TRACE("InsertRepeatedTest"); 652 653 this->makeSequence(this->theVector, 1, 4); 654 Constructable::reset(); 655 auto I = 656 this->theVector.insert(this->theVector.begin() + 1, 2, Constructable(16)); 657 // Move construct the top element into newly allocated space, and optionally 658 // reallocate the whole buffer, move constructing into it. 659 // FIXME: This is inefficient, we shouldn't move things into newly allocated 660 // space, then move them up/around, there should only be 2 or 4 move 661 // constructions here. 662 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 || 663 Constructable::getNumMoveConstructorCalls() == 6); 664 // Move assign the next two to shift them up and make a gap. 665 EXPECT_EQ(1, Constructable::getNumMoveAssignmentCalls()); 666 // Copy construct the two new elements from the parameter. 667 EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls()); 668 // All without any copy construction. 669 EXPECT_EQ(0, Constructable::getNumCopyConstructorCalls()); 670 EXPECT_EQ(this->theVector.begin() + 1, I); 671 this->assertValuesInOrder(this->theVector, 6u, 1, 16, 16, 2, 3, 4); 672 } 673 674 TYPED_TEST(SmallVectorTest, InsertRepeatedNonIterTest) { 675 SCOPED_TRACE("InsertRepeatedTest"); 676 677 this->makeSequence(this->theVector, 1, 4); 678 Constructable::reset(); 679 auto I = this->theVector.insert(this->theVector.begin() + 1, 2, 7); 680 EXPECT_EQ(this->theVector.begin() + 1, I); 681 this->assertValuesInOrder(this->theVector, 6u, 1, 7, 7, 2, 3, 4); 682 } 683 684 TYPED_TEST(SmallVectorTest, InsertRepeatedAtEndTest) { 685 SCOPED_TRACE("InsertRepeatedTest"); 686 687 this->makeSequence(this->theVector, 1, 4); 688 Constructable::reset(); 689 auto I = this->theVector.insert(this->theVector.end(), 2, Constructable(16)); 690 // Just copy construct them into newly allocated space 691 EXPECT_EQ(2, Constructable::getNumCopyConstructorCalls()); 692 // Move everything across if reallocation is needed. 693 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 || 694 Constructable::getNumMoveConstructorCalls() == 4); 695 // Without ever moving or copying anything else. 696 EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls()); 697 EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls()); 698 699 EXPECT_EQ(this->theVector.begin() + 4, I); 700 this->assertValuesInOrder(this->theVector, 6u, 1, 2, 3, 4, 16, 16); 701 } 702 703 TYPED_TEST(SmallVectorTest, InsertRepeatedEmptyTest) { 704 SCOPED_TRACE("InsertRepeatedTest"); 705 706 this->makeSequence(this->theVector, 10, 15); 707 708 // Empty insert. 709 EXPECT_EQ(this->theVector.end(), 710 this->theVector.insert(this->theVector.end(), 711 0, Constructable(42))); 712 EXPECT_EQ(this->theVector.begin() + 1, 713 this->theVector.insert(this->theVector.begin() + 1, 714 0, Constructable(42))); 715 } 716 717 // Insert range. 718 TYPED_TEST(SmallVectorTest, InsertRangeTest) { 719 SCOPED_TRACE("InsertRangeTest"); 720 721 Constructable Arr[3] = 722 { Constructable(77), Constructable(77), Constructable(77) }; 723 724 this->makeSequence(this->theVector, 1, 3); 725 Constructable::reset(); 726 auto I = this->theVector.insert(this->theVector.begin() + 1, Arr, Arr + 3); 727 // Move construct the top 3 elements into newly allocated space. 728 // Possibly move the whole sequence into new space first. 729 // FIXME: This is inefficient, we shouldn't move things into newly allocated 730 // space, then move them up/around, there should only be 2 or 3 move 731 // constructions here. 732 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 || 733 Constructable::getNumMoveConstructorCalls() == 5); 734 // Copy assign the lower 2 new elements into existing space. 735 EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls()); 736 // Copy construct the third element into newly allocated space. 737 EXPECT_EQ(1, Constructable::getNumCopyConstructorCalls()); 738 EXPECT_EQ(this->theVector.begin() + 1, I); 739 this->assertValuesInOrder(this->theVector, 6u, 1, 77, 77, 77, 2, 3); 740 } 741 742 743 TYPED_TEST(SmallVectorTest, InsertRangeAtEndTest) { 744 SCOPED_TRACE("InsertRangeTest"); 745 746 Constructable Arr[3] = 747 { Constructable(77), Constructable(77), Constructable(77) }; 748 749 this->makeSequence(this->theVector, 1, 3); 750 751 // Insert at end. 752 Constructable::reset(); 753 auto I = this->theVector.insert(this->theVector.end(), Arr, Arr+3); 754 // Copy construct the 3 elements into new space at the top. 755 EXPECT_EQ(3, Constructable::getNumCopyConstructorCalls()); 756 // Don't copy/move anything else. 757 EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls()); 758 // Reallocation might occur, causing all elements to be moved into the new 759 // buffer. 760 EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 || 761 Constructable::getNumMoveConstructorCalls() == 3); 762 EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls()); 763 EXPECT_EQ(this->theVector.begin() + 3, I); 764 this->assertValuesInOrder(this->theVector, 6u, 765 1, 2, 3, 77, 77, 77); 766 } 767 768 TYPED_TEST(SmallVectorTest, InsertEmptyRangeTest) { 769 SCOPED_TRACE("InsertRangeTest"); 770 771 this->makeSequence(this->theVector, 1, 3); 772 773 // Empty insert. 774 EXPECT_EQ(this->theVector.end(), 775 this->theVector.insert(this->theVector.end(), 776 this->theVector.begin(), 777 this->theVector.begin())); 778 EXPECT_EQ(this->theVector.begin() + 1, 779 this->theVector.insert(this->theVector.begin() + 1, 780 this->theVector.begin(), 781 this->theVector.begin())); 782 } 783 784 // Comparison tests. 785 TYPED_TEST(SmallVectorTest, ComparisonEqualityTest) { 786 SCOPED_TRACE("ComparisonEqualityTest"); 787 788 this->makeSequence(this->theVector, 1, 3); 789 this->makeSequence(this->otherVector, 1, 3); 790 791 EXPECT_TRUE(this->theVector == this->otherVector); 792 EXPECT_FALSE(this->theVector != this->otherVector); 793 794 this->otherVector.clear(); 795 this->makeSequence(this->otherVector, 2, 4); 796 797 EXPECT_FALSE(this->theVector == this->otherVector); 798 EXPECT_TRUE(this->theVector != this->otherVector); 799 } 800 801 // Comparison tests. 802 TYPED_TEST(SmallVectorTest, ComparisonLessThanTest) { 803 SCOPED_TRACE("ComparisonLessThanTest"); 804 805 this->theVector = {1, 2, 4}; 806 this->otherVector = {1, 4}; 807 808 EXPECT_TRUE(this->theVector < this->otherVector); 809 EXPECT_TRUE(this->theVector <= this->otherVector); 810 EXPECT_FALSE(this->theVector > this->otherVector); 811 EXPECT_FALSE(this->theVector >= this->otherVector); 812 813 EXPECT_FALSE(this->otherVector < this->theVector); 814 EXPECT_FALSE(this->otherVector <= this->theVector); 815 EXPECT_TRUE(this->otherVector > this->theVector); 816 EXPECT_TRUE(this->otherVector >= this->theVector); 817 818 this->otherVector = {1, 2, 4}; 819 820 EXPECT_FALSE(this->theVector < this->otherVector); 821 EXPECT_TRUE(this->theVector <= this->otherVector); 822 EXPECT_FALSE(this->theVector > this->otherVector); 823 EXPECT_TRUE(this->theVector >= this->otherVector); 824 825 EXPECT_FALSE(this->otherVector < this->theVector); 826 EXPECT_TRUE(this->otherVector <= this->theVector); 827 EXPECT_FALSE(this->otherVector > this->theVector); 828 EXPECT_TRUE(this->otherVector >= this->theVector); 829 } 830 831 // Constant vector tests. 832 TYPED_TEST(SmallVectorTest, ConstVectorTest) { 833 const TypeParam constVector; 834 835 EXPECT_EQ(0u, constVector.size()); 836 EXPECT_TRUE(constVector.empty()); 837 EXPECT_TRUE(constVector.begin() == constVector.end()); 838 } 839 840 // Direct array access. 841 TYPED_TEST(SmallVectorTest, DirectVectorTest) { 842 EXPECT_EQ(0u, this->theVector.size()); 843 this->theVector.reserve(4); 844 EXPECT_LE(4u, this->theVector.capacity()); 845 EXPECT_EQ(0, Constructable::getNumConstructorCalls()); 846 this->theVector.push_back(1); 847 this->theVector.push_back(2); 848 this->theVector.push_back(3); 849 this->theVector.push_back(4); 850 EXPECT_EQ(4u, this->theVector.size()); 851 EXPECT_EQ(8, Constructable::getNumConstructorCalls()); 852 EXPECT_EQ(1, this->theVector[0].getValue()); 853 EXPECT_EQ(2, this->theVector[1].getValue()); 854 EXPECT_EQ(3, this->theVector[2].getValue()); 855 EXPECT_EQ(4, this->theVector[3].getValue()); 856 } 857 858 TYPED_TEST(SmallVectorTest, IteratorTest) { 859 std::list<int> L; 860 this->theVector.insert(this->theVector.end(), L.begin(), L.end()); 861 } 862 863 template <typename InvalidType> class DualSmallVectorsTest; 864 865 template <typename VectorT1, typename VectorT2> 866 class DualSmallVectorsTest<std::pair<VectorT1, VectorT2>> : public SmallVectorTestBase { 867 protected: 868 VectorT1 theVector; 869 VectorT2 otherVector; 870 871 template <typename T, unsigned N> 872 static unsigned NumBuiltinElts(const SmallVector<T, N>&) { return N; } 873 }; 874 875 typedef ::testing::Types< 876 // Small mode -> Small mode. 877 std::pair<SmallVector<Constructable, 4>, SmallVector<Constructable, 4>>, 878 // Small mode -> Big mode. 879 std::pair<SmallVector<Constructable, 4>, SmallVector<Constructable, 2>>, 880 // Big mode -> Small mode. 881 std::pair<SmallVector<Constructable, 2>, SmallVector<Constructable, 4>>, 882 // Big mode -> Big mode. 883 std::pair<SmallVector<Constructable, 2>, SmallVector<Constructable, 2>> 884 > DualSmallVectorTestTypes; 885 886 TYPED_TEST_SUITE(DualSmallVectorsTest, DualSmallVectorTestTypes, ); 887 888 TYPED_TEST(DualSmallVectorsTest, MoveAssignment) { 889 SCOPED_TRACE("MoveAssignTest-DualVectorTypes"); 890 891 // Set up our vector with four elements. 892 for (unsigned I = 0; I < 4; ++I) 893 this->otherVector.push_back(Constructable(I)); 894 895 const Constructable *OrigDataPtr = this->otherVector.data(); 896 897 // Move-assign from the other vector. 898 this->theVector = 899 std::move(static_cast<SmallVectorImpl<Constructable>&>(this->otherVector)); 900 901 // Make sure we have the right result. 902 this->assertValuesInOrder(this->theVector, 4u, 0, 1, 2, 3); 903 904 // Make sure the # of constructor/destructor calls line up. There 905 // are two live objects after clearing the other vector. 906 this->otherVector.clear(); 907 EXPECT_EQ(Constructable::getNumConstructorCalls()-4, 908 Constructable::getNumDestructorCalls()); 909 910 // If the source vector (otherVector) was in small-mode, assert that we just 911 // moved the data pointer over. 912 EXPECT_TRUE(this->NumBuiltinElts(this->otherVector) == 4 || 913 this->theVector.data() == OrigDataPtr); 914 915 // There shouldn't be any live objects any more. 916 this->theVector.clear(); 917 EXPECT_EQ(Constructable::getNumConstructorCalls(), 918 Constructable::getNumDestructorCalls()); 919 920 // We shouldn't have copied anything in this whole process. 921 EXPECT_EQ(Constructable::getNumCopyConstructorCalls(), 0); 922 } 923 924 struct notassignable { 925 int &x; 926 notassignable(int &x) : x(x) {} 927 }; 928 929 TEST(SmallVectorCustomTest, NoAssignTest) { 930 int x = 0; 931 SmallVector<notassignable, 2> vec; 932 vec.push_back(notassignable(x)); 933 x = 42; 934 EXPECT_EQ(42, vec.pop_back_val().x); 935 } 936 937 struct MovedFrom { 938 bool hasValue; 939 MovedFrom() : hasValue(true) { 940 } 941 MovedFrom(MovedFrom&& m) : hasValue(m.hasValue) { 942 m.hasValue = false; 943 } 944 MovedFrom &operator=(MovedFrom&& m) { 945 hasValue = m.hasValue; 946 m.hasValue = false; 947 return *this; 948 } 949 }; 950 951 TEST(SmallVectorTest, MidInsert) { 952 SmallVector<MovedFrom, 3> v; 953 v.push_back(MovedFrom()); 954 v.insert(v.begin(), MovedFrom()); 955 for (MovedFrom &m : v) 956 EXPECT_TRUE(m.hasValue); 957 } 958 959 enum EmplaceableArgState { 960 EAS_Defaulted, 961 EAS_Arg, 962 EAS_LValue, 963 EAS_RValue, 964 EAS_Failure 965 }; 966 template <int I> struct EmplaceableArg { 967 EmplaceableArgState State; 968 EmplaceableArg() : State(EAS_Defaulted) {} 969 EmplaceableArg(EmplaceableArg &&X) 970 : State(X.State == EAS_Arg ? EAS_RValue : EAS_Failure) {} 971 EmplaceableArg(EmplaceableArg &X) 972 : State(X.State == EAS_Arg ? EAS_LValue : EAS_Failure) {} 973 974 explicit EmplaceableArg(bool) : State(EAS_Arg) {} 975 976 private: 977 EmplaceableArg &operator=(EmplaceableArg &&) = delete; 978 EmplaceableArg &operator=(const EmplaceableArg &) = delete; 979 }; 980 981 enum EmplaceableState { ES_Emplaced, ES_Moved }; 982 struct Emplaceable { 983 EmplaceableArg<0> A0; 984 EmplaceableArg<1> A1; 985 EmplaceableArg<2> A2; 986 EmplaceableArg<3> A3; 987 EmplaceableState State; 988 989 Emplaceable() : State(ES_Emplaced) {} 990 991 template <class A0Ty> 992 explicit Emplaceable(A0Ty &&A0) 993 : A0(std::forward<A0Ty>(A0)), State(ES_Emplaced) {} 994 995 template <class A0Ty, class A1Ty> 996 Emplaceable(A0Ty &&A0, A1Ty &&A1) 997 : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)), 998 State(ES_Emplaced) {} 999 1000 template <class A0Ty, class A1Ty, class A2Ty> 1001 Emplaceable(A0Ty &&A0, A1Ty &&A1, A2Ty &&A2) 1002 : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)), 1003 A2(std::forward<A2Ty>(A2)), State(ES_Emplaced) {} 1004 1005 template <class A0Ty, class A1Ty, class A2Ty, class A3Ty> 1006 Emplaceable(A0Ty &&A0, A1Ty &&A1, A2Ty &&A2, A3Ty &&A3) 1007 : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)), 1008 A2(std::forward<A2Ty>(A2)), A3(std::forward<A3Ty>(A3)), 1009 State(ES_Emplaced) {} 1010 1011 Emplaceable(Emplaceable &&) : State(ES_Moved) {} 1012 Emplaceable &operator=(Emplaceable &&) { 1013 State = ES_Moved; 1014 return *this; 1015 } 1016 1017 private: 1018 Emplaceable(const Emplaceable &) = delete; 1019 Emplaceable &operator=(const Emplaceable &) = delete; 1020 }; 1021 1022 TEST(SmallVectorTest, EmplaceBack) { 1023 EmplaceableArg<0> A0(true); 1024 EmplaceableArg<1> A1(true); 1025 EmplaceableArg<2> A2(true); 1026 EmplaceableArg<3> A3(true); 1027 { 1028 SmallVector<Emplaceable, 3> V; 1029 Emplaceable &back = V.emplace_back(); 1030 EXPECT_TRUE(&back == &V.back()); 1031 EXPECT_TRUE(V.size() == 1); 1032 EXPECT_TRUE(back.State == ES_Emplaced); 1033 EXPECT_TRUE(back.A0.State == EAS_Defaulted); 1034 EXPECT_TRUE(back.A1.State == EAS_Defaulted); 1035 EXPECT_TRUE(back.A2.State == EAS_Defaulted); 1036 EXPECT_TRUE(back.A3.State == EAS_Defaulted); 1037 } 1038 { 1039 SmallVector<Emplaceable, 3> V; 1040 Emplaceable &back = V.emplace_back(std::move(A0)); 1041 EXPECT_TRUE(&back == &V.back()); 1042 EXPECT_TRUE(V.size() == 1); 1043 EXPECT_TRUE(back.State == ES_Emplaced); 1044 EXPECT_TRUE(back.A0.State == EAS_RValue); 1045 EXPECT_TRUE(back.A1.State == EAS_Defaulted); 1046 EXPECT_TRUE(back.A2.State == EAS_Defaulted); 1047 EXPECT_TRUE(back.A3.State == EAS_Defaulted); 1048 } 1049 { 1050 SmallVector<Emplaceable, 3> V; 1051 Emplaceable &back = V.emplace_back(A0); 1052 EXPECT_TRUE(&back == &V.back()); 1053 EXPECT_TRUE(V.size() == 1); 1054 EXPECT_TRUE(back.State == ES_Emplaced); 1055 EXPECT_TRUE(back.A0.State == EAS_LValue); 1056 EXPECT_TRUE(back.A1.State == EAS_Defaulted); 1057 EXPECT_TRUE(back.A2.State == EAS_Defaulted); 1058 EXPECT_TRUE(back.A3.State == EAS_Defaulted); 1059 } 1060 { 1061 SmallVector<Emplaceable, 3> V; 1062 Emplaceable &back = V.emplace_back(A0, A1); 1063 EXPECT_TRUE(&back == &V.back()); 1064 EXPECT_TRUE(V.size() == 1); 1065 EXPECT_TRUE(back.State == ES_Emplaced); 1066 EXPECT_TRUE(back.A0.State == EAS_LValue); 1067 EXPECT_TRUE(back.A1.State == EAS_LValue); 1068 EXPECT_TRUE(back.A2.State == EAS_Defaulted); 1069 EXPECT_TRUE(back.A3.State == EAS_Defaulted); 1070 } 1071 { 1072 SmallVector<Emplaceable, 3> V; 1073 Emplaceable &back = V.emplace_back(std::move(A0), std::move(A1)); 1074 EXPECT_TRUE(&back == &V.back()); 1075 EXPECT_TRUE(V.size() == 1); 1076 EXPECT_TRUE(back.State == ES_Emplaced); 1077 EXPECT_TRUE(back.A0.State == EAS_RValue); 1078 EXPECT_TRUE(back.A1.State == EAS_RValue); 1079 EXPECT_TRUE(back.A2.State == EAS_Defaulted); 1080 EXPECT_TRUE(back.A3.State == EAS_Defaulted); 1081 } 1082 { 1083 SmallVector<Emplaceable, 3> V; 1084 Emplaceable &back = V.emplace_back(std::move(A0), A1, std::move(A2), A3); 1085 EXPECT_TRUE(&back == &V.back()); 1086 EXPECT_TRUE(V.size() == 1); 1087 EXPECT_TRUE(back.State == ES_Emplaced); 1088 EXPECT_TRUE(back.A0.State == EAS_RValue); 1089 EXPECT_TRUE(back.A1.State == EAS_LValue); 1090 EXPECT_TRUE(back.A2.State == EAS_RValue); 1091 EXPECT_TRUE(back.A3.State == EAS_LValue); 1092 } 1093 { 1094 SmallVector<int, 1> V; 1095 V.emplace_back(); 1096 V.emplace_back(42); 1097 EXPECT_EQ(2U, V.size()); 1098 EXPECT_EQ(0, V[0]); 1099 EXPECT_EQ(42, V[1]); 1100 } 1101 } 1102 1103 TEST(SmallVectorTest, DefaultInlinedElements) { 1104 SmallVector<int> V; 1105 EXPECT_TRUE(V.empty()); 1106 V.push_back(7); 1107 EXPECT_EQ(V[0], 7); 1108 1109 // Check that at least a couple layers of nested SmallVector<T>'s are allowed 1110 // by the default inline elements policy. This pattern happens in practice 1111 // with some frequency, and it seems fairly harmless even though each layer of 1112 // SmallVector's will grow the total sizeof by a vector header beyond the 1113 // "preferred" maximum sizeof. 1114 SmallVector<SmallVector<SmallVector<int>>> NestedV; 1115 NestedV.emplace_back().emplace_back().emplace_back(42); 1116 EXPECT_EQ(NestedV[0][0][0], 42); 1117 } 1118 1119 TEST(SmallVectorTest, InitializerList) { 1120 SmallVector<int, 2> V1 = {}; 1121 EXPECT_TRUE(V1.empty()); 1122 V1 = {0, 0}; 1123 EXPECT_TRUE(makeArrayRef(V1).equals({0, 0})); 1124 V1 = {-1, -1}; 1125 EXPECT_TRUE(makeArrayRef(V1).equals({-1, -1})); 1126 1127 SmallVector<int, 2> V2 = {1, 2, 3, 4}; 1128 EXPECT_TRUE(makeArrayRef(V2).equals({1, 2, 3, 4})); 1129 V2.assign({4}); 1130 EXPECT_TRUE(makeArrayRef(V2).equals({4})); 1131 V2.append({3, 2}); 1132 EXPECT_TRUE(makeArrayRef(V2).equals({4, 3, 2})); 1133 V2.insert(V2.begin() + 1, 5); 1134 EXPECT_TRUE(makeArrayRef(V2).equals({4, 5, 3, 2})); 1135 } 1136 1137 template <class VectorT> 1138 class SmallVectorReferenceInvalidationTest : public SmallVectorTestBase { 1139 protected: 1140 const char *AssertionMessage = 1141 "Attempting to reference an element of the vector in an operation \" " 1142 "\"that invalidates it"; 1143 1144 VectorT V; 1145 1146 template <typename T, unsigned N> 1147 static unsigned NumBuiltinElts(const SmallVector<T, N> &) { 1148 return N; 1149 } 1150 1151 template <class T> static bool isValueType() { 1152 return std::is_same<T, typename VectorT::value_type>::value; 1153 } 1154 1155 void SetUp() override { 1156 SmallVectorTestBase::SetUp(); 1157 1158 // Fill up the small size so that insertions move the elements. 1159 for (int I = 0, E = NumBuiltinElts(V); I != E; ++I) 1160 V.emplace_back(I + 1); 1161 } 1162 }; 1163 1164 // Test one type that's trivially copyable (int) and one that isn't 1165 // (Constructable) since reference invalidation may be fixed differently for 1166 // each. 1167 using SmallVectorReferenceInvalidationTestTypes = 1168 ::testing::Types<SmallVector<int, 3>, SmallVector<Constructable, 3>>; 1169 1170 TYPED_TEST_SUITE(SmallVectorReferenceInvalidationTest, 1171 SmallVectorReferenceInvalidationTestTypes, ); 1172 1173 TYPED_TEST(SmallVectorReferenceInvalidationTest, PushBack) { 1174 // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode. 1175 auto &V = this->V; 1176 int N = this->NumBuiltinElts(V); 1177 1178 // Push back a reference to last element when growing from small storage. 1179 V.push_back(V.back()); 1180 EXPECT_EQ(N, V.back()); 1181 1182 // Check that the old value is still there (not moved away). 1183 EXPECT_EQ(N, V[V.size() - 2]); 1184 1185 // Fill storage again. 1186 V.back() = V.size(); 1187 while (V.size() < V.capacity()) 1188 V.push_back(V.size() + 1); 1189 1190 // Push back a reference to last element when growing from large storage. 1191 V.push_back(V.back()); 1192 EXPECT_EQ(int(V.size()) - 1, V.back()); 1193 } 1194 1195 TYPED_TEST(SmallVectorReferenceInvalidationTest, PushBackMoved) { 1196 // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode. 1197 auto &V = this->V; 1198 int N = this->NumBuiltinElts(V); 1199 1200 // Push back a reference to last element when growing from small storage. 1201 V.push_back(std::move(V.back())); 1202 EXPECT_EQ(N, V.back()); 1203 if (this->template isValueType<Constructable>()) { 1204 // Check that the value was moved (not copied). 1205 EXPECT_EQ(0, V[V.size() - 2]); 1206 } 1207 1208 // Fill storage again. 1209 V.back() = V.size(); 1210 while (V.size() < V.capacity()) 1211 V.push_back(V.size() + 1); 1212 1213 // Push back a reference to last element when growing from large storage. 1214 V.push_back(std::move(V.back())); 1215 1216 // Check the values. 1217 EXPECT_EQ(int(V.size()) - 1, V.back()); 1218 if (this->template isValueType<Constructable>()) { 1219 // Check the value got moved out. 1220 EXPECT_EQ(0, V[V.size() - 2]); 1221 } 1222 } 1223 1224 TYPED_TEST(SmallVectorReferenceInvalidationTest, Resize) { 1225 auto &V = this->V; 1226 (void)V; 1227 int N = this->NumBuiltinElts(V); 1228 V.resize(N + 1, V.back()); 1229 EXPECT_EQ(N, V.back()); 1230 1231 // Resize to add enough elements that V will grow again. If reference 1232 // invalidation breaks in the future, sanitizers should be able to catch a 1233 // use-after-free here. 1234 V.resize(V.capacity() + 1, V.front()); 1235 EXPECT_EQ(1, V.back()); 1236 } 1237 1238 TYPED_TEST(SmallVectorReferenceInvalidationTest, Append) { 1239 auto &V = this->V; 1240 (void)V; 1241 V.append(1, V.back()); 1242 int N = this->NumBuiltinElts(V); 1243 EXPECT_EQ(N, V[N - 1]); 1244 1245 // Append enough more elements that V will grow again. This tests growing 1246 // when already in large mode. 1247 // 1248 // If reference invalidation breaks in the future, sanitizers should be able 1249 // to catch a use-after-free here. 1250 V.append(V.capacity() - V.size() + 1, V.front()); 1251 EXPECT_EQ(1, V.back()); 1252 } 1253 1254 TYPED_TEST(SmallVectorReferenceInvalidationTest, AppendRange) { 1255 auto &V = this->V; 1256 (void)V; 1257 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST 1258 EXPECT_DEATH(V.append(V.begin(), V.begin() + 1), this->AssertionMessage); 1259 1260 ASSERT_EQ(3u, this->NumBuiltinElts(V)); 1261 ASSERT_EQ(3u, V.size()); 1262 V.pop_back(); 1263 ASSERT_EQ(2u, V.size()); 1264 1265 // Confirm this checks for growth when there's more than one element 1266 // appended. 1267 EXPECT_DEATH(V.append(V.begin(), V.end()), this->AssertionMessage); 1268 #endif 1269 } 1270 1271 TYPED_TEST(SmallVectorReferenceInvalidationTest, Assign) { 1272 // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode. 1273 auto &V = this->V; 1274 (void)V; 1275 int N = this->NumBuiltinElts(V); 1276 ASSERT_EQ(unsigned(N), V.size()); 1277 ASSERT_EQ(unsigned(N), V.capacity()); 1278 1279 // Check assign that shrinks in small mode. 1280 V.assign(1, V.back()); 1281 EXPECT_EQ(1u, V.size()); 1282 EXPECT_EQ(N, V[0]); 1283 1284 // Check assign that grows within small mode. 1285 ASSERT_LT(V.size(), V.capacity()); 1286 V.assign(V.capacity(), V.back()); 1287 for (int I = 0, E = V.size(); I != E; ++I) { 1288 EXPECT_EQ(N, V[I]); 1289 1290 // Reset to [1, 2, ...]. 1291 V[I] = I + 1; 1292 } 1293 1294 // Check assign that grows to large mode. 1295 ASSERT_EQ(2, V[1]); 1296 V.assign(V.capacity() + 1, V[1]); 1297 for (int I = 0, E = V.size(); I != E; ++I) { 1298 EXPECT_EQ(2, V[I]); 1299 1300 // Reset to [1, 2, ...]. 1301 V[I] = I + 1; 1302 } 1303 1304 // Check assign that shrinks in large mode. 1305 V.assign(1, V[1]); 1306 EXPECT_EQ(2, V[0]); 1307 } 1308 1309 TYPED_TEST(SmallVectorReferenceInvalidationTest, AssignRange) { 1310 auto &V = this->V; 1311 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST 1312 EXPECT_DEATH(V.assign(V.begin(), V.end()), this->AssertionMessage); 1313 EXPECT_DEATH(V.assign(V.begin(), V.end() - 1), this->AssertionMessage); 1314 #endif 1315 V.assign(V.begin(), V.begin()); 1316 EXPECT_TRUE(V.empty()); 1317 } 1318 1319 TYPED_TEST(SmallVectorReferenceInvalidationTest, Insert) { 1320 // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode. 1321 auto &V = this->V; 1322 (void)V; 1323 1324 // Insert a reference to the back (not at end() or else insert delegates to 1325 // push_back()), growing out of small mode. Confirm the value was copied out 1326 // (moving out Constructable sets it to 0). 1327 V.insert(V.begin(), V.back()); 1328 EXPECT_EQ(int(V.size() - 1), V.front()); 1329 EXPECT_EQ(int(V.size() - 1), V.back()); 1330 1331 // Fill up the vector again. 1332 while (V.size() < V.capacity()) 1333 V.push_back(V.size() + 1); 1334 1335 // Grow again from large storage to large storage. 1336 V.insert(V.begin(), V.back()); 1337 EXPECT_EQ(int(V.size() - 1), V.front()); 1338 EXPECT_EQ(int(V.size() - 1), V.back()); 1339 } 1340 1341 TYPED_TEST(SmallVectorReferenceInvalidationTest, InsertMoved) { 1342 // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode. 1343 auto &V = this->V; 1344 (void)V; 1345 1346 // Insert a reference to the back (not at end() or else insert delegates to 1347 // push_back()), growing out of small mode. Confirm the value was copied out 1348 // (moving out Constructable sets it to 0). 1349 V.insert(V.begin(), std::move(V.back())); 1350 EXPECT_EQ(int(V.size() - 1), V.front()); 1351 if (this->template isValueType<Constructable>()) { 1352 // Check the value got moved out. 1353 EXPECT_EQ(0, V.back()); 1354 } 1355 1356 // Fill up the vector again. 1357 while (V.size() < V.capacity()) 1358 V.push_back(V.size() + 1); 1359 1360 // Grow again from large storage to large storage. 1361 V.insert(V.begin(), std::move(V.back())); 1362 EXPECT_EQ(int(V.size() - 1), V.front()); 1363 if (this->template isValueType<Constructable>()) { 1364 // Check the value got moved out. 1365 EXPECT_EQ(0, V.back()); 1366 } 1367 } 1368 1369 TYPED_TEST(SmallVectorReferenceInvalidationTest, InsertN) { 1370 auto &V = this->V; 1371 (void)V; 1372 1373 // Cover NumToInsert <= this->end() - I. 1374 V.insert(V.begin() + 1, 1, V.back()); 1375 int N = this->NumBuiltinElts(V); 1376 EXPECT_EQ(N, V[1]); 1377 1378 // Cover NumToInsert > this->end() - I, inserting enough elements that V will 1379 // also grow again; V.capacity() will be more elements than necessary but 1380 // it's a simple way to cover both conditions. 1381 // 1382 // If reference invalidation breaks in the future, sanitizers should be able 1383 // to catch a use-after-free here. 1384 V.insert(V.begin(), V.capacity(), V.front()); 1385 EXPECT_EQ(1, V.front()); 1386 } 1387 1388 TYPED_TEST(SmallVectorReferenceInvalidationTest, InsertRange) { 1389 auto &V = this->V; 1390 (void)V; 1391 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST 1392 EXPECT_DEATH(V.insert(V.begin(), V.begin(), V.begin() + 1), 1393 this->AssertionMessage); 1394 1395 ASSERT_EQ(3u, this->NumBuiltinElts(V)); 1396 ASSERT_EQ(3u, V.size()); 1397 V.pop_back(); 1398 ASSERT_EQ(2u, V.size()); 1399 1400 // Confirm this checks for growth when there's more than one element 1401 // inserted. 1402 EXPECT_DEATH(V.insert(V.begin(), V.begin(), V.end()), this->AssertionMessage); 1403 #endif 1404 } 1405 1406 TYPED_TEST(SmallVectorReferenceInvalidationTest, EmplaceBack) { 1407 // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode. 1408 auto &V = this->V; 1409 int N = this->NumBuiltinElts(V); 1410 1411 // Push back a reference to last element when growing from small storage. 1412 V.emplace_back(V.back()); 1413 EXPECT_EQ(N, V.back()); 1414 1415 // Check that the old value is still there (not moved away). 1416 EXPECT_EQ(N, V[V.size() - 2]); 1417 1418 // Fill storage again. 1419 V.back() = V.size(); 1420 while (V.size() < V.capacity()) 1421 V.push_back(V.size() + 1); 1422 1423 // Push back a reference to last element when growing from large storage. 1424 V.emplace_back(V.back()); 1425 EXPECT_EQ(int(V.size()) - 1, V.back()); 1426 } 1427 1428 template <class VectorT> 1429 class SmallVectorInternalReferenceInvalidationTest 1430 : public SmallVectorTestBase { 1431 protected: 1432 const char *AssertionMessage = 1433 "Attempting to reference an element of the vector in an operation \" " 1434 "\"that invalidates it"; 1435 1436 VectorT V; 1437 1438 template <typename T, unsigned N> 1439 static unsigned NumBuiltinElts(const SmallVector<T, N> &) { 1440 return N; 1441 } 1442 1443 void SetUp() override { 1444 SmallVectorTestBase::SetUp(); 1445 1446 // Fill up the small size so that insertions move the elements. 1447 for (int I = 0, E = NumBuiltinElts(V); I != E; ++I) 1448 V.emplace_back(I + 1, I + 1); 1449 } 1450 }; 1451 1452 // Test pairs of the same types from SmallVectorReferenceInvalidationTestTypes. 1453 using SmallVectorInternalReferenceInvalidationTestTypes = 1454 ::testing::Types<SmallVector<std::pair<int, int>, 3>, 1455 SmallVector<std::pair<Constructable, Constructable>, 3>>; 1456 1457 TYPED_TEST_SUITE(SmallVectorInternalReferenceInvalidationTest, 1458 SmallVectorInternalReferenceInvalidationTestTypes, ); 1459 1460 TYPED_TEST(SmallVectorInternalReferenceInvalidationTest, EmplaceBack) { 1461 // Note: setup adds [1, 2, ...] to V until it's at capacity in small mode. 1462 auto &V = this->V; 1463 int N = this->NumBuiltinElts(V); 1464 1465 // Push back a reference to last element when growing from small storage. 1466 V.emplace_back(V.back().first, V.back().second); 1467 EXPECT_EQ(N, V.back().first); 1468 EXPECT_EQ(N, V.back().second); 1469 1470 // Check that the old value is still there (not moved away). 1471 EXPECT_EQ(N, V[V.size() - 2].first); 1472 EXPECT_EQ(N, V[V.size() - 2].second); 1473 1474 // Fill storage again. 1475 V.back().first = V.back().second = V.size(); 1476 while (V.size() < V.capacity()) 1477 V.emplace_back(V.size() + 1, V.size() + 1); 1478 1479 // Push back a reference to last element when growing from large storage. 1480 V.emplace_back(V.back().first, V.back().second); 1481 EXPECT_EQ(int(V.size()) - 1, V.back().first); 1482 EXPECT_EQ(int(V.size()) - 1, V.back().second); 1483 } 1484 1485 } // end namespace 1486