Another try at an improved hash function.

This is based on the mix function from MurmurHash. It's not the full
algorithm as it's always seeded with 0, and doesn't do a final mix. This
should be okay as Boost.Hash doesn't claim to avalanche the bits.
This commit is contained in:
Daniel James
2014-02-23 10:16:53 +00:00
parent 5b893dfb06
commit 64e85476f1

View File

@@ -1,11 +1,17 @@
// Copyright 2005-2009 Daniel James. // Copyright 2005-2014 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying // Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Based on Peter Dimov's proposal // Based on Peter Dimov's proposal
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
// issue 6.18. // issue 6.18.
//
// This also contains public domain code from MurmurHash. From the
// MurmurHash header:
// MurmurHash3 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code.
#if !defined(BOOST_FUNCTIONAL_HASH_HASH_HPP) #if !defined(BOOST_FUNCTIONAL_HASH_HASH_HPP)
#define BOOST_FUNCTIONAL_HASH_HASH_HPP #define BOOST_FUNCTIONAL_HASH_HASH_HPP
@@ -18,6 +24,7 @@
#include <boost/type_traits/is_enum.hpp> #include <boost/type_traits/is_enum.hpp>
#include <boost/type_traits/is_integral.hpp> #include <boost/type_traits/is_integral.hpp>
#include <boost/utility/enable_if.hpp> #include <boost/utility/enable_if.hpp>
#include <boost/cstdint.hpp>
#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>
@@ -45,6 +52,12 @@
#define BOOST_HASH_CHAR_TRAITS char_traits #define BOOST_HASH_CHAR_TRAITS char_traits
#endif #endif
#if defined(_MSC_VER)
# define BOOST_FUNCTIONAL_HASH_ROTL32(x, r) _rotl(x,r)
#else
# define BOOST_FUNCTIONAL_HASH_ROTL32(x, r) (x << r) | (x >> (32 - r))
#endif
namespace boost namespace boost
{ {
namespace hash_detail namespace hash_detail
@@ -193,43 +206,50 @@ namespace boost
return seed; return seed;
} }
template <int Size> template <typename SizeT>
struct hash_combine_impl inline void hash_combine_impl(SizeT& seed, SizeT value)
{ {
inline static void combine(std::size_t& seed, seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
std::size_t value) }
{
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
};
template <> template <typename SizeT>
struct hash_combine_impl<4> inline void hash_combine_impl(boost::uint32_t& h1,
boost::uint32_t k1)
{ {
template <typename T> const uint32_t c1 = 0xcc9e2d51;
inline static void combine(T& seed, std::size_t value) const uint32_t c2 = 0x1b873593;
{
const T offset = 2166136261UL;
const T prime = 16777619UL;
seed ^= (value + offset); k1 *= c1;
seed *= prime; k1 = BOOST_FUNCTIONAL_HASH_ROTL32(k1,15);
} k1 *= c2;
};
template <> h1 ^= k1;
struct hash_combine_impl<8> h1 = BOOST_FUNCTIONAL_HASH_ROTL32(h1,13);
h1 = h1*5+0xe6546b64;
}
// Don't define 64-bit hash combine on platforms with 64 bit integers,
// 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)
template <typename SizeT>
inline void hash_combine_impl(boost::uint64_t& h,
boost::uint64_t k)
{ {
template <typename T> const uint64_t m = UINT64_C(0xc6a4a7935bd1e995);
inline static void combine(T& seed, std::size_t value) const int r = 47;
{
const T offset = 14695981039346656037ULL;
const T prime = 1099511628211ULL;
seed ^= (value + offset); k *= m;
seed *= prime; k ^= k >> r;
} k *= m;
};
h ^= k;
h *= m;
}
#endif // BOOST_NO_INT64_T
} }
template <typename T> template <typename T>
@@ -290,8 +310,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< return boost::hash_detail::hash_combine_impl(seed, hasher(v));
sizeof(std::size_t)>::combine(seed, hasher(v));
} }
#if defined(BOOST_MSVC) #if defined(BOOST_MSVC)
@@ -522,6 +541,7 @@ namespace boost
} }
#undef BOOST_HASH_CHAR_TRAITS #undef BOOST_HASH_CHAR_TRAITS
#undef BOOST_FUNCTIONAL_HASH_ROTL32
#if defined(BOOST_MSVC) #if defined(BOOST_MSVC)
#pragma warning(pop) #pragma warning(pop)