From da6e8e8041228281a965599f488bf10afac8e763 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 14 Oct 2016 09:27:40 +0100 Subject: [PATCH 01/20] Better allocator rebind support --- include/boost/unordered/detail/allocate.hpp | 71 ++++++++++++++++++++- test/objects/cxx11_allocator.hpp | 6 +- test/objects/minimal.hpp | 2 +- 3 files changed, 72 insertions(+), 7 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index 319c9cd5..73cff77c 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -412,11 +412,69 @@ namespace boost { namespace unordered { namespace detail { namespace boost { namespace unordered { namespace detail { - // TODO: Does this match std::allocator_traits::rebind_alloc? + template + struct rebind_alloc; + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template class Alloc, + typename U, typename T, typename... Args> + struct rebind_alloc, T> + { + typedef Alloc type; + }; + +#else + + template < + template class Alloc, + typename U, typename T> + struct rebind_alloc, T> + { + typedef Alloc type; + }; + + template < + template class Alloc, + typename U, typename T, + typename A0> + struct rebind_alloc, T> + { + typedef Alloc type; + }; + + template < + template class Alloc, + typename U, typename T, + typename A0, typename A1> + struct rebind_alloc, T> + { + typedef Alloc type; + }; + +#endif + template struct rebind_wrap { - typedef typename Alloc::BOOST_NESTED_TEMPLATE rebind::other type; + template + static choice1::type test(choice1, + typename X::BOOST_NESTED_TEMPLATE rebind::other* = 0); + template + static choice2::type test(choice2, void* = 0); + + enum { value = (1 == sizeof(test(choose()))) }; + + struct fallback { + template + struct rebind { + typedef typename rebind_alloc::type other; + }; + }; + + typedef typename boost::detail::if_true:: + BOOST_NESTED_TEMPLATE then + ::type::BOOST_NESTED_TEMPLATE rebind::other type; }; # if defined(BOOST_MSVC) && BOOST_MSVC <= 1400 @@ -606,7 +664,14 @@ namespace boost { namespace unordered { namespace detail { typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, size_type, std::size_t) size_type; - // TODO: rebind_alloc and rebind_traits +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + template + using rebind_alloc = typename rebind_wrap::type; + + template + using rebind_traits = + boost::unordered::detail::allocator_traits >; +#endif static pointer allocate(Alloc& a, size_type n) { return a.allocate(n); } diff --git a/test/objects/cxx11_allocator.hpp b/test/objects/cxx11_allocator.hpp index 11f67808..1c638be2 100644 --- a/test/objects/cxx11_allocator.hpp +++ b/test/objects/cxx11_allocator.hpp @@ -201,9 +201,9 @@ namespace test public move_allocator_base, Flags { - template struct rebind { - typedef cxx11_allocator other; - }; + //template struct rebind { + // typedef cxx11_allocator other; + //}; explicit cxx11_allocator(int t = 0) : cxx11_allocator_base(t) diff --git a/test/objects/minimal.hpp b/test/objects/minimal.hpp index b876aa20..d8e8a7eb 100644 --- a/test/objects/minimal.hpp +++ b/test/objects/minimal.hpp @@ -447,7 +447,7 @@ namespace minimal { public: typedef T value_type; - template struct rebind { typedef cxx11_allocator other; }; + //template struct rebind { typedef cxx11_allocator other; }; cxx11_allocator() {} template cxx11_allocator(cxx11_allocator const&) {} From b907cee69170a90bd0cc6be146d815ce74ea3acb Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 14 Oct 2016 09:27:40 +0100 Subject: [PATCH 02/20] Use std::allocator_traits where available. Might have to revert this when implementing C++17 features. --- include/boost/unordered/detail/allocate.hpp | 5 ++--- test/Jamfile.v2 | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index 73cff77c..7a330ca2 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -237,9 +237,8 @@ BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, // 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 0 +# if !defined(BOOST_NO_CXX11_ALLOCATOR) +# 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 diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index f2207f89..269413b6 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -27,6 +27,9 @@ test-suite unordered [ run unordered/minimal_allocator.cpp ] [ run unordered/compile_set.cpp ] [ run unordered/compile_map.cpp ] + [ run unordered/compile_map.cpp : : + : BOOST_UNORDERED_USE_ALLOCATOR=0 + : compile_map_unordered_allocator ] [ run unordered/noexcept_tests.cpp ] [ run unordered/link_test_1.cpp unordered/link_test_2.cpp ] [ run unordered/incomplete_test.cpp ] From b5205e58aa7e5f4d50a7a7e9fe11a0f60ea65d5e Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 14 Oct 2016 09:29:38 +0100 Subject: [PATCH 03/20] Change log for allocator support. --- doc/changes.qbk | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changes.qbk b/doc/changes.qbk index 03fe1987..cd7cba86 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -293,5 +293,6 @@ C++11 support has resulted in some breaking changes: objects wouldn't match the container elements, so elements might be in the wrong bucket and equivalent elements would be incorrectly handled. * Various reference documentation improvements. +* Better allocator support ([ticket 12459]). [endsect] From 82438a513be0e6a18a47142fcfa332dee1e0c84b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 17 Oct 2016 07:54:06 +0100 Subject: [PATCH 04/20] Fix allocator traits macro --- test/Jamfile.v2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 269413b6..daea0e74 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -28,7 +28,7 @@ test-suite unordered [ run unordered/compile_set.cpp ] [ run unordered/compile_map.cpp ] [ run unordered/compile_map.cpp : : - : BOOST_UNORDERED_USE_ALLOCATOR=0 + : BOOST_UNORDERED_USE_ALLOCATOR_TRAITS=0 : compile_map_unordered_allocator ] [ run unordered/noexcept_tests.cpp ] [ run unordered/link_test_1.cpp unordered/link_test_2.cpp ] From 7da307c696cf0299826e150061c12e21d62c2cf1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 17 Oct 2016 07:54:06 +0100 Subject: [PATCH 05/20] Supply explicit test::cxx11_allocator::rebind for old GCC The rebind mechanism doesn't work for templates with multiple template parameters on old versions of GCC. But allocators written for that compiler will have an explicit rebind, so that should be acceptable. --- test/objects/cxx11_allocator.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/objects/cxx11_allocator.hpp b/test/objects/cxx11_allocator.hpp index 1c638be2..8ace50c5 100644 --- a/test/objects/cxx11_allocator.hpp +++ b/test/objects/cxx11_allocator.hpp @@ -201,9 +201,11 @@ namespace test public move_allocator_base, Flags { - //template struct rebind { - // typedef cxx11_allocator other; - //}; +#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 402000) + template struct rebind { + typedef cxx11_allocator other; + }; +#endif explicit cxx11_allocator(int t = 0) : cxx11_allocator_base(t) @@ -251,9 +253,11 @@ namespace test return tmp; } +#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 402000) template struct rebind { typedef cxx11_allocator other; }; +#endif explicit cxx11_allocator(int t = 0) : cxx11_allocator_base(t) From e03a8732a676ca7ff8b2e03aa9ad50c30a21cb81 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 17 Oct 2016 07:54:06 +0100 Subject: [PATCH 06/20] Use static_cast for allocator_traits::construct std::allocator::construct uses a C-style cast to void pointer, so it can accept const pointers, but allocator_traits::construct uses a static_cast by default, so const pointers don't work. This means the implementation needs to cast away const when constructing members of a std::pair. This wouldn't happen if piecewise construction was used, as the members could be constructed normally. --- include/boost/unordered/detail/allocate.hpp | 34 ++++++++++++++------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index 7a330ca2..3ff26151 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -703,7 +703,7 @@ namespace boost { namespace unordered { namespace detail { ::value>::type construct(Alloc&, T* p, BOOST_FWD_REF(Args)... x) { - new ((void*) p) T(boost::forward(x)...); + new (static_cast(p)) T(boost::forward(x)...); } template @@ -737,7 +737,7 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::has_construct::value>::type construct(Alloc&, T* p, T const& x) { - new ((void*) p) T(x); + new (static_cast(p)) T(x); } template @@ -779,7 +779,7 @@ namespace boost { namespace unordered { namespace detail { boost::is_same::value, void*>::type = 0) { - new ((void*) p) T(x); + new (static_cast(p)) T(x); } template @@ -1331,6 +1331,14 @@ namespace boost { namespace unordered { namespace detail { namespace func { return a.release(); } + // This is a bit nasty, when constructing the individual members + // of a std::pair, need to cast away 'const'. For modern compilers, + // should be able to use std::piecewise_construct instead. + template T* const_cast_pointer(T* x) { return x; } + template T* const_cast_pointer(T const* x) { + return const_cast(x); + } + // TODO: When possible, it might be better to use std::pair's // constructor for std::piece_construct with std::tuple. template @@ -1339,11 +1347,13 @@ namespace boost { namespace unordered { namespace detail { namespace func { { node_constructor a(alloc); a.create_node(); - boost::unordered::detail::func::call_construct( - alloc, boost::addressof(a.node_->value_ptr()->first), + boost::unordered::detail::func::call_construct(alloc, + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->first)), boost::forward(k)); - boost::unordered::detail::func::call_construct( - alloc, boost::addressof(a.node_->value_ptr()->second)); + boost::unordered::detail::func::call_construct(alloc, + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->second))); return a.release(); } @@ -1353,11 +1363,13 @@ namespace boost { namespace unordered { namespace detail { namespace func { { node_constructor a(alloc); a.create_node(); - boost::unordered::detail::func::call_construct( - alloc, boost::addressof(a.node_->value_ptr()->first), + boost::unordered::detail::func::call_construct(alloc, + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->first)), boost::forward(k)); - boost::unordered::detail::func::call_construct( - alloc, boost::addressof(a.node_->value_ptr()->second), + boost::unordered::detail::func::call_construct(alloc, + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->second)), boost::forward(m)); return a.release(); } From dad0d48c9ca6d6a013fa385bcf51af6187d7eacb Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 17 Oct 2016 07:54:06 +0100 Subject: [PATCH 07/20] Support containers with const value type Currently just storing the value without a const. Can do better with C++11 constructors, so maybe should do that, and cast away const on compilers without support. Another problem is that std::allocator doesn't compile for libstdc++ (and potentially other standard libraries), so boost::unordered_set can't compile. I'm not sure if I should work around that, as it means changing the type of the container (i.e. to boost::unordered_set>). --- include/boost/unordered/detail/buckets.hpp | 31 ------------------- include/boost/unordered/detail/equivalent.hpp | 6 ++-- include/boost/unordered/detail/unique.hpp | 6 ++-- test/unordered/compile_map.cpp | 8 ++--- test/unordered/compile_set.cpp | 4 +-- 5 files changed, 14 insertions(+), 41 deletions(-) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 31e1ee59..e0835c56 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -359,21 +359,6 @@ namespace boost { namespace unordered { namespace detail { template inline node_pointer copy_of(T const& v) { - if (nodes_) { - node_tmp a(pop_node(), constructor_.alloc_); - a.node_->value() = v; - return a.release(); - } - else { - constructor_.create_node(); - boost::unordered::detail::func::call_construct( - constructor_.alloc_, constructor_.node_->value_ptr(), v); - return constructor_.release(); - } - } - - template - inline node_pointer copy_of(std::pair const& v) { if (nodes_) { constructor_.reclaim(pop_node()); } @@ -387,22 +372,6 @@ namespace boost { namespace unordered { namespace detail { template inline node_pointer move_copy_of(T& v) { - if (nodes_) { - node_tmp a(pop_node(), constructor_.alloc_); - a.node_->value() = boost::move(v); - return a.release(); - } - else { - constructor_.create_node(); - boost::unordered::detail::func::call_construct( - constructor_.alloc_, constructor_.node_->value_ptr(), - boost::move(v)); - return constructor_.release(); - } - } - - template - inline node_pointer move_copy_of(std::pair& v) { if (nodes_) { constructor_.reclaim(pop_node()); } diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 5835884a..76825f20 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -110,9 +110,11 @@ namespace boost { namespace unordered { namespace detail { template struct pick_grouped_node { + typedef typename boost::remove_const::type nonconst; + typedef boost::unordered::detail::allocator_traits< typename boost::unordered::detail::rebind_wrap >::type + boost::unordered::detail::grouped_ptr_node >::type > tentative_node_traits; typedef boost::unordered::detail::allocator_traits< @@ -120,7 +122,7 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::ptr_bucket >::type > tentative_bucket_traits; - typedef pick_grouped_node2 pick; diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index db397980..eb26c232 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -106,9 +106,11 @@ namespace boost { namespace unordered { namespace detail { template struct pick_node { + typedef typename boost::remove_const::type nonconst; + typedef boost::unordered::detail::allocator_traits< typename boost::unordered::detail::rebind_wrap >::type + boost::unordered::detail::ptr_node >::type > tentative_node_traits; typedef boost::unordered::detail::allocator_traits< @@ -116,7 +118,7 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::ptr_bucket >::type > tentative_bucket_traits; - typedef pick_node2 pick; diff --git a/test/unordered/compile_map.cpp b/test/unordered/compile_map.cpp index ebd944ea..f42da0de 100644 --- a/test/unordered/compile_map.cpp +++ b/test/unordered/compile_map.cpp @@ -24,15 +24,15 @@ template class boost::unordered_map< std::equal_to, test::minimal::allocator > >; template class boost::unordered_multimap< - int, - int, + int const, + int const, boost::hash, std::equal_to, test::minimal::allocator > >; template class boost::unordered_map< - test::minimal::assignable, - test::minimal::default_assignable, + test::minimal::assignable const, + test::minimal::default_assignable const, test::minimal::hash, test::minimal::equal_to, test::minimal::allocator >; diff --git a/test/unordered/compile_set.cpp b/test/unordered/compile_set.cpp index 5c622902..a95ab007 100644 --- a/test/unordered/compile_set.cpp +++ b/test/unordered/compile_set.cpp @@ -23,13 +23,13 @@ template class boost::unordered_set< std::equal_to, test::minimal::allocator >; template class boost::unordered_multiset< - int, + int const, boost::hash, std::equal_to, test::minimal::allocator >; template class boost::unordered_set< - test::minimal::assignable, + test::minimal::assignable const, test::minimal::hash, test::minimal::equal_to, test::minimal::allocator >; From ad2256b13cba38bdcedc1fe85cfb9c15114c969d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 22 Oct 2016 09:42:56 +0100 Subject: [PATCH 08/20] Add const cast for piecewise construction --- include/boost/unordered/detail/allocate.hpp | 34 +++++++++++++-------- test/unordered/compile_tests.hpp | 3 ++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index 3ff26151..137214d4 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -88,6 +88,16 @@ namespace boost { namespace unordered { namespace detail { convert_from_anything(T const&); }; + namespace func { + // This is a bit nasty, when constructing the individual members + // of a std::pair, need to cast away 'const'. For modern compilers, + // should be able to use std::piecewise_construct instead. + template T* const_cast_pointer(T* x) { return x; } + template T* const_cast_pointer(T const* x) { + return const_cast(x); + } + } + //////////////////////////////////////////////////////////////////////////// // emplace_args // @@ -1104,9 +1114,13 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) BOOST_FWD_REF(A0), BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { boost::unordered::detail::func::construct_from_tuple(alloc, - boost::addressof(address->first), boost::forward(a1)); + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->first)), + boost::forward(a1)); boost::unordered::detail::func::construct_from_tuple(alloc, - boost::addressof(address->second), boost::forward(a2)); + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->second)), + boost::forward(a2)); } #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES @@ -1176,9 +1190,13 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) typename enable_if, void*>::type = 0) { boost::unordered::detail::func::construct_from_tuple(alloc, - boost::addressof(address->first), args.a1); + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->first)), + args.a1); boost::unordered::detail::func::construct_from_tuple(alloc, - boost::addressof(address->second), args.a2); + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->second)), + args.a2); } #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES @@ -1331,14 +1349,6 @@ namespace boost { namespace unordered { namespace detail { namespace func { return a.release(); } - // This is a bit nasty, when constructing the individual members - // of a std::pair, need to cast away 'const'. For modern compilers, - // should be able to use std::piecewise_construct instead. - template T* const_cast_pointer(T* x) { return x; } - template T* const_cast_pointer(T const* x) { - return const_cast(x); - } - // TODO: When possible, it might be better to use std::pair's // constructor for std::piece_construct with std::tuple. template diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 7e475432..9e5dba30 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -247,6 +247,9 @@ void unordered_map_test(X& r, Key const& k, T const& v) r.emplace(k, v); r.emplace(k_lvalue, v_lvalue); r.emplace(rvalue(k), rvalue(v)); + + r.emplace(boost::unordered::piecewise_construct, + boost::make_tuple(k), boost::make_tuple(v)); } template From 6071f9a08b514825c7ab9ad2a54384796ad8180a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 22 Oct 2016 09:49:14 +0100 Subject: [PATCH 09/20] Stop testing no arg emplace when not available --- test/unordered/insert_tests.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 3f13ea0f..a3384652 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -434,6 +434,7 @@ void move_emplace_tests(X*, test::random_generator generator) template void default_emplace_tests(X*, test::random_generator) { +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) std::cerr<<"emplace() tests.\n"; bool is_unique = test::has_unique_keys::value; @@ -464,6 +465,7 @@ void default_emplace_tests(X*, test::random_generator) BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1u : 2u)); BOOST_TEST(*x.equal_range(test::get_key(y)).first == y); +#endif } template From 9772c01161e2bbfb93127416c6c5429b51b55e30 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 22 Oct 2016 10:04:36 +0100 Subject: [PATCH 10/20] Replace several uses of iterators with node pointers. Which is to some extent going in circles, as this is how the containers were originally implemented. But I think this is cleaner. It also fixes a minor problem where the internal and external iterator types are different for some containers, as the external iterators are all const. --- include/boost/unordered/detail/buckets.hpp | 14 +- include/boost/unordered/detail/equivalent.hpp | 156 +++++++++--------- include/boost/unordered/detail/table.hpp | 33 ++-- include/boost/unordered/detail/unique.hpp | 134 ++++++++------- include/boost/unordered/unordered_map.hpp | 28 ++-- include/boost/unordered/unordered_set.hpp | 14 +- 6 files changed, 196 insertions(+), 183 deletions(-) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index e0835c56..b857bfd6 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -61,7 +61,6 @@ namespace boost { namespace unordered { namespace iterator_detail { private: #endif typedef typename Node::node_pointer node_pointer; - typedef boost::unordered::iterator_detail::iterator n_iterator; node_pointer ptr_; std::size_t bucket_; std::size_t bucket_count_; @@ -72,8 +71,8 @@ namespace boost { namespace unordered { namespace iterator_detail { l_iterator() BOOST_NOEXCEPT : ptr_() {} - l_iterator(n_iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT - : ptr_(x.node_), bucket_(b), bucket_count_(c) {} + l_iterator(node_pointer n, std::size_t b, std::size_t c) BOOST_NOEXCEPT + : ptr_(n), bucket_(b), bucket_count_(c) {} value_type& operator*() const { return ptr_->value(); @@ -120,7 +119,6 @@ namespace boost { namespace unordered { namespace iterator_detail { private: typedef typename Node::node_pointer node_pointer; - typedef boost::unordered::iterator_detail::iterator n_iterator; node_pointer ptr_; std::size_t bucket_; std::size_t bucket_count_; @@ -131,8 +129,8 @@ namespace boost { namespace unordered { namespace iterator_detail { cl_iterator() BOOST_NOEXCEPT : ptr_() {} - cl_iterator(n_iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT : - ptr_(x.node_), bucket_(b), bucket_count_(c) {} + cl_iterator(node_pointer n, std::size_t b, std::size_t c) BOOST_NOEXCEPT : + ptr_(n), bucket_(b), bucket_count_(c) {} cl_iterator(boost::unordered::iterator_detail::l_iterator< Node, Policy> const& x) BOOST_NOEXCEPT : @@ -186,10 +184,6 @@ namespace boost { namespace unordered { namespace iterator_detail { #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template friend struct boost::unordered::iterator_detail::c_iterator; - template - friend struct boost::unordered::iterator_detail::l_iterator; - template - friend struct boost::unordered::iterator_detail::cl_iterator; template friend struct boost::unordered::detail::table; template diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 76825f20..16fc1f10 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -188,48 +188,58 @@ namespace boost { namespace unordered { namespace detail { this->move_init(x); } + // Node functions. + + static inline node_pointer next_node(link_pointer n) { + return static_cast(n->next_); + } + + static inline node_pointer next_group(node_pointer n) { + return static_cast(n->group_prev_->next_); + } + // Accessors template - iterator find_node_impl( + node_pointer find_node_impl( std::size_t key_hash, Key const& k, Pred const& eq) const { std::size_t bucket_index = this->hash_to_bucket(key_hash); - iterator n = this->begin(bucket_index); + node_pointer n = this->begin(bucket_index); for (;;) { - if (!n.node_) return n; + if (!n) return n; - std::size_t node_hash = n.node_->hash_; + std::size_t node_hash = n->hash_; if (key_hash == node_hash) { - if (eq(k, this->get_key(*n))) + if (eq(k, this->get_key(n->value()))) return n; } else { if (this->hash_to_bucket(node_hash) != bucket_index) - return iterator(); + return node_pointer(); } - n = iterator(n.node_->group_prev_->next_); + n = next_group(n); } } std::size_t count(key_type const& k) const { - iterator n = this->find_node(k); - if (!n.node_) return 0; + node_pointer n = this->find_node(k); + if (!n) return 0; std::size_t x = 0; - node_pointer it = n.node_; + node_pointer it = n; do { it = it->group_prev_; ++x; - } while(it != n.node_); + } while(it != n); return x; } @@ -237,9 +247,8 @@ namespace boost { namespace unordered { namespace detail { std::pair equal_range(key_type const& k) const { - iterator n = this->find_node(k); - return std::make_pair( - n, n.node_ ? iterator(n.node_->group_prev_->next_) : n); + node_pointer n = this->find_node(k); + return std::make_pair(iterator(n), iterator(n ? next_group(n) : n)); } // Equality @@ -248,12 +257,12 @@ namespace boost { namespace unordered { namespace detail { { if(this->size_ != other.size_) return false; - for(iterator n1 = this->begin(); n1.node_;) + for(iterator n1(this->begin()); n1.node_;) { - iterator n2 = other.find_matching_node(n1); + iterator n2(other.find_matching_node(n1)); if (!n2.node_) return false; - iterator end1(n1.node_->group_prev_->next_); - iterator end2(n2.node_->group_prev_->next_); + iterator end1(next_group(n1.node_)); + iterator end2(next_group(n2.node_)); if (!group_equals(n1, end1, n2, end2)) return false; n1 = end1; } @@ -336,17 +345,17 @@ namespace boost { namespace unordered { namespace detail { pos->group_prev_ = n; } - inline iterator add_node( + inline node_pointer add_node( node_pointer n, std::size_t key_hash, - iterator pos) + node_pointer pos) { n->hash_ = key_hash; - if (pos.node_) { - this->add_to_node_group(n, pos.node_); + if (pos) { + this->add_to_node_group(n, pos); if (n->next_) { std::size_t next_bucket = this->hash_to_bucket( - static_cast(n->next_)->hash_); + next_node(n)->hash_); if (next_bucket != this->hash_to_bucket(key_hash)) { this->get_bucket(next_bucket)->next_ = n; } @@ -362,7 +371,7 @@ namespace boost { namespace unordered { namespace detail { if (start_node->next_) { this->get_bucket(this->hash_to_bucket( - static_cast(start_node->next_)->hash_ + next_node(start_node)->hash_ ))->next_ = n; } @@ -377,10 +386,10 @@ namespace boost { namespace unordered { namespace detail { } } ++this->size_; - return iterator(n); + return n; } - inline iterator add_using_hint( + inline node_pointer add_using_hint( node_pointer n, node_pointer hint) { @@ -388,13 +397,13 @@ namespace boost { namespace unordered { namespace detail { this->add_to_node_group(n, hint); if (n->next_ != hint && n->next_) { std::size_t next_bucket = this->hash_to_bucket( - static_cast(n->next_)->hash_); + next_node(n)->hash_); if (next_bucket != this->hash_to_bucket(n->hash_)) { this->get_bucket(next_bucket)->next_ = n; } } ++this->size_; - return iterator(n); + return n; } @@ -451,9 +460,9 @@ namespace boost { namespace unordered { namespace detail { node_tmp a(n, this->node_alloc()); key_type const& k = this->get_key(a.node_->value()); std::size_t key_hash = this->hash(k); - iterator position = this->find_node(key_hash, k); + node_pointer position = this->find_node(key_hash, k); this->reserve_for_insert(this->size_ + 1); - return this->add_node(a.release(), key_hash, position); + return iterator(this->add_node(a.release(), key_hash, position)); } iterator emplace_hint_impl(c_iterator hint, node_pointer n) @@ -462,13 +471,13 @@ namespace boost { namespace unordered { namespace detail { key_type const& k = this->get_key(a.node_->value()); if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { this->reserve_for_insert(this->size_ + 1); - return this->add_using_hint(a.release(), hint.node_); + return iterator(this->add_using_hint(a.release(), hint.node_)); } else { std::size_t key_hash = this->hash(k); - iterator position = this->find_node(key_hash, k); + node_pointer position = this->find_node(key_hash, k); this->reserve_for_insert(this->size_ + 1); - return this->add_node(a.release(), key_hash, position); + return iterator(this->add_node(a.release(), key_hash, position)); } } @@ -477,7 +486,7 @@ namespace boost { namespace unordered { namespace detail { node_tmp a(n, this->node_alloc()); key_type const& k = this->get_key(a.node_->value()); std::size_t key_hash = this->hash(k); - iterator position = this->find_node(key_hash, k); + node_pointer position = this->find_node(key_hash, k); this->add_node(a.release(), key_hash, position); } @@ -535,21 +544,21 @@ namespace boost { namespace unordered { namespace detail { link_pointer prev = this->get_previous_start(bucket_index); if (!prev) return 0; + node_pointer first_node; + for (;;) { if (!prev->next_) return 0; - std::size_t node_hash = - static_cast(prev->next_)->hash_; + first_node = next_node(prev); + std::size_t node_hash = first_node->hash_; if (this->hash_to_bucket(node_hash) != bucket_index) return 0; if (node_hash == key_hash && - this->key_eq()(k, this->get_key( - static_cast(prev->next_)->value()))) + this->key_eq()(k, this->get_key(first_node->value()))) break; - prev = static_cast(prev->next_)->group_prev_; + prev = first_node->group_prev_; } - node_pointer first_node = static_cast(prev->next_); link_pointer end = first_node->group_prev_->next_; std::size_t deleted_count = this->delete_nodes(prev, end); @@ -560,10 +569,9 @@ namespace boost { namespace unordered { namespace detail { iterator erase(c_iterator r) { BOOST_ASSERT(r.node_); - iterator next(r.node_); - ++next; - erase_nodes(r.node_, next.node_); - return next; + node_pointer next = next_node(r.node_); + erase_nodes(r.node_, next); + return iterator(next); } iterator erase_range(c_iterator r1, c_iterator r2) @@ -588,13 +596,12 @@ namespace boost { namespace unordered { namespace detail { if (!prev) { prev = this->get_previous_start(bucket_index); while (prev->next_ != i) - prev = static_cast(prev->next_)->group_prev_; + prev = next_node(prev)->group_prev_; } // Delete the nodes. do { - link_pointer group_end = - static_cast(prev->next_)->group_prev_->next_; + link_pointer group_end = next_group(next_node(prev)); this->delete_nodes(prev, group_end); bucket_index = this->fix_bucket(bucket_index, prev); } while(prev->next_ != j); @@ -634,17 +641,17 @@ namespace boost { namespace unordered { namespace detail { void copy_buckets(table const& src) { this->create_buckets(this->bucket_count_); - for (iterator n = src.begin(); n.node_;) { - std::size_t key_hash = n.node_->hash_; - iterator group_end(n.node_->group_prev_->next_); - iterator pos = this->add_node( + for (node_pointer n = src.begin(); n;) { + std::size_t key_hash = n->hash_; + node_pointer group_end(next_group(n)); + node_pointer pos = this->add_node( boost::unordered::detail::func::construct_value( - this->node_alloc(), *n), key_hash, iterator()); - for (++n; n != group_end; ++n) + this->node_alloc(), n->value()), key_hash, node_pointer()); + for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node( boost::unordered::detail::func::construct_value( - this->node_alloc(), *n), key_hash, pos); + this->node_alloc(), n->value()), key_hash, pos); } } } @@ -652,43 +659,43 @@ namespace boost { namespace unordered { namespace detail { void move_buckets(table const& src) { this->create_buckets(this->bucket_count_); - for (iterator n = src.begin(); n.node_;) { - std::size_t key_hash = n.node_->hash_; - iterator group_end(n.node_->group_prev_->next_); - iterator pos = this->add_node( + for (node_pointer n = src.begin(); n;) { + std::size_t key_hash = n->hash_; + node_pointer group_end(next_group(n)); + node_pointer pos = this->add_node( boost::unordered::detail::func::construct_value( - this->node_alloc(), boost::move(*n)), key_hash, iterator()); - for (++n; n != group_end; ++n) + this->node_alloc(), boost::move(n->value())), key_hash, node_pointer()); + for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node( boost::unordered::detail::func::construct_value( - this->node_alloc(), boost::move(*n)), key_hash, pos); + this->node_alloc(), boost::move(n->value())), key_hash, pos); } } } void assign_buckets(table const& src) { node_holder holder(*this); - for (iterator n = src.begin(); n.node_;) { - std::size_t key_hash = n.node_->hash_; - iterator group_end(n.node_->group_prev_->next_); - iterator pos = this->add_node(holder.copy_of(*n), key_hash, iterator()); - for (++n; n != group_end; ++n) + for (node_pointer n = src.begin(); n;) { + std::size_t key_hash = n->hash_; + node_pointer group_end(next_group(n)); + node_pointer pos = this->add_node(holder.copy_of(n->value()), key_hash, node_pointer()); + for (n = next_node(n); n != group_end; n = next_node(n)) { - this->add_node(holder.copy_of(*n), key_hash, pos); + this->add_node(holder.copy_of(n->value()), key_hash, pos); } } } void move_assign_buckets(table& src) { node_holder holder(*this); - for (iterator n = src.begin(); n.node_;) { - std::size_t key_hash = n.node_->hash_; - iterator group_end(n.node_->group_prev_->next_); - iterator pos = this->add_node(holder.move_copy_of(*n), key_hash, iterator()); - for (++n; n != group_end; ++n) + for (node_pointer n = src.begin(); n;) { + std::size_t key_hash = n->hash_; + node_pointer group_end(next_group(n)); + node_pointer pos = this->add_node(holder.move_copy_of(n->value()), key_hash, node_pointer()); + for (n = next_node(n); n != group_end; n = next_node(n)) { - this->add_node(holder.move_copy_of(*n), key_hash, pos); + this->add_node(holder.move_copy_of(n->value()), key_hash, pos); } } } @@ -701,8 +708,7 @@ namespace boost { namespace unordered { namespace detail { this->create_buckets(num_buckets); link_pointer prev = this->get_previous_start(); while (prev->next_) - prev = place_in_bucket(*this, prev, - static_cast(prev->next_)->group_prev_); + prev = place_in_bucket(*this, prev, next_node(prev)->group_prev_); } // Iterate through the nodes placing them in the correct buckets. diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 6ae1d73e..10e03cb8 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -130,6 +130,13 @@ namespace boost { namespace unordered { namespace detail { std::size_t max_load_; bucket_pointer buckets_; + //////////////////////////////////////////////////////////////////////// + // Node functions + + static inline node_pointer next_node(link_pointer n) { + return static_cast(n->next_); + } + //////////////////////////////////////////////////////////////////////// // Data access @@ -176,16 +183,16 @@ namespace boost { namespace unordered { namespace detail { return get_bucket(bucket_index)->next_; } - iterator begin() const + node_pointer begin() const { - return size_ ? iterator(get_previous_start()->next_) : iterator(); + return size_ ? next_node(get_previous_start()) : node_pointer(); } - iterator begin(std::size_t bucket_index) const + node_pointer begin(std::size_t bucket_index) const { - if (!size_) return iterator(); + if (!size_) return node_pointer(); link_pointer prev = get_previous_start(bucket_index); - return prev ? iterator(prev->next_) : iterator(); + return prev ? next_node(prev) : node_pointer(); } std::size_t hash_to_bucket(std::size_t hash_value) const @@ -202,14 +209,14 @@ namespace boost { namespace unordered { namespace detail { std::size_t bucket_size(std::size_t index) const { - iterator it = begin(index); - if (!it.node_) return 0; + node_pointer n = begin(index); + if (!n) return 0; std::size_t count = 0; - while(it.node_ && hash_to_bucket(it.node_->hash_) == index) + while(n && hash_to_bucket(n->hash_) == index) { ++count; - ++it; + n = next_node(n); } return count; @@ -698,7 +705,7 @@ namespace boost { namespace unordered { namespace detail { // Find Node template - iterator generic_find_node( + node_pointer generic_find_node( Key const& k, Hash const& hf, Pred const& eq) const @@ -707,7 +714,7 @@ namespace boost { namespace unordered { namespace detail { find_node_impl(policy::apply_hash(hf, k), k, eq); } - iterator find_node( + node_pointer find_node( std::size_t key_hash, key_type const& k) const { @@ -715,13 +722,13 @@ namespace boost { namespace unordered { namespace detail { find_node_impl(key_hash, k, this->key_eq()); } - iterator find_node(key_type const& k) const + node_pointer find_node(key_type const& k) const { return static_cast(this)-> find_node_impl(hash(k), k, this->key_eq()); } - iterator find_matching_node(iterator n) const + node_pointer find_matching_node(iterator n) const { // TODO: Does this apply to C++11? // diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index eb26c232..52fd3cde 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -186,47 +186,53 @@ namespace boost { namespace unordered { namespace detail { this->move_init(x); } + // Node functions. + + static inline node_pointer next_node(link_pointer n) { + return static_cast(n->next_); + } + // Accessors template - iterator find_node_impl( + node_pointer find_node_impl( std::size_t key_hash, Key const& k, Pred const& eq) const { std::size_t bucket_index = this->hash_to_bucket(key_hash); - iterator n = this->begin(bucket_index); + node_pointer n = this->begin(bucket_index); for (;;) { - if (!n.node_) return n; + if (!n) return n; - std::size_t node_hash = n.node_->hash_; + std::size_t node_hash = n->hash_; if (key_hash == node_hash) { - if (eq(k, this->get_key(*n))) + if (eq(k, this->get_key(n->value()))) return n; } else { if (this->hash_to_bucket(node_hash) != bucket_index) - return iterator(); + return node_pointer(); } - ++n; + n = next_node(n); } } std::size_t count(key_type const& k) const { - return this->find_node(k).node_ ? 1 : 0; + return this->find_node(k) ? 1 : 0; } value_type& at(key_type const& k) const { if (this->size_) { - iterator it = this->find_node(k); - if (it.node_) return *it; + node_pointer n = this->find_node(k); + if (n) return n->value(); } boost::throw_exception( @@ -236,10 +242,8 @@ namespace boost { namespace unordered { namespace detail { std::pair equal_range(key_type const& k) const { - iterator n = this->find_node(k); - iterator n2 = n; - if (n2.node_) ++n2; - return std::make_pair(n, n2); + node_pointer n = this->find_node(k); + return std::make_pair(iterator(n), iterator(n ? next_node(n) : n)); } // equals @@ -248,11 +252,11 @@ namespace boost { namespace unordered { namespace detail { { if(this->size_ != other.size_) return false; - for(iterator n1 = this->begin(); n1.node_; ++n1) + for(iterator n1(this->begin()); n1.node_; ++n1) { - iterator n2 = other.find_matching_node(n1); + node_pointer n2 = other.find_matching_node(n1); - if (!n2.node_ || *n1 != *n2) + if (!n2 || *n1 != n2->value()) return false; } @@ -261,7 +265,7 @@ namespace boost { namespace unordered { namespace detail { // Emplace/Insert - inline iterator add_node( + inline node_pointer add_node( node_pointer n, std::size_t key_hash) { @@ -275,7 +279,7 @@ namespace boost { namespace unordered { namespace detail { if (start_node->next_) { this->get_bucket(this->hash_to_bucket( - static_cast(start_node->next_)->hash_) + next_node(start_node)->hash_) )->next_ = n; } @@ -290,10 +294,10 @@ namespace boost { namespace unordered { namespace detail { } ++this->size_; - return iterator(n); + return n; } - inline iterator resize_and_add_node(node_pointer n, std::size_t key_hash) + inline node_pointer resize_and_add_node(node_pointer n, std::size_t key_hash) { node_tmp b(n, this->node_alloc()); this->reserve_for_insert(this->size_ + 1); @@ -303,11 +307,15 @@ namespace boost { namespace unordered { namespace detail { value_type& operator[](key_type const& k) { std::size_t key_hash = this->hash(k); - iterator pos = this->find_node(key_hash, k); - if (pos.node_) return *pos; - return *this->resize_and_add_node( - boost::unordered::detail::func::construct_pair(this->node_alloc(), k), - key_hash); + node_pointer pos = this->find_node(key_hash, k); + if (pos) { + return pos->value(); + } + else { + return this->resize_and_add_node( + boost::unordered::detail::func::construct_pair(this->node_alloc(), k), + key_hash)->value(); + } } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -316,7 +324,7 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::please_ignore_this_overload> const&) { BOOST_ASSERT(false); - return emplace_return(this->begin(), false); + return emplace_return(iterator(), false); } iterator emplace_hint(c_iterator, @@ -324,21 +332,21 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::please_ignore_this_overload> const&) { BOOST_ASSERT(false); - return this->begin(); + return iterator(); } # else emplace_return emplace( boost::unordered::detail::please_ignore_this_overload const&) { BOOST_ASSERT(false); - return emplace_return(this->begin(), false); + return emplace_return(iterator(), false); } iterator emplace_hint(c_iterator, boost::unordered::detail::please_ignore_this_overload const&) { BOOST_ASSERT(false); - return this->begin(); + return iterator(); } # endif #endif @@ -405,16 +413,16 @@ namespace boost { namespace unordered { namespace detail { BOOST_UNORDERED_EMPLACE_ARGS) { std::size_t key_hash = this->hash(k); - iterator pos = this->find_node(key_hash, k); - if (pos.node_) { - return emplace_return(pos, false); + node_pointer pos = this->find_node(key_hash, k); + if (pos) { + return emplace_return(iterator(pos), false); } else { return emplace_return( - this->resize_and_add_node( + iterator(this->resize_and_add_node( boost::unordered::detail::func::construct_value_generic( this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), - key_hash), + key_hash)), true); } } @@ -432,12 +440,12 @@ namespace boost { namespace unordered { namespace detail { return iterator(hint.node_); } std::size_t key_hash = this->hash(k); - iterator pos = this->find_node(key_hash, k); - if (pos.node_) { - return pos; + node_pointer pos = this->find_node(key_hash, k); + if (pos) { + return iterator(pos); } else { - return this->resize_and_add_node(b.release(), key_hash); + return iterator(this->resize_and_add_node(b.release(), key_hash)); } } @@ -450,13 +458,13 @@ namespace boost { namespace unordered { namespace detail { this->node_alloc()); key_type const& k = this->get_key(b.node_->value()); std::size_t key_hash = this->hash(k); - iterator pos = this->find_node(key_hash, k); - if (pos.node_) { - return emplace_return(pos, false); + node_pointer pos = this->find_node(key_hash, k); + if (pos) { + return emplace_return(iterator(pos), false); } else { return emplace_return( - this->resize_and_add_node(b.release(), key_hash), + iterator(this->resize_and_add_node(b.release(), key_hash)), true); } } @@ -497,9 +505,9 @@ namespace boost { namespace unordered { namespace detail { { // No side effects in this initial code std::size_t key_hash = this->hash(k); - iterator pos = this->find_node(key_hash, k); + node_pointer pos = this->find_node(key_hash, k); - if (!pos.node_) { + if (!pos) { node_tmp b( boost::unordered::detail::func::construct_value(this->node_alloc(), *i), this->node_alloc()); @@ -523,9 +531,9 @@ namespace boost { namespace unordered { namespace detail { key_type const& k = this->get_key(b.node_->value()); std::size_t key_hash = this->hash(k); - iterator pos = this->find_node(key_hash, k); + node_pointer pos = this->find_node(key_hash, k); - if (pos.node_) { + if (pos) { a.reclaim(b.release()); } else { @@ -554,18 +562,17 @@ namespace boost { namespace unordered { namespace detail { for (;;) { if (!prev->next_) return 0; - std::size_t node_hash = - static_cast(prev->next_)->hash_; + std::size_t node_hash = next_node(prev)->hash_; if (this->hash_to_bucket(node_hash) != bucket_index) return 0; if (node_hash == key_hash && this->key_eq()(k, this->get_key( - static_cast(prev->next_)->value()))) + next_node(prev)->value()))) break; prev = prev->next_; } - link_pointer end = static_cast(prev->next_)->next_; + link_pointer end = next_node(prev)->next_; std::size_t deleted_count = this->delete_nodes(prev, end); this->fix_bucket(bucket_index, prev); @@ -575,10 +582,9 @@ namespace boost { namespace unordered { namespace detail { iterator erase(c_iterator r) { BOOST_ASSERT(r.node_); - iterator next(r.node_); - ++next; - erase_nodes(r.node_, next.node_); - return next; + node_pointer next = next_node(r.node_); + erase_nodes(r.node_, next); + return iterator(next); } iterator erase_range(c_iterator r1, c_iterator r2) @@ -609,36 +615,36 @@ namespace boost { namespace unordered { namespace detail { void copy_buckets(table const& src) { this->create_buckets(this->bucket_count_); - for(iterator n = src.begin(); n.node_; ++n) { + for(node_pointer n = src.begin(); n; n = next_node(n)) { this->add_node( boost::unordered::detail::func::construct_value( - this->node_alloc(), *n), n.node_->hash_); + this->node_alloc(), n->value()), n->hash_); } } void move_buckets(table const& src) { this->create_buckets(this->bucket_count_); - for(iterator n = src.begin(); n.node_; ++n) { + for(node_pointer n = src.begin(); n; n = next_node(n)) { this->add_node( boost::unordered::detail::func::construct_value( - this->node_alloc(), boost::move(*n)), n.node_->hash_); + this->node_alloc(), boost::move(n->value())), n->hash_); } } void assign_buckets(table const& src) { node_holder holder(*this); - for(iterator n = src.begin(); n.node_; ++n) { - this->add_node(holder.copy_of(*n), n.node_->hash_); + for(node_pointer n = src.begin(); n; n = next_node(n)) { + this->add_node(holder.copy_of(n->value()), n->hash_); } } void move_assign_buckets(table& src) { node_holder holder(*this); - for(iterator n = src.begin(); n.node_; ++n) { - this->add_node(holder.move_copy_of(*n), n.node_->hash_); + for(node_pointer n = src.begin(); n; n = next_node(n)) { + this->add_node(holder.move_copy_of(n->value()), n->hash_); } } @@ -657,7 +663,7 @@ namespace boost { namespace unordered { namespace detail { // pre: prev->next_ is not null. static link_pointer place_in_bucket(table& dst, link_pointer prev) { - node_pointer n = static_cast(prev->next_); + node_pointer n = next_node(prev); bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(n->hash_)); if (!b->next_) { diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index fc6fbe0e..84f144c5 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -202,12 +202,12 @@ namespace unordered iterator begin() BOOST_NOEXCEPT { - return table_.begin(); + return iterator(table_.begin()); } const_iterator begin() const BOOST_NOEXCEPT { - return table_.begin(); + return const_iterator(table_.begin()); } iterator end() BOOST_NOEXCEPT @@ -222,7 +222,7 @@ namespace unordered const_iterator cbegin() const BOOST_NOEXCEPT { - return table_.begin(); + return const_iterator(table_.begin()); } const_iterator cend() const BOOST_NOEXCEPT @@ -686,12 +686,12 @@ namespace unordered iterator begin() BOOST_NOEXCEPT { - return table_.begin(); + return iterator(table_.begin()); } const_iterator begin() const BOOST_NOEXCEPT { - return table_.begin(); + return const_iterator(table_.begin()); } iterator end() BOOST_NOEXCEPT @@ -706,7 +706,7 @@ namespace unordered const_iterator cbegin() const BOOST_NOEXCEPT { - return table_.begin(); + return const_iterator(table_.begin()); } const_iterator cend() const BOOST_NOEXCEPT @@ -1208,14 +1208,14 @@ namespace unordered typename unordered_map::iterator unordered_map::find(const key_type& k) { - return table_.find_node(k); + return iterator(table_.find_node(k)); } template typename unordered_map::const_iterator unordered_map::find(const key_type& k) const { - return table_.find_node(k); + return const_iterator(table_.find_node(k)); } template @@ -1227,7 +1227,7 @@ namespace unordered CompatibleHash const& hash, CompatiblePredicate const& eq) { - return table_.generic_find_node(k, hash, eq); + return iterator(table_.generic_find_node(k, hash, eq)); } template @@ -1239,7 +1239,7 @@ namespace unordered CompatibleHash const& hash, CompatiblePredicate const& eq) const { - return table_.generic_find_node(k, hash, eq); + return const_iterator(table_.generic_find_node(k, hash, eq)); } template @@ -1520,14 +1520,14 @@ namespace unordered typename unordered_multimap::iterator unordered_multimap::find(const key_type& k) { - return table_.find_node(k); + return iterator(table_.find_node(k)); } template typename unordered_multimap::const_iterator unordered_multimap::find(const key_type& k) const { - return table_.find_node(k); + return const_iterator(table_.find_node(k)); } template @@ -1539,7 +1539,7 @@ namespace unordered CompatibleHash const& hash, CompatiblePredicate const& eq) { - return table_.generic_find_node(k, hash, eq); + return iterator(table_.generic_find_node(k, hash, eq)); } template @@ -1551,7 +1551,7 @@ namespace unordered CompatibleHash const& hash, CompatiblePredicate const& eq) const { - return table_.generic_find_node(k, hash, eq); + return const_iterator(table_.generic_find_node(k, hash, eq)); } template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index aa9911bc..be17c399 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -199,12 +199,12 @@ namespace unordered iterator begin() BOOST_NOEXCEPT { - return table_.begin(); + return iterator(table_.begin()); } const_iterator begin() const BOOST_NOEXCEPT { - return table_.begin(); + return const_iterator(table_.begin()); } iterator end() BOOST_NOEXCEPT @@ -219,7 +219,7 @@ namespace unordered const_iterator cbegin() const BOOST_NOEXCEPT { - return table_.begin(); + return const_iterator(table_.begin()); } const_iterator cend() const BOOST_NOEXCEPT @@ -1161,7 +1161,7 @@ namespace unordered typename unordered_set::const_iterator unordered_set::find(const key_type& k) const { - return table_.find_node(k); + return const_iterator(table_.find_node(k)); } template @@ -1173,7 +1173,7 @@ namespace unordered CompatibleHash const& hash, CompatiblePredicate const& eq) const { - return table_.generic_find_node(k, hash, eq); + return const_iterator(table_.generic_find_node(k, hash, eq)); } template @@ -1445,7 +1445,7 @@ namespace unordered typename unordered_multiset::const_iterator unordered_multiset::find(const key_type& k) const { - return table_.find_node(k); + return const_iterator(table_.find_node(k)); } template @@ -1457,7 +1457,7 @@ namespace unordered CompatibleHash const& hash, CompatiblePredicate const& eq) const { - return table_.generic_find_node(k, hash, eq); + return const_iterator(table_.generic_find_node(k, hash, eq)); } template From c680fa7418986417de831dbe2e5ec98a33179108 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 22 Oct 2016 10:04:36 +0100 Subject: [PATCH 11/20] Remove find_matching_node. FWIW the standard says that equality is undefined behaviour if the Hash and Pred function objects behave differently. But I think we should support different hash functions, e.g. so that randomized hash functions will work. --- include/boost/unordered/detail/equivalent.hpp | 8 ++++---- include/boost/unordered/detail/table.hpp | 11 ----------- include/boost/unordered/detail/unique.hpp | 2 +- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 16fc1f10..4a482734 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -259,10 +259,10 @@ namespace boost { namespace unordered { namespace detail { for(iterator n1(this->begin()); n1.node_;) { - iterator n2(other.find_matching_node(n1)); - if (!n2.node_) return false; - iterator end1(next_group(n1.node_)); - iterator end2(next_group(n2.node_)); + node_pointer n2 = other.find_node(other.get_key(n1->value())); + if (!n2) return false; + node_pointer end1 = next_group(n1); + node_pointer end2 = next_group(n2); if (!group_equals(n1, end1, n2, end2)) return false; n1 = end1; } diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 10e03cb8..438feab7 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -728,17 +728,6 @@ namespace boost { namespace unordered { namespace detail { find_node_impl(hash(k), k, this->key_eq()); } - node_pointer find_matching_node(iterator n) const - { - // TODO: Does this apply to C++11? - // - // For some stupid reason, I decided to support equality comparison - // when different hash functions are used. So I can't use the hash - // value from the node here. - - return find_node(get_key(*n)); - } - // Reserve and rehash void reserve_for_insert(std::size_t); diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 52fd3cde..0e5771e2 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -254,7 +254,7 @@ namespace boost { namespace unordered { namespace detail { for(iterator n1(this->begin()); n1.node_; ++n1) { - node_pointer n2 = other.find_matching_node(n1); + node_pointer n2 = other.find_node(other.get_key(n1->value())); if (!n2 || *n1 != n2->value()) return false; From 9b7b485c33eb1411c3845ec11629a22a93c61e69 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 22 Oct 2016 10:04:36 +0100 Subject: [PATCH 12/20] Use node_pointer in equality. --- include/boost/unordered/detail/equivalent.hpp | 47 +++++++++---------- include/boost/unordered/detail/unique.hpp | 4 +- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 4a482734..5a71181e 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -257,7 +257,7 @@ namespace boost { namespace unordered { namespace detail { { if(this->size_ != other.size_) return false; - for(iterator n1(this->begin()); n1.node_;) + for(node_pointer n1 = this->begin(); n1;) { node_pointer n2 = other.find_node(other.get_key(n1->value())); if (!n2) return false; @@ -270,24 +270,24 @@ namespace boost { namespace unordered { namespace detail { return true; } - static bool group_equals(iterator n1, iterator end1, - iterator n2, iterator end2) + static bool group_equals(node_pointer n1, node_pointer end1, + node_pointer n2, node_pointer end2) { for(;;) { - if (*n1 != *n2) break; + if (n1->value() != n2->value()) break; - ++n1; - ++n2; + n1 = next_node(n1); + n2 = next_node(n2); if (n1 == end1) return n2 == end2; if (n2 == end2) return false; } - for(iterator n1a = n1, n2a = n2;;) + for(node_pointer n1a = n1, n2a = n2;;) { - ++n1a; - ++n2a; + n1a = next_node(n1a); + n2a = next_node(n2a); if (n1a == end1) { @@ -298,35 +298,34 @@ namespace boost { namespace unordered { namespace detail { if (n2a == end2) return false; } - iterator start = n1; - for(;n1 != end1; ++n1) + node_pointer start = n1; + for(;n1 != end1; n1 = next_node(n1)) { - value_type const& v = *n1; - if (find(start, n1, v)) continue; - std::size_t matches = count_equal(n2, end2, v); - if (!matches) return false; - iterator next = n1; - ++next; - if (matches != 1 + count_equal(next, end1, v)) return false; + value_type const& v = n1->value(); + if (!find(start, n1, v)) { + std::size_t matches = count_equal(n2, end2, v); + if (!matches) return false; + if (matches != 1 + count_equal(next_node(n1), end1, v)) return false; + } } return true; } - static bool find(iterator n, iterator end, value_type const& v) + static bool find(node_pointer n, node_pointer end, value_type const& v) { - for(;n != end; ++n) - if (*n == v) + for(;n != end; n = next_node(n)) + if (n->value() == v) return true; return false; } - static std::size_t count_equal(iterator n, iterator end, + static std::size_t count_equal(node_pointer n, node_pointer end, value_type const& v) { std::size_t count = 0; - for(;n != end; ++n) - if (*n == v) ++count; + for(;n != end; n = next_node(n)) + if (n->value() == v) ++count; return count; } diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 0e5771e2..c736456b 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -252,11 +252,11 @@ namespace boost { namespace unordered { namespace detail { { if(this->size_ != other.size_) return false; - for(iterator n1(this->begin()); n1.node_; ++n1) + for(node_pointer n1 = this->begin(); n1; n1 = next_node(n1)) { node_pointer n2 = other.find_node(other.get_key(n1->value())); - if (!n2 || *n1 != n2->value()) + if (!n2 || n1->value() != n2->value()) return false; } From e986b70981b3177795c9a6b499ab4c64540597a9 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 22 Oct 2016 10:04:36 +0100 Subject: [PATCH 13/20] Stricter iterator types --- include/boost/unordered/detail/map.hpp | 18 ++++++++++++++++++ include/boost/unordered/detail/set.hpp | 18 ++++++++++++++++++ include/boost/unordered/detail/table.hpp | 13 ++++--------- include/boost/unordered/unordered_set.hpp | 8 ++++---- 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index 22f8e633..14253ef4 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -31,6 +31,15 @@ namespace boost { namespace unordered { namespace detail { extractor; typedef typename boost::unordered::detail::pick_policy::type policy; + + typedef boost::unordered::iterator_detail:: + iterator iterator; + typedef boost::unordered::iterator_detail:: + c_iterator c_iterator; + typedef boost::unordered::iterator_detail:: + l_iterator l_iterator; + typedef boost::unordered::iterator_detail:: + cl_iterator cl_iterator; }; template @@ -56,6 +65,15 @@ namespace boost { namespace unordered { namespace detail { extractor; typedef typename boost::unordered::detail::pick_policy::type policy; + + typedef boost::unordered::iterator_detail:: + iterator iterator; + typedef boost::unordered::iterator_detail:: + c_iterator c_iterator; + typedef boost::unordered::iterator_detail:: + l_iterator l_iterator; + typedef boost::unordered::iterator_detail:: + cl_iterator cl_iterator; }; }}} diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index 3ed9dde0..ccbc4c99 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -29,6 +29,15 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::set_extractor extractor; typedef typename boost::unordered::detail::pick_policy::type policy; + + typedef boost::unordered::iterator_detail:: + c_iterator iterator; + typedef boost::unordered::iterator_detail:: + c_iterator c_iterator; + typedef boost::unordered::iterator_detail:: + cl_iterator l_iterator; + typedef boost::unordered::iterator_detail:: + cl_iterator cl_iterator; }; template @@ -53,5 +62,14 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::set_extractor extractor; typedef typename boost::unordered::detail::pick_policy::type policy; + + typedef boost::unordered::iterator_detail:: + c_iterator iterator; + typedef boost::unordered::iterator_detail:: + c_iterator c_iterator; + typedef boost::unordered::iterator_detail:: + cl_iterator l_iterator; + typedef boost::unordered::iterator_detail:: + cl_iterator cl_iterator; }; }}} diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 438feab7..65c06908 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -84,6 +84,10 @@ namespace boost { namespace unordered { namespace detail { typedef typename Types::table table_impl; typedef typename Types::link_pointer link_pointer; typedef typename Types::policy policy; + typedef typename Types::iterator iterator; + typedef typename Types::c_iterator c_iterator; + typedef typename Types::l_iterator l_iterator; + typedef typename Types::cl_iterator cl_iterator; typedef boost::unordered::detail::functions< typename Types::hasher, @@ -110,15 +114,6 @@ namespace boost { namespace unordered { namespace detail { typedef boost::unordered::detail::node_tmp node_tmp; - typedef boost::unordered::iterator_detail:: - iterator iterator; - typedef boost::unordered::iterator_detail:: - c_iterator c_iterator; - typedef boost::unordered::iterator_detail:: - l_iterator l_iterator; - typedef boost::unordered::iterator_detail:: - cl_iterator cl_iterator; - //////////////////////////////////////////////////////////////////////// // Members diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index be17c399..ea411f6d 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -67,9 +67,9 @@ namespace unordered typedef std::ptrdiff_t difference_type; typedef typename table::cl_iterator const_local_iterator; - typedef typename table::cl_iterator local_iterator; + typedef typename table::l_iterator local_iterator; typedef typename table::c_iterator const_iterator; - typedef typename table::c_iterator iterator; + typedef typename table::iterator iterator; private: @@ -536,9 +536,9 @@ namespace unordered typedef std::ptrdiff_t difference_type; typedef typename table::cl_iterator const_local_iterator; - typedef typename table::cl_iterator local_iterator; + typedef typename table::l_iterator local_iterator; typedef typename table::c_iterator const_iterator; - typedef typename table::c_iterator iterator; + typedef typename table::iterator iterator; private: From 0d1cfba823b4780879d3e2dbb8720cefbfc87714 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 22 Oct 2016 10:28:53 +0100 Subject: [PATCH 14/20] Rename functions in allocate.hpp --- include/boost/unordered/detail/allocate.hpp | 40 +++++++++---------- include/boost/unordered/detail/buckets.hpp | 2 +- include/boost/unordered/detail/equivalent.hpp | 18 ++++----- include/boost/unordered/detail/table.hpp | 2 +- include/boost/unordered/detail/unique.hpp | 14 +++---- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index 137214d4..bddfaf4f 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -917,7 +917,7 @@ namespace boost { namespace unordered { namespace detail { namespace func { } template - inline void destroy_value_impl(Alloc& alloc, T* x) { + inline void call_destroy(Alloc& alloc, T* x) { boost::unordered::detail::allocator_traits::destroy(alloc, x); } @@ -932,7 +932,7 @@ namespace boost { namespace unordered { namespace detail { namespace func { } template - inline void destroy_value_impl(Alloc&, T* x) { + inline void call_destroy(Alloc&, T* x) { boost::unordered::detail::func::destroy(x); } @@ -954,7 +954,7 @@ namespace boost { namespace unordered { namespace detail { namespace func { } template - inline void destroy_value_impl(Alloc&, T* x) { + inline void call_destroy(Alloc&, T* x) { boost::unordered::detail::func::destroy(x); } @@ -1095,7 +1095,7 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) // For the standard pair constructor. template - inline void construct_value_impl(Alloc& alloc, T* address, + inline void construct_from_args(Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args) { boost::unordered::detail::func::call_construct(alloc, @@ -1110,7 +1110,7 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) template inline typename enable_if, void>::type - construct_value_impl(Alloc& alloc, std::pair* address, + construct_from_args(Alloc& alloc, std::pair* address, BOOST_FWD_REF(A0), BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { boost::unordered::detail::func::construct_from_tuple(alloc, @@ -1125,21 +1125,21 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES -//////////////////////////////////////////////////////////////////////////////// -// Construct from emplace_args + //////////////////////////////////////////////////////////////////////////// + // Construct from emplace_args // Explicitly write out first three overloads for the sake of sane // error messages. template - inline void construct_value_impl(Alloc&, T* address, + inline void construct_from_args(Alloc&, T* address, emplace_args1 const& args) { new((void*) address) T(boost::forward(args.a0)); } template - inline void construct_value_impl(Alloc&, T* address, + inline void construct_from_args(Alloc&, T* address, emplace_args2 const& args) { new((void*) address) T( @@ -1149,7 +1149,7 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) } template - inline void construct_value_impl(Alloc&, T* address, + inline void construct_from_args(Alloc&, T* address, emplace_args3 const& args) { new((void*) address) T( @@ -1166,7 +1166,7 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) typename Alloc, typename T, \ BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \ > \ - inline void construct_value_impl(Alloc&, T* address, \ + inline void construct_from_args(Alloc&, T* address, \ boost::unordered::detail::BOOST_PP_CAT(emplace_args,num_params) < \ BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \ > const& args) \ @@ -1185,7 +1185,7 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) template - inline void construct_value_impl(Alloc& alloc, std::pair* address, + inline void construct_from_args(Alloc& alloc, std::pair* address, boost::unordered::detail::emplace_args3 const& args, typename enable_if, void*>::type = 0) { @@ -1247,7 +1247,7 @@ namespace boost { namespace unordered { namespace detail { BOOST_ASSERT(!node_); node_ = p; node_constructed_ = true; - boost::unordered::detail::func::destroy_value_impl(alloc_, + boost::unordered::detail::func::call_destroy(alloc_, node_->value_ptr()); } @@ -1313,7 +1313,7 @@ namespace boost { namespace unordered { namespace detail { node_tmp::~node_tmp() { if (node_) { - boost::unordered::detail::func::destroy_value_impl(alloc_, + boost::unordered::detail::func::call_destroy(alloc_, node_->value_ptr()); boost::unordered::detail::func::destroy( boost::addressof(*node_)); @@ -1324,23 +1324,23 @@ namespace boost { namespace unordered { namespace detail { namespace boost { namespace unordered { namespace detail { namespace func { - // Some nicer construct_value functions, might try to + // Some nicer construct_node functions, might try to // improve implementation later. template inline typename boost::unordered::detail::allocator_traits::pointer - construct_value_generic(Alloc& alloc, BOOST_UNORDERED_EMPLACE_ARGS) + construct_node_from_args(Alloc& alloc, BOOST_UNORDERED_EMPLACE_ARGS) { node_constructor a(alloc); a.create_node(); - construct_value_impl(alloc, a.node_->value_ptr(), + construct_from_args(alloc, a.node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); return a.release(); } template inline typename boost::unordered::detail::allocator_traits::pointer - construct_value(Alloc& alloc, BOOST_FWD_REF(U) x) + construct_node(Alloc& alloc, BOOST_FWD_REF(U) x) { node_constructor a(alloc); a.create_node(); @@ -1353,7 +1353,7 @@ namespace boost { namespace unordered { namespace detail { namespace func { // constructor for std::piece_construct with std::tuple. template inline typename boost::unordered::detail::allocator_traits::pointer - construct_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) + construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) { node_constructor a(alloc); a.create_node(); @@ -1369,7 +1369,7 @@ namespace boost { namespace unordered { namespace detail { namespace func { template inline typename boost::unordered::detail::allocator_traits::pointer - construct_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) + construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) { node_constructor a(alloc); a.create_node(); diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index b857bfd6..bd9a5cbb 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -391,7 +391,7 @@ namespace boost { namespace unordered { namespace detail { node_pointer p = nodes_; nodes_ = static_cast(p->next_); - boost::unordered::detail::func::destroy_value_impl(constructor_.alloc_, + boost::unordered::detail::func::call_destroy(constructor_.alloc_, p->value_ptr()); boost::unordered::detail::func::destroy(boost::addressof(*p)); node_allocator_traits::deallocate(constructor_.alloc_, p, 1); diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 5a71181e..618d3af9 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -442,7 +442,7 @@ namespace boost { namespace unordered { namespace detail { iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS) { return iterator(emplace_impl( - boost::unordered::detail::func::construct_value_generic( + boost::unordered::detail::func::construct_node_from_args( this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD))); } @@ -450,7 +450,7 @@ namespace boost { namespace unordered { namespace detail { iterator emplace_hint(c_iterator hint, BOOST_UNORDERED_EMPLACE_ARGS) { return iterator(emplace_hint_impl(hint, - boost::unordered::detail::func::construct_value_generic( + boost::unordered::detail::func::construct_node_from_args( this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD))); } @@ -503,7 +503,7 @@ namespace boost { namespace unordered { namespace detail { std::size_t distance = static_cast(std::distance(i, j)); if(distance == 1) { emplace_impl( - boost::unordered::detail::func::construct_value( + boost::unordered::detail::func::construct_node( this->node_alloc(), *i)); } else { @@ -512,7 +512,7 @@ namespace boost { namespace unordered { namespace detail { for (; i != j; ++i) { emplace_impl_no_rehash( - boost::unordered::detail::func::construct_value( + boost::unordered::detail::func::construct_node( this->node_alloc(), *i)); } } @@ -524,7 +524,7 @@ namespace boost { namespace unordered { namespace detail { { for (; i != j; ++i) { emplace_impl( - boost::unordered::detail::func::construct_value( + boost::unordered::detail::func::construct_node( this->node_alloc(), *i)); } } @@ -644,12 +644,12 @@ namespace boost { namespace unordered { namespace detail { std::size_t key_hash = n->hash_; node_pointer group_end(next_group(n)); node_pointer pos = this->add_node( - boost::unordered::detail::func::construct_value( + boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), key_hash, node_pointer()); for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node( - boost::unordered::detail::func::construct_value( + boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), key_hash, pos); } } @@ -662,12 +662,12 @@ namespace boost { namespace unordered { namespace detail { std::size_t key_hash = n->hash_; node_pointer group_end(next_group(n)); node_pointer pos = this->add_node( - boost::unordered::detail::func::construct_value( + boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), key_hash, node_pointer()); for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node( - boost::unordered::detail::func::construct_value( + boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), key_hash, pos); } } diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 65c06908..9657c763 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -464,7 +464,7 @@ namespace boost { namespace unordered { namespace detail { node_pointer n = static_cast(prev->next_); prev->next_ = n->next_; - boost::unordered::detail::func::destroy_value_impl(node_alloc(), + boost::unordered::detail::func::call_destroy(node_alloc(), n->value_ptr()); boost::unordered::detail::func::destroy(boost::addressof(*n)); node_allocator_traits::deallocate(node_alloc(), n, 1); diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index c736456b..e77b4c14 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -313,7 +313,7 @@ namespace boost { namespace unordered { namespace detail { } else { return this->resize_and_add_node( - boost::unordered::detail::func::construct_pair(this->node_alloc(), k), + boost::unordered::detail::func::construct_node_pair(this->node_alloc(), k), key_hash)->value(); } } @@ -420,7 +420,7 @@ namespace boost { namespace unordered { namespace detail { else { return emplace_return( iterator(this->resize_and_add_node( - boost::unordered::detail::func::construct_value_generic( + boost::unordered::detail::func::construct_node_from_args( this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), key_hash)), true); @@ -432,7 +432,7 @@ namespace boost { namespace unordered { namespace detail { BOOST_UNORDERED_EMPLACE_ARGS) { node_tmp b( - boost::unordered::detail::func::construct_value_generic( + boost::unordered::detail::func::construct_node_from_args( this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), this->node_alloc()); key_type const& k = this->get_key(b.node_->value()); @@ -453,7 +453,7 @@ namespace boost { namespace unordered { namespace detail { emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS) { node_tmp b( - boost::unordered::detail::func::construct_value_generic( + boost::unordered::detail::func::construct_node_from_args( this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), this->node_alloc()); key_type const& k = this->get_key(b.node_->value()); @@ -509,7 +509,7 @@ namespace boost { namespace unordered { namespace detail { if (!pos) { node_tmp b( - boost::unordered::detail::func::construct_value(this->node_alloc(), *i), + boost::unordered::detail::func::construct_node(this->node_alloc(), *i), this->node_alloc()); if(this->size_ + 1 > this->max_load_) this->reserve_for_insert(this->size_ + @@ -617,7 +617,7 @@ namespace boost { namespace unordered { namespace detail { for(node_pointer n = src.begin(); n; n = next_node(n)) { this->add_node( - boost::unordered::detail::func::construct_value( + boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), n->hash_); } } @@ -627,7 +627,7 @@ namespace boost { namespace unordered { namespace detail { for(node_pointer n = src.begin(); n; n = next_node(n)) { this->add_node( - boost::unordered::detail::func::construct_value( + boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), n->hash_); } } From 1bcd5b0003d52cf7b24ccdf87423dcfeb449ab1d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Oct 2016 13:31:07 +0100 Subject: [PATCH 15/20] Make no argument constructor implicit --- doc/changes.qbk | 1 + doc/ref.php | 14 +++++- doc/ref.xml | 56 +++++++++++++++++++++-- include/boost/unordered/unordered_map.hpp | 21 ++++++++- include/boost/unordered/unordered_set.hpp | 20 +++++++- test/unordered/compile_tests.hpp | 11 +++++ 6 files changed, 114 insertions(+), 9 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index cd7cba86..1ac6e023 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -294,5 +294,6 @@ C++11 support has resulted in some breaking changes: wrong bucket and equivalent elements would be incorrectly handled. * Various reference documentation improvements. * Better allocator support ([ticket 12459]). +* Make the no argument constructors implicit. [endsect] diff --git a/doc/ref.php b/doc/ref.php index d2fb2b42..bd16992c 100644 --- a/doc/ref.php +++ b/doc/ref.php @@ -189,10 +189,22 @@ EOL; A const_local_iterator object can be used to iterate through a single bucket. + + + size() == 0 + + + Constructs an empty container using hasher() as the hash function, key_equal() as the key equality predicate, allocator_type() as the allocator and a maximum load factor of 1.0. + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + size_type - implementation-defined hasher const& diff --git a/doc/ref.xml b/doc/ref.xml index d03e8dd3..73ec2920 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -130,10 +130,22 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) A const_local_iterator object can be used to iterate through a single bucket. + + + size() == 0 + + + Constructs an empty container using hasher() as the hash function, key_equal() as the key equality predicate, allocator_type() as the allocator and a maximum load factor of 1.0. + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + size_type - implementation-defined hasher const& @@ -1204,10 +1216,22 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) A const_local_iterator object can be used to iterate through a single bucket. + + + size() == 0 + + + Constructs an empty container using hasher() as the hash function, key_equal() as the key equality predicate, allocator_type() as the allocator and a maximum load factor of 1.0. + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + size_type - implementation-defined hasher const& @@ -2287,10 +2311,22 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) A const_local_iterator object can be used to iterate through a single bucket. + + + size() == 0 + + + Constructs an empty container using hasher() as the hash function, key_equal() as the key equality predicate, allocator_type() as the allocator and a maximum load factor of 1.0. + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + size_type - implementation-defined hasher const& @@ -3408,10 +3444,22 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) A const_local_iterator object can be used to iterate through a single bucket. + + + size() == 0 + + + Constructs an empty container using hasher() as the hash function, key_equal() as the key equality predicate, allocator_type() as the allocator and a maximum load factor of 1.0. + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + size_type - implementation-defined hasher const& diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 84f144c5..88108363 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -82,8 +82,10 @@ namespace unordered // constructors + unordered_map(); + explicit unordered_map( - size_type = boost::unordered::detail::default_bucket_count, + size_type, const hasher& = hasher(), const key_equal& = key_equal(), const allocator_type& = allocator_type()); @@ -565,8 +567,9 @@ namespace unordered // constructors + unordered_multimap(); explicit unordered_multimap( - size_type = boost::unordered::detail::default_bucket_count, + size_type, const hasher& = hasher(), const key_equal& = key_equal(), const allocator_type& = allocator_type()); @@ -1002,6 +1005,13 @@ namespace unordered //////////////////////////////////////////////////////////////////////////////// + template + unordered_map::unordered_map() + : table_(boost::unordered::detail::default_bucket_count, hasher(), + key_equal(), allocator_type()) + { + } + template unordered_map::unordered_map( size_type n, const hasher &hf, const key_equal &eql, @@ -1335,6 +1345,13 @@ namespace unordered //////////////////////////////////////////////////////////////////////////////// + template + unordered_multimap::unordered_multimap() + : table_(boost::unordered::detail::default_bucket_count, hasher(), + key_equal(), allocator_type()) + { + } + template unordered_multimap::unordered_multimap( size_type n, const hasher &hf, const key_equal &eql, diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index ea411f6d..42c30bc9 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -79,8 +79,9 @@ namespace unordered // constructors + unordered_set(); explicit unordered_set( - size_type = boost::unordered::detail::default_bucket_count, + size_type, const hasher& = hasher(), const key_equal& = key_equal(), const allocator_type& = allocator_type()); @@ -548,8 +549,9 @@ namespace unordered // constructors + unordered_multiset(); explicit unordered_multiset( - size_type = boost::unordered::detail::default_bucket_count, + size_type, const hasher& = hasher(), const key_equal& = key_equal(), const allocator_type& = allocator_type()); @@ -976,6 +978,13 @@ namespace unordered //////////////////////////////////////////////////////////////////////////////// + template + unordered_set::unordered_set() + : table_(boost::unordered::detail::default_bucket_count, hasher(), + key_equal(), allocator_type()) + { + } + template unordered_set::unordered_set( size_type n, const hasher &hf, const key_equal &eql, @@ -1260,6 +1269,13 @@ namespace unordered //////////////////////////////////////////////////////////////////////////////// + template + unordered_multiset::unordered_multiset() + : table_(boost::unordered::detail::default_bucket_count, hasher(), + key_equal(), allocator_type()) + { + } + template unordered_multiset::unordered_multiset( size_type n, const hasher &hf, const key_equal &eql, diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 9e5dba30..62a4c3fc 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -101,7 +101,18 @@ void container_test(X& r, T const&) static_cast( (std::numeric_limits::max)())); + // Constructors + // I don't test the runtime post-conditions here. + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + // It isn't specified in the container requirements that the no argument + // constructor is implicit, but it is defined that way in the concrete + // container specification. + X u_implicit = {}; + sink(u_implicit); +#endif + X u; BOOST_TEST(u.size() == 0); BOOST_TEST(X().size() == 0); From e3f534a148deeeb3b824f7bb7e5d4e7d0f034ba6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Oct 2016 13:31:07 +0100 Subject: [PATCH 16/20] Allocator aware constructors --- doc/changes.qbk | 1 + doc/ref.php | 169 +++++- doc/ref.xml | 676 +++++++++++++++++++++- include/boost/unordered/unordered_map.hpp | 211 ++++++- include/boost/unordered/unordered_set.hpp | 212 ++++++- test/unordered/compile_tests.hpp | 94 ++- 6 files changed, 1319 insertions(+), 44 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 1ac6e023..0353e292 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -295,5 +295,6 @@ C++11 support has resulted in some breaking changes: * Various reference documentation improvements. * Better allocator support ([ticket 12459]). * Make the no argument constructors implicit. +* Implement missing allocator aware constructors. [endsect] diff --git a/doc/ref.php b/doc/ref.php index bd16992c..3847ede3 100644 --- a/doc/ref.php +++ b/doc/ref.php @@ -258,7 +258,12 @@ EOL; allocator_type() - Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + If the defaults are used, hasher, key_equal and @@ -322,6 +327,168 @@ EOL; Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + + && + + + Allocator const& + + + Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. + + + This is implemented using Boost.Move. + + + + value_type is move insertable. + + + + + + initializer_list<value_type> + + + size_type + implementation-defined + + + hasher const& + hasher() + + + key_equal const& + key_equal() + + + allocator_type const& + allocator_type() + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from il into it. + + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + + + + size_type + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default hash function and key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + hasher and key_equal need to be DefaultConstructible. + + + + + + size_type + + + hasher const& + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + key_equal needs to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using a as the allocator, with the + default hash function and key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + hasher, key_equal need to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + hasher const& + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + a as the allocator, with the + default key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + key_equal needs to be DefaultConstructible. + + + The destructor is applied to every element, and all memory is deallocated diff --git a/doc/ref.xml b/doc/ref.xml index 73ec2920..dc22aace 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -199,7 +199,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) allocator_type() - Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + If the defaults are used, hasher, key_equal and @@ -263,6 +268,168 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + + unordered_set && + + + Allocator const& + + + Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. + + + This is implemented using Boost.Move. + + + + value_type is move insertable. + + + + + + initializer_list<value_type> + + + size_type + implementation-defined + + + hasher const& + hasher() + + + key_equal const& + key_equal() + + + allocator_type const& + allocator_type() + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from il into it. + + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + + + + size_type + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default hash function and key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + hasher and key_equal need to be DefaultConstructible. + + + + + + size_type + + + hasher const& + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + key_equal needs to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using a as the allocator, with the + default hash function and key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + hasher, key_equal need to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + hasher const& + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + a as the allocator, with the + default key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + key_equal needs to be DefaultConstructible. + + + The destructor is applied to every element, and all memory is deallocated @@ -1285,7 +1452,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) allocator_type() - Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + If the defaults are used, hasher, key_equal and @@ -1349,6 +1521,168 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + + unordered_multiset && + + + Allocator const& + + + Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. + + + This is implemented using Boost.Move. + + + + value_type is move insertable. + + + + + + initializer_list<value_type> + + + size_type + implementation-defined + + + hasher const& + hasher() + + + key_equal const& + key_equal() + + + allocator_type const& + allocator_type() + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from il into it. + + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + + + + size_type + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default hash function and key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + hasher and key_equal need to be DefaultConstructible. + + + + + + size_type + + + hasher const& + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + key_equal needs to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using a as the allocator, with the + default hash function and key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + hasher, key_equal need to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + hasher const& + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + a as the allocator, with the + default key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + key_equal needs to be DefaultConstructible. + + + The destructor is applied to every element, and all memory is deallocated @@ -2327,6 +2661,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) size_type + implementation-defined hasher const& @@ -2380,7 +2715,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) allocator_type() - Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + If the defaults are used, hasher, key_equal and @@ -2444,6 +2784,167 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + + unordered_map && + + + Allocator const& + + + Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. + + + This is implemented using Boost.Move. + + + + value_type is move insertable. + + + + + + initializer_list<value_type> + + + size_type + + + hasher const& + hasher() + + + key_equal const& + key_equal() + + + allocator_type const& + allocator_type() + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from il into it. + + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + + + + size_type + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default hash function and key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + hasher and key_equal need to be DefaultConstructible. + + + + + + size_type + + + hasher const& + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + key_equal needs to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using a as the allocator, with the + default hash function and key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + hasher, key_equal need to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + hasher const& + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + a as the allocator, with the + default key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + key_equal needs to be DefaultConstructible. + + + The destructor is applied to every element, and all memory is deallocated @@ -3513,7 +4014,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) allocator_type() - Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + If the defaults are used, hasher, key_equal and @@ -3577,6 +4083,168 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + + unordered_multimap && + + + Allocator const& + + + Construct a container moving x's contained elements, and having the hash function, predicate and maximum load factor, but using allocate a. + + + This is implemented using Boost.Move. + + + + value_type is move insertable. + + + + + + initializer_list<value_type> + + + size_type + implementation-defined + + + hasher const& + hasher() + + + key_equal const& + key_equal() + + + allocator_type const& + allocator_type() + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + eq as the key equality predicate, + a as the allocator and a maximum load factor of 1.0 + and inserts the elements from il into it. + + + + If the defaults are used, hasher, key_equal and + allocator_type need to be DefaultConstructible. + + + + + + size_type + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default hash function and key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + hasher and key_equal need to be DefaultConstructible. + + + + + + size_type + + + hasher const& + + + allocator_type const& + + + size() == 0 + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + the default key equality predicate, + a as the allocator and a maximum load factor of 1.0. + + + key_equal needs to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using a as the allocator, with the + default hash function and key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + hasher, key_equal need to be DefaultConstructible. + + + + + + + InputIterator + + + InputIterator + + + size_type + + + hasher const& + + + allocator_type const& + + + Constructs an empty container with at least n buckets, + using hf as the hash function, + a as the allocator, with the + default key equality predicate + and a maximum load factor of 1.0 + and inserts the elements from [f, l) into it. + + + + key_equal needs to be DefaultConstructible. + + + The destructor is applied to every element, and all memory is deallocated diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 88108363..101b1c1c 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -90,6 +90,15 @@ namespace unordered const key_equal& = key_equal(), const allocator_type& = allocator_type()); + explicit unordered_map( + size_type, + const allocator_type&); + + explicit unordered_map( + size_type, + const hasher&, + const allocator_type&); + explicit unordered_map(allocator_type const&); template @@ -110,11 +119,25 @@ namespace unordered const key_equal&, const allocator_type&); + template + unordered_map( + InputIt, InputIt, + size_type, + const hasher&, + const allocator_type&); + + template + unordered_map( + InputIt, InputIt, + size_type, + const allocator_type&); + // copy/move constructors unordered_map(unordered_map const&); unordered_map(unordered_map const&, allocator_type const&); + unordered_map(BOOST_RV_REF(unordered_map), allocator_type const&); #if defined(BOOST_UNORDERED_USE_MOVE) unordered_map(BOOST_RV_REF(unordered_map) other) @@ -130,10 +153,6 @@ namespace unordered } #endif -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_map(unordered_map&&, allocator_type const&); -#endif - #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) unordered_map( std::initializer_list, @@ -141,6 +160,15 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); + unordered_map( + std::initializer_list, + size_type, + const hasher&, + const allocator_type&); + unordered_map( + std::initializer_list, + size_type, + const allocator_type&); #endif // Destructor @@ -568,12 +596,22 @@ namespace unordered // constructors unordered_multimap(); + explicit unordered_multimap( size_type, const hasher& = hasher(), const key_equal& = key_equal(), const allocator_type& = allocator_type()); + explicit unordered_multimap( + size_type, + const allocator_type&); + + explicit unordered_multimap( + size_type, + const hasher&, + const allocator_type&); + explicit unordered_multimap(allocator_type const&); template @@ -594,11 +632,25 @@ namespace unordered const key_equal&, const allocator_type&); + template + unordered_multimap( + InputIt, InputIt, + size_type, + const hasher&, + const allocator_type&); + + template + unordered_multimap( + InputIt, InputIt, + size_type, + const allocator_type&); + // copy/move constructors unordered_multimap(unordered_multimap const&); unordered_multimap(unordered_multimap const&, allocator_type const&); + unordered_multimap(BOOST_RV_REF(unordered_multimap), allocator_type const&); #if defined(BOOST_UNORDERED_USE_MOVE) unordered_multimap(BOOST_RV_REF(unordered_multimap) other) @@ -614,10 +666,6 @@ namespace unordered } #endif -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_multimap(unordered_multimap&&, allocator_type const&); -#endif - #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) unordered_multimap( std::initializer_list, @@ -625,6 +673,15 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); + unordered_multimap( + std::initializer_list, + size_type, + const hasher&, + const allocator_type&); + unordered_multimap( + std::initializer_list, + size_type, + const allocator_type&); #endif // Destructor @@ -1020,6 +1077,20 @@ namespace unordered { } + template + unordered_map::unordered_map( + size_type n, const allocator_type &a) + : table_(n, hasher(), key_equal(), a) + { + } + + template + unordered_map::unordered_map( + size_type n, const hasher &hf, const allocator_type &a) + : table_(n, hf, key_equal(), a) + { + } + template unordered_map::unordered_map(allocator_type const& a) : table_(boost::unordered::detail::default_bucket_count, @@ -1069,6 +1140,31 @@ namespace unordered table_.insert_range(f, l); } + template + template + unordered_map::unordered_map( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hf, key_equal(), a) + { + table_.insert_range(f, l); + } + + template + template + unordered_map::unordered_map( + InputIt f, InputIt l, + size_type n, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hasher(), key_equal(), a) + { + table_.insert_range(f, l); + } + template unordered_map::~unordered_map() BOOST_NOEXCEPT {} @@ -1079,17 +1175,13 @@ namespace unordered { } -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - template unordered_map::unordered_map( - unordered_map&& other, allocator_type const& a) + BOOST_RV_REF(unordered_map) other, allocator_type const& a) : table_(other.table_, a, boost::unordered::detail::move_tag()) { } -#endif - #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) template @@ -1104,6 +1196,30 @@ namespace unordered table_.insert_range(list.begin(), list.end()); } + template + unordered_map::unordered_map( + std::initializer_list list, size_type n, + const hasher &hf, const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_map::unordered_map( + std::initializer_list list, size_type n, + const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hasher(), key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + template unordered_map& unordered_map::operator=( std::initializer_list list) @@ -1360,6 +1476,20 @@ namespace unordered { } + template + unordered_multimap::unordered_multimap( + size_type n, const allocator_type &a) + : table_(n, hasher(), key_equal(), a) + { + } + + template + unordered_multimap::unordered_multimap( + size_type n, const hasher &hf, const allocator_type &a) + : table_(n, hf, key_equal(), a) + { + } + template unordered_multimap::unordered_multimap(allocator_type const& a) : table_(boost::unordered::detail::default_bucket_count, @@ -1409,6 +1539,31 @@ namespace unordered table_.insert_range(f, l); } + template + template + unordered_multimap::unordered_multimap( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hf, key_equal(), a) + { + table_.insert_range(f, l); + } + + template + template + unordered_multimap::unordered_multimap( + InputIt f, InputIt l, + size_type n, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hasher(), key_equal(), a) + { + table_.insert_range(f, l); + } + template unordered_multimap::~unordered_multimap() BOOST_NOEXCEPT {} @@ -1419,17 +1574,13 @@ namespace unordered { } -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - template unordered_multimap::unordered_multimap( - unordered_multimap&& other, allocator_type const& a) + BOOST_RV_REF(unordered_multimap) other, allocator_type const& a) : table_(other.table_, a, boost::unordered::detail::move_tag()) { } -#endif - #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) template @@ -1444,6 +1595,30 @@ namespace unordered table_.insert_range(list.begin(), list.end()); } + template + unordered_multimap::unordered_multimap( + std::initializer_list list, size_type n, + const hasher &hf, const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_multimap::unordered_multimap( + std::initializer_list list, size_type n, + const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hasher(), key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + template unordered_multimap& unordered_multimap::operator=( std::initializer_list list) diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 42c30bc9..77cd87e0 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -80,12 +80,22 @@ namespace unordered // constructors unordered_set(); + explicit unordered_set( size_type, const hasher& = hasher(), const key_equal& = key_equal(), const allocator_type& = allocator_type()); + explicit unordered_set( + size_type, + const allocator_type&); + + explicit unordered_set( + size_type, + const hasher&, + const allocator_type&); + explicit unordered_set(allocator_type const&); template @@ -106,11 +116,25 @@ namespace unordered const key_equal&, const allocator_type&); + template + unordered_set( + InputIt, InputIt, + size_type, + const hasher&, + const allocator_type&); + + template + unordered_set( + InputIt, InputIt, + size_type, + const allocator_type&); + // copy/move constructors unordered_set(unordered_set const&); unordered_set(unordered_set const&, allocator_type const&); + unordered_set(BOOST_RV_REF(unordered_set), allocator_type const&); #if defined(BOOST_UNORDERED_USE_MOVE) unordered_set(BOOST_RV_REF(unordered_set) other) @@ -126,10 +150,6 @@ namespace unordered } #endif -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_set(unordered_set&&, allocator_type const&); -#endif - #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) unordered_set( std::initializer_list, @@ -137,6 +157,15 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); + unordered_set( + std::initializer_list, + size_type, + const hasher&, + const allocator_type&); + unordered_set( + std::initializer_list, + size_type, + const allocator_type&); #endif // Destructor @@ -550,12 +579,22 @@ namespace unordered // constructors unordered_multiset(); + explicit unordered_multiset( size_type, const hasher& = hasher(), const key_equal& = key_equal(), const allocator_type& = allocator_type()); + explicit unordered_multiset( + size_type, + const allocator_type&); + + explicit unordered_multiset( + size_type, + const hasher&, + const allocator_type&); + explicit unordered_multiset(allocator_type const&); template @@ -576,11 +615,25 @@ namespace unordered const key_equal&, const allocator_type&); + template + unordered_multiset( + InputIt, InputIt, + size_type, + const hasher&, + const allocator_type&); + + template + unordered_multiset( + InputIt, InputIt, + size_type, + const allocator_type&); + // copy/move constructors unordered_multiset(unordered_multiset const&); unordered_multiset(unordered_multiset const&, allocator_type const&); + unordered_multiset(BOOST_RV_REF(unordered_multiset), allocator_type const&); #if defined(BOOST_UNORDERED_USE_MOVE) unordered_multiset(BOOST_RV_REF(unordered_multiset) other) @@ -596,10 +649,6 @@ namespace unordered } #endif -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_multiset(unordered_multiset&&, allocator_type const&); -#endif - #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) unordered_multiset( std::initializer_list, @@ -607,6 +656,15 @@ namespace unordered const hasher& = hasher(), const key_equal&l = key_equal(), const allocator_type& = allocator_type()); + unordered_multiset( + std::initializer_list, + size_type, + const hasher&, + const allocator_type&); + unordered_multiset( + std::initializer_list, + size_type, + const allocator_type&); #endif // Destructor @@ -993,6 +1051,20 @@ namespace unordered { } + template + unordered_set::unordered_set( + size_type n, const allocator_type &a) + : table_(n, hasher(), key_equal(), a) + { + } + + template + unordered_set::unordered_set( + size_type n, const hasher &hf, const allocator_type &a) + : table_(n, hf, key_equal(), a) + { + } + template unordered_set::unordered_set(allocator_type const& a) : table_(boost::unordered::detail::default_bucket_count, @@ -1042,6 +1114,31 @@ namespace unordered table_.insert_range(f, l); } + template + template + unordered_set::unordered_set( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hf, key_equal(), a) + { + table_.insert_range(f, l); + } + + template + template + unordered_set::unordered_set( + InputIt f, InputIt l, + size_type n, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hasher(), key_equal(), a) + { + table_.insert_range(f, l); + } + template unordered_set::~unordered_set() BOOST_NOEXCEPT {} @@ -1052,17 +1149,13 @@ namespace unordered { } -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - template unordered_set::unordered_set( - unordered_set&& other, allocator_type const& a) + BOOST_RV_REF(unordered_set) other, allocator_type const& a) : table_(other.table_, a, boost::unordered::detail::move_tag()) { } -#endif - #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) template @@ -1077,6 +1170,30 @@ namespace unordered table_.insert_range(list.begin(), list.end()); } + template + unordered_set::unordered_set( + std::initializer_list list, size_type n, + const hasher &hf, const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_set::unordered_set( + std::initializer_list list, size_type n, + const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hasher(), key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + template unordered_set& unordered_set::operator=( std::initializer_list list) @@ -1284,6 +1401,20 @@ namespace unordered { } + template + unordered_multiset::unordered_multiset( + size_type n, const allocator_type &a) + : table_(n, hasher(), key_equal(), a) + { + } + + template + unordered_multiset::unordered_multiset( + size_type n, const hasher &hf, const allocator_type &a) + : table_(n, hf, key_equal(), a) + { + } + template unordered_multiset::unordered_multiset(allocator_type const& a) : table_(boost::unordered::detail::default_bucket_count, @@ -1333,6 +1464,31 @@ namespace unordered table_.insert_range(f, l); } + template + template + unordered_multiset::unordered_multiset( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hf, key_equal(), a) + { + table_.insert_range(f, l); + } + + template + template + unordered_multiset::unordered_multiset( + InputIt f, InputIt l, + size_type n, + const allocator_type &a) + : table_(boost::unordered::detail::initial_size(f, l, n), + hasher(), key_equal(), a) + { + table_.insert_range(f, l); + } + template unordered_multiset::~unordered_multiset() BOOST_NOEXCEPT {} @@ -1343,17 +1499,13 @@ namespace unordered { } -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - template unordered_multiset::unordered_multiset( - unordered_multiset&& other, allocator_type const& a) + BOOST_RV_REF(unordered_multiset) other, allocator_type const& a) : table_(other.table_, a, boost::unordered::detail::move_tag()) { } -#endif - #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) template @@ -1368,6 +1520,30 @@ namespace unordered table_.insert_range(list.begin(), list.end()); } + template + unordered_multiset::unordered_multiset( + std::initializer_list list, size_type n, + const hasher &hf, const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_multiset::unordered_multiset( + std::initializer_list list, size_type n, + const allocator_type &a) + : table_( + boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hasher(), key_equal(), a) + { + table_.insert_range(list.begin(), list.end()); + } + template unordered_multiset& unordered_multiset::operator=( std::initializer_list list) diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 62a4c3fc..4663c8e5 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -123,6 +123,8 @@ void container_test(X& r, T const&) sink(X(a)); X u2(a); X u3 = a; + X u4(rvalue(a_const)); + X u5 = rvalue(a_const); a.swap(b); boost::swap(a, b); @@ -132,12 +134,25 @@ void container_test(X& r, T const&) typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type; test::check_return_type::equals(a_const.get_allocator()); + + allocator_type m = a.get_allocator(); + sink(X(m)); + X c(m); + sink(X(a_const, m)); + X c2(a_const, m); + sink(X(rvalue(a_const), m)); + X c3(rvalue(a_const), m); // Avoid unused variable warnings: sink(u); sink(u2); sink(u3); + sink(u4); + sink(u5); + sink(c); + sink(c2); + sink(c3); } template @@ -369,6 +384,7 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq) typedef BOOST_DEDUCED_TYPENAME boost::iterator_reference::type const_local_iterator_reference; + typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type; BOOST_STATIC_ASSERT((boost::is_same::value)); //boost::function_requires >(); @@ -401,8 +417,13 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq) BOOST_STATIC_ASSERT((boost::is_same::value)); + X a; + allocator_type m = a.get_allocator(); + + // Constructors + X(10, hf, eq); - X a(10, hf, eq); + X a1(10, hf, eq); X(10, hf); X a2(10, hf); X(10); @@ -410,6 +431,15 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq) X(); X a4; + X(10, hf, eq, m); + X a1a(10, hf, eq, m); + X(10, hf, m); + X a2a(10, hf, m); + X(10, m); + X a3a(10, m); + sink(X(m)); + X a4a(m); + test::check_return_type::equals(a.erase(k)); const_iterator q1 = a.cbegin(), q2 = a.cend(); @@ -452,9 +482,14 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq) // Avoid unused variable warnings: sink(a); + sink(a1); sink(a2); sink(a3); sink(a4); + sink(a1a); + sink(a2a); + sink(a3a); + sink(a4a); } template @@ -464,14 +499,17 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator; + typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type; X a; + allocator_type m = a.get_allocator(); BOOST_DEDUCED_TYPENAME X::value_type* i = 0; BOOST_DEDUCED_TYPENAME X::value_type* j = 0; - X(i, j, 10, hf, eq); + // Constructors + X(i, j, 10, hf, eq); X a5(i, j, 10, hf, eq); X(i, j, 10, hf); X a6(i, j, 10, hf); @@ -480,11 +518,38 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) X(i, j); X a8(i, j); + X(i, j, 10, hf, eq, m); + X a5a(i, j, 10, hf, eq, m); + X(i, j, 10, hf, m); + X a6a(i, j, 10, hf, m); + X(i, j, 10, m); + X a7a(i, j, 10, m); + + // Not specified for some reason (maybe ambiguity with another constructor?) + //X(i, j, m); + //X a8a(i, j, m); + //sink(a8a); + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + std::size_t min_buckets = 10; + X({t}); + X({t}, min_buckets); + X({t}, min_buckets, hf); + X({t}, min_buckets, hf, eq); + //X({t}, m); + X({t}, min_buckets, m); + X({t}, min_buckets, hf, m); + X({t}, min_buckets, hf, eq, m); +#endif + X const b; sink(X(b)); X a9(b); a = b; + sink(X(b, m)); + X a9a(b, m); + const_iterator q = a.cbegin(); test::check_return_type::equals(a.insert(q, t)); @@ -516,6 +581,10 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) sink(a7); sink(a8); sink(a9); + sink(a5a); + sink(a6a); + sink(a7a); + sink(a9a); } template @@ -525,6 +594,7 @@ void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq) typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator; + typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type; #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) X x1(rvalue_default()); @@ -533,9 +603,14 @@ void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq) x2 = boost::move(x1); #endif + X a; + allocator_type m = a.get_allocator(); + test::minimal::constructor_param* i = 0; test::minimal::constructor_param* j = 0; + // Constructors + X(i, j, 10, hf, eq); X a5(i, j, 10, hf, eq); X(i, j, 10, hf); @@ -545,7 +620,17 @@ void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq) X(i, j); X a8(i, j); - X a; + X(i, j, 10, hf, eq, m); + X a5a(i, j, 10, hf, eq, m); + X(i, j, 10, hf, m); + X a6a(i, j, 10, hf, m); + X(i, j, 10, m); + X a7a(i, j, 10, m); + + // Not specified for some reason (maybe ambiguity with another constructor?) + //X(i, j, m); + //X a8a(i, j, m); + //sink(a8a); const_iterator q = a.cbegin(); @@ -579,6 +664,9 @@ void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq) sink(a6); sink(a7); sink(a8); + sink(a5a); + sink(a6a); + sink(a7a); sink(a10); } From 5b5b46ea1ce412b0d317f2cb1538b5d0a50463d8 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Oct 2016 13:51:58 +0100 Subject: [PATCH 17/20] Disable Visual C++ __declspec(allocator) warning Visual C++ is warning that memory can't be tracked for allocators whose pointer types aren't actually pointers, which is a correct warning but not relevant for our concerns, and is caused by the unit tests, not the container implementation. --- test/Jamfile.v2 | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index daea0e74..7cfa8d71 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -14,6 +14,7 @@ project unordered-test/unordered gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow" darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow" clang:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow" + msvc:"/wd4494" ; #alias framework : /boost/test//boost_unit_test_framework ; From 14ccdbc7b6ef6a488aa55f2b5c587e8d1f02d3b1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 24 Oct 2016 09:46:13 +0100 Subject: [PATCH 18/20] Add guards against exceptions that shouldn't happen I'm getting a couple of "terminate called after throwing an instance of 'test::lightweight::test_exception'" errors on the sun platform. Not sure where they're happening, so I've made the code a tad more resilient against exceptions that should not really be thrown. --- test/helpers/exception_test.hpp | 35 +++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/test/helpers/exception_test.hpp b/test/helpers/exception_test.hpp index c3aad5d5..d1bc1317 100644 --- a/test/helpers/exception_test.hpp +++ b/test/helpers/exception_test.hpp @@ -179,12 +179,13 @@ namespace test { class test_runner { Test const& test_; + bool exception_in_check_; test_runner(test_runner const&); test_runner& operator=(test_runner const&); public: - test_runner(Test const& t) : test_(t) {} - void operator()() const { + test_runner(Test const& t) : test_(t), exception_in_check_(false) {} + void run() { DISABLE_EXCEPTIONS; test::scope = ""; BOOST_DEDUCED_TYPENAME Test::data_type x(test_.init()); @@ -199,14 +200,24 @@ namespace test { >(&Test::run, test_, x, strong); } catch(...) { - call_ignore_extra_parameters< - Test, - BOOST_DEDUCED_TYPENAME Test::data_type const, - BOOST_DEDUCED_TYPENAME Test::strong_type const - >(&Test::check, test_, constant(x), constant(strong)); + try { + DISABLE_EXCEPTIONS; + call_ignore_extra_parameters< + Test, + BOOST_DEDUCED_TYPENAME Test::data_type const, + BOOST_DEDUCED_TYPENAME Test::strong_type const + >(&Test::check, test_, constant(x), constant(strong)); + } catch(...) { + exception_in_check_ = true; + } throw; } } + void end() { + if (exception_in_check_) { + BOOST_ERROR("Unexcpected exception in test_runner check call."); + } + } }; // Quick exception testing based on lightweight test @@ -236,26 +247,30 @@ namespace test { iteration = 0; bool success = false; + char const* error_msg = 0; do { ++iteration; count = 0; try { - runner(); + runner.run(); success = true; } catch(test_failure) { - BOOST_ERROR("test_failure caught."); + error_msg = "test_failure caught."; break; } catch(test_exception) { continue; } catch(...) { - BOOST_ERROR("Unexpected exception."); + error_msg = "Unexpected exception."; break; } } while(!success); + + if (error_msg) { BOOST_ERROR(error_msg); } + runner.end(); } } } From a34785fa0d71ff328129f86ae4da78f731f614ad Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Oct 2016 18:04:34 +0100 Subject: [PATCH 19/20] Don't 'sink' uncopyable container Calling sink was causing older versions of gcc to copy the container, resulting in a compile error. So instead just disambiguate by putting brackets around the expression. --- test/unordered/compile_tests.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 4663c8e5..12581763 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -437,7 +437,7 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq) X a2a(10, hf, m); X(10, m); X a3a(10, m); - sink(X(m)); + (X(m)); X a4a(m); test::check_return_type::equals(a.erase(k)); From 98cce956f900da02e08f43b987af80c4dbef0ba2 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 28 Oct 2016 09:06:53 +0100 Subject: [PATCH 20/20] Try to fix a 64-bit powerpc g++ 7 warning Warning is: allocate.hpp:335:19: warning: conversion to ???unsigned int??? from ???long unsigned int??? may alter its value [-Wconversion] I'm not sure, but I think it's because the sizeof is a long unsigned int, and the template parameter is an unsigned int. The sizeof isn't even used, it's just there to get a value for expression SFINAE. --- include/boost/unordered/detail/allocate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index bddfaf4f..2d9cf4b6 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -325,7 +325,7 @@ namespace boost { namespace unordered { namespace detail { #if !defined(BOOST_NO_SFINAE_EXPR) - template struct expr_test; + template struct expr_test; template struct expr_test : T {}; # define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \