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 = static_cast<unsigned char*>(std::memmove(std::addressof(t), std::addressof(t), sizeof(T)));
30 for (unsigned i = 0; i < sizeof(T) / 2; ++i)
31 std::swap(bytes[i], bytes[sizeof(T) - 1 - i]);
32}
33
34template <class T>
35/*constexpr*/
36inline void
40
41template <class T>
42/*constexpr*/
43inline void
48
49template <class T, class Hasher>
50/*constexpr*/
51inline void
56
57} // namespace detail
58
59// is_uniquely_represented<T>
60
61// A type T is contiguously hashable if for all combinations of two values of
62// a type, say x and y, if x == y, then it must also be true that
63// memcmp(addressof(x), addressof(y), sizeof(T)) == 0. I.e. if x == y,
64// then x and y have the same bit pattern representation.
65
66template <class T>
68 : public std::
69 integral_constant<bool, std::is_integral<T>::value || std::is_enum<T>::value || std::is_pointer<T>::value>
70{
71 explicit is_uniquely_represented() = default;
72};
73
74template <class T>
76{
77 explicit is_uniquely_represented() = default;
78};
79
80template <class T>
82{
83 explicit is_uniquely_represented() = default;
84};
85
86template <class T>
87struct is_uniquely_represented<T const volatile> : public is_uniquely_represented<T>
88{
89 explicit is_uniquely_represented() = default;
90};
91
92// is_uniquely_represented<std::pair<T, U>>
93
94template <class T, class U>
95struct is_uniquely_represented<std::pair<T, U>>
97 bool,
98 is_uniquely_represented<T>::value && is_uniquely_represented<U>::value &&
99 sizeof(T) + sizeof(U) == sizeof(std::pair<T, U>)>
100{
101 explicit is_uniquely_represented() = default;
102};
103
104// is_uniquely_represented<std::tuple<T...>>
105
106template <class... T>
107struct is_uniquely_represented<std::tuple<T...>>
108 : public std::integral_constant<
109 bool,
110 std::conjunction_v<is_uniquely_represented<T>...> && sizeof(std::tuple<T...>) == (sizeof(T) + ...)>
111{
112 explicit is_uniquely_represented() = default;
113};
114
115// is_uniquely_represented<T[N]>
116
117template <class T, std::size_t N>
119{
120 explicit is_uniquely_represented() = default;
121};
122
123// is_uniquely_represented<std::array<T, N>>
124
125template <class T, std::size_t N>
126struct is_uniquely_represented<std::array<T, N>>
127 : public std::
128 integral_constant<bool, is_uniquely_represented<T>::value && sizeof(T) * N == sizeof(std::array<T, N>)>
129{
130 explicit is_uniquely_represented() = default;
131};
132
147template <class T, class HashAlgorithm>
149 bool,
150 is_uniquely_represented<T>::value &&
151 (sizeof(T) == 1 || HashAlgorithm::endian == boost::endian::order::native)>
152{
153 explicit is_contiguously_hashable() = default;
154};
155
156template <class T, std::size_t N, class HashAlgorithm>
157struct is_contiguously_hashable<T[N], HashAlgorithm>
158 : public std::integral_constant<
159 bool,
160 is_uniquely_represented<T[N]>::value &&
161 (sizeof(T) == 1 || HashAlgorithm::endian == boost::endian::order::native)>
162{
163 explicit is_contiguously_hashable() = default;
164};
167//------------------------------------------------------------------------------
168
194// scalars
195
196template <class Hasher, class T>
198hash_append(Hasher& h, T const& t) noexcept
199{
200 h(std::addressof(t), sizeof(t));
201}
202
203template <class Hasher, class T>
204inline std::enable_if_t<
205 !is_contiguously_hashable<T, Hasher>::value &&
207hash_append(Hasher& h, T t) noexcept
208{
210 h(std::addressof(t), sizeof(t));
211}
212
213template <class Hasher, class T>
215hash_append(Hasher& h, T t) noexcept
216{
217 if (t == 0)
218 t = 0;
220 h(&t, sizeof(t));
221}
222
223template <class Hasher>
224inline void
225hash_append(Hasher& h, std::nullptr_t) noexcept
226{
227 void const* p = nullptr;
229 h(&p, sizeof(p));
230}
231
232// Forward declarations for ADL purposes
233
234template <class Hasher, class T, std::size_t N>
236hash_append(Hasher& h, T (&a)[N]) noexcept;
237
238template <class Hasher, class CharT, class Traits, class Alloc>
240hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
241
242template <class Hasher, class CharT, class Traits, class Alloc>
244hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
245
246template <class Hasher, class T, class U>
248hash_append(Hasher& h, std::pair<T, U> const& p) noexcept;
249
250template <class Hasher, class T, class Alloc>
252hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
253
254template <class Hasher, class T, class Alloc>
256hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
257
258template <class Hasher, class T, std::size_t N>
260hash_append(Hasher& h, std::array<T, N> const& a) noexcept;
261
262template <class Hasher, class... T>
263std::enable_if_t<!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
264hash_append(Hasher& h, std::tuple<T...> const& t) noexcept;
265
266template <class Hasher, class Key, class T, class Hash, class Pred, class Alloc>
267void
269
270template <class Hasher, class Key, class Hash, class Pred, class Alloc>
271void
273
274template <class Hasher, class Key, class Compare, class Alloc>
276hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
277template <class Hasher, class Key, class Compare, class Alloc>
279hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
280template <class Hasher, class T0, class T1, class... T>
281void
282hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
283
284// c-array
285
286template <class Hasher, class T, std::size_t N>
288hash_append(Hasher& h, T (&a)[N]) noexcept
289{
290 for (auto const& t : a)
291 hash_append(h, t);
292}
293
294// basic_string
295
296template <class Hasher, class CharT, class Traits, class Alloc>
299{
300 for (auto c : s)
301 hash_append(h, c);
302 hash_append(h, s.size());
303}
304
305template <class Hasher, class CharT, class Traits, class Alloc>
308{
309 h(s.data(), s.size() * sizeof(CharT));
310 hash_append(h, s.size());
311}
312
313// pair
314
315template <class Hasher, class T, class U>
317hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
318{
319 hash_append(h, p.first, p.second);
320}
321
322// vector
323
324template <class Hasher, class T, class Alloc>
326hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
327{
328 for (auto const& t : v)
329 hash_append(h, t);
330 hash_append(h, v.size());
331}
332
333template <class Hasher, class T, class Alloc>
335hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
336{
337 h(v.data(), v.size() * sizeof(T));
338 hash_append(h, v.size());
339}
340
341// array
342
343template <class Hasher, class T, std::size_t N>
345hash_append(Hasher& h, std::array<T, N> const& a) noexcept
346{
347 for (auto const& t : a)
348 hash_append(h, t);
349}
350
351template <class Hasher, class Key, class Compare, class Alloc>
353hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
354{
355 for (auto const& t : v)
356 hash_append(h, t);
357}
358template <class Hasher, class Key, class Compare, class Alloc>
360hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
361{
362 h(&(v.begin()), v.size() * sizeof(Key));
363}
364// tuple
365
366namespace detail {
367
368inline void
369for_each_item(...) noexcept
370{
371}
372
373template <class Hasher, class T>
374inline int
375hash_one(Hasher& h, T const& t) noexcept
376{
377 hash_append(h, t);
378 return 0;
379}
380
381template <class Hasher, class... T, std::size_t... I>
382inline void
384{
386}
387
388} // namespace detail
389
390template <class Hasher, class... T>
391inline std::enable_if_t<!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
392hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
393{
395}
396
397// shared_ptr
398
399template <class Hasher, class T>
400inline void
401hash_append(Hasher& h, std::shared_ptr<T> const& p) noexcept
402{
403 hash_append(h, p.get());
404}
405
406// chrono
407
408template <class Hasher, class Rep, class Period>
409inline void
411{
412 hash_append(h, d.count());
413}
414
415template <class Hasher, class Clock, class Duration>
416inline void
418{
419 hash_append(h, tp.time_since_epoch());
420}
421
422// variadic
423
424template <class Hasher, class T0, class T1, class... T>
425inline void
426hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept
427{
428 hash_append(h, t0);
429 hash_append(h, t1, t...);
430}
431
432// error_code
433
434template <class HashAlgorithm>
435inline void
436hash_append(HashAlgorithm& h, std::error_code const& ec)
437{
438 hash_append(h, ec.value(), &ec.category());
439}
440
441} // 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:37
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)