25 #ifndef COMMON_HASHMAP_H 26 #define COMMON_HASHMAP_H 39 #define USE_HASHMAP_MEMORY_POOL 42 #include "common/func.h" 44 #include "common/str.h" 46 #ifdef DEBUG_HASH_COLLISIONS 47 #include "common/debug.h" 50 #ifdef USE_HASHMAP_MEMORY_POOL 51 #include "common/memorypool.h" 66 #if defined(__INTEL_COMPILER) 67 template<
class T>
class IteratorImpl;
84 template<
class Key,
class Val,
class HashFunc = Hash<Key>,
class EqualFunc = EqualTo<Key> >
87 typedef uint size_type;
92 explicit Node(
const Key &key) : _key(key), _value() {}
93 Node() : _key(), _value() {}
101 HASHMAP_PERTURB_SHIFT = 5,
102 HASHMAP_MIN_CAPACITY = 16,
109 HASHMAP_LOADFACTOR_NUMERATOR = 2,
110 HASHMAP_LOADFACTOR_DENOMINATOR = 3,
112 #ifdef REDUCE_MEMORY_USAGE 113 HASHMAP_MEMORYPOOL_SIZE = 0
115 HASHMAP_MEMORYPOOL_SIZE = HASHMAP_MIN_CAPACITY * HASHMAP_LOADFACTOR_NUMERATOR / HASHMAP_LOADFACTOR_DENOMINATOR
119 #ifdef USE_HASHMAP_MEMORY_POOL 135 #define HASHMAP_DUMMY_NODE ((Node *)1) 137 #ifdef DEBUG_HASH_COLLISIONS 138 mutable int _collisions, _lookups, _dummyHits;
141 Node *allocNode(
const Key &key) {
142 #ifdef USE_HASHMAP_MEMORY_POOL 143 return new (_nodePool)
Node(key);
145 return new Node(key);
149 void freeNode(
Node *node) {
150 if (node && node != HASHMAP_DUMMY_NODE)
151 #ifdef USE_HASHMAP_MEMORY_POOL 158 void assign(
const HM_t &map);
159 size_type lookup(
const Key &key)
const;
160 size_type lookupAndCreateIfMissing(
const Key &key);
161 void expandStorage(size_type newCapacity);
163 template<
class T>
friend class IteratorImpl;
168 template<
class NodeType>
171 #if defined(__INTEL_COMPILER) 172 template<
class T>
friend class Common::IteratorImpl;
174 template<
class T>
friend class IteratorImpl;
177 typedef const HashMap hashmap_t;
183 IteratorImpl(size_type idx, hashmap_t *hashmap) : _idx(idx), _hashmap(hashmap) {}
185 NodeType *deref()
const {
186 assert(_hashmap !=
nullptr);
187 assert(_idx <= _hashmap->_mask);
188 Node *node = _hashmap->_storage[_idx];
189 assert(node !=
nullptr);
190 assert(node != HASHMAP_DUMMY_NODE);
195 IteratorImpl() : _idx(0), _hashmap(
nullptr) {}
197 IteratorImpl(
const IteratorImpl<T> &c) : _idx(c._idx), _hashmap(c._hashmap) {}
199 NodeType &operator*()
const {
return *deref(); }
200 NodeType *operator->()
const {
return deref(); }
202 bool operator==(
const IteratorImpl &iter)
const {
return _idx == iter._idx && _hashmap == iter._hashmap; }
203 bool operator!=(
const IteratorImpl &iter)
const {
return !(*
this == iter); }
205 IteratorImpl &operator++() {
209 }
while (_idx <= _hashmap->_mask && (_hashmap->_storage[_idx] ==
nullptr || _hashmap->_storage[_idx] == HASHMAP_DUMMY_NODE));
210 if (_idx > _hashmap->_mask)
211 _idx = (size_type)-1;
216 IteratorImpl operator++(
int) {
217 IteratorImpl old = *
this;
224 typedef IteratorImpl<Node> iterator;
225 typedef IteratorImpl<const Node> const_iterator;
231 HM_t &operator=(
const HM_t &map) {
243 bool contains(
const Key &key)
const;
249 Val &
getVal(
const Key &key);
250 const Val &
getVal(
const Key &key)
const;
251 const Val &getValOrDefault(
const Key &key)
const;
252 const Val &getValOrDefault(
const Key &key,
const Val &defaultVal)
const;
253 bool tryGetVal(
const Key &key, Val &out)
const;
254 void setVal(
const Key &key,
const Val &val);
256 void clear(
bool shrinkArray = 0);
258 void erase(iterator entry);
259 void erase(
const Key &key);
261 size_type size()
const {
return _size; }
265 for (size_type ctr = 0; ctr <= _mask; ++ctr) {
266 if (_storage[ctr] && _storage[ctr] != HASHMAP_DUMMY_NODE)
267 return iterator(ctr,
this);
272 return iterator((size_type)-1,
this);
275 const_iterator begin()
const {
277 for (size_type ctr = 0; ctr <= _mask; ++ctr) {
278 if (_storage[ctr] && _storage[ctr] != HASHMAP_DUMMY_NODE)
279 return const_iterator(ctr,
this);
283 const_iterator end()
const {
284 return const_iterator((size_type)-1,
this);
287 iterator
find(
const Key &key) {
288 size_type ctr = lookup(key);
290 return iterator(ctr,
this);
294 const_iterator
find(
const Key &key)
const {
295 size_type ctr = lookup(key);
297 return const_iterator(ctr,
this);
309 void NORETURN_PRE unknownKeyError(Key k) NORETURN_POST {
310 error(
"Unknown key");
314 void NORETURN_PRE unknownKeyError(::
Common::String key) NORETURN_POST;
316 void NORETURN_PRE unknownKeyError(
signed char key) NORETURN_POST;
318 void NORETURN_PRE unknownKeyError(
unsigned char key) NORETURN_POST;
320 void NORETURN_PRE unknownKeyError(
short signed key) NORETURN_POST;
322 void NORETURN_PRE unknownKeyError(
short unsigned key) NORETURN_POST;
324 void NORETURN_PRE unknownKeyError(
long signed key) NORETURN_POST;
326 void NORETURN_PRE unknownKeyError(
long unsigned key) NORETURN_POST;
328 void NORETURN_PRE unknownKeyError(
signed int key) NORETURN_POST;
330 void NORETURN_PRE unknownKeyError(
unsigned int key) NORETURN_POST;
332 void NORETURN_PRE unknownKeyError(
long long signed key) NORETURN_POST;
334 void NORETURN_PRE unknownKeyError(
long long unsigned key) NORETURN_POST;
336 void NORETURN_PRE unknownKeyError(
void *key) NORETURN_POST;
338 void NORETURN_PRE unknownKeyError(
const char *key) NORETURN_POST;
346 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
348 _mask = HASHMAP_MIN_CAPACITY - 1;
349 _storage =
new Node *[HASHMAP_MIN_CAPACITY];
350 assert(_storage !=
nullptr);
351 memset(_storage, 0, HASHMAP_MIN_CAPACITY *
sizeof(
Node *));
356 #ifdef DEBUG_HASH_COLLISIONS 368 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
371 #ifdef DEBUG_HASH_COLLISIONS 382 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
384 for (size_type ctr = 0; ctr <= _mask; ++ctr)
385 freeNode(_storage[ctr]);
388 #ifdef DEBUG_HASH_COLLISIONS 389 extern void updateHashCollisionStats(
int,
int,
int,
int,
int);
390 updateHashCollisionStats(_collisions, _dummyHits, _lookups, _mask + 1, _size);
401 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
404 _storage =
new Node *[_mask + 1];
405 assert(_storage !=
nullptr);
406 memset(_storage, 0, (_mask + 1) *
sizeof(
Node *));
411 for (size_type ctr = 0; ctr <= _mask; ++ctr) {
412 if (map._storage[ctr] == HASHMAP_DUMMY_NODE) {
413 _storage[ctr] = HASHMAP_DUMMY_NODE;
415 }
else if (map._storage[ctr] !=
nullptr) {
416 _storage[ctr] = allocNode(map._storage[ctr]->_key);
417 _storage[ctr]->_value = map._storage[ctr]->_value;
422 assert(_size == map._size);
423 assert(_deleted == map._deleted);
430 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
432 for (size_type ctr = 0; ctr <= _mask; ++ctr) {
433 freeNode(_storage[ctr]);
434 _storage[ctr] =
nullptr;
437 #ifdef USE_HASHMAP_MEMORY_POOL 438 _nodePool.freeUnusedPages();
441 if (shrinkArray && _mask >= HASHMAP_MIN_CAPACITY) {
444 _mask = HASHMAP_MIN_CAPACITY - 1;
445 _storage =
new Node *[HASHMAP_MIN_CAPACITY];
446 assert(_storage !=
nullptr);
447 memset(_storage, 0, HASHMAP_MIN_CAPACITY *
sizeof(
Node *));
454 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
456 assert(newCapacity > _mask + 1);
458 #ifndef RELEASE_BUILD 459 const size_type old_size = _size;
461 const size_type old_mask = _mask;
462 Node **old_storage = _storage;
467 _mask = newCapacity - 1;
468 _storage =
new Node *[newCapacity];
469 assert(_storage !=
nullptr);
470 memset(_storage, 0, newCapacity *
sizeof(
Node *));
473 for (size_type ctr = 0; ctr <= old_mask; ++ctr) {
474 if (old_storage[ctr] ==
nullptr || old_storage[ctr] == HASHMAP_DUMMY_NODE)
481 const size_type hash = _hash(old_storage[ctr]->_key);
482 size_type idx = hash & _mask;
483 for (size_type perturb = hash; _storage[idx] !=
nullptr && _storage[idx] != HASHMAP_DUMMY_NODE; perturb >>= HASHMAP_PERTURB_SHIFT) {
484 idx = (5 * idx + perturb + 1) & _mask;
487 _storage[idx] = old_storage[ctr];
491 #ifndef RELEASE_BUILD 494 assert(_size == old_size);
497 delete[] old_storage;
502 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
504 const size_type hash = _hash(key);
505 size_type ctr = hash & _mask;
506 for (size_type perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
507 if (_storage[ctr] ==
nullptr)
509 if (_storage[ctr] == HASHMAP_DUMMY_NODE) {
510 #ifdef DEBUG_HASH_COLLISIONS 513 }
else if (_equal(_storage[ctr]->_key, key))
516 ctr = (5 * ctr + perturb + 1) & _mask;
518 #ifdef DEBUG_HASH_COLLISIONS 523 #ifdef DEBUG_HASH_COLLISIONS 525 debug(
"collisions %d, dummies hit %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d",
526 _collisions, _dummyHits, _lookups, ((
double) _collisions / (
double)_lookups),
527 (
const void *)
this, _mask + 1, _size);
533 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
535 const size_type hash = _hash(key);
536 size_type ctr = hash & _mask;
537 const size_type NONE_FOUND = _mask + 1;
538 size_type first_free = NONE_FOUND;
540 for (size_type perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
541 if (_storage[ctr] ==
nullptr)
543 if (_storage[ctr] == HASHMAP_DUMMY_NODE) {
544 #ifdef DEBUG_HASH_COLLISIONS 547 if (first_free == NONE_FOUND)
549 }
else if (_equal(_storage[ctr]->_key, key)) {
554 ctr = (5 * ctr + perturb + 1) & _mask;
556 #ifdef DEBUG_HASH_COLLISIONS 561 #ifdef DEBUG_HASH_COLLISIONS 563 debug(
"collisions %d, dummies hit %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d",
564 _collisions, _dummyHits, _lookups, ((
double) _collisions / (
double)_lookups),
565 (
const void *)
this, _mask + 1, _size);
568 if (!found && first_free != NONE_FOUND)
574 _storage[ctr] = allocNode(key);
575 assert(_storage[ctr] !=
nullptr);
580 size_type capacity = _mask + 1;
581 if ((_size + _deleted) * HASHMAP_LOADFACTOR_DENOMINATOR >
582 capacity * HASHMAP_LOADFACTOR_NUMERATOR) {
583 capacity = capacity < 500 ? (capacity * 4) : (capacity * 2);
584 expandStorage(capacity);
586 assert(_storage[ctr] !=
nullptr);
597 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
599 size_type ctr = lookup(key);
600 return (_storage[ctr] !=
nullptr);
607 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
609 return getOrCreateVal(key);
616 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
625 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
627 size_type ctr = lookupAndCreateIfMissing(key);
628 assert(_storage[ctr] !=
nullptr);
629 return _storage[ctr]->_value;
636 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
638 size_type ctr = lookup(key);
639 if (_storage[ctr] !=
nullptr)
640 return _storage[ctr]->_value;
651 unknownKeyError(key);
655 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
657 size_type ctr = lookup(key);
658 if (_storage[ctr] !=
nullptr)
659 return _storage[ctr]->_value;
665 unknownKeyError(key);
669 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
671 return getValOrDefault(key, _defaultVal);
678 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
680 size_type ctr = lookup(key);
681 if (_storage[ctr] !=
nullptr)
682 return _storage[ctr]->_value;
691 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
693 size_type ctr = lookup(key);
694 if (_storage[ctr] !=
nullptr) {
695 out = _storage[ctr]->_value;
702 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
704 size_type ctr = lookupAndCreateIfMissing(key);
705 assert(_storage[ctr] !=
nullptr);
706 _storage[ctr]->_value = val;
713 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
716 assert(entry._hashmap ==
this);
717 const size_type ctr = entry._idx;
718 assert(ctr <= _mask);
719 Node *
const node = _storage[ctr];
720 assert(node != NULL);
721 assert(node != HASHMAP_DUMMY_NODE);
725 _storage[ctr] = HASHMAP_DUMMY_NODE;
734 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
737 size_type ctr = lookup(key);
738 if (_storage[ctr] ==
nullptr)
742 freeNode(_storage[ctr]);
743 _storage[ctr] = HASHMAP_DUMMY_NODE;
749 #undef HASHMAP_DUMMY_NODE void clear(bool shrinkArray=0)
Definition: hashmap.h:431
Val & getVal(const Key &key)
Definition: hashmap.h:637
Val & operator[](const Key &key)
Definition: hashmap.h:608
In find(In first, In last, const T &v)
Definition: algorithm.h:225
void debug(MSVC_PRINTF const char *s,...) GCC_PRINTF(1
void deleteChunk(T *ptr)
Definition: memorypool.h:149
Definition: algorithm.h:29
Definition: memorypool.h:143
bool empty() const
Definition: hashmap.h:303
bool tryGetVal(const Key &key, Val &out) const
Definition: hashmap.h:692
bool contains(const Key &key) const
Definition: hashmap.h:598
void NORETURN_PRE error(MSVC_PRINTF const char *s,...) GCC_PRINTF(1
void erase(iterator entry)
Definition: hashmap.h:714
HashMap()
Definition: hashmap.h:347
~HashMap()
Definition: hashmap.h:383
Val & getOrCreateVal(const Key &key)
Definition: hashmap.h:626
Definition: lobject.h:332