63ac956f21d8ff78bf1168c9377ff8ba585ab149
[yosys.git] / kernel / hashlib.h
1 // This is free and unencumbered software released into the public domain.
2 //
3 // Anyone is free to copy, modify, publish, use, compile, sell, or
4 // distribute this software, either in source code form or as a compiled
5 // binary, for any purpose, commercial or non-commercial, and by any
6 // means.
7
8 // -------------------------------------------------------
9 // Written by Clifford Wolf <clifford@clifford.at> in 2014
10 // -------------------------------------------------------
11
12 #ifndef HASHLIB_H
13 #define HASHLIB_H
14
15 #include <stdexcept>
16 #include <algorithm>
17 #include <string>
18 #include <vector>
19
20 namespace hashlib {
21
22 const int hashtable_size_trigger = 2;
23 const int hashtable_size_factor = 3;
24
25 // The XOR version of DJB2
26 inline unsigned int mkhash(unsigned int a, unsigned int b) {
27 return ((a << 5) + a) ^ b;
28 }
29
30 // traditionally 5381 is used as starting value for the djb2 hash
31 const unsigned int mkhash_init = 5381;
32
33 // The ADD version of DJB2
34 // (use this version for cache locality in b)
35 inline unsigned int mkhash_add(unsigned int a, unsigned int b) {
36 return ((a << 5) + a) + b;
37 }
38
39 inline unsigned int mkhash_xorshift(unsigned int a) {
40 if (sizeof(a) == 4) {
41 a ^= a << 13;
42 a ^= a >> 17;
43 a ^= a << 5;
44 } else if (sizeof(a) == 8) {
45 a ^= a << 13;
46 a ^= a >> 7;
47 a ^= a << 17;
48 } else
49 throw std::runtime_error("mkhash_xorshift() only implemented for 32 bit and 64 bit ints");
50 return a;
51 }
52
53 template<typename T> struct hash_ops {
54 static inline bool cmp(const T &a, const T &b) {
55 return a == b;
56 }
57 static inline unsigned int hash(const T &a) {
58 return a.hash();
59 }
60 };
61
62 struct hash_int_ops {
63 template<typename T>
64 static inline bool cmp(T a, T b) {
65 return a == b;
66 }
67 };
68
69 template<> struct hash_ops<int32_t> : hash_int_ops
70 {
71 static inline unsigned int hash(int32_t a) {
72 return a;
73 }
74 };
75 template<> struct hash_ops<int64_t> : hash_int_ops
76 {
77 static inline unsigned int hash(int64_t a) {
78 return mkhash((unsigned int)(a), (unsigned int)(a >> 32));
79 }
80 };
81
82 template<> struct hash_ops<std::string> {
83 static inline bool cmp(const std::string &a, const std::string &b) {
84 return a == b;
85 }
86 static inline unsigned int hash(const std::string &a) {
87 unsigned int v = 0;
88 for (auto c : a)
89 v = mkhash(v, c);
90 return v;
91 }
92 };
93
94 template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {
95 static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
96 return a == b;
97 }
98 static inline unsigned int hash(std::pair<P, Q> a) {
99 return mkhash(hash_ops<P>::hash(a.first), hash_ops<Q>::hash(a.second));
100 }
101 };
102
103 template<typename... T> struct hash_ops<std::tuple<T...>> {
104 static inline bool cmp(std::tuple<T...> a, std::tuple<T...> b) {
105 return a == b;
106 }
107 template<size_t I = 0>
108 static inline typename std::enable_if<I == sizeof...(T), unsigned int>::type hash(std::tuple<T...>) {
109 return mkhash_init;
110 }
111 template<size_t I = 0>
112 static inline typename std::enable_if<I != sizeof...(T), unsigned int>::type hash(std::tuple<T...> a) {
113 typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
114 return mkhash(hash<I+1>(a), element_ops_t::hash(std::get<I>(a)));
115 }
116 };
117
118 template<typename T> struct hash_ops<std::vector<T>> {
119 static inline bool cmp(std::vector<T> a, std::vector<T> b) {
120 return a == b;
121 }
122 static inline unsigned int hash(std::vector<T> a) {
123 unsigned int h = mkhash_init;
124 for (auto k : a)
125 h = mkhash(h, hash_ops<T>::hash(k));
126 return h;
127 }
128 };
129
130 struct hash_cstr_ops {
131 static inline bool cmp(const char *a, const char *b) {
132 for (int i = 0; a[i] || b[i]; i++)
133 if (a[i] != b[i])
134 return false;
135 return true;
136 }
137 static inline unsigned int hash(const char *a) {
138 unsigned int hash = mkhash_init;
139 while (*a)
140 hash = mkhash(hash, *(a++));
141 return hash;
142 }
143 };
144
145 struct hash_ptr_ops {
146 static inline bool cmp(const void *a, const void *b) {
147 return a == b;
148 }
149 static inline unsigned int hash(const void *a) {
150 return (uintptr_t)a;
151 }
152 };
153
154 struct hash_obj_ops {
155 static inline bool cmp(const void *a, const void *b) {
156 return a == b;
157 }
158 template<typename T>
159 static inline unsigned int hash(const T *a) {
160 return a ? a->hash() : 0;
161 }
162 };
163
164 template<typename T>
165 inline unsigned int mkhash(const T &v) {
166 return hash_ops<T>().hash(v);
167 }
168
169 inline int hashtable_size(int min_size)
170 {
171 static std::vector<int> zero_and_some_primes = {
172 0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,
173 853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,
174 12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281,
175 120371, 150473, 188107, 235159, 293957, 367453, 459317, 574157, 717697,
176 897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037,
177 5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411,
178 25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,
179 121590311, 151987889, 189984863, 237481091, 296851369, 371064217
180 };
181
182 for (auto p : zero_and_some_primes)
183 if (p >= min_size) return p;
184
185 if (sizeof(int) == 4)
186 throw std::length_error("hash table exceeded maximum size. use a ILP64 abi for larger tables.");
187
188 for (auto p : zero_and_some_primes)
189 if (100129 * p > min_size) return 100129 * p;
190
191 throw std::length_error("hash table exceeded maximum size.");
192 }
193
194 template<typename K, typename T, typename OPS = hash_ops<K>> class dict;
195 template<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict;
196 template<typename K, typename OPS = hash_ops<K>> class pool;
197 template<typename K, typename OPS = hash_ops<K>> class mfp;
198
199 template<typename K, typename T, typename OPS>
200 class dict
201 {
202 struct entry_t
203 {
204 std::pair<K, T> udata;
205 int next;
206
207 entry_t() { }
208 entry_t(const std::pair<K, T> &udata, int next) : udata(udata), next(next) { }
209 entry_t(std::pair<K, T> &&udata, int next) : udata(std::move(udata)), next(next) { }
210 };
211
212 std::vector<int> hashtable;
213 std::vector<entry_t> entries;
214 OPS ops;
215
216 #ifdef NDEBUG
217 static inline void do_assert(bool) { }
218 #else
219 static inline void do_assert(bool cond) {
220 if (!cond) throw std::runtime_error("dict<> assert failed.");
221 }
222 #endif
223
224 int do_hash(const K &key) const
225 {
226 unsigned int hash = 0;
227 if (!hashtable.empty())
228 hash = ops.hash(key) % (unsigned int)(hashtable.size());
229 return hash;
230 }
231
232 void do_rehash()
233 {
234 hashtable.clear();
235 hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
236
237 for (int i = 0; i < int(entries.size()); i++) {
238 do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
239 int hash = do_hash(entries[i].udata.first);
240 entries[i].next = hashtable[hash];
241 hashtable[hash] = i;
242 }
243 }
244
245 int do_erase(int index, int hash)
246 {
247 do_assert(index < int(entries.size()));
248 if (hashtable.empty() || index < 0)
249 return 0;
250
251 int k = hashtable[hash];
252 do_assert(0 <= k && k < int(entries.size()));
253
254 if (k == index) {
255 hashtable[hash] = entries[index].next;
256 } else {
257 while (entries[k].next != index) {
258 k = entries[k].next;
259 do_assert(0 <= k && k < int(entries.size()));
260 }
261 entries[k].next = entries[index].next;
262 }
263
264 int back_idx = entries.size()-1;
265
266 if (index != back_idx)
267 {
268 int back_hash = do_hash(entries[back_idx].udata.first);
269
270 k = hashtable[back_hash];
271 do_assert(0 <= k && k < int(entries.size()));
272
273 if (k == back_idx) {
274 hashtable[back_hash] = index;
275 } else {
276 while (entries[k].next != back_idx) {
277 k = entries[k].next;
278 do_assert(0 <= k && k < int(entries.size()));
279 }
280 entries[k].next = index;
281 }
282
283 entries[index] = std::move(entries[back_idx]);
284 }
285
286 entries.pop_back();
287
288 if (entries.empty())
289 hashtable.clear();
290
291 return 1;
292 }
293
294 int do_lookup(const K &key, int &hash) const
295 {
296 if (hashtable.empty())
297 return -1;
298
299 if (entries.size() * hashtable_size_trigger > hashtable.size()) {
300 ((dict*)this)->do_rehash();
301 hash = do_hash(key);
302 }
303
304 int index = hashtable[hash];
305
306 while (index >= 0 && !ops.cmp(entries[index].udata.first, key)) {
307 index = entries[index].next;
308 do_assert(-1 <= index && index < int(entries.size()));
309 }
310
311 return index;
312 }
313
314 int do_insert(const K &key, int &hash)
315 {
316 if (hashtable.empty()) {
317 entries.push_back(entry_t(std::pair<K, T>(key, T()), -1));
318 do_rehash();
319 hash = do_hash(key);
320 } else {
321 entries.push_back(entry_t(std::pair<K, T>(key, T()), hashtable[hash]));
322 hashtable[hash] = entries.size() - 1;
323 }
324 return entries.size() - 1;
325 }
326
327 int do_insert(const std::pair<K, T> &value, int &hash)
328 {
329 if (hashtable.empty()) {
330 entries.push_back(entry_t(value, -1));
331 do_rehash();
332 hash = do_hash(value.first);
333 } else {
334 entries.push_back(entry_t(value, hashtable[hash]));
335 hashtable[hash] = entries.size() - 1;
336 }
337 return entries.size() - 1;
338 }
339
340 public:
341 class const_iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
342 {
343 friend class dict;
344 protected:
345 const dict *ptr;
346 int index;
347 const_iterator(const dict *ptr, int index) : ptr(ptr), index(index) { }
348 public:
349 const_iterator() { }
350 const_iterator operator++() { index--; return *this; }
351 bool operator<(const const_iterator &other) const { return index > other.index; }
352 bool operator==(const const_iterator &other) const { return index == other.index; }
353 bool operator!=(const const_iterator &other) const { return index != other.index; }
354 const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }
355 const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
356 };
357
358 class iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
359 {
360 friend class dict;
361 protected:
362 dict *ptr;
363 int index;
364 iterator(dict *ptr, int index) : ptr(ptr), index(index) { }
365 public:
366 iterator() { }
367 iterator operator++() { index--; return *this; }
368 bool operator<(const iterator &other) const { return index > other.index; }
369 bool operator==(const iterator &other) const { return index == other.index; }
370 bool operator!=(const iterator &other) const { return index != other.index; }
371 std::pair<K, T> &operator*() { return ptr->entries[index].udata; }
372 std::pair<K, T> *operator->() { return &ptr->entries[index].udata; }
373 const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }
374 const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
375 operator const_iterator() const { return const_iterator(ptr, index); }
376 };
377
378 dict()
379 {
380 }
381
382 dict(const dict &other)
383 {
384 entries = other.entries;
385 do_rehash();
386 }
387
388 dict(dict &&other)
389 {
390 swap(other);
391 }
392
393 dict &operator=(const dict &other) {
394 entries = other.entries;
395 do_rehash();
396 return *this;
397 }
398
399 dict &operator=(dict &&other) {
400 clear();
401 swap(other);
402 return *this;
403 }
404
405 dict(const std::initializer_list<std::pair<K, T>> &list)
406 {
407 for (auto &it : list)
408 insert(it);
409 }
410
411 template<class InputIterator>
412 dict(InputIterator first, InputIterator last)
413 {
414 insert(first, last);
415 }
416
417 template<class InputIterator>
418 void insert(InputIterator first, InputIterator last)
419 {
420 for (; first != last; ++first)
421 insert(*first);
422 }
423
424 std::pair<iterator, bool> insert(const K &key)
425 {
426 int hash = do_hash(key);
427 int i = do_lookup(key, hash);
428 if (i >= 0)
429 return std::pair<iterator, bool>(iterator(this, i), false);
430 i = do_insert(key, hash);
431 return std::pair<iterator, bool>(iterator(this, i), true);
432 }
433
434 std::pair<iterator, bool> insert(const std::pair<K, T> &value)
435 {
436 int hash = do_hash(value.first);
437 int i = do_lookup(value.first, hash);
438 if (i >= 0)
439 return std::pair<iterator, bool>(iterator(this, i), false);
440 i = do_insert(value, hash);
441 return std::pair<iterator, bool>(iterator(this, i), true);
442 }
443
444 int erase(const K &key)
445 {
446 int hash = do_hash(key);
447 int index = do_lookup(key, hash);
448 return do_erase(index, hash);
449 }
450
451 iterator erase(iterator it)
452 {
453 int hash = do_hash(it->first);
454 do_erase(it.index, hash);
455 return ++it;
456 }
457
458 int count(const K &key) const
459 {
460 int hash = do_hash(key);
461 int i = do_lookup(key, hash);
462 return i < 0 ? 0 : 1;
463 }
464
465 int count(const K &key, const_iterator it) const
466 {
467 int hash = do_hash(key);
468 int i = do_lookup(key, hash);
469 return i < 0 || i > it.index ? 0 : 1;
470 }
471
472 iterator find(const K &key)
473 {
474 int hash = do_hash(key);
475 int i = do_lookup(key, hash);
476 if (i < 0)
477 return end();
478 return iterator(this, i);
479 }
480
481 const_iterator find(const K &key) const
482 {
483 int hash = do_hash(key);
484 int i = do_lookup(key, hash);
485 if (i < 0)
486 return end();
487 return const_iterator(this, i);
488 }
489
490 T& at(const K &key)
491 {
492 int hash = do_hash(key);
493 int i = do_lookup(key, hash);
494 if (i < 0)
495 throw std::out_of_range("dict::at()");
496 return entries[i].udata.second;
497 }
498
499 const T& at(const K &key) const
500 {
501 int hash = do_hash(key);
502 int i = do_lookup(key, hash);
503 if (i < 0)
504 throw std::out_of_range("dict::at()");
505 return entries[i].udata.second;
506 }
507
508 T at(const K &key, const T &defval) const
509 {
510 int hash = do_hash(key);
511 int i = do_lookup(key, hash);
512 if (i < 0)
513 return defval;
514 return entries[i].udata.second;
515 }
516
517 T& operator[](const K &key)
518 {
519 int hash = do_hash(key);
520 int i = do_lookup(key, hash);
521 if (i < 0)
522 i = do_insert(std::pair<K, T>(key, T()), hash);
523 return entries[i].udata.second;
524 }
525
526 template<typename Compare = std::less<K>>
527 void sort(Compare comp = Compare())
528 {
529 std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata.first, a.udata.first); });
530 do_rehash();
531 }
532
533 void swap(dict &other)
534 {
535 hashtable.swap(other.hashtable);
536 entries.swap(other.entries);
537 }
538
539 bool operator==(const dict &other) const {
540 if (size() != other.size())
541 return false;
542 for (auto &it : entries) {
543 auto oit = other.find(it.udata.first);
544 if (oit == other.end() || !(oit->second == it.udata.second))
545 return false;
546 }
547 return true;
548 }
549
550 bool operator!=(const dict &other) const {
551 return !operator==(other);
552 }
553
554 void reserve(size_t n) { entries.reserve(n); }
555 size_t size() const { return entries.size(); }
556 bool empty() const { return entries.empty(); }
557 void clear() { hashtable.clear(); entries.clear(); }
558
559 iterator begin() { return iterator(this, int(entries.size())-1); }
560 iterator end() { return iterator(nullptr, -1); }
561
562 const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
563 const_iterator end() const { return const_iterator(nullptr, -1); }
564 };
565
566 template<typename K, typename OPS>
567 class pool
568 {
569 template<typename, int, typename> friend class idict;
570
571 protected:
572 struct entry_t
573 {
574 K udata;
575 int next;
576
577 entry_t() { }
578 entry_t(const K &udata, int next) : udata(udata), next(next) { }
579 };
580
581 std::vector<int> hashtable;
582 std::vector<entry_t> entries;
583 OPS ops;
584
585 #ifdef NDEBUG
586 static inline void do_assert(bool) { }
587 #else
588 static inline void do_assert(bool cond) {
589 if (!cond) throw std::runtime_error("pool<> assert failed.");
590 }
591 #endif
592
593 int do_hash(const K &key) const
594 {
595 unsigned int hash = 0;
596 if (!hashtable.empty())
597 hash = ops.hash(key) % (unsigned int)(hashtable.size());
598 return hash;
599 }
600
601 void do_rehash()
602 {
603 hashtable.clear();
604 hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
605
606 for (int i = 0; i < int(entries.size()); i++) {
607 do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
608 int hash = do_hash(entries[i].udata);
609 entries[i].next = hashtable[hash];
610 hashtable[hash] = i;
611 }
612 }
613
614 int do_erase(int index, int hash)
615 {
616 do_assert(index < int(entries.size()));
617 if (hashtable.empty() || index < 0)
618 return 0;
619
620 int k = hashtable[hash];
621 if (k == index) {
622 hashtable[hash] = entries[index].next;
623 } else {
624 while (entries[k].next != index) {
625 k = entries[k].next;
626 do_assert(0 <= k && k < int(entries.size()));
627 }
628 entries[k].next = entries[index].next;
629 }
630
631 int back_idx = entries.size()-1;
632
633 if (index != back_idx)
634 {
635 int back_hash = do_hash(entries[back_idx].udata);
636
637 k = hashtable[back_hash];
638 if (k == back_idx) {
639 hashtable[back_hash] = index;
640 } else {
641 while (entries[k].next != back_idx) {
642 k = entries[k].next;
643 do_assert(0 <= k && k < int(entries.size()));
644 }
645 entries[k].next = index;
646 }
647
648 entries[index] = std::move(entries[back_idx]);
649 }
650
651 entries.pop_back();
652
653 if (entries.empty())
654 hashtable.clear();
655
656 return 1;
657 }
658
659 int do_lookup(const K &key, int &hash) const
660 {
661 if (hashtable.empty())
662 return -1;
663
664 if (entries.size() * hashtable_size_trigger > hashtable.size()) {
665 ((pool*)this)->do_rehash();
666 hash = do_hash(key);
667 }
668
669 int index = hashtable[hash];
670
671 while (index >= 0 && !ops.cmp(entries[index].udata, key)) {
672 index = entries[index].next;
673 do_assert(-1 <= index && index < int(entries.size()));
674 }
675
676 return index;
677 }
678
679 int do_insert(const K &value, int &hash)
680 {
681 if (hashtable.empty()) {
682 entries.push_back(entry_t(value, -1));
683 do_rehash();
684 hash = do_hash(value);
685 } else {
686 entries.push_back(entry_t(value, hashtable[hash]));
687 hashtable[hash] = entries.size() - 1;
688 }
689 return entries.size() - 1;
690 }
691
692 public:
693 class const_iterator : public std::iterator<std::forward_iterator_tag, K>
694 {
695 friend class pool;
696 protected:
697 const pool *ptr;
698 int index;
699 const_iterator(const pool *ptr, int index) : ptr(ptr), index(index) { }
700 public:
701 const_iterator() { }
702 const_iterator operator++() { index--; return *this; }
703 bool operator==(const const_iterator &other) const { return index == other.index; }
704 bool operator!=(const const_iterator &other) const { return index != other.index; }
705 const K &operator*() const { return ptr->entries[index].udata; }
706 const K *operator->() const { return &ptr->entries[index].udata; }
707 };
708
709 class iterator : public std::iterator<std::forward_iterator_tag, K>
710 {
711 friend class pool;
712 protected:
713 pool *ptr;
714 int index;
715 iterator(pool *ptr, int index) : ptr(ptr), index(index) { }
716 public:
717 iterator() { }
718 iterator operator++() { index--; return *this; }
719 bool operator==(const iterator &other) const { return index == other.index; }
720 bool operator!=(const iterator &other) const { return index != other.index; }
721 K &operator*() { return ptr->entries[index].udata; }
722 K *operator->() { return &ptr->entries[index].udata; }
723 const K &operator*() const { return ptr->entries[index].udata; }
724 const K *operator->() const { return &ptr->entries[index].udata; }
725 operator const_iterator() const { return const_iterator(ptr, index); }
726 };
727
728 pool()
729 {
730 }
731
732 pool(const pool &other)
733 {
734 entries = other.entries;
735 do_rehash();
736 }
737
738 pool(pool &&other)
739 {
740 swap(other);
741 }
742
743 pool &operator=(const pool &other) {
744 entries = other.entries;
745 do_rehash();
746 return *this;
747 }
748
749 pool &operator=(pool &&other) {
750 clear();
751 swap(other);
752 return *this;
753 }
754
755 pool(const std::initializer_list<K> &list)
756 {
757 for (auto &it : list)
758 insert(it);
759 }
760
761 template<class InputIterator>
762 pool(InputIterator first, InputIterator last)
763 {
764 insert(first, last);
765 }
766
767 template<class InputIterator>
768 void insert(InputIterator first, InputIterator last)
769 {
770 for (; first != last; ++first)
771 insert(*first);
772 }
773
774 std::pair<iterator, bool> insert(const K &value)
775 {
776 int hash = do_hash(value);
777 int i = do_lookup(value, hash);
778 if (i >= 0)
779 return std::pair<iterator, bool>(iterator(this, i), false);
780 i = do_insert(value, hash);
781 return std::pair<iterator, bool>(iterator(this, i), true);
782 }
783
784 int erase(const K &key)
785 {
786 int hash = do_hash(key);
787 int index = do_lookup(key, hash);
788 return do_erase(index, hash);
789 }
790
791 iterator erase(iterator it)
792 {
793 int hash = do_hash(*it);
794 do_erase(it.index, hash);
795 return ++it;
796 }
797
798 int count(const K &key) const
799 {
800 int hash = do_hash(key);
801 int i = do_lookup(key, hash);
802 return i < 0 ? 0 : 1;
803 }
804
805 int count(const K &key, const_iterator it) const
806 {
807 int hash = do_hash(key);
808 int i = do_lookup(key, hash);
809 return i < 0 || i > it.index ? 0 : 1;
810 }
811
812 iterator find(const K &key)
813 {
814 int hash = do_hash(key);
815 int i = do_lookup(key, hash);
816 if (i < 0)
817 return end();
818 return iterator(this, i);
819 }
820
821 const_iterator find(const K &key) const
822 {
823 int hash = do_hash(key);
824 int i = do_lookup(key, hash);
825 if (i < 0)
826 return end();
827 return const_iterator(this, i);
828 }
829
830 bool operator[](const K &key)
831 {
832 int hash = do_hash(key);
833 int i = do_lookup(key, hash);
834 return i >= 0;
835 }
836
837 template<typename Compare = std::less<K>>
838 void sort(Compare comp = Compare())
839 {
840 std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata, a.udata); });
841 do_rehash();
842 }
843
844 K pop()
845 {
846 iterator it = begin();
847 K ret = *it;
848 erase(it);
849 return ret;
850 }
851
852 void swap(pool &other)
853 {
854 hashtable.swap(other.hashtable);
855 entries.swap(other.entries);
856 }
857
858 bool operator==(const pool &other) const {
859 if (size() != other.size())
860 return false;
861 for (auto &it : entries)
862 if (!other.count(it.udata))
863 return false;
864 return true;
865 }
866
867 bool operator!=(const pool &other) const {
868 return !operator==(other);
869 }
870
871 void reserve(size_t n) { entries.reserve(n); }
872 size_t size() const { return entries.size(); }
873 bool empty() const { return entries.empty(); }
874 void clear() { hashtable.clear(); entries.clear(); }
875
876 iterator begin() { return iterator(this, int(entries.size())-1); }
877 iterator end() { return iterator(nullptr, -1); }
878
879 const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
880 const_iterator end() const { return const_iterator(nullptr, -1); }
881 };
882
883 template<typename K, int offset, typename OPS>
884 class idict
885 {
886 pool<K, OPS> database;
887
888 public:
889 typedef typename pool<K, OPS>::const_iterator const_iterator;
890
891 int operator()(const K &key)
892 {
893 int hash = database.do_hash(key);
894 int i = database.do_lookup(key, hash);
895 if (i < 0)
896 i = database.do_insert(key, hash);
897 return i + offset;
898 }
899
900 int at(const K &key) const
901 {
902 int hash = database.do_hash(key);
903 int i = database.do_lookup(key, hash);
904 if (i < 0)
905 throw std::out_of_range("idict::at()");
906 return i + offset;
907 }
908
909 int at(const K &key, int defval) const
910 {
911 int hash = database.do_hash(key);
912 int i = database.do_lookup(key, hash);
913 if (i < 0)
914 return defval;
915 return i + offset;
916 }
917
918 int count(const K &key) const
919 {
920 int hash = database.do_hash(key);
921 int i = database.do_lookup(key, hash);
922 return i < 0 ? 0 : 1;
923 }
924
925 void expect(const K &key, int i)
926 {
927 int j = (*this)(key);
928 if (i != j)
929 throw std::out_of_range("idict::expect()");
930 }
931
932 const K &operator[](int index) const
933 {
934 return database.entries.at(index - offset).udata;
935 }
936
937 void swap(idict &other)
938 {
939 database.swap(other.database);
940 }
941
942 void reserve(size_t n) { database.reserve(n); }
943 size_t size() const { return database.size(); }
944 bool empty() const { return database.empty(); }
945 void clear() { database.clear(); }
946
947 const_iterator begin() const { return database.begin(); }
948 const_iterator end() const { return database.end(); }
949 };
950
951 template<typename K, typename OPS>
952 class mfp
953 {
954 mutable idict<K, 0, OPS> database;
955 mutable std::vector<int> parents;
956
957 public:
958 typedef typename idict<K, 0, OPS>::const_iterator const_iterator;
959
960 int operator()(const K &key) const
961 {
962 int i = database(key);
963 parents.resize(database.size(), -1);
964 return i;
965 }
966
967 const K &operator[](int index) const
968 {
969 return database[index];
970 }
971
972 int ifind(int i) const
973 {
974 int p = i, k = i;
975
976 while (parents[p] != -1)
977 p = parents[p];
978
979 while (k != p) {
980 int next_k = parents[k];
981 parents[k] = p;
982 k = next_k;
983 }
984
985 return p;
986 }
987
988 void imerge(int i, int j)
989 {
990 i = ifind(i);
991 j = ifind(j);
992
993 if (i != j)
994 parents[i] = j;
995 }
996
997 void ipromote(int i)
998 {
999 int k = i;
1000
1001 while (k != -1) {
1002 int next_k = parents[k];
1003 parents[k] = i;
1004 k = next_k;
1005 }
1006
1007 parents[i] = -1;
1008 }
1009
1010 int lookup(const K &a) const
1011 {
1012 return ifind((*this)(a));
1013 }
1014
1015 const K &find(const K &a) const
1016 {
1017 int i = database.at(a, -1);
1018 if (i < 0)
1019 return a;
1020 return (*this)[ifind(i)];
1021 }
1022
1023 void merge(const K &a, const K &b)
1024 {
1025 imerge((*this)(a), (*this)(b));
1026 }
1027
1028 void promote(const K &a)
1029 {
1030 int i = database.at(a, -1);
1031 if (i >= 0)
1032 ipromote(i);
1033 }
1034
1035 void swap(mfp &other)
1036 {
1037 database.swap(other.database);
1038 parents.swap(other.parents);
1039 }
1040
1041 void reserve(size_t n) { database.reserve(n); }
1042 size_t size() const { return database.size(); }
1043 bool empty() const { return database.empty(); }
1044 void clear() { database.clear(); parents.clear(); }
1045
1046 const_iterator begin() const { return database.begin(); }
1047 const_iterator end() const { return database.end(); }
1048 };
1049
1050 } /* namespace hashlib */
1051
1052 #endif