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);
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];
489 assert(_size == old_size);
491 delete[] old_storage;
496 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
498 const size_type hash = _hash(key);
499 size_type ctr = hash & _mask;
500 for (size_type perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
501 if (_storage[ctr] ==
nullptr)
503 if (_storage[ctr] == HASHMAP_DUMMY_NODE) {
504 #ifdef DEBUG_HASH_COLLISIONS 507 }
else if (_equal(_storage[ctr]->_key, key))
510 ctr = (5 * ctr + perturb + 1) & _mask;
512 #ifdef DEBUG_HASH_COLLISIONS 517 #ifdef DEBUG_HASH_COLLISIONS 519 debug(
"collisions %d, dummies hit %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d",
520 _collisions, _dummyHits, _lookups, ((
double) _collisions / (
double)_lookups),
521 (
const void *)
this, _mask + 1, _size);
527 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
529 const size_type hash = _hash(key);
530 size_type ctr = hash & _mask;
531 const size_type NONE_FOUND = _mask + 1;
532 size_type first_free = NONE_FOUND;
534 for (size_type perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
535 if (_storage[ctr] ==
nullptr)
537 if (_storage[ctr] == HASHMAP_DUMMY_NODE) {
538 #ifdef DEBUG_HASH_COLLISIONS 541 if (first_free == NONE_FOUND)
543 }
else if (_equal(_storage[ctr]->_key, key)) {
548 ctr = (5 * ctr + perturb + 1) & _mask;
550 #ifdef DEBUG_HASH_COLLISIONS 555 #ifdef DEBUG_HASH_COLLISIONS 557 debug(
"collisions %d, dummies hit %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d",
558 _collisions, _dummyHits, _lookups, ((
double) _collisions / (
double)_lookups),
559 (
const void *)
this, _mask + 1, _size);
562 if (!found && first_free != NONE_FOUND)
568 _storage[ctr] = allocNode(key);
569 assert(_storage[ctr] !=
nullptr);
574 size_type capacity = _mask + 1;
575 if ((_size + _deleted) * HASHMAP_LOADFACTOR_DENOMINATOR >
576 capacity * HASHMAP_LOADFACTOR_NUMERATOR) {
577 capacity = capacity < 500 ? (capacity * 4) : (capacity * 2);
578 expandStorage(capacity);
580 assert(_storage[ctr] !=
nullptr);
591 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
593 size_type ctr = lookup(key);
594 return (_storage[ctr] !=
nullptr);
601 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
603 return getOrCreateVal(key);
610 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
619 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
621 size_type ctr = lookupAndCreateIfMissing(key);
622 assert(_storage[ctr] !=
nullptr);
623 return _storage[ctr]->_value;
630 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
632 size_type ctr = lookup(key);
633 if (_storage[ctr] !=
nullptr)
634 return _storage[ctr]->_value;
645 unknownKeyError(key);
649 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
651 size_type ctr = lookup(key);
652 if (_storage[ctr] !=
nullptr)
653 return _storage[ctr]->_value;
659 unknownKeyError(key);
663 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
665 return getValOrDefault(key, _defaultVal);
672 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
674 size_type ctr = lookup(key);
675 if (_storage[ctr] !=
nullptr)
676 return _storage[ctr]->_value;
685 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
687 size_type ctr = lookup(key);
688 if (_storage[ctr] !=
nullptr) {
689 out = _storage[ctr]->_value;
696 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
698 size_type ctr = lookupAndCreateIfMissing(key);
699 assert(_storage[ctr] !=
nullptr);
700 _storage[ctr]->_value = val;
707 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
710 assert(entry._hashmap ==
this);
711 const size_type ctr = entry._idx;
712 assert(ctr <= _mask);
713 Node *
const node = _storage[ctr];
714 assert(node != NULL);
715 assert(node != HASHMAP_DUMMY_NODE);
719 _storage[ctr] = HASHMAP_DUMMY_NODE;
728 template<
class Key,
class Val,
class HashFunc,
class EqualFunc>
731 size_type ctr = lookup(key);
732 if (_storage[ctr] ==
nullptr)
736 freeNode(_storage[ctr]);
737 _storage[ctr] = HASHMAP_DUMMY_NODE;
743 #undef HASHMAP_DUMMY_NODE void clear(bool shrinkArray=0)
Definition: hashmap.h:427
Val & getVal(const Key &key)
Definition: hashmap.h:631
Val & operator[](const Key &key)
Definition: hashmap.h:602
In find(In first, In last, const T &v)
Definition: algorithm.h:168
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:686
bool contains(const Key &key) const
Definition: hashmap.h:592
void NORETURN_PRE error(MSVC_PRINTF const char *s,...) GCC_PRINTF(1
void erase(iterator entry)
Definition: hashmap.h:708
HashMap()
Definition: hashmap.h:343
~HashMap()
Definition: hashmap.h:379
Val & getOrCreateVal(const Key &key)
Definition: hashmap.h:620
Definition: lobject.h:332