//------------------------------------------------------------------------------ /* This file is part of Beast: https://github.com/vinniefalco/Beast Copyright 2014, Howard Hinnant , Vinnie Falco #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace beast { namespace detail { template /*constexpr*/ inline void reverse_bytes(T& t) { unsigned char* bytes = static_cast( std::memmove(std::addressof(t), std::addressof(t), sizeof(T))); for (unsigned i = 0; i < sizeof(T) / 2; ++i) std::swap(bytes[i], bytes[sizeof(T) - 1 - i]); } template /*constexpr*/ inline void maybe_reverse_bytes(T& t, std::false_type) { } template /*constexpr*/ inline void maybe_reverse_bytes(T& t, std::true_type) { reverse_bytes(t); } template /*constexpr*/ inline void maybe_reverse_bytes(T& t, Hasher&) { maybe_reverse_bytes( t, std::integral_constant< bool, Hasher::endian != boost::endian::order::native>{}); } } // namespace detail // is_uniquely_represented // A type T is contiguously hashable if for all combinations of two values of // a type, say x and y, if x == y, then it must also be true that // memcmp(addressof(x), addressof(y), sizeof(T)) == 0. I.e. if x == y, // then x and y have the same bit pattern representation. template struct is_uniquely_represented : public std::integral_constant< bool, std::is_integral::value || std::is_enum::value || std::is_pointer::value> { explicit is_uniquely_represented() = default; }; template struct is_uniquely_represented : public is_uniquely_represented { explicit is_uniquely_represented() = default; }; template struct is_uniquely_represented : public is_uniquely_represented { explicit is_uniquely_represented() = default; }; template struct is_uniquely_represented : public is_uniquely_represented { explicit is_uniquely_represented() = default; }; // is_uniquely_represented> template struct is_uniquely_represented> : public std::integral_constant< bool, is_uniquely_represented::value && is_uniquely_represented::value && sizeof(T) + sizeof(U) == sizeof(std::pair)> { explicit is_uniquely_represented() = default; }; // is_uniquely_represented> template struct is_uniquely_represented> : public std::integral_constant< bool, std::conjunction_v...> && sizeof(std::tuple) == (sizeof(T) + ...)> { explicit is_uniquely_represented() = default; }; // is_uniquely_represented template struct is_uniquely_represented : public is_uniquely_represented { explicit is_uniquely_represented() = default; }; // is_uniquely_represented> template struct is_uniquely_represented> : public std::integral_constant< bool, is_uniquely_represented::value && sizeof(T) * N == sizeof(std::array)> { explicit is_uniquely_represented() = default; }; /** Metafunction returning `true` if the type can be hashed in one call. For `is_contiguously_hashable::value` to be true, then for every combination of possible values of `T` held in `x` and `y`, if `x == y`, then it must be true that `memcmp(&x, &y, sizeof(T))` return 0; i.e. that `x` and `y` are represented by the same bit pattern. For example: A two's complement `int` should be contiguously hashable. Every bit pattern produces a unique value that does not compare equal to any other bit pattern's value. A IEEE floating point should not be contiguously hashable because -0. and 0. have different bit patterns, though they compare equal. */ /** @{ */ template struct is_contiguously_hashable : public std::integral_constant< bool, is_uniquely_represented::value && (sizeof(T) == 1 || HashAlgorithm::endian == boost::endian::order::native)> { explicit is_contiguously_hashable() = default; }; template struct is_contiguously_hashable : public std::integral_constant< bool, is_uniquely_represented::value && (sizeof(T) == 1 || HashAlgorithm::endian == boost::endian::order::native)> { explicit is_contiguously_hashable() = default; }; /** @} */ //------------------------------------------------------------------------------ /** Logically concatenate input data to a `Hasher`. Hasher requirements: `X` is the type `Hasher` `h` is a value of type `x` `p` is a value convertible to `void const*` `n` is a value of type `std::size_t`, greater than zero Expression: `h.append (p, n);` Throws: Never Effect: Adds the input data to the hasher state. Expression: `static_cast(j)` Throws: Never Effect: Returns the reslting hash of all the input data. */ /** @{ */ // scalars template inline std::enable_if_t::value> hash_append(Hasher& h, T const& t) noexcept { h(std::addressof(t), sizeof(t)); } template inline std::enable_if_t< !is_contiguously_hashable::value && (std::is_integral::value || std::is_pointer::value || std::is_enum::value)> hash_append(Hasher& h, T t) noexcept { detail::reverse_bytes(t); h(std::addressof(t), sizeof(t)); } template inline std::enable_if_t::value> hash_append(Hasher& h, T t) noexcept { if (t == 0) t = 0; detail::maybe_reverse_bytes(t, h); h(&t, sizeof(t)); } template inline void hash_append(Hasher& h, std::nullptr_t) noexcept { void const* p = nullptr; detail::maybe_reverse_bytes(p, h); h(&p, sizeof(p)); } // Forward declarations for ADL purposes template std::enable_if_t::value> hash_append(Hasher& h, T (&a)[N]) noexcept; template std::enable_if_t::value> hash_append( Hasher& h, std::basic_string const& s) noexcept; template std::enable_if_t::value> hash_append( Hasher& h, std::basic_string const& s) noexcept; template std::enable_if_t, Hasher>::value> hash_append(Hasher& h, std::pair const& p) noexcept; template std::enable_if_t::value> hash_append(Hasher& h, std::vector const& v) noexcept; template std::enable_if_t::value> hash_append(Hasher& h, std::vector const& v) noexcept; template std::enable_if_t, Hasher>::value> hash_append(Hasher& h, std::array const& a) noexcept; template std::enable_if_t, Hasher>::value> hash_append(Hasher& h, std::tuple const& t) noexcept; template void hash_append(Hasher& h, std::unordered_map const& m); template void hash_append(Hasher& h, std::unordered_set const& s); template std::enable_if_t::value> hash_append( Hasher& h, boost::container::flat_set const& v) noexcept; template std::enable_if_t::value> hash_append( Hasher& h, boost::container::flat_set const& v) noexcept; template void hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept; // c-array template std::enable_if_t::value> hash_append(Hasher& h, T (&a)[N]) noexcept { for (auto const& t : a) hash_append(h, t); } // basic_string template inline std::enable_if_t::value> hash_append( Hasher& h, std::basic_string const& s) noexcept { for (auto c : s) hash_append(h, c); hash_append(h, s.size()); } template inline std::enable_if_t::value> hash_append( Hasher& h, std::basic_string const& s) noexcept { h(s.data(), s.size() * sizeof(CharT)); hash_append(h, s.size()); } // pair template inline std::enable_if_t< !is_contiguously_hashable, Hasher>::value> hash_append(Hasher& h, std::pair const& p) noexcept { hash_append(h, p.first, p.second); } // vector template inline std::enable_if_t::value> hash_append(Hasher& h, std::vector const& v) noexcept { for (auto const& t : v) hash_append(h, t); hash_append(h, v.size()); } template inline std::enable_if_t::value> hash_append(Hasher& h, std::vector const& v) noexcept { h(v.data(), v.size() * sizeof(T)); hash_append(h, v.size()); } // array template std::enable_if_t, Hasher>::value> hash_append(Hasher& h, std::array const& a) noexcept { for (auto const& t : a) hash_append(h, t); } template std::enable_if_t::value> hash_append( Hasher& h, boost::container::flat_set const& v) noexcept { for (auto const& t : v) hash_append(h, t); } template std::enable_if_t::value> hash_append( Hasher& h, boost::container::flat_set const& v) noexcept { h(&(v.begin()), v.size() * sizeof(Key)); } // tuple namespace detail { inline void for_each_item(...) noexcept { } template inline int hash_one(Hasher& h, T const& t) noexcept { hash_append(h, t); return 0; } template inline void tuple_hash( Hasher& h, std::tuple const& t, std::index_sequence) noexcept { for_each_item(hash_one(h, std::get(t))...); } } // namespace detail template inline std::enable_if_t< !is_contiguously_hashable, Hasher>::value> hash_append(Hasher& h, std::tuple const& t) noexcept { detail::tuple_hash(h, t, std::index_sequence_for{}); } // shared_ptr template inline void hash_append(Hasher& h, std::shared_ptr const& p) noexcept { hash_append(h, p.get()); } // chrono template inline void hash_append(Hasher& h, std::chrono::duration const& d) noexcept { hash_append(h, d.count()); } template inline void hash_append( Hasher& h, std::chrono::time_point const& tp) noexcept { hash_append(h, tp.time_since_epoch()); } // variadic template inline void hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept { hash_append(h, t0); hash_append(h, t1, t...); } // error_code template inline void hash_append(HashAlgorithm& h, std::error_code const& ec) { hash_append(h, ec.value(), &ec.category()); } } // namespace beast #endif