1 //===--- StringMap.cpp - String Hash table map implementation -------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the StringMap class.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ADT/StringMap.h"
15 #include "llvm/ADT/StringExtras.h"
19 StringMapImpl::StringMapImpl(unsigned InitSize
, unsigned itemSize
) {
22 // If a size is specified, initialize the table with that many buckets.
28 // Otherwise, initialize it with zero buckets to avoid the allocation.
35 void StringMapImpl::init(unsigned InitSize
) {
36 assert((InitSize
& (InitSize
-1)) == 0 &&
37 "Init Size must be a power of 2 or zero!");
38 NumBuckets
= InitSize
? InitSize
: 16;
42 TheTable
= (ItemBucket
*)calloc(NumBuckets
+1, sizeof(ItemBucket
));
44 // Allocate one extra bucket, set it to look filled so the iterators stop at
46 TheTable
[NumBuckets
].Item
= (StringMapEntryBase
*)2;
50 /// LookupBucketFor - Look up the bucket that the specified string should end
51 /// up in. If it already exists as a key in the map, the Item pointer for the
52 /// specified bucket will be non-null. Otherwise, it will be null. In either
53 /// case, the FullHashValue field of the bucket will be set to the hash value
55 unsigned StringMapImpl::LookupBucketFor(StringRef Name
) {
56 unsigned HTSize
= NumBuckets
;
57 if (HTSize
== 0) { // Hash table unallocated so far?
61 unsigned FullHashValue
= HashString(Name
);
62 unsigned BucketNo
= FullHashValue
& (HTSize
-1);
64 unsigned ProbeAmt
= 1;
65 int FirstTombstone
= -1;
67 ItemBucket
&Bucket
= TheTable
[BucketNo
];
68 StringMapEntryBase
*BucketItem
= Bucket
.Item
;
69 // If we found an empty bucket, this key isn't in the table yet, return it.
70 if (BucketItem
== 0) {
71 // If we found a tombstone, we want to reuse the tombstone instead of an
72 // empty bucket. This reduces probing.
73 if (FirstTombstone
!= -1) {
74 TheTable
[FirstTombstone
].FullHashValue
= FullHashValue
;
75 return FirstTombstone
;
78 Bucket
.FullHashValue
= FullHashValue
;
82 if (BucketItem
== getTombstoneVal()) {
83 // Skip over tombstones. However, remember the first one we see.
84 if (FirstTombstone
== -1) FirstTombstone
= BucketNo
;
85 } else if (Bucket
.FullHashValue
== FullHashValue
) {
86 // If the full hash value matches, check deeply for a match. The common
87 // case here is that we are only looking at the buckets (for item info
88 // being non-null and for the full hash value) not at the items. This
89 // is important for cache locality.
91 // Do the comparison like this because Name isn't necessarily
93 char *ItemStr
= (char*)BucketItem
+ItemSize
;
94 if (Name
== StringRef(ItemStr
, BucketItem
->getKeyLength())) {
100 // Okay, we didn't find the item. Probe to the next bucket.
101 BucketNo
= (BucketNo
+ProbeAmt
) & (HTSize
-1);
103 // Use quadratic probing, it has fewer clumping artifacts than linear
104 // probing and has good cache behavior in the common case.
110 /// FindKey - Look up the bucket that contains the specified key. If it exists
111 /// in the map, return the bucket number of the key. Otherwise return -1.
112 /// This does not modify the map.
113 int StringMapImpl::FindKey(StringRef Key
) const {
114 unsigned HTSize
= NumBuckets
;
115 if (HTSize
== 0) return -1; // Really empty table?
116 unsigned FullHashValue
= HashString(Key
);
117 unsigned BucketNo
= FullHashValue
& (HTSize
-1);
119 unsigned ProbeAmt
= 1;
121 ItemBucket
&Bucket
= TheTable
[BucketNo
];
122 StringMapEntryBase
*BucketItem
= Bucket
.Item
;
123 // If we found an empty bucket, this key isn't in the table yet, return.
127 if (BucketItem
== getTombstoneVal()) {
128 // Ignore tombstones.
129 } else if (Bucket
.FullHashValue
== FullHashValue
) {
130 // If the full hash value matches, check deeply for a match. The common
131 // case here is that we are only looking at the buckets (for item info
132 // being non-null and for the full hash value) not at the items. This
133 // is important for cache locality.
135 // Do the comparison like this because NameStart isn't necessarily
137 char *ItemStr
= (char*)BucketItem
+ItemSize
;
138 if (Key
== StringRef(ItemStr
, BucketItem
->getKeyLength())) {
144 // Okay, we didn't find the item. Probe to the next bucket.
145 BucketNo
= (BucketNo
+ProbeAmt
) & (HTSize
-1);
147 // Use quadratic probing, it has fewer clumping artifacts than linear
148 // probing and has good cache behavior in the common case.
153 /// RemoveKey - Remove the specified StringMapEntry from the table, but do not
154 /// delete it. This aborts if the value isn't in the table.
155 void StringMapImpl::RemoveKey(StringMapEntryBase
*V
) {
156 const char *VStr
= (char*)V
+ ItemSize
;
157 StringMapEntryBase
*V2
= RemoveKey(StringRef(VStr
, V
->getKeyLength()));
159 assert(V
== V2
&& "Didn't find key?");
162 /// RemoveKey - Remove the StringMapEntry for the specified key from the
163 /// table, returning it. If the key is not in the table, this returns null.
164 StringMapEntryBase
*StringMapImpl::RemoveKey(StringRef Key
) {
165 int Bucket
= FindKey(Key
);
166 if (Bucket
== -1) return 0;
168 StringMapEntryBase
*Result
= TheTable
[Bucket
].Item
;
169 TheTable
[Bucket
].Item
= getTombstoneVal();
177 /// RehashTable - Grow the table, redistributing values into the buckets with
178 /// the appropriate mod-of-hashtable-size.
179 void StringMapImpl::RehashTable() {
180 unsigned NewSize
= NumBuckets
*2;
181 // Allocate one extra bucket which will always be non-empty. This allows the
182 // iterators to stop at end.
183 ItemBucket
*NewTableArray
=(ItemBucket
*)calloc(NewSize
+1, sizeof(ItemBucket
));
184 NewTableArray
[NewSize
].Item
= (StringMapEntryBase
*)2;
186 // Rehash all the items into their new buckets. Luckily :) we already have
187 // the hash values available, so we don't have to rehash any strings.
188 for (ItemBucket
*IB
= TheTable
, *E
= TheTable
+NumBuckets
; IB
!= E
; ++IB
) {
189 if (IB
->Item
&& IB
->Item
!= getTombstoneVal()) {
190 // Fast case, bucket available.
191 unsigned FullHash
= IB
->FullHashValue
;
192 unsigned NewBucket
= FullHash
& (NewSize
-1);
193 if (NewTableArray
[NewBucket
].Item
== 0) {
194 NewTableArray
[FullHash
& (NewSize
-1)].Item
= IB
->Item
;
195 NewTableArray
[FullHash
& (NewSize
-1)].FullHashValue
= FullHash
;
199 // Otherwise probe for a spot.
200 unsigned ProbeSize
= 1;
202 NewBucket
= (NewBucket
+ ProbeSize
++) & (NewSize
-1);
203 } while (NewTableArray
[NewBucket
].Item
);
205 // Finally found a slot. Fill it in.
206 NewTableArray
[NewBucket
].Item
= IB
->Item
;
207 NewTableArray
[NewBucket
].FullHashValue
= FullHash
;
213 TheTable
= NewTableArray
;
214 NumBuckets
= NewSize
;