1 //===- ScopedHashTable.h - A simple scoped hash table ---------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements an efficient scoped hash table, which is useful for 11 // things like dominator-based optimizations. This allows clients to do things 12 // like this: 13 // 14 // ScopedHashTable<int, int> HT; 15 // { 16 // ScopedHashTableScope<int, int> Scope1(HT); 17 // HT.insert(0, 0); 18 // HT.insert(1, 1); 19 // { 20 // ScopedHashTableScope<int, int> Scope2(HT); 21 // HT.insert(0, 42); 22 // } 23 // } 24 // 25 // Looking up the value for "0" in the Scope2 block will return 42. Looking 26 // up the value for 0 before 42 is inserted or after Scope2 is popped will 27 // return 0. 28 // 29 //===----------------------------------------------------------------------===// 30 31 #ifndef LLVM_ADT_SCOPEDHASHTABLE_H 32 #define LLVM_ADT_SCOPEDHASHTABLE_H 33 34 #include "llvm/ADT/DenseMap.h" 35 #include "llvm/Support/Allocator.h" 36 37 namespace llvm { 38 39 template <typename K, typename V, typename KInfo = DenseMapInfo<K>, 40 typename AllocatorTy = MallocAllocator> 41 class ScopedHashTable; 42 43 template <typename K, typename V> 44 class ScopedHashTableVal { 45 ScopedHashTableVal *NextInScope; 46 ScopedHashTableVal *NextForKey; 47 K Key; 48 V Val; 49 ScopedHashTableVal(const K &key, const V &val) : Key(key), Val(val) {} 50 public: 51 52 const K &getKey() const { return Key; } 53 const V &getValue() const { return Val; } 54 V &getValue() { return Val; } 55 56 ScopedHashTableVal *getNextForKey() { return NextForKey; } 57 const ScopedHashTableVal *getNextForKey() const { return NextForKey; } 58 ScopedHashTableVal *getNextInScope() { return NextInScope; } 59 60 template <typename AllocatorTy> 61 static ScopedHashTableVal *Create(ScopedHashTableVal *nextInScope, 62 ScopedHashTableVal *nextForKey, 63 const K &key, const V &val, 64 AllocatorTy &Allocator) { 65 ScopedHashTableVal *New = Allocator.template Allocate<ScopedHashTableVal>(); 66 // Set up the value. 67 new (New) ScopedHashTableVal(key, val); 68 New->NextInScope = nextInScope; 69 New->NextForKey = nextForKey; 70 return New; 71 } 72 73 template <typename AllocatorTy> 74 void Destroy(AllocatorTy &Allocator) { 75 // Free memory referenced by the item. 76 this->~ScopedHashTableVal(); 77 Allocator.Deallocate(this); 78 } 79 }; 80 81 template <typename K, typename V, typename KInfo = DenseMapInfo<K>, 82 typename AllocatorTy = MallocAllocator> 83 class ScopedHashTableScope { 84 /// HT - The hashtable that we are active for. 85 ScopedHashTable<K, V, KInfo, AllocatorTy> &HT; 86 87 /// PrevScope - This is the scope that we are shadowing in HT. 88 ScopedHashTableScope *PrevScope; 89 90 /// LastValInScope - This is the last value that was inserted for this scope 91 /// or null if none have been inserted yet. 92 ScopedHashTableVal<K, V> *LastValInScope; 93 void operator=(ScopedHashTableScope&); // DO NOT IMPLEMENT 94 ScopedHashTableScope(ScopedHashTableScope&); // DO NOT IMPLEMENT 95 public: 96 ScopedHashTableScope(ScopedHashTable<K, V, KInfo, AllocatorTy> &HT); 97 ~ScopedHashTableScope(); 98 99 ScopedHashTableScope *getParentScope() { return PrevScope; } 100 const ScopedHashTableScope *getParentScope() const { return PrevScope; } 101 102 private: 103 friend class ScopedHashTable<K, V, KInfo, AllocatorTy>; 104 ScopedHashTableVal<K, V> *getLastValInScope() { 105 return LastValInScope; 106 } 107 void setLastValInScope(ScopedHashTableVal<K, V> *Val) { 108 LastValInScope = Val; 109 } 110 }; 111 112 113 template <typename K, typename V, typename KInfo = DenseMapInfo<K> > 114 class ScopedHashTableIterator { 115 ScopedHashTableVal<K, V> *Node; 116 public: 117 ScopedHashTableIterator(ScopedHashTableVal<K, V> *node) : Node(node) {} 118 119 V &operator*() const { 120 assert(Node && "Dereference end()"); 121 return Node->getValue(); 122 } 123 V *operator->() const { 124 return &Node->getValue(); 125 } 126 127 bool operator==(const ScopedHashTableIterator &RHS) const { 128 return Node == RHS.Node; 129 } 130 bool operator!=(const ScopedHashTableIterator &RHS) const { 131 return Node != RHS.Node; 132 } 133 134 inline ScopedHashTableIterator& operator++() { // Preincrement 135 assert(Node && "incrementing past end()"); 136 Node = Node->getNextForKey(); 137 return *this; 138 } 139 ScopedHashTableIterator operator++(int) { // Postincrement 140 ScopedHashTableIterator tmp = *this; ++*this; return tmp; 141 } 142 }; 143 144 145 template <typename K, typename V, typename KInfo, typename AllocatorTy> 146 class ScopedHashTable { 147 public: 148 /// ScopeTy - This is a helpful typedef that allows clients to get easy access 149 /// to the name of the scope for this hash table. 150 typedef ScopedHashTableScope<K, V, KInfo, AllocatorTy> ScopeTy; 151 private: 152 typedef ScopedHashTableVal<K, V> ValTy; 153 DenseMap<K, ValTy*, KInfo> TopLevelMap; 154 ScopeTy *CurScope; 155 156 AllocatorTy Allocator; 157 158 ScopedHashTable(const ScopedHashTable&); // NOT YET IMPLEMENTED 159 void operator=(const ScopedHashTable&); // NOT YET IMPLEMENTED 160 friend class ScopedHashTableScope<K, V, KInfo, AllocatorTy>; 161 public: 162 ScopedHashTable() : CurScope(0) {} 163 ScopedHashTable(AllocatorTy A) : CurScope(0), Allocator(A) {} 164 ~ScopedHashTable() { 165 assert(CurScope == 0 && TopLevelMap.empty() && "Scope imbalance!"); 166 } 167 168 169 /// Access to the allocator. 170 typedef typename ReferenceAdder<AllocatorTy>::result AllocatorRefTy; 171 typedef typename ReferenceAdder<const AllocatorTy>::result AllocatorCRefTy; 172 AllocatorRefTy getAllocator() { return Allocator; } 173 AllocatorCRefTy getAllocator() const { return Allocator; } 174 175 bool count(const K &Key) const { 176 return TopLevelMap.count(Key); 177 } 178 179 V lookup(const K &Key) { 180 typename DenseMap<K, ValTy*, KInfo>::iterator I = TopLevelMap.find(Key); 181 if (I != TopLevelMap.end()) 182 return I->second->getValue(); 183 184 return V(); 185 } 186 187 void insert(const K &Key, const V &Val) { 188 insertIntoScope(CurScope, Key, Val); 189 } 190 191 typedef ScopedHashTableIterator<K, V, KInfo> iterator; 192 193 iterator end() { return iterator(0); } 194 195 iterator begin(const K &Key) { 196 typename DenseMap<K, ValTy*, KInfo>::iterator I = 197 TopLevelMap.find(Key); 198 if (I == TopLevelMap.end()) return end(); 199 return iterator(I->second); 200 } 201 202 ScopeTy *getCurScope() { return CurScope; } 203 const ScopeTy *getCurScope() const { return CurScope; } 204 205 /// insertIntoScope - This inserts the specified key/value at the specified 206 /// (possibly not the current) scope. While it is ok to insert into a scope 207 /// that isn't the current one, it isn't ok to insert *underneath* an existing 208 /// value of the specified key. 209 void insertIntoScope(ScopeTy *S, const K &Key, const V &Val) { 210 assert(S && "No scope active!"); 211 ScopedHashTableVal<K, V> *&KeyEntry = TopLevelMap[Key]; 212 KeyEntry = ValTy::Create(S->getLastValInScope(), KeyEntry, Key, Val, 213 Allocator); 214 S->setLastValInScope(KeyEntry); 215 } 216 }; 217 218 /// ScopedHashTableScope ctor - Install this as the current scope for the hash 219 /// table. 220 template <typename K, typename V, typename KInfo, typename Allocator> 221 ScopedHashTableScope<K, V, KInfo, Allocator>:: 222 ScopedHashTableScope(ScopedHashTable<K, V, KInfo, Allocator> &ht) : HT(ht) { 223 PrevScope = HT.CurScope; 224 HT.CurScope = this; 225 LastValInScope = 0; 226 } 227 228 template <typename K, typename V, typename KInfo, typename Allocator> 229 ScopedHashTableScope<K, V, KInfo, Allocator>::~ScopedHashTableScope() { 230 assert(HT.CurScope == this && "Scope imbalance!"); 231 HT.CurScope = PrevScope; 232 233 // Pop and delete all values corresponding to this scope. 234 while (ScopedHashTableVal<K, V> *ThisEntry = LastValInScope) { 235 // Pop this value out of the TopLevelMap. 236 if (ThisEntry->getNextForKey() == 0) { 237 assert(HT.TopLevelMap[ThisEntry->getKey()] == ThisEntry && 238 "Scope imbalance!"); 239 HT.TopLevelMap.erase(ThisEntry->getKey()); 240 } else { 241 ScopedHashTableVal<K, V> *&KeyEntry = HT.TopLevelMap[ThisEntry->getKey()]; 242 assert(KeyEntry == ThisEntry && "Scope imbalance!"); 243 KeyEntry = ThisEntry->getNextForKey(); 244 } 245 246 // Pop this value out of the scope. 247 LastValInScope = ThisEntry->getNextInScope(); 248 249 // Delete this entry. 250 ThisEntry->Destroy(HT.getAllocator()); 251 } 252 } 253 254 } // end namespace llvm 255 256 #endif 257