123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736 |
- #pragma once
- #include "Array.h"
- #include <unordered_map>
- #define NEW_DICTIONAY
- NS_BF_BEGIN;
- #ifdef NEW_DICTIONAY
- template <typename TKey, typename TValue, typename TAlloc = AllocatorCLib >
- class Dictionary : public TAlloc
- {
- public:
- typedef int int_cosize;
- typedef TKey key_type;
- typedef TValue value_type;
- struct EntryPair
- {
- public:
- TKey mKey; // Key of entry
- TValue mValue; // Value of entry
- };
- struct RawEntryPair
- {
- public:
- typename std::aligned_storage<sizeof(TKey), alignof(TKey)>::type mKey;
- typename std::aligned_storage<sizeof(TValue), alignof(TValue)>::type mValue;
- };
- public:
- struct Entry : public RawEntryPair
- {
- int_cosize mNext; // Index of next entry, -1 if last
- int32 mHashCode; // Lower 31 bits of hash code, -1 if unused
- };
- public:
- int_cosize* mBuckets;
- Entry* mEntries;
- int_cosize mAllocSize;
- int_cosize mCount;
- int_cosize mFreeList;
- int_cosize mFreeCount;
- public:
- struct iterator
- {
- public:
- typedef std::bidirectional_iterator_tag iterator_category;
- //typedef T value_type;
- //typedef intptr difference_type;
- //typedef T* pointer;
- //typedef T& reference;
- public:
- Dictionary* mDictionary;
- int_cosize mIdx;
- int_cosize mCurrentIdx;
- protected:
- void MoveNext()
- {
- while ((uintptr)mIdx < (uintptr)mDictionary->mCount)
- {
- if (mDictionary->mEntries[mIdx].mHashCode >= 0)
- {
- mCurrentIdx = mIdx;
- mIdx++;
- return;
- }
- mIdx++;
- }
- mIdx = mDictionary->mCount + 1;
- mCurrentIdx = -1;
- }
- public:
- iterator()
- {
- mDictionary = NULL;
- mIdx = 0;
- mCurrentIdx = -1;
- }
- iterator(Dictionary* dict, int idx)
- {
- mDictionary = dict;
- mIdx = idx;
- mCurrentIdx = idx;
- }
- iterator(Dictionary* dict, int idx, int currentIdx)
- {
- mDictionary = dict;
- mIdx = idx;
- mCurrentIdx = currentIdx;
- }
- iterator& operator++()
- {
- MoveNext();
- return *this;
- }
- iterator operator++(int)
- {
- auto prevVal = *this;
- MoveNext();
- return prevVal;
- }
- bool NextWithSameKey(const TKey& key)
- {
- int_cosize hashCode = (int_cosize)BeefHash<TKey>()(key) & 0x7FFFFFFF;
- while (mCurrentIdx >= 0)
- {
- mCurrentIdx = mDictionary->mEntries[mCurrentIdx].mNext;
- if (mCurrentIdx < 0)
- break;
- if ((mDictionary->mEntries[mCurrentIdx].mHashCode == hashCode) &&
- ((*(TKey*)&mDictionary->mEntries[mCurrentIdx].mKey) == key))
- {
- mIdx = mCurrentIdx;
- return true;
- }
- }
- mIdx = mDictionary->mCount + 1;
- mCurrentIdx = -1;
- return false;
- }
-
- bool operator!=(const iterator& itr) const
- {
- return (itr.mDictionary != mDictionary) || (itr.mIdx != mIdx);
- }
- bool operator==(const iterator& itr) const
- {
- return (itr.mDictionary == mDictionary) && (itr.mIdx == mIdx);
- }
- EntryPair& operator*()
- {
- return *(EntryPair*)&mDictionary->mEntries[mCurrentIdx];
- }
- EntryPair* operator->()
- {
- return (EntryPair*)&mDictionary->mEntries[mCurrentIdx];
- }
- };
- private:
- int_cosize GetPrimeish(int_cosize min)
- {
- // This is a minimal effort to help address-aligned dataa
- return (min | 1);
- }
- int_cosize ExpandSize(int_cosize oldSize)
- {
- int_cosize newSize = 2 * oldSize;
- // Allow the hashtables to grow to maximum possible size (~2G elements) before encoutering capacity overflow.
- // Note that this check works even when mAllocSize overflowed thanks to the (uint) cast
- /*if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
- {
- Contract.Assert( MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength");
- return MaxPrimeArrayLength;
- }*/
- return GetPrimeish(newSize);
- }
- void Resize()
- {
- Resize(ExpandSize(mCount), false);
- }
- void Resize(intptr newSize, bool forceNewHashCodes)
- {
- BF_ASSERT(newSize >= mAllocSize);
- Entry* newEntries;
- int_cosize* newBuckets;
- AllocData(newSize, newEntries, newBuckets);
-
- for (int_cosize i = 0; i < newSize; i++)
- newBuckets[i] = -1;
- for (int i = 0; i < mCount; i++)
- {
- auto& newEntry = newEntries[i];
- auto& oldEntry = mEntries[i];
- newEntry.mHashCode = oldEntry.mHashCode;
- newEntry.mNext = oldEntry.mNext;
- new (&newEntry.mKey) TKey(std::move(*(TKey*)&oldEntry.mKey));
- new (&newEntry.mValue) TValue(std::move(*(TValue*)&oldEntry.mValue));
- }
- for (int i = mCount; i < newSize; i++)
- {
- newEntries[i].mHashCode = -1;
- }
- if (forceNewHashCodes)
- {
- for (int_cosize i = 0; i < mCount; i++)
- {
- if (newEntries[i].mHashCode != -1)
- {
- newEntries[i].mHashCode = (int_cosize)BeefHash<TKey>()(*(TKey*)&newEntries[i].mKey) & 0x7FFFFFFF;
- }
- }
- }
- for (int_cosize i = 0; i < mCount; i++)
- {
- if (newEntries[i].mHashCode >= 0)
- {
- int_cosize bucket = (int_cosize)(newEntries[i].mHashCode % newSize);
- newEntries[i].mNext = newBuckets[bucket];
- newBuckets[bucket] = i;
- }
- }
- DeleteData();
- mBuckets = newBuckets;
- mEntries = newEntries;
- mAllocSize = (int_cosize)newSize;
- }
- int FindEntry(const TKey& key)
- {
- if (mBuckets != NULL)
- {
- int_cosize hashCode = (int_cosize)BeefHash<TKey>()(key) & 0x7FFFFFFF;
- for (int_cosize i = mBuckets[hashCode % mAllocSize]; i >= 0; i = mEntries[i].mNext)
- {
- if (mEntries[i].mHashCode == hashCode && (*(TKey*)&mEntries[i].mKey == key)) return i;
- }
- }
- return -1;
- }
- template <typename TAltKey>
- int FindEntryWith(const TAltKey& key)
- {
- if (mBuckets != NULL)
- {
- int_cosize hashCode = (int_cosize)BeefHash<TAltKey>()(key) & 0x7FFFFFFF;
- for (int_cosize i = mBuckets[hashCode % mAllocSize]; i >= 0; i = mEntries[i].mNext)
- {
- if (mEntries[i].mHashCode == hashCode && (*(TKey*)&mEntries[i].mKey == key)) return i;
- }
- }
- return -1;
- }
- void Initialize(intptr capacity)
- {
- int_cosize size = GetPrimeish((int_cosize)capacity);
- AllocData(size, mEntries, mBuckets);
- mAllocSize = size;
- for (int_cosize i = 0; i < (int_cosize)mAllocSize; i++) mBuckets[i] = -1;
- mFreeList = -1;
- }
- bool Insert(const TKey& key, bool forceAdd, TKey** keyPtr, TValue** valuePtr)
- {
- if (mBuckets == NULL) Initialize(0);
- int_cosize hashCode = (int_cosize)BeefHash<TKey>()(key) & 0x7FFFFFFF;
- int_cosize targetBucket = hashCode % (int_cosize)mAllocSize;
- if (!forceAdd)
- {
- for (int_cosize i = mBuckets[targetBucket]; i >= 0; i = mEntries[i].mNext)
- {
- if ((mEntries[i].mHashCode == hashCode) && (*(TKey*)&mEntries[i].mKey == key))
- {
- if (keyPtr != NULL)
- *keyPtr = (TKey*)&mEntries[i].mKey;
- if (valuePtr != NULL)
- *valuePtr = (TValue*)&mEntries[i].mValue;
- return false;
- }
- }
- }
- int_cosize index;
- if (mFreeCount > 0)
- {
- index = mFreeList;
- mFreeList = mEntries[index].mNext;
- mFreeCount--;
- }
- else
- {
- if (mCount == mAllocSize)
- {
- Resize();
- targetBucket = hashCode % (int_cosize)mAllocSize;
- }
- index = mCount;
- mCount++;
- }
- mEntries[index].mHashCode = hashCode;
- mEntries[index].mNext = mBuckets[targetBucket];
- new (&mEntries[index].mKey) TKey(key);
- mBuckets[targetBucket] = index;
-
- if (keyPtr != NULL)
- *keyPtr = (TKey*)&mEntries[index].mKey;
- if (valuePtr != NULL)
- *valuePtr = (TValue*)&mEntries[index].mValue;
- return true;
- }
- void RemoveIdx(int_cosize bucket, int_cosize i, int_cosize last)
- {
- if (last < 0)
- {
- mBuckets[bucket] = mEntries[i].mNext;
- }
- else
- {
- mEntries[last].mNext = mEntries[i].mNext;
- }
- mEntries[i].mHashCode = -1;
- mEntries[i].mNext = mFreeList;
- ((TKey*)&mEntries[i].mKey)->~TKey();
- ((TValue*)&mEntries[i].mValue)->~TValue();
- mFreeList = i;
- mFreeCount++;
- }
- public:
- Dictionary()
- {
- mBuckets = NULL;
- mEntries = NULL;
- mAllocSize = 0;
- mCount = 0;
- mFreeList = 0;
- mFreeCount = 0;
- }
- Dictionary(const Dictionary& val)
- {
- mAllocSize = val.mAllocSize;
- mCount = val.mCount;
- if (mAllocSize == 0)
- {
- mBuckets = NULL;
- mEntries = NULL;
- }
- else
- {
- AllocData(mAllocSize, mEntries, mBuckets);
- for (int_cosize i = 0; i < mAllocSize; i++)
- mBuckets[i] = val.mBuckets[i];
- for (int i = 0; i < mCount; i++)
- {
- auto& newEntry = mEntries[i];
- auto& oldEntry = val.mEntries[i];
- newEntry.mHashCode = oldEntry.mHashCode;
- newEntry.mNext = oldEntry.mNext;
- new (&newEntry.mKey) TKey(*(TKey*)&oldEntry.mKey);
- new (&newEntry.mValue) TValue(*(TValue*)&oldEntry.mValue);
- }
- for (int i = mCount; i < mAllocSize; i++)
- {
- mEntries[i].mHashCode = -1;
- }
- }
- mFreeCount = val.mFreeCount;
- mFreeList = val.mFreeList;
- }
- Dictionary(Dictionary&& val)
- {
- mBuckets = val.mBuckets;
- mEntries = val.mEntries;
- mAllocSize = val.mAllocSize;
- mCount = val.mCount;
- mFreeList = val.mFreeList;
- mFreeCount = val.mFreeCount;
- val.mBuckets = NULL;
- val.mEntries = NULL;
- val.mAllocSize = 0;
- val.mCount = 0;
- val.mFreeList = 0;
- val.mFreeCount = 0;
- }
- ~Dictionary()
- {
- DeleteData();
- }
- void AllocData(intptr size, Entry*& outEntries, int_cosize*& outBuckets)
- {
- uint8* data = (uint8*)this->rawAllocate(size * (sizeof(Entry) + sizeof(int_cosize)));
- outEntries = (Entry*)data;
- outBuckets = (int_cosize*)(data + size * sizeof(Entry));
- }
- void DeleteData()
- {
- if (!std::is_pod<TKey>::value)
- {
- for (int_cosize i = 0; i < mCount; i++)
- {
- if (mEntries[i].mHashCode != -1)
- ((TKey*)&mEntries[i].mKey)->~TKey();
- }
- }
- if (!std::is_pod<TValue>::value)
- {
- for (int_cosize i = 0; i < mCount; i++)
- {
- if (mEntries[i].mHashCode != -1)
- ((TValue*)&mEntries[i].mValue)->~TValue();
- }
- }
- this->rawDeallocate(mEntries);
- }
- Dictionary& operator=(const Dictionary& rhs)
- {
- Clear();
- for (auto& kv : rhs)
- ForceAdd(kv.mKey, kv.mValue);
- return *this;
- }
- intptr GetCount() const
- {
- return mCount - mFreeCount;
- }
- intptr size() const
- {
- return mCount - mFreeCount;
- }
- bool IsEmpty() const
- {
- return mCount - mFreeCount == 0;
- }
- void Reserve(intptr size)
- {
- if (size > mAllocSize)
- Resize(size, false);
- }
- TValue& operator[](const TKey& key)
- {
- TValue* valuePtr;
- if (Insert(key, false, NULL, &valuePtr))
- {
- new (valuePtr) TValue();
- }
- return *valuePtr;
- }
- const TValue& operator[](const TKey& key) const
- {
- int_cosize i = (int_cosize)FindEntry(key);
- if (i >= 0)
- return mEntries[i].mValue;
- BF_FATAL("Key not found");
- return TValue();
- }
- void ForceAdd(const TKey& key, const TValue& value)
- {
- TValue* valuePtr = NULL;
- Insert(key, true, NULL, &valuePtr);
- new (valuePtr) TValue(value);
- }
- bool TryAdd(const TKey& key, const TValue& value)
- {
- TValue* valuePtr;
- if (!Insert(key, false, NULL, &valuePtr))
- return false;
- new (valuePtr) TValue(value);
- return true;
- }
- bool TryAdd(const TKey& key, TKey** keyPtr, TValue** valuePtr)
- {
- if (!Insert(key, false, keyPtr, valuePtr))
- return false;
- new (*valuePtr) TValue();
- return true;
- }
- // template <typename TAltKey>
- // bool TryAddWith(const TAltKey& key, TKey** keyPtr, TValue** valuePtr)
- // {
- // if (!Insert(key, false, keyPtr, valuePtr))
- // return false;
- // new (*valuePtr) TValue();
- // return true;
- // }
- // Returns uninitialized valuePtr - must use placement new
- bool TryAddRaw(const TKey& key, TKey** keyPtr, TValue** valuePtr)
- {
- return Insert(key, false, keyPtr, valuePtr);
- }
- bool TryGetValue(const TKey& key, TValue** valuePtr)
- {
- int_cosize i = (int_cosize)FindEntry(key);
- if (i >= 0)
- {
- *valuePtr = (TValue*)&mEntries[i].mValue;
- return true;
- }
- return false;
- }
- template <typename TAltKey>
- bool TryGetValueWith(const TAltKey& key, TValue** valuePtr)
- {
- int_cosize i = (int_cosize)FindEntryWith(key);
- if (i >= 0)
- {
- *valuePtr = (TValue*)&mEntries[i].mValue;
- return true;
- }
- return false;
- }
- bool TryGetValue(const TKey& key, TValue* valuePtr)
- {
- int_cosize i = (int_cosize)FindEntry(key);
- if (i >= 0)
- {
- *valuePtr = *(TValue*)&mEntries[i].mValue;
- return true;
- }
- return false;
- }
- iterator Find(const TKey& key)
- {
- int_cosize i = (int_cosize)FindEntry(key);
- iterator itr;
- if (i >= 0)
- {
- return iterator((Dictionary*)this, i);
- }
- else
- return iterator((Dictionary*)this, mCount + 1, -1);
- }
-
- bool Remove(const TKey& key)
- {
- if (mBuckets != NULL)
- {
- int_cosize hashCode = (int_cosize)BeefHash<TKey>()(key) & 0x7FFFFFFF;
- int_cosize bucket = hashCode % (int_cosize)mAllocSize;
- int_cosize last = -1;
- for (int_cosize i = mBuckets[bucket]; i >= 0; last = i, i = mEntries[i].mNext)
- {
- if ((mEntries[i].mHashCode == hashCode) && (*(TKey*)&mEntries[i].mKey == key))
- {
- RemoveIdx(bucket, i, last);
- return true;
- }
- }
- }
- return false;
- }
- bool Remove(const TKey& key, TValue* valuePtr)
- {
- if (mBuckets != NULL)
- {
- int_cosize hashCode = (int_cosize)BeefHash<TKey>()(key) & 0x7FFFFFFF;
- int_cosize bucket = hashCode % (int_cosize)mAllocSize;
- int_cosize last = -1;
- for (int_cosize i = mBuckets[bucket]; i >= 0; last = i, i = mEntries[i].mNext)
- {
- if ((mEntries[i].mHashCode == hashCode) && (*(TKey*)&mEntries[i].mKey == key))
- {
- *valuePtr = *(TValue*)&mEntries[i].mValue;
- RemoveIdx(bucket, i, last);
- return true;
- }
- }
- }
- return false;
- }
- bool Remove(const TKey& key, const TValue& value)
- {
- if (mBuckets != NULL)
- {
- int_cosize hashCode = (int_cosize)BeefHash<TKey>()(key) & 0x7FFFFFFF;
- int_cosize bucket = hashCode % (int_cosize)mAllocSize;
- int_cosize last = -1;
- for (int_cosize i = mBuckets[bucket]; i >= 0; last = i, i = mEntries[i].mNext)
- {
- if ((mEntries[i].mHashCode == hashCode) && (*(TKey*)&mEntries[i].mKey == key) &&
- (*(TValue*)&mEntries[i].mValue == value))
- {
- RemoveIdx(bucket, i, last);
- return true;
- }
- }
- }
- return false;
- }
- iterator Remove(const iterator& itr)
- {
- iterator nextItr = itr;
- ++nextItr;
- auto& entry = mEntries[itr.mCurrentIdx];
- BF_ASSERT(entry.mHashCode >= 0);
- // We have to iterate through to mCurrentIdx so we can get 'last'
- int_cosize hashCode = entry.mHashCode;
- int_cosize bucket = hashCode % (int_cosize)mAllocSize;
- int_cosize last = -1;
- for (int_cosize i = mBuckets[bucket]; i >= 0; last = i, i = mEntries[i].mNext)
- {
- if ((mEntries[i].mHashCode == hashCode) && (i == itr.mCurrentIdx))
- {
- RemoveIdx(bucket, i, last);
- return nextItr;
- }
- }
- BF_FATAL("not found");
- return nextItr;
- }
- void Clear()
- {
- if (mCount > 0)
- {
- for (int_cosize i = 0; i < mAllocSize; i++) mBuckets[i] = -1;
- if (!std::is_pod<TKey>::value)
- {
- for (int_cosize i = 0; i < mCount; i++)
- {
- if (mEntries[i].mHashCode != -1)
- ((TKey*)&mEntries[i].mKey)->~TKey();
- }
- }
-
- if (!std::is_pod<TValue>::value)
- {
- for (int_cosize i = 0; i < mCount; i++)
- {
- if (mEntries[i].mHashCode != -1)
- ((TValue*)&mEntries[i].mValue)->~TValue();
- }
- }
- for (int_cosize i = 0; i < mCount; i++)
- {
- mEntries[i].mHashCode = -1;
- }
- mFreeList = -1;
- mCount = 0;
- mFreeCount = 0;
- }
- }
- bool ContainsKey(const TKey& key)
- {
- return FindEntry(key) >= 0;
- }
-
- iterator begin() const
- {
- iterator itr((Dictionary*)this, 0);
- ++itr;
- return itr;
- }
- iterator end() const
- {
- return iterator((Dictionary*)this, mCount + 1, -1);
- }
- };
- #else
- template <typename TKey, typename TValue>
- class Dictionary : public std::unordered_map<TKey, TValue>
- {
- public:
- public:
- TValue* GetValuePtr(const TKey& key)
- {
- auto itr = find(key);
- if (itr == end())
- return NULL;
- return &itr->second;
- }
- bool ContainsKey(const TKey& key)
- {
- return find(key) != end();
- }
- };
- #endif
- NS_BF_END;
|