123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576 |
- // Copyright 2005-2014 Daniel James.
- // Copyright 2021, 2022 Peter Dimov.
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- // Based on Peter Dimov's proposal
- // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
- // issue 6.18.
- #ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP
- #define BOOST_FUNCTIONAL_HASH_HASH_HPP
- #include <boost/container_hash/hash_fwd.hpp>
- #include <boost/container_hash/is_range.hpp>
- #include <boost/container_hash/is_contiguous_range.hpp>
- #include <boost/container_hash/is_unordered_range.hpp>
- #include <boost/container_hash/is_described_class.hpp>
- #include <boost/container_hash/detail/hash_integral.hpp>
- #include <boost/container_hash/detail/hash_tuple_like.hpp>
- #include <boost/container_hash/detail/hash_mix.hpp>
- #include <boost/container_hash/detail/hash_range.hpp>
- #include <boost/describe/bases.hpp>
- #include <boost/describe/members.hpp>
- #include <type_traits>
- #include <cstdint>
- #if defined(BOOST_DESCRIBE_CXX14)
- # include <boost/mp11/algorithm.hpp>
- #endif
- #include <string>
- #include <iterator>
- #include <complex>
- #include <utility>
- #include <limits>
- #include <climits>
- #include <cstring>
- #if !defined(BOOST_NO_CXX11_SMART_PTR)
- # include <memory>
- #endif
- #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
- #include <typeindex>
- #endif
- #if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
- #include <system_error>
- #endif
- #if !defined(BOOST_NO_CXX17_HDR_OPTIONAL)
- #include <optional>
- #endif
- #if !defined(BOOST_NO_CXX17_HDR_VARIANT)
- #include <variant>
- #endif
- #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
- # include <string_view>
- #endif
- namespace boost
- {
- //
- // boost::hash_value
- //
- // integral types
- // in detail/hash_integral.hpp
- // enumeration types
- template <typename T>
- typename std::enable_if<std::is_enum<T>::value, std::size_t>::type
- hash_value( T v )
- {
- // This should in principle return the equivalent of
- //
- // boost::hash_value( to_underlying(v) );
- //
- // However, the C++03 implementation of underlying_type,
- //
- // conditional<is_signed<T>, make_signed<T>, make_unsigned<T>>::type::type
- //
- // generates a legitimate -Wconversion warning in is_signed,
- // because -1 is not a valid enum value when all the enumerators
- // are nonnegative.
- //
- // So the legacy implementation will have to do for now.
- return static_cast<std::size_t>( v );
- }
- // floating point types
- namespace hash_detail
- {
- template<class T,
- std::size_t Bits = sizeof(T) * CHAR_BIT,
- int Digits = std::numeric_limits<T>::digits>
- struct hash_float_impl;
- // float
- template<class T, int Digits> struct hash_float_impl<T, 32, Digits>
- {
- static std::size_t fn( T v )
- {
- std::uint32_t w;
- std::memcpy( &w, &v, sizeof( v ) );
- return w;
- }
- };
- // double
- template<class T, int Digits> struct hash_float_impl<T, 64, Digits>
- {
- static std::size_t fn( T v )
- {
- std::uint64_t w;
- std::memcpy( &w, &v, sizeof( v ) );
- return hash_value( w );
- }
- };
- // 80 bit long double in 12 bytes
- template<class T> struct hash_float_impl<T, 96, 64>
- {
- static std::size_t fn( T v )
- {
- std::uint64_t w[ 2 ] = {};
- std::memcpy( &w, &v, 80 / CHAR_BIT );
- std::size_t seed = 0;
- seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
- seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
- return seed;
- }
- };
- // 80 bit long double in 16 bytes
- template<class T> struct hash_float_impl<T, 128, 64>
- {
- static std::size_t fn( T v )
- {
- std::uint64_t w[ 2 ] = {};
- std::memcpy( &w, &v, 80 / CHAR_BIT );
- std::size_t seed = 0;
- seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
- seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
- return seed;
- }
- };
- // 128 bit long double
- template<class T, int Digits> struct hash_float_impl<T, 128, Digits>
- {
- static std::size_t fn( T v )
- {
- std::uint64_t w[ 2 ];
- std::memcpy( &w, &v, sizeof( v ) );
- std::size_t seed = 0;
- #if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__
- seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
- seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
- #else
- seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
- seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
- #endif
- return seed;
- }
- };
- } // namespace hash_detail
- template <typename T>
- typename std::enable_if<std::is_floating_point<T>::value, std::size_t>::type
- hash_value( T v )
- {
- return boost::hash_detail::hash_float_impl<T>::fn( v + 0 );
- }
- // pointer types
- // `x + (x >> 3)` adjustment by Alberto Barbati and Dave Harris.
- template <class T> std::size_t hash_value( T* const& v )
- {
- std::uintptr_t x = reinterpret_cast<std::uintptr_t>( v );
- return boost::hash_value( x + (x >> 3) );
- }
- // array types
- template<class T, std::size_t N>
- inline std::size_t hash_value( T const (&x)[ N ] )
- {
- return boost::hash_range( x, x + N );
- }
- template<class T, std::size_t N>
- inline std::size_t hash_value( T (&x)[ N ] )
- {
- return boost::hash_range( x, x + N );
- }
- // complex
- template <class T>
- std::size_t hash_value( std::complex<T> const& v )
- {
- std::size_t re = boost::hash<T>()( v.real() );
- std::size_t im = boost::hash<T>()( v.imag() );
- return re + hash_detail::hash_mix( im );
- }
- // pair
- template <class A, class B>
- std::size_t hash_value( std::pair<A, B> const& v )
- {
- std::size_t seed = 0;
- boost::hash_combine( seed, v.first );
- boost::hash_combine( seed, v.second );
- return seed;
- }
- // ranges (list, set, deque...)
- template <typename T>
- typename std::enable_if<container_hash::is_range<T>::value && !container_hash::is_contiguous_range<T>::value && !container_hash::is_unordered_range<T>::value, std::size_t>::type
- hash_value( T const& v )
- {
- return boost::hash_range( v.begin(), v.end() );
- }
- // contiguous ranges (string, vector, array)
- template <typename T>
- typename std::enable_if<container_hash::is_contiguous_range<T>::value, std::size_t>::type
- hash_value( T const& v )
- {
- return boost::hash_range( v.data(), v.data() + v.size() );
- }
- // unordered ranges (unordered_set, unordered_map)
- template <typename T>
- typename std::enable_if<container_hash::is_unordered_range<T>::value, std::size_t>::type
- hash_value( T const& v )
- {
- return boost::hash_unordered_range( v.begin(), v.end() );
- }
- #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ( \
- ( defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142 ) || \
- ( !defined(_MSVC_STL_VERSION) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520 ) )
- // resolve ambiguity with unconstrained stdext::hash_value in <xhash> :-/
- template<template<class...> class L, class... T>
- typename std::enable_if<container_hash::is_range<L<T...>>::value && !container_hash::is_contiguous_range<L<T...>>::value && !container_hash::is_unordered_range<L<T...>>::value, std::size_t>::type
- hash_value( L<T...> const& v )
- {
- return boost::hash_range( v.begin(), v.end() );
- }
- // contiguous ranges (string, vector, array)
- template<template<class...> class L, class... T>
- typename std::enable_if<container_hash::is_contiguous_range<L<T...>>::value, std::size_t>::type
- hash_value( L<T...> const& v )
- {
- return boost::hash_range( v.data(), v.data() + v.size() );
- }
- template<template<class, std::size_t> class L, class T, std::size_t N>
- typename std::enable_if<container_hash::is_contiguous_range<L<T, N>>::value, std::size_t>::type
- hash_value( L<T, N> const& v )
- {
- return boost::hash_range( v.data(), v.data() + v.size() );
- }
- // unordered ranges (unordered_set, unordered_map)
- template<template<class...> class L, class... T>
- typename std::enable_if<container_hash::is_unordered_range<L<T...>>::value, std::size_t>::type
- hash_value( L<T...> const& v )
- {
- return boost::hash_unordered_range( v.begin(), v.end() );
- }
- #endif
- // described classes
- #if defined(BOOST_DESCRIBE_CXX14)
- #if defined(_MSC_VER) && _MSC_VER == 1900
- # pragma warning(push)
- # pragma warning(disable: 4100) // unreferenced formal parameter
- #endif
- template <typename T>
- typename std::enable_if<container_hash::is_described_class<T>::value, std::size_t>::type
- hash_value( T const& v )
- {
- static_assert( !std::is_union<T>::value, "described unions are not supported" );
- std::size_t r = 0;
- using Bd = describe::describe_bases<T, describe::mod_any_access>;
- mp11::mp_for_each<Bd>([&](auto D){
- using B = typename decltype(D)::type;
- boost::hash_combine( r, (B const&)v );
- });
- using Md = describe::describe_members<T, describe::mod_any_access>;
- mp11::mp_for_each<Md>([&](auto D){
- boost::hash_combine( r, v.*D.pointer );
- });
- return r;
- }
- #if defined(_MSC_VER) && _MSC_VER == 1900
- # pragma warning(pop)
- #endif
- #endif
- // std::unique_ptr, std::shared_ptr
- #if !defined(BOOST_NO_CXX11_SMART_PTR)
- template <typename T>
- std::size_t hash_value( std::shared_ptr<T> const& x )
- {
- return boost::hash_value( x.get() );
- }
- template <typename T, typename Deleter>
- std::size_t hash_value( std::unique_ptr<T, Deleter> const& x )
- {
- return boost::hash_value( x.get() );
- }
- #endif
- // std::type_index
- #if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
- inline std::size_t hash_value( std::type_index const& v )
- {
- return v.hash_code();
- }
- #endif
- // std::error_code, std::error_condition
- #if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
- inline std::size_t hash_value( std::error_code const& v )
- {
- std::size_t seed = 0;
- boost::hash_combine( seed, v.value() );
- boost::hash_combine( seed, &v.category() );
- return seed;
- }
- inline std::size_t hash_value( std::error_condition const& v )
- {
- std::size_t seed = 0;
- boost::hash_combine( seed, v.value() );
- boost::hash_combine( seed, &v.category() );
- return seed;
- }
- #endif
- // std::nullptr_t
- #if !defined(BOOST_NO_CXX11_NULLPTR)
- template <typename T>
- typename std::enable_if<std::is_same<T, std::nullptr_t>::value, std::size_t>::type
- hash_value( T const& /*v*/ )
- {
- return boost::hash_value( static_cast<void*>( nullptr ) );
- }
- #endif
- // std::optional
- #if !defined(BOOST_NO_CXX17_HDR_OPTIONAL)
- template <typename T>
- std::size_t hash_value( std::optional<T> const& v )
- {
- if( !v )
- {
- // Arbitrary value for empty optional.
- return 0x12345678;
- }
- else
- {
- return boost::hash<T>()(*v);
- }
- }
- #endif
- // std::variant
- #if !defined(BOOST_NO_CXX17_HDR_VARIANT)
- inline std::size_t hash_value( std::monostate )
- {
- return 0x87654321;
- }
- template <typename... Types>
- std::size_t hash_value( std::variant<Types...> const& v )
- {
- std::size_t seed = 0;
- hash_combine( seed, v.index() );
- std::visit( [&seed](auto&& x) { hash_combine(seed, x); }, v );
- return seed;
- }
- #endif
- //
- // boost::hash_combine
- //
- template <class T>
- inline void hash_combine( std::size_t& seed, T const& v )
- {
- seed = boost::hash_detail::hash_mix( seed + 0x9e3779b9 + boost::hash<T>()( v ) );
- }
- //
- // boost::hash_range
- //
- template <class It>
- inline void hash_range( std::size_t& seed, It first, It last )
- {
- seed = hash_detail::hash_range( seed, first, last );
- }
- template <class It>
- inline std::size_t hash_range( It first, It last )
- {
- std::size_t seed = 0;
- hash_range( seed, first, last );
- return seed;
- }
- //
- // boost::hash_unordered_range
- //
- template <class It>
- inline void hash_unordered_range( std::size_t& seed, It first, It last )
- {
- std::size_t r = 0;
- std::size_t const s2( seed );
- for( ; first != last; ++first )
- {
- std::size_t s3( s2 );
- hash_combine<typename std::iterator_traits<It>::value_type>( s3, *first );
- r += s3;
- }
- seed += r;
- }
- template <class It>
- inline std::size_t hash_unordered_range( It first, It last )
- {
- std::size_t seed = 0;
- hash_unordered_range( seed, first, last );
- return seed;
- }
- //
- // boost::hash
- //
- template <class T> struct hash
- {
- typedef T argument_type;
- typedef std::size_t result_type;
- std::size_t operator()( T const& val ) const
- {
- return hash_value( val );
- }
- };
- #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ( \
- ( defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142 ) || \
- ( !defined(_MSVC_STL_VERSION) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520 ) )
- // Dinkumware has stdext::hash_value for basic_string in <xhash> :-/
- template<class E, class T, class A> struct hash< std::basic_string<E, T, A> >
- {
- typedef std::basic_string<E, T, A> argument_type;
- typedef std::size_t result_type;
- std::size_t operator()( std::basic_string<E, T, A> const& val ) const
- {
- return boost::hash_value( val );
- }
- };
- #endif
- // boost::unordered::hash_is_avalanching
- namespace unordered
- {
- template<class T> struct hash_is_avalanching;
- template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string<Ch> > >: std::is_integral<Ch> {};
- #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
- template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string_view<Ch> > >: std::is_integral<Ch> {};
- #endif
- } // namespace unordered
- } // namespace boost
- #endif // #ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP
|