751 lines · cpp
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-exception6//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>16using namespace llvm;17 18namespace {19 20static_assert(sizeof(StringMap<uint32_t>) <21 sizeof(StringMap<uint32_t, MallocAllocator &>),22 "Ensure empty base optimization happens with default allocator");23 24// Test fixture25class StringMapTest : public testing::Test {26protected: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 tests37 EXPECT_EQ(0u, testMap.size());38 EXPECT_TRUE(testMap.empty());39 40 // Iterator tests41 EXPECT_TRUE(testMap.begin() == testMap.end());42 43 // Lookup tests44 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 tests56 EXPECT_EQ(1u, testMap.size());57 EXPECT_FALSE(testMap.begin() == testMap.end());58 EXPECT_FALSE(testMap.empty());59 60 // Iterator tests61 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 tests68 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 79const char StringMapTest::testKey[] = "key";80const uint32_t StringMapTest::testValue = 1u;81const char *StringMapTest::testKeyFirst = testKey;82size_t StringMapTest::testKeyLength = sizeof(testKey) - 1;83const std::string StringMapTest::testKeyStr(testKey);84 85struct 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.96TEST_F(StringMapTest, EmptyMapTest) { assertEmptyMap(); }97 98// Constant map tests.99TEST_F(StringMapTest, ConstEmptyMapTest) {100 const StringMap<uint32_t> &constTestMap = testMap;101 102 // Size tests103 EXPECT_EQ(0u, constTestMap.size());104 EXPECT_TRUE(constTestMap.empty());105 106 // Iterator tests107 EXPECT_TRUE(constTestMap.begin() == constTestMap.end());108 109 // Lookup tests110 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 and120// iterator overloads of insert().121TEST_F(StringMapTest, InitializerListCtor) {122 testMap = StringMap<uint32_t>({{"key", 1}});123 assertSingleItemMap();124}125 126// A map with a single entry.127TEST_F(StringMapTest, SingleEntryMapTest) {128 testMap[testKey] = testValue;129 assertSingleItemMap();130}131 132// Test clear() method.133TEST_F(StringMapTest, ClearTest) {134 testMap[testKey] = testValue;135 testMap.clear();136 assertEmptyMap();137}138 139// Test erase(iterator) method.140TEST_F(StringMapTest, EraseIteratorTest) {141 testMap[testKey] = testValue;142 testMap.erase(testMap.begin());143 assertEmptyMap();144}145 146// Test erase(value) method.147TEST_F(StringMapTest, EraseValueTest) {148 testMap[testKey] = testValue;149 testMap.erase(testKey);150 assertEmptyMap();151}152 153// Test inserting two values and erasing one.154TEST_F(StringMapTest, InsertAndEraseTest) {155 testMap[testKey] = testValue;156 testMap["otherKey"] = 2;157 testMap.erase("otherKey");158 assertSingleItemMap();159}160 161TEST_F(StringMapTest, SmallFullMapTest) {162 // StringMap has a tricky corner case when the map is small (<8 buckets) and163 // it fills up through a balanced pattern of inserts and erases. This can164 // 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 183TEST_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 210TEST_F(StringMapTest, AtTest) {211 llvm::StringMap<int> Map;212 213 // keys both found and not found on non-empty map214 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.223TEST_F(StringMapTest, IterationTest) {224 bool visited[100];225 226 // Insert 100 numbers into the map227 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.250TEST_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.261TEST_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>) method269TEST_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 occurs290TEST_F(StringMapTest, InsertRehashingPairTest) {291 // Check that the correct iterator is returned when the inserted element is292 // moved to a different bucket during internal rehashing. This depends on293 // 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 305TEST_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 326TEST_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 340TEST_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 value355struct StringMapTestStruct {356 StringMapTestStruct(int i) : i(i) {}357 StringMapTestStruct() = delete;358 int i;359};360 361TEST_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 369struct Immovable {370 Immovable() = default;371 Immovable(Immovable &&) = delete; // will disable the other special members372};373 374struct 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 387private:388 MoveOnly(const MoveOnly &) = delete;389 MoveOnly &operator=(const MoveOnly &) = delete;390};391 392TEST_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 400TEST_F(StringMapTest, CtorArg) {401 StringRef Key = "Test";402 MallocAllocator Allocator;403 StringMapEntry<MoveOnly>::create(Key, Allocator, Immovable())404 ->Destroy(Allocator);405}406 407TEST_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 417TEST_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 429TEST_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 check435}436 437TEST_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 check455}456 457TEST_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 474TEST_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 493TEST_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 504struct 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 526TEST_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 548TEST_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 563TEST_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 578namespace {579// Simple class that counts how many moves and copy happens when growing a map580struct 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};599unsigned CountCtorCopyAndMove::Copy = 0;600unsigned CountCtorCopyAndMove::Move = 0;601unsigned CountCtorCopyAndMove::Ctor = 0;602 603} // anonymous namespace604 605// Make sure creating the map with an initial size of N actually gives us enough606// buckets to insert N items without increasing allocation size.607TEST(StringMapCustomTest, InitialSizeTest) {608 // 1 is an "edge value", 32 is an arbitrary power of two, and 67 is an609 // 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 vector622 EXPECT_EQ(0u, CountCtorCopyAndMove::Copy);623 // Check that the map didn't grow624 EXPECT_EQ(Map.getNumBuckets(), NumBuckets);625 }626}627 628TEST(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 map634 CountCtorCopyAndMove::Ctor = 0;635 Map["abcd"];636 EXPECT_EQ(0u, CountCtorCopyAndMove::Ctor);637}638 639namespace {640struct 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} // namespace648 649// Test that we can "emplace" an element in the map without involving map/move650TEST(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.658TEST(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 else665 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.677TEST(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 else684 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 696TEST(StringMapCustomTest, NonConstIterator) {697 StringMap<int> Map;698 Map["key"] = 1;699 700 // Check that Map.begin() returns a non-const iterator.701 static_assert(702 std::is_same_v<decltype(Map.begin()), StringMap<int>::iterator>);703 704 // Check that the value_type of a non-const iterator is not a const type.705 static_assert(706 !std::is_const_v<StringMap<int>::iterator::value_type>,707 "The value_type of a non-const iterator should not be a const type.");708 709 // Check that pointer and reference types are not const.710 static_assert(std::is_same_v<StringMap<int>::iterator::pointer,711 StringMap<int>::iterator::value_type *>);712 static_assert(std::is_same_v<StringMap<int>::iterator::reference,713 StringMap<int>::iterator::value_type &>);714 715 // Check that we can construct a const_iterator from an iterator.716 static_assert(std::is_constructible_v<StringMap<int>::const_iterator,717 StringMap<int>::iterator>);718 719 // Double check that we can actually construct a const_iterator.720 StringMap<int>::const_iterator const_it = Map.begin();721 (void)const_it;722}723 724TEST(StringMapCustomTest, ConstIterator) {725 StringMap<int> Map;726 const StringMap<int> &ConstMap = Map;727 728 // Check that ConstMap.begin() returns a const_iterator.729 static_assert(std::is_same_v<decltype(ConstMap.begin()),730 StringMap<int>::const_iterator>);731 732 // Check that the value_type of a const iterator is not a const type.733 static_assert(734 !std::is_const_v<StringMap<int>::const_iterator::value_type>,735 "The value_type of a const iterator should not be a const type.");736 737 // Check that pointer and reference types are const.738 static_assert(739 std::is_same_v<StringMap<int>::const_iterator::pointer,740 const StringMap<int>::const_iterator::value_type *>);741 static_assert(742 std::is_same_v<StringMap<int>::const_iterator::reference,743 const StringMap<int>::const_iterator::value_type &>);744 745 // Check that we cannot construct an iterator from a const_iterator.746 static_assert(!std::is_constructible_v<StringMap<int>::iterator,747 StringMap<int>::const_iterator>);748}749 750} // end anonymous namespace751