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/endian.h>
25 #include <ripple/beast/hash/meta.h>
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 <unordered_map>
38 #include <unordered_set>
39 #include <type_traits>
40 #include <utility>
41 #include <vector>
42 #include <boost/container/flat_set.hpp>
43 
44 namespace beast {
45 
46 namespace detail {
47 
48 template <class T>
49 /*constexpr*/
50 inline
51 void
53 {
54  unsigned char* bytes = static_cast<unsigned char*>(std::memmove(std::addressof(t),
55  std::addressof(t),
56  sizeof(T)));
57  for (unsigned i = 0; i < sizeof(T)/2; ++i)
58  std::swap(bytes[i], bytes[sizeof(T)-1-i]);
59 }
60 
61 template <class T>
62 /*constexpr*/
63 inline
64 void
66 {
67 }
68 
69 template <class T>
70 /*constexpr*/
71 inline
72 void
74 {
75  reverse_bytes(t);
76 }
77 
78 template <class T, class Hasher>
79 /*constexpr*/
80 inline
81 void
82 maybe_reverse_bytes(T& t, Hasher&)
83 {
85  Hasher::endian != endian::native>{});
86 }
87 
88 } // detail
89 
90 // is_uniquely_represented<T>
91 
92 // A type T is contiguously hashable if for all combinations of two values of
93 // a type, say x and y, if x == y, then it must also be true that
94 // memcmp(addressof(x), addressof(y), sizeof(T)) == 0. I.e. if x == y,
95 // then x and y have the same bit pattern representation.
96 
97 template <class T>
99  : public std::integral_constant<bool, std::is_integral<T>::value ||
100  std::is_enum<T>::value ||
101  std::is_pointer<T>::value>
102 {
103  explicit is_uniquely_represented() = default;
104 };
105 
106 template <class T>
107 struct is_uniquely_represented<T const>
108  : public is_uniquely_represented<T>
109 {
110  explicit is_uniquely_represented() = default;
111 };
112 
113 template <class T>
114 struct is_uniquely_represented<T volatile>
115  : public is_uniquely_represented<T>
116 {
117  explicit is_uniquely_represented() = default;
118 };
119 
120 template <class T>
121 struct is_uniquely_represented<T const volatile>
122  : public is_uniquely_represented<T>
123 {
124  explicit is_uniquely_represented() = default;
125 };
126 
127 // is_uniquely_represented<std::pair<T, U>>
128 
129 template <class T, class U>
130 struct is_uniquely_represented<std::pair<T, U>>
131  : public std::integral_constant<bool, is_uniquely_represented<T>::value &&
132  is_uniquely_represented<U>::value &&
133  sizeof(T) + sizeof(U) == sizeof(std::pair<T, U>)>
134 {
135  explicit is_uniquely_represented() = default;
136 };
137 
138 // is_uniquely_represented<std::tuple<T...>>
139 
140 template <class ...T>
141 struct is_uniquely_represented<std::tuple<T...>>
142  : public std::integral_constant<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  : public is_uniquely_represented<T>
154 {
155  explicit is_uniquely_represented() = default;
156 };
157 
158 // is_uniquely_represented<std::array<T, N>>
159 
160 template <class T, std::size_t N>
161 struct is_uniquely_represented<std::array<T, N>>
162  : public std::integral_constant<bool, 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<bool, is_uniquely_represented<T>::value &&
185  (sizeof(T) == 1 ||
186  HashAlgorithm::endian == endian::native)>
187 {
188  explicit is_contiguously_hashable() = default;
189 };
190 
191 template <class T, std::size_t N, class HashAlgorithm>
192 struct is_contiguously_hashable<T[N], HashAlgorithm>
193  : public std::integral_constant<bool, is_uniquely_represented<T[N]>::value &&
194  (sizeof(T) == 1 ||
195  HashAlgorithm::endian == endian::native)>
196 {
197  explicit is_contiguously_hashable() = default;
198 };
201 //------------------------------------------------------------------------------
202 
228 // scalars
229 
230 template <class Hasher, class T>
231 inline
233 <
235 >
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
244 <
245  !is_contiguously_hashable<T, Hasher>::value &&
247 >
248 hash_append(Hasher& h, T t) noexcept
249 {
251  h(std::addressof(t), sizeof(t));
252 }
253 
254 template <class Hasher, class T>
255 inline
257 <
259 >
260 hash_append(Hasher& h, T t) noexcept
261 {
262  if (t == 0)
263  t = 0;
265  h(&t, sizeof(t));
266 }
267 
268 template <class Hasher>
269 inline
270 void
271 hash_append(Hasher& h, std::nullptr_t) noexcept
272 {
273  void const* p = nullptr;
275  h(&p, sizeof(p));
276 }
277 
278 // Forward declarations for ADL purposes
279 
280 template <class Hasher, class T, std::size_t N>
282 <
283  !is_contiguously_hashable<T, Hasher>::value
284 >
285 hash_append(Hasher& h, T (&a)[N]) noexcept;
286 
287 template <class Hasher, class CharT, class Traits, class Alloc>
289 <
290  !is_contiguously_hashable<CharT, Hasher>::value
291 >
292 hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
293 
294 template <class Hasher, class CharT, class Traits, class Alloc>
296 <
297  is_contiguously_hashable<CharT, Hasher>::value
298 >
299 hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
300 
301 template <class Hasher, class T, class U>
303 <
304  !is_contiguously_hashable<std::pair<T, U>, Hasher>::value
305 >
306 hash_append (Hasher& h, std::pair<T, U> const& p) noexcept;
307 
308 template <class Hasher, class T, class Alloc>
310 <
311  !is_contiguously_hashable<T, Hasher>::value
312 >
313 hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
314 
315 template <class Hasher, class T, class Alloc>
317 <
318  is_contiguously_hashable<T, Hasher>::value
319 >
320 hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
321 
322 template <class Hasher, class T, std::size_t N>
324 <
325  !is_contiguously_hashable<std::array<T, N>, Hasher>::value
326 >
327 hash_append(Hasher& h, std::array<T, N> const& a) noexcept;
328 
329 template <class Hasher, class ...T>
331 <
332  !is_contiguously_hashable<std::tuple<T...>, Hasher>::value
333 >
334 hash_append(Hasher& h, std::tuple<T...> const& t) noexcept;
335 
336 template <class Hasher, class Key, class T, class Hash, class Pred, class Alloc>
337 void
339 
340 template <class Hasher, class Key, class Hash, class Pred, class Alloc>
341 void
343 
344 template <class Hasher, class Key, class Compare, class Alloc>
346 <
347  !is_contiguously_hashable<Key, Hasher>::value
348 >
349 hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
350 template <class Hasher, class Key, class Compare, class Alloc>
352 <
353  is_contiguously_hashable<Key, Hasher>::value
354 >
355 hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
356 template <class Hasher, class T0, class T1, class ...T>
357 void
358 hash_append (Hasher& h, T0 const& t0, T1 const& t1, T const& ...t) noexcept;
359 
360 // c-array
361 
362 template <class Hasher, class T, std::size_t N>
364 <
365  !is_contiguously_hashable<T, Hasher>::value
366 >
367 hash_append(Hasher& h, T (&a)[N]) noexcept
368 {
369  for (auto const& t : a)
370  hash_append(h, t);
371 }
372 
373 // basic_string
374 
375 template <class Hasher, class CharT, class Traits, class Alloc>
376 inline
378 <
379  !is_contiguously_hashable<CharT, Hasher>::value
380 >
382 {
383  for (auto c : s)
384  hash_append(h, c);
385  hash_append(h, s.size());
386 }
387 
388 template <class Hasher, class CharT, class Traits, class Alloc>
389 inline
391 <
392  is_contiguously_hashable<CharT, Hasher>::value
393 >
395 {
396  h(s.data(), s.size()*sizeof(CharT));
397  hash_append(h, s.size());
398 }
399 
400 // pair
401 
402 template <class Hasher, class T, class U>
403 inline
405 <
406  !is_contiguously_hashable<std::pair<T, U>, Hasher>::value
407 >
408 hash_append (Hasher& h, std::pair<T, U> const& p) noexcept
409 {
410  hash_append (h, p.first, p.second);
411 }
412 
413 // vector
414 
415 template <class Hasher, class T, class Alloc>
416 inline
418 <
419  !is_contiguously_hashable<T, Hasher>::value
420 >
421 hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
422 {
423  for (auto const& t : v)
424  hash_append(h, t);
425  hash_append(h, v.size());
426 }
427 
428 template <class Hasher, class T, class Alloc>
429 inline
431 <
432  is_contiguously_hashable<T, Hasher>::value
433 >
434 hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
435 {
436  h(v.data(), v.size()*sizeof(T));
437  hash_append(h, v.size());
438 }
439 
440 // array
441 
442 template <class Hasher, class T, std::size_t N>
444 <
445  !is_contiguously_hashable<std::array<T, N>, Hasher>::value
446 >
447 hash_append(Hasher& h, std::array<T, N> const& a) noexcept
448 {
449  for (auto const& t : a)
450  hash_append(h, t);
451 }
452 
453 template <class Hasher, class Key, class Compare, class Alloc>
455 <
456  !is_contiguously_hashable<Key, Hasher>::value
457 >
458 hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
459 {
460  for (auto const& t : v)
461  hash_append(h, t);
462 }
463 template <class Hasher, class Key, class Compare, class Alloc>
465 <
466  is_contiguously_hashable<Key, Hasher>::value
467 >
468 hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
469 {
470  h(&(v.begin()), v.size()*sizeof(Key));
471 }
472 // tuple
473 
474 namespace detail
475 {
476 
477 inline
478 void
479 for_each_item(...) noexcept
480 {
481 }
482 
483 template <class Hasher, class T>
484 inline
485 int
486 hash_one(Hasher& h, T const& t) noexcept
487 {
488  hash_append(h, t);
489  return 0;
490 }
491 
492 template <class Hasher, class ...T, std::size_t ...I>
493 inline
494 void
496 {
497  for_each_item(hash_one(h, std::get<I>(t))...);
498 }
499 
500 } // detail
501 
502 template <class Hasher, class ...T>
503 inline
505 <
506  !is_contiguously_hashable<std::tuple<T...>, Hasher>::value
507 >
508 hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
509 {
511 }
512 
513 // shared_ptr
514 
515 template <class Hasher, class T>
516 inline
517 void
518 hash_append (Hasher& h, std::shared_ptr<T> const& p) noexcept
519 {
520  hash_append(h, p.get());
521 }
522 
523 // chrono
524 
525 template <class Hasher, class Rep, class Period>
526 inline
527 void
528 hash_append (Hasher& h, std::chrono::duration<Rep, Period> const& d) noexcept
529 {
530  hash_append(h, d.count());
531 }
532 
533 template <class Hasher, class Clock, class Duration>
534 inline
535 void
537 {
538  hash_append(h, tp.time_since_epoch());
539 }
540 
541 // variadic
542 
543 template <class Hasher, class T0, class T1, class ...T>
544 inline
545 void
546 hash_append (Hasher& h, T0 const& t0, T1 const& t1, T const& ...t) noexcept
547 {
548  hash_append(h, t0);
549  hash_append(h, t1, t...);
550 }
551 
552 // error_code
553 
554 template <class HashAlgorithm>
555 inline
556 void
557 hash_append(HashAlgorithm& h, std::error_code const& ec)
558 {
559  hash_append(h, ec.value(), &ec.category());
560 }
561 
562 } // beast
563 
564 #endif
std::false_type
std::basic_string
STL class.
std::shared_ptr
STL class.
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
utility
cstring
system_error
beast::detail::hash_one
int hash_one(Hasher &h, T const &t) noexcept
Definition: hash_append.h:486
beast::detail::maybe_reverse_bytes
void maybe_reverse_bytes(T &t, std::false_type)
Definition: hash_append.h:65
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:98
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:52
std::enable_if_t
chrono
beast::endian::native
@ native
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:495
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::is_floating_point
std
STL namespace.
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:479
beast
Definition: base_uint.h:582
string