xrpld
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 <cstddef>
9#include <cstring>
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 auto* 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
46{
47 reverse_bytes(t);
48}
49
50template <class T, class Hasher>
51/*constexpr*/
52inline void
58
59} // namespace detail
60
61// IsUniquelyRepresented<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_v<T> || std::is_enum_v<T> || std::is_pointer_v<T>>
73{
74 explicit IsUniquelyRepresented() = default;
75};
76
77template <class T>
79{
80 explicit IsUniquelyRepresented() = default;
81};
82
83template <class T>
84struct IsUniquelyRepresented<T volatile> : public IsUniquelyRepresented<T>
85{
86 explicit IsUniquelyRepresented() = default;
87};
88
89template <class T>
90struct IsUniquelyRepresented<T const volatile> : public IsUniquelyRepresented<T>
91{
92 explicit IsUniquelyRepresented() = default;
93};
94
95// IsUniquelyRepresented<std::pair<T, U>>
96
97template <class T, class U>
98struct IsUniquelyRepresented<std::pair<T, U>>
100 bool,
101 IsUniquelyRepresented<T>::value && IsUniquelyRepresented<U>::value &&
102 sizeof(T) + sizeof(U) == sizeof(std::pair<T, U>)>
103{
104 explicit IsUniquelyRepresented() = default;
105};
106
107// IsUniquelyRepresented<std::tuple<T...>>
108
109template <class... T>
110struct IsUniquelyRepresented<std::tuple<T...>>
111 : public std::integral_constant<
112 bool,
113 std::conjunction_v<IsUniquelyRepresented<T>...> &&
114 sizeof(std::tuple<T...>) == (sizeof(T) + ...)>
115{
116 explicit IsUniquelyRepresented() = default;
117};
118
119// IsUniquelyRepresented<T[N]>
120
121template <class T, std::size_t N>
123{
124 explicit IsUniquelyRepresented() = default;
125};
126
127// IsUniquelyRepresented<std::array<T, N>>
128
129template <class T, std::size_t N>
130struct IsUniquelyRepresented<std::array<T, N>>
131 : public std::integral_constant<
132 bool,
133 IsUniquelyRepresented<T>::value && sizeof(T) * N == sizeof(std::array<T, N>)>
134{
135 explicit IsUniquelyRepresented() = default;
136};
137
153template <class T, class HashAlgorithm>
155 : public std::integral_constant<
156 bool,
157 IsUniquelyRepresented<T>::value &&
158 (sizeof(T) == 1 || HashAlgorithm::kEndian == boost::endian::order::native)>
159{
160 explicit IsContiguouslyHashable() = default;
161};
162
163template <class T, std::size_t N, class HashAlgorithm>
164struct IsContiguouslyHashable<T[N], HashAlgorithm>
165 : public std::integral_constant<
166 bool,
167 IsUniquelyRepresented<T[N]>::value &&
168 (sizeof(T) == 1 || HashAlgorithm::endian == boost::endian::order::native)>
169{
170 explicit IsContiguouslyHashable() = default;
171};
172
173
174//------------------------------------------------------------------------------
175
201
202// scalars
203
204template <class Hasher, class T>
205inline void
206hash_append(Hasher& h, T const& t) noexcept
208{
209 // NOLINTNEXTLINE(bugprone-sizeof-expression)
210 h(static_cast<void const*>(std::addressof(t)), sizeof(t));
211}
212
213template <class Hasher, class T>
214inline void
215hash_append(Hasher& h, T t) noexcept
216 requires(
219{
221 h(std::addressof(t), sizeof(t));
222}
223
224template <class Hasher, class T>
225inline void
226hash_append(Hasher& h, T t) noexcept
228{
229 if (t == 0)
230 t = 0;
232 h(&t, sizeof(t));
233}
234
235template <class Hasher>
236inline void
237hash_append(Hasher& h, std::nullptr_t) noexcept
238{
239 void const* p = nullptr;
241 h(&p, sizeof(p));
242}
243
244// Forward declarations for ADL purposes
245
246template <class Hasher, class T, std::size_t N>
247void
248hash_append(Hasher& h, T (&a)[N]) noexcept
249 requires(!IsContiguouslyHashable<T, Hasher>::value);
250
251template <class Hasher, class CharT, class Traits, class Alloc>
252void
253hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept
254 requires(!IsContiguouslyHashable<CharT, Hasher>::value);
255
256template <class Hasher, class CharT, class Traits, class Alloc>
257void
258hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept
259 requires(IsContiguouslyHashable<CharT, Hasher>::value);
260
261template <class Hasher, class T, class U>
262void
263hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
264 requires(!IsContiguouslyHashable<std::pair<T, U>, Hasher>::value);
265
266template <class Hasher, class T, class Alloc>
267void
268hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
269 requires(!IsContiguouslyHashable<T, Hasher>::value);
270
271template <class Hasher, class T, class Alloc>
272void
273hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
274 requires(IsContiguouslyHashable<T, Hasher>::value);
275
276template <class Hasher, class T, std::size_t N>
277void
278hash_append(Hasher& h, std::array<T, N> const& a) noexcept
279 requires(!IsContiguouslyHashable<std::array<T, N>, Hasher>::value);
280
281template <class Hasher, class... T>
282void
283hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
284 requires(!IsContiguouslyHashable<std::tuple<T...>, Hasher>::value);
285
286template <class Hasher, class Key, class T, class Hash, class Pred, class Alloc>
287void
289
290template <class Hasher, class Key, class Hash, class Pred, class Alloc>
291void
293
294template <class Hasher, class Key, class Compare, class Alloc>
295void
296hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
298template <class Hasher, class Key, class Compare, class Alloc>
299void
300hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
302template <class Hasher, class T0, class T1, class... T>
303void
304hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
305
306// c-array
307
308template <class Hasher, class T, std::size_t N>
309void
310hash_append(Hasher& h, T (&a)[N]) noexcept
312{
313 for (auto const& t : a)
314 hash_append(h, t);
315}
316
317// basic_string
318
319template <class Hasher, class CharT, class Traits, class Alloc>
320inline void
323{
324 for (auto c : s)
325 hash_append(h, c);
326 hash_append(h, s.size());
327}
328
329template <class Hasher, class CharT, class Traits, class Alloc>
330inline void
333{
334 h(s.data(), s.size() * sizeof(CharT));
335 hash_append(h, s.size());
336}
337
338// pair
339
340template <class Hasher, class T, class U>
341inline void
342hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
343 requires(!IsContiguouslyHashable<std::pair<T, U>, Hasher>::value)
344{
345 hash_append(h, p.first, p.second);
346}
347
348// vector
349
350template <class Hasher, class T, class Alloc>
351inline void
352hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
354{
355 for (auto const& t : v)
356 hash_append(h, t);
357 hash_append(h, v.size());
358}
359
360template <class Hasher, class T, class Alloc>
361inline void
362hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
364{
365 h(v.data(), v.size() * sizeof(T));
366 hash_append(h, v.size());
367}
368
369// array
370
371template <class Hasher, class T, std::size_t N>
372void
373hash_append(Hasher& h, std::array<T, N> const& a) noexcept
374 requires(!IsContiguouslyHashable<std::array<T, N>, Hasher>::value)
375{
376 for (auto const& t : a)
377 hash_append(h, t);
378}
379
380template <class Hasher, class Key, class Compare, class Alloc>
381void
382hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
384{
385 for (auto const& t : v)
386 hash_append(h, t);
387}
388template <class Hasher, class Key, class Compare, class Alloc>
389void
390hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
392{
393 h(&(v.begin()), v.size() * sizeof(Key));
394}
395// tuple
396
397template <class Hasher, class... T>
398inline void
399hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
400 requires(!IsContiguouslyHashable<std::tuple<T...>, Hasher>::value)
401{
402 std::apply([&h](auto const&... item) { (hash_append(h, item), ...); }, t);
403}
404
405// shared_ptr
406
407template <class Hasher, class T>
408inline void
409hash_append(Hasher& h, std::shared_ptr<T> const& p) noexcept
410{
411 hash_append(h, p.get());
412}
413
414// chrono
415
416template <class Hasher, class Rep, class Period>
417inline void
419{
420 hash_append(h, d.count());
421}
422
423template <class Hasher, class Clock, class Duration>
424inline void
426{
427 hash_append(h, tp.time_since_epoch());
428}
429
430// variadic
431
432template <class Hasher, class T0, class T1, class... T>
433inline void
434hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept
435{
436 hash_append(h, t0);
437 hash_append(h, t1, t...);
438}
439
440// error_code
441
442template <class HashAlgorithm>
443inline void
444hash_append(HashAlgorithm& h, std::error_code const& ec)
445{
446 hash_append(h, ec.value(), &ec.category());
447}
448
449} // namespace beast
T addressof(T... args)
T apply(T... args)
T category(T... args)
T is_enum_v
T is_floating_point_v
T is_integral_v
T is_pointer_v
T memmove(T... args)
void reverseBytes(T &t)
Definition hash_append.h:27
void maybeReverseBytes(T &t, std::false_type)
Definition hash_append.h:38
void 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)