17constexpr uint32_t PRIME32_1 = UINT32_C(0x9E3779B1);
18constexpr uint32_t PRIME32_2 = UINT32_C(0x85EBCA77);
19constexpr uint32_t PRIME32_3 = UINT32_C(0xC2B2AE3D);
21constexpr uint64_t PRIME64_1 = UINT64_C(11400714785074694791);
22constexpr uint64_t PRIME64_2 = UINT64_C(14029467366897019727);
23constexpr uint64_t PRIME64_3 = UINT64_C(1609587929392839161);
24constexpr uint64_t PRIME64_4 = UINT64_C(9650029242287828579);
25constexpr uint64_t PRIME64_5 = UINT64_C(2870177450012600261);
27constexpr uint64_t PRIME_MX1 = UINT64_C(0x165667919E3779F9);
28constexpr uint64_t PRIME_MX2 = UINT64_C(0x9FB21C651E98DF25);
30static constexpr uint32_t XXH32_avalanche(uint32_t hash) {
39static constexpr uint64_t XXH64_avalanche(uint64_t hash) {
48static constexpr uint64_t rotl64(uint64_t X,
size_t R) {
return (X << R) | (X >> (64 - R)); }
50static constexpr uint64_t XXH3_rrmxmx(uint64_t acc, uint64_t len) {
51 acc ^= rotl64(acc, 49) ^ rotl64(acc, 24);
53 acc ^= (acc >> 35) + len;
55 return acc ^ (acc >> 28);
58template <
typename Int>
60 constexpr size_t operator()(
const Int &i)
const noexcept {
61 static_assert(
sizeof(Int) <= 16,
"unsupported input type");
62 if constexpr (
sizeof(Int) <= 4) {
63 return static_cast<size_t>(XXH32_avalanche(
static_cast<uint32_t
>(i)));
64 }
else if constexpr (
sizeof(Int) <= 8) {
65 return static_cast<size_t>(XXH64_avalanche(
static_cast<uint64_t
>(i)));
67 using unsigned_type = std::make_unsigned_t<Int>;
68 auto const u =
static_cast<unsigned_type
>(i);
69 auto const hi =
static_cast<uint64_t
>(u >>
sizeof(Int) * 4);
70 auto const lo =
static_cast<uint64_t
>(u);
71 return static_cast<size_t>(XXH3_rrmxmx(hi, lo));
76template <
typename Float>
78 size_t operator()(
const Float &f)
const noexcept {
79 static_assert(
sizeof(Float) <= 8,
"unsupported input type");
82 if (f == Float{})
return 0;
85 memcpy(&u64, &f,
sizeof(Float));
86 return static_cast<size_t>(XXH64_avalanche(u64));
93 size_t operator()(
const T &t)
const noexcept(
noexcept(std::hash<T>()(t))) {
94 return std::hash<T>()(t);
99uint64_t hash(
const void *data, std::size_t size);
101static inline uint64_t hash_avalanche(uint64_t hash) {
return Detail::XXH64_avalanche(hash); }
103static inline uint64_t hash_combine(uint64_t lhs, uint64_t rhs) {
104 return Detail::XXH3_rrmxmx(lhs, rhs);
108auto hash(
const T &obj) ->
decltype(hash(obj.data(), obj.size())) {
109 return hash(obj.data(), obj.size());
122template <
class Key,
class Enable =
void>
127 constexpr size_t operator()(
const T &v)
const noexcept(
noexcept(
Hasher<T>()(v))) {
131 template <
class T,
class... Types>
132 constexpr size_t operator()(
const T &t,
const Types &...ts)
const {
133 return hash_combine((*
this)(t), (*
this)(ts...));
136 constexpr size_t operator()()
const noexcept {
return 0; }
141 constexpr size_t operator()(
bool val)
const noexcept {
142 return val ? std::numeric_limits<size_t>::max() : 0;
187 size_t operator()(
const std::string &val)
const {
188 return static_cast<size_t>(hash(val.data(), val.size()));
194 size_t operator()(
const std::string_view &val)
const {
195 return static_cast<size_t>(hash(val.data(), val.size()));
199template <
typename T1,
typename T2>
201 size_t operator()(
const std::pair<T1, T2> &val)
const {
return Hash()(val.first, val.second); }
203template <
typename... Types>
205 size_t operator()(
const std::tuple<Types...> &val)
const {
return apply(
Hash(), val); }
216 size_t operator()(T *val)
const {
return Hash()(
reinterpret_cast<std::uintptr_t
>(val)); }
221 size_t operator()(
const std::unique_ptr<T> &val)
const {
return Hash()(val.get()); }
226 size_t operator()(
const std::shared_ptr<T> &val)
const {
return Hash()(val.get()); }
236template <class Iter, class Hash = std::hash<typename std::iterator_traits<Iter>::value_type>>
237uint64_t hash_range(Iter begin, Iter end, uint64_t hash = 0,
Hash Hasher =
Hash()) {
238 for (; begin != end; ++begin) hash = hash_combine(hash,
Hasher(*begin));
243template <
class Hasher>
244inline size_t hash_combine_generic(
const Hasher &)
noexcept {
248template <
class Hasher,
typename T,
typename... Types>
249size_t hash_combine_generic(
const Hasher &h,
const T &t,
const Types &...ts) {
251 if (
sizeof...(ts) == 0)
return seed;
253 size_t remainder = hash_combine_generic(h, ts...);
254 if constexpr (
sizeof(size_t) ==
sizeof(uint32_t))
255 return static_cast<size_t>(
256 hash_combine(
static_cast<uint64_t
>(seed) << 32,
static_cast<uint64_t
>(remainder)));
258 return static_cast<size_t>(hash_combine(seed, remainder));
261template <
typename T,
typename... Types>
262size_t hash_combine(
const T &t,
const Types &...ts) {
263 return hash_combine_generic(Detail::StdHasher{}, t, ts...);
267template <
size_t index,
typename... Types>
269 size_t operator()(std::tuple<Types...>
const &val)
const {
274template <
typename... Types>
276 size_t operator()(std::tuple<Types...>
const &val)
const {
277 return hash_combine(std::get<0>(val));
284template <
typename T1,
typename T2>
285struct hash<
std::pair<T1, T2>> {
286 size_t operator()(
const std::pair<T1, T2> &x)
const {
287 return P4::Util::hash_combine(x.first, x.second);
291template <
typename... Types>
292struct hash<
std::tuple<Types...>> {
294 size_t operator()(std::tuple<Types...>
const &key)
const {