#pragma once #if _DEBUG //#include #define assert(a) if (!(a)) { throw #a; } #endif template struct equality { static bool Equals(T a, T b) { return a == b; } }; template struct hashing { static int Generate(T a) { return (int)a; } }; // Finetune this value for better performance. #define MAXBUCKETSIZE 10 template class Map { public: struct Pair { int Hash; TKey Key; TValue Value; }; private: class HashBucket { public: HashBucket(const List pairs) : left{ nullptr } , right{ nullptr } , pairs { pairs } { if (pairs.Count() > 0) centerHash = pairs[0]->Hash; } HashBucket() : left{ nullptr } , right{ nullptr } { } ~HashBucket() { delete left; delete right; } HashBucket* GetValue(const TKey& key, int hash, bool& success, TValue*& result) const { if ((hash == centerHash || left == nullptr) && pairs.Count() != 0) { for (const auto& pair : pairs) if (equality::Equals(pair->Key, key)) { success = true; result = &pair->Value; return nullptr; } return nullptr; } else if (left != nullptr) return hash < centerHash ? left : right; else return nullptr; } HashBucket* Remove(const TKey key, int hash, Pair*& pairResult) { if (left == nullptr || hash == centerHash) { for (int i = 0, iLength = pairs.Count(); i < iLength; ++i) { auto pair = pairs[i]; if (equality::Equals(pair->Key, key)) { pairs.RemoveAt(i); pairResult = pair; return nullptr; } } return nullptr; } else if (left != nullptr) return hash < centerHash ? left : right; else return nullptr; } HashBucket* Add(Pair* pair) { if (pairs.Count() == 0) centerHash = pair->Hash; if (centerHash == pair->Hash || (left == nullptr && pairs.Count() < MAXBUCKETSIZE)) { #ifdef _DEBUG for (const auto& oldPair : pairs) if (equality::Equals(oldPair->Key, pair->Key)) assert("Key already exists in map" && false); #endif pairs.Add(pair); } else if (left == nullptr) { centerHash = pairs[pairs.Count() / 2]->Hash; List leftPairs; List centerPairs; List rightPairs; for (const auto& oldPair : pairs) { if (oldPair->Hash < centerHash) leftPairs.Add(oldPair); if (oldPair->Hash > centerHash) rightPairs.Add(oldPair); else centerPairs.Add(oldPair); } left = new HashBucket(leftPairs); right = new HashBucket(rightPairs); pairs = centerPairs; return Add(pair); } else return pair->Hash < centerHash ? left : right; return nullptr; } private: int centerHash; HashBucket* left; HashBucket* right; List pairs; }; public: Map() : rootBucket{ new HashBucket() } { } Map(Map&& other) : pairs{ other.pairs } , rootBucket{ other.rootBucket } { other.rootBucket = nullptr; other.pairs.Clear(); } Map(const Map& other) { throw "Implement me bitch!"; } ~Map() { for (int i = 0, iLength = pairs.Count(); i < iLength; ++i) delete pairs[i]; delete rootBucket; } Map& operator=(Map&& other) { if (this != &other) { delete rootBucket; pairs = other.pairs; rootBucket = other.rootBucket; other.rootBucket = nullptr; other.pairs.Clear(); } return *this; } void Add(const TKey& key, const TValue& value) { auto pair = new Pair(); pair->Key = key; pair->Value = value; pair->Hash = hashing::Generate(key); auto bucket = rootBucket; do { bucket = bucket->Add(pair); } while (bucket != nullptr); pairs.Add(pair); } bool TryGetValue(const TKey& key, TValue& value) const { bool success = false; auto hash = hashing::Generate(key); TValue* result; auto bucket = rootBucket; do { bucket = bucket->GetValue(key, hash, success, result); } while (bucket != nullptr); if (success) value = *result; return success; } bool TryGetValue(const TKey& key, TValue*& value) const { bool success = false; auto hash = hashing::Generate(key); TValue* result; auto bucket = rootBucket; do { bucket = bucket->GetValue(key, hash, success, result); } while (bucket != nullptr); if (success) value = result; return success; } void Remove(const TKey& key) { auto hash = hashing::Generate(key); auto bucket = rootBucket; Pair* pair; do { bucket = bucket->Remove(key, hash, pair); } while (bucket != nullptr); if (pair != nullptr) { pairs.Remove(pair); } } TValue& GetValue(const TKey& key) const { TValue* result; bool success = false; auto hash = hashing::Generate(key); auto bucket = rootBucket; do { bucket = bucket->GetValue(key, hash, success, result); } while (bucket != nullptr); #if _DEBUG assert("No value found!" && success); #endif return *result; } Pair** begin() const { return pairs.begin(); } Pair** end() const { return pairs.end(); } int Count() const { return pairs.Count(); } bool ContainsKey(const TKey& key) const { TValue tmp; return TryGetValue(key, tmp); } TValue& operator[](const TKey& key) { return GetValue(key); } const TValue& operator[](const TKey& key) const { return GetValue(key); } List GetValues() const { List result; for (const auto& pair : pairs) result.Add(pair->Value); return result; } private: HashBucket* rootBucket; List pairs; };