From 3f105a78f052e8b883cce0b9b054b28e0ec1678e Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 9 Dec 2022 12:15:04 +0200 Subject: [PATCH] Add xmx3, mulx2 with multipliers from https://arxiv.org/abs/2001.05304 --- benchmark/uint32.cpp | 9 +++++++++ benchmark/uint64.cpp | 9 +++++++++ benchmark/uuid.cpp | 9 +++++++++ benchmark/word_size.cpp | 9 +++++++++ include/boost/unordered/detail/foa.hpp | 18 +++++++++++++++++ include/boost/unordered/detail/mulx.hpp | 17 ++++++++++++++++ include/boost/unordered/detail/xmx.hpp | 27 ++++++++++++++++++++++++- 7 files changed, 97 insertions(+), 1 deletion(-) diff --git a/benchmark/uint32.cpp b/benchmark/uint32.cpp index d0f23d3e..8d322692 100644 --- a/benchmark/uint32.cpp +++ b/benchmark/uint32.cpp @@ -295,9 +295,15 @@ template using boost_unordered_flat_map_xmx = template using boost_unordered_flat_map_xmx2 = boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::xmx2_mix>; +template using boost_unordered_flat_map_xmx3 = + boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::xmx3_mix>; + template using boost_unordered_flat_map_mulx = boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::mulx_mix>; +template using boost_unordered_flat_map_mulx2 = + boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::mulx2_mix>; + #ifdef HAVE_ABSEIL template using absl_node_hash_map = @@ -321,9 +327,12 @@ int main() test( "std::unordered_map" ); test( "boost::unordered_map" ); + test( "boost::unordered_flat_map, xmx" ); test( "boost::unordered_flat_map, xmx2" ); + test( "boost::unordered_flat_map, xmx3" ); test( "boost::unordered_flat_map, mulx" ); + test( "boost::unordered_flat_map, mulx2" ); #ifdef HAVE_ANKERL_UNORDERED_DENSE diff --git a/benchmark/uint64.cpp b/benchmark/uint64.cpp index c7765a8c..44b872d9 100644 --- a/benchmark/uint64.cpp +++ b/benchmark/uint64.cpp @@ -295,9 +295,15 @@ template using boost_unordered_flat_map_xmx = template using boost_unordered_flat_map_xmx2 = boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::xmx2_mix>; +template using boost_unordered_flat_map_xmx3 = + boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::xmx3_mix>; + template using boost_unordered_flat_map_mulx = boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::mulx_mix>; +template using boost_unordered_flat_map_mulx2 = + boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::mulx2_mix>; + #ifdef HAVE_ABSEIL template using absl_node_hash_map = @@ -331,9 +337,12 @@ int main() #endif test( "boost::unordered_map" ); + test( "boost::unordered_flat_map, xmx" ); test( "boost::unordered_flat_map, xmx2" ); + test( "boost::unordered_flat_map, xmx3" ); test( "boost::unordered_flat_map, mulx" ); + test( "boost::unordered_flat_map, mulx2" ); #ifdef HAVE_ANKERL_UNORDERED_DENSE diff --git a/benchmark/uuid.cpp b/benchmark/uuid.cpp index e201afae..0953770d 100644 --- a/benchmark/uuid.cpp +++ b/benchmark/uuid.cpp @@ -346,9 +346,15 @@ template using boost_unordered_flat_map_xmx = template using boost_unordered_flat_map_xmx2 = boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::xmx2_mix>; +template using boost_unordered_flat_map_xmx3 = + boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::xmx3_mix>; + template using boost_unordered_flat_map_mulx = boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::mulx_mix>; +template using boost_unordered_flat_map_mulx2 = + boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::mulx2_mix>; + #ifdef HAVE_ABSEIL template using absl_node_hash_map = @@ -372,9 +378,12 @@ int main() test( "std::unordered_map" ); test( "boost::unordered_map" ); + test( "boost::unordered_flat_map, xmx" ); test( "boost::unordered_flat_map, xmx2" ); + test( "boost::unordered_flat_map, xmx3" ); test( "boost::unordered_flat_map, mulx" ); + test( "boost::unordered_flat_map, mulx2" ); #ifdef HAVE_ANKERL_UNORDERED_DENSE diff --git a/benchmark/word_size.cpp b/benchmark/word_size.cpp index 2017776f..6465b3fb 100644 --- a/benchmark/word_size.cpp +++ b/benchmark/word_size.cpp @@ -187,9 +187,15 @@ template using boost_unordered_flat_map_xmx = template using boost_unordered_flat_map_xmx2 = boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::xmx2_mix>; +template using boost_unordered_flat_map_xmx3 = + boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::xmx3_mix>; + template using boost_unordered_flat_map_mulx = boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::mulx_mix>; +template using boost_unordered_flat_map_mulx2 = + boost::unordered_flat_map, std::equal_to, allocator_for, boost::unordered::detail::foa::mulx2_mix>; + #ifdef HAVE_ABSEIL template using absl_node_hash_map = @@ -213,9 +219,12 @@ int main() test( "std::unordered_map" ); test( "boost::unordered_map" ); + test( "boost::unordered_flat_map, xmx" ); test( "boost::unordered_flat_map, xmx2" ); + test( "boost::unordered_flat_map, xmx3" ); test( "boost::unordered_flat_map, mulx" ); + test( "boost::unordered_flat_map, mulx2" ); #ifdef HAVE_ANKERL_UNORDERED_DENSE diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 8cb3f393..e717bef6 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -770,6 +770,15 @@ struct xmx2_mix } }; +struct xmx3_mix +{ + template + static inline std::size_t mix(const Hash& h,const T& x) + { + return xmx3(h(x)); + } +}; + struct mulx_mix { template @@ -779,6 +788,15 @@ struct mulx_mix } }; +struct mulx2_mix +{ + template + static inline std::size_t mix(const Hash& h,const T& x) + { + return mulx2(h(x)); + } +}; + /* boost::core::countr_zero has a potentially costly check for * the case x==0. */ diff --git a/include/boost/unordered/detail/mulx.hpp b/include/boost/unordered/detail/mulx.hpp index 93baea9f..cbd61a8c 100644 --- a/include/boost/unordered/detail/mulx.hpp +++ b/include/boost/unordered/detail/mulx.hpp @@ -94,6 +94,8 @@ inline boost::uint32_t mulx32( boost::uint32_t x, boost::uint32_t y ) #endif #endif +// phi multipliers + inline std::size_t mulx( std::size_t x ) noexcept { #if defined(BOOST_UNORDERED_64B_ARCHITECTURE) @@ -107,6 +109,21 @@ inline std::size_t mulx( std::size_t x ) noexcept #endif } +// multipliers from https://arxiv.org/abs/2001.05304 + +inline std::size_t mulx2( std::size_t x ) noexcept +{ +#if defined(BOOST_UNORDERED_64B_ARCHITECTURE) + + return (std::size_t)mulx64( (boost::uint64_t)x, 0xDEFBA91144F2B375ull ); + +#else /* 32 bits assumed */ + + return mulx32( x, 0xE817FB2Du ); + +#endif +} + #ifdef BOOST_UNORDERED_64B_ARCHITECTURE #undef BOOST_UNORDERED_64B_ARCHITECTURE #endif diff --git a/include/boost/unordered/detail/xmx.hpp b/include/boost/unordered/detail/xmx.hpp index d4c27434..99f4841f 100644 --- a/include/boost/unordered/detail/xmx.hpp +++ b/include/boost/unordered/detail/xmx.hpp @@ -64,7 +64,7 @@ static inline std::size_t xmx(std::size_t x)noexcept #endif } -// alternative multipliers +// alternative multipliers (phi) static inline std::size_t xmx2( std::size_t x ) noexcept { @@ -89,6 +89,31 @@ static inline std::size_t xmx2( std::size_t x ) noexcept #endif } +// alternative multipliers (https://arxiv.org/abs/2001.05304) + +static inline std::size_t xmx3( std::size_t x ) noexcept +{ +#if defined(BOOST_UNORDERED_64B_ARCHITECTURE) + + boost::uint64_t z=(boost::uint64_t)x; + + z ^= z >> 23; + z *= 0xF1357AEA2E62A9C5ull; + z ^= z >> 23; + + return (std::size_t)z; + +#else /* 32 bits assumed */ + + x ^= x >> 18; + x *= 0x93D765DDu; + x ^= x >> 16; + + return x; + +#endif +} + #ifdef BOOST_UNORDERED_64B_ARCHITECTURE #undef BOOST_UNORDERED_64B_ARCHITECTURE #endif