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>
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 
453  friend class unordered_map;
454 
455  protected:
456  const unordered_map *ptr = nullptr;
458 
459  const_iterator(const unordered_map *iptr, hm_int iindex)
460  : ptr(iptr), index(iindex) { }
461 
462  public:
463  // Iterator traits
464  using iterator_category = std::forward_iterator_tag;
465  using value_type = std::pair<K, T>;
466  using difference_type = std::ptrdiff_t;
467  using pointer = const value_type*;
468  using reference = const value_type&;
469 
470  const_iterator() = default;
471 
472  // Pre-increment
473  const_iterator & operator++() { index--; return *this; }
474  // Post-increment
475  const_iterator operator++(int) { const_iterator tmp = *this; index--; return tmp; }
476 
477  // Pre-decrement
478  const_iterator & operator--() { index++; return *this; }
479  // Post-decrement
480  const_iterator operator--(int) { const_iterator tmp = *this; index++; return tmp; }
481 
482  // Comparison
483  bool operator<(const const_iterator &other) const { return index > other.index; }
484  bool operator==(const const_iterator &other) const { return index == other.index; }
485  bool operator!=(const const_iterator &other) const { return index != other.index; }
486 
487  // Dereference
488  reference operator*() const { return ptr->entries[index].udata; }
489  pointer operator->() const { return &ptr->entries[index].udata; }
490 };
491 
493 class iterator {
494  friend class unordered_map;
495 
496  protected:
497  unordered_map *ptr = nullptr;
499 
501  : ptr(iptr), index(iindex) { }
502 
503  public:
504  // Iterator traits
505  using iterator_category = std::forward_iterator_tag;
506  using value_type = std::pair<K, T>;
507  using difference_type = std::ptrdiff_t;
508  using pointer = value_type*;
510 
511  iterator() = default;
512 
513  // Pre-increment
514  iterator & operator++() { index--; return *this; }
515  // Post-increment
516  iterator operator++(int) { iterator tmp = *this; index--; return tmp; }
517 
518  // Pre-decrement
519  iterator & operator--() { index++; return *this; }
520  // Post-decrement
521  iterator operator--(int) { iterator tmp = *this; index++; return tmp; }
522 
523  // Comparison
524  bool operator<(const iterator &other) const { return index > other.index; }
525  bool operator==(const iterator &other) const { return index == other.index; }
526  bool operator!=(const iterator &other) const { return index != other.index; }
527 
528  // Dereference
529  reference operator*() { return ptr->entries[index].udata; }
530  pointer operator->() { return &ptr->entries[index].udata; }
531 
532  // Const dereference
533  const value_type &operator*() const { return ptr->entries[index].udata; }
534  const value_type *operator->() const { return &ptr->entries[index].udata; }
535 
536  // Conversion to const_iterator
537  operator const_iterator() const { return const_iterator(ptr, index); }
538  };
539 
542  {}
543 
546  {
547  entries = other.entries;
548  do_rehash();
549  }
550 
553  {
554  swap(other);
555  }
556 
558  entries = other.entries;
559  do_rehash();
560  return *this;
561  }
562 
564  clear();
565  swap(other);
566  return *this;
567  }
568 
569  unordered_map(const std::initializer_list<std::pair<K, T>> &list)
570  {
571  for (auto &it : list)
572  insert(it);
573  }
574 
576  template<class InputIterator>
577  unordered_map(InputIterator first, InputIterator last)
578  {
579  insert(first, last);
580  }
582  template<class InputIterator>
583  void insert(InputIterator first, InputIterator last)
584  {
585  for (; first != last; ++first)
586  insert(*first);
587  }
589  std::pair<iterator, bool> insert(const K &key)
590  {
591  hm_int hash = do_hash(key);
592  hm_int i = do_lookup(key, hash);
593  if (i >= 0)
594  return std::pair<iterator, bool>(iterator(this, i), false);
595  i = do_insert(key, hash);
596  return std::pair<iterator, bool>(iterator(this, i), true);
597  }
599  std::pair<iterator, bool> insert(const std::pair<K, T> &value)
600  {
601  hm_int hash = do_hash(value.first);
602  hm_int i = do_lookup(value.first, hash);
603  if (i >= 0)
604  return std::pair<iterator, bool>(iterator(this, i), false);
605  i = do_insert(value, hash);
606  return std::pair<iterator, bool>(iterator(this, i), true);
607  }
609  hm_int erase(const K &key)
610  {
611  hm_int hash = do_hash(key);
612  hm_int index = do_lookup(key, hash);
613  return do_erase(index, hash);
614  }
617  {
618  hm_int hash = do_hash(it->first);
619  do_erase(it.index, hash);
620  return ++it;
621  }
623  hm_int count(const K &key) const
624  {
625  hm_int hash = do_hash(key);
626  hm_int i = do_lookup(key, hash);
627  return i < 0 ? 0 : 1;
628  }
630  hm_int count(const K &key, const_iterator it) const
631  {
632  hm_int hash = do_hash(key);
633  hm_int i = do_lookup(key, hash);
634  return i < 0 || i > it.index ? 0 : 1;
635  }
637  iterator find(const K &key)
638  {
639  hm_int hash = do_hash(key);
640  hm_int i = do_lookup(key, hash);
641  if (i < 0)
642  return end();
643  return iterator(this, i);
644  }
645 
647  const_iterator find(const K &key) const
648  {
649  hm_int hash = do_hash(key);
650  hm_int i = do_lookup(key, hash);
651  if (i < 0)
652  return end();
653  return const_iterator(this, i);
654  }
655 
657  T& at(const K &key)
658  {
659  hm_int hash = do_hash(key);
660  hm_int i = do_lookup(key, hash);
661  if (i < 0)
662  throw std::out_of_range("unordered_map::at()");
663  return entries[i].udata.second;
664  }
665 
667  const T& at(const K &key) const
668  {
669  hm_int hash = do_hash(key);
670  hm_int i = do_lookup(key, hash);
671  if (i < 0)
672  throw std::out_of_range("unordered_map::at()");
673  return entries[i].udata.second;
674  }
675 
677  T at(const K &key, const T &defval) const
678  {
679  hm_int hash = do_hash(key);
680  hm_int i = do_lookup(key, hash);
681  if (i < 0)
682  return defval;
683  return entries[i].udata.second;
684  }
685 
687  T& operator[](const K &key)
688  {
689  hm_int hash = do_hash(key);
690  hm_int i = do_lookup(key, hash);
691  if (i < 0)
692  i = do_insert(std::pair<K, T>(key, T()), hash);
693  return entries[i].udata.second;
694  }
695 
702  template<typename Compare = std::less<K>>
703  void sort(Compare comp = Compare())
704  {
705  std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata.first, a.udata.first); });
706  do_rehash();
707  }
708 
709  void swap(unordered_map &other)
710  {
711  hashtable.swap(other.hashtable);
712  entries.swap(other.entries);
713  }
714 
715  bool operator==(const unordered_map &other) const {
716  if (size() != other.size())
717  return false;
718  for (auto &it : entries) {
719  auto oit = other.find(it.udata.first);
720  if (oit == other.end() || !(oit->second == it.udata.second))
721  return false;
722  }
723  return true;
724  }
725 
726  bool operator!=(const unordered_map &other) const {
727  return !operator==(other);
728  }
729 
730  void reserve(size_t n) { entries.reserve(n); }
731  size_t size() const { return entries.size(); }
732  bool empty() const { return entries.empty(); }
733  void clear() { hashtable.clear(); entries.clear(); }
734 
735  iterator begin() { return iterator(this, hm_int(entries.size())-1); }
736  iterator end() { return iterator(nullptr, -1); }
737 
738  const_iterator begin() const { return const_iterator(this, hm_int(entries.size())-1); }
739  const_iterator end() const { return const_iterator(nullptr, -1); }
740 };
741 
748 template<typename K, typename OPS>
750 {
751  template<typename, hm_int, typename> friend class idict;
752 
753  protected:
755  struct entry_t
756  {
757  K udata;
759 
760  entry_t() { }
761  entry_t(const K &idata, hm_int inext) : udata(idata), next(inext) { }
762  };
763 
765  std::vector<hm_int> hashtable;
767  std::vector<entry_t> entries;
769  OPS ops;
770 
771  #ifdef NDEBUG
772  static inline void do_assert(bool) { }
773  #else
774  static inline void do_assert(bool cond) {
775  if (!cond) throw std::runtime_error("unordered_set<> assert failed.");
776  }
777  #endif
778 
788  hm_int do_hash(const K &key) const
789  {
790  hm_uint hash = 0;
791  if (!hashtable.empty())
792  hash = ops.hash(key) % (hm_uint)(hashtable.size());
793  return hash;
794  }
795 
799  void do_rehash()
800  {
801  hashtable.clear();
802  hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
803 
804  for (hm_int i = 0; i < hm_int(entries.size()); i++) {
805  do_assert(-1 <= entries[i].next && entries[i].next < hm_int(entries.size()));
806  hm_int hash = do_hash(entries[i].udata);
807  entries[i].next = hashtable[hash];
808  hashtable[hash] = i;
809  }
810  }
811 
821  {
822  do_assert(index < hm_int(entries.size()));
823  if (hashtable.empty() || index < 0)
824  return 0;
825 
826  hm_int k = hashtable[hash];
827  if (k == index) {
828  hashtable[hash] = entries[index].next;
829  } else {
830  while (entries[k].next != index) {
831  k = entries[k].next;
832  do_assert(0 <= k && k < hm_int(entries.size()));
833  }
834  entries[k].next = entries[index].next;
835  }
836 
837  hm_int back_idx = entries.size()-1;
838 
839  if (index != back_idx)
840  {
841  hm_int back_hash = do_hash(entries[back_idx].udata);
842 
843  k = hashtable[back_hash];
844  if (k == back_idx) {
845  hashtable[back_hash] = index;
846  } else {
847  while (entries[k].next != back_idx) {
848  k = entries[k].next;
849  do_assert(0 <= k && k < hm_int(entries.size()));
850  }
851  entries[k].next = index;
852  }
853 
854  entries[index] = std::move(entries[back_idx]);
855  }
856 
857  entries.pop_back();
858 
859  if (entries.empty())
860  hashtable.clear();
861 
862  return 1;
863  }
864 
873  hm_int do_lookup(const K &key, hm_int &hash) const
874  {
875  if (hashtable.empty())
876  return -1;
877 
878  if (entries.size() * hashtable_size_trigger > hashtable.size()) {
879  ((unordered_set*)this)->do_rehash();
880  hash = do_hash(key);
881  }
882 
883  hm_int index = hashtable[hash];
884 
885  while (index >= 0 && !ops.cmp(entries[index].udata, key)) {
886  index = entries[index].next;
887  do_assert(-1 <= index && index < hm_int(entries.size()));
888  }
889 
890  return index;
891  }
892 
904  hm_int do_insert(const K &value, hm_int &hash)
905  {
906  if (hashtable.empty()) {
907  entries.push_back(entry_t(value, -1));
908  do_rehash();
909  hash = do_hash(value);
910  }
911  else {
912  entries.push_back(entry_t(value, hashtable[hash]));
913  hashtable[hash] = entries.size() - 1;
914  }
915  return entries.size() - 1;
916  }
917 
918  public:
921  friend class unordered_set;
922 
923  protected:
924  const unordered_set *ptr = nullptr;
926 
927  const_iterator(const unordered_set *iptr, hm_int iindex)
928  : ptr(iptr), index(iindex) { }
929 
930  public:
931  // Iterator traits
932  using iterator_category = std::forward_iterator_tag;
933  using value_type = K;
934  using difference_type = std::ptrdiff_t;
935  using pointer = const value_type*;
936  using reference = const value_type&;
937 
938  const_iterator() = default;
939 
940  // Pre-increment
941  const_iterator & operator++() { index--; return *this; }
942  // Post-increment
943  const_iterator operator++(int) { const_iterator tmp = *this; index--; return tmp; }
944 
945  // Pre-decrement
946  const_iterator & operator--() { index++; return *this; }
947  // Post-decrement
948  const_iterator operator--(int) { const_iterator tmp = *this; index++; return tmp; }
949 
950  // Comparison
951  bool operator==(const const_iterator &other) const { return index == other.index; }
952  bool operator!=(const const_iterator &other) const { return index != other.index; }
953 
954  // Dereference
955  reference operator*() const { return ptr->entries[index].udata; }
956  pointer operator->() const { return &ptr->entries[index].udata; }
957 };
958 
960 class iterator {
961  friend class unordered_set;
962 
963  protected:
964  unordered_set *ptr = nullptr;
966 
968  : ptr(iptr), index(iindex) { }
969 
970  public:
971  // Iterator traits
972  using iterator_category = std::forward_iterator_tag;
973  using value_type = K;
974  using difference_type = std::ptrdiff_t;
975  using pointer = value_type*;
977 
978  iterator() = default;
979 
980  // Pre-increment
981  iterator & operator++() { index--; return *this; }
982  // Post-increment
983  iterator operator++(int) { iterator tmp = *this; index--; return tmp; }
984 
985  // Pre-decrement
986  iterator & operator--() { index++; return *this; }
987  // Post-decrement
988  iterator operator--(int) { iterator tmp = *this; index++; return tmp; }
989 
990  // Comparison
991  bool operator==(const iterator &other) const { return index == other.index; }
992  bool operator!=(const iterator &other) const { return index != other.index; }
993 
994  // Dereference
995  reference operator*() { return ptr->entries[index].udata; }
996  pointer operator->() { return &ptr->entries[index].udata; }
997 
998  // Const dereference
999  const value_type &operator*() const { return ptr->entries[index].udata; }
1000  const value_type *operator->() const { return &ptr->entries[index].udata; }
1001 
1002  // Conversion to const_iterator
1003  operator const_iterator() const { return const_iterator(ptr, index); }
1004 };
1005 
1008  { }
1009 
1012  {
1013  entries = other.entries;
1014  do_rehash();
1015  }
1016 
1019  {
1020  swap(other);
1021  }
1022 
1024  entries = other.entries;
1025  do_rehash();
1026  return *this;
1027  }
1028 
1030  clear();
1031  swap(other);
1032  return *this;
1033  }
1034 
1035  unordered_set(const std::initializer_list<K> &list)
1036  {
1037  for (auto &it : list)
1038  insert(it);
1039  }
1040 
1041  template<class InputIterator>
1042  unordered_set(InputIterator first, InputIterator last)
1043  {
1044  insert(first, last);
1045  }
1046 
1047  template<class InputIterator>
1048  void insert(InputIterator first, InputIterator last)
1049  {
1050  for (; first != last; ++first)
1051  insert(*first);
1052  }
1053 
1054  std::pair<iterator, bool> insert(const K &value)
1055  {
1056  hm_int hash = do_hash(value);
1057  hm_int i = do_lookup(value, hash);
1058  if (i >= 0)
1059  return std::pair<iterator, bool>(iterator(this, i), false);
1060  i = do_insert(value, hash);
1061  return std::pair<iterator, bool>(iterator(this, i), true);
1062  }
1063 
1064  hm_int erase(const K &key)
1065  {
1066  hm_int hash = do_hash(key);
1067  hm_int index = do_lookup(key, hash);
1068  return do_erase(index, hash);
1069  }
1070 
1072  {
1073  hm_int hash = do_hash(*it);
1074  do_erase(it.index, hash);
1075  return ++it;
1076  }
1077 
1078  hm_int count(const K &key) const
1079  {
1080  hm_int hash = do_hash(key);
1081  hm_int i = do_lookup(key, hash);
1082  return i < 0 ? 0 : 1;
1083  }
1084 
1085  hm_int count(const K &key, const_iterator it) const
1086  {
1087  hm_int hash = do_hash(key);
1088  hm_int i = do_lookup(key, hash);
1089  return i < 0 || i > it.index ? 0 : 1;
1090  }
1091 
1092  iterator find(const K &key)
1093  {
1094  hm_int hash = do_hash(key);
1095  hm_int i = do_lookup(key, hash);
1096  if (i < 0)
1097  return end();
1098  return iterator(this, i);
1099  }
1100 
1101  const_iterator find(const K &key) const
1102  {
1103  hm_int hash = do_hash(key);
1104  hm_int i = do_lookup(key, hash);
1105  if (i < 0)
1106  return end();
1107  return const_iterator(this, i);
1108  }
1109 
1110  bool operator[](const K &key)
1111  {
1112  hm_int hash = do_hash(key);
1113  hm_int i = do_lookup(key, hash);
1114  return i >= 0;
1115  }
1116 
1117  template<typename Compare = std::less<K>>
1118  void sort(Compare comp = Compare())
1119  {
1120  std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata, a.udata); });
1121  do_rehash();
1122  }
1123 
1124  K pop()
1125  {
1126  iterator it = begin();
1127  K ret = *it;
1128  erase(it);
1129  return ret;
1130  }
1131 
1132  void swap(unordered_set &other)
1133  {
1134  hashtable.swap(other.hashtable);
1135  entries.swap(other.entries);
1136  }
1137 
1138  bool operator==(const unordered_set &other) const {
1139  if (size() != other.size())
1140  return false;
1141  for (auto &it : entries)
1142  if (!other.count(it.udata))
1143  return false;
1144  return true;
1145  }
1146 
1147  bool operator!=(const unordered_set &other) const {
1148  return !operator==(other);
1149  }
1150 
1151  void reserve(size_t n) { entries.reserve(n); }
1152  size_t size() const { return entries.size(); }
1153  bool empty() const { return entries.empty(); }
1154  void clear() { hashtable.clear(); entries.clear(); }
1155 
1156  iterator begin() { return iterator(this, hm_int(entries.size())-1); }
1157  iterator end() { return iterator(nullptr, -1); }
1158 
1159  const_iterator begin() const { return const_iterator(this, hm_int(entries.size())-1); }
1160  const_iterator end() const { return const_iterator(nullptr, -1); }
1161 };
1162 
1163 template<typename K, hm_int offset, typename OPS>
1164 class idict
1165 {
1166  unordered_set<K, OPS> database;
1167 
1168 public:
1170 
1171  hm_int operator()(const K &key)
1172  {
1173  hm_int hash = database.do_hash(key);
1174  hm_int i = database.do_lookup(key, hash);
1175  if (i < 0)
1176  i = database.do_insert(key, hash);
1177  return i + offset;
1178  }
1179 
1180  hm_int at(const K &key) const
1181  {
1182  hm_int hash = database.do_hash(key);
1183  hm_int i = database.do_lookup(key, hash);
1184  if (i < 0)
1185  throw std::out_of_range("idict::at()");
1186  return i + offset;
1187  }
1188 
1189  hm_int at(const K &key, hm_int defval) const
1190  {
1191  hm_int hash = database.do_hash(key);
1192  hm_int i = database.do_lookup(key, hash);
1193  if (i < 0)
1194  return defval;
1195  return i + offset;
1196  }
1197 
1198  hm_int count(const K &key) const
1199  {
1200  hm_int hash = database.do_hash(key);
1201  hm_int i = database.do_lookup(key, hash);
1202  return i < 0 ? 0 : 1;
1203  }
1204 
1205  void expect(const K &key, hm_int i)
1206  {
1207  hm_int j = (*this)(key);
1208  if (i != j)
1209  throw std::out_of_range("idict::expect()");
1210  }
1211 
1212  const K &operator[](hm_int index) const
1213  {
1214  return database.entries.at(index - offset).udata;
1215  }
1216 
1217  void swap(idict &other)
1218  {
1219  database.swap(other.database);
1220  }
1221 
1222  void reserve(size_t n) { database.reserve(n); }
1223  size_t size() const { return database.size(); }
1224  bool empty() const { return database.empty(); }
1225  void clear() { database.clear(); }
1226 
1227  const_iterator begin() const { return database.begin(); }
1228  const_iterator end() const { return database.end(); }
1229 };
1230 
1231 template<typename K, typename OPS>
1232 class mfp
1233 {
1234  mutable idict<K, 0, OPS> database;
1235  mutable std::vector<hm_int> parents;
1236 
1237 public:
1239 
1240  hm_int operator()(const K &key) const
1241  {
1242  hm_int i = database(key);
1243  parents.resize(database.size(), -1);
1244  return i;
1245  }
1246 
1247  const K &operator[](hm_int index) const
1248  {
1249  return database[index];
1250  }
1251 
1253  {
1254  hm_int p = i, k = i;
1255 
1256  while (parents[p] != -1)
1257  p = parents[p];
1258 
1259  while (k != p) {
1260  hm_int next_k = parents[k];
1261  parents[k] = p;
1262  k = next_k;
1263  }
1264 
1265  return p;
1266  }
1267 
1268  void imerge(hm_int i, hm_int j)
1269  {
1270  i = ifind(i);
1271  j = ifind(j);
1272 
1273  if (i != j)
1274  parents[i] = j;
1275  }
1276 
1278  {
1279  hm_int k = i;
1280 
1281  while (k != -1) {
1282  hm_int next_k = parents[k];
1283  parents[k] = i;
1284  k = next_k;
1285  }
1286 
1287  parents[i] = -1;
1288  }
1289 
1290  hm_int lookup(const K &a) const
1291  {
1292  return ifind((*this)(a));
1293  }
1294 
1295  const K &find(const K &a) const
1296  {
1297  hm_int i = database.at(a, -1);
1298  if (i < 0)
1299  return a;
1300  return (*this)[ifind(i)];
1301  }
1302 
1303  void merge(const K &a, const K &b)
1304  {
1305  imerge((*this)(a), (*this)(b));
1306  }
1307 
1308  void promote(const K &a)
1309  {
1310  hm_int i = database.at(a, -1);
1311  if (i >= 0)
1312  ipromote(i);
1313  }
1314 
1315  void swap(mfp &other)
1316  {
1317  database.swap(other.database);
1318  parents.swap(other.parents);
1319  }
1320 
1321  void reserve(size_t n) { database.reserve(n); }
1322  size_t size() const { return database.size(); }
1323  bool empty() const { return database.empty(); }
1324  void clear() { database.clear(); parents.clear(); }
1325 
1326  const_iterator begin() const { return database.begin(); }
1327  const_iterator end() const { return database.end(); }
1328 };
1329 
1330 } /* namespace hashmap */
1331 
1332 #endif
void swap(idict &other)
Definition: hashmap.hpp:1217
hm_int operator()(const K &key)
Definition: hashmap.hpp:1171
const K & operator[](hm_int index) const
Definition: hashmap.hpp:1212
void expect(const K &key, hm_int i)
Definition: hashmap.hpp:1205
void reserve(size_t n)
Definition: hashmap.hpp:1222
const_iterator begin() const
Definition: hashmap.hpp:1227
hm_int at(const K &key) const
Definition: hashmap.hpp:1180
size_t size() const
Definition: hashmap.hpp:1223
unordered_set< K, OPS >::const_iterator const_iterator
Definition: hashmap.hpp:1169
hm_int count(const K &key) const
Definition: hashmap.hpp:1198
bool empty() const
Definition: hashmap.hpp:1224
const_iterator end() const
Definition: hashmap.hpp:1228
hm_int at(const K &key, hm_int defval) const
Definition: hashmap.hpp:1189
hm_int operator()(const K &key) const
Definition: hashmap.hpp:1240
hm_int lookup(const K &a) const
Definition: hashmap.hpp:1290
void swap(mfp &other)
Definition: hashmap.hpp:1315
void ipromote(hm_int i)
Definition: hashmap.hpp:1277
const K & operator[](hm_int index) const
Definition: hashmap.hpp:1247
void reserve(size_t n)
Definition: hashmap.hpp:1321
const K & find(const K &a) const
Definition: hashmap.hpp:1295
void clear()
Definition: hashmap.hpp:1324
hm_int ifind(hm_int i) const
Definition: hashmap.hpp:1252
const_iterator begin() const
Definition: hashmap.hpp:1326
idict< K, 0, OPS >::const_iterator const_iterator
Definition: hashmap.hpp:1238
void promote(const K &a)
Definition: hashmap.hpp:1308
bool empty() const
Definition: hashmap.hpp:1323
void imerge(hm_int i, hm_int j)
Definition: hashmap.hpp:1268
const_iterator end() const
Definition: hashmap.hpp:1327
size_t size() const
Definition: hashmap.hpp:1322
void merge(const K &a, const K &b)
Definition: hashmap.hpp:1303
const_iterator(const unordered_map *iptr, hm_int iindex)
Definition: hashmap.hpp:459
std::forward_iterator_tag iterator_category
Definition: hashmap.hpp:464
bool operator!=(const const_iterator &other) const
Definition: hashmap.hpp:485
bool operator==(const const_iterator &other) const
Definition: hashmap.hpp:484
bool operator<(const const_iterator &other) const
Definition: hashmap.hpp:483
const value_type & operator*() const
Definition: hashmap.hpp:533
std::pair< K, T > value_type
Definition: hashmap.hpp:506
std::forward_iterator_tag iterator_category
Definition: hashmap.hpp:505
bool operator!=(const iterator &other) const
Definition: hashmap.hpp:526
iterator(unordered_map *iptr, hm_int iindex)
Definition: hashmap.hpp:500
const value_type * operator->() const
Definition: hashmap.hpp:534
bool operator<(const iterator &other) const
Definition: hashmap.hpp:524
bool operator==(const iterator &other) const
Definition: hashmap.hpp:525
T at(const K &key, const T &defval) const
Return data if existent or default value.
Definition: hashmap.hpp:677
iterator find(const K &key)
Search for key. Return iterator.
Definition: hashmap.hpp:637
hm_int count(const K &key, const_iterator it) const
Check if key exists and matches iterator.
Definition: hashmap.hpp:630
unordered_map & operator=(const unordered_map &other)
Definition: hashmap.hpp:557
const_iterator end() const
Definition: hashmap.hpp:739
unordered_map(const std::initializer_list< std::pair< K, T >> &list)
Definition: hashmap.hpp:569
unordered_map(unordered_map &&other)
Construct map form another map.
Definition: hashmap.hpp:552
hm_int count(const K &key) const
Check if key exists.
Definition: hashmap.hpp:623
bool operator!=(const unordered_map &other) const
Definition: hashmap.hpp:726
const_iterator begin() const
Definition: hashmap.hpp:738
std::pair< iterator, bool > insert(const std::pair< K, T > &value)
Insert key-value pair.
Definition: hashmap.hpp:599
const T & at(const K &key) const
Const data access by key.
Definition: hashmap.hpp:667
T & operator[](const K &key)
Data access or empty insert.
Definition: hashmap.hpp:687
void swap(unordered_map &other)
Definition: hashmap.hpp:709
void sort(Compare comp=Compare())
Sort data entries.
Definition: hashmap.hpp:703
bool operator==(const unordered_map &other) const
Definition: hashmap.hpp:715
const_iterator find(const K &key) const
Search for key. Return const_iterator.
Definition: hashmap.hpp:647
bool empty() const
Definition: hashmap.hpp:732
void reserve(size_t n)
Definition: hashmap.hpp:730
std::pair< iterator, bool > insert(const K &key)
User insert as key lookup.
Definition: hashmap.hpp:589
void insert(InputIterator first, InputIterator last)
Insert Iterator range.
Definition: hashmap.hpp:583
iterator erase(iterator it)
Erase by iterator.
Definition: hashmap.hpp:616
unordered_map()
Empty constructor.
Definition: hashmap.hpp:541
T & at(const K &key)
Data access by key.
Definition: hashmap.hpp:657
unordered_map(InputIterator first, InputIterator last)
Construct from Iterator range.
Definition: hashmap.hpp:577
unordered_map & operator=(unordered_map &&other)
Definition: hashmap.hpp:563
size_t size() const
Definition: hashmap.hpp:731
hm_int erase(const K &key)
Erase by key.
Definition: hashmap.hpp:609
unordered_map(const unordered_map &other)
Construct from another map.
Definition: hashmap.hpp:545
bool operator==(const const_iterator &other) const
Definition: hashmap.hpp:951
std::forward_iterator_tag iterator_category
Definition: hashmap.hpp:932
bool operator!=(const const_iterator &other) const
Definition: hashmap.hpp:952
const_iterator(const unordered_set *iptr, hm_int iindex)
Definition: hashmap.hpp:927
const value_type & operator*() const
Definition: hashmap.hpp:999
std::forward_iterator_tag iterator_category
Definition: hashmap.hpp:972
bool operator!=(const iterator &other) const
Definition: hashmap.hpp:992
const value_type * operator->() const
Definition: hashmap.hpp:1000
iterator(unordered_set *iptr, hm_int iindex)
Definition: hashmap.hpp:967
bool operator==(const iterator &other) const
Definition: hashmap.hpp:991
Custom unordered_set implementation.
Definition: hashmap.hpp:750
size_t size() const
Definition: hashmap.hpp:1152
unordered_set(InputIterator first, InputIterator last)
Definition: hashmap.hpp:1042
unordered_set(unordered_set &&other)
Construct from another set.
Definition: hashmap.hpp:1018
unordered_set & operator=(unordered_set &&other)
Definition: hashmap.hpp:1029
iterator find(const K &key)
Definition: hashmap.hpp:1092
std::pair< iterator, bool > insert(const K &value)
Definition: hashmap.hpp:1054
const_iterator end() const
Definition: hashmap.hpp:1160
void sort(Compare comp=Compare())
Definition: hashmap.hpp:1118
hm_int erase(const K &key)
Definition: hashmap.hpp:1064
const_iterator find(const K &key) const
Definition: hashmap.hpp:1101
bool operator==(const unordered_set &other) const
Definition: hashmap.hpp:1138
hm_int do_erase(hm_int index, hm_int hash)
Remove an entry.
Definition: hashmap.hpp:820
unordered_set(const unordered_set &other)
Construct from another set.
Definition: hashmap.hpp:1011
unordered_set(const std::initializer_list< K > &list)
Definition: hashmap.hpp:1035
OPS ops
the hash generator
Definition: hashmap.hpp:769
unordered_set & operator=(const unordered_set &other)
Definition: hashmap.hpp:1023
iterator erase(iterator it)
Definition: hashmap.hpp:1071
void do_rehash()
Resize the hashtable and compute new hashes.
Definition: hashmap.hpp:799
const_iterator begin() const
Definition: hashmap.hpp:1159
bool empty() const
Definition: hashmap.hpp:1153
hm_int do_hash(const K &key) const
Generate a hash from a key.
Definition: hashmap.hpp:788
std::vector< entry_t > entries
the stored entries
Definition: hashmap.hpp:767
std::vector< hm_int > hashtable
the hashtable
Definition: hashmap.hpp:765
static void do_assert(bool cond)
Definition: hashmap.hpp:774
void reserve(size_t n)
Definition: hashmap.hpp:1151
void swap(unordered_set &other)
Definition: hashmap.hpp:1132
hm_int do_lookup(const K &key, hm_int &hash) const
Return hash and index for a key.
Definition: hashmap.hpp:873
bool operator[](const K &key)
Definition: hashmap.hpp:1110
unordered_set()
Empty constructor.
Definition: hashmap.hpp:1007
bool operator!=(const unordered_set &other) const
Definition: hashmap.hpp:1147
hm_int count(const K &key) const
Definition: hashmap.hpp:1078
void insert(InputIterator first, InputIterator last)
Definition: hashmap.hpp:1048
hm_int count(const K &key, const_iterator it) const
Definition: hashmap.hpp:1085
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:904
long int hm_int
Definition: hashmap.hpp:44
unsigned long int hm_uint
Definition: hashmap.hpp:43
const hm_int hashtable_size_trigger
Definition: hashmap.hpp:48
hm_int hashtable_size(hm_int min_size)
Definition: hashmap.hpp:214
const hm_uint mkhash_init
Definition: hashmap.hpp:57
hm_uint mkhash_add(hm_uint a, hm_uint b)
Definition: hashmap.hpp:61
hm_uint mkhash(hm_uint a, hm_uint b)
Definition: hashmap.hpp:52
const hm_int hashtable_size_factor
Definition: hashmap.hpp:49
hm_uint mkhash_xorshift(hm_uint a)
Definition: hashmap.hpp:65
static hm_uint hash(const char *a)
Definition: hashmap.hpp:182
static bool cmp(const char *a, const char *b)
Definition: hashmap.hpp:176
static bool cmp(T a, T b)
Definition: hashmap.hpp:99
static hm_uint hash(const T *a)
Definition: hashmap.hpp:204
static bool cmp(const void *a, const void *b)
Definition: hashmap.hpp:200
static hm_uint hash(int32_t a)
Definition: hashmap.hpp:106
static hm_uint hash(int64_t a)
Definition: hashmap.hpp:112
static hm_uint hash(std::pair< P, Q > a)
Definition: hashmap.hpp:143
static bool cmp(std::pair< P, Q > a, std::pair< P, Q > b)
Definition: hashmap.hpp:140
static hm_uint hash(const std::string &a)
Definition: hashmap.hpp:131
static bool cmp(const std::string &a, const std::string &b)
Definition: hashmap.hpp:128
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::tuple< T... > a, std::tuple< T... > b)
Definition: hashmap.hpp:149
static hm_uint hash(std::vector< T > a)
Definition: hashmap.hpp:167
static bool cmp(std::vector< T > a, std::vector< T > b)
Definition: hashmap.hpp:164
Base hashing class.
Definition: hashmap.hpp:88
static hm_uint hash(const T &a)
Definition: hashmap.hpp:92
static bool cmp(const T &a, const T &b)
Definition: hashmap.hpp:89
static hm_uint hash(const void *a)
Definition: hashmap.hpp:194
static bool cmp(const void *a, const void *b)
Definition: hashmap.hpp:191
internal entry type
Definition: hashmap.hpp:756
entry_t(const K &idata, hm_int inext)
Definition: hashmap.hpp:761