DS_Hash.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. /// \internal
  11. /// \brief Hashing container
  12. ///
  13. #ifndef __HASH_H
  14. #define __HASH_H
  15. #include "RakAssert.h"
  16. #include <string.h> // memmove
  17. #include "Export.h"
  18. #include "RakMemoryOverride.h"
  19. #include "RakString.h"
  20. /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
  21. /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
  22. namespace DataStructures
  23. {
  24. struct HashIndex
  25. {
  26. unsigned int primaryIndex;
  27. unsigned int secondaryIndex;
  28. bool IsInvalid(void) const {return primaryIndex==(unsigned int) -1;}
  29. void SetInvalid(void) {primaryIndex=(unsigned int) -1; secondaryIndex=(unsigned int) -1;}
  30. };
  31. /// \brief Using a string as a identifier for a node, store an allocated pointer to that node
  32. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  33. class RAK_DLL_EXPORT Hash
  34. {
  35. public:
  36. /// Default constructor
  37. Hash();
  38. // Destructor
  39. ~Hash();
  40. void Push(key_type key, const data_type &input, const char *file, unsigned int line );
  41. data_type* Peek(key_type key );
  42. bool Pop(data_type& out, key_type key, const char *file, unsigned int line );
  43. bool RemoveAtIndex(HashIndex index, const char *file, unsigned int line );
  44. bool Remove(key_type key, const char *file, unsigned int line );
  45. HashIndex GetIndexOf(key_type key);
  46. bool HasData(key_type key);
  47. data_type& ItemAtIndex(const HashIndex &index);
  48. key_type KeyAtIndex(const HashIndex &index);
  49. void GetAsList(DataStructures::List<data_type> &itemList,DataStructures::List<key_type > &keyList,const char *file, unsigned int line) const;
  50. unsigned int Size(void) const;
  51. /// \brief Clear the list
  52. void Clear( const char *file, unsigned int line );
  53. struct Node
  54. {
  55. Node(key_type strIn, const data_type &_data) {string=strIn; data=_data;}
  56. key_type string;
  57. data_type data;
  58. // Next in the list for this key
  59. Node *next;
  60. };
  61. protected:
  62. void ClearIndex(unsigned int index,const char *file, unsigned int line);
  63. Node **nodeList;
  64. unsigned int size;
  65. };
  66. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  67. Hash<key_type, data_type, HASH_SIZE, hashFunction>::Hash()
  68. {
  69. nodeList=0;
  70. size=0;
  71. }
  72. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  73. Hash<key_type, data_type, HASH_SIZE, hashFunction>::~Hash()
  74. {
  75. Clear(_FILE_AND_LINE_);
  76. }
  77. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  78. void Hash<key_type, data_type, HASH_SIZE, hashFunction>::Push(key_type key, const data_type &input, const char *file, unsigned int line )
  79. {
  80. unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
  81. if (nodeList==0)
  82. {
  83. nodeList=RakNet::OP_NEW_ARRAY<Node *>(HASH_SIZE,file,line);
  84. memset(nodeList,0,sizeof(Node *)*HASH_SIZE);
  85. }
  86. Node *newNode=RakNet::OP_NEW_2<Node>(file,line,key,input);
  87. newNode->next=nodeList[hashIndex];
  88. nodeList[hashIndex]=newNode;
  89. size++;
  90. }
  91. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  92. data_type* Hash<key_type, data_type, HASH_SIZE, hashFunction>::Peek(key_type key )
  93. {
  94. if (nodeList==0)
  95. return 0;
  96. unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
  97. Node *node = nodeList[hashIndex];
  98. while (node!=0)
  99. {
  100. if (node->string==key)
  101. return &node->data;
  102. node=node->next;
  103. }
  104. return 0;
  105. }
  106. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  107. bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::Pop(data_type& out, key_type key, const char *file, unsigned int line )
  108. {
  109. if (nodeList==0)
  110. return false;
  111. unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
  112. Node *node = nodeList[hashIndex];
  113. if (node==0)
  114. return false;
  115. if (node->next==0)
  116. {
  117. // Only one item.
  118. if (node->string==key)
  119. {
  120. // Delete last item
  121. out=node->data;
  122. ClearIndex(hashIndex,_FILE_AND_LINE_);
  123. return true;
  124. }
  125. else
  126. {
  127. // Single item doesn't match
  128. return false;
  129. }
  130. }
  131. else if (node->string==key)
  132. {
  133. // First item does match, but more than one item
  134. out=node->data;
  135. nodeList[hashIndex]=node->next;
  136. RakNet::OP_DELETE(node,file,line);
  137. size--;
  138. return true;
  139. }
  140. Node *last=node;
  141. node=node->next;
  142. while (node!=0)
  143. {
  144. // First item does not match, but subsequent item might
  145. if (node->string==key)
  146. {
  147. out=node->data;
  148. // Skip over subsequent item
  149. last->next=node->next;
  150. // Delete existing item
  151. RakNet::OP_DELETE(node,file,line);
  152. size--;
  153. return true;
  154. }
  155. last=node;
  156. node=node->next;
  157. }
  158. return false;
  159. }
  160. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  161. bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::RemoveAtIndex(HashIndex index, const char *file, unsigned int line )
  162. {
  163. if (index.IsInvalid())
  164. return false;
  165. Node *node = nodeList[index.primaryIndex];
  166. if (node==0)
  167. return false;
  168. if (node->next==0)
  169. {
  170. // Delete last item
  171. ClearIndex(index.primaryIndex,file,line);
  172. return true;
  173. }
  174. else if (index.secondaryIndex==0)
  175. {
  176. // First item does match, but more than one item
  177. nodeList[index.primaryIndex]=node->next;
  178. RakNet::OP_DELETE(node,file,line);
  179. size--;
  180. return true;
  181. }
  182. Node *last=node;
  183. node=node->next;
  184. --index.secondaryIndex;
  185. while (index.secondaryIndex!=0)
  186. {
  187. last=node;
  188. node=node->next;
  189. --index.secondaryIndex;
  190. }
  191. // Skip over subsequent item
  192. last->next=node->next;
  193. // Delete existing item
  194. RakNet::OP_DELETE(node,file,line);
  195. size--;
  196. return true;
  197. }
  198. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  199. bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::Remove(key_type key, const char *file, unsigned int line )
  200. {
  201. return RemoveAtIndex(GetIndexOf(key),file,line);
  202. }
  203. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  204. HashIndex Hash<key_type, data_type, HASH_SIZE, hashFunction>::GetIndexOf(key_type key)
  205. {
  206. if (nodeList==0)
  207. {
  208. HashIndex temp;
  209. temp.SetInvalid();
  210. return temp;
  211. }
  212. HashIndex idx;
  213. idx.primaryIndex=(*hashFunction)(key) % HASH_SIZE;
  214. Node *node = nodeList[idx.primaryIndex];
  215. if (node==0)
  216. {
  217. idx.SetInvalid();
  218. return idx;
  219. }
  220. idx.secondaryIndex=0;
  221. while (node!=0)
  222. {
  223. if (node->string==key)
  224. {
  225. return idx;
  226. }
  227. node=node->next;
  228. idx.secondaryIndex++;
  229. }
  230. idx.SetInvalid();
  231. return idx;
  232. }
  233. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  234. bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::HasData(key_type key)
  235. {
  236. return GetIndexOf(key).IsInvalid()==false;
  237. }
  238. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  239. data_type& Hash<key_type, data_type, HASH_SIZE, hashFunction>::ItemAtIndex(const HashIndex &index)
  240. {
  241. Node *node = nodeList[index.primaryIndex];
  242. RakAssert(node);
  243. unsigned int i;
  244. for (i=0; i < index.secondaryIndex; i++)
  245. {
  246. node=node->next;
  247. RakAssert(node);
  248. }
  249. return node->data;
  250. }
  251. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  252. key_type Hash<key_type, data_type, HASH_SIZE, hashFunction>::KeyAtIndex(const HashIndex &index)
  253. {
  254. Node *node = nodeList[index.primaryIndex];
  255. RakAssert(node);
  256. unsigned int i;
  257. for (i=0; i < index.secondaryIndex; i++)
  258. {
  259. node=node->next;
  260. RakAssert(node);
  261. }
  262. return node->string;
  263. }
  264. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  265. void Hash<key_type, data_type, HASH_SIZE, hashFunction>::Clear(const char *file, unsigned int line)
  266. {
  267. if (nodeList)
  268. {
  269. unsigned int i;
  270. for (i=0; i < HASH_SIZE; i++)
  271. ClearIndex(i,file,line);
  272. RakNet::OP_DELETE_ARRAY(nodeList,file,line);
  273. nodeList=0;
  274. size=0;
  275. }
  276. }
  277. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  278. void Hash<key_type, data_type, HASH_SIZE, hashFunction>::ClearIndex(unsigned int index,const char *file, unsigned int line)
  279. {
  280. Node *node = nodeList[index];
  281. Node *next;
  282. while (node)
  283. {
  284. next=node->next;
  285. RakNet::OP_DELETE(node,file,line);
  286. node=next;
  287. size--;
  288. }
  289. nodeList[index]=0;
  290. }
  291. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  292. 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
  293. {
  294. if (nodeList==0)
  295. return;
  296. itemList.Clear(false,_FILE_AND_LINE_);
  297. keyList.Clear(false,_FILE_AND_LINE_);
  298. Node *node;
  299. unsigned int i;
  300. for (i=0; i < HASH_SIZE; i++)
  301. {
  302. if (nodeList[i])
  303. {
  304. node=nodeList[i];
  305. while (node)
  306. {
  307. itemList.Push(node->data,file,line);
  308. keyList.Push(node->string,file,line);
  309. node=node->next;
  310. }
  311. }
  312. }
  313. }
  314. template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
  315. unsigned int Hash<key_type, data_type, HASH_SIZE, hashFunction>::Size(void) const
  316. {
  317. return size;
  318. }
  319. }
  320. #endif
粤ICP备19079148号