Fix hash_combine_impl to only test for a specific bit width and not for concrete types

This commit is contained in:
Peter Dimov
2021-08-10 18:38:41 +03:00
parent b55fbc9252
commit 21f2b5e1db

View File

@@ -26,6 +26,7 @@
#include <boost/type_traits/is_integral.hpp> #include <boost/type_traits/is_integral.hpp>
#include <boost/core/enable_if.hpp> #include <boost/core/enable_if.hpp>
#include <boost/cstdint.hpp> #include <boost/cstdint.hpp>
#include <climits>
#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
#include <boost/type_traits/is_pointer.hpp> #include <boost/type_traits/is_pointer.hpp>
@@ -307,52 +308,56 @@ namespace boost
return seed; return seed;
} }
template <typename SizeT> template<int Bits> struct hash_combine_impl
inline void hash_combine_impl(SizeT& seed, SizeT value)
{ {
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2); template <typename SizeT>
} inline static SizeT fn(SizeT seed, SizeT value)
{
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
return seed;
}
};
inline void hash_combine_impl(boost::uint32_t& h1, template<> struct hash_combine_impl<32>
boost::uint32_t k1)
{ {
const uint32_t c1 = 0xcc9e2d51; inline static boost::uint32_t fn(boost::uint32_t h1, boost::uint32_t k1)
const uint32_t c2 = 0x1b873593; {
const boost::uint32_t c1 = 0xcc9e2d51;
const boost::uint32_t c2 = 0x1b873593;
k1 *= c1; k1 *= c1;
k1 = BOOST_FUNCTIONAL_HASH_ROTL32(k1,15); k1 = BOOST_FUNCTIONAL_HASH_ROTL32(k1,15);
k1 *= c2; k1 *= c2;
h1 ^= k1; h1 ^= k1;
h1 = BOOST_FUNCTIONAL_HASH_ROTL32(h1,13); h1 = BOOST_FUNCTIONAL_HASH_ROTL32(h1,13);
h1 = h1*5+0xe6546b64; h1 = h1*5+0xe6546b64;
}
return h1;
}
};
// Don't define 64-bit hash combine on platforms without 64 bit integers, template<> struct hash_combine_impl<64>
// and also not for 32-bit gcc as it warns about the 64-bit constant.
#if !defined(BOOST_NO_INT64_T) && \
!(defined(__GNUC__) && ULONG_MAX == 0xffffffff)
inline void hash_combine_impl(boost::uint64_t& h,
boost::uint64_t k)
{ {
const boost::uint64_t m = UINT64_C(0xc6a4a7935bd1e995); inline static boost::uint64_t fn(boost::uint64_t h, boost::uint64_t k)
const int r = 47; {
const boost::uint64_t m = (boost::uint64_t(0xc6a4a793) << 32) + 0x5bd1e995;
const int r = 47;
k *= m; k *= m;
k ^= k >> r; k ^= k >> r;
k *= m; k *= m;
h ^= k; h ^= k;
h *= m; h *= m;
// Completely arbitrary number, to prevent 0's // Completely arbitrary number, to prevent 0's
// from hashing to 0. // from hashing to 0.
h += 0xe6546b64; h += 0xe6546b64;
}
#endif // BOOST_NO_INT64_T return h;
}
};
} }
template <typename T> template <typename T>
@@ -413,7 +418,7 @@ namespace boost
inline void hash_combine(std::size_t& seed, T const& v) inline void hash_combine(std::size_t& seed, T const& v)
{ {
boost::hash<T> hasher; boost::hash<T> hasher;
return boost::hash_detail::hash_combine_impl(seed, hasher(v)); seed = boost::hash_detail::hash_combine_impl<sizeof(std::size_t) * CHAR_BIT>::fn(seed, hasher(v));
} }
#if defined(BOOST_MSVC) #if defined(BOOST_MSVC)