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