rippled
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 
43 namespace beast {
44 
45 namespace detail {
46 
47 template <class T>
48 /*constexpr*/
49 inline 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 
58 template <class T>
59 /*constexpr*/
60 inline void
62 {
63 }
64 
65 template <class T>
66 /*constexpr*/
67 inline void
69 {
70  reverse_bytes(t);
71 }
72 
73 template <class T, class Hasher>
74 /*constexpr*/
75 inline void
76 maybe_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 
94 template <class T>
96  : public std::integral_constant<
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 
104 template <class T>
106 {
107  explicit is_uniquely_represented() = default;
108 };
109 
110 template <class T>
111 struct is_uniquely_represented<T volatile> : public is_uniquely_represented<T>
112 {
113  explicit is_uniquely_represented() = default;
114 };
115 
116 template <class T>
117 struct 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 
125 template <class T, class U>
126 struct 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 
138 template <class... T>
139 struct 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 
150 template <class T, std::size_t N>
152 {
153  explicit is_uniquely_represented() = default;
154 };
155 
156 // is_uniquely_represented<std::array<T, N>>
157 
158 template <class T, std::size_t N>
159 struct 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 
182 template <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 
193 template <class T, std::size_t N, class HashAlgorithm>
194 struct 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 
234 template <class Hasher, class T>
236 hash_append(Hasher& h, T const& t) noexcept
237 {
238  h(std::addressof(t), sizeof(t));
239 }
240 
241 template <class Hasher, class T>
242 inline std::enable_if_t<
243  !is_contiguously_hashable<T, Hasher>::value &&
246 hash_append(Hasher& h, T t) noexcept
247 {
249  h(std::addressof(t), sizeof(t));
250 }
251 
252 template <class Hasher, class T>
254 hash_append(Hasher& h, T t) noexcept
255 {
256  if (t == 0)
257  t = 0;
259  h(&t, sizeof(t));
260 }
261 
262 template <class Hasher>
263 inline void
264 hash_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 
273 template <class Hasher, class T, std::size_t N>
275 hash_append(Hasher& h, T (&a)[N]) noexcept;
276 
277 template <class Hasher, class CharT, class Traits, class Alloc>
280  Hasher& h,
281  std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
282 
283 template <class Hasher, class CharT, class Traits, class Alloc>
286  Hasher& h,
287  std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
288 
289 template <class Hasher, class T, class U>
291 hash_append(Hasher& h, std::pair<T, U> const& p) noexcept;
292 
293 template <class Hasher, class T, class Alloc>
295 hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
296 
297 template <class Hasher, class T, class Alloc>
299 hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
300 
301 template <class Hasher, class T, std::size_t N>
303 hash_append(Hasher& h, std::array<T, N> const& a) noexcept;
304 
305 template <class Hasher, class... T>
306 std::enable_if_t<!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
307 hash_append(Hasher& h, std::tuple<T...> const& t) noexcept;
308 
309 template <class Hasher, class Key, class T, class Hash, class Pred, class Alloc>
310 void
312 
313 template <class Hasher, class Key, class Hash, class Pred, class Alloc>
314 void
316 
317 template <class Hasher, class Key, class Compare, class Alloc>
320  Hasher& h,
321  boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
322 template <class Hasher, class Key, class Compare, class Alloc>
325  Hasher& h,
326  boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
327 template <class Hasher, class T0, class T1, class... T>
328 void
329 hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
330 
331 // c-array
332 
333 template <class Hasher, class T, std::size_t N>
335 hash_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 
343 template <class Hasher, class CharT, class Traits, class Alloc>
346  Hasher& h,
347  std::basic_string<CharT, Traits, Alloc> const& s) noexcept
348 {
349  for (auto c : s)
350  hash_append(h, c);
351  hash_append(h, s.size());
352 }
353 
354 template <class Hasher, class CharT, class Traits, class Alloc>
357  Hasher& h,
358  std::basic_string<CharT, Traits, Alloc> const& s) noexcept
359 {
360  h(s.data(), s.size() * sizeof(CharT));
361  hash_append(h, s.size());
362 }
363 
364 // pair
365 
366 template <class Hasher, class T, class U>
367 inline std::enable_if_t<
368  !is_contiguously_hashable<std::pair<T, U>, Hasher>::value>
369 hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
370 {
371  hash_append(h, p.first, p.second);
372 }
373 
374 // vector
375 
376 template <class Hasher, class T, class Alloc>
378 hash_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 
385 template <class Hasher, class T, class Alloc>
387 hash_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 
395 template <class Hasher, class T, std::size_t N>
397 hash_append(Hasher& h, std::array<T, N> const& a) noexcept
398 {
399  for (auto const& t : a)
400  hash_append(h, t);
401 }
402 
403 template <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 }
412 template <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 
422 namespace detail {
423 
424 inline void
425 for_each_item(...) noexcept
426 {
427 }
428 
429 template <class Hasher, class T>
430 inline int
431 hash_one(Hasher& h, T const& t) noexcept
432 {
433  hash_append(h, t);
434  return 0;
435 }
436 
437 template <class Hasher, class... T, std::size_t... I>
438 inline void
440  Hasher& h,
441  std::tuple<T...> const& t,
442  std::index_sequence<I...>) noexcept
443 {
444  for_each_item(hash_one(h, std::get<I>(t))...);
445 }
446 
447 } // namespace detail
448 
449 template <class Hasher, class... T>
450 inline std::enable_if_t<
451  !is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
452 hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
453 {
455 }
456 
457 // shared_ptr
458 
459 template <class Hasher, class T>
460 inline void
461 hash_append(Hasher& h, std::shared_ptr<T> const& p) noexcept
462 {
463  hash_append(h, p.get());
464 }
465 
466 // chrono
467 
468 template <class Hasher, class Rep, class Period>
469 inline void
470 hash_append(Hasher& h, std::chrono::duration<Rep, Period> const& d) noexcept
471 {
472  hash_append(h, d.count());
473 }
474 
475 template <class Hasher, class Clock, class Duration>
476 inline void
478  Hasher& h,
479  std::chrono::time_point<Clock, Duration> const& tp) noexcept
480 {
481  hash_append(h, tp.time_since_epoch());
482 }
483 
484 // variadic
485 
486 template <class Hasher, class T0, class T1, class... T>
487 inline void
488 hash_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 
496 template <class HashAlgorithm>
497 inline void
498 hash_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
std::false_type
std::basic_string
STL class.
std::shared_ptr
STL class.
utility
cstring
system_error
beast::detail::hash_one
int hash_one(Hasher &h, T const &t) noexcept
Definition: hash_append.h:431
beast::detail::maybe_reverse_bytes
void maybe_reverse_bytes(T &t, std::false_type)
Definition: hash_append.h:61
functional
unordered_set
std::pair
std::index_sequence
vector
std::chrono::duration
tuple
beast::is_contiguously_hashable::is_contiguously_hashable
is_contiguously_hashable()=default
std::error_code
STL class.
beast::is_uniquely_represented
Definition: hash_append.h:95
beast::is_uniquely_represented::is_uniquely_represented
is_uniquely_represented()=default
std::nullptr_t
std::is_enum
std::addressof
T addressof(T... args)
beast::detail::reverse_bytes
void reverse_bytes(T &t)
Definition: hash_append.h:50
std::enable_if_t
chrono
array
beast::is_contiguously_hashable
Metafunction returning true if the type can be hashed in one call.
Definition: hash_append.h:183
beast::detail::tuple_hash
void tuple_hash(Hasher &h, std::tuple< T... > const &t, std::index_sequence< I... >) noexcept
Definition: hash_append.h:439
std::chrono::time_point
std::error_code::category
T category(T... args)
cstdint
map
std::is_integral
memory
std::swap
T swap(T... args)
std::error_code::value
T value(T... args)
std
STL namespace.
beast::hash_append
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
std::size_t
std::is_pointer
std::memmove
T memmove(T... args)
unordered_map
type_traits
set
beast::detail::for_each_item
void for_each_item(...) noexcept
Definition: hash_append.h:425
beast
Definition: base_uint.h:641
string