38 return ((a << 5) + a) ^ b;
47 return ((a << 5) + a) + b;
55 }
else if (
sizeof(a) == 8) {
60 throw std::runtime_error(
"mkhash_xorshift() only implemented for 32 bit and 64 bit ints");
74 static inline bool cmp(
const T &a,
const T &b) {
84 static inline bool cmp(T a, T b) {
104 template<>
struct hash_ops<long> : hash_int_ops
107 if constexpr (
sizeof(
long) <=
sizeof(
hm_uint)) {
108 return static_cast<hm_uint>(a);
110 return mkhash(
static_cast<hm_uint>(a),
static_cast<hm_uint>(
static_cast<unsigned long>(a) >> 32));
117 static inline bool cmp(
const std::string &a,
const std::string &b) {
128 template<
typename P,
typename Q>
struct hash_ops<std::pair<P, Q>> {
129 static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
137 template<
typename... T>
struct hash_ops<std::tuple<T...>> {
138 static inline bool cmp(std::tuple<T...> a, std::tuple<T...> b) {
141 template<
size_t I = 0>
142 static inline typename std::enable_if<I ==
sizeof...(T),
hm_uint>::type
hash(std::tuple<T...>) {
145 template<
size_t I = 0>
146 static inline typename std::enable_if<I !=
sizeof...(T),
hm_uint>::type
hash(std::tuple<T...> a) {
147 typedef hash_ops<
typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
148 return mkhash(hash<I+1>(a), element_ops_t::hash(std::get<I>(a)));
152 template<
typename T>
struct hash_ops<std::vector<T>> {
153 static inline bool cmp(std::vector<T> a, std::vector<T> b) {
165 static inline bool cmp(
const char *a,
const char *b) {
166 for (
int i = 0; a[i] || b[i]; i++)
180 static inline bool cmp(
const void *a,
const void *b) {
184 return (
unsigned long)a;
189 static inline bool cmp(
const void *a,
const void *b) {
194 return a ? a->hash() : 0;
205 static std::vector<hm_int> zero_and_some_primes = {
206 0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,
207 853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,
208 12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281,
209 120371, 150473, 188107, 235159, 293957, 367453, 459317, 574157, 717697,
210 897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037,
211 5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411,
212 25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,
213 121590311, 151987889, 189984863, 237481091, 296851369, 371064217
216 for (
auto p : zero_and_some_primes)
217 if (p >= min_size)
return p;
220 throw std::length_error(
"hash table exceeded maximum size. use a ILP64 abi for larger tables.");
222 for (
auto p : zero_and_some_primes)
223 if (100129 * p > min_size)
return 100129 * p;
225 throw std::length_error(
"hash table exceeded maximum size.");
228 template<
typename K,
typename T,
typename OPS = hash_ops<K>>
class unordered_map;
229 template<
typename K, hm_
int offset = 0,
typename OPS = hash_ops<K>>
class idict;
230 template<
typename K,
typename OPS = hash_ops<K>>
class unordered_set;
231 template<
typename K,
typename OPS = hash_ops<K>>
class mfp;
240 template<
typename K,
typename T,
typename OPS>
246 std::pair<K, T> udata;
250 entry_t(
const std::pair<K, T> & idata,
hm_int inext) : udata(idata), next(inext) { }
251 entry_t(std::pair<K, T> && idata,
hm_int inext) : udata(std::move(idata)), next(inext) { }
255 std::vector<hm_int> hashtable;
257 std::vector<entry_t> entries;
262 static inline void do_assert(
bool) { }
264 static inline void do_assert(
bool cond) {
265 if (!cond)
throw std::runtime_error(
"unordered_map<> assert failed.");
279 hm_int do_hash(
const K &key)
const
282 if (!hashtable.empty())
283 hash = ops.hash(key) % (
hm_uint)(hashtable.size());
296 do_assert(-1 <= entries[i].next && entries[i].next <
hm_int(entries.size()));
297 hm_int hash = do_hash(entries[i].udata.first);
298 entries[i].next = hashtable[hash];
313 do_assert(index <
hm_int(entries.size()));
314 if (hashtable.empty() || index < 0)
317 hm_int k = hashtable[hash];
318 do_assert(0 <= k && k <
hm_int(entries.size()));
321 hashtable[hash] = entries[index].next;
323 while (entries[k].next != index) {
325 do_assert(0 <= k && k <
hm_int(entries.size()));
327 entries[k].next = entries[index].next;
330 hm_int back_idx = entries.size()-1;
332 if (index != back_idx)
334 hm_int back_hash = do_hash(entries[back_idx].udata.first);
336 k = hashtable[back_hash];
337 do_assert(0 <= k && k <
hm_int(entries.size()));
340 hashtable[back_hash] = index;
342 while (entries[k].next != back_idx) {
344 do_assert(0 <= k && k <
hm_int(entries.size()));
346 entries[k].next = index;
349 entries[index] = std::move(entries[back_idx]);
370 if (hashtable.empty())
378 hm_int index = hashtable[hash];
380 while (index >= 0 && !ops.cmp(entries[index].udata.first, key)) {
381 index = entries[index].next;
382 do_assert(-1 <= index && index <
hm_int(entries.size()));
401 if (hashtable.empty()) {
402 entries.push_back(entry_t(std::pair<K, T>(key, T()), -1));
406 entries.push_back(entry_t(std::pair<K, T>(key, T()), hashtable[hash]));
407 hashtable[hash] = entries.size() - 1;
409 return entries.size() - 1;
423 hm_int do_insert(
const std::pair<K, T> &value,
hm_int &hash)
425 if (hashtable.empty()) {
426 entries.push_back(entry_t(value, -1));
428 hash = do_hash(value.first);
430 entries.push_back(entry_t(value, hashtable[hash]));
431 hashtable[hash] = entries.size() - 1;
433 return entries.size() - 1;
536 entries = other.entries;
547 entries = other.entries;
560 for (
auto &it : list)
565 template<
class InputIterator>
571 template<
class InputIterator>
572 void insert(InputIterator first, InputIterator last)
574 for (; first != last; ++first)
578 std::pair<iterator, bool>
insert(
const K &key)
580 hm_int hash = do_hash(key);
581 hm_int i = do_lookup(key, hash);
583 return std::pair<iterator, bool>(
iterator(
this, i),
false);
584 i = do_insert(key, hash);
585 return std::pair<iterator, bool>(
iterator(
this, i),
true);
588 std::pair<iterator, bool>
insert(
const std::pair<K, T> &value)
590 hm_int hash = do_hash(value.first);
591 hm_int i = do_lookup(value.first, hash);
593 return std::pair<iterator, bool>(
iterator(
this, i),
false);
594 i = do_insert(value, hash);
595 return std::pair<iterator, bool>(
iterator(
this, i),
true);
600 hm_int hash = do_hash(key);
601 hm_int index = do_lookup(key, hash);
602 return do_erase(index, hash);
607 hm_int hash = do_hash(it->first);
608 do_erase(it.
index, hash);
614 hm_int hash = do_hash(key);
615 hm_int i = do_lookup(key, hash);
616 return i < 0 ? 0 : 1;
621 hm_int hash = do_hash(key);
622 hm_int i = do_lookup(key, hash);
623 return i < 0 || i > it.
index ? 0 : 1;
628 hm_int hash = do_hash(key);
629 hm_int i = do_lookup(key, hash);
638 hm_int hash = do_hash(key);
639 hm_int i = do_lookup(key, hash);
648 hm_int hash = do_hash(key);
649 hm_int i = do_lookup(key, hash);
651 throw std::out_of_range(
"unordered_map::at()");
652 return entries[i].udata.second;
656 const T&
at(
const K &key)
const
658 hm_int hash = do_hash(key);
659 hm_int i = do_lookup(key, hash);
661 throw std::out_of_range(
"unordered_map::at()");
662 return entries[i].udata.second;
666 T
at(
const K &key,
const T &defval)
const
668 hm_int hash = do_hash(key);
669 hm_int i = do_lookup(key, hash);
672 return entries[i].udata.second;
678 hm_int hash = do_hash(key);
679 hm_int i = do_lookup(key, hash);
681 i = do_insert(std::pair<K, T>(key, T()), hash);
682 return entries[i].udata.second;
691 template<
typename Compare = std::less<K>>
692 void sort(Compare comp = Compare())
694 std::sort(entries.begin(), entries.end(), [comp](
const entry_t &a,
const entry_t &b){ return comp(b.udata.first, a.udata.first); });
700 hashtable.swap(other.hashtable);
701 entries.swap(other.entries);
707 for (
auto &it : entries) {
708 auto oit = other.
find(it.udata.first);
709 if (oit == other.
end() || !(oit->second == it.udata.second))
719 void reserve(
size_t n) { entries.reserve(n); }
720 size_t size()
const {
return entries.size(); }
721 bool empty()
const {
return entries.empty(); }
722 void clear() { hashtable.clear(); entries.clear(); }
737 template<
typename K,
typename OPS>
740 template<
typename, hm_
int,
typename>
friend class idict;
764 if (!cond)
throw std::runtime_error(
"unordered_set<> assert failed.");
819 while (
entries[k].next != index) {
828 if (index != back_idx)
836 while (
entries[k].next != back_idx) {
874 while (index >= 0 && !
ops.cmp(
entries[index].udata, key)) {
1026 for (
auto &it : list)
1030 template<
class InputIterator>
1036 template<
class InputIterator>
1037 void insert(InputIterator first, InputIterator last)
1039 for (; first != last; ++first)
1043 std::pair<iterator, bool>
insert(
const K &value)
1048 return std::pair<iterator, bool>(
iterator(
this, i),
false);
1050 return std::pair<iterator, bool>(
iterator(
this, i),
true);
1071 return i < 0 ? 0 : 1;
1078 return i < 0 || i > it.
index ? 0 : 1;
1106 template<
typename Compare = std::less<K>>
1107 void sort(Compare comp = Compare())
1131 if (!other.
count(it.udata))
1152 template<
typename K, hm_
int offset,
typename OPS>
1174 throw std::out_of_range(
"idict::at()");
1191 return i < 0 ? 0 : 1;
1198 throw std::out_of_range(
"idict::expect()");
1203 return database.
entries.at(index - offset).udata;
1208 database.
swap(other.database);
1220 template<
typename K,
typename OPS>
1224 mutable std::vector<hm_int> parents;
1231 hm_int i = database(key);
1232 parents.resize(database.
size(), -1);
1238 return database[index];
1245 while (parents[p] != -1)
1249 hm_int next_k = parents[k];
1271 hm_int next_k = parents[k];
1281 return ifind((*
this)(a));
1289 return (*
this)[
ifind(i)];
1294 imerge((*
this)(a), (*
this)(b));
1306 database.
swap(other.database);
1307 parents.swap(other.parents);
hm_int operator()(const K &key)
const K & operator[](hm_int index) const
void expect(const K &key, hm_int i)
const_iterator begin() const
hm_int at(const K &key) const
unordered_set< K, OPS >::const_iterator const_iterator
hm_int count(const K &key) const
const_iterator end() const
hm_int at(const K &key, hm_int defval) const
hm_int operator()(const K &key) const
hm_int lookup(const K &a) const
const K & operator[](hm_int index) const
const K & find(const K &a) const
hm_int ifind(hm_int i) const
const_iterator begin() const
idict< K, 0, OPS >::const_iterator const_iterator
void imerge(hm_int i, hm_int j)
const_iterator end() const
void merge(const K &a, const K &b)
const_iterator & operator--()
const_iterator(const unordered_map *iptr, hm_int iindex)
std::forward_iterator_tag iterator_category
std::ptrdiff_t difference_type
const value_type * pointer
bool operator!=(const const_iterator &other) const
const_iterator operator++(int)
const_iterator operator--(int)
const unordered_map * ptr
bool operator==(const const_iterator &other) const
std::pair< K, T > value_type
reference operator*() const
const_iterator & operator++()
bool operator<(const const_iterator &other) const
const value_type & reference
pointer operator->() const
const value_type & operator*() const
std::pair< K, T > value_type
std::forward_iterator_tag iterator_category
bool operator!=(const iterator &other) const
iterator(unordered_map *iptr, hm_int iindex)
const value_type * operator->() const
bool operator<(const iterator &other) const
std::ptrdiff_t difference_type
bool operator==(const iterator &other) const
T at(const K &key, const T &defval) const
Return data if existent or default value.
iterator find(const K &key)
Search for key. Return iterator.
hm_int count(const K &key, const_iterator it) const
Check if key exists and matches iterator.
unordered_map & operator=(const unordered_map &other)
const_iterator end() const
unordered_map(const std::initializer_list< std::pair< K, T >> &list)
unordered_map(unordered_map &&other)
Construct map form another map.
hm_int count(const K &key) const
Check if key exists.
bool operator!=(const unordered_map &other) const
const_iterator begin() const
std::pair< iterator, bool > insert(const std::pair< K, T > &value)
Insert key-value pair.
const T & at(const K &key) const
Const data access by key.
T & operator[](const K &key)
Data access or empty insert.
void swap(unordered_map &other)
void sort(Compare comp=Compare())
Sort data entries.
bool operator==(const unordered_map &other) const
const_iterator find(const K &key) const
Search for key. Return const_iterator.
std::pair< iterator, bool > insert(const K &key)
User insert as key lookup.
void insert(InputIterator first, InputIterator last)
Insert Iterator range.
iterator erase(iterator it)
Erase by iterator.
unordered_map()
Empty constructor.
T & at(const K &key)
Data access by key.
unordered_map(InputIterator first, InputIterator last)
Construct from Iterator range.
unordered_map & operator=(unordered_map &&other)
hm_int erase(const K &key)
Erase by key.
unordered_map(const unordered_map &other)
Construct from another map.
pointer operator->() const
bool operator==(const const_iterator &other) const
std::forward_iterator_tag iterator_category
const value_type * pointer
const_iterator operator--(int)
bool operator!=(const const_iterator &other) const
const value_type & reference
reference operator*() const
const_iterator & operator--()
const_iterator & operator++()
const_iterator operator++(int)
const_iterator(const unordered_set *iptr, hm_int iindex)
const unordered_set * ptr
std::ptrdiff_t difference_type
const value_type & operator*() const
std::ptrdiff_t difference_type
std::forward_iterator_tag iterator_category
bool operator!=(const iterator &other) const
const value_type * operator->() const
iterator(unordered_set *iptr, hm_int iindex)
bool operator==(const iterator &other) const
Custom unordered_set implementation.
unordered_set(InputIterator first, InputIterator last)
unordered_set(unordered_set &&other)
Construct from another set.
unordered_set & operator=(unordered_set &&other)
iterator find(const K &key)
std::pair< iterator, bool > insert(const K &value)
const_iterator end() const
void sort(Compare comp=Compare())
hm_int erase(const K &key)
const_iterator find(const K &key) const
bool operator==(const unordered_set &other) const
hm_int do_erase(hm_int index, hm_int hash)
Remove an entry.
unordered_set(const unordered_set &other)
Construct from another set.
unordered_set(const std::initializer_list< K > &list)
OPS ops
the hash generator
unordered_set & operator=(const unordered_set &other)
iterator erase(iterator it)
void do_rehash()
Resize the hashtable and compute new hashes.
const_iterator begin() const
hm_int do_hash(const K &key) const
Generate a hash from a key.
std::vector< entry_t > entries
the stored entries
std::vector< hm_int > hashtable
the hashtable
static void do_assert(bool cond)
void swap(unordered_set &other)
hm_int do_lookup(const K &key, hm_int &hash) const
Return hash and index for a key.
bool operator[](const K &key)
unordered_set()
Empty constructor.
bool operator!=(const unordered_set &other) const
hm_int count(const K &key) const
void insert(InputIterator first, InputIterator last)
hm_int count(const K &key, const_iterator it) const
hm_int do_insert(const K &value, hm_int &hash)
Insert a pair consisting of a key and a default (empty) value.
unsigned long int hm_uint
const hm_int hashtable_size_trigger
hm_int hashtable_size(hm_int min_size)
const hm_uint mkhash_init
hm_uint mkhash_add(hm_uint a, hm_uint b)
hm_uint mkhash(hm_uint a, hm_uint b)
const hm_int hashtable_size_factor
hm_uint mkhash_xorshift(hm_uint a)
static hm_uint hash(const char *a)
static bool cmp(const char *a, const char *b)
static bool cmp(T a, T b)
static hm_uint hash(const T *a)
static bool cmp(const void *a, const void *b)
static hm_uint hash(int32_t a)
static hm_uint hash(int64_t a)
static hm_uint hash(std::pair< P, Q > a)
static bool cmp(std::pair< P, Q > a, std::pair< P, Q > b)
static hm_uint hash(const std::string &a)
static bool cmp(const std::string &a, const std::string &b)
static std::enable_if< I !=sizeof...(T), hm_uint >::type hash(std::tuple< T... > a)
static std::enable_if< I==sizeof...(T), hm_uint >::type hash(std::tuple< T... >)
static bool cmp(std::tuple< T... > a, std::tuple< T... > b)
static hm_uint hash(std::vector< T > a)
static bool cmp(std::vector< T > a, std::vector< T > b)
static hm_uint hash(const T &a)
static bool cmp(const T &a, const T &b)
static hm_uint hash(const void *a)
static bool cmp(const void *a, const void *b)
entry_t(const K &idata, hm_int inext)