port from perforce

This commit is contained in:
2026-04-18 22:31:51 +02:00
commit 8d0ab5b7cc
8409 changed files with 3972376 additions and 0 deletions

View 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;
};