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