Unordered: Merge unordered from trunk.

- Activate `std::allocator_traits` for gcc 4.7 and Visual C++ 11.
- Implement variadic construct in `boost::unordered::detail::allocator_traits`
  when variadics, rvalue references and SFINAE expression are available.
- Use variadic construct from `allocator_traits`, or when not available move
  the logic for constructing `value_type` to a lower level, so the container
  code is a bit simpler.
- Avoid `-Wshadow` warnings. Fixes #6190.
- Implement `reserve`. Fixes #6857.


[SVN r78432]
This commit is contained in:
Daniel James
2012-05-12 08:14:05 +00:00
parent 880d778ab6
commit 808f1f939f
31 changed files with 763 additions and 297 deletions

View File

@@ -178,10 +178,14 @@ C++11 support has resulted in some breaking changes:
[h2 Boost 1.50.0] [h2 Boost 1.50.0]
* Fix equality for `unordered_multiset` and `unordered_multimap`. * Fix equality for `unordered_multiset` and `unordered_multimap`.
* [@http://svn.boost.org/trac/boost/ticket/6771 Ticket 6771]: * [@https://svn.boost.org/trac/boost/ticket/6857 Ticket 6857]:
Implement `reserve`.
* [@https://svn.boost.org/trac/boost/ticket/6771 Ticket 6771]:
Avoid gcc's `-Wfloat-equal` warning. Avoid gcc's `-Wfloat-equal` warning.
* [@http://svn.boost.org/trac/boost/ticket/6784 Ticket 6784]: * [@https://svn.boost.org/trac/boost/ticket/6784 Ticket 6784]:
Fix some Sun specific code. Fix some Sun specific code.
* [@https://svn.boost.org/trac/boost/ticket/6190 Ticket 6190]:
Avoid gcc's `-Wshadow` warning.
* Remove some of the smaller prime number of buckets, as they may make * Remove some of the smaller prime number of buckets, as they may make
collisions quite probable (e.g. multiples of 5 are very common because collisions quite probable (e.g. multiples of 5 are very common because
we used base 10). we used base 10).

View File

@@ -963,6 +963,18 @@ EOL;
<para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para> <para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para>
</throws> </throws>
</method> </method>
<method name="reserve">
<parameter name="n">
<paramtype>size_type</paramtype>
</parameter>
<type>void</type>
<description>
<para>Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.</para>
</description>
<throws>
<para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para>
</throws>
</method>
</method-group> </method-group>
<free-function-group name="Equality Comparisons"> <free-function-group name="Equality Comparisons">
<function name="operator=="> <function name="operator==">

View File

@@ -846,6 +846,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
<para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para> <para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para>
</throws> </throws>
</method> </method>
<method name="reserve">
<parameter name="n">
<paramtype>size_type</paramtype>
</parameter>
<type>void</type>
<description>
<para>Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.</para>
</description>
<throws>
<para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para>
</throws>
</method>
</method-group> </method-group>
<free-function-group name="Equality Comparisons"> <free-function-group name="Equality Comparisons">
<function name="operator=="> <function name="operator==">
@@ -1797,6 +1809,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
<para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para> <para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para>
</throws> </throws>
</method> </method>
<method name="reserve">
<parameter name="n">
<paramtype>size_type</paramtype>
</parameter>
<type>void</type>
<description>
<para>Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.</para>
</description>
<throws>
<para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para>
</throws>
</method>
</method-group> </method-group>
<free-function-group name="Equality Comparisons"> <free-function-group name="Equality Comparisons">
<function name="operator=="> <function name="operator==">
@@ -2793,6 +2817,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
<para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para> <para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para>
</throws> </throws>
</method> </method>
<method name="reserve">
<parameter name="n">
<paramtype>size_type</paramtype>
</parameter>
<type>void</type>
<description>
<para>Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.</para>
</description>
<throws>
<para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para>
</throws>
</method>
</method-group> </method-group>
<free-function-group name="Equality Comparisons"> <free-function-group name="Equality Comparisons">
<function name="operator=="> <function name="operator==">
@@ -3758,6 +3794,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
<para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para> <para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para>
</throws> </throws>
</method> </method>
<method name="reserve">
<parameter name="n">
<paramtype>size_type</paramtype>
</parameter>
<type>void</type>
<description>
<para>Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.</para>
</description>
<throws>
<para>The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.</para>
</throws>
</method>
</method-group> </method-group>
<free-function-group name="Equality Comparisons"> <free-function-group name="Equality Comparisons">
<function name="operator=="> <function name="operator==">

View File

@@ -15,47 +15,41 @@
# pragma once # pragma once
#endif #endif
#include <boost/config.hpp> #include <boost/unordered/detail/emplace_args.hpp>
#include <boost/detail/select_type.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/enum.hpp>
#include <boost/limits.hpp>
#include <boost/type_traits/add_lvalue_reference.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/utility/addressof.hpp> #include <boost/utility/addressof.hpp>
#if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS) ////////////////////////////////////////////////////////////////////////////////
// An allocator_traits test is currently failing for gcc 4.7 on mingw. I think //
// this is because it's an older development version. Temporarily disabling // Pick which version of allocator_traits to use
// std::allocator_traits in order ot get clean test results. Will reactivate //
// later. // 0 = Own partial implementation
// 1 = std::allocator_traits
// 2 = boost::container::allocator_traits
/* #if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS)
# if defined(__GXX_EXPERIMENTAL_CXX0X__) && \ # if defined(__GXX_EXPERIMENTAL_CXX0X__) && \
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1 # define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1
# elif defined(BOOST_MSVC)
# if BOOST_MSVC < 1400
// Use container's allocator_traits for older versions of Visual
// C++ as I don't test with them.
# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 2
# elif BOOST_MSVC >= 1700
# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1
# endif
# endif # endif
*/
// Use container's allocator_traits for older versions of Visual C++ as I don't
// test with them.
# if defined(BOOST_MSVC) && BOOST_MSVC < 1400
# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 2
# endif
#endif #endif
#if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS) #if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS)
# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0 # define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0
#endif #endif
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 ////////////////////////////////////////////////////////////////////////////////
# include <memory> //
#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2 // Some utilities for implementing allocator_traits, but useful elsewhere so
# include <boost/container/allocator/allocator_traits.hpp> // they're always defined.
#endif
#if !defined(BOOST_NO_0X_HDR_TYPE_TRAITS) #if !defined(BOOST_NO_0X_HDR_TYPE_TRAITS)
# include <type_traits> # include <type_traits>
@@ -102,48 +96,22 @@ namespace boost { namespace unordered { namespace detail {
#endif #endif
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Bits and pieces for implementing traits // Expression test mechanism
// //
// Some of these are also used elsewhere // When SFINAE expressions are available, define
// BOOST_UNORDERED_HAS_FUNCTION which can check if a function call is
template <typename T> typename boost::add_lvalue_reference<T>::type make(); // supported by a class, otherwise define BOOST_UNORDERED_HAS_MEMBER which
struct choice9 { typedef char (&type)[9]; }; // can detect if a class has the specified member, but not that it has the
struct choice8 : choice9 { typedef char (&type)[8]; }; // correct type, this is good enough for a passable impression of
struct choice7 : choice8 { typedef char (&type)[7]; }; // allocator_traits.
struct choice6 : choice7 { typedef char (&type)[6]; };
struct choice5 : choice6 { typedef char (&type)[5]; };
struct choice4 : choice5 { typedef char (&type)[4]; };
struct choice3 : choice4 { typedef char (&type)[3]; };
struct choice2 : choice3 { typedef char (&type)[2]; };
struct choice1 : choice2 { typedef char (&type)[1]; };
choice1 choose();
typedef choice1::type yes_type;
typedef choice2::type no_type;
struct private_type
{
private_type const &operator,(int) const;
};
template <typename T>
no_type is_private_type(T const&);
yes_type is_private_type(private_type const&);
struct convert_from_anything {
template <typename T>
convert_from_anything(T const&);
};
#if !defined(BOOST_NO_SFINAE_EXPR) #if !defined(BOOST_NO_SFINAE_EXPR)
# define BOOST_UNORDERED_HAVE_CALL_DETECTION 1
template <typename T, unsigned int> struct expr_test; template <typename T, unsigned int> struct expr_test;
template <typename T> struct expr_test<T, sizeof(char)> : T {}; template <typename T> struct expr_test<T, sizeof(char)> : T {};
template <typename U> static char for_expr_test(U const&); template <typename U> static char for_expr_test(U const&);
#define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \ # define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \
template <typename U> \ template <typename U> \
static typename boost::unordered::detail::expr_test< \ static typename boost::unordered::detail::expr_test< \
BOOST_PP_CAT(choice, result), \ BOOST_PP_CAT(choice, result), \
@@ -152,12 +120,12 @@ namespace boost { namespace unordered { namespace detail {
0)))>::type test( \ 0)))>::type test( \
BOOST_PP_CAT(choice, count)) BOOST_PP_CAT(choice, count))
#define BOOST_UNORDERED_DEFAULT_EXPRESSION(count, result) \ # define BOOST_UNORDERED_DEFAULT_EXPRESSION(count, result) \
template <typename U> \ template <typename U> \
static BOOST_PP_CAT(choice, result)::type test( \ static BOOST_PP_CAT(choice, result)::type test( \
BOOST_PP_CAT(choice, count)) BOOST_PP_CAT(choice, count))
#define BOOST_UNORDERED_HAS_FUNCTION(name, thing, args, _) \ # define BOOST_UNORDERED_HAS_FUNCTION(name, thing, args, _) \
struct BOOST_PP_CAT(has_, name) \ struct BOOST_PP_CAT(has_, name) \
{ \ { \
BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, \ BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, \
@@ -169,11 +137,9 @@ namespace boost { namespace unordered { namespace detail {
#else #else
# define BOOST_UNORDERED_HAVE_CALL_DETECTION 0
template <typename T> struct identity { typedef T type; }; template <typename T> struct identity { typedef T type; };
#define BOOST_UNORDERED_CHECK_MEMBER(count, result, name, member) \ # define BOOST_UNORDERED_CHECK_MEMBER(count, result, name, member) \
\ \
typedef typename boost::unordered::detail::identity<member>::type \ typedef typename boost::unordered::detail::identity<member>::type \
BOOST_PP_CAT(check, count); \ BOOST_PP_CAT(check, count); \
@@ -187,11 +153,11 @@ namespace boost { namespace unordered { namespace detail {
BOOST_PP_CAT(test, count)<&U::name>::type \ BOOST_PP_CAT(test, count)<&U::name>::type \
test(BOOST_PP_CAT(choice, count)) test(BOOST_PP_CAT(choice, count))
#define BOOST_UNORDERED_DEFAULT_MEMBER(count, result) \ # define BOOST_UNORDERED_DEFAULT_MEMBER(count, result) \
template <class U> static BOOST_PP_CAT(choice, result)::type \ template <class U> static BOOST_PP_CAT(choice, result)::type \
test(BOOST_PP_CAT(choice, count)) test(BOOST_PP_CAT(choice, count))
#define BOOST_UNORDERED_HAS_MEMBER(name) \ # define BOOST_UNORDERED_HAS_MEMBER(name) \
struct BOOST_PP_CAT(has_, name) \ struct BOOST_PP_CAT(has_, name) \
{ \ { \
struct impl { \ struct impl { \
@@ -211,97 +177,90 @@ namespace boost { namespace unordered { namespace detail {
#endif #endif
//////////////////////////////////////////////////////////////////////////// }}}
// Allocator traits
//
// Uses the standard versions if available.
// (although untested as I don't have access to a standard version yet)
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 ////////////////////////////////////////////////////////////////////////////////
//
// Allocator traits
//
// First our implementation, then later light wrappers around the alternatives
template <typename Alloc> #if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0
struct allocator_traits : std::allocator_traits<Alloc> {};
template <typename Alloc, typename T> # include <boost/limits.hpp>
struct rebind_wrap # include <boost/utility/enable_if.hpp>
{ # include <boost/pointer_to_other.hpp>
typedef typename std::allocator_traits<Alloc>:: # if defined(BOOST_NO_SFINAE_EXPR)
template rebind_alloc<T> type; # include <boost/type_traits/is_same.hpp>
}; # endif
#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2 # if defined(BOOST_UNORDERED_VARIADIC_MOVE) && \
!defined(BOOST_NO_SFINAE_EXPR)
# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1
# else
# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0
# endif
template <typename Alloc> namespace boost { namespace unordered { namespace detail {
struct allocator_traits :
boost::container::allocator_traits<Alloc> {};
template <typename Alloc, typename T>
struct rebind_wrap :
boost::container::allocator_traits<Alloc>::
template portable_rebind_alloc<T>
{};
#else
// TODO: Does this match std::allocator_traits<Alloc>::rebind_alloc<T>? // TODO: Does this match std::allocator_traits<Alloc>::rebind_alloc<T>?
template <typename Alloc, typename T> template <typename Alloc, typename T>
struct rebind_wrap struct rebind_wrap
{ {
typedef typename Alloc::BOOST_NESTED_TEMPLATE rebind<T>::other typedef typename Alloc::BOOST_NESTED_TEMPLATE rebind<T>::other type;
type;
}; };
#if defined(BOOST_MSVC) && BOOST_MSVC <= 1400 # if defined(BOOST_MSVC) && BOOST_MSVC <= 1400
#define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ # define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \
template <typename Tp, typename Default> \ template <typename Tp, typename Default> \
struct default_type_ ## tname { \ struct default_type_ ## tname { \
\ \
template <typename X> \ template <typename X> \
static choice1::type test(choice1, typename X::tname* = 0); \ static choice1::type test(choice1, typename X::tname* = 0); \
\ \
template <typename X> \ template <typename X> \
static choice2::type test(choice2, void* = 0); \ static choice2::type test(choice2, void* = 0); \
\ \
struct DefaultWrap { typedef Default tname; }; \ struct DefaultWrap { typedef Default tname; }; \
\ \
enum { value = (1 == sizeof(test<Tp>(choose()))) }; \ enum { value = (1 == sizeof(test<Tp>(choose()))) }; \
\ \
typedef typename boost::detail::if_true<value>:: \ typedef typename boost::detail::if_true<value>:: \
BOOST_NESTED_TEMPLATE then<Tp, DefaultWrap> \ BOOST_NESTED_TEMPLATE then<Tp, DefaultWrap> \
::type::tname type; \ ::type::tname type; \
} }
#else # else
template <typename T, typename T2> template <typename T, typename T2>
struct sfinae : T2 {}; struct sfinae : T2 {};
#define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ # define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \
template <typename Tp, typename Default> \ template <typename Tp, typename Default> \
struct default_type_ ## tname { \ struct default_type_ ## tname { \
\ \
template <typename X> \ template <typename X> \
static typename boost::unordered::detail::sfinae< \ static typename boost::unordered::detail::sfinae< \
typename X::tname, choice1>::type \ typename X::tname, choice1>::type \
test(choice1); \ test(choice1); \
\ \
template <typename X> \ template <typename X> \
static choice2::type test(choice2); \ static choice2::type test(choice2); \
\ \
struct DefaultWrap { typedef Default tname; }; \ struct DefaultWrap { typedef Default tname; }; \
\ \
enum { value = (1 == sizeof(test<Tp>(choose()))) }; \ enum { value = (1 == sizeof(test<Tp>(choose()))) }; \
\ \
typedef typename boost::detail::if_true<value>:: \ typedef typename boost::detail::if_true<value>:: \
BOOST_NESTED_TEMPLATE then<Tp, DefaultWrap> \ BOOST_NESTED_TEMPLATE then<Tp, DefaultWrap> \
::type::tname type; \ ::type::tname type; \
} }
#endif # endif
#define BOOST_UNORDERED_DEFAULT_TYPE(T,tname, arg) \ # define BOOST_UNORDERED_DEFAULT_TYPE(T,tname, arg) \
typename default_type_ ## tname<T, arg>::type typename default_type_ ## tname<T, arg>::type
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(pointer); BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(pointer);
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_pointer); BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_pointer);
@@ -313,7 +272,8 @@ namespace boost { namespace unordered { namespace detail {
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment); BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment);
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_swap); BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_swap);
#if BOOST_UNORDERED_HAVE_CALL_DETECTION # if !defined(BOOST_NO_SFINAE_EXPR)
template <typename T> template <typename T>
BOOST_UNORDERED_HAS_FUNCTION( BOOST_UNORDERED_HAS_FUNCTION(
select_on_container_copy_construction, U const, (), 0 select_on_container_copy_construction, U const, (), 0
@@ -324,18 +284,33 @@ namespace boost { namespace unordered { namespace detail {
max_size, U const, (), 0 max_size, U const, (), 0
); );
# if defined(BOOST_UNORDERED_VARIADIC_MOVE)
template <typename T, typename ValueType, typename... Args>
BOOST_UNORDERED_HAS_FUNCTION(
construct, U, (
boost::unordered::detail::make<ValueType*>(),
boost::unordered::detail::make<Args const>()...), 2
);
# else
template <typename T, typename ValueType> template <typename T, typename ValueType>
BOOST_UNORDERED_HAS_FUNCTION( BOOST_UNORDERED_HAS_FUNCTION(
construct, U, ( construct, U, (
boost::unordered::detail::make<ValueType*>(), boost::unordered::detail::make<ValueType*>(),
boost::unordered::detail::make<ValueType const>()), 2 boost::unordered::detail::make<ValueType const>()), 2
); );
# endif
template <typename T, typename ValueType> template <typename T, typename ValueType>
BOOST_UNORDERED_HAS_FUNCTION( BOOST_UNORDERED_HAS_FUNCTION(
destroy, U, (boost::unordered::detail::make<ValueType*>()), 1 destroy, U, (boost::unordered::detail::make<ValueType*>()), 1
); );
#else
# else
template <typename T> template <typename T>
BOOST_UNORDERED_HAS_MEMBER(select_on_container_copy_construction); BOOST_UNORDERED_HAS_MEMBER(select_on_container_copy_construction);
@@ -347,7 +322,8 @@ namespace boost { namespace unordered { namespace detail {
template <typename T, typename ValueType> template <typename T, typename ValueType>
BOOST_UNORDERED_HAS_MEMBER(destroy); BOOST_UNORDERED_HAS_MEMBER(destroy);
#endif
# endif
template <typename Alloc> template <typename Alloc>
inline typename boost::enable_if_c< inline typename boost::enable_if_c<
@@ -415,7 +391,7 @@ namespace boost { namespace unordered { namespace detail {
// TODO: rebind_alloc and rebind_traits // TODO: rebind_alloc and rebind_traits
static pointer allocate(Alloc& a, size_type n) static pointer allocate(Alloc& a, size_type n)
{ return a.allocate(n); } { return a.allocate(n); }
// I never use this, so I'll just comment it out for now. // I never use this, so I'll just comment it out for now.
@@ -423,13 +399,49 @@ namespace boost { namespace unordered { namespace detail {
//static pointer allocate(Alloc& a, size_type n, //static pointer allocate(Alloc& a, size_type n,
// const_void_pointer hint) // const_void_pointer hint)
// { return DEFAULT_FUNC(allocate, pointer)(a, n, hint); } // { return DEFAULT_FUNC(allocate, pointer)(a, n, hint); }
static void deallocate(Alloc& a, pointer p, size_type n) static void deallocate(Alloc& a, pointer p, size_type n)
{ a.deallocate(p, n); } { a.deallocate(p, n); }
public: public:
// Only supporting the basic copy constructor for now. # if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
template <typename T, typename... Args>
static typename boost::enable_if_c<
boost::unordered::detail::has_construct<Alloc, T, Args...>
::value>::type
construct(Alloc& a, T* p, Args&&... x)
{
a.construct(p, boost::forward<Args>(x)...);
}
template <typename T, typename... Args>
static typename boost::disable_if_c<
boost::unordered::detail::has_construct<Alloc, T, Args...>
::value>::type
construct(Alloc&, T* p, Args&&... x)
{
new ((void*) p) T(boost::forward<Args>(x)...);
}
template <typename T>
static typename boost::enable_if_c<
boost::unordered::detail::has_destroy<Alloc, T>::value>::type
destroy(Alloc& a, T* p)
{
a.destroy(p);
}
template <typename T>
static typename boost::disable_if_c<
boost::unordered::detail::has_destroy<Alloc, T>::value>::type
destroy(Alloc&, T* p)
{
boost::unordered::detail::destroy(p);
}
# elif !defined(BOOST_NO_SFINAE_EXPR)
template <typename T> template <typename T>
static typename boost::enable_if_c< static typename boost::enable_if_c<
@@ -463,19 +475,67 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::destroy(p); boost::unordered::detail::destroy(p);
} }
# else
// If we don't have SFINAE expressions, only call construct for the
// copy constructor for the allocator's value_type - as that's
// the only construct method that old fashioned allocators support.
template <typename T>
static typename boost::enable_if_c<
boost::unordered::detail::has_construct<Alloc, T>::value &&
boost::is_same<T, value_type>::value
>::type
construct(Alloc& a, T* p, T const& x)
{
a.construct(p, x);
}
template <typename T>
static typename boost::disable_if_c<
boost::unordered::detail::has_construct<Alloc, T>::value &&
boost::is_same<T, value_type>::value
>::type
construct(Alloc&, T* p, T const& x)
{
new ((void*) p) T(x);
}
template <typename T>
static typename boost::enable_if_c<
boost::unordered::detail::has_destroy<Alloc, T>::value &&
boost::is_same<T, value_type>::value
>::type
destroy(Alloc& a, T* p)
{
a.destroy(p);
}
template <typename T>
static typename boost::disable_if_c<
boost::unordered::detail::has_destroy<Alloc, T>::value &&
boost::is_same<T, value_type>::value
>::type
destroy(Alloc&, T* p)
{
boost::unordered::detail::destroy(p);
}
# endif
static size_type max_size(const Alloc& a) static size_type max_size(const Alloc& a)
{ {
return boost::unordered::detail::call_max_size<size_type>(a); return boost::unordered::detail::call_max_size<size_type>(a);
} }
// Allocator propagation on construction // Allocator propagation on construction
static Alloc select_on_container_copy_construction(Alloc const& rhs) static Alloc select_on_container_copy_construction(Alloc const& rhs)
{ {
return boost::unordered::detail:: return boost::unordered::detail::
call_select_on_container_copy_construction(rhs); call_select_on_container_copy_construction(rhs);
} }
// Allocator propagation on assignment and swap. // Allocator propagation on assignment and swap.
// Return true if lhs is modified. // Return true if lhs is modified.
typedef BOOST_UNORDERED_DEFAULT_TYPE( typedef BOOST_UNORDERED_DEFAULT_TYPE(
@@ -488,12 +548,117 @@ namespace boost { namespace unordered { namespace detail {
Alloc,propagate_on_container_swap,false_type) Alloc,propagate_on_container_swap,false_type)
propagate_on_container_swap; propagate_on_container_swap;
}; };
}}}
#undef BOOST_UNORDERED_DEFAULT_TYPE_TMPLT # undef BOOST_UNORDERED_DEFAULT_TYPE_TMPLT
#undef BOOST_UNORDERED_DEFAULT_TYPE # undef BOOST_UNORDERED_DEFAULT_TYPE
////////////////////////////////////////////////////////////////////////////////
//
// std::allocator_traits
#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
# include <memory>
# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1
namespace boost { namespace unordered { namespace detail {
template <typename Alloc>
struct allocator_traits : std::allocator_traits<Alloc> {};
template <typename Alloc, typename T>
struct rebind_wrap
{
typedef typename std::allocator_traits<Alloc>::
template rebind_alloc<T> type;
};
}}}
////////////////////////////////////////////////////////////////////////////////
//
// boost::container::allocator_traits
#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2
# include <boost/container/allocator_traits.hpp>
# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0
namespace boost { namespace unordered { namespace detail {
template <typename Alloc>
struct allocator_traits :
boost::container::allocator_traits<Alloc> {};
template <typename Alloc, typename T>
struct rebind_wrap :
boost::container::allocator_traits<Alloc>::
template portable_rebind_alloc<T>
{};
}}}
#else
#error "Invalid BOOST_UNORDERED_USE_ALLOCATOR_TRAITS value."
#endif #endif
////////////////////////////////////////////////////////////////////////////////
//
// Some helper functions for allocating & constructing
namespace boost { namespace unordered { namespace detail {
////////////////////////////////////////////////////////////////////////////
//
// construct_node/destroy_node
//
// Construct a node using the best available method.
#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
template <typename Alloc, typename T, BOOST_UNORDERED_EMPLACE_TEMPLATE>
inline void construct_node(Alloc& a, T* p, BOOST_UNORDERED_EMPLACE_ARGS)
{
boost::unordered::detail::allocator_traits<Alloc>::construct(
a, p, BOOST_UNORDERED_EMPLACE_FORWARD);
}
template <typename Alloc, typename T>
inline void destroy_node(Alloc& a, T* p)
{
boost::unordered::detail::allocator_traits<Alloc>::destroy(a, p);
}
#else
template <typename Alloc, typename T, BOOST_UNORDERED_EMPLACE_TEMPLATE>
inline void construct_node(Alloc& a, T* p, BOOST_UNORDERED_EMPLACE_ARGS)
{
boost::unordered::detail::allocator_traits<Alloc>::construct(a, p, T());
try {
boost::unordered::detail::construct_impl(
p->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
} catch(...) {
boost::unordered::detail::allocator_traits<Alloc>::destroy(a, p);
throw;
}
}
template <typename Alloc, typename T>
inline void destroy_node(Alloc& a, T* p)
{
boost::unordered::detail::destroy(p->value_ptr());
boost::unordered::detail::allocator_traits<Alloc>::destroy(a, p);
}
#endif
////////////////////////////////////////////////////////////////////////////
//
// array_constructor // array_constructor
// //
// Allocate and construct an array in an exception safe manner, and // Allocate and construct an array in an exception safe manner, and
@@ -549,7 +714,9 @@ namespace boost { namespace unordered { namespace detail {
ptr_ = pointer(); ptr_ = pointer();
return p; return p;
} }
private: private:
array_constructor(array_constructor const&); array_constructor(array_constructor const&);
array_constructor& operator=(array_constructor const&); array_constructor& operator=(array_constructor const&);
}; };

View File

@@ -13,7 +13,6 @@
#include <boost/unordered/detail/util.hpp> #include <boost/unordered/detail/util.hpp>
#include <boost/unordered/detail/allocator_helpers.hpp> #include <boost/unordered/detail/allocator_helpers.hpp>
#include <boost/unordered/detail/emplace_args.hpp>
#include <boost/type_traits/aligned_storage.hpp> #include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp> #include <boost/type_traits/alignment_of.hpp>
#include <boost/swap.hpp> #include <boost/swap.hpp>
@@ -54,16 +53,14 @@ namespace boost { namespace unordered { namespace detail {
node_allocator& alloc_; node_allocator& alloc_;
node_pointer node_; node_pointer node_;
bool node_constructed_; bool constructed_;
bool value_constructed_;
public: public:
node_constructor(node_allocator& n) : node_constructor(node_allocator& n) :
alloc_(n), alloc_(n),
node_(), node_(),
node_constructed_(false), constructed_(false)
value_constructed_(false)
{ {
} }
@@ -74,26 +71,40 @@ namespace boost { namespace unordered { namespace detail {
template <BOOST_UNORDERED_EMPLACE_TEMPLATE> template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
void construct_value(BOOST_UNORDERED_EMPLACE_ARGS) void construct_value(BOOST_UNORDERED_EMPLACE_ARGS)
{ {
BOOST_ASSERT(node_ && node_constructed_ && !value_constructed_); BOOST_ASSERT(node_ && !constructed_);
boost::unordered::detail::construct_impl( boost::unordered::detail::construct_node(alloc_,
node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); boost::addressof(*node_), BOOST_UNORDERED_EMPLACE_FORWARD);
value_constructed_ = true; node_->init(static_cast<typename node::link_pointer>(node_));
constructed_ = true;
} }
template <typename A0> template <typename A0>
void construct_value2(BOOST_FWD_REF(A0) a0) void construct_value2(BOOST_FWD_REF(A0) a0)
{ {
BOOST_ASSERT(node_ && node_constructed_ && !value_constructed_); BOOST_ASSERT(node_ && !constructed_);
boost::unordered::detail::construct_impl2( # if defined(BOOST_UNORDERED_VARIADIC_MOVE)
node_->value_ptr(), boost::forward<A0>(a0)); boost::unordered::detail::construct_node(alloc_,
value_constructed_ = true; boost::addressof(*node_), boost::forward<A0>(a0));
# else
boost::unordered::detail::construct_node(alloc_,
boost::addressof(*node_),
boost::unordered::detail::create_emplace_args(
boost::forward<A0>(a0)));
# endif
constructed_ = true;
node_->init(static_cast<typename node::link_pointer>(node_));
} }
value_type const& value() const { value_type const& value() const {
BOOST_ASSERT(node_ && node_constructed_ && value_constructed_); BOOST_ASSERT(node_ && constructed_);
return node_->value(); return node_->value();
} }
node_pointer get()
{
return node_;
}
// no throw // no throw
node_pointer release() node_pointer release()
{ {
@@ -111,12 +122,8 @@ namespace boost { namespace unordered { namespace detail {
node_constructor<Alloc>::~node_constructor() node_constructor<Alloc>::~node_constructor()
{ {
if (node_) { if (node_) {
if (value_constructed_) { if (constructed_) {
boost::unordered::detail::destroy(node_->value_ptr()); boost::unordered::detail::destroy_node(alloc_,
}
if (node_constructed_) {
node_allocator_traits::destroy(alloc_,
boost::addressof(*node_)); boost::addressof(*node_));
} }
@@ -128,24 +135,13 @@ namespace boost { namespace unordered { namespace detail {
void node_constructor<Alloc>::construct_node() void node_constructor<Alloc>::construct_node()
{ {
if(!node_) { if(!node_) {
node_constructed_ = false; constructed_ = false;
value_constructed_ = false;
node_ = node_allocator_traits::allocate(alloc_, 1); node_ = node_allocator_traits::allocate(alloc_, 1);
node_allocator_traits::construct(alloc_,
boost::addressof(*node_), node());
node_->init(static_cast<typename node::link_pointer>(node_));
node_constructed_ = true;
} }
else { else if (constructed_) {
BOOST_ASSERT(node_constructed_); boost::unordered::detail::destroy_node(alloc_,
boost::addressof(*node_));
if (value_constructed_) constructed_ = false;
{
boost::unordered::detail::destroy(node_->value_ptr());
value_constructed_ = false;
}
} }
} }
@@ -183,6 +179,16 @@ namespace boost { namespace unordered { namespace detail {
enum { extra_node = false }; enum { extra_node = false };
}; };
template <typename LinkPointer>
struct node_base
{
typedef LinkPointer link_pointer;
link_pointer next_;
node_base() : next_() {}
};
}}} }}}
namespace boost { namespace unordered { namespace iterator_detail { namespace boost { namespace unordered { namespace iterator_detail {
@@ -718,6 +724,14 @@ namespace boost { namespace unordered { namespace detail {
node_constructor a(this->node_alloc()); node_constructor a(this->node_alloc());
a.construct_node(); a.construct_node();
// Since this node is just to mark the beginning it doesn't
// contain a value, so just construct node::node_base
// which containers the pointer to the next element.
node_allocator_traits::construct(node_alloc(),
static_cast<typename node::node_base*>(
boost::addressof(*a.get())),
typename node::node_base());
(constructor.get() + (constructor.get() +
static_cast<std::ptrdiff_t>(this->bucket_count_))->next_ = static_cast<std::ptrdiff_t>(this->bucket_count_))->next_ =
a.release(); a.release();
@@ -762,9 +776,8 @@ namespace boost { namespace unordered { namespace detail {
inline void delete_node(c_iterator n) inline void delete_node(c_iterator n)
{ {
boost::unordered::detail::destroy(n.node_->value_ptr()); boost::unordered::detail::destroy_node(
node_allocator_traits::destroy(node_alloc(), node_alloc(), boost::addressof(*n.node_));
boost::addressof(*n.node_));
node_allocator_traits::deallocate(node_alloc(), n.node_, 1); node_allocator_traits::deallocate(node_alloc(), n.node_, 1);
--size_; --size_;
} }
@@ -786,7 +799,8 @@ namespace boost { namespace unordered { namespace detail {
inline void delete_extra_node(bucket_pointer) {} inline void delete_extra_node(bucket_pointer) {}
inline void delete_extra_node(node_pointer n) { inline void delete_extra_node(node_pointer n) {
node_allocator_traits::destroy(node_alloc(), boost::addressof(*n)); node_allocator_traits::destroy(node_alloc(),
static_cast<typename node::node_base*>(boost::addressof(*n)));
node_allocator_traits::deallocate(node_alloc(), n, 1); node_allocator_traits::deallocate(node_alloc(), n, 1);
} }
@@ -847,22 +861,24 @@ namespace boost { namespace unordered { namespace detail {
// This is called after erasing a node or group of nodes to fix up // This is called after erasing a node or group of nodes to fix up
// the bucket pointers. // the bucket pointers.
void fix_buckets(bucket_pointer bucket, void fix_buckets(bucket_pointer this_bucket,
previous_pointer prev, node_pointer next) previous_pointer prev, node_pointer next)
{ {
if (!next) if (!next)
{ {
if (bucket->next_ == prev) bucket->next_ = node_pointer(); if (this_bucket->next_ == prev)
this_bucket->next_ = node_pointer();
} }
else else
{ {
bucket_pointer next_bucket = this->get_bucket( bucket_pointer next_bucket = this->get_bucket(
policy::to_bucket(this->bucket_count_, next->hash_)); policy::to_bucket(this->bucket_count_, next->hash_));
if (next_bucket != bucket) if (next_bucket != this_bucket)
{ {
next_bucket->next_ = prev; next_bucket->next_ = prev;
if (bucket->next_ == prev) bucket->next_ = node_pointer(); if (this_bucket->next_ == prev)
this_bucket->next_ = node_pointer();
} }
} }
} }

View File

@@ -12,6 +12,7 @@
# pragma once # pragma once
#endif #endif
#include <boost/unordered/detail/fwd.hpp>
#include <boost/move/move.hpp> #include <boost/move/move.hpp>
#include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/inc.hpp> #include <boost/preprocessor/inc.hpp>
@@ -21,7 +22,10 @@
#include <boost/preprocessor/repetition/enum_binary_params.hpp> #include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/type_traits/is_class.hpp> #include <boost/type_traits/is_class.hpp>
#include <boost/type_traits/add_lvalue_reference.hpp>
#include <boost/tuple/tuple.hpp> #include <boost/tuple/tuple.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/detail/select_type.hpp>
#include <utility> #include <utility>
#if !defined(BOOST_NO_0X_HDR_TUPLE) #if !defined(BOOST_NO_0X_HDR_TUPLE)
@@ -45,6 +49,38 @@
namespace boost { namespace unordered { namespace detail { namespace boost { namespace unordered { namespace detail {
////////////////////////////////////////////////////////////////////////////
// Bits and pieces for implementing traits
template <typename T> typename boost::add_lvalue_reference<T>::type make();
struct choice9 { typedef char (&type)[9]; };
struct choice8 : choice9 { typedef char (&type)[8]; };
struct choice7 : choice8 { typedef char (&type)[7]; };
struct choice6 : choice7 { typedef char (&type)[6]; };
struct choice5 : choice6 { typedef char (&type)[5]; };
struct choice4 : choice5 { typedef char (&type)[4]; };
struct choice3 : choice4 { typedef char (&type)[3]; };
struct choice2 : choice3 { typedef char (&type)[2]; };
struct choice1 : choice2 { typedef char (&type)[1]; };
choice1 choose();
typedef choice1::type yes_type;
typedef choice2::type no_type;
struct private_type
{
private_type const &operator,(int) const;
};
template <typename T>
no_type is_private_type(T const&);
yes_type is_private_type(private_type const&);
struct convert_from_anything {
template <typename T>
convert_from_anything(T const&);
};
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// emplace_args // emplace_args
// //
@@ -75,7 +111,7 @@ namespace boost { namespace unordered { namespace detail {
{ \ { \
BOOST_PP_REPEAT_##z(n, BOOST_UNORDERED_EARGS_MEMBER, _) \ BOOST_PP_REPEAT_##z(n, BOOST_UNORDERED_EARGS_MEMBER, _) \
BOOST_PP_CAT(emplace_args, n) ( \ BOOST_PP_CAT(emplace_args, n) ( \
BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, a) \ BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, b) \
) : BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_EARGS_INIT, _) \ ) : BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_EARGS_INIT, _) \
{} \ {} \
\ \
@@ -85,12 +121,12 @@ namespace boost { namespace unordered { namespace detail {
inline BOOST_PP_CAT(emplace_args, n) < \ inline BOOST_PP_CAT(emplace_args, n) < \
BOOST_PP_ENUM_PARAMS_Z(z, n, A) \ BOOST_PP_ENUM_PARAMS_Z(z, n, A) \
> create_emplace_args( \ > create_emplace_args( \
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, b) \
) \ ) \
{ \ { \
BOOST_PP_CAT(emplace_args, n) < \ BOOST_PP_CAT(emplace_args, n) < \
BOOST_PP_ENUM_PARAMS_Z(z, n, A) \ BOOST_PP_ENUM_PARAMS_Z(z, n, A) \
> e(BOOST_PP_ENUM_PARAMS_Z(z, n, a)); \ > e(BOOST_PP_ENUM_PARAMS_Z(z, n, b)); \
return e; \ return e; \
} }
@@ -102,7 +138,7 @@ namespace boost { namespace unordered { namespace detail {
#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \ #define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
BOOST_PP_CAT(a, n)( \ BOOST_PP_CAT(a, n)( \
boost::forward<BOOST_PP_CAT(A,n)>(BOOST_PP_CAT(a, n))) boost::forward<BOOST_PP_CAT(A,n)>(BOOST_PP_CAT(b, n)))
#else #else
@@ -112,7 +148,7 @@ namespace boost { namespace unordered { namespace detail {
BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n); BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \ #define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
BOOST_PP_CAT(a, n)(BOOST_PP_CAT(a, n)) BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n))
#endif #endif

View File

@@ -12,7 +12,6 @@
#endif #endif
#include <boost/unordered/detail/table.hpp> #include <boost/unordered/detail/table.hpp>
#include <boost/unordered/detail/emplace_args.hpp>
#include <boost/unordered/detail/extract_key.hpp> #include <boost/unordered/detail/extract_key.hpp>
namespace boost { namespace unordered { namespace detail { namespace boost { namespace unordered { namespace detail {
@@ -23,20 +22,40 @@ namespace boost { namespace unordered { namespace detail {
template <typename A, typename T> template <typename A, typename T>
struct grouped_node : struct grouped_node :
boost::unordered::detail::node_base<
typename ::boost::unordered::detail::rebind_wrap<
A, grouped_node<A, T> >::type::pointer
>,
boost::unordered::detail::value_base<T> boost::unordered::detail::value_base<T>
{ {
typedef typename ::boost::unordered::detail::rebind_wrap< typedef typename ::boost::unordered::detail::rebind_wrap<
A, grouped_node<A, T> >::type::pointer link_pointer; A, grouped_node<A, T> >::type::pointer link_pointer;
typedef boost::unordered::detail::node_base<link_pointer> node_base;
link_pointer next_;
link_pointer group_prev_; link_pointer group_prev_;
std::size_t hash_; std::size_t hash_;
#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
grouped_node(BOOST_UNORDERED_EMPLACE_ARGS) :
node_base(),
group_prev_(),
hash_(0)
{
boost::unordered::detail::construct_impl(
this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
}
~grouped_node() {
boost::unordered::detail::destroy(this->value_ptr());
}
#else
grouped_node() : grouped_node() :
next_(), node_base(),
group_prev_(), group_prev_(),
hash_(0) hash_(0)
{} {}
#endif
void init(link_pointer self) void init(link_pointer self)
{ {
@@ -50,16 +69,33 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::ptr_bucket boost::unordered::detail::ptr_bucket
{ {
typedef boost::unordered::detail::ptr_bucket bucket_base; typedef boost::unordered::detail::ptr_bucket bucket_base;
typedef bucket_base node_base;
typedef ptr_bucket* link_pointer; typedef ptr_bucket* link_pointer;
link_pointer group_prev_; link_pointer group_prev_;
std::size_t hash_; std::size_t hash_;
#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
grouped_ptr_node(BOOST_UNORDERED_EMPLACE_ARGS) :
bucket_base(),
group_prev_(0),
hash_(0)
{
boost::unordered::detail::construct_impl(
this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
}
~grouped_ptr_node() {
boost::unordered::detail::destroy(this->value_ptr());
}
#else
grouped_ptr_node() : grouped_ptr_node() :
bucket_base(), bucket_base(),
group_prev_(0), group_prev_(0),
hash_(0) hash_(0)
{} {}
#endif
void init(link_pointer self) void init(link_pointer self)
{ {
@@ -221,12 +257,12 @@ namespace boost { namespace unordered { namespace detail {
template <class Key, class Pred> template <class Key, class Pred>
iterator find_node_impl( iterator find_node_impl(
std::size_t hash, std::size_t key_hash,
Key const& k, Key const& k,
Pred const& eq) const Pred const& eq) const
{ {
std::size_t bucket_index = std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, hash); policy::to_bucket(this->bucket_count_, key_hash);
iterator n = this->get_start(bucket_index); iterator n = this->get_start(bucket_index);
for (;;) for (;;)
@@ -234,7 +270,7 @@ namespace boost { namespace unordered { namespace detail {
if (!n.node_) return n; if (!n.node_) return n;
std::size_t node_hash = n.node_->hash_; std::size_t node_hash = n.node_->hash_;
if (hash == node_hash) if (key_hash == node_hash)
{ {
if (eq(k, this->get_key(*n))) if (eq(k, this->get_key(*n)))
return n; return n;
@@ -256,14 +292,14 @@ namespace boost { namespace unordered { namespace detail {
iterator n = this->find_node(k); iterator n = this->find_node(k);
if (!n.node_) return 0; if (!n.node_) return 0;
std::size_t count = 0; std::size_t x = 0;
node_pointer it = n.node_; node_pointer it = n.node_;
do { do {
it = static_cast<node_pointer>(it->group_prev_); it = static_cast<node_pointer>(it->group_prev_);
++count; ++x;
} while(it != n.node_); } while(it != n.node_);
return count; return x;
} }
std::pair<iterator, iterator> std::pair<iterator, iterator>
@@ -396,11 +432,11 @@ namespace boost { namespace unordered { namespace detail {
inline iterator add_node( inline iterator add_node(
node_constructor& a, node_constructor& a,
std::size_t hash, std::size_t key_hash,
iterator pos) iterator pos)
{ {
node_pointer n = a.release(); node_pointer n = a.release();
n->hash_ = hash; n->hash_ = key_hash;
if (pos.node_) { if (pos.node_) {
this->add_after_node(n, pos.node_); this->add_after_node(n, pos.node_);
if (n->next_) { if (n->next_) {
@@ -408,14 +444,14 @@ namespace boost { namespace unordered { namespace detail {
this->bucket_count_, this->bucket_count_,
static_cast<node_pointer>(n->next_)->hash_); static_cast<node_pointer>(n->next_)->hash_);
if (next_bucket != if (next_bucket !=
policy::to_bucket(this->bucket_count_, hash)) { policy::to_bucket(this->bucket_count_, key_hash)) {
this->get_bucket(next_bucket)->next_ = n; this->get_bucket(next_bucket)->next_ = n;
} }
} }
} }
else { else {
bucket_pointer b = this->get_bucket( bucket_pointer b = this->get_bucket(
policy::to_bucket(this->bucket_count_, hash)); policy::to_bucket(this->bucket_count_, key_hash));
if (!b->next_) if (!b->next_)
{ {
@@ -444,20 +480,20 @@ namespace boost { namespace unordered { namespace detail {
iterator emplace_impl(node_constructor& a) iterator emplace_impl(node_constructor& a)
{ {
key_type const& k = this->get_key(a.value()); key_type const& k = this->get_key(a.value());
std::size_t hash = this->hash(k); std::size_t key_hash = this->hash(k);
iterator position = this->find_node(hash, k); iterator position = this->find_node(key_hash, k);
// reserve has basic exception safety if the hash function // reserve has basic exception safety if the hash function
// throws, strong otherwise. // throws, strong otherwise.
this->reserve_for_insert(this->size_ + 1); this->reserve_for_insert(this->size_ + 1);
return this->add_node(a, hash, position); return this->add_node(a, key_hash, position);
} }
void emplace_impl_no_rehash(node_constructor& a) void emplace_impl_no_rehash(node_constructor& a)
{ {
key_type const& k = this->get_key(a.value()); key_type const& k = this->get_key(a.value());
std::size_t hash = this->hash(k); std::size_t key_hash = this->hash(k);
this->add_node(a, hash, this->find_node(hash, k)); this->add_node(a, key_hash, this->find_node(key_hash, k));
} }
#if defined(BOOST_NO_RVALUE_REFERENCES) #if defined(BOOST_NO_RVALUE_REFERENCES)
@@ -531,12 +567,12 @@ namespace boost { namespace unordered { namespace detail {
{ {
if(!this->size_) return 0; if(!this->size_) return 0;
std::size_t hash = this->hash(k); std::size_t key_hash = this->hash(k);
std::size_t bucket_index = std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, hash); policy::to_bucket(this->bucket_count_, key_hash);
bucket_pointer bucket = this->get_bucket(bucket_index); bucket_pointer this_bucket = this->get_bucket(bucket_index);
previous_pointer prev = bucket->next_; previous_pointer prev = this_bucket->next_;
if (!prev) return 0; if (!prev) return 0;
for (;;) for (;;)
@@ -547,7 +583,7 @@ namespace boost { namespace unordered { namespace detail {
if (policy::to_bucket(this->bucket_count_, node_hash) if (policy::to_bucket(this->bucket_count_, node_hash)
!= bucket_index) != bucket_index)
return 0; return 0;
if (node_hash == hash && if (node_hash == key_hash &&
this->key_eq()(k, this->get_key( this->key_eq()(k, this->get_key(
static_cast<node_pointer>(prev->next_)->value()))) static_cast<node_pointer>(prev->next_)->value())))
break; break;
@@ -560,7 +596,7 @@ namespace boost { namespace unordered { namespace detail {
static_cast<node_pointer>(pos->group_prev_)->next_; static_cast<node_pointer>(pos->group_prev_)->next_;
node_pointer end = static_cast<node_pointer>(end1); node_pointer end = static_cast<node_pointer>(end1);
prev->next_ = end1; prev->next_ = end1;
this->fix_buckets(bucket, prev, end); this->fix_buckets(this_bucket, prev, end);
return this->delete_nodes(c_iterator(pos), c_iterator(end)); return this->delete_nodes(c_iterator(pos), c_iterator(end));
} }
@@ -570,11 +606,11 @@ namespace boost { namespace unordered { namespace detail {
iterator next(r.node_); iterator next(r.node_);
++next; ++next;
bucket_pointer bucket = this->get_bucket( bucket_pointer this_bucket = this->get_bucket(
policy::to_bucket(this->bucket_count_, r.node_->hash_)); policy::to_bucket(this->bucket_count_, r.node_->hash_));
previous_pointer prev = unlink_node(*bucket, r.node_); previous_pointer prev = unlink_node(*this_bucket, r.node_);
this->fix_buckets(bucket, prev, next.node_); this->fix_buckets(this_bucket, prev, next.node_);
this->delete_node(r); this->delete_node(r);
@@ -713,7 +749,7 @@ namespace boost { namespace unordered { namespace detail {
previous_pointer prev = dst.get_previous_start(); previous_pointer prev = dst.get_previous_start();
while (n.node_) { while (n.node_) {
std::size_t hash = n.node_->hash_; std::size_t key_hash = n.node_->hash_;
iterator group_end( iterator group_end(
static_cast<node_pointer>( static_cast<node_pointer>(
static_cast<node_pointer>(n.node_->group_prev_)->next_ static_cast<node_pointer>(n.node_->group_prev_)->next_
@@ -724,7 +760,7 @@ namespace boost { namespace unordered { namespace detail {
node_pointer first_node = a.release(); node_pointer first_node = a.release();
node_pointer end = first_node; node_pointer end = first_node;
first_node->hash_ = hash; first_node->hash_ = key_hash;
prev->next_ = static_cast<link_pointer>(first_node); prev->next_ = static_cast<link_pointer>(first_node);
++dst.size_; ++dst.size_;
@@ -733,7 +769,7 @@ namespace boost { namespace unordered { namespace detail {
a.construct_node(); a.construct_node();
a.construct_value2(*n); a.construct_value2(*n);
end = a.release(); end = a.release();
end->hash_ = hash; end->hash_ = key_hash;
add_after_node(end, first_node); add_after_node(end, first_node);
++dst.size_; ++dst.size_;
} }
@@ -760,7 +796,7 @@ namespace boost { namespace unordered { namespace detail {
previous_pointer prev = dst.get_previous_start(); previous_pointer prev = dst.get_previous_start();
while (n.node_) { while (n.node_) {
std::size_t hash = n.node_->hash_; std::size_t key_hash = n.node_->hash_;
iterator group_end( iterator group_end(
static_cast<node_pointer>( static_cast<node_pointer>(
static_cast<node_pointer>(n.node_->group_prev_)->next_ static_cast<node_pointer>(n.node_->group_prev_)->next_
@@ -771,7 +807,7 @@ namespace boost { namespace unordered { namespace detail {
node_pointer first_node = a.release(); node_pointer first_node = a.release();
node_pointer end = first_node; node_pointer end = first_node;
first_node->hash_ = hash; first_node->hash_ = key_hash;
prev->next_ = static_cast<link_pointer>(first_node); prev->next_ = static_cast<link_pointer>(first_node);
++dst.size_; ++dst.size_;
@@ -780,7 +816,7 @@ namespace boost { namespace unordered { namespace detail {
a.construct_node(); a.construct_node();
a.construct_value2(boost::move(*n)); a.construct_value2(boost::move(*n));
end = a.release(); end = a.release();
end->hash_ = hash; end->hash_ = key_hash;
add_after_node(end, first_node); add_after_node(end, first_node);
++dst.size_; ++dst.size_;
} }

View File

@@ -348,21 +348,21 @@ namespace boost { namespace unordered { namespace detail {
template <typename Key, typename Hash, typename Pred> template <typename Key, typename Hash, typename Pred>
iterator generic_find_node( iterator generic_find_node(
Key const& k, Key const& k,
Hash const& hash_function, Hash const& hf,
Pred const& eq) const Pred const& eq) const
{ {
if (!this->size_) return iterator(); if (!this->size_) return iterator();
return static_cast<table_impl const*>(this)-> return static_cast<table_impl const*>(this)->
find_node_impl(policy::apply_hash(hash_function, k), k, eq); find_node_impl(policy::apply_hash(hf, k), k, eq);
} }
iterator find_node( iterator find_node(
std::size_t hash, std::size_t key_hash,
key_type const& k) const key_type const& k) const
{ {
if (!this->size_) return iterator(); if (!this->size_) return iterator();
return static_cast<table_impl const*>(this)-> return static_cast<table_impl const*>(this)->
find_node_impl(hash, k, this->key_eq()); find_node_impl(key_hash, k, this->key_eq());
} }
iterator find_node(key_type const& k) const iterator find_node(key_type const& k) const
@@ -387,6 +387,7 @@ namespace boost { namespace unordered { namespace detail {
void reserve_for_insert(std::size_t); void reserve_for_insert(std::size_t);
void rehash(std::size_t); void rehash(std::size_t);
void reserve(std::size_t);
}; };
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@@ -402,7 +403,9 @@ namespace boost { namespace unordered { namespace detail {
this->create_buckets(); this->create_buckets();
this->max_load_ = this->calculate_max_load(); this->max_load_ = this->calculate_max_load();
} }
else if(size >= max_load_) { // According to the standard this should be 'size >= max_load_',
// but I think this is better, defect report filed.
else if(size > max_load_) {
std::size_t num_buckets std::size_t num_buckets
= this->min_buckets_for_size((std::max)(size, = this->min_buckets_for_size((std::max)(size,
this->size_ + (this->size_ >> 1))); this->size_ + (this->size_ >> 1)));
@@ -417,7 +420,7 @@ namespace boost { namespace unordered { namespace detail {
// strong otherwise. // strong otherwise.
template <typename Types> template <typename Types>
void table<Types>::rehash(std::size_t min_buckets) inline void table<Types>::rehash(std::size_t min_buckets)
{ {
using namespace std; using namespace std;
@@ -437,6 +440,13 @@ namespace boost { namespace unordered { namespace detail {
} }
} }
} }
template <typename Types>
inline void table<Types>::reserve(std::size_t num_elements)
{
rehash(static_cast<std::size_t>(
std::ceil(static_cast<double>(num_elements) / this->mlf_)));
}
}}} }}}
#endif #endif

View File

@@ -12,31 +12,49 @@
#endif #endif
#include <boost/unordered/detail/table.hpp> #include <boost/unordered/detail/table.hpp>
#include <boost/unordered/detail/emplace_args.hpp>
#include <boost/unordered/detail/extract_key.hpp> #include <boost/unordered/detail/extract_key.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
#include <stdexcept> #include <stdexcept>
namespace boost { namespace unordered { namespace detail { namespace boost { namespace unordered { namespace detail {
template <typename A, typename T> struct node; template <typename A, typename T> struct unique_node;
template <typename T> struct ptr_node; template <typename T> struct ptr_node;
template <typename Types> struct table_impl; template <typename Types> struct table_impl;
template <typename A, typename T> template <typename A, typename T>
struct node : struct unique_node :
boost::unordered::detail::node_base<
typename ::boost::unordered::detail::rebind_wrap<
A, unique_node<A, T> >::type::pointer
>,
boost::unordered::detail::value_base<T> boost::unordered::detail::value_base<T>
{ {
typedef typename ::boost::unordered::detail::rebind_wrap< typedef typename ::boost::unordered::detail::rebind_wrap<
A, node<A, T> >::type::pointer link_pointer; A, unique_node<A, T> >::type::pointer link_pointer;
typedef boost::unordered::detail::node_base<link_pointer> node_base;
link_pointer next_;
std::size_t hash_; std::size_t hash_;
node() : #if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
next_(), template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
unique_node(BOOST_UNORDERED_EMPLACE_ARGS) :
node_base(),
hash_(0)
{
boost::unordered::detail::construct_impl(
this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
}
~unique_node() {
boost::unordered::detail::destroy(this->value_ptr());
}
#else
unique_node() :
node_base(),
hash_(0) hash_(0)
{} {}
#endif
void init(link_pointer) void init(link_pointer)
{ {
@@ -49,14 +67,30 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::ptr_bucket boost::unordered::detail::ptr_bucket
{ {
typedef boost::unordered::detail::ptr_bucket bucket_base; typedef boost::unordered::detail::ptr_bucket bucket_base;
typedef bucket_base node_base;
typedef ptr_bucket* link_pointer; typedef ptr_bucket* link_pointer;
std::size_t hash_; std::size_t hash_;
#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
ptr_node(BOOST_UNORDERED_EMPLACE_ARGS) :
bucket_base(),
hash_(0)
{
boost::unordered::detail::construct_impl(
this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
}
~ptr_node() {
boost::unordered::detail::destroy(this->value_ptr());
}
#else
ptr_node() : ptr_node() :
bucket_base(), bucket_base(),
hash_(0) hash_(0)
{} {}
#endif
void init(link_pointer) void init(link_pointer)
{ {
@@ -69,7 +103,7 @@ namespace boost { namespace unordered { namespace detail {
template <typename A, typename T, typename NodePtr, typename BucketPtr> template <typename A, typename T, typename NodePtr, typename BucketPtr>
struct pick_node2 struct pick_node2
{ {
typedef boost::unordered::detail::node<A, T> node; typedef boost::unordered::detail::unique_node<A, T> node;
typedef typename boost::unordered::detail::allocator_traits< typedef typename boost::unordered::detail::allocator_traits<
typename boost::unordered::detail::rebind_wrap<A, node>::type typename boost::unordered::detail::rebind_wrap<A, node>::type
@@ -219,12 +253,12 @@ namespace boost { namespace unordered { namespace detail {
template <class Key, class Pred> template <class Key, class Pred>
iterator find_node_impl( iterator find_node_impl(
std::size_t hash, std::size_t key_hash,
Key const& k, Key const& k,
Pred const& eq) const Pred const& eq) const
{ {
std::size_t bucket_index = std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, hash); policy::to_bucket(this->bucket_count_, key_hash);
iterator n = this->get_start(bucket_index); iterator n = this->get_start(bucket_index);
for (;;) for (;;)
@@ -232,7 +266,7 @@ namespace boost { namespace unordered { namespace detail {
if (!n.node_) return n; if (!n.node_) return n;
std::size_t node_hash = n.node_->hash_; std::size_t node_hash = n.node_->hash_;
if (hash == node_hash) if (key_hash == node_hash)
{ {
if (eq(k, this->get_key(*n))) if (eq(k, this->get_key(*n)))
return n; return n;
@@ -300,13 +334,13 @@ namespace boost { namespace unordered { namespace detail {
inline iterator add_node( inline iterator add_node(
node_constructor& a, node_constructor& a,
std::size_t hash) std::size_t key_hash)
{ {
node_pointer n = a.release(); node_pointer n = a.release();
n->hash_ = hash; n->hash_ = key_hash;
bucket_pointer b = this->get_bucket( bucket_pointer b = this->get_bucket(
policy::to_bucket(this->bucket_count_, hash)); policy::to_bucket(this->bucket_count_, key_hash));
if (!b->next_) if (!b->next_)
{ {
@@ -336,8 +370,8 @@ namespace boost { namespace unordered { namespace detail {
{ {
typedef typename value_type::second_type mapped_type; typedef typename value_type::second_type mapped_type;
std::size_t hash = this->hash(k); std::size_t key_hash = this->hash(k);
iterator pos = this->find_node(hash, k); iterator pos = this->find_node(key_hash, k);
if (pos.node_) return *pos; if (pos.node_) return *pos;
@@ -357,7 +391,7 @@ namespace boost { namespace unordered { namespace detail {
#endif #endif
this->reserve_for_insert(this->size_ + 1); this->reserve_for_insert(this->size_ + 1);
return *add_node(a, hash); return *add_node(a, key_hash);
} }
#if defined(BOOST_NO_RVALUE_REFERENCES) #if defined(BOOST_NO_RVALUE_REFERENCES)
@@ -397,8 +431,8 @@ namespace boost { namespace unordered { namespace detail {
emplace_return emplace_impl(key_type const& k, emplace_return emplace_impl(key_type const& k,
BOOST_UNORDERED_EMPLACE_ARGS) BOOST_UNORDERED_EMPLACE_ARGS)
{ {
std::size_t hash = this->hash(k); std::size_t key_hash = this->hash(k);
iterator pos = this->find_node(hash, k); iterator pos = this->find_node(key_hash, k);
if (pos.node_) return emplace_return(pos, false); if (pos.node_) return emplace_return(pos, false);
@@ -411,21 +445,21 @@ namespace boost { namespace unordered { namespace detail {
// reserve has basic exception safety if the hash function // reserve has basic exception safety if the hash function
// throws, strong otherwise. // throws, strong otherwise.
this->reserve_for_insert(this->size_ + 1); this->reserve_for_insert(this->size_ + 1);
return emplace_return(this->add_node(a, hash), true); return emplace_return(this->add_node(a, key_hash), true);
} }
emplace_return emplace_impl_with_node(node_constructor& a) emplace_return emplace_impl_with_node(node_constructor& a)
{ {
key_type const& k = this->get_key(a.value()); key_type const& k = this->get_key(a.value());
std::size_t hash = this->hash(k); std::size_t key_hash = this->hash(k);
iterator pos = this->find_node(hash, k); iterator pos = this->find_node(key_hash, k);
if (pos.node_) return emplace_return(pos, false); if (pos.node_) return emplace_return(pos, false);
// reserve has basic exception safety if the hash function // reserve has basic exception safety if the hash function
// throws, strong otherwise. // throws, strong otherwise.
this->reserve_for_insert(this->size_ + 1); this->reserve_for_insert(this->size_ + 1);
return emplace_return(this->add_node(a, hash), true); return emplace_return(this->add_node(a, key_hash), true);
} }
template <BOOST_UNORDERED_EMPLACE_TEMPLATE> template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
@@ -481,12 +515,12 @@ namespace boost { namespace unordered { namespace detail {
void insert_range_empty(node_constructor& a, key_type const& k, void insert_range_empty(node_constructor& a, key_type const& k,
InputIt i, InputIt j) InputIt i, InputIt j)
{ {
std::size_t hash = this->hash(k); std::size_t key_hash = this->hash(k);
a.construct_node(); a.construct_node();
a.construct_value2(*i); a.construct_value2(*i);
this->reserve_for_insert(this->size_ + this->reserve_for_insert(this->size_ +
boost::unordered::detail::insert_size(i, j)); boost::unordered::detail::insert_size(i, j));
this->add_node(a, hash); this->add_node(a, key_hash);
} }
template <class InputIt> template <class InputIt>
@@ -494,19 +528,19 @@ namespace boost { namespace unordered { namespace detail {
InputIt i, InputIt j) InputIt i, InputIt j)
{ {
// No side effects in this initial code // No side effects in this initial code
std::size_t hash = this->hash(k); std::size_t key_hash = this->hash(k);
iterator pos = this->find_node(hash, k); iterator pos = this->find_node(key_hash, k);
if (!pos.node_) { if (!pos.node_) {
a.construct_node(); a.construct_node();
a.construct_value2(*i); a.construct_value2(*i);
if(this->size_ + 1 >= this->max_load_) if(this->size_ + 1 > this->max_load_)
this->reserve_for_insert(this->size_ + this->reserve_for_insert(this->size_ +
boost::unordered::detail::insert_size(i, j)); boost::unordered::detail::insert_size(i, j));
// Nothing after this point can throw. // Nothing after this point can throw.
this->add_node(a, hash); this->add_node(a, key_hash);
} }
} }
@@ -531,12 +565,12 @@ namespace boost { namespace unordered { namespace detail {
{ {
if(!this->size_) return 0; if(!this->size_) return 0;
std::size_t hash = this->hash(k); std::size_t key_hash = this->hash(k);
std::size_t bucket_index = std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, hash); policy::to_bucket(this->bucket_count_, key_hash);
bucket_pointer bucket = this->get_bucket(bucket_index); bucket_pointer this_bucket = this->get_bucket(bucket_index);
previous_pointer prev = bucket->next_; previous_pointer prev = this_bucket->next_;
if (!prev) return 0; if (!prev) return 0;
for (;;) for (;;)
@@ -547,7 +581,7 @@ namespace boost { namespace unordered { namespace detail {
if (policy::to_bucket(this->bucket_count_, node_hash) if (policy::to_bucket(this->bucket_count_, node_hash)
!= bucket_index) != bucket_index)
return 0; return 0;
if (node_hash == hash && if (node_hash == key_hash &&
this->key_eq()(k, this->get_key( this->key_eq()(k, this->get_key(
static_cast<node_pointer>(prev->next_)->value()))) static_cast<node_pointer>(prev->next_)->value())))
break; break;
@@ -557,7 +591,7 @@ namespace boost { namespace unordered { namespace detail {
node_pointer pos = static_cast<node_pointer>(prev->next_); node_pointer pos = static_cast<node_pointer>(prev->next_);
node_pointer end = static_cast<node_pointer>(pos->next_); node_pointer end = static_cast<node_pointer>(pos->next_);
prev->next_ = pos->next_; prev->next_ = pos->next_;
this->fix_buckets(bucket, prev, end); this->fix_buckets(this_bucket, prev, end);
return this->delete_nodes(c_iterator(pos), c_iterator(end)); return this->delete_nodes(c_iterator(pos), c_iterator(end));
} }
@@ -567,11 +601,11 @@ namespace boost { namespace unordered { namespace detail {
iterator next(r.node_); iterator next(r.node_);
++next; ++next;
bucket_pointer bucket = this->get_bucket( bucket_pointer this_bucket = this->get_bucket(
policy::to_bucket(this->bucket_count_, r.node_->hash_)); policy::to_bucket(this->bucket_count_, r.node_->hash_));
previous_pointer prev = unlink_node(*bucket, r.node_); previous_pointer prev = unlink_node(*this_bucket, r.node_);
this->fix_buckets(bucket, prev, next.node_); this->fix_buckets(this_bucket, prev, next.node_);
this->delete_node(r); this->delete_node(r);

View File

@@ -515,6 +515,7 @@ namespace unordered
float load_factor() const; float load_factor() const;
void max_load_factor(float); void max_load_factor(float);
void rehash(size_type); void rehash(size_type);
void reserve(size_type);
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
friend bool operator==<K,T,H,P,A>( friend bool operator==<K,T,H,P,A>(
@@ -997,6 +998,7 @@ namespace unordered
float load_factor() const; float load_factor() const;
void max_load_factor(float); void max_load_factor(float);
void rehash(size_type); void rehash(size_type);
void reserve(size_type);
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
friend bool operator==<K,T,H,P,A>( friend bool operator==<K,T,H,P,A>(
@@ -1300,6 +1302,12 @@ namespace unordered
table_.rehash(n); table_.rehash(n);
} }
template <class K, class T, class H, class P, class A>
void unordered_map<K,T,H,P,A>::reserve(size_type n)
{
table_.reserve(n);
}
template <class K, class T, class H, class P, class A> template <class K, class T, class H, class P, class A>
inline bool operator==( inline bool operator==(
unordered_map<K,T,H,P,A> const& m1, unordered_map<K,T,H,P,A> const& m1,
@@ -1606,6 +1614,12 @@ namespace unordered
table_.rehash(n); table_.rehash(n);
} }
template <class K, class T, class H, class P, class A>
void unordered_multimap<K,T,H,P,A>::reserve(size_type n)
{
table_.reserve(n);
}
template <class K, class T, class H, class P, class A> template <class K, class T, class H, class P, class A>
inline bool operator==( inline bool operator==(
unordered_multimap<K,T,H,P,A> const& m1, unordered_multimap<K,T,H,P,A> const& m1,

View File

@@ -500,6 +500,7 @@ namespace unordered
float load_factor() const; float load_factor() const;
void max_load_factor(float); void max_load_factor(float);
void rehash(size_type); void rehash(size_type);
void reserve(size_type);
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
friend bool operator==<T,H,P,A>( friend bool operator==<T,H,P,A>(
@@ -972,6 +973,7 @@ namespace unordered
float load_factor() const; float load_factor() const;
void max_load_factor(float); void max_load_factor(float);
void rehash(size_type); void rehash(size_type);
void reserve(size_type);
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
friend bool operator==<T,H,P,A>( friend bool operator==<T,H,P,A>(
@@ -1226,6 +1228,12 @@ namespace unordered
table_.rehash(n); table_.rehash(n);
} }
template <class T, class H, class P, class A>
void unordered_set<T,H,P,A>::reserve(size_type n)
{
table_.reserve(n);
}
template <class T, class H, class P, class A> template <class T, class H, class P, class A>
inline bool operator==( inline bool operator==(
unordered_set<T,H,P,A> const& m1, unordered_set<T,H,P,A> const& m1,
@@ -1504,6 +1512,12 @@ namespace unordered
table_.rehash(n); table_.rehash(n);
} }
template <class T, class H, class P, class A>
void unordered_multiset<T,H,P,A>::reserve(size_type n)
{
table_.reserve(n);
}
template <class T, class H, class P, class A> template <class T, class H, class P, class A>
inline bool operator==( inline bool operator==(
unordered_multiset<T,H,P,A> const& m1, unordered_multiset<T,H,P,A> const& m1,

View File

@@ -11,7 +11,7 @@
#pragma warning(disable:4512) // assignment operator could not be generated #pragma warning(disable:4512) // assignment operator could not be generated
#endif #endif
test::seed_t seed(12847); test::seed_t initialize_seed(12847);
template <class T> template <class T>
struct self_assign_base : public test::exception_base struct self_assign_base : public test::exception_base

View File

@@ -9,7 +9,7 @@
template <typename T> inline void avoid_unused_warning(T const&) {} template <typename T> inline void avoid_unused_warning(T const&) {}
test::seed_t seed(91274); test::seed_t initialize_seed(91274);
struct objects struct objects
{ {

View File

@@ -8,7 +8,7 @@
template <typename T> inline void avoid_unused_warning(T const&) {} template <typename T> inline void avoid_unused_warning(T const&) {}
test::seed_t seed(73041); test::seed_t initialize_seed(73041);
template <class T> template <class T>
struct copy_test1 : public test::exception_base struct copy_test1 : public test::exception_base

View File

@@ -8,7 +8,7 @@
#include "../helpers/invariants.hpp" #include "../helpers/invariants.hpp"
#include "../helpers/helpers.hpp" #include "../helpers/helpers.hpp"
test::seed_t seed(835193); test::seed_t initialize_seed(835193);
template <class T> template <class T>
struct erase_test_base : public test::exception_base struct erase_test_base : public test::exception_base

View File

@@ -11,7 +11,7 @@
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <cmath> #include <cmath>
test::seed_t seed(747373); test::seed_t initialize_seed(747373);
template <class T> template <class T>
struct insert_test_base : public test::exception_base struct insert_test_base : public test::exception_base

View File

@@ -11,7 +11,7 @@
#include <iostream> #include <iostream>
test::seed_t seed(3298597); test::seed_t initialize_seed(3298597);
template <class T> template <class T>
struct rehash_test_base : public test::exception_base struct rehash_test_base : public test::exception_base

View File

@@ -11,7 +11,7 @@
#pragma warning(disable:4512) // assignment operator could not be generated #pragma warning(disable:4512) // assignment operator could not be generated
#endif #endif
test::seed_t seed(9387); test::seed_t initialize_seed(9387);
template <class T> template <class T>
struct self_swap_base : public test::exception_base struct self_swap_base : public test::exception_base

View File

@@ -219,14 +219,14 @@ namespace test
data_.last_ptr_ = &data_.first_; data_.last_ptr_ = &data_.first_;
} }
void erase(const_iterator start, const_iterator end) { void erase(const_iterator i, const_iterator j) {
node** ptr = &data_.first_; node** ptr = &data_.first_;
while(*ptr != start.ptr_) { while(*ptr != i.ptr_) {
ptr = &(*ptr)->next_; ptr = &(*ptr)->next_;
} }
while(*ptr != end.ptr_) { while(*ptr != j.ptr_) {
node* to_delete = *ptr; node* to_delete = *ptr;
*ptr = (*ptr)->next_; *ptr = (*ptr)->next_;
--data_.size_; --data_.size_;

View File

@@ -124,8 +124,8 @@ namespace test
: base() : base()
{} {}
explicit ordered(key_compare const& compare) explicit ordered(key_compare const& kc)
: base(compare) : base(kc)
{} {}
void compare(X const& x) void compare(X const& x)
@@ -143,10 +143,10 @@ namespace test
} }
template <class It> template <class It>
void insert_range(It begin, It end) { void insert_range(It b, It e) {
while(begin != end) { while(b != e) {
this->insert(*begin); this->insert(*b);
++begin; ++b;
} }
} }
}; };

View File

@@ -22,7 +22,7 @@
namespace assign_tests { namespace assign_tests {
test::seed_t seed(96785); test::seed_t initialize_seed(96785);
template <class T> template <class T>
void assign_tests1(T*, void assign_tests1(T*,

View File

@@ -21,7 +21,7 @@
namespace bucket_tests { namespace bucket_tests {
test::seed_t seed(54635); test::seed_t initialize_seed(54635);
template <class X> template <class X>
void tests(X* = 0, test::random_generator generator = test::default_generator) void tests(X* = 0, test::random_generator generator = test::default_generator)

View File

@@ -18,7 +18,7 @@
namespace constructor_tests { namespace constructor_tests {
test::seed_t seed(356730); test::seed_t initialize_seed(356730);
template <class T> template <class T>
void constructor_tests1(T*, void constructor_tests1(T*,

View File

@@ -16,7 +16,7 @@
#include "../helpers/equivalent.hpp" #include "../helpers/equivalent.hpp"
#include "../helpers/invariants.hpp" #include "../helpers/invariants.hpp"
test::seed_t seed(9063); test::seed_t initialize_seed(9063);
namespace copy_tests namespace copy_tests
{ {

View File

@@ -21,7 +21,7 @@
namespace erase_tests namespace erase_tests
{ {
test::seed_t seed(85638); test::seed_t initialize_seed(85638);
template <class Container> template <class Container>
void erase_tests1(Container*, void erase_tests1(Container*,

View File

@@ -17,7 +17,7 @@
namespace find_tests namespace find_tests
{ {
test::seed_t seed(78937); test::seed_t initialize_seed(78937);
template <class X> template <class X>
void find_tests1(X*, test::random_generator generator = test::default_generator) void find_tests1(X*, test::random_generator generator = test::default_generator)

View File

@@ -21,7 +21,7 @@
namespace insert_tests { namespace insert_tests {
test::seed_t seed(243432); test::seed_t initialize_seed(243432);
template <class X> template <class X>
void unique_insert_tests1(X*, void unique_insert_tests1(X*,

View File

@@ -20,7 +20,7 @@
namespace load_factor_tests namespace load_factor_tests
{ {
test::seed_t seed(783656); test::seed_t initialize_seed(783656);
template <class X> template <class X>
void set_load_factor_tests(X* = 0) void set_load_factor_tests(X* = 0)

View File

@@ -22,7 +22,7 @@
namespace move_tests namespace move_tests
{ {
test::seed_t seed(98624); test::seed_t initialize_seed(98624);
#if defined(BOOST_UNORDERED_USE_MOVE) || !defined(BOOST_NO_RVALUE_REFERENCES) #if defined(BOOST_UNORDERED_USE_MOVE) || !defined(BOOST_NO_RVALUE_REFERENCES)
#define BOOST_UNORDERED_TEST_MOVING 1 #define BOOST_UNORDERED_TEST_MOVING 1
#else #else

View File

@@ -15,7 +15,7 @@
namespace rehash_tests namespace rehash_tests
{ {
test::seed_t seed(2974); test::seed_t initialize_seed(2974);
template <class X> template <class X>
bool postcondition(X const& x, BOOST_DEDUCED_TYPENAME X::size_type n) bool postcondition(X const& x, BOOST_DEDUCED_TYPENAME X::size_type n)
@@ -100,6 +100,75 @@ void rehash_test1(X* = 0,
tracker.compare(x); tracker.compare(x);
} }
template <class X>
void reserve_test1(X* = 0,
test::random_generator generator = test::default_generator)
{
for (int random_mlf = 0; random_mlf < 2; ++random_mlf)
{
for (int i = 1; i < 2000; i += i < 50 ? 1 : 13)
{
test::random_values<X> v(i, generator);
test::ordered<X> tracker;
tracker.insert_range(v.begin(), v.end());
X x;
x.max_load_factor(random_mlf ?
static_cast<float>(std::rand() % 1000) / 500.0f + 0.5f : 1.0f);
// For the current standard this should reserve i+1, I've
// submitted a defect report and will assume it's a defect
// for now.
x.reserve(i);
// Insert an element before the range insert, otherwise there are
// no iterators to invalidate in the range insert, and it can
// rehash.
typename test::random_values<X>::iterator it = v.begin();
x.insert(*it);
++it;
std::size_t bucket_count = x.bucket_count();
x.insert(it, v.end());
BOOST_TEST(bucket_count == x.bucket_count());
tracker.compare(x);
}
}
}
template <class X>
void reserve_test2(X* = 0,
test::random_generator generator = test::default_generator)
{
for (int random_mlf = 0; random_mlf < 2; ++random_mlf)
{
for (int i = 0; i < 2000; i += i < 50 ? 1 : 13)
{
test::random_values<X> v(i, generator);
test::ordered<X> tracker;
tracker.insert_range(v.begin(), v.end());
X x;
x.max_load_factor(random_mlf ?
static_cast<float>(std::rand() % 1000) / 500.0f + 0.5f : 1.0f);
x.reserve(i);
std::size_t bucket_count = x.bucket_count();
for (typename test::random_values<X>::iterator it = v.begin();
it != v.end(); ++it)
{
x.insert(*it);
}
BOOST_TEST(bucket_count == x.bucket_count());
tracker.compare(x);
}
}
}
boost::unordered_set<int>* int_set_ptr; boost::unordered_set<int>* int_set_ptr;
boost::unordered_multiset<int>* int_multiset_ptr; boost::unordered_multiset<int>* int_multiset_ptr;
boost::unordered_map<int, int>* int_map_ptr; boost::unordered_map<int, int>* int_map_ptr;
@@ -117,6 +186,12 @@ UNORDERED_TEST(rehash_empty_test3,
UNORDERED_TEST(rehash_test1, UNORDERED_TEST(rehash_test1,
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr)) ((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
) )
UNORDERED_TEST(reserve_test1,
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
)
UNORDERED_TEST(reserve_test2,
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
)
} }

View File

@@ -25,7 +25,7 @@
namespace swap_tests namespace swap_tests
{ {
test::seed_t seed(783472); test::seed_t initialize_seed(783472);
template <class X> template <class X>
void swap_test_impl(X& x1, X& x2) void swap_test_impl(X& x1, X& x2)