1 //===- llvm/unittest/ADT/StringMapMap.cpp - StringMap unit tests ----------===// 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 #include "llvm/ADT/StringMap.h" 10 #include "llvm/ADT/STLExtras.h" 11 #include "llvm/ADT/Twine.h" 12 #include "llvm/Support/DataTypes.h" 13 #include "gtest/gtest.h" 14 #include <limits> 15 #include <tuple> 16 using namespace llvm; 17 18 namespace { 19 20 static_assert(sizeof(StringMap<uint32_t>) < 21 sizeof(StringMap<uint32_t, MallocAllocator &>), 22 "Ensure empty base optimization happens with default allocator"); 23 24 // Test fixture 25 class StringMapTest : public testing::Test { 26 protected: 27 StringMap<uint32_t> testMap; 28 29 static const char testKey[]; 30 static const uint32_t testValue; 31 static const char *testKeyFirst; 32 static size_t testKeyLength; 33 static const std::string testKeyStr; 34 35 void assertEmptyMap() { 36 // Size tests 37 EXPECT_EQ(0u, testMap.size()); 38 EXPECT_TRUE(testMap.empty()); 39 40 // Iterator tests 41 EXPECT_TRUE(testMap.begin() == testMap.end()); 42 43 // Lookup tests 44 EXPECT_FALSE(testMap.contains(testKey)); 45 EXPECT_EQ(0u, testMap.count(testKey)); 46 EXPECT_EQ(0u, testMap.count(StringRef(testKeyFirst, testKeyLength))); 47 EXPECT_EQ(0u, testMap.count(testKeyStr)); 48 EXPECT_TRUE(testMap.find(testKey) == testMap.end()); 49 EXPECT_TRUE(testMap.find(StringRef(testKeyFirst, testKeyLength)) == 50 testMap.end()); 51 EXPECT_TRUE(testMap.find(testKeyStr) == testMap.end()); 52 } 53 54 void assertSingleItemMap() { 55 // Size tests 56 EXPECT_EQ(1u, testMap.size()); 57 EXPECT_FALSE(testMap.begin() == testMap.end()); 58 EXPECT_FALSE(testMap.empty()); 59 60 // Iterator tests 61 StringMap<uint32_t>::iterator it = testMap.begin(); 62 EXPECT_STREQ(testKey, it->first().data()); 63 EXPECT_EQ(testValue, it->second); 64 ++it; 65 EXPECT_TRUE(it == testMap.end()); 66 67 // Lookup tests 68 EXPECT_TRUE(testMap.contains(testKey)); 69 EXPECT_EQ(1u, testMap.count(testKey)); 70 EXPECT_EQ(1u, testMap.count(StringRef(testKeyFirst, testKeyLength))); 71 EXPECT_EQ(1u, testMap.count(testKeyStr)); 72 EXPECT_TRUE(testMap.find(testKey) == testMap.begin()); 73 EXPECT_TRUE(testMap.find(StringRef(testKeyFirst, testKeyLength)) == 74 testMap.begin()); 75 EXPECT_TRUE(testMap.find(testKeyStr) == testMap.begin()); 76 } 77 }; 78 79 const char StringMapTest::testKey[] = "key"; 80 const uint32_t StringMapTest::testValue = 1u; 81 const char *StringMapTest::testKeyFirst = testKey; 82 size_t StringMapTest::testKeyLength = sizeof(testKey) - 1; 83 const std::string StringMapTest::testKeyStr(testKey); 84 85 struct CountCopyAndMove { 86 CountCopyAndMove() = default; 87 CountCopyAndMove(const CountCopyAndMove &) { copy = 1; } 88 CountCopyAndMove(CountCopyAndMove &&) { move = 1; } 89 void operator=(const CountCopyAndMove &) { ++copy; } 90 void operator=(CountCopyAndMove &&) { ++move; } 91 int copy = 0; 92 int move = 0; 93 }; 94 95 // Empty map tests. 96 TEST_F(StringMapTest, EmptyMapTest) { assertEmptyMap(); } 97 98 // Constant map tests. 99 TEST_F(StringMapTest, ConstEmptyMapTest) { 100 const StringMap<uint32_t> &constTestMap = testMap; 101 102 // Size tests 103 EXPECT_EQ(0u, constTestMap.size()); 104 EXPECT_TRUE(constTestMap.empty()); 105 106 // Iterator tests 107 EXPECT_TRUE(constTestMap.begin() == constTestMap.end()); 108 109 // Lookup tests 110 EXPECT_EQ(0u, constTestMap.count(testKey)); 111 EXPECT_EQ(0u, constTestMap.count(StringRef(testKeyFirst, testKeyLength))); 112 EXPECT_EQ(0u, constTestMap.count(testKeyStr)); 113 EXPECT_TRUE(constTestMap.find(testKey) == constTestMap.end()); 114 EXPECT_TRUE(constTestMap.find(StringRef(testKeyFirst, testKeyLength)) == 115 constTestMap.end()); 116 EXPECT_TRUE(constTestMap.find(testKeyStr) == constTestMap.end()); 117 } 118 119 // initializer_list ctor test; also implicitly tests initializer_list and 120 // iterator overloads of insert(). 121 TEST_F(StringMapTest, InitializerListCtor) { 122 testMap = StringMap<uint32_t>({{"key", 1}}); 123 assertSingleItemMap(); 124 } 125 126 // A map with a single entry. 127 TEST_F(StringMapTest, SingleEntryMapTest) { 128 testMap[testKey] = testValue; 129 assertSingleItemMap(); 130 } 131 132 // Test clear() method. 133 TEST_F(StringMapTest, ClearTest) { 134 testMap[testKey] = testValue; 135 testMap.clear(); 136 assertEmptyMap(); 137 } 138 139 // Test erase(iterator) method. 140 TEST_F(StringMapTest, EraseIteratorTest) { 141 testMap[testKey] = testValue; 142 testMap.erase(testMap.begin()); 143 assertEmptyMap(); 144 } 145 146 // Test erase(value) method. 147 TEST_F(StringMapTest, EraseValueTest) { 148 testMap[testKey] = testValue; 149 testMap.erase(testKey); 150 assertEmptyMap(); 151 } 152 153 // Test inserting two values and erasing one. 154 TEST_F(StringMapTest, InsertAndEraseTest) { 155 testMap[testKey] = testValue; 156 testMap["otherKey"] = 2; 157 testMap.erase("otherKey"); 158 assertSingleItemMap(); 159 } 160 161 TEST_F(StringMapTest, SmallFullMapTest) { 162 // StringMap has a tricky corner case when the map is small (<8 buckets) and 163 // it fills up through a balanced pattern of inserts and erases. This can 164 // lead to inf-loops in some cases (PR13148) so we test it explicitly here. 165 llvm::StringMap<int> Map(2); 166 167 Map["eins"] = 1; 168 Map["zwei"] = 2; 169 Map["drei"] = 3; 170 Map.erase("drei"); 171 Map.erase("eins"); 172 Map["veir"] = 4; 173 Map["funf"] = 5; 174 175 EXPECT_EQ(3u, Map.size()); 176 EXPECT_EQ(0, Map.lookup("eins")); 177 EXPECT_EQ(2, Map.lookup("zwei")); 178 EXPECT_EQ(0, Map.lookup("drei")); 179 EXPECT_EQ(4, Map.lookup("veir")); 180 EXPECT_EQ(5, Map.lookup("funf")); 181 } 182 183 TEST_F(StringMapTest, CopyCtorTest) { 184 llvm::StringMap<int> Map; 185 186 Map["eins"] = 1; 187 Map["zwei"] = 2; 188 Map["drei"] = 3; 189 Map.erase("drei"); 190 Map.erase("eins"); 191 Map["veir"] = 4; 192 Map["funf"] = 5; 193 194 EXPECT_EQ(3u, Map.size()); 195 EXPECT_EQ(0, Map.lookup("eins")); 196 EXPECT_EQ(2, Map.lookup("zwei")); 197 EXPECT_EQ(0, Map.lookup("drei")); 198 EXPECT_EQ(4, Map.lookup("veir")); 199 EXPECT_EQ(5, Map.lookup("funf")); 200 201 llvm::StringMap<int> Map2(Map); 202 EXPECT_EQ(3u, Map2.size()); 203 EXPECT_EQ(0, Map2.lookup("eins")); 204 EXPECT_EQ(2, Map2.lookup("zwei")); 205 EXPECT_EQ(0, Map2.lookup("drei")); 206 EXPECT_EQ(4, Map2.lookup("veir")); 207 EXPECT_EQ(5, Map2.lookup("funf")); 208 } 209 210 TEST_F(StringMapTest, AtTest) { 211 llvm::StringMap<int> Map; 212 213 // keys both found and not found on non-empty map 214 Map["a"] = 1; 215 Map["b"] = 2; 216 Map["c"] = 3; 217 EXPECT_EQ(1, Map.at("a")); 218 EXPECT_EQ(2, Map.at("b")); 219 EXPECT_EQ(3, Map.at("c")); 220 } 221 222 // A more complex iteration test. 223 TEST_F(StringMapTest, IterationTest) { 224 bool visited[100]; 225 226 // Insert 100 numbers into the map 227 for (int i = 0; i < 100; ++i) { 228 std::stringstream ss; 229 ss << "key_" << i; 230 testMap[ss.str()] = i; 231 visited[i] = false; 232 } 233 234 // Iterate over all numbers and mark each one found. 235 for (StringMap<uint32_t>::iterator it = testMap.begin(); it != testMap.end(); 236 ++it) { 237 std::stringstream ss; 238 ss << "key_" << it->second; 239 ASSERT_STREQ(ss.str().c_str(), it->first().data()); 240 visited[it->second] = true; 241 } 242 243 // Ensure every number was visited. 244 for (int i = 0; i < 100; ++i) { 245 ASSERT_TRUE(visited[i]) << "Entry #" << i << " was never visited"; 246 } 247 } 248 249 // Test StringMapEntry::Create() method. 250 TEST_F(StringMapTest, StringMapEntryTest) { 251 MallocAllocator Allocator; 252 StringMap<uint32_t>::value_type *entry = 253 StringMap<uint32_t>::value_type::create( 254 StringRef(testKeyFirst, testKeyLength), Allocator, 1u); 255 EXPECT_STREQ(testKey, entry->first().data()); 256 EXPECT_EQ(1u, entry->second); 257 entry->Destroy(Allocator); 258 } 259 260 // Test insert() method. 261 TEST_F(StringMapTest, InsertTest) { 262 SCOPED_TRACE("InsertTest"); 263 testMap.insert(StringMap<uint32_t>::value_type::create( 264 StringRef(testKeyFirst, testKeyLength), testMap.getAllocator(), 1u)); 265 assertSingleItemMap(); 266 } 267 268 // Test insert(pair<K, V>) method 269 TEST_F(StringMapTest, InsertPairTest) { 270 bool Inserted; 271 StringMap<uint32_t>::iterator NewIt; 272 std::tie(NewIt, Inserted) = 273 testMap.insert(std::make_pair(testKeyFirst, testValue)); 274 EXPECT_EQ(1u, testMap.size()); 275 EXPECT_EQ(testValue, testMap[testKeyFirst]); 276 EXPECT_EQ(testKeyFirst, NewIt->first()); 277 EXPECT_EQ(testValue, NewIt->second); 278 EXPECT_TRUE(Inserted); 279 280 StringMap<uint32_t>::iterator ExistingIt; 281 std::tie(ExistingIt, Inserted) = 282 testMap.insert(std::make_pair(testKeyFirst, testValue + 1)); 283 EXPECT_EQ(1u, testMap.size()); 284 EXPECT_EQ(testValue, testMap[testKeyFirst]); 285 EXPECT_FALSE(Inserted); 286 EXPECT_EQ(NewIt, ExistingIt); 287 } 288 289 // Test insert(pair<K, V>) method when rehashing occurs 290 TEST_F(StringMapTest, InsertRehashingPairTest) { 291 // Check that the correct iterator is returned when the inserted element is 292 // moved to a different bucket during internal rehashing. This depends on 293 // the particular key, and the implementation of StringMap and HashString. 294 // Changes to those might result in this test not actually checking that. 295 StringMap<uint32_t> t(0); 296 EXPECT_EQ(0u, t.getNumBuckets()); 297 298 StringMap<uint32_t>::iterator It = 299 t.insert(std::make_pair("abcdef", 42)).first; 300 EXPECT_EQ(16u, t.getNumBuckets()); 301 EXPECT_EQ("abcdef", It->first()); 302 EXPECT_EQ(42u, It->second); 303 } 304 305 TEST_F(StringMapTest, InsertOrAssignTest) { 306 struct A : CountCopyAndMove { 307 A(int v) : v(v) {} 308 int v; 309 }; 310 StringMap<A> t(0); 311 312 auto try1 = t.insert_or_assign("A", A(1)); 313 EXPECT_TRUE(try1.second); 314 EXPECT_EQ(1, try1.first->second.v); 315 EXPECT_EQ(1, try1.first->second.move); 316 317 auto try2 = t.insert_or_assign("A", A(2)); 318 EXPECT_FALSE(try2.second); 319 EXPECT_EQ(2, try2.first->second.v); 320 EXPECT_EQ(2, try1.first->second.move); 321 322 EXPECT_EQ(try1.first, try2.first); 323 EXPECT_EQ(0, try1.first->second.copy); 324 } 325 326 TEST_F(StringMapTest, IterMapKeysVector) { 327 StringMap<int> Map; 328 Map["A"] = 1; 329 Map["B"] = 2; 330 Map["C"] = 3; 331 Map["D"] = 3; 332 333 std::vector<StringRef> Keys{Map.keys().begin(), Map.keys().end()}; 334 llvm::sort(Keys); 335 336 std::vector<StringRef> Expected{{"A", "B", "C", "D"}}; 337 EXPECT_EQ(Expected, Keys); 338 } 339 340 TEST_F(StringMapTest, IterMapKeysSmallVector) { 341 StringMap<int> Map; 342 Map["A"] = 1; 343 Map["B"] = 2; 344 Map["C"] = 3; 345 Map["D"] = 3; 346 347 auto Keys = to_vector<4>(Map.keys()); 348 llvm::sort(Keys); 349 350 SmallVector<StringRef, 4> Expected = {"A", "B", "C", "D"}; 351 EXPECT_EQ(Expected, Keys); 352 } 353 354 // Create a non-default constructable value 355 struct StringMapTestStruct { 356 StringMapTestStruct(int i) : i(i) {} 357 StringMapTestStruct() = delete; 358 int i; 359 }; 360 361 TEST_F(StringMapTest, NonDefaultConstructable) { 362 StringMap<StringMapTestStruct> t; 363 t.insert(std::make_pair("Test", StringMapTestStruct(123))); 364 StringMap<StringMapTestStruct>::iterator iter = t.find("Test"); 365 ASSERT_NE(iter, t.end()); 366 ASSERT_EQ(iter->second.i, 123); 367 } 368 369 struct Immovable { 370 Immovable() {} 371 Immovable(Immovable &&) = delete; // will disable the other special members 372 }; 373 374 struct MoveOnly { 375 int i; 376 MoveOnly(int i) : i(i) {} 377 MoveOnly(const Immovable &) : i(0) {} 378 MoveOnly(MoveOnly &&RHS) : i(RHS.i) {} 379 MoveOnly &operator=(MoveOnly &&RHS) { 380 i = RHS.i; 381 return *this; 382 } 383 384 bool operator==(const MoveOnly &RHS) const { return i == RHS.i; } 385 bool operator!=(const MoveOnly &RHS) const { return i != RHS.i; } 386 387 private: 388 MoveOnly(const MoveOnly &) = delete; 389 MoveOnly &operator=(const MoveOnly &) = delete; 390 }; 391 392 TEST_F(StringMapTest, MoveOnly) { 393 StringMap<MoveOnly> t; 394 t.insert(std::make_pair("Test", MoveOnly(42))); 395 StringRef Key = "Test"; 396 StringMapEntry<MoveOnly>::create(Key, t.getAllocator(), MoveOnly(42)) 397 ->Destroy(t.getAllocator()); 398 } 399 400 TEST_F(StringMapTest, CtorArg) { 401 StringRef Key = "Test"; 402 MallocAllocator Allocator; 403 StringMapEntry<MoveOnly>::create(Key, Allocator, Immovable()) 404 ->Destroy(Allocator); 405 } 406 407 TEST_F(StringMapTest, MoveConstruct) { 408 StringMap<int> A; 409 A["x"] = 42; 410 StringMap<int> B = std::move(A); 411 ASSERT_EQ(A.size(), 0u); 412 ASSERT_EQ(B.size(), 1u); 413 ASSERT_EQ(B["x"], 42); 414 ASSERT_EQ(B.count("y"), 0u); 415 } 416 417 TEST_F(StringMapTest, MoveAssignment) { 418 StringMap<int> A; 419 A["x"] = 42; 420 StringMap<int> B; 421 B["y"] = 117; 422 A = std::move(B); 423 ASSERT_EQ(A.size(), 1u); 424 ASSERT_EQ(B.size(), 0u); 425 ASSERT_EQ(A["y"], 117); 426 ASSERT_EQ(B.count("x"), 0u); 427 } 428 429 TEST_F(StringMapTest, EqualEmpty) { 430 StringMap<int> A; 431 StringMap<int> B; 432 ASSERT_TRUE(A == B); 433 ASSERT_FALSE(A != B); 434 ASSERT_TRUE(A == A); // self check 435 } 436 437 TEST_F(StringMapTest, EqualWithValues) { 438 StringMap<int> A; 439 A["A"] = 1; 440 A["B"] = 2; 441 A["C"] = 3; 442 A["D"] = 3; 443 444 StringMap<int> B; 445 B["A"] = 1; 446 B["B"] = 2; 447 B["C"] = 3; 448 B["D"] = 3; 449 450 ASSERT_TRUE(A == B); 451 ASSERT_TRUE(B == A); 452 ASSERT_FALSE(A != B); 453 ASSERT_FALSE(B != A); 454 ASSERT_TRUE(A == A); // self check 455 } 456 457 TEST_F(StringMapTest, NotEqualMissingKeys) { 458 StringMap<int> A; 459 A["A"] = 1; 460 A["B"] = 2; 461 462 StringMap<int> B; 463 B["A"] = 1; 464 B["B"] = 2; 465 B["C"] = 3; 466 B["D"] = 3; 467 468 ASSERT_FALSE(A == B); 469 ASSERT_FALSE(B == A); 470 ASSERT_TRUE(A != B); 471 ASSERT_TRUE(B != A); 472 } 473 474 TEST_F(StringMapTest, NotEqualWithDifferentValues) { 475 StringMap<int> A; 476 A["A"] = 1; 477 A["B"] = 2; 478 A["C"] = 100; 479 A["D"] = 3; 480 481 StringMap<int> B; 482 B["A"] = 1; 483 B["B"] = 2; 484 B["C"] = 3; 485 B["D"] = 3; 486 487 ASSERT_FALSE(A == B); 488 ASSERT_FALSE(B == A); 489 ASSERT_TRUE(A != B); 490 ASSERT_TRUE(B != A); 491 } 492 493 TEST_F(StringMapTest, PrecomputedHash) { 494 StringMap<int> A; 495 StringRef Key = "foo"; 496 int Value = 42; 497 uint64_t Hash = StringMap<int>::hash(Key); 498 A.insert({"foo", Value}, Hash); 499 auto I = A.find(Key, Hash); 500 ASSERT_NE(I, A.end()); 501 ASSERT_EQ(I->second, Value); 502 } 503 504 struct Countable { 505 int &InstanceCount; 506 int Number; 507 Countable(int Number, int &InstanceCount) 508 : InstanceCount(InstanceCount), Number(Number) { 509 ++InstanceCount; 510 } 511 Countable(Countable &&C) : InstanceCount(C.InstanceCount), Number(C.Number) { 512 ++InstanceCount; 513 C.Number = -1; 514 } 515 Countable(const Countable &C) 516 : InstanceCount(C.InstanceCount), Number(C.Number) { 517 ++InstanceCount; 518 } 519 Countable &operator=(Countable C) { 520 Number = C.Number; 521 return *this; 522 } 523 ~Countable() { --InstanceCount; } 524 }; 525 526 TEST_F(StringMapTest, MoveDtor) { 527 int InstanceCount = 0; 528 StringMap<Countable> A; 529 A.insert(std::make_pair("x", Countable(42, InstanceCount))); 530 ASSERT_EQ(InstanceCount, 1); 531 auto I = A.find("x"); 532 ASSERT_NE(I, A.end()); 533 ASSERT_EQ(I->second.Number, 42); 534 535 StringMap<Countable> B; 536 B = std::move(A); 537 ASSERT_EQ(InstanceCount, 1); 538 ASSERT_TRUE(A.empty()); 539 I = B.find("x"); 540 ASSERT_NE(I, B.end()); 541 ASSERT_EQ(I->second.Number, 42); 542 543 B = StringMap<Countable>(); 544 ASSERT_EQ(InstanceCount, 0); 545 ASSERT_TRUE(B.empty()); 546 } 547 548 TEST_F(StringMapTest, StructuredBindings) { 549 StringMap<int> A; 550 A["a"] = 42; 551 552 for (auto &[Key, Value] : A) { 553 EXPECT_EQ("a", Key); 554 EXPECT_EQ(42, Value); 555 } 556 557 for (const auto &[Key, Value] : A) { 558 EXPECT_EQ("a", Key); 559 EXPECT_EQ(42, Value); 560 } 561 } 562 563 TEST_F(StringMapTest, StructuredBindingsMoveOnly) { 564 StringMap<MoveOnly> A; 565 A.insert(std::make_pair("a", MoveOnly(42))); 566 567 for (auto &[Key, Value] : A) { 568 EXPECT_EQ("a", Key); 569 EXPECT_EQ(MoveOnly(42), Value); 570 } 571 572 for (const auto &[Key, Value] : A) { 573 EXPECT_EQ("a", Key); 574 EXPECT_EQ(MoveOnly(42), Value); 575 } 576 } 577 578 namespace { 579 // Simple class that counts how many moves and copy happens when growing a map 580 struct CountCtorCopyAndMove { 581 static unsigned Ctor; 582 static unsigned Move; 583 static unsigned Copy; 584 int Data = 0; 585 CountCtorCopyAndMove(int Data) : Data(Data) { Ctor++; } 586 CountCtorCopyAndMove() { Ctor++; } 587 588 CountCtorCopyAndMove(const CountCtorCopyAndMove &) { Copy++; } 589 CountCtorCopyAndMove &operator=(const CountCtorCopyAndMove &) { 590 Copy++; 591 return *this; 592 } 593 CountCtorCopyAndMove(CountCtorCopyAndMove &&) { Move++; } 594 CountCtorCopyAndMove &operator=(const CountCtorCopyAndMove &&) { 595 Move++; 596 return *this; 597 } 598 }; 599 unsigned CountCtorCopyAndMove::Copy = 0; 600 unsigned CountCtorCopyAndMove::Move = 0; 601 unsigned CountCtorCopyAndMove::Ctor = 0; 602 603 } // anonymous namespace 604 605 // Make sure creating the map with an initial size of N actually gives us enough 606 // buckets to insert N items without increasing allocation size. 607 TEST(StringMapCustomTest, InitialSizeTest) { 608 // 1 is an "edge value", 32 is an arbitrary power of two, and 67 is an 609 // arbitrary prime, picked without any good reason. 610 for (auto Size : {1, 32, 67}) { 611 StringMap<CountCtorCopyAndMove> Map(Size); 612 auto NumBuckets = Map.getNumBuckets(); 613 CountCtorCopyAndMove::Move = 0; 614 CountCtorCopyAndMove::Copy = 0; 615 for (int i = 0; i < Size; ++i) 616 Map.insert(std::pair<std::string, CountCtorCopyAndMove>( 617 std::piecewise_construct, std::forward_as_tuple(Twine(i).str()), 618 std::forward_as_tuple(i))); 619 // After the initial move, the map will move the Elts in the Entry. 620 EXPECT_EQ((unsigned)Size * 2, CountCtorCopyAndMove::Move); 621 // We copy once the pair from the Elts vector 622 EXPECT_EQ(0u, CountCtorCopyAndMove::Copy); 623 // Check that the map didn't grow 624 EXPECT_EQ(Map.getNumBuckets(), NumBuckets); 625 } 626 } 627 628 TEST(StringMapCustomTest, BracketOperatorCtor) { 629 StringMap<CountCtorCopyAndMove> Map; 630 CountCtorCopyAndMove::Ctor = 0; 631 Map["abcd"]; 632 EXPECT_EQ(1u, CountCtorCopyAndMove::Ctor); 633 // Test that operator[] does not create a value when it is already in the map 634 CountCtorCopyAndMove::Ctor = 0; 635 Map["abcd"]; 636 EXPECT_EQ(0u, CountCtorCopyAndMove::Ctor); 637 } 638 639 namespace { 640 struct NonMoveableNonCopyableType { 641 int Data = 0; 642 NonMoveableNonCopyableType() = default; 643 NonMoveableNonCopyableType(int Data) : Data(Data) {} 644 NonMoveableNonCopyableType(const NonMoveableNonCopyableType &) = delete; 645 NonMoveableNonCopyableType(NonMoveableNonCopyableType &&) = delete; 646 }; 647 } // namespace 648 649 // Test that we can "emplace" an element in the map without involving map/move 650 TEST(StringMapCustomTest, EmplaceTest) { 651 StringMap<NonMoveableNonCopyableType> Map; 652 Map.try_emplace("abcd", 42); 653 EXPECT_EQ(1u, Map.count("abcd")); 654 EXPECT_EQ(42, Map["abcd"].Data); 655 } 656 657 // Test that StringMapEntryBase can handle size_t wide sizes. 658 TEST(StringMapCustomTest, StringMapEntryBaseSize) { 659 size_t LargeValue; 660 661 // Test that the entry can represent max-unsigned. 662 if (sizeof(size_t) <= sizeof(unsigned)) 663 LargeValue = std::numeric_limits<unsigned>::max(); 664 else 665 LargeValue = std::numeric_limits<unsigned>::max() + 1ULL; 666 StringMapEntryBase LargeBase(LargeValue); 667 EXPECT_EQ(LargeValue, LargeBase.getKeyLength()); 668 669 // Test that the entry can hold at least max size_t. 670 LargeValue = std::numeric_limits<size_t>::max(); 671 StringMapEntryBase LargerBase(LargeValue); 672 LargeValue = std::numeric_limits<size_t>::max(); 673 EXPECT_EQ(LargeValue, LargerBase.getKeyLength()); 674 } 675 676 // Test that StringMapEntry can handle size_t wide sizes. 677 TEST(StringMapCustomTest, StringMapEntrySize) { 678 size_t LargeValue; 679 680 // Test that the entry can represent max-unsigned. 681 if (sizeof(size_t) <= sizeof(unsigned)) 682 LargeValue = std::numeric_limits<unsigned>::max(); 683 else 684 LargeValue = std::numeric_limits<unsigned>::max() + 1ULL; 685 StringMapEntry<int> LargeEntry(LargeValue); 686 StringRef Key = LargeEntry.getKey(); 687 EXPECT_EQ(LargeValue, Key.size()); 688 689 // Test that the entry can hold at least max size_t. 690 LargeValue = std::numeric_limits<size_t>::max(); 691 StringMapEntry<int> LargerEntry(LargeValue); 692 Key = LargerEntry.getKey(); 693 EXPECT_EQ(LargeValue, Key.size()); 694 } 695 696 } // end anonymous namespace 697