hash.h
Go to the documentation of this file.
1 #ifndef TTG_UTIL_HASH_H
2 #define TTG_UTIL_HASH_H
3 
4 #include <cstddef>
5 #include <cstdint>
6 
7 #include "ttg/util/void.h"
8 
9 namespace ttg {
10  namespace detail {
12  class FNVhasher {
13  // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
14  using result_type = std::size_t;
15  static const result_type offset_basis = 14695981039346656037ul;
16  static const result_type prime = 1099511628211ul;
17  result_type value_ = offset_basis;
18 
19  public:
22  void update(std::byte byte) noexcept { value_ = (value_ ^ static_cast<uint_fast8_t>(byte)) * prime; }
23 
25  void update(size_t n, const std::byte* bytes) noexcept {
26  for (size_t i = 0; i < n; i++) update(bytes[i]);
27  }
28 
30  auto value() const noexcept { return value_; }
31 
33  static result_type initial_value() { return offset_basis; }
34  };
35 
38  static_assert(sizeof(std::size_t) == sizeof(std::uint64_t));
39 
40  inline static std::size_t fn(std::size_t h, std::size_t k) {
41  const std::size_t m = (std::size_t(0xc6a4a793) << 32) + 0x5bd1e995;
42  const int r = 47;
43 
44  k *= m;
45  k ^= k >> r;
46  k *= m;
47 
48  h ^= k;
49  h *= m;
50 
51  // Completely arbitrary number, to prevent 0's
52  // from hashing to 0.
53  h += 0xe6546b64;
54 
55  return h;
56  }
57  };
58 
59  } // namespace detail
60 
61  namespace meta {
63  // has_member_function_hash_v<T> evaluates to true if T::hash() is defined
65  template <typename T, typename Enabler = void>
66  struct has_member_function_hash : std::false_type {};
67  template <typename T>
68  struct has_member_function_hash<T, std::void_t<decltype(std::declval<const T&>().hash())>> : std::true_type {};
69  template <typename T>
71  } // namespace meta
72 
74  namespace overload {
75 
77 
80  template <typename T, typename Enabler = void>
81  struct hash;
82 
84  template <typename T>
85  struct hash<T, std::enable_if_t<meta::has_member_function_hash_v<T>>> {
86  auto operator()(const T& t) const { return t.hash(); }
87  };
88 
90  template <>
91  struct hash<void, void> {
92  auto operator()() const { return detail::FNVhasher::initial_value(); }
93  // convenient to be able to hash Void using hash<void>
94  auto operator()(const ttg::Void&) const { return operator()(); }
95  };
96 
98  template <>
99  struct hash<Void, void> {
100  auto operator()(const ttg::Void&) const { return hash<void>{}(); }
101  };
102 
104  template <typename T>
105  struct hash<T, std::enable_if_t<std::is_integral_v<std::decay_t<T>> && sizeof(T) <= sizeof(std::size_t), void>> {
106  auto operator()(T t) const { return static_cast<std::size_t>(t); }
107  };
108 
111  template <typename T>
112  struct hash<
113  T, std::enable_if_t<!(std::is_integral_v<std::decay_t<T>> && sizeof(T) <= sizeof(std::size_t)) &&
114  !(meta::has_member_function_hash_v<T>)&&std::has_unique_object_representations_v<T>,
115  void>> {
116  auto operator()(const T& t) const {
117  detail::FNVhasher hasher;
118  hasher.update(sizeof(T), reinterpret_cast<const std::byte*>(&t));
119  return hasher.value();
120  }
121  };
122 
124  template <typename T, typename Enabler>
125  struct hash {
126  constexpr static bool NEED_TO_PROVIDE_SPECIALIZATION_OF_TTG_OVERLOAD_HASH_FOR_THIS_TYPE = !std::is_same_v<T, T>;
127  static_assert(NEED_TO_PROVIDE_SPECIALIZATION_OF_TTG_OVERLOAD_HASH_FOR_THIS_TYPE);
128  };
129  } // namespace overload
130 
131  using namespace ttg::overload;
132 
133  namespace meta {
135  // has_ttg_hash_specialization_v<T> evaluates to true if ttg::hash<T> is defined
137  template <typename T, typename Enabler = void>
138  struct has_ttg_hash_specialization : std::false_type {};
139  template <typename T>
141  T, ttg::meta::void_t<decltype(std::declval<ttg::hash<T>>()(std::declval<const T&>()))>> : std::true_type {};
142  template <typename T>
144  } // namespace meta
145 
146  template <class T>
147  inline void hash_combine(std::size_t& seed, T const& v) {
148  ttg::hash<T> hasher;
149  seed = detail::hash_combine_impl::fn(seed, hasher(v));
150  }
151 
152 } // namespace ttg
153 
154 
155 #include "ttg/util/hash/std/pair.h"
156 
157 #endif // TTG_UTIL_HASH_H
A complete version of void.
Definition: void.h:11
byte-wise hasher
Definition: hash.h:12
void update(size_t n, const std::byte *bytes) noexcept
Updates the hash with an additional n bytes.
Definition: hash.h:25
static result_type initial_value()
Definition: hash.h:33
auto value() const noexcept
Definition: hash.h:30
void update(std::byte byte) noexcept
Definition: hash.h:22
unsigned char byte
Definition: span.h:137
constexpr bool has_member_function_hash_v
Definition: hash.h:70
void void_t
Definition: meta.h:23
constexpr bool has_ttg_hash_specialization_v
Definition: hash.h:143
place for overloading/instantiating hash and other functionality
Definition: pair.h:8
top-level TTG namespace contains runtime-neutral functionality
Definition: keymap.h:8
void hash_combine(std::size_t &seed, T const &v)
Definition: hash.h:147
combines 2 hash values; implementation based on boost::hash_combine_impl<64> from Boost v1....
Definition: hash.h:37
static std::size_t fn(std::size_t h, std::size_t k)
Definition: hash.h:40
auto operator()(const ttg::Void &) const
Definition: hash.h:100
auto operator()(const ttg::Void &) const
Definition: hash.h:94
Computes hash values for objects of type T.
Definition: hash.h:81