| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- /*
- * Copyright (c) 2014, Oculus VR, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- */
- /// \internal
- /// \brief Hashing container
- ///
- #ifndef __HASH_H
- #define __HASH_H
- #include "RakAssert.h"
- #include <string.h> // memmove
- #include "Export.h"
- #include "RakMemoryOverride.h"
- #include "RakString.h"
- /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
- /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
- namespace DataStructures
- {
- struct HashIndex
- {
- unsigned int primaryIndex;
- unsigned int secondaryIndex;
- bool IsInvalid(void) const {return primaryIndex==(unsigned int) -1;}
- void SetInvalid(void) {primaryIndex=(unsigned int) -1; secondaryIndex=(unsigned int) -1;}
- };
- /// \brief Using a string as a identifier for a node, store an allocated pointer to that node
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- class RAK_DLL_EXPORT Hash
- {
- public:
- /// Default constructor
- Hash();
- // Destructor
- ~Hash();
- void Push(key_type key, const data_type &input, const char *file, unsigned int line );
- data_type* Peek(key_type key );
- bool Pop(data_type& out, key_type key, const char *file, unsigned int line );
- bool RemoveAtIndex(HashIndex index, const char *file, unsigned int line );
- bool Remove(key_type key, const char *file, unsigned int line );
- HashIndex GetIndexOf(key_type key);
- bool HasData(key_type key);
- data_type& ItemAtIndex(const HashIndex &index);
- key_type KeyAtIndex(const HashIndex &index);
- void GetAsList(DataStructures::List<data_type> &itemList,DataStructures::List<key_type > &keyList,const char *file, unsigned int line) const;
- unsigned int Size(void) const;
- /// \brief Clear the list
- void Clear( const char *file, unsigned int line );
- struct Node
- {
- Node(key_type strIn, const data_type &_data) {string=strIn; data=_data;}
- key_type string;
- data_type data;
- // Next in the list for this key
- Node *next;
- };
- protected:
- void ClearIndex(unsigned int index,const char *file, unsigned int line);
- Node **nodeList;
- unsigned int size;
- };
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- Hash<key_type, data_type, HASH_SIZE, hashFunction>::Hash()
- {
- nodeList=0;
- size=0;
- }
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- Hash<key_type, data_type, HASH_SIZE, hashFunction>::~Hash()
- {
- Clear(_FILE_AND_LINE_);
- }
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- void Hash<key_type, data_type, HASH_SIZE, hashFunction>::Push(key_type key, const data_type &input, const char *file, unsigned int line )
- {
- unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
- if (nodeList==0)
- {
- nodeList=RakNet::OP_NEW_ARRAY<Node *>(HASH_SIZE,file,line);
- memset(nodeList,0,sizeof(Node *)*HASH_SIZE);
- }
- Node *newNode=RakNet::OP_NEW_2<Node>(file,line,key,input);
- newNode->next=nodeList[hashIndex];
- nodeList[hashIndex]=newNode;
- size++;
- }
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- data_type* Hash<key_type, data_type, HASH_SIZE, hashFunction>::Peek(key_type key )
- {
- if (nodeList==0)
- return 0;
- unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
- Node *node = nodeList[hashIndex];
- while (node!=0)
- {
- if (node->string==key)
- return &node->data;
- node=node->next;
- }
- return 0;
- }
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::Pop(data_type& out, key_type key, const char *file, unsigned int line )
- {
- if (nodeList==0)
- return false;
- unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
- Node *node = nodeList[hashIndex];
- if (node==0)
- return false;
- if (node->next==0)
- {
- // Only one item.
- if (node->string==key)
- {
- // Delete last item
- out=node->data;
- ClearIndex(hashIndex,_FILE_AND_LINE_);
- return true;
- }
- else
- {
- // Single item doesn't match
- return false;
- }
- }
- else if (node->string==key)
- {
- // First item does match, but more than one item
- out=node->data;
- nodeList[hashIndex]=node->next;
- RakNet::OP_DELETE(node,file,line);
- size--;
- return true;
- }
- Node *last=node;
- node=node->next;
- while (node!=0)
- {
- // First item does not match, but subsequent item might
- if (node->string==key)
- {
- out=node->data;
- // Skip over subsequent item
- last->next=node->next;
- // Delete existing item
- RakNet::OP_DELETE(node,file,line);
- size--;
- return true;
- }
- last=node;
- node=node->next;
- }
- return false;
- }
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::RemoveAtIndex(HashIndex index, const char *file, unsigned int line )
- {
- if (index.IsInvalid())
- return false;
- Node *node = nodeList[index.primaryIndex];
- if (node==0)
- return false;
- if (node->next==0)
- {
- // Delete last item
- ClearIndex(index.primaryIndex,file,line);
- return true;
- }
- else if (index.secondaryIndex==0)
- {
- // First item does match, but more than one item
- nodeList[index.primaryIndex]=node->next;
- RakNet::OP_DELETE(node,file,line);
- size--;
- return true;
- }
- Node *last=node;
- node=node->next;
- --index.secondaryIndex;
- while (index.secondaryIndex!=0)
- {
- last=node;
- node=node->next;
- --index.secondaryIndex;
- }
- // Skip over subsequent item
- last->next=node->next;
- // Delete existing item
- RakNet::OP_DELETE(node,file,line);
- size--;
- return true;
- }
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::Remove(key_type key, const char *file, unsigned int line )
- {
- return RemoveAtIndex(GetIndexOf(key),file,line);
- }
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- HashIndex Hash<key_type, data_type, HASH_SIZE, hashFunction>::GetIndexOf(key_type key)
- {
- if (nodeList==0)
- {
- HashIndex temp;
- temp.SetInvalid();
- return temp;
- }
- HashIndex idx;
- idx.primaryIndex=(*hashFunction)(key) % HASH_SIZE;
- Node *node = nodeList[idx.primaryIndex];
- if (node==0)
- {
- idx.SetInvalid();
- return idx;
- }
- idx.secondaryIndex=0;
- while (node!=0)
- {
- if (node->string==key)
- {
- return idx;
- }
- node=node->next;
- idx.secondaryIndex++;
- }
- idx.SetInvalid();
- return idx;
- }
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::HasData(key_type key)
- {
- return GetIndexOf(key).IsInvalid()==false;
- }
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- data_type& Hash<key_type, data_type, HASH_SIZE, hashFunction>::ItemAtIndex(const HashIndex &index)
- {
- Node *node = nodeList[index.primaryIndex];
- RakAssert(node);
- unsigned int i;
- for (i=0; i < index.secondaryIndex; i++)
- {
- node=node->next;
- RakAssert(node);
- }
- return node->data;
- }
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- key_type Hash<key_type, data_type, HASH_SIZE, hashFunction>::KeyAtIndex(const HashIndex &index)
- {
- Node *node = nodeList[index.primaryIndex];
- RakAssert(node);
- unsigned int i;
- for (i=0; i < index.secondaryIndex; i++)
- {
- node=node->next;
- RakAssert(node);
- }
- return node->string;
- }
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- void Hash<key_type, data_type, HASH_SIZE, hashFunction>::Clear(const char *file, unsigned int line)
- {
- if (nodeList)
- {
- unsigned int i;
- for (i=0; i < HASH_SIZE; i++)
- ClearIndex(i,file,line);
- RakNet::OP_DELETE_ARRAY(nodeList,file,line);
- nodeList=0;
- size=0;
- }
- }
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- void Hash<key_type, data_type, HASH_SIZE, hashFunction>::ClearIndex(unsigned int index,const char *file, unsigned int line)
- {
- Node *node = nodeList[index];
- Node *next;
- while (node)
- {
- next=node->next;
- RakNet::OP_DELETE(node,file,line);
- node=next;
- size--;
- }
- nodeList[index]=0;
- }
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- void Hash<key_type, data_type, HASH_SIZE, hashFunction>::GetAsList(DataStructures::List<data_type> &itemList,DataStructures::List<key_type > &keyList,const char *file, unsigned int line) const
- {
- if (nodeList==0)
- return;
- itemList.Clear(false,_FILE_AND_LINE_);
- keyList.Clear(false,_FILE_AND_LINE_);
- Node *node;
- unsigned int i;
- for (i=0; i < HASH_SIZE; i++)
- {
- if (nodeList[i])
- {
- node=nodeList[i];
- while (node)
- {
- itemList.Push(node->data,file,line);
- keyList.Push(node->string,file,line);
- node=node->next;
- }
- }
- }
- }
- template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
- unsigned int Hash<key_type, data_type, HASH_SIZE, hashFunction>::Size(void) const
- {
- return size;
- }
- }
- #endif
|