summaryrefslogtreecommitdiffstats
path: root/source/core/dictionary.h
diff options
context:
space:
mode:
Diffstat (limited to 'source/core/dictionary.h')
-rw-r--r--source/core/dictionary.h1018
1 files changed, 1018 insertions, 0 deletions
diff --git a/source/core/dictionary.h b/source/core/dictionary.h
new file mode 100644
index 000000000..77f0df515
--- /dev/null
+++ b/source/core/dictionary.h
@@ -0,0 +1,1018 @@
+#ifndef CORE_LIB_DICTIONARY_H
+#define CORE_LIB_DICTIONARY_H
+#include "list.h"
+#include "common.h"
+#include "int-set.h"
+#include "exception.h"
+#include "slang-math.h"
+#include "hash.h"
+
+namespace CoreLib
+{
+ namespace Basic
+ {
+ template<typename TKey, typename TValue>
+ class KeyValuePair
+ {
+ public:
+ TKey Key;
+ TValue Value;
+ KeyValuePair()
+ {}
+ KeyValuePair(const TKey & key, const TValue & value)
+ {
+ Key = key;
+ Value = value;
+ }
+ KeyValuePair(TKey && key, TValue && value)
+ {
+ Key = _Move(key);
+ Value = _Move(value);
+ }
+ KeyValuePair(TKey && key, const TValue & value)
+ {
+ Key = _Move(key);
+ Value = value;
+ }
+ KeyValuePair(const KeyValuePair<TKey, TValue> & _that)
+ {
+ Key = _that.Key;
+ Value = _that.Value;
+ }
+ KeyValuePair(KeyValuePair<TKey, TValue> && _that)
+ {
+ operator=(_Move(_that));
+ }
+ KeyValuePair & operator=(KeyValuePair<TKey, TValue> && that)
+ {
+ Key = _Move(that.Key);
+ Value = _Move(that.Value);
+ return *this;
+ }
+ KeyValuePair & operator=(const KeyValuePair<TKey, TValue> & that)
+ {
+ Key = that.Key;
+ Value = that.Value;
+ return *this;
+ }
+ int GetHashCode()
+ {
+ return GetHashCode(Key);
+ }
+ };
+
+ template<typename TKey, typename TValue>
+ inline KeyValuePair<TKey, TValue> KVPair(const TKey & k, const TValue & v)
+ {
+ return KeyValuePair<TKey, TValue>(k, v);
+ }
+
+ const float MaxLoadFactor = 0.7f;
+
+ template<typename TKey, typename TValue>
+ class Dictionary
+ {
+ friend class Iterator;
+ friend class ItemProxy;
+ private:
+ inline int GetProbeOffset(int /*probeId*/) const
+ {
+ // quadratic probing
+ return 1;
+ }
+ private:
+ int bucketSizeMinusOne, shiftBits;
+ int _count;
+ IntSet marks;
+ KeyValuePair<TKey, TValue>* hashMap;
+ void Free()
+ {
+ if (hashMap)
+ delete[] hashMap;
+ hashMap = 0;
+ }
+ inline bool IsDeleted(int pos) const
+ {
+ return marks.Contains((pos << 1) + 1);
+ }
+ inline bool IsEmpty(int pos) const
+ {
+ return !marks.Contains((pos << 1));
+ }
+ inline void SetDeleted(int pos, bool val)
+ {
+ if (val)
+ marks.Add((pos << 1) + 1);
+ else
+ marks.Remove((pos << 1) + 1);
+ }
+ inline void SetEmpty(int pos, bool val)
+ {
+ if (val)
+ marks.Remove((pos << 1));
+ else
+ marks.Add((pos << 1));
+ }
+ struct FindPositionResult
+ {
+ int ObjectPosition;
+ int InsertionPosition;
+ FindPositionResult()
+ {
+ ObjectPosition = -1;
+ InsertionPosition = -1;
+ }
+ FindPositionResult(int objPos, int insertPos)
+ {
+ ObjectPosition = objPos;
+ InsertionPosition = insertPos;
+ }
+
+ };
+ template<typename T>
+ inline int GetHashPos(T & key) const
+ {
+ return ((unsigned int)(GetHashCode(key) * 2654435761)) >> shiftBits;
+ }
+ template<typename T>
+ FindPositionResult FindPosition(const T & key) const
+ {
+ int hashPos = GetHashPos((T&)key);
+ int insertPos = -1;
+ int numProbes = 0;
+ while (numProbes <= bucketSizeMinusOne)
+ {
+ if (IsEmpty(hashPos))
+ {
+ if (insertPos == -1)
+ return FindPositionResult(-1, hashPos);
+ else
+ return FindPositionResult(-1, insertPos);
+ }
+ else if (IsDeleted(hashPos))
+ {
+ if (insertPos == -1)
+ insertPos = hashPos;
+ }
+ else if (hashMap[hashPos].Key == key)
+ {
+ return FindPositionResult(hashPos, -1);
+ }
+ numProbes++;
+ hashPos = (hashPos + GetProbeOffset(numProbes)) & bucketSizeMinusOne;
+ }
+ if (insertPos != -1)
+ return FindPositionResult(-1, insertPos);
+ throw InvalidOperationException("Hash map is full. This indicates an error in Key::Equal or Key::GetHashCode.");
+ }
+ TValue & _Insert(KeyValuePair<TKey, TValue> && kvPair, int pos)
+ {
+ hashMap[pos] = _Move(kvPair);
+ SetEmpty(pos, false);
+ SetDeleted(pos, false);
+ return hashMap[pos].Value;
+ }
+ void Rehash()
+ {
+ if (bucketSizeMinusOne == -1 || _count / (float)bucketSizeMinusOne >= MaxLoadFactor)
+ {
+ int newSize = (bucketSizeMinusOne + 1) * 2;
+ int newShiftBits = shiftBits - 1;
+ if (newSize == 0)
+ {
+ newSize = 16;
+ newShiftBits = 28;
+ }
+ Dictionary<TKey, TValue> newDict;
+ newDict.shiftBits = newShiftBits;
+ newDict.bucketSizeMinusOne = newSize - 1;
+ newDict.hashMap = new KeyValuePair<TKey, TValue>[newSize];
+ newDict.marks.SetMax(newSize * 2);
+ if (hashMap)
+ {
+ for (auto & kvPair : *this)
+ {
+ newDict.Add(_Move(kvPair));
+ }
+ }
+ *this = _Move(newDict);
+ }
+ }
+
+ bool AddIfNotExists(KeyValuePair<TKey, TValue> && kvPair)
+ {
+ Rehash();
+ auto pos = FindPosition(kvPair.Key);
+ if (pos.ObjectPosition != -1)
+ return false;
+ else if (pos.InsertionPosition != -1)
+ {
+ _count++;
+ _Insert(_Move(kvPair), pos.InsertionPosition);
+ return true;
+ }
+ else
+ throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation.");
+ }
+ void Add(KeyValuePair<TKey, TValue> && kvPair)
+ {
+ if (!AddIfNotExists(_Move(kvPair)))
+ throw KeyExistsException("The key already exists in Dictionary.");
+ }
+ TValue & Set(KeyValuePair<TKey, TValue> && kvPair)
+ {
+ Rehash();
+ auto pos = FindPosition(kvPair.Key);
+ if (pos.ObjectPosition != -1)
+ return _Insert(_Move(kvPair), pos.ObjectPosition);
+ else if (pos.InsertionPosition != -1)
+ {
+ _count++;
+ return _Insert(_Move(kvPair), pos.InsertionPosition);
+ }
+ else
+ throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation.");
+ }
+ public:
+ class Iterator
+ {
+ private:
+ const Dictionary<TKey, TValue> * dict;
+ int pos;
+ public:
+ KeyValuePair<TKey, TValue> & operator *() const
+ {
+ return dict->hashMap[pos];
+ }
+ KeyValuePair<TKey, TValue> * operator ->() const
+ {
+ return dict->hashMap + pos;
+ }
+ Iterator & operator ++()
+ {
+ if (pos > dict->bucketSizeMinusOne)
+ return *this;
+ pos++;
+ while (pos <= dict->bucketSizeMinusOne && (dict->IsDeleted(pos) || dict->IsEmpty(pos)))
+ {
+ pos++;
+ }
+ return *this;
+ }
+ Iterator operator ++(int)
+ {
+ Iterator rs = *this;
+ operator++();
+ return rs;
+ }
+ bool operator != (const Iterator & _that) const
+ {
+ return pos != _that.pos || dict != _that.dict;
+ }
+ bool operator == (const Iterator & _that) const
+ {
+ return pos == _that.pos && dict == _that.dict;
+ }
+ Iterator(const Dictionary<TKey, TValue> * _dict, int _pos)
+ {
+ this->dict = _dict;
+ this->pos = _pos;
+ }
+ Iterator()
+ {
+ this->dict = 0;
+ this->pos = 0;
+ }
+ };
+
+ Iterator begin() const
+ {
+ int pos = 0;
+ while (pos < bucketSizeMinusOne + 1)
+ {
+ if (IsEmpty(pos) || IsDeleted(pos))
+ pos++;
+ else
+ break;
+ }
+ return Iterator(this, pos);
+ }
+ Iterator end() const
+ {
+ return Iterator(this, bucketSizeMinusOne + 1);
+ }
+ public:
+ void Add(const TKey & key, const TValue & value)
+ {
+ Add(KeyValuePair<TKey, TValue>(key, value));
+ }
+ void Add(TKey && key, TValue && value)
+ {
+ Add(KeyValuePair<TKey, TValue>(_Move(key), _Move(value)));
+ }
+ bool AddIfNotExists(const TKey & key, const TValue & value)
+ {
+ return AddIfNotExists(KeyValuePair<TKey, TValue>(key, value));
+ }
+ bool AddIfNotExists(TKey && key, TValue && value)
+ {
+ return AddIfNotExists(KeyValuePair<TKey, TValue>(_Move(key), _Move(value)));
+ }
+ void Remove(const TKey & key)
+ {
+ if (_count == 0)
+ return;
+ auto pos = FindPosition(key);
+ if (pos.ObjectPosition != -1)
+ {
+ SetDeleted(pos.ObjectPosition, true);
+ _count--;
+ }
+ }
+ void Clear()
+ {
+ _count = 0;
+
+ marks.Clear();
+ }
+
+ template<typename T>
+ bool ContainsKey(const T & key) const
+ {
+ if (bucketSizeMinusOne == -1)
+ return false;
+ auto pos = FindPosition(key);
+ return pos.ObjectPosition != -1;
+ }
+ template<typename T>
+ bool TryGetValue(const T & key, TValue & value) const
+ {
+ if (bucketSizeMinusOne == -1)
+ return false;
+ auto pos = FindPosition(key);
+ if (pos.ObjectPosition != -1)
+ {
+ value = hashMap[pos.ObjectPosition].Value;
+ return true;
+ }
+ return false;
+ }
+ template<typename T>
+ TValue * TryGetValue(const T & key) const
+ {
+ if (bucketSizeMinusOne == -1)
+ return nullptr;
+ auto pos = FindPosition(key);
+ if (pos.ObjectPosition != -1)
+ {
+ return &hashMap[pos.ObjectPosition].Value;
+ }
+ return nullptr;
+ }
+ class ItemProxy
+ {
+ private:
+ const Dictionary<TKey, TValue> * dict;
+ TKey key;
+ public:
+ ItemProxy(const TKey & _key, const Dictionary<TKey, TValue> * _dict)
+ {
+ this->dict = _dict;
+ this->key = _key;
+ }
+ ItemProxy(TKey && _key, const Dictionary<TKey, TValue> * _dict)
+ {
+ this->dict = _dict;
+ this->key = _Move(_key);
+ }
+ TValue & GetValue() const
+ {
+ auto pos = dict->FindPosition(key);
+ if (pos.ObjectPosition != -1)
+ {
+ return dict->hashMap[pos.ObjectPosition].Value;
+ }
+ else
+ throw KeyNotFoundException("The key does not exists in dictionary.");
+ }
+ inline TValue & operator()() const
+ {
+ return GetValue();
+ }
+ operator TValue&() const
+ {
+ return GetValue();
+ }
+ TValue & operator = (const TValue & val) const
+ {
+ return ((Dictionary<TKey, TValue>*)dict)->Set(KeyValuePair<TKey, TValue>(_Move(key), val));
+ }
+ TValue & operator = (TValue && val) const
+ {
+ return ((Dictionary<TKey, TValue>*)dict)->Set(KeyValuePair<TKey, TValue>(_Move(key), _Move(val)));
+ }
+ };
+ ItemProxy operator [](const TKey & key) const
+ {
+ return ItemProxy(key, this);
+ }
+ ItemProxy operator [](TKey && key) const
+ {
+ return ItemProxy(_Move(key), this);
+ }
+ int Count() const
+ {
+ return _count;
+ }
+ private:
+ template<typename... Args>
+ void Init(const KeyValuePair<TKey, TValue> & kvPair, Args... args)
+ {
+ Add(kvPair);
+ Init(args...);
+ }
+ public:
+ Dictionary()
+ {
+ bucketSizeMinusOne = -1;
+ shiftBits = 32;
+ _count = 0;
+ hashMap = 0;
+ }
+ template<typename Arg, typename... Args>
+ Dictionary(Arg arg, Args... args)
+ {
+ Init(arg, args...);
+ }
+ Dictionary(const Dictionary<TKey, TValue> & other)
+ : bucketSizeMinusOne(-1), _count(0), hashMap(0)
+ {
+ *this = other;
+ }
+ Dictionary(Dictionary<TKey, TValue> && other)
+ : bucketSizeMinusOne(-1), _count(0), hashMap(0)
+ {
+ *this = (_Move(other));
+ }
+ Dictionary<TKey, TValue> & operator = (const Dictionary<TKey, TValue> & other)
+ {
+ if (this == &other)
+ return *this;
+ Free();
+ bucketSizeMinusOne = other.bucketSizeMinusOne;
+ _count = other._count;
+ shiftBits = other.shiftBits;
+ hashMap = new KeyValuePair<TKey, TValue>[other.bucketSizeMinusOne + 1];
+ marks = other.marks;
+ for (int i = 0; i <= bucketSizeMinusOne; i++)
+ hashMap[i] = other.hashMap[i];
+ return *this;
+ }
+ Dictionary<TKey, TValue> & operator = (Dictionary<TKey, TValue> && other)
+ {
+ if (this == &other)
+ return *this;
+ Free();
+ bucketSizeMinusOne = other.bucketSizeMinusOne;
+ _count = other._count;
+ hashMap = other.hashMap;
+ shiftBits = other.shiftBits;
+ marks = _Move(other.marks);
+ other.hashMap = 0;
+ other._count = 0;
+ other.bucketSizeMinusOne = -1;
+ return *this;
+ }
+ ~Dictionary()
+ {
+ Free();
+ }
+ };
+
+ template<typename TKey, typename TValue>
+ class EnumerableDictionary
+ {
+ friend class Iterator;
+ friend class ItemProxy;
+ private:
+ inline int GetProbeOffset(int /*probeIdx*/) const
+ {
+ // quadratic probing
+ return 1;
+ }
+ private:
+ int bucketSizeMinusOne, shiftBits;
+ int _count;
+ IntSet marks;
+
+ // debug op
+ struct Op
+ {
+ TKey key;
+ int opType;
+ Op()
+ {}
+ Op(const TKey & key, int t)
+ {
+ this->key = key;
+ opType = t;
+ }
+ };
+ LinkedList<KeyValuePair<TKey, TValue>> kvPairs;
+ LinkedNode<KeyValuePair<TKey, TValue>>** hashMap;
+ void Free()
+ {
+ if (hashMap)
+ delete[] hashMap;
+ hashMap = 0;
+ kvPairs.Clear();
+ }
+ inline bool IsDeleted(int pos) const
+ {
+ return marks.Contains((pos << 1) + 1);
+ }
+ inline bool IsEmpty(int pos) const
+ {
+ return !marks.Contains((pos << 1));
+ }
+ inline void SetDeleted(int pos, bool val)
+ {
+ if (val)
+ marks.Add((pos << 1) + 1);
+ else
+ marks.Remove((pos << 1) + 1);
+ }
+ inline void SetEmpty(int pos, bool val)
+ {
+ if (val)
+ marks.Remove((pos << 1));
+ else
+ marks.Add((pos << 1));
+ }
+ struct FindPositionResult
+ {
+ int ObjectPosition;
+ int InsertionPosition;
+ FindPositionResult()
+ {
+ ObjectPosition = -1;
+ InsertionPosition = -1;
+ }
+ FindPositionResult(int objPos, int insertPos)
+ {
+ ObjectPosition = objPos;
+ InsertionPosition = insertPos;
+ }
+
+ };
+ template<typename T>
+ inline int GetHashPos(T & key) const
+ {
+ return ((unsigned int)(GetHashCode(key) * 2654435761)) >> shiftBits;
+ }
+ template<typename T>
+ FindPositionResult FindPosition(const T & key) const
+ {
+ int hashPos = GetHashPos((T&)key);
+ int insertPos = -1;
+ int numProbes = 0;
+ while (numProbes <= bucketSizeMinusOne)
+ {
+ if (IsEmpty(hashPos))
+ {
+ if (insertPos == -1)
+ return FindPositionResult(-1, hashPos);
+ else
+ return FindPositionResult(-1, insertPos);
+ }
+ else if (IsDeleted(hashPos))
+ {
+ if (insertPos == -1)
+ insertPos = hashPos;
+ }
+ else if (hashMap[hashPos]->Value.Key == key)
+ {
+ return FindPositionResult(hashPos, -1);
+ }
+ numProbes++;
+ hashPos = (hashPos + GetProbeOffset(numProbes)) & bucketSizeMinusOne;
+ }
+ if (insertPos != -1)
+ return FindPositionResult(-1, insertPos);
+ throw InvalidOperationException("Hash map is full. This indicates an error in Key::Equal or Key::GetHashCode.");
+ }
+ TValue & _Insert(KeyValuePair<TKey, TValue> && kvPair, int pos)
+ {
+ auto node = kvPairs.AddLast();
+ node->Value = _Move(kvPair);
+ hashMap[pos] = node;
+ SetEmpty(pos, false);
+ SetDeleted(pos, false);
+ return node->Value.Value;
+ }
+ void Rehash()
+ {
+ if (bucketSizeMinusOne == -1 || _count / (float)bucketSizeMinusOne >= MaxLoadFactor)
+ {
+ int newSize = (bucketSizeMinusOne + 1) * 2;
+ int newShiftBits = shiftBits - 1;
+ if (newSize == 0)
+ {
+ newSize = 16;
+ newShiftBits = 28;
+ }
+ EnumerableDictionary<TKey, TValue> newDict;
+ newDict.shiftBits = newShiftBits;
+ newDict.bucketSizeMinusOne = newSize - 1;
+ newDict.hashMap = new LinkedNode<KeyValuePair<TKey, TValue>>*[newSize];
+ newDict.marks.SetMax(newSize * 2);
+ if (hashMap)
+ {
+ for (auto & kvPair : *this)
+ {
+ newDict.Add(_Move(kvPair));
+ }
+ }
+ *this = _Move(newDict);
+ }
+ }
+
+ bool AddIfNotExists(KeyValuePair<TKey, TValue> && kvPair)
+ {
+ Rehash();
+ auto pos = FindPosition(kvPair.Key);
+ if (pos.ObjectPosition != -1)
+ return false;
+ else if (pos.InsertionPosition != -1)
+ {
+ _count++;
+ _Insert(_Move(kvPair), pos.InsertionPosition);
+ return true;
+ }
+ else
+ throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation.");
+ }
+ void Add(KeyValuePair<TKey, TValue> && kvPair)
+ {
+ if (!AddIfNotExists(_Move(kvPair)))
+ throw KeyExistsException("The key already exists in Dictionary.");
+ }
+ TValue & Set(KeyValuePair<TKey, TValue> && kvPair)
+ {
+ Rehash();
+ auto pos = FindPosition(kvPair.Key);
+ if (pos.ObjectPosition != -1)
+ {
+ hashMap[pos.ObjectPosition]->Delete();
+ return _Insert(_Move(kvPair), pos.ObjectPosition);
+ }
+ else if (pos.InsertionPosition != -1)
+ {
+ _count++;
+ return _Insert(_Move(kvPair), pos.InsertionPosition);
+ }
+ else
+ throw InvalidOperationException("Inconsistent find result returned. This is a bug in Dictionary implementation.");
+ }
+ public:
+ typedef typename LinkedList<KeyValuePair<TKey, TValue>>::Iterator Iterator;
+
+ typename LinkedList<KeyValuePair<TKey, TValue>>::Iterator begin() const
+ {
+ return kvPairs.begin();
+ }
+ typename LinkedList<KeyValuePair<TKey, TValue>>::Iterator end() const
+ {
+ return kvPairs.end();
+ }
+ public:
+ void Add(const TKey & key, const TValue & value)
+ {
+ Add(KeyValuePair<TKey, TValue>(key, value));
+ }
+ void Add(TKey && key, TValue && value)
+ {
+ Add(KeyValuePair<TKey, TValue>(_Move(key), _Move(value)));
+ }
+ bool AddIfNotExists(const TKey & key, const TValue & value)
+ {
+ return AddIfNotExists(KeyValuePair<TKey, TValue>(key, value));
+ }
+ bool AddIfNotExists(TKey && key, TValue && value)
+ {
+ return AddIfNotExists(KeyValuePair<TKey, TValue>(_Move(key), _Move(value)));
+ }
+ void Remove(const TKey & key)
+ {
+ if (_count > 0)
+ {
+ auto pos = FindPosition(key);
+ if (pos.ObjectPosition != -1)
+ {
+ kvPairs.Delete(hashMap[pos.ObjectPosition]);
+ hashMap[pos.ObjectPosition] = 0;
+ SetDeleted(pos.ObjectPosition, true);
+ _count--;
+ }
+ }
+ }
+ void Clear()
+ {
+ _count = 0;
+ kvPairs.Clear();
+ marks.Clear();
+ }
+ template<typename T>
+ bool ContainsKey(const T & key) const
+ {
+ if (bucketSizeMinusOne == -1)
+ return false;
+ auto pos = FindPosition(key);
+ return pos.ObjectPosition != -1;
+ }
+ template<typename T>
+ TValue * TryGetValue(const T & key) const
+ {
+ if (bucketSizeMinusOne == -1)
+ return nullptr;
+ auto pos = FindPosition(key);
+ if (pos.ObjectPosition != -1)
+ {
+ return &(hashMap[pos.ObjectPosition]->Value.Value);
+ }
+ return nullptr;
+ }
+ template<typename T>
+ bool TryGetValue(const T & key, TValue & value) const
+ {
+ if (bucketSizeMinusOne == -1)
+ return false;
+ auto pos = FindPosition(key);
+ if (pos.ObjectPosition != -1)
+ {
+ value = hashMap[pos.ObjectPosition]->Value.Value;
+ return true;
+ }
+ return false;
+ }
+ class ItemProxy
+ {
+ private:
+ const EnumerableDictionary<TKey, TValue> * dict;
+ TKey key;
+ public:
+ ItemProxy(const TKey & _key, const EnumerableDictionary<TKey, TValue> * _dict)
+ {
+ this->dict = _dict;
+ this->key = _key;
+ }
+ ItemProxy(TKey && _key, const EnumerableDictionary<TKey, TValue> * _dict)
+ {
+ this->dict = _dict;
+ this->key = _Move(_key);
+ }
+ TValue & GetValue() const
+ {
+ auto pos = dict->FindPosition(key);
+ if (pos.ObjectPosition != -1)
+ {
+ return dict->hashMap[pos.ObjectPosition]->Value.Value;
+ }
+ else
+ {
+ throw KeyNotFoundException("The key does not exists in dictionary.");
+ }
+ }
+ inline TValue & operator()() const
+ {
+ return GetValue();
+ }
+ operator TValue&() const
+ {
+ return GetValue();
+ }
+ TValue & operator = (const TValue & val)
+ {
+ return ((EnumerableDictionary<TKey, TValue>*)dict)->Set(KeyValuePair<TKey, TValue>(_Move(key), val));
+ }
+ TValue & operator = (TValue && val)
+ {
+ return ((EnumerableDictionary<TKey, TValue>*)dict)->Set(KeyValuePair<TKey, TValue>(_Move(key), _Move(val)));
+ }
+ };
+ ItemProxy operator [](const TKey & key) const
+ {
+ return ItemProxy(key, this);
+ }
+ ItemProxy operator [](TKey && key) const
+ {
+ return ItemProxy(_Move(key), this);
+ }
+ int Count() const
+ {
+ return _count;
+ }
+ KeyValuePair<TKey, TValue> & First() const
+ {
+ return kvPairs.First();
+ }
+ KeyValuePair<TKey, TValue> & Last() const
+ {
+ return kvPairs.Last();
+ }
+ private:
+ template<typename... Args>
+ void Init(const KeyValuePair<TKey, TValue> & kvPair, Args... args)
+ {
+ Add(kvPair);
+ Init(args...);
+ }
+ public:
+ EnumerableDictionary()
+ {
+ bucketSizeMinusOne = -1;
+ shiftBits = 32;
+ _count = 0;
+ hashMap = 0;
+ }
+ template<typename Arg, typename... Args>
+ EnumerableDictionary(Arg arg, Args... args)
+ {
+ Init(arg, args...);
+ }
+ EnumerableDictionary(const EnumerableDictionary<TKey, TValue> & other)
+ : bucketSizeMinusOne(-1), _count(0), hashMap(0)
+ {
+ *this = other;
+ }
+ EnumerableDictionary(EnumerableDictionary<TKey, TValue> && other)
+ : bucketSizeMinusOne(-1), _count(0), hashMap(0)
+ {
+ *this = (_Move(other));
+ }
+ EnumerableDictionary<TKey, TValue> & operator = (const EnumerableDictionary<TKey, TValue> & other)
+ {
+ if (this == &other)
+ return *this;
+ Clear();
+ for (auto & item : other)
+ Add(item.Key, item.Value);
+ return *this;
+ }
+ EnumerableDictionary<TKey, TValue> & operator = (EnumerableDictionary<TKey, TValue> && other)
+ {
+ if (this == &other)
+ return *this;
+ Free();
+ bucketSizeMinusOne = other.bucketSizeMinusOne;
+ _count = other._count;
+ hashMap = other.hashMap;
+ shiftBits = other.shiftBits;
+ marks = _Move(other.marks);
+ other.hashMap = 0;
+ other._count = 0;
+ other.bucketSizeMinusOne = -1;
+ kvPairs = _Move(other.kvPairs);
+ return *this;
+ }
+ ~EnumerableDictionary()
+ {
+ Free();
+ }
+ };
+
+ class _DummyClass
+ {};
+
+ template<typename T, typename DictionaryType>
+ class HashSetBase
+ {
+ protected:
+ DictionaryType dict;
+ private:
+ template<typename... Args>
+ void Init(const T & v, Args... args)
+ {
+ Add(v);
+ Init(args...);
+ }
+ public:
+ HashSetBase()
+ {}
+ template<typename Arg, typename... Args>
+ HashSetBase(Arg arg, Args... args)
+ {
+ Init(arg, args...);
+ }
+ HashSetBase(const HashSetBase & set)
+ {
+ operator=(set);
+ }
+ HashSetBase(HashSetBase && set)
+ {
+ operator=(_Move(set));
+ }
+ HashSetBase & operator = (const HashSetBase & set)
+ {
+ dict = set.dict;
+ return *this;
+ }
+ HashSetBase & operator = (HashSetBase && set)
+ {
+ dict = _Move(set.dict);
+ return *this;
+ }
+ public:
+ class Iterator
+ {
+ private:
+ typename DictionaryType::Iterator iter;
+ public:
+ Iterator() = default;
+ T & operator *() const
+ {
+ return (*iter).Key;
+ }
+ T * operator ->() const
+ {
+ return &(*iter).Key;
+ }
+ Iterator & operator ++()
+ {
+ ++iter;
+ return *this;
+ }
+ Iterator operator ++(int)
+ {
+ Iterator rs = *this;
+ operator++();
+ return rs;
+ }
+ bool operator != (const Iterator & _that) const
+ {
+ return iter != _that.iter;
+ }
+ bool operator == (const Iterator & _that) const
+ {
+ return iter == _that.iter;
+ }
+ Iterator(const typename DictionaryType::Iterator & _iter)
+ {
+ this->iter = _iter;
+ }
+ };
+ Iterator begin() const
+ {
+ return Iterator(dict.begin());
+ }
+ Iterator end() const
+ {
+ return Iterator(dict.end());
+ }
+ public:
+ int Count() const
+ {
+ return dict.Count();
+ }
+ void Clear()
+ {
+ dict.Clear();
+ }
+ bool Add(const T& obj)
+ {
+ return dict.AddIfNotExists(obj, _DummyClass());
+ }
+ bool Add(T && obj)
+ {
+ return dict.AddIfNotExists(_Move(obj), _DummyClass());
+ }
+ void Remove(const T & obj)
+ {
+ dict.Remove(obj);
+ }
+ bool Contains(const T & obj) const
+ {
+ return dict.ContainsKey(obj);
+ }
+ };
+ template <typename T>
+ class HashSet : public HashSetBase<T, Dictionary<T, _DummyClass>>
+ {};
+
+ template <typename T>
+ class EnumerableHashSet : public HashSetBase<T, EnumerableDictionary<T, _DummyClass>>
+ {
+ public:
+ T & First() const
+ {
+ return this->dict.First().Key;
+ }
+ T & Last() const
+ {
+ return this->dict.Last().Key;
+ }
+ };
+ }
+}
+
+#endif