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#include <array>
28#include <chrono>
29#include <cstring>
30#include <functional>
31#include <memory>
32#include <string>
33#include <system_error>
34#include <tuple>
35#include <type_traits>
36#include <unordered_map>
37#include <unordered_set>
38#include <utility>
39#include <vector>
40
41namespace beast {
42
43namespace detail {
44
45template <class T>
46/*constexpr*/
47inline void
49{
50 unsigned char* bytes = static_cast<unsigned char*>(
51 std::memmove(std::addressof(t), std::addressof(t), sizeof(T)));
52 for (unsigned i = 0; i < sizeof(T) / 2; ++i)
53 std::swap(bytes[i], bytes[sizeof(T) - 1 - i]);
54}
55
56template <class T>
57/*constexpr*/
58inline void
62
63template <class T>
64/*constexpr*/
65inline void
70
71template <class T, class Hasher>
72/*constexpr*/
73inline void
74maybe_reverse_bytes(T& t, Hasher&)
75{
77 t,
79 bool,
80 Hasher::endian != boost::endian::order::native>{});
81}
82
83} // namespace detail
84
85// is_uniquely_represented<T>
86
87// A type T is contiguously hashable if for all combinations of two values of
88// a type, say x and y, if x == y, then it must also be true that
89// memcmp(addressof(x), addressof(y), sizeof(T)) == 0. I.e. if x == y,
90// then x and y have the same bit pattern representation.
91
92template <class T>
95 bool,
96 std::is_integral<T>::value || std::is_enum<T>::value ||
97 std::is_pointer<T>::value>
98{
99 explicit is_uniquely_represented() = default;
100};
101
102template <class T>
104{
105 explicit is_uniquely_represented() = default;
106};
107
108template <class T>
110{
111 explicit is_uniquely_represented() = default;
112};
113
114template <class T>
115struct is_uniquely_represented<T const volatile>
116 : public is_uniquely_represented<T>
117{
118 explicit is_uniquely_represented() = default;
119};
120
121// is_uniquely_represented<std::pair<T, U>>
122
123template <class T, class U>
124struct is_uniquely_represented<std::pair<T, U>>
125 : public std::integral_constant<
126 bool,
127 is_uniquely_represented<T>::value &&
128 is_uniquely_represented<U>::value &&
129 sizeof(T) + sizeof(U) == sizeof(std::pair<T, U>)>
130{
131 explicit is_uniquely_represented() = default;
132};
133
134// is_uniquely_represented<std::tuple<T...>>
135
136template <class... T>
137struct is_uniquely_represented<std::tuple<T...>>
138 : public std::integral_constant<
139 bool,
140 std::conjunction_v<is_uniquely_represented<T>...> &&
141 sizeof(std::tuple<T...>) == (sizeof(T) + ...)>
142{
143 explicit is_uniquely_represented() = default;
144};
145
146// is_uniquely_represented<T[N]>
147
148template <class T, std::size_t N>
150{
151 explicit is_uniquely_represented() = default;
152};
153
154// is_uniquely_represented<std::array<T, N>>
155
156template <class T, std::size_t N>
157struct is_uniquely_represented<std::array<T, N>>
158 : public std::integral_constant<
159 bool,
160 is_uniquely_represented<T>::value &&
161 sizeof(T) * N == sizeof(std::array<T, N>)>
162{
163 explicit is_uniquely_represented() = default;
164};
165
180template <class T, class HashAlgorithm>
182 : public std::integral_constant<
183 bool,
184 is_uniquely_represented<T>::value &&
185 (sizeof(T) == 1 ||
186 HashAlgorithm::endian == boost::endian::order::native)>
187{
188 explicit is_contiguously_hashable() = default;
189};
190
191template <class T, std::size_t N, class HashAlgorithm>
192struct is_contiguously_hashable<T[N], HashAlgorithm>
193 : public std::integral_constant<
194 bool,
195 is_uniquely_represented<T[N]>::value &&
196 (sizeof(T) == 1 ||
197 HashAlgorithm::endian == boost::endian::order::native)>
198{
199 explicit is_contiguously_hashable() = default;
200};
203//------------------------------------------------------------------------------
204
230// scalars
231
232template <class Hasher, class T>
234hash_append(Hasher& h, T const& t) noexcept
235{
236 h(std::addressof(t), sizeof(t));
237}
238
239template <class Hasher, class T>
240inline std::enable_if_t<
241 !is_contiguously_hashable<T, Hasher>::value &&
244hash_append(Hasher& h, T t) noexcept
245{
247 h(std::addressof(t), sizeof(t));
248}
249
250template <class Hasher, class T>
252hash_append(Hasher& h, T t) noexcept
253{
254 if (t == 0)
255 t = 0;
257 h(&t, sizeof(t));
258}
259
260template <class Hasher>
261inline void
262hash_append(Hasher& h, std::nullptr_t) noexcept
263{
264 void const* p = nullptr;
266 h(&p, sizeof(p));
267}
268
269// Forward declarations for ADL purposes
270
271template <class Hasher, class T, std::size_t N>
273hash_append(Hasher& h, T (&a)[N]) noexcept;
274
275template <class Hasher, class CharT, class Traits, class Alloc>
278 Hasher& h,
280
281template <class Hasher, class CharT, class Traits, class Alloc>
284 Hasher& h,
286
287template <class Hasher, class T, class U>
289hash_append(Hasher& h, std::pair<T, U> const& p) noexcept;
290
291template <class Hasher, class T, class Alloc>
293hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
294
295template <class Hasher, class T, class Alloc>
297hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
298
299template <class Hasher, class T, std::size_t N>
301hash_append(Hasher& h, std::array<T, N> const& a) noexcept;
302
303template <class Hasher, class... T>
304std::enable_if_t<!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
305hash_append(Hasher& h, std::tuple<T...> const& t) noexcept;
306
307template <class Hasher, class Key, class T, class Hash, class Pred, class Alloc>
308void
310
311template <class Hasher, class Key, class Hash, class Pred, class Alloc>
312void
314
315template <class Hasher, class Key, class Compare, class Alloc>
318 Hasher& h,
319 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
320template <class Hasher, class Key, class Compare, class Alloc>
323 Hasher& h,
324 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
325template <class Hasher, class T0, class T1, class... T>
326void
327hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
328
329// c-array
330
331template <class Hasher, class T, std::size_t N>
333hash_append(Hasher& h, T (&a)[N]) noexcept
334{
335 for (auto const& t : a)
336 hash_append(h, t);
337}
338
339// basic_string
340
341template <class Hasher, class CharT, class Traits, class Alloc>
344 Hasher& h,
346{
347 for (auto c : s)
348 hash_append(h, c);
349 hash_append(h, s.size());
350}
351
352template <class Hasher, class CharT, class Traits, class Alloc>
355 Hasher& h,
357{
358 h(s.data(), s.size() * sizeof(CharT));
359 hash_append(h, s.size());
360}
361
362// pair
363
364template <class Hasher, class T, class U>
365inline std::enable_if_t<
366 !is_contiguously_hashable<std::pair<T, U>, Hasher>::value>
367hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
368{
369 hash_append(h, p.first, p.second);
370}
371
372// vector
373
374template <class Hasher, class T, class Alloc>
376hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
377{
378 for (auto const& t : v)
379 hash_append(h, t);
380 hash_append(h, v.size());
381}
382
383template <class Hasher, class T, class Alloc>
385hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
386{
387 h(v.data(), v.size() * sizeof(T));
388 hash_append(h, v.size());
389}
390
391// array
392
393template <class Hasher, class T, std::size_t N>
395hash_append(Hasher& h, std::array<T, N> const& a) noexcept
396{
397 for (auto const& t : a)
398 hash_append(h, t);
399}
400
401template <class Hasher, class Key, class Compare, class Alloc>
404 Hasher& h,
405 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
406{
407 for (auto const& t : v)
408 hash_append(h, t);
409}
410template <class Hasher, class Key, class Compare, class Alloc>
413 Hasher& h,
414 boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
415{
416 h(&(v.begin()), v.size() * sizeof(Key));
417}
418// tuple
419
420namespace detail {
421
422inline void
423for_each_item(...) noexcept
424{
425}
426
427template <class Hasher, class T>
428inline int
429hash_one(Hasher& h, T const& t) noexcept
430{
431 hash_append(h, t);
432 return 0;
433}
434
435template <class Hasher, class... T, std::size_t... I>
436inline void
438 Hasher& h,
439 std::tuple<T...> const& t,
441{
443}
444
445} // namespace detail
446
447template <class Hasher, class... T>
448inline std::enable_if_t<
449 !is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
450hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
451{
453}
454
455// shared_ptr
456
457template <class Hasher, class T>
458inline void
459hash_append(Hasher& h, std::shared_ptr<T> const& p) noexcept
460{
461 hash_append(h, p.get());
462}
463
464// chrono
465
466template <class Hasher, class Rep, class Period>
467inline void
469{
470 hash_append(h, d.count());
471}
472
473template <class Hasher, class Clock, class Duration>
474inline void
476 Hasher& h,
478{
479 hash_append(h, tp.time_since_epoch());
480}
481
482// variadic
483
484template <class Hasher, class T0, class T1, class... T>
485inline void
486hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept
487{
488 hash_append(h, t0);
489 hash_append(h, t1, t...);
490}
491
492// error_code
493
494template <class HashAlgorithm>
495inline void
496hash_append(HashAlgorithm& h, std::error_code const& ec)
497{
498 hash_append(h, ec.value(), &ec.category());
499}
500
501} // namespace beast
502
503#endif
T addressof(T... args)
T category(T... args)
T is_same_v
T memmove(T... args)
void reverse_bytes(T &t)
Definition hash_append.h:48
int hash_one(Hasher &h, T const &t) noexcept
void maybe_reverse_bytes(T &t, std::false_type)
Definition hash_append.h:59
void tuple_hash(Hasher &h, std::tuple< T... > const &t, std::index_sequence< I... >) noexcept
void for_each_item(...) noexcept
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.
STL namespace.
Metafunction returning true if the type can be hashed in one call.
T swap(T... args)
T value(T... args)