|
|
@@ -8,6 +8,7 @@
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
+#include <cstdint>
|
|
|
#include <tuple>
|
|
|
#include <utility>
|
|
|
|
|
|
@@ -17,40 +18,43 @@ template <typename, typename> class identity;
|
|
|
struct ::std::hash<T> \
|
|
|
: public ::std::hash<identity<T, decltype(std::declval<T>().id)>> {}
|
|
|
|
|
|
-namespace std {
|
|
|
-template <typename T, typename I> struct hash<identity<T, I>> {
|
|
|
- std::size_t operator()(identity<T, I> tp) const {
|
|
|
- return std::hash<I>()(tp.id);
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-template <typename T, typename S> struct hash<std::pair<T, S>> {
|
|
|
- std::size_t operator()(std::pair<T, S> const & pair) const {
|
|
|
- return std::hash<T>()(pair.first) ^ std::hash<S>()(pair.second);
|
|
|
- }
|
|
|
-};
|
|
|
+namespace detail {
|
|
|
+// Code from boost
|
|
|
+// Reciprocal of the golden ratio helps spread entropy
|
|
|
+// and handles duplicates.
|
|
|
+// See Mike Seymour in magic-numbers-in-boosthash-combine:
|
|
|
+// http://stackoverflow.com/questions/4948780
|
|
|
+template <typename T> void hash_combine(size_t & seed, T const & v) {
|
|
|
+ seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
|
+}
|
|
|
|
|
|
-template <std::size_t I> struct tuple_hash;
|
|
|
+template <typename T, size_t... Is>
|
|
|
+void hash_combine(size_t & seed, T const & tuple, std::index_sequence<Is...>) {
|
|
|
+ // Expansion trick
|
|
|
+ [[maybe_unused]] int _[] = {(hash_combine(seed, std::get<Is>(tuple)), 0),
|
|
|
+ ...};
|
|
|
+}
|
|
|
+}
|
|
|
|
|
|
-template <> struct tuple_hash<0> {
|
|
|
- template <typename... As>
|
|
|
- std::size_t operator()(std::tuple<As...> const &) const {
|
|
|
- return 0;
|
|
|
+template <typename T, typename I> struct std::hash<identity<T, I>> {
|
|
|
+ std::size_t operator()(identity<T, I> tp) const {
|
|
|
+ return std::hash<I>()(tp.id);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-template <std::size_t I> struct tuple_hash {
|
|
|
- template <typename... As>
|
|
|
- std::size_t operator()(std::tuple<As...> const & tuple) const {
|
|
|
- using elt = typename std::tuple_element<I - 1, std::tuple<As...>>::type;
|
|
|
- return std::hash<elt>()(std::get<I - 1>(tuple)) ^
|
|
|
- tuple_hash<I - 1>()(tuple);
|
|
|
+template <typename T, typename S> struct std::hash<std::pair<T, S>> {
|
|
|
+ size_t operator()(std::pair<T, S> const & pair) const {
|
|
|
+ size_t seed = 0;
|
|
|
+ detail::hash_combine(seed, pair, std::make_index_sequence<2>{});
|
|
|
+ return seed;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-template <typename... As> struct hash<std::tuple<As...>> {
|
|
|
- std::size_t operator()(std::tuple<As...> const & tuple) const {
|
|
|
- return tuple_hash<sizeof...(As)>()(tuple);
|
|
|
+template <typename... As> struct std::hash<std::tuple<As...>> {
|
|
|
+ size_t operator()(std::tuple<As...> const & tuple) const {
|
|
|
+ size_t seed = 0;
|
|
|
+ detail::hash_combine(seed, tuple,
|
|
|
+ std::make_index_sequence<sizeof...(As)>{});
|
|
|
+ return seed;
|
|
|
}
|
|
|
};
|
|
|
-}
|