43 using uint128_t = std::array<std::uint64_t, 2>;
45 static constexpr std::uint64_t k0 = 0xc3a5c85c97cb3127ULL;
46 static constexpr std::uint64_t k1 = 0xb492b66fbe98f273ULL;
47 static constexpr std::uint64_t k2 = 0x9ae16a3b2f90404fULL;
50 template<std::
unsigned_
integral T>
51 constexpr T UnalignedLoad(std::span<const std::uint8_t> bytes)
54 if (std::is_constant_evaluated()) {
55 for (
size_t i = 0; i <
sizeof(T); ++i) {
60 std::memcpy(&result, bytes.data(),
sizeof(T));
66 template<std::
unsigned_
integral T>
67 constexpr T Fetch(std::span<const std::uint8_t> bytes)
69 return SwapBytes(UnalignedLoad<T>(bytes));
72 constexpr std::uint64_t Rotate(std::uint64_t val,
int shift)
74 return shift == 0 ? val : ((val >> shift) | (val << ((
sizeof(std::uint64_t) * 8) - shift)));
77 constexpr std::uint64_t ShiftMix(std::uint64_t val) {
return val ^ (val >> 47); }
79 constexpr std::uint64_t Hash128to64(
const uint128_t& x)
81 constexpr std::uint64_t kMul = 0x9ddfea08eb382d69ULL;
82 std::uint64_t a = (x[0] ^ x[1]) * kMul;
84 std::uint64_t b = (x[1] ^ a) * kMul;
90 constexpr std::uint64_t HashLen16(std::uint64_t u, std::uint64_t v)
92 return Hash128to64(uint128_t{ u, v });
95 constexpr std::uint64_t HashLen16(std::uint64_t u, std::uint64_t v, std::uint64_t mul)
98 std::uint64_t a = (u ^ v) * mul;
100 std::uint64_t b = (v ^ a) * mul;
106 constexpr std::uint64_t HashLen0to16(std::span<const std::uint8_t> bytes)
108 const std::size_t len = bytes.size();
111 std::uint64_t mul = k2 + len * 2;
112 std::uint64_t a = Fetch<std::uint64_t>(bytes) + k2;
113 std::uint64_t b = Fetch<std::uint64_t>(bytes.subspan(len - 8));
114 std::uint64_t c = Rotate(b, 37) * mul + a;
115 std::uint64_t d = (Rotate(a, 25) + b) * mul;
116 return HashLen16(c, d, mul);
119 std::uint64_t mul = k2 + len * 2;
120 std::uint64_t a = Fetch<std::uint32_t>(bytes);
121 return HashLen16(len + (a << 3), Fetch<std::uint32_t>(bytes.subspan(len - 4)), mul);
124 std::uint8_t a =
static_cast<std::uint8_t
>(bytes[0]);
125 std::uint8_t b =
static_cast<std::uint8_t
>(bytes[len >> 1]);
126 std::uint8_t c =
static_cast<std::uint8_t
>(bytes[len - 1]);
127 std::uint32_t y =
static_cast<std::uint32_t
>(a) + (
static_cast<std::uint32_t
>(b) << 8);
128 std::uint32_t z =
static_cast<std::uint32_t
>(len) + (
static_cast<std::uint32_t
>(c) << 2);
129 return ShiftMix(y * k2 ^ z * k0) * k2;
134 constexpr std::uint64_t HashLen17to32(std::span<const std::uint8_t> bytes)
136 const std::size_t len = bytes.size();
138 std::uint64_t mul = k2 + len * 2;
139 std::uint64_t a = Fetch<std::uint64_t>(bytes) * k1;
140 std::uint64_t b = Fetch<std::uint64_t>(bytes.subspan(8));
141 std::uint64_t c = Fetch<std::uint64_t>(bytes.subspan(len - 8)) * mul;
142 std::uint64_t d = Fetch<std::uint64_t>(bytes.subspan(len - 16)) * k2;
143 return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d, a + Rotate(b + k2, 18) + c, mul);
146 constexpr uint128_t WeakHashLen32WithSeeds(std::uint64_t w,
154 b = Rotate(b + a + z, 21);
159 return { a + z, b + c };
162 constexpr uint128_t WeakHashLen32WithSeeds(std::span<const std::uint8_t> bytes,
166 return WeakHashLen32WithSeeds(Fetch<std::uint64_t>(bytes),
167 Fetch<std::uint64_t>(bytes.subspan(8)),
168 Fetch<std::uint64_t>(bytes.subspan(16)),
169 Fetch<std::uint64_t>(bytes.subspan(24)),
174 constexpr std::uint64_t HashLen33to64(std::span<const std::uint8_t> bytes)
176 const std::size_t len = bytes.size();
177 std::uint64_t mul = k2 + len * 2;
178 std::uint64_t a = Fetch<std::uint64_t>(bytes) * k2;
179 std::uint64_t b = Fetch<std::uint64_t>(bytes.subspan(8));
180 std::uint64_t c = Fetch<std::uint64_t>(bytes.subspan(len - 24));
181 std::uint64_t d = Fetch<std::uint64_t>(bytes.subspan(len - 32));
182 std::uint64_t e = Fetch<std::uint64_t>(bytes.subspan(16)) * k2;
183 std::uint64_t f = Fetch<std::uint64_t>(bytes.subspan(24)) * 9;
184 std::uint64_t g = Fetch<std::uint64_t>(bytes.subspan(len - 8));
185 std::uint64_t h = Fetch<std::uint64_t>(bytes.subspan(len - 16)) * mul;
186 std::uint64_t u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9;
187 std::uint64_t v = ((a + g) ^ d) + f + 1;
188 std::uint64_t w = SwapBytes((u + v) * mul) + h;
189 std::uint64_t x = Rotate(e + f, 42) + c;
190 std::uint64_t y = (SwapBytes((v + w) * mul) + g) * mul;
191 std::uint64_t z = e + f + c;
193 a = SwapBytes((x + z) * mul + y) + b;
194 b = ShiftMix((z + a) * mul + d + h) * mul;
200 constexpr std::uint64_t
operator()(std::span<const std::uint8_t> bytes)
202 std::size_t len = bytes.size();
205 return HashLen0to16(bytes);
206 }
else if (len <= 32) {
207 return HashLen17to32(bytes);
208 }
else if (len <= 64) {
209 return HashLen33to64(bytes);
214 std::uint64_t x = Fetch<std::uint64_t>(bytes.subspan(len - 40));
216 Fetch<std::uint64_t>(bytes.subspan(len - 16)) + Fetch<std::uint64_t>(bytes.subspan(len - 56));
217 std::uint64_t z = HashLen16(Fetch<std::uint64_t>(bytes.subspan(len - 48)) + len,
218 Fetch<std::uint64_t>(bytes.subspan(len - 24)));
219 uint128_t v = WeakHashLen32WithSeeds(bytes.subspan(len - 64), len, z);
220 uint128_t w = WeakHashLen32WithSeeds(bytes.subspan(len - 32), y + k1, x);
221 x = x * k1 + Fetch<std::uint64_t>(bytes);
224 len = (len - 1) & ~
static_cast<size_t>(63);
226 x = Rotate(x + y + v[0] + Fetch<std::uint64_t>(bytes.subspan(8)), 37) * k1;
227 y = Rotate(y + v[1] + Fetch<std::uint64_t>(bytes.subspan(48)), 42) * k1;
229 y += v[0] + Fetch<std::uint64_t>(bytes.subspan(40));
230 z = Rotate(z + w[0], 33) * k1;
231 v = WeakHashLen32WithSeeds(bytes, v[1] * k1, x + w[0]);
233 WeakHashLen32WithSeeds(bytes.subspan(32), z + w[1], y + Fetch<std::uint64_t>(bytes.subspan(16)));
235 bytes = bytes.subspan(64);
239 return HashLen16(HashLen16(v[0], w[0]) + ShiftMix(y) * k1 + z, HashLen16(v[1], w[1]) + x);