xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ADT/ScopedHashTable.h (revision 753f127f3ace09432b2baeffd71a308760641a62)
10b57cec5SDimitry Andric //===- ScopedHashTable.h - A simple scoped hash table -----------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements an efficient scoped hash table, which is useful for
100b57cec5SDimitry Andric // things like dominator-based optimizations.  This allows clients to do things
110b57cec5SDimitry Andric // like this:
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //  ScopedHashTable<int, int> HT;
140b57cec5SDimitry Andric //  {
150b57cec5SDimitry Andric //    ScopedHashTableScope<int, int> Scope1(HT);
160b57cec5SDimitry Andric //    HT.insert(0, 0);
170b57cec5SDimitry Andric //    HT.insert(1, 1);
180b57cec5SDimitry Andric //    {
190b57cec5SDimitry Andric //      ScopedHashTableScope<int, int> Scope2(HT);
200b57cec5SDimitry Andric //      HT.insert(0, 42);
210b57cec5SDimitry Andric //    }
220b57cec5SDimitry Andric //  }
230b57cec5SDimitry Andric //
240b57cec5SDimitry Andric // Looking up the value for "0" in the Scope2 block will return 42.  Looking
250b57cec5SDimitry Andric // up the value for 0 before 42 is inserted or after Scope2 is popped will
260b57cec5SDimitry Andric // return 0.
270b57cec5SDimitry Andric //
280b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric #ifndef LLVM_ADT_SCOPEDHASHTABLE_H
310b57cec5SDimitry Andric #define LLVM_ADT_SCOPEDHASHTABLE_H
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
340b57cec5SDimitry Andric #include "llvm/ADT/DenseMapInfo.h"
355ffd83dbSDimitry Andric #include "llvm/Support/AllocatorBase.h"
360b57cec5SDimitry Andric #include <cassert>
370b57cec5SDimitry Andric #include <new>
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric namespace llvm {
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric template <typename K, typename V, typename KInfo = DenseMapInfo<K>,
420b57cec5SDimitry Andric           typename AllocatorTy = MallocAllocator>
430b57cec5SDimitry Andric class ScopedHashTable;
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric template <typename K, typename V>
460b57cec5SDimitry Andric class ScopedHashTableVal {
470b57cec5SDimitry Andric   ScopedHashTableVal *NextInScope;
480b57cec5SDimitry Andric   ScopedHashTableVal *NextForKey;
490b57cec5SDimitry Andric   K Key;
500b57cec5SDimitry Andric   V Val;
510b57cec5SDimitry Andric 
ScopedHashTableVal(const K & key,const V & val)520b57cec5SDimitry Andric   ScopedHashTableVal(const K &key, const V &val) : Key(key), Val(val) {}
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric public:
getKey()550b57cec5SDimitry Andric   const K &getKey() const { return Key; }
getValue()560b57cec5SDimitry Andric   const V &getValue() const { return Val; }
getValue()570b57cec5SDimitry Andric   V &getValue() { return Val; }
580b57cec5SDimitry Andric 
getNextForKey()590b57cec5SDimitry Andric   ScopedHashTableVal *getNextForKey() { return NextForKey; }
getNextForKey()600b57cec5SDimitry Andric   const ScopedHashTableVal *getNextForKey() const { return NextForKey; }
getNextInScope()610b57cec5SDimitry Andric   ScopedHashTableVal *getNextInScope() { return NextInScope; }
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   template <typename AllocatorTy>
Create(ScopedHashTableVal * nextInScope,ScopedHashTableVal * nextForKey,const K & key,const V & val,AllocatorTy & Allocator)640b57cec5SDimitry Andric   static ScopedHashTableVal *Create(ScopedHashTableVal *nextInScope,
650b57cec5SDimitry Andric                                     ScopedHashTableVal *nextForKey,
660b57cec5SDimitry Andric                                     const K &key, const V &val,
670b57cec5SDimitry Andric                                     AllocatorTy &Allocator) {
680b57cec5SDimitry Andric     ScopedHashTableVal *New = Allocator.template Allocate<ScopedHashTableVal>();
690b57cec5SDimitry Andric     // Set up the value.
700b57cec5SDimitry Andric     new (New) ScopedHashTableVal(key, val);
710b57cec5SDimitry Andric     New->NextInScope = nextInScope;
720b57cec5SDimitry Andric     New->NextForKey = nextForKey;
730b57cec5SDimitry Andric     return New;
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric 
Destroy(AllocatorTy & Allocator)760b57cec5SDimitry Andric   template <typename AllocatorTy> void Destroy(AllocatorTy &Allocator) {
770b57cec5SDimitry Andric     // Free memory referenced by the item.
780b57cec5SDimitry Andric     this->~ScopedHashTableVal();
790b57cec5SDimitry Andric     Allocator.Deallocate(this);
800b57cec5SDimitry Andric   }
810b57cec5SDimitry Andric };
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric template <typename K, typename V, typename KInfo = DenseMapInfo<K>,
840b57cec5SDimitry Andric           typename AllocatorTy = MallocAllocator>
850b57cec5SDimitry Andric class ScopedHashTableScope {
860b57cec5SDimitry Andric   /// HT - The hashtable that we are active for.
870b57cec5SDimitry Andric   ScopedHashTable<K, V, KInfo, AllocatorTy> &HT;
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   /// PrevScope - This is the scope that we are shadowing in HT.
900b57cec5SDimitry Andric   ScopedHashTableScope *PrevScope;
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   /// LastValInScope - This is the last value that was inserted for this scope
930b57cec5SDimitry Andric   /// or null if none have been inserted yet.
940b57cec5SDimitry Andric   ScopedHashTableVal<K, V> *LastValInScope;
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric public:
970b57cec5SDimitry Andric   ScopedHashTableScope(ScopedHashTable<K, V, KInfo, AllocatorTy> &HT);
980b57cec5SDimitry Andric   ScopedHashTableScope(ScopedHashTableScope &) = delete;
990b57cec5SDimitry Andric   ScopedHashTableScope &operator=(ScopedHashTableScope &) = delete;
1000b57cec5SDimitry Andric   ~ScopedHashTableScope();
1010b57cec5SDimitry Andric 
getParentScope()1020b57cec5SDimitry Andric   ScopedHashTableScope *getParentScope() { return PrevScope; }
getParentScope()1030b57cec5SDimitry Andric   const ScopedHashTableScope *getParentScope() const { return PrevScope; }
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric private:
1060b57cec5SDimitry Andric   friend class ScopedHashTable<K, V, KInfo, AllocatorTy>;
1070b57cec5SDimitry Andric 
getLastValInScope()1080b57cec5SDimitry Andric   ScopedHashTableVal<K, V> *getLastValInScope() {
1090b57cec5SDimitry Andric     return LastValInScope;
1100b57cec5SDimitry Andric   }
1110b57cec5SDimitry Andric 
setLastValInScope(ScopedHashTableVal<K,V> * Val)1120b57cec5SDimitry Andric   void setLastValInScope(ScopedHashTableVal<K, V> *Val) {
1130b57cec5SDimitry Andric     LastValInScope = Val;
1140b57cec5SDimitry Andric   }
1150b57cec5SDimitry Andric };
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric template <typename K, typename V, typename KInfo = DenseMapInfo<K>>
1180b57cec5SDimitry Andric class ScopedHashTableIterator {
1190b57cec5SDimitry Andric   ScopedHashTableVal<K, V> *Node;
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric public:
ScopedHashTableIterator(ScopedHashTableVal<K,V> * node)1220b57cec5SDimitry Andric   ScopedHashTableIterator(ScopedHashTableVal<K, V> *node) : Node(node) {}
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   V &operator*() const {
1250b57cec5SDimitry Andric     assert(Node && "Dereference end()");
1260b57cec5SDimitry Andric     return Node->getValue();
1270b57cec5SDimitry Andric   }
1280b57cec5SDimitry Andric   V *operator->() const {
1290b57cec5SDimitry Andric     return &Node->getValue();
1300b57cec5SDimitry Andric   }
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric   bool operator==(const ScopedHashTableIterator &RHS) const {
1330b57cec5SDimitry Andric     return Node == RHS.Node;
1340b57cec5SDimitry Andric   }
1350b57cec5SDimitry Andric   bool operator!=(const ScopedHashTableIterator &RHS) const {
1360b57cec5SDimitry Andric     return Node != RHS.Node;
1370b57cec5SDimitry Andric   }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric   inline ScopedHashTableIterator& operator++() {          // Preincrement
1400b57cec5SDimitry Andric     assert(Node && "incrementing past end()");
1410b57cec5SDimitry Andric     Node = Node->getNextForKey();
1420b57cec5SDimitry Andric     return *this;
1430b57cec5SDimitry Andric   }
1440b57cec5SDimitry Andric   ScopedHashTableIterator operator++(int) {        // Postincrement
1450b57cec5SDimitry Andric     ScopedHashTableIterator tmp = *this; ++*this; return tmp;
1460b57cec5SDimitry Andric   }
1470b57cec5SDimitry Andric };
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric template <typename K, typename V, typename KInfo, typename AllocatorTy>
150*753f127fSDimitry Andric class ScopedHashTable : detail::AllocatorHolder<AllocatorTy> {
151*753f127fSDimitry Andric   using AllocTy = detail::AllocatorHolder<AllocatorTy>;
152*753f127fSDimitry Andric 
1530b57cec5SDimitry Andric public:
1540b57cec5SDimitry Andric   /// ScopeTy - This is a helpful typedef that allows clients to get easy access
1550b57cec5SDimitry Andric   /// to the name of the scope for this hash table.
1560b57cec5SDimitry Andric   using ScopeTy = ScopedHashTableScope<K, V, KInfo, AllocatorTy>;
1570b57cec5SDimitry Andric   using size_type = unsigned;
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric private:
1600b57cec5SDimitry Andric   friend class ScopedHashTableScope<K, V, KInfo, AllocatorTy>;
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   using ValTy = ScopedHashTableVal<K, V>;
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   DenseMap<K, ValTy*, KInfo> TopLevelMap;
1650b57cec5SDimitry Andric   ScopeTy *CurScope = nullptr;
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric public:
1680b57cec5SDimitry Andric   ScopedHashTable() = default;
ScopedHashTable(AllocatorTy A)169*753f127fSDimitry Andric   ScopedHashTable(AllocatorTy A) : AllocTy(A) {}
1700b57cec5SDimitry Andric   ScopedHashTable(const ScopedHashTable &) = delete;
1710b57cec5SDimitry Andric   ScopedHashTable &operator=(const ScopedHashTable &) = delete;
1720b57cec5SDimitry Andric 
~ScopedHashTable()1730b57cec5SDimitry Andric   ~ScopedHashTable() {
1740b57cec5SDimitry Andric     assert(!CurScope && TopLevelMap.empty() && "Scope imbalance!");
1750b57cec5SDimitry Andric   }
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric   /// Access to the allocator.
178*753f127fSDimitry Andric   using AllocTy::getAllocator;
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   /// Return 1 if the specified key is in the table, 0 otherwise.
count(const K & Key)1810b57cec5SDimitry Andric   size_type count(const K &Key) const {
1820b57cec5SDimitry Andric     return TopLevelMap.count(Key);
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric 
lookup(const K & Key)1850b57cec5SDimitry Andric   V lookup(const K &Key) const {
1860b57cec5SDimitry Andric     auto I = TopLevelMap.find(Key);
1870b57cec5SDimitry Andric     if (I != TopLevelMap.end())
1880b57cec5SDimitry Andric       return I->second->getValue();
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric     return V();
1910b57cec5SDimitry Andric   }
1920b57cec5SDimitry Andric 
insert(const K & Key,const V & Val)1930b57cec5SDimitry Andric   void insert(const K &Key, const V &Val) {
1940b57cec5SDimitry Andric     insertIntoScope(CurScope, Key, Val);
1950b57cec5SDimitry Andric   }
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric   using iterator = ScopedHashTableIterator<K, V, KInfo>;
1980b57cec5SDimitry Andric 
end()19904eeddc0SDimitry Andric   iterator end() { return iterator(nullptr); }
2000b57cec5SDimitry Andric 
begin(const K & Key)2010b57cec5SDimitry Andric   iterator begin(const K &Key) {
2020b57cec5SDimitry Andric     typename DenseMap<K, ValTy*, KInfo>::iterator I =
2030b57cec5SDimitry Andric       TopLevelMap.find(Key);
2040b57cec5SDimitry Andric     if (I == TopLevelMap.end()) return end();
2050b57cec5SDimitry Andric     return iterator(I->second);
2060b57cec5SDimitry Andric   }
2070b57cec5SDimitry Andric 
getCurScope()2080b57cec5SDimitry Andric   ScopeTy *getCurScope() { return CurScope; }
getCurScope()2090b57cec5SDimitry Andric   const ScopeTy *getCurScope() const { return CurScope; }
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric   /// insertIntoScope - This inserts the specified key/value at the specified
2120b57cec5SDimitry Andric   /// (possibly not the current) scope.  While it is ok to insert into a scope
2130b57cec5SDimitry Andric   /// that isn't the current one, it isn't ok to insert *underneath* an existing
2140b57cec5SDimitry Andric   /// value of the specified key.
insertIntoScope(ScopeTy * S,const K & Key,const V & Val)2150b57cec5SDimitry Andric   void insertIntoScope(ScopeTy *S, const K &Key, const V &Val) {
2160b57cec5SDimitry Andric     assert(S && "No scope active!");
2170b57cec5SDimitry Andric     ScopedHashTableVal<K, V> *&KeyEntry = TopLevelMap[Key];
2180b57cec5SDimitry Andric     KeyEntry = ValTy::Create(S->getLastValInScope(), KeyEntry, Key, Val,
219*753f127fSDimitry Andric                              getAllocator());
2200b57cec5SDimitry Andric     S->setLastValInScope(KeyEntry);
2210b57cec5SDimitry Andric   }
2220b57cec5SDimitry Andric };
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric /// ScopedHashTableScope ctor - Install this as the current scope for the hash
2250b57cec5SDimitry Andric /// table.
2260b57cec5SDimitry Andric template <typename K, typename V, typename KInfo, typename Allocator>
2270b57cec5SDimitry Andric ScopedHashTableScope<K, V, KInfo, Allocator>::
ScopedHashTableScope(ScopedHashTable<K,V,KInfo,Allocator> & ht)2280b57cec5SDimitry Andric   ScopedHashTableScope(ScopedHashTable<K, V, KInfo, Allocator> &ht) : HT(ht) {
2290b57cec5SDimitry Andric   PrevScope = HT.CurScope;
2300b57cec5SDimitry Andric   HT.CurScope = this;
2310b57cec5SDimitry Andric   LastValInScope = nullptr;
2320b57cec5SDimitry Andric }
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric template <typename K, typename V, typename KInfo, typename Allocator>
~ScopedHashTableScope()2350b57cec5SDimitry Andric ScopedHashTableScope<K, V, KInfo, Allocator>::~ScopedHashTableScope() {
2360b57cec5SDimitry Andric   assert(HT.CurScope == this && "Scope imbalance!");
2370b57cec5SDimitry Andric   HT.CurScope = PrevScope;
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   // Pop and delete all values corresponding to this scope.
2400b57cec5SDimitry Andric   while (ScopedHashTableVal<K, V> *ThisEntry = LastValInScope) {
2410b57cec5SDimitry Andric     // Pop this value out of the TopLevelMap.
2420b57cec5SDimitry Andric     if (!ThisEntry->getNextForKey()) {
2430b57cec5SDimitry Andric       assert(HT.TopLevelMap[ThisEntry->getKey()] == ThisEntry &&
2440b57cec5SDimitry Andric              "Scope imbalance!");
2450b57cec5SDimitry Andric       HT.TopLevelMap.erase(ThisEntry->getKey());
2460b57cec5SDimitry Andric     } else {
2470b57cec5SDimitry Andric       ScopedHashTableVal<K, V> *&KeyEntry = HT.TopLevelMap[ThisEntry->getKey()];
2480b57cec5SDimitry Andric       assert(KeyEntry == ThisEntry && "Scope imbalance!");
2490b57cec5SDimitry Andric       KeyEntry = ThisEntry->getNextForKey();
2500b57cec5SDimitry Andric     }
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric     // Pop this value out of the scope.
2530b57cec5SDimitry Andric     LastValInScope = ThisEntry->getNextInScope();
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric     // Delete this entry.
2560b57cec5SDimitry Andric     ThisEntry->Destroy(HT.getAllocator());
2570b57cec5SDimitry Andric   }
2580b57cec5SDimitry Andric }
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric } // end namespace llvm
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric #endif // LLVM_ADT_SCOPEDHASHTABLE_H
263