DenseMap.h revision f6390f48e6324b0221d10a9c75ab625357d8a43a
1//===- llvm/ADT/DenseMap.h - Dense probed hash table ------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file was developed by Chris Lattner and is distributed under 6// the University of Illinois Open Source License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file defines the DenseMap class. 11// 12//===----------------------------------------------------------------------===// 13 14#ifndef LLVM_ADT_DENSEMAP_H 15#define LLVM_ADT_DENSEMAP_H 16 17#include "llvm/Support/DataTypes.h" 18#include <cassert> 19#include <utility> 20 21namespace llvm { 22 23template<typename T> 24struct DenseMapKeyInfo { 25 //static inline T getEmptyKey(); 26 //static inline T getTombstoneKey(); 27 //static unsigned getHashValue(const T &Val); 28 //static bool isPod() 29}; 30 31template<typename T> 32struct DenseMapKeyInfo<T*> { 33 static inline T* getEmptyKey() { return (T*)-1; } 34 static inline T* getTombstoneKey() { return (T*)-2; } 35 static unsigned getHashValue(const T *PtrVal) { 36 return (unsigned)((uintptr_t)PtrVal >> 4) ^ 37 (unsigned)((uintptr_t)PtrVal >> 9); 38 } 39 static bool isPod() { return true; } 40}; 41 42template<typename KeyT, typename ValueT> 43class DenseMapIterator; 44 45template<typename KeyT, typename ValueT> 46class DenseMap { 47 typedef std::pair<KeyT, ValueT> BucketT; 48 unsigned NumBuckets; 49 BucketT *Buckets; 50 51 unsigned NumEntries; 52 DenseMap(const DenseMap &); // not implemented. 53public: 54 explicit DenseMap(unsigned NumInitBuckets = 8) { 55 init(NumInitBuckets); 56 } 57 ~DenseMap() { 58 const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey(); 59 for (BucketT *P = Buckets, *E = Buckets+NumBuckets; P != E; ++P) { 60 if (P->first != EmptyKey && P->first != TombstoneKey) 61 P->second.~ValueT(); 62 P->first.~KeyT(); 63 } 64 delete[] (char*)Buckets; 65 } 66 67 typedef DenseMapIterator<KeyT, ValueT> iterator; 68 typedef DenseMapIterator<KeyT, ValueT> const_iterator; 69 inline iterator begin() const; 70 inline iterator end() const; 71 72 unsigned size() const { return NumEntries; } 73 74 void clear() { 75 const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey(); 76 for (BucketT *P = Buckets, *E = Buckets+NumBuckets; P != E; ++P) { 77 if (P->first != EmptyKey && P->first != TombstoneKey) { 78 P->first = EmptyKey; 79 P->second.~ValueT(); 80 --NumEntries; 81 } 82 } 83 assert(NumEntries == 0 && "Node count imbalance!"); 84 } 85 86 /// count - Return true if the specified key is in the map. 87 bool count(const KeyT &Val) const { 88 BucketT *TheBucket; 89 return LookupBucketFor(Val, TheBucket); 90 } 91 92 ValueT &operator[](const KeyT &Val) { 93 BucketT *TheBucket; 94 if (LookupBucketFor(Val, TheBucket)) 95 return TheBucket->second; 96 97 // If the load of the hash table is more than 3/4, grow it. 98 if (NumEntries*4 >= NumBuckets*3) { 99 this->grow(); 100 LookupBucketFor(Val, TheBucket); 101 } 102 ++NumEntries; 103 TheBucket->first = Val; 104 new (&TheBucket->second) ValueT(); 105 return TheBucket->second; 106 } 107 108private: 109 unsigned getHashValue(const KeyT &Val) const { 110 return DenseMapKeyInfo<KeyT>::getHashValue(Val); 111 } 112 const KeyT getEmptyKey() const { return DenseMapKeyInfo<KeyT>::getEmptyKey();} 113 const KeyT getTombstoneKey() const { 114 return DenseMapKeyInfo<KeyT>::getTombstoneKey(); 115 } 116 117 /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in 118 /// FoundBucket. If the bucket contains the key and a value, this returns 119 /// true, otherwise it returns a bucket with an empty marker or tombstone and 120 /// returns false. 121 bool LookupBucketFor(const KeyT &Val, BucketT *&FoundBucket) const { 122 unsigned BucketNo = getHashValue(Val); 123 unsigned ProbeAmt = 1; 124 BucketT *BucketsPtr = Buckets; 125 126 // FoundTombstone - Keep track of whether we find a tombstone while probing. 127 BucketT *FoundTombstone = 0; 128 const KeyT EmptyKey = getEmptyKey(); 129 const KeyT TombstoneKey = getTombstoneKey(); 130 assert(Val != EmptyKey && Val != TombstoneKey && 131 "Empty/Tombstone value shouldn't be inserted into map!"); 132 133 while (1) { 134 BucketT *ThisBucket = BucketsPtr + (BucketNo & (NumBuckets-1)); 135 // Found Val's bucket? If so, return it. 136 if (ThisBucket->first == Val) { 137 FoundBucket = ThisBucket; 138 return true; 139 } 140 141 // If we found an empty bucket, the key doesn't exist in the set. 142 // Insert it and return the default value. 143 if (ThisBucket->first == EmptyKey) { 144 // If we've already seen a tombstone while probing, fill it in instead 145 // of the empty bucket we eventually probed to. 146 if (FoundTombstone) ThisBucket = FoundTombstone; 147 FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket; 148 return false; 149 } 150 151 // If this is a tombstone, remember it. If Val ends up not in the map, we 152 // prefer to return it than something that would require more probing. 153 if (ThisBucket->first == TombstoneKey && !FoundTombstone) 154 FoundTombstone = ThisBucket; // Remember the first tombstone found. 155 156 // Otherwise, it's a hash collision or a tombstone, continue quadratic 157 // probing. 158 BucketNo += ProbeAmt++; 159 } 160 } 161 162 void init(unsigned InitBuckets) { 163 NumEntries = 0; 164 NumBuckets = InitBuckets; 165 assert(InitBuckets && (InitBuckets & InitBuckets-1) == 0 && 166 "# initial buckets must be a power of two!"); 167 Buckets = (BucketT*)new char[sizeof(BucketT)*InitBuckets]; 168 // Initialize all the keys to EmptyKey. 169 const KeyT EmptyKey = getEmptyKey(); 170 for (unsigned i = 0; i != InitBuckets; ++i) 171 new (&Buckets[i].first) KeyT(EmptyKey); 172 } 173 174 void grow() { 175 unsigned OldNumBuckets = NumBuckets; 176 BucketT *OldBuckets = Buckets; 177 178 // Double the number of buckets. 179 NumBuckets <<= 1; 180 Buckets = (BucketT*)new char[sizeof(BucketT)*NumBuckets]; 181 182 // Initialize all the keys to EmptyKey. 183 const KeyT EmptyKey = getEmptyKey(); 184 for (unsigned i = 0, e = NumBuckets; i != e; ++i) 185 new (&Buckets[i].first) KeyT(EmptyKey); 186 187 // Insert all the old elements. 188 const KeyT TombstoneKey = getTombstoneKey(); 189 for (BucketT *B = OldBuckets, *E = OldBuckets+OldNumBuckets; B != E; ++B) { 190 if (B->first != EmptyKey && B->first != TombstoneKey) { 191 // Insert the key/value into the new table. 192 BucketT *DestBucket; 193 bool FoundVal = LookupBucketFor(B->first, DestBucket); 194 assert(!FoundVal && "Key already in new map?"); 195 DestBucket->first = B->first; 196 new (&DestBucket->second) ValueT(B->second); 197 198 // Free the value. 199 B->second.~ValueT(); 200 } 201 B->first.~KeyT(); 202 } 203 204 // Free the old table. 205 delete[] (char*)OldBuckets; 206 } 207}; 208 209template<typename KeyT, typename ValueT> 210class DenseMapIterator { 211 typedef std::pair<KeyT, ValueT> BucketT; 212 const BucketT *Ptr, *End; 213public: 214 DenseMapIterator(const BucketT *Pos, const BucketT *E) : Ptr(Pos), End(E) { 215 AdvancePastEmptyBuckets(); 216 } 217 218 const std::pair<KeyT, ValueT> &operator*() const { 219 return *Ptr; 220 } 221 const std::pair<KeyT, ValueT> *operator->() const { 222 return Ptr; 223 } 224 225 bool operator==(const DenseMapIterator &RHS) const { 226 return Ptr == RHS.Ptr; 227 } 228 bool operator!=(const DenseMapIterator &RHS) const { 229 return Ptr != RHS.Ptr; 230 } 231 232 inline DenseMapIterator& operator++() { // Preincrement 233 ++Ptr; 234 AdvancePastEmptyBuckets(); 235 return *this; 236 } 237 DenseMapIterator operator++(int) { // Postincrement 238 DenseMapIterator tmp = *this; ++*this; return tmp; 239 } 240 241private: 242 void AdvancePastEmptyBuckets() { 243 const KeyT Empty = DenseMapKeyInfo<KeyT>::getEmptyKey(); 244 const KeyT Tombstone = DenseMapKeyInfo<KeyT>::getTombstoneKey(); 245 246 while (Ptr != End && Ptr->first != Empty && Ptr->first != Tombstone) 247 ++Ptr; 248 } 249}; 250 251 252template<typename KeyT, typename ValueT> 253inline DenseMapIterator<KeyT, ValueT> DenseMap<KeyT, ValueT>::begin() const { 254 return DenseMapIterator<KeyT, ValueT>(Buckets, Buckets+NumBuckets); 255} 256template<typename KeyT, typename ValueT> 257inline DenseMapIterator<KeyT, ValueT> DenseMap<KeyT, ValueT>::end() const { 258 return DenseMapIterator<KeyT, ValueT>(Buckets+NumBuckets, Buckets+NumBuckets); 259} 260 261} // end namespace llvm 262 263#endif 264