332 lines
8.0 KiB
C++
332 lines
8.0 KiB
C++
#ifndef _STR_HASH_TABLE_H_
|
||
#define _STR_HASH_TABLE_H_
|
||
/************************************************************************
|
||
* <20><>ϣ<EFBFBD><CFA3>
|
||
*
|
||
* <20><>ϣ<EFBFBD>㷨<EFBFBD><E3B7A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD>ѩ<EFBFBD><D1A9>ϣ<EFBFBD>㷨<EFBFBD><E3B7A8>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD>3<EFBFBD><33><EFBFBD><EFBFBD>ϣֵ<CFA3><D6B5><EFBFBD><EFBFBD><EFBFBD>жϣ<D0B6>һ<EFBFBD><D2BB><EFBFBD>̶<EFBFBD><CCB6>Ͽ<EFBFBD><CFBF>Լ<EFBFBD>
|
||
* <20><>ķ<EFBFBD>ֹ<EFBFBD><D6B9><EFBFBD>ֳ<EFBFBD>ͻ<EFBFBD><CDBB>
|
||
*
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>hash<73><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ã<EFBFBD><C3A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7>
|
||
* ʼ<><CABC><EFBFBD>ҿ<EFBFBD>λ<EFBFBD><CEBB>ֱ֪<D6AA><D6B1><EFBFBD>ҵ<EFBFBD><D2B5><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>α<EFBFBD><CEB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
*
|
||
* <20>ӱ<EFBFBD><D3B1>в<EFBFBD><D0B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD>hashֵ<68><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD><32><EFBFBD><EFBFBD>ϣֵ<CFA3><D6B5>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7>ʼ<EFBFBD><CABC><EFBFBD>ҿ<EFBFBD>λ<EFBFBD><CEBB>ֱ֪<D6AA><D6B1><EFBFBD>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>α<EFBFBD><CEB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
*
|
||
*
|
||
************************************************************************/
|
||
|
||
#include "bzhash.h"
|
||
|
||
template <typename T>
|
||
class StrHashTable;
|
||
|
||
template <typename T>
|
||
class StrHashTableIterator
|
||
{
|
||
public:
|
||
StrHashTableIterator()
|
||
{
|
||
m_pTable = NULL;
|
||
m_nIndex = 0;
|
||
}
|
||
StrHashTableIterator(const StrHashTable<T>& table)
|
||
{
|
||
setTable(table);
|
||
}
|
||
inline void setTable(const StrHashTable<T>& table)
|
||
{
|
||
m_pTable = &table;
|
||
m_nIndex = 0;
|
||
}
|
||
inline T* first()
|
||
{
|
||
int nLen = (int)(m_pTable->m_nLen);
|
||
|
||
m_nIndex = 0;
|
||
|
||
while (m_nIndex < nLen)
|
||
{
|
||
typename StrHashTable<T>::NodeType* pNode =
|
||
&m_pTable->m_pTable[m_nIndex];
|
||
|
||
m_nIndex++;
|
||
|
||
if (pNode->hash1)
|
||
return &pNode->value;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
inline T* next()
|
||
{
|
||
int nLen = (int)(m_pTable->m_nLen);
|
||
|
||
while (m_nIndex < nLen)
|
||
{
|
||
typename StrHashTable<T>::NodeType* pNode =
|
||
&m_pTable->m_pTable[m_nIndex];
|
||
|
||
m_nIndex++;
|
||
|
||
if (pNode->hash1) return &pNode->value;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
private:
|
||
const StrHashTable<T>* m_pTable;
|
||
int m_nIndex;
|
||
};
|
||
|
||
template <typename T>
|
||
class StrHashTable
|
||
{
|
||
friend class StrHashTableIterator<T>;
|
||
public:
|
||
typedef StrHashTable<T> ClassType;
|
||
|
||
public:
|
||
StrHashTable(size_t len = 0)
|
||
{
|
||
m_pTable = NULL;
|
||
m_nLen = m_nFree = 0;
|
||
m_nInitSize = len;
|
||
|
||
if (len > MiniSize)
|
||
{
|
||
// <20><><EFBFBD>Ƴ<EFBFBD><C6B3>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>Ĵη<C4B4><CEB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϣ<EFBFBD>±<EFBFBD><C2B1>㷨<EFBFBD><EFBFBD><DEB7><EFBFBD><EFBFBD><EFBFBD>
|
||
size_t val;
|
||
|
||
for (int i = 0; i < 32; ++i)
|
||
{
|
||
val = size_t(1 << i);
|
||
|
||
if (len <= val)
|
||
{
|
||
m_nInitSize = val;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
m_nInitSize = MiniSize; // <20><><EFBFBD>Ƴ<EFBFBD><C6B3>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>Ĵη<C4B4><CEB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϣ<EFBFBD>±<EFBFBD><C2B1>㷨<EFBFBD><EFBFBD><DEB7><EFBFBD><EFBFBD><EFBFBD>
|
||
}
|
||
}
|
||
virtual ~StrHashTable()
|
||
{
|
||
clear();
|
||
}
|
||
//<2F><>չ<EFBFBD>ϣ<EFBFBD><CFA3>
|
||
void clear()
|
||
{
|
||
//ѭ<><D1AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
for (int i = (int)m_nLen - 1; i > -1; --i)
|
||
{
|
||
if (m_pTable[i].hash1)
|
||
{
|
||
m_pTable[i].value.~T();
|
||
}
|
||
}
|
||
|
||
//<2F>ͷ<EFBFBD><CDB7>ڴ<EFBFBD>
|
||
if (m_pTable) realloc(m_pTable, 0);
|
||
|
||
m_pTable = NULL;
|
||
m_nLen = m_nFree = 0;
|
||
}
|
||
//<2F><>ȡ<EFBFBD><C8A1>Ч<EFBFBD><D0A7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
inline size_t count() const
|
||
{
|
||
return m_nLen - m_nFree;
|
||
}
|
||
protected:
|
||
/** <20><><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD>ʹ<EFBFBD>õĹ<C3B5>ϣ<EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD>ݽṹ **/
|
||
template <typename TA>
|
||
class HashNode
|
||
{
|
||
public:
|
||
unsigned int hash1; //<2F><>ϣֵ1
|
||
unsigned int hash2; //<2F><>ϣֵ2
|
||
unsigned int hash3; //<2F><>ϣֵ3
|
||
TA value; //<2F><><EFBFBD><EFBFBD>ֵ
|
||
};
|
||
|
||
typedef HashNode<T> NodeType;
|
||
public:
|
||
//ͨ<><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||
inline T* get(const char* sKey)
|
||
{
|
||
int idx = getIndex(sKey);
|
||
return (idx >= 0) ? &m_pTable[idx].value : NULL;
|
||
}
|
||
//ͨ<><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||
inline const T* get(const char* sKey) const
|
||
{
|
||
int idx = getIndex(sKey);
|
||
return (idx >= 0) ? &m_pTable[idx].value : NULL;
|
||
}
|
||
/* ͨ<><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||
* <20><><EFBFBD>һ<EFBFBD><D2BB>hash<73><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ã<EFBFBD><C3A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
* <20><><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7>ʼ<EFBFBD><CABC><EFBFBD>ҿ<EFBFBD>λ<EFBFBD><CEBB>ֱ֪<D6AA><D6B1><EFBFBD>ҵ<EFBFBD><D2B5><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>α<EFBFBD><CEB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
*/
|
||
inline T* put(const char* sKey)
|
||
{
|
||
unsigned int hash1, idx, start;
|
||
#ifdef _MSC_VER
|
||
unsigned int hash2, hash3;
|
||
#else
|
||
unsigned int __attribute__ ((unused)) hash2, hash3;
|
||
#endif
|
||
//<2F>ڴ<EFBFBD>ռ䲻<D5BC>㣬<EFBFBD><E3A3AC><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>ռ<EFBFBD>
|
||
if (m_nFree <= 0)
|
||
{
|
||
size_t oldlen = m_nLen;
|
||
m_nLen = (oldlen <= 0) ? m_nInitSize : m_nLen << 1;//<2F><><EFBFBD><EFBFBD><EFBFBD>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>Ĵη<C4B4>
|
||
m_nFree = m_nLen - oldlen;
|
||
m_pTable = (NodeType*)realloc(m_pTable, m_nLen * sizeof(m_pTable[0]));
|
||
memset(&m_pTable[oldlen], 0, m_nFree * sizeof(m_pTable[0]));
|
||
}
|
||
|
||
hash1 = ::bzhashstr(sKey, 0);
|
||
hash2 = ::bzhashstr(sKey, 1);
|
||
hash3 = ::bzhashstr(sKey, 2);
|
||
start = idx = hash1 & ((unsigned int)m_nLen - 1);//<2F><><EFBFBD><EFBFBD><EFBFBD>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>Ĵη<C4B4>
|
||
|
||
do
|
||
{
|
||
NodeType* pNode = &m_pTable[idx];
|
||
|
||
//<2F><><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>û<EFBFBD><C3BB>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD><C3B5><EFBFBD>λ<EFBFBD>ã<EFBFBD><C3A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>
|
||
if (!pNode->hash1)
|
||
{
|
||
pNode->hash1 = hash1;
|
||
pNode->hash2 = ::bzhashstr(sKey, 1);
|
||
pNode->hash3 = ::bzhashstr(sKey, 2);
|
||
m_nFree--;
|
||
new(&pNode->value)T();
|
||
return &pNode->value;
|
||
}
|
||
|
||
#ifdef _DEBUG
|
||
else if (pNode->hash1 == hash1 && pNode->hash2 == hash2 && pNode->hash3 == hash3)
|
||
{
|
||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD><D8B8><EFBFBD><EFBFBD>ӣ<EFBFBD><D3A3><EFBFBD><EFBFBD><EFBFBD>ȷʵ<C8B7><CAB5><EFBFBD>ִ<EFBFBD><D6B4><EFBFBD>
|
||
//DebugBreak();
|
||
}
|
||
#endif
|
||
idx = (idx + 1) & ((unsigned int)m_nLen - 1);//<2F><><EFBFBD><EFBFBD><EFBFBD>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>Ĵη<C4B4>
|
||
}
|
||
while (start != idx);
|
||
|
||
return NULL;
|
||
}
|
||
//ͨ<><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||
inline int update(const char* sKey, const T& value)
|
||
{
|
||
int idx = getIndex(sKey);
|
||
|
||
if (idx >= 0)
|
||
m_pTable[idx].value = value;
|
||
|
||
return idx;
|
||
}
|
||
//ͨ<><CDA8><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD>ֵ<EFBFBD><D6B5>û<EFBFBD><C3BB><EFBFBD>ҵ<EFBFBD><D2B5><EFBFBD>-1
|
||
inline int remove(const char* sKey)
|
||
{
|
||
int idx = getIndex(sKey);
|
||
|
||
if (idx >= 0)
|
||
{
|
||
NodeType* pNode = &m_pTable[idx];
|
||
pNode->hash1 = pNode->hash2 = pNode->hash3 = 0;
|
||
m_nFree++;
|
||
pNode->value.~T();
|
||
return idx;
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
//<2F><>ȡ<EFBFBD><C8A1><EFBFBD>ڱ<EFBFBD><DAB1>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD>
|
||
int getIndex(const char* sKey) const
|
||
{
|
||
unsigned int idx, start;
|
||
size_t len;
|
||
|
||
if (m_nLen <= 0)
|
||
return -1;
|
||
|
||
unsigned int hash1 = ::bzhashstr(sKey, 0);
|
||
unsigned int hash2 = ::bzhashstr(sKey, 1);
|
||
unsigned int hash3 = ::bzhashstr(sKey, 2);
|
||
|
||
//<2F><><EFBFBD>ȿ<EFBFBD>ʼ<EFBFBD>۰<EFBFBD><DBB0><EFBFBD><EFBFBD>
|
||
len = m_nLen;
|
||
|
||
while (len >= m_nInitSize)
|
||
{
|
||
idx = hash1 & ((unsigned int)len - 1);//<2F><><EFBFBD><EFBFBD><EFBFBD>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>Ĵη<C4B4>
|
||
NodeType* pNode = &m_pTable[idx];
|
||
|
||
if (pNode->hash1 == hash1 && pNode->hash2 == hash2 && pNode->hash3 == hash3)
|
||
{
|
||
return idx;
|
||
}
|
||
|
||
len >>= 1;
|
||
}
|
||
|
||
//<2F>۰<EFBFBD><DBB0><EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>hashλ<68>ÿ<EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
start = idx = hash1 & ((unsigned int)m_nLen - 1);//<2F><><EFBFBD><EFBFBD><EFBFBD>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>Ĵη<C4B4>
|
||
|
||
do
|
||
{
|
||
NodeType* pNode = &m_pTable[idx];
|
||
|
||
if (pNode->hash1 == hash1 && pNode->hash2 == hash2 && pNode->hash3 == hash3)
|
||
{
|
||
return idx;
|
||
}
|
||
|
||
idx = (idx + 1) & ((unsigned int)m_nLen - 1);//<2F><><EFBFBD><EFBFBD><EFBFBD>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>Ĵη<C4B4>
|
||
}
|
||
while (start != idx);
|
||
|
||
return -1;
|
||
}
|
||
|
||
protected:
|
||
//<2F>ڴ<EFBFBD><DAB4><EFBFBD><EFBFBD>뺯<EFBFBD><EBBAAF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD>reallocʵ<63><CAB5><EFBFBD><EFBFBD>ͬ<EFBFBD><CDAC>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD>롢<EFBFBD><EBA1A2>չ<EFBFBD>Լ<EFBFBD><D4BC>ͷ<EFBFBD><CDB7>ڴ<EFBFBD>
|
||
virtual void* realloc(void* p, size_t s)
|
||
{
|
||
#ifdef _MSC_VER
|
||
static BaseAllocator alloc("bzhashtable");
|
||
if (s > 0)
|
||
{
|
||
return alloc.ReAllocBuffer(p, s);
|
||
}
|
||
else
|
||
{
|
||
if (p)
|
||
{
|
||
alloc.FreeBuffer(p);
|
||
}
|
||
return NULL;
|
||
}
|
||
return alloc.ReAllocBuffer(p, s);
|
||
#else
|
||
return ::realloc(p, s);
|
||
#endif
|
||
}
|
||
protected:
|
||
size_t m_nInitSize;//<2F><><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>
|
||
size_t m_nLen; //<2F><>ϣ<EFBFBD><CFA3><EFBFBD>ij<EFBFBD><C4B3><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>Ĵη<C4B4><CEB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϣ<EFBFBD>±<EFBFBD><C2B1>㷨<EFBFBD><EFBFBD><DEB7><EFBFBD><EFBFBD><EFBFBD>
|
||
size_t m_nFree; //<2F><><EFBFBD>нڵ<D0BD><DAB5><EFBFBD><EFBFBD><EFBFBD>
|
||
HashNode<T>* m_pTable; //<2F><>ϣ<EFBFBD><CFA3>
|
||
|
||
public:
|
||
static const size_t MiniSize = 16;//<2F><>ϣ<EFBFBD><CFA3><EFBFBD><EFBFBD>С<EFBFBD><D0A1><EFBFBD>ȣ<EFBFBD><C8A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>Ĵη<C4B4><CEB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϣ<EFBFBD>±<EFBFBD><C2B1>㷨<EFBFBD><EFBFBD><DEB7><EFBFBD><EFBFBD><EFBFBD>
|
||
};
|
||
#endif
|
||
|