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
27/*
28
29Workaround for overzealous clang warning, which trips on libstdc++ headers
30
31 In file included from
32 /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/stl_algo.h:61:
33 /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/stl_tempbuf.h:263:8:
34 error: 'get_temporary_buffer<std::pair<ripple::Quality, const
35 std::vector<std::unique_ptr<ripple::Step>> *>>' is deprecated
36 [-Werror,-Wdeprecated-declarations] 263 |
37 std::get_temporary_buffer<value_type>(_M_original_len));
38 ^
39*/
40
41#if defined(__clang__)
42#pragma clang diagnostic push
43#pragma clang diagnostic ignored "-Wdeprecated"
44#pragma clang diagnostic ignored "-Wdeprecated-declarations"
45#endif
46
47#include <functional>
48
49#if defined(__clang__)
50#pragma clang diagnostic pop
51#endif
52
53#include <array>
54#include <chrono>
55#include <cstring>
56#include <memory>
57#include <string>
58#include <system_error>
59#include <tuple>
60#include <type_traits>
61#include <unordered_map>
62#include <unordered_set>
63#include <utility>
64#include <vector>
65
66namespace beast {
67
68namespace detail {
69
70template <class T>
71/*constexpr*/
72inline void
74{
75 unsigned char* bytes = static_cast<unsigned char*>(
76 std::memmove(std::addressof(t), std::addressof(t), sizeof(T)));
77 for (unsigned i = 0; i < sizeof(T) / 2; ++i)
78 std::swap(bytes[i], bytes[sizeof(T) - 1 - i]);
79}
80
81template <class T>
82/*constexpr*/
83inline void
85{
86}
87
88template <class T>
89/*constexpr*/
90inline void
92{
94}
95
96template <class T, class Hasher>
97/*constexpr*/
98inline void
99maybe_reverse_bytes(T& t, Hasher&)
100{
102 t,
104 bool,
105 Hasher::endian != boost::endian::order::native>{});
106}
107
108} // namespace detail
109
110// is_uniquely_represented<T>
111
112// A type T is contiguously hashable if for all combinations of two values of
113// a type, say x and y, if x == y, then it must also be true that
114// memcmp(addressof(x), addressof(y), sizeof(T)) == 0. I.e. if x == y,
115// then x and y have the same bit pattern representation.
116
117template <class T>
119 : public std::integral_constant<
120 bool,
121 std::is_integral<T>::value || std::is_enum<T>::value ||
122 std::is_pointer<T>::value>
123{
124 explicit is_uniquely_represented() = default;
125};
126
127template <class T>
129{
130 explicit is_uniquely_represented() = default;
131};
132
133template <class T>
135{
136 explicit is_uniquely_represented() = default;
137};
138
139template <class T>
140struct is_uniquely_represented<T const volatile>
141 : public is_uniquely_represented<T>
142{
143 explicit is_uniquely_represented() = default;
144};
145
146// is_uniquely_represented<std::pair<T, U>>
147
148template <class T, class U>
149struct is_uniquely_represented<std::pair<T, U>>
150 : public std::integral_constant<
151 bool,
152 is_uniquely_represented<T>::value &&
153 is_uniquely_represented<U>::value &&
154 sizeof(T) + sizeof(U) == sizeof(std::pair<T, U>)>
155{
156 explicit is_uniquely_represented() = default;
157};
158
159// is_uniquely_represented<std::tuple<T...>>
160
161template <class... T>
162struct is_uniquely_represented<std::tuple<T...>>
163 : public std::integral_constant<
164 bool,
165 std::conjunction_v<is_uniquely_represented<T>...> &&
166 sizeof(std::tuple<T...>) == (sizeof(T) + ...)>
167{
168 explicit is_uniquely_represented() = default;
169};
170
171// is_uniquely_represented<T[N]>
172
173template <class T, std::size_t N>
175{
176 explicit is_uniquely_represented() = default;
177};
178
179// is_uniquely_represented<std::array<T, N>>
180
181template <class T, std::size_t N>
182struct is_uniquely_represented<std::array<T, N>>
183 : public std::integral_constant<
184 bool,
185 is_uniquely_represented<T>::value &&
186 sizeof(T) * N == sizeof(std::array<T, N>)>
187{
188 explicit is_uniquely_represented() = default;
189};
190
205template <class T, class HashAlgorithm>
207 : public std::integral_constant<
208 bool,
209 is_uniquely_represented<T>::value &&
210 (sizeof(T) == 1 ||
211 HashAlgorithm::endian == boost::endian::order::native)>
212{
213 explicit is_contiguously_hashable() = default;
214};
215
216template <class T, std::size_t N, class HashAlgorithm>
217struct is_contiguously_hashable<T[N], HashAlgorithm>
218 : public std::integral_constant<
219 bool,
220 is_uniquely_represented<T[N]>::value &&
221 (sizeof(T) == 1 ||
222 HashAlgorithm::endian == boost::endian::order::native)>
223{
224 explicit is_contiguously_hashable() = default;
225};
228//------------------------------------------------------------------------------
229
255// scalars
256
257template <class Hasher, class T>
259hash_append(Hasher& h, T const& t) noexcept
260{
261 h(std::addressof(t), sizeof(t));
262}
263
264template <class Hasher, class T>
265inline std::enable_if_t<
266 !is_contiguously_hashable<T, Hasher>::value &&
269hash_append(Hasher& h, T t) noexcept
270{
272 h(std::addressof(t), sizeof(t));
273}
274
275template <class Hasher, class T>
277hash_append(Hasher& h, T t) noexcept
278{
279 if (t == 0)
280 t = 0;
282 h(&t, sizeof(t));
283}
284
285template <class Hasher>
286inline void
287hash_append(Hasher& h, std::nullptr_t) noexcept
288{
289 void const* p = nullptr;
291 h(&p, sizeof(p));
292}
293
294// Forward declarations for ADL purposes
295
296template <class Hasher, class T, std::size_t N>
298hash_append(Hasher& h, T (&a)[N]) noexcept;
299
300template <class Hasher, class CharT, class Traits, class Alloc>
303 Hasher& h,
305
306template <class Hasher, class CharT, class Traits, class Alloc>
309 Hasher& h,
311
312template <class Hasher, class T, class U>
314hash_append(Hasher& h, std::pair<T, U> const& p) noexcept;
315
316template <class Hasher, class T, class Alloc>
318hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
319
320template <class Hasher, class T, class Alloc>
322hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
323
324template <class Hasher, class T, std::size_t N>
326hash_append(Hasher& h, std::array<T, N> const& a) noexcept;
327
328template <class Hasher, class... T>
329std::enable_if_t<!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
330hash_append(Hasher& h, std::tuple<T...> const& t) noexcept;
331
332template <class Hasher, class Key, class T, class Hash, class Pred, class Alloc>
333void
335
336template <class Hasher, class Key, class Hash, class Pred, class Alloc>
337void
339
340template <class Hasher, class Key, class Compare, class Alloc>
343 Hasher& h,
344 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
345template <class Hasher, class Key, class Compare, class Alloc>
348 Hasher& h,
349 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
350template <class Hasher, class T0, class T1, class... T>
351void
352hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
353
354// c-array
355
356template <class Hasher, class T, std::size_t N>
358hash_append(Hasher& h, T (&a)[N]) noexcept
359{
360 for (auto const& t : a)
361 hash_append(h, t);
362}
363
364// basic_string
365
366template <class Hasher, class CharT, class Traits, class Alloc>
369 Hasher& h,
371{
372 for (auto c : s)
373 hash_append(h, c);
374 hash_append(h, s.size());
375}
376
377template <class Hasher, class CharT, class Traits, class Alloc>
380 Hasher& h,
382{
383 h(s.data(), s.size() * sizeof(CharT));
384 hash_append(h, s.size());
385}
386
387// pair
388
389template <class Hasher, class T, class U>
390inline std::enable_if_t<
391 !is_contiguously_hashable<std::pair<T, U>, Hasher>::value>
392hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
393{
394 hash_append(h, p.first, p.second);
395}
396
397// vector
398
399template <class Hasher, class T, class Alloc>
401hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
402{
403 for (auto const& t : v)
404 hash_append(h, t);
405 hash_append(h, v.size());
406}
407
408template <class Hasher, class T, class Alloc>
410hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
411{
412 h(v.data(), v.size() * sizeof(T));
413 hash_append(h, v.size());
414}
415
416// array
417
418template <class Hasher, class T, std::size_t N>
420hash_append(Hasher& h, std::array<T, N> const& a) noexcept
421{
422 for (auto const& t : a)
423 hash_append(h, t);
424}
425
426template <class Hasher, class Key, class Compare, class Alloc>
429 Hasher& h,
430 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
431{
432 for (auto const& t : v)
433 hash_append(h, t);
434}
435template <class Hasher, class Key, class Compare, class Alloc>
438 Hasher& h,
439 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
440{
441 h(&(v.begin()), v.size() * sizeof(Key));
442}
443// tuple
444
445namespace detail {
446
447inline void
448for_each_item(...) noexcept
449{
450}
451
452template <class Hasher, class T>
453inline int
454hash_one(Hasher& h, T const& t) noexcept
455{
456 hash_append(h, t);
457 return 0;
458}
459
460template <class Hasher, class... T, std::size_t... I>
461inline void
463 Hasher& h,
464 std::tuple<T...> const& t,
466{
467 for_each_item(hash_one(h, std::get<I>(t))...);
468}
469
470} // namespace detail
471
472template <class Hasher, class... T>
473inline std::enable_if_t<
474 !is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
475hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
476{
478}
479
480// shared_ptr
481
482template <class Hasher, class T>
483inline void
484hash_append(Hasher& h, std::shared_ptr<T> const& p) noexcept
485{
486 hash_append(h, p.get());
487}
488
489// chrono
490
491template <class Hasher, class Rep, class Period>
492inline void
494{
495 hash_append(h, d.count());
496}
497
498template <class Hasher, class Clock, class Duration>
499inline void
501 Hasher& h,
503{
504 hash_append(h, tp.time_since_epoch());
505}
506
507// variadic
508
509template <class Hasher, class T0, class T1, class... T>
510inline void
511hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept
512{
513 hash_append(h, t0);
514 hash_append(h, t1, t...);
515}
516
517// error_code
518
519template <class HashAlgorithm>
520inline void
521hash_append(HashAlgorithm& h, std::error_code const& ec)
522{
523 hash_append(h, ec.value(), &ec.category());
524}
525
526} // namespace beast
527
528#endif
T addressof(T... args)
T category(T... args)
T memmove(T... args)
void reverse_bytes(T &t)
Definition: hash_append.h:73
int hash_one(Hasher &h, T const &t) noexcept
Definition: hash_append.h:454
void maybe_reverse_bytes(T &t, std::false_type)
Definition: hash_append.h:84
void tuple_hash(Hasher &h, std::tuple< T... > const &t, std::index_sequence< I... >) noexcept
Definition: hash_append.h:462
void for_each_item(...) noexcept
Definition: hash_append.h:448
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:259
STL namespace.
Metafunction returning true if the type can be hashed in one call.
Definition: hash_append.h:212
T swap(T... args)
T value(T... args)