123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- ScopedHashTable.h - A simple scoped hash table -----------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file implements an efficient scoped hash table, which is useful for
- // things like dominator-based optimizations. This allows clients to do things
- // like this:
- //
- // ScopedHashTable<int, int> HT;
- // {
- // ScopedHashTableScope<int, int> Scope1(HT);
- // HT.insert(0, 0);
- // HT.insert(1, 1);
- // {
- // ScopedHashTableScope<int, int> Scope2(HT);
- // HT.insert(0, 42);
- // }
- // }
- //
- // Looking up the value for "0" in the Scope2 block will return 42. Looking
- // up the value for 0 before 42 is inserted or after Scope2 is popped will
- // return 0.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_ADT_SCOPEDHASHTABLE_H
- #define LLVM_ADT_SCOPEDHASHTABLE_H
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/DenseMapInfo.h"
- #include "llvm/Support/AllocatorBase.h"
- #include <cassert>
- #include <new>
- namespace llvm {
- template <typename K, typename V, typename KInfo = DenseMapInfo<K>,
- typename AllocatorTy = MallocAllocator>
- class ScopedHashTable;
- template <typename K, typename V>
- class ScopedHashTableVal {
- ScopedHashTableVal *NextInScope;
- ScopedHashTableVal *NextForKey;
- K Key;
- V Val;
- ScopedHashTableVal(const K &key, const V &val) : Key(key), Val(val) {}
- public:
- const K &getKey() const { return Key; }
- const V &getValue() const { return Val; }
- V &getValue() { return Val; }
- ScopedHashTableVal *getNextForKey() { return NextForKey; }
- const ScopedHashTableVal *getNextForKey() const { return NextForKey; }
- ScopedHashTableVal *getNextInScope() { return NextInScope; }
- template <typename AllocatorTy>
- static ScopedHashTableVal *Create(ScopedHashTableVal *nextInScope,
- ScopedHashTableVal *nextForKey,
- const K &key, const V &val,
- AllocatorTy &Allocator) {
- ScopedHashTableVal *New = Allocator.template Allocate<ScopedHashTableVal>();
- // Set up the value.
- new (New) ScopedHashTableVal(key, val);
- New->NextInScope = nextInScope;
- New->NextForKey = nextForKey;
- return New;
- }
- template <typename AllocatorTy> void Destroy(AllocatorTy &Allocator) {
- // Free memory referenced by the item.
- this->~ScopedHashTableVal();
- Allocator.Deallocate(this);
- }
- };
- template <typename K, typename V, typename KInfo = DenseMapInfo<K>,
- typename AllocatorTy = MallocAllocator>
- class ScopedHashTableScope {
- /// HT - The hashtable that we are active for.
- ScopedHashTable<K, V, KInfo, AllocatorTy> &HT;
- /// PrevScope - This is the scope that we are shadowing in HT.
- ScopedHashTableScope *PrevScope;
- /// LastValInScope - This is the last value that was inserted for this scope
- /// or null if none have been inserted yet.
- ScopedHashTableVal<K, V> *LastValInScope;
- public:
- ScopedHashTableScope(ScopedHashTable<K, V, KInfo, AllocatorTy> &HT);
- ScopedHashTableScope(ScopedHashTableScope &) = delete;
- ScopedHashTableScope &operator=(ScopedHashTableScope &) = delete;
- ~ScopedHashTableScope();
- ScopedHashTableScope *getParentScope() { return PrevScope; }
- const ScopedHashTableScope *getParentScope() const { return PrevScope; }
- private:
- friend class ScopedHashTable<K, V, KInfo, AllocatorTy>;
- ScopedHashTableVal<K, V> *getLastValInScope() {
- return LastValInScope;
- }
- void setLastValInScope(ScopedHashTableVal<K, V> *Val) {
- LastValInScope = Val;
- }
- };
- template <typename K, typename V, typename KInfo = DenseMapInfo<K>>
- class ScopedHashTableIterator {
- ScopedHashTableVal<K, V> *Node;
- public:
- ScopedHashTableIterator(ScopedHashTableVal<K, V> *node) : Node(node) {}
- V &operator*() const {
- assert(Node && "Dereference end()");
- return Node->getValue();
- }
- V *operator->() const {
- return &Node->getValue();
- }
- bool operator==(const ScopedHashTableIterator &RHS) const {
- return Node == RHS.Node;
- }
- bool operator!=(const ScopedHashTableIterator &RHS) const {
- return Node != RHS.Node;
- }
- inline ScopedHashTableIterator& operator++() { // Preincrement
- assert(Node && "incrementing past end()");
- Node = Node->getNextForKey();
- return *this;
- }
- ScopedHashTableIterator operator++(int) { // Postincrement
- ScopedHashTableIterator tmp = *this; ++*this; return tmp;
- }
- };
- template <typename K, typename V, typename KInfo, typename AllocatorTy>
- class ScopedHashTable {
- public:
- /// ScopeTy - This is a helpful typedef that allows clients to get easy access
- /// to the name of the scope for this hash table.
- using ScopeTy = ScopedHashTableScope<K, V, KInfo, AllocatorTy>;
- using size_type = unsigned;
- private:
- friend class ScopedHashTableScope<K, V, KInfo, AllocatorTy>;
- using ValTy = ScopedHashTableVal<K, V>;
- DenseMap<K, ValTy*, KInfo> TopLevelMap;
- ScopeTy *CurScope = nullptr;
- AllocatorTy Allocator;
- public:
- ScopedHashTable() = default;
- ScopedHashTable(AllocatorTy A) : Allocator(A) {}
- ScopedHashTable(const ScopedHashTable &) = delete;
- ScopedHashTable &operator=(const ScopedHashTable &) = delete;
- ~ScopedHashTable() {
- assert(!CurScope && TopLevelMap.empty() && "Scope imbalance!");
- }
- /// Access to the allocator.
- AllocatorTy &getAllocator() { return Allocator; }
- const AllocatorTy &getAllocator() const { return Allocator; }
- /// Return 1 if the specified key is in the table, 0 otherwise.
- size_type count(const K &Key) const {
- return TopLevelMap.count(Key);
- }
- V lookup(const K &Key) const {
- auto I = TopLevelMap.find(Key);
- if (I != TopLevelMap.end())
- return I->second->getValue();
- return V();
- }
- void insert(const K &Key, const V &Val) {
- insertIntoScope(CurScope, Key, Val);
- }
- using iterator = ScopedHashTableIterator<K, V, KInfo>;
- iterator end() { return iterator(nullptr); }
- iterator begin(const K &Key) {
- typename DenseMap<K, ValTy*, KInfo>::iterator I =
- TopLevelMap.find(Key);
- if (I == TopLevelMap.end()) return end();
- return iterator(I->second);
- }
- ScopeTy *getCurScope() { return CurScope; }
- const ScopeTy *getCurScope() const { return CurScope; }
- /// insertIntoScope - This inserts the specified key/value at the specified
- /// (possibly not the current) scope. While it is ok to insert into a scope
- /// that isn't the current one, it isn't ok to insert *underneath* an existing
- /// value of the specified key.
- void insertIntoScope(ScopeTy *S, const K &Key, const V &Val) {
- assert(S && "No scope active!");
- ScopedHashTableVal<K, V> *&KeyEntry = TopLevelMap[Key];
- KeyEntry = ValTy::Create(S->getLastValInScope(), KeyEntry, Key, Val,
- Allocator);
- S->setLastValInScope(KeyEntry);
- }
- };
- /// ScopedHashTableScope ctor - Install this as the current scope for the hash
- /// table.
- template <typename K, typename V, typename KInfo, typename Allocator>
- ScopedHashTableScope<K, V, KInfo, Allocator>::
- ScopedHashTableScope(ScopedHashTable<K, V, KInfo, Allocator> &ht) : HT(ht) {
- PrevScope = HT.CurScope;
- HT.CurScope = this;
- LastValInScope = nullptr;
- }
- template <typename K, typename V, typename KInfo, typename Allocator>
- ScopedHashTableScope<K, V, KInfo, Allocator>::~ScopedHashTableScope() {
- assert(HT.CurScope == this && "Scope imbalance!");
- HT.CurScope = PrevScope;
- // Pop and delete all values corresponding to this scope.
- while (ScopedHashTableVal<K, V> *ThisEntry = LastValInScope) {
- // Pop this value out of the TopLevelMap.
- if (!ThisEntry->getNextForKey()) {
- assert(HT.TopLevelMap[ThisEntry->getKey()] == ThisEntry &&
- "Scope imbalance!");
- HT.TopLevelMap.erase(ThisEntry->getKey());
- } else {
- ScopedHashTableVal<K, V> *&KeyEntry = HT.TopLevelMap[ThisEntry->getKey()];
- assert(KeyEntry == ThisEntry && "Scope imbalance!");
- KeyEntry = ThisEntry->getNextForKey();
- }
- // Pop this value out of the scope.
- LastValInScope = ThisEntry->getNextInScope();
- // Delete this entry.
- ThisEntry->Destroy(HT.getAllocator());
- }
- }
- } // end namespace llvm
- #endif // LLVM_ADT_SCOPEDHASHTABLE_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|