123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- /////////////////////////////////////////////////////////////////////////////
- //
- // Copyright 2005-2014 Daniel James.
- // Copyright 2021, 2022 Peter Dimov.
- // Copyright 2024 Ion Gaztanaga.
- // 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.
- //
- // The original C++11 implementation was done by Peter Dimov
- // The C++03 porting was done by Ion Gaztanaga.
- //
- // The goal of this header is to avoid Intrusive's hard dependency on ContainerHash,
- // which adds additional dependencies and the minimum supported C++ standard can
- // differ between both libraries. However, a compatibility protocol is used so that
- // users compatible with ContainerHash are also compatible with Intrusive:
- //
- // - If users define `hash_value` (as required by boost::hash) for their classes
- // are automatically compatible with Intrusive unordered containers.
- //
- // - If users include boost/container_hash/hash.hpp in their headers, Intrusive
- // unordered containers will take advantage of boost::hash compatibility hash functions
- // (such as hashing functions for range-compatible types, standard containers, etc.)
- //
- // See http://www.boost.org/libs/intrusive for documentation.
- //
- /////////////////////////////////////////////////////////////////////////////
- #ifndef BOOST_INTRUSIVE_HASH_HASH_HPP
- #define BOOST_INTRUSIVE_HASH_HASH_HPP
- #include <boost/intrusive/detail/config_begin.hpp>
- #include <boost/intrusive/detail/workaround.hpp>
- #include <boost/intrusive/detail/hash_integral.hpp>
- #include <boost/intrusive/detail/hash_mix.hpp>
- #include <boost/intrusive/detail/hash_combine.hpp>
- #include <boost/cstdint.hpp>
- #include <climits>
- #include <cstring>
- #include <cfloat>
- #include <boost/intrusive/detail/mpl.hpp>
- namespace boost {
- template<class T>
- struct hash;
- } //namespace boost
- //Fallback function to call boost::hash if scalar type and ADL fail.
- //The user must include boost/container_hash/hash.hpp when to make this call work,
- //this allows boost::intrusive to be compatible with boost::hash without
- //a mandatory physical (header inclusion) dependency
- namespace boost_intrusive_adl
- {
- template<class T>
- inline std::size_t hash_value(const T& v)
- {
- return boost::hash<T>()(v);
- }
- }
- namespace boost {
- namespace intrusive {
- namespace detail {
- //ADL-based lookup hash call
- template <class T>
- inline typename detail::disable_if_c<detail::is_scalar<T>::value, std::size_t>::type
- hash_value_dispatch(const T& v)
- {
- //Try ADL lookup, if it fails, boost_intrusive_adl::hash_value will retry with boost::hash
- using boost_intrusive_adl::hash_value;
- return hash_value(v);
- }
- template <typename T>
- typename enable_if_c<is_enum<T>::value, std::size_t>::type
- hash_value( T v )
- {
- return static_cast<std::size_t>( v );
- }
- ////////////////////////////////////////////////////////////
- //
- // floating point types
- //
- ////////////////////////////////////////////////////////////
- template<class T, std::size_t Bits = sizeof(T) * CHAR_BIT>
- struct hash_float_impl;
- // float
- template<class T> struct hash_float_impl<T, 32>
- {
- static std::size_t fn( T v )
- {
- boost::uint32_t w;
- std::memcpy( &w, &v, sizeof( v ) );
- return w;
- }
- };
- // double
- template<class T> struct hash_float_impl<T, 64>
- {
- static std::size_t fn( T v )
- {
- boost::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>
- {
- static std::size_t fn( T v )
- {
- boost::uint64_t w[ 2 ] = {};
- std::memcpy( &w, &v, 80 / CHAR_BIT );
- std::size_t seed = 0;
- seed = hash_value( w[0] ) + (hash_mix)( seed );
- seed = hash_value( w[1] ) + (hash_mix)( seed );
- return seed;
- }
- };
- #if (LDBL_MAX_10_EXP == 4932)
- // 80 bit long double in 16 bytes
- template<class T> struct hash_float_impl<T, 128>
- {
- static std::size_t fn( T v )
- {
- boost::uint64_t w[ 2 ] = {};
- std::memcpy( &w, &v, 80 / CHAR_BIT );
- std::size_t seed = 0;
- seed = hash_value( w[0] ) + (hash_mix)( seed );
- seed = hash_value( w[1] ) + (hash_mix)( seed );
- return seed;
- }
- };
- #elif (LDBL_MAX_10_EXP > 4932)
- // 128 bit long double
- template<class T> struct hash_float_impl<T, 128>
- {
- static std::size_t fn( T v )
- {
- boost::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_mix)( seed );
- seed = hash_value( w[0] ) + (hash_mix)( seed );
- #else
- seed = hash_value( w[0] ) + (hash_mix)( seed );
- seed = hash_value( w[1] ) + (hash_mix)( seed );
- #endif
- return seed;
- }
- };
- #endif //#if (LDBL_MAX_10_EXP == 4932)
- template <typename T>
- typename enable_if_c<is_floating_point<T>::value, std::size_t>::type
- hash_value( T v )
- {
- return boost::intrusive::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::size_t x = reinterpret_cast<std::size_t>( v );
- return hash_value( x + (x >> 3) );
- }
- ////////////////////////////////////////////////////////////
- //
- // std::nullptr_t
- //
- ////////////////////////////////////////////////////////////
- #if !defined(BOOST_NO_CXX11_NULLPTR)
- template <typename T>
- typename enable_if_c<is_same<T, std::nullptr_t>::value, std::size_t>::type
- hash_value( T const &)
- {
- return (hash_value)( static_cast<void*>( nullptr ) );
- }
- #endif
- ////////////////////////////////////////////////////////////
- //
- // Array types
- //
- ////////////////////////////////////////////////////////////
- //Forward declaration or internal hash functor, for array iteration
- template<class T>
- struct internal_hash_functor;
- template<class T, std::size_t N>
- inline std::size_t hash_value_dispatch( T const (&x)[ N ] )
- {
- std::size_t seed = 0;
- for(std::size_t i = 0; i != N; ++i){
- hash_combine_size_t(seed, internal_hash_functor<T>()(x[i]));
- }
- return seed;
- }
- template<class T, std::size_t N>
- inline std::size_t hash_value_dispatch( T (&x)[ N ] )
- {
- std::size_t seed = 0;
- for (std::size_t i = 0; i != N; ++i) {
- hash_combine_size_t(seed, internal_hash_functor<T>()(x[i]));
- }
- return seed;
- }
- ////////////////////////////////////////////////////////////
- //
- // Scalar types, calls proper overload
- //
- ////////////////////////////////////////////////////////////
- template <class T>
- inline typename detail::enable_if_c<detail::is_scalar<T>::value, std::size_t>::type
- hash_value_dispatch(const T &v)
- {
- return boost::intrusive::detail::hash_value(v);
- }
- //Internal "anonymous" hash functor, first selects between "built-in" scalar/array types
- //and ADL-based lookup
- template<class T>
- struct internal_hash_functor
- {
- inline std::size_t operator()(T const& val) const
- {
- return ::boost::intrusive::detail::hash_value_dispatch(val);
- }
- };
- } // namespace detail {
- } // namespace intrusive {
- } // namespace boost
- #include <boost/intrusive/detail/config_end.hpp>
- #endif // #ifndef BOOST_INTRUSIVE_HASH_HASH_HPP
|