00001
00002
00003
00004
00005
00006
00007
00008
00009 #ifndef __HASH_H
00010 #define __HASH_H
00011
00012 #include "RakAssert.h"
00013 #include <string.h>
00014 #include "Export.h"
00015 #include "RakMemoryOverride.h"
00016 #include "RakString.h"
00017
00020 namespace DataStructures
00021 {
00022 struct StringKeyedHashIndex
00023 {
00024 unsigned int primaryIndex;
00025 unsigned int secondaryIndex;
00026 bool IsInvalid(void) const {return primaryIndex==(unsigned int) -1;}
00027 void SetInvalid(void) {primaryIndex=(unsigned int) -1;}
00028 };
00029
00031 template <class data_type, unsigned int HASH_SIZE>
00032 class RAK_DLL_EXPORT StringKeyedHash
00033 {
00034 public:
00036 StringKeyedHash();
00037
00038
00039 ~StringKeyedHash();
00040
00041 void Push(const char *key, const data_type &input, const char *file, unsigned int line );
00042 data_type* Peek(const char *key );
00043 bool Pop(data_type& out, const char *key, const char *file, unsigned int line );
00044 bool RemoveAtIndex(StringKeyedHashIndex index, const char *file, unsigned int line );
00045 StringKeyedHashIndex GetIndexOf(const char *key);
00046 data_type& ItemAtIndex(const StringKeyedHashIndex &index);
00047 RakNet::RakString KeyAtIndex(const StringKeyedHashIndex &index);
00048 void GetItemList(DataStructures::List<data_type> &outputList,const char *file, unsigned int line);
00049 unsigned int GetHashIndex(const char *str);
00050
00052 void Clear( const char *file, unsigned int line );
00053
00054 struct Node
00055 {
00056 Node(const char *strIn, const data_type &_data) {string=strIn; data=_data;}
00057 RakNet::RakString string;
00058 data_type data;
00059
00060 Node *next;
00061 };
00062
00063 protected:
00064 void ClearIndex(unsigned int index,const char *file, unsigned int line);
00065 Node **nodeList;
00066 };
00067
00068 template <class data_type, unsigned int HASH_SIZE>
00069 StringKeyedHash<data_type, HASH_SIZE>::StringKeyedHash()
00070 {
00071 nodeList=0;
00072 }
00073
00074 template <class data_type, unsigned int HASH_SIZE>
00075 StringKeyedHash<data_type, HASH_SIZE>::~StringKeyedHash()
00076 {
00077 Clear(__FILE__,__LINE__);
00078 }
00079
00080 template <class data_type, unsigned int HASH_SIZE>
00081 void StringKeyedHash<data_type, HASH_SIZE>::Push(const char *key, const data_type &input, const char *file, unsigned int line )
00082 {
00083 unsigned long hashIndex = GetHashIndex(key);
00084 if (nodeList==0)
00085 {
00086 nodeList=RakNet::OP_NEW_ARRAY<Node *>(HASH_SIZE,file,line);
00087 memset(nodeList,0,sizeof(Node *)*HASH_SIZE);
00088 }
00089
00090 Node *newNode=RakNet::OP_NEW_2<Node>(file,line,key,input);
00091 newNode->next=nodeList[hashIndex];
00092 nodeList[hashIndex]=newNode;
00093 }
00094
00095 template <class data_type, unsigned int HASH_SIZE>
00096 data_type* StringKeyedHash<data_type, HASH_SIZE>::Peek(const char *key )
00097 {
00098 unsigned long hashIndex = GetHashIndex(key);
00099 Node *node = nodeList[hashIndex];
00100 while (node!=0)
00101 {
00102 if (node->string==key)
00103 return &node->data;
00104 node=node->next;
00105 }
00106 return 0;
00107 }
00108
00109 template <class data_type, unsigned int HASH_SIZE>
00110 bool StringKeyedHash<data_type, HASH_SIZE>::Pop(data_type& out, const char *key, const char *file, unsigned int line )
00111 {
00112 unsigned long hashIndex = GetHashIndex(key);
00113 Node *node = nodeList[hashIndex];
00114 if (node==0)
00115 return false;
00116 if (node->next==0)
00117 {
00118
00119 if (node->string==key)
00120 {
00121
00122 out=node->data;
00123 ClearIndex(hashIndex,__FILE__,__LINE__);
00124 return true;
00125 }
00126 else
00127 {
00128
00129 return false;
00130 }
00131 }
00132 else if (node->string==key)
00133 {
00134
00135 out=node->data;
00136 nodeList[hashIndex]=node->next;
00137 RakNet::OP_DELETE(node,file,line);
00138 return true;
00139 }
00140
00141 Node *last=node;
00142 node=node->next;
00143
00144 while (node!=0)
00145 {
00146
00147 if (node->string==key)
00148 {
00149 out=node->data;
00150
00151 last->next=node->next;
00152
00153 RakNet::OP_DELETE(node,file,line);
00154 return true;
00155 }
00156 last=node;
00157 node=node->next;
00158 }
00159 return false;
00160 }
00161
00162 template <class data_type, unsigned int HASH_SIZE>
00163 bool StringKeyedHash<data_type, HASH_SIZE>::RemoveAtIndex(StringKeyedHashIndex index, const char *file, unsigned int line )
00164 {
00165 if (index.IsInvalid())
00166 return false;
00167
00168 Node *node = nodeList[index.primaryIndex];
00169 if (node==0)
00170 return false;
00171 if (node->next==0)
00172 {
00173
00174 ClearIndex(index.primaryIndex);
00175 return true;
00176 }
00177 else if (index.secondaryIndex==0)
00178 {
00179
00180 nodeList[index.primaryIndex]=node->next;
00181 RakNet::OP_DELETE(node,file,line);
00182 return true;
00183 }
00184
00185 Node *last=node;
00186 node=node->next;
00187 --index.secondaryIndex;
00188
00189 while (index.secondaryIndex!=0)
00190 {
00191 last=node;
00192 node=node->next;
00193 --index.secondaryIndex;
00194 }
00195
00196
00197 last->next=node->next;
00198
00199 RakNet::OP_DELETE(node,file,line);
00200 return true;
00201 }
00202
00203 template <class data_type, unsigned int HASH_SIZE>
00204 StringKeyedHashIndex StringKeyedHash<data_type, HASH_SIZE>::GetIndexOf(const char *key)
00205 {
00206 if (nodeList==0)
00207 {
00208 StringKeyedHashIndex temp;
00209 temp.SetInvalid();
00210 return temp;
00211 }
00212 StringKeyedHashIndex idx;
00213 idx.primaryIndex=GetHashIndex(key);
00214 Node *node = nodeList[idx.primaryIndex];
00215 if (node==0)
00216 {
00217 idx.SetInvalid();
00218 return idx;
00219 }
00220 idx.secondaryIndex=0;
00221 while (node!=0)
00222 {
00223 if (node->string==key)
00224 {
00225 return idx;
00226 }
00227 node=node->next;
00228 idx.secondaryIndex++;
00229 }
00230
00231 idx.SetInvalid();
00232 return idx;
00233 }
00234
00235 template <class data_type, unsigned int HASH_SIZE>
00236 data_type& StringKeyedHash<data_type, HASH_SIZE>::ItemAtIndex(const StringKeyedHashIndex &index)
00237 {
00238 Node *node = nodeList[index.primaryIndex];
00239 RakAssert(node);
00240 unsigned int i;
00241 for (i=0; i < index.secondaryIndex; i++)
00242 {
00243 node=node->next;
00244 RakAssert(node);
00245 }
00246 return node->data;
00247 }
00248
00249 template <class data_type, unsigned int HASH_SIZE>
00250 RakNet::RakString StringKeyedHash<data_type, HASH_SIZE>::KeyAtIndex(const StringKeyedHashIndex &index)
00251 {
00252 Node *node = nodeList[index.primaryIndex];
00253 RakAssert(node);
00254 unsigned int i;
00255 for (i=0; i < index.secondaryIndex; i++)
00256 {
00257 node=node->next;
00258 RakAssert(node);
00259 }
00260 return node->string;
00261 }
00262
00263 template <class data_type, unsigned int HASH_SIZE>
00264 void StringKeyedHash<data_type, HASH_SIZE>::Clear(const char *file, unsigned int line)
00265 {
00266 if (nodeList)
00267 {
00268 unsigned int i;
00269 for (i=0; i < HASH_SIZE; i++)
00270 ClearIndex(i,file,line);
00271 RakNet::OP_DELETE_ARRAY(nodeList,file,line);
00272 nodeList=0;
00273 }
00274 }
00275
00276 template <class data_type, unsigned int HASH_SIZE>
00277 void StringKeyedHash<data_type, HASH_SIZE>::ClearIndex(unsigned int index,const char *file, unsigned int line)
00278 {
00279 Node *node = nodeList[index];
00280 Node *next;
00281 while (node)
00282 {
00283 next=node->next;
00284 RakNet::OP_DELETE(node,file,line);
00285 node=next;
00286 }
00287 nodeList[index]=0;
00288 }
00289
00290 template <class data_type, unsigned int HASH_SIZE>
00291 void StringKeyedHash<data_type, HASH_SIZE>::GetItemList(DataStructures::List<data_type> &outputList,const char *file, unsigned int line)
00292 {
00293 if (nodeList==0)
00294 return;
00295 outputList.Clear(false,__FILE__,__LINE__);
00296
00297 Node *node;
00298 unsigned int i;
00299 for (i=0; i < HASH_SIZE; i++)
00300 {
00301 if (nodeList[i])
00302 {
00303 node=nodeList[i];
00304 while (node)
00305 {
00306 outputList.Push(node->data,file,line);
00307 node=node->next;
00308 }
00309 }
00310 }
00311 }
00312
00313 template <class data_type, unsigned int HASH_SIZE>
00314 unsigned int StringKeyedHash<data_type, HASH_SIZE>::GetHashIndex(const char *str)
00315 {
00316 return RakNet::RakString::ToInteger(str) % HASH_SIZE;
00317 }
00318 }
00319 #endif