siplasplas
A library for C++ reflection and introspection
hash.hpp
1 #ifndef SIPLASPLAS_UTILITY_HASH_HPP
2 #define SIPLASPLAS_UTILITY_HASH_HPP
3 
4 #include "tuple.hpp"
5 #include "function_traits.hpp"
6 
7 #include <unordered_map>
8 #include <unordered_set>
9 #include <tuple>
10 #include <memory>
11 #include <cstring>
12 
30 namespace cpp
31 {
32 
45 template<typename T>
46 constexpr std::size_t hash(const T& value);
47 
65 template<typename T, typename U, typename... Args>
66 constexpr std::size_t hash(const T& first, const U& second, const Args&... tail);
67 
79 template<typename T>
80 std::size_t raw_hash(const T& value);
81 
82 namespace
83 {
84 
85 template<typename T, cpp::FunctionKind Kind = cpp::function_kind<T>()>
86 class HashDispatch
87 {
88 public:
89  template<typename U, typename = void>
90  class HashDispatchForValueTypes
91  {
92  public:
93  static constexpr std::size_t apply(const U& value)
94  {
95  return std::hash<T>{}(value);
96  }
97  };
98 
99  template<typename U>
100  class HashDispatchForValueTypes<U, typename std::enable_if<std::is_enum<U>::value>::type>
101  {
102  public:
103  static constexpr std::size_t apply(const U& value)
104  {
105  return std::hash<T>{}(static_cast<typename std::underlying_type<U>::type>(value));
106  }
107  };
108 
109  static constexpr std::size_t apply(const T& value)
110  {
111  return HashDispatchForValueTypes<T>::apply(value);
112  }
113 };
114 
115 template<typename T>
116 class HashDispatch<T, cpp::FunctionKind::FREE_FUNCTION>
117 {
118 public:
119  static constexpr std::size_t apply(const T& value)
120  {
121  return ::cpp::raw_hash(value);
122  }
123 };
124 
125 template<typename T>
126 class HashDispatch<T, cpp::FunctionKind::MEMBER_FUNCTION>
127 {
128 public:
129  static constexpr std::size_t apply(const T& value)
130  {
131  return ::cpp::raw_hash(value);
132  }
133 };
134 
135 template<typename T>
136 class HashDispatch<T, cpp::FunctionKind::CONST_MEMBER_FUNCTION>
137 {
138 public:
139  static constexpr std::size_t apply(const T& value)
140  {
141  return ::cpp::raw_hash(value);
142  }
143 };
144 
145 template<typename T>
146 class HashDispatch<T, cpp::FunctionKind::FUNCTOR>
147 {
148 public:
149  static constexpr std::size_t apply(const T& value)
150  {
151  return std::is_empty<T>::value ?
152  ::cpp::hash(&T::operator())
153  :
154  ::cpp::hash(&value, &T::operator())
155  ;
156  }
157 };
158 
159 }
160 
173 template<typename T>
174 constexpr std::size_t hash_combine(std::size_t seed, const T& value)
175 {
176  return seed ^ (hash(value) + 0x9e3779b9 + (seed<<6) + (seed>>2));
177 }
178 
179 template<typename T>
180 constexpr std::size_t hash(const T& value)
181 {
182  return HashDispatch<T>::apply(value);
183 }
184 
185 template<typename T, typename U, typename... Args>
186 constexpr std::size_t hash(const T& first, const U& second, const Args&... tail)
187 {
188  return hash_combine(
189  hash(first),
190  hash(second, tail...)
191  );
192 }
193 
194 template<typename T, typename U>
195 constexpr std::size_t hash(const std::pair<T, U>& pair)
196 {
197  return hash(pair.first, pair.second);
198 }
199 
200 template<typename... Ts>
201 constexpr std::size_t hash(const std::tuple<Ts...>& tuple)
202 {
203  return cpp::tuple_call(
204  tuple,
205  [](const Ts&... args)
206  {
207  return hash(args...);
208  }
209  );
210 }
211 
222 template<typename T>
223 struct Hash
224 {
225 public:
226  constexpr std::size_t operator()(const T& value) const
227  {
228  return ::cpp::hash(value);
229  }
230 };
231 
239 template<typename Key, typename Value>
240 using HashTable = std::unordered_map<Key, Value, Hash<Key>>;
241 
248 template<typename Key>
249 using HashSet = std::unordered_set<Key, Hash<Key>>;
250 
251 template<typename T>
252 std::size_t raw_hash(const T& value)
253 {
254  std::aligned_storage_t<sizeof(T), alignof(T)> rawStorage;
255  std::memcpy(&rawStorage, &value, sizeof(T));
256  std::size_t hash = 0;
257 
258  for(std::size_t i = 0; i < sizeof(T); ++i)
259  {
260  hash = hash_combine(hash, reinterpret_cast<const char*>(&rawStorage)[i]);
261  }
262 
263  return hash;
264 }
265 
276 template<typename T>
277 class RawHash
278 {
279 public:
280  constexpr std::size_t operator()(const T& value) const
281  {
282  return raw_hash(value);
283  }
284 };
285 
286 }
287 
288 #endif // SIPLASPLAS_UTILITY_HASH_HPP
constexpr std::size_t hash_combine(std::size_t seed, const T &value)
Implements a hash combination function of a given hash value and a value of type T.
Definition: hash.hpp:174
std::unordered_set< Key, Hash< Key >> HashSet
std::set alias using cpp::Hash as hash.
Definition: hash.hpp:249
A functor that implements a bytewise hash function for values of type T.
Definition: hash.hpp:277
Definition: canary_allocator.hpp:7
Definition: variant.hpp:500
A functor that implements a hash function for values of type T.
Definition: hash.hpp:223
std::unordered_map< Key, Value, Hash< Key >> HashTable
std::unordered_map alias using cpp::Hash as hash.
Definition: hash.hpp:240
std::size_t raw_hash(const T &value)
Returns a bytewise hash of a given value.
Definition: hash.hpp:252
constexpr std::size_t hash(const T &first, const U &second, const Args &...tail)
Returns the comination of hashes of a set of values.
Definition: hash.hpp:186