hash_map.h
1 /*************************************************************************/
2 /* hash_map.h */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* http://www.godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
9 /* */
10 /* Permission is hereby granted, free of charge, to any person obtaining */
11 /* a copy of this software and associated documentation files (the */
12 /* "Software"), to deal in the Software without restriction, including */
13 /* without limitation the rights to use, copy, modify, merge, publish, */
14 /* distribute, sublicense, and/or sell copies of the Software, and to */
15 /* permit persons to whom the Software is furnished to do so, subject to */
16 /* the following conditions: */
17 /* */
18 /* The above copyright notice and this permission notice shall be */
19 /* included in all copies or substantial portions of the Software. */
20 /* */
21 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
22 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
23 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
24 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
25 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
26 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
27 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
28 /*************************************************************************/
29 #ifndef HASH_MAP_H
30 #define HASH_MAP_H
31 
32 #include "hashfuncs.h"
33 #include "error_macros.h"
34 #include "ustring.h"
35 #include "os/memory.h"
36 #include "list.h"
37 
38 
40 public:
41 
42  static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }
43  static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); }
44  static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) {
45  uint64_t v=p_int;
46  v = (~v) + (v << 18); // v = (v << 18) - v - 1;
47  v = v ^ (v >> 31);
48  v = v * 21; // v = (v + (v << 2)) + (v << 4);
49  v = v ^ (v >> 11);
50  v = v + (v << 6);
51  v = v ^ (v >> 22);
52  return (int) v;
53  }
54  static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash(uint64_t(p_int)); }
55 
56 
57  static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return p_int; }
58  static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return (uint32_t)p_int; }
59  static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return p_int; }
60  static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return (uint32_t)p_int; }
61  static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return p_int; }
62  static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return (uint32_t)p_int; }
63  static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return (uint32_t)p_wchar; }
64 // static _FORCE_INLINE_ uint32_t hash(const void* p_ptr) { return uint32_t(uint64_t(p_ptr))*(0x9e3779b1L); }
65 };
66 
83 template<class TKey, class TData, class Hasher=HashMapHahserDefault,uint8_t MIN_HASH_TABLE_POWER=3,uint8_t RELATIONSHIP=8>
84 class HashMap {
85 public:
86 
87  struct Pair {
88 
89  TKey key;
90  TData data;
91 
92  Pair() {}
93  Pair(const TKey& p_key, const TData& p_data) { key=p_key; data=p_data; }
94  };
95 
96 
97 private:
98  struct Entry {
99 
100  uint32_t hash;
101  Entry *next;
102  Pair pair;
103 
104  Entry() { next=0; }
105  };
106 
107  Entry **hash_table;
108  uint8_t hash_table_power;
109  uint32_t elements;
110 
111  void make_hash_table() {
112 
113  ERR_FAIL_COND( hash_table );
114 
115 
116  hash_table = memnew_arr( Entry*, (1<<MIN_HASH_TABLE_POWER) );
117 
118  hash_table_power = MIN_HASH_TABLE_POWER;
119  elements=0;
120  for (int i=0;i<(1<<MIN_HASH_TABLE_POWER);i++)
121  hash_table[i]=0;
122  }
123 
124  void erase_hash_table() {
125 
126  ERR_FAIL_COND(elements);
127 
128  memdelete_arr( hash_table );
129  hash_table=0;
130  hash_table_power=0;
131  elements=0;
132  }
133 
134  void check_hash_table() {
135 
136  int new_hash_table_power=-1;
137 
138  if ((int)elements > ( (1<<hash_table_power) * RELATIONSHIP ) ) {
139  /* rehash up */
140  new_hash_table_power=hash_table_power+1;
141 
142  while( (int)elements > ( (1<<new_hash_table_power) * RELATIONSHIP ) ) {
143 
144  new_hash_table_power++;
145  }
146 
147  } else if ( (hash_table_power>(int)MIN_HASH_TABLE_POWER) && ((int)elements < ( (1<<(hash_table_power-1)) * RELATIONSHIP ) ) ) {
148 
149  /* rehash down */
150  new_hash_table_power=hash_table_power-1;
151 
152  while( (int)elements < ( (1<<(new_hash_table_power-1)) * RELATIONSHIP ) ) {
153 
154  new_hash_table_power--;
155  }
156 
157  if (new_hash_table_power<(int)MIN_HASH_TABLE_POWER)
158  new_hash_table_power=MIN_HASH_TABLE_POWER;
159  }
160 
161 
162  if (new_hash_table_power==-1)
163  return;
164 
165  Entry ** new_hash_table = memnew_arr( Entry*, (1<<new_hash_table_power) );
166  if (!new_hash_table) {
167 
168  ERR_PRINT("Out of Memory");
169  return;
170  }
171 
172  for (int i=0;i<(1<<new_hash_table_power);i++) {
173 
174  new_hash_table[i]=0;
175  }
176 
177  for (int i=0;i<(1<<hash_table_power);i++) {
178 
179  while( hash_table[i] ) {
180 
181  Entry *se=hash_table[i];
182  hash_table[i]=se->next;
183  int new_pos = se->hash & ((1<<new_hash_table_power)-1);
184  se->next=new_hash_table[new_pos];
185  new_hash_table[new_pos]=se;
186  }
187 
188  }
189 
190  if (hash_table)
191  memdelete_arr( hash_table );
192  hash_table=new_hash_table;
193  hash_table_power=new_hash_table_power;
194 
195  }
196 
197 
198  /* I want to have only one function.. */
199  _FORCE_INLINE_ const Entry * get_entry( const TKey& p_key ) const {
200 
201  uint32_t hash = Hasher::hash( p_key );
202  uint32_t index = hash&((1<<hash_table_power)-1);
203 
204  Entry *e = hash_table[index];
205 
206  while (e) {
207 
208  /* checking hash first avoids comparing key, which may take longer */
209  if (e->hash == hash && e->pair.key == p_key ) {
210 
211  /* the pair exists in this hashtable, so just update data */
212  return e;
213  }
214 
215  e=e->next;
216  }
217 
218  return NULL;
219  }
220 
221  Entry * create_entry(const TKey& p_key) {
222 
223  /* if entry doesn't exist, create it */
224  Entry *e = memnew( Entry );
225  ERR_FAIL_COND_V(!e,NULL); /* out of memory */
226  uint32_t hash = Hasher::hash( p_key );
227  uint32_t index = hash&((1<<hash_table_power)-1);
228  e->next = hash_table[index];
229  e->hash = hash;
230  e->pair.key=p_key;
231 
232  hash_table[index]=e;
233  elements++;
234 
235  return e;
236  }
237 
238 
239  void copy_from(const HashMap& p_t) {
240 
241  if (&p_t==this)
242  return; /* much less bother with that */
243 
244  clear();
245 
246  if (!p_t.hash_table || p_t.hash_table_power==0)
247  return; /* not copying from empty table */
248 
249  hash_table = memnew_arr(Entry*,1<<p_t.hash_table_power);
250  hash_table_power=p_t.hash_table_power;
251  elements=p_t.elements;
252 
253  for (int i=0;i<( 1<<p_t.hash_table_power );i++) {
254 
255  hash_table[i]=NULL;
256  /* elements will be in the reverse order, but it doesn't matter */
257 
258  const Entry *e = p_t.hash_table[i];
259 
260  while(e) {
261 
262  Entry *le = memnew( Entry ); /* local entry */
263 
264  *le=*e; /* copy data */
265 
266  /* add to list and reassign pointers */
267  le->next=hash_table[i];
268  hash_table[i]=le;
269 
270  e=e->next;
271  }
272 
273 
274  }
275 
276 
277  }
278 public:
279 
280 
281  void set( const TKey& p_key, const TData& p_data ) {
282 
283  set( Pair( p_key, p_data ) );
284 
285  }
286 
287  void set( const Pair& p_pair ) {
288 
289  Entry *e=NULL;
290  if (!hash_table)
291  make_hash_table(); // if no table, make one
292  else
293  e = const_cast<Entry*>( get_entry(p_pair.key) );
294 
295  /* if we made it up to here, the pair doesn't exist, create and assign */
296 
297  if (!e) {
298 
299  e=create_entry(p_pair.key);
300  if (!e)
301  return;
302  check_hash_table(); // perform mantenience routine
303  }
304 
305  e->pair.data = p_pair.data;
306 
307  }
308 
309 
310  bool has( const TKey& p_key ) const {
311 
312  return getptr(p_key)!=NULL;
313  }
314 
321  const TData& get( const TKey& p_key ) const {
322 
323  const TData* res = getptr(p_key);
324  ERR_FAIL_COND_V(!res,*res);
325  return *res;
326  }
327 
328  TData& get( const TKey& p_key ) {
329 
330  TData* res = getptr(p_key);
331  ERR_FAIL_COND_V(!res,*res);
332  return *res;
333  }
334 
341  _FORCE_INLINE_ TData* getptr( const TKey& p_key ) {
342 
343  if (!hash_table)
344  return NULL;
345 
346  Entry *e=const_cast<Entry*>(get_entry(p_key ));
347 
348  if (e)
349  return &e->pair.data;
350 
351  return NULL;
352 
353  }
354 
355  _FORCE_INLINE_ const TData* getptr( const TKey& p_key ) const {
356 
357  if (!hash_table)
358  return NULL;
359 
360  const Entry *e=const_cast<Entry*>(get_entry(p_key ));
361 
362  if (e)
363  return &e->pair.data;
364 
365  return NULL;
366 
367  }
368 
374  template<class C>
375  _FORCE_INLINE_ TData* custom_getptr( C p_custom_key,uint32_t p_custom_hash ) {
376 
377  if (!hash_table)
378  return NULL;
379 
380  uint32_t hash = p_custom_hash;
381  uint32_t index = hash&((1<<hash_table_power)-1);
382 
383  Entry *e = hash_table[index];
384 
385  while (e) {
386 
387  /* checking hash first avoids comparing key, which may take longer */
388  if (e->hash == hash && e->pair.key == p_custom_key ) {
389 
390  /* the pair exists in this hashtable, so just update data */
391  return &e->pair.data;
392  }
393 
394  e=e->next;
395  }
396 
397  return NULL;
398  }
399 
400  template<class C>
401  _FORCE_INLINE_ const TData* custom_getptr( C p_custom_key,uint32_t p_custom_hash ) const {
402 
403  if (!hash_table)
404  return NULL;
405 
406  uint32_t hash = p_custom_hash;
407  uint32_t index = hash&((1<<hash_table_power)-1);
408 
409  const Entry *e = hash_table[index];
410 
411  while (e) {
412 
413  /* checking hash first avoids comparing key, which may take longer */
414  if (e->hash == hash && e->pair.key == p_custom_key ) {
415 
416  /* the pair exists in this hashtable, so just update data */
417  return &e->pair.data;
418  }
419 
420  e=e->next;
421  }
422 
423  return NULL;
424  }
425 
426 
431  bool erase( const TKey& p_key ) {
432 
433  if (!hash_table)
434  return false;
435 
436  uint32_t hash = Hasher::hash( p_key );
437  uint32_t index = hash&((1<<hash_table_power)-1);
438 
439 
440  Entry *e = hash_table[index];
441  Entry *p=NULL;
442  while (e) {
443 
444  /* checking hash first avoids comparing key, which may take longer */
445  if (e->hash == hash && e->pair.key == p_key ) {
446 
447  if (p) {
448 
449  p->next=e->next;
450  } else {
451  //begin of list
452  hash_table[index]=e->next;
453  }
454 
455  memdelete(e);
456  elements--;
457 
458  if (elements==0)
459  erase_hash_table();
460  else
461  check_hash_table();
462  return true;
463  }
464 
465  p=e;
466  e=e->next;
467  }
468 
469 
470  return false;
471 
472  }
473 
474  inline const TData& operator[](const TKey& p_key) const { //constref
475 
476  return get(p_key);
477  }
478  inline TData& operator[](const TKey& p_key ) { //assignment
479 
480  Entry *e=NULL;
481  if (!hash_table)
482  make_hash_table(); // if no table, make one
483  else
484  e = const_cast<Entry*>( get_entry(p_key) );
485 
486  /* if we made it up to here, the pair doesn't exist, create */
487  if (!e) {
488 
489  e=create_entry(p_key);
490  if (!e)
491  return *(TData*)NULL; /* panic! */
492  check_hash_table(); // perform mantenience routine
493  }
494 
495  return e->pair.data;
496 
497  }
498 
514  const TKey* next(const TKey* p_key) const {
515 
516  if (!hash_table) return NULL;
517 
518  if (!p_key) { /* get the first key */
519 
520  for (int i=0;i<(1<<hash_table_power);i++) {
521 
522  if (hash_table[i]) {
523  return &hash_table[i]->pair.key;
524  }
525  }
526 
527  } else { /* get the next key */
528 
529  const Entry *e = get_entry( *p_key );
530  ERR_FAIL_COND_V( !e, NULL ); /* invalid key supplied */
531 
532  if (e->next) {
533  /* if there is a "next" in the list, return that */
534  return &e->next->pair.key;
535  } else {
536  /* go to next entries */
537  uint32_t index = e->hash&((1<<hash_table_power)-1);
538  index++;
539  for (int i=index;i<(1<<hash_table_power);i++) {
540 
541  if (hash_table[i]) {
542  return &hash_table[i]->pair.key;
543  }
544  }
545  }
546 
547  /* nothing found, was at end */
548 
549  }
550 
551 
552  return NULL; /* nothing found */
553  }
554 
555  inline unsigned int size() const {
556 
557  return elements;
558  }
559 
560  inline bool empty() const {
561 
562  return elements==0;
563  }
564 
565  void clear() {
566 
567  /* clean up */
568  if (hash_table) {
569  for (int i=0;i<(1<<hash_table_power);i++) {
570 
571  while (hash_table[i]) {
572 
573  Entry *e=hash_table[i];
574  hash_table[i]=e->next;
575  memdelete( e );
576  }
577  }
578 
579  memdelete_arr( hash_table );
580  }
581 
582  hash_table=0;
583  hash_table_power=0;
584  elements=0;
585  }
586 
587 
588  void operator=(const HashMap& p_table) {
589 
590  copy_from(p_table);
591  }
592 
593  HashMap() {
594  hash_table=NULL;
595  elements=0;
596  hash_table_power=0;
597  }
598 
599  void get_key_list(List<TKey> *p_keys) const {
600  if (!hash_table)
601  return;
602  for(int i=0;i<(1<<hash_table_power);i++) {
603 
604  Entry *e=hash_table[i];
605  while(e) {
606  p_keys->push_back(e->pair.key);
607  e=e->next;
608  }
609  }
610  }
611 
612  HashMap(const HashMap& p_table) {
613 
614  hash_table=NULL;
615  elements=0;
616  hash_table_power=0;
617 
618  copy_from(p_table);
619 
620  }
621 
622  ~HashMap() {
623 
624  clear();
625  }
626 
627 };
628 
629 #endif
Element * push_back(const T &value)
Definition: list.h:220
Definition: hash_map.h:84
Definition: list.h:44
Definition: hash_map.h:87
Definition: hash_map.h:39
const TKey * next(const TKey *p_key) const
Definition: hash_map.h:514
bool erase(const TKey &p_key)
Definition: hash_map.h:431
_FORCE_INLINE_ TData * getptr(const TKey &p_key)
Definition: hash_map.h:341
Definition: ustring.h:64
_FORCE_INLINE_ TData * custom_getptr(C p_custom_key, uint32_t p_custom_hash)
Definition: hash_map.h:375