SLikeNet 0.1.3

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DS_Hash.h
Go to the documentation of this file.
1 /*
2 * Original work: 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 * RakNet License.txt file in the licenses directory of this source tree. An additional grant
7 * of patent rights can be found in the RakNet Patents.txt file in the same directory.
8 *
9 *
10 * Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
11 *
12 * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
13 * license found in the license.txt file in the root directory of this source tree.
14 */
15
19
20
21 #ifndef __HASH_H
22 #define __HASH_H
23
24 #include "assert.h"
25 #include <string.h> // memmove
26 #include "Export.h"
27 #include "memoryoverride.h"
28 #include "string.h"
29
32 namespace DataStructures
33 {
34 struct HashIndex
35 {
36 unsigned int primaryIndex;
37 unsigned int secondaryIndex;
38 bool IsInvalid(void) const {return primaryIndex==(unsigned int) -1;}
39 void SetInvalid(void) {primaryIndex=(unsigned int) -1; secondaryIndex=(unsigned int) -1;}
40 };
41
43 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
44 class RAK_DLL_EXPORT Hash
45 {
46 public:
48 Hash();
49
50 // Destructor
51 ~Hash();
52
53 void Push(key_type key, const data_type &input, const char *file, unsigned int line );
54 data_type* Peek(key_type key );
55 bool Pop(data_type& out, key_type key, const char *file, unsigned int line );
56 bool RemoveAtIndex(HashIndex index, const char *file, unsigned int line );
57 bool Remove(key_type key, const char *file, unsigned int line );
58 HashIndex GetIndexOf(key_type key);
59 bool HasData(key_type key);
60 data_type& ItemAtIndex(const HashIndex &index);
61 key_type KeyAtIndex(const HashIndex &index);
62 void GetAsList(DataStructures::List<data_type> &itemList,DataStructures::List<key_type > &keyList,const char *file, unsigned int line) const;
63 unsigned int Size(void) const;
64
66 void Clear( const char *file, unsigned int line );
67
68 struct Node
69 {
70 Node(key_type strIn, const data_type &_data) {string=strIn; data=_data;}
71 key_type string;
72 data_type data;
73 // Next in the list for this key
74 Node *next;
75 };
76
77 protected:
78 void ClearIndex(unsigned int index,const char *file, unsigned int line);
79 Node **nodeList;
80 unsigned int size;
81 };
82
83 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
84 Hash<key_type, data_type, HASH_SIZE, hashFunction>::Hash()
85 {
86 nodeList=0;
87 size=0;
88 }
89
90 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
91 Hash<key_type, data_type, HASH_SIZE, hashFunction>::~Hash()
92 {
93 Clear(_FILE_AND_LINE_);
94 }
95
96 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
97 void Hash<key_type, data_type, HASH_SIZE, hashFunction>::Push(key_type key, const data_type &input, const char *file, unsigned int line )
98 {
99 unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
100 if (nodeList==0)
101 {
102 nodeList= SLNet::OP_NEW_ARRAY<Node *>(HASH_SIZE,file,line);
103 memset(nodeList,0,sizeof(Node *)*HASH_SIZE);
104 }
105
106 Node *newNode= SLNet::OP_NEW_2<Node>(file,line,key,input);
107 newNode->next=nodeList[hashIndex];
108 nodeList[hashIndex]=newNode;
109
110 size++;
111 }
112
113 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
114 data_type* Hash<key_type, data_type, HASH_SIZE, hashFunction>::Peek(key_type key )
115 {
116 if (nodeList==0)
117 return 0;
118
119 unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
120 Node *node = nodeList[hashIndex];
121 while (node!=0)
122 {
123 if (node->string==key)
124 return &node->data;
125 node=node->next;
126 }
127 return 0;
128 }
129
130 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
131 bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::Pop(data_type& out, key_type key, const char *file, unsigned int line )
132 {
133 if (nodeList==0)
134 return false;
135
136 unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
137 Node *node = nodeList[hashIndex];
138 if (node==0)
139 return false;
140 if (node->next==0)
141 {
142 // Only one item.
143 if (node->string==key)
144 {
145 // Delete last item
146 out=node->data;
147 ClearIndex(hashIndex,_FILE_AND_LINE_);
148 return true;
149 }
150 else
151 {
152 // Single item doesn't match
153 return false;
154 }
155 }
156 else if (node->string==key)
157 {
158 // First item does match, but more than one item
159 out=node->data;
160 nodeList[hashIndex]=node->next;
161 SLNet::OP_DELETE(node,file,line);
162 size--;
163 return true;
164 }
165
166 Node *last=node;
167 node=node->next;
168
169 while (node!=0)
170 {
171 // First item does not match, but subsequent item might
172 if (node->string==key)
173 {
174 out=node->data;
175 // Skip over subsequent item
176 last->next=node->next;
177 // Delete existing item
178 SLNet::OP_DELETE(node,file,line);
179 size--;
180 return true;
181 }
182 last=node;
183 node=node->next;
184 }
185 return false;
186 }
187
188 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
189 bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::RemoveAtIndex(HashIndex index, const char *file, unsigned int line )
190 {
191 if (index.IsInvalid())
192 return false;
193
194 Node *node = nodeList[index.primaryIndex];
195 if (node==0)
196 return false;
197 if (node->next==0)
198 {
199 // Delete last item
200 ClearIndex(index.primaryIndex,file,line);
201 return true;
202 }
203 else if (index.secondaryIndex==0)
204 {
205 // First item does match, but more than one item
206 nodeList[index.primaryIndex]=node->next;
207 SLNet::OP_DELETE(node,file,line);
208 size--;
209 return true;
210 }
211
212 Node *last=node;
213 node=node->next;
214 --index.secondaryIndex;
215
216 while (index.secondaryIndex!=0)
217 {
218 last=node;
219 node=node->next;
220 --index.secondaryIndex;
221 }
222
223 // Skip over subsequent item
224 last->next=node->next;
225 // Delete existing item
226 SLNet::OP_DELETE(node,file,line);
227 size--;
228 return true;
229 }
230
231 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
232 bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::Remove(key_type key, const char *file, unsigned int line )
233 {
234 return RemoveAtIndex(GetIndexOf(key),file,line);
235 }
236
237 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
238 HashIndex Hash<key_type, data_type, HASH_SIZE, hashFunction>::GetIndexOf(key_type key)
239 {
240 if (nodeList==0)
241 {
242 HashIndex temp;
243 temp.SetInvalid();
244 return temp;
245 }
246 HashIndex idx;
247 idx.primaryIndex=(*hashFunction)(key) % HASH_SIZE;
248 Node *node = nodeList[idx.primaryIndex];
249 if (node==0)
250 {
251 idx.SetInvalid();
252 return idx;
253 }
254 idx.secondaryIndex=0;
255 while (node!=0)
256 {
257 if (node->string==key)
258 {
259 return idx;
260 }
261 node=node->next;
262 idx.secondaryIndex++;
263 }
264
265 idx.SetInvalid();
266 return idx;
267 }
268
269 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
270 bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::HasData(key_type key)
271 {
272 return GetIndexOf(key).IsInvalid()==false;
273 }
274
275 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
276 data_type& Hash<key_type, data_type, HASH_SIZE, hashFunction>::ItemAtIndex(const HashIndex &index)
277 {
278 Node *node = nodeList[index.primaryIndex];
279 RakAssert(node);
280 unsigned int i;
281 for (i=0; i < index.secondaryIndex; i++)
282 {
283 node=node->next;
284 RakAssert(node);
285 }
286 return node->data;
287 }
288
289 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
290 key_type Hash<key_type, data_type, HASH_SIZE, hashFunction>::KeyAtIndex(const HashIndex &index)
291 {
292 Node *node = nodeList[index.primaryIndex];
293 RakAssert(node);
294 unsigned int i;
295 for (i=0; i < index.secondaryIndex; i++)
296 {
297 node=node->next;
298 RakAssert(node);
299 }
300 return node->string;
301 }
302
303 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
304 void Hash<key_type, data_type, HASH_SIZE, hashFunction>::Clear(const char *file, unsigned int line)
305 {
306 if (nodeList)
307 {
308 unsigned int i;
309 for (i=0; i < HASH_SIZE; i++)
310 ClearIndex(i,file,line);
311 SLNet::OP_DELETE_ARRAY(nodeList,file,line);
312 nodeList=0;
313 size=0;
314 }
315 }
316
317 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
318 void Hash<key_type, data_type, HASH_SIZE, hashFunction>::ClearIndex(unsigned int index,const char *file, unsigned int line)
319 {
320 Node *node = nodeList[index];
321 Node *next;
322 while (node)
323 {
324 next=node->next;
325 SLNet::OP_DELETE(node,file,line);
326 node=next;
327 size--;
328 }
329 nodeList[index]=0;
330 }
331
332 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
333 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
334 {
335 if (nodeList==0)
336 return;
337 itemList.Clear(false,_FILE_AND_LINE_);
338 keyList.Clear(false,_FILE_AND_LINE_);
339
340 Node *node;
341 unsigned int i;
342 for (i=0; i < HASH_SIZE; i++)
343 {
344 if (nodeList[i])
345 {
346 node=nodeList[i];
347 while (node)
348 {
349 itemList.Push(node->data,file,line);
350 keyList.Push(node->string,file,line);
351 node=node->next;
352 }
353 }
354 }
355 }
356 template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
357 unsigned int Hash<key_type, data_type, HASH_SIZE, hashFunction>::Size(void) const
358 {
359 return size;
360 }
361 }
362 #endif