• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

DS_StringKeyedHash.h

Go to the documentation of this file.
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> // memmove
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                 // Destructor
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                         // Next in the list for this key
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                         // Only one item.
00119                         if (node->string==key)
00120                         {
00121                                 // Delete last item
00122                                 out=node->data;
00123                                 ClearIndex(hashIndex,__FILE__,__LINE__);
00124                                 return true;
00125                         }
00126                         else
00127                         {
00128                                 // Single item doesn't match
00129                                 return false;
00130                         }
00131                 }
00132                 else if (node->string==key)
00133                 {
00134                         // First item does match, but more than one item
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                         // First item does not match, but subsequent item might
00147                         if (node->string==key)
00148                         {
00149                                 out=node->data;
00150                                 // Skip over subsequent item
00151                                 last->next=node->next;
00152                                 // Delete existing item
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                         // Delete last item
00174                         ClearIndex(index.primaryIndex);
00175                         return true;
00176                 }
00177                 else if (index.secondaryIndex==0)
00178                 {
00179                         // First item does match, but more than one item
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                 // Skip over subsequent item
00197                 last->next=node->next;
00198                 // Delete existing item
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

Generated on Thu Sep 30 2010 01:27:23 for RakNet by  doxygen 1.7.1