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 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 {