openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
hashmap.hpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) NumeriCor GmbH
2 // SPDX-License-Identifier: Apache-2.0
3 
15 #ifndef _MT_HASHMAP_H
16 #define _MT_HASHMAP_H
17 
18 #include <stdint.h>
19 #include <limits.h>
20 
21 #include <stdexcept>
22 #include <algorithm>
23 #include <string>
24 #include <vector>
25 
26 // #define NDEBUG
27 
28 typedef unsigned long int hm_uint;
29 typedef long int hm_int;
30 
31 namespace hashmap {
32 
35 
36 // The XOR version of DJB2
37 inline hm_uint mkhash(hm_uint a, hm_uint b) {
38  return ((a << 5) + a) ^ b;
39 }
40 
41 // traditionally 5381 is used as starting value for the djb2 hash
42 const hm_uint mkhash_init = 5381;
43 
44 // The ADD version of DJB2
45 // (use this version for cache locality in b)
47  return ((a << 5) + a) + b;
48 }
49 
51  if (sizeof(a) == 4) {
52  a ^= a << 13;
53  a ^= a >> 17;
54  a ^= a << 5;
55  } else if (sizeof(a) == 8) {
56  a ^= a << 13;
57  a ^= a >> 7;
58  a ^= a << 17;
59  } else
60  throw std::runtime_error("mkhash_xorshift() only implemented for 32 bit and 64 bit ints");
61  return a;
62 }
63 
64 // ================== Hashing structs ==============================
65 
71 template<typename T>
72 struct hash_ops
73 {
74  static inline bool cmp(const T &a, const T &b) {
75  return a == b;
76  }
77  static inline hm_uint hash(const T &a) {
78  return a.hash();
79  }
80 };
81 
82 struct hash_int_ops {
83  template<typename T>
84  static inline bool cmp(T a, T b) {
85  return a == b;
86  }
87 };
88 
89 template<> struct hash_ops<int32_t> : hash_int_ops
90 {
91  static inline hm_uint hash(int32_t a) {
92  return a;
93  }
94 };
95 template<> struct hash_ops<int64_t> : hash_int_ops
96 {
97  static inline hm_uint hash(int64_t a) {
98  return mkhash((hm_uint)(a), (hm_uint)(a >> 32));
99  }
100 };
101 
102 // in the case that long is not an int64 we define an additional long hasher
103 #ifdef __APPLE__
104 template<> struct hash_ops<long> : hash_int_ops
105 {
106  static inline hm_uint hash(long a) {
107  if constexpr (sizeof(long) <= sizeof(hm_uint)) {
108  return static_cast<hm_uint>(a);
109  } else {
110  return mkhash(static_cast<hm_uint>(a), static_cast<hm_uint>(static_cast<unsigned long>(a) >> 32));
111  }
112  }
113 };
114 #endif
115 
116 template<> struct hash_ops<std::string> {
117  static inline bool cmp(const std::string &a, const std::string &b) {
118  return a == b;
119  }
120  static inline hm_uint hash(const std::string &a) {
121  hm_uint v = 0;
122  for (auto c : a)
123  v = mkhash(v, c);
124  return v;
125  }
126 };
127 
128 template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {
129  static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
130  return a == b;
131  }
132  static inline hm_uint hash(std::pair<P, Q> a) {
133  return mkhash(hash_ops<P>::hash(a.first), hash_ops<Q>::hash(a.second));
134  }
135 };
136 
137 template<typename... T> struct hash_ops<std::tuple<T...>> {
138  static inline bool cmp(std::tuple<T...> a, std::tuple<T...> b) {
139  return a == b;
140  }
141  template<size_t I = 0>
142  static inline typename std::enable_if<I == sizeof...(T), hm_uint>::type hash(std::tuple<T...>) {
143  return mkhash_init;
144  }
145  template<size_t I = 0>
146  static inline typename std::enable_if<I != sizeof...(T), hm_uint>::type hash(std::tuple<T...> a) {
147  typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
148  return mkhash(hash<I+1>(a), element_ops_t::hash(std::get<I>(a)));
149  }
150 };
151 
152 template<typename T> struct hash_ops<std::vector<T>> {
153  static inline bool cmp(std::vector<T> a, std::vector<T> b) {
154  return a == b;
155  }
156  static inline hm_uint hash(std::vector<T> a) {
157  hm_uint h = mkhash_init;
158  for (auto k : a)
159  h = mkhash(h, hash_ops<T>::hash(k));
160  return h;
161  }
162 };
163 
165  static inline bool cmp(const char *a, const char *b) {
166  for (int i = 0; a[i] || b[i]; i++)
167  if (a[i] != b[i])
168  return false;
169  return true;
170  }
171  static inline hm_uint hash(const char *a) {
173  while (*a)
174  hash = mkhash(hash, *(a++));
175  return hash;
176  }
177 };
178 
179 struct hash_ptr_ops {
180  static inline bool cmp(const void *a, const void *b) {
181  return a == b;
182  }
183  static inline hm_uint hash(const void *a) {
184  return (unsigned long)a;
185  }
186 };
187 
188 struct hash_obj_ops {
189  static inline bool cmp(const void *a, const void *b) {
190  return a == b;
191  }
192  template<typename T>
193  static inline hm_uint hash(const T *a) {
194  return a ? a->hash() : 0;
195  }
196 };
197 
198 template<typename T>
199 inline hm_uint mkhash(const T &v) {
200  return hash_ops<T>().hash(v);
201 }
202 
203 inline hm_int hashtable_size(hm_int min_size)
204 {
205  static std::vector<hm_int> zero_and_some_primes = {
206  0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,
207  853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,
208  12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281,
209  120371, 150473, 188107, 235159, 293957, 367453, 459317, 574157, 717697,
210  897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037,
211  5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411,
212  25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,
213  121590311, 151987889, 189984863, 237481091, 296851369, 371064217
214  };
215 
216  for (auto p : zero_and_some_primes)
217  if (p >= min_size) return p;
218 
219  if (sizeof(hm_int) == 4)
220  throw std::length_error("hash table exceeded maximum size. use a ILP64 abi for larger tables.");
221 
222  for (auto p : zero_and_some_primes)
223  if (100129 * p > min_size) return 100129 * p;
224 
225  throw std::length_error("hash table exceeded maximum size.");
226 }
227 
228 template<typename K, typename T, typename OPS = hash_ops<K>> class unordered_map;
229 template<typename K, hm_int offset = 0, typename OPS = hash_ops<K>> class idict;
230 template<typename K, typename OPS = hash_ops<K>> class unordered_set;
231 template<typename K, typename OPS = hash_ops<K>> class mfp;
232 
240 template<typename K, typename T, typename OPS>
242 {
244  struct entry_t
245  {
246  std::pair<K, T> udata;
247  hm_int next;
248 
249  entry_t() { }
250  entry_t(const std::pair<K, T> & idata, hm_int inext) : udata(idata), next(inext) { }
251  entry_t(std::pair<K, T> && idata, hm_int inext) : udata(std::move(idata)), next(inext) { }
252  };
253 
255  std::vector<hm_int> hashtable;
257  std::vector<entry_t> entries;
259  OPS ops;
260 
261  #ifdef NDEBUG
262  static inline void do_assert(bool) { }
263  #else
264  static inline void do_assert(bool cond) {
265  if (!cond) throw std::runtime_error("unordered_map<> assert failed.");
266  }
267  #endif
268 
269 
279  hm_int do_hash(const K &key) const
280  {
281  hm_uint hash = 0;
282  if (!hashtable.empty())
283  hash = ops.hash(key) % (hm_uint)(hashtable.size());
284  return hash;
285  }
286 
290  void do_rehash()
291  {
292  hashtable.clear();
293  hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
294 
295  for (hm_int i = 0; i < hm_int(entries.size()); i++) {
296  do_assert(-1 <= entries[i].next && entries[i].next < hm_int(entries.size()));
297  hm_int hash = do_hash(entries[i].udata.first);
298  entries[i].next = hashtable[hash];
299  hashtable[hash] = i;
300  }
301  }
302 
311  hm_int do_erase(hm_int index, hm_int hash)
312  {
313  do_assert(index < hm_int(entries.size()));
314  if (hashtable.empty() || index < 0)
315  return 0;
316 
317  hm_int k = hashtable[hash];
318  do_assert(0 <= k && k < hm_int(entries.size()));
319 
320  if (k == index) {
321  hashtable[hash] = entries[index].next;
322  } else {
323  while (entries[k].next != index) {
324  k = entries[k].next;
325  do_assert(0 <= k && k < hm_int(entries.size()));
326  }
327  entries[k].next = entries[index].next;
328  }
329 
330  hm_int back_idx = entries.size()-1;
331 
332  if (index != back_idx)
333  {
334  hm_int back_hash = do_hash(entries[back_idx].udata.first);
335 
336  k = hashtable[back_hash];
337  do_assert(0 <= k && k < hm_int(entries.size()));
338 
339  if (k == back_idx) {
340  hashtable[back_hash] = index;
341  } else {
342  while (entries[k].next != back_idx) {
343  k = entries[k].next;
344  do_assert(0 <= k && k < hm_int(entries.size()));
345  }
346  entries[k].next = index;
347  }
348 
349  entries[index] = std::move(entries[back_idx]);
350  }
351 
352  entries.pop_back();
353 
354  if (entries.empty())
355  hashtable.clear();
356 
357  return 1;
358  }
359 
368  hm_int do_lookup(const K &key, hm_int &hash) const
369  {
370  if (hashtable.empty())
371  return -1;
372 
373  if (entries.size() * hashtable_size_trigger > hashtable.size()) {
374  ((unordered_map*)this)->do_rehash();
375  hash = do_hash(key);
376  }
377 
378  hm_int index = hashtable[hash];
379 
380  while (index >= 0 && !ops.cmp(entries[index].udata.first, key)) {
381  index = entries[index].next;
382  do_assert(-1 <= index && index < hm_int(entries.size()));
383  }
384 
385  return index;
386  }
387 
399  hm_int do_insert(const K &key, hm_int &hash)
400  {
401  if (hashtable.empty()) {
402  entries.push_back(entry_t(std::pair<K, T>(key, T()), -1));
403  do_rehash();
404  hash = do_hash(key);
405  } else {
406  entries.push_back(entry_t(std::pair<K, T>(key, T()), hashtable[hash]));
407  hashtable[hash] = entries.size() - 1;
408  }
409  return entries.size() - 1;
410  }
411 
423  hm_int do_insert(const std::pair<K, T> &value, hm_int &hash)
424  {
425  if (hashtable.empty()) {
426  entries.push_back(entry_t(value, -1));
427  do_rehash();
428  hash = do_hash(value.first);
429  } else {
430  entries.push_back(entry_t(value, hashtable[hash]));
431  hashtable[hash] = entries.size() - 1;
432  }
433  return entries.size() - 1;
434  }
435 
436 
437 
438  public:
439 
442  friend class unordered_map;
443 
444  protected:
445  const unordered_map *ptr = nullptr;
447 
448  const_iterator(const unordered_map *iptr, hm_int iindex)
449  : ptr(iptr), index(iindex) { }
450 
451  public:
452  // Iterator traits
453  using iterator_category = std::forward_iterator_tag;
454  using value_type = std::pair<K, T>;
455  using difference_type = std::ptrdiff_t;
456  using pointer = const value_type*;
457  using reference = const value_type&;
458 
459  const_iterator() = default;
460 
461  // Pre-increment
462  const_iterator & operator++() { index--; return *this; }
463  // Post-increment
464  const_iterator operator++(int) { const_iterator tmp = *this; index--; return tmp; }
465 
466  // Pre-decrement
467  const_iterator & operator--() { index++; return *this; }
468  // Post-decrement
469  const_iterator operator--(int) { const_iterator tmp = *this; index++; return tmp; }
470 
471  // Comparison
472  bool operator<(const const_iterator &other) const { return index > other.index; }
473  bool operator==(const const_iterator &other) const { return index == other.index; }
474  bool operator!=(const const_iterator &other) const { return index != other.index; }
475 
476  // Dereference
477  reference operator*() const { return ptr->entries[index].udata; }
478  pointer operator->() const { return &ptr->entries[index].udata; }
479 };
480 
482 class iterator {
483  friend class unordered_map;
484 
485  protected:
486  unordered_map *ptr = nullptr;
488 
490  : ptr(iptr), index(iindex) { }
491 
492  public:
493  // Iterator traits
494  using iterator_category = std::forward_iterator_tag;
495  using value_type = std::pair<K, T>;
496  using difference_type = std::ptrdiff_t;
497  using pointer = value_type*;
499 
500  iterator() = default;
501 
502  // Pre-increment
503  iterator & operator++() { index--; return *this; }
504  // Post-increment
505  iterator operator++(int) { iterator tmp = *this; index--; return tmp; }
506 
507  // Pre-decrement
508  iterator & operator--() { index++; return *this; }
509  // Post-decrement
510  iterator operator--(int) { iterator tmp = *this; index++; return tmp; }
511 
512  // Comparison
513  bool operator<(const iterator &other) const { return index > other.index; }
514  bool operator==(const iterator &other) const { return index == other.index; }
515  bool operator!=(const iterator &other) const { return index != other.index; }
516 
517  // Dereference
518  reference operator*() { return ptr->entries[index].udata; }
519  pointer operator->() { return &ptr->entries[index].udata; }
520 
521  // Const dereference
522  const value_type &operator*() const { return ptr->entries[index].udata; }
523  const value_type *operator->() const { return &ptr->entries[index].udata; }
524 
525  // Conversion to const_iterator
526  operator const_iterator() const { return const_iterator(ptr, index); }
527  };
528 
531  {}
532 
535  {
536  entries = other.entries;
537  do_rehash();
538  }
539 
542  {
543  swap(other);
544  }
545 
547  entries = other.entries;
548  do_rehash();
549  return *this;
550  }
551 
553  clear();
554  swap(other);
555  return *this;
556  }
557 
558  unordered_map(const std::initializer_list<std::pair<K, T>> &list)
559  {
560  for (auto &it : list)
561  insert(it);
562  }
563 
565  template<class InputIterator>
566  unordered_map(InputIterator first, InputIterator last)
567  {
568  insert(first, last);
569  }
571  template<class InputIterator>
572  void insert(InputIterator first, InputIterator last)
573  {
574  for (; first != last; ++first)
575  insert(*first);
576  }
578  std::pair<iterator, bool> insert(const K &key)
579  {
580  hm_int hash = do_hash(key);
581  hm_int i = do_lookup(key, hash);
582  if (i >= 0)
583  return std::pair<iterator, bool>(iterator(this, i), false);
584  i = do_insert(key, hash);
585  return std::pair<iterator, bool>(iterator(this, i), true);
586  }
588  std::pair<iterator, bool> insert(const std::pair<K, T> &value)
589  {
590  hm_int hash = do_hash(value.first);
591  hm_int i = do_lookup(value.first, hash);
592  if (i >= 0)
593  return std::pair<iterator, bool>(iterator(this, i), false);
594  i = do_insert(value, hash);
595  return std::pair<iterator, bool>(iterator(this, i), true);
596  }
598  hm_int erase(const K &key)
599  {
600  hm_int hash = do_hash(key);
601  hm_int index = do_lookup(key, hash);
602  return do_erase(index, hash);
603  }
606  {
607  hm_int hash = do_hash(it->first);
608  do_erase(it.index, hash);
609  return ++it;
610  }
612  hm_int count(const K &key) const
613  {
614  hm_int hash = do_hash(key);
615  hm_int i = do_lookup(key, hash);
616  return i < 0 ? 0 : 1;
617  }
619  hm_int count(const K &key, const_iterator it) const
620  {
621  hm_int hash = do_hash(key);
622  hm_int i = do_lookup(key, hash);
623  return i < 0 || i > it.index ? 0 : 1;
624  }
626  iterator find(const K &key)
627  {
628  hm_int hash = do_hash(key);
629  hm_int i = do_lookup(key, hash);
630  if (i < 0)
631  return end();
632  return iterator(this, i);
633  }
634 
636  const_iterator find(const K &key) const
637  {
638  hm_int hash = do_hash(key);
639  hm_int i = do_lookup(key, hash);
640  if (i < 0)
641  return end();
642  return const_iterator(this, i);
643  }
644 
646  T& at(const K &key)
647  {
648  hm_int hash = do_hash(key);
649  hm_int i = do_lookup(key, hash);
650  if (i < 0)
651  throw std::out_of_range("unordered_map::at()");
652  return entries[i].udata.second;
653  }
654 
656  const T& at(const K &key) const
657  {
658  hm_int hash = do_hash(key);
659  hm_int i = do_lookup(key, hash);
660  if (i < 0)
661  throw std::out_of_range("unordered_map::at()");
662  return entries[i].udata.second;
663  }
664 
666  T at(const K &key, const T &defval) const
667  {
668  hm_int hash = do_hash(key);
669  hm_int i = do_lookup(key, hash);
670  if (i < 0)
671  return defval;
672  return entries[i].udata.second;
673  }
674 
676  T& operator[](const K &key)
677  {
678  hm_int hash = do_hash(key);
679  hm_int i = do_lookup(key, hash);
680  if (i < 0)
681  i = do_insert(std::pair<K, T>(key, T()), hash);
682  return entries[i].udata.second;
683  }
684 
691  template<typename Compare = std::less<K>>
692  void sort(Compare comp = Compare())
693  {
694  std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata.first, a.udata.first); });
695  do_rehash();
696  }
697 
698  void swap(unordered_map &other)
699  {
700  hashtable.swap(other.hashtable);
701  entries.swap(other.entries);
702  }
703 
704  bool operator==(const unordered_map &other) const {
705  if (size() != other.size())
706  return false;
707  for (auto &it : entries) {
708  auto oit = other.find(it.udata.first);
709  if (oit == other.end() || !(oit->second == it.udata.second))
710  return false;
711  }
712  return true;
713  }
714 
715  bool operator!=(const unordered_map &other) const {
716  return !operator==(other);
717  }
718 
719  void reserve(size_t n) { entries.reserve(n); }
720  size_t size() const { return entries.size(); }
721  bool empty() const { return entries.empty(); }
722  void clear() { hashtable.clear(); entries.clear(); }
723 
724  iterator begin() { return iterator(this, hm_int(entries.size())-1); }
725  iterator end() { return iterator(nullptr, -1); }
726 
727  const_iterator begin() const { return const_iterator(this, hm_int(entries.size())-1); }
728  const_iterator end() const { return const_iterator(nullptr, -1); }
729 };
730 
737 template<typename K, typename OPS>
739 {
740  template<typename, hm_int, typename> friend class idict;
741 
742  protected:
744  struct entry_t
745  {
746  K udata;
748 
749  entry_t() { }
750  entry_t(const K &idata, hm_int inext) : udata(idata), next(inext) { }
751  };
752 
754  std::vector<hm_int> hashtable;
756  std::vector<entry_t> entries;
758  OPS ops;
759 
760  #ifdef NDEBUG
761  static inline void do_assert(bool) { }
762  #else
763  static inline void do_assert(bool cond) {
764  if (!cond) throw std::runtime_error("unordered_set<> assert failed.");
765  }
766  #endif
767 
777  hm_int do_hash(const K &key) const
778  {
779  hm_uint hash = 0;
780  if (!hashtable.empty())
781  hash = ops.hash(key) % (hm_uint)(hashtable.size());
782  return hash;
783  }
784 
788  void do_rehash()
789  {
790  hashtable.clear();
791  hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
792 
793  for (hm_int i = 0; i < hm_int(entries.size()); i++) {
794  do_assert(-1 <= entries[i].next && entries[i].next < hm_int(entries.size()));
795  hm_int hash = do_hash(entries[i].udata);
796  entries[i].next = hashtable[hash];
797  hashtable[hash] = i;
798  }
799  }
800 
810  {
811  do_assert(index < hm_int(entries.size()));
812  if (hashtable.empty() || index < 0)
813  return 0;
814 
815  hm_int k = hashtable[hash];
816  if (k == index) {
817  hashtable[hash] = entries[index].next;
818  } else {
819  while (entries[k].next != index) {
820  k = entries[k].next;
821  do_assert(0 <= k && k < hm_int(entries.size()));
822  }
823  entries[k].next = entries[index].next;
824  }
825 
826  hm_int back_idx = entries.size()-1;
827 
828  if (index != back_idx)
829  {
830  hm_int back_hash = do_hash(entries[back_idx].udata);
831 
832  k = hashtable[back_hash];
833  if (k == back_idx) {
834  hashtable[back_hash] = index;
835  } else {
836  while (entries[k].next != back_idx) {
837  k = entries[k].next;
838  do_assert(0 <= k && k < hm_int(entries.size()));
839  }
840  entries[k].next = index;
841  }
842 
843  entries[index] = std::move(entries[back_idx]);
844  }
845 
846  entries.pop_back();
847 
848  if (entries.empty())
849  hashtable.clear();
850 
851  return 1;
852  }
853 
862  hm_int do_lookup(const K &key, hm_int &hash) const
863  {
864  if (hashtable.empty())
865  return -1;
866 
867  if (entries.size() * hashtable_size_trigger > hashtable.size()) {
868  ((unordered_set*)this)->do_rehash();
869  hash = do_hash(key);
870  }
871 
872  hm_int index = hashtable[hash];
873 
874  while (index >= 0 && !ops.cmp(entries[index].udata, key)) {
875  index = entries[index].next;
876  do_assert(-1 <= index && index < hm_int(entries.size()));
877  }
878 
879  return index;
880  }
881 
893  hm_int do_insert(const K &value, hm_int &hash)
894  {
895  if (hashtable.empty()) {
896  entries.push_back(entry_t(value, -1));
897  do_rehash();
898  hash = do_hash(value);
899  }
900  else {
901  entries.push_back(entry_t(value, hashtable[hash]));
902  hashtable[hash] = entries.size() - 1;
903  }
904  return entries.size() - 1;
905  }
906 
907  public:
910  friend class unordered_set;
911 
912  protected:
913  const unordered_set *ptr = nullptr;
915 
916  const_iterator(const unordered_set *iptr, hm_int iindex)
917  : ptr(iptr), index(iindex) { }
918 
919  public:
920  // Iterator traits
921  using iterator_category = std::forward_iterator_tag;
922  using value_type = K;
923  using difference_type = std::ptrdiff_t;
924  using pointer = const value_type*;
925  using reference = const value_type&;
926 
927  const_iterator() = default;
928 
929  // Pre-increment
930  const_iterator & operator++() { index--; return *this; }
931  // Post-increment
932  const_iterator operator++(int) { const_iterator tmp = *this; index--; return tmp; }
933 
934  // Pre-decrement
935  const_iterator & operator--() { index++; return *this; }
936  // Post-decrement
937  const_iterator operator--(int) { const_iterator tmp = *this; index++; return tmp; }
938 
939  // Comparison
940  bool operator==(const const_iterator &other) const { return index == other.index; }
941  bool operator!=(const const_iterator &other) const { return index != other.index; }
942 
943  // Dereference
944  reference operator*() const { return ptr->entries[index].udata; }
945  pointer operator->() const { return &ptr->entries[index].udata; }
946 };
947 
949 class iterator {
950  friend class unordered_set;
951 
952  protected:
953  unordered_set *ptr = nullptr;
955 
957  : ptr(iptr), index(iindex) { }
958 
959  public:
960  // Iterator traits
961  using iterator_category = std::forward_iterator_tag;
962  using value_type = K;
963  using difference_type = std::ptrdiff_t;
964  using pointer = value_type*;
966 
967  iterator() = default;
968 
969  // Pre-increment
970  iterator & operator++() { index--; return *this; }
971  // Post-increment
972  iterator operator++(int) { iterator tmp = *this; index--; return tmp; }
973 
974  // Pre-decrement
975  iterator & operator--() { index++; return *this; }
976  // Post-decrement
977  iterator operator--(int) { iterator tmp = *this; index++; return tmp; }
978 
979  // Comparison
980  bool operator==(const iterator &other) const { return index == other.index; }
981  bool operator!=(const iterator &other) const { return index != other.index; }
982 
983  // Dereference
984  reference operator*() { return ptr->entries[index].udata; }
985  pointer operator->() { return &ptr->entries[index].udata; }
986 
987  // Const dereference
988  const value_type &operator*() const { return ptr->entries[index].udata; }
989  const value_type *operator->() const { return &ptr->entries[index].udata; }
990 
991  // Conversion to const_iterator
992  operator const_iterator() const { return const_iterator(ptr, index); }
993 };
994 
997  { }
998 
1001  {
1002  entries = other.entries;
1003  do_rehash();
1004  }
1005 
1008  {
1009  swap(other);
1010  }
1011 
1013  entries = other.entries;
1014  do_rehash();
1015  return *this;
1016  }
1017 
1019  clear();
1020  swap(other);
1021  return *this;
1022  }
1023 
1024  unordered_set(const std::initializer_list<K> &list)
1025  {
1026  for (auto &it : list)
1027  insert(it);
1028  }
1029 
1030  template<class InputIterator>
1031  unordered_set(InputIterator first, InputIterator last)
1032  {
1033  insert(first, last);
1034  }
1035 
1036  template<class InputIterator>
1037  void insert(InputIterator first, InputIterator last)
1038  {
1039  for (; first != last; ++first)
1040  insert(*first);
1041  }
1042 
1043  std::pair<iterator, bool> insert(const K &value)
1044  {
1045  hm_int hash = do_hash(value);
1046  hm_int i = do_lookup(value, hash);
1047  if (i >= 0)
1048  return std::pair<iterator, bool>(iterator(this, i), false);
1049  i = do_insert(value, hash);
1050  return std::pair<iterator, bool>(iterator(this, i), true);
1051  }
1052 
1053  hm_int erase(const K &key)
1054  {
1055  hm_int hash = do_hash(key);
1056  hm_int index = do_lookup(key, hash);
1057  return do_erase(index, hash);
1058  }
1059 
1061  {
1062  hm_int hash = do_hash(*it);
1063  do_erase(it.index, hash);
1064  return ++it;
1065  }
1066 
1067  hm_int count(const K &key) const
1068  {
1069  hm_int hash = do_hash(key);
1070  hm_int i = do_lookup(key, hash);
1071  return i < 0 ? 0 : 1;
1072  }
1073 
1074  hm_int count(const K &key, const_iterator it) const
1075  {
1076  hm_int hash = do_hash(key);
1077  hm_int i = do_lookup(key, hash);
1078  return i < 0 || i > it.index ? 0 : 1;
1079  }
1080 
1081  iterator find(const K &key)
1082  {
1083  hm_int hash = do_hash(key);
1084  hm_int i = do_lookup(key, hash);
1085  if (i < 0)
1086  return end();
1087  return iterator(this, i);
1088  }
1089 
1090  const_iterator find(const K &key) const
1091  {
1092  hm_int hash = do_hash(key);
1093  hm_int i = do_lookup(key, hash);
1094  if (i < 0)
1095  return end();
1096  return const_iterator(this, i);
1097  }
1098 
1099  bool operator[](const K &key)
1100  {
1101  hm_int hash = do_hash(key);
1102  hm_int i = do_lookup(key, hash);
1103  return i >= 0;
1104  }
1105 
1106  template<typename Compare = std::less<K>>
1107  void sort(Compare comp = Compare())
1108  {
1109  std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata, a.udata); });
1110  do_rehash();
1111  }
1112 
1113  K pop()
1114  {
1115  iterator it = begin();
1116  K ret = *it;
1117  erase(it);
1118  return ret;
1119  }
1120 
1121  void swap(unordered_set &other)
1122  {
1123  hashtable.swap(other.hashtable);
1124  entries.swap(other.entries);
1125  }
1126 
1127  bool operator==(const unordered_set &other) const {
1128  if (size() != other.size())
1129  return false;
1130  for (auto &it : entries)
1131  if (!other.count(it.udata))
1132  return false;
1133  return true;
1134  }
1135 
1136  bool operator!=(const unordered_set &other) const {
1137  return !operator==(other);
1138  }
1139 
1140  void reserve(size_t n) { entries.reserve(n); }
1141  size_t size() const { return entries.size(); }
1142  bool empty() const { return entries.empty(); }
1143  void clear() { hashtable.clear(); entries.clear(); }
1144 
1145  iterator begin() { return iterator(this, hm_int(entries.size())-1); }
1146  iterator end() { return iterator(nullptr, -1); }
1147 
1148  const_iterator begin() const { return const_iterator(this, hm_int(entries.size())-1); }
1149  const_iterator end() const { return const_iterator(nullptr, -1); }
1150 };
1151 
1152 template<typename K, hm_int offset, typename OPS>
1153 class idict
1154 {
1155  unordered_set<K, OPS> database;
1156 
1157 public:
1159 
1160  hm_int operator()(const K &key)
1161  {
1162  hm_int hash = database.do_hash(key);
1163  hm_int i = database.do_lookup(key, hash);
1164  if (i < 0)
1165  i = database.do_insert(key, hash);
1166  return i + offset;
1167  }
1168 
1169  hm_int at(const K &key) const
1170  {
1171  hm_int hash = database.do_hash(key);
1172  hm_int i = database.do_lookup(key, hash);
1173  if (i < 0)
1174  throw std::out_of_range("idict::at()");
1175  return i + offset;
1176  }
1177 
1178  hm_int at(const K &key, hm_int defval) const
1179  {
1180  hm_int hash = database.do_hash(key);
1181  hm_int i = database.do_lookup(key, hash);
1182  if (i < 0)
1183  return defval;
1184  return i + offset;
1185  }
1186 
1187  hm_int count(const K &key) const
1188  {
1189  hm_int hash = database.do_hash(key);
1190  hm_int i = database.do_lookup(key, hash);
1191  return i < 0 ? 0 : 1;
1192  }
1193 
1194  void expect(const K &key, hm_int i)
1195  {
1196  hm_int j = (*this)(key);
1197  if (i != j)
1198  throw std::out_of_range("idict::expect()");
1199  }
1200 
1201  const K &operator[](hm_int index) const
1202  {
1203  return database.entries.at(index - offset).udata;
1204  }
1205 
1206  void swap(idict &other)
1207  {
1208  database.swap(other.database);
1209  }
1210 
1211  void reserve(size_t n) { database.reserve(n); }
1212  size_t size() const { return database.size(); }
1213  bool empty() const { return database.empty(); }
1214  void clear() { database.clear(); }
1215 
1216  const_iterator begin() const { return database.begin(); }
1217  const_iterator end() const { return database.end(); }
1218 };
1219 
1220 template<typename K, typename OPS>
1221 class mfp
1222 {
1223  mutable idict<K, 0, OPS> database;
1224  mutable std::vector<hm_int> parents;
1225 
1226 public:
1228 
1229  hm_int operator()(const K &key) const
1230  {
1231  hm_int i = database(key);
1232  parents.resize(database.size(), -1);
1233  return i;
1234  }
1235 
1236  const K &operator[](hm_int index) const
1237  {
1238  return database[index];
1239  }
1240 
1242  {
1243  hm_int p = i, k = i;
1244 
1245  while (parents[p] != -1)
1246  p = parents[p];
1247 
1248  while (k != p) {
1249  hm_int next_k = parents[k];
1250  parents[k] = p;
1251  k = next_k;
1252  }
1253 
1254  return p;
1255  }
1256 
1257  void imerge(hm_int i, hm_int j)
1258  {
1259  i = ifind(i);
1260  j = ifind(j);
1261 
1262  if (i != j)
1263  parents[i] = j;
1264  }
1265 
1267  {
1268  hm_int k = i;
1269 
1270  while (k != -1) {
1271  hm_int next_k = parents[k];
1272  parents[k] = i;
1273  k = next_k;
1274  }
1275 
1276  parents[i] = -1;
1277  }
1278 
1279  hm_int lookup(const K &a) const
1280  {
1281  return ifind((*this)(a));
1282  }
1283 
1284  const K &find(const K &a) const
1285  {
1286  hm_int i = database.at(a, -1);
1287  if (i < 0)
1288  return a;
1289  return (*this)[ifind(i)];
1290  }
1291 
1292  void merge(const K &a, const K &b)
1293  {
1294  imerge((*this)(a), (*this)(b));
1295  }
1296 
1297  void promote(const K &a)
1298  {
1299  hm_int i = database.at(a, -1);
1300  if (i >= 0)
1301  ipromote(i);
1302  }
1303 
1304  void swap(mfp &other)
1305  {
1306  database.swap(other.database);
1307  parents.swap(other.parents);
1308  }
1309 
1310  void reserve(size_t n) { database.reserve(n); }
1311  size_t size() const { return database.size(); }
1312  bool empty() const { return database.empty(); }
1313  void clear() { database.clear(); parents.clear(); }
1314 
1315  const_iterator begin() const { return database.begin(); }
1316  const_iterator end() const { return database.end(); }
1317 };
1318 
1319 } /* namespace hashmap */
1320 
1321 #endif
void swap(idict &other)
Definition: hashmap.hpp:1206
hm_int operator()(const K &key)
Definition: hashmap.hpp:1160
const K & operator[](hm_int index) const
Definition: hashmap.hpp:1201
void expect(const K &key, hm_int i)
Definition: hashmap.hpp:1194
void reserve(size_t n)
Definition: hashmap.hpp:1211
const_iterator begin() const
Definition: hashmap.hpp:1216
hm_int at(const K &key) const
Definition: hashmap.hpp:1169
size_t size() const
Definition: hashmap.hpp:1212
unordered_set< K, OPS >::const_iterator const_iterator
Definition: hashmap.hpp:1158
hm_int count(const K &key) const
Definition: hashmap.hpp:1187
bool empty() const
Definition: hashmap.hpp:1213
const_iterator end() const
Definition: hashmap.hpp:1217
hm_int at(const K &key, hm_int defval) const
Definition: hashmap.hpp:1178
hm_int operator()(const K &key) const
Definition: hashmap.hpp:1229
hm_int lookup(const K &a) const
Definition: hashmap.hpp:1279
void swap(mfp &other)
Definition: hashmap.hpp:1304
void ipromote(hm_int i)
Definition: hashmap.hpp:1266
const K & operator[](hm_int index) const
Definition: hashmap.hpp:1236
void reserve(size_t n)
Definition: hashmap.hpp:1310
const K & find(const K &a) const
Definition: hashmap.hpp:1284
void clear()
Definition: hashmap.hpp:1313
hm_int ifind(hm_int i) const
Definition: hashmap.hpp:1241
const_iterator begin() const
Definition: hashmap.hpp:1315
idict< K, 0, OPS >::const_iterator const_iterator
Definition: hashmap.hpp:1227
void promote(const K &a)
Definition: hashmap.hpp:1297
bool empty() const
Definition: hashmap.hpp:1312
void imerge(hm_int i, hm_int j)
Definition: hashmap.hpp:1257
const_iterator end() const
Definition: hashmap.hpp:1316
size_t size() const
Definition: hashmap.hpp:1311
void merge(const K &a, const K &b)
Definition: hashmap.hpp:1292
const_iterator(const unordered_map *iptr, hm_int iindex)
Definition: hashmap.hpp:448
std::forward_iterator_tag iterator_category
Definition: hashmap.hpp:453
bool operator!=(const const_iterator &other) const
Definition: hashmap.hpp:474
bool operator==(const const_iterator &other) const
Definition: hashmap.hpp:473
bool operator<(const const_iterator &other) const
Definition: hashmap.hpp:472
const value_type & operator*() const
Definition: hashmap.hpp:522
std::pair< K, T > value_type
Definition: hashmap.hpp:495
std::forward_iterator_tag iterator_category
Definition: hashmap.hpp:494
bool operator!=(const iterator &other) const
Definition: hashmap.hpp:515
iterator(unordered_map *iptr, hm_int iindex)
Definition: hashmap.hpp:489
const value_type * operator->() const
Definition: hashmap.hpp:523
bool operator<(const iterator &other) const
Definition: hashmap.hpp:513
bool operator==(const iterator &other) const
Definition: hashmap.hpp:514
T at(const K &key, const T &defval) const
Return data if existent or default value.
Definition: hashmap.hpp:666
iterator find(const K &key)
Search for key. Return iterator.
Definition: hashmap.hpp:626
hm_int count(const K &key, const_iterator it) const
Check if key exists and matches iterator.
Definition: hashmap.hpp:619
unordered_map & operator=(const unordered_map &other)
Definition: hashmap.hpp:546
const_iterator end() const
Definition: hashmap.hpp:728
unordered_map(const std::initializer_list< std::pair< K, T >> &list)
Definition: hashmap.hpp:558
unordered_map(unordered_map &&other)
Construct map form another map.
Definition: hashmap.hpp:541
hm_int count(const K &key) const
Check if key exists.
Definition: hashmap.hpp:612
bool operator!=(const unordered_map &other) const
Definition: hashmap.hpp:715
const_iterator begin() const
Definition: hashmap.hpp:727
std::pair< iterator, bool > insert(const std::pair< K, T > &value)
Insert key-value pair.
Definition: hashmap.hpp:588
const T & at(const K &key) const
Const data access by key.
Definition: hashmap.hpp:656
T & operator[](const K &key)
Data access or empty insert.
Definition: hashmap.hpp:676
void swap(unordered_map &other)
Definition: hashmap.hpp:698
void sort(Compare comp=Compare())
Sort data entries.
Definition: hashmap.hpp:692
bool operator==(const unordered_map &other) const
Definition: hashmap.hpp:704
const_iterator find(const K &key) const
Search for key. Return const_iterator.
Definition: hashmap.hpp:636
bool empty() const
Definition: hashmap.hpp:721
void reserve(size_t n)
Definition: hashmap.hpp:719
std::pair< iterator, bool > insert(const K &key)
User insert as key lookup.
Definition: hashmap.hpp:578
void insert(InputIterator first, InputIterator last)
Insert Iterator range.
Definition: hashmap.hpp:572
iterator erase(iterator it)
Erase by iterator.
Definition: hashmap.hpp:605
unordered_map()
Empty constructor.
Definition: hashmap.hpp:530
T & at(const K &key)
Data access by key.
Definition: hashmap.hpp:646
unordered_map(InputIterator first, InputIterator last)
Construct from Iterator range.
Definition: hashmap.hpp:566
unordered_map & operator=(unordered_map &&other)
Definition: hashmap.hpp:552
size_t size() const
Definition: hashmap.hpp:720
hm_int erase(const K &key)
Erase by key.
Definition: hashmap.hpp:598
unordered_map(const unordered_map &other)
Construct from another map.
Definition: hashmap.hpp:534
bool operator==(const const_iterator &other) const
Definition: hashmap.hpp:940
std::forward_iterator_tag iterator_category
Definition: hashmap.hpp:921
bool operator!=(const const_iterator &other) const
Definition: hashmap.hpp:941
const_iterator(const unordered_set *iptr, hm_int iindex)
Definition: hashmap.hpp:916
const value_type & operator*() const
Definition: hashmap.hpp:988
std::forward_iterator_tag iterator_category
Definition: hashmap.hpp:961
bool operator!=(const iterator &other) const
Definition: hashmap.hpp:981
const value_type * operator->() const
Definition: hashmap.hpp:989
iterator(unordered_set *iptr, hm_int iindex)
Definition: hashmap.hpp:956
bool operator==(const iterator &other) const
Definition: hashmap.hpp:980
Custom unordered_set implementation.
Definition: hashmap.hpp:739
size_t size() const
Definition: hashmap.hpp:1141
unordered_set(InputIterator first, InputIterator last)
Definition: hashmap.hpp:1031
unordered_set(unordered_set &&other)
Construct from another set.
Definition: hashmap.hpp:1007
unordered_set & operator=(unordered_set &&other)
Definition: hashmap.hpp:1018
iterator find(const K &key)
Definition: hashmap.hpp:1081
std::pair< iterator, bool > insert(const K &value)
Definition: hashmap.hpp:1043
const_iterator end() const
Definition: hashmap.hpp:1149
void sort(Compare comp=Compare())
Definition: hashmap.hpp:1107
hm_int erase(const K &key)
Definition: hashmap.hpp:1053
const_iterator find(const K &key) const
Definition: hashmap.hpp:1090
bool operator==(const unordered_set &other) const
Definition: hashmap.hpp:1127
hm_int do_erase(hm_int index, hm_int hash)
Remove an entry.
Definition: hashmap.hpp:809
unordered_set(const unordered_set &other)
Construct from another set.
Definition: hashmap.hpp:1000
unordered_set(const std::initializer_list< K > &list)
Definition: hashmap.hpp:1024
OPS ops
the hash generator
Definition: hashmap.hpp:758
unordered_set & operator=(const unordered_set &other)
Definition: hashmap.hpp:1012
iterator erase(iterator it)
Definition: hashmap.hpp:1060
void do_rehash()
Resize the hashtable and compute new hashes.
Definition: hashmap.hpp:788
const_iterator begin() const
Definition: hashmap.hpp:1148
bool empty() const
Definition: hashmap.hpp:1142
hm_int do_hash(const K &key) const
Generate a hash from a key.
Definition: hashmap.hpp:777
std::vector< entry_t > entries
the stored entries
Definition: hashmap.hpp:756
std::vector< hm_int > hashtable
the hashtable
Definition: hashmap.hpp:754
static void do_assert(bool cond)
Definition: hashmap.hpp:763
void reserve(size_t n)
Definition: hashmap.hpp:1140
void swap(unordered_set &other)
Definition: hashmap.hpp:1121
hm_int do_lookup(const K &key, hm_int &hash) const
Return hash and index for a key.
Definition: hashmap.hpp:862
bool operator[](const K &key)
Definition: hashmap.hpp:1099
unordered_set()
Empty constructor.
Definition: hashmap.hpp:996
bool operator!=(const unordered_set &other) const
Definition: hashmap.hpp:1136
hm_int count(const K &key) const
Definition: hashmap.hpp:1067
void insert(InputIterator first, InputIterator last)
Definition: hashmap.hpp:1037
hm_int count(const K &key, const_iterator it) const
Definition: hashmap.hpp:1074
hm_int do_insert(const K &value, hm_int &hash)
Insert a pair consisting of a key and a default (empty) value.
Definition: hashmap.hpp:893
long int hm_int
Definition: hashmap.hpp:29
unsigned long int hm_uint
Definition: hashmap.hpp:28
const hm_int hashtable_size_trigger
Definition: hashmap.hpp:33
hm_int hashtable_size(hm_int min_size)
Definition: hashmap.hpp:203
const hm_uint mkhash_init
Definition: hashmap.hpp:42
hm_uint mkhash_add(hm_uint a, hm_uint b)
Definition: hashmap.hpp:46
hm_uint mkhash(hm_uint a, hm_uint b)
Definition: hashmap.hpp:37
const hm_int hashtable_size_factor
Definition: hashmap.hpp:34
hm_uint mkhash_xorshift(hm_uint a)
Definition: hashmap.hpp:50
static hm_uint hash(const char *a)
Definition: hashmap.hpp:171
static bool cmp(const char *a, const char *b)
Definition: hashmap.hpp:165
static bool cmp(T a, T b)
Definition: hashmap.hpp:84
static hm_uint hash(const T *a)
Definition: hashmap.hpp:193
static bool cmp(const void *a, const void *b)
Definition: hashmap.hpp:189
static hm_uint hash(int32_t a)
Definition: hashmap.hpp:91
static hm_uint hash(int64_t a)
Definition: hashmap.hpp:97
static hm_uint hash(std::pair< P, Q > a)
Definition: hashmap.hpp:132
static bool cmp(std::pair< P, Q > a, std::pair< P, Q > b)
Definition: hashmap.hpp:129
static hm_uint hash(const std::string &a)
Definition: hashmap.hpp:120
static bool cmp(const std::string &a, const std::string &b)
Definition: hashmap.hpp:117
static std::enable_if< I !=sizeof...(T), hm_uint >::type hash(std::tuple< T... > a)
Definition: hashmap.hpp:146
static std::enable_if< I==sizeof...(T), hm_uint >::type hash(std::tuple< T... >)
Definition: hashmap.hpp:142
static bool cmp(std::tuple< T... > a, std::tuple< T... > b)
Definition: hashmap.hpp:138
static hm_uint hash(std::vector< T > a)
Definition: hashmap.hpp:156
static bool cmp(std::vector< T > a, std::vector< T > b)
Definition: hashmap.hpp:153
Base hashing class.
Definition: hashmap.hpp:73
static hm_uint hash(const T &a)
Definition: hashmap.hpp:77
static bool cmp(const T &a, const T &b)
Definition: hashmap.hpp:74
static hm_uint hash(const void *a)
Definition: hashmap.hpp:183
static bool cmp(const void *a, const void *b)
Definition: hashmap.hpp:180
internal entry type
Definition: hashmap.hpp:745
entry_t(const K &idata, hm_int inext)
Definition: hashmap.hpp:750