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 HASHMAP_MEMORYPOOL_SIZE = HASHMAP_MIN_CAPACITY * HASHMAP_LOADFACTOR_NUMERATOR / HASHMAP_LOADFACTOR_DENOMINATOR
115 #ifdef USE_HASHMAP_MEMORY_POOL 131 #define HASHMAP_DUMMY_NODE ((Node *)1) 133 #ifdef DEBUG_HASH_COLLISIONS 134 mutable int _collisions, _lookups, _dummyHits;
137 Node *allocNode(
const Key &key) {
138 #ifdef USE_HASHMAP_MEMORY_POOL 139 return new (_nodePool)
Node(key);
141 return new Node(key);
145 void freeNode(
Node *node) {
146 if (node && node != HASHMAP_DUMMY_NODE)
147 #ifdef USE_HASHMAP_MEMORY_POOL 154 void assign(
const HM_t &map);
155 size_type lookup(
const Key &key)
const;
156 size_type lookupAndCreateIfMissing(
const Key &key);
157 void expandStorage(size_type newCapacity);
159 template<
class T>
friend class IteratorImpl;
164 template<
class NodeType>
167 #if defined(__INTEL_COMPILER) 168 template<
class T>
friend class Common::IteratorImpl;
170 template<
class T>
friend class IteratorImpl;
173 typedef const HashMap hashmap_t;
179 IteratorImpl(size_type idx, hashmap_t *hashmap) : _idx(idx), _hashmap(hashmap) {}
181 NodeType *deref()
const {
182 assert(_hashmap !=
nullptr);
183 assert(_idx <= _hashmap->_mask);
184 Node *node = _hashmap->_storage[_idx];
185 assert(node !=
nullptr);
186 assert(node != HASHMAP_DUMMY_NODE);
191 IteratorImpl() : _idx(0), _hashmap(
nullptr) {}
193 IteratorImpl(
const IteratorImpl<T> &c) : _idx(c._idx), _hashmap(c._hashmap) {}
195 NodeType &operator*()
const {
return *deref(); }
196 NodeType *operator->()
const {
return deref(); }
198 bool operator==(
const IteratorImpl &iter)
const {
return _idx == iter._idx && _hashmap == iter._hashmap; }
199 bool operator!=(
const IteratorImpl &iter)
const {
return !(*
this == iter); }
201 IteratorImpl &operator++() {
205 }
while (_idx <= _hashmap->_mask && (_hashmap->_storage[_idx] ==
nullptr || _hashmap->_storage[_idx] == HASHMAP_DUMMY_NODE));
206 if (_idx > _hashmap->_mask)
207 _idx = (size_type)-1;
212 IteratorImpl operator++(
int) {
213 IteratorImpl old = *
this;
220 typedef IteratorImpl<Node> iterator;
221 typedef IteratorImpl<const Node> const_iterator;
227 HM_t &operator=(
const HM_t &map) {
239 bool contains(
const Key &key)
const;
245 Val &
getVal(
const Key &key);
246 const Val &
getVal(
const Key &key)
const;
247 const Val &getValOrDefault(
const Key &key)
const;
248 const Val &getValOrDefault(
const Key &key,
const Val &defaultVal)
const;
249 bool tryGetVal(
const Key &key, Val &out)
const;
250 void setVal(
const Key &key,
const Val &val);
252 void clear(
bool shrinkArray = 0);
254 void erase(iterator entry);
255 void erase(
const Key &key);
257 size_type size()
const {
return _size; }
261 for (size_type ctr = 0; ctr <= _mask; ++ctr) {
262 if (_storage[ctr] && _storage[ctr] != HASHMAP_DUMMY_NODE)
263 return iterator(ctr,
this);
268 return iterator((size_type)-1,
this);
271 const_iterator begin()
const {
273 for (size_type ctr = 0; ctr <= _mask; ++ctr) {
274 if (_storage[ctr] && _storage[ctr] != HASHMAP_DUMMY_NODE)
275 return const_iterator(ctr,
this);
279 const_iterator end()
const {
280 return const_iterator((size_type)-1,
this);
283 iterator
find(
const Key &key) {
284 size_type ctr = lookup(key);
286 return iterator(ctr,
this);
290 const_iterator
find(
const Key &key)
const {
291 size_type ctr = lookup(key);
293 return const_iterator(ctr,
this);
305 void NORETURN_PRE unknownKeyError(Key k) NORETURN_POST {
306 error(
"Unknown key");
310 void NORETURN_PRE unknownKeyError(::
Common::String key) NORETURN_POST;
312 void NORETURN_PRE unknownKeyError(
signed char key) NORETURN_POST;
314 void NORETURN_PRE unknownKeyError(
unsigned char key) NORETURN_POST;
316 void NORETURN_PRE unknownKeyError(
short signed key) NORETURN_POST;
318 void NORETURN_PRE unknownKeyError(
short unsigned key) NORETURN_POST;
320 void NORETURN_PRE unknownKeyError(
long signed key) NORETURN_POST;
322 void NORETURN_PRE unknownKeyError(
long unsigned key) NORETURN_POST;
324 void NORETURN_PRE unknownKeyError(
signed int key) NORETURN_POST;
326 void NORETURN_PRE unknownKeyError(
unsigned int key) NORETURN_POST;
328 void NORETURN_PRE unknownKeyError(
long long signed key) NORETURN_POST;
330 void NORETURN_PRE unknownKeyError(
long long unsigned key) NORETURN_POST;
332 void NORETURN_PRE unknownKeyError(
void *key) NORETURN_POST;
334 void NORETURN_PRE unknownKeyError(
const char *key) NORETURN_POST;
342 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
344 _mask = HASHMAP_MIN_CAPACITY - 1;
345 _storage =
new Node *[HASHMAP_MIN_CAPACITY];
346 assert(_storage !=
nullptr);
347 memset(_storage, 0, HASHMAP_MIN_CAPACITY *
sizeof(
Node *));
352 #ifdef DEBUG_HASH_COLLISIONS 364 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
367 #ifdef DEBUG_HASH_COLLISIONS 378 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
380 for (size_type ctr = 0; ctr <= _mask; ++ctr)
381 freeNode(_storage[ctr]);
384 #ifdef DEBUG_HASH_COLLISIONS 385 extern void updateHashCollisionStats(
int,
int,
int,
int,
int);
386 updateHashCollisionStats(_collisions, _dummyHits, _lookups, _mask + 1, _size);
397 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
400 _storage =
new Node *[_mask + 1];
401 assert(_storage !=
nullptr);
402 memset(_storage, 0, (_mask + 1) *
sizeof(
Node *));
407 for (size_type ctr = 0; ctr <= _mask; ++ctr) {
408 if (map._storage[ctr] == HASHMAP_DUMMY_NODE) {
409 _storage[ctr] = HASHMAP_DUMMY_NODE;
411 }
else if (map._storage[ctr] !=
nullptr) {
412 _storage[ctr] = allocNode(map._storage[ctr]->_key);
413 _storage[ctr]->_value = map._storage[ctr]->_value;
418 assert(_size == map._size);
419 assert(_deleted == map._deleted);
426 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
428 for (size_type ctr = 0; ctr <= _mask; ++ctr) {
429 freeNode(_storage[ctr]);
430 _storage[ctr] =
nullptr;
433 #ifdef USE_HASHMAP_MEMORY_POOL 434 _nodePool.freeUnusedPages();
437 if (shrinkArray && _mask >= HASHMAP_MIN_CAPACITY) {
440 _mask = HASHMAP_MIN_CAPACITY - 1;
441 _storage =
new Node *[HASHMAP_MIN_CAPACITY];
442 assert(_storage !=
nullptr);
443 memset(_storage, 0, HASHMAP_MIN_CAPACITY *
sizeof(
Node *));
450 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
452 assert(newCapacity > _mask + 1);
454 #ifndef RELEASE_BUILD 455 const size_type old_size = _size;
457 const size_type old_mask = _mask;
458 Node **old_storage = _storage;
463 _mask = newCapacity - 1;
464 _storage =
new Node *[newCapacity];
465 assert(_storage !=
nullptr);
466 memset(_storage, 0, newCapacity *
sizeof(
Node *));
469 for (size_type ctr = 0; ctr <= old_mask; ++ctr) {
470 if (old_storage[ctr] ==
nullptr || old_storage[ctr] == HASHMAP_DUMMY_NODE)
477 const size_type hash = _hash(old_storage[ctr]->_key);
478 size_type idx = hash & _mask;
479 for (size_type perturb = hash; _storage[idx] !=
nullptr && _storage[idx] != HASHMAP_DUMMY_NODE; perturb >>= HASHMAP_PERTURB_SHIFT) {
480 idx = (5 * idx + perturb + 1) & _mask;
483 _storage[idx] = old_storage[ctr];
487 #ifndef RELEASE_BUILD 490 assert(_size == old_size);
493 delete[] old_storage;
498 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
500 const size_type hash = _hash(key);
501 size_type ctr = hash & _mask;
502 for (size_type perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
503 if (_storage[ctr] ==
nullptr)
505 if (_storage[ctr] == HASHMAP_DUMMY_NODE) {
506 #ifdef DEBUG_HASH_COLLISIONS 509 }
else if (_equal(_storage[ctr]->_key, key))
512 ctr = (5 * ctr + perturb + 1) & _mask;
514 #ifdef DEBUG_HASH_COLLISIONS 519 #ifdef DEBUG_HASH_COLLISIONS 521 debug(
"collisions %d, dummies hit %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d",
522 _collisions, _dummyHits, _lookups, ((
double) _collisions / (
double)_lookups),
523 (
const void *)
this, _mask + 1, _size);
529 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
531 const size_type hash = _hash(key);
532 size_type ctr = hash & _mask;
533 const size_type NONE_FOUND = _mask + 1;
534 size_type first_free = NONE_FOUND;
536 for (size_type perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
537 if (_storage[ctr] ==
nullptr)
539 if (_storage[ctr] == HASHMAP_DUMMY_NODE) {
540 #ifdef DEBUG_HASH_COLLISIONS 543 if (first_free == NONE_FOUND)
545 }
else if (_equal(_storage[ctr]->_key, key)) {
550 ctr = (5 * ctr + perturb + 1) & _mask;
552 #ifdef DEBUG_HASH_COLLISIONS 557 #ifdef DEBUG_HASH_COLLISIONS 559 debug(
"collisions %d, dummies hit %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d",
560 _collisions, _dummyHits, _lookups, ((
double) _collisions / (
double)_lookups),
561 (
const void *)
this, _mask + 1, _size);
564 if (!found && first_free != NONE_FOUND)
570 _storage[ctr] = allocNode(key);
571 assert(_storage[ctr] !=
nullptr);
576 size_type capacity = _mask + 1;
577 if ((_size + _deleted) * HASHMAP_LOADFACTOR_DENOMINATOR >
578 capacity * HASHMAP_LOADFACTOR_NUMERATOR) {
579 capacity = capacity < 500 ? (capacity * 4) : (capacity * 2);
580 expandStorage(capacity);
582 assert(_storage[ctr] !=
nullptr);
593 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
595 size_type ctr = lookup(key);
596 return (_storage[ctr] !=
nullptr);
603 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
605 return getOrCreateVal(key);
612 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
621 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
623 size_type ctr = lookupAndCreateIfMissing(key);
624 assert(_storage[ctr] !=
nullptr);
625 return _storage[ctr]->_value;
632 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
634 size_type ctr = lookup(key);
635 if (_storage[ctr] !=
nullptr)
636 return _storage[ctr]->_value;
647 unknownKeyError(key);
651 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
653 size_type ctr = lookup(key);
654 if (_storage[ctr] !=
nullptr)
655 return _storage[ctr]->_value;
661 unknownKeyError(key);
665 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
667 return getValOrDefault(key, _defaultVal);
674 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
676 size_type ctr = lookup(key);
677 if (_storage[ctr] !=
nullptr)
678 return _storage[ctr]->_value;
687 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
689 size_type ctr = lookup(key);
690 if (_storage[ctr] !=
nullptr) {
691 out = _storage[ctr]->_value;
698 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
700 size_type ctr = lookupAndCreateIfMissing(key);
701 assert(_storage[ctr] !=
nullptr);
702 _storage[ctr]->_value = val;
709 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
712 assert(entry._hashmap ==
this);
713 const size_type ctr = entry._idx;
714 assert(ctr <= _mask);
715 Node *
const node = _storage[ctr];
716 assert(node != NULL);
717 assert(node != HASHMAP_DUMMY_NODE);
721 _storage[ctr] = HASHMAP_DUMMY_NODE;
730 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
733 size_type ctr = lookup(key);
734 if (_storage[ctr] ==
nullptr)
738 freeNode(_storage[ctr]);
739 _storage[ctr] = HASHMAP_DUMMY_NODE;
745 #undef HASHMAP_DUMMY_NODE void clear(bool shrinkArray=0)
Definition: hashmap.h:427
Val & getVal(const Key &key)
Definition: hashmap.h:633
Val & operator[](const Key &key)
Definition: hashmap.h:604
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:145
Definition: algorithm.h:29
Definition: memorypool.h:139
bool empty() const
Definition: hashmap.h:299
bool tryGetVal(const Key &key, Val &out) const
Definition: hashmap.h:688
bool contains(const Key &key) const
Definition: hashmap.h:594
void NORETURN_PRE error(MSVC_PRINTF const char *s,...) GCC_PRINTF(1
void erase(iterator entry)
Definition: hashmap.h:710
HashMap()
Definition: hashmap.h:343
~HashMap()
Definition: hashmap.h:379
Val & getOrCreateVal(const Key &key)
Definition: hashmap.h:622
Definition: lobject.h:332