ScopedHashTable.h 8.3 KB

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