port from perforce
This commit is contained in:
317
meshToolsV5/src/Lib/mt/common/Map.h
Normal file
317
meshToolsV5/src/Lib/mt/common/Map.h
Normal file
@@ -0,0 +1,317 @@
|
||||
#pragma once
|
||||
#if _DEBUG
|
||||
//#include <assert.h>
|
||||
#define assert(a) if (!(a)) { throw #a; }
|
||||
#endif
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct equality { static bool Equals(T a, T b) { return a == b; } };
|
||||
|
||||
template<typename T>
|
||||
struct hashing
|
||||
{
|
||||
static int Generate(T a)
|
||||
{
|
||||
return (int)a;
|
||||
}
|
||||
};
|
||||
|
||||
// Finetune this value for better performance.
|
||||
#define MAXBUCKETSIZE 10
|
||||
|
||||
template<typename TKey, typename TValue>
|
||||
class Map
|
||||
{
|
||||
public:
|
||||
struct Pair
|
||||
{
|
||||
int Hash;
|
||||
TKey Key;
|
||||
TValue Value;
|
||||
};
|
||||
|
||||
private:
|
||||
class HashBucket
|
||||
{
|
||||
public:
|
||||
HashBucket(const List<Pair*> 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<const TKey&>::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<const TKey&>::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<const TKey&>::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<Pair*> leftPairs;
|
||||
List<Pair*> centerPairs;
|
||||
List<Pair*> 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<Pair*> 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<const TKey&>::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<const TKey&>::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<const TKey&>::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<const TKey&>::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<const TKey&>::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<TValue> GetValues() const
|
||||
{
|
||||
List<TValue> result;
|
||||
for (const auto& pair : pairs)
|
||||
result.Add(pair->Value);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
HashBucket* rootBucket;
|
||||
List<Pair*> pairs;
|
||||
};
|
||||
Reference in New Issue
Block a user