psemek/libs/util/include/psemek/util/hash.hpp

85 lines
1.8 KiB
C++

#pragma once
#include <functional>
#include <tuple>
namespace psemek::util
{
constexpr void hash_combine(std::size_t & seed, std::size_t value)
{
constexpr std::size_t k = 0x9ddfea08eb382d69ULL;
std::size_t a = (value ^ seed) * k;
a ^= (a >> 47);
std::size_t b = (seed ^ a) * k;
b ^= (b >> 47);
seed = b * k;
}
template <typename Iterator, typename Hash = std::hash<std::decay_t<decltype(*std::declval<Iterator>())>>>
constexpr void hash_sequence(std::size_t & seed, Iterator begin, Iterator end, Hash hash = Hash{})
{
for (; begin != end; ++begin)
{
hash_combine(seed, hash(*begin));
}
}
struct any_hash
{
struct is_transparent{};
template <typename T>
std::size_t operator() (T const & x) const
{
return std::hash<T>{}(x);
}
};
template <typename ... T>
constexpr std::size_t hash_all(T const & ... x)
{
any_hash hash;
std::size_t seed = 0;
(hash_combine(seed, hash(x)), ...);
return seed;
}
}
namespace std
{
template <typename T, typename H>
struct hash<std::pair<T, H>>
: std::pair<std::hash<T>, std::hash<H>>
{
std::size_t operator()(std::pair<T, H> const & x) const
{
std::size_t seed = 0;
::psemek::util::hash_combine(seed, this->first(x.first));
::psemek::util::hash_combine(seed, this->second(x.second));
return seed;
}
};
template <typename ... Ts>
struct hash<std::tuple<Ts...>>
: std::tuple<std::hash<Ts>...>
{
std::size_t operator()(std::tuple<Ts...> const & t) const
{
return hash_impl(t, std::make_index_sequence<sizeof...(Ts)>{});
}
private:
template <std::size_t ... Is>
std::size_t hash_impl(std::tuple<Ts...> const & t, std::index_sequence<Is...>) const
{
std::size_t result = 0;
(::psemek::util::hash_combine(result, std::get<Is>(*this)(std::get<Is>(t))), ...);
return result;
}
};
}