Compare commits

..
Author SHA1 Message Date
joaquintides f864ea3ade added next node prefetching 2022-06-21 20:19:56 +02:00
9 changed files with 133 additions and 486 deletions
+2 -10
View File
@@ -106,17 +106,9 @@ environment:
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
ADDPATH: C:\cygwin64\bin;
B2_ADDRESS_MODEL: 64
B2_CXXSTD: 03,11
B2_CXXSTD: 03,11,14,1z
B2_TOOLSET: gcc
B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception"
- FLAVOR: cygwin (64-bit, latest)
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
ADDPATH: C:\cygwin64\bin;
B2_ADDRESS_MODEL: 64
B2_CXXSTD: 14,1z
B2_TOOLSET: gcc
B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception"
MAYFAIL: true
- FLAVOR: mingw32
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+1
View File
@@ -18,6 +18,7 @@ target_link_libraries(boost_unordered
Boost::config
Boost::container_hash
Boost::core
Boost::iterator
Boost::move
Boost::mp11
Boost::predef
+51 -107
View File
@@ -124,6 +124,25 @@ to normal separate chaining implementations.
#include <boost/core/empty_value.hpp>
#include <boost/core/no_exceptions_support.hpp>
#include <boost/cstdint.hpp>
// `iterator_facade` has transitive dependencies on Boost.MPL; one of the
// headers is generating a `-Wsign-conversion` warning which has an open PR to
// address the issue but merging does not seem likely so for now create a rote
// workaround.
//
// TODO: eventually remove this once MPL is fixed or we decide to migrate off of
// the Boost.Iterator dependency.
//
#if defined(BOOST_GCC)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
#pragma GCC diagnostic ignored "-Wconversion"
#include <boost/iterator/iterator_facade.hpp>
#pragma GCC diagnostic pop
#else
#include <boost/iterator/iterator_facade.hpp>
#endif
#include <boost/move/core.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/preprocessor/seq/enum.hpp>
@@ -134,7 +153,6 @@ to normal separate chaining implementations.
#include <boost/type_traits/alignment_of.hpp>
#include <climits>
#include <iterator>
namespace boost {
namespace unordered {
@@ -151,7 +169,7 @@ namespace boost {
#endif
#if !defined(BOOST_NO_INT64_T) && \
(defined(BOOST_HAS_INT128) || (defined(_MSC_VER) && defined(_M_X64)))
(defined(BOOST_HAS_INT128) || (defined(BOOST_MSVC) && defined(_WIN64)))
#define BOOST_UNORDERED_FCA_FASTMOD_SUPPORT
#endif
@@ -344,7 +362,7 @@ namespace boost {
(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 */,
#if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
#if !defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
};
#else
(boost::ulong_long_type(1ul) << 32) + boost::ulong_long_type(6ul) /* 4294967302 */
@@ -378,8 +396,16 @@ namespace boost {
#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
#undef BOOST_UNORDERED_PRIME_FMOD_SIZES_34BIT
#undef BOOST_UNORDERED_PRIME_FMOD_SIZES_34BIT_INCOMPLETE
#ifdef BOOST_UNORDERED_FCA_FASTMOD_SUPPORT
#undef BOOST_UNORDERED_FCA_FASTMOD_SUPPORT
#endif
#ifdef BOOST_UNORDERED_FCA_HAS_64B_SIZE_T
#undef BOOST_UNORDERED_FCA_HAS_64B_SIZE_T
#endif
template <class ValueType, class VoidPtr> struct node
{
@@ -446,7 +472,10 @@ namespace boost {
return ~(~(std::size_t(0)) >> (sizeof(std::size_t) * 8 - n));
}
template <class Bucket> struct grouped_bucket_iterator
template <class Bucket>
struct grouped_bucket_iterator
: public boost::iterator_facade<grouped_bucket_iterator<Bucket>,
Bucket, boost::forward_traversal_tag>
{
public:
typedef typename Bucket::bucket_pointer bucket_pointer;
@@ -454,12 +483,8 @@ namespace boost {
typename boost::pointer_traits<bucket_pointer>::template rebind_to<
bucket_group<Bucket> >::type bucket_group_pointer;
typedef Bucket value_type;
typedef typename boost::pointer_traits<bucket_pointer>::difference_type
difference_type;
typedef Bucket& reference;
typedef Bucket* pointer;
typedef std::forward_iterator_tag iterator_category;
private:
bucket_pointer p;
@@ -468,38 +493,9 @@ namespace boost {
public:
grouped_bucket_iterator() : p(), pbg() {}
reference operator*() const BOOST_NOEXCEPT { return dereference(); }
pointer operator->() const BOOST_NOEXCEPT
{
return boost::to_address(p);
}
grouped_bucket_iterator& operator++() BOOST_NOEXCEPT
{
increment();
return *this;
}
grouped_bucket_iterator operator++(int) BOOST_NOEXCEPT
{
grouped_bucket_iterator old = *this;
increment();
return old;
}
bool operator==(
grouped_bucket_iterator const& other) const BOOST_NOEXCEPT
{
return equal(other);
}
bool operator!=(
grouped_bucket_iterator const& other) const BOOST_NOEXCEPT
{
return !equal(other);
}
private:
friend class boost::iterator_core_access;
template <typename, typename, typename>
friend class grouped_bucket_array;
@@ -537,8 +533,12 @@ namespace boost {
template <class Node> struct const_grouped_local_bucket_iterator;
template <class Node> struct grouped_local_bucket_iterator
template <class Node>
struct grouped_local_bucket_iterator
: public boost::iterator_facade<grouped_local_bucket_iterator<Node>,
typename Node::value_type, boost::forward_traversal_tag>
{
typedef typename Node::node_pointer node_pointer;
public:
@@ -551,39 +551,9 @@ namespace boost {
grouped_local_bucket_iterator() : p() {}
reference operator*() const BOOST_NOEXCEPT { return dereference(); }
pointer operator->() const BOOST_NOEXCEPT
{
return boost::to_address(p);
}
grouped_local_bucket_iterator& operator++() BOOST_NOEXCEPT
{
increment();
return *this;
}
grouped_local_bucket_iterator operator++(int) BOOST_NOEXCEPT
{
grouped_local_bucket_iterator old = *this;
increment();
return old;
}
bool operator==(
grouped_local_bucket_iterator const& other) const BOOST_NOEXCEPT
{
return equal(other);
}
bool operator!=(
grouped_local_bucket_iterator const& other) const BOOST_NOEXCEPT
{
return !equal(other);
}
private:
friend class boost::iterator_core_access;
template <typename, typename, typename>
friend class grouped_bucket_array;
@@ -603,7 +573,11 @@ namespace boost {
node_pointer p;
};
template <class Node> struct const_grouped_local_bucket_iterator
template <class Node>
struct const_grouped_local_bucket_iterator
: public boost::iterator_facade<
const_grouped_local_bucket_iterator<Node>,
typename Node::value_type const, boost::forward_traversal_tag>
{
typedef typename Node::node_pointer node_pointer;
@@ -622,39 +596,9 @@ namespace boost {
{
}
reference operator*() const BOOST_NOEXCEPT { return dereference(); }
pointer operator->() const BOOST_NOEXCEPT
{
return boost::to_address(p);
}
const_grouped_local_bucket_iterator& operator++() BOOST_NOEXCEPT
{
increment();
return *this;
}
const_grouped_local_bucket_iterator operator++(int) BOOST_NOEXCEPT
{
const_grouped_local_bucket_iterator old = *this;
increment();
return old;
}
bool operator==(
const_grouped_local_bucket_iterator const& other) const BOOST_NOEXCEPT
{
return equal(other);
}
bool operator!=(
const_grouped_local_bucket_iterator const& other) const BOOST_NOEXCEPT
{
return !equal(other);
}
private:
friend class boost::iterator_core_access;
template <typename, typename, typename>
friend class grouped_bucket_array;
+57 -104
View File
@@ -15,6 +15,7 @@
#endif
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/core/allocator_traits.hpp>
#include <boost/core/bit.hpp>
#include <boost/core/no_exceptions_support.hpp>
@@ -59,6 +60,15 @@
#include <type_traits>
#endif
#if __SSE2__
#include <emmintrin.h>
#endif
#if defined(__SSE2__) || \
defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
#define BOOST_UNORDERED_SSE2_SUPPORTED
#endif
////////////////////////////////////////////////////////////////////////////////
// Configuration
//
@@ -1697,9 +1707,10 @@ namespace boost {
};
template <typename T>
struct rv_ref : boost::conditional<boost::is_class<T>::value,
boost::unordered::detail::rv_ref_impl<T>,
please_ignore_this_overload>::type
struct rv_ref
: boost::detail::if_true<boost::is_class<T>::value>::
BOOST_NESTED_TEMPLATE then<boost::unordered::detail::rv_ref_impl<T>,
please_ignore_this_overload>::type
{
};
@@ -1729,7 +1740,10 @@ namespace boost {
namespace iterator_detail {
template <class Node, class Bucket> class c_iterator;
template <class Node, class Bucket> class iterator
template <class Node, class Bucket>
class iterator
: public boost::iterator_facade<iterator<Node, Bucket>,
typename Node::value_type, boost::forward_traversal_tag>
{
public:
typedef typename Node::value_type value_type;
@@ -1741,50 +1755,6 @@ namespace boost {
iterator() : p(), itb(){};
reference operator*() const BOOST_NOEXCEPT { return dereference(); }
pointer operator->() const BOOST_NOEXCEPT
{
pointer x = boost::addressof(p->value());
return x;
}
iterator& operator++() BOOST_NOEXCEPT
{
increment();
return *this;
}
iterator operator++(int) BOOST_NOEXCEPT
{
iterator old = *this;
increment();
return old;
}
bool operator==(iterator const& other) const BOOST_NOEXCEPT
{
return equal(other);
}
bool operator!=(iterator const& other) const BOOST_NOEXCEPT
{
return !equal(other);
}
bool operator==(
boost::unordered::detail::iterator_detail::c_iterator<Node,
Bucket> const& other) const BOOST_NOEXCEPT
{
return equal(other);
}
bool operator!=(
boost::unordered::detail::iterator_detail::c_iterator<Node,
Bucket> const& other) const BOOST_NOEXCEPT
{
return !equal(other);
}
private:
typedef typename Node::node_pointer node_pointer;
typedef grouped_bucket_iterator<Bucket> bucket_iterator;
@@ -1794,6 +1764,7 @@ namespace boost {
template <class Types> friend struct boost::unordered::detail::table;
template <class N, class B> friend class c_iterator;
friend class boost::iterator_core_access;
iterator(node_pointer p_, bucket_iterator itb_) : p(p_), itb(itb_) {}
@@ -1804,13 +1775,6 @@ namespace boost {
return (p == x.p);
}
bool equal(
const boost::unordered::detail::iterator_detail::c_iterator<Node,
Bucket>& x) const BOOST_NOEXCEPT
{
return (p == x.p);
}
void increment() BOOST_NOEXCEPT
{
p = p->next;
@@ -1820,7 +1784,10 @@ namespace boost {
}
};
template <class Node, class Bucket> class c_iterator
template <class Node, class Bucket>
class c_iterator
: public boost::iterator_facade<c_iterator<Node, Bucket>,
typename Node::value_type const, boost::forward_traversal_tag>
{
public:
typedef typename Node::value_type value_type;
@@ -1831,51 +1798,7 @@ namespace boost {
typedef std::forward_iterator_tag iterator_category;
c_iterator() : p(), itb(){};
c_iterator(iterator<Node, Bucket> it) : p(it.p), itb(it.itb) {}
reference operator*() const BOOST_NOEXCEPT { return dereference(); }
pointer operator->() const BOOST_NOEXCEPT
{
pointer x = boost::addressof(p->value());
return x;
}
c_iterator& operator++() BOOST_NOEXCEPT
{
increment();
return *this;
}
c_iterator operator++(int) BOOST_NOEXCEPT
{
c_iterator old = *this;
increment();
return old;
}
bool operator==(c_iterator const& other) const BOOST_NOEXCEPT
{
return equal(other);
}
bool operator!=(c_iterator const& other) const BOOST_NOEXCEPT
{
return !equal(other);
}
bool operator==(
boost::unordered::detail::iterator_detail::iterator<Node,
Bucket> const& other) const BOOST_NOEXCEPT
{
return equal(other);
}
bool operator!=(
boost::unordered::detail::iterator_detail::iterator<Node,
Bucket> const& other) const BOOST_NOEXCEPT
{
return !equal(other);
}
c_iterator(iterator<Node, Bucket> it) : p(it.p), itb(it.itb){};
private:
typedef typename Node::node_pointer node_pointer;
@@ -1885,7 +1808,7 @@ namespace boost {
bucket_iterator itb;
template <class Types> friend struct boost::unordered::detail::table;
template <class, class> friend class iterator;
friend class boost::iterator_core_access;
c_iterator(node_pointer p_, bucket_iterator itb_) : p(p_), itb(itb_)
{
@@ -2453,6 +2376,7 @@ namespace boost {
inline iterator transparent_find(
Key const& k, Hash const& h, Pred const& pred) const
{
#if 0
std::size_t const key_hash = h(k);
bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
for (node_pointer p = itb->next; p; p = p->next) {
@@ -2460,7 +2384,36 @@ namespace boost {
return iterator(p, itb);
}
}
#else
std::size_t const key_hash = h(k);
bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
node_pointer p = itb->next;
if (p) {
for (;;) {
node_pointer p1 = p->next;
if (p1) {
#if defined(BOOST_GCC)||defined(BOOST_CLANG)
__builtin_prefetch((const char*)p1, 0);
#elif defined(BOOST_UNORDERED_SSE2_SUPPORTED)
_mm_prefetch((const char*)p1, _MM_HINT_T0);
#endif
if (BOOST_LIKELY(pred(k, extractor::extract(p->value())))) {
return iterator(p, itb);
}
p = p1;
}
else{
if (BOOST_LIKELY(pred(k, extractor::extract(p->value())))) {
return iterator(p, itb);
}
break;
}
}
}
#endif
return this->end();
}
@@ -3496,8 +3449,8 @@ namespace boost {
sizeof(choice2::type)
};
typedef
typename boost::conditional<value, Key const&, no_key>::type type;
typedef typename boost::detail::if_true<value>::BOOST_NESTED_TEMPLATE
then<Key const&, no_key>::type type;
};
template <class ValueType> struct set_extractor
+1 -7
View File
@@ -6,12 +6,6 @@ include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
if(HAVE_BOOST_TEST)
boost_test_jamfile(
FILE Jamfile.v2
LINK_LIBRARIES
Boost::unordered
Boost::core
Boost::concept_check
)
boost_test_jamfile(FILE Jamfile.v2 LINK_LIBRARIES Boost::unordered Boost::core)
endif()
-1
View File
@@ -29,7 +29,6 @@ project
<toolset>msvc:<warnings-as-errors>on
;
run unordered/prime_fmod_tests.cpp ;
run unordered/fwd_set_test.cpp ;
run unordered/fwd_map_test.cpp ;
run unordered/allocator_traits.cpp ;
+17 -2
View File
@@ -18,6 +18,7 @@ assert
config
container_hash
core
iterator
move
mp11
predef
@@ -28,10 +29,24 @@ type_traits
# Secondary dependencies
detail
integer
static_assert
concept_check
conversion
detail
function_types
fusion
mpl
optional
smart_ptr
utility
winapi
typeof
functional
io
function
bind
integer
type_index
)
foreach(dep IN LISTS deps)
+4 -3
View File
@@ -9,8 +9,8 @@
#include "./generators.hpp"
#include "./list.hpp"
#include "./metafunctions.hpp"
#include <boost/type_traits/conditional.hpp>
#include <algorithm>
#include <boost/detail/select_type.hpp>
namespace test {
template <class X> struct unordered_generator_set
@@ -69,8 +69,9 @@ namespace test {
template <class X>
struct unordered_generator_base
: public boost::conditional<test::is_set<X>::value,
test::unordered_generator_set<X>, test::unordered_generator_map<X> >
: public boost::detail::if_true<test::is_set<X>::value>::
BOOST_NESTED_TEMPLATE then<test::unordered_generator_set<X>,
test::unordered_generator_map<X> >
{
};
-252
View File
@@ -1,252 +0,0 @@
// Copyright 2022 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)
#include <boost/unordered/detail/fca.hpp>
#include <boost/core/detail/splitmix64.hpp>
#include <boost/core/lightweight_test.hpp>
#include <limits>
#if defined(BOOST_MSVC)
// conditional expression is constant
#pragma warning(disable : 4127)
#endif
void macros_test()
{
if (std::numeric_limits<std::size_t>::digits >= 64) {
#if !defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
BOOST_ERROR("std::numeric_limits<size_t>::digits >= 64, but "
"BOOST_UNORDERED_FCA_HAS_64B_SIZE_T is not defined");
#endif
}
else {
#if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
BOOST_ERROR("std::numeric_limits<size_t>::digits < 64, but "
"BOOST_UNORDERED_FCA_HAS_64B_SIZE_T is defined");
#endif
}
#if ((defined(__GNUC__) || defined(__clang__)) && \
defined(__SIZEOF_INT128__)) || \
(defined(_MSC_VER) && defined(_M_X64))
#if !defined(BOOST_UNORDERED_FCA_FASTMOD_SUPPORT)
BOOST_ERROR("fast_modulo support should be enabled for this toolchain but "
"it's currently not");
#endif
#endif
}
// Pretty inefficient, but the test is fast enough.
// Might be too slow if we had larger primes?
bool is_prime(std::size_t x)
{
if (x == 2) {
return true;
}
if (x == 1 || x % 2 == 0) {
return false;
}
// y*y <= x is susceptible to overflow, so instead make sure to use y <= (x/y)
for (std::size_t y = 3; y <= (x / y); y += 2) {
if (x % y == 0) {
return false;
}
}
return true;
}
void prime_sizes_test()
{
// just some basic sanity checks
//
BOOST_TEST(!is_prime(0));
BOOST_TEST(!is_prime(1));
BOOST_TEST(is_prime(2));
BOOST_TEST(is_prime(3));
BOOST_TEST(is_prime(13));
BOOST_TEST(!is_prime(4));
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;
// prove every number in our sizes array is prime
//
BOOST_TEST_GT(sizes_len, 0u);
for (std::size_t i = 0; i < sizes_len; ++i) {
BOOST_TEST(is_prime(sizes[i]));
}
// prove that every subsequent number in the sequence is larger than the
// previous
//
for (std::size_t i = 1; i < sizes_len; ++i) {
BOOST_TEST_GT(sizes[i], sizes[i - 1]);
}
#if defined(BOOST_UNORDERED_FCA_FASTMOD_SUPPORT)
// now we wish to prove that if we do have the reciprocals stored, we have the
// 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;
std::size_t 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) {
if (sizes[i] <= UINT32_MAX) {
++count;
}
}
BOOST_TEST_GT(inv_sizes32_len, 0u);
BOOST_TEST_EQ(inv_sizes32_len, count);
// these values should also be monotonically decreasing
//
for (std::size_t i = 1; i < inv_sizes32_len; ++i) {
BOOST_TEST_LT(inv_sizes32[i], inv_sizes32[i - 1]);
}
// now make sure the values in inv_sizes32 are what they should be as derived
// from the paper
//
for (std::size_t i = 0; i < inv_sizes32_len; ++i) {
std::size_t const size = sizes[i];
BOOST_TEST_LE(size, UINT_MAX);
boost::uint32_t d = static_cast<boost::uint32_t>(sizes[i]);
boost::uint64_t M = ((boost::ulong_long_type(0xffffffff) << 32) +
boost::ulong_long_type(0xffffffff)) /
d +
1;
BOOST_TEST_EQ(inv_sizes32[i], M);
}
#endif
}
void get_remainder_test()
{
#if defined(BOOST_UNORDERED_FCA_FASTMOD_SUPPORT)
struct
{
// internally, our get_remainder() function will rely on either msvc
// intrinsics or 128 bit integer support which isn't always available. This
// is a slower, portable version we can use for verification of the
// routines.
//
boost::uint64_t operator()(boost::uint64_t f, boost::uint32_t d)
{
boost::uint64_t r1 = (f & UINT32_MAX) * d;
boost::uint64_t r2 = (f >> 32) * d;
r2 += r1 >> 32;
return r2 >> 32;
}
} get_remainder;
boost::detail::splitmix64 rng;
for (std::size_t i = 0; i < 1000000u; ++i) {
boost::uint64_t f = rng();
boost::uint32_t d = static_cast<uint32_t>(rng());
boost::uint64_t r1 =
boost::unordered::detail::prime_fmod_size<>::get_remainder(f, d);
boost::uint64_t r2 = get_remainder(f, d);
if (!BOOST_TEST_EQ(r1, r2)) {
std::cerr << "f: " << f << ", d: " << d << std::endl;
return;
}
}
#endif
}
void modulo32_test()
{
std::size_t* sizes = boost::unordered::detail::prime_fmod_size<>::sizes;
std::size_t const sizes_len =
boost::unordered::detail::prime_fmod_size<>::sizes_len;
boost::detail::splitmix64 rng;
for (std::size_t i = 0; i < 1000000u; ++i) {
std::size_t hash = static_cast<boost::uint32_t>(rng());
for (std::size_t j = 0; j < sizes_len; ++j) {
std::size_t p1 =
boost::unordered::detail::prime_fmod_size<>::position(hash, j);
std::size_t p2 = hash % sizes[j];
if (!BOOST_TEST_EQ(p1, p2)) {
std::cerr << "hash: " << hash << ", j: " << j << ", sizes[" << j
<< "]: " << sizes[j] << std::endl;
return;
}
}
}
}
void modulo64_test()
{
#if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
std::size_t* sizes = boost::unordered::detail::prime_fmod_size<>::sizes;
std::size_t const sizes_len =
boost::unordered::detail::prime_fmod_size<>::sizes_len;
boost::detail::splitmix64 rng;
for (std::size_t i = 0; i < 1000000u; ++i) {
std::size_t hash = rng();
for (std::size_t j = 0; j < sizes_len; ++j) {
std::size_t h = hash;
#if defined(BOOST_UNORDERED_FCA_FASTMOD_SUPPORT)
if (sizes[j] <= UINT_MAX) {
h = boost::uint32_t(h) + boost::uint32_t(h >> 32);
}
#endif
std::size_t p1 =
boost::unordered::detail::prime_fmod_size<>::position(hash, j);
std::size_t p2 = h % sizes[j];
if (!BOOST_TEST_EQ(p1, p2)) {
std::cerr << "hash: " << hash << ", j: " << j << ", h: " << h
<< ", sizes[" << j << "]: " << sizes[j] << std::endl;
return;
}
}
}
#endif
}
int main()
{
macros_test();
prime_sizes_test();
modulo32_test();
get_remainder_test();
modulo64_test();
return boost::report_errors();
}