diff --git a/doc/changes.qbk b/doc/changes.qbk index abe2b812..c5cb963c 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -178,10 +178,14 @@ C++11 support has resulted in some breaking changes: [h2 Boost 1.50.0] * 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. -* [@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. +* [@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 collisions quite probable (e.g. multiples of 5 are very common because we used base 10). diff --git a/doc/ref.php b/doc/ref.php index cc871be5..e014555c 100644 --- a/doc/ref.php +++ b/doc/ref.php @@ -963,6 +963,18 @@ EOL; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + + + size_type + + void + + Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated. + + + The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + + diff --git a/doc/ref.xml b/doc/ref.xml index aecfd0af..9e4e399e 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -846,6 +846,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + + + size_type + + void + + Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated. + + + The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + + @@ -1797,6 +1809,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + + + size_type + + void + + Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated. + + + The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + + @@ -2793,6 +2817,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + + + size_type + + void + + Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated. + + + The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + + @@ -3758,6 +3794,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + + + size_type + + void + + Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated. + + + The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + + diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index 4f2e13d8..d77aa6a1 100644 --- a/include/boost/unordered/detail/allocator_helpers.hpp +++ b/include/boost/unordered/detail/allocator_helpers.hpp @@ -15,47 +15,41 @@ # pragma once #endif -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include -#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 -// std::allocator_traits in order ot get clean test results. Will reactivate -// later. +//////////////////////////////////////////////////////////////////////////////// +// +// Pick which version of allocator_traits to use +// +// 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__) && \ (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) # 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 -*/ - -// 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 #if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS) # define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0 #endif -#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 -# include -#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2 -# include -#endif +//////////////////////////////////////////////////////////////////////////////// +// +// Some utilities for implementing allocator_traits, but useful elsewhere so +// they're always defined. #if !defined(BOOST_NO_0X_HDR_TYPE_TRAITS) # include @@ -102,48 +96,22 @@ namespace boost { namespace unordered { namespace detail { #endif //////////////////////////////////////////////////////////////////////////// - // Bits and pieces for implementing traits + // Expression test mechanism // - // Some of these are also used elsewhere - - template typename boost::add_lvalue_reference::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 - no_type is_private_type(T const&); - yes_type is_private_type(private_type const&); - - struct convert_from_anything { - template - convert_from_anything(T const&); - }; + // When SFINAE expressions are available, define + // BOOST_UNORDERED_HAS_FUNCTION which can check if a function call is + // supported by a class, otherwise define BOOST_UNORDERED_HAS_MEMBER which + // can detect if a class has the specified member, but not that it has the + // correct type, this is good enough for a passable impression of + // allocator_traits. #if !defined(BOOST_NO_SFINAE_EXPR) -# define BOOST_UNORDERED_HAVE_CALL_DETECTION 1 - template struct expr_test; template struct expr_test : T {}; template static char for_expr_test(U const&); -#define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \ +# define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \ template \ static typename boost::unordered::detail::expr_test< \ BOOST_PP_CAT(choice, result), \ @@ -152,12 +120,12 @@ namespace boost { namespace unordered { namespace detail { 0)))>::type test( \ BOOST_PP_CAT(choice, count)) -#define BOOST_UNORDERED_DEFAULT_EXPRESSION(count, result) \ +# define BOOST_UNORDERED_DEFAULT_EXPRESSION(count, result) \ template \ static BOOST_PP_CAT(choice, result)::type test( \ 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) \ { \ BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, \ @@ -169,11 +137,9 @@ namespace boost { namespace unordered { namespace detail { #else -# define BOOST_UNORDERED_HAVE_CALL_DETECTION 0 - template 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::type \ BOOST_PP_CAT(check, count); \ @@ -187,11 +153,11 @@ namespace boost { namespace unordered { namespace detail { BOOST_PP_CAT(test, count)<&U::name>::type \ test(BOOST_PP_CAT(choice, count)) -#define BOOST_UNORDERED_DEFAULT_MEMBER(count, result) \ +# define BOOST_UNORDERED_DEFAULT_MEMBER(count, result) \ template static BOOST_PP_CAT(choice, result)::type \ 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 impl { \ @@ -211,97 +177,90 @@ namespace boost { namespace unordered { namespace detail { #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 - struct allocator_traits : std::allocator_traits {}; +#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 - template - struct rebind_wrap - { - typedef typename std::allocator_traits:: - template rebind_alloc type; - }; +# include +# include +# include +# if defined(BOOST_NO_SFINAE_EXPR) +# include +# 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 - struct allocator_traits : - boost::container::allocator_traits {}; - - template - struct rebind_wrap : - boost::container::allocator_traits:: - template portable_rebind_alloc - {}; - -#else +namespace boost { namespace unordered { namespace detail { // TODO: Does this match std::allocator_traits::rebind_alloc? template struct rebind_wrap { - typedef typename Alloc::BOOST_NESTED_TEMPLATE rebind::other - type; + typedef typename Alloc::BOOST_NESTED_TEMPLATE rebind::other type; }; -#if defined(BOOST_MSVC) && BOOST_MSVC <= 1400 +# if defined(BOOST_MSVC) && BOOST_MSVC <= 1400 - #define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ - template \ - struct default_type_ ## tname { \ +# define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ + template \ + struct default_type_ ## tname { \ \ - template \ - static choice1::type test(choice1, typename X::tname* = 0); \ + template \ + static choice1::type test(choice1, typename X::tname* = 0); \ \ - template \ - static choice2::type test(choice2, void* = 0); \ + template \ + static choice2::type test(choice2, void* = 0); \ \ - struct DefaultWrap { typedef Default tname; }; \ + struct DefaultWrap { typedef Default tname; }; \ \ - enum { value = (1 == sizeof(test(choose()))) }; \ + enum { value = (1 == sizeof(test(choose()))) }; \ \ - typedef typename boost::detail::if_true:: \ - BOOST_NESTED_TEMPLATE then \ - ::type::tname type; \ - } + typedef typename boost::detail::if_true:: \ + BOOST_NESTED_TEMPLATE then \ + ::type::tname type; \ + } -#else +# else template struct sfinae : T2 {}; - #define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ - template \ - struct default_type_ ## tname { \ +# define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ + template \ + struct default_type_ ## tname { \ \ - template \ - static typename boost::unordered::detail::sfinae< \ - typename X::tname, choice1>::type \ - test(choice1); \ + template \ + static typename boost::unordered::detail::sfinae< \ + typename X::tname, choice1>::type \ + test(choice1); \ \ - template \ - static choice2::type test(choice2); \ + template \ + static choice2::type test(choice2); \ \ - struct DefaultWrap { typedef Default tname; }; \ + struct DefaultWrap { typedef Default tname; }; \ \ - enum { value = (1 == sizeof(test(choose()))) }; \ + enum { value = (1 == sizeof(test(choose()))) }; \ \ - typedef typename boost::detail::if_true:: \ - BOOST_NESTED_TEMPLATE then \ - ::type::tname type; \ - } + typedef typename boost::detail::if_true:: \ + BOOST_NESTED_TEMPLATE then \ + ::type::tname type; \ + } -#endif +# endif - #define BOOST_UNORDERED_DEFAULT_TYPE(T,tname, arg) \ - typename default_type_ ## tname::type +# define BOOST_UNORDERED_DEFAULT_TYPE(T,tname, arg) \ + typename default_type_ ## tname::type BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(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_swap); -#if BOOST_UNORDERED_HAVE_CALL_DETECTION +# if !defined(BOOST_NO_SFINAE_EXPR) + template BOOST_UNORDERED_HAS_FUNCTION( select_on_container_copy_construction, U const, (), 0 @@ -324,18 +284,33 @@ namespace boost { namespace unordered { namespace detail { max_size, U const, (), 0 ); +# if defined(BOOST_UNORDERED_VARIADIC_MOVE) + + template + BOOST_UNORDERED_HAS_FUNCTION( + construct, U, ( + boost::unordered::detail::make(), + boost::unordered::detail::make()...), 2 + ); + +# else + template BOOST_UNORDERED_HAS_FUNCTION( - construct, U, ( - boost::unordered::detail::make(), - boost::unordered::detail::make()), 2 + construct, U, ( + boost::unordered::detail::make(), + boost::unordered::detail::make()), 2 ); +# endif + template BOOST_UNORDERED_HAS_FUNCTION( destroy, U, (boost::unordered::detail::make()), 1 ); -#else + +# else + template BOOST_UNORDERED_HAS_MEMBER(select_on_container_copy_construction); @@ -347,7 +322,8 @@ namespace boost { namespace unordered { namespace detail { template BOOST_UNORDERED_HAS_MEMBER(destroy); -#endif + +# endif template inline typename boost::enable_if_c< @@ -415,7 +391,7 @@ namespace boost { namespace unordered { namespace detail { // 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); } // 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, // const_void_pointer hint) // { return DEFAULT_FUNC(allocate, pointer)(a, n, hint); } - + static void deallocate(Alloc& a, pointer p, size_type n) { a.deallocate(p, n); } public: - // Only supporting the basic copy constructor for now. +# if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT + + template + static typename boost::enable_if_c< + boost::unordered::detail::has_construct + ::value>::type + construct(Alloc& a, T* p, Args&&... x) + { + a.construct(p, boost::forward(x)...); + } + + template + static typename boost::disable_if_c< + boost::unordered::detail::has_construct + ::value>::type + construct(Alloc&, T* p, Args&&... x) + { + new ((void*) p) T(boost::forward(x)...); + } + + template + static typename boost::enable_if_c< + boost::unordered::detail::has_destroy::value>::type + destroy(Alloc& a, T* p) + { + a.destroy(p); + } + + template + static typename boost::disable_if_c< + boost::unordered::detail::has_destroy::value>::type + destroy(Alloc&, T* p) + { + boost::unordered::detail::destroy(p); + } + +# elif !defined(BOOST_NO_SFINAE_EXPR) template static typename boost::enable_if_c< @@ -463,19 +475,67 @@ namespace boost { namespace unordered { namespace detail { 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 + static typename boost::enable_if_c< + boost::unordered::detail::has_construct::value && + boost::is_same::value + >::type + construct(Alloc& a, T* p, T const& x) + { + a.construct(p, x); + } + + template + static typename boost::disable_if_c< + boost::unordered::detail::has_construct::value && + boost::is_same::value + >::type + construct(Alloc&, T* p, T const& x) + { + new ((void*) p) T(x); + } + + template + static typename boost::enable_if_c< + boost::unordered::detail::has_destroy::value && + boost::is_same::value + >::type + destroy(Alloc& a, T* p) + { + a.destroy(p); + } + + template + static typename boost::disable_if_c< + boost::unordered::detail::has_destroy::value && + boost::is_same::value + >::type + destroy(Alloc&, T* p) + { + boost::unordered::detail::destroy(p); + } + +# endif + static size_type max_size(const Alloc& a) { return boost::unordered::detail::call_max_size(a); } // Allocator propagation on construction - + static Alloc select_on_container_copy_construction(Alloc const& rhs) { return boost::unordered::detail:: call_select_on_container_copy_construction(rhs); } - + // Allocator propagation on assignment and swap. // Return true if lhs is modified. typedef BOOST_UNORDERED_DEFAULT_TYPE( @@ -488,12 +548,117 @@ namespace boost { namespace unordered { namespace detail { Alloc,propagate_on_container_swap,false_type) propagate_on_container_swap; }; +}}} -#undef BOOST_UNORDERED_DEFAULT_TYPE_TMPLT -#undef BOOST_UNORDERED_DEFAULT_TYPE +# undef BOOST_UNORDERED_DEFAULT_TYPE_TMPLT +# undef BOOST_UNORDERED_DEFAULT_TYPE + +//////////////////////////////////////////////////////////////////////////////// +// +// std::allocator_traits + +#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 + +# include + +# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1 + +namespace boost { namespace unordered { namespace detail { + + template + struct allocator_traits : std::allocator_traits {}; + + template + struct rebind_wrap + { + typedef typename std::allocator_traits:: + template rebind_alloc type; + }; +}}} + +//////////////////////////////////////////////////////////////////////////////// +// +// boost::container::allocator_traits + +#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2 + +# include + +# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0 + +namespace boost { namespace unordered { namespace detail { + + template + struct allocator_traits : + boost::container::allocator_traits {}; + + template + struct rebind_wrap : + boost::container::allocator_traits:: + template portable_rebind_alloc + {}; + +}}} + +#else + +#error "Invalid BOOST_UNORDERED_USE_ALLOCATOR_TRAITS value." #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 + inline void construct_node(Alloc& a, T* p, BOOST_UNORDERED_EMPLACE_ARGS) + { + boost::unordered::detail::allocator_traits::construct( + a, p, BOOST_UNORDERED_EMPLACE_FORWARD); + } + + template + inline void destroy_node(Alloc& a, T* p) + { + boost::unordered::detail::allocator_traits::destroy(a, p); + } + +#else + + template + inline void construct_node(Alloc& a, T* p, BOOST_UNORDERED_EMPLACE_ARGS) + { + boost::unordered::detail::allocator_traits::construct(a, p, T()); + try { + boost::unordered::detail::construct_impl( + p->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); + } catch(...) { + boost::unordered::detail::allocator_traits::destroy(a, p); + throw; + } + } + + template + inline void destroy_node(Alloc& a, T* p) + { + boost::unordered::detail::destroy(p->value_ptr()); + boost::unordered::detail::allocator_traits::destroy(a, p); + } + +#endif + + //////////////////////////////////////////////////////////////////////////// + // // array_constructor // // Allocate and construct an array in an exception safe manner, and @@ -549,7 +714,9 @@ namespace boost { namespace unordered { namespace detail { ptr_ = pointer(); return p; } + private: + array_constructor(array_constructor const&); array_constructor& operator=(array_constructor const&); }; diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 9ee1343c..8f0054f3 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -13,7 +13,6 @@ #include #include -#include #include #include #include @@ -54,16 +53,14 @@ namespace boost { namespace unordered { namespace detail { node_allocator& alloc_; node_pointer node_; - bool node_constructed_; - bool value_constructed_; + bool constructed_; public: node_constructor(node_allocator& n) : alloc_(n), node_(), - node_constructed_(false), - value_constructed_(false) + constructed_(false) { } @@ -74,26 +71,40 @@ namespace boost { namespace unordered { namespace detail { template void construct_value(BOOST_UNORDERED_EMPLACE_ARGS) { - BOOST_ASSERT(node_ && node_constructed_ && !value_constructed_); - boost::unordered::detail::construct_impl( - node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); - value_constructed_ = true; + BOOST_ASSERT(node_ && !constructed_); + boost::unordered::detail::construct_node(alloc_, + boost::addressof(*node_), BOOST_UNORDERED_EMPLACE_FORWARD); + node_->init(static_cast(node_)); + constructed_ = true; } template void construct_value2(BOOST_FWD_REF(A0) a0) { - BOOST_ASSERT(node_ && node_constructed_ && !value_constructed_); - boost::unordered::detail::construct_impl2( - node_->value_ptr(), boost::forward(a0)); - value_constructed_ = true; + BOOST_ASSERT(node_ && !constructed_); +# if defined(BOOST_UNORDERED_VARIADIC_MOVE) + boost::unordered::detail::construct_node(alloc_, + boost::addressof(*node_), boost::forward(a0)); +# else + boost::unordered::detail::construct_node(alloc_, + boost::addressof(*node_), + boost::unordered::detail::create_emplace_args( + boost::forward(a0))); +# endif + constructed_ = true; + node_->init(static_cast(node_)); } value_type const& value() const { - BOOST_ASSERT(node_ && node_constructed_ && value_constructed_); + BOOST_ASSERT(node_ && constructed_); return node_->value(); } + node_pointer get() + { + return node_; + } + // no throw node_pointer release() { @@ -111,12 +122,8 @@ namespace boost { namespace unordered { namespace detail { node_constructor::~node_constructor() { if (node_) { - if (value_constructed_) { - boost::unordered::detail::destroy(node_->value_ptr()); - } - - if (node_constructed_) { - node_allocator_traits::destroy(alloc_, + if (constructed_) { + boost::unordered::detail::destroy_node(alloc_, boost::addressof(*node_)); } @@ -128,24 +135,13 @@ namespace boost { namespace unordered { namespace detail { void node_constructor::construct_node() { if(!node_) { - node_constructed_ = false; - value_constructed_ = false; - + constructed_ = false; node_ = node_allocator_traits::allocate(alloc_, 1); - - node_allocator_traits::construct(alloc_, - boost::addressof(*node_), node()); - node_->init(static_cast(node_)); - node_constructed_ = true; } - else { - BOOST_ASSERT(node_constructed_); - - if (value_constructed_) - { - boost::unordered::detail::destroy(node_->value_ptr()); - value_constructed_ = false; - } + else if (constructed_) { + boost::unordered::detail::destroy_node(alloc_, + boost::addressof(*node_)); + constructed_ = false; } } @@ -183,6 +179,16 @@ namespace boost { namespace unordered { namespace detail { enum { extra_node = false }; }; + + template + struct node_base + { + typedef LinkPointer link_pointer; + link_pointer next_; + + node_base() : next_() {} + }; + }}} namespace boost { namespace unordered { namespace iterator_detail { @@ -718,6 +724,14 @@ namespace boost { namespace unordered { namespace detail { node_constructor a(this->node_alloc()); 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( + boost::addressof(*a.get())), + typename node::node_base()); + (constructor.get() + static_cast(this->bucket_count_))->next_ = a.release(); @@ -762,9 +776,8 @@ namespace boost { namespace unordered { namespace detail { inline void delete_node(c_iterator n) { - boost::unordered::detail::destroy(n.node_->value_ptr()); - node_allocator_traits::destroy(node_alloc(), - boost::addressof(*n.node_)); + boost::unordered::detail::destroy_node( + node_alloc(), boost::addressof(*n.node_)); node_allocator_traits::deallocate(node_alloc(), n.node_, 1); --size_; } @@ -786,7 +799,8 @@ namespace boost { namespace unordered { namespace detail { inline void delete_extra_node(bucket_pointer) {} 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(boost::addressof(*n))); 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 // the bucket pointers. - void fix_buckets(bucket_pointer bucket, + void fix_buckets(bucket_pointer this_bucket, previous_pointer prev, node_pointer next) { if (!next) { - if (bucket->next_ == prev) bucket->next_ = node_pointer(); + if (this_bucket->next_ == prev) + this_bucket->next_ = node_pointer(); } else { bucket_pointer next_bucket = this->get_bucket( policy::to_bucket(this->bucket_count_, next->hash_)); - if (next_bucket != bucket) + if (next_bucket != this_bucket) { next_bucket->next_ = prev; - if (bucket->next_ == prev) bucket->next_ = node_pointer(); + if (this_bucket->next_ == prev) + this_bucket->next_ = node_pointer(); } } } diff --git a/include/boost/unordered/detail/emplace_args.hpp b/include/boost/unordered/detail/emplace_args.hpp index be2339fe..60b6cb9c 100644 --- a/include/boost/unordered/detail/emplace_args.hpp +++ b/include/boost/unordered/detail/emplace_args.hpp @@ -12,6 +12,7 @@ # pragma once #endif +#include #include #include #include @@ -21,7 +22,10 @@ #include #include #include +#include #include +#include +#include #include #if !defined(BOOST_NO_0X_HDR_TUPLE) @@ -45,6 +49,38 @@ namespace boost { namespace unordered { namespace detail { + //////////////////////////////////////////////////////////////////////////// + // Bits and pieces for implementing traits + + template typename boost::add_lvalue_reference::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 + no_type is_private_type(T const&); + yes_type is_private_type(private_type const&); + + struct convert_from_anything { + template + convert_from_anything(T const&); + }; + //////////////////////////////////////////////////////////////////////////// // emplace_args // @@ -75,7 +111,7 @@ namespace boost { namespace unordered { namespace detail { { \ BOOST_PP_REPEAT_##z(n, BOOST_UNORDERED_EARGS_MEMBER, _) \ 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, _) \ {} \ \ @@ -85,12 +121,12 @@ namespace boost { namespace unordered { namespace detail { inline BOOST_PP_CAT(emplace_args, n) < \ BOOST_PP_ENUM_PARAMS_Z(z, n, A) \ > 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_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; \ } @@ -102,7 +138,7 @@ namespace boost { namespace unordered { namespace detail { #define BOOST_UNORDERED_EARGS_INIT(z, n, _) \ BOOST_PP_CAT(a, n)( \ - boost::forward(BOOST_PP_CAT(a, n))) + boost::forward(BOOST_PP_CAT(b, n))) #else @@ -112,7 +148,7 @@ namespace boost { namespace unordered { namespace detail { BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, 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 diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index ba58c8a2..6df3c03a 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -12,7 +12,6 @@ #endif #include -#include #include namespace boost { namespace unordered { namespace detail { @@ -23,20 +22,40 @@ namespace boost { namespace unordered { namespace detail { template struct grouped_node : + boost::unordered::detail::node_base< + typename ::boost::unordered::detail::rebind_wrap< + A, grouped_node >::type::pointer + >, boost::unordered::detail::value_base { typedef typename ::boost::unordered::detail::rebind_wrap< A, grouped_node >::type::pointer link_pointer; + typedef boost::unordered::detail::node_base node_base; - link_pointer next_; link_pointer group_prev_; std::size_t hash_; +#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT + 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() : - next_(), + node_base(), group_prev_(), hash_(0) {} +#endif void init(link_pointer self) { @@ -50,16 +69,33 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::ptr_bucket { typedef boost::unordered::detail::ptr_bucket bucket_base; + typedef bucket_base node_base; typedef ptr_bucket* link_pointer; link_pointer group_prev_; std::size_t hash_; +#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT + 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() : bucket_base(), group_prev_(0), hash_(0) {} +#endif void init(link_pointer self) { @@ -221,12 +257,12 @@ namespace boost { namespace unordered { namespace detail { template iterator find_node_impl( - std::size_t hash, + std::size_t key_hash, Key const& k, Pred const& eq) const { 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); for (;;) @@ -234,7 +270,7 @@ namespace boost { namespace unordered { namespace detail { if (!n.node_) return n; std::size_t node_hash = n.node_->hash_; - if (hash == node_hash) + if (key_hash == node_hash) { if (eq(k, this->get_key(*n))) return n; @@ -256,14 +292,14 @@ namespace boost { namespace unordered { namespace detail { iterator n = this->find_node(k); if (!n.node_) return 0; - std::size_t count = 0; + std::size_t x = 0; node_pointer it = n.node_; do { it = static_cast(it->group_prev_); - ++count; + ++x; } while(it != n.node_); - return count; + return x; } std::pair @@ -396,11 +432,11 @@ namespace boost { namespace unordered { namespace detail { inline iterator add_node( node_constructor& a, - std::size_t hash, + std::size_t key_hash, iterator pos) { node_pointer n = a.release(); - n->hash_ = hash; + n->hash_ = key_hash; if (pos.node_) { this->add_after_node(n, pos.node_); if (n->next_) { @@ -408,14 +444,14 @@ namespace boost { namespace unordered { namespace detail { this->bucket_count_, static_cast(n->next_)->hash_); 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; } } } else { bucket_pointer b = this->get_bucket( - policy::to_bucket(this->bucket_count_, hash)); + policy::to_bucket(this->bucket_count_, key_hash)); if (!b->next_) { @@ -444,20 +480,20 @@ namespace boost { namespace unordered { namespace detail { iterator emplace_impl(node_constructor& a) { key_type const& k = this->get_key(a.value()); - std::size_t hash = this->hash(k); - iterator position = this->find_node(hash, k); + std::size_t key_hash = this->hash(k); + iterator position = this->find_node(key_hash, k); // reserve has basic exception safety if the hash function // throws, strong otherwise. 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) { key_type const& k = this->get_key(a.value()); - std::size_t hash = this->hash(k); - this->add_node(a, hash, this->find_node(hash, k)); + std::size_t key_hash = this->hash(k); + this->add_node(a, key_hash, this->find_node(key_hash, k)); } #if defined(BOOST_NO_RVALUE_REFERENCES) @@ -531,12 +567,12 @@ namespace boost { namespace unordered { namespace detail { { 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 = - policy::to_bucket(this->bucket_count_, hash); - bucket_pointer bucket = this->get_bucket(bucket_index); + policy::to_bucket(this->bucket_count_, key_hash); + bucket_pointer this_bucket = this->get_bucket(bucket_index); - previous_pointer prev = bucket->next_; + previous_pointer prev = this_bucket->next_; if (!prev) return 0; for (;;) @@ -547,7 +583,7 @@ namespace boost { namespace unordered { namespace detail { if (policy::to_bucket(this->bucket_count_, node_hash) != bucket_index) return 0; - if (node_hash == hash && + if (node_hash == key_hash && this->key_eq()(k, this->get_key( static_cast(prev->next_)->value()))) break; @@ -560,7 +596,7 @@ namespace boost { namespace unordered { namespace detail { static_cast(pos->group_prev_)->next_; node_pointer end = static_cast(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)); } @@ -570,11 +606,11 @@ namespace boost { namespace unordered { namespace detail { iterator next(r.node_); ++next; - bucket_pointer bucket = this->get_bucket( + bucket_pointer this_bucket = this->get_bucket( 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); @@ -713,7 +749,7 @@ namespace boost { namespace unordered { namespace detail { previous_pointer prev = dst.get_previous_start(); while (n.node_) { - std::size_t hash = n.node_->hash_; + std::size_t key_hash = n.node_->hash_; iterator group_end( static_cast( static_cast(n.node_->group_prev_)->next_ @@ -724,7 +760,7 @@ namespace boost { namespace unordered { namespace detail { node_pointer first_node = a.release(); node_pointer end = first_node; - first_node->hash_ = hash; + first_node->hash_ = key_hash; prev->next_ = static_cast(first_node); ++dst.size_; @@ -733,7 +769,7 @@ namespace boost { namespace unordered { namespace detail { a.construct_node(); a.construct_value2(*n); end = a.release(); - end->hash_ = hash; + end->hash_ = key_hash; add_after_node(end, first_node); ++dst.size_; } @@ -760,7 +796,7 @@ namespace boost { namespace unordered { namespace detail { previous_pointer prev = dst.get_previous_start(); while (n.node_) { - std::size_t hash = n.node_->hash_; + std::size_t key_hash = n.node_->hash_; iterator group_end( static_cast( static_cast(n.node_->group_prev_)->next_ @@ -771,7 +807,7 @@ namespace boost { namespace unordered { namespace detail { node_pointer first_node = a.release(); node_pointer end = first_node; - first_node->hash_ = hash; + first_node->hash_ = key_hash; prev->next_ = static_cast(first_node); ++dst.size_; @@ -780,7 +816,7 @@ namespace boost { namespace unordered { namespace detail { a.construct_node(); a.construct_value2(boost::move(*n)); end = a.release(); - end->hash_ = hash; + end->hash_ = key_hash; add_after_node(end, first_node); ++dst.size_; } diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 9e2f13c5..cbf62195 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -348,21 +348,21 @@ namespace boost { namespace unordered { namespace detail { template iterator generic_find_node( Key const& k, - Hash const& hash_function, + Hash const& hf, Pred const& eq) const { if (!this->size_) return iterator(); return static_cast(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( - std::size_t hash, + std::size_t key_hash, key_type const& k) const { if (!this->size_) return iterator(); return static_cast(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 @@ -387,6 +387,7 @@ namespace boost { namespace unordered { namespace detail { void reserve_for_insert(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->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 = this->min_buckets_for_size((std::max)(size, this->size_ + (this->size_ >> 1))); @@ -417,7 +420,7 @@ namespace boost { namespace unordered { namespace detail { // strong otherwise. template - void table::rehash(std::size_t min_buckets) + inline void table::rehash(std::size_t min_buckets) { using namespace std; @@ -437,6 +440,13 @@ namespace boost { namespace unordered { namespace detail { } } } + + template + inline void table::reserve(std::size_t num_elements) + { + rehash(static_cast( + std::ceil(static_cast(num_elements) / this->mlf_))); + } }}} #endif diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 84fef433..8628591e 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -12,31 +12,49 @@ #endif #include -#include #include #include #include namespace boost { namespace unordered { namespace detail { - template struct node; + template struct unique_node; template struct ptr_node; template struct table_impl; template - struct node : + struct unique_node : + boost::unordered::detail::node_base< + typename ::boost::unordered::detail::rebind_wrap< + A, unique_node >::type::pointer + >, boost::unordered::detail::value_base { typedef typename ::boost::unordered::detail::rebind_wrap< - A, node >::type::pointer link_pointer; + A, unique_node >::type::pointer link_pointer; + typedef boost::unordered::detail::node_base node_base; - link_pointer next_; std::size_t hash_; - node() : - next_(), +#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT + 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) {} +#endif void init(link_pointer) { @@ -49,14 +67,30 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::ptr_bucket { typedef boost::unordered::detail::ptr_bucket bucket_base; + typedef bucket_base node_base; typedef ptr_bucket* link_pointer; std::size_t hash_; +#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT + 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() : bucket_base(), hash_(0) {} +#endif void init(link_pointer) { @@ -69,7 +103,7 @@ namespace boost { namespace unordered { namespace detail { template struct pick_node2 { - typedef boost::unordered::detail::node node; + typedef boost::unordered::detail::unique_node node; typedef typename boost::unordered::detail::allocator_traits< typename boost::unordered::detail::rebind_wrap::type @@ -219,12 +253,12 @@ namespace boost { namespace unordered { namespace detail { template iterator find_node_impl( - std::size_t hash, + std::size_t key_hash, Key const& k, Pred const& eq) const { 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); for (;;) @@ -232,7 +266,7 @@ namespace boost { namespace unordered { namespace detail { if (!n.node_) return n; std::size_t node_hash = n.node_->hash_; - if (hash == node_hash) + if (key_hash == node_hash) { if (eq(k, this->get_key(*n))) return n; @@ -300,13 +334,13 @@ namespace boost { namespace unordered { namespace detail { inline iterator add_node( node_constructor& a, - std::size_t hash) + std::size_t key_hash) { node_pointer n = a.release(); - n->hash_ = hash; + n->hash_ = key_hash; bucket_pointer b = this->get_bucket( - policy::to_bucket(this->bucket_count_, hash)); + policy::to_bucket(this->bucket_count_, key_hash)); if (!b->next_) { @@ -336,8 +370,8 @@ namespace boost { namespace unordered { namespace detail { { typedef typename value_type::second_type mapped_type; - std::size_t hash = this->hash(k); - iterator pos = this->find_node(hash, k); + std::size_t key_hash = this->hash(k); + iterator pos = this->find_node(key_hash, k); if (pos.node_) return *pos; @@ -357,7 +391,7 @@ namespace boost { namespace unordered { namespace detail { #endif this->reserve_for_insert(this->size_ + 1); - return *add_node(a, hash); + return *add_node(a, key_hash); } #if defined(BOOST_NO_RVALUE_REFERENCES) @@ -397,8 +431,8 @@ namespace boost { namespace unordered { namespace detail { emplace_return emplace_impl(key_type const& k, BOOST_UNORDERED_EMPLACE_ARGS) { - std::size_t hash = this->hash(k); - iterator pos = this->find_node(hash, k); + std::size_t key_hash = this->hash(k); + iterator pos = this->find_node(key_hash, k); 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 // throws, strong otherwise. 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) { key_type const& k = this->get_key(a.value()); - std::size_t hash = this->hash(k); - iterator pos = this->find_node(hash, k); + std::size_t key_hash = this->hash(k); + iterator pos = this->find_node(key_hash, k); if (pos.node_) return emplace_return(pos, false); // reserve has basic exception safety if the hash function // throws, strong otherwise. 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 @@ -481,12 +515,12 @@ namespace boost { namespace unordered { namespace detail { void insert_range_empty(node_constructor& a, key_type const& k, InputIt i, InputIt j) { - std::size_t hash = this->hash(k); + std::size_t key_hash = this->hash(k); a.construct_node(); a.construct_value2(*i); this->reserve_for_insert(this->size_ + boost::unordered::detail::insert_size(i, j)); - this->add_node(a, hash); + this->add_node(a, key_hash); } template @@ -494,19 +528,19 @@ namespace boost { namespace unordered { namespace detail { InputIt i, InputIt j) { // No side effects in this initial code - std::size_t hash = this->hash(k); - iterator pos = this->find_node(hash, k); + std::size_t key_hash = this->hash(k); + iterator pos = this->find_node(key_hash, k); if (!pos.node_) { a.construct_node(); a.construct_value2(*i); - if(this->size_ + 1 >= this->max_load_) + if(this->size_ + 1 > this->max_load_) this->reserve_for_insert(this->size_ + boost::unordered::detail::insert_size(i, j)); // 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; - std::size_t hash = this->hash(k); + std::size_t key_hash = this->hash(k); std::size_t bucket_index = - policy::to_bucket(this->bucket_count_, hash); - bucket_pointer bucket = this->get_bucket(bucket_index); + policy::to_bucket(this->bucket_count_, key_hash); + bucket_pointer this_bucket = this->get_bucket(bucket_index); - previous_pointer prev = bucket->next_; + previous_pointer prev = this_bucket->next_; if (!prev) return 0; for (;;) @@ -547,7 +581,7 @@ namespace boost { namespace unordered { namespace detail { if (policy::to_bucket(this->bucket_count_, node_hash) != bucket_index) return 0; - if (node_hash == hash && + if (node_hash == key_hash && this->key_eq()(k, this->get_key( static_cast(prev->next_)->value()))) break; @@ -557,7 +591,7 @@ namespace boost { namespace unordered { namespace detail { node_pointer pos = static_cast(prev->next_); node_pointer end = static_cast(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)); } @@ -567,11 +601,11 @@ namespace boost { namespace unordered { namespace detail { iterator next(r.node_); ++next; - bucket_pointer bucket = this->get_bucket( + bucket_pointer this_bucket = this->get_bucket( 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); diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 7378b913..8e6621d4 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -515,6 +515,7 @@ namespace unordered float load_factor() const; void max_load_factor(float); void rehash(size_type); + void reserve(size_type); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) friend bool operator==( @@ -997,6 +998,7 @@ namespace unordered float load_factor() const; void max_load_factor(float); void rehash(size_type); + void reserve(size_type); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) friend bool operator==( @@ -1300,6 +1302,12 @@ namespace unordered table_.rehash(n); } + template + void unordered_map::reserve(size_type n) + { + table_.reserve(n); + } + template inline bool operator==( unordered_map const& m1, @@ -1606,6 +1614,12 @@ namespace unordered table_.rehash(n); } + template + void unordered_multimap::reserve(size_type n) + { + table_.reserve(n); + } + template inline bool operator==( unordered_multimap const& m1, diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 1d56c777..a85a1676 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -500,6 +500,7 @@ namespace unordered float load_factor() const; void max_load_factor(float); void rehash(size_type); + void reserve(size_type); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) friend bool operator==( @@ -972,6 +973,7 @@ namespace unordered float load_factor() const; void max_load_factor(float); void rehash(size_type); + void reserve(size_type); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) friend bool operator==( @@ -1226,6 +1228,12 @@ namespace unordered table_.rehash(n); } + template + void unordered_set::reserve(size_type n) + { + table_.reserve(n); + } + template inline bool operator==( unordered_set const& m1, @@ -1504,6 +1512,12 @@ namespace unordered table_.rehash(n); } + template + void unordered_multiset::reserve(size_type n) + { + table_.reserve(n); + } + template inline bool operator==( unordered_multiset const& m1, diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index bee732d4..624d4779 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -11,7 +11,7 @@ #pragma warning(disable:4512) // assignment operator could not be generated #endif -test::seed_t seed(12847); +test::seed_t initialize_seed(12847); template struct self_assign_base : public test::exception_base diff --git a/test/exception/constructor_exception_tests.cpp b/test/exception/constructor_exception_tests.cpp index 3a803651..9657bae0 100644 --- a/test/exception/constructor_exception_tests.cpp +++ b/test/exception/constructor_exception_tests.cpp @@ -9,7 +9,7 @@ template inline void avoid_unused_warning(T const&) {} -test::seed_t seed(91274); +test::seed_t initialize_seed(91274); struct objects { diff --git a/test/exception/copy_exception_tests.cpp b/test/exception/copy_exception_tests.cpp index 019410ba..57d17fac 100644 --- a/test/exception/copy_exception_tests.cpp +++ b/test/exception/copy_exception_tests.cpp @@ -8,7 +8,7 @@ template inline void avoid_unused_warning(T const&) {} -test::seed_t seed(73041); +test::seed_t initialize_seed(73041); template struct copy_test1 : public test::exception_base diff --git a/test/exception/erase_exception_tests.cpp b/test/exception/erase_exception_tests.cpp index 5d40995a..f761fcc3 100644 --- a/test/exception/erase_exception_tests.cpp +++ b/test/exception/erase_exception_tests.cpp @@ -8,7 +8,7 @@ #include "../helpers/invariants.hpp" #include "../helpers/helpers.hpp" -test::seed_t seed(835193); +test::seed_t initialize_seed(835193); template struct erase_test_base : public test::exception_base diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index fc962cec..1d3ee67a 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -11,7 +11,7 @@ #include #include -test::seed_t seed(747373); +test::seed_t initialize_seed(747373); template struct insert_test_base : public test::exception_base diff --git a/test/exception/rehash_exception_tests.cpp b/test/exception/rehash_exception_tests.cpp index 2a987867..0426e589 100644 --- a/test/exception/rehash_exception_tests.cpp +++ b/test/exception/rehash_exception_tests.cpp @@ -11,7 +11,7 @@ #include -test::seed_t seed(3298597); +test::seed_t initialize_seed(3298597); template struct rehash_test_base : public test::exception_base diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index 5fcab288..23f12476 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_exception_tests.cpp @@ -11,7 +11,7 @@ #pragma warning(disable:4512) // assignment operator could not be generated #endif -test::seed_t seed(9387); +test::seed_t initialize_seed(9387); template struct self_swap_base : public test::exception_base diff --git a/test/helpers/list.hpp b/test/helpers/list.hpp index 991404ee..5d02c2df 100644 --- a/test/helpers/list.hpp +++ b/test/helpers/list.hpp @@ -219,14 +219,14 @@ namespace test 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_; - while(*ptr != start.ptr_) { + while(*ptr != i.ptr_) { ptr = &(*ptr)->next_; } - while(*ptr != end.ptr_) { + while(*ptr != j.ptr_) { node* to_delete = *ptr; *ptr = (*ptr)->next_; --data_.size_; diff --git a/test/helpers/tracker.hpp b/test/helpers/tracker.hpp index bf56b356..fdb30815 100644 --- a/test/helpers/tracker.hpp +++ b/test/helpers/tracker.hpp @@ -124,8 +124,8 @@ namespace test : base() {} - explicit ordered(key_compare const& compare) - : base(compare) + explicit ordered(key_compare const& kc) + : base(kc) {} void compare(X const& x) @@ -143,10 +143,10 @@ namespace test } template - void insert_range(It begin, It end) { - while(begin != end) { - this->insert(*begin); - ++begin; + void insert_range(It b, It e) { + while(b != e) { + this->insert(*b); + ++b; } } }; diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index 5079f4d5..60a11306 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -22,7 +22,7 @@ namespace assign_tests { -test::seed_t seed(96785); +test::seed_t initialize_seed(96785); template void assign_tests1(T*, diff --git a/test/unordered/bucket_tests.cpp b/test/unordered/bucket_tests.cpp index c54d58d2..c9d74b99 100644 --- a/test/unordered/bucket_tests.cpp +++ b/test/unordered/bucket_tests.cpp @@ -21,7 +21,7 @@ namespace bucket_tests { -test::seed_t seed(54635); +test::seed_t initialize_seed(54635); template void tests(X* = 0, test::random_generator generator = test::default_generator) diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 53149061..e0536187 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -18,7 +18,7 @@ namespace constructor_tests { -test::seed_t seed(356730); +test::seed_t initialize_seed(356730); template void constructor_tests1(T*, diff --git a/test/unordered/copy_tests.cpp b/test/unordered/copy_tests.cpp index 5bbdb901..2fe79b1b 100644 --- a/test/unordered/copy_tests.cpp +++ b/test/unordered/copy_tests.cpp @@ -16,7 +16,7 @@ #include "../helpers/equivalent.hpp" #include "../helpers/invariants.hpp" -test::seed_t seed(9063); +test::seed_t initialize_seed(9063); namespace copy_tests { diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index 168e72a8..0d5a0b4a 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -21,7 +21,7 @@ namespace erase_tests { -test::seed_t seed(85638); +test::seed_t initialize_seed(85638); template void erase_tests1(Container*, diff --git a/test/unordered/find_tests.cpp b/test/unordered/find_tests.cpp index 2766b938..3999bae4 100644 --- a/test/unordered/find_tests.cpp +++ b/test/unordered/find_tests.cpp @@ -17,7 +17,7 @@ namespace find_tests { -test::seed_t seed(78937); +test::seed_t initialize_seed(78937); template void find_tests1(X*, test::random_generator generator = test::default_generator) diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index be8cdc30..2db28c24 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -21,7 +21,7 @@ namespace insert_tests { -test::seed_t seed(243432); +test::seed_t initialize_seed(243432); template void unique_insert_tests1(X*, diff --git a/test/unordered/load_factor_tests.cpp b/test/unordered/load_factor_tests.cpp index 59e91e98..92d56947 100644 --- a/test/unordered/load_factor_tests.cpp +++ b/test/unordered/load_factor_tests.cpp @@ -20,7 +20,7 @@ namespace load_factor_tests { -test::seed_t seed(783656); +test::seed_t initialize_seed(783656); template void set_load_factor_tests(X* = 0) diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index a99171f2..85159926 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -22,7 +22,7 @@ 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) #define BOOST_UNORDERED_TEST_MOVING 1 #else diff --git a/test/unordered/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index dbfb84c2..4f62ae9b 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -15,7 +15,7 @@ namespace rehash_tests { -test::seed_t seed(2974); +test::seed_t initialize_seed(2974); template bool postcondition(X const& x, BOOST_DEDUCED_TYPENAME X::size_type n) @@ -100,6 +100,75 @@ void rehash_test1(X* = 0, tracker.compare(x); } +template +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 v(i, generator); + + test::ordered tracker; + tracker.insert_range(v.begin(), v.end()); + + X x; + x.max_load_factor(random_mlf ? + static_cast(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::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 +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 v(i, generator); + + test::ordered tracker; + tracker.insert_range(v.begin(), v.end()); + + X x; + x.max_load_factor(random_mlf ? + static_cast(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::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_set_ptr; boost::unordered_multiset* int_multiset_ptr; boost::unordered_map* int_map_ptr; @@ -117,6 +186,12 @@ UNORDERED_TEST(rehash_empty_test3, UNORDERED_TEST(rehash_test1, ((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)) +) } diff --git a/test/unordered/swap_tests.cpp b/test/unordered/swap_tests.cpp index 9194a575..c67a15fa 100644 --- a/test/unordered/swap_tests.cpp +++ b/test/unordered/swap_tests.cpp @@ -25,7 +25,7 @@ namespace swap_tests { -test::seed_t seed(783472); +test::seed_t initialize_seed(783472); template void swap_test_impl(X& x1, X& x2)