LLVM API Documentation
00001 //===- ScopedHashTable.h - A simple scoped hash table ---------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file implements an efficient scoped hash table, which is useful for 00011 // things like dominator-based optimizations. This allows clients to do things 00012 // like this: 00013 // 00014 // ScopedHashTable<int, int> HT; 00015 // { 00016 // ScopedHashTableScope<int, int> Scope1(HT); 00017 // HT.insert(0, 0); 00018 // HT.insert(1, 1); 00019 // { 00020 // ScopedHashTableScope<int, int> Scope2(HT); 00021 // HT.insert(0, 42); 00022 // } 00023 // } 00024 // 00025 // Looking up the value for "0" in the Scope2 block will return 42. Looking 00026 // up the value for 0 before 42 is inserted or after Scope2 is popped will 00027 // return 0. 00028 // 00029 //===----------------------------------------------------------------------===// 00030 00031 #ifndef LLVM_ADT_SCOPEDHASHTABLE_H 00032 #define LLVM_ADT_SCOPEDHASHTABLE_H 00033 00034 #include "llvm/ADT/DenseMap.h" 00035 #include "llvm/Support/Allocator.h" 00036 00037 namespace llvm { 00038 00039 template <typename K, typename V, typename KInfo = DenseMapInfo<K>, 00040 typename AllocatorTy = MallocAllocator> 00041 class ScopedHashTable; 00042 00043 template <typename K, typename V> 00044 class ScopedHashTableVal { 00045 ScopedHashTableVal *NextInScope; 00046 ScopedHashTableVal *NextForKey; 00047 K Key; 00048 V Val; 00049 ScopedHashTableVal(const K &key, const V &val) : Key(key), Val(val) {} 00050 public: 00051 00052 const K &getKey() const { return Key; } 00053 const V &getValue() const { return Val; } 00054 V &getValue() { return Val; } 00055 00056 ScopedHashTableVal *getNextForKey() { return NextForKey; } 00057 const ScopedHashTableVal *getNextForKey() const { return NextForKey; } 00058 ScopedHashTableVal *getNextInScope() { return NextInScope; } 00059 00060 template <typename AllocatorTy> 00061 static ScopedHashTableVal *Create(ScopedHashTableVal *nextInScope, 00062 ScopedHashTableVal *nextForKey, 00063 const K &key, const V &val, 00064 AllocatorTy &Allocator) { 00065 ScopedHashTableVal *New = Allocator.template Allocate<ScopedHashTableVal>(); 00066 // Set up the value. 00067 new (New) ScopedHashTableVal(key, val); 00068 New->NextInScope = nextInScope; 00069 New->NextForKey = nextForKey; 00070 return New; 00071 } 00072 00073 template <typename AllocatorTy> 00074 void Destroy(AllocatorTy &Allocator) { 00075 // Free memory referenced by the item. 00076 this->~ScopedHashTableVal(); 00077 Allocator.Deallocate(this); 00078 } 00079 }; 00080 00081 template <typename K, typename V, typename KInfo = DenseMapInfo<K>, 00082 typename AllocatorTy = MallocAllocator> 00083 class ScopedHashTableScope { 00084 /// HT - The hashtable that we are active for. 00085 ScopedHashTable<K, V, KInfo, AllocatorTy> &HT; 00086 00087 /// PrevScope - This is the scope that we are shadowing in HT. 00088 ScopedHashTableScope *PrevScope; 00089 00090 /// LastValInScope - This is the last value that was inserted for this scope 00091 /// or null if none have been inserted yet. 00092 ScopedHashTableVal<K, V> *LastValInScope; 00093 void operator=(ScopedHashTableScope&) LLVM_DELETED_FUNCTION; 00094 ScopedHashTableScope(ScopedHashTableScope&) LLVM_DELETED_FUNCTION; 00095 public: 00096 ScopedHashTableScope(ScopedHashTable<K, V, KInfo, AllocatorTy> &HT); 00097 ~ScopedHashTableScope(); 00098 00099 ScopedHashTableScope *getParentScope() { return PrevScope; } 00100 const ScopedHashTableScope *getParentScope() const { return PrevScope; } 00101 00102 private: 00103 friend class ScopedHashTable<K, V, KInfo, AllocatorTy>; 00104 ScopedHashTableVal<K, V> *getLastValInScope() { 00105 return LastValInScope; 00106 } 00107 void setLastValInScope(ScopedHashTableVal<K, V> *Val) { 00108 LastValInScope = Val; 00109 } 00110 }; 00111 00112 00113 template <typename K, typename V, typename KInfo = DenseMapInfo<K> > 00114 class ScopedHashTableIterator { 00115 ScopedHashTableVal<K, V> *Node; 00116 public: 00117 ScopedHashTableIterator(ScopedHashTableVal<K, V> *node) : Node(node) {} 00118 00119 V &operator*() const { 00120 assert(Node && "Dereference end()"); 00121 return Node->getValue(); 00122 } 00123 V *operator->() const { 00124 return &Node->getValue(); 00125 } 00126 00127 bool operator==(const ScopedHashTableIterator &RHS) const { 00128 return Node == RHS.Node; 00129 } 00130 bool operator!=(const ScopedHashTableIterator &RHS) const { 00131 return Node != RHS.Node; 00132 } 00133 00134 inline ScopedHashTableIterator& operator++() { // Preincrement 00135 assert(Node && "incrementing past end()"); 00136 Node = Node->getNextForKey(); 00137 return *this; 00138 } 00139 ScopedHashTableIterator operator++(int) { // Postincrement 00140 ScopedHashTableIterator tmp = *this; ++*this; return tmp; 00141 } 00142 }; 00143 00144 00145 template <typename K, typename V, typename KInfo, typename AllocatorTy> 00146 class ScopedHashTable { 00147 public: 00148 /// ScopeTy - This is a helpful typedef that allows clients to get easy access 00149 /// to the name of the scope for this hash table. 00150 typedef ScopedHashTableScope<K, V, KInfo, AllocatorTy> ScopeTy; 00151 typedef unsigned size_type; 00152 private: 00153 typedef ScopedHashTableVal<K, V> ValTy; 00154 DenseMap<K, ValTy*, KInfo> TopLevelMap; 00155 ScopeTy *CurScope; 00156 00157 AllocatorTy Allocator; 00158 00159 ScopedHashTable(const ScopedHashTable&); // NOT YET IMPLEMENTED 00160 void operator=(const ScopedHashTable&); // NOT YET IMPLEMENTED 00161 friend class ScopedHashTableScope<K, V, KInfo, AllocatorTy>; 00162 public: 00163 ScopedHashTable() : CurScope(nullptr) {} 00164 ScopedHashTable(AllocatorTy A) : CurScope(0), Allocator(A) {} 00165 ~ScopedHashTable() { 00166 assert(!CurScope && TopLevelMap.empty() && "Scope imbalance!"); 00167 } 00168 00169 00170 /// Access to the allocator. 00171 AllocatorTy &getAllocator() { return Allocator; } 00172 const AllocatorTy &getAllocator() const { return Allocator; } 00173 00174 /// Return 1 if the specified key is in the table, 0 otherwise. 00175 size_type count(const K &Key) const { 00176 return TopLevelMap.count(Key); 00177 } 00178 00179 V lookup(const K &Key) { 00180 typename DenseMap<K, ValTy*, KInfo>::iterator I = TopLevelMap.find(Key); 00181 if (I != TopLevelMap.end()) 00182 return I->second->getValue(); 00183 00184 return V(); 00185 } 00186 00187 void insert(const K &Key, const V &Val) { 00188 insertIntoScope(CurScope, Key, Val); 00189 } 00190 00191 typedef ScopedHashTableIterator<K, V, KInfo> iterator; 00192 00193 iterator end() { return iterator(0); } 00194 00195 iterator begin(const K &Key) { 00196 typename DenseMap<K, ValTy*, KInfo>::iterator I = 00197 TopLevelMap.find(Key); 00198 if (I == TopLevelMap.end()) return end(); 00199 return iterator(I->second); 00200 } 00201 00202 ScopeTy *getCurScope() { return CurScope; } 00203 const ScopeTy *getCurScope() const { return CurScope; } 00204 00205 /// insertIntoScope - This inserts the specified key/value at the specified 00206 /// (possibly not the current) scope. While it is ok to insert into a scope 00207 /// that isn't the current one, it isn't ok to insert *underneath* an existing 00208 /// value of the specified key. 00209 void insertIntoScope(ScopeTy *S, const K &Key, const V &Val) { 00210 assert(S && "No scope active!"); 00211 ScopedHashTableVal<K, V> *&KeyEntry = TopLevelMap[Key]; 00212 KeyEntry = ValTy::Create(S->getLastValInScope(), KeyEntry, Key, Val, 00213 Allocator); 00214 S->setLastValInScope(KeyEntry); 00215 } 00216 }; 00217 00218 /// ScopedHashTableScope ctor - Install this as the current scope for the hash 00219 /// table. 00220 template <typename K, typename V, typename KInfo, typename Allocator> 00221 ScopedHashTableScope<K, V, KInfo, Allocator>:: 00222 ScopedHashTableScope(ScopedHashTable<K, V, KInfo, Allocator> &ht) : HT(ht) { 00223 PrevScope = HT.CurScope; 00224 HT.CurScope = this; 00225 LastValInScope = nullptr; 00226 } 00227 00228 template <typename K, typename V, typename KInfo, typename Allocator> 00229 ScopedHashTableScope<K, V, KInfo, Allocator>::~ScopedHashTableScope() { 00230 assert(HT.CurScope == this && "Scope imbalance!"); 00231 HT.CurScope = PrevScope; 00232 00233 // Pop and delete all values corresponding to this scope. 00234 while (ScopedHashTableVal<K, V> *ThisEntry = LastValInScope) { 00235 // Pop this value out of the TopLevelMap. 00236 if (!ThisEntry->getNextForKey()) { 00237 assert(HT.TopLevelMap[ThisEntry->getKey()] == ThisEntry && 00238 "Scope imbalance!"); 00239 HT.TopLevelMap.erase(ThisEntry->getKey()); 00240 } else { 00241 ScopedHashTableVal<K, V> *&KeyEntry = HT.TopLevelMap[ThisEntry->getKey()]; 00242 assert(KeyEntry == ThisEntry && "Scope imbalance!"); 00243 KeyEntry = ThisEntry->getNextForKey(); 00244 } 00245 00246 // Pop this value out of the scope. 00247 LastValInScope = ThisEntry->getNextInScope(); 00248 00249 // Delete this entry. 00250 ThisEntry->Destroy(HT.getAllocator()); 00251 } 00252 } 00253 00254 } // end namespace llvm 00255 00256 #endif