184 lines
3.7 KiB
C
184 lines
3.7 KiB
C
|
|
#ifndef _BZ_HASH_TABLE_H_
|
|||
|
|
#define _BZ_HASH_TABLE_H_
|
|||
|
|
/************************
|
|||
|
|
* һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>װ<EFBFBD>˱<EFBFBD>ѩhash<EFBFBD>㷨<EFBFBD><EFBFBD>hashtable
|
|||
|
|
* <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>ṩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
*************************/
|
|||
|
|
#include "memory/base_allocator.hpp"
|
|||
|
|
#include "bzhash.h"
|
|||
|
|
|
|||
|
|
template <typename T>
|
|||
|
|
class BZHashTable
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
BZHashTable(size_t len)
|
|||
|
|
{
|
|||
|
|
assert(len > 0);
|
|||
|
|
|
|||
|
|
max_size_ = len;
|
|||
|
|
data_ = NULL;
|
|||
|
|
size_ = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
virtual ~BZHashTable()
|
|||
|
|
{
|
|||
|
|
clear();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// <20><>չ<EFBFBD>ϣ<EFBFBD><CFA3>
|
|||
|
|
void clear()
|
|||
|
|
{
|
|||
|
|
if (size_ > 0)
|
|||
|
|
{
|
|||
|
|
for (int i = (int)(max_size_ - 1); i > -1; --i)
|
|||
|
|
{
|
|||
|
|
if (data_[i].exists)
|
|||
|
|
{
|
|||
|
|
data_[i].value.~T();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (data_) realloc(data_, 0);
|
|||
|
|
data_ = NULL;
|
|||
|
|
size_ = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
inline size_t count() const { return size_; }
|
|||
|
|
protected:
|
|||
|
|
template <typename TA>
|
|||
|
|
class HashNode
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
bool exists; // <20>Ƿ<C7B7><F1B1A3B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
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* key)
|
|||
|
|
{
|
|||
|
|
int idx = getIndex(key);
|
|||
|
|
return (idx >= 0) ? &data_[idx].value : NULL;
|
|||
|
|
}
|
|||
|
|
//ͨ<><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
|||
|
|
inline const T* get(const char* key) const
|
|||
|
|
{
|
|||
|
|
int idx = getIndex(key);
|
|||
|
|
return (idx >= 0) ? &data_[idx].value : NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
inline T* put(const char* key)
|
|||
|
|
{
|
|||
|
|
if (size_ >= max_size_)
|
|||
|
|
{
|
|||
|
|
#ifdef _DEBUG
|
|||
|
|
DbgAssert(false);
|
|||
|
|
#endif
|
|||
|
|
return NULL; // no free
|
|||
|
|
}
|
|||
|
|
if (!data_)
|
|||
|
|
{
|
|||
|
|
data_ = (HashNode<T> *)realloc(NULL, sizeof(HashNode<T>) * max_size_);
|
|||
|
|
for (size_t i = 0; i < max_size_; ++i)
|
|||
|
|
{
|
|||
|
|
data_[i].exists = false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
unsigned int hash1, hash2, hash3, idx, start;
|
|||
|
|
hash1 = ::bzhashstr(key, 0);
|
|||
|
|
hash2 = ::bzhashstr(key, 1);
|
|||
|
|
hash3 = ::bzhashstr(key, 2);
|
|||
|
|
start = idx = hash1 % (unsigned int)max_size_;
|
|||
|
|
do
|
|||
|
|
{
|
|||
|
|
NodeType *node = data_ + 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 (!node->exists)
|
|||
|
|
{
|
|||
|
|
node->exists = true;
|
|||
|
|
node->hash1 = hash1;
|
|||
|
|
node->hash2 = hash2;
|
|||
|
|
node->hash3 = hash3;
|
|||
|
|
size_++;
|
|||
|
|
new (&node->value)T();
|
|||
|
|
return &node->value;
|
|||
|
|
}
|
|||
|
|
#ifdef _DEBUG
|
|||
|
|
else if (node->hash1 == hash1 && node->hash2 == hash2 && node->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)max_size_;
|
|||
|
|
}
|
|||
|
|
while (start != idx);
|
|||
|
|
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//<2F><>ȡ<EFBFBD><C8A1><EFBFBD>ڱ<EFBFBD><DAB1>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
int getIndex(const char* sKey) const
|
|||
|
|
{
|
|||
|
|
if (!data_) return -1;
|
|||
|
|
|
|||
|
|
unsigned int hash1, hash2, hash3;
|
|||
|
|
|
|||
|
|
hash1 = ::bzhashstr(sKey, 0);
|
|||
|
|
hash2 = ::bzhashstr(sKey, 1);
|
|||
|
|
hash3 = ::bzhashstr(sKey, 2);
|
|||
|
|
|
|||
|
|
size_t start = hash1 % max_size_, idx = start;
|
|||
|
|
|
|||
|
|
while (data_[idx].exists)
|
|||
|
|
{
|
|||
|
|
if (data_[idx].hash2 == hash2 && data_[idx].hash3 == hash3)
|
|||
|
|
return (int)idx;
|
|||
|
|
else
|
|||
|
|
idx = (idx + 1) % max_size_;
|
|||
|
|
|
|||
|
|
if (idx == start)
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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 max_size_;
|
|||
|
|
size_t size_;
|
|||
|
|
HashNode<T> *data_; //<2F><>ϣ<EFBFBD><CFA3>
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
#endif
|