blob: 5c521faba626f4eadbed2f6a14cf8a4680ce5b2a [file] [log] [blame]
#pragma once
#include <array>
#include <cstddef>
#include <tuple>
#include <utility>
namespace std
{
template <class Key>
struct hash;
}
namespace stdplus
{
template <class Key>
struct hash;
namespace detail
{
constexpr std::size_t updateSeed(std::size_t seed, std::size_t v) noexcept
{
return seed ^ (v + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}
template <typename T>
constexpr std::size_t
hashMultiS(std::size_t seed,
const T& t) noexcept(noexcept(hash<T>{}(std::declval<T>())))
{
return updateSeed(seed, hash<T>{}(t));
}
template <typename T, typename... Ts>
constexpr std::size_t
hashMultiS(std::size_t seed, const T& t, const Ts&... ts) noexcept(
(noexcept(hashMultiS(0, std::declval<T>())) &&
...&& noexcept(hashMultiS(0, std::declval<Ts>()))))
{
return hashMultiS(hashMultiS(seed, t), ts...);
}
} // namespace detail
constexpr std::size_t hashMulti() noexcept
{
return 0;
}
template <typename T>
constexpr std::size_t
hashMulti(const T& t) noexcept(noexcept(hash<T>{}(std::declval<T>())))
{
return hash<T>{}(t);
}
template <typename T, typename... Ts>
constexpr std::size_t hashMulti(const T& t, const Ts&... ts) noexcept(
noexcept(hashMulti(std::declval<T>())) && noexcept(
detail::hashMultiS(0, std::declval<Ts>()...)))
{
return detail::hashMultiS(hashMulti(t), ts...);
}
namespace detail
{
template <typename T>
constexpr std::size_t
hashArr(std::size_t seed, const T* ts,
std::size_t n) noexcept(noexcept(hashMulti(std::declval<T>())))
{
if (n == 1)
{
return updateSeed(seed, hashMulti(*ts));
}
return hashArr(updateSeed(seed, hashMulti(*ts)), ts + 1, n - 1);
}
template <typename T>
constexpr std::size_t
hashArr(const T* ts,
std::size_t n) noexcept(noexcept(hashMulti(std::declval<T>())))
{
if (n == 0)
{
return 0;
}
if (n == 1)
{
return hashMulti(*ts);
}
return hashArr(hashMulti(*ts), ts + 1, n - 1);
}
} // namespace detail
template <class Key>
struct hash : std::hash<Key>
{};
template <typename T, std::size_t N>
struct hash<std::array<T, N>>
{
constexpr std::size_t operator()(const std::array<T, N>& a) noexcept(
noexcept(hashMulti(std::declval<T>())))
{
return detail::hashArr(a.data(), N);
}
};
template <typename T, std::size_t N>
struct hash<T[N]>
{
constexpr std::size_t operator()(const T (&a)[N]) noexcept(
noexcept(hashMulti(std::declval<T>())))
{
return detail::hashArr(a, N);
}
};
template <typename... Ts>
struct hash<std::tuple<Ts...>>
{
constexpr std::size_t operator()(const std::tuple<Ts...>& ts) noexcept(
noexcept(hashMulti(std::declval<Ts>()...)))
{
return std::apply(hashMulti<Ts...>, ts);
}
};
} // namespace stdplus