| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #pragma once
- #if PROFILE_DICTIONARY
- #include "DictionaryStats.h"
- #endif
- template <typename TData, typename TElement>
- class HashBucket
- {
- public:
- TElement element;
- TData value;
- public:
- HashBucket() : element(NULL), value(NULL) {}
- static void Copy(HashBucket const& bucket, HashBucket& newBucket)
- {
- newBucket.element = bucket.element;
- newBucket.value = bucket.value;
- }
- };
- class Key
- {
- public:
- static uint Get(Sym const *sym) { return static_cast<uint>(sym->m_id); }
- static uint Get(ExprHash hash) { return static_cast<uint>(hash); }
- };
- #define FOREACH_GLOBHASHTABLE_ENTRY(bucket, hashTable) \
- for (uint _iterHash = 0; _iterHash < (hashTable)->tableSize; _iterHash++) \
- { \
- FOREACH_SLISTBASE_ENTRY(GlobHashBucket, bucket, &(hashTable)->table[_iterHash]) \
- {
- #define NEXT_GLOBHASHTABLE_ENTRY \
- } \
- NEXT_SLISTBASE_ENTRY; \
- }
- template<typename TData, typename TElement>
- class ValueHashTable
- {
- private:
- typedef HashBucket<TData, TElement> HashBucket;
- public:
- JitArenaAllocator * alloc;
- uint tableSize;
- SListBase<HashBucket> * table;
- public:
- static ValueHashTable * New(JitArenaAllocator *allocator, DECLSPEC_GUARD_OVERFLOW uint tableSize)
- {
- return AllocatorNewPlus(JitArenaAllocator, allocator, (tableSize*sizeof(SListBase<HashBucket>)), ValueHashTable, allocator, tableSize);
- }
- void Delete()
- {
- AllocatorDeletePlus(JitArenaAllocator, alloc, (tableSize*sizeof(SListBase<HashBucket>)), this);
- }
- ~ValueHashTable()
- {
- for (uint i = 0; i< tableSize; i++)
- {
- table[i].Clear(alloc);
- }
- }
- SListBase<HashBucket> * SwapBucket(SListBase<HashBucket> * newTable)
- {
- SListBase<HashBucket> * retTable = table;
- table = newTable;
- return retTable;
- }
- TElement * FindOrInsertNew(TData value)
- {
- uint key = Key::Get(value);
- uint hash = this->Hash(key);
- #if PROFILE_DICTIONARY
- uint depth = 1;
- #endif
- // Keep sorted
- FOREACH_SLISTBASE_ENTRY_EDITING(HashBucket, bucket, &this->table[hash], iter)
- {
- if (Key::Get(bucket.value) <= key)
- {
- if (Key::Get(bucket.value) == key)
- {
- return &(bucket.element);
- }
- break;
- }
- #if PROFILE_DICTIONARY
- ++depth;
- #endif
- } NEXT_SLISTBASE_ENTRY_EDITING;
- HashBucket * newBucket = iter.InsertNodeBefore(this->alloc);
- newBucket->value = value;
- #if PROFILE_DICTIONARY
- if (stats)
- stats->Insert(depth);
- #endif
- return &newBucket->element;
- }
- TElement * FindOrInsertNewNoThrow(TData * value)
- {
- uint key = Key::Get(value);
- uint hash = this->Hash(key);
- #if PROFILE_DICTIONARY
- uint depth = 1;
- #endif
- // Keep sorted
- FOREACH_SLISTBASE_ENTRY_EDITING(HashBucket, bucket, &this->table[hash], iter)
- {
- if (Key::Get(bucket.value) <= key)
- {
- if (Key::Get(bucket.value) == key)
- {
- return &(bucket.element);
- }
- break;
- }
- #if PROFILE_DICTIONARY
- ++depth;
- #endif
- } NEXT_SLISTBASE_ENTRY_EDITING;
- HashBucket * newBucket = iter.InsertNodeBeforeNoThrow(this->alloc);
- if (newBucket == nullptr)
- {
- return nullptr;
- }
- newBucket->value = value;
- #if PROFILE_DICTIONARY
- if (stats)
- stats->Insert(depth);
- #endif
- return &newBucket->element;
- }
- TElement * FindOrInsert(TElement element, TData value)
- {
- uint key = Key::Get(value);
- uint hash = this->Hash(key);
- #if PROFILE_DICTIONARY
- uint depth = 1;
- #endif
- // Keep sorted
- FOREACH_SLISTBASE_ENTRY_EDITING(HashBucket, bucket, &this->table[hash], iter)
- {
- if (Key::Get(bucket.value) <= key)
- {
- if (Key::Get(bucket.value) == key)
- {
- return &(bucket.element);
- }
- break;
- }
- #if PROFILE_DICTIONARY
- ++depth;
- #endif
- } NEXT_SLISTBASE_ENTRY_EDITING;
- HashBucket * newBucket = iter.InsertNodeBefore(this->alloc);
- Assert(newBucket != nullptr);
- newBucket->value = value;
- newBucket->element = element;
- #if PROFILE_DICTIONARY
- if (stats)
- stats->Insert(depth);
- #endif
- return NULL;
- }
- TElement * Get(TData value)
- {
- uint key = Key::Get(value);
- return Get(key);
- }
- TElement * Get(uint key)
- {
- uint hash = this->Hash(key);
- // Assumes sorted lists
- FOREACH_SLISTBASE_ENTRY(HashBucket, bucket, &this->table[hash])
- {
- if (Key::Get(bucket.value) <= key)
- {
- if (Key::Get(bucket.value) == key)
- {
- return &(bucket.element);
- }
- break;
- }
- } NEXT_SLISTBASE_ENTRY;
- return NULL;
- }
- HashBucket * GetBucket(uint key)
- {
- uint hash = this->Hash(key);
- // Assumes sorted lists
- FOREACH_SLISTBASE_ENTRY(HashBucket, bucket, &this->table[hash])
- {
- if (Key::Get(bucket.value) <= key)
- {
- if (Key::Get(bucket.value) == key)
- {
- return &bucket;
- }
- break;
- }
- } NEXT_SLISTBASE_ENTRY;
- return nullptr;
- }
- TElement GetAndClear(TData * value)
- {
- uint key = Key::Get(value);
- uint hash = this->Hash(key);
- SListBase<HashBucket> * list = &this->table[hash];
- #if PROFILE_DICTIONARY
- bool first = true;
- #endif
- // Assumes sorted lists
- FOREACH_SLISTBASE_ENTRY_EDITING(HashBucket, bucket, list, iter)
- {
- if (Key::Get(bucket.value) <= key)
- {
- if (Key::Get(bucket.value) == key)
- {
- TElement retVal = bucket.element;
- iter.RemoveCurrent(this->alloc);
- #if PROFILE_DICTIONARY
- if (stats)
- stats->Remove(first && !(iter.Next()));
- #endif
- return retVal;
- }
- break;
- }
- #if PROFILE_DICTIONARY
- first = false;
- #endif
- } NEXT_SLISTBASE_ENTRY_EDITING;
- return nullptr;
- }
- void Clear(uint key)
- {
- uint hash = this->Hash(key);
- SListBase<HashBucket> * list = &this->table[hash];
- // Assumes sorted lists
- #if PROFILE_DICTIONARY
- bool first = true;
- #endif
- FOREACH_SLISTBASE_ENTRY_EDITING(HashBucket, bucket, list, iter)
- {
- if (Key::Get(bucket.value) <= key)
- {
- if (Key::Get(bucket.value) == key)
- {
- iter.RemoveCurrent(this->alloc);
- #if PROFILE_DICTIONARY
- if (stats)
- stats->Remove(first && !(iter.Next()));
- #endif
- }
- return;
- }
- #if PROFILE_DICTIONARY
- first = false;
- #endif
- } NEXT_SLISTBASE_ENTRY_EDITING;
- }
- void And(ValueHashTable *this2)
- {
- for (uint i = 0; i < this->tableSize; i++)
- {
- _TYPENAME SListBase<HashBucket>::Iterator iter2(&this2->table[i]);
- iter2.Next();
- FOREACH_SLISTBASE_ENTRY_EDITING(HashBucket, bucket, &this->table[i], iter)
- {
- while (iter2.IsValid() && bucket.value < iter2.Data().value)
- {
- iter2.Next();
- }
- if (!iter2.IsValid() || bucket.value != iter2.Data().value || bucket.element != iter2.Data().element)
- {
- iter.RemoveCurrent(this->alloc);
- #if PROFILE_DICTIONARY
- if (stats)
- stats->Remove(false);
- #endif
- continue;
- }
- else
- {
- AssertMsg(bucket.value == iter2.Data().value && bucket.element == iter2.Data().element, "Huh??");
- }
- iter2.Next();
- } NEXT_SLISTBASE_ENTRY_EDITING;
- }
- }
- template <class Fn>
- void Or(ValueHashTable * this2, Fn fn)
- {
- for (uint i = 0; i < this->tableSize; i++)
- {
- _TYPENAME SListBase<HashBucket>::Iterator iter2(&this2->table[i]);
- iter2.Next();
- FOREACH_SLISTBASE_ENTRY_EDITING((HashBucket), bucket, &this->table[i], iter)
- {
- while (iter2.IsValid() && bucket.value < iter2.Data().value)
- {
- HashBucket * newBucket = iter.InsertNodeBefore(this->alloc);
- newBucket->value = iter2.Data().value;
- newBucket->element = fn(null, iter2.Data().element);
- iter2.Next();
- }
- if (!iter2.IsValid())
- {
- break;
- }
- if (bucket.value == iter2.Data().value)
- {
- bucket.element = fn(bucket.element, iter2.Data().element);
- iter2.Next();
- }
- } NEXT_SLISTBASE_ENTRY_EDITING;
- while (iter2.IsValid())
- {
- HashBucket * newBucket = iter.InsertNodeBefore(this->alloc);
- newBucket->value = iter2.Data().value;
- newBucket->element = fn(null, iter2.Data().element);
- iter2.Next();
- }
- }
- }
- ValueHashTable *Copy()
- {
- ValueHashTable *newTable = ValueHashTable::New(this->alloc, this->tableSize);
- for (uint i = 0; i < this->tableSize; i++)
- {
- this->table[i].template CopyTo<HashBucket::Copy>(this->alloc, newTable->table[i]);
- }
- #if PROFILE_DICTIONARY
- if (stats)
- newTable->stats = stats->Clone();
- #endif
- return newTable;
- }
- void ClearAll()
- {
- for (uint i = 0; i < this->tableSize; i++)
- {
- this->table[i].Clear(this->alloc);
- }
- #if PROFILE_DICTIONARY
- // To not lose previously collected data, we will treat cleared dictionary as a separate instance for stats tracking purpose
- stats = DictionaryStats::Create(typeid(this).name(), tableSize);
- #endif
- }
- #if DBG_DUMP
- void Dump()
- {
- FOREACH_GLOBHASHTABLE_ENTRY(bucket, this)
- {
- Output::Print(_u("%4d => "), bucket.value);
- bucket.element->Dump();
- Output::Print(_u("\n"));
- Output::Print(_u("\n"));
- }
- NEXT_GLOBHASHTABLE_ENTRY;
- }
- void Dump(void (*valueDump)(TData))
- {
- Output::Print(_u("\n-------------------------------------------------------------------------------------------------\n"));
- FOREACH_GLOBHASHTABLE_ENTRY(bucket, this)
- {
- valueDump(bucket.value);
- Output::Print(_u(" => "), bucket.value);
- bucket.element->Dump();
- Output::Print(_u("\n"));
- }
- NEXT_GLOBHASHTABLE_ENTRY;
- }
- #endif
- protected:
- ValueHashTable(JitArenaAllocator * allocator, uint tableSize) : alloc(allocator), tableSize(tableSize)
- {
- Init();
- #if PROFILE_DICTIONARY
- stats = DictionaryStats::Create(typeid(this).name(), tableSize);
- #endif
- }
- void Init()
- {
- table = (SListBase<HashBucket> *)(((char *)this) + sizeof(ValueHashTable));
- for (uint i = 0; i < tableSize; i++)
- {
- // placement new
- ::new (&table[i]) SListBase<HashBucket>();
- }
- }
- private:
- uint Hash(uint key) { return (key % this->tableSize); }
- #if PROFILE_DICTIONARY
- DictionaryStats *stats;
- #endif
- };
|