xref: /llvm-project/llvm/unittests/ADT/StringMapTest.cpp (revision a565509308f9372c4de1c4c32afde461a42e81c8)
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_EQ(0u, testMap.count(testKey));
45     EXPECT_EQ(0u, testMap.count(StringRef(testKeyFirst, testKeyLength)));
46     EXPECT_EQ(0u, testMap.count(testKeyStr));
47     EXPECT_TRUE(testMap.find(testKey) == testMap.end());
48     EXPECT_TRUE(testMap.find(StringRef(testKeyFirst, testKeyLength)) ==
49                 testMap.end());
50     EXPECT_TRUE(testMap.find(testKeyStr) == testMap.end());
51   }
52 
53   void assertSingleItemMap() {
54     // Size tests
55     EXPECT_EQ(1u, testMap.size());
56     EXPECT_FALSE(testMap.begin() == testMap.end());
57     EXPECT_FALSE(testMap.empty());
58 
59     // Iterator tests
60     StringMap<uint32_t>::iterator it = testMap.begin();
61     EXPECT_STREQ(testKey, it->first().data());
62     EXPECT_EQ(testValue, it->second);
63     ++it;
64     EXPECT_TRUE(it == testMap.end());
65 
66     // Lookup tests
67     EXPECT_EQ(1u, testMap.count(testKey));
68     EXPECT_EQ(1u, testMap.count(StringRef(testKeyFirst, testKeyLength)));
69     EXPECT_EQ(1u, testMap.count(testKeyStr));
70     EXPECT_TRUE(testMap.find(testKey) == testMap.begin());
71     EXPECT_TRUE(testMap.find(StringRef(testKeyFirst, testKeyLength)) ==
72                 testMap.begin());
73     EXPECT_TRUE(testMap.find(testKeyStr) == testMap.begin());
74   }
75 };
76 
77 const char StringMapTest::testKey[] = "key";
78 const uint32_t StringMapTest::testValue = 1u;
79 const char* StringMapTest::testKeyFirst = testKey;
80 size_t StringMapTest::testKeyLength = sizeof(testKey) - 1;
81 const std::string StringMapTest::testKeyStr(testKey);
82 
83 struct CountCopyAndMove {
84   CountCopyAndMove() = default;
85   CountCopyAndMove(const CountCopyAndMove &) { copy = 1; }
86   CountCopyAndMove(CountCopyAndMove &&) { move = 1; }
87   void operator=(const CountCopyAndMove &) { ++copy; }
88   void operator=(CountCopyAndMove &&) { ++move; }
89   int copy = 0;
90   int move = 0;
91 };
92 
93 // Empty map tests.
94 TEST_F(StringMapTest, EmptyMapTest) {
95   assertEmptyMap();
96 }
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 // A more complex iteration test.
211 TEST_F(StringMapTest, IterationTest) {
212   bool visited[100];
213 
214   // Insert 100 numbers into the map
215   for (int i = 0; i < 100; ++i) {
216     std::stringstream ss;
217     ss << "key_" << i;
218     testMap[ss.str()] = i;
219     visited[i] = false;
220   }
221 
222   // Iterate over all numbers and mark each one found.
223   for (StringMap<uint32_t>::iterator it = testMap.begin();
224       it != testMap.end(); ++it) {
225     std::stringstream ss;
226     ss << "key_" << it->second;
227     ASSERT_STREQ(ss.str().c_str(), it->first().data());
228     visited[it->second] = true;
229   }
230 
231   // Ensure every number was visited.
232   for (int i = 0; i < 100; ++i) {
233     ASSERT_TRUE(visited[i]) << "Entry #" << i << " was never visited";
234   }
235 }
236 
237 // Test StringMapEntry::Create() method.
238 TEST_F(StringMapTest, StringMapEntryTest) {
239   MallocAllocator Allocator;
240   StringMap<uint32_t>::value_type *entry =
241       StringMap<uint32_t>::value_type::Create(
242           StringRef(testKeyFirst, testKeyLength), Allocator, 1u);
243   EXPECT_STREQ(testKey, entry->first().data());
244   EXPECT_EQ(1u, entry->second);
245   entry->Destroy(Allocator);
246 }
247 
248 // Test insert() method.
249 TEST_F(StringMapTest, InsertTest) {
250   SCOPED_TRACE("InsertTest");
251   testMap.insert(
252       StringMap<uint32_t>::value_type::Create(
253           StringRef(testKeyFirst, testKeyLength),
254           testMap.getAllocator(), 1u));
255   assertSingleItemMap();
256 }
257 
258 // Test insert(pair<K, V>) method
259 TEST_F(StringMapTest, InsertPairTest) {
260   bool Inserted;
261   StringMap<uint32_t>::iterator NewIt;
262   std::tie(NewIt, Inserted) =
263       testMap.insert(std::make_pair(testKeyFirst, testValue));
264   EXPECT_EQ(1u, testMap.size());
265   EXPECT_EQ(testValue, testMap[testKeyFirst]);
266   EXPECT_EQ(testKeyFirst, NewIt->first());
267   EXPECT_EQ(testValue, NewIt->second);
268   EXPECT_TRUE(Inserted);
269 
270   StringMap<uint32_t>::iterator ExistingIt;
271   std::tie(ExistingIt, Inserted) =
272       testMap.insert(std::make_pair(testKeyFirst, testValue + 1));
273   EXPECT_EQ(1u, testMap.size());
274   EXPECT_EQ(testValue, testMap[testKeyFirst]);
275   EXPECT_FALSE(Inserted);
276   EXPECT_EQ(NewIt, ExistingIt);
277 }
278 
279 // Test insert(pair<K, V>) method when rehashing occurs
280 TEST_F(StringMapTest, InsertRehashingPairTest) {
281   // Check that the correct iterator is returned when the inserted element is
282   // moved to a different bucket during internal rehashing. This depends on
283   // the particular key, and the implementation of StringMap and HashString.
284   // Changes to those might result in this test not actually checking that.
285   StringMap<uint32_t> t(0);
286   EXPECT_EQ(0u, t.getNumBuckets());
287 
288   StringMap<uint32_t>::iterator It =
289     t.insert(std::make_pair("abcdef", 42)).first;
290   EXPECT_EQ(16u, t.getNumBuckets());
291   EXPECT_EQ("abcdef", It->first());
292   EXPECT_EQ(42u, It->second);
293 }
294 
295 TEST_F(StringMapTest, InsertOrAssignTest) {
296   struct A : CountCopyAndMove {
297     A(int v) : v(v) {}
298     int v;
299   };
300   StringMap<A> t(0);
301 
302   auto try1 = t.insert_or_assign("A", A(1));
303   EXPECT_TRUE(try1.second);
304   EXPECT_EQ(1, try1.first->second.v);
305   EXPECT_EQ(1, try1.first->second.move);
306 
307   auto try2 = t.insert_or_assign("A", A(2));
308   EXPECT_FALSE(try2.second);
309   EXPECT_EQ(2, try2.first->second.v);
310   EXPECT_EQ(2, try1.first->second.move);
311 
312   EXPECT_EQ(try1.first, try2.first);
313   EXPECT_EQ(0, try1.first->second.copy);
314 }
315 
316 TEST_F(StringMapTest, IterMapKeysVector) {
317   StringMap<int> Map;
318   Map["A"] = 1;
319   Map["B"] = 2;
320   Map["C"] = 3;
321   Map["D"] = 3;
322 
323   std::vector<StringRef> Keys{Map.keys().begin(), Map.keys().end()};
324   llvm::sort(Keys);
325 
326   std::vector<StringRef> Expected{{"A", "B", "C", "D"}};
327   EXPECT_EQ(Expected, Keys);
328 }
329 
330 TEST_F(StringMapTest, IterMapKeysSmallVector) {
331   StringMap<int> Map;
332   Map["A"] = 1;
333   Map["B"] = 2;
334   Map["C"] = 3;
335   Map["D"] = 3;
336 
337   auto Keys = to_vector<4>(Map.keys());
338   llvm::sort(Keys);
339 
340   SmallVector<StringRef, 4> Expected = {"A", "B", "C", "D"};
341   EXPECT_EQ(Expected, Keys);
342 }
343 
344 // Create a non-default constructable value
345 struct StringMapTestStruct {
346   StringMapTestStruct(int i) : i(i) {}
347   StringMapTestStruct() = delete;
348   int i;
349 };
350 
351 TEST_F(StringMapTest, NonDefaultConstructable) {
352   StringMap<StringMapTestStruct> t;
353   t.insert(std::make_pair("Test", StringMapTestStruct(123)));
354   StringMap<StringMapTestStruct>::iterator iter = t.find("Test");
355   ASSERT_NE(iter, t.end());
356   ASSERT_EQ(iter->second.i, 123);
357 }
358 
359 struct Immovable {
360   Immovable() {}
361   Immovable(Immovable&&) = delete; // will disable the other special members
362 };
363 
364 struct MoveOnly {
365   int i;
366   MoveOnly(int i) : i(i) {}
367   MoveOnly(const Immovable&) : i(0) {}
368   MoveOnly(MoveOnly &&RHS) : i(RHS.i) {}
369   MoveOnly &operator=(MoveOnly &&RHS) {
370     i = RHS.i;
371     return *this;
372   }
373 
374 private:
375   MoveOnly(const MoveOnly &) = delete;
376   MoveOnly &operator=(const MoveOnly &) = delete;
377 };
378 
379 TEST_F(StringMapTest, MoveOnly) {
380   StringMap<MoveOnly> t;
381   t.insert(std::make_pair("Test", MoveOnly(42)));
382   StringRef Key = "Test";
383   StringMapEntry<MoveOnly>::Create(Key, t.getAllocator(), MoveOnly(42))
384       ->Destroy(t.getAllocator());
385 }
386 
387 TEST_F(StringMapTest, CtorArg) {
388   StringRef Key = "Test";
389   MallocAllocator Allocator;
390   StringMapEntry<MoveOnly>::Create(Key, Allocator, Immovable())
391       ->Destroy(Allocator);
392 }
393 
394 TEST_F(StringMapTest, MoveConstruct) {
395   StringMap<int> A;
396   A["x"] = 42;
397   StringMap<int> B = std::move(A);
398   ASSERT_EQ(A.size(), 0u);
399   ASSERT_EQ(B.size(), 1u);
400   ASSERT_EQ(B["x"], 42);
401   ASSERT_EQ(B.count("y"), 0u);
402 }
403 
404 TEST_F(StringMapTest, MoveAssignment) {
405   StringMap<int> A;
406   A["x"] = 42;
407   StringMap<int> B;
408   B["y"] = 117;
409   A = std::move(B);
410   ASSERT_EQ(A.size(), 1u);
411   ASSERT_EQ(B.size(), 0u);
412   ASSERT_EQ(A["y"], 117);
413   ASSERT_EQ(B.count("x"), 0u);
414 }
415 
416 TEST_F(StringMapTest, EqualEmpty) {
417   StringMap<int> A;
418   StringMap<int> B;
419   ASSERT_TRUE(A == B);
420   ASSERT_FALSE(A != B);
421   ASSERT_TRUE(A == A); // self check
422 }
423 
424 TEST_F(StringMapTest, EqualWithValues) {
425   StringMap<int> A;
426   A["A"] = 1;
427   A["B"] = 2;
428   A["C"] = 3;
429   A["D"] = 3;
430 
431   StringMap<int> B;
432   B["A"] = 1;
433   B["B"] = 2;
434   B["C"] = 3;
435   B["D"] = 3;
436 
437   ASSERT_TRUE(A == B);
438   ASSERT_TRUE(B == A);
439   ASSERT_FALSE(A != B);
440   ASSERT_FALSE(B != A);
441   ASSERT_TRUE(A == A); // self check
442 }
443 
444 TEST_F(StringMapTest, NotEqualMissingKeys) {
445   StringMap<int> A;
446   A["A"] = 1;
447   A["B"] = 2;
448 
449   StringMap<int> B;
450   B["A"] = 1;
451   B["B"] = 2;
452   B["C"] = 3;
453   B["D"] = 3;
454 
455   ASSERT_FALSE(A == B);
456   ASSERT_FALSE(B == A);
457   ASSERT_TRUE(A != B);
458   ASSERT_TRUE(B != A);
459 }
460 
461 TEST_F(StringMapTest, NotEqualWithDifferentValues) {
462   StringMap<int> A;
463   A["A"] = 1;
464   A["B"] = 2;
465   A["C"] = 100;
466   A["D"] = 3;
467 
468   StringMap<int> B;
469   B["A"] = 1;
470   B["B"] = 2;
471   B["C"] = 3;
472   B["D"] = 3;
473 
474   ASSERT_FALSE(A == B);
475   ASSERT_FALSE(B == A);
476   ASSERT_TRUE(A != B);
477   ASSERT_TRUE(B != A);
478 }
479 
480 struct Countable {
481   int &InstanceCount;
482   int Number;
483   Countable(int Number, int &InstanceCount)
484       : InstanceCount(InstanceCount), Number(Number) {
485     ++InstanceCount;
486   }
487   Countable(Countable &&C) : InstanceCount(C.InstanceCount), Number(C.Number) {
488     ++InstanceCount;
489     C.Number = -1;
490   }
491   Countable(const Countable &C)
492       : InstanceCount(C.InstanceCount), Number(C.Number) {
493     ++InstanceCount;
494   }
495   Countable &operator=(Countable C) {
496     Number = C.Number;
497     return *this;
498   }
499   ~Countable() { --InstanceCount; }
500 };
501 
502 TEST_F(StringMapTest, MoveDtor) {
503   int InstanceCount = 0;
504   StringMap<Countable> A;
505   A.insert(std::make_pair("x", Countable(42, InstanceCount)));
506   ASSERT_EQ(InstanceCount, 1);
507   auto I = A.find("x");
508   ASSERT_NE(I, A.end());
509   ASSERT_EQ(I->second.Number, 42);
510 
511   StringMap<Countable> B;
512   B = std::move(A);
513   ASSERT_EQ(InstanceCount, 1);
514   ASSERT_TRUE(A.empty());
515   I = B.find("x");
516   ASSERT_NE(I, B.end());
517   ASSERT_EQ(I->second.Number, 42);
518 
519   B = StringMap<Countable>();
520   ASSERT_EQ(InstanceCount, 0);
521   ASSERT_TRUE(B.empty());
522 }
523 
524 namespace {
525 // Simple class that counts how many moves and copy happens when growing a map
526 struct CountCtorCopyAndMove {
527   static unsigned Ctor;
528   static unsigned Move;
529   static unsigned Copy;
530   int Data = 0;
531   CountCtorCopyAndMove(int Data) : Data(Data) { Ctor++; }
532   CountCtorCopyAndMove() { Ctor++; }
533 
534   CountCtorCopyAndMove(const CountCtorCopyAndMove &) { Copy++; }
535   CountCtorCopyAndMove &operator=(const CountCtorCopyAndMove &) {
536     Copy++;
537     return *this;
538   }
539   CountCtorCopyAndMove(CountCtorCopyAndMove &&) { Move++; }
540   CountCtorCopyAndMove &operator=(const CountCtorCopyAndMove &&) {
541     Move++;
542     return *this;
543   }
544 };
545 unsigned CountCtorCopyAndMove::Copy = 0;
546 unsigned CountCtorCopyAndMove::Move = 0;
547 unsigned CountCtorCopyAndMove::Ctor = 0;
548 
549 } // anonymous namespace
550 
551 // Make sure creating the map with an initial size of N actually gives us enough
552 // buckets to insert N items without increasing allocation size.
553 TEST(StringMapCustomTest, InitialSizeTest) {
554   // 1 is an "edge value", 32 is an arbitrary power of two, and 67 is an
555   // arbitrary prime, picked without any good reason.
556   for (auto Size : {1, 32, 67}) {
557     StringMap<CountCtorCopyAndMove> Map(Size);
558     auto NumBuckets = Map.getNumBuckets();
559     CountCtorCopyAndMove::Move = 0;
560     CountCtorCopyAndMove::Copy = 0;
561     for (int i = 0; i < Size; ++i)
562       Map.insert(std::pair<std::string, CountCtorCopyAndMove>(
563           std::piecewise_construct, std::forward_as_tuple(Twine(i).str()),
564           std::forward_as_tuple(i)));
565     // After the initial move, the map will move the Elts in the Entry.
566     EXPECT_EQ((unsigned)Size * 2, CountCtorCopyAndMove::Move);
567     // We copy once the pair from the Elts vector
568     EXPECT_EQ(0u, CountCtorCopyAndMove::Copy);
569     // Check that the map didn't grow
570     EXPECT_EQ(Map.getNumBuckets(), NumBuckets);
571   }
572 }
573 
574 TEST(StringMapCustomTest, BracketOperatorCtor) {
575   StringMap<CountCtorCopyAndMove> Map;
576   CountCtorCopyAndMove::Ctor = 0;
577   Map["abcd"];
578   EXPECT_EQ(1u, CountCtorCopyAndMove::Ctor);
579   // Test that operator[] does not create a value when it is already in the map
580   CountCtorCopyAndMove::Ctor = 0;
581   Map["abcd"];
582   EXPECT_EQ(0u, CountCtorCopyAndMove::Ctor);
583 }
584 
585 namespace {
586 struct NonMoveableNonCopyableType {
587   int Data = 0;
588   NonMoveableNonCopyableType() = default;
589   NonMoveableNonCopyableType(int Data) : Data(Data) {}
590   NonMoveableNonCopyableType(const NonMoveableNonCopyableType &) = delete;
591   NonMoveableNonCopyableType(NonMoveableNonCopyableType &&) = delete;
592 };
593 }
594 
595 // Test that we can "emplace" an element in the map without involving map/move
596 TEST(StringMapCustomTest, EmplaceTest) {
597   StringMap<NonMoveableNonCopyableType> Map;
598   Map.try_emplace("abcd", 42);
599   EXPECT_EQ(1u, Map.count("abcd"));
600   EXPECT_EQ(42, Map["abcd"].Data);
601 }
602 
603 // Test that StringMapEntryBase can handle size_t wide sizes.
604 TEST(StringMapCustomTest, StringMapEntryBaseSize) {
605   size_t LargeValue;
606 
607   // Test that the entry can represent max-unsigned.
608   if (sizeof(size_t) <= sizeof(unsigned))
609     LargeValue = std::numeric_limits<unsigned>::max();
610   else
611     LargeValue = std::numeric_limits<unsigned>::max() + 1ULL;
612   StringMapEntryBase LargeBase(LargeValue);
613   EXPECT_EQ(LargeValue, LargeBase.getKeyLength());
614 
615   // Test that the entry can hold at least max size_t.
616   LargeValue = std::numeric_limits<size_t>::max();
617   StringMapEntryBase LargerBase(LargeValue);
618   LargeValue = std::numeric_limits<size_t>::max();
619   EXPECT_EQ(LargeValue, LargerBase.getKeyLength());
620 }
621 
622 // Test that StringMapEntry can handle size_t wide sizes.
623 TEST(StringMapCustomTest, StringMapEntrySize) {
624   size_t LargeValue;
625 
626   // Test that the entry can represent max-unsigned.
627   if (sizeof(size_t) <= sizeof(unsigned))
628     LargeValue = std::numeric_limits<unsigned>::max();
629   else
630     LargeValue = std::numeric_limits<unsigned>::max() + 1ULL;
631   StringMapEntry<int> LargeEntry(LargeValue);
632   StringRef Key = LargeEntry.getKey();
633   EXPECT_EQ(LargeValue, Key.size());
634 
635   // Test that the entry can hold at least max size_t.
636   LargeValue = std::numeric_limits<size_t>::max();
637   StringMapEntry<int> LargerEntry(LargeValue);
638   Key = LargerEntry.getKey();
639   EXPECT_EQ(LargeValue, Key.size());
640 }
641 
642 } // end anonymous namespace
643