From 6c623e8d16254ca21eb40b5a84640fa4eb5518f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 18 Mar 2014 17:06:38 +0100 Subject: [PATCH] Fixed #8468. Added 64 bit prime values. --- doc/intrusive.qbk | 3 + .../boost/intrusive/detail/hashtable_node.hpp | 59 ++++++++++++++++--- include/boost/intrusive/detail/mpl.hpp | 18 +++++- include/boost/intrusive/hashtable.hpp | 6 +- test/test_container.hpp | 27 +++++++++ 5 files changed, 100 insertions(+), 13 deletions(-) diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index a7b15ac..847c81e 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -3795,10 +3795,13 @@ to be inserted in intrusive containers are allocated using `std::vector` or `std extra parameter is `splaytree_algorithms` functions. * Fixed bugs: + * [@https://svn.boost.org/trac/boost/ticket/8468 #8468: Compile error on visual studio 2010/2012 using vector with custom allocator and aligned types] * [@https://svn.boost.org/trac/boost/ticket/9332 #9332: ['"has_member_function_callable_with.hpp compile error on msvc-12.0"]]. * Optimized tree rebalancing code to avoid redundant assignments. +* Added 64 bit prime values for `suggested_upper_bucket_count`/`suggested_lower_bucket_count` in 64 bit platforms. + [endsect] [section:release_notes_boost_1_55_00 Boost 1.55 Release] diff --git a/include/boost/intrusive/detail/hashtable_node.hpp b/include/boost/intrusive/detail/hashtable_node.hpp index 7fd1821..4702e98 100644 --- a/include/boost/intrusive/detail/hashtable_node.hpp +++ b/include/boost/intrusive/detail/hashtable_node.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -40,15 +41,59 @@ struct prime_list_holder static const std::size_t prime_list_size; }; +//We only support LLP64(Win64) or LP64(most Unix) data models +#ifdef _WIN64 //In 64 bit windows sizeof(size_t) == sizeof(unsigned long long) + #define BOOST_INTRUSIVE_PRIME_C(NUMBER) NUMBER##ULL + #define BOOST_INTRUSIVE_64_BIT_SIZE_T 1 +#else //In 32 bit windows and 32/64 bit unixes sizeof(size_t) == sizeof(unsigned long) + #define BOOST_INTRUSIVE_PRIME_C(NUMBER) NUMBER##UL + #define BOOST_INTRUSIVE_64_BIT_SIZE_T (((((ULONG_MAX>>16)>>16)>>16)>>15) != 0) +#endif + template const std::size_t prime_list_holder::prime_list[] = { - 3ul, 7ul, 11ul, 17ul, 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, 4294967291ul }; + BOOST_INTRUSIVE_PRIME_C(3), BOOST_INTRUSIVE_PRIME_C(7), + BOOST_INTRUSIVE_PRIME_C(11), BOOST_INTRUSIVE_PRIME_C(17), + BOOST_INTRUSIVE_PRIME_C(29), BOOST_INTRUSIVE_PRIME_C(53), + BOOST_INTRUSIVE_PRIME_C(97), BOOST_INTRUSIVE_PRIME_C(193), + BOOST_INTRUSIVE_PRIME_C(389), BOOST_INTRUSIVE_PRIME_C(769), + BOOST_INTRUSIVE_PRIME_C(1543), BOOST_INTRUSIVE_PRIME_C(3079), + BOOST_INTRUSIVE_PRIME_C(6151), BOOST_INTRUSIVE_PRIME_C(12289), + BOOST_INTRUSIVE_PRIME_C(24593), BOOST_INTRUSIVE_PRIME_C(49157), + BOOST_INTRUSIVE_PRIME_C(98317), BOOST_INTRUSIVE_PRIME_C(196613), + BOOST_INTRUSIVE_PRIME_C(393241), BOOST_INTRUSIVE_PRIME_C(786433), + BOOST_INTRUSIVE_PRIME_C(1572869), BOOST_INTRUSIVE_PRIME_C(3145739), + BOOST_INTRUSIVE_PRIME_C(6291469), BOOST_INTRUSIVE_PRIME_C(12582917), + BOOST_INTRUSIVE_PRIME_C(25165843), BOOST_INTRUSIVE_PRIME_C(50331653), + BOOST_INTRUSIVE_PRIME_C(100663319), BOOST_INTRUSIVE_PRIME_C(201326611), + BOOST_INTRUSIVE_PRIME_C(402653189), BOOST_INTRUSIVE_PRIME_C(805306457), + BOOST_INTRUSIVE_PRIME_C(1610612741), BOOST_INTRUSIVE_PRIME_C(3221225473), +#if BOOST_INTRUSIVE_64_BIT_SIZE_T + //Taken from Boost.MultiIndex code, thanks to Joaquin M Lopez Munoz. + BOOST_INTRUSIVE_PRIME_C(6442450939), BOOST_INTRUSIVE_PRIME_C(12884901893), + BOOST_INTRUSIVE_PRIME_C(25769803751), BOOST_INTRUSIVE_PRIME_C(51539607551), + BOOST_INTRUSIVE_PRIME_C(103079215111), BOOST_INTRUSIVE_PRIME_C(206158430209), + BOOST_INTRUSIVE_PRIME_C(412316860441), BOOST_INTRUSIVE_PRIME_C(824633720831), + BOOST_INTRUSIVE_PRIME_C(1649267441651), BOOST_INTRUSIVE_PRIME_C(3298534883309), + BOOST_INTRUSIVE_PRIME_C(6597069766657), BOOST_INTRUSIVE_PRIME_C(13194139533299), + BOOST_INTRUSIVE_PRIME_C(26388279066623), BOOST_INTRUSIVE_PRIME_C(52776558133303), + BOOST_INTRUSIVE_PRIME_C(105553116266489), BOOST_INTRUSIVE_PRIME_C(211106232532969), + BOOST_INTRUSIVE_PRIME_C(422212465066001), BOOST_INTRUSIVE_PRIME_C(844424930131963), + BOOST_INTRUSIVE_PRIME_C(1688849860263953), BOOST_INTRUSIVE_PRIME_C(3377699720527861), + BOOST_INTRUSIVE_PRIME_C(6755399441055731), BOOST_INTRUSIVE_PRIME_C(13510798882111483), + BOOST_INTRUSIVE_PRIME_C(27021597764222939), BOOST_INTRUSIVE_PRIME_C(54043195528445957), + BOOST_INTRUSIVE_PRIME_C(108086391056891903), BOOST_INTRUSIVE_PRIME_C(216172782113783843), + BOOST_INTRUSIVE_PRIME_C(432345564227567621), BOOST_INTRUSIVE_PRIME_C(864691128455135207), + BOOST_INTRUSIVE_PRIME_C(1729382256910270481), BOOST_INTRUSIVE_PRIME_C(3458764513820540933), + BOOST_INTRUSIVE_PRIME_C(6917529027641081903), BOOST_INTRUSIVE_PRIME_C(13835058055282163729), + BOOST_INTRUSIVE_PRIME_C(18446744073709551557) +#else + BOOST_INTRUSIVE_PRIME_C(4294967291) +#endif + }; + +#undef BOOST_INTRUSIVE_PRIME_C +#undef BOOST_INTRUSIVE_64_BIT_SIZE_T template const std::size_t prime_list_holder::prime_list_size diff --git a/include/boost/intrusive/detail/mpl.hpp b/include/boost/intrusive/detail/mpl.hpp index 4358aec..98cb3b3 100644 --- a/include/boost/intrusive/detail/mpl.hpp +++ b/include/boost/intrusive/detail/mpl.hpp @@ -64,18 +64,32 @@ struct apply typedef typename F::template apply::type type; }; +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + +template +struct is_convertible +{ + static const bool value = __is_convertible_to(T, U); +}; + +#else + template class is_convertible { typedef char true_t; class false_t { char dummy[2]; }; - static true_t dispatch(U); + //use any_conversion as first parameter since in MSVC + //overaligned types can't go through ellipsis static false_t dispatch(...); - static const T &trigger(); + static true_t dispatch(U); + static T &trigger(); public: static const bool value = sizeof(dispatch(trigger())) == sizeof(true_t); }; +#endif + template< bool C , typename T1 diff --git a/include/boost/intrusive/hashtable.hpp b/include/boost/intrusive/hashtable.hpp index 607e80d..db73002 100644 --- a/include/boost/intrusive/hashtable.hpp +++ b/include/boost/intrusive/hashtable.hpp @@ -2585,8 +2585,7 @@ class hashtable_impl const std::size_t *primes = &detail::prime_list_holder<0>::prime_list[0]; const std::size_t *primes_end = primes + detail::prime_list_holder<0>::prime_list_size; std::size_t const* bound = std::lower_bound(primes, primes_end, n); - if(bound == primes_end) - --bound; + bound -= (bound == primes_end); return size_type(*bound); } @@ -2604,8 +2603,7 @@ class hashtable_impl const std::size_t *primes = &detail::prime_list_holder<0>::prime_list[0]; const std::size_t *primes_end = primes + detail::prime_list_holder<0>::prime_list_size; size_type const* bound = std::upper_bound(primes, primes_end, n); - if(bound != primes) - --bound; + bound -= (bound != primes); return size_type(*bound); } diff --git a/test/test_container.hpp b/test/test_container.hpp index 47ac9e6..f73e91b 100644 --- a/test/test_container.hpp +++ b/test/test_container.hpp @@ -193,6 +193,33 @@ void test_common_unordered_and_associative_container(Container & c, Data & d, bo c.clear(); BOOST_TEST( c.equal_range(*da, c.hash_function(), c.key_eq()).first == c.end() ); + + // + //suggested_upper_bucket_count + // + //Maximum fallbacks to the highest possible value + typename Container::size_type sz = Container::suggested_upper_bucket_count(size_type(-1)); + BOOST_TEST( sz > size_type(-1)/2 ); + //In the rest of cases the upper bound is returned + sz = Container::suggested_upper_bucket_count(size_type(-1)/2); + BOOST_TEST( sz >= size_type(-1)/2 ); + sz = Container::suggested_upper_bucket_count(size_type(-1)/4); + BOOST_TEST( sz >= size_type(-1)/4 ); + sz = Container::suggested_upper_bucket_count(0); + BOOST_TEST( sz > 0 ); + // + //suggested_lower_bucket_count + // + sz = Container::suggested_lower_bucket_count(size_type(-1)); + BOOST_TEST( sz <= size_type(-1) ); + //In the rest of cases the lower bound is returned + sz = Container::suggested_lower_bucket_count(size_type(-1)/2); + BOOST_TEST( sz <= size_type(-1)/2 ); + sz = Container::suggested_lower_bucket_count(size_type(-1)/4); + BOOST_TEST( sz <= size_type(-1)/4 ); + //Minimum fallbacks to the lowest possible value + sz = Container::suggested_upper_bucket_count(0); + BOOST_TEST( sz > 0 ); } template< class Container, class Data >