cai_lw's competitive programming library
 
Loading...
Searching...
No Matches
wyhash.hpp
1#include <cstdint>
2#include <cstring>
3#include <random>
4#include <string>
5
6namespace cplib {
7
8namespace impl {
9/* wyhash.h adopted from https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h
10 * by removing code for other platforms, only leaving support for x86_64 gcc.
11 */
12
13// 128bit multiply function
14static inline void _wymum(uint64_t* A, uint64_t* B) {
15 __uint128_t r = *A;
16 r *= *B;
17 *A = (uint64_t)r;
18 *B = (uint64_t)(r >> 64);
19}
20
21// multiply and xor mix function, aka MUM
22static inline uint64_t _wymix(uint64_t A, uint64_t B) {
23 _wymum(&A, &B);
24 return A ^ B;
25}
26
27// read functions
28static inline uint64_t _wyr8(const uint8_t* p) {
29 uint64_t v;
30 memcpy(&v, p, 8);
31 return v;
32}
33static inline uint64_t _wyr4(const uint8_t* p) {
34 uint32_t v;
35 memcpy(&v, p, 4);
36 return v;
37}
38static inline uint64_t _wyr3(const uint8_t* p, size_t k) {
39 return (((uint64_t)p[0]) << 16) | (((uint64_t)p[k >> 1]) << 8) | p[k - 1];
40}
41
42// wyhash main function
43static inline uint64_t wyhash(const void* key, size_t len, uint64_t seed, const uint64_t* secret) {
44 const uint8_t* p = (const uint8_t*)key;
45 seed ^= *secret;
46 uint64_t a, b;
47 if (__builtin_expect(len <= 16, true)) {
48 if (__builtin_expect(len >= 4, true)) {
49 a = (_wyr4(p) << 32) | _wyr4(p + ((len >> 3) << 2));
50 b = (_wyr4(p + len - 4) << 32) | _wyr4(p + len - 4 - ((len >> 3) << 2));
51 } else if (__builtin_expect(len > 0, true)) {
52 a = _wyr3(p, len);
53 b = 0;
54 } else
55 a = b = 0;
56 } else {
57 size_t i = len;
58 if (__builtin_expect(i > 48, false)) {
59 uint64_t see1 = seed, see2 = seed;
60 do {
61 seed = _wymix(_wyr8(p) ^ secret[1], _wyr8(p + 8) ^ seed);
62 see1 = _wymix(_wyr8(p + 16) ^ secret[2], _wyr8(p + 24) ^ see1);
63 see2 = _wymix(_wyr8(p + 32) ^ secret[3], _wyr8(p + 40) ^ see2);
64 p += 48;
65 i -= 48;
66 } while (__builtin_expect(i > 48, true));
67 seed ^= see1 ^ see2;
68 }
69 while (__builtin_expect(i > 16, false)) {
70 seed = _wymix(_wyr8(p) ^ secret[1], _wyr8(p + 8) ^ seed);
71 i -= 16;
72 p += 16;
73 }
74 a = _wyr8(p + i - 16);
75 b = _wyr8(p + i - 8);
76 }
77 return _wymix(secret[1] ^ len, _wymix(a ^ secret[1], b ^ seed));
78}
79
80// the default secret parameters
81static const uint64_t _wyp[4] = {0xa0761d6478bd642full, 0xe7037ed1a0b428dbull, 0x8ebc6af09c88c6e3ull,
82 0x589965cc75374cc3ull};
83
84// a useful 64bit-64bit mix function to produce deterministic pseudo random numbers that can pass BigCrush and PractRand
85static inline uint64_t wyhash64(uint64_t A, uint64_t B) {
86 A ^= 0xa0761d6478bd642full;
87 B ^= 0xe7037ed1a0b428dbull;
88 _wymum(&A, &B);
89 return _wymix(A ^ 0xa0761d6478bd642full, B ^ 0xe7037ed1a0b428dbull);
90}
91
92/* end of wyhash.h */
93
94uint64_t gen_random_seed() {
95 std::random_device rd;
96 std::uniform_int_distribution<uint64_t> dis(0, std::numeric_limits<uint64_t>::max());
97 return dis(rd);
98}
99
100} // namespace impl
101
118static inline uint64_t wyhash_bytes(const void* key, size_t len) {
119 static const uint64_t seed = impl::gen_random_seed();
120 return impl::wyhash(key, len, seed, impl::_wyp);
121}
122
135static inline uint64_t wyhash_combine(uint64_t a, uint64_t b) { return impl::wyhash64(a, b); }
136
147template <typename T>
148struct WyHash {};
149
151template <>
152struct WyHash<std::string> {
153 size_t operator()(const std::string& s) const { return wyhash_bytes(s.c_str(), s.size()); }
154};
155
161template <typename T1, typename T2>
162struct WyHash<std::pair<T1, T2>> {
163 WyHash<T1> first_hash;
164 WyHash<T2> second_hash;
165 size_t operator()(const std::pair<T1, T2>& p) const {
166 return wyhash_combine(first_hash(p.first), second_hash(p.second));
167 }
168};
169
170#define _wyhash_for_integral_type(T) \
171 template <> \
172 struct WyHash<T> { \
173 size_t operator()(T t) const { return wyhash_bytes((void*)&t, sizeof(T)); } \
174 }
175
176_wyhash_for_integral_type(bool);
177_wyhash_for_integral_type(char);
178_wyhash_for_integral_type(unsigned char);
179_wyhash_for_integral_type(signed char);
180_wyhash_for_integral_type(short);
181_wyhash_for_integral_type(unsigned short);
182_wyhash_for_integral_type(int);
183_wyhash_for_integral_type(unsigned int);
184_wyhash_for_integral_type(long);
185_wyhash_for_integral_type(unsigned long);
186_wyhash_for_integral_type(long long);
187_wyhash_for_integral_type(unsigned long long);
188
189#undef _wyhash_for_integral_type
190
191} // namespace cplib
static uint64_t wyhash_combine(uint64_t a, uint64_t b)
Combine two hash values to produce a new hash value.
Definition: wyhash.hpp:135
static uint64_t wyhash_bytes(const void *key, size_t len)
Hash function for arbitrary bytes using wyhash.
Definition: wyhash.hpp:118
Hash function class like std::hash but uses wyhash.
Definition: wyhash.hpp:148