blob: 6f28277890e3978016343e4d22e350377ae37457 [file] [log] [blame]
Chris Lattnerbb28a812007-02-08 19:20:57 +00001//===--- StringMap.cpp - String Hash table map implementation -------------===//
Chris Lattner23d7b362006-10-29 23:42:03 +00002//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner4ee451d2007-12-29 20:36:04 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Chris Lattner23d7b362006-10-29 23:42:03 +00007//
8//===----------------------------------------------------------------------===//
9//
Chris Lattnerbb28a812007-02-08 19:20:57 +000010// This file implements the StringMap class.
Chris Lattner23d7b362006-10-29 23:42:03 +000011//
12//===----------------------------------------------------------------------===//
13
Chris Lattnerbb28a812007-02-08 19:20:57 +000014#include "llvm/ADT/StringMap.h"
Daniel Dunbar4dee7fd2009-10-17 18:21:06 +000015#include "llvm/ADT/StringExtras.h"
Chris Lattner23d7b362006-10-29 23:42:03 +000016#include <cassert>
17using namespace llvm;
18
Chris Lattnerbb28a812007-02-08 19:20:57 +000019StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
Chris Lattner794a0142007-04-04 00:29:37 +000020 ItemSize = itemSize;
21
22 // If a size is specified, initialize the table with that many buckets.
23 if (InitSize) {
24 init(InitSize);
25 return;
26 }
27
28 // Otherwise, initialize it with zero buckets to avoid the allocation.
29 TheTable = 0;
30 NumBuckets = 0;
31 NumItems = 0;
32 NumTombstones = 0;
33}
34
35void StringMapImpl::init(unsigned InitSize) {
Chris Lattner23d7b362006-10-29 23:42:03 +000036 assert((InitSize & (InitSize-1)) == 0 &&
37 "Init Size must be a power of 2 or zero!");
Chris Lattneref4c9162007-04-03 22:15:38 +000038 NumBuckets = InitSize ? InitSize : 16;
Chris Lattner23d7b362006-10-29 23:42:03 +000039 NumItems = 0;
Chris Lattner44dcd012007-02-11 20:58:00 +000040 NumTombstones = 0;
Chris Lattner23d7b362006-10-29 23:42:03 +000041
Chris Lattnerd2f197d2007-04-04 00:44:31 +000042 TheTable = (ItemBucket*)calloc(NumBuckets+1, sizeof(ItemBucket));
Chris Lattnera86559e2007-02-11 08:20:35 +000043
44 // Allocate one extra bucket, set it to look filled so the iterators stop at
45 // end.
46 TheTable[NumBuckets].Item = (StringMapEntryBase*)2;
Chris Lattner23d7b362006-10-29 23:42:03 +000047}
48
49
Chris Lattner23d7b362006-10-29 23:42:03 +000050/// 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
54/// of the string.
Daniel Dunbar2928c832009-11-06 10:58:06 +000055unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
Chris Lattner23d7b362006-10-29 23:42:03 +000056 unsigned HTSize = NumBuckets;
Chris Lattner794a0142007-04-04 00:29:37 +000057 if (HTSize == 0) { // Hash table unallocated so far?
58 init(16);
59 HTSize = NumBuckets;
60 }
Daniel Dunbar4dee7fd2009-10-17 18:21:06 +000061 unsigned FullHashValue = HashString(Name);
Chris Lattner23d7b362006-10-29 23:42:03 +000062 unsigned BucketNo = FullHashValue & (HTSize-1);
63
64 unsigned ProbeAmt = 1;
Chris Lattner44dcd012007-02-11 20:58:00 +000065 int FirstTombstone = -1;
Chris Lattner23d7b362006-10-29 23:42:03 +000066 while (1) {
67 ItemBucket &Bucket = TheTable[BucketNo];
Chris Lattneree182422007-02-08 19:08:37 +000068 StringMapEntryBase *BucketItem = Bucket.Item;
Chris Lattner23d7b362006-10-29 23:42:03 +000069 // If we found an empty bucket, this key isn't in the table yet, return it.
70 if (BucketItem == 0) {
Chris Lattner44dcd012007-02-11 20:58:00 +000071 // 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;
76 }
77
Chris Lattner23d7b362006-10-29 23:42:03 +000078 Bucket.FullHashValue = FullHashValue;
79 return BucketNo;
80 }
81
Chris Lattner44dcd012007-02-11 20:58:00 +000082 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.
90
Daniel Dunbar6316fbc2009-07-23 18:17:34 +000091 // Do the comparison like this because Name isn't necessarily
Chris Lattner23d7b362006-10-29 23:42:03 +000092 // null-terminated!
93 char *ItemStr = (char*)BucketItem+ItemSize;
Daniel Dunbar6316fbc2009-07-23 18:17:34 +000094 if (Name == StringRef(ItemStr, BucketItem->getKeyLength())) {
Chris Lattner23d7b362006-10-29 23:42:03 +000095 // We found a match!
96 return BucketNo;
97 }
98 }
99
100 // Okay, we didn't find the item. Probe to the next bucket.
101 BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
102
103 // Use quadratic probing, it has fewer clumping artifacts than linear
104 // probing and has good cache behavior in the common case.
105 ++ProbeAmt;
106 }
107}
108
Chris Lattnerb5bb9f52007-02-11 19:49:41 +0000109
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.
Daniel Dunbar2928c832009-11-06 10:58:06 +0000113int StringMapImpl::FindKey(StringRef Key) const {
Chris Lattnerb5bb9f52007-02-11 19:49:41 +0000114 unsigned HTSize = NumBuckets;
Chris Lattner794a0142007-04-04 00:29:37 +0000115 if (HTSize == 0) return -1; // Really empty table?
Daniel Dunbar4dee7fd2009-10-17 18:21:06 +0000116 unsigned FullHashValue = HashString(Key);
Chris Lattnerb5bb9f52007-02-11 19:49:41 +0000117 unsigned BucketNo = FullHashValue & (HTSize-1);
118
119 unsigned ProbeAmt = 1;
120 while (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.
124 if (BucketItem == 0)
125 return -1;
126
Chris Lattner44dcd012007-02-11 20:58:00 +0000127 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.
134
Chris Lattnerb5bb9f52007-02-11 19:49:41 +0000135 // Do the comparison like this because NameStart isn't necessarily
136 // null-terminated!
137 char *ItemStr = (char*)BucketItem+ItemSize;
Daniel Dunbar6316fbc2009-07-23 18:17:34 +0000138 if (Key == StringRef(ItemStr, BucketItem->getKeyLength())) {
Chris Lattnerb5bb9f52007-02-11 19:49:41 +0000139 // We found a match!
140 return BucketNo;
141 }
142 }
143
144 // Okay, we didn't find the item. Probe to the next bucket.
145 BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
146
147 // Use quadratic probing, it has fewer clumping artifacts than linear
148 // probing and has good cache behavior in the common case.
149 ++ProbeAmt;
150 }
151}
152
Chris Lattner44dcd012007-02-11 20:58:00 +0000153/// RemoveKey - Remove the specified StringMapEntry from the table, but do not
154/// delete it. This aborts if the value isn't in the table.
155void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
156 const char *VStr = (char*)V + ItemSize;
Daniel Dunbar6316fbc2009-07-23 18:17:34 +0000157 StringMapEntryBase *V2 = RemoveKey(StringRef(VStr, V->getKeyLength()));
Chris Lattner44dcd012007-02-11 20:58:00 +0000158 V2 = V2;
159 assert(V == V2 && "Didn't find key?");
160}
161
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.
Daniel Dunbar2928c832009-11-06 10:58:06 +0000164StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) {
Daniel Dunbar6316fbc2009-07-23 18:17:34 +0000165 int Bucket = FindKey(Key);
Chris Lattner44dcd012007-02-11 20:58:00 +0000166 if (Bucket == -1) return 0;
167
168 StringMapEntryBase *Result = TheTable[Bucket].Item;
169 TheTable[Bucket].Item = getTombstoneVal();
170 --NumItems;
171 ++NumTombstones;
172 return Result;
173}
174
175
Chris Lattnerb5bb9f52007-02-11 19:49:41 +0000176
Chris Lattner23d7b362006-10-29 23:42:03 +0000177/// RehashTable - Grow the table, redistributing values into the buckets with
178/// the appropriate mod-of-hashtable-size.
Chris Lattnerbb28a812007-02-08 19:20:57 +0000179void StringMapImpl::RehashTable() {
Chris Lattner23d7b362006-10-29 23:42:03 +0000180 unsigned NewSize = NumBuckets*2;
Chris Lattnera86559e2007-02-11 08:20:35 +0000181 // Allocate one extra bucket which will always be non-empty. This allows the
182 // iterators to stop at end.
Chris Lattnerd2f197d2007-04-04 00:44:31 +0000183 ItemBucket *NewTableArray =(ItemBucket*)calloc(NewSize+1, sizeof(ItemBucket));
Chris Lattnera86559e2007-02-11 08:20:35 +0000184 NewTableArray[NewSize].Item = (StringMapEntryBase*)2;
Chris Lattner23d7b362006-10-29 23:42:03 +0000185
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) {
Chris Lattner44dcd012007-02-11 20:58:00 +0000189 if (IB->Item && IB->Item != getTombstoneVal()) {
Chris Lattner23d7b362006-10-29 23:42:03 +0000190 // 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;
196 continue;
197 }
198
Chris Lattner44dcd012007-02-11 20:58:00 +0000199 // Otherwise probe for a spot.
Chris Lattner23d7b362006-10-29 23:42:03 +0000200 unsigned ProbeSize = 1;
201 do {
202 NewBucket = (NewBucket + ProbeSize++) & (NewSize-1);
203 } while (NewTableArray[NewBucket].Item);
204
205 // Finally found a slot. Fill it in.
206 NewTableArray[NewBucket].Item = IB->Item;
207 NewTableArray[NewBucket].FullHashValue = FullHash;
208 }
209 }
210
Chris Lattner12ba8062007-04-04 17:24:28 +0000211 free(TheTable);
Chris Lattner23d7b362006-10-29 23:42:03 +0000212
213 TheTable = NewTableArray;
214 NumBuckets = NewSize;
215}