rippled
Loading...
Searching...
No Matches
hash_append.h
1#ifndef BEAST_HASH_HASH_APPEND_H_INCLUDED
2#define BEAST_HASH_HASH_APPEND_H_INCLUDED
3
4#include <boost/container/flat_set.hpp>
5#include <boost/endian/conversion.hpp>
6
7#include <array>
8#include <chrono>
9#include <cstring>
10#include <functional>
11#include <memory>
12#include <string>
13#include <system_error>
14#include <tuple>
15#include <type_traits>
16#include <unordered_map>
17#include <unordered_set>
18#include <utility>
19#include <vector>
20
21namespace beast {
22
23namespace detail {
24
25template <class T>
26/*constexpr*/
27inline void
29{
30 unsigned char* bytes = static_cast<unsigned char*>(
31 std::memmove(std::addressof(t), std::addressof(t), sizeof(T)));
32 for (unsigned i = 0; i < sizeof(T) / 2; ++i)
33 std::swap(bytes[i], bytes[sizeof(T) - 1 - i]);
34}
35
36template <class T>
37/*constexpr*/
38inline void
42
43template <class T>
44/*constexpr*/
45inline void
50
51template <class T, class Hasher>
52/*constexpr*/
53inline void
54maybe_reverse_bytes(T& t, Hasher&)
55{
57 t,
59 bool,
60 Hasher::endian != boost::endian::order::native>{});
61}
62
63} // namespace detail
64
65// is_uniquely_represented<T>
66
67// A type T is contiguously hashable if for all combinations of two values of
68// a type, say x and y, if x == y, then it must also be true that
69// memcmp(addressof(x), addressof(y), sizeof(T)) == 0. I.e. if x == y,
70// then x and y have the same bit pattern representation.
71
72template <class T>
75 bool,
76 std::is_integral<T>::value || std::is_enum<T>::value ||
77 std::is_pointer<T>::value>
78{
79 explicit is_uniquely_represented() = default;
80};
81
82template <class T>
84{
85 explicit is_uniquely_represented() = default;
86};
87
88template <class T>
90{
91 explicit is_uniquely_represented() = default;
92};
93
94template <class T>
95struct is_uniquely_represented<T const volatile>
96 : public is_uniquely_represented<T>
97{
98 explicit is_uniquely_represented() = default;
99};
100
101// is_uniquely_represented<std::pair<T, U>>
102
103template <class T, class U>
104struct is_uniquely_represented<std::pair<T, U>>
105 : public std::integral_constant<
106 bool,
107 is_uniquely_represented<T>::value &&
108 is_uniquely_represented<U>::value &&
109 sizeof(T) + sizeof(U) == sizeof(std::pair<T, U>)>
110{
111 explicit is_uniquely_represented() = default;
112};
113
114// is_uniquely_represented<std::tuple<T...>>
115
116template <class... T>
117struct is_uniquely_represented<std::tuple<T...>>
118 : public std::integral_constant<
119 bool,
120 std::conjunction_v<is_uniquely_represented<T>...> &&
121 sizeof(std::tuple<T...>) == (sizeof(T) + ...)>
122{
123 explicit is_uniquely_represented() = default;
124};
125
126// is_uniquely_represented<T[N]>
127
128template <class T, std::size_t N>
130{
131 explicit is_uniquely_represented() = default;
132};
133
134// is_uniquely_represented<std::array<T, N>>
135
136template <class T, std::size_t N>
137struct is_uniquely_represented<std::array<T, N>>
138 : public std::integral_constant<
139 bool,
140 is_uniquely_represented<T>::value &&
141 sizeof(T) * N == sizeof(std::array<T, N>)>
142{
143 explicit is_uniquely_represented() = default;
144};
145
160template <class T, class HashAlgorithm>
162 : public std::integral_constant<
163 bool,
164 is_uniquely_represented<T>::value &&
165 (sizeof(T) == 1 ||
166 HashAlgorithm::endian == boost::endian::order::native)>
167{
168 explicit is_contiguously_hashable() = default;
169};
170
171template <class T, std::size_t N, class HashAlgorithm>
172struct is_contiguously_hashable<T[N], HashAlgorithm>
173 : public std::integral_constant<
174 bool,
175 is_uniquely_represented<T[N]>::value &&
176 (sizeof(T) == 1 ||
177 HashAlgorithm::endian == boost::endian::order::native)>
178{
179 explicit is_contiguously_hashable() = default;
180};
183//------------------------------------------------------------------------------
184
210// scalars
211
212template <class Hasher, class T>
214hash_append(Hasher& h, T const& t) noexcept
215{
216 h(std::addressof(t), sizeof(t));
217}
218
219template <class Hasher, class T>
220inline std::enable_if_t<
221 !is_contiguously_hashable<T, Hasher>::value &&
224hash_append(Hasher& h, T t) noexcept
225{
227 h(std::addressof(t), sizeof(t));
228}
229
230template <class Hasher, class T>
232hash_append(Hasher& h, T t) noexcept
233{
234 if (t == 0)
235 t = 0;
237 h(&t, sizeof(t));
238}
239
240template <class Hasher>
241inline void
242hash_append(Hasher& h, std::nullptr_t) noexcept
243{
244 void const* p = nullptr;
246 h(&p, sizeof(p));
247}
248
249// Forward declarations for ADL purposes
250
251template <class Hasher, class T, std::size_t N>
253hash_append(Hasher& h, T (&a)[N]) noexcept;
254
255template <class Hasher, class CharT, class Traits, class Alloc>
258 Hasher& h,
260
261template <class Hasher, class CharT, class Traits, class Alloc>
264 Hasher& h,
266
267template <class Hasher, class T, class U>
269hash_append(Hasher& h, std::pair<T, U> const& p) noexcept;
270
271template <class Hasher, class T, class Alloc>
273hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
274
275template <class Hasher, class T, class Alloc>
277hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
278
279template <class Hasher, class T, std::size_t N>
281hash_append(Hasher& h, std::array<T, N> const& a) noexcept;
282
283template <class Hasher, class... T>
284std::enable_if_t<!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
285hash_append(Hasher& h, std::tuple<T...> const& t) noexcept;
286
287template <class Hasher, class Key, class T, class Hash, class Pred, class Alloc>
288void
290
291template <class Hasher, class Key, class Hash, class Pred, class Alloc>
292void
294
295template <class Hasher, class Key, class Compare, class Alloc>
298 Hasher& h,
299 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
300template <class Hasher, class Key, class Compare, class Alloc>
303 Hasher& h,
304 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
305template <class Hasher, class T0, class T1, class... T>
306void
307hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
308
309// c-array
310
311template <class Hasher, class T, std::size_t N>
313hash_append(Hasher& h, T (&a)[N]) noexcept
314{
315 for (auto const& t : a)
316 hash_append(h, t);
317}
318
319// basic_string
320
321template <class Hasher, class CharT, class Traits, class Alloc>
324 Hasher& h,
326{
327 for (auto c : s)
328 hash_append(h, c);
329 hash_append(h, s.size());
330}
331
332template <class Hasher, class CharT, class Traits, class Alloc>
335 Hasher& h,
337{
338 h(s.data(), s.size() * sizeof(CharT));
339 hash_append(h, s.size());
340}
341
342// pair
343
344template <class Hasher, class T, class U>
345inline std::enable_if_t<
346 !is_contiguously_hashable<std::pair<T, U>, Hasher>::value>
347hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
348{
349 hash_append(h, p.first, p.second);
350}
351
352// vector
353
354template <class Hasher, class T, class Alloc>
356hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
357{
358 for (auto const& t : v)
359 hash_append(h, t);
360 hash_append(h, v.size());
361}
362
363template <class Hasher, class T, class Alloc>
365hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
366{
367 h(v.data(), v.size() * sizeof(T));
368 hash_append(h, v.size());
369}
370
371// array
372
373template <class Hasher, class T, std::size_t N>
375hash_append(Hasher& h, std::array<T, N> const& a) noexcept
376{
377 for (auto const& t : a)
378 hash_append(h, t);
379}
380
381template <class Hasher, class Key, class Compare, class Alloc>
384 Hasher& h,
385 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
386{
387 for (auto const& t : v)
388 hash_append(h, t);
389}
390template <class Hasher, class Key, class Compare, class Alloc>
393 Hasher& h,
394 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
395{
396 h(&(v.begin()), v.size() * sizeof(Key));
397}
398// tuple
399
400namespace detail {
401
402inline void
403for_each_item(...) noexcept
404{
405}
406
407template <class Hasher, class T>
408inline int
409hash_one(Hasher& h, T const& t) noexcept
410{
411 hash_append(h, t);
412 return 0;
413}
414
415template <class Hasher, class... T, std::size_t... I>
416inline void
418 Hasher& h,
419 std::tuple<T...> const& t,
421{
423}
424
425} // namespace detail
426
427template <class Hasher, class... T>
428inline std::enable_if_t<
429 !is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
430hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
431{
433}
434
435// shared_ptr
436
437template <class Hasher, class T>
438inline void
439hash_append(Hasher& h, std::shared_ptr<T> const& p) noexcept
440{
441 hash_append(h, p.get());
442}
443
444// chrono
445
446template <class Hasher, class Rep, class Period>
447inline void
449{
450 hash_append(h, d.count());
451}
452
453template <class Hasher, class Clock, class Duration>
454inline void
456 Hasher& h,
458{
459 hash_append(h, tp.time_since_epoch());
460}
461
462// variadic
463
464template <class Hasher, class T0, class T1, class... T>
465inline void
466hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept
467{
468 hash_append(h, t0);
469 hash_append(h, t1, t...);
470}
471
472// error_code
473
474template <class HashAlgorithm>
475inline void
476hash_append(HashAlgorithm& h, std::error_code const& ec)
477{
478 hash_append(h, ec.value(), &ec.category());
479}
480
481} // namespace beast
482
483#endif
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:28
int hash_one(Hasher &h, T const &t) noexcept
void maybe_reverse_bytes(T &t, std::false_type)
Definition hash_append.h:39
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)