diff --git a/include/boost/container_hash/hash.hpp b/include/boost/container_hash/hash.hpp index 7cb2d01..391d9b7 100644 --- a/include/boost/container_hash/hash.hpp +++ b/include/boost/container_hash/hash.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -72,9 +73,13 @@ namespace boost namespace hash_detail { - template sizeof(std::size_t)), bool size_t_64 = (sizeof(std::size_t) * CHAR_BIT >= 64)> struct hash_integral_impl; + template sizeof(std::size_t)), + std::size_t size_t_bits = sizeof(std::size_t) * CHAR_BIT, + std::size_t type_bits = sizeof(T) * CHAR_BIT> + struct hash_integral_impl; - template struct hash_integral_impl + template struct hash_integral_impl { static std::size_t fn( T v ) { @@ -82,48 +87,72 @@ namespace boost } }; - template struct hash_integral_impl + template struct hash_integral_impl { static std::size_t fn( T v ) { - // The bias makes negative numbers that fit into a ssize_t hash to themselves - // E.g. hash_value( -4LL ) == (size_t)-4 + std::size_t seed = 0; - std::size_t const bias = (std::numeric_limits::max)() / 4; + seed ^= static_cast( v >> 32 ) + ( seed << 6 ) + ( seed >> 2 ); + seed ^= static_cast( v ) + ( seed << 6 ) + ( seed >> 2 ); - // 4294967291 = 2^32-5, biggest prime under 2^32 - // we use boost::uint32_t( -5 ), because g++ warns on 4294967291 - - return static_cast( - ( static_cast::type>( v ) + bias ) - % static_cast( -5 ) ) - bias; + return seed; } }; - template struct hash_integral_impl + template struct hash_integral_impl { static std::size_t fn( T v ) { - std::size_t const bias = (std::numeric_limits::max)() / 4; + std::size_t seed = 0; - // 18446744073709551557ULL = 2^64-59, biggest prime under 2^64 - // we have to use boost::uint64_t( -59 ), because g++ warns in C++03 mode + seed ^= static_cast( v >> 96 ) + ( seed << 6 ) + ( seed >> 2 ); + seed ^= static_cast( v >> 64 ) + ( seed << 6 ) + ( seed >> 2 ); + seed ^= static_cast( v >> 32 ) + ( seed << 6 ) + ( seed >> 2 ); + seed ^= static_cast( v ) + ( seed << 6 ) + ( seed >> 2 ); - return static_cast( - ( static_cast::type>( v ) + bias ) - % static_cast( -59 ) ) - bias; + return seed; + } + }; + + template struct hash_integral_impl + { + static std::size_t fn( T v ) + { + std::size_t seed = 0; + + seed ^= static_cast( v >> 64 ) + ( seed << 6 ) + ( seed >> 2 ); + seed ^= static_cast( v ) + ( seed << 6 ) + ( seed >> 2 ); + + return seed; } }; } // namespace hash_detail template - typename boost::enable_if_::value, std::size_t>::type + typename boost::enable_if_::value && !boost::is_signed::value, std::size_t>::type hash_value( T v ) { return hash_detail::hash_integral_impl::fn( v ); } + template + typename boost::enable_if_::value && boost::is_signed::value, std::size_t>::type + hash_value( T v ) + { + typedef typename boost::make_unsigned::type U; + + if( v >= 0 ) + { + return hash_value( static_cast( v ) ); + } + else + { + return ~hash_value( static_cast( ~static_cast( v ) ) ); + } + } + // enumeration types template