rippled
Loading...
Searching...
No Matches
hash_append.h
1#pragma once
2
3#include <boost/container/flat_set.hpp>
4#include <boost/endian/conversion.hpp>
5
6#include <array>
7#include <chrono>
8#include <cstring>
9#include <functional>
10#include <memory>
11#include <string>
12#include <system_error>
13#include <tuple>
14#include <type_traits>
15#include <unordered_map>
16#include <unordered_set>
17#include <utility>
18#include <vector>
19
20namespace beast {
21
22namespace detail {
23
24template <class T>
25/*constexpr*/
26inline void
28{
29 unsigned char* bytes =
30 static_cast<unsigned char*>(std::memmove(std::addressof(t), std::addressof(t), sizeof(T)));
31 for (unsigned i = 0; i < sizeof(T) / 2; ++i)
32 std::swap(bytes[i], bytes[sizeof(T) - 1 - i]);
33}
34
35template <class T>
36/*constexpr*/
37inline void
41
42template <class T>
43/*constexpr*/
44inline void
49
50template <class T, class Hasher>
51/*constexpr*/
52inline void
58
59} // namespace detail
60
61// is_uniquely_represented<T>
62
63// A type T is contiguously hashable if for all combinations of two values of
64// a type, say x and y, if x == y, then it must also be true that
65// memcmp(addressof(x), addressof(y), sizeof(T)) == 0. I.e. if x == y,
66// then x and y have the same bit pattern representation.
67
68template <class T>
71 bool,
72 std::is_integral<T>::value || std::is_enum<T>::value || std::is_pointer<T>::value>
73{
74 explicit is_uniquely_represented() = default;
75};
76
77template <class T>
79{
80 explicit is_uniquely_represented() = default;
81};
82
83template <class T>
85{
86 explicit is_uniquely_represented() = default;
87};
88
89template <class T>
90struct is_uniquely_represented<T const volatile> : public is_uniquely_represented<T>
91{
92 explicit is_uniquely_represented() = default;
93};
94
95// is_uniquely_represented<std::pair<T, U>>
96
97template <class T, class U>
98struct is_uniquely_represented<std::pair<T, U>>
100 bool,
101 is_uniquely_represented<T>::value && is_uniquely_represented<U>::value &&
102 sizeof(T) + sizeof(U) == sizeof(std::pair<T, U>)>
103{
104 explicit is_uniquely_represented() = default;
105};
106
107// is_uniquely_represented<std::tuple<T...>>
108
109template <class... T>
110struct is_uniquely_represented<std::tuple<T...>>
111 : public std::integral_constant<
112 bool,
113 std::conjunction_v<is_uniquely_represented<T>...> &&
114 sizeof(std::tuple<T...>) == (sizeof(T) + ...)>
115{
116 explicit is_uniquely_represented() = default;
117};
118
119// is_uniquely_represented<T[N]>
120
121template <class T, std::size_t N>
123{
124 explicit is_uniquely_represented() = default;
125};
126
127// is_uniquely_represented<std::array<T, N>>
128
129template <class T, std::size_t N>
130struct is_uniquely_represented<std::array<T, N>>
131 : public std::integral_constant<
132 bool,
133 is_uniquely_represented<T>::value && sizeof(T) * N == sizeof(std::array<T, N>)>
134{
135 explicit is_uniquely_represented() = default;
136};
137
152template <class T, class HashAlgorithm>
154 : public std::integral_constant<
155 bool,
156 is_uniquely_represented<T>::value &&
157 (sizeof(T) == 1 || HashAlgorithm::endian == boost::endian::order::native)>
158{
159 explicit is_contiguously_hashable() = default;
160};
161
162template <class T, std::size_t N, class HashAlgorithm>
163struct is_contiguously_hashable<T[N], HashAlgorithm>
164 : public std::integral_constant<
165 bool,
166 is_uniquely_represented<T[N]>::value &&
167 (sizeof(T) == 1 || HashAlgorithm::endian == boost::endian::order::native)>
168{
169 explicit is_contiguously_hashable() = default;
170};
173//------------------------------------------------------------------------------
174
200// scalars
201
202template <class Hasher, class T>
204hash_append(Hasher& h, T const& t) noexcept
205{
206 h(std::addressof(t), sizeof(t));
207}
208
209template <class Hasher, class T>
210inline std::enable_if_t<
211 !is_contiguously_hashable<T, Hasher>::value &&
213hash_append(Hasher& h, T t) noexcept
214{
216 h(std::addressof(t), sizeof(t));
217}
218
219template <class Hasher, class T>
221hash_append(Hasher& h, T t) noexcept
222{
223 if (t == 0)
224 t = 0;
226 h(&t, sizeof(t));
227}
228
229template <class Hasher>
230inline void
231hash_append(Hasher& h, std::nullptr_t) noexcept
232{
233 void const* p = nullptr;
235 h(&p, sizeof(p));
236}
237
238// Forward declarations for ADL purposes
239
240template <class Hasher, class T, std::size_t N>
242hash_append(Hasher& h, T (&a)[N]) noexcept;
243
244template <class Hasher, class CharT, class Traits, class Alloc>
246hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
247
248template <class Hasher, class CharT, class Traits, class Alloc>
250hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
251
252template <class Hasher, class T, class U>
254hash_append(Hasher& h, std::pair<T, U> const& p) noexcept;
255
256template <class Hasher, class T, class Alloc>
258hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
259
260template <class Hasher, class T, class Alloc>
262hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
263
264template <class Hasher, class T, std::size_t N>
266hash_append(Hasher& h, std::array<T, N> const& a) noexcept;
267
268template <class Hasher, class... T>
269std::enable_if_t<!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
270hash_append(Hasher& h, std::tuple<T...> const& t) noexcept;
271
272template <class Hasher, class Key, class T, class Hash, class Pred, class Alloc>
273void
275
276template <class Hasher, class Key, class Hash, class Pred, class Alloc>
277void
279
280template <class Hasher, class Key, class Compare, class Alloc>
282hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
283template <class Hasher, class Key, class Compare, class Alloc>
285hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
286template <class Hasher, class T0, class T1, class... T>
287void
288hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
289
290// c-array
291
292template <class Hasher, class T, std::size_t N>
294hash_append(Hasher& h, T (&a)[N]) noexcept
295{
296 for (auto const& t : a)
297 hash_append(h, t);
298}
299
300// basic_string
301
302template <class Hasher, class CharT, class Traits, class Alloc>
305{
306 for (auto c : s)
307 hash_append(h, c);
308 hash_append(h, s.size());
309}
310
311template <class Hasher, class CharT, class Traits, class Alloc>
314{
315 h(s.data(), s.size() * sizeof(CharT));
316 hash_append(h, s.size());
317}
318
319// pair
320
321template <class Hasher, class T, class U>
323hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
324{
325 hash_append(h, p.first, p.second);
326}
327
328// vector
329
330template <class Hasher, class T, class Alloc>
332hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
333{
334 for (auto const& t : v)
335 hash_append(h, t);
336 hash_append(h, v.size());
337}
338
339template <class Hasher, class T, class Alloc>
341hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
342{
343 h(v.data(), v.size() * sizeof(T));
344 hash_append(h, v.size());
345}
346
347// array
348
349template <class Hasher, class T, std::size_t N>
351hash_append(Hasher& h, std::array<T, N> const& a) noexcept
352{
353 for (auto const& t : a)
354 hash_append(h, t);
355}
356
357template <class Hasher, class Key, class Compare, class Alloc>
359hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
360{
361 for (auto const& t : v)
362 hash_append(h, t);
363}
364template <class Hasher, class Key, class Compare, class Alloc>
366hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
367{
368 h(&(v.begin()), v.size() * sizeof(Key));
369}
370// tuple
371
372namespace detail {
373
374inline void
375for_each_item(...) noexcept
376{
377}
378
379template <class Hasher, class T>
380inline int
381hash_one(Hasher& h, T const& t) noexcept
382{
383 hash_append(h, t);
384 return 0;
385}
386
387template <class Hasher, class... T, std::size_t... I>
388inline void
390{
392}
393
394} // namespace detail
395
396template <class Hasher, class... T>
397inline std::enable_if_t<!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
398hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
399{
401}
402
403// shared_ptr
404
405template <class Hasher, class T>
406inline void
407hash_append(Hasher& h, std::shared_ptr<T> const& p) noexcept
408{
409 hash_append(h, p.get());
410}
411
412// chrono
413
414template <class Hasher, class Rep, class Period>
415inline void
417{
418 hash_append(h, d.count());
419}
420
421template <class Hasher, class Clock, class Duration>
422inline void
424{
425 hash_append(h, tp.time_since_epoch());
426}
427
428// variadic
429
430template <class Hasher, class T0, class T1, class... T>
431inline void
432hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept
433{
434 hash_append(h, t0);
435 hash_append(h, t1, t...);
436}
437
438// error_code
439
440template <class HashAlgorithm>
441inline void
442hash_append(HashAlgorithm& h, std::error_code const& ec)
443{
444 hash_append(h, ec.value(), &ec.category());
445}
446
447} // namespace beast
T addressof(T... args)
T category(T... args)
T is_same_v
T memmove(T... args)
void reverse_bytes(T &t)
Definition hash_append.h:27
int hash_one(Hasher &h, T const &t) noexcept
void maybe_reverse_bytes(T &t, std::false_type)
Definition hash_append.h:38
void tuple_hash(Hasher &h, std::tuple< T... > const &t, std::index_sequence< I... >) noexcept
void for_each_item(...) noexcept
std::enable_if_t< is_contiguously_hashable< T, Hasher >::value > hash_append(Hasher &h, T const &t) noexcept
Logically concatenate input data to a Hasher.
STL namespace.
Metafunction returning true if the type can be hashed in one call.
T swap(T... args)
T value(T... args)