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