forked from boostorg/container_hash
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:
@@ -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)
|
||||||
|
Reference in New Issue
Block a user