rippled
Loading...
Searching...
No Matches
hash_append.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of Beast: https://github.com/vinniefalco/Beast
4 Copyright 2014, Howard Hinnant <howard.hinnant@gmail.com>,
5 Vinnie Falco <vinnie.falco@gmail.com
6
7 Permission to use, copy, modify, and/or distribute this software for any
8 purpose with or without fee is hereby granted, provided that the above
9 copyright notice and this permission notice appear in all copies.
10
11 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18*/
19//==============================================================================
20
21#ifndef BEAST_HASH_HASH_APPEND_H_INCLUDED
22#define BEAST_HASH_HASH_APPEND_H_INCLUDED
23
24#include <boost/container/flat_set.hpp>
25#include <boost/endian/conversion.hpp>
26#include <array>
27#include <chrono>
28#include <cstdint>
29#include <cstring>
30#include <functional>
31#include <map>
32#include <memory>
33#include <set>
34#include <string>
35#include <system_error>
36#include <tuple>
37#include <type_traits>
38#include <unordered_map>
39#include <unordered_set>
40#include <utility>
41#include <vector>
42
43namespace beast {
44
45namespace detail {
46
47template <class T>
48/*constexpr*/
49inline void
51{
52 unsigned char* bytes = static_cast<unsigned char*>(
53 std::memmove(std::addressof(t), std::addressof(t), sizeof(T)));
54 for (unsigned i = 0; i < sizeof(T) / 2; ++i)
55 std::swap(bytes[i], bytes[sizeof(T) - 1 - i]);
56}
57
58template <class T>
59/*constexpr*/
60inline void
62{
63}
64
65template <class T>
66/*constexpr*/
67inline void
69{
71}
72
73template <class T, class Hasher>
74/*constexpr*/
75inline void
76maybe_reverse_bytes(T& t, Hasher&)
77{
79 t,
81 bool,
82 Hasher::endian != boost::endian::order::native>{});
83}
84
85} // namespace detail
86
87// is_uniquely_represented<T>
88
89// A type T is contiguously hashable if for all combinations of two values of
90// a type, say x and y, if x == y, then it must also be true that
91// memcmp(addressof(x), addressof(y), sizeof(T)) == 0. I.e. if x == y,
92// then x and y have the same bit pattern representation.
93
94template <class T>
97 bool,
98 std::is_integral<T>::value || std::is_enum<T>::value ||
99 std::is_pointer<T>::value>
100{
101 explicit is_uniquely_represented() = default;
102};
103
104template <class T>
106{
107 explicit is_uniquely_represented() = default;
108};
109
110template <class T>
112{
113 explicit is_uniquely_represented() = default;
114};
115
116template <class T>
117struct is_uniquely_represented<T const volatile>
118 : public is_uniquely_represented<T>
119{
120 explicit is_uniquely_represented() = default;
121};
122
123// is_uniquely_represented<std::pair<T, U>>
124
125template <class T, class U>
126struct is_uniquely_represented<std::pair<T, U>>
127 : public std::integral_constant<
128 bool,
129 is_uniquely_represented<T>::value &&
130 is_uniquely_represented<U>::value &&
131 sizeof(T) + sizeof(U) == sizeof(std::pair<T, U>)>
132{
133 explicit is_uniquely_represented() = default;
134};
135
136// is_uniquely_represented<std::tuple<T...>>
137
138template <class... T>
139struct is_uniquely_represented<std::tuple<T...>>
140 : public std::integral_constant<
141 bool,
142 std::conjunction_v<is_uniquely_represented<T>...> &&
143 sizeof(std::tuple<T...>) == (sizeof(T) + ...)>
144{
145 explicit is_uniquely_represented() = default;
146};
147
148// is_uniquely_represented<T[N]>
149
150template <class T, std::size_t N>
152{
153 explicit is_uniquely_represented() = default;
154};
155
156// is_uniquely_represented<std::array<T, N>>
157
158template <class T, std::size_t N>
159struct is_uniquely_represented<std::array<T, N>>
160 : public std::integral_constant<
161 bool,
162 is_uniquely_represented<T>::value &&
163 sizeof(T) * N == sizeof(std::array<T, N>)>
164{
165 explicit is_uniquely_represented() = default;
166};
167
182template <class T, class HashAlgorithm>
184 : public std::integral_constant<
185 bool,
186 is_uniquely_represented<T>::value &&
187 (sizeof(T) == 1 ||
188 HashAlgorithm::endian == boost::endian::order::native)>
189{
190 explicit is_contiguously_hashable() = default;
191};
192
193template <class T, std::size_t N, class HashAlgorithm>
194struct is_contiguously_hashable<T[N], HashAlgorithm>
195 : public std::integral_constant<
196 bool,
197 is_uniquely_represented<T[N]>::value &&
198 (sizeof(T) == 1 ||
199 HashAlgorithm::endian == boost::endian::order::native)>
200{
201 explicit is_contiguously_hashable() = default;
202};
205//------------------------------------------------------------------------------
206
232// scalars
233
234template <class Hasher, class T>
236hash_append(Hasher& h, T const& t) noexcept
237{
238 h(std::addressof(t), sizeof(t));
239}
240
241template <class Hasher, class T>
242inline std::enable_if_t<
243 !is_contiguously_hashable<T, Hasher>::value &&
246hash_append(Hasher& h, T t) noexcept
247{
249 h(std::addressof(t), sizeof(t));
250}
251
252template <class Hasher, class T>
254hash_append(Hasher& h, T t) noexcept
255{
256 if (t == 0)
257 t = 0;
259 h(&t, sizeof(t));
260}
261
262template <class Hasher>
263inline void
264hash_append(Hasher& h, std::nullptr_t) noexcept
265{
266 void const* p = nullptr;
268 h(&p, sizeof(p));
269}
270
271// Forward declarations for ADL purposes
272
273template <class Hasher, class T, std::size_t N>
275hash_append(Hasher& h, T (&a)[N]) noexcept;
276
277template <class Hasher, class CharT, class Traits, class Alloc>
280 Hasher& h,
282
283template <class Hasher, class CharT, class Traits, class Alloc>
286 Hasher& h,
288
289template <class Hasher, class T, class U>
291hash_append(Hasher& h, std::pair<T, U> const& p) noexcept;
292
293template <class Hasher, class T, class Alloc>
295hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
296
297template <class Hasher, class T, class Alloc>
299hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
300
301template <class Hasher, class T, std::size_t N>
303hash_append(Hasher& h, std::array<T, N> const& a) noexcept;
304
305template <class Hasher, class... T>
306std::enable_if_t<!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
307hash_append(Hasher& h, std::tuple<T...> const& t) noexcept;
308
309template <class Hasher, class Key, class T, class Hash, class Pred, class Alloc>
310void
312
313template <class Hasher, class Key, class Hash, class Pred, class Alloc>
314void
316
317template <class Hasher, class Key, class Compare, class Alloc>
320 Hasher& h,
321 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
322template <class Hasher, class Key, class Compare, class Alloc>
325 Hasher& h,
326 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
327template <class Hasher, class T0, class T1, class... T>
328void
329hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
330
331// c-array
332
333template <class Hasher, class T, std::size_t N>
335hash_append(Hasher& h, T (&a)[N]) noexcept
336{
337 for (auto const& t : a)
338 hash_append(h, t);
339}
340
341// basic_string
342
343template <class Hasher, class CharT, class Traits, class Alloc>
346 Hasher& h,
348{
349 for (auto c : s)
350 hash_append(h, c);
351 hash_append(h, s.size());
352}
353
354template <class Hasher, class CharT, class Traits, class Alloc>
357 Hasher& h,
359{
360 h(s.data(), s.size() * sizeof(CharT));
361 hash_append(h, s.size());
362}
363
364// pair
365
366template <class Hasher, class T, class U>
367inline std::enable_if_t<
368 !is_contiguously_hashable<std::pair<T, U>, Hasher>::value>
369hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
370{
371 hash_append(h, p.first, p.second);
372}
373
374// vector
375
376template <class Hasher, class T, class Alloc>
378hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
379{
380 for (auto const& t : v)
381 hash_append(h, t);
382 hash_append(h, v.size());
383}
384
385template <class Hasher, class T, class Alloc>
387hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
388{
389 h(v.data(), v.size() * sizeof(T));
390 hash_append(h, v.size());
391}
392
393// array
394
395template <class Hasher, class T, std::size_t N>
397hash_append(Hasher& h, std::array<T, N> const& a) noexcept
398{
399 for (auto const& t : a)
400 hash_append(h, t);
401}
402
403template <class Hasher, class Key, class Compare, class Alloc>
406 Hasher& h,
407 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
408{
409 for (auto const& t : v)
410 hash_append(h, t);
411}
412template <class Hasher, class Key, class Compare, class Alloc>
415 Hasher& h,
416 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
417{
418 h(&(v.begin()), v.size() * sizeof(Key));
419}
420// tuple
421
422namespace detail {
423
424inline void
425for_each_item(...) noexcept
426{
427}
428
429template <class Hasher, class T>
430inline int
431hash_one(Hasher& h, T const& t) noexcept
432{
433 hash_append(h, t);
434 return 0;
435}
436
437template <class Hasher, class... T, std::size_t... I>
438inline void
440 Hasher& h,
441 std::tuple<T...> const& t,
443{
444 for_each_item(hash_one(h, std::get<I>(t))...);
445}
446
447} // namespace detail
448
449template <class Hasher, class... T>
450inline std::enable_if_t<
451 !is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
452hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
453{
455}
456
457// shared_ptr
458
459template <class Hasher, class T>
460inline void
461hash_append(Hasher& h, std::shared_ptr<T> const& p) noexcept
462{
463 hash_append(h, p.get());
464}
465
466// chrono
467
468template <class Hasher, class Rep, class Period>
469inline void
471{
472 hash_append(h, d.count());
473}
474
475template <class Hasher, class Clock, class Duration>
476inline void
478 Hasher& h,
480{
481 hash_append(h, tp.time_since_epoch());
482}
483
484// variadic
485
486template <class Hasher, class T0, class T1, class... T>
487inline void
488hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept
489{
490 hash_append(h, t0);
491 hash_append(h, t1, t...);
492}
493
494// error_code
495
496template <class HashAlgorithm>
497inline void
498hash_append(HashAlgorithm& h, std::error_code const& ec)
499{
500 hash_append(h, ec.value(), &ec.category());
501}
502
503} // namespace beast
504
505#endif
T addressof(T... args)
T category(T... args)
T memmove(T... args)
void reverse_bytes(T &t)
Definition: hash_append.h:50
int hash_one(Hasher &h, T const &t) noexcept
Definition: hash_append.h:431
void maybe_reverse_bytes(T &t, std::false_type)
Definition: hash_append.h:61
void tuple_hash(Hasher &h, std::tuple< T... > const &t, std::index_sequence< I... >) noexcept
Definition: hash_append.h:439
void for_each_item(...) noexcept
Definition: hash_append.h:425
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.
Definition: hash_append.h:236
STL namespace.
Metafunction returning true if the type can be hashed in one call.
Definition: hash_append.h:189
T swap(T... args)
T value(T... args)