53 return ((a << 5) + a) ^ b;
62 return ((a << 5) + a) + b;
70 }
else if (
sizeof(a) == 8) {
75 throw std::runtime_error(
"mkhash_xorshift() only implemented for 32 bit and 64 bit ints");
89 static inline bool cmp(
const T &a,
const T &b) {
99 static inline bool cmp(T a, T b) {
119 template<>
struct hash_ops<long> : hash_int_ops
122 if constexpr (
sizeof(
long) <=
sizeof(
hm_uint)) {
123 return static_cast<hm_uint>(a);
125 return mkhash(
static_cast<hm_uint>(a),
static_cast<hm_uint>(
static_cast<unsigned long>(a) >> 32));
132 static inline bool cmp(
const std::string &a,
const std::string &b) {
143 template<
typename P,
typename Q>
struct hash_ops<std::pair<P, Q>> {
144 static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
152 template<
typename... T>
struct hash_ops<std::tuple<T...>> {
153 static inline bool cmp(std::tuple<T...> a, std::tuple<T...> b) {
156 template<
size_t I = 0>
157 static inline typename std::enable_if<I ==
sizeof...(T),
hm_uint>::type
hash(std::tuple<T...>) {
160 template<
size_t I = 0>
161 static inline typename std::enable_if<I !=
sizeof...(T),
hm_uint>::type
hash(std::tuple<T...> a) {
162 typedef hash_ops<
typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
163 return mkhash(hash<I+1>(a), element_ops_t::hash(std::get<I>(a)));
167 template<
typename T>
struct hash_ops<std::vector<T>> {
168 static inline bool cmp(std::vector<T> a, std::vector<T> b) {
180 static inline bool cmp(
const char *a,
const char *b) {
181 for (
int i = 0; a[i] || b[i]; i++)
195 static inline bool cmp(
const void *a,
const void *b) {
199 return (
unsigned long)a;
204 static inline bool cmp(
const void *a,
const void *b) {
209 return a ? a->hash() : 0;
220 static std::vector<hm_int> zero_and_some_primes = {
221 0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,
222 853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,
223 12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281,
224 120371, 150473, 188107, 235159, 293957, 367453, 459317, 574157, 717697,
225 897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037,
226 5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411,
227 25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,
228 121590311, 151987889, 189984863, 237481091, 296851369, 371064217
231 for (
auto p : zero_and_some_primes)
232 if (p >= min_size)
return p;
235 throw std::length_error(
"hash table exceeded maximum size. use a ILP64 abi for larger tables.");
237 for (
auto p : zero_and_some_primes)
238 if (100129 * p > min_size)
return 100129 * p;
240 throw std::length_error(
"hash table exceeded maximum size.");
243 template<
typename K,
typename T,
typename OPS = hash_ops<K>>
class unordered_map;
244 template<
typename K, hm_
int offset = 0,
typename OPS = hash_ops<K>>
class idict;
245 template<
typename K,
typename OPS = hash_ops<K>>
class unordered_set;
246 template<
typename K,
typename OPS = hash_ops<K>>
class mfp;
255 template<
typename K,
typename T,
typename OPS>
261 std::pair<K, T> udata;
265 entry_t(
const std::pair<K, T> & idata,
hm_int inext) : udata(idata), next(inext) { }
266 entry_t(std::pair<K, T> && idata,
hm_int inext) : udata(std::move(idata)), next(inext) { }
270 std::vector<hm_int> hashtable;
272 std::vector<entry_t> entries;
277 static inline void do_assert(
bool) { }
279 static inline void do_assert(
bool cond) {
280 if (!cond)
throw std::runtime_error(
"unordered_map<> assert failed.");
294 hm_int do_hash(
const K &key)
const
297 if (!hashtable.empty())
298 hash = ops.hash(key) % (
hm_uint)(hashtable.size());
311 do_assert(-1 <= entries[i].next && entries[i].next <
hm_int(entries.size()));
312 hm_int hash = do_hash(entries[i].udata.first);
313 entries[i].next = hashtable[hash];
328 do_assert(index <
hm_int(entries.size()));
329 if (hashtable.empty() || index < 0)
332 hm_int k = hashtable[hash];
333 do_assert(0 <= k && k <
hm_int(entries.size()));
336 hashtable[hash] = entries[index].next;
338 while (entries[k].next != index) {
340 do_assert(0 <= k && k <
hm_int(entries.size()));
342 entries[k].next = entries[index].next;
345 hm_int back_idx = entries.size()-1;
347 if (index != back_idx)
349 hm_int back_hash = do_hash(entries[back_idx].udata.first);
351 k = hashtable[back_hash];
352 do_assert(0 <= k && k <
hm_int(entries.size()));
355 hashtable[back_hash] = index;
357 while (entries[k].next != back_idx) {
359 do_assert(0 <= k && k <
hm_int(entries.size()));
361 entries[k].next = index;
364 entries[index] = std::move(entries[back_idx]);
385 if (hashtable.empty())
393 hm_int index = hashtable[hash];
395 while (index >= 0 && !ops.cmp(entries[index].udata.first, key)) {
396 index = entries[index].next;
397 do_assert(-1 <= index && index <
hm_int(entries.size()));
416 if (hashtable.empty()) {
417 entries.push_back(entry_t(std::pair<K, T>(key, T()), -1));
421 entries.push_back(entry_t(std::pair<K, T>(key, T()), hashtable[hash]));
422 hashtable[hash] = entries.size() - 1;
424 return entries.size() - 1;
438 hm_int do_insert(
const std::pair<K, T> &value,
hm_int &hash)
440 if (hashtable.empty()) {
441 entries.push_back(entry_t(value, -1));
443 hash = do_hash(value.first);
445 entries.push_back(entry_t(value, hashtable[hash]));
446 hashtable[hash] = entries.size() - 1;
448 return entries.size() - 1;
551 entries = other.entries;
562 entries = other.entries;
575 for (
auto &it : list)
580 template<
class InputIterator>
586 template<
class InputIterator>
587 void insert(InputIterator first, InputIterator last)
589 for (; first != last; ++first)
593 std::pair<iterator, bool>
insert(
const K &key)
595 hm_int hash = do_hash(key);
596 hm_int i = do_lookup(key, hash);
598 return std::pair<iterator, bool>(
iterator(
this, i),
false);
599 i = do_insert(key, hash);
600 return std::pair<iterator, bool>(
iterator(
this, i),
true);
603 std::pair<iterator, bool>
insert(
const std::pair<K, T> &value)
605 hm_int hash = do_hash(value.first);
606 hm_int i = do_lookup(value.first, hash);
608 return std::pair<iterator, bool>(
iterator(
this, i),
false);
609 i = do_insert(value, hash);
610 return std::pair<iterator, bool>(
iterator(
this, i),
true);
615 hm_int hash = do_hash(key);
616 hm_int index = do_lookup(key, hash);
617 return do_erase(index, hash);
622 hm_int hash = do_hash(it->first);
623 do_erase(it.
index, hash);
629 hm_int hash = do_hash(key);
630 hm_int i = do_lookup(key, hash);
631 return i < 0 ? 0 : 1;
636 hm_int hash = do_hash(key);
637 hm_int i = do_lookup(key, hash);
638 return i < 0 || i > it.
index ? 0 : 1;
643 hm_int hash = do_hash(key);
644 hm_int i = do_lookup(key, hash);
653 hm_int hash = do_hash(key);
654 hm_int i = do_lookup(key, hash);
663 hm_int hash = do_hash(key);
664 hm_int i = do_lookup(key, hash);
666 throw std::out_of_range(
"unordered_map::at()");
667 return entries[i].udata.second;
671 const T&
at(
const K &key)
const
673 hm_int hash = do_hash(key);
674 hm_int i = do_lookup(key, hash);
676 throw std::out_of_range(
"unordered_map::at()");
677 return entries[i].udata.second;
681 T
at(
const K &key,
const T &defval)
const
683 hm_int hash = do_hash(key);
684 hm_int i = do_lookup(key, hash);
687 return entries[i].udata.second;
693 hm_int hash = do_hash(key);
694 hm_int i = do_lookup(key, hash);
696 i = do_insert(std::pair<K, T>(key, T()), hash);
697 return entries[i].udata.second;
706 template<
typename Compare = std::less<K>>
707 void sort(Compare comp = Compare())
709 std::sort(entries.begin(), entries.end(), [comp](
const entry_t &a,
const entry_t &b){ return comp(b.udata.first, a.udata.first); });
715 hashtable.swap(other.hashtable);
716 entries.swap(other.entries);
722 for (
auto &it : entries) {
723 auto oit = other.
find(it.udata.first);
724 if (oit == other.
end() || !(oit->second == it.udata.second))
734 void reserve(
size_t n) { entries.reserve(n); }
735 size_t size()
const {
return entries.size(); }
736 bool empty()
const {
return entries.empty(); }
737 void clear() { hashtable.clear(); entries.clear(); }
752 template<
typename K,
typename OPS>
755 template<
typename, hm_
int,
typename>
friend class idict;
779 if (!cond)
throw std::runtime_error(
"unordered_set<> assert failed.");
834 while (
entries[k].next != index) {
843 if (index != back_idx)
851 while (
entries[k].next != back_idx) {
889 while (index >= 0 && !
ops.cmp(
entries[index].udata, key)) {
1041 for (
auto &it : list)
1045 template<
class InputIterator>
1051 template<
class InputIterator>
1052 void insert(InputIterator first, InputIterator last)
1054 for (; first != last; ++first)
1058 std::pair<iterator, bool>
insert(
const K &value)
1063 return std::pair<iterator, bool>(
iterator(
this, i),
false);
1065 return std::pair<iterator, bool>(
iterator(
this, i),
true);
1086 return i < 0 ? 0 : 1;
1093 return i < 0 || i > it.
index ? 0 : 1;
1121 template<
typename Compare = std::less<K>>
1122 void sort(Compare comp = Compare())
1146 if (!other.
count(it.udata))
1167 template<
typename K, hm_
int offset,
typename OPS>
1189 throw std::out_of_range(
"idict::at()");
1206 return i < 0 ? 0 : 1;
1213 throw std::out_of_range(
"idict::expect()");
1218 return database.
entries.at(index - offset).udata;
1223 database.
swap(other.database);
1235 template<
typename K,
typename OPS>
1239 mutable std::vector<hm_int> parents;
1246 hm_int i = database(key);
1247 parents.resize(database.
size(), -1);
1253 return database[index];
1260 while (parents[p] != -1)
1264 hm_int next_k = parents[k];
1286 hm_int next_k = parents[k];
1296 return ifind((*
this)(a));
1304 return (*
this)[
ifind(i)];
1309 imerge((*
this)(a), (*
this)(b));
1321 database.
swap(other.database);
1322 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)