@@ -102,14 +102,15 @@ class TrieSubtrie final : public TrieNode {
102102};
103103} // end namespace
104104
105- static size_t getTrieTailSize (size_t StartBit, size_t NumBits) {
106- assert (NumBits < 20 && " Tries should have fewer than ~1M slots" );
105+ // Compute the trailing object size in the trie node. This is the size of \c
106+ // Slots in TrieNodes that pointing to the children.
107+ static size_t getTrieTailSize (size_t NumBits) {
107108 return sizeof (TrieNode *) * (1u << NumBits);
108109}
109110
110111std::unique_ptr<TrieSubtrie> TrieSubtrie::create (size_t StartBit,
111112 size_t NumBits) {
112- size_t Size = sizeof (TrieSubtrie) + getTrieTailSize (StartBit, NumBits);
113+ size_t Size = sizeof (TrieSubtrie) + getTrieTailSize (NumBits);
113114 void *Memory = ::malloc (Size);
114115 TrieSubtrie *S = ::new (Memory) TrieSubtrie (StartBit, NumBits);
115116 return std::unique_ptr<TrieSubtrie>(S);
@@ -128,15 +129,22 @@ TrieSubtrie::TrieSubtrie(size_t StartBit, size_t NumBits)
128129 " Expected no work in destructor for TrieNode" );
129130}
130131
132+ // Sink the nodes down sub-trie when the object being inserted collides with
133+ // the index of existing object in the trie. In this case, a new sub-trie needs
134+ // to be allocated to hold existing object.
131135TrieSubtrie *TrieSubtrie::sink (
132136 size_t I, TrieContent &Content, size_t NumSubtrieBits, size_t NewI,
133137 function_ref<TrieSubtrie *(std::unique_ptr<TrieSubtrie>)> Saver) {
138+ // Create a new sub-trie that points to the existing object with the new
139+ // index for the next level.
134140 assert (NumSubtrieBits > 0 );
135141 std::unique_ptr<TrieSubtrie> S = create (StartBit + NumBits, NumSubtrieBits);
136142
137143 assert (NewI < S->Slots .size ());
138144 S->Slots [NewI].store (&Content);
139145
146+ // Using compare_exchange to atomically add back the new sub-trie to the trie
147+ // in the place of the exsiting object.
140148 TrieNode *ExistingNode = &Content;
141149 assert (I < Slots.size ());
142150 if (Slots[I].compare_exchange_strong (ExistingNode, S.get ()))
@@ -149,12 +157,15 @@ TrieSubtrie *TrieSubtrie::sink(
149157
150158struct ThreadSafeTrieRawHashMapBase ::ImplType {
151159 static std::unique_ptr<ImplType> create (size_t StartBit, size_t NumBits) {
152- size_t Size = sizeof (ImplType) + getTrieTailSize (StartBit, NumBits);
160+ size_t Size = sizeof (ImplType) + getTrieTailSize (NumBits);
153161 void *Memory = ::malloc (Size);
154162 ImplType *Impl = ::new (Memory) ImplType (StartBit, NumBits);
155163 return std::unique_ptr<ImplType>(Impl);
156164 }
157165
166+ // Save the Subtrie into the ownship list of the trie structure in a
167+ // thread-safe way. The ownership transfer is done by compare_exchange the
168+ // pointer value inside the unique_ptr.
158169 TrieSubtrie *save (std::unique_ptr<TrieSubtrie> S) {
159170 assert (!S->Next && " Expected S to a freshly-constructed leaf" );
160171
@@ -306,12 +317,7 @@ ThreadSafeTrieRawHashMapBase::ThreadSafeTrieRawHashMapBase(
306317 ContentOffset(ContentOffset),
307318 NumRootBits(NumRootBits ? *NumRootBits : DefaultNumRootBits),
308319 NumSubtrieBits(NumSubtrieBits ? *NumSubtrieBits : DefaultNumSubtrieBits),
309- ImplPtr(nullptr ) {
310- assert ((!NumRootBits || *NumRootBits < 20 ) &&
311- " Root should have fewer than ~1M slots" );
312- assert ((!NumSubtrieBits || *NumSubtrieBits < 10 ) &&
313- " Subtries should have fewer than ~1K slots" );
314- }
320+ ImplPtr(nullptr ) {}
315321
316322ThreadSafeTrieRawHashMapBase::ThreadSafeTrieRawHashMapBase (
317323 ThreadSafeTrieRawHashMapBase &&RHS)
@@ -413,7 +419,7 @@ std::string ThreadSafeTrieRawHashMapBase::getTriePrefixAsString(
413419 TrieContent *Node = nullptr ;
414420 while (Current) {
415421 TrieSubtrie *Next = nullptr ;
416- // find first used slot in the trie.
422+ // Find first used slot in the trie.
417423 for (unsigned I = 0 , E = Current->Slots .size (); I < E; ++I) {
418424 auto *S = Current->get (I);
419425 if (!S)
0 commit comments