Merge pull request #2168 from whitequark/assert-unused-exprs
[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 bool operator<(const entry_t &other) const { return udata.first < other.udata.first; }
211 };
212
213 std::vector<int> hashtable;
214 std::vector<entry_t> entries;
215 OPS ops;
216
217 #ifdef NDEBUG
218 static inline void do_assert(bool) { }
219 #else
220 static inline void do_assert(bool cond) {
221 if (!cond) throw std::runtime_error("dict<> assert failed.");
222 }
223 #endif
224
225 int do_hash(const K &key) const
226 {
227 unsigned int hash = 0;
228 if (!hashtable.empty())
229 hash = ops.hash(key) % (unsigned int)(hashtable.size());
230 return hash;
231 }
232
233 void do_rehash()
234 {
235 hashtable.clear();
236 hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
237
238 for (int i = 0; i < int(entries.size()); i++) {
239 do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
240 int hash = do_hash(entries[i].udata.first);
241 entries[i].next = hashtable[hash];
242 hashtable[hash] = i;
243 }
244 }
245
246 int do_erase(int index, int hash)
247 {
248 do_assert(index < int(entries.size()));
249 if (hashtable.empty() || index < 0)
250 return 0;
251
252 int k = hashtable[hash];
253 do_assert(0 <= k && k < int(entries.size()));
254
255 if (k == index) {
256 hashtable[hash] = entries[index].next;
257 } else {
258 while (entries[k].next != index) {
259 k = entries[k].next;
260 do_assert(0 <= k && k < int(entries.size()));
261 }
262 entries[k].next = entries[index].next;
263 }
264
265 int back_idx = entries.size()-1;
266
267 if (index != back_idx)
268 {
269 int back_hash = do_hash(entries[back_idx].udata.first);
270
271 k = hashtable[back_hash];
272 do_assert(0 <= k && k < int(entries.size()));
273
274 if (k == back_idx) {
275 hashtable[back_hash] = index;
276 } else {
277 while (entries[k].next != back_idx) {
278 k = entries[k].next;
279 do_assert(0 <= k && k < int(entries.size()));
280 }
281 entries[k].next = index;
282 }
283
284 entries[index] = std::move(entries[back_idx]);
285 }
286
287 entries.pop_back();
288
289 if (entries.empty())
290 hashtable.clear();
291
292 return 1;
293 }
294
295 int do_lookup(const K &key, int &hash) const
296 {
297 if (hashtable.empty())
298 return -1;
299
300 if (entries.size() * hashtable_size_trigger > hashtable.size()) {
301 ((dict*)this)->do_rehash();
302 hash = do_hash(key);
303 }
304
305 int index = hashtable[hash];
306
307 while (index >= 0 && !ops.cmp(entries[index].udata.first, key)) {
308 index = entries[index].next;
309 do_assert(-1 <= index && index < int(entries.size()));
310 }
311
312 return index;
313 }
314
315 int do_insert(const K &key, int &hash)
316 {
317 if (hashtable.empty()) {
318 entries.emplace_back(std::pair<K, T>(key, T()), -1);
319 do_rehash();
320 hash = do_hash(key);
321 } else {
322 entries.emplace_back(std::pair<K, T>(key, T()), hashtable[hash]);
323 hashtable[hash] = entries.size() - 1;
324 }
325 return entries.size() - 1;
326 }
327
328 int do_insert(const std::pair<K, T> &value, int &hash)
329 {
330 if (hashtable.empty()) {
331 entries.emplace_back(value, -1);
332 do_rehash();
333 hash = do_hash(value.first);
334 } else {
335 entries.emplace_back(value, hashtable[hash]);
336 hashtable[hash] = entries.size() - 1;
337 }
338 return entries.size() - 1;
339 }
340
341 int do_insert(std::pair<K, T> &&rvalue, int &hash)
342 {
343 if (hashtable.empty()) {
344 auto key = rvalue.first;
345 entries.emplace_back(std::forward<std::pair<K, T>>(rvalue), -1);
346 do_rehash();
347 hash = do_hash(key);
348 } else {
349 entries.emplace_back(std::forward<std::pair<K, T>>(rvalue), hashtable[hash]);
350 hashtable[hash] = entries.size() - 1;
351 }
352 return entries.size() - 1;
353 }
354
355 public:
356 class const_iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
357 {
358 friend class dict;
359 protected:
360 const dict *ptr;
361 int index;
362 const_iterator(const dict *ptr, int index) : ptr(ptr), index(index) { }
363 public:
364 const_iterator() { }
365 const_iterator operator++() { index--; return *this; }
366 const_iterator operator+=(int amt) { index -= amt; return *this; }
367 bool operator<(const const_iterator &other) const { return index > other.index; }
368 bool operator==(const const_iterator &other) const { return index == other.index; }
369 bool operator!=(const const_iterator &other) const { return index != other.index; }
370 const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }
371 const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
372 };
373
374 class iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
375 {
376 friend class dict;
377 protected:
378 dict *ptr;
379 int index;
380 iterator(dict *ptr, int index) : ptr(ptr), index(index) { }
381 public:
382 iterator() { }
383 iterator operator++() { index--; return *this; }
384 iterator operator+=(int amt) { index -= amt; return *this; }
385 bool operator<(const iterator &other) const { return index > other.index; }
386 bool operator==(const iterator &other) const { return index == other.index; }
387 bool operator!=(const iterator &other) const { return index != other.index; }
388 std::pair<K, T> &operator*() { return ptr->entries[index].udata; }
389 std::pair<K, T> *operator->() { return &ptr->entries[index].udata; }
390 const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }
391 const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
392 operator const_iterator() const { return const_iterator(ptr, index); }
393 };
394
395 dict()
396 {
397 }
398
399 dict(const dict &other)
400 {
401 entries = other.entries;
402 do_rehash();
403 }
404
405 dict(dict &&other)
406 {
407 swap(other);
408 }
409
410 dict &operator=(const dict &other) {
411 entries = other.entries;
412 do_rehash();
413 return *this;
414 }
415
416 dict &operator=(dict &&other) {
417 clear();
418 swap(other);
419 return *this;
420 }
421
422 dict(const std::initializer_list<std::pair<K, T>> &list)
423 {
424 for (auto &it : list)
425 insert(it);
426 }
427
428 template<class InputIterator>
429 dict(InputIterator first, InputIterator last)
430 {
431 insert(first, last);
432 }
433
434 template<class InputIterator>
435 void insert(InputIterator first, InputIterator last)
436 {
437 for (; first != last; ++first)
438 insert(*first);
439 }
440
441 std::pair<iterator, bool> insert(const K &key)
442 {
443 int hash = do_hash(key);
444 int i = do_lookup(key, hash);
445 if (i >= 0)
446 return std::pair<iterator, bool>(iterator(this, i), false);
447 i = do_insert(key, hash);
448 return std::pair<iterator, bool>(iterator(this, i), true);
449 }
450
451 std::pair<iterator, bool> insert(const std::pair<K, T> &value)
452 {
453 int hash = do_hash(value.first);
454 int i = do_lookup(value.first, hash);
455 if (i >= 0)
456 return std::pair<iterator, bool>(iterator(this, i), false);
457 i = do_insert(value, hash);
458 return std::pair<iterator, bool>(iterator(this, i), true);
459 }
460
461 std::pair<iterator, bool> insert(std::pair<K, T> &&rvalue)
462 {
463 int hash = do_hash(rvalue.first);
464 int i = do_lookup(rvalue.first, hash);
465 if (i >= 0)
466 return std::pair<iterator, bool>(iterator(this, i), false);
467 i = do_insert(std::forward<std::pair<K, T>>(rvalue), hash);
468 return std::pair<iterator, bool>(iterator(this, i), true);
469 }
470
471 std::pair<iterator, bool> emplace(K const &key, T const &value)
472 {
473 int hash = do_hash(key);
474 int i = do_lookup(key, hash);
475 if (i >= 0)
476 return std::pair<iterator, bool>(iterator(this, i), false);
477 i = do_insert(std::make_pair(key, value), hash);
478 return std::pair<iterator, bool>(iterator(this, i), true);
479 }
480
481 std::pair<iterator, bool> emplace(K const &key, T &&rvalue)
482 {
483 int hash = do_hash(key);
484 int i = do_lookup(key, hash);
485 if (i >= 0)
486 return std::pair<iterator, bool>(iterator(this, i), false);
487 i = do_insert(std::make_pair(key, std::forward<T>(rvalue)), hash);
488 return std::pair<iterator, bool>(iterator(this, i), true);
489 }
490
491 std::pair<iterator, bool> emplace(K &&rkey, T const &value)
492 {
493 int hash = do_hash(rkey);
494 int i = do_lookup(rkey, hash);
495 if (i >= 0)
496 return std::pair<iterator, bool>(iterator(this, i), false);
497 i = do_insert(std::make_pair(std::forward<K>(rkey), value), hash);
498 return std::pair<iterator, bool>(iterator(this, i), true);
499 }
500
501 std::pair<iterator, bool> emplace(K &&rkey, T &&rvalue)
502 {
503 int hash = do_hash(rkey);
504 int i = do_lookup(rkey, hash);
505 if (i >= 0)
506 return std::pair<iterator, bool>(iterator(this, i), false);
507 i = do_insert(std::make_pair(std::forward<K>(rkey), std::forward<T>(rvalue)), hash);
508 return std::pair<iterator, bool>(iterator(this, i), true);
509 }
510
511 int erase(const K &key)
512 {
513 int hash = do_hash(key);
514 int index = do_lookup(key, hash);
515 return do_erase(index, hash);
516 }
517
518 iterator erase(iterator it)
519 {
520 int hash = do_hash(it->first);
521 do_erase(it.index, hash);
522 return ++it;
523 }
524
525 int count(const K &key) const
526 {
527 int hash = do_hash(key);
528 int i = do_lookup(key, hash);
529 return i < 0 ? 0 : 1;
530 }
531
532 int count(const K &key, const_iterator it) const
533 {
534 int hash = do_hash(key);
535 int i = do_lookup(key, hash);
536 return i < 0 || i > it.index ? 0 : 1;
537 }
538
539 iterator find(const K &key)
540 {
541 int hash = do_hash(key);
542 int i = do_lookup(key, hash);
543 if (i < 0)
544 return end();
545 return iterator(this, i);
546 }
547
548 const_iterator find(const K &key) const
549 {
550 int hash = do_hash(key);
551 int i = do_lookup(key, hash);
552 if (i < 0)
553 return end();
554 return const_iterator(this, i);
555 }
556
557 T& at(const K &key)
558 {
559 int hash = do_hash(key);
560 int i = do_lookup(key, hash);
561 if (i < 0)
562 throw std::out_of_range("dict::at()");
563 return entries[i].udata.second;
564 }
565
566 const T& at(const K &key) const
567 {
568 int hash = do_hash(key);
569 int i = do_lookup(key, hash);
570 if (i < 0)
571 throw std::out_of_range("dict::at()");
572 return entries[i].udata.second;
573 }
574
575 const T& at(const K &key, const T &defval) const
576 {
577 int hash = do_hash(key);
578 int i = do_lookup(key, hash);
579 if (i < 0)
580 return defval;
581 return entries[i].udata.second;
582 }
583
584 T& operator[](const K &key)
585 {
586 int hash = do_hash(key);
587 int i = do_lookup(key, hash);
588 if (i < 0)
589 i = do_insert(std::pair<K, T>(key, T()), hash);
590 return entries[i].udata.second;
591 }
592
593 template<typename Compare = std::less<K>>
594 void sort(Compare comp = Compare())
595 {
596 std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata.first, a.udata.first); });
597 do_rehash();
598 }
599
600 void swap(dict &other)
601 {
602 hashtable.swap(other.hashtable);
603 entries.swap(other.entries);
604 }
605
606 bool operator==(const dict &other) const {
607 if (size() != other.size())
608 return false;
609 for (auto &it : entries) {
610 auto oit = other.find(it.udata.first);
611 if (oit == other.end() || !(oit->second == it.udata.second))
612 return false;
613 }
614 return true;
615 }
616
617 bool operator!=(const dict &other) const {
618 return !operator==(other);
619 }
620
621 unsigned int hash() const {
622 unsigned int h = mkhash_init;
623 for (auto &entry : entries) {
624 h ^= hash_ops<K>::hash(entry.udata.first);
625 h ^= hash_ops<T>::hash(entry.udata.second);
626 }
627 return h;
628 }
629
630 void reserve(size_t n) { entries.reserve(n); }
631 size_t size() const { return entries.size(); }
632 bool empty() const { return entries.empty(); }
633 void clear() { hashtable.clear(); entries.clear(); }
634
635 iterator begin() { return iterator(this, int(entries.size())-1); }
636 iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
637 iterator end() { return iterator(nullptr, -1); }
638
639 const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
640 const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
641 const_iterator end() const { return const_iterator(nullptr, -1); }
642 };
643
644 template<typename K, typename OPS>
645 class pool
646 {
647 template<typename, int, typename> friend class idict;
648
649 protected:
650 struct entry_t
651 {
652 K udata;
653 int next;
654
655 entry_t() { }
656 entry_t(const K &udata, int next) : udata(udata), next(next) { }
657 entry_t(K &&udata, int next) : udata(std::move(udata)), next(next) { }
658 };
659
660 std::vector<int> hashtable;
661 std::vector<entry_t> entries;
662 OPS ops;
663
664 #ifdef NDEBUG
665 static inline void do_assert(bool) { }
666 #else
667 static inline void do_assert(bool cond) {
668 if (!cond) throw std::runtime_error("pool<> assert failed.");
669 }
670 #endif
671
672 int do_hash(const K &key) const
673 {
674 unsigned int hash = 0;
675 if (!hashtable.empty())
676 hash = ops.hash(key) % (unsigned int)(hashtable.size());
677 return hash;
678 }
679
680 void do_rehash()
681 {
682 hashtable.clear();
683 hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);
684
685 for (int i = 0; i < int(entries.size()); i++) {
686 do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
687 int hash = do_hash(entries[i].udata);
688 entries[i].next = hashtable[hash];
689 hashtable[hash] = i;
690 }
691 }
692
693 int do_erase(int index, int hash)
694 {
695 do_assert(index < int(entries.size()));
696 if (hashtable.empty() || index < 0)
697 return 0;
698
699 int k = hashtable[hash];
700 if (k == index) {
701 hashtable[hash] = entries[index].next;
702 } else {
703 while (entries[k].next != index) {
704 k = entries[k].next;
705 do_assert(0 <= k && k < int(entries.size()));
706 }
707 entries[k].next = entries[index].next;
708 }
709
710 int back_idx = entries.size()-1;
711
712 if (index != back_idx)
713 {
714 int back_hash = do_hash(entries[back_idx].udata);
715
716 k = hashtable[back_hash];
717 if (k == back_idx) {
718 hashtable[back_hash] = index;
719 } else {
720 while (entries[k].next != back_idx) {
721 k = entries[k].next;
722 do_assert(0 <= k && k < int(entries.size()));
723 }
724 entries[k].next = index;
725 }
726
727 entries[index] = std::move(entries[back_idx]);
728 }
729
730 entries.pop_back();
731
732 if (entries.empty())
733 hashtable.clear();
734
735 return 1;
736 }
737
738 int do_lookup(const K &key, int &hash) const
739 {
740 if (hashtable.empty())
741 return -1;
742
743 if (entries.size() * hashtable_size_trigger > hashtable.size()) {
744 ((pool*)this)->do_rehash();
745 hash = do_hash(key);
746 }
747
748 int index = hashtable[hash];
749
750 while (index >= 0 && !ops.cmp(entries[index].udata, key)) {
751 index = entries[index].next;
752 do_assert(-1 <= index && index < int(entries.size()));
753 }
754
755 return index;
756 }
757
758 int do_insert(const K &value, int &hash)
759 {
760 if (hashtable.empty()) {
761 entries.emplace_back(value, -1);
762 do_rehash();
763 hash = do_hash(value);
764 } else {
765 entries.emplace_back(value, hashtable[hash]);
766 hashtable[hash] = entries.size() - 1;
767 }
768 return entries.size() - 1;
769 }
770
771 int do_insert(K &&rvalue, int &hash)
772 {
773 if (hashtable.empty()) {
774 entries.emplace_back(std::forward<K>(rvalue), -1);
775 do_rehash();
776 hash = do_hash(rvalue);
777 } else {
778 entries.emplace_back(std::forward<K>(rvalue), hashtable[hash]);
779 hashtable[hash] = entries.size() - 1;
780 }
781 return entries.size() - 1;
782 }
783
784 public:
785 class const_iterator : public std::iterator<std::forward_iterator_tag, K>
786 {
787 friend class pool;
788 protected:
789 const pool *ptr;
790 int index;
791 const_iterator(const pool *ptr, int index) : ptr(ptr), index(index) { }
792 public:
793 const_iterator() { }
794 const_iterator operator++() { index--; return *this; }
795 bool operator==(const const_iterator &other) const { return index == other.index; }
796 bool operator!=(const const_iterator &other) const { return index != other.index; }
797 const K &operator*() const { return ptr->entries[index].udata; }
798 const K *operator->() const { return &ptr->entries[index].udata; }
799 };
800
801 class iterator : public std::iterator<std::forward_iterator_tag, K>
802 {
803 friend class pool;
804 protected:
805 pool *ptr;
806 int index;
807 iterator(pool *ptr, int index) : ptr(ptr), index(index) { }
808 public:
809 iterator() { }
810 iterator operator++() { index--; return *this; }
811 bool operator==(const iterator &other) const { return index == other.index; }
812 bool operator!=(const iterator &other) const { return index != other.index; }
813 K &operator*() { return ptr->entries[index].udata; }
814 K *operator->() { return &ptr->entries[index].udata; }
815 const K &operator*() const { return ptr->entries[index].udata; }
816 const K *operator->() const { return &ptr->entries[index].udata; }
817 operator const_iterator() const { return const_iterator(ptr, index); }
818 };
819
820 pool()
821 {
822 }
823
824 pool(const pool &other)
825 {
826 entries = other.entries;
827 do_rehash();
828 }
829
830 pool(pool &&other)
831 {
832 swap(other);
833 }
834
835 pool &operator=(const pool &other) {
836 entries = other.entries;
837 do_rehash();
838 return *this;
839 }
840
841 pool &operator=(pool &&other) {
842 clear();
843 swap(other);
844 return *this;
845 }
846
847 pool(const std::initializer_list<K> &list)
848 {
849 for (auto &it : list)
850 insert(it);
851 }
852
853 template<class InputIterator>
854 pool(InputIterator first, InputIterator last)
855 {
856 insert(first, last);
857 }
858
859 template<class InputIterator>
860 void insert(InputIterator first, InputIterator last)
861 {
862 for (; first != last; ++first)
863 insert(*first);
864 }
865
866 std::pair<iterator, bool> insert(const K &value)
867 {
868 int hash = do_hash(value);
869 int i = do_lookup(value, hash);
870 if (i >= 0)
871 return std::pair<iterator, bool>(iterator(this, i), false);
872 i = do_insert(value, hash);
873 return std::pair<iterator, bool>(iterator(this, i), true);
874 }
875
876 std::pair<iterator, bool> insert(K &&rvalue)
877 {
878 int hash = do_hash(rvalue);
879 int i = do_lookup(rvalue, hash);
880 if (i >= 0)
881 return std::pair<iterator, bool>(iterator(this, i), false);
882 i = do_insert(std::forward<K>(rvalue), hash);
883 return std::pair<iterator, bool>(iterator(this, i), true);
884 }
885
886 template<typename... Args>
887 std::pair<iterator, bool> emplace(Args&&... args)
888 {
889 return insert(K(std::forward<Args>(args)...));
890 }
891
892 int erase(const K &key)
893 {
894 int hash = do_hash(key);
895 int index = do_lookup(key, hash);
896 return do_erase(index, hash);
897 }
898
899 iterator erase(iterator it)
900 {
901 int hash = do_hash(*it);
902 do_erase(it.index, hash);
903 return ++it;
904 }
905
906 int count(const K &key) const
907 {
908 int hash = do_hash(key);
909 int i = do_lookup(key, hash);
910 return i < 0 ? 0 : 1;
911 }
912
913 int count(const K &key, const_iterator it) const
914 {
915 int hash = do_hash(key);
916 int i = do_lookup(key, hash);
917 return i < 0 || i > it.index ? 0 : 1;
918 }
919
920 iterator find(const K &key)
921 {
922 int hash = do_hash(key);
923 int i = do_lookup(key, hash);
924 if (i < 0)
925 return end();
926 return iterator(this, i);
927 }
928
929 const_iterator find(const K &key) const
930 {
931 int hash = do_hash(key);
932 int i = do_lookup(key, hash);
933 if (i < 0)
934 return end();
935 return const_iterator(this, i);
936 }
937
938 bool operator[](const K &key)
939 {
940 int hash = do_hash(key);
941 int i = do_lookup(key, hash);
942 return i >= 0;
943 }
944
945 template<typename Compare = std::less<K>>
946 void sort(Compare comp = Compare())
947 {
948 std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata, a.udata); });
949 do_rehash();
950 }
951
952 K pop()
953 {
954 iterator it = begin();
955 K ret = *it;
956 erase(it);
957 return ret;
958 }
959
960 void swap(pool &other)
961 {
962 hashtable.swap(other.hashtable);
963 entries.swap(other.entries);
964 }
965
966 bool operator==(const pool &other) const {
967 if (size() != other.size())
968 return false;
969 for (auto &it : entries)
970 if (!other.count(it.udata))
971 return false;
972 return true;
973 }
974
975 bool operator!=(const pool &other) const {
976 return !operator==(other);
977 }
978
979 bool hash() const {
980 unsigned int hashval = mkhash_init;
981 for (auto &it : entries)
982 hashval ^= ops.hash(it.udata);
983 return hashval;
984 }
985
986 void reserve(size_t n) { entries.reserve(n); }
987 size_t size() const { return entries.size(); }
988 bool empty() const { return entries.empty(); }
989 void clear() { hashtable.clear(); entries.clear(); }
990
991 iterator begin() { return iterator(this, int(entries.size())-1); }
992 iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
993 iterator end() { return iterator(nullptr, -1); }
994
995 const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
996 const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
997 const_iterator end() const { return const_iterator(nullptr, -1); }
998 };
999
1000 template<typename K, int offset, typename OPS>
1001 class idict
1002 {
1003 pool<K, OPS> database;
1004
1005 public:
1006 class const_iterator : public std::iterator<std::forward_iterator_tag, K>
1007 {
1008 friend class idict;
1009 protected:
1010 const idict &container;
1011 int index;
1012 const_iterator(const idict &container, int index) : container(container), index(index) { }
1013 public:
1014 const_iterator() { }
1015 const_iterator operator++() { index++; return *this; }
1016 bool operator==(const const_iterator &other) const { return index == other.index; }
1017 bool operator!=(const const_iterator &other) const { return index != other.index; }
1018 const K &operator*() const { return container[index]; }
1019 const K *operator->() const { return &container[index]; }
1020 };
1021
1022 int operator()(const K &key)
1023 {
1024 int hash = database.do_hash(key);
1025 int i = database.do_lookup(key, hash);
1026 if (i < 0)
1027 i = database.do_insert(key, hash);
1028 return i + offset;
1029 }
1030
1031 int at(const K &key) const
1032 {
1033 int hash = database.do_hash(key);
1034 int i = database.do_lookup(key, hash);
1035 if (i < 0)
1036 throw std::out_of_range("idict::at()");
1037 return i + offset;
1038 }
1039
1040 int at(const K &key, int defval) const
1041 {
1042 int hash = database.do_hash(key);
1043 int i = database.do_lookup(key, hash);
1044 if (i < 0)
1045 return defval;
1046 return i + offset;
1047 }
1048
1049 int count(const K &key) const
1050 {
1051 int hash = database.do_hash(key);
1052 int i = database.do_lookup(key, hash);
1053 return i < 0 ? 0 : 1;
1054 }
1055
1056 void expect(const K &key, int i)
1057 {
1058 int j = (*this)(key);
1059 if (i != j)
1060 throw std::out_of_range("idict::expect()");
1061 }
1062
1063 const K &operator[](int index) const
1064 {
1065 return database.entries.at(index - offset).udata;
1066 }
1067
1068 void swap(idict &other)
1069 {
1070 database.swap(other.database);
1071 }
1072
1073 void reserve(size_t n) { database.reserve(n); }
1074 size_t size() const { return database.size(); }
1075 bool empty() const { return database.empty(); }
1076 void clear() { database.clear(); }
1077
1078 const_iterator begin() const { return const_iterator(*this, offset); }
1079 const_iterator element(int n) const { return const_iterator(*this, n); }
1080 const_iterator end() const { return const_iterator(*this, offset + size()); }
1081 };
1082
1083 template<typename K, typename OPS>
1084 class mfp
1085 {
1086 mutable idict<K, 0, OPS> database;
1087 mutable std::vector<int> parents;
1088
1089 public:
1090 typedef typename idict<K, 0, OPS>::const_iterator const_iterator;
1091
1092 int operator()(const K &key) const
1093 {
1094 int i = database(key);
1095 parents.resize(database.size(), -1);
1096 return i;
1097 }
1098
1099 const K &operator[](int index) const
1100 {
1101 return database[index];
1102 }
1103
1104 int ifind(int i) const
1105 {
1106 int p = i, k = i;
1107
1108 while (parents[p] != -1)
1109 p = parents[p];
1110
1111 while (k != p) {
1112 int next_k = parents[k];
1113 parents[k] = p;
1114 k = next_k;
1115 }
1116
1117 return p;
1118 }
1119
1120 void imerge(int i, int j)
1121 {
1122 i = ifind(i);
1123 j = ifind(j);
1124
1125 if (i != j)
1126 parents[i] = j;
1127 }
1128
1129 void ipromote(int i)
1130 {
1131 int k = i;
1132
1133 while (k != -1) {
1134 int next_k = parents[k];
1135 parents[k] = i;
1136 k = next_k;
1137 }
1138
1139 parents[i] = -1;
1140 }
1141
1142 int lookup(const K &a) const
1143 {
1144 return ifind((*this)(a));
1145 }
1146
1147 const K &find(const K &a) const
1148 {
1149 int i = database.at(a, -1);
1150 if (i < 0)
1151 return a;
1152 return (*this)[ifind(i)];
1153 }
1154
1155 void merge(const K &a, const K &b)
1156 {
1157 imerge((*this)(a), (*this)(b));
1158 }
1159
1160 void promote(const K &a)
1161 {
1162 int i = database.at(a, -1);
1163 if (i >= 0)
1164 ipromote(i);
1165 }
1166
1167 void swap(mfp &other)
1168 {
1169 database.swap(other.database);
1170 parents.swap(other.parents);
1171 }
1172
1173 void reserve(size_t n) { database.reserve(n); }
1174 size_t size() const { return database.size(); }
1175 bool empty() const { return database.empty(); }
1176 void clear() { database.clear(); parents.clear(); }
1177
1178 const_iterator begin() const { return database.begin(); }
1179 const_iterator element(int n) const { return database.element(n); }
1180 const_iterator end() const { return database.end(); }
1181 };
1182
1183 } /* namespace hashlib */
1184
1185 #endif