Stun Server  Compliant with the latest RFCs including 5389, 5769, and 5780
discover the local host's own external IP address
fasthash.h
Go to the documentation of this file.
1 /*
2  Copyright 2011 John Selbie
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 #ifndef FASTHASH_H
18 #define FASTHASH_H
19 
20 // FastHash is a cheap and dirty hash table template class
21 // It is "fast" because it never allocates memory beyond the static arrays inside each instance
22 // Hence, it can be used off the stack or in cases where memory allocations impact performance
23 // Limitations:
24 // Fixed number of insertions (specified by FSIZE)
25 // Made for simple types and structs of simple types - as items are pre-allocated (no regards to constructors or destructors)
26 // Duplicate key insertions will not remove the previous item
27 // Template parameters
28 // K = key type
29 // V = value type
30 // FSIZE = max number of items in the hash table (default is 100)
31 // TSIZE = hash table width (higher value reduces collisions, but with extra memory overhead - default is 37). Usually a prime number.
32 
33 // FastHashDynamic is similar to FastHash, except it will "new" all the memory in the constructor and "delete" it in the destructor
34 
35 // Use FastHash when the maximum number of elements in the hash table is known at compile time
36 
37 
38 size_t FastHash_GetHashTableWidth(unsigned int maxItems);
39 
40 
41 inline size_t FastHash_Hash(void* ptr)
42 {
43  return (size_t)ptr;
44 }
45 inline size_t FastHash_Hash(unsigned int x)
46 {
47  return (size_t)x;
48 }
49 inline size_t FastHash_Hash(signed int x)
50 {
51  return (size_t)x;
52 }
53 
54 
55 template <typename K, typename V>
57 {
58 
59 public:
60  struct Item
61  {
62  K key;
63  V value;
64  };
65 
66 protected:
67 
68 
69  struct ItemNode
70  {
71  int index;
73  };
74 
75  typedef ItemNode* ItemNodePtr;
76 
77  size_t _fsize; // max number of items the table can hold
78  size_t _tsize; // number of table columns (length of lookuptable)
79 
80  Item* _nodes; // array of key/value pair instances, size==fsize
81  ItemNode* _itemnodes; // array of ItemNode instances, size==fsize
82  ItemNode* _freelist;
83  ItemNodePtr* _lookuptable; // hash table (array of size tsize of ItemNode*)
84 
85  // for iterators and fast lookup by index
86  int* _indexlist; // array of index values, size==fsize
88  size_t _indexStart; // _indexList is a circular array
89 
90  size_t _size;
91 
92  // disable copy constructor and bad overloads
94  FastHashBase& operator=(const FastHashBase&) {return *this;}
95  bool operator==(const FastHashBase&) {return false;}
96 
97 
98 
99  ItemNode* Find(const K& key, size_t* pHashIndex=NULL, ItemNode** ppPrev=NULL)
100  {
101  size_t hashindex = ((size_t)(FastHash_Hash(key))) % _tsize;
102  ItemNode* pPrev = NULL;
103  ItemNode* pProbe = _lookuptable[hashindex];
104  while (pProbe)
105  {
106  if (_nodes[pProbe->index].key == key)
107  {
108  break;
109  }
110  pPrev = pProbe;
111  pProbe = pProbe->pNext;
112  }
113 
114  if (pHashIndex)
115  {
116  *pHashIndex = hashindex;
117  }
118 
119  if (ppPrev)
120  {
121  *ppPrev = pPrev;
122  }
123 
124  return pProbe;
125  }
126 
127 
128  void ReIndex()
129  {
130  int index = 0;
131 
132  if ((_indexlist == NULL) || (_size == 0))
133  {
134  return;
135  }
136 
137  for (size_t t = 0; t < _tsize; t++)
138  {
139  ItemNode* pNode = _lookuptable[t];
140  while (pNode)
141  {
142  _indexlist[index] = pNode->index;
143  index++;
144  pNode = pNode->pNext;
145  }
146  }
147 
148  _fIndexValid = true;
149  _indexStart = 0;
150  }
151 
152  void UpdateIndexWithAdd(ItemNode* pNode)
153  {
154  // this method is called before _size is incremented
155  // ASSERT( _size < _fsize)
156 
157 
158  if (_fIndexValid && (_size < _fsize) && _indexlist)
159  {
160  size_t pos = (_size + _indexStart) % _fsize;
161 
162  _indexlist[pos] = pNode->index;
163  }
164  }
165 
166  void UpdateIndexWithRemove(ItemNode* pNode)
167  {
168  // this method is called before size is decremented
169  // ASSERT(_size > 0)
170 
171  // if size is 0, then that's an error
172  // if there is no indexlist, then just bail
173  if ( (_size == 0) ||
174  (_indexlist == NULL) ||
175  ((_size > 1) && (_fIndexValid==false)))
176  {
177  return;
178  }
179 
180  // the list is always valid again when the table goes empty
181  if (_size == 1)
182  {
183  _fIndexValid = true;
184  _indexStart = 0;
185  return;
186  }
187 
188  // If the item being removed is from the front or end of the index, then nothing to do
189  if (pNode->index == _indexlist[_indexStart])
190  {
191  _indexStart = (_indexStart + 1) % _fsize;
192  return;
193  }
194 
195  size_t indexlast = (_indexStart + (_size-1)) % _fsize;
196  if (pNode->index == _indexlist[indexlast])
197  {
198  return;
199  }
200 
201  // otherwise, we're removing an item from the middle - the index is now invalid
202  // I suppose we could do a memmove, but then that creates other perf issues
203  _fIndexValid = false;
204  }
205 
206 
207 
208 public:
209 
211  {
212  Init(0, 0, NULL, NULL, NULL, NULL);
213  }
214 
215 
216  FastHashBase(size_t fsize, size_t tsize, Item* nodelist, ItemNode* itemnodelist, ItemNode** table, int* indexlist)
217  {
218  Init(fsize, tsize, nodelist, itemnodelist, table, indexlist);
219  }
220 
221  void Init(size_t fsize, size_t tsize, Item* nodelist, ItemNode* itemnodelist, ItemNode** table, int* indexlist)
222  {
223 
224  _fsize = fsize;
225  _tsize = tsize;
226 
227  _nodes = nodelist;
228  _itemnodes = itemnodelist;
229  _freelist = NULL;
230  _lookuptable = table;
231  _indexlist = indexlist;
232  _fIndexValid = (_indexlist != NULL);
233  _indexStart = 0;
234 
235  Reset();
236 
237  }
238 
239  void Reset()
240  {
241  if (_lookuptable != NULL)
242  {
243  memset(_lookuptable, '\0', sizeof(ItemNodePtr)*_tsize);
244  }
245 
246  if ((_fsize > 0) && (_itemnodes != NULL))
247  {
248  for (size_t x = 0; x < _fsize; x++)
249  {
250  _itemnodes[x].pNext = &_itemnodes[x+1];
251  _itemnodes[x].index = x;
252  }
253 
254  _itemnodes[_fsize-1].pNext = NULL;
255  }
256 
257  _freelist = _itemnodes;
258  _size = 0;
259 
260  _fIndexValid = (_indexlist != NULL); // index is valid when we are empty
261  _indexStart = 0;
262  }
263 
264  bool IsValid()
265  {
266  return ((_tsize > 0) && (_fsize > 0) && (_itemnodes != NULL) && (_lookuptable != NULL) && (_nodes != NULL));
267  }
268 
269  size_t Size()
270  {
271  return _size;
272  }
273 
274  size_t GetMaxCapacity()
275  {
276  return _fsize;
277  }
278 
279  size_t GetTableWidth()
280  {
281  return _tsize;
282  }
283 
284  int Insert(const K& key, V& value)
285  {
286  size_t hashindex = FastHash_Hash(key) % _tsize;
287  ItemNode* pInsert = NULL;
288  ItemNode* pHead = _lookuptable[hashindex];
289  Item* pItem = NULL;
290 
291  if (_freelist == NULL)
292  {
293  return -1;
294  }
295 
296  pInsert = _freelist;
297  _freelist = _freelist->pNext;
298 
299  pItem = &_nodes[pInsert->index];
300 
301  pItem->key = key;
302  pItem->value = value;
303 
304  pInsert->pNext = pHead;
305 
306  _lookuptable[hashindex]= pInsert;
307 
308  UpdateIndexWithAdd(pInsert);
309 
310  _size++;
311 
312 
313  return 1;
314  }
315 
316  int Remove(const K& key)
317  {
318  size_t hashindex;
319 
320  ItemNode* pPrev = NULL;
321  ItemNode* pNode = Find(key, &hashindex, &pPrev);
322  ItemNode* pNext = NULL;
323 
324  if (pNode == NULL)
325  {
326  return -1;
327  }
328 
329  pNext = pNode->pNext;
330 
331  if (pPrev == NULL)
332  {
333  _lookuptable[hashindex] = pNext;
334  }
335 
336  if (pPrev)
337  {
338  pPrev->pNext = pNext;
339  }
340 
341  UpdateIndexWithRemove(pNode);
342 
343  pNode->pNext = _freelist;
344  _freelist = pNode;
345 
346  _size--;
347 
348  return 1;
349  }
350 
351  V* Lookup(const K& key)
352  {
353  V* pValue = NULL;
354  ItemNode* pNode = Find(key);
355  if (pNode)
356  {
357  Item* pItem = &(_nodes[pNode->index]);
358  pValue = &(pItem->value);
359  }
360  return pValue;
361  }
362 
363  bool Exists(const K& key)
364  {
365  return (Find(key) != NULL);
366  }
367 
368  Item* LookupByIndex(size_t index)
369  {
370  int itemindex;
371  int indexadjusted;
372 
373  if ((index >= _size) || (_indexlist == NULL))
374  {
375  return NULL;
376  }
377 
378  if (_fIndexValid == false)
379  {
380  ReIndex();
381  if (_fIndexValid == false)
382  {
383  return NULL;
384  }
385  }
386 
387  indexadjusted = (_indexStart + index) % _fsize;
388  itemindex = _indexlist[indexadjusted];
389  return &(_nodes[itemindex]);
390  }
391 
392  V* LookupValueByIndex(size_t index)
393  {
394  Item* pItem = LookupByIndex(index);
395  return pItem ? &pItem->value : NULL;
396  }
397 
398 };
399 
400 
401 template <typename K, typename V, size_t FSIZE=100, size_t TSIZE=37>
402 class FastHash : public FastHashBase<K, V>
403 {
404 public:
405  typedef typename FastHashBase<K,V>::Item Item;
406 
407 protected:
408  // disable copy constructor and bad overloads
409  FastHash(const FastHash&) {;}
410  FastHash& operator=(const FastHash&) {return *this;}
411  bool operator==(const FastHash&) {return false;}
412 
415 
416  Item _nodesarray[FSIZE];
417  ItemNodePtr _lookuptablearray[TSIZE];
418  ItemNode _itemnodesarray[FSIZE];
419  int _indexarray[FSIZE];
420 
421 public:
423  FastHashBase<K,V>(FSIZE, TSIZE, _nodesarray, _itemnodesarray, _lookuptablearray, _indexarray)
424  {
425  COMPILE_TIME_ASSERT(FSIZE > 0);
426  COMPILE_TIME_ASSERT(TSIZE > 0);
427 
428  }
429 };
430 
431 template <class K, class V>
432 class FastHashDynamic : public FastHashBase<K,V>
433 {
434 public:
435  typedef typename FastHashBase<K,V>::Item Item;
436 
437 protected:
438  Item* _nodesarray; // array of ItemNode instances, size==fsize
439 
442 
443  ItemNode* _itemnodesarray; // array of ItemNode instances, size==fsize
444  ItemNodePtr* _lookuptablearray; // hash table (array of size tsize of ItemNode*)
446 
447 public:
448 
450  _nodesarray(NULL),
451  _itemnodesarray(NULL),
452  _lookuptablearray(NULL),
453  _indexarray(NULL)
454  {
455  }
456 
457  FastHashDynamic(size_t fsize, size_t tsize) :
458  _nodesarray(NULL),
459  _itemnodesarray(NULL),
460  _lookuptablearray(NULL),
461  _indexarray(NULL)
462  {
463  InitTable(fsize, tsize);
464  }
465 
467  {
468  ResetTable();
469  }
470 
471  int InitTable(size_t fsize, size_t tsize)
472  {
473 
474  if (fsize <= 0)
475  {
476  return -1;
477  }
478 
479  if (tsize == 0)
480  {
481  tsize = FastHash_GetHashTableWidth(fsize);
482  }
483 
484  ResetTable();
485 
486  _nodesarray = new Item[fsize];
487  _itemnodesarray = new ItemNode[fsize];
488  _lookuptablearray = new ItemNodePtr[tsize];
489  _indexarray = new int[fsize];
490 
491  if ((_nodesarray == NULL) || (_itemnodesarray == NULL) || (_lookuptablearray == NULL) || (_indexarray==NULL))
492  {
493  ResetTable();
494  return -1;
495  }
496 
497  this->Init(fsize, tsize, _nodesarray, _itemnodesarray, _lookuptablearray, _indexarray);
498  return 1;
499  }
500 
501  void ResetTable()
502  {
503  delete [] _nodesarray;
504  _nodesarray = NULL;
505 
506  delete [] _itemnodesarray;
507  _itemnodesarray = NULL;
508 
509  delete [] _lookuptablearray;
510  _lookuptablearray = NULL;
511 
512  delete [] _indexarray;
513  _indexarray = NULL;
514 
515  this->Init(0,0, NULL, NULL, NULL, NULL);
516  }
517 
518 
519 };
520 
521 
522 
523 
524 #endif
FastHashBase & operator=(const FastHashBase &)
Definition: fasthash.h:94
int * _indexlist
Definition: fasthash.h:86
size_t _size
Definition: fasthash.h:90
size_t _tsize
Definition: fasthash.h:78
FastHashBase< K, V >::ItemNode ItemNode
Definition: fasthash.h:440
void ReIndex()
Definition: fasthash.h:128
bool Exists(const K &key)
Definition: fasthash.h:363
void Reset()
Definition: fasthash.h:239
void UpdateIndexWithAdd(ItemNode *pNode)
Definition: fasthash.h:152
size_t GetMaxCapacity()
Definition: fasthash.h:274
int * _indexarray
Definition: fasthash.h:445
Item * _nodes
Definition: fasthash.h:80
size_t GetTableWidth()
Definition: fasthash.h:279
int Insert(const K &key, V &value)
Definition: fasthash.h:284
FastHashBase< K, V >::ItemNode ItemNode
Definition: fasthash.h:413
size_t FastHash_Hash(void *ptr)
Definition: fasthash.h:41
bool _fIndexValid
Definition: fasthash.h:87
FastHashDynamic(size_t fsize, size_t tsize)
Definition: fasthash.h:457
V * LookupValueByIndex(size_t index)
Definition: fasthash.h:392
FastHashBase(size_t fsize, size_t tsize, Item *nodelist, ItemNode *itemnodelist, ItemNode **table, int *indexlist)
Definition: fasthash.h:216
void UpdateIndexWithRemove(ItemNode *pNode)
Definition: fasthash.h:166
Item * LookupByIndex(size_t index)
Definition: fasthash.h:368
void Init(size_t fsize, size_t tsize, Item *nodelist, ItemNode *itemnodelist, ItemNode **table, int *indexlist)
Definition: fasthash.h:221
void ResetTable()
Definition: fasthash.h:501
ItemNode * Find(const K &key, size_t *pHashIndex=NULL, ItemNode **ppPrev=NULL)
Definition: fasthash.h:99
ItemNode * _freelist
Definition: fasthash.h:82
size_t _fsize
Definition: fasthash.h:77
FastHash & operator=(const FastHash &)
Definition: fasthash.h:410
V * Lookup(const K &key)
Definition: fasthash.h:351
bool operator==(const FastHash &)
Definition: fasthash.h:411
FastHashBase< K, V >::Item Item
Definition: fasthash.h:435
Item * _nodesarray
Definition: fasthash.h:438
#define COMPILE_TIME_ASSERT(x)
FastHash()
Definition: fasthash.h:422
bool operator==(const FastHashBase &)
Definition: fasthash.h:95
FastHashBase(const FastHashBase &)
Definition: fasthash.h:93
FastHashBase< K, V >::Item Item
Definition: fasthash.h:405
ItemNode * pNext
Definition: fasthash.h:72
int InitTable(size_t fsize, size_t tsize)
Definition: fasthash.h:471
int Remove(const K &key)
Definition: fasthash.h:316
ItemNode * _itemnodesarray
Definition: fasthash.h:443
FastHash(const FastHash &)
Definition: fasthash.h:409
size_t Size()
Definition: fasthash.h:269
FastHashBase< K, V >::ItemNodePtr ItemNodePtr
Definition: fasthash.h:441
ItemNodePtr * _lookuptablearray
Definition: fasthash.h:444
size_t FastHash_GetHashTableWidth(unsigned int maxItems)
Definition: fasthash.cpp:64
ItemNode * _itemnodes
Definition: fasthash.h:81
ItemNodePtr * _lookuptable
Definition: fasthash.h:83
size_t _indexStart
Definition: fasthash.h:88
FastHashBase< K, V >::ItemNodePtr ItemNodePtr
Definition: fasthash.h:414
bool IsValid()
Definition: fasthash.h:264
ItemNode * ItemNodePtr
Definition: fasthash.h:75