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 <ripple/beast/hash/meta.h>
25 #include <boost/container/flat_set.hpp>
26 #include <boost/endian/conversion.hpp>
27 #include <array>
28 #include <chrono>
29 #include <cstdint>
30 #include <cstring>
31 #include <functional>
32 #include <map>
33 #include <memory>
34 #include <set>
35 #include <string>
36 #include <system_error>
37 #include <tuple>
38 #include <type_traits>
39 #include <unordered_map>
40 #include <unordered_set>
41 #include <utility>
42 #include <vector>
43 
44 namespace beast {
45 
46 namespace detail {
47 
48 template <class T>
49 /*constexpr*/
50 inline void
52 {
53  unsigned char* bytes = static_cast<unsigned char*>(
54  std::memmove(std::addressof(t), std::addressof(t), sizeof(T)));
55  for (unsigned i = 0; i < sizeof(T) / 2; ++i)
56  std::swap(bytes[i], bytes[sizeof(T) - 1 - i]);
57 }
58 
59 template <class T>
60 /*constexpr*/
61 inline void
63 {
64 }
65 
66 template <class T>
67 /*constexpr*/
68 inline void
70 {
71  reverse_bytes(t);
72 }
73 
74 template <class T, class Hasher>
75 /*constexpr*/
76 inline void
77 maybe_reverse_bytes(T& t, Hasher&)
78 {
80  t,
82  bool,
83  Hasher::endian != boost::endian::order::native>{});
84 }
85 
86 } // namespace detail
87 
88 // is_uniquely_represented<T>
89 
90 // A type T is contiguously hashable if for all combinations of two values of
91 // a type, say x and y, if x == y, then it must also be true that
92 // memcmp(addressof(x), addressof(y), sizeof(T)) == 0. I.e. if x == y,
93 // then x and y have the same bit pattern representation.
94 
95 template <class T>
97  : public std::integral_constant<
98  bool,
99  std::is_integral<T>::value || std::is_enum<T>::value ||
100  std::is_pointer<T>::value>
101 {
102  explicit is_uniquely_represented() = default;
103 };
104 
105 template <class T>
107 {
108  explicit is_uniquely_represented() = default;
109 };
110 
111 template <class T>
112 struct is_uniquely_represented<T volatile> : public is_uniquely_represented<T>
113 {
114  explicit is_uniquely_represented() = default;
115 };
116 
117 template <class T>
118 struct is_uniquely_represented<T const volatile>
119  : public is_uniquely_represented<T>
120 {
121  explicit is_uniquely_represented() = default;
122 };
123 
124 // is_uniquely_represented<std::pair<T, U>>
125 
126 template <class T, class U>
127 struct is_uniquely_represented<std::pair<T, U>>
128  : public std::integral_constant<
129  bool,
130  is_uniquely_represented<T>::value &&
131  is_uniquely_represented<U>::value &&
132  sizeof(T) + sizeof(U) == sizeof(std::pair<T, U>)>
133 {
134  explicit is_uniquely_represented() = default;
135 };
136 
137 // is_uniquely_represented<std::tuple<T...>>
138 
139 template <class... T>
140 struct is_uniquely_represented<std::tuple<T...>>
141  : public std::integral_constant<
142  bool,
143  static_and<is_uniquely_represented<T>::value...>::value &&
144  static_sum<sizeof(T)...>::value == sizeof(std::tuple<T...>)>
145 {
146  explicit is_uniquely_represented() = default;
147 };
148 
149 // is_uniquely_represented<T[N]>
150 
151 template <class T, std::size_t N>
153 {
154  explicit is_uniquely_represented() = default;
155 };
156 
157 // is_uniquely_represented<std::array<T, N>>
158 
159 template <class T, std::size_t N>
160 struct is_uniquely_represented<std::array<T, N>>
161  : public std::integral_constant<
162  bool,
163  is_uniquely_represented<T>::value &&
164  sizeof(T) * N == sizeof(std::array<T, N>)>
165 {
166  explicit is_uniquely_represented() = default;
167 };
168 
183 template <class T, class HashAlgorithm>
185  : public std::integral_constant<
186  bool,
187  is_uniquely_represented<T>::value &&
188  (sizeof(T) == 1 ||
189  HashAlgorithm::endian == boost::endian::order::native)>
190 {
191  explicit is_contiguously_hashable() = default;
192 };
193 
194 template <class T, std::size_t N, class HashAlgorithm>
195 struct is_contiguously_hashable<T[N], HashAlgorithm>
196  : public std::integral_constant<
197  bool,
198  is_uniquely_represented<T[N]>::value &&
199  (sizeof(T) == 1 ||
200  HashAlgorithm::endian == boost::endian::order::native)>
201 {
202  explicit is_contiguously_hashable() = default;
203 };
206 //------------------------------------------------------------------------------
207 
233 // scalars
234 
235 template <class Hasher, class T>
237 hash_append(Hasher& h, T const& t) noexcept
238 {
239  h(std::addressof(t), sizeof(t));
240 }
241 
242 template <class Hasher, class T>
243 inline std::enable_if_t<
244  !is_contiguously_hashable<T, Hasher>::value &&
247 hash_append(Hasher& h, T t) noexcept
248 {
250  h(std::addressof(t), sizeof(t));
251 }
252 
253 template <class Hasher, class T>
255 hash_append(Hasher& h, T t) noexcept
256 {
257  if (t == 0)
258  t = 0;
260  h(&t, sizeof(t));
261 }
262 
263 template <class Hasher>
264 inline void
265 hash_append(Hasher& h, std::nullptr_t) noexcept
266 {
267  void const* p = nullptr;
269  h(&p, sizeof(p));
270 }
271 
272 // Forward declarations for ADL purposes
273 
274 template <class Hasher, class T, std::size_t N>
276 hash_append(Hasher& h, T (&a)[N]) noexcept;
277 
278 template <class Hasher, class CharT, class Traits, class Alloc>
281  Hasher& h,
282  std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
283 
284 template <class Hasher, class CharT, class Traits, class Alloc>
287  Hasher& h,
288  std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
289 
290 template <class Hasher, class T, class U>
292 hash_append(Hasher& h, std::pair<T, U> const& p) noexcept;
293 
294 template <class Hasher, class T, class Alloc>
296 hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
297 
298 template <class Hasher, class T, class Alloc>
300 hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
301 
302 template <class Hasher, class T, std::size_t N>
304 hash_append(Hasher& h, std::array<T, N> const& a) noexcept;
305 
306 template <class Hasher, class... T>
307 std::enable_if_t<!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
308 hash_append(Hasher& h, std::tuple<T...> const& t) noexcept;
309 
310 template <class Hasher, class Key, class T, class Hash, class Pred, class Alloc>
311 void
313 
314 template <class Hasher, class Key, class Hash, class Pred, class Alloc>
315 void
317 
318 template <class Hasher, class Key, class Compare, class Alloc>
321  Hasher& h,
322  boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
323 template <class Hasher, class Key, class Compare, class Alloc>
326  Hasher& h,
327  boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
328 template <class Hasher, class T0, class T1, class... T>
329 void
330 hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
331 
332 // c-array
333 
334 template <class Hasher, class T, std::size_t N>
336 hash_append(Hasher& h, T (&a)[N]) noexcept
337 {
338  for (auto const& t : a)
339  hash_append(h, t);
340 }
341 
342 // basic_string
343 
344 template <class Hasher, class CharT, class Traits, class Alloc>
347  Hasher& h,
348  std::basic_string<CharT, Traits, Alloc> const& s) noexcept
349 {
350  for (auto c : s)
351  hash_append(h, c);
352  hash_append(h, s.size());
353 }
354 
355 template <class Hasher, class CharT, class Traits, class Alloc>
358  Hasher& h,
359  std::basic_string<CharT, Traits, Alloc> const& s) noexcept
360 {
361  h(s.data(), s.size() * sizeof(CharT));
362  hash_append(h, s.size());
363 }
364 
365 // pair
366 
367 template <class Hasher, class T, class U>
368 inline std::enable_if_t<
369  !is_contiguously_hashable<std::pair<T, U>, Hasher>::value>
370 hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
371 {
372  hash_append(h, p.first, p.second);
373 }
374 
375 // vector
376 
377 template <class Hasher, class T, class Alloc>
379 hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
380 {
381  for (auto const& t : v)
382  hash_append(h, t);
383  hash_append(h, v.size());
384 }
385 
386 template <class Hasher, class T, class Alloc>
388 hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
389 {
390  h(v.data(), v.size() * sizeof(T));
391  hash_append(h, v.size());
392 }
393 
394 // array
395 
396 template <class Hasher, class T, std::size_t N>
398 hash_append(Hasher& h, std::array<T, N> const& a) noexcept
399 {
400  for (auto const& t : a)
401  hash_append(h, t);
402 }
403 
404 template <class Hasher, class Key, class Compare, class Alloc>
407  Hasher& h,
408  boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
409 {
410  for (auto const& t : v)
411  hash_append(h, t);
412 }
413 template <class Hasher, class Key, class Compare, class Alloc>
416  Hasher& h,
417  boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
418 {
419  h(&(v.begin()), v.size() * sizeof(Key));
420 }
421 // tuple
422 
423 namespace detail {
424 
425 inline void
426 for_each_item(...) noexcept
427 {
428 }
429 
430 template <class Hasher, class T>
431 inline int
432 hash_one(Hasher& h, T const& t) noexcept
433 {
434  hash_append(h, t);
435  return 0;
436 }
437 
438 template <class Hasher, class... T, std::size_t... I>
439 inline void
441  Hasher& h,
442  std::tuple<T...> const& t,
443  std::index_sequence<I...>) noexcept
444 {
445  for_each_item(hash_one(h, std::get<I>(t))...);
446 }
447 
448 } // namespace detail
449 
450 template <class Hasher, class... T>
451 inline std::enable_if_t<
452  !is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
453 hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
454 {
456 }
457 
458 // shared_ptr
459 
460 template <class Hasher, class T>
461 inline void
462 hash_append(Hasher& h, std::shared_ptr<T> const& p) noexcept
463 {
464  hash_append(h, p.get());
465 }
466 
467 // chrono
468 
469 template <class Hasher, class Rep, class Period>
470 inline void
471 hash_append(Hasher& h, std::chrono::duration<Rep, Period> const& d) noexcept
472 {
473  hash_append(h, d.count());
474 }
475 
476 template <class Hasher, class Clock, class Duration>
477 inline void
479  Hasher& h,
480  std::chrono::time_point<Clock, Duration> const& tp) noexcept
481 {
482  hash_append(h, tp.time_since_epoch());
483 }
484 
485 // variadic
486 
487 template <class Hasher, class T0, class T1, class... T>
488 inline void
489 hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept
490 {
491  hash_append(h, t0);
492  hash_append(h, t1, t...);
493 }
494 
495 // error_code
496 
497 template <class HashAlgorithm>
498 inline void
499 hash_append(HashAlgorithm& h, std::error_code const& ec)
500 {
501  hash_append(h, ec.value(), &ec.category());
502 }
503 
504 } // namespace beast
505 
506 #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:432
beast::detail::maybe_reverse_bytes
void maybe_reverse_bytes(T &t, std::false_type)
Definition: hash_append.h:62
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:96
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:51
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:184
beast::detail::tuple_hash
void tuple_hash(Hasher &h, std::tuple< T... > const &t, std::index_sequence< I... >) noexcept
Definition: hash_append.h:440
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:237
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:426
beast
Definition: base_uint.h:585
string