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 <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
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
152template <class T, class HashAlgorithm>
154 : public std::integral_constant<
155 bool,
156 IsUniquelyRepresented<T>::value &&
157 (sizeof(T) == 1 || HashAlgorithm::kEndian == boost::endian::order::native)>
158{
159 explicit IsContiguouslyHashable() = default;
160};
161
162template <class T, std::size_t N, class HashAlgorithm>
163struct IsContiguouslyHashable<T[N], HashAlgorithm>
164 : public std::integral_constant<
165 bool,
166 IsUniquelyRepresented<T[N]>::value &&
167 (sizeof(T) == 1 || HashAlgorithm::endian == boost::endian::order::native)>
168{
169 explicit IsContiguouslyHashable() = default;
170};
171
172
173//------------------------------------------------------------------------------
174
199
200// scalars
201
202template <class Hasher, class T>
204hash_append(Hasher& h, T const& t) noexcept
205{
206 // NOLINTNEXTLINE(bugprone-sizeof-expression)
207 h(static_cast<void const*>(std::addressof(t)), sizeof(t));
208}
209
210template <class Hasher, class T>
211inline std::enable_if_t<
212 !IsContiguouslyHashable<T, Hasher>::value &&
214hash_append(Hasher& h, T t) noexcept
215{
217 h(std::addressof(t), sizeof(t));
218}
219
220template <class Hasher, class T>
222hash_append(Hasher& h, T t) noexcept
223{
224 if (t == 0)
225 t = 0;
227 h(&t, sizeof(t));
228}
229
230template <class Hasher>
231inline void
232hash_append(Hasher& h, std::nullptr_t) noexcept
233{
234 void const* p = nullptr;
236 h(&p, sizeof(p));
237}
238
239// Forward declarations for ADL purposes
240
241template <class Hasher, class T, std::size_t N>
243hash_append(Hasher& h, T (&a)[N]) noexcept;
244
245template <class Hasher, class CharT, class Traits, class Alloc>
247hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
248
249template <class Hasher, class CharT, class Traits, class Alloc>
251hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
252
253template <class Hasher, class T, class U>
255hash_append(Hasher& h, std::pair<T, U> const& p) noexcept;
256
257template <class Hasher, class T, class Alloc>
259hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
260
261template <class Hasher, class T, class Alloc>
263hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
264
265template <class Hasher, class T, std::size_t N>
267hash_append(Hasher& h, std::array<T, N> const& a) noexcept;
268
269template <class Hasher, class... T>
270std::enable_if_t<!IsContiguouslyHashable<std::tuple<T...>, Hasher>::value>
271hash_append(Hasher& h, std::tuple<T...> const& t) noexcept;
272
273template <class Hasher, class Key, class T, class Hash, class Pred, class Alloc>
274void
276
277template <class Hasher, class Key, class Hash, class Pred, class Alloc>
278void
280
281template <class Hasher, class Key, class Compare, class Alloc>
283hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
284template <class Hasher, class Key, class Compare, class Alloc>
286hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
287template <class Hasher, class T0, class T1, class... T>
288void
289hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
290
291// c-array
292
293template <class Hasher, class T, std::size_t N>
295hash_append(Hasher& h, T (&a)[N]) noexcept
296{
297 for (auto const& t : a)
298 hash_append(h, t);
299}
300
301// basic_string
302
303template <class Hasher, class CharT, class Traits, class Alloc>
306{
307 for (auto c : s)
308 hash_append(h, c);
309 hash_append(h, s.size());
310}
311
312template <class Hasher, class CharT, class Traits, class Alloc>
315{
316 h(s.data(), s.size() * sizeof(CharT));
317 hash_append(h, s.size());
318}
319
320// pair
321
322template <class Hasher, class T, class U>
324hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
325{
326 hash_append(h, p.first, p.second);
327}
328
329// vector
330
331template <class Hasher, class T, class Alloc>
333hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
334{
335 for (auto const& t : v)
336 hash_append(h, t);
337 hash_append(h, v.size());
338}
339
340template <class Hasher, class T, class Alloc>
342hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
343{
344 h(v.data(), v.size() * sizeof(T));
345 hash_append(h, v.size());
346}
347
348// array
349
350template <class Hasher, class T, std::size_t N>
352hash_append(Hasher& h, std::array<T, N> const& a) noexcept
353{
354 for (auto const& t : a)
355 hash_append(h, t);
356}
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 for (auto const& t : v)
363 hash_append(h, t);
364}
365template <class Hasher, class Key, class Compare, class Alloc>
367hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
368{
369 h(&(v.begin()), v.size() * sizeof(Key));
370}
371// tuple
372
373namespace detail {
374
375inline void
376forEachItem(...) noexcept
377{
378}
379
380template <class Hasher, class T>
381inline int
382hashOne(Hasher& h, T const& t) noexcept
383{
384 hash_append(h, t);
385 return 0;
386}
387
388template <class Hasher, class... T, std::size_t... I>
389inline void
391{
392 for_each_item(hash_one(h, std::get<I>(t))...);
393}
394
395} // namespace detail
396
397template <class Hasher, class... T>
398inline std::enable_if_t<!IsContiguouslyHashable<std::tuple<T...>, Hasher>::value>
399hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
400{
402}
403
404// shared_ptr
405
406template <class Hasher, class T>
407inline void
408hash_append(Hasher& h, std::shared_ptr<T> const& p) noexcept
409{
410 hash_append(h, p.get());
411}
412
413// chrono
414
415template <class Hasher, class Rep, class Period>
416inline void
418{
419 hash_append(h, d.count());
420}
421
422template <class Hasher, class Clock, class Duration>
423inline void
425{
426 hash_append(h, tp.time_since_epoch());
427}
428
429// variadic
430
431template <class Hasher, class T0, class T1, class... T>
432inline void
433hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept
434{
435 hash_append(h, t0);
436 hash_append(h, t1, t...);
437}
438
439// error_code
440
441template <class HashAlgorithm>
442inline void
443hash_append(HashAlgorithm& h, std::error_code const& ec)
444{
445 hash_append(h, ec.value(), &ec.category());
446}
447
448} // namespace beast
T addressof(T... args)
T category(T... args)
T is_enum_v
T is_integral_v
T is_pointer_v
T memmove(T... args)
void reverseBytes(T &t)
Definition hash_append.h:27
void forEachItem(...) noexcept
void tuple_hash(Hasher &h, std::tuple< T... > const &t, std::index_sequence< I... >) noexcept
void maybeReverseBytes(T &t, std::false_type)
Definition hash_append.h:38
int hashOne(Hasher &h, T const &t) noexcept
std::enable_if_t< IsContiguouslyHashable< T, Hasher >::value > hash_append(Hasher &h, T const &t) noexcept
Logically concatenate input data to a Hasher.
STL namespace.
T swap(T... args)
T value(T... args)