Fixed bug at18919
This commit is contained in:
parent
164a47bde4
commit
a816767abb
@ -66,7 +66,7 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
String(String &src)
|
||||
String(const String &src)
|
||||
{
|
||||
v = NULL;
|
||||
a_size = 0;
|
||||
|
@ -2,7 +2,8 @@
|
||||
#define _INCLUDE_JOURNAL_H
|
||||
|
||||
#include "Binary.h"
|
||||
#include "NHash.h"
|
||||
#include "sh_list.h"
|
||||
#include "sh_tinyhash.h"
|
||||
#include "CString.h"
|
||||
|
||||
enum JOp
|
||||
@ -21,7 +22,7 @@ enum Encode
|
||||
Encode_Medium,
|
||||
};
|
||||
|
||||
typedef NHash<String,String> VaultMap;
|
||||
typedef THash<String,String> VaultMap;
|
||||
|
||||
class Journal
|
||||
{
|
||||
|
@ -1,320 +0,0 @@
|
||||
#ifndef _INCLUDE_NHASH_H
|
||||
#define _INCLUDE_NHASH_H
|
||||
|
||||
#include <time.h>
|
||||
#include "compat.h"
|
||||
|
||||
/**
|
||||
* This is a primitive, typical hash class.
|
||||
* Design goals were: modular, easy to use, compact
|
||||
* The table size is fixed by a constant, 2K gives about ~8-16K in immediate memory usage.
|
||||
* Each entry in the table uses about 20-28 bytes, depending on the data being stored.
|
||||
* In theory we could optimize this further by storing a linked list of the hash items.
|
||||
* (this would sacrifice ~8 bytes per node!)
|
||||
* --- by David "BAILOPAN" Anderson
|
||||
*/
|
||||
|
||||
#define TABLE_SIZE 2048
|
||||
|
||||
template <class K>
|
||||
int HashFunction(const K & k);
|
||||
|
||||
template <class K>
|
||||
bool Compare(const K & k1, const K & k2);
|
||||
|
||||
template <class K, class V>
|
||||
class NHash
|
||||
{
|
||||
private:
|
||||
struct hashnode
|
||||
{
|
||||
K key;
|
||||
V val;
|
||||
time_t stamp;
|
||||
hashnode *next;
|
||||
hashnode *prev;
|
||||
};
|
||||
struct bucket
|
||||
{
|
||||
hashnode *head;
|
||||
hashnode *tail;
|
||||
};
|
||||
public:
|
||||
NHash()
|
||||
{
|
||||
memset(&m_Buckets, 0, sizeof(m_Buckets));
|
||||
m_Size = 0;
|
||||
}
|
||||
~NHash()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
void Clear()
|
||||
{
|
||||
hashnode *n, *t;
|
||||
for (size_t i=0; i<TABLE_SIZE; i++)
|
||||
{
|
||||
n = m_Buckets[i].head;
|
||||
while (n)
|
||||
{
|
||||
t = n->next;
|
||||
delete n;
|
||||
n = t;
|
||||
}
|
||||
m_Buckets[i].head = NULL;
|
||||
m_Buckets[i].tail = NULL;
|
||||
}
|
||||
}
|
||||
void Insert(const K & key, const V & val)
|
||||
{
|
||||
Insert(key, val, time(NULL));
|
||||
}
|
||||
void Insert(const K & key, const V & val, time_t stamp)
|
||||
{
|
||||
bucket *b;
|
||||
hashnode *n;
|
||||
if (!_Find(key, &b, &n))
|
||||
{
|
||||
n = new hashnode;
|
||||
n->key = key;
|
||||
_Insert(b, n);
|
||||
}
|
||||
n->val = val;
|
||||
n->stamp = stamp;
|
||||
}
|
||||
bool Exists(const K & k)
|
||||
{
|
||||
uint16_t h = HashFunction(k);
|
||||
if (h >= TABLE_SIZE)
|
||||
h = h % TABLE_SIZE;
|
||||
bucket *b = &(m_Buckets[h]);
|
||||
hashnode *n = b->head;
|
||||
while (n)
|
||||
{
|
||||
if (Compare(n->key,k))
|
||||
return true;
|
||||
n = n->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
V & Retrieve(const K & k, time_t & stamp)
|
||||
{
|
||||
hashnode *n;
|
||||
bucket *b;
|
||||
if (!_Find(k, &b, &n))
|
||||
{
|
||||
n = new hashnode;
|
||||
n->key = k;
|
||||
n->stamp = time(NULL);
|
||||
_Insert(b, n);
|
||||
}
|
||||
stamp = n->stamp;
|
||||
return n->val;
|
||||
}
|
||||
V & Retrieve(const K & k)
|
||||
{
|
||||
time_t stamp;
|
||||
return Retrieve(k, stamp);
|
||||
}
|
||||
size_t Size()
|
||||
{
|
||||
return m_Size;
|
||||
}
|
||||
void Remove(const K & key)
|
||||
{
|
||||
bucket *b;
|
||||
hashnode *n;
|
||||
if (_Find(key, &b, &n))
|
||||
{
|
||||
_Remove(b, n);
|
||||
}
|
||||
}
|
||||
size_t Prune(time_t start=0, time_t end=0)
|
||||
{
|
||||
size_t num = m_Size;
|
||||
hashnode *n, *t;
|
||||
bucket *b;
|
||||
for (size_t i=0; i<TABLE_SIZE; i++)
|
||||
{
|
||||
b = &(m_Buckets[i]);
|
||||
n = b->head;
|
||||
while (n)
|
||||
{
|
||||
t = n->next;
|
||||
if (n->stamp != 0)
|
||||
{
|
||||
if (start == 0 && end == 0)
|
||||
_Remove(b, n);
|
||||
else if (start == 0 && n->stamp < end)
|
||||
_Remove(b, n);
|
||||
else if (end == 0 && n->stamp > start)
|
||||
_Remove(b, n);
|
||||
else if (n->stamp > start && n->stamp < end)
|
||||
_Remove(b, n);
|
||||
}
|
||||
n = t;
|
||||
}
|
||||
if (!m_Size)
|
||||
return num;
|
||||
}
|
||||
return (num - m_Size);
|
||||
}
|
||||
private:
|
||||
bucket m_Buckets[TABLE_SIZE];
|
||||
size_t m_Size;
|
||||
public:
|
||||
friend class iterator;
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
iterator()
|
||||
{
|
||||
}
|
||||
iterator(NHash *hash) : m_Hash(hash),
|
||||
m_CurPos(0),
|
||||
m_CurNode(0)
|
||||
{
|
||||
Next();
|
||||
}
|
||||
void Next()
|
||||
{
|
||||
if (!m_CurNode || !m_CurNode->next)
|
||||
{
|
||||
bucket *b;
|
||||
int i;
|
||||
for (i=m_CurPos+1; i<TABLE_SIZE; i++)
|
||||
{
|
||||
b = &(m_Hash->m_Buckets[i]);
|
||||
if (b->head)
|
||||
{
|
||||
m_CurNode = b->head;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//m_LastPos = m_CurPos;
|
||||
m_CurPos = i;
|
||||
} else {
|
||||
m_CurNode = m_CurNode->next;
|
||||
}
|
||||
}
|
||||
bool Done()
|
||||
{
|
||||
if (!m_CurNode)
|
||||
return true;
|
||||
if (!m_CurNode->next && m_CurPos >= TABLE_SIZE)
|
||||
return true;
|
||||
if (!m_CurNode->next)
|
||||
{
|
||||
bucket *b;
|
||||
for (int i=m_CurPos+1; i<TABLE_SIZE; i++)
|
||||
{
|
||||
b = &(m_Hash->m_Buckets[i]);
|
||||
if (b->head)
|
||||
{
|
||||
//trick next into moving to this one quickly :)
|
||||
m_CurPos = i - 1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
K & GetKey()
|
||||
{
|
||||
return m_CurNode->key;
|
||||
}
|
||||
V & GetVal()
|
||||
{
|
||||
return m_CurNode->val;
|
||||
}
|
||||
time_t GetStamp()
|
||||
{
|
||||
return m_CurNode->stamp;
|
||||
}
|
||||
private:
|
||||
NHash *m_Hash;
|
||||
int m_CurPos;
|
||||
//int m_LastPos;
|
||||
hashnode *m_CurNode;
|
||||
//hashnode *m_LastNode;
|
||||
};
|
||||
public:
|
||||
iterator GetIter()
|
||||
{
|
||||
return iterator(this);
|
||||
}
|
||||
private:
|
||||
bool _Find(const K & k, bucket **b, hashnode **n)
|
||||
{
|
||||
uint16_t h = HashFunction(k);
|
||||
if (h >= TABLE_SIZE)
|
||||
h = h % TABLE_SIZE;
|
||||
bucket *bb = &(m_Buckets[h]);
|
||||
if (b)
|
||||
*b = bb;
|
||||
hashnode *nn = bb->head;
|
||||
while (nn)
|
||||
{
|
||||
if (Compare(nn->key,k))
|
||||
{
|
||||
if (n)
|
||||
*n = nn;
|
||||
return true;
|
||||
}
|
||||
nn = nn->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void _Insert(hashnode *n)
|
||||
{
|
||||
uint16_t h = HashFunction(n->key);
|
||||
if (h >= TABLE_SIZE)
|
||||
h = h % TABLE_SIZE;
|
||||
bucket *b = &(m_Buckets[h]);
|
||||
_Insert(b, n);
|
||||
}
|
||||
//Lowest call for insertion
|
||||
void _Insert(bucket *b, hashnode *n)
|
||||
{
|
||||
n->next = NULL;
|
||||
if (b->head == NULL)
|
||||
{
|
||||
b->head = n;
|
||||
b->tail = n;
|
||||
n->prev = NULL;
|
||||
} else {
|
||||
b->tail->next = n;
|
||||
n->prev = b->tail;
|
||||
b->tail = n;
|
||||
}
|
||||
m_Size++;
|
||||
}
|
||||
//Lowest call for deletion, returns next node if any
|
||||
hashnode *_Remove(bucket *b, hashnode *n)
|
||||
{
|
||||
hashnode *n2 = n->next;
|
||||
if (b->head == n && b->tail == n)
|
||||
{
|
||||
b->head = NULL;
|
||||
b->tail = NULL;
|
||||
} else if (b->head == n) {
|
||||
n->next->prev = NULL;
|
||||
b->head = n->next;
|
||||
if (b->head->next == NULL)
|
||||
b->tail = b->head;
|
||||
} else if (b->tail == n) {
|
||||
n->prev->next = NULL;
|
||||
b->tail = n->prev;
|
||||
if (b->tail->prev == NULL)
|
||||
b->head = b->tail;
|
||||
} else {
|
||||
n->prev->next = n->next;
|
||||
n->next->prev = n->prev;
|
||||
}
|
||||
delete n;
|
||||
m_Size--;
|
||||
return n2;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_NHASH_H
|
@ -18,9 +18,9 @@ int HashFunction<String>(const String & k)
|
||||
}
|
||||
|
||||
template <>
|
||||
bool Compare<String>(const String & k1, const String & k2)
|
||||
int Compare<String>(const String & k1, const String & k2)
|
||||
{
|
||||
return (strcmp(k1.c_str(),k2.c_str())==0);
|
||||
return strcmp(k1.c_str(),k2.c_str());
|
||||
}
|
||||
|
||||
NVault::NVault(const char *file)
|
||||
@ -137,18 +137,18 @@ bool NVault::_SaveToFile()
|
||||
String key;
|
||||
String val;
|
||||
|
||||
NHash<String,String>::iterator iter = m_Hash.GetIter();
|
||||
while (!iter.Done())
|
||||
THash<String,String>::iterator iter = m_Hash.begin();
|
||||
while (iter != m_Hash.end())
|
||||
{
|
||||
key = iter.GetKey();
|
||||
val = iter.GetVal();
|
||||
stamp = iter.GetStamp();
|
||||
key = (*iter).key;
|
||||
val = (*iter).val;
|
||||
stamp = (*iter).stamp;
|
||||
bw.WriteInt32(stamp);
|
||||
bw.WriteUInt8( key.size() );
|
||||
bw.WriteUInt16( val.size() );
|
||||
bw.WriteChars( key.c_str(), key.size() );
|
||||
bw.WriteChars( val.c_str(), val.size() );
|
||||
iter.Next();
|
||||
iter++;
|
||||
}
|
||||
} catch (...) {
|
||||
fclose(fp);
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef _INCLUDE_NVAULT_H
|
||||
#define _INCLUDE_NVAULT_H
|
||||
|
||||
#include "sh_list.h"
|
||||
#include "sh_tinyhash.h"
|
||||
#include "IVault.h"
|
||||
#include "CString.h"
|
||||
#include "Journal.h"
|
||||
@ -51,7 +53,7 @@ private:
|
||||
bool _SaveToFile();
|
||||
private:
|
||||
String m_File;
|
||||
NHash<String, String> m_Hash;
|
||||
THash<String, String> m_Hash;
|
||||
Journal *m_Journal;
|
||||
bool m_Open;
|
||||
};
|
||||
|
@ -29,10 +29,10 @@ static cell nvault_open(AMX *amx, cell *params)
|
||||
sprintf(file, "%s/%s.vault", path, name);
|
||||
for (size_t i=0; i<g_Vaults.size(); i++)
|
||||
{
|
||||
if (!g_Vaults[i])
|
||||
continue;
|
||||
if (strcmp(g_Vaults.at(i)->GetFilename(), file) == 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
NVault *v = new NVault(file);
|
||||
if (!v->Open())
|
||||
|
@ -162,10 +162,13 @@
|
||||
RelativePath=".\Journal.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\NHash.h">
|
||||
RelativePath=".\NVault.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\NVault.h">
|
||||
RelativePath=".\sh_list.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\sh_tinyhash.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
@ -186,10 +189,10 @@
|
||||
RelativePath=".\CString.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\sdk\moduleconfig.h">
|
||||
RelativePath=".\moduleconfig.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\moduleconfig.h">
|
||||
RelativePath=".\sdk\moduleconfig.h">
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
|
250
dlls/nvault/sh_list.h
Executable file
250
dlls/nvault/sh_list.h
Executable file
@ -0,0 +1,250 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2005 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SMM_LIST_H
|
||||
#define _INCLUDE_SMM_LIST_H
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
//namespace SourceHook
|
||||
//{
|
||||
//This class is from CSDM for AMX Mod X
|
||||
template <class T>
|
||||
class List
|
||||
{
|
||||
public:
|
||||
class iterator;
|
||||
friend class iterator;
|
||||
class ListNode
|
||||
{
|
||||
public:
|
||||
ListNode(const T & o) : obj(o) { };
|
||||
ListNode() { };
|
||||
T obj;
|
||||
ListNode *next;
|
||||
ListNode *prev;
|
||||
};
|
||||
private:
|
||||
ListNode *_Initialize()
|
||||
{
|
||||
ListNode *n = (ListNode *)malloc(sizeof(ListNode));
|
||||
n->next = NULL;
|
||||
n->prev = NULL;
|
||||
return n;
|
||||
}
|
||||
public:
|
||||
List() : m_Head(_Initialize()), m_Size(0)
|
||||
{
|
||||
}
|
||||
List(const List &src) : m_Head(_Initialize()), m_Size(0)
|
||||
{
|
||||
iterator iter;
|
||||
for (iter=src.begin(); iter!=src.end(); iter++)
|
||||
push_back( (*iter) );
|
||||
}
|
||||
~List()
|
||||
{
|
||||
clear();
|
||||
if (m_Head)
|
||||
{
|
||||
free(m_Head);
|
||||
m_Head = NULL;
|
||||
}
|
||||
}
|
||||
void push_back(const T &obj)
|
||||
{
|
||||
ListNode *node = new ListNode(obj);
|
||||
|
||||
if (!m_Head->prev)
|
||||
{
|
||||
//link in the node as the first item
|
||||
node->next = m_Head;
|
||||
node->prev = m_Head;
|
||||
m_Head->prev = node;
|
||||
m_Head->next = node;
|
||||
} else {
|
||||
node->prev = m_Head->prev;
|
||||
node->next = m_Head;
|
||||
m_Head->prev->next = node;
|
||||
m_Head->prev = node;
|
||||
}
|
||||
m_Size++;
|
||||
}
|
||||
size_t size()
|
||||
{
|
||||
return m_Size;
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
ListNode *node = m_Head->next;
|
||||
ListNode *temp;
|
||||
m_Head->next = NULL;
|
||||
m_Head->prev = NULL;
|
||||
while (node && node != m_Head)
|
||||
{
|
||||
temp = node->next;
|
||||
delete node;
|
||||
node = temp;
|
||||
}
|
||||
m_Size = 0;
|
||||
}
|
||||
bool empty()
|
||||
{
|
||||
return (m_Head->next == NULL);
|
||||
}
|
||||
T & back()
|
||||
{
|
||||
return m_Head->prev->obj;
|
||||
}
|
||||
private:
|
||||
ListNode *m_Head;
|
||||
size_t m_Size;
|
||||
public:
|
||||
class iterator
|
||||
{
|
||||
friend class List;
|
||||
public:
|
||||
iterator()
|
||||
{
|
||||
m_This = NULL;
|
||||
}
|
||||
iterator(const List &src)
|
||||
{
|
||||
m_This = src.m_Head;
|
||||
}
|
||||
iterator(ListNode *n) : m_This(n)
|
||||
{
|
||||
}
|
||||
iterator(const iterator &where)
|
||||
{
|
||||
m_This = where.m_This;
|
||||
}
|
||||
iterator & operator--()
|
||||
{
|
||||
if (m_This)
|
||||
m_This = m_This->prev;
|
||||
return *this;
|
||||
}
|
||||
//pre increment
|
||||
iterator & operator++()
|
||||
{
|
||||
if (m_This)
|
||||
m_This = m_This->next;
|
||||
return *this;
|
||||
}
|
||||
//post increment
|
||||
iterator operator++(int)
|
||||
{
|
||||
iterator old(*this);
|
||||
if (m_This)
|
||||
m_This = m_This->next;
|
||||
return old;
|
||||
}
|
||||
T & operator * () const
|
||||
{
|
||||
return m_This->obj;
|
||||
}
|
||||
T & operator * ()
|
||||
{
|
||||
return m_This->obj;
|
||||
}
|
||||
T * operator -> () const
|
||||
{
|
||||
return &(m_This->obj);
|
||||
}
|
||||
bool operator != (const iterator &where) const
|
||||
{
|
||||
return (m_This != where.m_This);
|
||||
}
|
||||
bool operator ==(const iterator &where) const
|
||||
{
|
||||
return (m_This == where.m_This);
|
||||
}
|
||||
private:
|
||||
ListNode *m_This;
|
||||
};
|
||||
public:
|
||||
iterator begin() const
|
||||
{
|
||||
if (m_Size)
|
||||
return iterator(m_Head->next);
|
||||
else
|
||||
return iterator(m_Head);
|
||||
}
|
||||
iterator end() const
|
||||
{
|
||||
return iterator(m_Head);
|
||||
}
|
||||
iterator erase(iterator &where)
|
||||
{
|
||||
ListNode *pNode = where.m_This;
|
||||
iterator iter(where);
|
||||
iter++;
|
||||
|
||||
//If we are both the head and tail...
|
||||
if (m_Head->next == pNode && m_Head->prev == pNode)
|
||||
{
|
||||
m_Head->next = NULL;
|
||||
m_Head->prev = NULL;
|
||||
} else if (m_Head->next == pNode) {
|
||||
//we are only the first
|
||||
pNode->next->prev = m_Head;
|
||||
m_Head->next = pNode->next;
|
||||
} else if (m_Head->prev == pNode) {
|
||||
//we are the tail
|
||||
pNode->prev->next = m_Head;
|
||||
m_Head->prev = pNode->prev;
|
||||
} else {
|
||||
//middle unlink
|
||||
pNode->prev->next = pNode->next;
|
||||
pNode->next->prev = pNode->prev;
|
||||
}
|
||||
|
||||
delete pNode;
|
||||
m_Size--;
|
||||
|
||||
return iter;
|
||||
}
|
||||
public:
|
||||
void remove(const T & obj)
|
||||
{
|
||||
iterator b;
|
||||
for (b=begin(); b!=end(); b++)
|
||||
{
|
||||
if ( (*b) == obj )
|
||||
{
|
||||
erase( b );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
template <typename U>
|
||||
iterator find(const U & equ)
|
||||
{
|
||||
iterator iter;
|
||||
for (iter=begin(); iter!=end(); iter++)
|
||||
{
|
||||
if ( (*iter) == equ )
|
||||
return iter;
|
||||
}
|
||||
return end();
|
||||
}
|
||||
List & operator =(List &src)
|
||||
{
|
||||
iterator iter;
|
||||
for (iter=src.begin(); iter!=src.end(); iter++)
|
||||
push_back( (*iter) );
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
//}; //NAMESPACE
|
||||
|
||||
#endif //_INCLUDE_CSDM_LIST_H
|
407
dlls/nvault/sh_tinyhash.h
Executable file
407
dlls/nvault/sh_tinyhash.h
Executable file
@ -0,0 +1,407 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2005 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
*
|
||||
* Author(s): David "BAILOPAN" Anderson
|
||||
* ============================
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SH_TINYHASH_H_
|
||||
#define _INCLUDE_SH_TINYHASH_H_
|
||||
|
||||
#include <time.h>
|
||||
#include "sh_list.h"
|
||||
|
||||
#define _T_INIT_HASH_SIZE 32
|
||||
|
||||
//namespace SourceHook
|
||||
//{
|
||||
template <class K>
|
||||
int HashFunction(const K & k);
|
||||
|
||||
template <class K>
|
||||
int Compare(const K & k1, const K & k2);
|
||||
|
||||
/**
|
||||
* This is a tiny, growable hash class.
|
||||
* Meant for quick and dirty dictionaries only!
|
||||
*/
|
||||
template <class K, class V>
|
||||
class THash
|
||||
{
|
||||
public:
|
||||
struct THashNode
|
||||
{
|
||||
THashNode(const K & k, const V & v) :
|
||||
key(k), val(v)
|
||||
{
|
||||
};
|
||||
K key;
|
||||
V val;
|
||||
time_t stamp;
|
||||
};
|
||||
typedef List<THashNode *> * NodePtr;
|
||||
public:
|
||||
THash() : m_numBuckets(0), m_Buckets(NULL), m_Items(0)
|
||||
{
|
||||
_Refactor();
|
||||
}
|
||||
~THash()
|
||||
{
|
||||
_Clear();
|
||||
}
|
||||
void Clear()
|
||||
{
|
||||
_Clear();
|
||||
_Refactor();
|
||||
}
|
||||
void Insert(const K & key, const V & val)
|
||||
{
|
||||
Insert(key, val, time(NULL));
|
||||
}
|
||||
void Insert(const K & key, const V & val, time_t stamp)
|
||||
{
|
||||
THashNode *pNode = _FindOrInsert(key);
|
||||
pNode->val = val;
|
||||
pNode->stamp = stamp;
|
||||
}
|
||||
bool Exists(const K & key)
|
||||
{
|
||||
size_t place = HashFunction(key) % m_numBuckets;
|
||||
|
||||
if (!m_Buckets[place])
|
||||
return false;
|
||||
|
||||
typename List<THashNode *>::iterator iter;
|
||||
for (iter = m_Buckets[place]->begin(); iter != m_Buckets[place]->end(); iter++)
|
||||
{
|
||||
if (Compare(key, (*iter)->key) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
V & Retrieve(const K & k, time_t & stamp)
|
||||
{
|
||||
THashNode *pNode = _FindOrInsert(k);
|
||||
stamp = pNode->stamp;
|
||||
return pNode->val;
|
||||
}
|
||||
V & Retrieve(const K & k)
|
||||
{
|
||||
time_t stamp;
|
||||
return Retrieve(k, stamp);
|
||||
}
|
||||
void Remove(const K & key)
|
||||
{
|
||||
size_t place = HashFunction(key) % m_numBuckets;
|
||||
|
||||
if (!m_Buckets[place])
|
||||
return;
|
||||
|
||||
typename List<THashNode *>::iterator iter;
|
||||
for (iter = m_Buckets[place]->begin(); iter != m_Buckets[place]->end(); iter++)
|
||||
{
|
||||
if (Compare(key, (*iter)->key) == 0)
|
||||
{
|
||||
iter = m_Buckets[place]->erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
size_t Prune(time_t start=0, time_t end=0)
|
||||
{
|
||||
typename List<THashNode *>::iterator iter;
|
||||
time_t stamp;
|
||||
size_t removed = 0;
|
||||
for (size_t i=0; i<m_numBuckets; i++)
|
||||
{
|
||||
iter = m_Buckets[i]->begin();
|
||||
bool remove;
|
||||
while (iter != m_Buckets[i]->end())
|
||||
{
|
||||
stamp = (*iter)->stamp;
|
||||
remove = false;
|
||||
if (stamp != 0)
|
||||
{
|
||||
if (start == 0 && end == 0)
|
||||
remove = true;
|
||||
else if (start == 0 && stamp < end)
|
||||
remove = true;
|
||||
else if (end == 0 && stamp > start)
|
||||
remove = true;
|
||||
else if (stamp > start && stamp < end)
|
||||
remove = true;
|
||||
if (remove)
|
||||
{
|
||||
iter = m_Buckets[i]->erase(iter);
|
||||
removed++;
|
||||
} else {
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
size_t Size()
|
||||
{
|
||||
return m_Items;
|
||||
}
|
||||
size_t GetBuckets()
|
||||
{
|
||||
return m_numBuckets;
|
||||
}
|
||||
float PercentUsed()
|
||||
{
|
||||
return m_percentUsed;
|
||||
}
|
||||
V & operator [](const K & key)
|
||||
{
|
||||
THashNode *pNode = _FindOrInsert(key);
|
||||
return pNode->val;
|
||||
}
|
||||
private:
|
||||
void _Clear()
|
||||
{
|
||||
for (size_t i=0; i<m_numBuckets; i++)
|
||||
{
|
||||
if (m_Buckets[i])
|
||||
{
|
||||
m_Buckets[i]->clear();
|
||||
delete m_Buckets[i];
|
||||
}
|
||||
}
|
||||
delete [] m_Buckets;
|
||||
m_numBuckets = 0;
|
||||
m_Items = 0;
|
||||
m_Buckets = NULL;
|
||||
}
|
||||
THashNode *_FindOrInsert(const K & key)
|
||||
{
|
||||
size_t place = HashFunction(key) % m_numBuckets;
|
||||
THashNode *pNode = NULL;
|
||||
if (!m_Buckets[place])
|
||||
{
|
||||
m_Buckets[place] = new List<THashNode *>;
|
||||
pNode = new THashNode(key, V());
|
||||
m_Buckets[place]->push_back(pNode);
|
||||
m_percentUsed += (1.0f / (float)m_numBuckets);
|
||||
} else {
|
||||
typename List<THashNode *>::iterator iter;
|
||||
for (iter=m_Buckets[place]->begin(); iter!=m_Buckets[place]->end(); iter++)
|
||||
{
|
||||
if (Compare((*iter)->key, key) == 0)
|
||||
return (*iter);
|
||||
}
|
||||
//node does not exist
|
||||
pNode = new THashNode(key, V());
|
||||
m_Buckets[place]->push_back(pNode);
|
||||
}
|
||||
if (PercentUsed() > 0.75f)
|
||||
_Refactor();
|
||||
m_Items++;
|
||||
return pNode;
|
||||
}
|
||||
void _Refactor()
|
||||
{
|
||||
m_percentUsed = 0.0f;
|
||||
if (!m_numBuckets)
|
||||
{
|
||||
m_numBuckets = _T_INIT_HASH_SIZE;
|
||||
m_Buckets = new NodePtr[m_numBuckets];
|
||||
for (size_t i=0; i<m_numBuckets; i++)
|
||||
m_Buckets[i] = NULL;
|
||||
} else {
|
||||
size_t oldSize = m_numBuckets;
|
||||
m_numBuckets *= 2;
|
||||
typename List<THashNode *>::iterator iter;
|
||||
size_t place;
|
||||
THashNode *pHashNode;
|
||||
NodePtr *temp = new NodePtr[m_numBuckets];
|
||||
for (size_t i=0; i<m_numBuckets; i++)
|
||||
temp[i] = NULL;
|
||||
//look in old hash table
|
||||
for (size_t i=0; i<oldSize; i++)
|
||||
{
|
||||
//does a bucket have anything?
|
||||
if (m_Buckets[i])
|
||||
{
|
||||
//go through the list of items
|
||||
for (iter = m_Buckets[i]->begin(); iter != m_Buckets[i]->end(); iter++)
|
||||
{
|
||||
pHashNode = (*iter);
|
||||
//rehash it with the new bucket filter
|
||||
place = HashFunction(pHashNode->key) % m_numBuckets;
|
||||
//add it to the new hash table
|
||||
if (!temp[place])
|
||||
{
|
||||
temp[place] = new List<THashNode *>;
|
||||
m_percentUsed += (1.0f / (float)m_numBuckets);
|
||||
}
|
||||
temp[place]->push_back(pHashNode);
|
||||
}
|
||||
//delete that bucket!
|
||||
delete m_Buckets[i];
|
||||
m_Buckets[i] = NULL;
|
||||
}
|
||||
}
|
||||
//reassign bucket table
|
||||
delete [] m_Buckets;
|
||||
m_Buckets = temp;
|
||||
}
|
||||
}
|
||||
public:
|
||||
friend class iterator;
|
||||
class iterator
|
||||
{
|
||||
friend class THash;
|
||||
public:
|
||||
iterator() : hash(NULL), end(true)
|
||||
{
|
||||
};
|
||||
iterator(THash *h) : hash(h), end(false)
|
||||
{
|
||||
if (!h->m_Buckets)
|
||||
end = true;
|
||||
else
|
||||
_Inc();
|
||||
};
|
||||
//pre increment
|
||||
iterator & operator++()
|
||||
{
|
||||
_Inc();
|
||||
return *this;
|
||||
}
|
||||
//post increment
|
||||
iterator operator++(int)
|
||||
{
|
||||
iterator old(*this);
|
||||
_Inc();
|
||||
return old;
|
||||
}
|
||||
THashNode & operator * () const
|
||||
{
|
||||
return *(*iter);
|
||||
}
|
||||
THashNode & operator * ()
|
||||
{
|
||||
return *(*iter);
|
||||
}
|
||||
THashNode * operator ->() const
|
||||
{
|
||||
return (*iter);
|
||||
}
|
||||
THashNode * operator ->()
|
||||
{
|
||||
return (*iter);
|
||||
}
|
||||
bool operator ==(const iterator &where) const
|
||||
{
|
||||
if (where.hash == this->hash
|
||||
&& where.end == this->end
|
||||
&&
|
||||
(this->end ||
|
||||
((where.curbucket == this->curbucket)
|
||||
&& (where.iter == iter))
|
||||
))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool operator !=(const iterator &where) const
|
||||
{
|
||||
return !( (*this) == where );
|
||||
}
|
||||
private:
|
||||
void _Inc()
|
||||
{
|
||||
if (end || !hash || curbucket >= (int)hash->m_numBuckets)
|
||||
return;
|
||||
if (curbucket < 0)
|
||||
{
|
||||
for (int i=0; i<(int)hash->m_numBuckets; i++)
|
||||
{
|
||||
if (hash->m_Buckets[i])
|
||||
{
|
||||
iter = hash->m_Buckets[i]->begin();
|
||||
if (iter == hash->m_Buckets[i]->end())
|
||||
continue;
|
||||
curbucket = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (curbucket < 0)
|
||||
end = true;
|
||||
} else {
|
||||
if (iter != hash->m_Buckets[curbucket]->end())
|
||||
iter++;
|
||||
if (iter == hash->m_Buckets[curbucket]->end())
|
||||
{
|
||||
int oldbucket = curbucket;
|
||||
for (int i=curbucket+1; i<(int)hash->m_numBuckets; i++)
|
||||
{
|
||||
if (hash->m_Buckets[i])
|
||||
{
|
||||
iter = hash->m_Buckets[i]->begin();
|
||||
if (iter == hash->m_Buckets[i]->end())
|
||||
continue;
|
||||
curbucket = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (curbucket == oldbucket)
|
||||
end = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
int curbucket;
|
||||
typename List<THashNode *>::iterator iter;
|
||||
THash *hash;
|
||||
bool end;
|
||||
};
|
||||
public:
|
||||
iterator begin()
|
||||
{
|
||||
return iterator(this);
|
||||
}
|
||||
iterator end()
|
||||
{
|
||||
iterator iter;
|
||||
iter.hash = this;
|
||||
return iter;
|
||||
}
|
||||
template <typename U>
|
||||
iterator find(const U & u) const
|
||||
{
|
||||
iterator b = begin();
|
||||
iterator e = end();
|
||||
for (iterator iter = b; iter != e; iter++)
|
||||
{
|
||||
if ( (*iter).key == u )
|
||||
return iter;
|
||||
}
|
||||
return end();
|
||||
}
|
||||
template <typename U>
|
||||
iterator find(const U & u)
|
||||
{
|
||||
iterator b = begin();
|
||||
iterator e = end();
|
||||
for (iterator iter = b; iter != e; iter++)
|
||||
{
|
||||
if ( (*iter).key == u )
|
||||
return iter;
|
||||
}
|
||||
return end();
|
||||
}
|
||||
private:
|
||||
NodePtr *m_Buckets;
|
||||
size_t m_numBuckets;
|
||||
float m_percentUsed;
|
||||
size_t m_Items;
|
||||
};
|
||||
//};
|
||||
|
||||
#endif //_INCLUDE_SH_TINYHASH_H_
|
Loading…
Reference in New Issue
Block a user