mirror of
https://github.com/0TheSpy/Seaside.git
synced 2025-01-11 03:32:10 +08:00
732 lines
19 KiB
C++
732 lines
19 KiB
C++
#ifndef UTLHASH_H
|
|
#define UTLHASH_H
|
|
#pragma once
|
|
|
|
#include <assert.h>
|
|
#include <limits.h>
|
|
#include "utlmemory.h"
|
|
#include "utlvector.h"
|
|
#include "utllinkedlist.h"
|
|
#include "commonmacros.h"
|
|
#include "generichash.h"
|
|
|
|
typedef unsigned int UtlHashHandle_t;
|
|
|
|
template<class Data, typename C = bool (*)(Data const&, Data const&), typename K = unsigned int (*)(Data const&) >
|
|
class CUtlHash
|
|
{
|
|
public:
|
|
typedef C CompareFunc_t;
|
|
typedef K KeyFunc_t;
|
|
|
|
CUtlHash(int bucketCount = 0, int growCount = 0, int initCount = 0,
|
|
CompareFunc_t compareFunc = 0, KeyFunc_t keyFunc = 0);
|
|
~CUtlHash();
|
|
|
|
static UtlHashHandle_t InvalidHandle(void) { return (UtlHashHandle_t)~0; }
|
|
bool IsValidHandle(UtlHashHandle_t handle) const;
|
|
|
|
int Count(void) const;
|
|
|
|
void Purge(void);
|
|
|
|
UtlHashHandle_t Insert(Data const& src);
|
|
UtlHashHandle_t Insert(Data const& src, bool* pDidInsert);
|
|
UtlHashHandle_t AllocEntryFromKey(Data const& src);
|
|
|
|
void Remove(UtlHashHandle_t handle);
|
|
void RemoveAll();
|
|
|
|
UtlHashHandle_t Find(Data const& src) const;
|
|
|
|
Data& Element(UtlHashHandle_t handle);
|
|
Data const& Element(UtlHashHandle_t handle) const;
|
|
Data& operator[](UtlHashHandle_t handle);
|
|
Data const& operator[](UtlHashHandle_t handle) const;
|
|
|
|
UtlHashHandle_t GetFirstHandle() const;
|
|
UtlHashHandle_t GetNextHandle(UtlHashHandle_t h) const;
|
|
|
|
void Log(const char* filename);
|
|
|
|
protected:
|
|
|
|
int GetBucketIndex(UtlHashHandle_t handle) const;
|
|
int GetKeyDataIndex(UtlHashHandle_t handle) const;
|
|
UtlHashHandle_t BuildHandle(int ndxBucket, int ndxKeyData) const;
|
|
|
|
bool DoFind(Data const& src, unsigned int* pBucket, int* pIndex) const;
|
|
|
|
protected:
|
|
|
|
typedef CUtlVector<Data> HashBucketList_t;
|
|
CUtlVector<HashBucketList_t> m_Buckets;
|
|
|
|
CompareFunc_t m_CompareFunc;
|
|
KeyFunc_t m_KeyFunc;
|
|
|
|
bool m_bPowerOfTwo;
|
|
unsigned int m_ModMask;
|
|
};
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
CUtlHash<Data, C, K>::CUtlHash(int bucketCount, int growCount, int initCount,
|
|
CompareFunc_t compareFunc, KeyFunc_t keyFunc) :
|
|
m_CompareFunc(compareFunc),
|
|
m_KeyFunc(keyFunc)
|
|
{
|
|
m_Buckets.SetSize(bucketCount);
|
|
for (int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++)
|
|
{
|
|
m_Buckets[ndxBucket].SetSize(initCount);
|
|
m_Buckets[ndxBucket].SetGrowSize(growCount);
|
|
}
|
|
|
|
m_bPowerOfTwo = IsPowerOfTwo(bucketCount);
|
|
m_ModMask = m_bPowerOfTwo ? (bucketCount - 1) : 0;
|
|
}
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
CUtlHash<Data, C, K>::~CUtlHash()
|
|
{
|
|
Purge();
|
|
}
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline bool CUtlHash<Data, C, K>::IsValidHandle(UtlHashHandle_t handle) const
|
|
{
|
|
int ndxBucket = GetBucketIndex(handle);
|
|
int ndxKeyData = GetKeyDataIndex(handle);
|
|
|
|
if ( (ndxBucket < m_Buckets.Count()))
|
|
{
|
|
if ( (ndxKeyData < m_Buckets[ndxBucket].Count()))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline int CUtlHash<Data, C, K>::Count(void) const
|
|
{
|
|
int count = 0;
|
|
|
|
int bucketCount = m_Buckets.Count();
|
|
for (int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++)
|
|
{
|
|
count += m_Buckets[ndxBucket].Count();
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline int CUtlHash<Data, C, K>::GetBucketIndex(UtlHashHandle_t handle) const
|
|
{
|
|
return (((handle >> 16) & 0x0000ffff));
|
|
}
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline int CUtlHash<Data, C, K>::GetKeyDataIndex(UtlHashHandle_t handle) const
|
|
{
|
|
return (handle & 0x0000ffff);
|
|
}
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline UtlHashHandle_t CUtlHash<Data, C, K>::BuildHandle(int ndxBucket, int ndxKeyData) const
|
|
{
|
|
assert((ndxBucket >= 0) && (ndxBucket < 65536));
|
|
assert((ndxKeyData >= 0) && (ndxKeyData < 65536));
|
|
|
|
UtlHashHandle_t handle = ndxKeyData;
|
|
handle |= (ndxBucket << 16);
|
|
|
|
return handle;
|
|
}
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline void CUtlHash<Data, C, K>::Purge(void)
|
|
{
|
|
int bucketCount = m_Buckets.Count();
|
|
for (int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++)
|
|
{
|
|
m_Buckets[ndxBucket].Purge();
|
|
}
|
|
}
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline bool CUtlHash<Data, C, K>::DoFind(Data const& src, unsigned int* pBucket, int* pIndex) const
|
|
{
|
|
unsigned int key = m_KeyFunc(src);
|
|
|
|
unsigned int ndxBucket;
|
|
if (m_bPowerOfTwo)
|
|
{
|
|
*pBucket = ndxBucket = (key & m_ModMask);
|
|
}
|
|
else
|
|
{
|
|
int bucketCount = m_Buckets.Count();
|
|
*pBucket = ndxBucket = key % bucketCount;
|
|
}
|
|
|
|
int ndxKeyData;
|
|
const CUtlVector<Data>& bucket = m_Buckets[ndxBucket];
|
|
int keyDataCount = bucket.Count();
|
|
for (ndxKeyData = 0; ndxKeyData < keyDataCount; ndxKeyData++)
|
|
{
|
|
if (m_CompareFunc(bucket.Element(ndxKeyData), src))
|
|
break;
|
|
}
|
|
|
|
if (ndxKeyData == keyDataCount)
|
|
return false;
|
|
|
|
*pIndex = ndxKeyData;
|
|
return true;
|
|
}
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline UtlHashHandle_t CUtlHash<Data, C, K>::Find(Data const& src) const
|
|
{
|
|
unsigned int ndxBucket;
|
|
int ndxKeyData;
|
|
|
|
if (DoFind(src, &ndxBucket, &ndxKeyData))
|
|
{
|
|
return (BuildHandle(ndxBucket, ndxKeyData));
|
|
}
|
|
return (InvalidHandle());
|
|
}
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline UtlHashHandle_t CUtlHash<Data, C, K>::Insert(Data const& src)
|
|
{
|
|
unsigned int ndxBucket;
|
|
int ndxKeyData;
|
|
|
|
if (DoFind(src, &ndxBucket, &ndxKeyData))
|
|
{
|
|
return (BuildHandle(ndxBucket, ndxKeyData));
|
|
}
|
|
|
|
ndxKeyData = m_Buckets[ndxBucket].AddToTail(src);
|
|
|
|
return (BuildHandle(ndxBucket, ndxKeyData));
|
|
}
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline UtlHashHandle_t CUtlHash<Data, C, K>::Insert(Data const& src, bool* pDidInsert)
|
|
{
|
|
unsigned int ndxBucket;
|
|
int ndxKeyData;
|
|
|
|
if (DoFind(src, &ndxBucket, &ndxKeyData))
|
|
{
|
|
*pDidInsert = false;
|
|
return (BuildHandle(ndxBucket, ndxKeyData));
|
|
}
|
|
|
|
*pDidInsert = true;
|
|
ndxKeyData = m_Buckets[ndxBucket].AddToTail(src);
|
|
|
|
return (BuildHandle(ndxBucket, ndxKeyData));
|
|
}
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline UtlHashHandle_t CUtlHash<Data, C, K>::AllocEntryFromKey(Data const& src)
|
|
{
|
|
unsigned int ndxBucket;
|
|
int ndxKeyData;
|
|
|
|
if (DoFind(src, &ndxBucket, &ndxKeyData))
|
|
{
|
|
return (BuildHandle(ndxBucket, ndxKeyData));
|
|
}
|
|
|
|
ndxKeyData = m_Buckets[ndxBucket].AddToTail();
|
|
|
|
return (BuildHandle(ndxBucket, ndxKeyData));
|
|
}
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline void CUtlHash<Data, C, K>::Remove(UtlHashHandle_t handle)
|
|
{
|
|
assert(IsValidHandle(handle));
|
|
|
|
int ndxBucket = GetBucketIndex(handle);
|
|
int ndxKeyData = GetKeyDataIndex(handle);
|
|
|
|
if (m_Buckets[ndxBucket].IsValidIndex(ndxKeyData))
|
|
{
|
|
m_Buckets[ndxBucket].FastRemove(ndxKeyData);
|
|
}
|
|
}
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline void CUtlHash<Data, C, K>::RemoveAll()
|
|
{
|
|
int bucketCount = m_Buckets.Count();
|
|
for (int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++)
|
|
{
|
|
m_Buckets[ndxBucket].RemoveAll();
|
|
}
|
|
}
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline Data& CUtlHash<Data, C, K>::Element(UtlHashHandle_t handle)
|
|
{
|
|
int ndxBucket = GetBucketIndex(handle);
|
|
int ndxKeyData = GetKeyDataIndex(handle);
|
|
|
|
return (m_Buckets[ndxBucket].Element(ndxKeyData));
|
|
}
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline Data const& CUtlHash<Data, C, K>::Element(UtlHashHandle_t handle) const
|
|
{
|
|
int ndxBucket = GetBucketIndex(handle);
|
|
int ndxKeyData = GetKeyDataIndex(handle);
|
|
|
|
return (m_Buckets[ndxBucket].Element(ndxKeyData));
|
|
}
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline Data& CUtlHash<Data, C, K>::operator[](UtlHashHandle_t handle)
|
|
{
|
|
int ndxBucket = GetBucketIndex(handle);
|
|
int ndxKeyData = GetKeyDataIndex(handle);
|
|
|
|
return (m_Buckets[ndxBucket].Element(ndxKeyData));
|
|
}
|
|
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline Data const& CUtlHash<Data, C, K>::operator[](UtlHashHandle_t handle) const
|
|
{
|
|
int ndxBucket = GetBucketIndex(handle);
|
|
int ndxKeyData = GetKeyDataIndex(handle);
|
|
|
|
return (m_Buckets[ndxBucket].Element(ndxKeyData));
|
|
}
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline UtlHashHandle_t CUtlHash<Data, C, K>::GetFirstHandle() const
|
|
{
|
|
return GetNextHandle((UtlHashHandle_t)-1);
|
|
}
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline UtlHashHandle_t CUtlHash<Data, C, K>::GetNextHandle(UtlHashHandle_t handle) const
|
|
{
|
|
++handle;
|
|
|
|
int bi = GetBucketIndex(handle);
|
|
int ki = GetKeyDataIndex(handle);
|
|
|
|
int nBuckets = m_Buckets.Count();
|
|
for (; bi < nBuckets; ++bi)
|
|
{
|
|
if (ki < m_Buckets[bi].Count())
|
|
return BuildHandle(bi, ki);
|
|
|
|
ki = 0;
|
|
}
|
|
|
|
return InvalidHandle();
|
|
}
|
|
|
|
template<class Data, typename C, typename K>
|
|
inline void CUtlHash<Data, C, K>::Log(const char* filename)
|
|
{
|
|
FILE* pDebugFp;
|
|
pDebugFp = fopen(filename, "w");
|
|
if (!pDebugFp)
|
|
return;
|
|
|
|
int maxBucketSize = 0;
|
|
int numBucketsEmpty = 0;
|
|
|
|
int bucketCount = m_Buckets.Count();
|
|
fprintf(pDebugFp, "\n%d Buckets\n", bucketCount);
|
|
|
|
for (int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++)
|
|
{
|
|
int count = m_Buckets[ndxBucket].Count();
|
|
|
|
if (count > maxBucketSize) { maxBucketSize = count; }
|
|
if (count == 0)
|
|
numBucketsEmpty++;
|
|
|
|
fprintf(pDebugFp, "Bucket %d: %d\n", ndxBucket, count);
|
|
}
|
|
|
|
fprintf(pDebugFp, "\nBucketHeads Used: %d\n", bucketCount - numBucketsEmpty);
|
|
fprintf(pDebugFp, "Max Bucket Size: %d\n", maxBucketSize);
|
|
|
|
fclose(pDebugFp);
|
|
}
|
|
|
|
typedef int UtlHashFastHandle_t;
|
|
|
|
#define UTLHASH_POOL_SCALAR 2
|
|
|
|
class CUtlHashFastNoHash
|
|
{
|
|
public:
|
|
static int Hash(int key, int bucketMask)
|
|
{
|
|
return (key & bucketMask);
|
|
}
|
|
};
|
|
|
|
class CUtlHashFastGenericHash
|
|
{
|
|
public:
|
|
static int Hash(int key, int bucketMask)
|
|
{
|
|
return (HashIntConventional(key) & bucketMask);
|
|
}
|
|
};
|
|
|
|
template<class Data, class HashFuncs = CUtlHashFastNoHash >
|
|
class CUtlHashFast
|
|
{
|
|
public:
|
|
|
|
CUtlHashFast();
|
|
~CUtlHashFast();
|
|
|
|
void Purge(void);
|
|
|
|
static UtlHashFastHandle_t InvalidHandle(void) { return (UtlHashFastHandle_t)~0; }
|
|
|
|
bool Init(int nBucketCount);
|
|
|
|
int Count(void);
|
|
|
|
UtlHashFastHandle_t Insert(unsigned int uiKey, const Data& data);
|
|
UtlHashFastHandle_t FastInsert(unsigned int uiKey, const Data& data);
|
|
|
|
void Remove(UtlHashFastHandle_t hHash);
|
|
void RemoveAll(void);
|
|
|
|
UtlHashFastHandle_t Find(unsigned int uiKey);
|
|
|
|
Data& Element(UtlHashFastHandle_t hHash);
|
|
Data const& Element(UtlHashFastHandle_t hHash) const;
|
|
Data& operator[](UtlHashFastHandle_t hHash);
|
|
Data const& operator[](UtlHashFastHandle_t hHash) const;
|
|
|
|
template <typename HashData>
|
|
struct HashFastData_t_
|
|
{
|
|
unsigned int m_uiKey;
|
|
HashData m_Data;
|
|
};
|
|
|
|
typedef HashFastData_t_<Data> HashFastData_t;
|
|
|
|
unsigned int m_uiBucketMask;
|
|
CUtlVector<UtlHashFastHandle_t> m_aBuckets;
|
|
CUtlFixedLinkedList<HashFastData_t> m_aDataPool;
|
|
};
|
|
|
|
template<class Data, class HashFuncs> CUtlHashFast<Data, HashFuncs>::CUtlHashFast()
|
|
{
|
|
Purge();
|
|
}
|
|
|
|
template<class Data, class HashFuncs> CUtlHashFast<Data, HashFuncs>::~CUtlHashFast()
|
|
{
|
|
Purge();
|
|
}
|
|
|
|
template<class Data, class HashFuncs> inline void CUtlHashFast<Data, HashFuncs>::Purge(void)
|
|
{
|
|
m_aBuckets.Purge();
|
|
m_aDataPool.Purge();
|
|
}
|
|
|
|
template<class Data, class HashFuncs> bool CUtlHashFast<Data, HashFuncs>::Init(int nBucketCount)
|
|
{
|
|
if (!IsPowerOfTwo(nBucketCount))
|
|
return false;
|
|
|
|
m_aBuckets.SetSize(nBucketCount);
|
|
for (int iBucket = 0; iBucket < nBucketCount; ++iBucket)
|
|
{
|
|
m_aBuckets[iBucket] = m_aDataPool.InvalidIndex();
|
|
}
|
|
|
|
m_uiBucketMask = nBucketCount - 1;
|
|
|
|
int nGrowSize = UTLHASH_POOL_SCALAR * nBucketCount;
|
|
m_aDataPool.SetGrowSize(nGrowSize);
|
|
|
|
return true;
|
|
}
|
|
|
|
template<class Data, class HashFuncs> inline int CUtlHashFast<Data, HashFuncs>::Count(void)
|
|
{
|
|
return m_aDataPool.Count();
|
|
}
|
|
|
|
template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data, HashFuncs>::Insert(unsigned int uiKey, const Data& data)
|
|
{
|
|
UtlHashFastHandle_t hHash = Find(uiKey);
|
|
if (hHash != InvalidHandle())
|
|
return hHash;
|
|
|
|
return FastInsert(uiKey, data);
|
|
}
|
|
|
|
template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data, HashFuncs>::FastInsert(unsigned int uiKey, const Data& data)
|
|
{
|
|
int iHashData = m_aDataPool.Alloc(true);
|
|
HashFastData_t* pHashData = &m_aDataPool[iHashData];
|
|
if (!pHashData)
|
|
return InvalidHandle();
|
|
|
|
pHashData->m_uiKey = uiKey;
|
|
pHashData->m_Data = data;
|
|
|
|
int iBucket = HashFuncs::Hash(uiKey, m_uiBucketMask);
|
|
m_aDataPool.LinkBefore(m_aBuckets[iBucket], iHashData);
|
|
m_aBuckets[iBucket] = iHashData;
|
|
|
|
return iHashData;
|
|
}
|
|
|
|
template<class Data, class HashFuncs> inline void CUtlHashFast<Data, HashFuncs>::Remove(UtlHashFastHandle_t hHash)
|
|
{
|
|
int iBucket = HashFuncs::Hash(m_aDataPool[hHash].m_uiKey, m_uiBucketMask);
|
|
if (m_aBuckets[iBucket] == hHash)
|
|
{
|
|
m_aBuckets[iBucket] = m_aDataPool.Next(hHash);
|
|
}
|
|
else
|
|
{
|
|
m_aDataPool.Unlink(hHash);
|
|
}
|
|
|
|
m_aDataPool.Remove(hHash);
|
|
}
|
|
|
|
template<class Data, class HashFuncs> inline void CUtlHashFast<Data, HashFuncs>::RemoveAll(void)
|
|
{
|
|
m_aBuckets.RemoveAll();
|
|
m_aDataPool.RemoveAll();
|
|
}
|
|
|
|
template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data, HashFuncs>::Find(unsigned int uiKey)
|
|
{
|
|
int iBucket = HashFuncs::Hash(uiKey, m_uiBucketMask);
|
|
|
|
for (int iElement = m_aBuckets[iBucket]; iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next(iElement))
|
|
{
|
|
if (m_aDataPool[iElement].m_uiKey == uiKey)
|
|
return iElement;
|
|
}
|
|
|
|
return InvalidHandle();
|
|
}
|
|
|
|
template<class Data, class HashFuncs> inline Data& CUtlHashFast<Data, HashFuncs>::Element(UtlHashFastHandle_t hHash)
|
|
{
|
|
return (m_aDataPool[hHash].m_Data);
|
|
}
|
|
|
|
template<class Data, class HashFuncs> inline Data const& CUtlHashFast<Data, HashFuncs>::Element(UtlHashFastHandle_t hHash) const
|
|
{
|
|
return (m_aDataPool[hHash].m_Data);
|
|
}
|
|
|
|
template<class Data, class HashFuncs> inline Data& CUtlHashFast<Data, HashFuncs>::operator[](UtlHashFastHandle_t hHash)
|
|
{
|
|
return (m_aDataPool[hHash].m_Data);
|
|
}
|
|
|
|
template<class Data, class HashFuncs> inline Data const& CUtlHashFast<Data, HashFuncs>::operator[](UtlHashFastHandle_t hHash) const
|
|
{
|
|
return (m_aDataPool[hHash].m_Data);
|
|
}
|
|
|
|
typedef int UtlHashFixedHandle_t;
|
|
|
|
template <int NUM_BUCKETS>
|
|
class CUtlHashFixedGenericHash
|
|
{
|
|
public:
|
|
static int Hash(int key, int bucketMask)
|
|
{
|
|
int hash = HashIntConventional(key);
|
|
if (NUM_BUCKETS <= USHRT_MAX)
|
|
{
|
|
hash ^= (hash >> 16);
|
|
}
|
|
if (NUM_BUCKETS <= UCHAR_MAX)
|
|
{
|
|
hash ^= (hash >> 8);
|
|
}
|
|
return (hash & bucketMask);
|
|
}
|
|
};
|
|
|
|
template<class Data, int NUM_BUCKETS, class CHashFuncs = CUtlHashFastNoHash >
|
|
class CUtlHashFixed
|
|
{
|
|
public:
|
|
|
|
CUtlHashFixed();
|
|
~CUtlHashFixed();
|
|
|
|
void Purge(void);
|
|
|
|
static UtlHashFixedHandle_t InvalidHandle(void) { return (UtlHashFixedHandle_t)~0; }
|
|
|
|
int Count(void);
|
|
|
|
UtlHashFixedHandle_t Insert(unsigned int uiKey, const Data& data);
|
|
UtlHashFixedHandle_t FastInsert(unsigned int uiKey, const Data& data);
|
|
|
|
void Remove(UtlHashFixedHandle_t hHash);
|
|
void RemoveAll(void);
|
|
|
|
UtlHashFixedHandle_t Find(unsigned int uiKey);
|
|
|
|
Data& Element(UtlHashFixedHandle_t hHash);
|
|
Data const& Element(UtlHashFixedHandle_t hHash) const;
|
|
Data& operator[](UtlHashFixedHandle_t hHash);
|
|
Data const& operator[](UtlHashFixedHandle_t hHash) const;
|
|
|
|
template <typename Data_t>
|
|
struct HashFixedData_t_
|
|
{
|
|
unsigned int m_uiKey;
|
|
Data_t m_Data;
|
|
};
|
|
|
|
typedef HashFixedData_t_<Data> HashFixedData_t;
|
|
|
|
enum
|
|
{
|
|
BUCKET_MASK = NUM_BUCKETS - 1
|
|
};
|
|
CUtlPtrLinkedList<HashFixedData_t> m_aBuckets[NUM_BUCKETS];
|
|
int m_nElements;
|
|
};
|
|
|
|
template<class Data, int NUM_BUCKETS, class HashFuncs> CUtlHashFixed<Data, NUM_BUCKETS, HashFuncs>::CUtlHashFixed()
|
|
{
|
|
Purge();
|
|
}
|
|
|
|
template<class Data, int NUM_BUCKETS, class HashFuncs> CUtlHashFixed<Data, NUM_BUCKETS, HashFuncs>::~CUtlHashFixed()
|
|
{
|
|
Purge();
|
|
}
|
|
|
|
template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data, NUM_BUCKETS, HashFuncs>::Purge(void)
|
|
{
|
|
RemoveAll();
|
|
}
|
|
|
|
template<class Data, int NUM_BUCKETS, class HashFuncs> inline int CUtlHashFixed<Data, NUM_BUCKETS, HashFuncs>::Count(void)
|
|
{
|
|
return m_nElements;
|
|
}
|
|
|
|
template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data, NUM_BUCKETS, HashFuncs>::Insert(unsigned int uiKey, const Data& data)
|
|
{
|
|
UtlHashFixedHandle_t hHash = Find(uiKey);
|
|
if (hHash != InvalidHandle())
|
|
return hHash;
|
|
|
|
return FastInsert(uiKey, data);
|
|
}
|
|
|
|
template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data, NUM_BUCKETS, HashFuncs>::FastInsert(unsigned int uiKey, const Data& data)
|
|
{
|
|
int iBucket = HashFuncs::Hash(uiKey, NUM_BUCKETS - 1);
|
|
UtlPtrLinkedListIndex_t iElem = m_aBuckets[iBucket].AddToHead();
|
|
|
|
HashFixedData_t* pHashData = &m_aBuckets[iBucket][iElem];
|
|
|
|
Assert((UtlPtrLinkedListIndex_t)pHashData == iElem);
|
|
|
|
pHashData->m_uiKey = uiKey;
|
|
pHashData->m_Data = data;
|
|
|
|
m_nElements++;
|
|
return (UtlHashFixedHandle_t)pHashData;
|
|
}
|
|
|
|
template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data, NUM_BUCKETS, HashFuncs>::Remove(UtlHashFixedHandle_t hHash)
|
|
{
|
|
HashFixedData_t* pHashData = (HashFixedData_t*)hHash;
|
|
Assert(Find(pHashData->m_uiKey) != InvalidHandle());
|
|
int iBucket = HashFuncs::Hash(pHashData->m_uiKey, NUM_BUCKETS - 1);
|
|
m_aBuckets[iBucket].Remove((UtlPtrLinkedListIndex_t)pHashData);
|
|
m_nElements--;
|
|
}
|
|
|
|
template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data, NUM_BUCKETS, HashFuncs>::RemoveAll(void)
|
|
{
|
|
for (int i = 0; i < NUM_BUCKETS; i++)
|
|
{
|
|
m_aBuckets[i].RemoveAll();
|
|
}
|
|
m_nElements = 0;
|
|
}
|
|
|
|
template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data, NUM_BUCKETS, HashFuncs>::Find(unsigned int uiKey)
|
|
{
|
|
int iBucket = HashFuncs::Hash(uiKey, NUM_BUCKETS - 1);
|
|
CUtlPtrLinkedList<HashFixedData_t>& bucket = m_aBuckets[iBucket];
|
|
|
|
for (UtlPtrLinkedListIndex_t iElement = bucket.Head(); iElement != bucket.InvalidIndex(); iElement = bucket.Next(iElement))
|
|
{
|
|
if (bucket[iElement].m_uiKey == uiKey)
|
|
return (UtlHashFixedHandle_t)iElement;
|
|
}
|
|
|
|
return InvalidHandle();
|
|
}
|
|
|
|
template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data& CUtlHashFixed<Data, NUM_BUCKETS, HashFuncs>::Element(UtlHashFixedHandle_t hHash)
|
|
{
|
|
return ((HashFixedData_t*)hHash)->m_Data;
|
|
}
|
|
|
|
template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data const& CUtlHashFixed<Data, NUM_BUCKETS, HashFuncs>::Element(UtlHashFixedHandle_t hHash) const
|
|
{
|
|
return ((HashFixedData_t*)hHash)->m_Data;
|
|
}
|
|
|
|
template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data& CUtlHashFixed<Data, NUM_BUCKETS, HashFuncs>::operator[](UtlHashFixedHandle_t hHash)
|
|
{
|
|
return ((HashFixedData_t*)hHash)->m_Data;
|
|
}
|
|
|
|
template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data const& CUtlHashFixed<Data, NUM_BUCKETS, HashFuncs>::operator[](UtlHashFixedHandle_t hHash) const
|
|
{
|
|
return ((HashFixedData_t*)hHash)->m_Data;
|
|
}
|
|
|
|
#endif |