Fixed bug at18919

This commit is contained in:
David Anderson 2005-09-18 02:59:36 +00:00
parent 164a47bde4
commit a816767abb
9 changed files with 681 additions and 338 deletions

View File

@ -66,7 +66,7 @@ public:
return ret; return ret;
} }
String(String &src) String(const String &src)
{ {
v = NULL; v = NULL;
a_size = 0; a_size = 0;

View File

@ -2,7 +2,8 @@
#define _INCLUDE_JOURNAL_H #define _INCLUDE_JOURNAL_H
#include "Binary.h" #include "Binary.h"
#include "NHash.h" #include "sh_list.h"
#include "sh_tinyhash.h"
#include "CString.h" #include "CString.h"
enum JOp enum JOp
@ -21,7 +22,7 @@ enum Encode
Encode_Medium, Encode_Medium,
}; };
typedef NHash<String,String> VaultMap; typedef THash<String,String> VaultMap;
class Journal class Journal
{ {

View File

@ -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

View File

@ -18,9 +18,9 @@ int HashFunction<String>(const String & k)
} }
template <> 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) NVault::NVault(const char *file)
@ -137,18 +137,18 @@ bool NVault::_SaveToFile()
String key; String key;
String val; String val;
NHash<String,String>::iterator iter = m_Hash.GetIter(); THash<String,String>::iterator iter = m_Hash.begin();
while (!iter.Done()) while (iter != m_Hash.end())
{ {
key = iter.GetKey(); key = (*iter).key;
val = iter.GetVal(); val = (*iter).val;
stamp = iter.GetStamp(); stamp = (*iter).stamp;
bw.WriteInt32(stamp); bw.WriteInt32(stamp);
bw.WriteUInt8( key.size() ); bw.WriteUInt8( key.size() );
bw.WriteUInt16( val.size() ); bw.WriteUInt16( val.size() );
bw.WriteChars( key.c_str(), key.size() ); bw.WriteChars( key.c_str(), key.size() );
bw.WriteChars( val.c_str(), val.size() ); bw.WriteChars( val.c_str(), val.size() );
iter.Next(); iter++;
} }
} catch (...) { } catch (...) {
fclose(fp); fclose(fp);

View File

@ -1,6 +1,8 @@
#ifndef _INCLUDE_NVAULT_H #ifndef _INCLUDE_NVAULT_H
#define _INCLUDE_NVAULT_H #define _INCLUDE_NVAULT_H
#include "sh_list.h"
#include "sh_tinyhash.h"
#include "IVault.h" #include "IVault.h"
#include "CString.h" #include "CString.h"
#include "Journal.h" #include "Journal.h"
@ -51,7 +53,7 @@ private:
bool _SaveToFile(); bool _SaveToFile();
private: private:
String m_File; String m_File;
NHash<String, String> m_Hash; THash<String, String> m_Hash;
Journal *m_Journal; Journal *m_Journal;
bool m_Open; bool m_Open;
}; };

View File

@ -29,11 +29,11 @@ static cell nvault_open(AMX *amx, cell *params)
sprintf(file, "%s/%s.vault", path, name); sprintf(file, "%s/%s.vault", path, name);
for (size_t i=0; i<g_Vaults.size(); i++) for (size_t i=0; i<g_Vaults.size(); i++)
{ {
if (!g_Vaults[i])
continue;
if (strcmp(g_Vaults.at(i)->GetFilename(), file) == 0) if (strcmp(g_Vaults.at(i)->GetFilename(), file) == 0)
{
return i; return i;
} }
}
NVault *v = new NVault(file); NVault *v = new NVault(file);
if (!v->Open()) if (!v->Open())
{ {

View File

@ -162,10 +162,13 @@
RelativePath=".\Journal.h"> RelativePath=".\Journal.h">
</File> </File>
<File <File
RelativePath=".\NHash.h"> RelativePath=".\NVault.h">
</File> </File>
<File <File
RelativePath=".\NVault.h"> RelativePath=".\sh_list.h">
</File>
<File
RelativePath=".\sh_tinyhash.h">
</File> </File>
</Filter> </Filter>
<Filter <Filter
@ -186,10 +189,10 @@
RelativePath=".\CString.h"> RelativePath=".\CString.h">
</File> </File>
<File <File
RelativePath=".\sdk\moduleconfig.h"> RelativePath=".\moduleconfig.h">
</File> </File>
<File <File
RelativePath=".\moduleconfig.h"> RelativePath=".\sdk\moduleconfig.h">
</File> </File>
</Filter> </Filter>
</Files> </Files>

250
dlls/nvault/sh_list.h Executable file
View 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
View 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_