Merge pull request #1900 from Xiretza/suppress-makefile-echo
[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 element(int n) { return iterator(this, int(entries.size())-1-n); }
561 iterator end() { return iterator(nullptr, -1); }
562
563 const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
564 const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
565 const_iterator end() const { return const_iterator(nullptr, -1); }
566 };
567
568 template<typename K, typename OPS>
569 class pool
570 {
571 template<typename, int, typename> friend class idict;
572
573 protected:
574 struct entry_t
575 {
576 K udata;
577 int next;
578
579 entry_t() { }
580 entry_t(const K &udata, int next) : udata(udata), next(next) { }
581 };
582
583 std::vector<int> hashtable;
584 std::vector<entry_t> entries;
585 OPS ops;
586
587 #ifdef NDEBUG
588 static inline void do_assert(bool) { }
589 #else
590 static inline void do_assert(bool cond) {
591 if (!cond) throw std::runtime_error("pool<> assert failed.");
592 }
593 #endif
594
595 int do_hash(const K &key) const
596 {
597 unsigned int hash = 0;
598 if (!hashtable.empty())
599 hash = ops.hash(key) % (unsigned int)(hashtable.size());
600 return hash;
601 }
602
603 void do_rehash()
604 {
605 hashtable.clear();
606 hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
607
608 for (int i = 0; i < int(entries.size()); i++) {
609 do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
610 int hash = do_hash(entries[i].udata);
611 entries[i].next = hashtable[hash];
612 hashtable[hash] = i;
613 }
614 }
615
616 int do_erase(int index, int hash)
617 {
618 do_assert(index < int(entries.size()));
619 if (hashtable.empty() || index < 0)
620 return 0;
621
622 int k = hashtable[hash];
623 if (k == index) {
624 hashtable[hash] = entries[index].next;
625 } else {
626 while (entries[k].next != index) {
627 k = entries[k].next;
628 do_assert(0 <= k && k < int(entries.size()));
629 }
630 entries[k].next = entries[index].next;
631 }
632
633 int back_idx = entries.size()-1;
634
635 if (index != back_idx)
636 {
637 int back_hash = do_hash(entries[back_idx].udata);
638
639 k = hashtable[back_hash];
640 if (k == back_idx) {
641 hashtable[back_hash] = index;
642 } else {
643 while (entries[k].next != back_idx) {
644 k = entries[k].next;
645 do_assert(0 <= k && k < int(entries.size()));
646 }
647 entries[k].next = index;
648 }
649
650 entries[index] = std::move(entries[back_idx]);
651 }
652
653 entries.pop_back();
654
655 if (entries.empty())
656 hashtable.clear();
657
658 return 1;
659 }
660
661 int do_lookup(const K &key, int &hash) const
662 {
663 if (hashtable.empty())
664 return -1;
665
666 if (entries.size() * hashtable_size_trigger > hashtable.size()) {
667 ((pool*)this)->do_rehash();
668 hash = do_hash(key);
669 }
670
671 int index = hashtable[hash];
672
673 while (index >= 0 && !ops.cmp(entries[index].udata, key)) {
674 index = entries[index].next;
675 do_assert(-1 <= index && index < int(entries.size()));
676 }
677
678 return index;
679 }
680
681 int do_insert(const K &value, int &hash)
682 {
683 if (hashtable.empty()) {
684 entries.push_back(entry_t(value, -1));
685 do_rehash();
686 hash = do_hash(value);
687 } else {
688 entries.push_back(entry_t(value, hashtable[hash]));
689 hashtable[hash] = entries.size() - 1;
690 }
691 return entries.size() - 1;
692 }
693
694 public:
695 class const_iterator : public std::iterator<std::forward_iterator_tag, K>
696 {
697 friend class pool;
698 protected:
699 const pool *ptr;
700 int index;
701 const_iterator(const pool *ptr, int index) : ptr(ptr), index(index) { }
702 public:
703 const_iterator() { }
704 const_iterator operator++() { index--; return *this; }
705 bool operator==(const const_iterator &other) const { return index == other.index; }
706 bool operator!=(const const_iterator &other) const { return index != other.index; }
707 const K &operator*() const { return ptr->entries[index].udata; }
708 const K *operator->() const { return &ptr->entries[index].udata; }
709 };
710
711 class iterator : public std::iterator<std::forward_iterator_tag, K>
712 {
713 friend class pool;
714 protected:
715 pool *ptr;
716 int index;
717 iterator(pool *ptr, int index) : ptr(ptr), index(index) { }
718 public:
719 iterator() { }
720 iterator operator++() { index--; return *this; }
721 bool operator==(const iterator &other) const { return index == other.index; }
722 bool operator!=(const iterator &other) const { return index != other.index; }
723 K &operator*() { return ptr->entries[index].udata; }
724 K *operator->() { return &ptr->entries[index].udata; }
725 const K &operator*() const { return ptr->entries[index].udata; }
726 const K *operator->() const { return &ptr->entries[index].udata; }
727 operator const_iterator() const { return const_iterator(ptr, index); }
728 };
729
730 pool()
731 {
732 }
733
734 pool(const pool &other)
735 {
736 entries = other.entries;
737 do_rehash();
738 }
739
740 pool(pool &&other)
741 {
742 swap(other);
743 }
744
745 pool &operator=(const pool &other) {
746 entries = other.entries;
747 do_rehash();
748 return *this;
749 }
750
751 pool &operator=(pool &&other) {
752 clear();
753 swap(other);
754 return *this;
755 }
756
757 pool(const std::initializer_list<K> &list)
758 {
759 for (auto &it : list)
760 insert(it);
761 }
762
763 template<class InputIterator>
764 pool(InputIterator first, InputIterator last)
765 {
766 insert(first, last);
767 }
768
769 template<class InputIterator>
770 void insert(InputIterator first, InputIterator last)
771 {
772 for (; first != last; ++first)
773 insert(*first);
774 }
775
776 std::pair<iterator, bool> insert(const K &value)
777 {
778 int hash = do_hash(value);
779 int i = do_lookup(value, hash);
780 if (i >= 0)
781 return std::pair<iterator, bool>(iterator(this, i), false);
782 i = do_insert(value, hash);
783 return std::pair<iterator, bool>(iterator(this, i), true);
784 }
785
786 int erase(const K &key)
787 {
788 int hash = do_hash(key);
789 int index = do_lookup(key, hash);
790 return do_erase(index, hash);
791 }
792
793 iterator erase(iterator it)
794 {
795 int hash = do_hash(*it);
796 do_erase(it.index, hash);
797 return ++it;
798 }
799
800 int count(const K &key) const
801 {
802 int hash = do_hash(key);
803 int i = do_lookup(key, hash);
804 return i < 0 ? 0 : 1;
805 }
806
807 int count(const K &key, const_iterator it) const
808 {
809 int hash = do_hash(key);
810 int i = do_lookup(key, hash);
811 return i < 0 || i > it.index ? 0 : 1;
812 }
813
814 iterator find(const K &key)
815 {
816 int hash = do_hash(key);
817 int i = do_lookup(key, hash);
818 if (i < 0)
819 return end();
820 return iterator(this, i);
821 }
822
823 const_iterator find(const K &key) const
824 {
825 int hash = do_hash(key);
826 int i = do_lookup(key, hash);
827 if (i < 0)
828 return end();
829 return const_iterator(this, i);
830 }
831
832 bool operator[](const K &key)
833 {
834 int hash = do_hash(key);
835 int i = do_lookup(key, hash);
836 return i >= 0;
837 }
838
839 template<typename Compare = std::less<K>>
840 void sort(Compare comp = Compare())
841 {
842 std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata, a.udata); });
843 do_rehash();
844 }
845
846 K pop()
847 {
848 iterator it = begin();
849 K ret = *it;
850 erase(it);
851 return ret;
852 }
853
854 void swap(pool &other)
855 {
856 hashtable.swap(other.hashtable);
857 entries.swap(other.entries);
858 }
859
860 bool operator==(const pool &other) const {
861 if (size() != other.size())
862 return false;
863 for (auto &it : entries)
864 if (!other.count(it.udata))
865 return false;
866 return true;
867 }
868
869 bool operator!=(const pool &other) const {
870 return !operator==(other);
871 }
872
873 bool hash() const {
874 unsigned int hashval = mkhash_init;
875 for (auto &it : entries)
876 hashval ^= ops.hash(it.udata);
877 return hashval;
878 }
879
880 void reserve(size_t n) { entries.reserve(n); }
881 size_t size() const { return entries.size(); }
882 bool empty() const { return entries.empty(); }
883 void clear() { hashtable.clear(); entries.clear(); }
884
885 iterator begin() { return iterator(this, int(entries.size())-1); }
886 iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
887 iterator end() { return iterator(nullptr, -1); }
888
889 const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
890 const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
891 const_iterator end() const { return const_iterator(nullptr, -1); }
892 };
893
894 template<typename K, int offset, typename OPS>
895 class idict
896 {
897 pool<K, OPS> database;
898
899 public:
900 typedef typename pool<K, OPS>::const_iterator const_iterator;
901
902 int operator()(const K &key)
903 {
904 int hash = database.do_hash(key);
905 int i = database.do_lookup(key, hash);
906 if (i < 0)
907 i = database.do_insert(key, hash);
908 return i + offset;
909 }
910
911 int at(const K &key) const
912 {
913 int hash = database.do_hash(key);
914 int i = database.do_lookup(key, hash);
915 if (i < 0)
916 throw std::out_of_range("idict::at()");
917 return i + offset;
918 }
919
920 int at(const K &key, int defval) const
921 {
922 int hash = database.do_hash(key);
923 int i = database.do_lookup(key, hash);
924 if (i < 0)
925 return defval;
926 return i + offset;
927 }
928
929 int count(const K &key) const
930 {
931 int hash = database.do_hash(key);
932 int i = database.do_lookup(key, hash);
933 return i < 0 ? 0 : 1;
934 }
935
936 void expect(const K &key, int i)
937 {
938 int j = (*this)(key);
939 if (i != j)
940 throw std::out_of_range("idict::expect()");
941 }
942
943 const K &operator[](int index) const
944 {
945 return database.entries.at(index - offset).udata;
946 }
947
948 void swap(idict &other)
949 {
950 database.swap(other.database);
951 }
952
953 void reserve(size_t n) { database.reserve(n); }
954 size_t size() const { return database.size(); }
955 bool empty() const { return database.empty(); }
956 void clear() { database.clear(); }
957
958 const_iterator begin() const { return database.begin(); }
959 const_iterator element(int n) const { return database.element(n); }
960 const_iterator end() const { return database.end(); }
961 };
962
963 template<typename K, typename OPS>
964 class mfp
965 {
966 mutable idict<K, 0, OPS> database;
967 mutable std::vector<int> parents;
968
969 public:
970 typedef typename idict<K, 0, OPS>::const_iterator const_iterator;
971
972 int operator()(const K &key) const
973 {
974 int i = database(key);
975 parents.resize(database.size(), -1);
976 return i;
977 }
978
979 const K &operator[](int index) const
980 {
981 return database[index];
982 }
983
984 int ifind(int i) const
985 {
986 int p = i, k = i;
987
988 while (parents[p] != -1)
989 p = parents[p];
990
991 while (k != p) {
992 int next_k = parents[k];
993 parents[k] = p;
994 k = next_k;
995 }
996
997 return p;
998 }
999
1000 void imerge(int i, int j)
1001 {
1002 i = ifind(i);
1003 j = ifind(j);
1004
1005 if (i != j)
1006 parents[i] = j;
1007 }
1008
1009 void ipromote(int i)
1010 {
1011 int k = i;
1012
1013 while (k != -1) {
1014 int next_k = parents[k];
1015 parents[k] = i;
1016 k = next_k;
1017 }
1018
1019 parents[i] = -1;
1020 }
1021
1022 int lookup(const K &a) const
1023 {
1024 return ifind((*this)(a));
1025 }
1026
1027 const K &find(const K &a) const
1028 {
1029 int i = database.at(a, -1);
1030 if (i < 0)
1031 return a;
1032 return (*this)[ifind(i)];
1033 }
1034
1035 void merge(const K &a, const K &b)
1036 {
1037 imerge((*this)(a), (*this)(b));
1038 }
1039
1040 void promote(const K &a)
1041 {
1042 int i = database.at(a, -1);
1043 if (i >= 0)
1044 ipromote(i);
1045 }
1046
1047 void swap(mfp &other)
1048 {
1049 database.swap(other.database);
1050 parents.swap(other.parents);
1051 }
1052
1053 void reserve(size_t n) { database.reserve(n); }
1054 size_t size() const { return database.size(); }
1055 bool empty() const { return database.empty(); }
1056 void clear() { database.clear(); parents.clear(); }
1057
1058 const_iterator begin() const { return database.begin(); }
1059 const_iterator element(int n) const { return database.element(n); }
1060 const_iterator end() const { return database.end(); }
1061 };
1062
1063 } /* namespace hashlib */
1064
1065 #endif