mirror of
https://github.com/boostorg/container_hash.git
synced 2025-08-04 15:04:39 +02:00
Add hash_mix, change hash_combine to use it
This commit is contained in:
113
include/boost/container_hash/detail/hash_mix.hpp
Normal file
113
include/boost/container_hash/detail/hash_mix.hpp
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
// Copyright 2022 Peter Dimov
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
|
#ifndef BOOST_HASH_DETAIL_HASH_MIX_HPP
|
||||||
|
#define BOOST_HASH_DETAIL_HASH_MIX_HPP
|
||||||
|
|
||||||
|
#include <boost/cstdint.hpp>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
namespace hash_detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<std::size_t Bits> struct hash_mix_impl;
|
||||||
|
|
||||||
|
// hash_mix for 64 bit size_t
|
||||||
|
//
|
||||||
|
// The general "xmxmx" form of state of the art 64 bit mixers originates
|
||||||
|
// from Murmur3 by Austin Appleby, which uses the following function as
|
||||||
|
// its "final mix":
|
||||||
|
//
|
||||||
|
// k ^= k >> 33;
|
||||||
|
// k *= 0xff51afd7ed558ccd;
|
||||||
|
// k ^= k >> 33;
|
||||||
|
// k *= 0xc4ceb9fe1a85ec53;
|
||||||
|
// k ^= k >> 33;
|
||||||
|
//
|
||||||
|
// (https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp)
|
||||||
|
//
|
||||||
|
// It has subsequently been improved multiple times by different authors
|
||||||
|
// by changing the constants. The most well known improvement is the
|
||||||
|
// so-called "variant 13" function by David Stafford:
|
||||||
|
//
|
||||||
|
// k ^= k >> 30;
|
||||||
|
// k *= 0xbf58476d1ce4e5b9;
|
||||||
|
// k ^= k >> 27;
|
||||||
|
// k *= 0x94d049bb133111eb;
|
||||||
|
// k ^= k >> 31;
|
||||||
|
//
|
||||||
|
// (https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html)
|
||||||
|
//
|
||||||
|
// This mixing function is used in the splitmix64 RNG:
|
||||||
|
// http://xorshift.di.unimi.it/splitmix64.c
|
||||||
|
//
|
||||||
|
// We use Jon Maiga's implementation from
|
||||||
|
// http://jonkagstrom.com/mx3/mx3_rev2.html
|
||||||
|
//
|
||||||
|
// x ^= x >> 32;
|
||||||
|
// x *= 0xe9846af9b1a615d;
|
||||||
|
// x ^= x >> 32;
|
||||||
|
// x *= 0xe9846af9b1a615d;
|
||||||
|
// x ^= x >> 28;
|
||||||
|
//
|
||||||
|
// An equally good alternative is Pelle Evensen's Moremur:
|
||||||
|
//
|
||||||
|
// x ^= x >> 27;
|
||||||
|
// x *= 0x3C79AC492BA7B653;
|
||||||
|
// x ^= x >> 33;
|
||||||
|
// x *= 0x1C69B3F74AC4AE35;
|
||||||
|
// x ^= x >> 27;
|
||||||
|
//
|
||||||
|
// (https://mostlymangling.blogspot.com/2019/12/stronger-better-morer-moremur-better.html)
|
||||||
|
|
||||||
|
template<> struct hash_mix_impl<64>
|
||||||
|
{
|
||||||
|
inline static boost::uint64_t fn( boost::uint64_t x )
|
||||||
|
{
|
||||||
|
boost::uint64_t const m = (boost::uint64_t(0xe9846af9) << 32) + 0xb1a615d;
|
||||||
|
|
||||||
|
x ^= x >> 32;
|
||||||
|
x *= m;
|
||||||
|
x ^= x >> 32;
|
||||||
|
x *= m;
|
||||||
|
x ^= x >> 28;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// hash_mix for 32 bit size_t
|
||||||
|
//
|
||||||
|
// We use the "best xmxmx" implementation from
|
||||||
|
// https://github.com/skeeto/hash-prospector/issues/19
|
||||||
|
|
||||||
|
template<> struct hash_mix_impl<32>
|
||||||
|
{
|
||||||
|
inline static boost::uint32_t fn( boost::uint32_t x )
|
||||||
|
{
|
||||||
|
boost::uint32_t const m1 = 0x21f0aaad;
|
||||||
|
boost::uint32_t const m2 = 0x735a2d97;
|
||||||
|
|
||||||
|
x ^= x >> 16;
|
||||||
|
x *= m1;
|
||||||
|
x ^= x >> 15;
|
||||||
|
x *= m2;
|
||||||
|
x ^= x >> 15;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::size_t hash_mix( std::size_t v )
|
||||||
|
{
|
||||||
|
return hash_mix_impl<sizeof(std::size_t) * CHAR_BIT>::fn( v );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace hash_detail
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // #ifndef BOOST_HASH_DETAIL_HASH_MIX_HPP
|
@@ -1,17 +1,11 @@
|
|||||||
// Copyright 2005-2014 Daniel James.
|
// Copyright 2005-2014 Daniel James.
|
||||||
// Copyright 2021 Peter Dimov.
|
// Copyright 2021, 2022 Peter Dimov.
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
// https://www.boost.org/LICENSE_1_0.txt
|
// https://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.
|
|
||||||
|
|
||||||
#ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP
|
#ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP
|
||||||
#define BOOST_FUNCTIONAL_HASH_HASH_HPP
|
#define BOOST_FUNCTIONAL_HASH_HASH_HPP
|
||||||
@@ -21,6 +15,7 @@
|
|||||||
#include <boost/container_hash/is_contiguous_range.hpp>
|
#include <boost/container_hash/is_contiguous_range.hpp>
|
||||||
#include <boost/container_hash/is_unordered_range.hpp>
|
#include <boost/container_hash/is_unordered_range.hpp>
|
||||||
#include <boost/container_hash/detail/hash_tuple.hpp>
|
#include <boost/container_hash/detail/hash_tuple.hpp>
|
||||||
|
#include <boost/container_hash/detail/hash_mix.hpp>
|
||||||
#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/type_traits/is_floating_point.hpp>
|
#include <boost/type_traits/is_floating_point.hpp>
|
||||||
@@ -58,12 +53,6 @@
|
|||||||
#include <variant>
|
#include <variant>
|
||||||
#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
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -558,82 +547,12 @@ namespace boost
|
|||||||
// boost::hash_combine
|
// boost::hash_combine
|
||||||
//
|
//
|
||||||
|
|
||||||
namespace hash_detail
|
|
||||||
{
|
|
||||||
|
|
||||||
template<std::size_t Bits> struct hash_combine_impl
|
|
||||||
{
|
|
||||||
template <typename SizeT>
|
|
||||||
inline static SizeT fn(SizeT seed, SizeT value)
|
|
||||||
{
|
|
||||||
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<> struct hash_combine_impl<32>
|
|
||||||
{
|
|
||||||
inline static boost::uint32_t fn(boost::uint32_t h1, boost::uint32_t k1)
|
|
||||||
{
|
|
||||||
const boost::uint32_t c1 = 0xcc9e2d51;
|
|
||||||
const boost::uint32_t c2 = 0x1b873593;
|
|
||||||
|
|
||||||
k1 *= c1;
|
|
||||||
k1 = BOOST_FUNCTIONAL_HASH_ROTL32(k1,15);
|
|
||||||
k1 *= c2;
|
|
||||||
|
|
||||||
h1 ^= k1;
|
|
||||||
h1 = BOOST_FUNCTIONAL_HASH_ROTL32(h1,13);
|
|
||||||
h1 = h1*5+0xe6546b64;
|
|
||||||
|
|
||||||
return h1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<> struct hash_combine_impl<64>
|
|
||||||
{
|
|
||||||
inline static boost::uint64_t fn(boost::uint64_t h, boost::uint64_t k)
|
|
||||||
{
|
|
||||||
const boost::uint64_t m = (boost::uint64_t(0xc6a4a793) << 32) + 0x5bd1e995;
|
|
||||||
const int r = 47;
|
|
||||||
|
|
||||||
k *= m;
|
|
||||||
k ^= k >> r;
|
|
||||||
k *= m;
|
|
||||||
|
|
||||||
h ^= k;
|
|
||||||
h *= m;
|
|
||||||
|
|
||||||
// Completely arbitrary number, to prevent 0's
|
|
||||||
// from hashing to 0.
|
|
||||||
h += 0xe6546b64;
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(BOOST_MSVC)
|
|
||||||
#pragma warning(push)
|
|
||||||
#if BOOST_MSVC <= 1400
|
|
||||||
#pragma warning(disable:4267) // 'argument' : conversion from 'size_t' to
|
|
||||||
// 'unsigned int', possible loss of data
|
|
||||||
// A misguided attempt to detect 64-bit
|
|
||||||
// incompatability.
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
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;
|
seed = boost::hash_detail::hash_mix( seed + 0x9e3779b9 + boost::hash<T>()( v ) );
|
||||||
seed = boost::hash_detail::hash_combine_impl<sizeof(std::size_t) * CHAR_BIT>::fn(seed, hasher(v));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(BOOST_MSVC)
|
|
||||||
#pragma warning(pop)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// boost::hash_range
|
// boost::hash_range
|
||||||
//
|
//
|
||||||
|
Reference in New Issue
Block a user