From 15318f0e46a1e10d9eba0adf8fa5a06ef14dcb27 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 1 Sep 2023 14:02:32 -0700 Subject: [PATCH] Refactor prime_fmod_size impl to no longer use Boost.Preprocessor --- .../boost/unordered/detail/implementation.hpp | 2 +- include/boost/unordered/detail/prime_fmod.hpp | 255 +++++++----------- test/unordered/prime_fmod_tests.cpp | 21 +- 3 files changed, 108 insertions(+), 170 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index e5c1b2c1..e44471b2 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1235,7 +1235,7 @@ namespace boost { typedef node node_type; typedef boost::unordered::detail::grouped_bucket_array< - bucket, value_allocator, prime_fmod_size<> > + bucket, value_allocator, prime_fmod_size> bucket_array_type; typedef diff --git a/include/boost/unordered/detail/prime_fmod.hpp b/include/boost/unordered/detail/prime_fmod.hpp index fab8f94e..e43c7fb8 100644 --- a/include/boost/unordered/detail/prime_fmod.hpp +++ b/include/boost/unordered/detail/prime_fmod.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2022 Joaquin M Lopez Munoz. -// Copyright (C) 2022 Christian Mazakas +// Copyright (C) 2022-2023 Christian Mazakas // // 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) @@ -7,13 +7,10 @@ #ifndef BOOST_UNORDERED_DETAIL_PRIME_FMOD_HPP #define BOOST_UNORDERED_DETAIL_PRIME_FMOD_HPP -#include -#include -#include -#include #include #include +#include #include #include @@ -35,28 +32,101 @@ namespace boost { namespace unordered { namespace detail { - template struct prime_fmod_size - { - // Because we compile for C++03, we don't have access to any inline - // initialization for array data members so the definitions must exist - // out-of-line. To keep the library header-only, we introduce a dummy - // template parameter which permits the definition to be included in - // multiple TUs without conflict. - // - static std::size_t sizes[]; - static std::size_t const sizes_len; - static std::size_t (*positions[])(std::size_t); + constexpr static std::size_t const prime_fmod_sizes[] = {13ul, 29ul, 53ul, + 97ul, 193ul, 389ul, 769ul, 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, + 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, + 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, + 402653189ul, 805306457ul, 1610612741ul, 3221225473ul, +#if !defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) + 4294967291ul +#else + 6442450939ull, 12884901893ull, 25769803751ull, 51539607551ull, + 103079215111ull, 206158430209ull, 412316860441ull, 824633720831ull, + 1649267441651ull +#endif + }; #if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) - static boost::uint64_t inv_sizes32[]; - static std::size_t const inv_sizes32_len; + constexpr static boost::uint64_t const prime_fmod_inv_sizes32[] = { + 1418980313362273202ull, 636094623231363849ull, 348051774975651918ull, + 190172619316593316ull, 95578984837873325ull, 47420935922132524ull, + 23987963684927896ull, 11955116055547344ull, 5991147799191151ull, + 2998982941588287ull, 1501077717772769ull, 750081082979285ull, + 375261795343686ull, 187625172388393ull, 93822606204624ull, + 46909513691883ull, 23456218233098ull, 11728086747027ull, + 5864041509391ull, 2932024948977ull, 1466014921160ull, 733007198436ull, + 366503839517ull, 183251896093ull, 91625960335ull, 45812983922ull, + 22906489714ull, 11453246088ull, 5726623060ull}; + +#endif /* defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) */ + + template + static std::size_t prime_fmod_position(std::size_t hash) + { + return hash % Size; + } + + constexpr static std::size_t (*prime_fmod_positions[])(std::size_t) = { +#if !defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) + prime_fmod_position<0>, + prime_fmod_position<1>, + prime_fmod_position<2>, + prime_fmod_position<3>, + prime_fmod_position<4>, + prime_fmod_position<5>, + prime_fmod_position<6>, + prime_fmod_position<7>, + prime_fmod_position<8>, + prime_fmod_position<9>, + prime_fmod_position<10>, + prime_fmod_position<11>, + prime_fmod_position<12>, + prime_fmod_position<13>, + prime_fmod_position<14>, + prime_fmod_position<15>, + prime_fmod_position<16>, + prime_fmod_position<17>, + prime_fmod_position<18>, + prime_fmod_position<19>, + prime_fmod_position<20>, + prime_fmod_position<21>, + prime_fmod_position<22>, + prime_fmod_position<23>, + prime_fmod_position<24>, + prime_fmod_position<25>, + prime_fmod_position<26>, + prime_fmod_position<27>, + prime_fmod_position<28>, + prime_fmod_position<29>, +#else + prime_fmod_position<29>, + prime_fmod_position<30>, + prime_fmod_position<31>, + prime_fmod_position<32>, + prime_fmod_position<33>, + prime_fmod_position<34>, + prime_fmod_position<35>, + prime_fmod_position<36>, + prime_fmod_position<37>, +#endif + }; + + struct prime_fmod_size + { + constexpr static std::size_t const sizes_len = + sizeof(prime_fmod_sizes) / sizeof(prime_fmod_sizes[0]); + +#if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) + constexpr static std::size_t const inv_sizes32_len = + sizeof(prime_fmod_inv_sizes32) / sizeof(prime_fmod_inv_sizes32[0]); #endif /* defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) */ static inline std::size_t size_index(std::size_t n) { std::size_t i = 0; for (; i < (sizes_len - 1); ++i) { - if (sizes[i] >= n) { + if (prime_fmod_sizes[i] >= n) { break; } } @@ -65,12 +135,7 @@ namespace boost { static inline std::size_t size(std::size_t size_index) { - return sizes[size_index]; - } - - template static std::size_t modulo(std::size_t hash) - { - return hash % Size; + return prime_fmod_sizes[size_index]; } #if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) @@ -118,146 +183,20 @@ namespace boost { #if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) std::size_t sizes_under_32bit = inv_sizes32_len; if (BOOST_LIKELY(size_index < sizes_under_32bit)) { - return fast_modulo( - narrow_cast(hash) + narrow_cast(hash >> 32), - inv_sizes32[size_index], boost::uint32_t(sizes[size_index])); + return fast_modulo(narrow_cast(hash) + + narrow_cast(hash >> 32), + prime_fmod_inv_sizes32[size_index], + boost::uint32_t(prime_fmod_sizes[size_index])); } else { - return positions[size_index - sizes_under_32bit](hash); + return prime_fmod_positions[size_index - sizes_under_32bit](hash); } #else - return positions[size_index](hash); + return prime_fmod_positions[size_index](hash); #endif /* defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) */ } }; // prime_fmod_size - -#define BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT_INCOMPLETE \ - (13ul)(29ul)(53ul)(97ul)(193ul)(389ul)(769ul)(1543ul)(3079ul)(6151ul)( \ - 12289ul)(24593ul)(49157ul)(98317ul)(196613ul)(393241ul)(786433ul)( \ - 1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul)(50331653ul)( \ - 100663319ul)(201326611ul)(402653189ul)(805306457ul)(1610612741ul)( \ - 3221225473ul) - -#if !defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) - -#define BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT \ - BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT_INCOMPLETE(4294967291ul) - -#define BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT - -#else - -#define BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT \ - BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT_INCOMPLETE - -// The original sequence here is this: -// (6442450939ul) -// (12884901893ul) -// (25769803751ul) -// (51539607551ul) -// (103079215111ul) -// (206158430209ul) -// (412316860441ul) -// (824633720831ul) -// (1649267441651ul) -// -// but this causes problems on versions of mingw where the `long` type is 32 -// bits, even for 64-bit targets. We work around this by replacing the literals -// with compile-time arithmetic, using bitshifts to reconstruct the number. -// - -// clang-format off -#define BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT \ - ((boost::ulong_long_type(1ul) << 32) + boost::ulong_long_type(2147483643ul)) \ - ((boost::ulong_long_type(3ul) << 32) + boost::ulong_long_type(5ul)) \ - ((boost::ulong_long_type(5ul) << 32) + boost::ulong_long_type(4294967271ul)) \ - ((boost::ulong_long_type(11ul) << 32) + boost::ulong_long_type(4294967295ul)) \ - ((boost::ulong_long_type(24ul) << 32) + boost::ulong_long_type(7ul)) \ - ((boost::ulong_long_type(48ul) << 32) + boost::ulong_long_type(1ul)) \ - ((boost::ulong_long_type(96ul) << 32) + boost::ulong_long_type(25ul)) \ - ((boost::ulong_long_type(191ul) << 32) + boost::ulong_long_type(4294967295ul)) \ - ((boost::ulong_long_type(383ul) << 32) + boost::ulong_long_type(4294967283ul)) - // clang-format on - -#endif /* BOOST_UNORDERED_FCA_HAS_64B_SIZE_T */ - -#define BOOST_UNORDERED_PRIME_FMOD_SIZES \ - BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT - - template - std::size_t prime_fmod_size::sizes[] = { - BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIME_FMOD_SIZES)}; - - template - std::size_t const prime_fmod_size::sizes_len = BOOST_PP_SEQ_SIZE( - BOOST_UNORDERED_PRIME_FMOD_SIZES); - -// Similarly here, we have to re-express the integer initialization using -// arithmetic such that each literal can fit in a 32-bit value. -// -#if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) - // clang-format off - template - boost::uint64_t prime_fmod_size::inv_sizes32[] = { - (boost::ulong_long_type(330382099ul) << 32) + boost::ulong_long_type(2973438898ul) /* = 1418980313362273202 */, - (boost::ulong_long_type(148102320ul) << 32) + boost::ulong_long_type(2369637129ul) /* = 636094623231363849 */, - (boost::ulong_long_type(81037118ul) << 32) + boost::ulong_long_type(3403558990ul) /* = 348051774975651918 */, - (boost::ulong_long_type(44278013ul) << 32) + boost::ulong_long_type(1549730468ul) /* = 190172619316593316 */, - (boost::ulong_long_type(22253716ul) << 32) + boost::ulong_long_type(2403401389ul) /* = 95578984837873325 */, - (boost::ulong_long_type(11041047ul) << 32) + boost::ulong_long_type(143533612ul) /* = 47420935922132524 */, - (boost::ulong_long_type(5585133ul) << 32) + boost::ulong_long_type(106117528ul) /* = 23987963684927896 */, - (boost::ulong_long_type(2783517ul) << 32) + boost::ulong_long_type(1572687312ul) /* = 11955116055547344 */, - (boost::ulong_long_type(1394922ul) << 32) + boost::ulong_long_type(3428720239ul) /* = 5991147799191151 */, - (boost::ulong_long_type(698255ul) << 32) + boost::ulong_long_type(552319807ul) /* = 2998982941588287 */, - (boost::ulong_long_type(349496ul) << 32) + boost::ulong_long_type(3827689953ul) /* = 1501077717772769 */, - (boost::ulong_long_type(174641ul) << 32) + boost::ulong_long_type(3699438549ul) /* = 750081082979285 */, - (boost::ulong_long_type(87372ul) << 32) + boost::ulong_long_type(1912757574ul) /* = 375261795343686 */, - (boost::ulong_long_type(43684ul) << 32) + boost::ulong_long_type(3821029929ul) /* = 187625172388393 */, - (boost::ulong_long_type(21844ul) << 32) + boost::ulong_long_type(3340590800ul) /* = 93822606204624 */, - (boost::ulong_long_type(10921ul) << 32) + boost::ulong_long_type(4175852267ul) /* = 46909513691883 */, - (boost::ulong_long_type(5461ul) << 32) + boost::ulong_long_type(1401829642ul) /* = 23456218233098 */, - (boost::ulong_long_type(2730ul) << 32) + boost::ulong_long_type(2826028947ul) /* = 11728086747027 */, - (boost::ulong_long_type(1365ul) << 32) + boost::ulong_long_type(1411150351ul) /* = 5864041509391 */, - (boost::ulong_long_type(682ul) << 32) + boost::ulong_long_type(2857253105ul) /* = 2932024948977 */, - (boost::ulong_long_type(341ul) << 32) + boost::ulong_long_type(1431073224ul) /* = 1466014921160 */, - (boost::ulong_long_type(170ul) << 32) + boost::ulong_long_type(2862758116ul) /* = 733007198436 */, - (boost::ulong_long_type(85ul) << 32) + boost::ulong_long_type(1431619357ul) /* = 366503839517 */, - (boost::ulong_long_type(42ul) << 32) + boost::ulong_long_type(2863269661ul) /* = 183251896093 */, - (boost::ulong_long_type(21ul) << 32) + boost::ulong_long_type(1431647119ul) /* = 91625960335 */, - (boost::ulong_long_type(10ul) << 32) + boost::ulong_long_type(2863310962ul) /* = 45812983922 */, - (boost::ulong_long_type(5ul) << 32) + boost::ulong_long_type(1431653234ul) /* = 22906489714 */, - (boost::ulong_long_type(2ul) << 32) + boost::ulong_long_type(2863311496ul) /* = 11453246088 */, - (boost::ulong_long_type(1ul) << 32) + boost::ulong_long_type(1431655764ul) /* = 5726623060 */, - }; - // clang-format on - - template - std::size_t const - prime_fmod_size::inv_sizes32_len = sizeof(inv_sizes32) / - sizeof(inv_sizes32[0]); - -#endif /* defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) */ - -#define BOOST_UNORDERED_PRIME_FMOD_POSITIONS_ELEMENT(z, _, n) \ - prime_fmod_size::template modulo, - - template - std::size_t (*prime_fmod_size::positions[])(std::size_t) = { -#if !defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) - BOOST_PP_SEQ_FOR_EACH(BOOST_UNORDERED_PRIME_FMOD_POSITIONS_ELEMENT, ~, - BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT) -#else - BOOST_PP_SEQ_FOR_EACH(BOOST_UNORDERED_PRIME_FMOD_POSITIONS_ELEMENT, ~, - BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT) -#endif - }; - -#undef BOOST_UNORDERED_PRIME_FMOD_POSITIONS_ELEMENT -#undef BOOST_UNORDERED_PRIME_FMOD_SIZES -#undef BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT -#undef BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT -#undef BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT_INCOMPLETE } // namespace detail - } // namespace unordered + } // namespace unordered } // namespace boost #endif // BOOST_UNORDERED_DETAIL_PRIME_FMOD_HPP diff --git a/test/unordered/prime_fmod_tests.cpp b/test/unordered/prime_fmod_tests.cpp index 2094bc57..360596be 100644 --- a/test/unordered/prime_fmod_tests.cpp +++ b/test/unordered/prime_fmod_tests.cpp @@ -64,9 +64,8 @@ void prime_sizes_test() BOOST_TEST(!is_prime(100)); BOOST_TEST(!is_prime(49)); - std::size_t* sizes = boost::unordered::detail::prime_fmod_size<>::sizes; - std::size_t sizes_len = - boost::unordered::detail::prime_fmod_size<>::sizes_len; + std::size_t const* sizes = boost::unordered::detail::prime_fmod_sizes; + std::size_t sizes_len = boost::unordered::detail::prime_fmod_size::sizes_len; // prove every number in our sizes array is prime // @@ -88,11 +87,11 @@ void prime_sizes_test() // correct amount of them, i.e. one for every entry in sizes[] that fits in 32 // bits // - boost::uint64_t* inv_sizes32 = - boost::unordered::detail::prime_fmod_size<>::inv_sizes32; + boost::uint64_t const* inv_sizes32 = + boost::unordered::detail::prime_fmod_inv_sizes32; std::size_t inv_sizes32_len = - boost::unordered::detail::prime_fmod_size<>::inv_sizes32_len; + boost::unordered::detail::prime_fmod_size::inv_sizes32_len; std::size_t count = 0; for (std::size_t i = 0; i < sizes_len; ++i) { @@ -133,7 +132,7 @@ void get_remainder_test() #if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) struct { - // boost::unordered::detail::prime_fmod_size<>::get_remainder + // boost::unordered::detail::prime_fmod_size::get_remainder // uses several internal implementations depending on the availability of // certain intrinsics or 128 bit integer support, defaulting to a slow, // portable routine. The following is a transcription of the portable @@ -157,7 +156,7 @@ void get_remainder_test() boost::uint32_t d = rng() & 0xffffffffu; boost::uint64_t r1 = - boost::unordered::detail::prime_fmod_size<>::get_remainder(f, d); + boost::unordered::detail::prime_fmod_size::get_remainder(f, d); boost::uint64_t r2 = get_remainder(f, d); @@ -171,10 +170,10 @@ void get_remainder_test() void modulo_test() { - std::size_t* sizes = boost::unordered::detail::prime_fmod_size<>::sizes; + std::size_t const* sizes = boost::unordered::detail::prime_fmod_sizes; std::size_t const sizes_len = - boost::unordered::detail::prime_fmod_size<>::sizes_len; + boost::unordered::detail::prime_fmod_size::sizes_len; boost::detail::splitmix64 rng; @@ -190,7 +189,7 @@ void modulo_test() } #endif std::size_t p1 = - boost::unordered::detail::prime_fmod_size<>::position(hash, j); + boost::unordered::detail::prime_fmod_size::position(hash, j); std::size_t p2 = h % sizes[j];