openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
hashmap.hpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // openCARP is an open cardiac electrophysiology simulator.
3 //
4 // Copyright (C) 2020 openCARP project
5 //
6 // This program is licensed under the openCARP Academic Public License (APL)
7 // v1.0: You can use and redistribute it and/or modify it in non-commercial
8 // academic environments under the terms of APL as published by the openCARP
9 // project v1.0, or (at your option) any later version. Commercial use requires
10 // a commercial license (info@opencarp.org).
11 //
12 // This program is distributed without any warranty; see the openCARP APL for
13 // more details.
14 //
15 // You should have received a copy of the openCARP APL along with this program
16 // and can find it online: http://www.opencarp.org/license
17 // ----------------------------------------------------------------------------
18 
30 #ifndef _MT_HASHMAP_H
31 #define _MT_HASHMAP_H
32 
33 #include <stdint.h>
34 #include <limits.h>
35 
36 #include <stdexcept>
37 #include <algorithm>
38 #include <string>
39 #include <vector>
40 
41 // #define NDEBUG
42 
43 typedef unsigned long int hm_uint;
44 typedef long int hm_int;
45 
46 namespace hashmap {
47 
50 
51 // The XOR version of DJB2
52 inline hm_uint mkhash(hm_uint a, hm_uint b) {
53  return ((a << 5) + a) ^ b;
54 }
55 
56 // traditionally 5381 is used as starting value for the djb2 hash
57 const hm_uint mkhash_init = 5381;
58 
59 // The ADD version of DJB2
60 // (use this version for cache locality in b)
62  return ((a << 5) + a) + b;
63 }
64 
66  if (sizeof(a) == 4) {
67  a ^= a << 13;
68  a ^= a >> 17;
69  a ^= a << 5;
70  } else if (sizeof(a) == 8) {
71  a ^= a << 13;
72  a ^= a >> 7;
73  a ^= a << 17;
74  } else
75  throw std::runtime_error("mkhash_xorshift() only implemented for 32 bit and 64 bit ints");
76  return a;
77 }
78 
79 // ================== Hashing structs ==============================
80 
86 template<typename T>
87 struct hash_ops
88 {
89  static inline bool cmp(const T &a, const T &b) {
90  return a == b;
91  }
92  static inline hm_uint hash(const T &a) {
93  return a.hash();
94  }
95 };
96 
97 struct hash_int_ops {
98  template<typename T>
99  static inline bool cmp(T a, T b) {
100  return a == b;
101  }
102 };
103 
104 template<> struct hash_ops<int32_t> : hash_int_ops
105 {
106  static inline hm_uint hash(int32_t a) {
107  return a;
108  }
109 };
110 template<> struct hash_ops<int64_t> : hash_int_ops
111 {
112  static inline hm_uint hash(int64_t a) {
113  return mkhash((hm_uint)(a), (hm_uint)(a >> 32));
114  }
115 };
116 
117 // in the case that long is not an int64 we define an additional long hasher
118 #ifdef __APPLE__
119 template<> struct hash_ops<long> : hash_int_ops
120 {
121  static inline hm_uint hash(long a) {
122  return (hm_uint)a;
123  }
124 };
125 #endif
126 
127 template<> struct hash_ops<std::string> {
128  static inline bool cmp(const std::string &a, const std::string &b) {
129  return a == b;
130  }
131  static inline hm_uint hash(const std::string &a) {
132  hm_uint v = 0;
133  for (auto c : a)
134  v = mkhash(v, c);
135  return v;
136  }
137 };
138 
139 template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {
140  static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
141  return a == b;
142  }
143  static inline hm_uint hash(std::pair<P, Q> a) {
144  return mkhash(hash_ops<P>::hash(a.first), hash_ops<Q>::hash(a.second));
145  }
146 };
147 
148 template<typename... T> struct hash_ops<std::tuple<T...>> {
149  static inline bool cmp(std::tuple<T...> a, std::tuple<T...> b) {
150  return a == b;
151  }
152  template<size_t I = 0>
153  static inline typename std::enable_if<I == sizeof...(T), hm_uint>::type hash(std::tuple<T...>) {
154  return mkhash_init;
155  }
156  template<size_t I = 0>
157  static inline typename std::enable_if<I != sizeof...(T), hm_uint>::type hash(std::tuple<T...> a) {
158  typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
159  return mkhash(hash<I+1>(a), element_ops_t::hash(std::get<I>(a)));
160  }
161 };
162 
163 template<typename T> struct hash_ops<std::vector<T>> {
164  static inline bool cmp(std::vector<T> a, std::vector<T> b) {
165  return a == b;
166  }
167  static inline hm_uint hash(std::vector<T> a) {
168  hm_uint h = mkhash_init;
169  for (auto k : a)
170  h = mkhash(h, hash_ops<T>::hash(k));
171  return h;
172  }
173 };
174 
176  static inline bool cmp(const char *a, const char *b) {
177  for (int i = 0; a[i] || b[i]; i++)
178  if (a[i] != b[i])
179  return false;
180  return true;
181  }
182  static inline hm_uint hash(const char *a) {
184  while (*a)
185  hash = mkhash(hash, *(a++));
186  return hash;
187  }
188 };
189 
190 struct hash_ptr_ops {
191  static inline bool cmp(const void *a, const void *b) {
192  return a == b;
193  }
194  static inline hm_uint hash(const void *a) {
195  return (unsigned long)a;
196  }
197 };
198 
199 struct hash_obj_ops {
200  static inline bool cmp(const void *a, const void *b) {
201  return a == b;
202  }
203  template<typename T>
204  static inline hm_uint hash(const T *a) {
205  return a ? a->hash() : 0;
206  }
207 };
208 
209 template<typename T>
210 inline hm_uint mkhash(const T &v) {
211  return hash_ops<T>().hash(v);
212 }
213 
214 inline hm_int hashtable_size(hm_int min_size)
215 {
216  static std::vector<hm_int> zero_and_some_primes = {
217  0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,
218  853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,
219  12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281,
220  120371, 150473, 188107, 235159, 293957, 367453, 459317, 574157, 717697,
221  897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037,
222  5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411,
223  25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,
224  121590311, 151987889, 189984863, 237481091, 296851369, 371064217
225  };
226 
227  for (auto p : zero_and_some_primes)
228  if (p >= min_size) return p;
229 
230  if (sizeof(hm_int) == 4)
231  throw std::length_error("hash table exceeded maximum size. use a ILP64 abi for larger tables.");
232 
233  for (auto p : zero_and_some_primes)
234  if (100129 * p > min_size) return 100129 * p;
235 
236  throw std::length_error("hash table exceeded maximum size.");
237 }
238 
239 template<typename K, typename T, typename OPS = hash_ops<K>> class unordered_map;
240 template<typename K, hm_int offset = 0, typename OPS = hash_ops<K>> class idict;
241 template<typename K, typename OPS = hash_ops<K>> class unordered_set;
242 template<typename K, typename OPS = hash_ops<K>> class mfp;
243 
251 template<typename K, typename T, typename OPS>
252 class unordered_map
253 {
255  struct entry_t
256  {
257  std::pair<K, T> udata;
258  hm_int next;
259 
260  entry_t() { }
261  entry_t(const std::pair<K, T> & idata, hm_int inext) : udata(idata), next(inext) { }
262  entry_t(std::pair<K, T> && idata, hm_int inext) : udata(std::move(idata)), next(inext) { }
263  };
264 
266  std::vector<hm_int> hashtable;
268  std::vector<entry_t> entries;
270  OPS ops;
271 
272  #ifdef NDEBUG
273  static inline void do_assert(bool) { }
274  #else
275  static inline void do_assert(bool cond) {
276  if (!cond) throw std::runtime_error("unordered_map<> assert failed.");
277  }
278  #endif
279 
280 
290  hm_int do_hash(const K &key) const
291  {
292  hm_uint hash = 0;
293  if (!hashtable.empty())
294  hash = ops.hash(key) % (hm_uint)(hashtable.size());
295  return hash;
296  }
297 
301  void do_rehash()
302  {
303  hashtable.clear();
304  hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
305 
306  for (hm_int i = 0; i < hm_int(entries.size()); i++) {
307  do_assert(-1 <= entries[i].next && entries[i].next < hm_int(entries.size()));
308  hm_int hash = do_hash(entries[i].udata.first);
309  entries[i].next = hashtable[hash];
310  hashtable[hash] = i;
311  }
312  }
313 
322  hm_int do_erase(hm_int index, hm_int hash)
323  {
324  do_assert(index < hm_int(entries.size()));
325  if (hashtable.empty() || index < 0)
326  return 0;
327 
328  hm_int k = hashtable[hash];
329  do_assert(0 <= k && k < hm_int(entries.size()));
330 
331  if (k == index) {
332  hashtable[hash] = entries[index].next;
333  } else {
334  while (entries[k].next != index) {
335  k = entries[k].next;
336  do_assert(0 <= k && k < hm_int(entries.size()));
337  }
338  entries[k].next = entries[index].next;
339  }
340 
341  hm_int back_idx = entries.size()-1;
342 
343  if (index != back_idx)
344  {
345  hm_int back_hash = do_hash(entries[back_idx].udata.first);
346 
347  k = hashtable[back_hash];
348  do_assert(0 <= k && k < hm_int(entries.size()));
349 
350  if (k == back_idx) {
351  hashtable[back_hash] = index;
352  } else {
353  while (entries[k].next != back_idx) {
354  k = entries[k].next;
355  do_assert(0 <= k && k < hm_int(entries.size()));
356  }
357  entries[k].next = index;
358  }
359 
360  entries[index] = std::move(entries[back_idx]);
361  }
362 
363  entries.pop_back();
364 
365  if (entries.empty())
366  hashtable.clear();
367 
368  return 1;
369  }
370 
379  hm_int do_lookup(const K &key, hm_int &hash) const
380  {
381  if (hashtable.empty())
382  return -1;
383 
384  if (entries.size() * hashtable_size_trigger > hashtable.size()) {
385  ((unordered_map*)this)->do_rehash();
386  hash = do_hash(key);
387  }
388 
389  hm_int index = hashtable[hash];
390 
391  while (index >= 0 && !ops.cmp(entries[index].udata.first, key)) {
392  index = entries[index].next;
393  do_assert(-1 <= index && index < hm_int(entries.size()));
394  }
395 
396  return index;
397  }
398 
410  hm_int do_insert(const K &key, hm_int &hash)
411  {
412  if (hashtable.empty()) {
413  entries.push_back(entry_t(std::pair<K, T>(key, T()), -1));
414  do_rehash();
415  hash = do_hash(key);
416  } else {
417  entries.push_back(entry_t(std::pair<K, T>(key, T()), hashtable[hash]));
418  hashtable[hash] = entries.size() - 1;
419  }
420  return entries.size() - 1;
421  }
422 
434  hm_int do_insert(const std::pair<K, T> &value, hm_int &hash)
435  {
436  if (hashtable.empty()) {
437  entries.push_back(entry_t(value, -1));
438  do_rehash();
439  hash = do_hash(value.first);
440  } else {
441  entries.push_back(entry_t(value, hashtable[hash]));
442  hashtable[hash] = entries.size() - 1;
443  }
444  return entries.size() - 1;
445  }
446 
447 
448 
449  public:
450 
452  class const_iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
453  {
454  friend class unordered_map;
455  protected:
458  const_iterator(const unordered_map *iptr, hm_int iindex) : ptr(iptr), index(iindex) { }
459  public:
461  const_iterator & operator++() { index--; return *this; } // pre-increment
462  const_iterator operator++(int) { index--; return *this; } // post-increment
463  const_iterator & operator--() { index++; return *this; } // pre-decrement
464  const_iterator operator--(int) { index++; return *this; } // post-decrement
465  bool operator<(const const_iterator &other) const { return index > other.index; }
466  bool operator==(const const_iterator &other) const { return index == other.index; }
467  bool operator!=(const const_iterator &other) const { return index != other.index; }
468  const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }
469  const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
470  };
471 
473  class iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
474  {
475  friend class unordered_map;
476  protected:
479  iterator(unordered_map *iptr, hm_int iindex) : ptr(iptr), index(iindex) { }
480  public:
481  iterator() { }
482  iterator & operator++() { index--; return *this; } // pre-increment
483  iterator operator++(int) { index--; return *this; } // post-increment
484  iterator & operator--() { index++; return *this; } // pre-decrement
485  iterator operator--(int) { index++; return *this; } // post-decrement
486  bool operator<(const iterator &other) const { return index > other.index; }
487  bool operator==(const iterator &other) const { return index == other.index; }
488  bool operator!=(const iterator &other) const { return index != other.index; }
489  std::pair<K, T> &operator*() { return ptr->entries[index].udata; }
490  std::pair<K, T> *operator->() { return &ptr->entries[index].udata; }
491  const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }
492  const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
493  operator const_iterator() const { return const_iterator(ptr, index); }
494  };
495 
498  {}
499 
502  {
503  entries = other.entries;
504  do_rehash();
505  }
506 
509  {
510  swap(other);
511  }
512 
514  entries = other.entries;
515  do_rehash();
516  return *this;
517  }
518 
520  clear();
521  swap(other);
522  return *this;
523  }
524 
525  unordered_map(const std::initializer_list<std::pair<K, T>> &list)
526  {
527  for (auto &it : list)
528  insert(it);
529  }
530 
532  template<class InputIterator>
533  unordered_map(InputIterator first, InputIterator last)
534  {
535  insert(first, last);
536  }
538  template<class InputIterator>
539  void insert(InputIterator first, InputIterator last)
540  {
541  for (; first != last; ++first)
542  insert(*first);
543  }
545  std::pair<iterator, bool> insert(const K &key)
546  {
547  hm_int hash = do_hash(key);
548  hm_int i = do_lookup(key, hash);
549  if (i >= 0)
550  return std::pair<iterator, bool>(iterator(this, i), false);
551  i = do_insert(key, hash);
552  return std::pair<iterator, bool>(iterator(this, i), true);
553  }
555  std::pair<iterator, bool> insert(const std::pair<K, T> &value)
556  {
557  hm_int hash = do_hash(value.first);
558  hm_int i = do_lookup(value.first, hash);
559  if (i >= 0)
560  return std::pair<iterator, bool>(iterator(this, i), false);
561  i = do_insert(value, hash);
562  return std::pair<iterator, bool>(iterator(this, i), true);
563  }
565  hm_int erase(const K &key)
566  {
567  hm_int hash = do_hash(key);
568  hm_int index = do_lookup(key, hash);
569  return do_erase(index, hash);
570  }
572  iterator erase(iterator it)
573  {
574  hm_int hash = do_hash(it->first);
575  do_erase(it.index, hash);
576  return ++it;
577  }
579  hm_int count(const K &key) const
580  {
581  hm_int hash = do_hash(key);
582  hm_int i = do_lookup(key, hash);
583  return i < 0 ? 0 : 1;
584  }
586  hm_int count(const K &key, const_iterator it) const
587  {
588  hm_int hash = do_hash(key);
589  hm_int i = do_lookup(key, hash);
590  return i < 0 || i > it.index ? 0 : 1;
591  }
593  iterator find(const K &key)
594  {
595  hm_int hash = do_hash(key);
596  hm_int i = do_lookup(key, hash);
597  if (i < 0)
598  return end();
599  return iterator(this, i);
600  }
601 
603  const_iterator find(const K &key) const
604  {
605  hm_int hash = do_hash(key);
606  hm_int i = do_lookup(key, hash);
607  if (i < 0)
608  return end();
609  return const_iterator(this, i);
610  }
611 
613  T& at(const K &key)
614  {
615  hm_int hash = do_hash(key);
616  hm_int i = do_lookup(key, hash);
617  if (i < 0)
618  throw std::out_of_range("unordered_map::at()");
619  return entries[i].udata.second;
620  }
621 
623  const T& at(const K &key) const
624  {
625  hm_int hash = do_hash(key);
626  hm_int i = do_lookup(key, hash);
627  if (i < 0)
628  throw std::out_of_range("unordered_map::at()");
629  return entries[i].udata.second;
630  }
631 
633  T at(const K &key, const T &defval) const
634  {
635  hm_int hash = do_hash(key);
636  hm_int i = do_lookup(key, hash);
637  if (i < 0)
638  return defval;
639  return entries[i].udata.second;
640  }
641 
643  T& operator[](const K &key)
644  {
645  hm_int hash = do_hash(key);
646  hm_int i = do_lookup(key, hash);
647  if (i < 0)
648  i = do_insert(std::pair<K, T>(key, T()), hash);
649  return entries[i].udata.second;
650  }
651 
658  template<typename Compare = std::less<K>>
659  void sort(Compare comp = Compare())
660  {
661  std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata.first, a.udata.first); });
662  do_rehash();
663  }
664 
665  void swap(unordered_map &other)
666  {
667  hashtable.swap(other.hashtable);
668  entries.swap(other.entries);
669  }
670 
671  bool operator==(const unordered_map &other) const {
672  if (size() != other.size())
673  return false;
674  for (auto &it : entries) {
675  auto oit = other.find(it.udata.first);
676  if (oit == other.end() || !(oit->second == it.udata.second))
677  return false;
678  }
679  return true;
680  }
681 
682  bool operator!=(const unordered_map &other) const {
683  return !operator==(other);
684  }
685 
686  void reserve(size_t n) { entries.reserve(n); }
687  size_t size() const { return entries.size(); }
688  bool empty() const { return entries.empty(); }
689  void clear() { hashtable.clear(); entries.clear(); }
690 
691  iterator begin() { return iterator(this, hm_int(entries.size())-1); }
692  iterator end() { return iterator(nullptr, -1); }
693 
694  const_iterator begin() const { return const_iterator(this, hm_int(entries.size())-1); }
695  const_iterator end() const { return const_iterator(nullptr, -1); }
696 };
697 
704 template<typename K, typename OPS>
705 class unordered_set
706 {
707  template<typename, hm_int, typename> friend class idict;
708 
709  protected:
711  struct entry_t
712  {
713  K udata;
715 
716  entry_t() { }
717  entry_t(const K &idata, hm_int inext) : udata(idata), next(inext) { }
718  };
719 
721  std::vector<hm_int> hashtable;
723  std::vector<entry_t> entries;
725  OPS ops;
726 
727  #ifdef NDEBUG
728  static inline void do_assert(bool) { }
729  #else
730  static inline void do_assert(bool cond) {
731  if (!cond) throw std::runtime_error("unordered_set<> assert failed.");
732  }
733  #endif
734 
744  hm_int do_hash(const K &key) const
745  {
746  hm_uint hash = 0;
747  if (!hashtable.empty())
748  hash = ops.hash(key) % (hm_uint)(hashtable.size());
749  return hash;
750  }
751 
755  void do_rehash()
756  {
757  hashtable.clear();
758  hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
759 
760  for (hm_int i = 0; i < hm_int(entries.size()); i++) {
761  do_assert(-1 <= entries[i].next && entries[i].next < hm_int(entries.size()));
762  hm_int hash = do_hash(entries[i].udata);
763  entries[i].next = hashtable[hash];
764  hashtable[hash] = i;
765  }
766  }
767 
777  {
778  do_assert(index < hm_int(entries.size()));
779  if (hashtable.empty() || index < 0)
780  return 0;
781 
782  hm_int k = hashtable[hash];
783  if (k == index) {
784  hashtable[hash] = entries[index].next;
785  } else {
786  while (entries[k].next != index) {
787  k = entries[k].next;
788  do_assert(0 <= k && k < hm_int(entries.size()));
789  }
790  entries[k].next = entries[index].next;
791  }
792 
793  hm_int back_idx = entries.size()-1;
794 
795  if (index != back_idx)
796  {
797  hm_int back_hash = do_hash(entries[back_idx].udata);
798 
799  k = hashtable[back_hash];
800  if (k == back_idx) {
801  hashtable[back_hash] = index;
802  } else {
803  while (entries[k].next != back_idx) {
804  k = entries[k].next;
805  do_assert(0 <= k && k < hm_int(entries.size()));
806  }
807  entries[k].next = index;
808  }
809 
810  entries[index] = std::move(entries[back_idx]);
811  }
812 
813  entries.pop_back();
814 
815  if (entries.empty())
816  hashtable.clear();
817 
818  return 1;
819  }
820 
829  hm_int do_lookup(const K &key, hm_int &hash) const
830  {
831  if (hashtable.empty())
832  return -1;
833 
834  if (entries.size() * hashtable_size_trigger > hashtable.size()) {
835  ((unordered_set*)this)->do_rehash();
836  hash = do_hash(key);
837  }
838 
839  hm_int index = hashtable[hash];
840 
841  while (index >= 0 && !ops.cmp(entries[index].udata, key)) {
842  index = entries[index].next;
843  do_assert(-1 <= index && index < hm_int(entries.size()));
844  }
845 
846  return index;
847  }
848 
860  hm_int do_insert(const K &value, hm_int &hash)
861  {
862  if (hashtable.empty()) {
863  entries.push_back(entry_t(value, -1));
864  do_rehash();
865  hash = do_hash(value);
866  }
867  else {
868  entries.push_back(entry_t(value, hashtable[hash]));
869  hashtable[hash] = entries.size() - 1;
870  }
871  return entries.size() - 1;
872  }
873 
874  public:
875  class const_iterator : public std::iterator<std::forward_iterator_tag, K>
876  {
877  friend class unordered_set;
878 
879  protected:
882  const_iterator(const unordered_set *iptr, hm_int iindex) : ptr(iptr), index(iindex) { }
883 
884  public:
886  const_iterator & operator++() { index--; return *this; } // pre-increment
887  const_iterator operator++(int) { index--; return *this; } // post-increment
888  const_iterator & operator--() { index++; return *this; } // pre-decrement
889  const_iterator operator--(int) { index++; return *this; } // post-decrement
890  bool operator==(const const_iterator &other) const { return index == other.index; }
891  bool operator!=(const const_iterator &other) const { return index != other.index; }
892  const K &operator*() const { return ptr->entries[index].udata; }
893  const K *operator->() const { return &ptr->entries[index].udata; }
894  };
895 
896  class iterator : public std::iterator<std::forward_iterator_tag, K>
897  {
898  friend class unordered_set;
899 
900  protected:
903  iterator(unordered_set *iptr, hm_int iindex) : ptr(iptr), index(iindex) { }
904 
905  public:
906  iterator() { }
907  iterator & operator++() { index--; return *this; } // pre-increment
908  iterator operator++(int) { index--; return *this; } // post-increment
909  iterator & operator--() { index++; return *this; } // pre-decrement
910  iterator operator--(int) { index++; return *this; } // post-decrement
911  bool operator==(const iterator &other) const { return index == other.index; }
912  bool operator!=(const iterator &other) const { return index != other.index; }
913  K &operator*() { return ptr->entries[index].udata; }
914  K *operator->() { return &ptr->entries[index].udata; }
915  const K &operator*() const { return ptr->entries[index].udata; }
916  const K *operator->() const { return &ptr->entries[index].udata; }
917  operator const_iterator() const { return const_iterator(ptr, index); }
918  };
919 
922  { }
923 
926  {
927  entries = other.entries;
928  do_rehash();
929  }
930 
933  {
934  swap(other);
935  }
936 
938  entries = other.entries;
939  do_rehash();
940  return *this;
941  }
942 
944  clear();
945  swap(other);
946  return *this;
947  }
948 
949  unordered_set(const std::initializer_list<K> &list)
950  {
951  for (auto &it : list)
952  insert(it);
953  }
954 
955  template<class InputIterator>
956  unordered_set(InputIterator first, InputIterator last)
957  {
958  insert(first, last);
959  }
960 
961  template<class InputIterator>
962  void insert(InputIterator first, InputIterator last)
963  {
964  for (; first != last; ++first)
965  insert(*first);
966  }
967 
968  std::pair<iterator, bool> insert(const K &value)
969  {
970  hm_int hash = do_hash(value);
971  hm_int i = do_lookup(value, hash);
972  if (i >= 0)
973  return std::pair<iterator, bool>(iterator(this, i), false);
974  i = do_insert(value, hash);
975  return std::pair<iterator, bool>(iterator(this, i), true);
976  }
977 
978  hm_int erase(const K &key)
979  {
980  hm_int hash = do_hash(key);
981  hm_int index = do_lookup(key, hash);
982  return do_erase(index, hash);
983  }
984 
985  iterator erase(iterator it)
986  {
987  hm_int hash = do_hash(*it);
988  do_erase(it.index, hash);
989  return ++it;
990  }
991 
992  hm_int count(const K &key) const
993  {
994  hm_int hash = do_hash(key);
995  hm_int i = do_lookup(key, hash);
996  return i < 0 ? 0 : 1;
997  }
998 
999  hm_int count(const K &key, const_iterator it) const
1000  {
1001  hm_int hash = do_hash(key);
1002  hm_int i = do_lookup(key, hash);
1003  return i < 0 || i > it.index ? 0 : 1;
1004  }
1005 
1006  iterator find(const K &key)
1007  {
1008  hm_int hash = do_hash(key);
1009  hm_int i = do_lookup(key, hash);
1010  if (i < 0)
1011  return end();
1012  return iterator(this, i);
1013  }
1014 
1015  const_iterator find(const K &key) const
1016  {
1017  hm_int hash = do_hash(key);
1018  hm_int i = do_lookup(key, hash);
1019  if (i < 0)
1020  return end();
1021  return const_iterator(this, i);
1022  }
1023 
1024  bool operator[](const K &key)
1025  {
1026  hm_int hash = do_hash(key);
1027  hm_int i = do_lookup(key, hash);
1028  return i >= 0;
1029  }
1030 
1031  template<typename Compare = std::less<K>>
1032  void sort(Compare comp = Compare())
1033  {
1034  std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata, a.udata); });
1035  do_rehash();
1036  }
1037 
1038  K pop()
1039  {
1040  iterator it = begin();
1041  K ret = *it;
1042  erase(it);
1043  return ret;
1044  }
1045 
1046  void swap(unordered_set &other)
1047  {
1048  hashtable.swap(other.hashtable);
1049  entries.swap(other.entries);
1050  }
1051 
1052  bool operator==(const unordered_set &other) const {
1053  if (size() != other.size())
1054  return false;
1055  for (auto &it : entries)
1056  if (!other.count(it.udata))
1057  return false;
1058  return true;
1059  }
1060 
1061  bool operator!=(const unordered_set &other) const {
1062  return !operator==(other);
1063  }
1064 
1065  void reserve(size_t n) { entries.reserve(n); }
1066  size_t size() const { return entries.size(); }
1067  bool empty() const { return entries.empty(); }
1068  void clear() { hashtable.clear(); entries.clear(); }
1069 
1070  iterator begin() { return iterator(this, hm_int(entries.size())-1); }
1071  iterator end() { return iterator(nullptr, -1); }
1072 
1073  const_iterator begin() const { return const_iterator(this, hm_int(entries.size())-1); }
1074  const_iterator end() const { return const_iterator(nullptr, -1); }
1075 };
1076 
1077 template<typename K, hm_int offset, typename OPS>
1078 class idict
1079 {
1080  unordered_set<K, OPS> database;
1081 
1082 public:
1084 
1085  hm_int operator()(const K &key)
1086  {
1087  hm_int hash = database.do_hash(key);
1088  hm_int i = database.do_lookup(key, hash);
1089  if (i < 0)
1090  i = database.do_insert(key, hash);
1091  return i + offset;
1092  }
1093 
1094  hm_int at(const K &key) const
1095  {
1096  hm_int hash = database.do_hash(key);
1097  hm_int i = database.do_lookup(key, hash);
1098  if (i < 0)
1099  throw std::out_of_range("idict::at()");
1100  return i + offset;
1101  }
1102 
1103  hm_int at(const K &key, hm_int defval) const
1104  {
1105  hm_int hash = database.do_hash(key);
1106  hm_int i = database.do_lookup(key, hash);
1107  if (i < 0)
1108  return defval;
1109  return i + offset;
1110  }
1111 
1112  hm_int count(const K &key) const
1113  {
1114  hm_int hash = database.do_hash(key);
1115  hm_int i = database.do_lookup(key, hash);
1116  return i < 0 ? 0 : 1;
1117  }
1118 
1119  void expect(const K &key, hm_int i)
1120  {
1121  hm_int j = (*this)(key);
1122  if (i != j)
1123  throw std::out_of_range("idict::expect()");
1124  }
1125 
1126  const K &operator[](hm_int index) const
1127  {
1128  return database.entries.at(index - offset).udata;
1129  }
1130 
1131  void swap(idict &other)
1132  {
1133  database.swap(other.database);
1134  }
1135 
1136  void reserve(size_t n) { database.reserve(n); }
1137  size_t size() const { return database.size(); }
1138  bool empty() const { return database.empty(); }
1139  void clear() { database.clear(); }
1140 
1141  const_iterator begin() const { return database.begin(); }
1142  const_iterator end() const { return database.end(); }
1143 };
1144 
1145 template<typename K, typename OPS>
1146 class mfp
1147 {
1148  mutable idict<K, 0, OPS> database;
1149  mutable std::vector<hm_int> parents;
1150 
1151 public:
1153 
1154  hm_int operator()(const K &key) const
1155  {
1156  hm_int i = database(key);
1157  parents.resize(database.size(), -1);
1158  return i;
1159  }
1160 
1161  const K &operator[](hm_int index) const
1162  {
1163  return database[index];
1164  }
1165 
1167  {
1168  hm_int p = i, k = i;
1169 
1170  while (parents[p] != -1)
1171  p = parents[p];
1172 
1173  while (k != p) {
1174  hm_int next_k = parents[k];
1175  parents[k] = p;
1176  k = next_k;
1177  }
1178 
1179  return p;
1180  }
1181 
1182  void imerge(hm_int i, hm_int j)
1183  {
1184  i = ifind(i);
1185  j = ifind(j);
1186 
1187  if (i != j)
1188  parents[i] = j;
1189  }
1190 
1192  {
1193  hm_int k = i;
1194 
1195  while (k != -1) {
1196  hm_int next_k = parents[k];
1197  parents[k] = i;
1198  k = next_k;
1199  }
1200 
1201  parents[i] = -1;
1202  }
1203 
1204  hm_int lookup(const K &a) const
1205  {
1206  return ifind((*this)(a));
1207  }
1208 
1209  const K &find(const K &a) const
1210  {
1211  hm_int i = database.at(a, -1);
1212  if (i < 0)
1213  return a;
1214  return (*this)[ifind(i)];
1215  }
1216 
1217  void merge(const K &a, const K &b)
1218  {
1219  imerge((*this)(a), (*this)(b));
1220  }
1221 
1222  void promote(const K &a)
1223  {
1224  hm_int i = database.at(a, -1);
1225  if (i >= 0)
1226  ipromote(i);
1227  }
1228 
1229  void swap(mfp &other)
1230  {
1231  database.swap(other.database);
1232  parents.swap(other.parents);
1233  }
1234 
1235  void reserve(size_t n) { database.reserve(n); }
1236  size_t size() const { return database.size(); }
1237  bool empty() const { return database.empty(); }
1238  void clear() { database.clear(); parents.clear(); }
1239 
1240  const_iterator begin() const { return database.begin(); }
1241  const_iterator end() const { return database.end(); }
1242 };
1243 
1244 } /* namespace hashmap */
1245 
1246 #endif
hm_int do_hash(const K &key) const
Generate a hash from a key.
Definition: hashmap.hpp:744
std::pair< iterator, bool > insert(const K &key)
User insert as key lookup.
Definition: hashmap.hpp:545
unordered_set(const std::initializer_list< K > &list)
Definition: hashmap.hpp:949
hm_uint mkhash(hm_uint a, hm_uint b)
Definition: hashmap.hpp:52
Custom unordered_set implementation.
Definition: hashmap.hpp:241
const_iterator find(const K &key) const
Definition: hashmap.hpp:1015
const hm_int hashtable_size_factor
Definition: hashmap.hpp:49
unordered_set(const unordered_set &other)
Construct from another set.
Definition: hashmap.hpp:925
const std::pair< K, T > * operator->() const
Definition: hashmap.hpp:469
void ipromote(hm_int i)
Definition: hashmap.hpp:1191
bool operator==(const const_iterator &other) const
Definition: hashmap.hpp:890
void insert(InputIterator first, InputIterator last)
Insert Iterator range.
Definition: hashmap.hpp:539
static bool cmp(const T &a, const T &b)
Definition: hashmap.hpp:89
unsigned long int hm_uint
Definition: hashmap.hpp:43
static hm_uint hash(std::vector< T > a)
Definition: hashmap.hpp:167
const K & operator[](hm_int index) const
Definition: hashmap.hpp:1161
unordered_map & operator=(unordered_map &&other)
Definition: hashmap.hpp:519
void reserve(size_t n)
Definition: hashmap.hpp:686
unordered_map & operator=(const unordered_map &other)
Definition: hashmap.hpp:513
static bool cmp(const void *a, const void *b)
Definition: hashmap.hpp:200
iterator(unordered_set *iptr, hm_int iindex)
Definition: hashmap.hpp:903
unordered_set & operator=(const unordered_set &other)
Definition: hashmap.hpp:937
std::vector< hm_int > hashtable
the hashtable
Definition: hashmap.hpp:721
const_iterator(const unordered_set *iptr, hm_int iindex)
Definition: hashmap.hpp:882
bool operator!=(const const_iterator &other) const
Definition: hashmap.hpp:467
void expect(const K &key, hm_int i)
Definition: hashmap.hpp:1119
hm_uint mkhash_add(hm_uint a, hm_uint b)
Definition: hashmap.hpp:61
OPS ops
the hash generator
Definition: hashmap.hpp:725
void promote(const K &a)
Definition: hashmap.hpp:1222
bool operator==(const unordered_set &other) const
Definition: hashmap.hpp:1052
unordered_map()
Empty constructor.
Definition: hashmap.hpp:497
const_iterator(const unordered_map *iptr, hm_int iindex)
Definition: hashmap.hpp:458
const std::pair< K, T > * operator->() const
Definition: hashmap.hpp:492
hm_int count(const K &key) const
Definition: hashmap.hpp:1112
bool operator!=(const iterator &other) const
Definition: hashmap.hpp:912
unordered_set & operator=(unordered_set &&other)
Definition: hashmap.hpp:943
const_iterator end() const
Definition: hashmap.hpp:1241
void swap(unordered_map &other)
Definition: hashmap.hpp:665
size_t size() const
Definition: hashmap.hpp:1236
std::pair< K, T > * operator->()
Definition: hashmap.hpp:490
static hm_uint hash(int64_t a)
Definition: hashmap.hpp:112
static bool cmp(const void *a, const void *b)
Definition: hashmap.hpp:191
bool operator<(const const_iterator &other) const
Definition: hashmap.hpp:465
bool operator==(const iterator &other) const
Definition: hashmap.hpp:911
void imerge(hm_int i, hm_int j)
Definition: hashmap.hpp:1182
hm_int do_erase(hm_int index, hm_int hash)
Remove an entry.
Definition: hashmap.hpp:776
bool operator==(const const_iterator &other) const
Definition: hashmap.hpp:466
bool operator!=(const unordered_map &other) const
Definition: hashmap.hpp:682
void merge(const K &a, const K &b)
Definition: hashmap.hpp:1217
const hm_int hashtable_size_trigger
Definition: hashmap.hpp:48
const T & at(const K &key) const
Const data access by key.
Definition: hashmap.hpp:623
T & at(const K &key)
Data access by key.
Definition: hashmap.hpp:613
const_iterator begin() const
Definition: hashmap.hpp:1141
size_t size() const
Definition: hashmap.hpp:1137
std::pair< iterator, bool > insert(const K &value)
Definition: hashmap.hpp:968
void do_rehash()
Resize the hashtable and compute new hashes.
Definition: hashmap.hpp:755
static hm_uint hash(const std::string &a)
Definition: hashmap.hpp:131
const_iterator begin() const
Definition: hashmap.hpp:1073
const K & find(const K &a) const
Definition: hashmap.hpp:1209
bool operator[](const K &key)
Definition: hashmap.hpp:1024
hm_int lookup(const K &a) const
Definition: hashmap.hpp:1204
hm_int count(const K &key) const
Definition: hashmap.hpp:992
size_t size() const
Definition: hashmap.hpp:1066
bool empty() const
Definition: hashmap.hpp:688
hm_int at(const K &key, hm_int defval) const
Definition: hashmap.hpp:1103
hm_uint mkhash_xorshift(hm_uint a)
Definition: hashmap.hpp:65
Base hashing class.
Definition: hashmap.hpp:87
const std::pair< K, T > & operator*() const
Definition: hashmap.hpp:491
void sort(Compare comp=Compare())
Sort data entries.
Definition: hashmap.hpp:659
void reserve(size_t n)
Definition: hashmap.hpp:1065
void swap(idict &other)
Definition: hashmap.hpp:1131
iterator(unordered_map *iptr, hm_int iindex)
Definition: hashmap.hpp:479
static bool cmp(const char *a, const char *b)
Definition: hashmap.hpp:176
const_iterator end() const
Definition: hashmap.hpp:1074
static bool cmp(std::pair< P, Q > a, std::pair< P, Q > b)
Definition: hashmap.hpp:140
iterator erase(iterator it)
Erase by iterator.
Definition: hashmap.hpp:572
hm_int hashtable_size(hm_int min_size)
Definition: hashmap.hpp:214
static bool cmp(std::tuple< T... > a, std::tuple< T... > b)
Definition: hashmap.hpp:149
unordered_set()
Empty constructor.
Definition: hashmap.hpp:921
bool empty() const
Definition: hashmap.hpp:1067
const K * operator->() const
Definition: hashmap.hpp:916
const_iterator find(const K &key) const
Search for key. Return const_iterator.
Definition: hashmap.hpp:603
size_t size() const
Definition: hashmap.hpp:687
static hm_uint hash(const T *a)
Definition: hashmap.hpp:204
unordered_set(unordered_set &&other)
Construct from another set.
Definition: hashmap.hpp:932
bool operator!=(const unordered_set &other) const
Definition: hashmap.hpp:1061
std::vector< entry_t > entries
the stored entries
Definition: hashmap.hpp:723
const_iterator end() const
Definition: hashmap.hpp:1142
void insert(InputIterator first, InputIterator last)
Definition: hashmap.hpp:962
static bool cmp(T a, T b)
Definition: hashmap.hpp:99
hm_int do_lookup(const K &key, hm_int &hash) const
Return hash and index for a key.
Definition: hashmap.hpp:829
void reserve(size_t n)
Definition: hashmap.hpp:1136
void reserve(size_t n)
Definition: hashmap.hpp:1235
hm_int erase(const K &key)
Erase by key.
Definition: hashmap.hpp:565
hm_int at(const K &key) const
Definition: hashmap.hpp:1094
bool operator==(const iterator &other) const
Definition: hashmap.hpp:487
const std::pair< K, T > & operator*() const
Definition: hashmap.hpp:468
const K & operator[](hm_int index) const
Definition: hashmap.hpp:1126
static std::enable_if< I !=sizeof...(T), hm_uint >::type hash(std::tuple< T... > a)
Definition: hashmap.hpp:157
static std::enable_if< I==sizeof...(T), hm_uint >::type hash(std::tuple< T... >)
Definition: hashmap.hpp:153
static bool cmp(std::vector< T > a, std::vector< T > b)
Definition: hashmap.hpp:164
const_iterator begin() const
Definition: hashmap.hpp:1240
long int hm_int
Definition: hashmap.hpp:44
unordered_set< K, OPS >::const_iterator const_iterator
Definition: hashmap.hpp:1083
hm_int count(const K &key, const_iterator it) const
Definition: hashmap.hpp:999
const K & operator*() const
Definition: hashmap.hpp:915
bool operator<(const iterator &other) const
Definition: hashmap.hpp:486
static bool cmp(const std::string &a, const std::string &b)
Definition: hashmap.hpp:128
bool empty() const
Definition: hashmap.hpp:1138
hm_int count(const K &key) const
Check if key exists.
Definition: hashmap.hpp:579
hm_int operator()(const K &key)
Definition: hashmap.hpp:1085
hm_int count(const K &key, const_iterator it) const
Check if key exists and matches iterator.
Definition: hashmap.hpp:586
void swap(mfp &other)
Definition: hashmap.hpp:1229
void swap(unordered_set &other)
Definition: hashmap.hpp:1046
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:860
bool operator!=(const const_iterator &other) const
Definition: hashmap.hpp:891
iterator erase(iterator it)
Definition: hashmap.hpp:985
std::pair< iterator, bool > insert(const std::pair< K, T > &value)
Insert key-value pair.
Definition: hashmap.hpp:555
const hm_uint mkhash_init
Definition: hashmap.hpp:57
hm_int operator()(const K &key) const
Definition: hashmap.hpp:1154
static hm_uint hash(const char *a)
Definition: hashmap.hpp:182
static hm_uint hash(const void *a)
Definition: hashmap.hpp:194
entry_t(const K &idata, hm_int inext)
Definition: hashmap.hpp:717
static hm_uint hash(const T &a)
Definition: hashmap.hpp:92
unordered_map(const unordered_map &other)
Construct from another map.
Definition: hashmap.hpp:501
void clear()
Definition: hashmap.hpp:1238
T at(const K &key, const T &defval) const
Return data if existent or default value.
Definition: hashmap.hpp:633
bool operator==(const unordered_map &other) const
Definition: hashmap.hpp:671
internal entry type
Definition: hashmap.hpp:711
unordered_map(InputIterator first, InputIterator last)
Construct from Iterator range.
Definition: hashmap.hpp:533
unordered_set(InputIterator first, InputIterator last)
Definition: hashmap.hpp:956
idict< K, 0, OPS >::const_iterator const_iterator
Definition: hashmap.hpp:1152
hm_int ifind(hm_int i) const
Definition: hashmap.hpp:1166
static hm_uint hash(std::pair< P, Q > a)
Definition: hashmap.hpp:143
T & operator[](const K &key)
Data access or empty insert.
Definition: hashmap.hpp:643
iterator find(const K &key)
Search for key. Return iterator.
Definition: hashmap.hpp:593
iterator find(const K &key)
Definition: hashmap.hpp:1006
unordered_map(const std::initializer_list< std::pair< K, T >> &list)
Definition: hashmap.hpp:525
bool empty() const
Definition: hashmap.hpp:1237
bool operator!=(const iterator &other) const
Definition: hashmap.hpp:488
const_iterator begin() const
Definition: hashmap.hpp:694
void sort(Compare comp=Compare())
Definition: hashmap.hpp:1032
const_iterator end() const
Definition: hashmap.hpp:695
hm_int erase(const K &key)
Definition: hashmap.hpp:978
unordered_map(unordered_map &&other)
Construct map form another map.
Definition: hashmap.hpp:508
std::pair< K, T > & operator*()
Definition: hashmap.hpp:489
static hm_uint hash(int32_t a)
Definition: hashmap.hpp:106
static void do_assert(bool cond)
Definition: hashmap.hpp:730