13#if !defined(VITA_CACHE_HASH_H)
14#define VITA_CACHE_HASH_H
28 explicit hash_t(std::uint64_t a = 0, std::uint64_t b = 0) : data{a, b} {}
31 void clear() { data[0] = data[1] = 0; }
35 {
return data[0] == h.data[0] && data[1] == h.data[1]; }
39 {
return data[0] != h.data[0] || data[1] != h.data[1]; }
52 data[0] = data[0] * 37 + h.data[0];
53 data[1] = data[1] * 37 + h.data[1];
61 bool empty()
const {
return !data[0] && !data[1]; }
64 bool load(std::istream &);
65 bool save(std::ostream &)
const;
68 std::uint_least64_t data[2];
71std::ostream &
operator<<(std::ostream &, hash_t);
74# define ROTL64(x, y) _rotl64(x, y)
82inline std::uint64_t
rotl64(std::uint64_t x, std::uint8_t r)
84 return (x << r) | (x >> (64 - r));
86#define ROTL64(x, y) rotl64(x, y)
103 static hash_t hash128(
const void *
const, std::size_t, std::uint32_t = 1973);
106 static std::uint64_t fmix(std::uint64_t);
107 static std::uint32_t fmix(std::uint32_t);
108 template<
class T>
static T get_block(
const T *, std::size_t);
122 const auto n_blocks(len / 16);
124 const std::uint64_t c1(0x87c37b91114253d5), c2(0x4cf5ad432745937f);
127 const auto *blocks(
reinterpret_cast<const std::uint64_t *
>(data));
130 for (std::size_t i(0); i < n_blocks; ++i)
132 std::uint64_t k1(get_block(blocks, i * 2 + 0));
133 std::uint64_t k2(get_block(blocks, i * 2 + 1));
140 h.data[0] = ROTL64(h.data[0], 27);
141 h.data[0] += h.data[1];
142 h.data[0] = h.data[0] * 5 + 0x52dce729;
149 h.data[1] = ROTL64(h.data[1], 31);
150 h.data[1] += h.data[0];
151 h.data[1] = h.data[1] * 5 + 0x38495ab5;
155 auto tail(
reinterpret_cast<const std::byte *
>(data) + n_blocks * 16);
157 std::uint64_t k1(0), k2(0);
161 case 15: k2 ^= std::uint64_t(tail[14]) << 48; [[fallthrough]];
162 case 14: k2 ^= std::uint64_t(tail[13]) << 40; [[fallthrough]];
163 case 13: k2 ^= std::uint64_t(tail[12]) << 32; [[fallthrough]];
164 case 12: k2 ^= std::uint64_t(tail[11]) << 24; [[fallthrough]];
165 case 11: k2 ^= std::uint64_t(tail[10]) << 16; [[fallthrough]];
166 case 10: k2 ^= std::uint64_t(tail[ 9]) << 8; [[fallthrough]];
167 case 9: k2 ^= std::uint64_t(tail[ 8]) << 0;
168 k2 *= c2; k2 = ROTL64(k2, 33); k2 *= c1; h.data[1] ^= k2;
170 case 8: k1 ^= std::uint64_t(tail[ 7]) << 56; [[fallthrough]];
171 case 7: k1 ^= std::uint64_t(tail[ 6]) << 48; [[fallthrough]];
172 case 6: k1 ^= std::uint64_t(tail[ 5]) << 40; [[fallthrough]];
173 case 5: k1 ^= std::uint64_t(tail[ 4]) << 32; [[fallthrough]];
174 case 4: k1 ^= std::uint64_t(tail[ 3]) << 24; [[fallthrough]];
175 case 3: k1 ^= std::uint64_t(tail[ 2]) << 16; [[fallthrough]];
176 case 2: k1 ^= std::uint64_t(tail[ 1]) << 8; [[fallthrough]];
177 case 1: k1 ^= std::uint64_t(tail[ 0]) << 0;
178 k1 *= c1; k1 = ROTL64(k1, 31); k1 *= c2; h.data[0] ^= k1;
185 h.data[0] += h.data[1];
186 h.data[1] += h.data[0];
188 h.data[0] = fmix(h.data[0]);
189 h.data[1] = fmix(h.data[1]);
191 h.data[0] += h.data[1];
192 h.data[1] += h.data[0];
197inline std::uint64_t murmurhash3::fmix(std::uint64_t k)
201 k *= 0xff51afd7ed558ccd;
203 k *= 0xc4ceb9fe1a85ec53;
209inline std::uint32_t murmurhash3::fmix(std::uint32_t k)
222inline T murmurhash3::get_block(
const T *p, std::size_t i)
228 std::memcpy(&tmp, p + i,
sizeof(T));
232typedef murmurhash3 hash;
MurmurHash3 (https://github.com/aappleby/smhasher) by Austin Appleby.
static hash_t hash128(const void *const, std::size_t, std::uint32_t=1973)
Hashes a single message in one call, return 128-bit output.
The main namespace for the project.
std::uint64_t rotl64(std::uint64_t x, std::uint8_t r)
std::ostream & operator<<(std::ostream &o, hash_t h)
Mainly useful for debugging / testing.
A 128bit unsigned integer used as individual's signature / hash table look-up key.
bool empty() const
We assume that a string of 128 zero bits means empty.
bool operator!=(hash_t h) const
Standard inequality operator for hash signature.
bool save(std::ostream &) const
bool operator==(hash_t h) const
Standard equality operator for hash signature.
void clear()
Resets the content of the object.
bool load(std::istream &)
void combine(hash_t h)
Used to combine multiple hashes.