xref: /aosp_15_r20/external/llvm/lib/Support/StringMap.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===--- StringMap.cpp - String Hash table map implementation -------------===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker //
10*9880d681SAndroid Build Coastguard Worker // This file implements the StringMap class.
11*9880d681SAndroid Build Coastguard Worker //
12*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
13*9880d681SAndroid Build Coastguard Worker 
14*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/StringMap.h"
15*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/StringExtras.h"
16*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/Compiler.h"
17*9880d681SAndroid Build Coastguard Worker #include <cassert>
18*9880d681SAndroid Build Coastguard Worker using namespace llvm;
19*9880d681SAndroid Build Coastguard Worker 
20*9880d681SAndroid Build Coastguard Worker /// Returns the number of buckets to allocate to ensure that the DenseMap can
21*9880d681SAndroid Build Coastguard Worker /// accommodate \p NumEntries without need to grow().
getMinBucketToReserveForEntries(unsigned NumEntries)22*9880d681SAndroid Build Coastguard Worker static unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
23*9880d681SAndroid Build Coastguard Worker   // Ensure that "NumEntries * 4 < NumBuckets * 3"
24*9880d681SAndroid Build Coastguard Worker   if (NumEntries == 0)
25*9880d681SAndroid Build Coastguard Worker     return 0;
26*9880d681SAndroid Build Coastguard Worker   // +1 is required because of the strict equality.
27*9880d681SAndroid Build Coastguard Worker   // For example if NumEntries is 48, we need to return 401.
28*9880d681SAndroid Build Coastguard Worker   return NextPowerOf2(NumEntries * 4 / 3 + 1);
29*9880d681SAndroid Build Coastguard Worker }
30*9880d681SAndroid Build Coastguard Worker 
StringMapImpl(unsigned InitSize,unsigned itemSize)31*9880d681SAndroid Build Coastguard Worker StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
32*9880d681SAndroid Build Coastguard Worker   ItemSize = itemSize;
33*9880d681SAndroid Build Coastguard Worker 
34*9880d681SAndroid Build Coastguard Worker   // If a size is specified, initialize the table with that many buckets.
35*9880d681SAndroid Build Coastguard Worker   if (InitSize) {
36*9880d681SAndroid Build Coastguard Worker     // The table will grow when the number of entries reach 3/4 of the number of
37*9880d681SAndroid Build Coastguard Worker     // buckets. To guarantee that "InitSize" number of entries can be inserted
38*9880d681SAndroid Build Coastguard Worker     // in the table without growing, we allocate just what is needed here.
39*9880d681SAndroid Build Coastguard Worker     init(getMinBucketToReserveForEntries(InitSize));
40*9880d681SAndroid Build Coastguard Worker     return;
41*9880d681SAndroid Build Coastguard Worker   }
42*9880d681SAndroid Build Coastguard Worker 
43*9880d681SAndroid Build Coastguard Worker   // Otherwise, initialize it with zero buckets to avoid the allocation.
44*9880d681SAndroid Build Coastguard Worker   TheTable = nullptr;
45*9880d681SAndroid Build Coastguard Worker   NumBuckets = 0;
46*9880d681SAndroid Build Coastguard Worker   NumItems = 0;
47*9880d681SAndroid Build Coastguard Worker   NumTombstones = 0;
48*9880d681SAndroid Build Coastguard Worker }
49*9880d681SAndroid Build Coastguard Worker 
init(unsigned InitSize)50*9880d681SAndroid Build Coastguard Worker void StringMapImpl::init(unsigned InitSize) {
51*9880d681SAndroid Build Coastguard Worker   assert((InitSize & (InitSize-1)) == 0 &&
52*9880d681SAndroid Build Coastguard Worker          "Init Size must be a power of 2 or zero!");
53*9880d681SAndroid Build Coastguard Worker   NumBuckets = InitSize ? InitSize : 16;
54*9880d681SAndroid Build Coastguard Worker   NumItems = 0;
55*9880d681SAndroid Build Coastguard Worker   NumTombstones = 0;
56*9880d681SAndroid Build Coastguard Worker 
57*9880d681SAndroid Build Coastguard Worker   TheTable = (StringMapEntryBase **)calloc(NumBuckets+1,
58*9880d681SAndroid Build Coastguard Worker                                            sizeof(StringMapEntryBase **) +
59*9880d681SAndroid Build Coastguard Worker                                            sizeof(unsigned));
60*9880d681SAndroid Build Coastguard Worker 
61*9880d681SAndroid Build Coastguard Worker   // Allocate one extra bucket, set it to look filled so the iterators stop at
62*9880d681SAndroid Build Coastguard Worker   // end.
63*9880d681SAndroid Build Coastguard Worker   TheTable[NumBuckets] = (StringMapEntryBase*)2;
64*9880d681SAndroid Build Coastguard Worker }
65*9880d681SAndroid Build Coastguard Worker 
66*9880d681SAndroid Build Coastguard Worker 
67*9880d681SAndroid Build Coastguard Worker /// LookupBucketFor - Look up the bucket that the specified string should end
68*9880d681SAndroid Build Coastguard Worker /// up in.  If it already exists as a key in the map, the Item pointer for the
69*9880d681SAndroid Build Coastguard Worker /// specified bucket will be non-null.  Otherwise, it will be null.  In either
70*9880d681SAndroid Build Coastguard Worker /// case, the FullHashValue field of the bucket will be set to the hash value
71*9880d681SAndroid Build Coastguard Worker /// of the string.
LookupBucketFor(StringRef Name)72*9880d681SAndroid Build Coastguard Worker unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
73*9880d681SAndroid Build Coastguard Worker   unsigned HTSize = NumBuckets;
74*9880d681SAndroid Build Coastguard Worker   if (HTSize == 0) {  // Hash table unallocated so far?
75*9880d681SAndroid Build Coastguard Worker     init(16);
76*9880d681SAndroid Build Coastguard Worker     HTSize = NumBuckets;
77*9880d681SAndroid Build Coastguard Worker   }
78*9880d681SAndroid Build Coastguard Worker   unsigned FullHashValue = HashString(Name);
79*9880d681SAndroid Build Coastguard Worker   unsigned BucketNo = FullHashValue & (HTSize-1);
80*9880d681SAndroid Build Coastguard Worker   unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
81*9880d681SAndroid Build Coastguard Worker 
82*9880d681SAndroid Build Coastguard Worker   unsigned ProbeAmt = 1;
83*9880d681SAndroid Build Coastguard Worker   int FirstTombstone = -1;
84*9880d681SAndroid Build Coastguard Worker   while (1) {
85*9880d681SAndroid Build Coastguard Worker     StringMapEntryBase *BucketItem = TheTable[BucketNo];
86*9880d681SAndroid Build Coastguard Worker     // If we found an empty bucket, this key isn't in the table yet, return it.
87*9880d681SAndroid Build Coastguard Worker     if (LLVM_LIKELY(!BucketItem)) {
88*9880d681SAndroid Build Coastguard Worker       // If we found a tombstone, we want to reuse the tombstone instead of an
89*9880d681SAndroid Build Coastguard Worker       // empty bucket.  This reduces probing.
90*9880d681SAndroid Build Coastguard Worker       if (FirstTombstone != -1) {
91*9880d681SAndroid Build Coastguard Worker         HashTable[FirstTombstone] = FullHashValue;
92*9880d681SAndroid Build Coastguard Worker         return FirstTombstone;
93*9880d681SAndroid Build Coastguard Worker       }
94*9880d681SAndroid Build Coastguard Worker 
95*9880d681SAndroid Build Coastguard Worker       HashTable[BucketNo] = FullHashValue;
96*9880d681SAndroid Build Coastguard Worker       return BucketNo;
97*9880d681SAndroid Build Coastguard Worker     }
98*9880d681SAndroid Build Coastguard Worker 
99*9880d681SAndroid Build Coastguard Worker     if (BucketItem == getTombstoneVal()) {
100*9880d681SAndroid Build Coastguard Worker       // Skip over tombstones.  However, remember the first one we see.
101*9880d681SAndroid Build Coastguard Worker       if (FirstTombstone == -1) FirstTombstone = BucketNo;
102*9880d681SAndroid Build Coastguard Worker     } else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) {
103*9880d681SAndroid Build Coastguard Worker       // If the full hash value matches, check deeply for a match.  The common
104*9880d681SAndroid Build Coastguard Worker       // case here is that we are only looking at the buckets (for item info
105*9880d681SAndroid Build Coastguard Worker       // being non-null and for the full hash value) not at the items.  This
106*9880d681SAndroid Build Coastguard Worker       // is important for cache locality.
107*9880d681SAndroid Build Coastguard Worker 
108*9880d681SAndroid Build Coastguard Worker       // Do the comparison like this because Name isn't necessarily
109*9880d681SAndroid Build Coastguard Worker       // null-terminated!
110*9880d681SAndroid Build Coastguard Worker       char *ItemStr = (char*)BucketItem+ItemSize;
111*9880d681SAndroid Build Coastguard Worker       if (Name == StringRef(ItemStr, BucketItem->getKeyLength())) {
112*9880d681SAndroid Build Coastguard Worker         // We found a match!
113*9880d681SAndroid Build Coastguard Worker         return BucketNo;
114*9880d681SAndroid Build Coastguard Worker       }
115*9880d681SAndroid Build Coastguard Worker     }
116*9880d681SAndroid Build Coastguard Worker 
117*9880d681SAndroid Build Coastguard Worker     // Okay, we didn't find the item.  Probe to the next bucket.
118*9880d681SAndroid Build Coastguard Worker     BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
119*9880d681SAndroid Build Coastguard Worker 
120*9880d681SAndroid Build Coastguard Worker     // Use quadratic probing, it has fewer clumping artifacts than linear
121*9880d681SAndroid Build Coastguard Worker     // probing and has good cache behavior in the common case.
122*9880d681SAndroid Build Coastguard Worker     ++ProbeAmt;
123*9880d681SAndroid Build Coastguard Worker   }
124*9880d681SAndroid Build Coastguard Worker }
125*9880d681SAndroid Build Coastguard Worker 
126*9880d681SAndroid Build Coastguard Worker 
127*9880d681SAndroid Build Coastguard Worker /// FindKey - Look up the bucket that contains the specified key. If it exists
128*9880d681SAndroid Build Coastguard Worker /// in the map, return the bucket number of the key.  Otherwise return -1.
129*9880d681SAndroid Build Coastguard Worker /// This does not modify the map.
FindKey(StringRef Key) const130*9880d681SAndroid Build Coastguard Worker int StringMapImpl::FindKey(StringRef Key) const {
131*9880d681SAndroid Build Coastguard Worker   unsigned HTSize = NumBuckets;
132*9880d681SAndroid Build Coastguard Worker   if (HTSize == 0) return -1;  // Really empty table?
133*9880d681SAndroid Build Coastguard Worker   unsigned FullHashValue = HashString(Key);
134*9880d681SAndroid Build Coastguard Worker   unsigned BucketNo = FullHashValue & (HTSize-1);
135*9880d681SAndroid Build Coastguard Worker   unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
136*9880d681SAndroid Build Coastguard Worker 
137*9880d681SAndroid Build Coastguard Worker   unsigned ProbeAmt = 1;
138*9880d681SAndroid Build Coastguard Worker   while (1) {
139*9880d681SAndroid Build Coastguard Worker     StringMapEntryBase *BucketItem = TheTable[BucketNo];
140*9880d681SAndroid Build Coastguard Worker     // If we found an empty bucket, this key isn't in the table yet, return.
141*9880d681SAndroid Build Coastguard Worker     if (LLVM_LIKELY(!BucketItem))
142*9880d681SAndroid Build Coastguard Worker       return -1;
143*9880d681SAndroid Build Coastguard Worker 
144*9880d681SAndroid Build Coastguard Worker     if (BucketItem == getTombstoneVal()) {
145*9880d681SAndroid Build Coastguard Worker       // Ignore tombstones.
146*9880d681SAndroid Build Coastguard Worker     } else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) {
147*9880d681SAndroid Build Coastguard Worker       // If the full hash value matches, check deeply for a match.  The common
148*9880d681SAndroid Build Coastguard Worker       // case here is that we are only looking at the buckets (for item info
149*9880d681SAndroid Build Coastguard Worker       // being non-null and for the full hash value) not at the items.  This
150*9880d681SAndroid Build Coastguard Worker       // is important for cache locality.
151*9880d681SAndroid Build Coastguard Worker 
152*9880d681SAndroid Build Coastguard Worker       // Do the comparison like this because NameStart isn't necessarily
153*9880d681SAndroid Build Coastguard Worker       // null-terminated!
154*9880d681SAndroid Build Coastguard Worker       char *ItemStr = (char*)BucketItem+ItemSize;
155*9880d681SAndroid Build Coastguard Worker       if (Key == StringRef(ItemStr, BucketItem->getKeyLength())) {
156*9880d681SAndroid Build Coastguard Worker         // We found a match!
157*9880d681SAndroid Build Coastguard Worker         return BucketNo;
158*9880d681SAndroid Build Coastguard Worker       }
159*9880d681SAndroid Build Coastguard Worker     }
160*9880d681SAndroid Build Coastguard Worker 
161*9880d681SAndroid Build Coastguard Worker     // Okay, we didn't find the item.  Probe to the next bucket.
162*9880d681SAndroid Build Coastguard Worker     BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
163*9880d681SAndroid Build Coastguard Worker 
164*9880d681SAndroid Build Coastguard Worker     // Use quadratic probing, it has fewer clumping artifacts than linear
165*9880d681SAndroid Build Coastguard Worker     // probing and has good cache behavior in the common case.
166*9880d681SAndroid Build Coastguard Worker     ++ProbeAmt;
167*9880d681SAndroid Build Coastguard Worker   }
168*9880d681SAndroid Build Coastguard Worker }
169*9880d681SAndroid Build Coastguard Worker 
170*9880d681SAndroid Build Coastguard Worker /// RemoveKey - Remove the specified StringMapEntry from the table, but do not
171*9880d681SAndroid Build Coastguard Worker /// delete it.  This aborts if the value isn't in the table.
RemoveKey(StringMapEntryBase * V)172*9880d681SAndroid Build Coastguard Worker void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
173*9880d681SAndroid Build Coastguard Worker   const char *VStr = (char*)V + ItemSize;
174*9880d681SAndroid Build Coastguard Worker   StringMapEntryBase *V2 = RemoveKey(StringRef(VStr, V->getKeyLength()));
175*9880d681SAndroid Build Coastguard Worker   (void)V2;
176*9880d681SAndroid Build Coastguard Worker   assert(V == V2 && "Didn't find key?");
177*9880d681SAndroid Build Coastguard Worker }
178*9880d681SAndroid Build Coastguard Worker 
179*9880d681SAndroid Build Coastguard Worker /// RemoveKey - Remove the StringMapEntry for the specified key from the
180*9880d681SAndroid Build Coastguard Worker /// table, returning it.  If the key is not in the table, this returns null.
RemoveKey(StringRef Key)181*9880d681SAndroid Build Coastguard Worker StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) {
182*9880d681SAndroid Build Coastguard Worker   int Bucket = FindKey(Key);
183*9880d681SAndroid Build Coastguard Worker   if (Bucket == -1) return nullptr;
184*9880d681SAndroid Build Coastguard Worker 
185*9880d681SAndroid Build Coastguard Worker   StringMapEntryBase *Result = TheTable[Bucket];
186*9880d681SAndroid Build Coastguard Worker   TheTable[Bucket] = getTombstoneVal();
187*9880d681SAndroid Build Coastguard Worker   --NumItems;
188*9880d681SAndroid Build Coastguard Worker   ++NumTombstones;
189*9880d681SAndroid Build Coastguard Worker   assert(NumItems + NumTombstones <= NumBuckets);
190*9880d681SAndroid Build Coastguard Worker 
191*9880d681SAndroid Build Coastguard Worker   return Result;
192*9880d681SAndroid Build Coastguard Worker }
193*9880d681SAndroid Build Coastguard Worker 
194*9880d681SAndroid Build Coastguard Worker 
195*9880d681SAndroid Build Coastguard Worker 
196*9880d681SAndroid Build Coastguard Worker /// RehashTable - Grow the table, redistributing values into the buckets with
197*9880d681SAndroid Build Coastguard Worker /// the appropriate mod-of-hashtable-size.
RehashTable(unsigned BucketNo)198*9880d681SAndroid Build Coastguard Worker unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
199*9880d681SAndroid Build Coastguard Worker   unsigned NewSize;
200*9880d681SAndroid Build Coastguard Worker   unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
201*9880d681SAndroid Build Coastguard Worker 
202*9880d681SAndroid Build Coastguard Worker   // If the hash table is now more than 3/4 full, or if fewer than 1/8 of
203*9880d681SAndroid Build Coastguard Worker   // the buckets are empty (meaning that many are filled with tombstones),
204*9880d681SAndroid Build Coastguard Worker   // grow/rehash the table.
205*9880d681SAndroid Build Coastguard Worker   if (LLVM_UNLIKELY(NumItems * 4 > NumBuckets * 3)) {
206*9880d681SAndroid Build Coastguard Worker     NewSize = NumBuckets*2;
207*9880d681SAndroid Build Coastguard Worker   } else if (LLVM_UNLIKELY(NumBuckets - (NumItems + NumTombstones) <=
208*9880d681SAndroid Build Coastguard Worker                            NumBuckets / 8)) {
209*9880d681SAndroid Build Coastguard Worker     NewSize = NumBuckets;
210*9880d681SAndroid Build Coastguard Worker   } else {
211*9880d681SAndroid Build Coastguard Worker     return BucketNo;
212*9880d681SAndroid Build Coastguard Worker   }
213*9880d681SAndroid Build Coastguard Worker 
214*9880d681SAndroid Build Coastguard Worker   unsigned NewBucketNo = BucketNo;
215*9880d681SAndroid Build Coastguard Worker   // Allocate one extra bucket which will always be non-empty.  This allows the
216*9880d681SAndroid Build Coastguard Worker   // iterators to stop at end.
217*9880d681SAndroid Build Coastguard Worker   StringMapEntryBase **NewTableArray =
218*9880d681SAndroid Build Coastguard Worker     (StringMapEntryBase **)calloc(NewSize+1, sizeof(StringMapEntryBase *) +
219*9880d681SAndroid Build Coastguard Worker                                              sizeof(unsigned));
220*9880d681SAndroid Build Coastguard Worker   unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1);
221*9880d681SAndroid Build Coastguard Worker   NewTableArray[NewSize] = (StringMapEntryBase*)2;
222*9880d681SAndroid Build Coastguard Worker 
223*9880d681SAndroid Build Coastguard Worker   // Rehash all the items into their new buckets.  Luckily :) we already have
224*9880d681SAndroid Build Coastguard Worker   // the hash values available, so we don't have to rehash any strings.
225*9880d681SAndroid Build Coastguard Worker   for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
226*9880d681SAndroid Build Coastguard Worker     StringMapEntryBase *Bucket = TheTable[I];
227*9880d681SAndroid Build Coastguard Worker     if (Bucket && Bucket != getTombstoneVal()) {
228*9880d681SAndroid Build Coastguard Worker       // Fast case, bucket available.
229*9880d681SAndroid Build Coastguard Worker       unsigned FullHash = HashTable[I];
230*9880d681SAndroid Build Coastguard Worker       unsigned NewBucket = FullHash & (NewSize-1);
231*9880d681SAndroid Build Coastguard Worker       if (!NewTableArray[NewBucket]) {
232*9880d681SAndroid Build Coastguard Worker         NewTableArray[FullHash & (NewSize-1)] = Bucket;
233*9880d681SAndroid Build Coastguard Worker         NewHashArray[FullHash & (NewSize-1)] = FullHash;
234*9880d681SAndroid Build Coastguard Worker         if (I == BucketNo)
235*9880d681SAndroid Build Coastguard Worker           NewBucketNo = NewBucket;
236*9880d681SAndroid Build Coastguard Worker         continue;
237*9880d681SAndroid Build Coastguard Worker       }
238*9880d681SAndroid Build Coastguard Worker 
239*9880d681SAndroid Build Coastguard Worker       // Otherwise probe for a spot.
240*9880d681SAndroid Build Coastguard Worker       unsigned ProbeSize = 1;
241*9880d681SAndroid Build Coastguard Worker       do {
242*9880d681SAndroid Build Coastguard Worker         NewBucket = (NewBucket + ProbeSize++) & (NewSize-1);
243*9880d681SAndroid Build Coastguard Worker       } while (NewTableArray[NewBucket]);
244*9880d681SAndroid Build Coastguard Worker 
245*9880d681SAndroid Build Coastguard Worker       // Finally found a slot.  Fill it in.
246*9880d681SAndroid Build Coastguard Worker       NewTableArray[NewBucket] = Bucket;
247*9880d681SAndroid Build Coastguard Worker       NewHashArray[NewBucket] = FullHash;
248*9880d681SAndroid Build Coastguard Worker       if (I == BucketNo)
249*9880d681SAndroid Build Coastguard Worker         NewBucketNo = NewBucket;
250*9880d681SAndroid Build Coastguard Worker     }
251*9880d681SAndroid Build Coastguard Worker   }
252*9880d681SAndroid Build Coastguard Worker 
253*9880d681SAndroid Build Coastguard Worker   free(TheTable);
254*9880d681SAndroid Build Coastguard Worker 
255*9880d681SAndroid Build Coastguard Worker   TheTable = NewTableArray;
256*9880d681SAndroid Build Coastguard Worker   NumBuckets = NewSize;
257*9880d681SAndroid Build Coastguard Worker   NumTombstones = 0;
258*9880d681SAndroid Build Coastguard Worker   return NewBucketNo;
259*9880d681SAndroid Build Coastguard Worker }
260