1*b510cdb8SSteven Wu //===- TrieRawHashMapTest.cpp ---------------------------------------------===// 2*b510cdb8SSteven Wu // 3*b510cdb8SSteven Wu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*b510cdb8SSteven Wu // See https://llvm.org/LICENSE.txt for license information. 5*b510cdb8SSteven Wu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*b510cdb8SSteven Wu // 7*b510cdb8SSteven Wu //===----------------------------------------------------------------------===// 8*b510cdb8SSteven Wu 9*b510cdb8SSteven Wu #include "llvm/ADT/TrieRawHashMap.h" 10*b510cdb8SSteven Wu #include "llvm/ADT/Twine.h" 11*b510cdb8SSteven Wu #include "llvm/Support/Endian.h" 12*b510cdb8SSteven Wu #include "llvm/Support/SHA1.h" 13*b510cdb8SSteven Wu #include "gtest/gtest.h" 14*b510cdb8SSteven Wu 15*b510cdb8SSteven Wu using namespace llvm; 16*b510cdb8SSteven Wu 17*b510cdb8SSteven Wu namespace llvm { 18*b510cdb8SSteven Wu class TrieRawHashMapTestHelper { 19*b510cdb8SSteven Wu public: 20*b510cdb8SSteven Wu TrieRawHashMapTestHelper() = default; 21*b510cdb8SSteven Wu 22*b510cdb8SSteven Wu void setTrie(ThreadSafeTrieRawHashMapBase *T) { Trie = T; } 23*b510cdb8SSteven Wu 24*b510cdb8SSteven Wu ThreadSafeTrieRawHashMapBase::PointerBase getRoot() const { 25*b510cdb8SSteven Wu return Trie->getRoot(); 26*b510cdb8SSteven Wu } 27*b510cdb8SSteven Wu unsigned getStartBit(ThreadSafeTrieRawHashMapBase::PointerBase P) const { 28*b510cdb8SSteven Wu return Trie->getStartBit(P); 29*b510cdb8SSteven Wu } 30*b510cdb8SSteven Wu unsigned getNumBits(ThreadSafeTrieRawHashMapBase::PointerBase P) const { 31*b510cdb8SSteven Wu return Trie->getNumBits(P); 32*b510cdb8SSteven Wu } 33*b510cdb8SSteven Wu unsigned getNumSlotUsed(ThreadSafeTrieRawHashMapBase::PointerBase P) const { 34*b510cdb8SSteven Wu return Trie->getNumSlotUsed(P); 35*b510cdb8SSteven Wu } 36*b510cdb8SSteven Wu unsigned getNumTries() const { return Trie->getNumTries(); } 37*b510cdb8SSteven Wu std::string 38*b510cdb8SSteven Wu getTriePrefixAsString(ThreadSafeTrieRawHashMapBase::PointerBase P) const { 39*b510cdb8SSteven Wu return Trie->getTriePrefixAsString(P); 40*b510cdb8SSteven Wu } 41*b510cdb8SSteven Wu ThreadSafeTrieRawHashMapBase::PointerBase 42*b510cdb8SSteven Wu getNextTrie(ThreadSafeTrieRawHashMapBase::PointerBase P) const { 43*b510cdb8SSteven Wu return Trie->getNextTrie(P); 44*b510cdb8SSteven Wu } 45*b510cdb8SSteven Wu 46*b510cdb8SSteven Wu private: 47*b510cdb8SSteven Wu ThreadSafeTrieRawHashMapBase *Trie = nullptr; 48*b510cdb8SSteven Wu }; 49*b510cdb8SSteven Wu } // namespace llvm 50*b510cdb8SSteven Wu 51*b510cdb8SSteven Wu namespace { 52*b510cdb8SSteven Wu template <typename DataType, size_t HashSize = sizeof(uint64_t)> 53*b510cdb8SSteven Wu class SimpleTrieHashMapTest : public TrieRawHashMapTestHelper, 54*b510cdb8SSteven Wu public ::testing::Test { 55*b510cdb8SSteven Wu public: 56*b510cdb8SSteven Wu using NumType = DataType; 57*b510cdb8SSteven Wu using HashType = std::array<uint8_t, HashSize>; 58*b510cdb8SSteven Wu using TrieType = ThreadSafeTrieRawHashMap<DataType, sizeof(HashType)>; 59*b510cdb8SSteven Wu 60*b510cdb8SSteven Wu TrieType &createTrie(size_t RootBits, size_t SubtrieBits) { 61*b510cdb8SSteven Wu auto &Ret = Trie.emplace(RootBits, SubtrieBits); 62*b510cdb8SSteven Wu TrieRawHashMapTestHelper::setTrie(&Ret); 63*b510cdb8SSteven Wu return Ret; 64*b510cdb8SSteven Wu } 65*b510cdb8SSteven Wu 66*b510cdb8SSteven Wu void destroyTrie() { Trie.reset(); } 67*b510cdb8SSteven Wu ~SimpleTrieHashMapTest() { destroyTrie(); } 68*b510cdb8SSteven Wu 69*b510cdb8SSteven Wu // Use the number itself as hash to test the pathological case. 70*b510cdb8SSteven Wu static HashType hash(uint64_t Num) { 71*b510cdb8SSteven Wu uint64_t HashN = 72*b510cdb8SSteven Wu llvm::support::endian::byte_swap(Num, llvm::endianness::big); 73*b510cdb8SSteven Wu HashType Hash; 74*b510cdb8SSteven Wu memcpy(&Hash[0], &HashN, sizeof(HashType)); 75*b510cdb8SSteven Wu return Hash; 76*b510cdb8SSteven Wu }; 77*b510cdb8SSteven Wu 78*b510cdb8SSteven Wu private: 79*b510cdb8SSteven Wu std::optional<TrieType> Trie; 80*b510cdb8SSteven Wu }; 81*b510cdb8SSteven Wu 82*b510cdb8SSteven Wu using SmallNodeTrieTest = SimpleTrieHashMapTest<uint64_t>; 83*b510cdb8SSteven Wu 84*b510cdb8SSteven Wu TEST_F(SmallNodeTrieTest, TrieAllocation) { 85*b510cdb8SSteven Wu NumType Numbers[] = { 86*b510cdb8SSteven Wu 0x0, std::numeric_limits<NumType>::max(), 0x1, 0x2, 87*b510cdb8SSteven Wu 0x3, std::numeric_limits<NumType>::max() - 1u, 88*b510cdb8SSteven Wu }; 89*b510cdb8SSteven Wu 90*b510cdb8SSteven Wu unsigned ExpectedTries[] = { 91*b510cdb8SSteven Wu 1, // Allocate Root. 92*b510cdb8SSteven Wu 1, // Both on the root. 93*b510cdb8SSteven Wu 64, // 0 and 1 sinks all the way down. 94*b510cdb8SSteven Wu 64, // no new allocation needed. 95*b510cdb8SSteven Wu 65, // need a new node between 2 and 3. 96*b510cdb8SSteven Wu 65 + 63, // 63 new allocation to sink two big numbers all the way. 97*b510cdb8SSteven Wu }; 98*b510cdb8SSteven Wu 99*b510cdb8SSteven Wu const char *ExpectedPrefix[] = { 100*b510cdb8SSteven Wu "", // Root. 101*b510cdb8SSteven Wu "", // Root. 102*b510cdb8SSteven Wu "00000000000000[0000000]", 103*b510cdb8SSteven Wu "00000000000000[0000000]", 104*b510cdb8SSteven Wu "00000000000000[0000001]", 105*b510cdb8SSteven Wu "ffffffffffffff[1111111]", 106*b510cdb8SSteven Wu }; 107*b510cdb8SSteven Wu 108*b510cdb8SSteven Wu // Use root and subtrie sizes of 1 so this gets sunk quite deep. 109*b510cdb8SSteven Wu auto &Trie = createTrie(/*RootBits=*/1, /*SubtrieBits=*/1); 110*b510cdb8SSteven Wu 111*b510cdb8SSteven Wu for (unsigned I = 0; I < 6; ++I) { 112*b510cdb8SSteven Wu // Lookup first to exercise hint code for deep tries. 113*b510cdb8SSteven Wu TrieType::pointer Lookup = Trie.find(hash(Numbers[I])); 114*b510cdb8SSteven Wu EXPECT_FALSE(Lookup); 115*b510cdb8SSteven Wu 116*b510cdb8SSteven Wu Trie.insert(Lookup, TrieType::value_type(hash(Numbers[I]), Numbers[I])); 117*b510cdb8SSteven Wu EXPECT_EQ(getNumTries(), ExpectedTries[I]); 118*b510cdb8SSteven Wu EXPECT_EQ(getTriePrefixAsString(getNextTrie(getRoot())), ExpectedPrefix[I]); 119*b510cdb8SSteven Wu } 120*b510cdb8SSteven Wu } 121*b510cdb8SSteven Wu 122*b510cdb8SSteven Wu TEST_F(SmallNodeTrieTest, TrieStructure) { 123*b510cdb8SSteven Wu NumType Numbers[] = { 124*b510cdb8SSteven Wu // Three numbers that will nest deeply to test (1) sinking subtries and 125*b510cdb8SSteven Wu // (2) deep, non-trivial hints. 126*b510cdb8SSteven Wu std::numeric_limits<NumType>::max(), 127*b510cdb8SSteven Wu std::numeric_limits<NumType>::max() - 2u, 128*b510cdb8SSteven Wu std::numeric_limits<NumType>::max() - 3u, 129*b510cdb8SSteven Wu // One number to stay at the top-level. 130*b510cdb8SSteven Wu 0x37, 131*b510cdb8SSteven Wu }; 132*b510cdb8SSteven Wu 133*b510cdb8SSteven Wu // Use root and subtrie sizes of 1 so this gets sunk quite deep. 134*b510cdb8SSteven Wu auto &Trie = createTrie(/*RootBits=*/1, /*SubtrieBits=*/1); 135*b510cdb8SSteven Wu 136*b510cdb8SSteven Wu for (NumType N : Numbers) { 137*b510cdb8SSteven Wu // Lookup first to exercise hint code for deep tries. 138*b510cdb8SSteven Wu TrieType::pointer Lookup = Trie.find(hash(N)); 139*b510cdb8SSteven Wu EXPECT_FALSE(Lookup); 140*b510cdb8SSteven Wu 141*b510cdb8SSteven Wu Trie.insert(Lookup, TrieType::value_type(hash(N), N)); 142*b510cdb8SSteven Wu } 143*b510cdb8SSteven Wu for (NumType N : Numbers) { 144*b510cdb8SSteven Wu TrieType::pointer Lookup = Trie.find(hash(N)); 145*b510cdb8SSteven Wu EXPECT_TRUE(Lookup); 146*b510cdb8SSteven Wu if (!Lookup) 147*b510cdb8SSteven Wu continue; 148*b510cdb8SSteven Wu EXPECT_EQ(hash(N), Lookup->Hash); 149*b510cdb8SSteven Wu EXPECT_EQ(N, Lookup->Data); 150*b510cdb8SSteven Wu 151*b510cdb8SSteven Wu // Confirm a subsequent insertion fails to overwrite by trying to insert a 152*b510cdb8SSteven Wu // bad value. 153*b510cdb8SSteven Wu auto Result = Trie.insert(Lookup, TrieType::value_type(hash(N), N - 1)); 154*b510cdb8SSteven Wu EXPECT_EQ(N, Result->Data); 155*b510cdb8SSteven Wu } 156*b510cdb8SSteven Wu 157*b510cdb8SSteven Wu // Check the trie so we can confirm the structure is correct. Each subtrie 158*b510cdb8SSteven Wu // should have 2 slots. The root's index=0 should have the content for 159*b510cdb8SSteven Wu // 0x37 directly, and index=1 should be a linked-list of subtries, finally 160*b510cdb8SSteven Wu // ending with content for (max-2) and (max-3). 161*b510cdb8SSteven Wu // 162*b510cdb8SSteven Wu // Note: This structure is not exhaustive (too expensive to update tests), 163*b510cdb8SSteven Wu // but it does test that the dump format is somewhat readable and that the 164*b510cdb8SSteven Wu // basic structure is correct. 165*b510cdb8SSteven Wu // 166*b510cdb8SSteven Wu // Note: This test requires that the trie reads bytes starting from index 0 167*b510cdb8SSteven Wu // of the array of uint8_t, and then reads each byte's bits from high to low. 168*b510cdb8SSteven Wu 169*b510cdb8SSteven Wu // Check the Trie. 170*b510cdb8SSteven Wu // We should allocated a total of 64 SubTries for 64 bit hash. 171*b510cdb8SSteven Wu ASSERT_EQ(getNumTries(), 64u); 172*b510cdb8SSteven Wu // Check the root trie. Two slots and both are used. 173*b510cdb8SSteven Wu ASSERT_EQ(getNumSlotUsed(getRoot()), 2u); 174*b510cdb8SSteven Wu // Check last subtrie. 175*b510cdb8SSteven Wu // Last allocated trie is the next node in the allocation chain. 176*b510cdb8SSteven Wu auto LastAlloctedSubTrie = getNextTrie(getRoot()); 177*b510cdb8SSteven Wu ASSERT_EQ(getTriePrefixAsString(LastAlloctedSubTrie), 178*b510cdb8SSteven Wu "ffffffffffffff[1111110]"); 179*b510cdb8SSteven Wu ASSERT_EQ(getStartBit(LastAlloctedSubTrie), 63u); 180*b510cdb8SSteven Wu ASSERT_EQ(getNumBits(LastAlloctedSubTrie), 1u); 181*b510cdb8SSteven Wu ASSERT_EQ(getNumSlotUsed(LastAlloctedSubTrie), 2u); 182*b510cdb8SSteven Wu } 183*b510cdb8SSteven Wu 184*b510cdb8SSteven Wu TEST_F(SmallNodeTrieTest, TrieStructureSmallFinalSubtrie) { 185*b510cdb8SSteven Wu NumType Numbers[] = { 186*b510cdb8SSteven Wu // Three numbers that will nest deeply to test (1) sinking subtries and 187*b510cdb8SSteven Wu // (2) deep, non-trivial hints. 188*b510cdb8SSteven Wu std::numeric_limits<NumType>::max(), 189*b510cdb8SSteven Wu std::numeric_limits<NumType>::max() - 2u, 190*b510cdb8SSteven Wu std::numeric_limits<NumType>::max() - 3u, 191*b510cdb8SSteven Wu // One number to stay at the top-level. 192*b510cdb8SSteven Wu 0x37, 193*b510cdb8SSteven Wu }; 194*b510cdb8SSteven Wu 195*b510cdb8SSteven Wu // Use subtrie size of 5 to avoid hitting 64 evenly, making the final subtrie 196*b510cdb8SSteven Wu // small. 197*b510cdb8SSteven Wu auto &Trie = createTrie(/*RootBits=*/8, /*SubtrieBits=*/5); 198*b510cdb8SSteven Wu 199*b510cdb8SSteven Wu for (NumType N : Numbers) { 200*b510cdb8SSteven Wu // Lookup first to exercise hint code for deep tries. 201*b510cdb8SSteven Wu TrieType::pointer Lookup = Trie.find(hash(N)); 202*b510cdb8SSteven Wu EXPECT_FALSE(Lookup); 203*b510cdb8SSteven Wu 204*b510cdb8SSteven Wu Trie.insert(Lookup, TrieType::value_type(hash(N), N)); 205*b510cdb8SSteven Wu } 206*b510cdb8SSteven Wu for (NumType N : Numbers) { 207*b510cdb8SSteven Wu TrieType::pointer Lookup = Trie.find(hash(N)); 208*b510cdb8SSteven Wu ASSERT_TRUE(Lookup); 209*b510cdb8SSteven Wu EXPECT_EQ(hash(N), Lookup->Hash); 210*b510cdb8SSteven Wu EXPECT_EQ(N, Lookup->Data); 211*b510cdb8SSteven Wu 212*b510cdb8SSteven Wu // Confirm a subsequent insertion fails to overwrite by trying to insert a 213*b510cdb8SSteven Wu // bad value. 214*b510cdb8SSteven Wu auto Result = Trie.insert(Lookup, TrieType::value_type(hash(N), N - 1)); 215*b510cdb8SSteven Wu EXPECT_EQ(N, Result->Data); 216*b510cdb8SSteven Wu } 217*b510cdb8SSteven Wu 218*b510cdb8SSteven Wu // Check the trie so we can confirm the structure is correct. The root 219*b510cdb8SSteven Wu // should have 2^8=256 slots, most subtries should have 2^5=32 slots, and the 220*b510cdb8SSteven Wu // deepest subtrie should have 2^1=2 slots (since (64-8)mod(5)=1). 221*b510cdb8SSteven Wu // should have 2 slots. The root's index=0 should have the content for 222*b510cdb8SSteven Wu // 0x37 directly, and index=1 should be a linked-list of subtries, finally 223*b510cdb8SSteven Wu // ending with content for (max-2) and (max-3). 224*b510cdb8SSteven Wu // 225*b510cdb8SSteven Wu // Note: This structure is not exhaustive (too expensive to update tests), 226*b510cdb8SSteven Wu // but it does test that the dump format is somewhat readable and that the 227*b510cdb8SSteven Wu // basic structure is correct. 228*b510cdb8SSteven Wu // 229*b510cdb8SSteven Wu // Note: This test requires that the trie reads bytes starting from index 0 230*b510cdb8SSteven Wu // of the array of uint8_t, and then reads each byte's bits from high to low. 231*b510cdb8SSteven Wu 232*b510cdb8SSteven Wu // Check the Trie. 233*b510cdb8SSteven Wu // 64 bit hash = 8 + 5 * 11 + 1, so 1 root, 11 8bit subtrie and 1 last level 234*b510cdb8SSteven Wu // subtrie, 13 total. 235*b510cdb8SSteven Wu ASSERT_EQ(getNumTries(), 13u); 236*b510cdb8SSteven Wu // Check the root trie. Two slots and both are used. 237*b510cdb8SSteven Wu ASSERT_EQ(getNumSlotUsed(getRoot()), 2u); 238*b510cdb8SSteven Wu // Check last subtrie. 239*b510cdb8SSteven Wu // Last allocated trie is the next node in the allocation chain. 240*b510cdb8SSteven Wu auto LastAlloctedSubTrie = getNextTrie(getRoot()); 241*b510cdb8SSteven Wu ASSERT_EQ(getTriePrefixAsString(LastAlloctedSubTrie), 242*b510cdb8SSteven Wu "ffffffffffffff[1111110]"); 243*b510cdb8SSteven Wu ASSERT_EQ(getStartBit(LastAlloctedSubTrie), 63u); 244*b510cdb8SSteven Wu ASSERT_EQ(getNumBits(LastAlloctedSubTrie), 1u); 245*b510cdb8SSteven Wu ASSERT_EQ(getNumSlotUsed(LastAlloctedSubTrie), 2u); 246*b510cdb8SSteven Wu } 247*b510cdb8SSteven Wu 248*b510cdb8SSteven Wu TEST_F(SmallNodeTrieTest, TrieDestructionLoop) { 249*b510cdb8SSteven Wu // Test destroying large Trie. Make sure there is no recursion that can 250*b510cdb8SSteven Wu // overflow the stack. 251*b510cdb8SSteven Wu 252*b510cdb8SSteven Wu // Limit the tries to 2 slots (1 bit) to generate subtries at a higher rate. 253*b510cdb8SSteven Wu auto &Trie = createTrie(/*NumRootBits=*/1, /*NumSubtrieBits=*/1); 254*b510cdb8SSteven Wu 255*b510cdb8SSteven Wu // Fill them up. Pick a MaxN high enough to cause a stack overflow in debug 256*b510cdb8SSteven Wu // builds. 257*b510cdb8SSteven Wu static constexpr uint64_t MaxN = 100000; 258*b510cdb8SSteven Wu for (uint64_t N = 0; N != MaxN; ++N) { 259*b510cdb8SSteven Wu HashType Hash = hash(N); 260*b510cdb8SSteven Wu Trie.insert(TrieType::pointer(), TrieType::value_type(Hash, NumType{N})); 261*b510cdb8SSteven Wu } 262*b510cdb8SSteven Wu 263*b510cdb8SSteven Wu // Destroy tries. If destruction is recursive and MaxN is high enough, these 264*b510cdb8SSteven Wu // will both fail. 265*b510cdb8SSteven Wu destroyTrie(); 266*b510cdb8SSteven Wu } 267*b510cdb8SSteven Wu 268*b510cdb8SSteven Wu struct NumWithDestructorT { 269*b510cdb8SSteven Wu uint64_t Num; 270*b510cdb8SSteven Wu llvm::function_ref<void()> DestructorCallback; 271*b510cdb8SSteven Wu ~NumWithDestructorT() { DestructorCallback(); } 272*b510cdb8SSteven Wu }; 273*b510cdb8SSteven Wu 274*b510cdb8SSteven Wu using NodeWithDestructorTrieTest = SimpleTrieHashMapTest<NumWithDestructorT>; 275*b510cdb8SSteven Wu 276*b510cdb8SSteven Wu TEST_F(NodeWithDestructorTrieTest, TrieDestructionLoop) { 277*b510cdb8SSteven Wu // Test destroying large Trie. Make sure there is no recursion that can 278*b510cdb8SSteven Wu // overflow the stack. 279*b510cdb8SSteven Wu 280*b510cdb8SSteven Wu // Limit the tries to 2 slots (1 bit) to generate subtries at a higher rate. 281*b510cdb8SSteven Wu auto &Trie = createTrie(/*NumRootBits=*/1, /*NumSubtrieBits=*/1); 282*b510cdb8SSteven Wu 283*b510cdb8SSteven Wu // Fill them up. Pick a MaxN high enough to cause a stack overflow in debug 284*b510cdb8SSteven Wu // builds. 285*b510cdb8SSteven Wu static constexpr uint64_t MaxN = 100000; 286*b510cdb8SSteven Wu 287*b510cdb8SSteven Wu uint64_t DestructorCalled = 0; 288*b510cdb8SSteven Wu auto DtorCallback = [&DestructorCalled]() { ++DestructorCalled; }; 289*b510cdb8SSteven Wu for (uint64_t N = 0; N != MaxN; ++N) { 290*b510cdb8SSteven Wu HashType Hash = hash(N); 291*b510cdb8SSteven Wu Trie.insert(TrieType::pointer(), 292*b510cdb8SSteven Wu TrieType::value_type(Hash, NumType{N, DtorCallback})); 293*b510cdb8SSteven Wu } 294*b510cdb8SSteven Wu // Reset the count after all the temporaries get destroyed. 295*b510cdb8SSteven Wu DestructorCalled = 0; 296*b510cdb8SSteven Wu 297*b510cdb8SSteven Wu // Destroy tries. If destruction is recursive and MaxN is high enough, these 298*b510cdb8SSteven Wu // will both fail. 299*b510cdb8SSteven Wu destroyTrie(); 300*b510cdb8SSteven Wu 301*b510cdb8SSteven Wu // Count the number of destructor calls during `destroyTrie()`. 302*b510cdb8SSteven Wu ASSERT_EQ(DestructorCalled, MaxN); 303*b510cdb8SSteven Wu } 304*b510cdb8SSteven Wu 305*b510cdb8SSteven Wu using NumStrNodeTrieTest = SimpleTrieHashMapTest<std::string>; 306*b510cdb8SSteven Wu 307*b510cdb8SSteven Wu TEST_F(NumStrNodeTrieTest, TrieInsertLazy) { 308*b510cdb8SSteven Wu for (unsigned RootBits : {2, 3, 6, 10}) { 309*b510cdb8SSteven Wu for (unsigned SubtrieBits : {2, 3, 4}) { 310*b510cdb8SSteven Wu auto &Trie = createTrie(RootBits, SubtrieBits); 311*b510cdb8SSteven Wu for (int I = 0, E = 1000; I != E; ++I) { 312*b510cdb8SSteven Wu TrieType::pointer Lookup; 313*b510cdb8SSteven Wu HashType H = hash(I); 314*b510cdb8SSteven Wu if (I & 1) 315*b510cdb8SSteven Wu Lookup = Trie.find(H); 316*b510cdb8SSteven Wu 317*b510cdb8SSteven Wu auto insertNum = [&](uint64_t Num) { 318*b510cdb8SSteven Wu std::string S = Twine(I).str(); 319*b510cdb8SSteven Wu auto Hash = hash(Num); 320*b510cdb8SSteven Wu return Trie.insertLazy( 321*b510cdb8SSteven Wu Hash, [&](TrieType::LazyValueConstructor C) { C(std::move(S)); }); 322*b510cdb8SSteven Wu }; 323*b510cdb8SSteven Wu auto S1 = insertNum(I); 324*b510cdb8SSteven Wu // The address of the Data should be the same. 325*b510cdb8SSteven Wu EXPECT_EQ(&S1->Data, &insertNum(I)->Data); 326*b510cdb8SSteven Wu 327*b510cdb8SSteven Wu auto insertStr = [&](std::string S) { 328*b510cdb8SSteven Wu int Num = std::stoi(S); 329*b510cdb8SSteven Wu return insertNum(Num); 330*b510cdb8SSteven Wu }; 331*b510cdb8SSteven Wu std::string S2 = S1->Data; 332*b510cdb8SSteven Wu // The address of the Data should be the same. 333*b510cdb8SSteven Wu EXPECT_EQ(&S1->Data, &insertStr(S2)->Data); 334*b510cdb8SSteven Wu } 335*b510cdb8SSteven Wu for (int I = 0, E = 1000; I != E; ++I) { 336*b510cdb8SSteven Wu std::string S = Twine(I).str(); 337*b510cdb8SSteven Wu TrieType::pointer Lookup = Trie.find(hash(I)); 338*b510cdb8SSteven Wu EXPECT_TRUE(Lookup); 339*b510cdb8SSteven Wu if (!Lookup) 340*b510cdb8SSteven Wu continue; 341*b510cdb8SSteven Wu EXPECT_EQ(S, Lookup->Data); 342*b510cdb8SSteven Wu } 343*b510cdb8SSteven Wu } 344*b510cdb8SSteven Wu } 345*b510cdb8SSteven Wu } 346*b510cdb8SSteven Wu } // end anonymous namespace 347