From a816767abb321e43405d93912ada1c1f0c41ee9a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 18 Sep 2005 02:59:36 +0000 Subject: [PATCH] Fixed bug at18919 --- dlls/nvault/CString.h | 2 +- dlls/nvault/Journal.h | 5 +- dlls/nvault/NHash.h | 320 ------------------------------ dlls/nvault/NVault.cpp | 16 +- dlls/nvault/NVault.h | 4 +- dlls/nvault/amxxapi.cpp | 4 +- dlls/nvault/nvault.vcproj | 11 +- dlls/nvault/sh_list.h | 250 +++++++++++++++++++++++ dlls/nvault/sh_tinyhash.h | 407 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 681 insertions(+), 338 deletions(-) delete mode 100755 dlls/nvault/NHash.h create mode 100755 dlls/nvault/sh_list.h create mode 100755 dlls/nvault/sh_tinyhash.h diff --git a/dlls/nvault/CString.h b/dlls/nvault/CString.h index 1a9e3ac9..54b2b2b8 100755 --- a/dlls/nvault/CString.h +++ b/dlls/nvault/CString.h @@ -66,7 +66,7 @@ public: return ret; } - String(String &src) + String(const String &src) { v = NULL; a_size = 0; diff --git a/dlls/nvault/Journal.h b/dlls/nvault/Journal.h index 89df2674..167b0491 100755 --- a/dlls/nvault/Journal.h +++ b/dlls/nvault/Journal.h @@ -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 VaultMap; +typedef THash VaultMap; class Journal { diff --git a/dlls/nvault/NHash.h b/dlls/nvault/NHash.h deleted file mode 100755 index 428559c1..00000000 --- a/dlls/nvault/NHash.h +++ /dev/null @@ -1,320 +0,0 @@ -#ifndef _INCLUDE_NHASH_H -#define _INCLUDE_NHASH_H - -#include -#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 -int HashFunction(const K & k); - -template -bool Compare(const K & k1, const K & k2); - -template -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; inext; - 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; ihead; - 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; im_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; im_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 diff --git a/dlls/nvault/NVault.cpp b/dlls/nvault/NVault.cpp index 13bf6166..e1643461 100755 --- a/dlls/nvault/NVault.cpp +++ b/dlls/nvault/NVault.cpp @@ -18,9 +18,9 @@ int HashFunction(const String & k) } template <> -bool Compare(const String & k1, const String & k2) +int Compare(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::iterator iter = m_Hash.GetIter(); - while (!iter.Done()) + THash::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); diff --git a/dlls/nvault/NVault.h b/dlls/nvault/NVault.h index af9e4777..89e6b7fe 100755 --- a/dlls/nvault/NVault.h +++ b/dlls/nvault/NVault.h @@ -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 m_Hash; + THash m_Hash; Journal *m_Journal; bool m_Open; }; diff --git a/dlls/nvault/amxxapi.cpp b/dlls/nvault/amxxapi.cpp index 526e17bd..dc88d6c0 100755 --- a/dlls/nvault/amxxapi.cpp +++ b/dlls/nvault/amxxapi.cpp @@ -29,10 +29,10 @@ static cell nvault_open(AMX *amx, cell *params) sprintf(file, "%s/%s.vault", path, name); for (size_t i=0; iGetFilename(), file) == 0) - { return i; - } } NVault *v = new NVault(file); if (!v->Open()) diff --git a/dlls/nvault/nvault.vcproj b/dlls/nvault/nvault.vcproj index 267fe071..9f7c272f 100755 --- a/dlls/nvault/nvault.vcproj +++ b/dlls/nvault/nvault.vcproj @@ -162,10 +162,13 @@ RelativePath=".\Journal.h"> + RelativePath=".\NVault.h"> + RelativePath=".\sh_list.h"> + + + RelativePath=".\moduleconfig.h"> + RelativePath=".\sdk\moduleconfig.h"> diff --git a/dlls/nvault/sh_list.h b/dlls/nvault/sh_list.h new file mode 100755 index 00000000..7df01d99 --- /dev/null +++ b/dlls/nvault/sh_list.h @@ -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 +#include + +//namespace SourceHook +//{ +//This class is from CSDM for AMX Mod X +template +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 + 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 diff --git a/dlls/nvault/sh_tinyhash.h b/dlls/nvault/sh_tinyhash.h new file mode 100755 index 00000000..e1cf1a02 --- /dev/null +++ b/dlls/nvault/sh_tinyhash.h @@ -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 +#include "sh_list.h" + +#define _T_INIT_HASH_SIZE 32 + +//namespace SourceHook +//{ + template + int HashFunction(const K & k); + + template + int Compare(const K & k1, const K & k2); + + /** + * This is a tiny, growable hash class. + * Meant for quick and dirty dictionaries only! + */ + template + 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 * 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::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::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::iterator iter; + time_t stamp; + size_t removed = 0; + for (size_t i=0; ibegin(); + 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; iclear(); + 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; + pNode = new THashNode(key, V()); + m_Buckets[place]->push_back(pNode); + m_percentUsed += (1.0f / (float)m_numBuckets); + } else { + typename List::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::iterator iter; + size_t place; + THashNode *pHashNode; + NodePtr *temp = new NodePtr[m_numBuckets]; + for (size_t i=0; ibegin(); 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; + 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::iterator iter; + THash *hash; + bool end; + }; + public: + iterator begin() + { + return iterator(this); + } + iterator end() + { + iterator iter; + iter.hash = this; + return iter; + } + template + 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 + 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_