|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
#include <math/eigen_alias.hpp>
|
|
|
|
|
|
|
|
|
|
#include <xxhash.h>
|
|
|
|
|
|
|
|
|
|
namespace detail
|
|
|
|
|
{
|
|
|
|
|
template <typename T>
|
|
|
|
|
struct float_to_int_type {
|
|
|
|
|
static_assert(std::is_floating_point_v<T>, "T must be a floating point type");
|
|
|
|
|
using type = std::conditional_t<sizeof(T) == 4, uint32_t, uint64_t>;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static constexpr float float_hash_epsilon = 1e-6f;
|
|
|
|
|
} // namespace detail
|
|
|
|
|
|
|
|
|
|
static inline void hash_combine(size_t &seed, uint32_t value)
|
|
|
|
|
{
|
|
|
|
|
seed = seed ^ (std::hash<uint32_t>()(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void hash_combine(uint64_t &seed, uint64_t value)
|
|
|
|
|
{
|
|
|
|
|
seed = seed ^ (std::hash<uint64_t>()(value) + 0x9e3779b97f4a7c15ULL + (seed << 12) + (seed >> 4));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename... InputTypes>
|
|
|
|
|
static inline size_t hash_combine(size_t seed, InputTypes... values)
|
|
|
|
|
{
|
|
|
|
|
(hash_combine(seed, values), ...);
|
|
|
|
|
return seed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct hash_funcs_fn {
|
|
|
|
|
template <typename T, int M, int N>
|
|
|
|
|
size_t operator()(const Eigen::Matrix<T, M, N> &mat, double epsilon = detail::float_hash_epsilon) const
|
|
|
|
|
{
|
|
|
|
|
static_assert(M != Eigen::Dynamic && N != Eigen::Dynamic, "only fixed size matrix is supported");
|
|
|
|
|
|
|
|
|
|
if constexpr (std::is_integral_v<T>)
|
|
|
|
|
return XXH3_64bits(mat.data(), sizeof(T) * M * N);
|
|
|
|
|
else if constexpr (std::is_floating_point_v<T>) {
|
|
|
|
|
using integral_type = typename detail::float_to_int_type<T>::type;
|
|
|
|
|
Eigen::Matrix<integral_type, M, N> int_mat = (mat.array() / static_cast<T>(epsilon)).template cast<integral_type>();
|
|
|
|
|
return XXH3_64bits(int_mat.data(), sizeof(integral_type) * M * N);
|
|
|
|
|
} else
|
|
|
|
|
static_assert(false, "unsupported type in hash<Eigen::Matrix>");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T, int N>
|
|
|
|
|
size_t operator()(const Eigen::Transform<T, N, Eigen::AffineCompact> &trans,
|
|
|
|
|
double epsilon = detail::float_hash_epsilon) const
|
|
|
|
|
{
|
|
|
|
|
if constexpr (std::is_integral_v<T>)
|
|
|
|
|
return XXH3_64bits(trans.data(), sizeof(T) * N * (N + 1));
|
|
|
|
|
else if constexpr (std::is_floating_point_v<T>) {
|
|
|
|
|
using integral_type = typename detail::float_to_int_type<T>::type;
|
|
|
|
|
Eigen::Matrix<integral_type, N, N + 1> int_mat =
|
|
|
|
|
(trans.affine().array() / static_cast<T>(epsilon)).template cast<integral_type>();
|
|
|
|
|
return XXH3_64bits(int_mat.data(), sizeof(integral_type) * N * (N + 1));
|
|
|
|
|
} else
|
|
|
|
|
static_assert(false, "unsupported type in hash<Eigen::Matrix>");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
size_t operator()(std::reference_wrapper<T> ref) const
|
|
|
|
|
{
|
|
|
|
|
return size_t(std::addressof(ref.get()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
size_t operator()(std::reference_wrapper<const T> ref) const
|
|
|
|
|
{
|
|
|
|
|
return size_t(std::addressof(ref.get()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename InputIt>
|
|
|
|
|
size_t operator()(InputIt first, InputIt last) const
|
|
|
|
|
{
|
|
|
|
|
using T = std::decay<InputIt>;
|
|
|
|
|
return XXH3_64bits(&*first, std::distance(first, last) * sizeof(T));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static constexpr hash_funcs_fn hash_funcs{};
|