1 // This is free and unencumbered software released into the public domain.
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
8 // -------------------------------------------------------
9 // Written by Clifford Wolf <clifford@clifford.at> in 2014
10 // -------------------------------------------------------
22 template<typename T
> struct hash_ops
;
23 template<typename K
, typename T
, typename OPS
= hash_ops
<K
>> class dict
;
24 template<typename K
, int offset
= 0, typename OPS
= hash_ops
<K
>> class idict
;
25 template<typename K
, typename OPS
= hash_ops
<K
>> class pool
;
26 template<typename K
, typename OPS
= hash_ops
<K
>> class mfp
;
28 const int hashtable_size_trigger
= 2;
29 const int hashtable_size_factor
= 3;
31 // The XOR version of DJB2
32 inline unsigned int mkhash(unsigned int a
, unsigned int b
) {
33 return ((a
<< 5) + a
) ^ b
;
36 // traditionally 5381 is used as starting value for the djb2 hash
37 const unsigned int mkhash_init
= 5381;
39 // The ADD version of DJB2
40 // (use this version for cache locality in b)
41 inline unsigned int mkhash_add(unsigned int a
, unsigned int b
) {
42 return ((a
<< 5) + a
) + b
;
45 inline unsigned int mkhash_xorshift(unsigned int a
) {
50 } else if (sizeof(a
) == 8) {
55 throw std::runtime_error("mkhash_xorshift() only implemented for 32 bit and 64 bit ints");
59 template<typename T
> struct hash_ops
{
60 static inline bool cmp(const T
&a
, const T
&b
) {
63 static inline unsigned int hash(const T
&a
) {
70 static inline bool cmp(T a
, T b
) {
75 template<> struct hash_ops
<int32_t> : hash_int_ops
77 static inline unsigned int hash(int32_t a
) {
81 template<> struct hash_ops
<int64_t> : hash_int_ops
83 static inline unsigned int hash(int64_t a
) {
84 return mkhash((unsigned int)(a
), (unsigned int)(a
>> 32));
88 template<> struct hash_ops
<std::string
> {
89 static inline bool cmp(const std::string
&a
, const std::string
&b
) {
92 static inline unsigned int hash(const std::string
&a
) {
100 template<typename P
, typename Q
> struct hash_ops
<std::pair
<P
, Q
>> {
101 static inline bool cmp(std::pair
<P
, Q
> a
, std::pair
<P
, Q
> b
) {
104 static inline unsigned int hash(std::pair
<P
, Q
> a
) {
105 return mkhash(hash_ops
<P
>::hash(a
.first
), hash_ops
<Q
>::hash(a
.second
));
109 template<typename P
, typename Q
> struct hash_ops
<dict
<P
, Q
>> {
110 static inline bool cmp(dict
<P
, Q
> a
, dict
<P
, Q
> b
) {
113 static inline unsigned int hash(dict
<P
, Q
> a
) {
114 unsigned int h
= mkhash_init
;
116 h
= mkhash(h
, hash_ops
<P
>::hash(it
.first
));
117 h
= mkhash(h
, hash_ops
<Q
>::hash(it
.second
));
123 template<typename
... T
> struct hash_ops
<std::tuple
<T
...>> {
124 static inline bool cmp(std::tuple
<T
...> a
, std::tuple
<T
...> b
) {
127 template<size_t I
= 0>
128 static inline typename
std::enable_if
<I
== sizeof...(T
), unsigned int>::type
hash(std::tuple
<T
...>) {
131 template<size_t I
= 0>
132 static inline typename
std::enable_if
<I
!= sizeof...(T
), unsigned int>::type
hash(std::tuple
<T
...> a
) {
133 typedef hash_ops
<typename
std::tuple_element
<I
, std::tuple
<T
...>>::type
> element_ops_t
;
134 return mkhash(hash
<I
+1>(a
), element_ops_t::hash(std::get
<I
>(a
)));
138 template<typename T
> struct hash_ops
<std::vector
<T
>> {
139 static inline bool cmp(std::vector
<T
> a
, std::vector
<T
> b
) {
142 static inline unsigned int hash(std::vector
<T
> a
) {
143 unsigned int h
= mkhash_init
;
145 h
= mkhash(h
, hash_ops
<T
>::hash(k
));
150 struct hash_cstr_ops
{
151 static inline bool cmp(const char *a
, const char *b
) {
152 for (int i
= 0; a
[i
] || b
[i
]; i
++)
157 static inline unsigned int hash(const char *a
) {
158 unsigned int hash
= mkhash_init
;
160 hash
= mkhash(hash
, *(a
++));
165 struct hash_ptr_ops
{
166 static inline bool cmp(const void *a
, const void *b
) {
169 static inline unsigned int hash(const void *a
) {
174 struct hash_obj_ops
{
175 static inline bool cmp(const void *a
, const void *b
) {
179 static inline unsigned int hash(const T
*a
) {
180 return a
? a
->hash() : 0;
185 inline unsigned int mkhash(const T
&v
) {
186 return hash_ops
<T
>().hash(v
);
189 inline int hashtable_size(int min_size
)
191 static std::vector
<int> zero_and_some_primes
= {
192 0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,
193 853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,
194 12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281,
195 120371, 150473, 188107, 235159, 293957, 367453, 459317, 574157, 717697,
196 897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037,
197 5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411,
198 25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,
199 121590311, 151987889, 189984863, 237481091, 296851369, 371064217
202 for (auto p
: zero_and_some_primes
)
203 if (p
>= min_size
) return p
;
205 if (sizeof(int) == 4)
206 throw std::length_error("hash table exceeded maximum size. use a ILP64 abi for larger tables.");
208 for (auto p
: zero_and_some_primes
)
209 if (100129 * p
> min_size
) return 100129 * p
;
211 throw std::length_error("hash table exceeded maximum size.");
214 template<typename K
, typename T
, typename OPS
>
219 std::pair
<K
, T
> udata
;
223 entry_t(const std::pair
<K
, T
> &udata
, int next
) : udata(udata
), next(next
) { }
224 entry_t(std::pair
<K
, T
> &&udata
, int next
) : udata(std::move(udata
)), next(next
) { }
227 std::vector
<int> hashtable
;
228 std::vector
<entry_t
> entries
;
232 static inline void do_assert(bool) { }
234 static inline void do_assert(bool cond
) {
235 if (!cond
) throw std::runtime_error("dict<> assert failed.");
239 int do_hash(const K
&key
) const
241 unsigned int hash
= 0;
242 if (!hashtable
.empty())
243 hash
= ops
.hash(key
) % (unsigned int)(hashtable
.size());
250 hashtable
.resize(hashtable_size(entries
.capacity() * hashtable_size_factor
), -1);
252 for (int i
= 0; i
< int(entries
.size()); i
++) {
253 do_assert(-1 <= entries
[i
].next
&& entries
[i
].next
< int(entries
.size()));
254 int hash
= do_hash(entries
[i
].udata
.first
);
255 entries
[i
].next
= hashtable
[hash
];
260 int do_erase(int index
, int hash
)
262 do_assert(index
< int(entries
.size()));
263 if (hashtable
.empty() || index
< 0)
266 int k
= hashtable
[hash
];
267 do_assert(0 <= k
&& k
< int(entries
.size()));
270 hashtable
[hash
] = entries
[index
].next
;
272 while (entries
[k
].next
!= index
) {
274 do_assert(0 <= k
&& k
< int(entries
.size()));
276 entries
[k
].next
= entries
[index
].next
;
279 int back_idx
= entries
.size()-1;
281 if (index
!= back_idx
)
283 int back_hash
= do_hash(entries
[back_idx
].udata
.first
);
285 k
= hashtable
[back_hash
];
286 do_assert(0 <= k
&& k
< int(entries
.size()));
289 hashtable
[back_hash
] = index
;
291 while (entries
[k
].next
!= back_idx
) {
293 do_assert(0 <= k
&& k
< int(entries
.size()));
295 entries
[k
].next
= index
;
298 entries
[index
] = std::move(entries
[back_idx
]);
309 int do_lookup(const K
&key
, int &hash
) const
311 if (hashtable
.empty())
314 if (entries
.size() * hashtable_size_trigger
> hashtable
.size()) {
315 ((dict
*)this)->do_rehash();
319 int index
= hashtable
[hash
];
321 while (index
>= 0 && !ops
.cmp(entries
[index
].udata
.first
, key
)) {
322 index
= entries
[index
].next
;
323 do_assert(-1 <= index
&& index
< int(entries
.size()));
329 int do_insert(const K
&key
, int &hash
)
331 if (hashtable
.empty()) {
332 entries
.emplace_back(std::pair
<K
, T
>(key
, T()), -1);
336 entries
.emplace_back(std::pair
<K
, T
>(key
, T()), hashtable
[hash
]);
337 hashtable
[hash
] = entries
.size() - 1;
339 return entries
.size() - 1;
342 int do_insert(const std::pair
<K
, T
> &value
, int &hash
)
344 if (hashtable
.empty()) {
345 entries
.emplace_back(value
, -1);
347 hash
= do_hash(value
.first
);
349 entries
.emplace_back(value
, hashtable
[hash
]);
350 hashtable
[hash
] = entries
.size() - 1;
352 return entries
.size() - 1;
355 int do_insert(std::pair
<K
, T
> &&rvalue
, int &hash
)
357 if (hashtable
.empty()) {
358 auto key
= rvalue
.first
;
359 entries
.emplace_back(std::forward
<std::pair
<K
, T
>>(rvalue
), -1);
363 entries
.emplace_back(std::forward
<std::pair
<K
, T
>>(rvalue
), hashtable
[hash
]);
364 hashtable
[hash
] = entries
.size() - 1;
366 return entries
.size() - 1;
370 class const_iterator
: public std::iterator
<std::forward_iterator_tag
, std::pair
<K
, T
>>
376 const_iterator(const dict
*ptr
, int index
) : ptr(ptr
), index(index
) { }
379 const_iterator
operator++() { index
--; return *this; }
380 bool operator<(const const_iterator
&other
) const { return index
> other
.index
; }
381 bool operator==(const const_iterator
&other
) const { return index
== other
.index
; }
382 bool operator!=(const const_iterator
&other
) const { return index
!= other
.index
; }
383 const std::pair
<K
, T
> &operator*() const { return ptr
->entries
[index
].udata
; }
384 const std::pair
<K
, T
> *operator->() const { return &ptr
->entries
[index
].udata
; }
387 class iterator
: public std::iterator
<std::forward_iterator_tag
, std::pair
<K
, T
>>
393 iterator(dict
*ptr
, int index
) : ptr(ptr
), index(index
) { }
396 iterator
operator++() { index
--; return *this; }
397 bool operator<(const iterator
&other
) const { return index
> other
.index
; }
398 bool operator==(const iterator
&other
) const { return index
== other
.index
; }
399 bool operator!=(const iterator
&other
) const { return index
!= other
.index
; }
400 std::pair
<K
, T
> &operator*() { return ptr
->entries
[index
].udata
; }
401 std::pair
<K
, T
> *operator->() { return &ptr
->entries
[index
].udata
; }
402 const std::pair
<K
, T
> &operator*() const { return ptr
->entries
[index
].udata
; }
403 const std::pair
<K
, T
> *operator->() const { return &ptr
->entries
[index
].udata
; }
404 operator const_iterator() const { return const_iterator(ptr
, index
); }
411 dict(const dict
&other
)
413 entries
= other
.entries
;
422 dict
&operator=(const dict
&other
) {
423 entries
= other
.entries
;
428 dict
&operator=(dict
&&other
) {
434 dict(const std::initializer_list
<std::pair
<K
, T
>> &list
)
436 for (auto &it
: list
)
440 template<class InputIterator
>
441 dict(InputIterator first
, InputIterator last
)
446 template<class InputIterator
>
447 void insert(InputIterator first
, InputIterator last
)
449 for (; first
!= last
; ++first
)
453 std::pair
<iterator
, bool> insert(const K
&key
)
455 int hash
= do_hash(key
);
456 int i
= do_lookup(key
, hash
);
458 return std::pair
<iterator
, bool>(iterator(this, i
), false);
459 i
= do_insert(key
, hash
);
460 return std::pair
<iterator
, bool>(iterator(this, i
), true);
463 std::pair
<iterator
, bool> insert(const std::pair
<K
, T
> &value
)
465 int hash
= do_hash(value
.first
);
466 int i
= do_lookup(value
.first
, hash
);
468 return std::pair
<iterator
, bool>(iterator(this, i
), false);
469 i
= do_insert(value
, hash
);
470 return std::pair
<iterator
, bool>(iterator(this, i
), true);
473 std::pair
<iterator
, bool> insert(std::pair
<K
, T
> &&rvalue
)
475 int hash
= do_hash(rvalue
.first
);
476 int i
= do_lookup(rvalue
.first
, hash
);
478 return std::pair
<iterator
, bool>(iterator(this, i
), false);
479 i
= do_insert(std::forward
<std::pair
<K
, T
>>(rvalue
), hash
);
480 return std::pair
<iterator
, bool>(iterator(this, i
), true);
483 std::pair
<iterator
, bool> emplace(K
const &key
, T
const &value
)
485 int hash
= do_hash(key
);
486 int i
= do_lookup(key
, hash
);
488 return std::pair
<iterator
, bool>(iterator(this, i
), false);
489 i
= do_insert(std::make_pair(key
, value
), hash
);
490 return std::pair
<iterator
, bool>(iterator(this, i
), true);
493 std::pair
<iterator
, bool> emplace(K
const &key
, T
&&rvalue
)
495 int hash
= do_hash(key
);
496 int i
= do_lookup(key
, hash
);
498 return std::pair
<iterator
, bool>(iterator(this, i
), false);
499 i
= do_insert(std::make_pair(key
, std::forward
<T
>(rvalue
)), hash
);
500 return std::pair
<iterator
, bool>(iterator(this, i
), true);
503 std::pair
<iterator
, bool> emplace(K
&&rkey
, T
const &value
)
505 int hash
= do_hash(rkey
);
506 int i
= do_lookup(rkey
, hash
);
508 return std::pair
<iterator
, bool>(iterator(this, i
), false);
509 i
= do_insert(std::make_pair(std::forward
<K
>(rkey
), value
), hash
);
510 return std::pair
<iterator
, bool>(iterator(this, i
), true);
513 std::pair
<iterator
, bool> emplace(K
&&rkey
, T
&&rvalue
)
515 int hash
= do_hash(rkey
);
516 int i
= do_lookup(rkey
, hash
);
518 return std::pair
<iterator
, bool>(iterator(this, i
), false);
519 i
= do_insert(std::make_pair(std::forward
<K
>(rkey
), std::forward
<T
>(rvalue
)), hash
);
520 return std::pair
<iterator
, bool>(iterator(this, i
), true);
523 int erase(const K
&key
)
525 int hash
= do_hash(key
);
526 int index
= do_lookup(key
, hash
);
527 return do_erase(index
, hash
);
530 iterator
erase(iterator it
)
532 int hash
= do_hash(it
->first
);
533 do_erase(it
.index
, hash
);
537 int count(const K
&key
) const
539 int hash
= do_hash(key
);
540 int i
= do_lookup(key
, hash
);
541 return i
< 0 ? 0 : 1;
544 int count(const K
&key
, const_iterator it
) const
546 int hash
= do_hash(key
);
547 int i
= do_lookup(key
, hash
);
548 return i
< 0 || i
> it
.index
? 0 : 1;
551 iterator
find(const K
&key
)
553 int hash
= do_hash(key
);
554 int i
= do_lookup(key
, hash
);
557 return iterator(this, i
);
560 const_iterator
find(const K
&key
) const
562 int hash
= do_hash(key
);
563 int i
= do_lookup(key
, hash
);
566 return const_iterator(this, i
);
571 int hash
= do_hash(key
);
572 int i
= do_lookup(key
, hash
);
574 throw std::out_of_range("dict::at()");
575 return entries
[i
].udata
.second
;
578 const T
& at(const K
&key
) const
580 int hash
= do_hash(key
);
581 int i
= do_lookup(key
, hash
);
583 throw std::out_of_range("dict::at()");
584 return entries
[i
].udata
.second
;
587 const T
& at(const K
&key
, const T
&defval
) const
589 int hash
= do_hash(key
);
590 int i
= do_lookup(key
, hash
);
593 return entries
[i
].udata
.second
;
596 T
& operator[](const K
&key
)
598 int hash
= do_hash(key
);
599 int i
= do_lookup(key
, hash
);
601 i
= do_insert(std::pair
<K
, T
>(key
, T()), hash
);
602 return entries
[i
].udata
.second
;
605 template<typename Compare
= std::less
<K
>>
606 void sort(Compare comp
= Compare())
608 std::sort(entries
.begin(), entries
.end(), [comp
](const entry_t
&a
, const entry_t
&b
){ return comp(b
.udata
.first
, a
.udata
.first
); });
612 void swap(dict
&other
)
614 hashtable
.swap(other
.hashtable
);
615 entries
.swap(other
.entries
);
618 bool operator==(const dict
&other
) const {
619 if (size() != other
.size())
621 for (auto &it
: entries
) {
622 auto oit
= other
.find(it
.udata
.first
);
623 if (oit
== other
.end() || !(oit
->second
== it
.udata
.second
))
629 bool operator!=(const dict
&other
) const {
630 return !operator==(other
);
633 void reserve(size_t n
) { entries
.reserve(n
); }
634 size_t size() const { return entries
.size(); }
635 bool empty() const { return entries
.empty(); }
636 void clear() { hashtable
.clear(); entries
.clear(); }
638 iterator
begin() { return iterator(this, int(entries
.size())-1); }
639 iterator
element(int n
) { return iterator(this, int(entries
.size())-1-n
); }
640 iterator
end() { return iterator(nullptr, -1); }
642 const_iterator
begin() const { return const_iterator(this, int(entries
.size())-1); }
643 const_iterator
element(int n
) const { return const_iterator(this, int(entries
.size())-1-n
); }
644 const_iterator
end() const { return const_iterator(nullptr, -1); }
647 template<typename K
, typename OPS
>
650 template<typename
, int, typename
> friend class idict
;
659 entry_t(const K
&udata
, int next
) : udata(udata
), next(next
) { }
660 entry_t(K
&&udata
, int next
) : udata(std::move(udata
)), next(next
) { }
663 std::vector
<int> hashtable
;
664 std::vector
<entry_t
> entries
;
668 static inline void do_assert(bool) { }
670 static inline void do_assert(bool cond
) {
671 if (!cond
) throw std::runtime_error("pool<> assert failed.");
675 int do_hash(const K
&key
) const
677 unsigned int hash
= 0;
678 if (!hashtable
.empty())
679 hash
= ops
.hash(key
) % (unsigned int)(hashtable
.size());
686 hashtable
.resize(hashtable_size(entries
.capacity() * hashtable_size_factor
), -1);
688 for (int i
= 0; i
< int(entries
.size()); i
++) {
689 do_assert(-1 <= entries
[i
].next
&& entries
[i
].next
< int(entries
.size()));
690 int hash
= do_hash(entries
[i
].udata
);
691 entries
[i
].next
= hashtable
[hash
];
696 int do_erase(int index
, int hash
)
698 do_assert(index
< int(entries
.size()));
699 if (hashtable
.empty() || index
< 0)
702 int k
= hashtable
[hash
];
704 hashtable
[hash
] = entries
[index
].next
;
706 while (entries
[k
].next
!= index
) {
708 do_assert(0 <= k
&& k
< int(entries
.size()));
710 entries
[k
].next
= entries
[index
].next
;
713 int back_idx
= entries
.size()-1;
715 if (index
!= back_idx
)
717 int back_hash
= do_hash(entries
[back_idx
].udata
);
719 k
= hashtable
[back_hash
];
721 hashtable
[back_hash
] = index
;
723 while (entries
[k
].next
!= back_idx
) {
725 do_assert(0 <= k
&& k
< int(entries
.size()));
727 entries
[k
].next
= index
;
730 entries
[index
] = std::move(entries
[back_idx
]);
741 int do_lookup(const K
&key
, int &hash
) const
743 if (hashtable
.empty())
746 if (entries
.size() * hashtable_size_trigger
> hashtable
.size()) {
747 ((pool
*)this)->do_rehash();
751 int index
= hashtable
[hash
];
753 while (index
>= 0 && !ops
.cmp(entries
[index
].udata
, key
)) {
754 index
= entries
[index
].next
;
755 do_assert(-1 <= index
&& index
< int(entries
.size()));
761 int do_insert(const K
&value
, int &hash
)
763 if (hashtable
.empty()) {
764 entries
.emplace_back(value
, -1);
766 hash
= do_hash(value
);
768 entries
.emplace_back(value
, hashtable
[hash
]);
769 hashtable
[hash
] = entries
.size() - 1;
771 return entries
.size() - 1;
774 int do_insert(K
&&rvalue
, int &hash
)
776 if (hashtable
.empty()) {
777 entries
.emplace_back(std::forward
<K
>(rvalue
), -1);
779 hash
= do_hash(rvalue
);
781 entries
.emplace_back(std::forward
<K
>(rvalue
), hashtable
[hash
]);
782 hashtable
[hash
] = entries
.size() - 1;
784 return entries
.size() - 1;
788 class const_iterator
: public std::iterator
<std::forward_iterator_tag
, K
>
794 const_iterator(const pool
*ptr
, int index
) : ptr(ptr
), index(index
) { }
797 const_iterator
operator++() { index
--; return *this; }
798 bool operator==(const const_iterator
&other
) const { return index
== other
.index
; }
799 bool operator!=(const const_iterator
&other
) const { return index
!= other
.index
; }
800 const K
&operator*() const { return ptr
->entries
[index
].udata
; }
801 const K
*operator->() const { return &ptr
->entries
[index
].udata
; }
804 class iterator
: public std::iterator
<std::forward_iterator_tag
, K
>
810 iterator(pool
*ptr
, int index
) : ptr(ptr
), index(index
) { }
813 iterator
operator++() { index
--; return *this; }
814 bool operator==(const iterator
&other
) const { return index
== other
.index
; }
815 bool operator!=(const iterator
&other
) const { return index
!= other
.index
; }
816 K
&operator*() { return ptr
->entries
[index
].udata
; }
817 K
*operator->() { return &ptr
->entries
[index
].udata
; }
818 const K
&operator*() const { return ptr
->entries
[index
].udata
; }
819 const K
*operator->() const { return &ptr
->entries
[index
].udata
; }
820 operator const_iterator() const { return const_iterator(ptr
, index
); }
827 pool(const pool
&other
)
829 entries
= other
.entries
;
838 pool
&operator=(const pool
&other
) {
839 entries
= other
.entries
;
844 pool
&operator=(pool
&&other
) {
850 pool(const std::initializer_list
<K
> &list
)
852 for (auto &it
: list
)
856 template<class InputIterator
>
857 pool(InputIterator first
, InputIterator last
)
862 template<class InputIterator
>
863 void insert(InputIterator first
, InputIterator last
)
865 for (; first
!= last
; ++first
)
869 std::pair
<iterator
, bool> insert(const K
&value
)
871 int hash
= do_hash(value
);
872 int i
= do_lookup(value
, hash
);
874 return std::pair
<iterator
, bool>(iterator(this, i
), false);
875 i
= do_insert(value
, hash
);
876 return std::pair
<iterator
, bool>(iterator(this, i
), true);
879 std::pair
<iterator
, bool> insert(K
&&rvalue
)
881 int hash
= do_hash(rvalue
);
882 int i
= do_lookup(rvalue
, hash
);
884 return std::pair
<iterator
, bool>(iterator(this, i
), false);
885 i
= do_insert(std::forward
<K
>(rvalue
), hash
);
886 return std::pair
<iterator
, bool>(iterator(this, i
), true);
889 template<typename
... Args
>
890 std::pair
<iterator
, bool> emplace(Args
&&... args
)
892 return insert(K(std::forward
<Args
>(args
)...));
895 int erase(const K
&key
)
897 int hash
= do_hash(key
);
898 int index
= do_lookup(key
, hash
);
899 return do_erase(index
, hash
);
902 iterator
erase(iterator it
)
904 int hash
= do_hash(*it
);
905 do_erase(it
.index
, hash
);
909 int count(const K
&key
) const
911 int hash
= do_hash(key
);
912 int i
= do_lookup(key
, hash
);
913 return i
< 0 ? 0 : 1;
916 int count(const K
&key
, const_iterator it
) const
918 int hash
= do_hash(key
);
919 int i
= do_lookup(key
, hash
);
920 return i
< 0 || i
> it
.index
? 0 : 1;
923 iterator
find(const K
&key
)
925 int hash
= do_hash(key
);
926 int i
= do_lookup(key
, hash
);
929 return iterator(this, i
);
932 const_iterator
find(const K
&key
) const
934 int hash
= do_hash(key
);
935 int i
= do_lookup(key
, hash
);
938 return const_iterator(this, i
);
941 bool operator[](const K
&key
)
943 int hash
= do_hash(key
);
944 int i
= do_lookup(key
, hash
);
948 template<typename Compare
= std::less
<K
>>
949 void sort(Compare comp
= Compare())
951 std::sort(entries
.begin(), entries
.end(), [comp
](const entry_t
&a
, const entry_t
&b
){ return comp(b
.udata
, a
.udata
); });
957 iterator it
= begin();
963 void swap(pool
&other
)
965 hashtable
.swap(other
.hashtable
);
966 entries
.swap(other
.entries
);
969 bool operator==(const pool
&other
) const {
970 if (size() != other
.size())
972 for (auto &it
: entries
)
973 if (!other
.count(it
.udata
))
978 bool operator!=(const pool
&other
) const {
979 return !operator==(other
);
983 unsigned int hashval
= mkhash_init
;
984 for (auto &it
: entries
)
985 hashval
^= ops
.hash(it
.udata
);
989 void reserve(size_t n
) { entries
.reserve(n
); }
990 size_t size() const { return entries
.size(); }
991 bool empty() const { return entries
.empty(); }
992 void clear() { hashtable
.clear(); entries
.clear(); }
994 iterator
begin() { return iterator(this, int(entries
.size())-1); }
995 iterator
element(int n
) { return iterator(this, int(entries
.size())-1-n
); }
996 iterator
end() { return iterator(nullptr, -1); }
998 const_iterator
begin() const { return const_iterator(this, int(entries
.size())-1); }
999 const_iterator
element(int n
) const { return const_iterator(this, int(entries
.size())-1-n
); }
1000 const_iterator
end() const { return const_iterator(nullptr, -1); }
1003 template<typename K
, int offset
, typename OPS
>
1006 pool
<K
, OPS
> database
;
1009 class const_iterator
: public std::iterator
<std::forward_iterator_tag
, K
>
1013 const idict
&container
;
1015 const_iterator(const idict
&container
, int index
) : container(container
), index(index
) { }
1017 const_iterator() { }
1018 const_iterator
operator++() { index
++; return *this; }
1019 bool operator==(const const_iterator
&other
) const { return index
== other
.index
; }
1020 bool operator!=(const const_iterator
&other
) const { return index
!= other
.index
; }
1021 const K
&operator*() const { return container
[index
]; }
1022 const K
*operator->() const { return &container
[index
]; }
1025 int operator()(const K
&key
)
1027 int hash
= database
.do_hash(key
);
1028 int i
= database
.do_lookup(key
, hash
);
1030 i
= database
.do_insert(key
, hash
);
1034 int at(const K
&key
) const
1036 int hash
= database
.do_hash(key
);
1037 int i
= database
.do_lookup(key
, hash
);
1039 throw std::out_of_range("idict::at()");
1043 int at(const K
&key
, int defval
) const
1045 int hash
= database
.do_hash(key
);
1046 int i
= database
.do_lookup(key
, hash
);
1052 int count(const K
&key
) const
1054 int hash
= database
.do_hash(key
);
1055 int i
= database
.do_lookup(key
, hash
);
1056 return i
< 0 ? 0 : 1;
1059 void expect(const K
&key
, int i
)
1061 int j
= (*this)(key
);
1063 throw std::out_of_range("idict::expect()");
1066 const K
&operator[](int index
) const
1068 return database
.entries
.at(index
- offset
).udata
;
1071 void swap(idict
&other
)
1073 database
.swap(other
.database
);
1076 void reserve(size_t n
) { database
.reserve(n
); }
1077 size_t size() const { return database
.size(); }
1078 bool empty() const { return database
.empty(); }
1079 void clear() { database
.clear(); }
1081 const_iterator
begin() const { return const_iterator(*this, offset
); }
1082 const_iterator
element(int n
) const { return const_iterator(*this, n
); }
1083 const_iterator
end() const { return const_iterator(*this, offset
+ size()); }
1086 template<typename K
, typename OPS
>
1089 mutable idict
<K
, 0, OPS
> database
;
1090 mutable std::vector
<int> parents
;
1093 typedef typename idict
<K
, 0, OPS
>::const_iterator const_iterator
;
1095 int operator()(const K
&key
) const
1097 int i
= database(key
);
1098 parents
.resize(database
.size(), -1);
1102 const K
&operator[](int index
) const
1104 return database
[index
];
1107 int ifind(int i
) const
1111 while (parents
[p
] != -1)
1115 int next_k
= parents
[k
];
1123 void imerge(int i
, int j
)
1132 void ipromote(int i
)
1137 int next_k
= parents
[k
];
1145 int lookup(const K
&a
) const
1147 return ifind((*this)(a
));
1150 const K
&find(const K
&a
) const
1152 int i
= database
.at(a
, -1);
1155 return (*this)[ifind(i
)];
1158 void merge(const K
&a
, const K
&b
)
1160 imerge((*this)(a
), (*this)(b
));
1163 void promote(const K
&a
)
1165 int i
= database
.at(a
, -1);
1170 void swap(mfp
&other
)
1172 database
.swap(other
.database
);
1173 parents
.swap(other
.parents
);
1176 void reserve(size_t n
) { database
.reserve(n
); }
1177 size_t size() const { return database
.size(); }
1178 bool empty() const { return database
.empty(); }
1179 void clear() { database
.clear(); parents
.clear(); }
1181 const_iterator
begin() const { return database
.begin(); }
1182 const_iterator
element(int n
) const { return database
.element(n
); }
1183 const_iterator
end() const { return database
.end(); }
1186 } /* namespace hashlib */