From 64e85476f1f6d65c16f89157f1018f0484c688bb Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Feb 2014 10:16:53 +0000 Subject: [PATCH] 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. --- include/boost/functional/hash/hash.hpp | 86 ++++++++++++++++---------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/include/boost/functional/hash/hash.hpp b/include/boost/functional/hash/hash.hpp index 9716e6c..3e5ab5b 100644 --- a/include/boost/functional/hash/hash.hpp +++ b/include/boost/functional/hash/hash.hpp @@ -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 // file LICENSE_1_0.txt or copy at http://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. +// +// 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) #define BOOST_FUNCTIONAL_HASH_HASH_HPP @@ -18,6 +24,7 @@ #include #include #include +#include #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) #include @@ -45,6 +52,12 @@ #define BOOST_HASH_CHAR_TRAITS char_traits #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 hash_detail @@ -193,43 +206,50 @@ namespace boost return seed; } - template - struct hash_combine_impl + template + inline void hash_combine_impl(SizeT& seed, SizeT value) { - inline static void combine(std::size_t& seed, - std::size_t value) - { - seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2); - } - }; + seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2); + } - template <> - struct hash_combine_impl<4> + template + inline void hash_combine_impl(boost::uint32_t& h1, + boost::uint32_t k1) { - template - inline static void combine(T& seed, std::size_t value) - { - const T offset = 2166136261UL; - const T prime = 16777619UL; + const uint32_t c1 = 0xcc9e2d51; + const uint32_t c2 = 0x1b873593; - seed ^= (value + offset); - seed *= prime; - } - }; + k1 *= c1; + k1 = BOOST_FUNCTIONAL_HASH_ROTL32(k1,15); + k1 *= c2; - template <> - struct hash_combine_impl<8> + h1 ^= k1; + 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 + inline void hash_combine_impl(boost::uint64_t& h, + boost::uint64_t k) { - template - inline static void combine(T& seed, std::size_t value) - { - const T offset = 14695981039346656037ULL; - const T prime = 1099511628211ULL; + const uint64_t m = UINT64_C(0xc6a4a7935bd1e995); + const int r = 47; - seed ^= (value + offset); - seed *= prime; - } - }; + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; + } + +#endif // BOOST_NO_INT64_T } template @@ -290,8 +310,7 @@ namespace boost inline void hash_combine(std::size_t& seed, T const& v) { boost::hash hasher; - return boost::hash_detail::hash_combine_impl< - sizeof(std::size_t)>::combine(seed, hasher(v)); + return boost::hash_detail::hash_combine_impl(seed, hasher(v)); } #if defined(BOOST_MSVC) @@ -522,6 +541,7 @@ namespace boost } #undef BOOST_HASH_CHAR_TRAITS +#undef BOOST_FUNCTIONAL_HASH_ROTL32 #if defined(BOOST_MSVC) #pragma warning(pop)