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  if constexpr (sizeof(long) <= sizeof(hm_uint)) {
123  return static_cast<hm_uint>(a);
124  } else {
125  return mkhash(static_cast<hm_uint>(a), static_cast<hm_uint>(static_cast<unsigned long>(a) >> 32));
126  }
127  }
128 };
129 #endif
130 
131 template<> struct hash_ops<std::string> {
132  static inline bool cmp(const std::string &a, const std::string &b) {
133  return a == b;
134  }
135  static inline hm_uint hash(const std::string &a) {
136  hm_uint v = 0;
137  for (auto c : a)
138  v = mkhash(v, c);
139  return v;
140  }
141 };
142 
143 template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {
144  static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
145  return a == b;
146  }
147  static inline hm_uint hash(std::pair<P, Q> a) {
148  return mkhash(hash_ops<P>::hash(a.first), hash_ops<Q>::hash(a.second));
149  }
150 };
151 
152 template<typename... T> struct hash_ops<std::tuple<T...>> {
153  static inline bool cmp(std::tuple<T...> a, std::tuple<T...> b) {
154  return a == b;
155  }
156  template<size_t I = 0>
157  static inline typename std::enable_if<I == sizeof...(T), hm_uint>::type hash(std::tuple<T...>) {
158  return mkhash_init;
159  }
160  template<size_t I = 0>
161  static inline typename std::enable_if<I != sizeof...(T), hm_uint>::type hash(std::tuple<T...> a) {
162  typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
163  return mkhash(hash<I+1>(a), element_ops_t::hash(std::get<I>(a)));
164  }
165 };
166 
167 template<typename T> struct hash_ops<std::vector<T>> {
168  static inline bool cmp(std::vector<T> a, std::vector<T> b) {
169  return a == b;
170  }
171  static inline hm_uint hash(std::vector<T> a) {
172  hm_uint h = mkhash_init;
173  for (auto k : a)
174  h = mkhash(h, hash_ops<T>::hash(k));
175  return h;
176  }
177 };
178 
180  static inline bool cmp(const char *a, const char *b) {
181  for (int i = 0; a[i] || b[i]; i++)
182  if (a[i] != b[i])
183  return false;
184  return true;
185  }
186  static inline hm_uint hash(const char *a) {
188  while (*a)
189  hash = mkhash(hash, *(a++));
190  return hash;
191  }
192 };
193 
194 struct hash_ptr_ops {
195  static inline bool cmp(const void *a, const void *b) {
196  return a == b;
197  }
198  static inline hm_uint hash(const void *a) {
199  return (unsigned long)a;
200  }
201 };
202 
203 struct hash_obj_ops {
204  static inline bool cmp(const void *a, const void *b) {
205  return a == b;
206  }
207  template<typename T>
208  static inline hm_uint hash(const T *a) {
209  return a ? a->hash() : 0;
210  }
211 };
212 
213 template<typename T>
214 inline hm_uint mkhash(const T &v) {
215  return hash_ops<T>().hash(v);
216 }
217 
218 inline hm_int hashtable_size(hm_int min_size)
219 {
220  static std::vector<hm_int> zero_and_some_primes = {
221  0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,
222  853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,
223  12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281,
224  120371, 150473, 188107, 235159, 293957, 367453, 459317, 574157, 717697,
225  897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037,
226  5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411,
227  25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,
228  121590311, 151987889, 189984863, 237481091, 296851369, 371064217
229  };
230 
231  for (auto p : zero_and_some_primes)
232  if (p >= min_size) return p;
233 
234  if (sizeof(hm_int) == 4)
235  throw std::length_error("hash table exceeded maximum size. use a ILP64 abi for larger tables.");
236 
237  for (auto p : zero_and_some_primes)
238  if (100129 * p > min_size) return 100129 * p;
239 
240  throw std::length_error("hash table exceeded maximum size.");
241 }
242 
243 template<typename K, typename T, typename OPS = hash_ops<K>> class unordered_map;
244 template<typename K, hm_int offset = 0, typename OPS = hash_ops<K>> class idict;
245 template<typename K, typename OPS = hash_ops<K>> class unordered_set;
246 template<typename K, typename OPS = hash_ops<K>> class mfp;
247 
255 template<typename K, typename T, typename OPS>
257 {
259  struct entry_t
260  {
261  std::pair<K, T> udata;
262  hm_int next;
263 
264  entry_t() { }
265  entry_t(const std::pair<K, T> & idata, hm_int inext) : udata(idata), next(inext) { }
266  entry_t(std::pair<K, T> && idata, hm_int inext) : udata(std::move(idata)), next(inext) { }
267  };
268 
270  std::vector<hm_int> hashtable;
272  std::vector<entry_t> entries;
274  OPS ops;
275 
276  #ifdef NDEBUG
277  static inline void do_assert(bool) { }
278  #else
279  static inline void do_assert(bool cond) {
280  if (!cond) throw std::runtime_error("unordered_map<> assert failed.");
281  }
282  #endif
283 
284 
294  hm_int do_hash(const K &key) const
295  {
296  hm_uint hash = 0;
297  if (!hashtable.empty())
298  hash = ops.hash(key) % (hm_uint)(hashtable.size());
299  return hash;
300  }
301 
305  void do_rehash()
306  {
307  hashtable.clear();
308  hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
309 
310  for (hm_int i = 0; i < hm_int(entries.size()); i++) {
311  do_assert(-1 <= entries[i].next && entries[i].next < hm_int(entries.size()));
312  hm_int hash = do_hash(entries[i].udata.first);
313  entries[i].next = hashtable[hash];
314  hashtable[hash] = i;
315  }
316  }
317 
326  hm_int do_erase(hm_int index, hm_int hash)
327  {
328  do_assert(index < hm_int(entries.size()));
329  if (hashtable.empty() || index < 0)
330  return 0;
331 
332  hm_int k = hashtable[hash];
333  do_assert(0 <= k && k < hm_int(entries.size()));
334 
335  if (k == index) {
336  hashtable[hash] = entries[index].next;
337  } else {
338  while (entries[k].next != index) {
339  k = entries[k].next;
340  do_assert(0 <= k && k < hm_int(entries.size()));
341  }
342  entries[k].next = entries[index].next;
343  }
344 
345  hm_int back_idx = entries.size()-1;
346 
347  if (index != back_idx)
348  {
349  hm_int back_hash = do_hash(entries[back_idx].udata.first);
350 
351  k = hashtable[back_hash];
352  do_assert(0 <= k && k < hm_int(entries.size()));
353 
354  if (k == back_idx) {
355  hashtable[back_hash] = index;
356  } else {
357  while (entries[k].next != back_idx) {
358  k = entries[k].next;
359  do_assert(0 <= k && k < hm_int(entries.size()));
360  }
361  entries[k].next = index;
362  }
363 
364  entries[index] = std::move(entries[back_idx]);
365  }
366 
367  entries.pop_back();
368 
369  if (entries.empty())
370  hashtable.clear();
371 
372  return 1;
373  }
374 
383  hm_int do_lookup(const K &key, hm_int &hash) const
384  {
385  if (hashtable.empty())
386  return -1;
387 
388  if (entries.size() * hashtable_size_trigger > hashtable.size()) {
389  ((unordered_map*)this)->do_rehash();
390  hash = do_hash(key);
391  }
392 
393  hm_int index = hashtable[hash];
394 
395  while (index >= 0 && !ops.cmp(entries[index].udata.first, key)) {
396  index = entries[index].next;
397  do_assert(-1 <= index && index < hm_int(entries.size()));
398  }
399 
400  return index;
401  }
402 
414  hm_int do_insert(const K &key, hm_int &hash)
415  {
416  if (hashtable.empty()) {
417  entries.push_back(entry_t(std::pair<K, T>(key, T()), -1));
418  do_rehash();
419  hash = do_hash(key);
420  } else {
421  entries.push_back(entry_t(std::pair<K, T>(key, T()), hashtable[hash]));
422  hashtable[hash] = entries.size() - 1;
423  }
424  return entries.size() - 1;
425  }
426 
438  hm_int do_insert(const std::pair<K, T> &value, hm_int &hash)
439  {
440  if (hashtable.empty()) {
441  entries.push_back(entry_t(value, -1));
442  do_rehash();
443  hash = do_hash(value.first);
444  } else {
445  entries.push_back(entry_t(value, hashtable[hash]));
446  hashtable[hash] = entries.size() - 1;
447  }
448  return entries.size() - 1;
449  }
450 
451 
452 
453  public:
454 
457  friend class unordered_map;
458 
459  protected:
460  const unordered_map *ptr = nullptr;
462 
463  const_iterator(const unordered_map *iptr, hm_int iindex)
464  : ptr(iptr), index(iindex) { }
465 
466  public:
467  // Iterator traits
468  using iterator_category = std::forward_iterator_tag;
469  using value_type = std::pair<K, T>;
470  using difference_type = std::ptrdiff_t;
471  using pointer = const value_type*;
472  using reference = const value_type&;
473 
474  const_iterator() = default;
475 
476  // Pre-increment
477  const_iterator & operator++() { index--; return *this; }
478  // Post-increment
479  const_iterator operator++(int) { const_iterator tmp = *this; index--; return tmp; }
480 
481  // Pre-decrement
482  const_iterator & operator--() { index++; return *this; }
483  // Post-decrement
484  const_iterator operator--(int) { const_iterator tmp = *this; index++; return tmp; }
485 
486  // Comparison
487  bool operator<(const const_iterator &other) const { return index > other.index; }
488  bool operator==(const const_iterator &other) const { return index == other.index; }
489  bool operator!=(const const_iterator &other) const { return index != other.index; }
490 
491  // Dereference
492  reference operator*() const { return ptr->entries[index].udata; }
493  pointer operator->() const { return &ptr->entries[index].udata; }
494 };
495 
497 class iterator {
498  friend class unordered_map;
499 
500  protected:
501  unordered_map *ptr = nullptr;
503 
505  : ptr(iptr), index(iindex) { }
506 
507  public:
508  // Iterator traits
509  using iterator_category = std::forward_iterator_tag;
510  using value_type = std::pair<K, T>;
511  using difference_type = std::ptrdiff_t;
512  using pointer = value_type*;
514 
515  iterator() = default;
516 
517  // Pre-increment
518  iterator & operator++() { index--; return *this; }
519  // Post-increment
520  iterator operator++(int) { iterator tmp = *this; index--; return tmp; }
521 
522  // Pre-decrement
523  iterator & operator--() { index++; return *this; }
524  // Post-decrement
525  iterator operator--(int) { iterator tmp = *this; index++; return tmp; }
526 
527  // Comparison
528  bool operator<(const iterator &other) const { return index > other.index; }
529  bool operator==(const iterator &other) const { return index == other.index; }
530  bool operator!=(const iterator &other) const { return index != other.index; }
531 
532  // Dereference
533  reference operator*() { return ptr->entries[index].udata; }
534  pointer operator->() { return &ptr->entries[index].udata; }
535 
536  // Const dereference
537  const value_type &operator*() const { return ptr->entries[index].udata; }
538  const value_type *operator->() const { return &ptr->entries[index].udata; }
539 
540  // Conversion to const_iterator
541  operator const_iterator() const { return const_iterator(ptr, index); }
542  };
543 
546  {}
547 
550  {
551  entries = other.entries;
552  do_rehash();
553  }
554 
557  {
558  swap(other);
559  }
560 
562  entries = other.entries;
563  do_rehash();
564  return *this;
565  }
566 
568  clear();
569  swap(other);
570  return *this;
571  }
572 
573  unordered_map(const std::initializer_list<std::pair<K, T>> &list)
574  {
575  for (auto &it : list)
576  insert(it);
577  }
578 
580  template<class InputIterator>
581  unordered_map(InputIterator first, InputIterator last)
582  {
583  insert(first, last);
584  }
586  template<class InputIterator>
587  void insert(InputIterator first, InputIterator last)
588  {
589  for (; first != last; ++first)
590  insert(*first);
591  }
593  std::pair<iterator, bool> insert(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 std::pair<iterator, bool>(iterator(this, i), false);
599  i = do_insert(key, hash);
600  return std::pair<iterator, bool>(iterator(this, i), true);
601  }
603  std::pair<iterator, bool> insert(const std::pair<K, T> &value)
604  {
605  hm_int hash = do_hash(value.first);
606  hm_int i = do_lookup(value.first, hash);
607  if (i >= 0)
608  return std::pair<iterator, bool>(iterator(this, i), false);
609  i = do_insert(value, hash);
610  return std::pair<iterator, bool>(iterator(this, i), true);
611  }
613  hm_int erase(const K &key)
614  {
615  hm_int hash = do_hash(key);
616  hm_int index = do_lookup(key, hash);
617  return do_erase(index, hash);
618  }
621  {
622  hm_int hash = do_hash(it->first);
623  do_erase(it.index, hash);
624  return ++it;
625  }
627  hm_int count(const K &key) const
628  {
629  hm_int hash = do_hash(key);
630  hm_int i = do_lookup(key, hash);
631  return i < 0 ? 0 : 1;
632  }
634  hm_int count(const K &key, const_iterator it) const
635  {
636  hm_int hash = do_hash(key);
637  hm_int i = do_lookup(key, hash);
638  return i < 0 || i > it.index ? 0 : 1;
639  }
641  iterator find(const K &key)
642  {
643  hm_int hash = do_hash(key);
644  hm_int i = do_lookup(key, hash);
645  if (i < 0)
646  return end();
647  return iterator(this, i);
648  }
649 
651  const_iterator find(const K &key) const
652  {
653  hm_int hash = do_hash(key);
654  hm_int i = do_lookup(key, hash);
655  if (i < 0)
656  return end();
657  return const_iterator(this, i);
658  }
659 
661  T& at(const K &key)
662  {
663  hm_int hash = do_hash(key);
664  hm_int i = do_lookup(key, hash);
665  if (i < 0)
666  throw std::out_of_range("unordered_map::at()");
667  return entries[i].udata.second;
668  }
669 
671  const T& at(const K &key) const
672  {
673  hm_int hash = do_hash(key);
674  hm_int i = do_lookup(key, hash);
675  if (i < 0)
676  throw std::out_of_range("unordered_map::at()");
677  return entries[i].udata.second;
678  }
679 
681  T at(const K &key, const T &defval) const
682  {
683  hm_int hash = do_hash(key);
684  hm_int i = do_lookup(key, hash);
685  if (i < 0)
686  return defval;
687  return entries[i].udata.second;
688  }
689 
691  T& operator[](const K &key)
692  {
693  hm_int hash = do_hash(key);
694  hm_int i = do_lookup(key, hash);
695  if (i < 0)
696  i = do_insert(std::pair<K, T>(key, T()), hash);
697  return entries[i].udata.second;
698  }
699 
706  template<typename Compare = std::less<K>>
707  void sort(Compare comp = Compare())
708  {
709  std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata.first, a.udata.first); });
710  do_rehash();
711  }
712 
713  void swap(unordered_map &other)
714  {
715  hashtable.swap(other.hashtable);
716  entries.swap(other.entries);
717  }
718 
719  bool operator==(const unordered_map &other) const {
720  if (size() != other.size())
721  return false;
722  for (auto &it : entries) {
723  auto oit = other.find(it.udata.first);
724  if (oit == other.end() || !(oit->second == it.udata.second))
725  return false;
726  }
727  return true;
728  }
729 
730  bool operator!=(const unordered_map &other) const {
731  return !operator==(other);
732  }
733 
734  void reserve(size_t n) { entries.reserve(n); }
735  size_t size() const { return entries.size(); }
736  bool empty() const { return entries.empty(); }
737  void clear() { hashtable.clear(); entries.clear(); }
738 
739  iterator begin() { return iterator(this, hm_int(entries.size())-1); }
740  iterator end() { return iterator(nullptr, -1); }
741 
742  const_iterator begin() const { return const_iterator(this, hm_int(entries.size())-1); }
743  const_iterator end() const { return const_iterator(nullptr, -1); }
744 };
745 
752 template<typename K, typename OPS>
754 {
755  template<typename, hm_int, typename> friend class idict;
756 
757  protected:
759  struct entry_t
760  {
761  K udata;
763 
764  entry_t() { }
765  entry_t(const K &idata, hm_int inext) : udata(idata), next(inext) { }
766  };
767 
769  std::vector<hm_int> hashtable;
771  std::vector<entry_t> entries;
773  OPS ops;
774 
775  #ifdef NDEBUG
776  static inline void do_assert(bool) { }
777  #else
778  static inline void do_assert(bool cond) {
779  if (!cond) throw std::runtime_error("unordered_set<> assert failed.");
780  }
781  #endif
782 
792  hm_int do_hash(const K &key) const
793  {
794  hm_uint hash = 0;
795  if (!hashtable.empty())
796  hash = ops.hash(key) % (hm_uint)(hashtable.size());
797  return hash;
798  }
799 
803  void do_rehash()
804  {
805  hashtable.clear();
806  hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
807 
808  for (hm_int i = 0; i < hm_int(entries.size()); i++) {
809  do_assert(-1 <= entries[i].next && entries[i].next < hm_int(entries.size()));
810  hm_int hash = do_hash(entries[i].udata);
811  entries[i].next = hashtable[hash];
812  hashtable[hash] = i;
813  }
814  }
815 
825  {
826  do_assert(index < hm_int(entries.size()));
827  if (hashtable.empty() || index < 0)
828  return 0;
829 
830  hm_int k = hashtable[hash];
831  if (k == index) {
832  hashtable[hash] = entries[index].next;
833  } else {
834  while (entries[k].next != index) {
835  k = entries[k].next;
836  do_assert(0 <= k && k < hm_int(entries.size()));
837  }
838  entries[k].next = entries[index].next;
839  }
840 
841  hm_int back_idx = entries.size()-1;
842 
843  if (index != back_idx)
844  {
845  hm_int back_hash = do_hash(entries[back_idx].udata);
846 
847  k = hashtable[back_hash];
848  if (k == back_idx) {
849  hashtable[back_hash] = index;
850  } else {
851  while (entries[k].next != back_idx) {
852  k = entries[k].next;
853  do_assert(0 <= k && k < hm_int(entries.size()));
854  }
855  entries[k].next = index;
856  }
857 
858  entries[index] = std::move(entries[back_idx]);
859  }
860 
861  entries.pop_back();
862 
863  if (entries.empty())
864  hashtable.clear();
865 
866  return 1;
867  }
868 
877  hm_int do_lookup(const K &key, hm_int &hash) const
878  {
879  if (hashtable.empty())
880  return -1;
881 
882  if (entries.size() * hashtable_size_trigger > hashtable.size()) {
883  ((unordered_set*)this)->do_rehash();
884  hash = do_hash(key);
885  }
886 
887  hm_int index = hashtable[hash];
888 
889  while (index >= 0 && !ops.cmp(entries[index].udata, key)) {
890  index = entries[index].next;
891  do_assert(-1 <= index && index < hm_int(entries.size()));
892  }
893 
894  return index;
895  }
896 
908  hm_int do_insert(const K &value, hm_int &hash)
909  {
910  if (hashtable.empty()) {
911  entries.push_back(entry_t(value, -1));
912  do_rehash();
913  hash = do_hash(value);
914  }
915  else {
916  entries.push_back(entry_t(value, hashtable[hash]));
917  hashtable[hash] = entries.size() - 1;
918  }
919  return entries.size() - 1;
920  }
921 
922  public:
925  friend class unordered_set;
926 
927  protected:
928  const unordered_set *ptr = nullptr;
930 
931  const_iterator(const unordered_set *iptr, hm_int iindex)
932  : ptr(iptr), index(iindex) { }
933 
934  public:
935  // Iterator traits
936  using iterator_category = std::forward_iterator_tag;
937  using value_type = K;
938  using difference_type = std::ptrdiff_t;
939  using pointer = const value_type*;
940  using reference = const value_type&;
941 
942  const_iterator() = default;
943 
944  // Pre-increment
945  const_iterator & operator++() { index--; return *this; }
946  // Post-increment
947  const_iterator operator++(int) { const_iterator tmp = *this; index--; return tmp; }
948 
949  // Pre-decrement
950  const_iterator & operator--() { index++; return *this; }
951  // Post-decrement
952  const_iterator operator--(int) { const_iterator tmp = *this; index++; return tmp; }
953 
954  // Comparison
955  bool operator==(const const_iterator &other) const { return index == other.index; }
956  bool operator!=(const const_iterator &other) const { return index != other.index; }
957 
958  // Dereference
959  reference operator*() const { return ptr->entries[index].udata; }
960  pointer operator->() const { return &ptr->entries[index].udata; }
961 };
962 
964 class iterator {
965  friend class unordered_set;
966 
967  protected:
968  unordered_set *ptr = nullptr;
970 
972  : ptr(iptr), index(iindex) { }
973 
974  public:
975  // Iterator traits
976  using iterator_category = std::forward_iterator_tag;
977  using value_type = K;
978  using difference_type = std::ptrdiff_t;
979  using pointer = value_type*;
981 
982  iterator() = default;
983 
984  // Pre-increment
985  iterator & operator++() { index--; return *this; }
986  // Post-increment
987  iterator operator++(int) { iterator tmp = *this; index--; return tmp; }
988 
989  // Pre-decrement
990  iterator & operator--() { index++; return *this; }
991  // Post-decrement
992  iterator operator--(int) { iterator tmp = *this; index++; return tmp; }
993 
994  // Comparison
995  bool operator==(const iterator &other) const { return index == other.index; }
996  bool operator!=(const iterator &other) const { return index != other.index; }
997 
998  // Dereference
999  reference operator*() { return ptr->entries[index].udata; }
1000  pointer operator->() { return &ptr->entries[index].udata; }
1001 
1002  // Const dereference
1003  const value_type &operator*() const { return ptr->entries[index].udata; }
1004  const value_type *operator->() const { return &ptr->entries[index].udata; }
1005 
1006  // Conversion to const_iterator
1007  operator const_iterator() const { return const_iterator(ptr, index); }
1008 };
1009 
1012  { }
1013 
1016  {
1017  entries = other.entries;
1018  do_rehash();
1019  }
1020 
1023  {
1024  swap(other);
1025  }
1026 
1028  entries = other.entries;
1029  do_rehash();
1030  return *this;
1031  }
1032 
1034  clear();
1035  swap(other);
1036  return *this;
1037  }
1038 
1039  unordered_set(const std::initializer_list<K> &list)
1040  {
1041  for (auto &it : list)
1042  insert(it);
1043  }
1044 
1045  template<class InputIterator>
1046  unordered_set(InputIterator first, InputIterator last)
1047  {
1048  insert(first, last);
1049  }
1050 
1051  template<class InputIterator>
1052  void insert(InputIterator first, InputIterator last)
1053  {
1054  for (; first != last; ++first)
1055  insert(*first);
1056  }
1057 
1058  std::pair<iterator, bool> insert(const K &value)
1059  {
1060  hm_int hash = do_hash(value);
1061  hm_int i = do_lookup(value, hash);
1062  if (i >= 0)
1063  return std::pair<iterator, bool>(iterator(this, i), false);
1064  i = do_insert(value, hash);
1065  return std::pair<iterator, bool>(iterator(this, i), true);
1066  }
1067 
1068  hm_int erase(const K &key)
1069  {
1070  hm_int hash = do_hash(key);
1071  hm_int index = do_lookup(key, hash);
1072  return do_erase(index, hash);
1073  }
1074 
1076  {
1077  hm_int hash = do_hash(*it);
1078  do_erase(it.index, hash);
1079  return ++it;
1080  }
1081 
1082  hm_int count(const K &key) const
1083  {
1084  hm_int hash = do_hash(key);
1085  hm_int i = do_lookup(key, hash);
1086  return i < 0 ? 0 : 1;
1087  }
1088 
1089  hm_int count(const K &key, const_iterator it) const
1090  {
1091  hm_int hash = do_hash(key);
1092  hm_int i = do_lookup(key, hash);
1093  return i < 0 || i > it.index ? 0 : 1;
1094  }
1095 
1096  iterator find(const K &key)
1097  {
1098  hm_int hash = do_hash(key);
1099  hm_int i = do_lookup(key, hash);
1100  if (i < 0)
1101  return end();
1102  return iterator(this, i);
1103  }
1104 
1105  const_iterator find(const K &key) const
1106  {
1107  hm_int hash = do_hash(key);
1108  hm_int i = do_lookup(key, hash);
1109  if (i < 0)
1110  return end();
1111  return const_iterator(this, i);
1112  }
1113 
1114  bool operator[](const K &key)
1115  {
1116  hm_int hash = do_hash(key);
1117  hm_int i = do_lookup(key, hash);
1118  return i >= 0;
1119  }
1120 
1121  template<typename Compare = std::less<K>>
1122  void sort(Compare comp = Compare())
1123  {
1124  std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata, a.udata); });
1125  do_rehash();
1126  }
1127 
1128  K pop()
1129  {
1130  iterator it = begin();
1131  K ret = *it;
1132  erase(it);
1133  return ret;
1134  }
1135 
1136  void swap(unordered_set &other)
1137  {
1138  hashtable.swap(other.hashtable);
1139  entries.swap(other.entries);
1140  }
1141 
1142  bool operator==(const unordered_set &other) const {
1143  if (size() != other.size())
1144  return false;
1145  for (auto &it : entries)
1146  if (!other.count(it.udata))
1147  return false;
1148  return true;
1149  }
1150 
1151  bool operator!=(const unordered_set &other) const {
1152  return !operator==(other);
1153  }
1154 
1155  void reserve(size_t n) { entries.reserve(n); }
1156  size_t size() const { return entries.size(); }
1157  bool empty() const { return entries.empty(); }
1158  void clear() { hashtable.clear(); entries.clear(); }
1159 
1160  iterator begin() { return iterator(this, hm_int(entries.size())-1); }
1161  iterator end() { return iterator(nullptr, -1); }
1162 
1163  const_iterator begin() const { return const_iterator(this, hm_int(entries.size())-1); }
1164  const_iterator end() const { return const_iterator(nullptr, -1); }
1165 };
1166 
1167 template<typename K, hm_int offset, typename OPS>
1168 class idict
1169 {
1170  unordered_set<K, OPS> database;
1171 
1172 public:
1174 
1175  hm_int operator()(const K &key)
1176  {
1177  hm_int hash = database.do_hash(key);
1178  hm_int i = database.do_lookup(key, hash);
1179  if (i < 0)
1180  i = database.do_insert(key, hash);
1181  return i + offset;
1182  }
1183 
1184  hm_int at(const K &key) const
1185  {
1186  hm_int hash = database.do_hash(key);
1187  hm_int i = database.do_lookup(key, hash);
1188  if (i < 0)
1189  throw std::out_of_range("idict::at()");
1190  return i + offset;
1191  }
1192 
1193  hm_int at(const K &key, hm_int defval) const
1194  {
1195  hm_int hash = database.do_hash(key);
1196  hm_int i = database.do_lookup(key, hash);
1197  if (i < 0)
1198  return defval;
1199  return i + offset;
1200  }
1201 
1202  hm_int count(const K &key) const
1203  {
1204  hm_int hash = database.do_hash(key);
1205  hm_int i = database.do_lookup(key, hash);
1206  return i < 0 ? 0 : 1;
1207  }
1208 
1209  void expect(const K &key, hm_int i)
1210  {
1211  hm_int j = (*this)(key);
1212  if (i != j)
1213  throw std::out_of_range("idict::expect()");
1214  }
1215 
1216  const K &operator[](hm_int index) const
1217  {
1218  return database.entries.at(index - offset).udata;
1219  }
1220 
1221  void swap(idict &other)
1222  {
1223  database.swap(other.database);
1224  }
1225 
1226  void reserve(size_t n) { database.reserve(n); }
1227  size_t size() const { return database.size(); }
1228  bool empty() const { return database.empty(); }
1229  void clear() { database.clear(); }
1230 
1231  const_iterator begin() const { return database.begin(); }
1232  const_iterator end() const { return database.end(); }
1233 };
1234 
1235 template<typename K, typename OPS>
1236 class mfp
1237 {
1238  mutable idict<K, 0, OPS> database;
1239  mutable std::vector<hm_int> parents;
1240 
1241 public:
1243 
1244  hm_int operator()(const K &key) const
1245  {
1246  hm_int i = database(key);
1247  parents.resize(database.size(), -1);
1248  return i;
1249  }
1250 
1251  const K &operator[](hm_int index) const
1252  {
1253  return database[index];
1254  }
1255 
1257  {
1258  hm_int p = i, k = i;
1259 
1260  while (parents[p] != -1)
1261  p = parents[p];
1262 
1263  while (k != p) {
1264  hm_int next_k = parents[k];
1265  parents[k] = p;
1266  k = next_k;
1267  }
1268 
1269  return p;
1270  }
1271 
1272  void imerge(hm_int i, hm_int j)
1273  {
1274  i = ifind(i);
1275  j = ifind(j);
1276 
1277  if (i != j)
1278  parents[i] = j;
1279  }
1280 
1282  {
1283  hm_int k = i;
1284 
1285  while (k != -1) {
1286  hm_int next_k = parents[k];
1287  parents[k] = i;
1288  k = next_k;
1289  }
1290 
1291  parents[i] = -1;
1292  }
1293 
1294  hm_int lookup(const K &a) const
1295  {
1296  return ifind((*this)(a));
1297  }
1298 
1299  const K &find(const K &a) const
1300  {
1301  hm_int i = database.at(a, -1);
1302  if (i < 0)
1303  return a;
1304  return (*this)[ifind(i)];
1305  }
1306 
1307  void merge(const K &a, const K &b)
1308  {
1309  imerge((*this)(a), (*this)(b));
1310  }
1311 
1312  void promote(const K &a)
1313  {
1314  hm_int i = database.at(a, -1);
1315  if (i >= 0)
1316  ipromote(i);
1317  }
1318 
1319  void swap(mfp &other)
1320  {
1321  database.swap(other.database);
1322  parents.swap(other.parents);
1323  }
1324 
1325  void reserve(size_t n) { database.reserve(n); }
1326  size_t size() const { return database.size(); }
1327  bool empty() const { return database.empty(); }
1328  void clear() { database.clear(); parents.clear(); }
1329 
1330  const_iterator begin() const { return database.begin(); }
1331  const_iterator end() const { return database.end(); }
1332 };
1333 
1334 } /* namespace hashmap */
1335 
1336 #endif
void swap(idict &other)
Definition: hashmap.hpp:1221
hm_int operator()(const K &key)
Definition: hashmap.hpp:1175
const K & operator[](hm_int index) const
Definition: hashmap.hpp:1216
void expect(const K &key, hm_int i)
Definition: hashmap.hpp:1209
void reserve(size_t n)
Definition: hashmap.hpp:1226
const_iterator begin() const
Definition: hashmap.hpp:1231
hm_int at(const K &key) const
Definition: hashmap.hpp:1184
size_t size() const
Definition: hashmap.hpp:1227
unordered_set< K, OPS >::const_iterator const_iterator
Definition: hashmap.hpp:1173
hm_int count(const K &key) const
Definition: hashmap.hpp:1202
bool empty() const
Definition: hashmap.hpp:1228
const_iterator end() const
Definition: hashmap.hpp:1232
hm_int at(const K &key, hm_int defval) const
Definition: hashmap.hpp:1193
hm_int operator()(const K &key) const
Definition: hashmap.hpp:1244
hm_int lookup(const K &a) const
Definition: hashmap.hpp:1294
void swap(mfp &other)
Definition: hashmap.hpp:1319
void ipromote(hm_int i)
Definition: hashmap.hpp:1281
const K & operator[](hm_int index) const
Definition: hashmap.hpp:1251
void reserve(size_t n)
Definition: hashmap.hpp:1325
const K & find(const K &a) const
Definition: hashmap.hpp:1299
void clear()
Definition: hashmap.hpp:1328
hm_int ifind(hm_int i) const
Definition: hashmap.hpp:1256
const_iterator begin() const
Definition: hashmap.hpp:1330
idict< K, 0, OPS >::const_iterator const_iterator
Definition: hashmap.hpp:1242
void promote(const K &a)
Definition: hashmap.hpp:1312
bool empty() const
Definition: hashmap.hpp:1327
void imerge(hm_int i, hm_int j)
Definition: hashmap.hpp:1272
const_iterator end() const
Definition: hashmap.hpp:1331
size_t size() const
Definition: hashmap.hpp:1326
void merge(const K &a, const K &b)
Definition: hashmap.hpp:1307
const_iterator(const unordered_map *iptr, hm_int iindex)
Definition: hashmap.hpp:463
std::forward_iterator_tag iterator_category
Definition: hashmap.hpp:468
bool operator!=(const const_iterator &other) const
Definition: hashmap.hpp:489
bool operator==(const const_iterator &other) const
Definition: hashmap.hpp:488
bool operator<(const const_iterator &other) const
Definition: hashmap.hpp:487
const value_type & operator*() const
Definition: hashmap.hpp:537
std::pair< K, T > value_type
Definition: hashmap.hpp:510
std::forward_iterator_tag iterator_category
Definition: hashmap.hpp:509
bool operator!=(const iterator &other) const
Definition: hashmap.hpp:530
iterator(unordered_map *iptr, hm_int iindex)
Definition: hashmap.hpp:504
const value_type * operator->() const
Definition: hashmap.hpp:538
bool operator<(const iterator &other) const
Definition: hashmap.hpp:528
bool operator==(const iterator &other) const
Definition: hashmap.hpp:529
T at(const K &key, const T &defval) const
Return data if existent or default value.
Definition: hashmap.hpp:681
iterator find(const K &key)
Search for key. Return iterator.
Definition: hashmap.hpp:641
hm_int count(const K &key, const_iterator it) const
Check if key exists and matches iterator.
Definition: hashmap.hpp:634
unordered_map & operator=(const unordered_map &other)
Definition: hashmap.hpp:561
const_iterator end() const
Definition: hashmap.hpp:743
unordered_map(const std::initializer_list< std::pair< K, T >> &list)
Definition: hashmap.hpp:573
unordered_map(unordered_map &&other)
Construct map form another map.
Definition: hashmap.hpp:556
hm_int count(const K &key) const
Check if key exists.
Definition: hashmap.hpp:627
bool operator!=(const unordered_map &other) const
Definition: hashmap.hpp:730
const_iterator begin() const
Definition: hashmap.hpp:742
std::pair< iterator, bool > insert(const std::pair< K, T > &value)
Insert key-value pair.
Definition: hashmap.hpp:603
const T & at(const K &key) const
Const data access by key.
Definition: hashmap.hpp:671
T & operator[](const K &key)
Data access or empty insert.
Definition: hashmap.hpp:691
void swap(unordered_map &other)
Definition: hashmap.hpp:713
void sort(Compare comp=Compare())
Sort data entries.
Definition: hashmap.hpp:707
bool operator==(const unordered_map &other) const
Definition: hashmap.hpp:719
const_iterator find(const K &key) const
Search for key. Return const_iterator.
Definition: hashmap.hpp:651
bool empty() const
Definition: hashmap.hpp:736
void reserve(size_t n)
Definition: hashmap.hpp:734
std::pair< iterator, bool > insert(const K &key)
User insert as key lookup.
Definition: hashmap.hpp:593
void insert(InputIterator first, InputIterator last)
Insert Iterator range.
Definition: hashmap.hpp:587
iterator erase(iterator it)
Erase by iterator.
Definition: hashmap.hpp:620
unordered_map()
Empty constructor.
Definition: hashmap.hpp:545
T & at(const K &key)
Data access by key.
Definition: hashmap.hpp:661
unordered_map(InputIterator first, InputIterator last)
Construct from Iterator range.
Definition: hashmap.hpp:581
unordered_map & operator=(unordered_map &&other)
Definition: hashmap.hpp:567
size_t size() const
Definition: hashmap.hpp:735
hm_int erase(const K &key)
Erase by key.
Definition: hashmap.hpp:613
unordered_map(const unordered_map &other)
Construct from another map.
Definition: hashmap.hpp:549
bool operator==(const const_iterator &other) const
Definition: hashmap.hpp:955
std::forward_iterator_tag iterator_category
Definition: hashmap.hpp:936
bool operator!=(const const_iterator &other) const
Definition: hashmap.hpp:956
const_iterator(const unordered_set *iptr, hm_int iindex)
Definition: hashmap.hpp:931
const value_type & operator*() const
Definition: hashmap.hpp:1003
std::forward_iterator_tag iterator_category
Definition: hashmap.hpp:976
bool operator!=(const iterator &other) const
Definition: hashmap.hpp:996
const value_type * operator->() const
Definition: hashmap.hpp:1004
iterator(unordered_set *iptr, hm_int iindex)
Definition: hashmap.hpp:971
bool operator==(const iterator &other) const
Definition: hashmap.hpp:995
Custom unordered_set implementation.
Definition: hashmap.hpp:754
size_t size() const
Definition: hashmap.hpp:1156
unordered_set(InputIterator first, InputIterator last)
Definition: hashmap.hpp:1046
unordered_set(unordered_set &&other)
Construct from another set.
Definition: hashmap.hpp:1022
unordered_set & operator=(unordered_set &&other)
Definition: hashmap.hpp:1033
iterator find(const K &key)
Definition: hashmap.hpp:1096
std::pair< iterator, bool > insert(const K &value)
Definition: hashmap.hpp:1058
const_iterator end() const
Definition: hashmap.hpp:1164
void sort(Compare comp=Compare())
Definition: hashmap.hpp:1122
hm_int erase(const K &key)
Definition: hashmap.hpp:1068
const_iterator find(const K &key) const
Definition: hashmap.hpp:1105
bool operator==(const unordered_set &other) const
Definition: hashmap.hpp:1142
hm_int do_erase(hm_int index, hm_int hash)
Remove an entry.
Definition: hashmap.hpp:824
unordered_set(const unordered_set &other)
Construct from another set.
Definition: hashmap.hpp:1015
unordered_set(const std::initializer_list< K > &list)
Definition: hashmap.hpp:1039
OPS ops
the hash generator
Definition: hashmap.hpp:773
unordered_set & operator=(const unordered_set &other)
Definition: hashmap.hpp:1027
iterator erase(iterator it)
Definition: hashmap.hpp:1075
void do_rehash()
Resize the hashtable and compute new hashes.
Definition: hashmap.hpp:803
const_iterator begin() const
Definition: hashmap.hpp:1163
bool empty() const
Definition: hashmap.hpp:1157
hm_int do_hash(const K &key) const
Generate a hash from a key.
Definition: hashmap.hpp:792
std::vector< entry_t > entries
the stored entries
Definition: hashmap.hpp:771
std::vector< hm_int > hashtable
the hashtable
Definition: hashmap.hpp:769
static void do_assert(bool cond)
Definition: hashmap.hpp:778
void reserve(size_t n)
Definition: hashmap.hpp:1155
void swap(unordered_set &other)
Definition: hashmap.hpp:1136
hm_int do_lookup(const K &key, hm_int &hash) const
Return hash and index for a key.
Definition: hashmap.hpp:877
bool operator[](const K &key)
Definition: hashmap.hpp:1114
unordered_set()
Empty constructor.
Definition: hashmap.hpp:1011
bool operator!=(const unordered_set &other) const
Definition: hashmap.hpp:1151
hm_int count(const K &key) const
Definition: hashmap.hpp:1082
void insert(InputIterator first, InputIterator last)
Definition: hashmap.hpp:1052
hm_int count(const K &key, const_iterator it) const
Definition: hashmap.hpp:1089
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:908
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:218
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:186
static bool cmp(const char *a, const char *b)
Definition: hashmap.hpp:180
static bool cmp(T a, T b)
Definition: hashmap.hpp:99
static hm_uint hash(const T *a)
Definition: hashmap.hpp:208
static bool cmp(const void *a, const void *b)
Definition: hashmap.hpp:204
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:147
static bool cmp(std::pair< P, Q > a, std::pair< P, Q > b)
Definition: hashmap.hpp:144
static hm_uint hash(const std::string &a)
Definition: hashmap.hpp:135
static bool cmp(const std::string &a, const std::string &b)
Definition: hashmap.hpp:132
static std::enable_if< I !=sizeof...(T), hm_uint >::type hash(std::tuple< T... > a)
Definition: hashmap.hpp:161
static std::enable_if< I==sizeof...(T), hm_uint >::type hash(std::tuple< T... >)
Definition: hashmap.hpp:157
static bool cmp(std::tuple< T... > a, std::tuple< T... > b)
Definition: hashmap.hpp:153
static hm_uint hash(std::vector< T > a)
Definition: hashmap.hpp:171
static bool cmp(std::vector< T > a, std::vector< T > b)
Definition: hashmap.hpp:168
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:198
static bool cmp(const void *a, const void *b)
Definition: hashmap.hpp:195
internal entry type
Definition: hashmap.hpp:760
entry_t(const K &idata, hm_int inext)
Definition: hashmap.hpp:765