//------------------------------------------------------------------------------ /* This file is part of Beast: https://github.com/vinniefalco/Beast Copyright 2014, Howard Hinnant , Vinnie Falco #include #if BEAST_USE_BOOST_FEATURES #include #endif #include #include #include #include #include #include #include #include // #include // #include // Set to 1 to disable variadic hash_append for tuple. When set, overloads // will be manually provided for tuples up to 10-arity. This also causes // is_contiguously_hashable<> to always return false for tuples. // #ifndef BEAST_NO_TUPLE_VARIADICS # ifdef _MSC_VER # define BEAST_NO_TUPLE_VARIADICS 1 # ifndef BEAST_VARIADIC_MAX # ifdef _VARIADIC_MAX # define BEAST_VARIADIC_MAX _VARIADIC_MAX # else # define BEAST_VARIADIC_MAX 10 # endif # endif # else # define BEAST_NO_TUPLE_VARIADICS 0 # endif #endif // Set to 1 if std::pair fails the trait test on a platform. #ifndef BEAST_NO_IS_CONTIGUOUS_HASHABLE_PAIR #define BEAST_NO_IS_CONTIGUOUS_HASHABLE_PAIR 0 #endif // Set to 1 if std::tuple fails the trait test on a platform. #ifndef BEAST_NO_IS_CONTIGUOUS_HASHABLE_TUPLE # ifdef _MSC_VER # define BEAST_NO_IS_CONTIGUOUS_HASHABLE_TUPLE 1 # else # define BEAST_NO_IS_CONTIGUOUS_HASHABLE_TUPLE 0 # endif #endif namespace beast { /** 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. */ /** @{ */ // scalars template struct is_contiguously_hashable : public std::integral_constant ::value || std::is_enum::value || std::is_pointer::value> { }; // If this fails, something is wrong with the trait static_assert (is_contiguously_hashable::value, ""); // pair template struct is_contiguously_hashable > : public std::integral_constant ::value && is_contiguously_hashable::value && sizeof(T) + sizeof(U) == sizeof(std::pair)> { }; #if ! BEAST_NO_IS_CONTIGUOUS_HASHABLE_PAIR static_assert (is_contiguously_hashable >::value, ""); #endif #if ! BEAST_NO_TUPLE_VARIADICS // std::tuple template struct is_contiguously_hashable > : public std::integral_constant ::value...>::value && static_sum ::value == sizeof(std::tuple)> { }; #endif // std::array template struct is_contiguously_hashable > : public std::integral_constant ::value && sizeof(T)*N == sizeof(std::array)> { }; static_assert (is_contiguously_hashable >::value, ""); #if ! BEAST_NO_IS_CONTIGUOUS_HASHABLE_TUPLE static_assert (is_contiguously_hashable < std::tuple >::value, ""); #endif /** @} */ //------------------------------------------------------------------------------ /** 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 typename std::enable_if < is_contiguously_hashable::value >::type hash_append (Hasher& h, T const& t) noexcept { h.append (&t, sizeof(t)); } template inline typename std::enable_if < std::is_floating_point::value >::type hash_append (Hasher& h, T t) noexcept { // hash both signed zeroes identically if (t == 0) t = 0; h.append (&t, sizeof(t)); } // arrays template inline typename std::enable_if < !is_contiguously_hashable::value >::type hash_append (Hasher& h, T (&a)[N]) noexcept { for (auto const& t : a) hash_append (h, t); } template inline typename std::enable_if < is_contiguously_hashable::value >::type hash_append (Hasher& h, T (&a)[N]) noexcept { h.append (a, N*sizeof(T)); } // nullptr_t template inline void hash_append (Hasher& h, std::nullptr_t p) noexcept { h.append (&p, sizeof(p)); } // strings template inline void hash_append (Hasher& h, std::basic_string const& s) noexcept { h.append (s.data (), (s.size()+1)*sizeof(CharT)); } //------------------------------------------------------------------------------ // Forward declare hash_append for all containers. This is required so that // argument dependent lookup works recursively (i.e. containers of containers). template typename std::enable_if < !is_contiguously_hashable>::value >::type hash_append (Hasher& h, std::pair const& p) noexcept; template typename std::enable_if < !is_contiguously_hashable::value >::type hash_append (Hasher& h, std::vector const& v) noexcept; template typename std::enable_if < is_contiguously_hashable::value >::type hash_append (Hasher& h, std::vector const& v) noexcept; template typename std::enable_if < !is_contiguously_hashable>::value >::type hash_append (Hasher& h, std::array const& a) noexcept; // std::tuple template inline void hash_append (Hasher& h, std::tuple<> const& t) noexcept; #if BEAST_NO_TUPLE_VARIADICS #if BEAST_VARIADIC_MAX >= 1 template inline void hash_append (Hasher& h, std::tuple const& t) noexcept; #endif #if BEAST_VARIADIC_MAX >= 2 template inline void hash_append (Hasher& h, std::tuple const& t) noexcept; #endif #if BEAST_VARIADIC_MAX >= 3 template inline void hash_append (Hasher& h, std::tuple const& t) noexcept; #endif #if BEAST_VARIADIC_MAX >= 4 template inline void hash_append (Hasher& h, std::tuple const& t) noexcept; #endif #if BEAST_VARIADIC_MAX >= 5 template inline void hash_append (Hasher& h, std::tuple const& t) noexcept; #endif #if BEAST_VARIADIC_MAX >= 6 template inline void hash_append (Hasher& h, std::tuple < T1, T2, T3, T4, T5, T6> const& t) noexcept; #endif #if BEAST_VARIADIC_MAX >= 7 template inline void hash_append (Hasher& h, std::tuple < T1, T2, T3, T4, T5, T6, T7> const& t) noexcept; #endif #if BEAST_VARIADIC_MAX >= 8 template inline void hash_append (Hasher& h, std::tuple < T1, T2, T3, T4, T5, T6, T7, T8> const& t) noexcept; #endif #if BEAST_VARIADIC_MAX >= 9 template inline void hash_append (Hasher& h, std::tuple < T1, T2, T3, T4, T5, T6, T7, T8, T9> const& t) noexcept; #endif #if BEAST_VARIADIC_MAX >= 10 template inline void hash_append (Hasher& h, std::tuple < T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> const& t) noexcept; #endif #endif // BEAST_NO_TUPLE_VARIADICS //------------------------------------------------------------------------------ namespace detail { template inline int hash_one (Hasher& h, T const& t) noexcept { hash_append (h, t); return 0; } } // detail //------------------------------------------------------------------------------ // std::tuple template inline void hash_append (Hasher& h, std::tuple<> const& t) noexcept { hash_append (h, nullptr); } #if BEAST_NO_TUPLE_VARIADICS #if BEAST_VARIADIC_MAX >= 1 template inline void hash_append (Hasher& h, std::tuple const& t) noexcept { hash_append (h, std::get<0>(t)); } #endif #if BEAST_VARIADIC_MAX >= 2 template inline void hash_append (Hasher& h, std::tuple const& t) noexcept { hash_append (h, std::get<0>(t)); hash_append (h, std::get<1>(t)); } #endif #if BEAST_VARIADIC_MAX >= 3 template inline void hash_append (Hasher& h, std::tuple const& t) noexcept { hash_append (h, std::get<0>(t)); hash_append (h, std::get<1>(t)); hash_append (h, std::get<2>(t)); } #endif #if BEAST_VARIADIC_MAX >= 4 template inline void hash_append (Hasher& h, std::tuple const& t) noexcept { hash_append (h, std::get<0>(t)); hash_append (h, std::get<1>(t)); hash_append (h, std::get<2>(t)); hash_append (h, std::get<3>(t)); } #endif #if BEAST_VARIADIC_MAX >= 5 template inline void hash_append (Hasher& h, std::tuple < T1, T2, T3, T4, T5> const& t) noexcept { hash_append (h, std::get<0>(t)); hash_append (h, std::get<1>(t)); hash_append (h, std::get<2>(t)); hash_append (h, std::get<3>(t)); hash_append (h, std::get<4>(t)); } #endif #if BEAST_VARIADIC_MAX >= 6 template inline void hash_append (Hasher& h, std::tuple < T1, T2, T3, T4, T5, T6> const& t) noexcept { hash_append (h, std::get<0>(t)); hash_append (h, std::get<1>(t)); hash_append (h, std::get<2>(t)); hash_append (h, std::get<3>(t)); hash_append (h, std::get<4>(t)); hash_append (h, std::get<5>(t)); } #endif #if BEAST_VARIADIC_MAX >= 7 template inline void hash_append (Hasher& h, std::tuple < T1, T2, T3, T4, T5, T6, T7> const& t) noexcept { hash_append (h, std::get<0>(t)); hash_append (h, std::get<1>(t)); hash_append (h, std::get<2>(t)); hash_append (h, std::get<3>(t)); hash_append (h, std::get<4>(t)); hash_append (h, std::get<5>(t)); hash_append (h, std::get<6>(t)); } #endif #if BEAST_VARIADIC_MAX >= 8 template inline void hash_append (Hasher& h, std::tuple < T1, T2, T3, T4, T5, T6, T7, T8> const& t) noexcept { hash_append (h, std::get<0>(t)); hash_append (h, std::get<1>(t)); hash_append (h, std::get<2>(t)); hash_append (h, std::get<3>(t)); hash_append (h, std::get<4>(t)); hash_append (h, std::get<5>(t)); hash_append (h, std::get<6>(t)); hash_append (h, std::get<7>(t)); } #endif #if BEAST_VARIADIC_MAX >= 9 template inline void hash_append (Hasher& h, std::tuple < T1, T2, T3, T4, T5, T6, T7, T8, T9> const& t) noexcept { hash_append (h, std::get<0>(t)); hash_append (h, std::get<1>(t)); hash_append (h, std::get<2>(t)); hash_append (h, std::get<3>(t)); hash_append (h, std::get<4>(t)); hash_append (h, std::get<5>(t)); hash_append (h, std::get<6>(t)); hash_append (h, std::get<7>(t)); hash_append (h, std::get<8>(t)); } #endif #if BEAST_VARIADIC_MAX >= 10 template inline void hash_append (Hasher& h, std::tuple < T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> const& t) noexcept { hash_append (h, std::get<0>(t)); hash_append (h, std::get<1>(t)); hash_append (h, std::get<2>(t)); hash_append (h, std::get<3>(t)); hash_append (h, std::get<4>(t)); hash_append (h, std::get<5>(t)); hash_append (h, std::get<6>(t)); hash_append (h, std::get<7>(t)); hash_append (h, std::get<8>(t)); hash_append (h, std::get<9>(t)); } #endif #else // BEAST_NO_TUPLE_VARIADICS namespace detail { template inline void tuple_hash (Hasher& h, std::tuple const& t, std::index_sequence) noexcept { struct for_each_item { for_each_item (...) { } }; for_each_item (hash_one(h, std::get(t))...); } } // detail template inline typename std::enable_if < !is_contiguously_hashable>::value >::type hash_append (Hasher& h, std::tuple const& t) noexcept { detail::tuple_hash(h, t, std::index_sequence_for{}); } #endif // BEAST_NO_TUPLE_VARIADICS // pair template inline typename std::enable_if < !is_contiguously_hashable>::value >::type hash_append (Hasher& h, std::pair const& p) noexcept { hash_append (h, p.first); hash_append (h, p.second); } // vector template inline typename std::enable_if < !is_contiguously_hashable::value >::type hash_append (Hasher& h, std::vector const& v) noexcept { for (auto const& t : v) hash_append (h, t); } template inline typename std::enable_if < is_contiguously_hashable::value >::type hash_append (Hasher& h, std::vector const& v) noexcept { h.append (v.data(), v.size()*sizeof(T)); } // shared_ptr template inline void hash_append (Hasher& h, std::shared_ptr const& p) noexcept { hash_append(h, p.get()); } #if BEAST_USE_BOOST_FEATURES template inline void hash_append (Hasher& h, boost::shared_ptr const& p) noexcept { hash_append(h, p.get()); } #endif // variadic hash_append 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...); } namespace detail { class spooky_wrapper { SpookyHash state_; public: using result_type = std::size_t; spooky_wrapper (std::size_t seed1 = 1, std::size_t seed2 = 2) noexcept { state_.Init (seed1, seed2); } void append (void const* key, std::size_t len) noexcept { state_.Update (key, len); } explicit operator std::size_t() noexcept { std::uint64_t h1, h2; state_.Final (&h1, &h2); return static_cast (h1); } }; } // detail template struct uhash { using result_type = typename Hasher::result_type; template result_type operator()(T const& t) const noexcept { Hasher h; hash_append (h, t); return static_cast(h); } }; struct call_hash_value { template std::size_t operator()(T const& t) const noexcept { return hash_value(t); } }; } // beast #endif