From c2d2be021aa7744778b0371d52d331c36d52a4c6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 8 Apr 2017 06:17:43 +0100 Subject: [PATCH 001/147] Don't test inserting from initializer list in old clang There's a problem with it causing an ambiguous overload. I don't think there's anything we can do to fix that, so just don't test it. There's another bug where a std::pair doesn't get correctly constructed from an rvalue when using Clang 3.1 in C++11 mode. But I can't see any way to easily fix that, and it's a pretty old compiler now. --- test/unordered/compile_tests.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index fb908ffd..babfd2fa 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -638,7 +638,9 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) a.insert(list); a.insert({t, t, t}); -#if !BOOST_WORKAROUND(BOOST_MSVC, < 1900) +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1900) && \ + (!defined(__clang__) || __clang_major__ >= 4 || \ + (__clang_major__ == 3 && __clang_minor__ >= 4)) a.insert({}); a.insert({t}); a.insert({t, t}); From 7e940e6e4549102c21d47c1603b43e719059007a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 12 Apr 2017 07:52:12 +0100 Subject: [PATCH 002/147] Fix some typos --- doc/changes.qbk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 3a294bb2..118ca16f 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -99,7 +99,7 @@ First official release. has been rewritten to use templates instead of macros for the implementation classes. -* The container objcet is now smaller thanks to using `boost::compressed_pair` +* The container object is now smaller thanks to using `boost::compressed_pair` for EBO and a slightly different function buffer - now using a bool instead of a member pointer. @@ -170,7 +170,7 @@ C++11 support has resulted in some breaking changes: longer does so. It does emulate the new `piecewise_construct` pair constructors - only you need to use `boost::piecewise_construct`. To use the old emulation of - the variadic consturctors define + the variadic constructors define `BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT`. [h2 Boost 1.49.0] @@ -207,7 +207,7 @@ C++11 support has resulted in some breaking changes: * Fix construction/destruction issue when using a C++11 compiler with a C++03 allocator ([ticket 7100]). * Remove a `try..catch` to support compiling without exceptions. -* Adjust SFINAE use to try to supprt g++ 3.4 ([ticket 7175]). +* Adjust SFINAE use to try to support g++ 3.4 ([ticket 7175]). * Updated to use the new config macros. [h2 Boost 1.52.0] @@ -307,7 +307,7 @@ C++11 support has resulted in some breaking changes: * Initial support for new C++17 member functions: `insert_or_assign` and `try_emplace` in `unordered_map`, * Initial support for `merge` and `extract`. - Does not include transfering nodes between + Does not include transferring nodes between `unordered_map` and `unordered_multimap` or between `unordered_set` and `unordered_multiset` yet. That will hopefully be in the next version of Boost. From 51cd1cd2af0442dc89a977f502a237fe02c94bf1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 12 Apr 2017 08:25:14 +0100 Subject: [PATCH 003/147] Some more typos --- doc/rationale.qbk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/rationale.qbk b/doc/rationale.qbk index 788cabc8..60f0849b 100644 --- a/doc/rationale.qbk +++ b/doc/rationale.qbk @@ -13,7 +13,7 @@ containers in the draft standard, so the interface was fixed. But there are still some implementation decisions to make. The priorities are conformance to the standard and portability. -The [@http://en.wikipedia.org/wiki/Hash_table wikipedia article on hash tables] +The [@http://en.wikipedia.org/wiki/Hash_table Wikipedia article on hash tables] has a good summary of the implementation issues for hash tables in general. [h2 Data Structure] @@ -100,7 +100,7 @@ knowledge of the number of bits in the hash value, so it isn't portable enough to use as a default. It can applicable in certain cases so the containers have a policy based implementation that can use this alternative technique. -Currently this is only done on 64 bit architecures, where prime number +Currently this is only done on 64 bit architectures, where prime number modulus can be expensive. Although this varies depending on the architecture, so I probably should revisit it. From 5d98f3d0f06ab708fef9f7019f7ffa3313c5d049 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 15 Apr 2017 17:35:08 +0100 Subject: [PATCH 004/147] Noexcept specs for swap free functions --- include/boost/unordered/unordered_map.hpp | 2 ++ include/boost/unordered/unordered_map_fwd.hpp | 9 ++++++--- include/boost/unordered/unordered_set.hpp | 2 ++ include/boost/unordered/unordered_set_fwd.hpp | 6 ++++-- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 64e5b1fd..f1d5b0df 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1594,6 +1594,7 @@ inline bool operator!=(unordered_map const& m1, template inline void swap( unordered_map& m1, unordered_map& m2) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2))) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy @@ -2003,6 +2004,7 @@ inline bool operator!=(unordered_multimap const& m1, template inline void swap(unordered_multimap& m1, unordered_multimap& m2) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2))) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy diff --git a/include/boost/unordered/unordered_map_fwd.hpp b/include/boost/unordered/unordered_map_fwd.hpp index 12855e92..ebac59b4 100644 --- a/include/boost/unordered/unordered_map_fwd.hpp +++ b/include/boost/unordered/unordered_map_fwd.hpp @@ -30,7 +30,9 @@ template inline bool operator!=( unordered_map const&, unordered_map const&); template -inline void swap(unordered_map&, unordered_map&); +inline void swap( + unordered_map& m1, unordered_map& m2) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2))); template , class P = std::equal_to, @@ -44,8 +46,9 @@ template inline bool operator!=(unordered_multimap const&, unordered_multimap const&); template -inline void swap( - unordered_multimap&, unordered_multimap&); +inline void swap(unordered_multimap& m1, + unordered_multimap& m2) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2))); template class node_handle_map; template struct insert_return_type_map; diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 40d566c2..fc35503d 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1297,6 +1297,7 @@ inline bool operator!=( template inline void swap(unordered_set& m1, unordered_set& m2) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2))) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy @@ -1681,6 +1682,7 @@ inline bool operator!=(unordered_multiset const& m1, template inline void swap( unordered_multiset& m1, unordered_multiset& m2) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2))) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy diff --git a/include/boost/unordered/unordered_set_fwd.hpp b/include/boost/unordered/unordered_set_fwd.hpp index d3a3b51e..24842c80 100644 --- a/include/boost/unordered/unordered_set_fwd.hpp +++ b/include/boost/unordered/unordered_set_fwd.hpp @@ -29,7 +29,8 @@ template inline bool operator!=( unordered_set const&, unordered_set const&); template -inline void swap(unordered_set& m1, unordered_set& m2); +inline void swap(unordered_set& m1, unordered_set& m2) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2))); template , class P = std::equal_to, class A = std::allocator > @@ -43,7 +44,8 @@ inline bool operator!=(unordered_multiset const&, unordered_multiset const&); template inline void swap( - unordered_multiset& m1, unordered_multiset& m2); + unordered_multiset& m1, unordered_multiset& m2) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2))); template class node_handle_set; template struct insert_return_type_set; From 972ac220f54c25ee9ef11e1cf967d68415bb6409 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 15 Apr 2017 17:35:08 +0100 Subject: [PATCH 005/147] Add missing insert(P&&) methods to unordered_map/unordered_multimap --- include/boost/unordered/unordered_map.hpp | 37 +++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index f1d5b0df..aa3913ae 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -545,6 +546,15 @@ template class unordered_map return this->emplace(boost::move(x)); } + template + std::pair insert(BOOST_RV_REF(P2) obj, + typename boost::enable_if_c< + boost::is_constructible::value, + void*>::type = 0) + { + return this->emplace(boost::forward(obj)); + } + iterator insert(const_iterator hint, value_type const& x) { return this->emplace_hint(hint, x); @@ -555,6 +565,15 @@ template class unordered_map return this->emplace_hint(hint, boost::move(x)); } + template + iterator insert(const_iterator hint, BOOST_RV_REF(P2) obj, + typename boost::enable_if_c< + boost::is_constructible::value, + void*>::type = 0) + { + return this->emplace_hint(hint, boost::forward(obj)); + } + template std::pair insert_or_assign( key_type const& k, BOOST_FWD_REF(M) obj) @@ -1037,6 +1056,15 @@ template class unordered_multimap return this->emplace(boost::move(x)); } + template + iterator insert(BOOST_RV_REF(P2) obj, + typename boost::enable_if_c< + boost::is_constructible::value, + void*>::type = 0) + { + return this->emplace(boost::forward(obj)); + } + iterator insert(const_iterator hint, value_type const& x) { return this->emplace_hint(hint, x); @@ -1047,6 +1075,15 @@ template class unordered_multimap return this->emplace_hint(hint, boost::move(x)); } + template + iterator insert(const_iterator hint, BOOST_RV_REF(P2) obj, + typename boost::enable_if_c< + boost::is_constructible::value, + void*>::type = 0) + { + return this->emplace_hint(hint, boost::forward(obj)); + } + template void insert(InputIt, InputIt); #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) From 97b68ea05e6c87a6e8d8eca1011ba66d27ab7f10 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 15 Apr 2017 17:35:08 +0100 Subject: [PATCH 006/147] Rename (grouped_)table_impl to table_unique/equiv The old names don't make sense any more as either style can be used for containers with equivalent keys, due to the use of node_algo. --- .../boost/unordered/detail/implementation.hpp | 48 +++++++++---------- include/boost/unordered/detail/map.hpp | 4 +- include/boost/unordered/detail/set.hpp | 4 +- include/boost/unordered/unordered_map.hpp | 4 +- include/boost/unordered/unordered_set.hpp | 4 +- 5 files changed, 30 insertions(+), 34 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index c293ae2f..4c482d78 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -122,16 +122,16 @@ namespace detail { template struct table; template struct bucket; struct ptr_bucket; -template struct table_impl; -template struct grouped_table_impl; +template struct table_unique; +template struct table_equiv; template struct unique_node; template struct ptr_node; -template struct table_impl; +template struct table_unique; template struct grouped_node; template struct grouped_ptr_node; -template struct grouped_table_impl; +template struct table_equiv; template struct node_algo; template struct grouped_node_algo; @@ -1921,9 +1921,8 @@ struct iterator : public std::iterator friend struct boost::unordered::iterator_detail::c_iterator; template friend struct boost::unordered::detail::table; - template friend struct boost::unordered::detail::table_impl; - template - friend struct boost::unordered::detail::grouped_table_impl; + template friend struct boost::unordered::detail::table_unique; + template friend struct boost::unordered::detail::table_equiv; private: #endif @@ -1978,9 +1977,8 @@ struct c_iterator #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template friend struct boost::unordered::detail::table; - template friend struct boost::unordered::detail::table_impl; - template - friend struct boost::unordered::detail::grouped_table_impl; + template friend struct boost::unordered::detail::table_unique; + template friend struct boost::unordered::detail::table_equiv; private: #endif @@ -3607,7 +3605,7 @@ template struct pick_node }; template -struct table_impl : boost::unordered::detail::table +struct table_unique : boost::unordered::detail::table { typedef boost::unordered::detail::table table; typedef typename table::value_type value_type; @@ -3633,30 +3631,30 @@ struct table_impl : boost::unordered::detail::table // Constructors - table_impl(std::size_t n, hasher const& hf, key_equal const& eq, + table_unique(std::size_t n, hasher const& hf, key_equal const& eq, node_allocator const& a) : table(n, hf, eq, a) { } - table_impl(table_impl const& x) + table_unique(table_unique const& x) : table(x, node_allocator_traits::select_on_container_copy_construction( x.node_alloc())) { this->init(x); } - table_impl(table_impl const& x, node_allocator const& a) : table(x, a) + table_unique(table_unique const& x, node_allocator const& a) : table(x, a) { this->init(x); } - table_impl(table_impl& x, boost::unordered::detail::move_tag m) + table_unique(table_unique& x, boost::unordered::detail::move_tag m) : table(x, m) { } - table_impl(table_impl& x, node_allocator const& a, + table_unique(table_unique& x, node_allocator const& a, boost::unordered::detail::move_tag m) : table(x, a, m) { @@ -3691,7 +3689,7 @@ struct table_impl : boost::unordered::detail::table // equals - bool equals(table_impl const& other) const + bool equals(table_unique const& other) const { if (this->size_ != other.size_) return false; @@ -4431,7 +4429,7 @@ template struct pick_grouped_node }; template -struct grouped_table_impl : boost::unordered::detail::table +struct table_equiv : boost::unordered::detail::table { typedef boost::unordered::detail::table table; typedef typename table::value_type value_type; @@ -4454,32 +4452,30 @@ struct grouped_table_impl : boost::unordered::detail::table // Constructors - grouped_table_impl(std::size_t n, hasher const& hf, key_equal const& eq, + table_equiv(std::size_t n, hasher const& hf, key_equal const& eq, node_allocator const& a) : table(n, hf, eq, a) { } - grouped_table_impl(grouped_table_impl const& x) + table_equiv(table_equiv const& x) : table(x, node_allocator_traits::select_on_container_copy_construction( x.node_alloc())) { this->init(x); } - grouped_table_impl(grouped_table_impl const& x, node_allocator const& a) - : table(x, a) + table_equiv(table_equiv const& x, node_allocator const& a) : table(x, a) { this->init(x); } - grouped_table_impl( - grouped_table_impl& x, boost::unordered::detail::move_tag m) + table_equiv(table_equiv& x, boost::unordered::detail::move_tag m) : table(x, m) { } - grouped_table_impl(grouped_table_impl& x, node_allocator const& a, + table_equiv(table_equiv& x, node_allocator const& a, boost::unordered::detail::move_tag m) : table(x, a, m) { @@ -4503,7 +4499,7 @@ struct grouped_table_impl : boost::unordered::detail::table // Equality - bool equals(grouped_table_impl const& other) const + bool equals(table_equiv const& other) const { if (this->size_ != other.size_) return false; diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index cb9a954b..a8bf9f3a 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -29,7 +29,7 @@ template struct map typedef typename pick::link_pointer link_pointer; typedef typename pick::node_algo node_algo; - typedef boost::unordered::detail::table_impl table; + typedef boost::unordered::detail::table_unique table; typedef boost::unordered::detail::map_extractor extractor; typedef typename boost::unordered::detail::pick_policy::type policy; @@ -71,7 +71,7 @@ struct multimap typedef typename pick::link_pointer link_pointer; typedef typename pick::node_algo node_algo; - typedef boost::unordered::detail::grouped_table_impl table; + typedef boost::unordered::detail::table_equiv table; typedef boost::unordered::detail::map_extractor extractor; typedef typename boost::unordered::detail::pick_policy::type policy; diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index 42e9cad7..2e7d6ef5 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -29,7 +29,7 @@ template struct set typedef typename pick::link_pointer link_pointer; typedef typename pick::node_algo node_algo; - typedef boost::unordered::detail::table_impl table; + typedef boost::unordered::detail::table_unique table; typedef boost::unordered::detail::set_extractor extractor; typedef typename boost::unordered::detail::pick_policy::type policy; @@ -70,7 +70,7 @@ template struct multiset typedef typename pick::link_pointer link_pointer; typedef typename pick::node_algo node_algo; - typedef boost::unordered::detail::grouped_table_impl table; + typedef boost::unordered::detail::table_equiv table; typedef boost::unordered::detail::set_extractor extractor; typedef typename boost::unordered::detail::pick_policy::type policy; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index aa3913ae..f4dbeaf5 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -2057,9 +2057,9 @@ template class node_handle_map BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle_map) template - friend struct ::boost::unordered::detail::table_impl; + friend struct ::boost::unordered::detail::table_unique; template - friend struct ::boost::unordered::detail::grouped_table_impl; + friend struct ::boost::unordered::detail::table_equiv; typedef typename boost::unordered::detail::rebind_wrap >::type value_allocator; diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index fc35503d..fe1f2196 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1698,9 +1698,9 @@ template class node_handle_set BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle_set) template - friend struct ::boost::unordered::detail::table_impl; + friend struct ::boost::unordered::detail::table_unique; template - friend struct ::boost::unordered::detail::grouped_table_impl; + friend struct ::boost::unordered::detail::table_equiv; typedef typename boost::unordered::detail::rebind_wrap::type value_allocator; From f089adc160eb6d36146792ef3c3a5c48e51aaa18 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 15 Apr 2017 17:35:08 +0100 Subject: [PATCH 007/147] Change get_key to have node parameter --- .../boost/unordered/detail/implementation.hpp | 51 +++++++++---------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 4c482d78..2a2f7c65 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3095,9 +3095,9 @@ struct table : boost::unordered::detail::functionsvalue()); } std::size_t hash(const_key_type& k) const @@ -3137,7 +3137,7 @@ struct table : boost::unordered::detail::functionshash_; if (key_hash == node_hash) { - if (eq(k, this->get_key(n->value()))) + if (eq(k, this->get_key(n))) return n; } else { if (this->hash_to_bucket(node_hash) != bucket_index) @@ -3166,8 +3166,7 @@ struct table : boost::unordered::detail::functionskey_eq()( - k, this->get_key(node_algo::next_node(prev)->value()))) { + this->key_eq()(k, this->get_key(node_algo::next_node(prev)))) { return prev; } prev = node_algo::next_for_erase(prev); @@ -3515,8 +3514,7 @@ template struct node_algo node_pointer n1 = n; do { n1 = next_node(n1); - } while ( - n1 && t->key_eq()(t->get_key(n->value()), t->get_key(n1->value()))); + } while (n1 && t->key_eq()(t->get_key(n), t->get_key(n1))); return n1; } @@ -3528,8 +3526,7 @@ template struct node_algo do { ++x; it = next_node(it); - } while ( - it && t->key_eq()(t->get_key(n->value()), t->get_key(it->value()))); + } while (it && t->key_eq()(t->get_key(n), t->get_key(it))); return x; } @@ -3696,7 +3693,7 @@ struct table_unique : boost::unordered::detail::table for (node_pointer n1 = this->begin(); n1; n1 = node_algo::next_node(n1)) { - node_pointer n2 = other.find_node(other.get_key(n1->value())); + node_pointer n2 = other.find_node(other.get_key(n1)); if (!n2 || n1->value() != n2->value()) return false; @@ -3821,7 +3818,7 @@ struct table_unique : boost::unordered::detail::table iterator emplace_hint_impl( c_iterator hint, const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS) { - if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { + if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { return iterator(hint.node_); } else { return emplace_impl(k, BOOST_UNORDERED_EMPLACE_FORWARD).first; @@ -3852,8 +3849,8 @@ struct table_unique : boost::unordered::detail::table node_tmp b(boost::unordered::detail::func::construct_node_from_args( this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), this->node_alloc()); - const_key_type& k = this->get_key(b.node_->value()); - if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { + const_key_type& k = this->get_key(b.node_); + if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { return iterator(hint.node_); } std::size_t key_hash = this->hash(k); @@ -3871,7 +3868,7 @@ struct table_unique : boost::unordered::detail::table node_tmp b(boost::unordered::detail::func::construct_node_from_args( this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), this->node_alloc()); - const_key_type& k = this->get_key(b.node_->value()); + const_key_type& k = this->get_key(b.node_); std::size_t key_hash = this->hash(k); node_pointer pos = this->find_node(key_hash, k); if (pos) { @@ -3966,7 +3963,7 @@ struct table_unique : boost::unordered::detail::table void move_insert_node_type(NodeType& np, InsertReturnType& result) { if (np) { - const_key_type& k = this->get_key(np.ptr_->value()); + const_key_type& k = this->get_key(np.ptr_); std::size_t key_hash = this->hash(k); node_pointer pos = this->find_node(key_hash, k); @@ -3988,8 +3985,8 @@ struct table_unique : boost::unordered::detail::table if (!np) { return iterator(); } - const_key_type& k = this->get_key(np.ptr_->value()); - if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { + const_key_type& k = this->get_key(np.ptr_); + if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { return iterator(hint.node_); } std::size_t key_hash = this->hash(k); @@ -4015,7 +4012,7 @@ struct table_unique : boost::unordered::detail::table while (prev->next_) { node_pointer n = other_table::node_algo::next_node(prev); - const_key_type& k = this->get_key(n->value()); + const_key_type& k = this->get_key(n); std::size_t key_hash = this->hash(k); node_pointer pos = this->find_node(key_hash, k); @@ -4095,7 +4092,7 @@ struct table_unique : boost::unordered::detail::table a.alloc_, a.node_->value_ptr(), *i); node_tmp b(a.release(), a.alloc_); - const_key_type& k = this->get_key(b.node_->value()); + const_key_type& k = this->get_key(b.node_); std::size_t key_hash = this->hash(k); node_pointer pos = this->find_node(key_hash, k); @@ -4505,7 +4502,7 @@ struct table_equiv : boost::unordered::detail::table return false; for (node_pointer n1 = this->begin(); n1;) { - node_pointer n2 = other.find_node(other.get_key(n1->value())); + node_pointer n2 = other.find_node(other.get_key(n1)); if (!n2) return false; node_pointer end1 = node_algo::next_group(n1, this); @@ -4691,7 +4688,7 @@ struct table_equiv : boost::unordered::detail::table iterator emplace_impl(node_pointer n) { node_tmp a(n, this->node_alloc()); - const_key_type& k = this->get_key(a.node_->value()); + const_key_type& k = this->get_key(a.node_); std::size_t key_hash = this->hash(k); node_pointer position = this->find_node(key_hash, k); this->reserve_for_insert(this->size_ + 1); @@ -4701,8 +4698,8 @@ struct table_equiv : boost::unordered::detail::table iterator emplace_hint_impl(c_iterator hint, node_pointer n) { node_tmp a(n, this->node_alloc()); - const_key_type& k = this->get_key(a.node_->value()); - if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { + const_key_type& k = this->get_key(a.node_); + if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { this->reserve_for_insert(this->size_ + 1); return iterator(this->add_using_hint(a.release(), hint.node_)); } else { @@ -4716,7 +4713,7 @@ struct table_equiv : boost::unordered::detail::table void emplace_impl_no_rehash(node_pointer n) { node_tmp a(n, this->node_alloc()); - const_key_type& k = this->get_key(a.node_->value()); + const_key_type& k = this->get_key(a.node_); std::size_t key_hash = this->hash(k); node_pointer position = this->find_node(key_hash, k); this->add_node(a.release(), key_hash, position); @@ -4727,7 +4724,7 @@ struct table_equiv : boost::unordered::detail::table iterator result; if (np) { - const_key_type& k = this->get_key(np.ptr_->value()); + const_key_type& k = this->get_key(np.ptr_); std::size_t key_hash = this->hash(k); node_pointer pos = this->find_node(key_hash, k); this->reserve_for_insert(this->size_ + 1); @@ -4744,9 +4741,9 @@ struct table_equiv : boost::unordered::detail::table iterator result; if (np) { - const_key_type& k = this->get_key(np.ptr_->value()); + const_key_type& k = this->get_key(np.ptr_); - if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) { + if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { this->reserve_for_insert(this->size_ + 1); result = iterator(this->add_using_hint(np.ptr_, hint.node_)); } else { From 09bddd8df4a833d1199a856967188900d6226ec8 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 15 Apr 2017 17:35:08 +0100 Subject: [PATCH 008/147] Clear buckets before deleting nodes in clear. The order shouldn't really matter as nothing throws an exception, but it seems cleaner to never have any dangling pointers. --- include/boost/unordered/detail/implementation.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 2a2f7c65..e51b0254 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -2925,8 +2925,8 @@ struct table : boost::unordered::detail::functions Date: Sat, 15 Apr 2017 17:35:09 +0100 Subject: [PATCH 009/147] Comment about clear_buckets/create_buckets awkwardness. They both leave the container in an invalid state that needs to be cleaned up immediately. This confused me slightly. --- .../boost/unordered/detail/implementation.hpp | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index e51b0254..2d0830ea 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -2765,8 +2765,30 @@ struct table : boost::unordered::detail::functionsnext_ = node_pointer(); + } + } + + // Create container buckets. If the container already contains any buckets + // the linked list will be transferred to the new buckets, but none + // of the bucket pointers will be set. See above note. + // + // Strong exception safety. void create_buckets(std::size_t new_count) { std::size_t length = new_count + 1; @@ -2931,14 +2953,6 @@ struct table : boost::unordered::detail::functionsnext_ = node_pointer(); - } - } - void destroy_buckets() { bucket_pointer end = get_bucket(bucket_count_ + 1); From 2bfc59c46149642d09a12014259f81038e452147 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 15 Apr 2017 17:35:09 +0100 Subject: [PATCH 010/147] Make node_handler constructor private + additional compile tests --- include/boost/unordered/unordered_map.hpp | 17 +++++---- include/boost/unordered/unordered_set.hpp | 17 +++++---- test/unordered/compile_tests.hpp | 42 ++++++++++++++++++++--- 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index f4dbeaf5..8aaf8d33 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -2060,6 +2060,10 @@ template class node_handle_map friend struct ::boost::unordered::detail::table_unique; template friend struct ::boost::unordered::detail::table_equiv; + template + friend class boost::unordered::unordered_map; + template + friend class boost::unordered::unordered_multimap; typedef typename boost::unordered::detail::rebind_wrap >::type value_allocator; @@ -2082,13 +2086,7 @@ template class node_handle_map bool has_alloc_; boost::unordered::detail::value_base alloc_; - public: - BOOST_CONSTEXPR node_handle_map() BOOST_NOEXCEPT : ptr_(), has_alloc_(false) - { - } - - /*BOOST_CONSTEXPR */ node_handle_map( - node_pointer ptr, allocator_type const& a) + node_handle_map(node_pointer ptr, allocator_type const& a) : ptr_(ptr), has_alloc_(false) { if (ptr_) { @@ -2097,6 +2095,11 @@ template class node_handle_map } } + public: + BOOST_CONSTEXPR node_handle_map() BOOST_NOEXCEPT : ptr_(), has_alloc_(false) + { + } + ~node_handle_map() { if (has_alloc_ && ptr_) { diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index fe1f2196..0c6b221a 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1701,6 +1701,10 @@ template class node_handle_set friend struct ::boost::unordered::detail::table_unique; template friend struct ::boost::unordered::detail::table_equiv; + template + friend class unordered_set; + template + friend class unordered_multiset; typedef typename boost::unordered::detail::rebind_wrap::type value_allocator; @@ -1722,13 +1726,7 @@ template class node_handle_set bool has_alloc_; boost::unordered::detail::value_base alloc_; - public: - BOOST_CONSTEXPR node_handle_set() BOOST_NOEXCEPT : ptr_(), has_alloc_(false) - { - } - - /*BOOST_CONSTEXPR */ node_handle_set( - node_pointer ptr, allocator_type const& a) + node_handle_set(node_pointer ptr, allocator_type const& a) : ptr_(ptr), has_alloc_(false) { if (ptr_) { @@ -1737,6 +1735,11 @@ template class node_handle_set } } + public: + BOOST_CONSTEXPR node_handle_set() BOOST_NOEXCEPT : ptr_(), has_alloc_(false) + { + } + ~node_handle_set() { if (has_alloc_ && ptr_) { diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index babfd2fa..df49bf91 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,23 @@ template void sink(T const&) {} template T rvalue(T const& v) { return v; } template T rvalue_default() { return T(); } +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +template T implicit_construct() { return {}; } +#else +template int implicit_construct() +{ + T x; + sink(x); + return 0; +} +#endif + +#if !defined(BOOST_NO_CXX11_NOEXCEPT) +#define TEST_NOEXCEPT_EXPR(x) BOOST_STATIC_ASSERT((BOOST_NOEXCEPT_EXPR(x))); +#else +#define TEST_NOEXCEPT_EXPR(x) +#endif + template void container_test(X& r, T const&) { typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; @@ -52,6 +70,8 @@ template void container_test(X& r, T const&) typedef BOOST_DEDUCED_TYPENAME X::node_type node_type; + typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type; + // value_type BOOST_STATIC_ASSERT((boost::is_same::value)); @@ -75,7 +95,9 @@ template void container_test(X& r, T const&) BOOST_STATIC_ASSERT((boost::is_same::value)); // node_type - // TODO? + + BOOST_STATIC_ASSERT((boost::is_same::value)); // difference_type @@ -134,7 +156,6 @@ template void container_test(X& r, T const&) // Allocator - typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type; test::check_return_type::equals(a_const.get_allocator()); allocator_type m = a.get_allocator(); @@ -147,21 +168,26 @@ template void container_test(X& r, T const&) // node_type - typedef BOOST_DEDUCED_TYPENAME X::node_type node_type; - BOOST_STATIC_ASSERT((boost::is_same::value)); + implicit_construct(); + TEST_NOEXCEPT_EXPR(node_type()); node_type n1; node_type n2(rvalue_default()); + TEST_NOEXCEPT_EXPR(node_type(boost::move(n1))); node_type n3; n3 = boost::move(n2); n1.swap(n3); swap(n1, n3); + // TODO: noexcept for swap? + // value, key, mapped tests in map and set specific testing. node_type const n_const; BOOST_TEST(n_const ? 0 : 1); + TEST_NOEXCEPT_EXPR(n_const ? 0 : 1); test::check_return_type::equals(!n_const); test::check_return_type::equals(n_const.empty()); + TEST_NOEXCEPT_EXPR(!n_const); + TEST_NOEXCEPT_EXPR(n_const.empty()); // Avoid unused variable warnings: @@ -302,6 +328,8 @@ void unordered_map_test(X& r, Key const& k, T const& v) BOOST_STATIC_ASSERT((boost::is_same::value)); BOOST_STATIC_ASSERT((boost::is_same::value)); + // Superfluous,but just to make sure. + BOOST_STATIC_ASSERT((!boost::is_const::value)); // Calling functions @@ -329,6 +357,10 @@ void unordered_map_test(X& r, Key const& k, T const& v) r.insert(boost::move(n1)); r.insert(r.end(), r.extract(r.begin())); + + node_type n = r.extract(r.begin()); + test::check_return_type::equals_ref(n.key()); + test::check_return_type::equals_ref(n.mapped()); } template void equality_test(X& r) From ed8c0f9ecdf6ec558c2e6c405f63bd28bc3c25b4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 15 Apr 2017 17:35:09 +0100 Subject: [PATCH 011/147] Add deprecated attributes to deprecated functions --- doc/changes.qbk | 5 ++++ .../boost/unordered/detail/implementation.hpp | 27 +++++++++++++++++++ include/boost/unordered/unordered_map.hpp | 4 +++ include/boost/unordered/unordered_set.hpp | 4 +++ test/Jamfile.v2 | 2 +- 5 files changed, 41 insertions(+), 1 deletion(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 118ca16f..987c818f 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -312,4 +312,9 @@ C++11 support has resulted in some breaking changes: `unordered_multiset` yet. That will hopefully be in the next version of Boost. +[h2 Boost 1.65.0] + +* Add deprecated attributes to `quick_erase` and `erase_return_void`. + Will fully remove in a future version. + [endsect] diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 2d0830ea..9b5928e1 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -104,6 +104,33 @@ #define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0 #endif +// +// Other configuration macros +// + +#if defined(BOOST_UNORDERED_SUPPRESS_DEPRECATED) +#define BOOST_UNORDERED_DEPRECATED(msg) +#endif + +#if defined(__has_cpp_attribute) && \ + (!defined(BOOST_GCC) || defined(BOOST_GCC_CXX11)) +#if __has_cpp_attribute(deprecated) && !defined(BOOST_UNORDERED_DEPRECATED) +#define BOOST_UNORDERED_DEPRECATED(msg) [[deprecated(msg)]] +#endif +#endif + +#if !defined(BOOST_UNORDERED_DEPRECATED) +#if defined(__GNUC__) && __GNUC__ >= 4 +#define BOOST_UNORDERED_DEPRECATED(msg) __attribute__((deprecated)) +#elif defined(_MSC_VER) && _MSC_VER >= 1400 +#define BOOST_UNORDERED_DEPRECATED(msg) __declspec(deprecated(msg)) +#elif defined(_MSC_VER) && _MSC_VER >= 1310 +#define BOOST_UNORDERED_DEPRECATED(msg) __declspec(deprecated) +#else +#define BOOST_UNORDERED_DEPRECATED(msg) +#endif +#endif + namespace boost { namespace unordered { namespace iterator_detail { diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 8aaf8d33..75e8a02a 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -635,7 +635,9 @@ template class unordered_map iterator erase(const_iterator); size_type erase(const key_type&); iterator erase(const_iterator, const_iterator); + BOOST_UNORDERED_DEPRECATED("Use erase instead") void quick_erase(const_iterator it) { erase(it); } + BOOST_UNORDERED_DEPRECATED("Use erase instead") void erase_return_void(const_iterator it) { erase(it); } void clear(); @@ -1112,7 +1114,9 @@ template class unordered_multimap iterator erase(const_iterator); size_type erase(const key_type&); iterator erase(const_iterator, const_iterator); + BOOST_UNORDERED_DEPRECATED("Use erase instead") void quick_erase(const_iterator it) { erase(it); } + BOOST_UNORDERED_DEPRECATED("Use erase instead") void erase_return_void(const_iterator it) { erase(it); } void clear(); diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 0c6b221a..afb25916 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -388,7 +388,9 @@ template class unordered_set iterator erase(const_iterator); size_type erase(const key_type&); iterator erase(const_iterator, const_iterator); + BOOST_UNORDERED_DEPRECATED("Use erase instead") void quick_erase(const_iterator it) { erase(it); } + BOOST_UNORDERED_DEPRECATED("Use erase instead") void erase_return_void(const_iterator it) { erase(it); } void clear(); @@ -835,7 +837,9 @@ template class unordered_multiset iterator erase(const_iterator); size_type erase(const key_type&); iterator erase(const_iterator, const_iterator); + BOOST_UNORDERED_DEPRECATED("Use erase instead") void quick_erase(const_iterator it) { erase(it); } + BOOST_UNORDERED_DEPRECATED("Use erase instead") void erase_return_void(const_iterator it) { erase(it); } void clear(); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 2aad7e8d..c50aec60 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -45,7 +45,7 @@ test-suite unordered [ run unordered/insert_hint_tests.cpp ] [ run unordered/emplace_tests.cpp ] [ run unordered/unnecessary_copy_tests.cpp ] - [ run unordered/erase_tests.cpp ] + [ run unordered/erase_tests.cpp : : : BOOST_UNORDERED_SUPPRESS_DEPRECATED ] [ run unordered/erase_equiv_tests.cpp ] [ run unordered/extract_tests.cpp ] [ run unordered/node_handle_tests.cpp ] From c0e03c36407e5ffe0ea4a6b0e82262a50d4b418e Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 15 Apr 2017 20:52:00 +0100 Subject: [PATCH 012/147] Add some more details to change log --- doc/changes.qbk | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 987c818f..9fa3f753 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -315,6 +315,9 @@ C++11 support has resulted in some breaking changes: [h2 Boost 1.65.0] * Add deprecated attributes to `quick_erase` and `erase_return_void`. - Will fully remove in a future version. + I really will remove them in a future version this time. +* Small standards compliance fixes: + * `noexpect` specs for `swap` free functions. + * Add missing `insert(P&&)` methods. [endsect] From 64a3be7d3e76bcf3818eaf2b9eb37e585297d402 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 16 Apr 2017 10:37:10 +0100 Subject: [PATCH 013/147] Use aligned_storage's address method to get pointer --- include/boost/unordered/detail/implementation.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 9b5928e1..ae40fce1 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -2357,13 +2357,13 @@ template class functions function_pair const& current() const { return *static_cast( - static_cast(&funcs_[current_])); + static_cast(funcs_[current_].address())); } function_pair& current() { return *static_cast( - static_cast(&funcs_[current_])); + static_cast(funcs_[current_].address())); } void construct(bool which, H const& hf, P const& eq) From 2b01bdbc259427f3e1cacac91be3cd7700e005b8 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 16 Apr 2017 16:34:22 +0100 Subject: [PATCH 014/147] More general deprecated check `__has_cpp_attribute(deprecated)` returns true for C++11, but then warns that it's a C++14 attribute, so only check in C++14 mode. --- include/boost/unordered/detail/implementation.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index ae40fce1..47bc5b82 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -113,7 +113,7 @@ #endif #if defined(__has_cpp_attribute) && \ - (!defined(BOOST_GCC) || defined(BOOST_GCC_CXX11)) + (!defined(__cplusplus) || __cplusplus >= 201402) #if __has_cpp_attribute(deprecated) && !defined(BOOST_UNORDERED_DEPRECATED) #define BOOST_UNORDERED_DEPRECATED(msg) [[deprecated(msg)]] #endif From 7e5520f974bc74078ed680af0c7d1a8d852370b4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 015/147] Increase template depth for GCC This appears to be an unavoidable problem with GCC's tuple implementation. For example: http://stackoverflow.com/q/23374953/2434 Appears to be okay in later versions of GCC though. --- test/Jamfile.v2 | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c50aec60..72c09867 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -15,6 +15,7 @@ project unordered-test/unordered 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" + gcc:500 ; #alias framework : /boost/test//boost_unit_test_framework ; From 1092c972c908861599c30840dbb754888a70d198 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 016/147] Use allocator_traits to construct/destruct buckets --- .../boost/unordered/detail/implementation.hpp | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 47bc5b82..c534a94e 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -2156,6 +2156,7 @@ template struct bucket link_pointer next_; bucket() : next_() {} + bucket(link_pointer n) : next_(n) {} link_pointer first_from_start() { return next_; } @@ -2171,6 +2172,7 @@ struct ptr_bucket link_pointer next_; ptr_bucket() : next_(0) {} + ptr_bucket(link_pointer n) : next_(n) {} link_pointer first_from_start() { return this; } @@ -2826,30 +2828,39 @@ struct table : boost::unordered::detail::functions(length); + new_buckets + static_cast(new_count); for (; constructed != end; ++constructed) { - new ((void*)boost::addressof(*constructed)) bucket(); + boost::unordered::detail::func::call_construct( + bucket_alloc(), boost::addressof(*constructed)); } if (buckets_) { // Copy the nodes to the new buckets, including the dummy // node if there is one. - (new_buckets + static_cast(new_count))->next_ = + boost::unordered::detail::func::call_construct(bucket_alloc(), + boost::addressof(*constructed), (buckets_ + static_cast(bucket_count_)) - ->next_; + ->next_); + ++constructed; destroy_buckets(); } else if (bucket::extra_node) { node_constructor a(node_alloc()); a.create_node(); - (new_buckets + static_cast(new_count))->next_ = - a.release(); + boost::unordered::detail::func::call_construct(bucket_alloc(), + boost::addressof(*constructed), a.release()); + ++constructed; + } else { + boost::unordered::detail::func::call_construct( + bucket_alloc(), boost::addressof(*constructed)); + ++constructed; } } BOOST_CATCH(...) { for (bucket_pointer p = new_buckets; p != constructed; ++p) { - boost::unordered::detail::func::destroy(boost::addressof(*p)); + boost::unordered::detail::func::call_destroy( + bucket_alloc(), boost::addressof(*p)); } bucket_allocator_traits::deallocate( @@ -2984,7 +2995,8 @@ struct table : boost::unordered::detail::functions Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 017/147] Replace BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT with BOOST_UNORDERED_CXX11_CONSTRUCTION Require good construct support and piecewise construction. I don't know if there are any platforms with good construct support, but no piecewise construction, if there are then they'll no longer use 'allocator_traits::construct'/'allocator_traits::destruct'. --- .../boost/unordered/detail/implementation.hpp | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index c534a94e..c0f069c8 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -104,6 +104,25 @@ #define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0 #endif +// BOOST_UNORDERED_CXX11_CONSTRUCTION +// +// Use C++11 construction, requires variadic arguments, good construct support +// in allocator_traits and piecewise construction of std::pair +// Otherwise allocators aren't used for construction/destruction + +#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT && \ + !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 && !defined(BOOST_NO_SFINAE_EXPR) +#define BOOST_UNORDERED_CXX11_CONSTRUCTION 1 +#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 +#define BOOST_UNORDERED_CXX11_CONSTRUCTION 1 +#endif +#endif + +#if !defined(BOOST_UNORDERED_CXX11_CONSTRUCTION) +#define BOOST_UNORDERED_CXX11_CONSTRUCTION 0 +#endif + // // Other configuration macros // @@ -765,13 +784,6 @@ template struct identity #include #include -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ - !defined(BOOST_NO_SFINAE_EXPR) -#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1 -#else -#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0 -#endif - namespace boost { namespace unordered { namespace detail { @@ -1040,7 +1052,7 @@ template struct allocator_traits } public: -#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT +#if BOOST_UNORDERED_CXX11_CONSTRUCTION template static typename boost::enable_if_c< @@ -1195,8 +1207,6 @@ template struct allocator_traits #include -#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1 - namespace boost { namespace unordered { namespace detail { @@ -1222,8 +1232,6 @@ template struct rebind_wrap #include -#define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0 - namespace boost { namespace unordered { namespace detail { @@ -1260,9 +1268,7 @@ namespace func { //////////////////////////////////////////////////////////////////////////// // call_construct -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - -#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT +#if BOOST_UNORDERED_CXX11_CONSTRUCTION template inline void call_construct( @@ -1278,7 +1284,7 @@ inline void call_destroy(Alloc& alloc, T* x) boost::unordered::detail::allocator_traits::destroy(alloc, x); } -#else +#elif !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template inline void call_construct(Alloc&, T* address, BOOST_FWD_REF(Args)... args) @@ -1291,9 +1297,8 @@ template inline void call_destroy(Alloc&, T* x) boost::unordered::detail::func::destroy(x); } -#endif - #else + template inline void call_construct(Alloc&, T* address) { From bc36a06a2da557fda977677070a1e26919c9aaf2 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 018/147] Comment about call_construct --- include/boost/unordered/detail/implementation.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index c0f069c8..dac24837 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1267,6 +1267,9 @@ namespace func { //////////////////////////////////////////////////////////////////////////// // call_construct +// +// Only use allocator_traits::construct, allocator_traits::destroy when full +// C++11 support is available. #if BOOST_UNORDERED_CXX11_CONSTRUCTION From c333a7f9fcab6382b787dfed0deaaf81c1ed0aa4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 019/147] Use piecewise construction where possible --- .../boost/unordered/detail/implementation.hpp | 118 ++++++++++++++++-- 1 file changed, 106 insertions(+), 12 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index dac24837..1df07137 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1324,7 +1324,7 @@ template inline void call_destroy(Alloc&, T* x) //////////////////////////////////////////////////////////////////////////// // Construct from tuple // -// Used for piecewise construction. +// Used to emulate piecewise construction. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -1408,7 +1408,8 @@ template struct length BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) -#if !defined(__SUNPRO_CC) && !defined(BOOST_NO_CXX11_HDR_TUPLE) +#if !BOOST_UNORDERED_CXX11_CONSTRUCTION && !defined(__SUNPRO_CC) && \ + !defined(BOOST_NO_CXX11_HDR_TUPLE) BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::) #endif @@ -1444,13 +1445,11 @@ template struct use_piecewise }; }; -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if BOOST_UNORDERED_CXX11_CONSTRUCTION //////////////////////////////////////////////////////////////////////////// // Construct from variadic parameters -// For the standard pair constructor. - template inline void construct_from_args( Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args) @@ -1459,10 +1458,64 @@ inline void construct_from_args( alloc, address, boost::forward(args)...); } -// Special case for piece_construct -// -// TODO: When possible, it might be better to use std::pair's -// constructor for std::piece_construct with std::tuple. +// For backwards compatibility, implement a special case for +// piecewise_construct with boost::tuple + +template struct detect_boost_tuple +{ + template + static choice1::type test(choice1, boost::tuple const&); + + static choice2::type test(choice2, ...); + + enum + { + value = sizeof(choice1::type) == + sizeof(test(choose(), boost::unordered::detail::make())) + }; +}; + +// Special case for piecewise_construct + +template +inline typename boost::enable_if_c::value && + detect_boost_tuple::value && + detect_boost_tuple::value, + void>::type +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, boost::addressof(address->first), boost::forward(a1)); + BOOST_TRY + { + boost::unordered::detail::func::construct_from_tuple( + alloc, boost::addressof(address->second), boost::forward(a2)); + } + BOOST_CATCH(...) + { + boost::unordered::detail::func::destroy( + boost::addressof(address->first)); + BOOST_RETHROW; + } + BOOST_CATCH_END +} + +#elif !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +//////////////////////////////////////////////////////////////////////////// +// Construct from variadic parameters + +template +inline void construct_from_args( + Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args) +{ + boost::unordered::detail::func::call_construct( + alloc, address, boost::forward(args)...); +} + +// Special case for piecewise_construct template @@ -1540,7 +1593,7 @@ BOOST_PP_REPEAT_FROM_TO( #undef BOOST_UNORDERED_CONSTRUCT_IMPL -// Construct with piece_construct +// Construct with piecewise_construct template @@ -1716,8 +1769,47 @@ construct_node(Alloc& alloc, BOOST_FWD_REF(U) x) return a.release(); } -// TODO: When possible, it might be better to use std::pair's -// constructor for std::piece_construct with std::tuple. +#if BOOST_UNORDERED_CXX11_CONSTRUCTION + +template +inline typename boost::unordered::detail::allocator_traits::pointer +construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) +{ + node_constructor a(alloc); + a.create_node(); + boost::unordered::detail::func::call_construct(alloc, a.node_->value_ptr(), + std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple()); + return a.release(); +} + +template +inline typename boost::unordered::detail::allocator_traits::pointer +construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) +{ + node_constructor a(alloc); + a.create_node(); + boost::unordered::detail::func::call_construct(alloc, a.node_->value_ptr(), + std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(m))); + return a.release(); +} + +template +inline typename boost::unordered::detail::allocator_traits::pointer +construct_node_pair_from_args( + Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Args)... args) +{ + node_constructor a(alloc); + a.create_node(); + boost::unordered::detail::func::call_construct(alloc, a.node_->value_ptr(), + std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(args)...)); + return a.release(); +} + +#else + template inline typename boost::unordered::detail::allocator_traits::pointer construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) @@ -1801,6 +1893,8 @@ construct_node_pair_from_args( BOOST_CATCH_END return a.release(); } + +#endif } } } From 7de8c91301728e95515f2cd0d8c6411a619cf0cb Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 020/147] Remove calls to const_cast_pointer It was needed because std::allocator_traits::construct doesn't work with a const pointer (e.g. pointer to the first member of a std::pair). But now we're only calling construct if BOOST_UNORDERED_CXX11_CONSTRUCTION is true, so the allocator_traits::construct is no longer used here. --- .../boost/unordered/detail/implementation.hpp | 73 +++++-------------- 1 file changed, 20 insertions(+), 53 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 1df07137..a10e4c79 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -485,17 +485,6 @@ struct convert_from_anything template 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 // @@ -1524,21 +1513,16 @@ inline typename enable_if, void>::type construct_from_args( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { boost::unordered::detail::func::construct_from_tuple( - alloc, boost::unordered::detail::func::const_cast_pointer( - boost::addressof(address->first)), - boost::forward(a1)); + alloc, boost::addressof(address->first), boost::forward(a1)); BOOST_TRY { boost::unordered::detail::func::construct_from_tuple( - alloc, boost::unordered::detail::func::const_cast_pointer( - boost::addressof(address->second)), - boost::forward(a2)); + alloc, boost::addressof(address->second), boost::forward(a2)); } BOOST_CATCH(...) { boost::unordered::detail::func::call_destroy( - alloc, boost::unordered::detail::func::const_cast_pointer( - boost::addressof(address->first))); + alloc, boost::addressof(address->first)); BOOST_RETHROW; } BOOST_CATCH_END @@ -1602,21 +1586,16 @@ inline void construct_from_args(Alloc& alloc, std::pair* address, typename enable_if, void*>::type = 0) { boost::unordered::detail::func::construct_from_tuple( - alloc, boost::unordered::detail::func::const_cast_pointer( - boost::addressof(address->first)), - args.a1); + alloc, boost::addressof(address->first), args.a1); BOOST_TRY { boost::unordered::detail::func::construct_from_tuple( - alloc, boost::unordered::detail::func::const_cast_pointer( - boost::addressof(address->second)), - args.a2); + alloc, boost::addressof(address->second), args.a2); } BOOST_CATCH(...) { boost::unordered::detail::func::call_destroy( - alloc, boost::unordered::detail::func::const_cast_pointer( - boost::addressof(address->first))); + alloc, boost::addressof(address->first)); BOOST_RETHROW; } BOOST_CATCH_END @@ -1816,21 +1795,17 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) { node_constructor a(alloc); a.create_node(); - 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()->first), boost::forward(k)); BOOST_TRY { boost::unordered::detail::func::call_construct( - alloc, boost::unordered::detail::func::const_cast_pointer( - boost::addressof(a.node_->value_ptr()->second))); + alloc, boost::addressof(a.node_->value_ptr()->second)); } BOOST_CATCH(...) { boost::unordered::detail::func::call_destroy( - alloc, boost::unordered::detail::func::const_cast_pointer( - boost::addressof(a.node_->value_ptr()->first))); + alloc, boost::addressof(a.node_->value_ptr()->first)); BOOST_RETHROW; } BOOST_CATCH_END @@ -1843,22 +1818,18 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) { node_constructor a(alloc); a.create_node(); - 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()->first), boost::forward(k)); BOOST_TRY { - boost::unordered::detail::func::call_construct( - alloc, boost::unordered::detail::func::const_cast_pointer( - boost::addressof(a.node_->value_ptr()->second)), + boost::unordered::detail::func::call_construct(alloc, + boost::addressof(a.node_->value_ptr()->second), boost::forward(m)); } BOOST_CATCH(...) { boost::unordered::detail::func::call_destroy( - alloc, boost::unordered::detail::func::const_cast_pointer( - boost::addressof(a.node_->value_ptr()->first))); + alloc, boost::addressof(a.node_->value_ptr()->first)); BOOST_RETHROW; } BOOST_CATCH_END @@ -1872,22 +1843,18 @@ construct_node_pair_from_args( { node_constructor a(alloc); a.create_node(); - 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()->first), boost::forward(k)); BOOST_TRY { - boost::unordered::detail::func::construct_from_args( - alloc, boost::unordered::detail::func::const_cast_pointer( - boost::addressof(a.node_->value_ptr()->second)), + boost::unordered::detail::func::construct_from_args(alloc, + boost::addressof(a.node_->value_ptr()->second), BOOST_UNORDERED_EMPLACE_FORWARD); } BOOST_CATCH(...) { boost::unordered::detail::func::call_destroy( - alloc, boost::unordered::detail::func::const_cast_pointer( - boost::addressof(a.node_->value_ptr()->first))); + alloc, boost::addressof(a.node_->value_ptr()->first)); BOOST_RETHROW; } BOOST_CATCH_END From 9e7068004463d7dbce2b20a158a5e4f9cb3f65d6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 021/147] Bypass construct_value/call_destroy_in a few places --- .../boost/unordered/detail/implementation.hpp | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index a10e4c79..38eaa6a5 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1319,9 +1319,9 @@ template inline void call_destroy(Alloc&, T* x) #define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ template \ - void construct_from_tuple(Alloc& alloc, T* ptr, namespace_ tuple<>) \ + void construct_from_tuple(Alloc&, T* ptr, namespace_ tuple<>) \ { \ - boost::unordered::detail::func::call_construct(alloc, ptr); \ + new ((void*)ptr) T(); \ } \ \ BOOST_PP_REPEAT_FROM_TO( \ @@ -1330,10 +1330,10 @@ template inline void call_destroy(Alloc&, T* x) #define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ template \ - void construct_from_tuple(Alloc& alloc, T* ptr, \ + void construct_from_tuple(Alloc&, T* ptr, \ namespace_ tuple const& x) \ { \ - boost::unordered::detail::func::call_construct(alloc, ptr, \ + new ((void*)ptr) T( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_)); \ } @@ -1443,7 +1443,7 @@ template inline void construct_from_args( Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args) { - boost::unordered::detail::func::call_construct( + boost::unordered::detail::allocator_traits::construct( alloc, address, boost::forward(args)...); } @@ -1500,8 +1500,7 @@ template inline void construct_from_args( Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args) { - boost::unordered::detail::func::call_construct( - alloc, address, boost::forward(args)...); + new ((void*)address) T(boost::forward(args)...); } // Special case for piecewise_construct @@ -1521,8 +1520,8 @@ inline typename enable_if, void>::type construct_from_args( } BOOST_CATCH(...) { - boost::unordered::detail::func::call_destroy( - alloc, boost::addressof(address->first)); + boost::unordered::detail::func::destroy( + boost::addressof(address->first)); BOOST_RETHROW; } BOOST_CATCH_END @@ -1594,8 +1593,8 @@ inline void construct_from_args(Alloc& alloc, std::pair* address, } BOOST_CATCH(...) { - boost::unordered::detail::func::call_destroy( - alloc, boost::addressof(address->first)); + boost::unordered::detail::func::destroy( + boost::addressof(address->first)); BOOST_RETHROW; } BOOST_CATCH_END @@ -1756,9 +1755,9 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) { node_constructor a(alloc); a.create_node(); - boost::unordered::detail::func::call_construct(alloc, a.node_->value_ptr(), - std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), - std::forward_as_tuple()); + boost::unordered::detail::allocator_traits::construct(alloc, + a.node_->value_ptr(), std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple()); return a.release(); } @@ -1768,8 +1767,9 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) { node_constructor a(alloc); a.create_node(); - boost::unordered::detail::func::call_construct(alloc, a.node_->value_ptr(), - std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), + boost::unordered::detail::allocator_traits::construct(alloc, + a.node_->value_ptr(), std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(m))); return a.release(); } @@ -1781,8 +1781,9 @@ construct_node_pair_from_args( { node_constructor a(alloc); a.create_node(); - boost::unordered::detail::func::call_construct(alloc, a.node_->value_ptr(), - std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), + boost::unordered::detail::allocator_traits::construct(alloc, + a.node_->value_ptr(), std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(args)...)); return a.release(); } @@ -1804,8 +1805,8 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) } BOOST_CATCH(...) { - boost::unordered::detail::func::call_destroy( - alloc, boost::addressof(a.node_->value_ptr()->first)); + boost::unordered::detail::func::destroy( + boost::addressof(a.node_->value_ptr()->first)); BOOST_RETHROW; } BOOST_CATCH_END @@ -1828,8 +1829,8 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) } BOOST_CATCH(...) { - boost::unordered::detail::func::call_destroy( - alloc, boost::addressof(a.node_->value_ptr()->first)); + boost::unordered::detail::func::destroy( + boost::addressof(a.node_->value_ptr()->first)); BOOST_RETHROW; } BOOST_CATCH_END @@ -1853,8 +1854,8 @@ construct_node_pair_from_args( } BOOST_CATCH(...) { - boost::unordered::detail::func::call_destroy( - alloc, boost::addressof(a.node_->value_ptr()->first)); + boost::unordered::detail::func::destroy( + boost::addressof(a.node_->value_ptr()->first)); BOOST_RETHROW; } BOOST_CATCH_END From 6d79a322e2e184bb7ec758f80c403d62f24cfb37 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 022/147] Use macros to reduce call chain --- .../boost/unordered/detail/implementation.hpp | 89 +++++++++---------- 1 file changed, 44 insertions(+), 45 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 38eaa6a5..09baab65 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1262,19 +1262,11 @@ namespace func { #if BOOST_UNORDERED_CXX11_CONSTRUCTION -template -inline void call_construct( - Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args) -{ - boost::unordered::detail::allocator_traits::construct( - alloc, address, boost::forward(args)...); -} - -template -inline void call_destroy(Alloc& alloc, T* x) -{ - boost::unordered::detail::allocator_traits::destroy(alloc, x); -} +#define BOOST_UNORDERED_CALL_CONSTRUCT0(Traits, alloc, address) \ + Traits::construct(alloc, address) +#define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \ + Traits::construct(alloc, address, a0) +#define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) Traits::destroy(alloc, x) #elif !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -1284,10 +1276,12 @@ inline void call_construct(Alloc&, T* address, BOOST_FWD_REF(Args)... args) new ((void*)address) T(boost::forward(args)...); } -template inline void call_destroy(Alloc&, T* x) -{ - boost::unordered::detail::func::destroy(x); -} +#define BOOST_UNORDERED_CALL_CONSTRUCT0(Traits, alloc, address) \ + boost::unordered::detail::func::call_construct(alloc, address) +#define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \ + boost::unordered::detail::func::call_construct(alloc, address, a0) +#define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) \ + boost::unordered::detail::func::destroy(x) #else @@ -1303,10 +1297,12 @@ inline void call_construct(Alloc&, T* address, BOOST_FWD_REF(A0) a0) new ((void*)address) T(boost::forward(a0)); } -template inline void call_destroy(Alloc&, T* x) -{ - boost::unordered::detail::func::destroy(x); -} +#define BOOST_UNORDERED_CALL_CONSTRUCT0(Traits, alloc, address) \ + boost::unordered::detail::func::call_construct(alloc, address) +#define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \ + boost::unordered::detail::func::call_construct(alloc, address, a0) +#define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) \ + boost::unordered::detail::func::destroy(x) #endif @@ -1650,8 +1646,8 @@ template struct node_constructor BOOST_ASSERT(!node_); node_ = p; node_constructed_ = true; - boost::unordered::detail::func::call_destroy( - alloc_, node_->value_ptr()); + BOOST_UNORDERED_CALL_DESTROY( + node_allocator_traits, alloc_, node_->value_ptr()); } private: @@ -1707,8 +1703,8 @@ template struct node_tmp template node_tmp::~node_tmp() { if (node_) { - boost::unordered::detail::func::call_destroy( - alloc_, node_->value_ptr()); + BOOST_UNORDERED_CALL_DESTROY( + node_allocator_traits, alloc_, node_->value_ptr()); boost::unordered::detail::func::destroy(boost::addressof(*node_)); node_allocator_traits::deallocate(alloc_, node_, 1); } @@ -1742,8 +1738,9 @@ construct_node(Alloc& alloc, BOOST_FWD_REF(U) x) { node_constructor a(alloc); a.create_node(); - boost::unordered::detail::func::call_construct( - alloc, a.node_->value_ptr(), boost::forward(x)); + BOOST_UNORDERED_CALL_CONSTRUCT1( + boost::unordered::detail::allocator_traits, alloc, + a.node_->value_ptr(), boost::forward(x)); return a.release(); } @@ -2183,7 +2180,7 @@ template struct node_holder } else { constructor_.create_node(); } - boost::unordered::detail::func::call_construct( + BOOST_UNORDERED_CALL_CONSTRUCT1(node_allocator_traits, constructor_.alloc_, constructor_.node_->value_ptr(), v); return constructor_.release(); } @@ -2195,8 +2192,9 @@ template struct node_holder } else { constructor_.create_node(); } - boost::unordered::detail::func::call_construct(constructor_.alloc_, - constructor_.node_->value_ptr(), boost::move(v)); + BOOST_UNORDERED_CALL_CONSTRUCT1(node_allocator_traits, + constructor_.alloc_, constructor_.node_->value_ptr(), + boost::move(v)); return constructor_.release(); } @@ -2209,8 +2207,8 @@ template node_holder::~node_holder() node_pointer p = nodes_; nodes_ = static_cast(p->next_); - boost::unordered::detail::func::call_destroy( - constructor_.alloc_, p->value_ptr()); + BOOST_UNORDERED_CALL_DESTROY( + node_allocator_traits, constructor_.alloc_, p->value_ptr()); boost::unordered::detail::func::destroy(boost::addressof(*p)); node_allocator_traits::deallocate(constructor_.alloc_, p, 1); } @@ -2900,15 +2898,15 @@ struct table : boost::unordered::detail::functions(new_count); for (; constructed != end; ++constructed) { - boost::unordered::detail::func::call_construct( + BOOST_UNORDERED_CALL_CONSTRUCT0(bucket_allocator_traits, bucket_alloc(), boost::addressof(*constructed)); } if (buckets_) { // Copy the nodes to the new buckets, including the dummy // node if there is one. - boost::unordered::detail::func::call_construct(bucket_alloc(), - boost::addressof(*constructed), + BOOST_UNORDERED_CALL_CONSTRUCT1(bucket_allocator_traits, + bucket_alloc(), boost::addressof(*constructed), (buckets_ + static_cast(bucket_count_)) ->next_); ++constructed; @@ -2917,11 +2915,12 @@ struct table : boost::unordered::detail::functions(prev->next_); prev->next_ = n->next_; - boost::unordered::detail::func::call_destroy( - node_alloc(), n->value_ptr()); + BOOST_UNORDERED_CALL_DESTROY( + node_allocator_traits, node_alloc(), n->value_ptr()); boost::unordered::detail::func::destroy(boost::addressof(*n)); node_allocator_traits::deallocate(node_alloc(), n, 1); --size_; @@ -3065,8 +3064,8 @@ struct table : boost::unordered::detail::functions if (!a.node_) { a.create_node(); } - boost::unordered::detail::func::call_construct( - a.alloc_, a.node_->value_ptr(), *i); + BOOST_UNORDERED_CALL_CONSTRUCT1( + node_allocator_traits, a.alloc_, a.node_->value_ptr(), *i); node_tmp b(a.release(), a.alloc_); const_key_type& k = this->get_key(b.node_); From 08ce2c98e0bdec3b62d6beb08393fdc40b5aafce Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 023/147] Rename call_construct to construct_value --- .../boost/unordered/detail/implementation.hpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 09baab65..e49fe4d7 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1255,7 +1255,7 @@ namespace detail { namespace func { //////////////////////////////////////////////////////////////////////////// -// call_construct +// construct_value // // Only use allocator_traits::construct, allocator_traits::destroy when full // C++11 support is available. @@ -1271,36 +1271,36 @@ namespace func { #elif !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template -inline void call_construct(Alloc&, T* address, BOOST_FWD_REF(Args)... args) +inline void construct_value(Alloc&, T* address, BOOST_FWD_REF(Args)... args) { new ((void*)address) T(boost::forward(args)...); } #define BOOST_UNORDERED_CALL_CONSTRUCT0(Traits, alloc, address) \ - boost::unordered::detail::func::call_construct(alloc, address) + boost::unordered::detail::func::construct_value(alloc, address) #define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \ - boost::unordered::detail::func::call_construct(alloc, address, a0) + boost::unordered::detail::func::construct_value(alloc, address, a0) #define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) \ boost::unordered::detail::func::destroy(x) #else template -inline void call_construct(Alloc&, T* address) +inline void construct_value(Alloc&, T* address) { new ((void*)address) T(); } template -inline void call_construct(Alloc&, T* address, BOOST_FWD_REF(A0) a0) +inline void construct_value(Alloc&, T* address, BOOST_FWD_REF(A0) a0) { new ((void*)address) T(boost::forward(a0)); } #define BOOST_UNORDERED_CALL_CONSTRUCT0(Traits, alloc, address) \ - boost::unordered::detail::func::call_construct(alloc, address) + boost::unordered::detail::func::construct_value(alloc, address) #define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \ - boost::unordered::detail::func::call_construct(alloc, address, a0) + boost::unordered::detail::func::construct_value(alloc, address, a0) #define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) \ boost::unordered::detail::func::destroy(x) @@ -1793,11 +1793,11 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) { node_constructor a(alloc); a.create_node(); - boost::unordered::detail::func::call_construct(alloc, + boost::unordered::detail::func::construct_value(alloc, boost::addressof(a.node_->value_ptr()->first), boost::forward(k)); BOOST_TRY { - boost::unordered::detail::func::call_construct( + boost::unordered::detail::func::construct_value( alloc, boost::addressof(a.node_->value_ptr()->second)); } BOOST_CATCH(...) @@ -1816,11 +1816,11 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) { node_constructor a(alloc); a.create_node(); - boost::unordered::detail::func::call_construct(alloc, + boost::unordered::detail::func::construct_value(alloc, boost::addressof(a.node_->value_ptr()->first), boost::forward(k)); BOOST_TRY { - boost::unordered::detail::func::call_construct(alloc, + boost::unordered::detail::func::construct_value(alloc, boost::addressof(a.node_->value_ptr()->second), boost::forward(m)); } @@ -1841,7 +1841,7 @@ construct_node_pair_from_args( { node_constructor a(alloc); a.create_node(); - boost::unordered::detail::func::call_construct(alloc, + boost::unordered::detail::func::construct_value(alloc, boost::addressof(a.node_->value_ptr()->first), boost::forward(k)); BOOST_TRY { From 3414e6628add93a2bef3c647dbb7c4d73c3d0f7e Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 024/147] Use allocator to construct/destroy nodes --- .../boost/unordered/detail/implementation.hpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index e49fe4d7..4741170a 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1659,7 +1659,8 @@ template node_constructor::~node_constructor() { if (node_) { if (node_constructed_) { - boost::unordered::detail::func::destroy(boost::addressof(*node_)); + BOOST_UNORDERED_CALL_DESTROY( + node_allocator_traits, alloc_, boost::addressof(*node_)); } node_allocator_traits::deallocate(alloc_, node_, 1); @@ -1673,7 +1674,8 @@ template void node_constructor::create_node() node_ = node_allocator_traits::allocate(alloc_, 1); - new ((void*)boost::addressof(*node_)) node(); + BOOST_UNORDERED_CALL_CONSTRUCT0( + node_allocator_traits, alloc_, boost::addressof(*node_)); node_->init(node_); node_constructed_ = true; } @@ -1705,7 +1707,8 @@ template node_tmp::~node_tmp() if (node_) { BOOST_UNORDERED_CALL_DESTROY( node_allocator_traits, alloc_, node_->value_ptr()); - boost::unordered::detail::func::destroy(boost::addressof(*node_)); + BOOST_UNORDERED_CALL_DESTROY( + node_allocator_traits, alloc_, boost::addressof(*node_)); node_allocator_traits::deallocate(alloc_, node_, 1); } } @@ -2209,7 +2212,8 @@ template node_holder::~node_holder() BOOST_UNORDERED_CALL_DESTROY( node_allocator_traits, constructor_.alloc_, p->value_ptr()); - boost::unordered::detail::func::destroy(boost::addressof(*p)); + BOOST_UNORDERED_CALL_DESTROY( + node_allocator_traits, constructor_.alloc_, boost::addressof(*p)); node_allocator_traits::deallocate(constructor_.alloc_, p, 1); } } @@ -3009,7 +3013,8 @@ struct table : boost::unordered::detail::functionsvalue_ptr()); - boost::unordered::detail::func::destroy(boost::addressof(*n)); + BOOST_UNORDERED_CALL_DESTROY( + node_allocator_traits, node_alloc(), boost::addressof(*n)); node_allocator_traits::deallocate(node_alloc(), n, 1); --size_; } @@ -3037,7 +3042,8 @@ struct table : boost::unordered::detail::functions(get_bucket(bucket_count_)->next_); - boost::unordered::detail::func::destroy(boost::addressof(*n)); + BOOST_UNORDERED_CALL_DESTROY( + node_allocator_traits, node_alloc(), boost::addressof(*n)); node_allocator_traits::deallocate(node_alloc(), n, 1); } From e0054c7dd0dae53e57ae3414e6c786d3798b6ac6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 025/147] Remove alloc parameter from construct_value --- .../boost/unordered/detail/implementation.hpp | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 4741170a..95502fe0 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1270,37 +1270,36 @@ namespace func { #elif !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) -template -inline void construct_value(Alloc&, T* address, BOOST_FWD_REF(Args)... args) +template +inline void construct_value(T* address, BOOST_FWD_REF(Args)... args) { new ((void*)address) T(boost::forward(args)...); } #define BOOST_UNORDERED_CALL_CONSTRUCT0(Traits, alloc, address) \ - boost::unordered::detail::func::construct_value(alloc, address) + boost::unordered::detail::func::construct_value(address) #define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \ - boost::unordered::detail::func::construct_value(alloc, address, a0) + boost::unordered::detail::func::construct_value(address, a0) #define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) \ boost::unordered::detail::func::destroy(x) #else -template -inline void construct_value(Alloc&, T* address) +template inline void construct_value(T* address) { new ((void*)address) T(); } -template -inline void construct_value(Alloc&, T* address, BOOST_FWD_REF(A0) a0) +template +inline void construct_value(T* address, BOOST_FWD_REF(A0) a0) { new ((void*)address) T(boost::forward(a0)); } #define BOOST_UNORDERED_CALL_CONSTRUCT0(Traits, alloc, address) \ - boost::unordered::detail::func::construct_value(alloc, address) + boost::unordered::detail::func::construct_value(address) #define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \ - boost::unordered::detail::func::construct_value(alloc, address, a0) + boost::unordered::detail::func::construct_value(address, a0) #define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) \ boost::unordered::detail::func::destroy(x) @@ -1796,12 +1795,12 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) { node_constructor a(alloc); a.create_node(); - boost::unordered::detail::func::construct_value(alloc, + boost::unordered::detail::func::construct_value( boost::addressof(a.node_->value_ptr()->first), boost::forward(k)); BOOST_TRY { boost::unordered::detail::func::construct_value( - alloc, boost::addressof(a.node_->value_ptr()->second)); + boost::addressof(a.node_->value_ptr()->second)); } BOOST_CATCH(...) { @@ -1819,11 +1818,11 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) { node_constructor a(alloc); a.create_node(); - boost::unordered::detail::func::construct_value(alloc, + boost::unordered::detail::func::construct_value( boost::addressof(a.node_->value_ptr()->first), boost::forward(k)); BOOST_TRY { - boost::unordered::detail::func::construct_value(alloc, + boost::unordered::detail::func::construct_value( boost::addressof(a.node_->value_ptr()->second), boost::forward(m)); } @@ -1844,7 +1843,7 @@ construct_node_pair_from_args( { node_constructor a(alloc); a.create_node(); - boost::unordered::detail::func::construct_value(alloc, + boost::unordered::detail::func::construct_value( boost::addressof(a.node_->value_ptr()->first), boost::forward(k)); BOOST_TRY { From cafd236a1880f2efcb27d8845142e1afa68cf6e5 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 026/147] Test more memory tracking --- test/helpers/memory.hpp | 2 + test/objects/test.hpp | 13 ++- test/unordered/insert_tests.cpp | 150 ++++++++++++++++++++++---------- 3 files changed, 118 insertions(+), 47 deletions(-) diff --git a/test/helpers/memory.hpp b/test/helpers/memory.hpp index 84822b4a..16837e77 100644 --- a/test/helpers/memory.hpp +++ b/test/helpers/memory.hpp @@ -66,6 +66,8 @@ struct memory_tracker { } + ~memory_tracker() { BOOST_TEST(count_allocators == 0); } + void allocator_ref() { if (count_allocators == 0) { diff --git a/test/objects/test.hpp b/test/objects/test.hpp index ab346806..aba215f0 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -391,16 +391,23 @@ template class allocator1 ::operator delete((void*)p); } +#if BOOST_UNORDERED_CXX11_CONSTRUCTION + template void construct(T* p, Args&&... args) + { + detail::tracker.track_construct((void*)p, sizeof(T), tag_); + new (p) T(boost::forward(args)...); + } +#else void construct(T* p, T const& t) { - // Don't count constructions here as it isn't always called. - // detail::tracker.track_construct((void*) p, sizeof(T), tag_); + detail::tracker.track_construct((void*)p, sizeof(T), tag_); new (p) T(t); } +#endif void destroy(T* p) { - // detail::tracker.track_destroy((void*) p, sizeof(T), tag_); + detail::tracker.track_destroy((void*)p, sizeof(T), tag_); p->~T(); // Work around MSVC buggy unused parameter warning. diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index ae50fa18..332a9b0f 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -1030,21 +1030,43 @@ struct overloaded_constructor UNORDERED_AUTO_TEST(map_emplace_test) { - boost::unordered_map x; + { + boost::unordered_map > > + x; #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) - x.emplace(); - BOOST_TEST( - x.find(0) != x.end() && x.find(0)->second == overloaded_constructor()); + x.emplace(); + BOOST_TEST(x.find(0) != x.end() && + x.find(0)->second == overloaded_constructor()); #endif - x.emplace(2, 3); - BOOST_TEST( - x.find(2) != x.end() && x.find(2)->second == overloaded_constructor(3)); + x.emplace(2, 3); + BOOST_TEST(x.find(2) != x.end() && + x.find(2)->second == overloaded_constructor(3)); - x.try_emplace(5); - BOOST_TEST( - x.find(5) != x.end() && x.find(5)->second == overloaded_constructor()); + x.try_emplace(5); + BOOST_TEST(x.find(5) != x.end() && + x.find(5)->second == overloaded_constructor()); + } + + { + boost::unordered_multimap > > + x; + +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) + x.emplace(); + BOOST_TEST(x.find(0) != x.end() && + x.find(0)->second == overloaded_constructor()); +#endif + + x.emplace(2, 3); + BOOST_TEST(x.find(2) != x.end() && + x.find(2)->second == overloaded_constructor(3)); + } } UNORDERED_AUTO_TEST(set_emplace_test) @@ -1098,48 +1120,88 @@ struct convertible_to_piecewise UNORDERED_AUTO_TEST(map_emplace_test2) { - boost::unordered_map x; + { + boost::unordered_map, + std::equal_to, + test::allocator1 > > + x; - x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(), - boost::make_tuple()); - BOOST_TEST( - x.find(overloaded_constructor()) != x.end() && - x.find(overloaded_constructor())->second == overloaded_constructor()); + x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(), + boost::make_tuple()); + BOOST_TEST(x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == + overloaded_constructor()); - x.emplace( - convertible_to_piecewise(), boost::make_tuple(1), boost::make_tuple()); - BOOST_TEST( - x.find(overloaded_constructor(1)) != x.end() && - x.find(overloaded_constructor(1))->second == overloaded_constructor()); + x.emplace(convertible_to_piecewise(), boost::make_tuple(1), + boost::make_tuple()); + BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == + overloaded_constructor()); - x.emplace(piecewise_rvalue(), boost::make_tuple(2, 3), - boost::make_tuple(4, 5, 6)); - BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && - x.find(overloaded_constructor(2, 3))->second == - overloaded_constructor(4, 5, 6)); + x.emplace(piecewise_rvalue(), boost::make_tuple(2, 3), + boost::make_tuple(4, 5, 6)); + BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && + x.find(overloaded_constructor(2, 3))->second == + overloaded_constructor(4, 5, 6)); - derived_from_piecewise_construct_t d; - x.emplace(d, boost::make_tuple(9, 3, 1), boost::make_tuple(10)); - BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() && - x.find(overloaded_constructor(9, 3, 1))->second == - overloaded_constructor(10)); + derived_from_piecewise_construct_t d; + x.emplace(d, boost::make_tuple(9, 3, 1), boost::make_tuple(10)); + BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() && + x.find(overloaded_constructor(9, 3, 1))->second == + overloaded_constructor(10)); - x.clear(); + x.clear(); - x.try_emplace(overloaded_constructor()); - BOOST_TEST( - x.find(overloaded_constructor()) != x.end() && - x.find(overloaded_constructor())->second == overloaded_constructor()); + x.try_emplace(overloaded_constructor()); + BOOST_TEST(x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == + overloaded_constructor()); - x.try_emplace(1); - BOOST_TEST( - x.find(overloaded_constructor(1)) != x.end() && - x.find(overloaded_constructor(1))->second == overloaded_constructor()); + x.try_emplace(1); + BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == + overloaded_constructor()); - x.try_emplace(overloaded_constructor(2, 3), 4, 5, 6); - BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && - x.find(overloaded_constructor(2, 3))->second == - overloaded_constructor(4, 5, 6)); + x.try_emplace(overloaded_constructor(2, 3), 4, 5, 6); + BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && + x.find(overloaded_constructor(2, 3))->second == + overloaded_constructor(4, 5, 6)); + } + { + + boost::unordered_multimap, + std::equal_to, + test::allocator1 > > + x; + + x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(), + boost::make_tuple()); + BOOST_TEST(x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == + overloaded_constructor()); + + x.emplace(convertible_to_piecewise(), boost::make_tuple(1), + boost::make_tuple()); + BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == + overloaded_constructor()); + + x.emplace(piecewise_rvalue(), boost::make_tuple(2, 3), + boost::make_tuple(4, 5, 6)); + BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && + x.find(overloaded_constructor(2, 3))->second == + overloaded_constructor(4, 5, 6)); + + derived_from_piecewise_construct_t d; + x.emplace(d, boost::make_tuple(9, 3, 1), boost::make_tuple(10)); + BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() && + x.find(overloaded_constructor(9, 3, 1))->second == + overloaded_constructor(10)); + } } UNORDERED_AUTO_TEST(set_emplace_test2) From 7a0a598649131aaec54616dc8736b5cdcab498e6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 027/147] Don't track construction when using boost::tuple Because it doesn't quiet work on C++11 compilers onwards. --- test/helpers/memory.hpp | 39 +++++++++-- test/objects/test.hpp | 12 ++-- test/unordered/insert_tests.cpp | 114 +++++++++++++++++++++++++++++++- 3 files changed, 152 insertions(+), 13 deletions(-) diff --git a/test/helpers/memory.hpp b/test/helpers/memory.hpp index 16837e77..2f910676 100644 --- a/test/helpers/memory.hpp +++ b/test/helpers/memory.hpp @@ -60,9 +60,11 @@ struct memory_tracker unsigned int count_allocators; unsigned int count_allocations; unsigned int count_constructions; + bool tracking_constructions; memory_tracker() - : count_allocators(0), count_allocations(0), count_constructions(0) + : count_allocators(0), count_allocations(0), count_constructions(0), + tracking_constructions(true) { } @@ -133,14 +135,18 @@ struct memory_tracker void track_construct(void* /*ptr*/, std::size_t /*size*/, int /*tag*/) { - ++count_constructions; + if (tracking_constructions) { + ++count_constructions; + } } void track_destroy(void* /*ptr*/, std::size_t /*size*/, int /*tag*/) { - BOOST_TEST(count_constructions > 0); - if (count_constructions > 0) - --count_constructions; + if (tracking_constructions) { + BOOST_TEST(count_constructions > 0); + if (count_constructions > 0) + --count_constructions; + } } }; } @@ -155,6 +161,29 @@ namespace { test::detail::memory_tracker tracker; } } + +namespace detail { +struct disable_construction_tracking +{ + bool old_value; + + disable_construction_tracking() + : old_value(detail::tracker.tracking_constructions) + { + test::detail::tracker.tracking_constructions = false; + } + + ~disable_construction_tracking() + { + test::detail::tracker.tracking_constructions = old_value; + } + + private: + disable_construction_tracking(disable_construction_tracking const&); + disable_construction_tracking& operator=( + disable_construction_tracking const&); +}; +} } #endif diff --git a/test/objects/test.hpp b/test/objects/test.hpp index aba215f0..14f29ab9 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -392,10 +392,10 @@ template class allocator1 } #if BOOST_UNORDERED_CXX11_CONSTRUCTION - template void construct(T* p, Args&&... args) + template void construct(U* p, Args&&... args) { - detail::tracker.track_construct((void*)p, sizeof(T), tag_); - new (p) T(boost::forward(args)...); + detail::tracker.track_construct((void*)p, sizeof(U), tag_); + new (p) U(boost::forward(args)...); } #else void construct(T* p, T const& t) @@ -405,10 +405,10 @@ template class allocator1 } #endif - void destroy(T* p) + template void destroy(U* p) { - detail::tracker.track_destroy((void*)p, sizeof(T), tag_); - p->~T(); + detail::tracker.track_destroy((void*)p, sizeof(U), tag_); + p->~U(); // Work around MSVC buggy unused parameter warning. ignore_variable(&p); diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 332a9b0f..a53f43c3 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -1120,6 +1120,10 @@ struct convertible_to_piecewise UNORDERED_AUTO_TEST(map_emplace_test2) { + // Emulating piecewise construction with boost::tuple bypasses the + // allocator's construct method, but still uses test destroy method. + test::detail::disable_construction_tracking _scoped; + { boost::unordered_map, @@ -1169,8 +1173,8 @@ UNORDERED_AUTO_TEST(map_emplace_test2) x.find(overloaded_constructor(2, 3))->second == overloaded_constructor(4, 5, 6)); } - { + { boost::unordered_multimap, std::equal_to, @@ -1220,9 +1224,115 @@ UNORDERED_AUTO_TEST(set_emplace_test2) boost::make_tuple(2, 3)); check = std::make_pair(overloaded_constructor(1), overloaded_constructor(2, 3)); - ; BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); } + +#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT + +UNORDERED_AUTO_TEST(map_std_emplace_test2) +{ + { + boost::unordered_map, + std::equal_to, + test::allocator1 > > + x; + + x.emplace( + std::piecewise_construct, std::make_tuple(), std::make_tuple()); + BOOST_TEST(x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == + overloaded_constructor()); + + x.emplace( + convertible_to_piecewise(), std::make_tuple(1), std::make_tuple()); + BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == + overloaded_constructor()); + + x.emplace(piecewise_rvalue(), std::make_tuple(2, 3), + std::make_tuple(4, 5, 6)); + BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && + x.find(overloaded_constructor(2, 3))->second == + overloaded_constructor(4, 5, 6)); + + derived_from_piecewise_construct_t d; + x.emplace(d, std::make_tuple(9, 3, 1), std::make_tuple(10)); + BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() && + x.find(overloaded_constructor(9, 3, 1))->second == + overloaded_constructor(10)); + + x.clear(); + + x.try_emplace(overloaded_constructor()); + BOOST_TEST(x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == + overloaded_constructor()); + + x.try_emplace(1); + BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == + overloaded_constructor()); + + x.try_emplace(overloaded_constructor(2, 3), 4, 5, 6); + BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && + x.find(overloaded_constructor(2, 3))->second == + overloaded_constructor(4, 5, 6)); + } + { + boost::unordered_multimap, + std::equal_to, + test::allocator1 > > + x; + + x.emplace( + std::piecewise_construct, std::make_tuple(), std::make_tuple()); + BOOST_TEST(x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == + overloaded_constructor()); + + x.emplace( + convertible_to_piecewise(), std::make_tuple(1), std::make_tuple()); + BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == + overloaded_constructor()); + + x.emplace(piecewise_rvalue(), std::make_tuple(2, 3), + std::make_tuple(4, 5, 6)); + BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && + x.find(overloaded_constructor(2, 3))->second == + overloaded_constructor(4, 5, 6)); + + derived_from_piecewise_construct_t d; + x.emplace(d, std::make_tuple(9, 3, 1), std::make_tuple(10)); + BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() && + x.find(overloaded_constructor(9, 3, 1))->second == + overloaded_constructor(10)); + } +} + +UNORDERED_AUTO_TEST(set_std_emplace_test2) +{ + boost::unordered_set< + std::pair > + x; + std::pair check; + + x.emplace(std::piecewise_construct, std::make_tuple(), std::make_tuple()); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); + + x.clear(); + x.emplace( + std::piecewise_construct, std::make_tuple(1), std::make_tuple(2, 3)); + check = + std::make_pair(overloaded_constructor(1), overloaded_constructor(2, 3)); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); +} + +#endif } RUN_TESTS() From ef05493c839bee3d072d23e9cf409d17b4ca602e Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 028/147] Test that construct/destroy aren't used when C++11 isn't available --- test/objects/test.hpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/test/objects/test.hpp b/test/objects/test.hpp index 14f29ab9..e0e155f9 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -397,13 +397,6 @@ template class allocator1 detail::tracker.track_construct((void*)p, sizeof(U), tag_); new (p) U(boost::forward(args)...); } -#else - void construct(T* p, T const& t) - { - detail::tracker.track_construct((void*)p, sizeof(T), tag_); - new (p) T(t); - } -#endif template void destroy(U* p) { @@ -413,6 +406,22 @@ template class allocator1 // Work around MSVC buggy unused parameter warning. ignore_variable(&p); } +#else + private: + // I'm going to claim in the documentation that construct/destroy + // is never used when C++11 support isn't available, so might as + // well check that in the text. + // TODO: Or maybe just disallow them for values? + template void construct(U* p); + template void construct(U* p, A0 const&); + template + void construct(U* p, A0 const&, A1 const&); + template + void construct(U* p, A0 const&, A1 const&, A2 const&); + template void destroy(U* p); + + public: +#endif bool operator==(allocator1 const& x) const { return tag_ == x.tag_; } From 8c9080f11f15d509439f7cc1d9ee69b15f5bf5c7 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 029/147] Document changes to allocator use --- doc/compliance.qbk | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/doc/compliance.qbk b/doc/compliance.qbk index 771e473d..b0fd9472 100644 --- a/doc/compliance.qbk +++ b/doc/compliance.qbk @@ -51,23 +51,32 @@ Due to imperfect move emulation, some assignments might check `propagate_on_container_copy_assignment` on some compilers and `propagate_on_container_move_assignment` on others. -The use of the allocator's construct and destruct methods might be a bit -surprising. -Nodes are constructed and destructed using the allocator, but the elements -are stored in aligned space within the node and constructed and destructed -by calling the constructor and destructor directly. +[endsect] -In C++11 the allocator's construct function has the signature: +[section:construction Construction/Destruction using allocators] - template - void construct(U* p, Args&&... args); +The following support is required for full use of C++11 style +construction/destruction: -which supports calling `construct` for the contained object, but -most existing allocators don't support this. If member function detection -was good enough then with old allocators it would fall back to calling -the element's constructor directly but in general, detection isn't good -enough to do this which is why Boost.Unordered just calls the constructor -directly every time. In most cases this will work okay. + * Variadic templates. + * Piecewise construction of `std::pair`. + * Either `std::allocator_traits` or expression SFINAE. + +This is detected using Boost.Config. The macro +`BOOST_UNORDERED_CXX11_CONSTRUCTION` will be set to 1 if it is found, or 0 +otherwise. + +When this is the case `allocator_traits::construct` and +`allocator_traits::destroy` will always be used, apart from when piecewise +constructing a `std::pair` using `boost::tuple` (see [link +unordered.compliance.pairs below]), but that should be easily avoided. + +When support is not available `allocator_traits::construct` and +`allocator_traits::destroy` are never called. + +[endsect] + +[section:pointer_traits Pointer Traits] `pointer_traits` aren't used. Instead, pointer types are obtained from rebound allocators, this can cause problems if the allocator can't be @@ -77,6 +86,7 @@ is used to obtain a const pointer. [endsect] +[#unordered.compliance.pairs] [section:pairs Pairs] Since the containers use `std::pair` they're limited to the version From 2effcfa1959b0cfd69ed71b6e8dffae3aa3c8ae9 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 18 Apr 2017 10:14:26 +0100 Subject: [PATCH 030/147] Intro to compliance section Needs more info on C++17 compliance - particularly `noexecpt`. --- doc/compliance.qbk | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/compliance.qbk b/doc/compliance.qbk index b0fd9472..1553d987 100644 --- a/doc/compliance.qbk +++ b/doc/compliance.qbk @@ -2,7 +2,13 @@ / Distributed under the Boost Software License, Version 1.0. (See accompanying / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:compliance C++11 Compliance] +[section:compliance Standard Compliance] + +The intent of Boost.Unordered is to implement a close (but inperfect) +implementation of the C++17 standard, that will work with C++98 upwards. +The wide compatibility does mean some comprimises have to be made. +With a compiler and library that fully support C++11, the differences should +be minor. [section:move Move emulation] From cee94e9fcb957cf5d7557242027d39a5104c7265 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 19 Apr 2017 09:20:31 +0100 Subject: [PATCH 031/147] Fix unused parameter warning --- include/boost/unordered/detail/implementation.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 95502fe0..0d2e4a1b 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1492,8 +1492,7 @@ construct_from_args(Alloc& alloc, std::pair* address, BOOST_FWD_REF(A0), // Construct from variadic parameters template -inline void construct_from_args( - Alloc& alloc, T* address, BOOST_FWD_REF(Args)... args) +inline void construct_from_args(Alloc&, T* address, BOOST_FWD_REF(Args)... args) { new ((void*)address) T(boost::forward(args)...); } From d47754acac035762fe90404618ca65472d27ccac Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 19 Apr 2017 09:44:58 +0100 Subject: [PATCH 032/147] Include unordered macro values in test output --- test/helpers/test.hpp | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/test/helpers/test.hpp b/test/helpers/test.hpp index 393658ea..e02647fe 100644 --- a/test/helpers/test.hpp +++ b/test/helpers/test.hpp @@ -27,7 +27,7 @@ #define RUN_TESTS() \ int main(int, char**) \ { \ - ::test::write_compiler_info(); \ + BOOST_UNORDERED_TEST_COMPILER_INFO() \ ::test::test_list::run_tests(); \ return boost::report_errors(); \ } @@ -76,22 +76,32 @@ static inline void run_tests() } } } +} -inline void write_compiler_info() -{ +// TODO: Detect C++11 on more compilers #if defined(BOOST_GCC_CXX11) - char const* cpp11 = "true"; +#define BOOST_UNORDERED_TEST_CXX11 "true" #else - char const* cpp11 = "false"; +#define BOOST_UNORDERED_TEST_CXX11 "false" #endif - std::cout << "Compiler: " << BOOST_COMPILER << "\n" - << "Library: " << BOOST_STDLIB << "\n" - << "C++11: " << cpp11 << "\n" - << "\n" - << std::flush; -} -} +#define BOOST_UNORDERED_TEST_COMPILER_INFO() \ + { \ + std::cout << "Compiler: " << BOOST_COMPILER << "\n" \ + << "Library: " << BOOST_STDLIB << "\n" \ + << "C++11: " << BOOST_UNORDERED_TEST_CXX11 << "\n\n" \ + << "BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT: " \ + << BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT << "\n" \ + << "BOOST_UNORDERED_EMPLACE_LIMIT: " \ + << BOOST_UNORDERED_EMPLACE_LIMIT << "\n" \ + << "BOOST_UNORDERED_INTEROPERABLE_NODES: " \ + << BOOST_UNORDERED_INTEROPERABLE_NODES << "\n" \ + << "BOOST_UNORDERED_USE_ALLOCATOR_TRAITS: " \ + << BOOST_UNORDERED_USE_ALLOCATOR_TRAITS << "\n" \ + << "BOOST_UNORDERED_CXX11_CONSTRUCTION: " \ + << BOOST_UNORDERED_CXX11_CONSTRUCTION << "\n\n" \ + << std::flush; \ + } #include #include From 6bdf1ba2442580d028b66b9dd4fb0b15309fb9dc Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 19 Apr 2017 09:46:15 +0100 Subject: [PATCH 033/147] Fix a comment --- include/boost/unordered/detail/implementation.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 0d2e4a1b..3b4c3a47 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -61,9 +61,9 @@ // Unless documented elsewhere these configuration macros should be considered // an implementation detail, I'll try not to break them, but you never know. -// BOOST_UNORDERED_EMPLACE_LIMIT = The maximum number of parameters in emplace -// (not including things like hints). Don't set it to a lower value, as that -// might break something. +// BOOST_UNORDERED_EMPLACE_LIMIT = The maximum number of parameters + 1 in +// emplace (not including things like hints). Don't set it to a lower value, as +// that might break something. #if !defined BOOST_UNORDERED_EMPLACE_LIMIT #define BOOST_UNORDERED_EMPLACE_LIMIT 11 From ee73a534976a18bcaa2a227562deb5ff1bb37ae7 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 10:09:57 +0100 Subject: [PATCH 034/147] Disable failing tests on gcc 4.6/4.7 c++11 mode Works fine on later versions of GCC, I suspect it's a bug in their noexcept support. --- test/unordered/compile_tests.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index df49bf91..45ad2111 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -19,6 +19,7 @@ #include "../helpers/check_return_type.hpp" #include #include +#include #include #include #include @@ -169,11 +170,15 @@ template void container_test(X& r, T const&) // node_type implicit_construct(); +#if !BOOST_COMP_GNUC || BOOST_COMP_GNUC >= BOOST_VERSION_NUMBER(4, 8, 0) TEST_NOEXCEPT_EXPR(node_type()); +#endif node_type n1; node_type n2(rvalue_default()); +#if !BOOST_COMP_GNUC || BOOST_COMP_GNUC >= BOOST_VERSION_NUMBER(4, 8, 0) TEST_NOEXCEPT_EXPR(node_type(boost::move(n1))); +#endif node_type n3; n3 = boost::move(n2); n1.swap(n3); From af94e6a40eb96eb88259cc5fa0e832fc720af532 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 035/147] Reorder the constructors to match the draft standard In order to make it easier to check against the standard. This includes collapsing some of the input iterator overloads into one constructor. --- include/boost/unordered/unordered_map.hpp | 376 ++++++++++------------ include/boost/unordered/unordered_set.hpp | 375 ++++++++++----------- 2 files changed, 351 insertions(+), 400 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 75e8a02a..8da55311 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -85,36 +85,14 @@ template class unordered_map 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 unordered_map(InputIt, InputIt); - template - unordered_map(InputIt, InputIt, size_type, const hasher& = hasher(), - const key_equal& = key_equal()); - - template - unordered_map(InputIt, InputIt, size_type, const hasher&, 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(InputIt, InputIt, + size_type = boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), const key_equal& = key_equal(), + const allocator_type& = allocator_type()); 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) BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) @@ -129,15 +107,36 @@ template class unordered_map } #endif + explicit unordered_map(allocator_type const&); + + unordered_map(unordered_map const&, allocator_type const&); + + unordered_map(BOOST_RV_REF(unordered_map), allocator_type const&); + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) unordered_map(std::initializer_list, size_type = boost::unordered::detail::default_bucket_count, 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&); +#endif + + explicit unordered_map(size_type, const allocator_type&); + + explicit unordered_map(size_type, const hasher&, const allocator_type&); + + template + unordered_map(InputIt, InputIt, size_type, const allocator_type&); + + template + unordered_map( + InputIt, InputIt, size_type, const hasher&, const allocator_type&); + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) unordered_map( std::initializer_list, size_type, const allocator_type&); + + unordered_map(std::initializer_list, size_type, const hasher&, + const allocator_type&); #endif // Destructor @@ -800,37 +799,14 @@ template class unordered_multimap 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 unordered_multimap(InputIt, InputIt); - template - unordered_multimap(InputIt, InputIt, size_type, const hasher& = hasher(), - const key_equal& = key_equal()); - - template - unordered_multimap(InputIt, InputIt, size_type, const hasher&, - 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(InputIt, InputIt, + size_type = boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), const key_equal& = key_equal(), + const allocator_type& = allocator_type()); 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) BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) @@ -845,15 +821,37 @@ template class unordered_multimap } #endif + explicit unordered_multimap(allocator_type const&); + + unordered_multimap(unordered_multimap const&, allocator_type const&); + + unordered_multimap(BOOST_RV_REF(unordered_multimap), allocator_type const&); + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) unordered_multimap(std::initializer_list, size_type = boost::unordered::detail::default_bucket_count, 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&); +#endif + + explicit unordered_multimap(size_type, const allocator_type&); + + explicit unordered_multimap( + size_type, const hasher&, const allocator_type&); + + template + unordered_multimap(InputIt, InputIt, size_type, const allocator_type&); + + template + unordered_multimap( + InputIt, InputIt, size_type, const hasher&, const allocator_type&); + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) unordered_multimap( std::initializer_list, size_type, const allocator_type&); + + unordered_multimap(std::initializer_list, size_type, + const hasher&, const allocator_type&); #endif // Destructor @@ -1243,16 +1241,17 @@ unordered_map::unordered_map(size_type n, const hasher& hf, } template -unordered_map::unordered_map( - size_type n, const allocator_type& a) - : table_(n, hasher(), key_equal(), a) +template +unordered_map::unordered_map(InputIt f, InputIt l, size_type n, + const hasher& hf, const key_equal& eql, const allocator_type& a) + : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) { + table_.insert_range(f, l); } template -unordered_map::unordered_map( - size_type n, const hasher& hf, const allocator_type& a) - : table_(n, hf, key_equal(), a) +unordered_map::unordered_map(unordered_map const& other) + : table_(other.table_) { } @@ -1270,65 +1269,6 @@ unordered_map::unordered_map( { } -template -template -unordered_map::unordered_map(InputIt f, InputIt l) - : table_(boost::unordered::detail::initial_size(f, l), hasher(), - key_equal(), allocator_type()) -{ - table_.insert_range(f, l); -} - -template -template -unordered_map::unordered_map( - InputIt f, InputIt l, size_type n, const hasher& hf, const key_equal& eql) - : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, - allocator_type()) -{ - table_.insert_range(f, l); -} - -template -template -unordered_map::unordered_map(InputIt f, InputIt l, size_type n, - const hasher& hf, const key_equal& eql, const allocator_type& a) - : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) -{ - 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 -{ -} - -template -unordered_map::unordered_map(unordered_map const& other) - : table_(other.table_) -{ -} - template unordered_map::unordered_map( BOOST_RV_REF(unordered_map) other, allocator_type const& a) @@ -1349,17 +1289,44 @@ unordered_map::unordered_map( table_.insert_range(list.begin(), list.end()); } +#endif + 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) + size_type n, const allocator_type& a) + : table_(n, hasher(), key_equal(), a) { - table_.insert_range(list.begin(), list.end()); } +template +unordered_map::unordered_map( + size_type n, const hasher& hf, const allocator_type& a) + : table_(n, hf, key_equal(), a) +{ +} + +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 +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); +} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + template unordered_map::unordered_map( std::initializer_list list, size_type n, @@ -1371,6 +1338,26 @@ unordered_map::unordered_map( 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()); +} + +#endif + +template +unordered_map::~unordered_map() BOOST_NOEXCEPT +{ +} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + template unordered_map& unordered_map::operator=( std::initializer_list list) @@ -1663,16 +1650,19 @@ unordered_multimap::unordered_multimap(size_type n, } template -unordered_multimap::unordered_multimap( - size_type n, const allocator_type& a) - : table_(n, hasher(), key_equal(), a) +template +unordered_multimap::unordered_multimap(InputIt f, InputIt l, + size_type n, const hasher& hf, const key_equal& eql, + const allocator_type& a) + : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) { + table_.insert_range(f, l); } template unordered_multimap::unordered_multimap( - size_type n, const hasher& hf, const allocator_type& a) - : table_(n, hf, key_equal(), a) + unordered_multimap const& other) + : table_(other.table_) { } @@ -1690,67 +1680,6 @@ unordered_multimap::unordered_multimap( { } -template -template -unordered_multimap::unordered_multimap(InputIt f, InputIt l) - : table_(boost::unordered::detail::initial_size(f, l), hasher(), - key_equal(), allocator_type()) -{ - table_.insert_range(f, l); -} - -template -template -unordered_multimap::unordered_multimap( - InputIt f, InputIt l, size_type n, const hasher& hf, const key_equal& eql) - : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, - allocator_type()) -{ - table_.insert_range(f, l); -} - -template -template -unordered_multimap::unordered_multimap(InputIt f, InputIt l, - size_type n, const hasher& hf, const key_equal& eql, - const allocator_type& a) - : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) -{ - 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 -{ -} - -template -unordered_multimap::unordered_multimap( - unordered_multimap const& other) - : table_(other.table_) -{ -} - template unordered_multimap::unordered_multimap( BOOST_RV_REF(unordered_multimap) other, allocator_type const& a) @@ -1771,17 +1700,44 @@ unordered_multimap::unordered_multimap( table_.insert_range(list.begin(), list.end()); } +#endif + 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) + size_type n, const allocator_type& a) + : table_(n, hasher(), key_equal(), a) { - table_.insert_range(list.begin(), list.end()); } +template +unordered_multimap::unordered_multimap( + size_type n, const hasher& hf, const allocator_type& a) + : table_(n, hf, key_equal(), a) +{ +} + +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 +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); +} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + template unordered_multimap::unordered_multimap( std::initializer_list list, size_type n, @@ -1793,6 +1749,26 @@ unordered_multimap::unordered_multimap( 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()); +} + +#endif + +template +unordered_multimap::~unordered_multimap() BOOST_NOEXCEPT +{ +} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + 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 afb25916..52e357f1 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -83,36 +83,14 @@ template class unordered_set 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 unordered_set(InputIt, InputIt); - template - unordered_set(InputIt, InputIt, size_type, const hasher& = hasher(), - const key_equal& = key_equal()); - - template - unordered_set(InputIt, InputIt, size_type, const hasher&, 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(InputIt, InputIt, + size_type = boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), const key_equal& = key_equal(), + const allocator_type& = allocator_type()); 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) BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) @@ -127,15 +105,36 @@ template class unordered_set } #endif + explicit unordered_set(allocator_type const&); + + unordered_set(unordered_set const&, allocator_type const&); + + unordered_set(BOOST_RV_REF(unordered_set), allocator_type const&); + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) unordered_set(std::initializer_list, size_type = boost::unordered::detail::default_bucket_count, 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&); +#endif + + explicit unordered_set(size_type, const allocator_type&); + + explicit unordered_set(size_type, const hasher&, const allocator_type&); + + template + unordered_set(InputIt, InputIt, size_type, const allocator_type&); + + template + unordered_set( + InputIt, InputIt, size_type, const hasher&, const allocator_type&); + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) unordered_set( std::initializer_list, size_type, const allocator_type&); + + unordered_set(std::initializer_list, size_type, const hasher&, + const allocator_type&); #endif // Destructor @@ -541,37 +540,14 @@ template class unordered_multiset 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 unordered_multiset(InputIt, InputIt); - template - unordered_multiset(InputIt, InputIt, size_type, const hasher& = hasher(), - const key_equal& = key_equal()); - - template - unordered_multiset(InputIt, InputIt, size_type, const hasher&, - 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(InputIt, InputIt, + size_type = boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), const key_equal& = key_equal(), + const allocator_type& = allocator_type()); 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) BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) @@ -586,15 +562,37 @@ template class unordered_multiset } #endif + explicit unordered_multiset(allocator_type const&); + + unordered_multiset(unordered_multiset const&, allocator_type const&); + + unordered_multiset(BOOST_RV_REF(unordered_multiset), allocator_type const&); + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) unordered_multiset(std::initializer_list, size_type = boost::unordered::detail::default_bucket_count, 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&); +#endif + + explicit unordered_multiset(size_type, const allocator_type&); + + explicit unordered_multiset( + size_type, const hasher&, const allocator_type&); + + template + unordered_multiset(InputIt, InputIt, size_type, const allocator_type&); + + template + unordered_multiset( + InputIt, InputIt, size_type, const hasher&, const allocator_type&); + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) unordered_multiset( std::initializer_list, size_type, const allocator_type&); + + unordered_multiset(std::initializer_list, size_type, + const hasher&, const allocator_type&); #endif // Destructor @@ -943,7 +941,6 @@ template class unordered_multiset }; // class template unordered_multiset //////////////////////////////////////////////////////////////////////////////// - template unordered_set::unordered_set() : table_(boost::unordered::detail::default_bucket_count, hasher(), @@ -959,15 +956,17 @@ unordered_set::unordered_set(size_type n, const hasher& hf, } template -unordered_set::unordered_set(size_type n, const allocator_type& a) - : table_(n, hasher(), key_equal(), a) +template +unordered_set::unordered_set(InputIt f, InputIt l, size_type n, + const hasher& hf, const key_equal& eql, const allocator_type& a) + : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) { + table_.insert_range(f, l); } template -unordered_set::unordered_set( - size_type n, const hasher& hf, const allocator_type& a) - : table_(n, hf, key_equal(), a) +unordered_set::unordered_set(unordered_set const& other) + : table_(other.table_) { } @@ -985,65 +984,6 @@ unordered_set::unordered_set( { } -template -template -unordered_set::unordered_set(InputIt f, InputIt l) - : table_(boost::unordered::detail::initial_size(f, l), hasher(), - key_equal(), allocator_type()) -{ - table_.insert_range(f, l); -} - -template -template -unordered_set::unordered_set( - InputIt f, InputIt l, size_type n, const hasher& hf, const key_equal& eql) - : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, - allocator_type()) -{ - table_.insert_range(f, l); -} - -template -template -unordered_set::unordered_set(InputIt f, InputIt l, size_type n, - const hasher& hf, const key_equal& eql, const allocator_type& a) - : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) -{ - 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 -{ -} - -template -unordered_set::unordered_set(unordered_set const& other) - : table_(other.table_) -{ -} - template unordered_set::unordered_set( BOOST_RV_REF(unordered_set) other, allocator_type const& a) @@ -1064,16 +1004,43 @@ unordered_set::unordered_set(std::initializer_list list, table_.insert_range(list.begin(), list.end()); } +#endif + 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) +unordered_set::unordered_set(size_type n, const allocator_type& a) + : table_(n, hasher(), key_equal(), a) { - table_.insert_range(list.begin(), list.end()); } +template +unordered_set::unordered_set( + size_type n, const hasher& hf, const allocator_type& a) + : table_(n, hf, key_equal(), a) +{ +} + +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 +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); +} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + template unordered_set::unordered_set(std::initializer_list list, size_type n, const allocator_type& a) @@ -1084,6 +1051,25 @@ unordered_set::unordered_set(std::initializer_list list, 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()); +} + +#endif + +template +unordered_set::~unordered_set() BOOST_NOEXCEPT +{ +} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + template unordered_set& unordered_set::operator=( std::initializer_list list) @@ -1329,16 +1315,19 @@ unordered_multiset::unordered_multiset(size_type n, } template -unordered_multiset::unordered_multiset( - size_type n, const allocator_type& a) - : table_(n, hasher(), key_equal(), a) +template +unordered_multiset::unordered_multiset(InputIt f, InputIt l, + size_type n, const hasher& hf, const key_equal& eql, + const allocator_type& a) + : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) { + table_.insert_range(f, l); } template unordered_multiset::unordered_multiset( - size_type n, const hasher& hf, const allocator_type& a) - : table_(n, hf, key_equal(), a) + unordered_multiset const& other) + : table_(other.table_) { } @@ -1356,67 +1345,6 @@ unordered_multiset::unordered_multiset( { } -template -template -unordered_multiset::unordered_multiset(InputIt f, InputIt l) - : table_(boost::unordered::detail::initial_size(f, l), hasher(), - key_equal(), allocator_type()) -{ - table_.insert_range(f, l); -} - -template -template -unordered_multiset::unordered_multiset( - InputIt f, InputIt l, size_type n, const hasher& hf, const key_equal& eql) - : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, - allocator_type()) -{ - table_.insert_range(f, l); -} - -template -template -unordered_multiset::unordered_multiset(InputIt f, InputIt l, - size_type n, const hasher& hf, const key_equal& eql, - const allocator_type& a) - : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) -{ - 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 -{ -} - -template -unordered_multiset::unordered_multiset( - unordered_multiset const& other) - : table_(other.table_) -{ -} - template unordered_multiset::unordered_multiset( BOOST_RV_REF(unordered_multiset) other, allocator_type const& a) @@ -1437,17 +1365,44 @@ unordered_multiset::unordered_multiset( table_.insert_range(list.begin(), list.end()); } +#endif + 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) + size_type n, const allocator_type& a) + : table_(n, hasher(), key_equal(), a) { - table_.insert_range(list.begin(), list.end()); } +template +unordered_multiset::unordered_multiset( + size_type n, const hasher& hf, const allocator_type& a) + : table_(n, hf, key_equal(), a) +{ +} + +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 +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); +} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + template unordered_multiset::unordered_multiset( std::initializer_list list, size_type n, @@ -1459,6 +1414,26 @@ unordered_multiset::unordered_multiset( 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()); +} + +#endif + +template +unordered_multiset::~unordered_multiset() BOOST_NOEXCEPT +{ +} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + template unordered_multiset& unordered_multiset::operator=( std::initializer_list list) From e4a00980f8bd83c8fb3ac1d587f3b20821a95d43 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 036/147] Commented out noexcept for move assignment --- include/boost/unordered/unordered_map.hpp | 16 ++++++++++++++++ include/boost/unordered/unordered_set.hpp | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 8da55311..8b5fffe2 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -153,6 +153,10 @@ template class unordered_map } unordered_map& operator=(BOOST_RV_REF(unordered_map) x) + // C++17 support: BOOST_NOEXCEPT_IF( + // value_allocator_traits::is_always_equal::value && + // is_nothrow_move_assignable_v && + // is_nothrow_move_assignable_v

) { table_.move_assign(x.table_); return *this; @@ -166,6 +170,10 @@ template class unordered_map #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_map& operator=(unordered_map&& x) + // C++17 support: BOOST_NOEXCEPT_IF( + // value_allocator_traits::is_always_equal::value && + // is_nothrow_move_assignable_v && + // is_nothrow_move_assignable_v

) { table_.move_assign(x.table_); return *this; @@ -868,6 +876,10 @@ template class unordered_multimap } unordered_multimap& operator=(BOOST_RV_REF(unordered_multimap) x) + // C++17 support: BOOST_NOEXCEPT_IF( + // value_allocator_traits::is_always_equal::value && + // is_nothrow_move_assignable_v && + // is_nothrow_move_assignable_v

) { table_.move_assign(x.table_); return *this; @@ -881,6 +893,10 @@ template class unordered_multimap #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_multimap& operator=(unordered_multimap&& x) + // C++17 support: BOOST_NOEXCEPT_IF( + // value_allocator_traits::is_always_equal::value && + // is_nothrow_move_assignable_v && + // is_nothrow_move_assignable_v

) { table_.move_assign(x.table_); return *this; diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 52e357f1..52136bc6 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -151,6 +151,10 @@ template class unordered_set } unordered_set& operator=(BOOST_RV_REF(unordered_set) x) + // C++17 support: BOOST_NOEXCEPT_IF( + // value_allocator_traits::is_always_equal::value && + // is_nothrow_move_assignable_v && + // is_nothrow_move_assignable_v

) { table_.move_assign(x.table_); return *this; @@ -164,6 +168,10 @@ template class unordered_set #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_set& operator=(unordered_set&& x) + // C++17 support: BOOST_NOEXCEPT_IF( + // value_allocator_traits::is_always_equal::value && + // is_nothrow_move_assignable_v && + // is_nothrow_move_assignable_v

) { table_.move_assign(x.table_); return *this; @@ -609,6 +617,10 @@ template class unordered_multiset } unordered_multiset& operator=(BOOST_RV_REF(unordered_multiset) x) + // C++17 support: BOOST_NOEXCEPT_IF( + // value_allocator_traits::is_always_equal::value && + // is_nothrow_move_assignable_v && + // is_nothrow_move_assignable_v

) { table_.move_assign(x.table_); return *this; @@ -622,6 +634,10 @@ template class unordered_multiset #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_multiset& operator=(unordered_multiset&& x) + // C++17 support: BOOST_NOEXCEPT_IF( + // value_allocator_traits::is_always_equal::value && + // is_nothrow_move_assignable_v && + // is_nothrow_move_assignable_v

) { table_.move_assign(x.table_); return *this; From 1a18cd2196d8d0bcb2433cdabdef03168bd5a7af Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 037/147] Move capacity functions to match order in standard --- include/boost/unordered/unordered_map.hpp | 32 +++++++++++------------ include/boost/unordered/unordered_set.hpp | 32 +++++++++++------------ 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 8b5fffe2..41419b9d 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -190,14 +190,6 @@ template class unordered_map return table_.node_alloc(); } - // size and capacity - - bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } - - size_type size() const BOOST_NOEXCEPT { return table_.size_; } - - size_type max_size() const BOOST_NOEXCEPT; - // iterators iterator begin() BOOST_NOEXCEPT { return iterator(table_.begin()); } @@ -218,6 +210,14 @@ template class unordered_map const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); } + // size and capacity + + bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } + + size_type size() const BOOST_NOEXCEPT { return table_.size_; } + + size_type max_size() const BOOST_NOEXCEPT; + // extract node_type extract(const_iterator position) @@ -913,14 +913,6 @@ template class unordered_multimap return table_.node_alloc(); } - // size and capacity - - bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } - - size_type size() const BOOST_NOEXCEPT { return table_.size_; } - - size_type max_size() const BOOST_NOEXCEPT; - // iterators iterator begin() BOOST_NOEXCEPT { return iterator(table_.begin()); } @@ -941,6 +933,14 @@ template class unordered_multimap const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); } + // size and capacity + + bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } + + size_type size() const BOOST_NOEXCEPT { return table_.size_; } + + size_type max_size() const BOOST_NOEXCEPT; + // extract node_type extract(const_iterator position) diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 52136bc6..0bc240c1 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -188,14 +188,6 @@ template class unordered_set return table_.node_alloc(); } - // size and capacity - - bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } - - size_type size() const BOOST_NOEXCEPT { return table_.size_; } - - size_type max_size() const BOOST_NOEXCEPT; - // iterators iterator begin() BOOST_NOEXCEPT { return iterator(table_.begin()); } @@ -216,6 +208,14 @@ template class unordered_set const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); } + // size and capacity + + bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } + + size_type size() const BOOST_NOEXCEPT { return table_.size_; } + + size_type max_size() const BOOST_NOEXCEPT; + // extract node_type extract(const_iterator position) @@ -654,14 +654,6 @@ template class unordered_multiset return table_.node_alloc(); } - // size and capacity - - bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } - - size_type size() const BOOST_NOEXCEPT { return table_.size_; } - - size_type max_size() const BOOST_NOEXCEPT; - // iterators iterator begin() BOOST_NOEXCEPT { return iterator(table_.begin()); } @@ -682,6 +674,14 @@ template class unordered_multiset const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); } + // size and capacity + + bool empty() const BOOST_NOEXCEPT { return table_.size_ == 0; } + + size_type size() const BOOST_NOEXCEPT { return table_.size_; } + + size_type max_size() const BOOST_NOEXCEPT; + // extract node_type extract(const_iterator position) From ab76814aa6af00c69877f442c7514179619abac5 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 038/147] Move 'insert_or_assign' into same order as draft standard --- include/boost/unordered/unordered_map.hpp | 54 +++++++++++------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 41419b9d..985e9142 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -581,6 +581,33 @@ template class unordered_map return this->emplace_hint(hint, boost::forward(obj)); } + template void insert(InputIt, InputIt); + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + void insert(std::initializer_list); +#endif + + insert_return_type insert(BOOST_RV_REF(node_type) np) + { + insert_return_type result; + table_.move_insert_node_type(np, result); + return boost::move(result); + } + + iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np) + { + return table_.move_insert_node_type_with_hint(hint, np); + } + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + private: + // Note: Use r-value node_type to insert. + insert_return_type insert(node_type&); + iterator insert(const_iterator, node_type& np); + + public: +#endif + template std::pair insert_or_assign( key_type const& k, BOOST_FWD_REF(M) obj) @@ -612,33 +639,6 @@ template class unordered_map .first; } - template void insert(InputIt, InputIt); - -#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - void insert(std::initializer_list); -#endif - - insert_return_type insert(BOOST_RV_REF(node_type) np) - { - insert_return_type result; - table_.move_insert_node_type(np, result); - return boost::move(result); - } - - iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np) - { - return table_.move_insert_node_type_with_hint(hint, np); - } - -#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - private: - // Note: Use r-value node_type to insert. - insert_return_type insert(node_type&); - iterator insert(const_iterator, node_type& np); - - public: -#endif - iterator erase(const_iterator); size_type erase(const key_type&); iterator erase(const_iterator, const_iterator); From d8969c71fca55a1a6b91ba812206e1ea99f7ecba Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 039/147] Move 'try_emplace' into same order as draft standard --- include/boost/unordered/unordered_map.hpp | 404 +++++++++++----------- 1 file changed, 209 insertions(+), 195 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 985e9142..7233aa27 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -246,36 +246,6 @@ template class unordered_map return table_.emplace_hint(hint, boost::forward(args)...); } - template - std::pair try_emplace( - key_type const& k, BOOST_FWD_REF(Args)... args) - { - return table_.try_emplace_impl(k, boost::forward(args)...); - } - - template - iterator try_emplace( - const_iterator hint, key_type const& k, BOOST_FWD_REF(Args)... args) - { - return table_.try_emplace_hint_impl( - hint, k, boost::forward(args)...); - } - - template - std::pair try_emplace( - BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) - { - return table_.try_emplace_impl( - boost::move(k), boost::forward(args)...); - } - - template - iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, - BOOST_FWD_REF(Args)... args) - { - return table_.try_emplace_hint_impl( - hint, boost::move(k), boost::forward(args)...); - } #else #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) @@ -302,18 +272,6 @@ template class unordered_map #endif - template - std::pair try_emplace(BOOST_FWD_REF(Key) k) - { - return table_.try_emplace_impl(boost::forward(k)); - } - - template - iterator try_emplace(const_iterator hint, BOOST_FWD_REF(Key) k) - { - return table_.try_emplace_hint_impl(hint, boost::forward(k)); - } - template std::pair emplace(BOOST_FWD_REF(A0) a0) { @@ -329,42 +287,6 @@ template class unordered_map boost::forward(a0))); } - template - std::pair try_emplace( - key_type const& k, BOOST_FWD_REF(A0) a0) - { - return table_.try_emplace_impl( - k, boost::unordered::detail::create_emplace_args( - boost::forward(a0))); - } - - template - iterator try_emplace( - const_iterator hint, key_type const& k, BOOST_FWD_REF(A0) a0) - { - return table_.try_emplace_hint_impl( - hint, k, boost::unordered::detail::create_emplace_args( - boost::forward(a0))); - } - - template - std::pair try_emplace( - BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) - { - return table_.try_emplace_impl( - boost::move(k), boost::unordered::detail::create_emplace_args( - boost::forward(a0))); - } - - template - iterator try_emplace( - const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) - { - return table_.try_emplace_hint_impl( - hint, boost::move(k), boost::unordered::detail::create_emplace_args( - boost::forward(a0))); - } - template std::pair emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) @@ -382,44 +304,6 @@ template class unordered_map boost::forward(a0), boost::forward(a1))); } - template - std::pair try_emplace( - key_type const& k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) - { - return table_.try_emplace_impl( - k, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); - } - - template - iterator try_emplace(const_iterator hint, key_type const& k, - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) - { - return table_.try_emplace_hint_impl( - hint, k, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); - } - - template - std::pair try_emplace( - BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) - { - return table_.try_emplace_impl( - boost::move(k), - boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); - } - - template - iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) - { - return table_.try_emplace_hint_impl( - hint, boost::move(k), - boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); - } - template std::pair emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) @@ -439,49 +323,6 @@ template class unordered_map boost::forward(a2))); } - template - std::pair try_emplace(key_type const& k, - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) - { - return table_.try_emplace_impl( - k, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); - } - - template - iterator try_emplace(const_iterator hint, key_type const& k, - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) - { - return table_ - .try_emplace_impl_( - hint, k, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))) - .first; - } - - template - std::pair try_emplace(BOOST_RV_REF(key_type) k, - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) - { - return table_.try_emplace_impl( - boost::move(k), boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); - } - - template - iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) - { - return table_.try_emplace_hint_impl( - hint, boost::move(k), - boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); - } - #define BOOST_UNORDERED_EMPLACE(z, n, _) \ template \ std::pair emplace( \ @@ -498,42 +339,6 @@ template class unordered_map return table_.emplace_hint( \ hint, boost::unordered::detail::create_emplace_args( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ - } \ - \ - template \ - std::pair try_emplace( \ - key_type const& k, BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ - { \ - return table_.try_emplace_impl( \ - k, boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ - } \ - \ - template \ - iterator try_emplace(const_iterator hint, key_type const& k, \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ - { \ - return table_.try_emplace_hint_impl(hint, k, \ - boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ - n, BOOST_UNORDERED_CALL_FORWARD, a))); \ - } \ - \ - template \ - std::pair try_emplace(BOOST_RV_REF(key_type) k, \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ - { \ - return table_.try_emplace_impl(boost::move(k), \ - boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ - n, BOOST_UNORDERED_CALL_FORWARD, a))); \ - } \ - \ - template \ - iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ - { \ - return table_.try_emplace_hint_impl(hint, boost::move(k), \ - boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ - n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } BOOST_PP_REPEAT_FROM_TO( @@ -606,6 +411,215 @@ template class unordered_map iterator insert(const_iterator, node_type& np); public: +#endif + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template + std::pair try_emplace( + key_type const& k, BOOST_FWD_REF(Args)... args) + { + return table_.try_emplace_impl(k, boost::forward(args)...); + } + + template + iterator try_emplace( + const_iterator hint, key_type const& k, BOOST_FWD_REF(Args)... args) + { + return table_.try_emplace_hint_impl( + hint, k, boost::forward(args)...); + } + + template + std::pair try_emplace( + BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) + { + return table_.try_emplace_impl( + boost::move(k), boost::forward(args)...); + } + + template + iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, + BOOST_FWD_REF(Args)... args) + { + return table_.try_emplace_hint_impl( + hint, boost::move(k), boost::forward(args)...); + } + +#else + + template + std::pair try_emplace(BOOST_FWD_REF(Key) k) + { + return table_.try_emplace_impl(boost::forward(k)); + } + + template + iterator try_emplace(const_iterator hint, BOOST_FWD_REF(Key) k) + { + return table_.try_emplace_hint_impl(hint, boost::forward(k)); + } + + template + std::pair try_emplace( + key_type const& k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_impl( + k, boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + iterator try_emplace( + const_iterator hint, key_type const& k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_hint_impl( + hint, k, boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + std::pair try_emplace( + BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_impl( + boost::move(k), boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + iterator try_emplace( + const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_hint_impl( + hint, boost::move(k), boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + std::pair try_emplace( + key_type const& k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_impl( + k, boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + + template + iterator try_emplace(const_iterator hint, key_type const& k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_hint_impl( + hint, k, boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + + template + std::pair try_emplace( + BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_impl( + boost::move(k), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + + template + iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_hint_impl( + hint, boost::move(k), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + + template + std::pair try_emplace(key_type const& k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.try_emplace_impl( + k, boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))); + } + + template + iterator try_emplace(const_iterator hint, key_type const& k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_ + .try_emplace_impl_( + hint, k, boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))) + .first; + } + + template + std::pair try_emplace(BOOST_RV_REF(key_type) k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.try_emplace_impl( + boost::move(k), boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))); + } + + template + iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.try_emplace_hint_impl( + hint, boost::move(k), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))); + } + +#define BOOST_UNORDERED_TRY_EMPLACE(z, n, _) \ + \ + template \ + std::pair try_emplace( \ + key_type const& k, BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.try_emplace_impl( \ + k, boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } \ + \ + template \ + iterator try_emplace(const_iterator hint, key_type const& k, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.try_emplace_hint_impl(hint, k, \ + boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ + n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } \ + \ + template \ + std::pair try_emplace(BOOST_RV_REF(key_type) k, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.try_emplace_impl(boost::move(k), \ + boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ + n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } \ + \ + template \ + iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ + { \ + return table_.try_emplace_hint_impl(hint, boost::move(k), \ + boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ + n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + } + + BOOST_PP_REPEAT_FROM_TO( + 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_TRY_EMPLACE, _) + +#undef BOOST_UNORDERED_TRY_EMPLACE + #endif template From e2e995938998a3c822a8b139c5d994f5c5333801 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 040/147] Split up emplace and emplace_hint code Busywork I guess, but I think it's more readable this way. The emplace macros are still unreadable, but I think they're rarely used. Btw. a bit weird that clang format has removed the indentation on the '// emplace' comment, not sure why that is. --- include/boost/unordered/unordered_map.hpp | 150 +++++++++++++--------- include/boost/unordered/unordered_set.hpp | 143 +++++++++++++-------- 2 files changed, 177 insertions(+), 116 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 7233aa27..0a257b7e 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -234,18 +234,13 @@ template class unordered_map // emplace #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template std::pair emplace(BOOST_FWD_REF(Args)... args) { return table_.emplace(boost::forward(args)...); } - template - iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) - { - return table_.emplace_hint(hint, boost::forward(args)...); - } - #else #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) @@ -262,6 +257,46 @@ template class unordered_map return this->emplace(boost::move(v)); } +#endif + + template + std::pair emplace(BOOST_FWD_REF(A0) a0) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + std::pair emplace( + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + + template + std::pair emplace( + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))); + } + +#endif + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) + { + return table_.emplace_hint(hint, boost::forward(args)...); + } + +#else + +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) + iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = boost::unordered::detail::empty_emplace(), @@ -272,13 +307,6 @@ template class unordered_map #endif - template - std::pair emplace(BOOST_FWD_REF(A0) a0) - { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0))); - } - template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { @@ -287,14 +315,6 @@ template class unordered_map boost::forward(a0))); } - template - std::pair emplace( - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) - { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); - } - template iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) @@ -304,15 +324,6 @@ template class unordered_map boost::forward(a0), boost::forward(a1))); } - template - std::pair emplace( - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) - { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); - } - template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) @@ -323,6 +334,10 @@ template class unordered_map boost::forward(a2))); } +#endif + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + #define BOOST_UNORDERED_EMPLACE(z, n, _) \ template \ std::pair emplace( \ @@ -971,16 +986,12 @@ template class unordered_multimap // emplace #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template iterator emplace(BOOST_FWD_REF(Args)... args) { return table_.emplace(boost::forward(args)...); } - template - iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) - { - return table_.emplace_hint(hint, boost::forward(args)...); - } #else #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) @@ -996,14 +1007,6 @@ template class unordered_multimap return this->emplace(boost::move(v)); } - iterator emplace_hint(const_iterator hint, - boost::unordered::detail::empty_emplace = - boost::unordered::detail::empty_emplace(), - value_type v = value_type()) - { - return this->emplace_hint(hint, boost::move(v)); - } - #endif template iterator emplace(BOOST_FWD_REF(A0) a0) @@ -1012,14 +1015,6 @@ template class unordered_multimap boost::forward(a0))); } - template - iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) - { - return table_.emplace_hint( - hint, boost::unordered::detail::create_emplace_args( - boost::forward(a0))); - } - template iterator emplace(BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { @@ -1027,15 +1022,6 @@ template class unordered_multimap boost::forward(a0), boost::forward(a1))); } - template - iterator emplace_hint( - const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) - { - return table_.emplace_hint( - hint, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); - } - template iterator emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) @@ -1045,6 +1031,46 @@ template class unordered_multimap boost::forward(a2))); } +#endif + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) + { + return table_.emplace_hint(hint, boost::forward(args)...); + } + +#else + +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) + + iterator emplace_hint(const_iterator hint, + boost::unordered::detail::empty_emplace = + boost::unordered::detail::empty_emplace(), + value_type v = value_type()) + { + return this->emplace_hint(hint, boost::move(v)); + } + +#endif + + template + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) + { + return table_.emplace_hint( + hint, boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + template + iterator emplace_hint( + const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.emplace_hint( + hint, boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) @@ -1055,6 +1081,10 @@ template class unordered_multimap boost::forward(a2))); } +#endif + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + #define BOOST_UNORDERED_EMPLACE(z, n, _) \ template \ iterator emplace(BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 0bc240c1..aee65b41 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -232,17 +232,13 @@ template class unordered_set // emplace #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template std::pair emplace(BOOST_FWD_REF(Args)... args) { return table_.emplace(boost::forward(args)...); } - template - iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) - { - return table_.emplace_hint(hint, boost::forward(args)...); - } #else #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) @@ -259,6 +255,46 @@ template class unordered_set return this->emplace(boost::move(v)); } +#endif + + template + std::pair emplace(BOOST_FWD_REF(A0) a0) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + std::pair emplace( + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + + template + std::pair emplace( + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))); + } + +#endif + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) + { + return table_.emplace_hint(hint, boost::forward(args)...); + } + +#else + +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) + iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = boost::unordered::detail::empty_emplace(), @@ -269,13 +305,6 @@ template class unordered_set #endif - template - std::pair emplace(BOOST_FWD_REF(A0) a0) - { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0))); - } - template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { @@ -284,14 +313,6 @@ template class unordered_set boost::forward(a0))); } - template - std::pair emplace( - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) - { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); - } - template iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) @@ -301,15 +322,6 @@ template class unordered_set boost::forward(a0), boost::forward(a1))); } - template - std::pair emplace( - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) - { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); - } - template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) @@ -320,6 +332,10 @@ template class unordered_set boost::forward(a2))); } +#endif + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + #define BOOST_UNORDERED_EMPLACE(z, n, _) \ template \ std::pair emplace( \ @@ -703,11 +719,6 @@ template class unordered_multiset return table_.emplace(boost::forward(args)...); } - template - iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) - { - return table_.emplace_hint(hint, boost::forward(args)...); - } #else #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) @@ -723,6 +734,44 @@ template class unordered_multiset return this->emplace(boost::move(v)); } +#endif + + template iterator emplace(BOOST_FWD_REF(A0) a0) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + iterator emplace(BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + + template + iterator emplace( + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.emplace(boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))); + } + +#endif + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) + { + return table_.emplace_hint(hint, boost::forward(args)...); + } + +#else + +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) + iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = boost::unordered::detail::empty_emplace(), @@ -733,12 +782,6 @@ template class unordered_multiset #endif - template iterator emplace(BOOST_FWD_REF(A0) a0) - { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0))); - } - template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { @@ -747,13 +790,6 @@ template class unordered_multiset boost::forward(a0))); } - template - iterator emplace(BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) - { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); - } - template iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) @@ -763,15 +799,6 @@ template class unordered_multiset boost::forward(a0), boost::forward(a1))); } - template - iterator emplace( - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) - { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); - } - template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) @@ -782,6 +809,10 @@ template class unordered_multiset boost::forward(a2))); } +#endif + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + #define BOOST_UNORDERED_EMPLACE(z, n, _) \ template \ iterator emplace(BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ From 5eb10fd0b235bc9e468e7f6f85ee6ecd26d45bec Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 041/147] Move extract into place --- include/boost/unordered/unordered_map.hpp | 52 +++++++++++------------ include/boost/unordered/unordered_set.hpp | 52 +++++++++++------------ 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 0a257b7e..ec3d891e 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -218,19 +218,6 @@ template class unordered_map size_type max_size() const BOOST_NOEXCEPT; - // extract - - node_type extract(const_iterator position) - { - return node_type( - table_.extract_by_iterator(position), table_.node_alloc()); - } - - node_type extract(const key_type& k) - { - return node_type(table_.extract_by_key(k), table_.node_alloc()); - } - // emplace #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -407,6 +394,19 @@ template class unordered_map void insert(std::initializer_list); #endif + // extract + + node_type extract(const_iterator position) + { + return node_type( + table_.extract_by_iterator(position), table_.node_alloc()); + } + + node_type extract(const key_type& k) + { + return node_type(table_.extract_by_key(k), table_.node_alloc()); + } + insert_return_type insert(BOOST_RV_REF(node_type) np) { insert_return_type result; @@ -970,19 +970,6 @@ template class unordered_multimap size_type max_size() const BOOST_NOEXCEPT; - // extract - - node_type extract(const_iterator position) - { - return node_type( - table_.extract_by_iterator(position), table_.node_alloc()); - } - - node_type extract(const key_type& k) - { - return node_type(table_.extract_by_key(k), table_.node_alloc()); - } - // emplace #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -1150,6 +1137,19 @@ template class unordered_multimap void insert(std::initializer_list); #endif + // extract + + node_type extract(const_iterator position) + { + return node_type( + table_.extract_by_iterator(position), table_.node_alloc()); + } + + node_type extract(const key_type& k) + { + return node_type(table_.extract_by_key(k), table_.node_alloc()); + } + iterator insert(BOOST_RV_REF(node_type) np) { return table_.move_insert_node_type(np); diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index aee65b41..d2497620 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -216,19 +216,6 @@ template class unordered_set size_type max_size() const BOOST_NOEXCEPT; - // extract - - node_type extract(const_iterator position) - { - return node_type( - table_.extract_by_iterator(position), table_.node_alloc()); - } - - node_type extract(const key_type& k) - { - return node_type(table_.extract_by_key(k), table_.node_alloc()); - } - // emplace #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -387,6 +374,19 @@ template class unordered_set void insert(std::initializer_list); #endif + // extract + + node_type extract(const_iterator position) + { + return node_type( + table_.extract_by_iterator(position), table_.node_alloc()); + } + + node_type extract(const key_type& k) + { + return node_type(table_.extract_by_key(k), table_.node_alloc()); + } + insert_return_type insert(BOOST_RV_REF(node_type) np) { insert_return_type result; @@ -698,19 +698,6 @@ template class unordered_multiset size_type max_size() const BOOST_NOEXCEPT; - // extract - - node_type extract(const_iterator position) - { - return node_type( - table_.extract_by_iterator(position), table_.node_alloc()); - } - - node_type extract(const key_type& k) - { - return node_type(table_.extract_by_key(k), table_.node_alloc()); - } - // emplace #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -860,6 +847,19 @@ template class unordered_multiset void insert(std::initializer_list); #endif + // extract + + node_type extract(const_iterator position) + { + return node_type( + table_.extract_by_iterator(position), table_.node_alloc()); + } + + node_type extract(const key_type& k) + { + return node_type(table_.extract_by_key(k), table_.node_alloc()); + } + iterator insert(BOOST_RV_REF(node_type) np) { return table_.move_insert_node_type(np); From 461ac96a2cd05c4df10efa0e8f822817873d654b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 042/147] Reorder insert_or_assign to match standard --- include/boost/unordered/unordered_map.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index ec3d891e..cfaa1a29 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -644,13 +644,6 @@ template class unordered_map return table_.insert_or_assign_impl(k, boost::forward(obj)); } - template - iterator insert_or_assign( - const_iterator, key_type const& k, BOOST_FWD_REF(M) obj) - { - return table_.insert_or_assign_impl(k, boost::forward(obj)).first; - } - template std::pair insert_or_assign( BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) @@ -659,6 +652,13 @@ template class unordered_map boost::move(k), boost::forward(obj)); } + template + iterator insert_or_assign( + const_iterator, key_type const& k, BOOST_FWD_REF(M) obj) + { + return table_.insert_or_assign_impl(k, boost::forward(obj)).first; + } + template iterator insert_or_assign( const_iterator, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) From bf7a65010c843495dddc487a8f7889f1d6745871 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 043/147] Add new erase(iterator) overloads Not for unordered_set/unordered_multiset as they use the same type for iterator and const_iterator. --- include/boost/unordered/unordered_map.hpp | 16 ++++++++++++ test/unordered/compile_map.cpp | 32 +++++++++++++++++++++++ test/unordered/compile_set.cpp | 32 +++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index cfaa1a29..61081e36 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -668,6 +668,7 @@ template class unordered_map .first; } + iterator erase(iterator); iterator erase(const_iterator); size_type erase(const key_type&); iterator erase(const_iterator, const_iterator); @@ -1169,6 +1170,7 @@ template class unordered_multimap public: #endif + iterator erase(iterator); iterator erase(const_iterator); size_type erase(const key_type&); iterator erase(const_iterator, const_iterator); @@ -1455,6 +1457,13 @@ void unordered_map::insert( } #endif +template +typename unordered_map::iterator +unordered_map::erase(iterator position) +{ + return table_.erase(position); +} + template typename unordered_map::iterator unordered_map::erase(const_iterator position) @@ -1866,6 +1875,13 @@ void unordered_multimap::insert( } #endif +template +typename unordered_multimap::iterator +unordered_multimap::erase(iterator position) +{ + return table_.erase(position); +} + template typename unordered_multimap::iterator unordered_multimap::erase(const_iterator position) diff --git a/test/unordered/compile_map.cpp b/test/unordered/compile_map.cpp index 1b099c70..6293dfb8 100644 --- a/test/unordered/compile_map.cpp +++ b/test/unordered/compile_map.cpp @@ -227,4 +227,36 @@ UNORDERED_AUTO_TEST(test2) unordered_map_member_test(multimap, map_value); } +// Test for ambiguity when using key convertible from iterator +// See LWG2059 + +struct lwg2059_key +{ + int value; + + template lwg2059_key(T v) : value(v) {} +}; + +std::size_t hash_value(lwg2059_key x) +{ + return static_cast(x.value); +} + +bool operator==(lwg2059_key x, lwg2059_key y) { return x.value == y.value; } + +UNORDERED_AUTO_TEST(lwg2059) +{ + { + boost::unordered_map x; + x.emplace(lwg2059_key(10), 5); + x.erase(x.begin()); + } + + { + boost::unordered_multimap x; + x.emplace(lwg2059_key(10), 5); + x.erase(x.begin()); + } +} + RUN_TESTS() diff --git a/test/unordered/compile_set.cpp b/test/unordered/compile_set.cpp index 3ea98703..e0a07737 100644 --- a/test/unordered/compile_set.cpp +++ b/test/unordered/compile_set.cpp @@ -290,4 +290,36 @@ UNORDERED_AUTO_TEST(destructible_tests) unordered_destructible_test(multiset); } +// Test for ambiguity when using key convertible from iterator +// See LWG2059 + +struct lwg2059_key +{ + int value; + + template lwg2059_key(T v) : value(v) {} +}; + +std::size_t hash_value(lwg2059_key x) +{ + return static_cast(x.value); +} + +bool operator==(lwg2059_key x, lwg2059_key y) { return x.value == y.value; } + +UNORDERED_AUTO_TEST(lwg2059) +{ + { + boost::unordered_set x; + x.emplace(lwg2059_key(10)); + x.erase(x.begin()); + } + + { + boost::unordered_multiset x; + x.emplace(lwg2059_key(10)); + x.erase(x.begin()); + } +} + RUN_TESTS() From 5167c970af485e1f6a730a5fb5678d04d69d9194 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 044/147] Swap order of swap/clear to match standard --- include/boost/unordered/unordered_map.hpp | 28 +++++++++++------------ include/boost/unordered/unordered_set.hpp | 20 ++++++++-------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 61081e36..4897f386 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -677,8 +677,8 @@ template class unordered_map BOOST_UNORDERED_DEPRECATED("Use erase instead") void erase_return_void(const_iterator it) { erase(it); } - void clear(); void swap(unordered_map&); + void clear(); template void merge(boost::unordered_map& source); @@ -1179,8 +1179,8 @@ template class unordered_multimap BOOST_UNORDERED_DEPRECATED("Use erase instead") void erase_return_void(const_iterator it) { erase(it); } - void clear(); void swap(unordered_multimap&); + void clear(); template void merge(boost::unordered_multimap& source); @@ -1485,18 +1485,18 @@ unordered_map::erase(const_iterator first, const_iterator last) return table_.erase_range(first, last); } -template -void unordered_map::clear() -{ - table_.clear(); -} - template void unordered_map::swap(unordered_map& other) { table_.swap(other.table_); } +template +void unordered_map::clear() +{ + table_.clear(); +} + template template void unordered_map::merge( @@ -1904,18 +1904,18 @@ unordered_multimap::erase( return table_.erase_range(first, last); } -template -void unordered_multimap::clear() -{ - table_.clear(); -} - template void unordered_multimap::swap(unordered_multimap& other) { table_.swap(other.table_); } +template +void unordered_multimap::clear() +{ + table_.clear(); +} + // observers template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index d2497620..2cf710f5 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -416,8 +416,8 @@ template class unordered_set BOOST_UNORDERED_DEPRECATED("Use erase instead") void erase_return_void(const_iterator it) { erase(it); } - void clear(); void swap(unordered_set&); + void clear(); template void merge(boost::unordered_set& source); @@ -887,8 +887,8 @@ template class unordered_multiset BOOST_UNORDERED_DEPRECATED("Use erase instead") void erase_return_void(const_iterator it) { erase(it); } - void clear(); void swap(unordered_multiset&); + void clear(); template void merge(boost::unordered_multiset& source); @@ -1174,6 +1174,12 @@ typename unordered_set::iterator unordered_set::erase( return table_.erase_range(first, last); } +template +void unordered_set::swap(unordered_set& other) +{ + table_.swap(other.table_); +} + template void unordered_set::clear() { @@ -1181,9 +1187,9 @@ void unordered_set::clear() } template -void unordered_set::swap(unordered_set& other) +void unordered_multiset::clear() { - table_.swap(other.table_); + table_.clear(); } // observers @@ -1539,12 +1545,6 @@ unordered_multiset::erase(const_iterator first, const_iterator last) return table_.erase_range(first, last); } -template -void unordered_multiset::clear() -{ - table_.clear(); -} - template void unordered_multiset::swap(unordered_multiset& other) { From 85a834cf62940da0203eb53f1d54a1e822b57308 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 045/147] Comment on changes needed for C++17 support --- include/boost/unordered/unordered_map.hpp | 16 ++++++++++++++++ include/boost/unordered/unordered_set.hpp | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 4897f386..f12666c4 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -678,6 +678,10 @@ template class unordered_map void erase_return_void(const_iterator it) { erase(it); } void swap(unordered_map&); + // C++17 support: BOOST_NOEXCEPT_IF( + // value_allocator_traits::is_always_equal::value && + // is_nothrow_move_assignable_v && + // is_nothrow_move_assignable_v

) void clear(); template @@ -1180,6 +1184,10 @@ template class unordered_multimap void erase_return_void(const_iterator it) { erase(it); } void swap(unordered_multimap&); + // C++17 support: BOOST_NOEXCEPT_IF( + // value_allocator_traits::is_always_equal::value && + // is_nothrow_move_assignable_v && + // is_nothrow_move_assignable_v

) void clear(); template @@ -1487,6 +1495,10 @@ unordered_map::erase(const_iterator first, const_iterator last) template void unordered_map::swap(unordered_map& other) +// C++17 support: BOOST_NOEXCEPT_IF( +// value_allocator_traits::is_always_equal::value && +// is_nothrow_move_assignable_v && +// is_nothrow_move_assignable_v

) { table_.swap(other.table_); } @@ -1906,6 +1918,10 @@ unordered_multimap::erase( template void unordered_multimap::swap(unordered_multimap& other) +// C++17 support: BOOST_NOEXCEPT_IF( +// value_allocator_traits::is_always_equal::value && +// is_nothrow_move_assignable_v && +// is_nothrow_move_assignable_v

) { table_.swap(other.table_); } diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 2cf710f5..58731b43 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -417,6 +417,10 @@ template class unordered_set void erase_return_void(const_iterator it) { erase(it); } void swap(unordered_set&); + // C++17 support: BOOST_NOEXCEPT_IF( + // value_allocator_traits::is_always_equal::value && + // is_nothrow_move_assignable_v && + // is_nothrow_move_assignable_v

) void clear(); template @@ -888,6 +892,10 @@ template class unordered_multiset void erase_return_void(const_iterator it) { erase(it); } void swap(unordered_multiset&); + // C++17 support: BOOST_NOEXCEPT_IF( + // value_allocator_traits::is_always_equal::value && + // is_nothrow_move_assignable_v && + // is_nothrow_move_assignable_v

) void clear(); template @@ -1176,6 +1184,10 @@ typename unordered_set::iterator unordered_set::erase( template void unordered_set::swap(unordered_set& other) +// C++17 support: BOOST_NOEXCEPT_IF( +// value_allocator_traits::is_always_equal::value && +// is_nothrow_move_assignable_v && +// is_nothrow_move_assignable_v

) { table_.swap(other.table_); } @@ -1547,6 +1559,10 @@ unordered_multiset::erase(const_iterator first, const_iterator last) template void unordered_multiset::swap(unordered_multiset& other) +// C++17 support: BOOST_NOEXCEPT_IF( +// value_allocator_traits::is_always_equal::value && +// is_nothrow_move_assignable_v && +// is_nothrow_move_assignable_v

) { table_.swap(other.table_); } From 9cd673c71d82ae4e64e164527071a99548c0076a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 046/147] Specify clear as noexcept --- include/boost/unordered/unordered_map.hpp | 8 ++++---- include/boost/unordered/unordered_set.hpp | 8 ++++---- test/unordered/compile_tests.hpp | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index f12666c4..51d37e6b 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -682,7 +682,7 @@ template class unordered_map // value_allocator_traits::is_always_equal::value && // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) - void clear(); + void clear() BOOST_NOEXCEPT; template void merge(boost::unordered_map& source); @@ -1188,7 +1188,7 @@ template class unordered_multimap // value_allocator_traits::is_always_equal::value && // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) - void clear(); + void clear() BOOST_NOEXCEPT; template void merge(boost::unordered_multimap& source); @@ -1504,7 +1504,7 @@ void unordered_map::swap(unordered_map& other) } template -void unordered_map::clear() +void unordered_map::clear() BOOST_NOEXCEPT { table_.clear(); } @@ -1927,7 +1927,7 @@ void unordered_multimap::swap(unordered_multimap& other) } template -void unordered_multimap::clear() +void unordered_multimap::clear() BOOST_NOEXCEPT { table_.clear(); } diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 58731b43..6300d6d3 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -421,7 +421,7 @@ template class unordered_set // value_allocator_traits::is_always_equal::value && // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) - void clear(); + void clear() BOOST_NOEXCEPT; template void merge(boost::unordered_set& source); @@ -896,7 +896,7 @@ template class unordered_multiset // value_allocator_traits::is_always_equal::value && // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) - void clear(); + void clear() BOOST_NOEXCEPT; template void merge(boost::unordered_multiset& source); @@ -1193,13 +1193,13 @@ void unordered_set::swap(unordered_set& other) } template -void unordered_set::clear() +void unordered_set::clear() BOOST_NOEXCEPT { table_.clear(); } template -void unordered_multiset::clear() +void unordered_multiset::clear() BOOST_NOEXCEPT { table_.clear(); } diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 45ad2111..c676f2d5 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -554,6 +554,7 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq) const_iterator q1 = a.cbegin(), q2 = a.cend(); test::check_return_type::equals(a.erase(q1, q2)); + TEST_NOEXCEPT_EXPR(a.clear()); a.clear(); X const b; From fedf5336990f617ab86d46cff027c3a874323db4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 047/147] Move index functions into place --- include/boost/unordered/unordered_map.hpp | 50 +++++++++++------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 51d37e6b..7b2ff6fc 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -707,10 +707,6 @@ template class unordered_map hasher hash_function() const; key_equal key_eq() const; - mapped_type& operator[](const key_type&); - mapped_type& at(const key_type&); - mapped_type const& at(const key_type&) const; - // lookup iterator find(const key_type&); @@ -732,6 +728,10 @@ template class unordered_map std::pair equal_range( const key_type&) const; + mapped_type& operator[](const key_type&); + mapped_type& at(const key_type&); + mapped_type const& at(const key_type&) const; + // bucket interface size_type bucket_count() const BOOST_NOEXCEPT @@ -1563,27 +1563,6 @@ unordered_map::key_eq() const return table_.key_eq(); } -template -typename unordered_map::mapped_type& - unordered_map::operator[](const key_type& k) -{ - return table_.try_emplace_impl(k).first->second; -} - -template -typename unordered_map::mapped_type& -unordered_map::at(const key_type& k) -{ - return table_.at(k).second; -} - -template -typename unordered_map::mapped_type const& -unordered_map::at(const key_type& k) const -{ - return table_.at(k).second; -} - // lookup template @@ -1641,6 +1620,27 @@ unordered_map::equal_range(const key_type& k) const return table_.equal_range(k); } +template +typename unordered_map::mapped_type& + unordered_map::operator[](const key_type& k) +{ + return table_.try_emplace_impl(k).first->second; +} + +template +typename unordered_map::mapped_type& +unordered_map::at(const key_type& k) +{ + return table_.at(k).second; +} + +template +typename unordered_map::mapped_type const& +unordered_map::at(const key_type& k) const +{ + return table_.at(k).second; +} + template typename unordered_map::size_type unordered_map::bucket_size(size_type n) const From de5373413be4f2b7f005dfcbb0cee6f6d72d0d2b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 048/147] Missing rvalue overload of at --- include/boost/unordered/unordered_map.hpp | 8 ++++++++ test/unordered/compile_tests.hpp | 1 + 2 files changed, 9 insertions(+) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 7b2ff6fc..f40d03d4 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -729,6 +729,7 @@ template class unordered_map const key_type&) const; mapped_type& operator[](const key_type&); + mapped_type& operator[](BOOST_RV_REF(key_type)); mapped_type& at(const key_type&); mapped_type const& at(const key_type&) const; @@ -1627,6 +1628,13 @@ typename unordered_map::mapped_type& return table_.try_emplace_impl(k).first->second; } +template +typename unordered_map::mapped_type& + unordered_map::operator[](BOOST_RV_REF(key_type) k) +{ + return table_.try_emplace_impl(boost::move(k)).first->second; +} + template typename unordered_map::mapped_type& unordered_map::at(const key_type& k) diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index c676f2d5..12759c16 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -422,6 +422,7 @@ void unordered_map_functions(X&, Key const& k, T const& v) X a; test::check_return_type::equals_ref(a[k]); + test::check_return_type::equals_ref(a[rvalue(k)]); test::check_return_type::equals_ref(a.at(k)); test::check_return_type >::equals( a.try_emplace(k, v)); From f3b179d451c92bce053fc67f514dff2931db378b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 049/147] Remove pointless duplication of move constructor --- include/boost/unordered/unordered_map.hpp | 18 ++++-------------- include/boost/unordered/unordered_set.hpp | 18 ++++-------------- 2 files changed, 8 insertions(+), 28 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index f40d03d4..a991950c 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -93,18 +93,13 @@ template class unordered_map unordered_map(unordered_map const&); -#if defined(BOOST_UNORDERED_USE_MOVE) +#if defined(BOOST_UNORDERED_USE_MOVE) || \ + !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_map(BOOST_RV_REF(unordered_map) other) BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { } -#elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_map(unordered_map&& other) - BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) - : table_(other.table_, boost::unordered::detail::move_tag()) - { - } #endif explicit unordered_map(allocator_type const&); @@ -850,18 +845,13 @@ template class unordered_multimap unordered_multimap(unordered_multimap const&); -#if defined(BOOST_UNORDERED_USE_MOVE) +#if defined(BOOST_UNORDERED_USE_MOVE) || \ + !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_multimap(BOOST_RV_REF(unordered_multimap) other) BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { } -#elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_multimap(unordered_multimap&& other) - BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) - : table_(other.table_, boost::unordered::detail::move_tag()) - { - } #endif explicit unordered_multimap(allocator_type const&); diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 6300d6d3..747f00f5 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -91,18 +91,13 @@ template class unordered_set unordered_set(unordered_set const&); -#if defined(BOOST_UNORDERED_USE_MOVE) +#if defined(BOOST_UNORDERED_USE_MOVE) || \ + !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_set(BOOST_RV_REF(unordered_set) other) BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { } -#elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_set(unordered_set&& other) - BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) - : table_(other.table_, boost::unordered::detail::move_tag()) - { - } #endif explicit unordered_set(allocator_type const&); @@ -576,18 +571,13 @@ template class unordered_multiset unordered_multiset(unordered_multiset const&); -#if defined(BOOST_UNORDERED_USE_MOVE) +#if defined(BOOST_UNORDERED_USE_MOVE) || \ + !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) unordered_multiset(BOOST_RV_REF(unordered_multiset) other) BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { } -#elif !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - unordered_multiset(unordered_multiset&& other) - BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) - : table_(other.table_, boost::unordered::detail::move_tag()) - { - } #endif explicit unordered_multiset(allocator_type const&); From b067e6573149124069634cee02015eb1b89101a8 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 22:59:00 +0100 Subject: [PATCH 050/147] Clean table forward declarations --- include/boost/unordered/detail/implementation.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 3b4c3a47..c08adf29 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -168,17 +168,16 @@ namespace detail { template struct table; template struct bucket; struct ptr_bucket; + template struct table_unique; template struct table_equiv; template struct unique_node; template struct ptr_node; -template struct table_unique; +template struct node_algo; template struct grouped_node; template struct grouped_ptr_node; -template struct table_equiv; -template struct node_algo; template struct grouped_node_algo; static const float minimum_max_load_factor = 1e-3f; From 2add451d6372f970d72223d9cf8e1dd8c72e6af4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 23:11:14 +0100 Subject: [PATCH 051/147] Use boost 1.64.0 on travis --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 652af9b8..199da13c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,9 +55,9 @@ before_script: echo "using gcc : interopable : g++-4.8 -Werror --std=c++03 -fsanitize=address -DBOOST_UNORDERED_INTEROPERABLE_NODES=1 ;" >> ~/user-config.jam echo "using clang : interopable : clang++ -Werror --std=c++11 -fsanitize=address -DBOOST_UNORDERED_INTEROPERABLE_NODES=1 ;" >> ~/user-config.jam - cat ~/user-config.jam - - wget -O boost.tar.bz2 https://sourceforge.net/projects/boost/files/boost/1.63.0/boost_1_63_0.tar.bz2 + - wget -O boost.tar.bz2 https://dl.bintray.com/boostorg/release/1.64.0/source/boost_1_64_0.tar.bz2 - tar -xjf boost.tar.bz2 - - mv boost_1_63_0 boost + - mv boost_1_64_0 boost - rm -r boost/boost/unordered script: From 96f8f85eef537776251795208c0b6e1889318332 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 23:39:44 +0100 Subject: [PATCH 052/147] Use environment variable to set user-config.jam --- .travis.yml | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/.travis.yml b/.travis.yml index 199da13c..44392aa3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,42 +18,40 @@ addons: matrix: include: - compiler: gcc - env: BJAM_TOOLSET=gcc + env: | + label="gcc C++03"; + user_config="using gcc : : g++-4.8 -fsanitize=address -Werror --std=c++03 ;" - compiler: gcc - env: BJAM_TOOLSET=gcc-std11 - #- compiler: gcc - # env: BJAM_TOOLSET=gcc-m32 + env: | + label="gcc C++11"; + user_config="using gcc : : g++-4.8 -fsanitize=address -Werror --std=c++11 ;" - compiler: gcc - env: BJAM_TOOLSET=gcc-std11m32 - #- compiler: clang - # env: BJAM_TOOLSET=clang + env: | + label="gcc 32 bit C++11"; + user_config="using gcc : : g++-4.8 -m32 -fsanitize=address -Werror --std=c++11 ;" - compiler: clang - env: BJAM_TOOLSET=clang-std11 + env: | + label="clang C++11"; + user_config="using clang : : clang++ -fsanitize=address -Werror --std=c++11 ;" + # sanitized=address not available for 32-bit clang on travis. - compiler: clang - env: BJAM_TOOLSET=clang-m32 - #- compiler: clang - # env: BJAM_TOOLSET=clang-std11m32 + env: | + label="clang 32 bit"; + user_config="using clang : : clang++ -m32 -Werror --std=c++03 ;" - compiler: gcc - env: BJAM_TOOLSET=gcc-interopable + env: | + label="gcc C++03 interopable1"; + user_config="using gcc : : g++-4.8 -fsanitize=address -Werror --std=c++03 -DBOOST_UNORDERED_INTEROPERABLE_NODES=1 ;" - compiler: clang - env: BJAM_TOOLSET=clang-interopable + env: | + label="gcc C++11 interopable1"; + user_config="using clang : : clang++ -fsanitize=address -Werror --std=c++03 -DBOOST_UNORDERED_INTEROPERABLE_NODES=1 ;" before_script: - cd ${TRAVIS_BUILD_DIR} - touch Jamroot.jam - cd $HOME - - | - echo "using gcc : : g++-4.8 -Werror --std=c++03 -fsanitize=address ;" > ~/user-config.jam - echo "using gcc : std11 : g++-4.8 -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam - echo "using gcc : m32 : g++-4.8 -m32 -Werror -fsanitize=address ;" >> ~/user-config.jam - echo "using gcc : std11m32 : g++-4.8 -m32 -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam - echo "using clang : : clang++ -Werror --std=c++03 -fsanitize=address ;" >> ~/user-config.jam - echo "using clang : std11 : clang++ -Werror --std=c++11 -fsanitize=address ;" >> ~/user-config.jam - # sanitized=address not available for 32-bit clang on travis. - echo "using clang : m32 : clang++ -m32 -Werror --std=c++03 ;" >> ~/user-config.jam - echo "using clang : std11m32 : clang++ -m32 -Werror --std=c++11 ;" >> ~/user-config.jam - echo "using gcc : interopable : g++-4.8 -Werror --std=c++03 -fsanitize=address -DBOOST_UNORDERED_INTEROPERABLE_NODES=1 ;" >> ~/user-config.jam - echo "using clang : interopable : clang++ -Werror --std=c++11 -fsanitize=address -DBOOST_UNORDERED_INTEROPERABLE_NODES=1 ;" >> ~/user-config.jam + - echo $user_config > ~/user-config.jam - cat ~/user-config.jam - wget -O boost.tar.bz2 https://dl.bintray.com/boostorg/release/1.64.0/source/boost_1_64_0.tar.bz2 - tar -xjf boost.tar.bz2 @@ -62,5 +60,5 @@ before_script: script: - cd ${TRAVIS_BUILD_DIR}/test - - bjam ${BJAM_TOOLSET} include=${HOME}/boost include=${TRAVIS_BUILD_DIR}/include + - bjam include=${HOME}/boost include=${TRAVIS_BUILD_DIR}/include - xmllint --noout ${TRAVIS_BUILD_DIR}/doc/ref.xml From a119caaa1b58de244f7e8ac89e8057eff63ef3ac Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 20 Apr 2017 23:39:44 +0100 Subject: [PATCH 053/147] Stop travis build after first failure --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 44392aa3..eaa2200a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,5 +60,5 @@ before_script: script: - cd ${TRAVIS_BUILD_DIR}/test - - bjam include=${HOME}/boost include=${TRAVIS_BUILD_DIR}/include + - bjam -q include=${HOME}/boost include=${TRAVIS_BUILD_DIR}/include - xmllint --noout ${TRAVIS_BUILD_DIR}/doc/ref.xml From 1e491533fa11c81c5ae11b6e3f749b6b961bd7f3 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 21 Apr 2017 20:26:32 +0100 Subject: [PATCH 054/147] More consistent std::tuple configuration Was getting a weird test failure for Visual C++ 11, BOOST_NO_CXX11_HDR_TUPLE is defined, so the code doesn't support std::tuple, but BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT was also true, and so there are functions for constructing using std::piecewise_construct/std::tuple, which don't work. So, I'm assuming that if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT is true, then there must be a std::tuple. I guess it doesn't have full C++11 support, which is why BOOST_NO_CXX11_HDR_TUPLE is defined, but it appears to be good enough for us. If not, this will break things. --- .../boost/unordered/detail/implementation.hpp | 19 +++++++++++++------ test/unordered/unnecessary_copy_tests.cpp | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index c08adf29..480aef32 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -47,9 +47,6 @@ #include #include -#if !defined(BOOST_NO_CXX11_HDR_TUPLE) -#include -#endif #if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) #include @@ -127,6 +124,17 @@ // Other configuration macros // +#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT || \ + (!defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(__SUNPRO_CC)) +#define BOOST_UNORDERED_HAS_STD_TUPLE 1 +#else +#define BOOST_UNORDERED_HAS_STD_TUPLE 0 +#endif + +#if BOOST_UNORDERED_HAS_STD_TUPLE +#include +#endif + #if defined(BOOST_UNORDERED_SUPPRESS_DEPRECATED) #define BOOST_UNORDERED_DEPRECATED(msg) #endif @@ -1391,8 +1399,7 @@ template struct length BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) -#if !BOOST_UNORDERED_CXX11_CONSTRUCTION && !defined(__SUNPRO_CC) && \ - !defined(BOOST_NO_CXX11_HDR_TUPLE) +#if !BOOST_UNORDERED_CXX11_CONSTRUCTION && BOOST_UNORDERED_HAS_STD_TUPLE BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::) #endif @@ -3541,7 +3548,7 @@ template struct map_extractor BOOST_UNORDERED_KEY_FROM_TUPLE(boost::) -#if !defined(BOOST_NO_CXX11_HDR_TUPLE) +#if BOOST_UNORDERED_HAS_STD_TUPLE BOOST_UNORDERED_KEY_FROM_TUPLE(std::) #endif }; diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index 7d17dfcf..7aea3111 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -501,7 +501,7 @@ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_map_test) COPY_COUNT(0); MOVE_COUNT(0); -#if !defined(BOOST_NO_CXX11_HDR_TUPLE) || defined(BOOST_HAS_TR1_TUPLE) +#if BOOST_UNORDERED_HAS_STD_TUPLE reset(); x.emplace(boost::unordered::piecewise_construct, From 3117611a554f6cef37acc89201fefb035be52cc8 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 22 Apr 2017 18:27:49 +0100 Subject: [PATCH 055/147] New tuple implementation Adjusts to use less arguments on Visual C++ 11, which will hopefully fix it on that compiler. Also changed to be a little less preprocessor heavy. I'm not sure about the __SUNPRO_CC support, hopefully recent versions of that compiler will have better support, and can use the normal implementation. Will check that later. --- .../boost/unordered/detail/implementation.hpp | 151 ++++++++++-------- test/unordered/unnecessary_copy_tests.cpp | 2 +- 2 files changed, 85 insertions(+), 68 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 480aef32..f2980285 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +48,6 @@ #include #include - #if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) #include #endif @@ -124,14 +124,22 @@ // Other configuration macros // -#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT || \ - (!defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(__SUNPRO_CC)) -#define BOOST_UNORDERED_HAS_STD_TUPLE 1 +#if defined(BOOST_UNORDERED_TUPLE_ARGS) +#elif defined(__SUNPRO_CC) +#define BOOST_UNORDERED_TUPLE_ARGS 0 +#elif !defined(BOOST_NO_CXX11_HDR_TUPLE) +#define BOOST_UNORDERED_TUPLE_ARGS 10 +#elif BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT +#if defined(BOOST_MSVC) && defined(_VARIADIC_MAX) +#define BOOST_UNORDERED_TUPLE_ARGS _VARIADIC_MAX #else -#define BOOST_UNORDERED_HAS_STD_TUPLE 0 +#define BOOST_UNORDERED_TUPLE_ARGS 5 +#endif +#else +#define BOOST_UNORDERED_TUPLE_ARGS 0 #endif -#if BOOST_UNORDERED_HAS_STD_TUPLE +#if BOOST_UNORDERED_TUPLE_ARGS #include #endif @@ -1317,97 +1325,103 @@ inline void construct_value(T* address, BOOST_FWD_REF(A0) a0) // // Used to emulate piecewise construction. -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if !defined(__SUNPRO_CC) -#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ - template \ - void construct_from_tuple(Alloc&, T* ptr, namespace_ tuple<>) \ - { \ - new ((void*)ptr) T(); \ - } \ - \ - BOOST_PP_REPEAT_FROM_TO( \ - 1, n, BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) - -#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ +#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(z, n, namespace_) \ template \ void construct_from_tuple(Alloc&, T* ptr, \ - namespace_ tuple const& x) \ + namespace_::tuple const& x) \ { \ new ((void*)ptr) T( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_)); \ } -#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_ get(x) +#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_::get(x) -#elif !defined(__SUNPRO_CC) +// construct_from_tuple for boost::tuple -#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ - template \ - void construct_from_tuple(Alloc&, T* ptr, namespace_ tuple<>) \ - { \ - new ((void*)ptr) T(); \ - } \ - \ - BOOST_PP_REPEAT_FROM_TO( \ - 1, n, BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) +template +void construct_from_tuple(Alloc&, T* ptr, boost::tuple<>) +{ + new ((void*)ptr) T(); +} -#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ - template \ - void construct_from_tuple(Alloc&, T* ptr, \ - namespace_ tuple const& x) \ - { \ - new ((void*)ptr) T( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_)); \ - } +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 1, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 2, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 3, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 4, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 5, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 6, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 7, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 8, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 9, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 10, boost) -#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_ get(x) +// construct_from_tuple for std::tuple -#else +#if !BOOST_UNORDERED_CXX11_CONSTRUCTION && BOOST_UNORDERED_TUPLE_ARGS + +template +void construct_from_tuple(Alloc&, T* ptr, std::tuple<>) +{ + new ((void*)ptr) T(); +} + +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 1, std) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 2, std) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 3, std) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 4, std) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 5, std) + +#if BOOST_UNORDERED_TUPLE_ARGS >= 6 +BOOST_PP_REPEAT_FROM_TO(6, BOOST_PP_INC(BOOST_UNORDERED_TUPLE_ARGS), + BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE, std) +#endif + +#endif + +#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE +#undef BOOST_UNORDERED_GET_TUPLE_ARG + +#else // __SUNPRO_CC template struct length { }; -#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ - template \ - void construct_from_tuple_impl(boost::unordered::detail::func::length<0>, \ - Alloc&, T* ptr, namespace_ tuple<>) \ - { \ - new ((void*)ptr) T(); \ - } \ - \ - BOOST_PP_REPEAT_FROM_TO( \ - 1, n, BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) - -#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ +#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(z, n, namespace_) \ template \ void construct_from_tuple_impl(boost::unordered::detail::func::length, \ Alloc&, T* ptr, \ - namespace_ tuple const& x) \ + namespace_::tuple const& x) \ { \ new ((void*)ptr) T( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_)); \ } -#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_ get(x) +#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_::get(x) -#endif +// construct_from_tuple for boost::tuple -BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) +template +void construct_from_tuple_impl( + boost::unordered::detail::func::length<0>, Alloc&, T* ptr, boost::tuple<>) +{ + new ((void*)ptr) T(); +} -#if !BOOST_UNORDERED_CXX11_CONSTRUCTION && BOOST_UNORDERED_HAS_STD_TUPLE -BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::) -#endif - -#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE -#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL -#undef BOOST_UNORDERED_GET_TUPLE_ARG - -#if defined(__SUNPRO_CC) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 1, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 2, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 3, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 4, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 5, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 6, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 7, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 8, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 9, boost) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 10, boost) template void construct_from_tuple(Alloc& alloc, T* ptr, Tuple const& x) @@ -1417,6 +1431,9 @@ void construct_from_tuple(Alloc& alloc, T* ptr, Tuple const& x) alloc, ptr, x); } +#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE +#undef BOOST_UNORDERED_GET_TUPLE_ARG + #endif //////////////////////////////////////////////////////////////////////////// @@ -3548,7 +3565,7 @@ template struct map_extractor BOOST_UNORDERED_KEY_FROM_TUPLE(boost::) -#if BOOST_UNORDERED_HAS_STD_TUPLE +#if BOOST_UNORDERED_TUPLE_ARGS BOOST_UNORDERED_KEY_FROM_TUPLE(std::) #endif }; diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index 7aea3111..9618778b 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -501,7 +501,7 @@ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_map_test) COPY_COUNT(0); MOVE_COUNT(0); -#if BOOST_UNORDERED_HAS_STD_TUPLE +#if BOOST_UNORDERED_TUPLE_ARGS reset(); x.emplace(boost::unordered::piecewise_construct, From cfe4c26f9907bd9e84aac3cfb1e989c76f5d5a45 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 09:31:18 +0100 Subject: [PATCH 056/147] Explicitly write out boost::tuple template arguments GCC 4.6 doesn't support using variadic arguments for a fixed length template. There's a config macro for this, but might as well use the same code everywhere. --- include/boost/unordered/detail/implementation.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index f2980285..831f0329 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1470,8 +1470,10 @@ inline void construct_from_args( template struct detect_boost_tuple { - template - static choice1::type test(choice1, boost::tuple const&); + template + static choice1::type test( + choice1, boost::tuple const&); static choice2::type test(choice2, ...); From 42b6b13943668df16e5f2a8866e66975a909481c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 09:44:56 +0100 Subject: [PATCH 057/147] Use the preprocessor to increment emplace limit So that there's no need to add one. --- include/boost/unordered/detail/implementation.hpp | 10 +++++----- include/boost/unordered/unordered_map.hpp | 6 +++--- include/boost/unordered/unordered_set.hpp | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 831f0329..89ac1fbf 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -58,12 +58,12 @@ // Unless documented elsewhere these configuration macros should be considered // an implementation detail, I'll try not to break them, but you never know. -// BOOST_UNORDERED_EMPLACE_LIMIT = The maximum number of parameters + 1 in +// BOOST_UNORDERED_EMPLACE_LIMIT = The maximum number of parameters in // emplace (not including things like hints). Don't set it to a lower value, as // that might break something. #if !defined BOOST_UNORDERED_EMPLACE_LIMIT -#define BOOST_UNORDERED_EMPLACE_LIMIT 11 +#define BOOST_UNORDERED_EMPLACE_LIMIT 10 #endif // BOOST_UNORDERED_INTEROPERABLE_NODES - Use the same node type for @@ -619,7 +619,7 @@ inline emplace_args3 create_emplace_args( } BOOST_PP_REPEAT_FROM_TO( - 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS, _) + 4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_EARGS, _) #undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS #undef BOOST_UNORDERED_EARGS_MEMBER @@ -1590,8 +1590,8 @@ inline void construct_from_args( num_params, BOOST_UNORDERED_CALL_FORWARD, args.a)); \ } -BOOST_PP_REPEAT_FROM_TO( - 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_CONSTRUCT_IMPL, _) +BOOST_PP_REPEAT_FROM_TO(4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), + BOOST_UNORDERED_CONSTRUCT_IMPL, _) #undef BOOST_UNORDERED_CONSTRUCT_IMPL diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index a991950c..32d8f0ae 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -339,7 +339,7 @@ template class unordered_map } BOOST_PP_REPEAT_FROM_TO( - 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) + 4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_EMPLACE, _) #undef BOOST_UNORDERED_EMPLACE @@ -626,7 +626,7 @@ template class unordered_map } BOOST_PP_REPEAT_FROM_TO( - 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_TRY_EMPLACE, _) + 4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_TRY_EMPLACE, _) #undef BOOST_UNORDERED_TRY_EMPLACE @@ -1086,7 +1086,7 @@ template class unordered_multimap } BOOST_PP_REPEAT_FROM_TO( - 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) + 4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_EMPLACE, _) #undef BOOST_UNORDERED_EMPLACE diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 747f00f5..ec7cfd1d 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -336,8 +336,8 @@ template class unordered_set BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } - BOOST_PP_REPEAT_FROM_TO( - 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) + BOOST_PP_REPEAT_FROM_TO(4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), + BOOST_UNORDERED_EMPLACE, _) #undef BOOST_UNORDERED_EMPLACE @@ -811,8 +811,8 @@ template class unordered_multiset BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } - BOOST_PP_REPEAT_FROM_TO( - 4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) + BOOST_PP_REPEAT_FROM_TO(4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), + BOOST_UNORDERED_EMPLACE, _) #undef BOOST_UNORDERED_EMPLACE From f6f5ecdc008b10224a00e864ea527e1b2aaa11d0 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 10:09:18 +0100 Subject: [PATCH 058/147] Expand calls to emplace implementation Also manually call the emplace macro up to 9 arguments, nicer error messages for little effort. Does it matter that there's no longer a nice backend for `please_ignore_this_overload`? I don't think so, I was worried that it would be confusing if triggered, but I'm not really aware of that ever happening. --- .../boost/unordered/detail/implementation.hpp | 125 ------------- include/boost/unordered/unordered_map.hpp | 168 ++++++++++++------ include/boost/unordered/unordered_set.hpp | 160 +++++++++++------ 3 files changed, 224 insertions(+), 229 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 89ac1fbf..086bc613 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3890,81 +3890,6 @@ struct table_unique : boost::unordered::detail::table return this->add_node(b.release(), key_hash); } -#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) -#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - emplace_return emplace(boost::unordered::detail::emplace_args1< - boost::unordered::detail::please_ignore_this_overload> const&) - { - BOOST_ASSERT(false); - return emplace_return(iterator(), false); - } - - iterator emplace_hint( - c_iterator, - boost::unordered::detail::emplace_args1< - boost::unordered::detail::please_ignore_this_overload> const&) - { - BOOST_ASSERT(false); - return iterator(); - } -#else - emplace_return emplace( - boost::unordered::detail::please_ignore_this_overload const&) - { - BOOST_ASSERT(false); - return emplace_return(iterator(), false); - } - - iterator emplace_hint(c_iterator, - boost::unordered::detail::please_ignore_this_overload const&) - { - BOOST_ASSERT(false); - return iterator(); - } -#endif -#endif - - template - emplace_return emplace(BOOST_UNORDERED_EMPLACE_ARGS) - { -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - return emplace_impl(extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD), - BOOST_UNORDERED_EMPLACE_FORWARD); -#else - return emplace_impl(extractor::extract(args.a0, args.a1), - BOOST_UNORDERED_EMPLACE_FORWARD); -#endif - } - - template - iterator emplace_hint(c_iterator hint, BOOST_UNORDERED_EMPLACE_ARGS) - { -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - return emplace_hint_impl(hint, - extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD), - BOOST_UNORDERED_EMPLACE_FORWARD); -#else - return emplace_hint_impl(hint, extractor::extract(args.a0, args.a1), - BOOST_UNORDERED_EMPLACE_FORWARD); -#endif - } - -#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template - emplace_return emplace( - boost::unordered::detail::emplace_args1 const& args) - { - return emplace_impl(extractor::extract(args.a0), args); - } - - template - iterator emplace_hint(c_iterator hint, - boost::unordered::detail::emplace_args1 const& args) - { - return emplace_hint_impl(hint, extractor::extract(args.a0), args); - } -#endif - template iterator emplace_hint_impl( c_iterator hint, const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS) @@ -4786,56 +4711,6 @@ struct table_equiv : boost::unordered::detail::table return n; } -#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) -#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - iterator emplace(boost::unordered::detail::emplace_args1< - boost::unordered::detail::please_ignore_this_overload> const&) - { - BOOST_ASSERT(false); - return iterator(); - } - - iterator emplace_hint( - c_iterator, - boost::unordered::detail::emplace_args1< - boost::unordered::detail::please_ignore_this_overload> const&) - { - BOOST_ASSERT(false); - return iterator(); - } -#else - iterator emplace( - boost::unordered::detail::please_ignore_this_overload const&) - { - BOOST_ASSERT(false); - return iterator(); - } - - iterator emplace_hint(c_iterator, - boost::unordered::detail::please_ignore_this_overload const&) - { - BOOST_ASSERT(false); - return iterator(); - } -#endif -#endif - - template - iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS) - { - return iterator(emplace_impl( - boost::unordered::detail::func::construct_node_from_args( - this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD))); - } - - template - iterator emplace_hint(c_iterator hint, BOOST_UNORDERED_EMPLACE_ARGS) - { - return iterator(emplace_hint_impl( - hint, boost::unordered::detail::func::construct_node_from_args( - this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD))); - } - iterator emplace_impl(node_pointer n) { node_tmp a(n, this->node_alloc()); diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 32d8f0ae..34122ff6 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -220,7 +220,9 @@ template class unordered_map template std::pair emplace(BOOST_FWD_REF(Args)... args) { - return table_.emplace(boost::forward(args)...); + return table_.emplace_impl( + table::extractor::extract(boost::forward(args)...), + boost::forward(args)...); } #else @@ -244,25 +246,33 @@ template class unordered_map template std::pair emplace(BOOST_FWD_REF(A0) a0) { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0))); + return table_.emplace_impl( + table::extractor::extract(boost::forward(a0)), + boost::unordered::detail::create_emplace_args( + boost::forward(a0))); } template std::pair emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); + return table_.emplace_impl( + table::extractor::extract( + boost::forward(a0), boost::forward(a1)), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); } template std::pair emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); + return table_.emplace_impl( + table::extractor::extract( + boost::forward(a0), boost::forward(a1)), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))); } #endif @@ -272,7 +282,9 @@ template class unordered_map template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return table_.emplace_hint(hint, boost::forward(args)...); + return table_.emplace_hint_impl(hint, + table::extractor::extract(boost::forward(args)...), + boost::forward(args)...); } #else @@ -292,28 +304,33 @@ template class unordered_map template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return table_.emplace_hint( - hint, boost::unordered::detail::create_emplace_args( - boost::forward(a0))); + return table_.emplace_hint_impl(hint, + table::extractor::extract(boost::forward(a0)), + boost::unordered::detail::create_emplace_args( + boost::forward(a0))); } template iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace_hint( - hint, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); + return table_.emplace_hint_impl( + hint, table::extractor::extract( + boost::forward(a0), boost::forward(a1)), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); } template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace_hint( - hint, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); + return table_.emplace_hint_impl( + hint, table::extractor::extract( + boost::forward(a0), boost::forward(a1)), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))); } #endif @@ -325,21 +342,32 @@ template class unordered_map std::pair emplace( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace(boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + return table_.emplace_impl( \ + table::extractor::extract( \ + boost::forward(a0), boost::forward(a1)), \ + boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } \ \ template \ iterator emplace_hint(const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace_hint( \ - hint, boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + return table_.emplace_hint_impl( \ + hint, table::extractor::extract( \ + boost::forward(a0), boost::forward(a1)), \ + boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } - BOOST_PP_REPEAT_FROM_TO( - 4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_EMPLACE, _) + BOOST_UNORDERED_EMPLACE(1, 4, _) + BOOST_UNORDERED_EMPLACE(1, 5, _) + BOOST_UNORDERED_EMPLACE(1, 6, _) + BOOST_UNORDERED_EMPLACE(1, 7, _) + BOOST_UNORDERED_EMPLACE(1, 8, _) + BOOST_UNORDERED_EMPLACE(1, 9, _) + BOOST_PP_REPEAT_FROM_TO(10, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), + BOOST_UNORDERED_EMPLACE, _) #undef BOOST_UNORDERED_EMPLACE @@ -625,8 +653,8 @@ template class unordered_map n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } - BOOST_PP_REPEAT_FROM_TO( - 4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_TRY_EMPLACE, _) + BOOST_PP_REPEAT_FROM_TO(4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), + BOOST_UNORDERED_TRY_EMPLACE, _) #undef BOOST_UNORDERED_TRY_EMPLACE @@ -972,7 +1000,9 @@ template class unordered_multimap template iterator emplace(BOOST_FWD_REF(Args)... args) { - return table_.emplace(boost::forward(args)...); + return iterator(table_.emplace_impl( + boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), boost::forward(args)...))); } #else @@ -994,24 +1024,33 @@ template class unordered_multimap template iterator emplace(BOOST_FWD_REF(A0) a0) { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0))); + return iterator(table_.emplace_impl( + boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), + boost::unordered::detail::create_emplace_args( + boost::forward(a0))))); } template iterator emplace(BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); + return iterator(table_.emplace_impl( + boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))))); } template iterator emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); + return iterator(table_.emplace_impl( + boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))))); } #endif @@ -1021,7 +1060,9 @@ template class unordered_multimap template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return table_.emplace_hint(hint, boost::forward(args)...); + return iterator(table_.emplace_hint_impl( + hint, boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), boost::forward(args)...))); } #else @@ -1041,27 +1082,34 @@ template class unordered_multimap template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return table_.emplace_hint( - hint, boost::unordered::detail::create_emplace_args( - boost::forward(a0))); + return iterator(table_.emplace_hint_impl( + hint, boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), + boost::unordered::detail::create_emplace_args( + boost::forward(a0))))); } + template iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace_hint( - hint, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); + return iterator(table_.emplace_hint_impl( + hint, boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))))); } template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace_hint( - hint, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); + return iterator(table_.emplace_hint_impl( + hint, boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))))); } #endif @@ -1072,21 +1120,33 @@ template class unordered_multimap template \ iterator emplace(BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace(boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + return iterator(table_.emplace_impl( \ + boost::unordered::detail::func::construct_node_from_args( \ + table_.node_alloc(), \ + boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))))); \ } \ \ template \ iterator emplace_hint(const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace_hint( \ - hint, boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + return iterator(table_.emplace_hint_impl( \ + hint, \ + boost::unordered::detail::func::construct_node_from_args( \ + table_.node_alloc(), \ + boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))))); \ } - BOOST_PP_REPEAT_FROM_TO( - 4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_EMPLACE, _) + BOOST_UNORDERED_EMPLACE(1, 4, _) + BOOST_UNORDERED_EMPLACE(1, 5, _) + BOOST_UNORDERED_EMPLACE(1, 6, _) + BOOST_UNORDERED_EMPLACE(1, 7, _) + BOOST_UNORDERED_EMPLACE(1, 8, _) + BOOST_UNORDERED_EMPLACE(1, 9, _) + BOOST_PP_REPEAT_FROM_TO(10, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), + BOOST_UNORDERED_EMPLACE, _) #undef BOOST_UNORDERED_EMPLACE diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index ec7cfd1d..336a9472 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -218,7 +218,9 @@ template class unordered_set template std::pair emplace(BOOST_FWD_REF(Args)... args) { - return table_.emplace(boost::forward(args)...); + return table_.emplace_impl( + table::extractor::extract(boost::forward(args)...), + boost::forward(args)...); } #else @@ -242,25 +244,33 @@ template class unordered_set template std::pair emplace(BOOST_FWD_REF(A0) a0) { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0))); + return table_.emplace_impl( + table::extractor::extract(boost::forward(a0)), + boost::unordered::detail::create_emplace_args( + boost::forward(a0))); } template std::pair emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); + return table_.emplace_impl( + table::extractor::extract( + boost::forward(a0), boost::forward(a1)), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); } template std::pair emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); + return table_.emplace_impl( + table::extractor::extract( + boost::forward(a0), boost::forward(a1)), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))); } #endif @@ -270,7 +280,9 @@ template class unordered_set template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return table_.emplace_hint(hint, boost::forward(args)...); + return table_.emplace_hint_impl(hint, + table::extractor::extract(boost::forward(args)...), + boost::forward(args)...); } #else @@ -290,28 +302,33 @@ template class unordered_set template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return table_.emplace_hint( - hint, boost::unordered::detail::create_emplace_args( - boost::forward(a0))); + return table_.emplace_hint_impl(hint, + table::extractor::extract(boost::forward(a0)), + boost::unordered::detail::create_emplace_args( + boost::forward(a0))); } template iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace_hint( - hint, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); + return table_.emplace_hint_impl( + hint, table::extractor::extract( + boost::forward(a0), boost::forward(a1)), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); } template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace_hint( - hint, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); + return table_.emplace_hint_impl( + hint, table::extractor::extract( + boost::forward(a0), boost::forward(a1)), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))); } #endif @@ -323,20 +340,31 @@ template class unordered_set std::pair emplace( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace(boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + return table_.emplace_impl( \ + table::extractor::extract( \ + boost::forward(a0), boost::forward(a1)), \ + boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } \ \ template \ iterator emplace_hint(const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace_hint( \ - hint, boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + return table_.emplace_hint_impl( \ + hint, table::extractor::extract( \ + boost::forward(a0), boost::forward(a1)), \ + boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } - BOOST_PP_REPEAT_FROM_TO(4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), + BOOST_UNORDERED_EMPLACE(1, 4, _) + BOOST_UNORDERED_EMPLACE(1, 5, _) + BOOST_UNORDERED_EMPLACE(1, 6, _) + BOOST_UNORDERED_EMPLACE(1, 7, _) + BOOST_UNORDERED_EMPLACE(1, 8, _) + BOOST_UNORDERED_EMPLACE(1, 9, _) + BOOST_PP_REPEAT_FROM_TO(10, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_EMPLACE, _) #undef BOOST_UNORDERED_EMPLACE @@ -695,9 +723,12 @@ template class unordered_multiset // emplace #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template iterator emplace(BOOST_FWD_REF(Args)... args) { - return table_.emplace(boost::forward(args)...); + return iterator(table_.emplace_impl( + boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), boost::forward(args)...))); } #else @@ -719,24 +750,33 @@ template class unordered_multiset template iterator emplace(BOOST_FWD_REF(A0) a0) { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0))); + return iterator(table_.emplace_impl( + boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), + boost::unordered::detail::create_emplace_args( + boost::forward(a0))))); } template iterator emplace(BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); + return iterator(table_.emplace_impl( + boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))))); } template iterator emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace(boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); + return iterator(table_.emplace_impl( + boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))))); } #endif @@ -746,7 +786,9 @@ template class unordered_multiset template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return table_.emplace_hint(hint, boost::forward(args)...); + return iterator(table_.emplace_hint_impl( + hint, boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), boost::forward(args)...))); } #else @@ -766,28 +808,34 @@ template class unordered_multiset template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return table_.emplace_hint( - hint, boost::unordered::detail::create_emplace_args( - boost::forward(a0))); + return iterator(table_.emplace_hint_impl( + hint, boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), + boost::unordered::detail::create_emplace_args( + boost::forward(a0))))); } template iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace_hint( - hint, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); + return iterator(table_.emplace_hint_impl( + hint, boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))))); } template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace_hint( - hint, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); + return iterator(table_.emplace_hint_impl( + hint, boost::unordered::detail::func::construct_node_from_args( + table_.node_alloc(), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))))); } #endif @@ -798,20 +846,32 @@ template class unordered_multiset template \ iterator emplace(BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace(boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + return iterator(table_.emplace_impl( \ + boost::unordered::detail::func::construct_node_from_args( \ + table_.node_alloc(), \ + boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))))); \ } \ \ template \ iterator emplace_hint(const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace_hint( \ - hint, boost::unordered::detail::create_emplace_args( \ - BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ + return iterator(table_.emplace_hint_impl( \ + hint, \ + boost::unordered::detail::func::construct_node_from_args( \ + table_.node_alloc(), \ + boost::unordered::detail::create_emplace_args( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))))); \ } - BOOST_PP_REPEAT_FROM_TO(4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), + BOOST_UNORDERED_EMPLACE(1, 4, _) + BOOST_UNORDERED_EMPLACE(1, 5, _) + BOOST_UNORDERED_EMPLACE(1, 6, _) + BOOST_UNORDERED_EMPLACE(1, 7, _) + BOOST_UNORDERED_EMPLACE(1, 8, _) + BOOST_UNORDERED_EMPLACE(1, 9, _) + BOOST_PP_REPEAT_FROM_TO(10, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_EMPLACE, _) #undef BOOST_UNORDERED_EMPLACE From 814926ef31e5a1f21dfc2a84a31d0b20488eb6f6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 10:09:18 +0100 Subject: [PATCH 059/147] Expand calls to clear implementation --- .../boost/unordered/detail/implementation.hpp | 11 -------- include/boost/unordered/unordered_map.hpp | 16 +++++++++--- include/boost/unordered/unordered_set.hpp | 26 ++++++++++++------- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 086bc613..35d03f4b 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3078,17 +3078,6 @@ struct table : boost::unordered::detail::functions class unordered_map typedef boost::unordered::detail::map types; typedef typename types::value_allocator_traits value_allocator_traits; typedef typename types::table table; + typedef typename table::link_pointer link_pointer; public: typedef typename value_allocator_traits::pointer pointer; @@ -836,6 +837,7 @@ template class unordered_multimap typedef boost::unordered::detail::multimap types; typedef typename types::value_allocator_traits value_allocator_traits; typedef typename types::table table; + typedef typename table::link_pointer link_pointer; public: typedef typename value_allocator_traits::pointer pointer; @@ -1483,7 +1485,7 @@ template unordered_map& unordered_map::operator=( std::initializer_list list) { - table_.clear(); + this->clear(); table_.insert_range(list.begin(), list.end()); return *this; } @@ -1557,7 +1559,10 @@ void unordered_map::swap(unordered_map& other) template void unordered_map::clear() BOOST_NOEXCEPT { - table_.clear(); + if (table_.size_) { + table_.clear_buckets(); + table_.delete_nodes(table_.get_previous_start(), link_pointer()); + } } template @@ -1912,7 +1917,7 @@ template unordered_multimap& unordered_multimap::operator=( std::initializer_list list) { - table_.clear(); + this->clear(); table_.insert_range(list.begin(), list.end()); return *this; } @@ -1987,7 +1992,10 @@ void unordered_multimap::swap(unordered_multimap& other) template void unordered_multimap::clear() BOOST_NOEXCEPT { - table_.clear(); + if (table_.size_) { + table_.clear_buckets(); + table_.delete_nodes(table_.get_previous_start(), link_pointer()); + } } // observers diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 336a9472..75fde4fa 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -53,6 +53,7 @@ template class unordered_set typedef boost::unordered::detail::set types; typedef typename types::value_allocator_traits value_allocator_traits; typedef typename types::table table; + typedef typename table::link_pointer link_pointer; public: typedef typename value_allocator_traits::pointer pointer; @@ -562,6 +563,7 @@ template class unordered_multiset typedef boost::unordered::detail::multiset types; typedef typename types::value_allocator_traits value_allocator_traits; typedef typename types::table table; + typedef typename table::link_pointer link_pointer; public: typedef typename value_allocator_traits::pointer pointer; @@ -1179,7 +1181,7 @@ template unordered_set& unordered_set::operator=( std::initializer_list list) { - table_.clear(); + this->clear(); table_.insert_range(list.begin(), list.end()); return *this; } @@ -1245,13 +1247,10 @@ void unordered_set::swap(unordered_set& other) template void unordered_set::clear() BOOST_NOEXCEPT { - table_.clear(); -} - -template -void unordered_multiset::clear() BOOST_NOEXCEPT -{ - table_.clear(); + if (table_.size_) { + table_.clear_buckets(); + table_.delete_nodes(table_.get_previous_start(), link_pointer()); + } } // observers @@ -1553,7 +1552,7 @@ template unordered_multiset& unordered_multiset::operator=( std::initializer_list list) { - table_.clear(); + this->clear(); table_.insert_range(list.begin(), list.end()); return *this; } @@ -1617,6 +1616,15 @@ void unordered_multiset::swap(unordered_multiset& other) table_.swap(other.table_); } +template +void unordered_multiset::clear() BOOST_NOEXCEPT +{ + if (table_.size_) { + table_.clear_buckets(); + table_.delete_nodes(table_.get_previous_start(), link_pointer()); + } +} + // observers template From a41a0f3a068723fb3baf4ef62edbdb43d1a9b1af Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 10:09:18 +0100 Subject: [PATCH 060/147] Expand calls to load_factor implementation --- include/boost/unordered/detail/implementation.hpp | 6 ------ include/boost/unordered/unordered_map.hpp | 8 ++++++-- include/boost/unordered/unordered_set.hpp | 8 ++++++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 35d03f4b..deb3a480 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -2758,12 +2758,6 @@ struct table : boost::unordered::detail::functions(size_) / static_cast(bucket_count_); - } - std::size_t bucket_size(std::size_t index) const { node_pointer n = begin(index); diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index f6eeda96..dc8600ba 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1716,7 +1716,9 @@ unordered_map::bucket_size(size_type n) const template float unordered_map::load_factor() const BOOST_NOEXCEPT { - return table_.load_factor(); + BOOST_ASSERT(table_.bucket_count_ != 0); + return static_cast(table_.size_) / + static_cast(table_.bucket_count_); } template @@ -2129,7 +2131,9 @@ unordered_multimap::bucket_size(size_type n) const template float unordered_multimap::load_factor() const BOOST_NOEXCEPT { - return table_.load_factor(); + BOOST_ASSERT(table_.bucket_count_ != 0); + return static_cast(table_.size_) / + static_cast(table_.bucket_count_); } template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 75fde4fa..99d1fa2f 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1352,7 +1352,9 @@ unordered_set::bucket_size(size_type n) const template float unordered_set::load_factor() const BOOST_NOEXCEPT { - return table_.load_factor(); + BOOST_ASSERT(table_.bucket_count_ != 0); + return static_cast(table_.size_) / + static_cast(table_.bucket_count_); } template @@ -1732,7 +1734,9 @@ unordered_multiset::bucket_size(size_type n) const template float unordered_multiset::load_factor() const BOOST_NOEXCEPT { - return table_.load_factor(); + BOOST_ASSERT(table_.bucket_count_ != 0); + return static_cast(table_.size_) / + static_cast(table_.bucket_count_); } template From 435b7450d4c4fcf3118a164053ddda57d30c72de Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 10:09:18 +0100 Subject: [PATCH 061/147] Expand calls to max_size implementation --- .../boost/unordered/detail/implementation.hpp | 11 ----------- include/boost/unordered/unordered_map.hpp | 16 ++++++++++++++-- include/boost/unordered/unordered_set.hpp | 16 ++++++++++++++-- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index deb3a480..f680283c 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -2776,17 +2776,6 @@ struct table : boost::unordered::detail::functions(mlf_) * - static_cast(max_bucket_count()))) - - 1; - } - void recalculate_max_load() { using namespace std; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index dc8600ba..b0e7055d 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1497,7 +1497,13 @@ unordered_map& unordered_map::operator=( template std::size_t unordered_map::max_size() const BOOST_NOEXCEPT { - return table_.max_size(); + using namespace std; + + // size <= mlf_ * count + return boost::unordered::detail::double_to_size( + ceil(static_cast(table_.mlf_) * + static_cast(table_.max_bucket_count()))) - + 1; } // modifiers @@ -1931,7 +1937,13 @@ unordered_multimap& unordered_multimap::operator=( template std::size_t unordered_multimap::max_size() const BOOST_NOEXCEPT { - return table_.max_size(); + using namespace std; + + // size <= mlf_ * count + return boost::unordered::detail::double_to_size( + ceil(static_cast(table_.mlf_) * + static_cast(table_.max_bucket_count()))) - + 1; } // modifiers diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 99d1fa2f..86f553c4 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1193,7 +1193,13 @@ unordered_set& unordered_set::operator=( template std::size_t unordered_set::max_size() const BOOST_NOEXCEPT { - return table_.max_size(); + using namespace std; + + // size < mlf_ * count + return boost::unordered::detail::double_to_size( + ceil(static_cast(table_.mlf_) * + static_cast(table_.max_bucket_count()))) - + 1; } // modifiers @@ -1566,7 +1572,13 @@ unordered_multiset& unordered_multiset::operator=( template std::size_t unordered_multiset::max_size() const BOOST_NOEXCEPT { - return table_.max_size(); + using namespace std; + + // size < mlf_ * count + return boost::unordered::detail::double_to_size( + ceil(static_cast(table_.mlf_) * + static_cast(table_.max_bucket_count()))) - + 1; } // modifiers From 19a45e028af268d51bae2ab4150dce199733c9e1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 10:09:18 +0100 Subject: [PATCH 062/147] Expand calls to generic_find_node --- include/boost/unordered/detail/implementation.hpp | 7 ------- include/boost/unordered/unordered_map.hpp | 12 ++++++++---- include/boost/unordered/unordered_set.hpp | 6 ++++-- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index f680283c..b7f18498 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3230,13 +3230,6 @@ struct table : boost::unordered::detail::functions - node_pointer generic_find_node( - Key const& k, Hash const& hf, Pred const& eq) const - { - return this->find_node_impl(policy::apply_hash(hf, k), k, eq); - } - node_pointer find_node(std::size_t key_hash, const_key_type& k) const { return this->find_node_impl(key_hash, k, this->key_eq()); diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index b0e7055d..d5c45f3e 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1647,7 +1647,8 @@ typename unordered_map::iterator unordered_map::find(CompatibleKey const& k, CompatibleHash const& hash, CompatiblePredicate const& eq) { - return iterator(table_.generic_find_node(k, hash, eq)); + return iterator( + table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq)); } template @@ -1656,7 +1657,8 @@ typename unordered_map::const_iterator unordered_map::find(CompatibleKey const& k, CompatibleHash const& hash, CompatiblePredicate const& eq) const { - return const_iterator(table_.generic_find_node(k, hash, eq)); + return const_iterator( + table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq)); } template @@ -2096,7 +2098,8 @@ typename unordered_multimap::iterator unordered_multimap::find(CompatibleKey const& k, CompatibleHash const& hash, CompatiblePredicate const& eq) { - return iterator(table_.generic_find_node(k, hash, eq)); + return iterator( + table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq)); } template @@ -2105,7 +2108,8 @@ typename unordered_multimap::const_iterator unordered_multimap::find(CompatibleKey const& k, CompatibleHash const& hash, CompatiblePredicate const& eq) const { - return const_iterator(table_.generic_find_node(k, hash, eq)); + return const_iterator( + table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq)); } template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 86f553c4..cda04175 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1328,7 +1328,8 @@ typename unordered_set::const_iterator unordered_set::find(CompatibleKey const& k, CompatibleHash const& hash, CompatiblePredicate const& eq) const { - return const_iterator(table_.generic_find_node(k, hash, eq)); + return const_iterator( + table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq)); } template @@ -1716,7 +1717,8 @@ typename unordered_multiset::const_iterator unordered_multiset::find(CompatibleKey const& k, CompatibleHash const& hash, CompatiblePredicate const& eq) const { - return const_iterator(table_.generic_find_node(k, hash, eq)); + return const_iterator( + table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq)); } template From b6c229e2bb0fafaede1adda55ee112c181eb82df Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 10:09:18 +0100 Subject: [PATCH 063/147] Expand calls to reserve implementation --- include/boost/unordered/detail/implementation.hpp | 7 ------- include/boost/unordered/unordered_map.hpp | 6 ++++-- include/boost/unordered/unordered_set.hpp | 6 ++++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index b7f18498..d3612c21 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3358,13 +3358,6 @@ inline void table::rehash(std::size_t min_buckets) } } -template -inline void table::reserve(std::size_t num_elements) -{ - rehash(static_cast( - std::ceil(static_cast(num_elements) / mlf_))); -} - template inline void table::rehash_impl(std::size_t num_buckets) { diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index d5c45f3e..08135a57 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1744,7 +1744,8 @@ void unordered_map::rehash(size_type n) template void unordered_map::reserve(size_type n) { - table_.reserve(n); + table_.rehash(static_cast( + std::ceil(static_cast(n) / table_.mlf_))); } template @@ -2167,7 +2168,8 @@ void unordered_multimap::rehash(size_type n) template void unordered_multimap::reserve(size_type n) { - table_.reserve(n); + table_.rehash(static_cast( + std::ceil(static_cast(n) / table_.mlf_))); } template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index cda04175..705c9b87 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1379,7 +1379,8 @@ void unordered_set::rehash(size_type n) template void unordered_set::reserve(size_type n) { - table_.reserve(n); + table_.rehash(static_cast( + std::ceil(static_cast(n) / table_.mlf_))); } template @@ -1768,7 +1769,8 @@ void unordered_multiset::rehash(size_type n) template void unordered_multiset::reserve(size_type n) { - table_.reserve(n); + table_.rehash(static_cast( + std::ceil(static_cast(n) / table_.mlf_))); } template From da835e88b8f4b50a5313105b189a6c029795e8c2 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 10:09:18 +0100 Subject: [PATCH 064/147] Expand calls to insert_range --- .../boost/unordered/detail/implementation.hpp | 6 --- include/boost/unordered/unordered_map.hpp | 37 ++++++++++--------- include/boost/unordered/unordered_set.hpp | 37 ++++++++++--------- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index d3612c21..9e7e01e8 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -4071,12 +4071,6 @@ struct table_unique : boost::unordered::detail::table // if hash function throws, or inserting > 1 element, basic exception // safety strong otherwise - template void insert_range(InputIt i, InputIt j) - { - if (i != j) - return insert_range_impl(extractor::extract(*i), i, j); - } - template void insert_range_impl(const_key_type& k, InputIt i, InputIt j) { diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 08135a57..3aa0d12a 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1369,7 +1369,7 @@ unordered_map::unordered_map(InputIt f, InputIt l, size_type n, const hasher& hf, const key_equal& eql, const allocator_type& a) : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) { - table_.insert_range(f, l); + this->insert(f, l); } template @@ -1409,7 +1409,7 @@ unordered_map::unordered_map( boost::unordered::detail::initial_size(list.begin(), list.end(), n), hf, eql, a) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } #endif @@ -1435,7 +1435,7 @@ unordered_map::unordered_map( : table_(boost::unordered::detail::initial_size(f, l, n), hasher(), key_equal(), a) { - table_.insert_range(f, l); + this->insert(f, l); } template @@ -1445,7 +1445,7 @@ unordered_map::unordered_map(InputIt f, InputIt l, size_type n, : table_( boost::unordered::detail::initial_size(f, l, n), hf, key_equal(), a) { - table_.insert_range(f, l); + this->insert(f, l); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1458,7 +1458,7 @@ unordered_map::unordered_map( boost::unordered::detail::initial_size(list.begin(), list.end(), n), hasher(), key_equal(), a) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } template @@ -1469,7 +1469,7 @@ unordered_map::unordered_map( boost::unordered::detail::initial_size(list.begin(), list.end(), n), hf, key_equal(), a) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } #endif @@ -1486,7 +1486,7 @@ unordered_map& unordered_map::operator=( std::initializer_list list) { this->clear(); - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); return *this; } @@ -1512,7 +1512,10 @@ template template void unordered_map::insert(InputIt first, InputIt last) { - table_.insert_range(first, last); + if (first != last) { + table_.insert_range_impl( + table::extractor::extract(*first), first, last); + } } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1520,7 +1523,7 @@ template void unordered_map::insert( std::initializer_list list) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } #endif @@ -1811,7 +1814,7 @@ unordered_multimap::unordered_multimap(InputIt f, InputIt l, const allocator_type& a) : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) { - table_.insert_range(f, l); + this->insert(f, l); } template @@ -1852,7 +1855,7 @@ unordered_multimap::unordered_multimap( boost::unordered::detail::initial_size(list.begin(), list.end(), n), hf, eql, a) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } #endif @@ -1878,7 +1881,7 @@ unordered_multimap::unordered_multimap( : table_(boost::unordered::detail::initial_size(f, l, n), hasher(), key_equal(), a) { - table_.insert_range(f, l); + this->insert(f, l); } template @@ -1888,7 +1891,7 @@ unordered_multimap::unordered_multimap(InputIt f, InputIt l, : table_( boost::unordered::detail::initial_size(f, l, n), hf, key_equal(), a) { - table_.insert_range(f, l); + this->insert(f, l); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1901,7 +1904,7 @@ unordered_multimap::unordered_multimap( boost::unordered::detail::initial_size(list.begin(), list.end(), n), hasher(), key_equal(), a) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } template @@ -1912,7 +1915,7 @@ unordered_multimap::unordered_multimap( boost::unordered::detail::initial_size(list.begin(), list.end(), n), hf, key_equal(), a) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } #endif @@ -1929,7 +1932,7 @@ unordered_multimap& unordered_multimap::operator=( std::initializer_list list) { this->clear(); - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); return *this; } @@ -1963,7 +1966,7 @@ template void unordered_multimap::insert( std::initializer_list list) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } #endif diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 705c9b87..4cb8eaa9 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1068,7 +1068,7 @@ unordered_set::unordered_set(InputIt f, InputIt l, size_type n, const hasher& hf, const key_equal& eql, const allocator_type& a) : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) { - table_.insert_range(f, l); + this->insert(f, l); } template @@ -1108,7 +1108,7 @@ unordered_set::unordered_set(std::initializer_list list, boost::unordered::detail::initial_size(list.begin(), list.end(), n), hf, eql, a) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } #endif @@ -1133,7 +1133,7 @@ unordered_set::unordered_set( : table_(boost::unordered::detail::initial_size(f, l, n), hasher(), key_equal(), a) { - table_.insert_range(f, l); + this->insert(f, l); } template @@ -1143,7 +1143,7 @@ unordered_set::unordered_set(InputIt f, InputIt l, size_type n, : table_( boost::unordered::detail::initial_size(f, l, n), hf, key_equal(), a) { - table_.insert_range(f, l); + this->insert(f, l); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1155,7 +1155,7 @@ unordered_set::unordered_set(std::initializer_list list, boost::unordered::detail::initial_size(list.begin(), list.end(), n), hasher(), key_equal(), a) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } template @@ -1165,7 +1165,7 @@ unordered_set::unordered_set(std::initializer_list list, boost::unordered::detail::initial_size(list.begin(), list.end(), n), hf, key_equal(), a) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } #endif @@ -1182,7 +1182,7 @@ unordered_set& unordered_set::operator=( std::initializer_list list) { this->clear(); - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); return *this; } @@ -1208,14 +1208,17 @@ template template void unordered_set::insert(InputIt first, InputIt last) { - table_.insert_range(first, last); + if (first != last) { + table_.insert_range_impl( + table::extractor::extract(*first), first, last); + } } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) template void unordered_set::insert(std::initializer_list list) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } #endif @@ -1445,7 +1448,7 @@ unordered_multiset::unordered_multiset(InputIt f, InputIt l, const allocator_type& a) : table_(boost::unordered::detail::initial_size(f, l, n), hf, eql, a) { - table_.insert_range(f, l); + this->insert(f, l); } template @@ -1486,7 +1489,7 @@ unordered_multiset::unordered_multiset( boost::unordered::detail::initial_size(list.begin(), list.end(), n), hf, eql, a) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } #endif @@ -1512,7 +1515,7 @@ unordered_multiset::unordered_multiset( : table_(boost::unordered::detail::initial_size(f, l, n), hasher(), key_equal(), a) { - table_.insert_range(f, l); + this->insert(f, l); } template @@ -1522,7 +1525,7 @@ unordered_multiset::unordered_multiset(InputIt f, InputIt l, : table_( boost::unordered::detail::initial_size(f, l, n), hf, key_equal(), a) { - table_.insert_range(f, l); + this->insert(f, l); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1535,7 +1538,7 @@ unordered_multiset::unordered_multiset( boost::unordered::detail::initial_size(list.begin(), list.end(), n), hasher(), key_equal(), a) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } template @@ -1546,7 +1549,7 @@ unordered_multiset::unordered_multiset( boost::unordered::detail::initial_size(list.begin(), list.end(), n), hf, key_equal(), a) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } #endif @@ -1563,7 +1566,7 @@ unordered_multiset& unordered_multiset::operator=( std::initializer_list list) { this->clear(); - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); return *this; } @@ -1597,7 +1600,7 @@ template void unordered_multiset::insert( std::initializer_list list) { - table_.insert_range(list.begin(), list.end()); + this->insert(list.begin(), list.end()); } #endif From 25b0b66e527036a9e2d50193426e8ae254381de0 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 10:09:18 +0100 Subject: [PATCH 065/147] Expand calls to erase implementation Doesn't work as well as the previous changes. --- .../boost/unordered/detail/implementation.hpp | 34 +---------------- include/boost/unordered/unordered_map.hpp | 38 ++++++++++++++++--- include/boost/unordered/unordered_set.hpp | 26 +++++++++++-- 3 files changed, 56 insertions(+), 42 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 9e7e01e8..0b7fe3b0 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -2708,6 +2708,8 @@ struct table : boost::unordered::detail::functions return 1; } - iterator erase(c_iterator r) - { - BOOST_ASSERT(r.node_); - node_pointer next = node_algo::next_node(r.node_); - erase_nodes(r.node_, next); - return iterator(next); - } - - iterator erase_range(c_iterator r1, c_iterator r2) - { - if (r1 == r2) - return iterator(r2.node_); - erase_nodes(r1.node_, r2.node_); - return iterator(r2.node_); - } - void erase_nodes(node_pointer i, node_pointer j) { std::size_t bucket_index = this->hash_to_bucket(i->hash_); @@ -4832,22 +4818,6 @@ struct table_equiv : boost::unordered::detail::table return deleted_count; } - iterator erase(c_iterator r) - { - BOOST_ASSERT(r.node_); - node_pointer next = node_algo::next_node(r.node_); - erase_nodes(r.node_, next); - return iterator(next); - } - - iterator erase_range(c_iterator r1, c_iterator r2) - { - if (r1 == r2) - return iterator(r2.node_); - erase_nodes(r1.node_, r2.node_); - return iterator(r2.node_); - } - link_pointer erase_nodes(node_pointer i, node_pointer j) { std::size_t bucket_index = this->hash_to_bucket(i->hash_); diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 3aa0d12a..2b17ab04 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -55,6 +55,7 @@ template class unordered_map typedef boost::unordered::detail::map types; typedef typename types::value_allocator_traits value_allocator_traits; typedef typename types::table table; + typedef typename table::node_pointer node_pointer; typedef typename table::link_pointer link_pointer; public: @@ -837,6 +838,7 @@ template class unordered_multimap typedef boost::unordered::detail::multimap types; typedef typename types::value_allocator_traits value_allocator_traits; typedef typename types::table table; + typedef typename table::node_pointer node_pointer; typedef typename table::link_pointer link_pointer; public: @@ -1531,14 +1533,22 @@ template typename unordered_map::iterator unordered_map::erase(iterator position) { - return table_.erase(position); + node_pointer node = table::get_node(position); + BOOST_ASSERT(node); + node_pointer next = table::node_algo::next_node(node); + table_.erase_nodes(node, next); + return iterator(next); } template typename unordered_map::iterator unordered_map::erase(const_iterator position) { - return table_.erase(position); + node_pointer node = table::get_node(position); + BOOST_ASSERT(node); + node_pointer next = table::node_algo::next_node(node); + table_.erase_nodes(node, next); + return iterator(next); } template @@ -1552,7 +1562,11 @@ template typename unordered_map::iterator unordered_map::erase(const_iterator first, const_iterator last) { - return table_.erase_range(first, last); + node_pointer last_node = table::get_node(last); + if (first == last) + return iterator(last_node); + table_.erase_nodes(table::get_node(first), last_node); + return iterator(last_node); } template @@ -1974,14 +1988,22 @@ template typename unordered_multimap::iterator unordered_multimap::erase(iterator position) { - return table_.erase(position); + node_pointer node = table::get_node(position); + BOOST_ASSERT(node); + node_pointer next = table::node_algo::next_node(node); + table_.erase_nodes(node, next); + return iterator(next); } template typename unordered_multimap::iterator unordered_multimap::erase(const_iterator position) { - return table_.erase(position); + node_pointer node = table::get_node(position); + BOOST_ASSERT(node); + node_pointer next = table::node_algo::next_node(node); + table_.erase_nodes(node, next); + return iterator(next); } template @@ -1996,7 +2018,11 @@ typename unordered_multimap::iterator unordered_multimap::erase( const_iterator first, const_iterator last) { - return table_.erase_range(first, last); + node_pointer last_node = table::get_node(last); + if (first == last) + return iterator(last_node); + table_.erase_nodes(table::get_node(first), last_node); + return iterator(last_node); } template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 4cb8eaa9..be316fd2 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -53,6 +53,7 @@ template class unordered_set typedef boost::unordered::detail::set types; typedef typename types::value_allocator_traits value_allocator_traits; typedef typename types::table table; + typedef typename table::node_pointer node_pointer; typedef typename table::link_pointer link_pointer; public: @@ -563,6 +564,7 @@ template class unordered_multiset typedef boost::unordered::detail::multiset types; typedef typename types::value_allocator_traits value_allocator_traits; typedef typename types::table table; + typedef typename table::node_pointer node_pointer; typedef typename table::link_pointer link_pointer; public: @@ -1226,7 +1228,11 @@ template typename unordered_set::iterator unordered_set::erase( const_iterator position) { - return table_.erase(position); + node_pointer node = table::get_node(position); + BOOST_ASSERT(node); + node_pointer next = table::node_algo::next_node(node); + table_.erase_nodes(node, next); + return iterator(next); } template @@ -1240,7 +1246,11 @@ template typename unordered_set::iterator unordered_set::erase( const_iterator first, const_iterator last) { - return table_.erase_range(first, last); + node_pointer last_node = table::get_node(last); + if (first == last) + return iterator(last_node); + table_.erase_nodes(table::get_node(first), last_node); + return iterator(last_node); } template @@ -1608,7 +1618,11 @@ template typename unordered_multiset::iterator unordered_multiset::erase(const_iterator position) { - return table_.erase(position); + node_pointer node = table::get_node(position); + BOOST_ASSERT(node); + node_pointer next = table::node_algo::next_node(node); + table_.erase_nodes(node, next); + return iterator(next); } template @@ -1622,7 +1636,11 @@ template typename unordered_multiset::iterator unordered_multiset::erase(const_iterator first, const_iterator last) { - return table_.erase_range(first, last); + node_pointer last_node = table::get_node(last); + if (first == last) + return iterator(last_node); + table_.erase_nodes(table::get_node(first), last_node); + return iterator(last_node); } template From 13ff1e7fb136aae192a67aecb606eaef66c96007 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 10:09:18 +0100 Subject: [PATCH 066/147] Expand calls to count and equal_range implementation --- .../boost/unordered/detail/implementation.hpp | 27 ------------------- include/boost/unordered/unordered_map.hpp | 21 ++++++++++----- include/boost/unordered/unordered_set.hpp | 13 ++++++--- 3 files changed, 24 insertions(+), 37 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 0b7fe3b0..ed0f8c32 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3771,11 +3771,6 @@ struct table_unique : boost::unordered::detail::table // Accessors - std::size_t count(const_key_type& k) const - { - return this->find_node(k) ? 1 : 0; - } - value_type& at(const_key_type& k) const { if (this->size_) { @@ -3788,13 +3783,6 @@ struct table_unique : boost::unordered::detail::table std::out_of_range("Unable to find key in unordered_map.")); } - std::pair equal_range(const_key_type& k) const - { - node_pointer n = this->find_node(k); - return std::make_pair( - iterator(n), iterator(n ? node_algo::next_node(n) : n)); - } - // equals bool equals(table_unique const& other) const @@ -4493,21 +4481,6 @@ struct table_equiv : boost::unordered::detail::table this->move_init(x); } - // Accessors - - std::size_t count(const_key_type& k) const - { - node_pointer n = this->find_node(k); - return n ? node_algo::count(n, this) : 0; - } - - std::pair equal_range(const_key_type& k) const - { - node_pointer n = this->find_node(k); - return std::make_pair( - iterator(n), iterator(n ? node_algo::next_group(n, this) : n)); - } - // Equality bool equals(table_equiv const& other) const diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 2b17ab04..8deca06d 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1682,7 +1682,7 @@ template typename unordered_map::size_type unordered_map::count(const key_type& k) const { - return table_.count(k); + return table_.find_node(k) ? 1 : 0; } template @@ -1690,7 +1690,9 @@ std::pair::iterator, typename unordered_map::iterator> unordered_map::equal_range(const key_type& k) { - return table_.equal_range(k); + node_pointer n = table_.find_node(k); + return std::make_pair( + iterator(n), iterator(n ? table::node_algo::next_node(n) : n)); } template @@ -1698,7 +1700,9 @@ std::pair::const_iterator, typename unordered_map::const_iterator> unordered_map::equal_range(const key_type& k) const { - return table_.equal_range(k); + node_pointer n = table_.find_node(k); + return std::make_pair(const_iterator(n), + const_iterator(n ? table::node_algo::next_node(n) : n)); } template @@ -2146,7 +2150,8 @@ template typename unordered_multimap::size_type unordered_multimap::count(const key_type& k) const { - return table_.count(k); + node_pointer n = table_.find_node(k); + return n ? table::node_algo::count(n, &table_) : 0; } template @@ -2154,7 +2159,9 @@ std::pair::iterator, typename unordered_multimap::iterator> unordered_multimap::equal_range(const key_type& k) { - return table_.equal_range(k); + node_pointer n = table_.find_node(k); + return std::make_pair(iterator(n), + iterator(n ? table::node_algo::next_group(n, &table_) : n)); } template @@ -2162,7 +2169,9 @@ std::pair::const_iterator, typename unordered_multimap::const_iterator> unordered_multimap::equal_range(const key_type& k) const { - return table_.equal_range(k); + node_pointer n = table_.find_node(k); + return std::make_pair(const_iterator(n), + const_iterator(n ? table::node_algo::next_group(n, &table_) : n)); } template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index be316fd2..7bb86954 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1349,7 +1349,7 @@ template typename unordered_set::size_type unordered_set::count( const key_type& k) const { - return table_.count(k); + return table_.find_node(k) ? 1 : 0; } template @@ -1357,7 +1357,9 @@ std::pair::const_iterator, typename unordered_set::const_iterator> unordered_set::equal_range(const key_type& k) const { - return table_.equal_range(k); + node_pointer n = table_.find_node(k); + return std::make_pair(const_iterator(n), + const_iterator(n ? table::node_algo::next_node(n) : n)); } template @@ -1747,7 +1749,8 @@ template typename unordered_multiset::size_type unordered_multiset::count(const key_type& k) const { - return table_.count(k); + node_pointer n = table_.find_node(k); + return n ? table::node_algo::count(n, &table_) : 0; } template @@ -1755,7 +1758,9 @@ std::pair::const_iterator, typename unordered_multiset::const_iterator> unordered_multiset::equal_range(const key_type& k) const { - return table_.equal_range(k); + node_pointer n = table_.find_node(k); + return std::make_pair(const_iterator(n), + const_iterator(n ? table::node_algo::next_group(n, &table_) : n)); } template From 4f1c6e1ebf98b667bb143785fb590afb309eff84 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 10:09:18 +0100 Subject: [PATCH 067/147] Expand calls to init/move_init --- .../boost/unordered/detail/implementation.hpp | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index ed0f8c32..599ec1c7 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -2853,26 +2853,6 @@ struct table : boost::unordered::detail::functions(this)->copy_buckets(x); - } - } - - void move_init(table& x) - { - if (node_alloc() == x.node_alloc()) { - move_buckets_from(x); - } else if (x.size_) { - // TODO: Could pick new bucket size? - static_cast(this)->move_buckets(x); - } - } - //////////////////////////////////////////////////////////////////////// // Clear buckets and Create buckets // @@ -3749,24 +3729,34 @@ struct table_unique : boost::unordered::detail::table : table(x, node_allocator_traits::select_on_container_copy_construction( x.node_alloc())) { - this->init(x); + if (x.size_) { + this->copy_buckets(x); + } } table_unique(table_unique const& x, node_allocator const& a) : table(x, a) { - this->init(x); + if (x.size_) { + this->copy_buckets(x); + } } table_unique(table_unique& x, boost::unordered::detail::move_tag m) : table(x, m) { + // The move is done in the base class. } table_unique(table_unique& x, node_allocator const& a, boost::unordered::detail::move_tag m) : table(x, a, m) { - this->move_init(x); + if (this->node_alloc() == x.node_alloc()) { + this->move_buckets_from(x); + } else if (x.size_) { + // TODO: Could pick new bucket size? + this->move_buckets(x); + } } // Accessors @@ -4461,24 +4451,34 @@ struct table_equiv : boost::unordered::detail::table : table(x, node_allocator_traits::select_on_container_copy_construction( x.node_alloc())) { - this->init(x); + if (x.size_) { + copy_buckets(x); + } } table_equiv(table_equiv const& x, node_allocator const& a) : table(x, a) { - this->init(x); + if (x.size_) { + copy_buckets(x); + } } table_equiv(table_equiv& x, boost::unordered::detail::move_tag m) : table(x, m) { + // The move is done in the base class. } table_equiv(table_equiv& x, node_allocator const& a, boost::unordered::detail::move_tag m) : table(x, a, m) { - this->move_init(x); + if (this->node_alloc() == x.node_alloc()) { + this->move_buckets_from(x); + } else if (x.size_) { + // TODO: Could pick new bucket size? + this->move_buckets(x); + } } // Equality From 7941771d617a7df14319ade31ed30c69af27c2af Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 10:09:18 +0100 Subject: [PATCH 068/147] Expand calls to at implementation --- .../boost/unordered/detail/implementation.hpp | 14 -------------- include/boost/unordered/unordered_map.hpp | 18 ++++++++++++++++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 599ec1c7..afbfb2a2 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3759,20 +3759,6 @@ struct table_unique : boost::unordered::detail::table } } - // Accessors - - value_type& at(const_key_type& k) const - { - if (this->size_) { - node_pointer n = this->find_node(k); - if (n) - return n->value(); - } - - boost::throw_exception( - std::out_of_range("Unable to find key in unordered_map.")); - } - // equals bool equals(table_unique const& other) const diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 8deca06d..a55e2b5c 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1723,14 +1723,28 @@ template typename unordered_map::mapped_type& unordered_map::at(const key_type& k) { - return table_.at(k).second; + if (table_.size_) { + node_pointer n = table_.find_node(k); + if (n) + return n->value().second; + } + + boost::throw_exception( + std::out_of_range("Unable to find key in unordered_map.")); } template typename unordered_map::mapped_type const& unordered_map::at(const key_type& k) const { - return table_.at(k).second; + if (table_.size_) { + node_pointer n = table_.find_node(k); + if (n) + return n->value().second; + } + + boost::throw_exception( + std::out_of_range("Unable to find key in unordered_map.")); } template From fc08f62d6ab02be5b70cf5edddfafef6f95bc215 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 10:51:17 +0100 Subject: [PATCH 069/147] Remove a TODO --- include/boost/unordered/detail/implementation.hpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index afbfb2a2..937b0a0e 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -4046,11 +4046,6 @@ struct table_unique : boost::unordered::detail::table // Note: can't use get_key as '*i' might not be value_type - it // could be a pair with first_types as key_type without const or // a different second_type. - // - // TODO: Might be worth storing the value_type instead of the - // key here. Could be more efficient if '*i' is expensive. Could - // be less efficient if copying the full value_type is - // expensive. insert_range_impl2(extractor::extract(*i), i, j); } } From 8229aa6b3ce875d8c4738ecee7cbeee43bc53961 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 23 Apr 2017 10:51:17 +0100 Subject: [PATCH 070/147] Stop throwing exception in allocator copy/assignment The standard specifies that all of these "shall not exit via an exception". The containers have been exception safe when these throw, but the 'noexcept' attribute on 'get_allocator' will terminate if an exception is thrown in the copy constructor. The standard doesn't specify a default constructor, so that is allowed to throw an exception (not just pedantry, this makes sense if an allocator has shared data that's allocated in the initial constructor). --- test/objects/exception.hpp | 36 ++---------------------------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/test/objects/exception.hpp b/test/objects/exception.hpp index d5f0f5db..e76ac477 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -339,19 +339,11 @@ template class allocator template allocator(allocator const& x) : tag_(x.tag_) { - UNORDERED_SCOPE(allocator::allocator()) - { - UNORDERED_EPOINT("Mock allocator template copy constructor."); - } test::detail::tracker.allocator_ref(); } allocator(allocator const& x) : tag_(x.tag_) { - UNORDERED_SCOPE(allocator::allocator()) - { - UNORDERED_EPOINT("Mock allocator copy constructor."); - } test::detail::tracker.allocator_ref(); } @@ -359,11 +351,7 @@ template class allocator allocator& operator=(allocator const& x) { - UNORDERED_SCOPE(allocator::allocator()) - { - UNORDERED_EPOINT("Mock allocator assignment operator."); - tag_ = x.tag_; - } + tag_ = x.tag_; return *this; } @@ -530,42 +518,22 @@ template class allocator2 allocator2(allocator const& x) : tag_(x.tag_) { - UNORDERED_SCOPE(allocator2::allocator2()) - { - UNORDERED_EPOINT("Mock allocator2 constructor from allocator."); - } test::detail::tracker.allocator_ref(); } template allocator2(allocator2 const& x) : tag_(x.tag_) { - UNORDERED_SCOPE(allocator2::allocator2()) - { - UNORDERED_EPOINT("Mock allocator2 template copy constructor."); - } test::detail::tracker.allocator_ref(); } allocator2(allocator2 const& x) : tag_(x.tag_) { - UNORDERED_SCOPE(allocator2::allocator2()) - { - UNORDERED_EPOINT("Mock allocator2 copy constructor."); - } test::detail::tracker.allocator_ref(); } ~allocator2() { test::detail::tracker.allocator_unref(); } - allocator2& operator=(allocator2 const& x) - { - UNORDERED_SCOPE(allocator2::allocator2()) - { - UNORDERED_EPOINT("Mock allocator2 assignment operator."); - tag_ = x.tag_; - } - return *this; - } + allocator2& operator=(allocator2 const&) { return *this; } // If address throws, then it can't be used in erase or the // destructor, which is very limiting. I need to check up on From 77bf2b5e33e173bef22baca90f2e7a603480f776 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 24 Apr 2017 09:46:05 +0100 Subject: [PATCH 071/147] Rename methods to be different for unique/equiv keys So that the implementation can be moved into a single class. Still some other methods to rename. Some methods didn't need to be renamed (e.g. try_emplace is only used with unique keys), but still renamed for consistency. --- .../boost/unordered/detail/implementation.hpp | 211 ++++++++++-------- include/boost/unordered/unordered_map.hpp | 146 ++++++------ include/boost/unordered/unordered_set.hpp | 86 +++---- 3 files changed, 229 insertions(+), 214 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 937b0a0e..d45a11a4 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3624,7 +3624,7 @@ template struct node_algo // Add node 'n' after 'pos'. // This results in a different order to the grouped implementation. - static inline void add_to_node_group(node_pointer n, node_pointer pos) + static inline void add_to_node(node_pointer n, node_pointer pos) { n->next_ = pos->next_; pos->next_ = n; @@ -3761,7 +3761,7 @@ struct table_unique : boost::unordered::detail::table // equals - bool equals(table_unique const& other) const + bool equals_unique(table const& other) const { if (this->size_ != other.size_) return false; @@ -3779,7 +3779,7 @@ struct table_unique : boost::unordered::detail::table // Emplace/Insert - inline node_pointer add_node(node_pointer n, std::size_t key_hash) + inline node_pointer add_node_unique(node_pointer n, std::size_t key_hash) { n->hash_ = key_hash; @@ -3806,27 +3806,28 @@ struct table_unique : boost::unordered::detail::table return n; } - inline node_pointer resize_and_add_node( + inline node_pointer resize_and_add_node_unique( node_pointer n, std::size_t key_hash) { node_tmp b(n, this->node_alloc()); this->reserve_for_insert(this->size_ + 1); - return this->add_node(b.release(), key_hash); + return this->add_node_unique(b.release(), key_hash); } template - iterator emplace_hint_impl( + iterator emplace_hint_unique( c_iterator hint, const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS) { if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { return iterator(hint.node_); } else { - return emplace_impl(k, BOOST_UNORDERED_EMPLACE_FORWARD).first; + return emplace_unique(k, BOOST_UNORDERED_EMPLACE_FORWARD).first; } } template - emplace_return emplace_impl(const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS) + emplace_return emplace_unique( + const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS) { std::size_t key_hash = this->hash(k); node_pointer pos = this->find_node(key_hash, k); @@ -3834,7 +3835,7 @@ struct table_unique : boost::unordered::detail::table return emplace_return(iterator(pos), false); } else { return emplace_return( - iterator(this->resize_and_add_node( + iterator(this->resize_and_add_node_unique( boost::unordered::detail::func::construct_node_from_args( this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), key_hash)), @@ -3843,7 +3844,7 @@ struct table_unique : boost::unordered::detail::table } template - iterator emplace_hint_impl( + iterator emplace_hint_unique( c_iterator hint, no_key, BOOST_UNORDERED_EMPLACE_ARGS) { node_tmp b(boost::unordered::detail::func::construct_node_from_args( @@ -3858,12 +3859,13 @@ struct table_unique : boost::unordered::detail::table if (pos) { return iterator(pos); } else { - return iterator(this->resize_and_add_node(b.release(), key_hash)); + return iterator( + this->resize_and_add_node_unique(b.release(), key_hash)); } } template - emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS) + emplace_return emplace_unique(no_key, BOOST_UNORDERED_EMPLACE_ARGS) { node_tmp b(boost::unordered::detail::func::construct_node_from_args( this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), @@ -3874,14 +3876,14 @@ struct table_unique : boost::unordered::detail::table if (pos) { return emplace_return(iterator(pos), false); } else { - return emplace_return( - iterator(this->resize_and_add_node(b.release(), key_hash)), + return emplace_return(iterator(this->resize_and_add_node_unique( + b.release(), key_hash)), true); } } template - emplace_return try_emplace_impl(BOOST_FWD_REF(Key) k) + emplace_return try_emplace_unique(BOOST_FWD_REF(Key) k) { std::size_t key_hash = this->hash(k); node_pointer pos = this->find_node(key_hash, k); @@ -3889,7 +3891,7 @@ struct table_unique : boost::unordered::detail::table return emplace_return(iterator(pos), false); } else { return emplace_return( - iterator(this->resize_and_add_node( + iterator(this->resize_and_add_node_unique( boost::unordered::detail::func::construct_node_pair( this->node_alloc(), boost::forward(k)), key_hash)), @@ -3898,17 +3900,17 @@ struct table_unique : boost::unordered::detail::table } template - iterator try_emplace_hint_impl(c_iterator hint, BOOST_FWD_REF(Key) k) + iterator try_emplace_hint_unique(c_iterator hint, BOOST_FWD_REF(Key) k) { if (hint.node_ && this->key_eq()(hint->first, k)) { return iterator(hint.node_); } else { - return try_emplace_impl(k).first; + return try_emplace_unique(k).first; } } template - emplace_return try_emplace_impl( + emplace_return try_emplace_unique( BOOST_FWD_REF(Key) k, BOOST_UNORDERED_EMPLACE_ARGS) { std::size_t key_hash = this->hash(k); @@ -3917,7 +3919,7 @@ struct table_unique : boost::unordered::detail::table return emplace_return(iterator(pos), false); } else { return emplace_return( - iterator(this->resize_and_add_node( + iterator(this->resize_and_add_node_unique( boost::unordered::detail::func:: construct_node_pair_from_args(this->node_alloc(), boost::forward(k), @@ -3928,18 +3930,18 @@ struct table_unique : boost::unordered::detail::table } template - iterator try_emplace_hint_impl( + iterator try_emplace_hint_unique( c_iterator hint, BOOST_FWD_REF(Key) k, BOOST_UNORDERED_EMPLACE_ARGS) { if (hint.node_ && this->key_eq()(hint->first, k)) { return iterator(hint.node_); } else { - return try_emplace_impl(k, BOOST_UNORDERED_EMPLACE_FORWARD).first; + return try_emplace_unique(k, BOOST_UNORDERED_EMPLACE_FORWARD).first; } } template - emplace_return insert_or_assign_impl( + emplace_return insert_or_assign_unique( BOOST_FWD_REF(Key) k, BOOST_FWD_REF(M) obj) { std::size_t key_hash = this->hash(k); @@ -3950,7 +3952,7 @@ struct table_unique : boost::unordered::detail::table return emplace_return(iterator(pos), false); } else { return emplace_return( - iterator(this->resize_and_add_node( + iterator(this->resize_and_add_node_unique( boost::unordered::detail::func::construct_node_pair( this->node_alloc(), boost::forward(k), boost::forward(obj)), @@ -3960,7 +3962,7 @@ struct table_unique : boost::unordered::detail::table } template - void move_insert_node_type(NodeType& np, InsertReturnType& result) + void move_insert_node_type_unique(NodeType& np, InsertReturnType& result) { if (np) { const_key_type& k = this->get_key(np.ptr_); @@ -3972,7 +3974,8 @@ struct table_unique : boost::unordered::detail::table result.position = iterator(pos); } else { this->reserve_for_insert(this->size_ + 1); - result.position = iterator(this->add_node(np.ptr_, key_hash)); + result.position = + iterator(this->add_node_unique(np.ptr_, key_hash)); result.inserted = true; np.ptr_ = node_pointer(); } @@ -3980,7 +3983,8 @@ struct table_unique : boost::unordered::detail::table } template - iterator move_insert_node_type_with_hint(c_iterator hint, NodeType& np) + iterator move_insert_node_type_with_hint_unique( + c_iterator hint, NodeType& np) { if (!np) { return iterator(); @@ -3993,14 +3997,14 @@ struct table_unique : boost::unordered::detail::table node_pointer pos = this->find_node(key_hash, k); if (!pos) { this->reserve_for_insert(this->size_ + 1); - pos = this->add_node(np.ptr_, key_hash); + pos = this->add_node_unique(np.ptr_, key_hash); np.ptr_ = node_pointer(); } return iterator(pos); } template - void merge_impl(boost::unordered::detail::table& other) + void merge_unique(boost::unordered::detail::table& other) { typedef boost::unordered::detail::table other_table; BOOST_STATIC_ASSERT( @@ -4025,7 +4029,7 @@ struct table_unique : boost::unordered::detail::table prev->next_ = n->next_; --other.size_; other.fix_bucket(other.hash_to_bucket(n->hash_), prev); - this->add_node(n, key_hash); + this->add_node_unique(n, key_hash); } } } @@ -4038,20 +4042,20 @@ struct table_unique : boost::unordered::detail::table // safety strong otherwise template - void insert_range_impl(const_key_type& k, InputIt i, InputIt j) + void insert_range_unique(const_key_type& k, InputIt i, InputIt j) { - insert_range_impl2(k, i, j); + insert_range_unique2(k, i, j); while (++i != j) { // Note: can't use get_key as '*i' might not be value_type - it // could be a pair with first_types as key_type without const or // a different second_type. - insert_range_impl2(extractor::extract(*i), i, j); + insert_range_unique2(extractor::extract(*i), i, j); } } template - void insert_range_impl2(const_key_type& k, InputIt i, InputIt j) + void insert_range_unique2(const_key_type& k, InputIt i, InputIt j) { // No side effects in this initial code std::size_t key_hash = this->hash(k); @@ -4064,12 +4068,12 @@ struct table_unique : boost::unordered::detail::table if (this->size_ + 1 > this->max_load_) this->reserve_for_insert( this->size_ + boost::unordered::detail::insert_size(i, j)); - this->add_node(b.release(), key_hash); + this->add_node_unique(b.release(), key_hash); } } template - void insert_range_impl(no_key, InputIt i, InputIt j) + void insert_range_unique(no_key, InputIt i, InputIt j) { node_constructor a(this->node_alloc()); @@ -4091,7 +4095,7 @@ struct table_unique : boost::unordered::detail::table // reserve has basic exception safety if the hash function // throws, strong otherwise. this->reserve_for_insert(this->size_ + 1); - this->add_node(b.release(), key_hash); + this->add_node_unique(b.release(), key_hash); } } while (++i != j); } @@ -4099,7 +4103,7 @@ struct table_unique : boost::unordered::detail::table //////////////////////////////////////////////////////////////////////// // Extract - inline node_pointer extract_by_iterator(c_iterator i) + inline node_pointer extract_by_iterator_unique(c_iterator i) { node_pointer n = i.node_; BOOST_ASSERT(n); @@ -4121,7 +4125,7 @@ struct table_unique : boost::unordered::detail::table // // no throw - std::size_t erase_key(const_key_type& k) + std::size_t erase_key_unique(const_key_type& k) { if (!this->size_) return 0; @@ -4136,7 +4140,7 @@ struct table_unique : boost::unordered::detail::table return 1; } - void erase_nodes(node_pointer i, node_pointer j) + void erase_nodes_unique(node_pointer i, node_pointer j) { std::size_t bucket_index = this->hash_to_bucket(i->hash_); @@ -4153,15 +4157,16 @@ struct table_unique : boost::unordered::detail::table } //////////////////////////////////////////////////////////////////////// - // fill_buckets + // fill_buckets_unique void copy_buckets(table const& src) { this->create_buckets(this->bucket_count_); for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { - this->add_node(boost::unordered::detail::func::construct_node( - this->node_alloc(), n->value()), + this->add_node_unique( + boost::unordered::detail::func::construct_node( + this->node_alloc(), n->value()), n->hash_); } } @@ -4171,8 +4176,9 @@ struct table_unique : boost::unordered::detail::table this->create_buckets(this->bucket_count_); for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { - this->add_node(boost::unordered::detail::func::construct_node( - this->node_alloc(), boost::move(n->value())), + this->add_node_unique( + boost::unordered::detail::func::construct_node( + this->node_alloc(), boost::move(n->value())), n->hash_); } } @@ -4181,7 +4187,7 @@ struct table_unique : boost::unordered::detail::table { node_holder holder(*this); for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { - this->add_node(holder.copy_of(n->value()), n->hash_); + this->add_node_unique(holder.copy_of(n->value()), n->hash_); } } @@ -4189,7 +4195,7 @@ struct table_unique : boost::unordered::detail::table { node_holder holder(*this); for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { - this->add_node(holder.move_copy_of(n->value()), n->hash_); + this->add_node_unique(holder.move_copy_of(n->value()), n->hash_); } } }; @@ -4297,7 +4303,7 @@ template struct grouped_node_algo // If 'pos' is the first node in group, add to the end of the group, // otherwise add before 'pos'. Other versions will probably behave // differently. - static inline void add_to_node_group(node_pointer n, node_pointer pos) + static inline void add_to_node(node_pointer n, node_pointer pos) { n->next_ = pos->group_prev_->next_; n->group_prev_ = pos->group_prev_; @@ -4458,13 +4464,13 @@ struct table_equiv : boost::unordered::detail::table this->move_buckets_from(x); } else if (x.size_) { // TODO: Could pick new bucket size? - this->move_buckets(x); + this->move_buckets_equiv(x); } } // Equality - bool equals(table_equiv const& other) const + bool equals_equiv(table const& other) const { if (this->size_ != other.size_) return false; @@ -4475,7 +4481,7 @@ struct table_equiv : boost::unordered::detail::table return false; node_pointer end1 = node_algo::next_group(n1, this); node_pointer end2 = node_algo::next_group(n2, this); - if (!group_equals(n1, end1, n2, end2)) + if (!group_equals_equiv(n1, end1, n2, end2)) return false; n1 = end1; } @@ -4483,7 +4489,7 @@ struct table_equiv : boost::unordered::detail::table return true; } - static bool group_equals( + static bool group_equals_equiv( node_pointer n1, node_pointer end1, node_pointer n2, node_pointer end2) { for (;;) { @@ -4517,12 +4523,12 @@ struct table_equiv : boost::unordered::detail::table node_pointer start = n1; for (; n1 != end1; n1 = node_algo::next_node(n1)) { value_type const& v = n1->value(); - if (!find(start, n1, v)) { - std::size_t matches = count_equal(n2, end2, v); + if (!find_equiv(start, n1, v)) { + std::size_t matches = count_equal_equiv(n2, end2, v); if (!matches) return false; if (matches != - 1 + count_equal(node_algo::next_node(n1), end1, v)) + 1 + count_equal_equiv(node_algo::next_node(n1), end1, v)) return false; } } @@ -4530,7 +4536,8 @@ struct table_equiv : boost::unordered::detail::table return true; } - static bool find(node_pointer n, node_pointer end, value_type const& v) + static bool find_equiv( + node_pointer n, node_pointer end, value_type const& v) { for (; n != end; n = node_algo::next_node(n)) if (n->value() == v) @@ -4538,7 +4545,7 @@ struct table_equiv : boost::unordered::detail::table return false; } - static std::size_t count_equal( + static std::size_t count_equal_equiv( node_pointer n, node_pointer end, value_type const& v) { std::size_t count = 0; @@ -4550,12 +4557,12 @@ struct table_equiv : boost::unordered::detail::table // Emplace/Insert - inline node_pointer add_node( + inline node_pointer add_node_equiv( node_pointer n, std::size_t key_hash, node_pointer pos) { n->hash_ = key_hash; if (pos) { - node_algo::add_to_node_group(n, pos); + node_algo::add_to_node(n, pos); if (n->next_) { std::size_t next_bucket = this->hash_to_bucket(node_algo::next_node(n)->hash_); @@ -4588,10 +4595,10 @@ struct table_equiv : boost::unordered::detail::table return n; } - inline node_pointer add_using_hint(node_pointer n, node_pointer hint) + inline node_pointer add_using_hint_equiv(node_pointer n, node_pointer hint) { n->hash_ = hint->hash_; - node_algo::add_to_node_group(n, hint); + node_algo::add_to_node(n, hint); if (n->next_ != hint && n->next_) { std::size_t next_bucket = this->hash_to_bucket(node_algo::next_node(n)->hash_); @@ -4603,41 +4610,44 @@ struct table_equiv : boost::unordered::detail::table return n; } - iterator emplace_impl(node_pointer n) + iterator emplace_equiv(node_pointer n) { node_tmp a(n, this->node_alloc()); const_key_type& k = this->get_key(a.node_); std::size_t key_hash = this->hash(k); node_pointer position = this->find_node(key_hash, k); this->reserve_for_insert(this->size_ + 1); - return iterator(this->add_node(a.release(), key_hash, position)); + return iterator(this->add_node_equiv(a.release(), key_hash, position)); } - iterator emplace_hint_impl(c_iterator hint, node_pointer n) + iterator emplace_hint_equiv(c_iterator hint, node_pointer n) { node_tmp a(n, this->node_alloc()); const_key_type& k = this->get_key(a.node_); if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { this->reserve_for_insert(this->size_ + 1); - return iterator(this->add_using_hint(a.release(), hint.node_)); + return iterator( + this->add_using_hint_equiv(a.release(), hint.node_)); } else { std::size_t key_hash = this->hash(k); node_pointer position = this->find_node(key_hash, k); this->reserve_for_insert(this->size_ + 1); - return iterator(this->add_node(a.release(), key_hash, position)); + return iterator( + this->add_node_equiv(a.release(), key_hash, position)); } } - void emplace_impl_no_rehash(node_pointer n) + void emplace_no_rehash_equiv(node_pointer n) { node_tmp a(n, this->node_alloc()); const_key_type& k = this->get_key(a.node_); std::size_t key_hash = this->hash(k); node_pointer position = this->find_node(key_hash, k); - this->add_node(a.release(), key_hash, position); + this->add_node_equiv(a.release(), key_hash, position); } - template iterator move_insert_node_type(NodeType& np) + template + iterator move_insert_node_type_equiv(NodeType& np) { iterator result; @@ -4646,7 +4656,7 @@ struct table_equiv : boost::unordered::detail::table std::size_t key_hash = this->hash(k); node_pointer pos = this->find_node(key_hash, k); this->reserve_for_insert(this->size_ + 1); - result = iterator(this->add_node(np.ptr_, key_hash, pos)); + result = iterator(this->add_node_equiv(np.ptr_, key_hash, pos)); np.ptr_ = node_pointer(); } @@ -4654,7 +4664,8 @@ struct table_equiv : boost::unordered::detail::table } template - iterator move_insert_node_type_with_hint(c_iterator hint, NodeType& np) + iterator move_insert_node_type_with_hint_equiv( + c_iterator hint, NodeType& np) { iterator result; @@ -4663,12 +4674,13 @@ struct table_equiv : boost::unordered::detail::table if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { this->reserve_for_insert(this->size_ + 1); - result = iterator(this->add_using_hint(np.ptr_, hint.node_)); + result = + iterator(this->add_using_hint_equiv(np.ptr_, hint.node_)); } else { std::size_t key_hash = this->hash(k); node_pointer pos = this->find_node(key_hash, k); this->reserve_for_insert(this->size_ + 1); - result = iterator(this->add_node(np.ptr_, key_hash, pos)); + result = iterator(this->add_node_equiv(np.ptr_, key_hash, pos)); } np.ptr_ = node_pointer(); } @@ -4682,7 +4694,7 @@ struct table_equiv : boost::unordered::detail::table // if hash function throws, or inserting > 1 element, basic exception // safety. Strong otherwise template - void insert_range(I i, I j, + void insert_range_equiv(I i, I j, typename boost::unordered::detail::enable_if_forward::type = 0) { @@ -4691,14 +4703,14 @@ struct table_equiv : boost::unordered::detail::table std::size_t distance = static_cast(std::distance(i, j)); if (distance == 1) { - emplace_impl(boost::unordered::detail::func::construct_node( + emplace_equiv(boost::unordered::detail::func::construct_node( this->node_alloc(), *i)); } else { // Only require basic exception safety here this->reserve_for_insert(this->size_ + distance); for (; i != j; ++i) { - emplace_impl_no_rehash( + emplace_no_rehash_equiv( boost::unordered::detail::func::construct_node( this->node_alloc(), *i)); } @@ -4706,12 +4718,12 @@ struct table_equiv : boost::unordered::detail::table } template - void insert_range(I i, I j, + void insert_range_equiv(I i, I j, typename boost::unordered::detail::disable_if_forward::type = 0) { for (; i != j; ++i) { - emplace_impl(boost::unordered::detail::func::construct_node( + emplace_equiv(boost::unordered::detail::func::construct_node( this->node_alloc(), *i)); } } @@ -4719,7 +4731,7 @@ struct table_equiv : boost::unordered::detail::table //////////////////////////////////////////////////////////////////////// // Extract - inline node_pointer extract_by_iterator(c_iterator n) + inline node_pointer extract_by_iterator_equiv(c_iterator n) { node_pointer i = n.node_; BOOST_ASSERT(i); @@ -4753,7 +4765,7 @@ struct table_equiv : boost::unordered::detail::table // // no throw - std::size_t erase_key(const_key_type& k) + std::size_t erase_key_equiv(const_key_type& k) { if (!this->size_) return 0; @@ -4772,7 +4784,7 @@ struct table_equiv : boost::unordered::detail::table return deleted_count; } - link_pointer erase_nodes(node_pointer i, node_pointer j) + link_pointer erase_nodes_equiv(node_pointer i, node_pointer j) { std::size_t bucket_index = this->hash_to_bucket(i->hash_); @@ -4811,34 +4823,36 @@ struct table_equiv : boost::unordered::detail::table for (node_pointer n = src.begin(); n;) { std::size_t key_hash = n->hash_; node_pointer group_end(node_algo::next_group(n, this)); - node_pointer pos = - this->add_node(boost::unordered::detail::func::construct_node( - this->node_alloc(), n->value()), - key_hash, node_pointer()); + node_pointer pos = this->add_node_equiv( + boost::unordered::detail::func::construct_node( + this->node_alloc(), n->value()), + key_hash, node_pointer()); for (n = node_algo::next_node(n); n != group_end; n = node_algo::next_node(n)) { - this->add_node(boost::unordered::detail::func::construct_node( - this->node_alloc(), n->value()), + this->add_node_equiv( + boost::unordered::detail::func::construct_node( + this->node_alloc(), n->value()), key_hash, pos); } } } - void move_buckets(table const& src) + void move_buckets_equiv(table const& src) { this->create_buckets(this->bucket_count_); for (node_pointer n = src.begin(); n;) { std::size_t key_hash = n->hash_; node_pointer group_end(node_algo::next_group(n, this)); - node_pointer pos = - this->add_node(boost::unordered::detail::func::construct_node( - this->node_alloc(), boost::move(n->value())), - key_hash, node_pointer()); + node_pointer pos = this->add_node_equiv( + boost::unordered::detail::func::construct_node( + this->node_alloc(), boost::move(n->value())), + key_hash, node_pointer()); for (n = node_algo::next_node(n); n != group_end; n = node_algo::next_node(n)) { - this->add_node(boost::unordered::detail::func::construct_node( - this->node_alloc(), boost::move(n->value())), + this->add_node_equiv( + boost::unordered::detail::func::construct_node( + this->node_alloc(), boost::move(n->value())), key_hash, pos); } } @@ -4850,11 +4864,11 @@ struct table_equiv : boost::unordered::detail::table for (node_pointer n = src.begin(); n;) { std::size_t key_hash = n->hash_; node_pointer group_end(node_algo::next_group(n, this)); - node_pointer pos = this->add_node( + node_pointer pos = this->add_node_equiv( holder.copy_of(n->value()), key_hash, node_pointer()); for (n = node_algo::next_node(n); n != group_end; n = node_algo::next_node(n)) { - this->add_node(holder.copy_of(n->value()), key_hash, pos); + this->add_node_equiv(holder.copy_of(n->value()), key_hash, pos); } } } @@ -4865,11 +4879,12 @@ struct table_equiv : boost::unordered::detail::table for (node_pointer n = src.begin(); n;) { std::size_t key_hash = n->hash_; node_pointer group_end(node_algo::next_group(n, this)); - node_pointer pos = this->add_node( + node_pointer pos = this->add_node_equiv( holder.move_copy_of(n->value()), key_hash, node_pointer()); for (n = node_algo::next_node(n); n != group_end; n = node_algo::next_node(n)) { - this->add_node(holder.move_copy_of(n->value()), key_hash, pos); + this->add_node_equiv( + holder.move_copy_of(n->value()), key_hash, pos); } } } diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index a55e2b5c..85f1c134 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -222,7 +222,7 @@ template class unordered_map template std::pair emplace(BOOST_FWD_REF(Args)... args) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract(boost::forward(args)...), boost::forward(args)...); } @@ -248,7 +248,7 @@ template class unordered_map template std::pair emplace(BOOST_FWD_REF(A0) a0) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract(boost::forward(a0)), boost::unordered::detail::create_emplace_args( boost::forward(a0))); @@ -258,7 +258,7 @@ template class unordered_map std::pair emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -269,7 +269,7 @@ template class unordered_map std::pair emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -284,7 +284,7 @@ template class unordered_map template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return table_.emplace_hint_impl(hint, + return table_.emplace_hint_unique(hint, table::extractor::extract(boost::forward(args)...), boost::forward(args)...); } @@ -306,17 +306,17 @@ template class unordered_map template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return table_.emplace_hint_impl(hint, + return table_.emplace_hint_unique(hint, table::extractor::extract(boost::forward(a0)), boost::unordered::detail::create_emplace_args( - boost::forward(a0))); + boost::forward(a0))); } template iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace_hint_impl( + return table_.emplace_hint_unique( hint, table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -327,7 +327,7 @@ template class unordered_map iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace_hint_impl( + return table_.emplace_hint_unique( hint, table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -344,7 +344,7 @@ template class unordered_map std::pair emplace( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace_impl( \ + return table_.emplace_unique( \ table::extractor::extract( \ boost::forward(a0), boost::forward(a1)), \ boost::unordered::detail::create_emplace_args( \ @@ -355,7 +355,7 @@ template class unordered_map iterator emplace_hint(const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace_hint_impl( \ + return table_.emplace_hint_unique( \ hint, table::extractor::extract( \ boost::forward(a0), boost::forward(a1)), \ boost::unordered::detail::create_emplace_args( \ @@ -424,7 +424,7 @@ template class unordered_map node_type extract(const_iterator position) { return node_type( - table_.extract_by_iterator(position), table_.node_alloc()); + table_.extract_by_iterator_unique(position), table_.node_alloc()); } node_type extract(const key_type& k) @@ -435,13 +435,13 @@ template class unordered_map insert_return_type insert(BOOST_RV_REF(node_type) np) { insert_return_type result; - table_.move_insert_node_type(np, result); + table_.move_insert_node_type_unique(np, result); return boost::move(result); } iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np) { - return table_.move_insert_node_type_with_hint(hint, np); + return table_.move_insert_node_type_with_hint_unique(hint, np); } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -459,14 +459,14 @@ template class unordered_map std::pair try_emplace( key_type const& k, BOOST_FWD_REF(Args)... args) { - return table_.try_emplace_impl(k, boost::forward(args)...); + return table_.try_emplace_unique(k, boost::forward(args)...); } template iterator try_emplace( const_iterator hint, key_type const& k, BOOST_FWD_REF(Args)... args) { - return table_.try_emplace_hint_impl( + return table_.try_emplace_hint_unique( hint, k, boost::forward(args)...); } @@ -474,7 +474,7 @@ template class unordered_map std::pair try_emplace( BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) { - return table_.try_emplace_impl( + return table_.try_emplace_unique( boost::move(k), boost::forward(args)...); } @@ -482,7 +482,7 @@ template class unordered_map iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) { - return table_.try_emplace_hint_impl( + return table_.try_emplace_hint_unique( hint, boost::move(k), boost::forward(args)...); } @@ -491,20 +491,20 @@ template class unordered_map template std::pair try_emplace(BOOST_FWD_REF(Key) k) { - return table_.try_emplace_impl(boost::forward(k)); + return table_.try_emplace_unique(boost::forward(k)); } template iterator try_emplace(const_iterator hint, BOOST_FWD_REF(Key) k) { - return table_.try_emplace_hint_impl(hint, boost::forward(k)); + return table_.try_emplace_hint_unique(hint, boost::forward(k)); } template std::pair try_emplace( key_type const& k, BOOST_FWD_REF(A0) a0) { - return table_.try_emplace_impl( + return table_.try_emplace_unique( k, boost::unordered::detail::create_emplace_args( boost::forward(a0))); } @@ -513,7 +513,7 @@ template class unordered_map iterator try_emplace( const_iterator hint, key_type const& k, BOOST_FWD_REF(A0) a0) { - return table_.try_emplace_hint_impl( + return table_.try_emplace_hint_unique( hint, k, boost::unordered::detail::create_emplace_args( boost::forward(a0))); } @@ -522,7 +522,7 @@ template class unordered_map std::pair try_emplace( BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) { - return table_.try_emplace_impl( + return table_.try_emplace_hint_unique( boost::move(k), boost::unordered::detail::create_emplace_args( boost::forward(a0))); } @@ -531,7 +531,7 @@ template class unordered_map iterator try_emplace( const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) { - return table_.try_emplace_hint_impl( + return table_.try_emplace_hint_unique( hint, boost::move(k), boost::unordered::detail::create_emplace_args( boost::forward(a0))); } @@ -540,7 +540,7 @@ template class unordered_map std::pair try_emplace( key_type const& k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.try_emplace_impl( + return table_.try_emplace_unique( k, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1))); } @@ -549,7 +549,7 @@ template class unordered_map iterator try_emplace(const_iterator hint, key_type const& k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.try_emplace_hint_impl( + return table_.try_emplace_hint_unique( hint, k, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1))); } @@ -558,7 +558,7 @@ template class unordered_map std::pair try_emplace( BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.try_emplace_impl( + return table_.try_emplace_unique( boost::move(k), boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1))); @@ -568,7 +568,7 @@ template class unordered_map iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.try_emplace_hint_impl( + return table_.try_emplace_hint_unique( hint, boost::move(k), boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1))); @@ -578,7 +578,7 @@ template class unordered_map std::pair try_emplace(key_type const& k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.try_emplace_impl( + return table_.try_emplace_unique( k, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1), boost::forward(a2))); @@ -589,7 +589,7 @@ template class unordered_map BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { return table_ - .try_emplace_impl_( + .try_emplace_unique( hint, k, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1), boost::forward(a2))) @@ -600,7 +600,7 @@ template class unordered_map std::pair try_emplace(BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.try_emplace_impl( + return table_.try_emplace_unique( boost::move(k), boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1), boost::forward(a2))); @@ -610,7 +610,7 @@ template class unordered_map iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.try_emplace_hint_impl( + return table_.try_emplace_hint_unique( hint, boost::move(k), boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1), @@ -623,7 +623,7 @@ template class unordered_map std::pair try_emplace( \ key_type const& k, BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.try_emplace_impl( \ + return table_.try_emplace_unique( \ k, boost::unordered::detail::create_emplace_args( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } \ @@ -632,7 +632,7 @@ template class unordered_map iterator try_emplace(const_iterator hint, key_type const& k, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.try_emplace_hint_impl(hint, k, \ + return table_.try_emplace_hint_unique(hint, k, \ boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } \ @@ -641,7 +641,7 @@ template class unordered_map std::pair try_emplace(BOOST_RV_REF(key_type) k, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.try_emplace_impl(boost::move(k), \ + return table_.try_emplace_unique(boost::move(k), \ boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } \ @@ -650,7 +650,7 @@ template class unordered_map iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.try_emplace_hint_impl(hint, boost::move(k), \ + return table_.try_emplace_hint_unique(hint, boost::move(k), \ boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } @@ -666,14 +666,14 @@ template class unordered_map std::pair insert_or_assign( key_type const& k, BOOST_FWD_REF(M) obj) { - return table_.insert_or_assign_impl(k, boost::forward(obj)); + return table_.insert_or_assign_unique(k, boost::forward(obj)); } template std::pair insert_or_assign( BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) { - return table_.insert_or_assign_impl( + return table_.insert_or_assign_unique( boost::move(k), boost::forward(obj)); } @@ -681,7 +681,7 @@ template class unordered_map iterator insert_or_assign( const_iterator, key_type const& k, BOOST_FWD_REF(M) obj) { - return table_.insert_or_assign_impl(k, boost::forward(obj)).first; + return table_.insert_or_assign_unique(k, boost::forward(obj)).first; } template @@ -689,7 +689,7 @@ template class unordered_map const_iterator, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) { return table_ - .insert_or_assign_impl(boost::move(k), boost::forward(obj)) + .insert_or_assign_unique(boost::move(k), boost::forward(obj)) .first; } @@ -1004,7 +1004,7 @@ template class unordered_multimap template iterator emplace(BOOST_FWD_REF(Args)... args) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::forward(args)...))); } @@ -1028,7 +1028,7 @@ template class unordered_multimap template iterator emplace(BOOST_FWD_REF(A0) a0) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -1038,7 +1038,7 @@ template class unordered_multimap template iterator emplace(BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -1049,7 +1049,7 @@ template class unordered_multimap iterator emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -1064,7 +1064,7 @@ template class unordered_multimap template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::forward(args)...))); } @@ -1086,7 +1086,7 @@ template class unordered_multimap template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -1097,7 +1097,7 @@ template class unordered_multimap iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -1108,7 +1108,7 @@ template class unordered_multimap iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -1124,7 +1124,7 @@ template class unordered_multimap template \ iterator emplace(BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return iterator(table_.emplace_impl( \ + return iterator(table_.emplace_equiv( \ boost::unordered::detail::func::construct_node_from_args( \ table_.node_alloc(), \ boost::unordered::detail::create_emplace_args( \ @@ -1135,7 +1135,7 @@ template class unordered_multimap iterator emplace_hint(const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return iterator(table_.emplace_hint_impl( \ + return iterator(table_.emplace_hint_equiv( \ hint, \ boost::unordered::detail::func::construct_node_from_args( \ table_.node_alloc(), \ @@ -1202,7 +1202,7 @@ template class unordered_multimap node_type extract(const_iterator position) { return node_type( - table_.extract_by_iterator(position), table_.node_alloc()); + table_.extract_by_iterator_equiv(position), table_.node_alloc()); } node_type extract(const key_type& k) @@ -1212,12 +1212,12 @@ template class unordered_multimap iterator insert(BOOST_RV_REF(node_type) np) { - return table_.move_insert_node_type(np); + return table_.move_insert_node_type_equiv(np); } iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np) { - return table_.move_insert_node_type_with_hint(hint, np); + return table_.move_insert_node_type_with_hint_equiv(hint, np); } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -1515,7 +1515,7 @@ template void unordered_map::insert(InputIt first, InputIt last) { if (first != last) { - table_.insert_range_impl( + table_.insert_range_unique( table::extractor::extract(*first), first, last); } } @@ -1536,7 +1536,7 @@ unordered_map::erase(iterator position) node_pointer node = table::get_node(position); BOOST_ASSERT(node); node_pointer next = table::node_algo::next_node(node); - table_.erase_nodes(node, next); + table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1547,7 +1547,7 @@ unordered_map::erase(const_iterator position) node_pointer node = table::get_node(position); BOOST_ASSERT(node); node_pointer next = table::node_algo::next_node(node); - table_.erase_nodes(node, next); + table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1555,7 +1555,7 @@ template typename unordered_map::size_type unordered_map::erase(const key_type& k) { - return table_.erase_key(k); + return table_.erase_key_unique(k); } template @@ -1565,7 +1565,7 @@ unordered_map::erase(const_iterator first, const_iterator last) node_pointer last_node = table::get_node(last); if (first == last) return iterator(last_node); - table_.erase_nodes(table::get_node(first), last_node); + table_.erase_nodes_unique(table::get_node(first), last_node); return iterator(last_node); } @@ -1593,7 +1593,7 @@ template void unordered_map::merge( boost::unordered_map& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -1602,7 +1602,7 @@ template void unordered_map::merge( boost::unordered_map&& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #endif @@ -1612,7 +1612,7 @@ template void unordered_map::merge( boost::unordered_multimap& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -1621,7 +1621,7 @@ template void unordered_map::merge( boost::unordered_multimap&& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #endif #endif @@ -1709,14 +1709,14 @@ template typename unordered_map::mapped_type& unordered_map::operator[](const key_type& k) { - return table_.try_emplace_impl(k).first->second; + return table_.try_emplace_unique(k).first->second; } template typename unordered_map::mapped_type& unordered_map::operator[](BOOST_RV_REF(key_type) k) { - return table_.try_emplace_impl(boost::move(k)).first->second; + return table_.try_emplace_unique(boost::move(k)).first->second; } template @@ -1793,7 +1793,7 @@ inline bool operator==(unordered_map const& m1, unordered_map x; }; #endif - return m1.table_.equals(m2.table_); + return m1.table_.equals_unique(m2.table_); } template @@ -1806,7 +1806,7 @@ inline bool operator!=(unordered_map const& m1, unordered_map x; }; #endif - return !m1.table_.equals(m2.table_); + return !m1.table_.equals_unique(m2.table_); } template @@ -1990,7 +1990,7 @@ template template void unordered_multimap::insert(InputIt first, InputIt last) { - table_.insert_range(first, last); + table_.insert_range_equiv(first, last); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -2009,7 +2009,7 @@ unordered_multimap::erase(iterator position) node_pointer node = table::get_node(position); BOOST_ASSERT(node); node_pointer next = table::node_algo::next_node(node); - table_.erase_nodes(node, next); + table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -2020,7 +2020,7 @@ unordered_multimap::erase(const_iterator position) node_pointer node = table::get_node(position); BOOST_ASSERT(node); node_pointer next = table::node_algo::next_node(node); - table_.erase_nodes(node, next); + table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -2028,7 +2028,7 @@ template typename unordered_multimap::size_type unordered_multimap::erase(const key_type& k) { - return table_.erase_key(k); + return table_.erase_key_equiv(k); } template @@ -2039,7 +2039,7 @@ unordered_multimap::erase( node_pointer last_node = table::get_node(last); if (first == last) return iterator(last_node); - table_.erase_nodes(table::get_node(first), last_node); + table_.erase_nodes_equiv(table::get_node(first), last_node); return iterator(last_node); } @@ -2234,7 +2234,7 @@ inline bool operator==(unordered_multimap const& m1, unordered_multimap x; }; #endif - return m1.table_.equals(m2.table_); + return m1.table_.equals_equiv(m2.table_); } template @@ -2247,7 +2247,7 @@ inline bool operator!=(unordered_multimap const& m1, unordered_multimap x; }; #endif - return !m1.table_.equals(m2.table_); + return !m1.table_.equals_equiv(m2.table_); } template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 7bb86954..f6165b10 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -220,7 +220,7 @@ template class unordered_set template std::pair emplace(BOOST_FWD_REF(Args)... args) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract(boost::forward(args)...), boost::forward(args)...); } @@ -246,7 +246,7 @@ template class unordered_set template std::pair emplace(BOOST_FWD_REF(A0) a0) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract(boost::forward(a0)), boost::unordered::detail::create_emplace_args( boost::forward(a0))); @@ -256,7 +256,7 @@ template class unordered_set std::pair emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -267,7 +267,7 @@ template class unordered_set std::pair emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -282,7 +282,7 @@ template class unordered_set template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return table_.emplace_hint_impl(hint, + return table_.emplace_hint_unique(hint, table::extractor::extract(boost::forward(args)...), boost::forward(args)...); } @@ -304,17 +304,17 @@ template class unordered_set template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return table_.emplace_hint_impl(hint, + return table_.emplace_hint_unique(hint, table::extractor::extract(boost::forward(a0)), boost::unordered::detail::create_emplace_args( - boost::forward(a0))); + boost::forward(a0))); } template iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace_hint_impl( + return table_.emplace_hint_unique( hint, table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -325,7 +325,7 @@ template class unordered_set iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace_hint_impl( + return table_.emplace_hint_unique( hint, table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -342,7 +342,7 @@ template class unordered_set std::pair emplace( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace_impl( \ + return table_.emplace_unique( \ table::extractor::extract( \ boost::forward(a0), boost::forward(a1)), \ boost::unordered::detail::create_emplace_args( \ @@ -353,7 +353,7 @@ template class unordered_set iterator emplace_hint(const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace_hint_impl( \ + return table_.emplace_hint_unique( \ hint, table::extractor::extract( \ boost::forward(a0), boost::forward(a1)), \ boost::unordered::detail::create_emplace_args( \ @@ -404,7 +404,7 @@ template class unordered_set node_type extract(const_iterator position) { return node_type( - table_.extract_by_iterator(position), table_.node_alloc()); + table_.extract_by_iterator_unique(position), table_.node_alloc()); } node_type extract(const key_type& k) @@ -415,13 +415,13 @@ template class unordered_set insert_return_type insert(BOOST_RV_REF(node_type) np) { insert_return_type result; - table_.move_insert_node_type(np, result); + table_.move_insert_node_type_unique(np, result); return boost::move(result); } iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np) { - return table_.move_insert_node_type_with_hint(hint, np); + return table_.move_insert_node_type_with_hint_unique(hint, np); } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -730,7 +730,7 @@ template class unordered_multiset template iterator emplace(BOOST_FWD_REF(Args)... args) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::forward(args)...))); } @@ -754,7 +754,7 @@ template class unordered_multiset template iterator emplace(BOOST_FWD_REF(A0) a0) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -764,7 +764,7 @@ template class unordered_multiset template iterator emplace(BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -775,7 +775,7 @@ template class unordered_multiset iterator emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -790,7 +790,7 @@ template class unordered_multiset template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::forward(args)...))); } @@ -812,7 +812,7 @@ template class unordered_multiset template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -823,7 +823,7 @@ template class unordered_multiset iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -834,7 +834,7 @@ template class unordered_multiset iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -850,7 +850,7 @@ template class unordered_multiset template \ iterator emplace(BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return iterator(table_.emplace_impl( \ + return iterator(table_.emplace_equiv( \ boost::unordered::detail::func::construct_node_from_args( \ table_.node_alloc(), \ boost::unordered::detail::create_emplace_args( \ @@ -861,7 +861,7 @@ template class unordered_multiset iterator emplace_hint(const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return iterator(table_.emplace_hint_impl( \ + return iterator(table_.emplace_hint_equiv( \ hint, \ boost::unordered::detail::func::construct_node_from_args( \ table_.node_alloc(), \ @@ -910,7 +910,7 @@ template class unordered_multiset node_type extract(const_iterator position) { return node_type( - table_.extract_by_iterator(position), table_.node_alloc()); + table_.extract_by_iterator_equiv(position), table_.node_alloc()); } node_type extract(const key_type& k) @@ -920,12 +920,12 @@ template class unordered_multiset iterator insert(BOOST_RV_REF(node_type) np) { - return table_.move_insert_node_type(np); + return table_.move_insert_node_type_equiv(np); } iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np) { - return table_.move_insert_node_type_with_hint(hint, np); + return table_.move_insert_node_type_with_hint_equiv(hint, np); } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -1211,7 +1211,7 @@ template void unordered_set::insert(InputIt first, InputIt last) { if (first != last) { - table_.insert_range_impl( + table_.insert_range_unique( table::extractor::extract(*first), first, last); } } @@ -1231,7 +1231,7 @@ typename unordered_set::iterator unordered_set::erase( node_pointer node = table::get_node(position); BOOST_ASSERT(node); node_pointer next = table::node_algo::next_node(node); - table_.erase_nodes(node, next); + table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1239,7 +1239,7 @@ template typename unordered_set::size_type unordered_set::erase( const key_type& k) { - return table_.erase_key(k); + return table_.erase_key_unique(k); } template @@ -1249,7 +1249,7 @@ typename unordered_set::iterator unordered_set::erase( node_pointer last_node = table::get_node(last); if (first == last) return iterator(last_node); - table_.erase_nodes(table::get_node(first), last_node); + table_.erase_nodes_unique(table::get_node(first), last_node); return iterator(last_node); } @@ -1293,7 +1293,7 @@ template void unordered_set::merge( boost::unordered_set& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -1302,7 +1302,7 @@ template void unordered_set::merge( boost::unordered_set&& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #endif @@ -1312,7 +1312,7 @@ template void unordered_set::merge( boost::unordered_multiset& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -1321,7 +1321,7 @@ template void unordered_set::merge( boost::unordered_multiset&& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #endif #endif @@ -1408,7 +1408,7 @@ inline bool operator==( unordered_set x; }; #endif - return m1.table_.equals(m2.table_); + return m1.table_.equals_unique(m2.table_); } template @@ -1421,7 +1421,7 @@ inline bool operator!=( unordered_set x; }; #endif - return !m1.table_.equals(m2.table_); + return !m1.table_.equals_unique(m2.table_); } template @@ -1604,7 +1604,7 @@ template template void unordered_multiset::insert(InputIt first, InputIt last) { - table_.insert_range(first, last); + table_.insert_range_equiv(first, last); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1623,7 +1623,7 @@ unordered_multiset::erase(const_iterator position) node_pointer node = table::get_node(position); BOOST_ASSERT(node); node_pointer next = table::node_algo::next_node(node); - table_.erase_nodes(node, next); + table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -1631,7 +1631,7 @@ template typename unordered_multiset::size_type unordered_multiset::erase(const key_type& k) { - return table_.erase_key(k); + return table_.erase_key_equiv(k); } template @@ -1641,7 +1641,7 @@ unordered_multiset::erase(const_iterator first, const_iterator last) node_pointer last_node = table::get_node(last); if (first == last) return iterator(last_node); - table_.erase_nodes(table::get_node(first), last_node); + table_.erase_nodes_equiv(table::get_node(first), last_node); return iterator(last_node); } @@ -1809,7 +1809,7 @@ inline bool operator==(unordered_multiset const& m1, unordered_multiset x; }; #endif - return m1.table_.equals(m2.table_); + return m1.table_.equals_equiv(m2.table_); } template @@ -1822,7 +1822,7 @@ inline bool operator!=(unordered_multiset const& m1, unordered_multiset x; }; #endif - return !m1.table_.equals(m2.table_); + return !m1.table_.equals_equiv(m2.table_); } template From 84f1ef6d2d76674910e31c9367dcf5b274c82536 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 24 Apr 2017 09:46:05 +0100 Subject: [PATCH 072/147] Move constructor implementation into containers --- .../boost/unordered/detail/implementation.hpp | 30 +------------------ include/boost/unordered/unordered_map.hpp | 26 ++++++++++++++++ include/boost/unordered/unordered_set.hpp | 26 ++++++++++++++++ 3 files changed, 53 insertions(+), 29 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index d45a11a4..8e723f13 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3729,34 +3729,21 @@ struct table_unique : boost::unordered::detail::table : table(x, node_allocator_traits::select_on_container_copy_construction( x.node_alloc())) { - if (x.size_) { - this->copy_buckets(x); - } } table_unique(table_unique const& x, node_allocator const& a) : table(x, a) { - if (x.size_) { - this->copy_buckets(x); - } } table_unique(table_unique& x, boost::unordered::detail::move_tag m) : table(x, m) { - // The move is done in the base class. } table_unique(table_unique& x, node_allocator const& a, boost::unordered::detail::move_tag m) : table(x, a, m) { - if (this->node_alloc() == x.node_alloc()) { - this->move_buckets_from(x); - } else if (x.size_) { - // TODO: Could pick new bucket size? - this->move_buckets(x); - } } // equals @@ -4438,34 +4425,19 @@ struct table_equiv : boost::unordered::detail::table : table(x, node_allocator_traits::select_on_container_copy_construction( x.node_alloc())) { - if (x.size_) { - copy_buckets(x); - } } - table_equiv(table_equiv const& x, node_allocator const& a) : table(x, a) - { - if (x.size_) { - copy_buckets(x); - } - } + table_equiv(table_equiv const& x, node_allocator const& a) : table(x, a) {} table_equiv(table_equiv& x, boost::unordered::detail::move_tag m) : table(x, m) { - // The move is done in the base class. } table_equiv(table_equiv& x, node_allocator const& a, boost::unordered::detail::move_tag m) : table(x, a, m) { - if (this->node_alloc() == x.node_alloc()) { - this->move_buckets_from(x); - } else if (x.size_) { - // TODO: Could pick new bucket size? - this->move_buckets_equiv(x); - } } // Equality diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 85f1c134..4188a594 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -101,6 +101,7 @@ template class unordered_map BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { + // The move is done in table_ } #endif @@ -883,6 +884,7 @@ template class unordered_multimap BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { + // The move is done in table_ } #endif @@ -1378,6 +1380,9 @@ template unordered_map::unordered_map(unordered_map const& other) : table_(other.table_) { + if (other.table_.size_) { + table_.copy_buckets(other.table_); + } } template @@ -1392,6 +1397,9 @@ unordered_map::unordered_map( unordered_map const& other, allocator_type const& a) : table_(other.table_, a) { + if (other.table_.size_) { + table_.copy_buckets(other.table_); + } } template @@ -1399,6 +1407,12 @@ unordered_map::unordered_map( BOOST_RV_REF(unordered_map) other, allocator_type const& a) : table_(other.table_, a, boost::unordered::detail::move_tag()) { + if (table_.node_alloc() == other.table_.node_alloc()) { + table_.move_buckets_from(other.table_); + } else if (other.table_.size_) { + // TODO: Could pick new bucket size? + table_.move_buckets(other.table_); + } } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1854,6 +1868,9 @@ unordered_multimap::unordered_multimap( unordered_multimap const& other) : table_(other.table_) { + if (other.table_.size_) { + table_.copy_buckets(other.table_); + } } template @@ -1868,6 +1885,9 @@ unordered_multimap::unordered_multimap( unordered_multimap const& other, allocator_type const& a) : table_(other.table_, a) { + if (other.table_.size_) { + table_.copy_buckets(other.table_); + } } template @@ -1875,6 +1895,12 @@ unordered_multimap::unordered_multimap( BOOST_RV_REF(unordered_multimap) other, allocator_type const& a) : table_(other.table_, a, boost::unordered::detail::move_tag()) { + if (table_.node_alloc() == other.table_.node_alloc()) { + table_.move_buckets_from(other.table_); + } else if (other.table_.size()) { + // TODO: Could pick new bucket size? + table_.move_buckets_equiv(other.table_); + } } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index f6165b10..6ef28460 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -99,6 +99,7 @@ template class unordered_set BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { + // The move is done in table_ } #endif @@ -609,6 +610,7 @@ template class unordered_multiset BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { + // The move is done in table_ } #endif @@ -1077,6 +1079,9 @@ template unordered_set::unordered_set(unordered_set const& other) : table_(other.table_) { + if (other.table_.size_) { + table_.copy_buckets(other.table_); + } } template @@ -1091,6 +1096,9 @@ unordered_set::unordered_set( unordered_set const& other, allocator_type const& a) : table_(other.table_, a) { + if (other.table_.size_) { + table_.copy_buckets(other.table_); + } } template @@ -1098,6 +1106,12 @@ unordered_set::unordered_set( BOOST_RV_REF(unordered_set) other, allocator_type const& a) : table_(other.table_, a, boost::unordered::detail::move_tag()) { + if (table_.node_alloc() == other.table_.node_alloc()) { + table_.move_buckets_from(other.table_); + } else if (other.table_.size_) { + // TODO: Could pick new bucket size? + table_.move_buckets(other.table_); + } } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1468,6 +1482,9 @@ unordered_multiset::unordered_multiset( unordered_multiset const& other) : table_(other.table_) { + if (other.table_.size_) { + table_.copy_buckets(other.table_); + } } template @@ -1482,6 +1499,9 @@ unordered_multiset::unordered_multiset( unordered_multiset const& other, allocator_type const& a) : table_(other.table_, a) { + if (other.table_.size_) { + table_.copy_buckets(other.table_); + } } template @@ -1489,6 +1509,12 @@ unordered_multiset::unordered_multiset( BOOST_RV_REF(unordered_multiset) other, allocator_type const& a) : table_(other.table_, a, boost::unordered::detail::move_tag()) { + if (table_.node_alloc() == other.table_.node_alloc()) { + table_.move_buckets_from(other.table_); + } else if (other.table_.size()) { + // TODO: Could pick new bucket size? + table_.move_buckets_equiv(other.table_); + } } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) From e5181201041564c3de5281c35388fe10a9c921a6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 24 Apr 2017 09:46:05 +0100 Subject: [PATCH 073/147] Rename some copy/assign/move methods But with a hack so that the static casts will work until there's a better method. --- .../boost/unordered/detail/implementation.hpp | 42 ++++++++++++++++--- include/boost/unordered/unordered_map.hpp | 8 ++-- include/boost/unordered/unordered_set.hpp | 8 ++-- 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 8e723f13..662af550 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -4146,7 +4146,12 @@ struct table_unique : boost::unordered::detail::table //////////////////////////////////////////////////////////////////////// // fill_buckets_unique - void copy_buckets(table const& src) + BOOST_FORCEINLINE void copy_buckets(table const& src) + { + this->copy_buckets_unique(src); + } + + void copy_buckets_unique(table const& src) { this->create_buckets(this->bucket_count_); @@ -4170,7 +4175,12 @@ struct table_unique : boost::unordered::detail::table } } - void assign_buckets(table const& src) + BOOST_FORCEINLINE void assign_buckets(table const& src) + { + this->assign_buckets_unique(src); + } + + void assign_buckets_unique(table const& src) { node_holder holder(*this); for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { @@ -4178,7 +4188,12 @@ struct table_unique : boost::unordered::detail::table } } - void move_assign_buckets(table& src) + BOOST_FORCEINLINE void move_assign_buckets(table const& src) + { + this->move_assign_buckets_unique(src); + } + + void move_assign_buckets_unique(table& src) { node_holder holder(*this); for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { @@ -4788,7 +4803,12 @@ struct table_equiv : boost::unordered::detail::table //////////////////////////////////////////////////////////////////////// // fill_buckets - void copy_buckets(table const& src) + BOOST_FORCEINLINE void copy_buckets(table const& src) + { + this->copy_buckets_equiv(src); + } + + void copy_buckets_equiv(table const& src) { this->create_buckets(this->bucket_count_); @@ -4830,7 +4850,12 @@ struct table_equiv : boost::unordered::detail::table } } - void assign_buckets(table const& src) + BOOST_FORCEINLINE void assign_buckets(table const& src) + { + this->assign_buckets_equiv(src); + } + + void assign_buckets_equiv(table const& src) { node_holder holder(*this); for (node_pointer n = src.begin(); n;) { @@ -4845,7 +4870,12 @@ struct table_equiv : boost::unordered::detail::table } } - void move_assign_buckets(table& src) + BOOST_FORCEINLINE void move_assign_buckets(table const& src) + { + this->move_assign_buckets_equiv(src); + } + + void move_assign_buckets_equiv(table& src) { node_holder holder(*this); for (node_pointer n = src.begin(); n;) { diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 4188a594..7972cc89 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1381,7 +1381,7 @@ unordered_map::unordered_map(unordered_map const& other) : table_(other.table_) { if (other.table_.size_) { - table_.copy_buckets(other.table_); + table_.copy_buckets_unique(other.table_); } } @@ -1398,7 +1398,7 @@ unordered_map::unordered_map( : table_(other.table_, a) { if (other.table_.size_) { - table_.copy_buckets(other.table_); + table_.copy_buckets_unique(other.table_); } } @@ -1869,7 +1869,7 @@ unordered_multimap::unordered_multimap( : table_(other.table_) { if (other.table_.size_) { - table_.copy_buckets(other.table_); + table_.copy_buckets_equiv(other.table_); } } @@ -1886,7 +1886,7 @@ unordered_multimap::unordered_multimap( : table_(other.table_, a) { if (other.table_.size_) { - table_.copy_buckets(other.table_); + table_.copy_buckets_equiv(other.table_); } } diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 6ef28460..273975ab 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1080,7 +1080,7 @@ unordered_set::unordered_set(unordered_set const& other) : table_(other.table_) { if (other.table_.size_) { - table_.copy_buckets(other.table_); + table_.copy_buckets_unique(other.table_); } } @@ -1097,7 +1097,7 @@ unordered_set::unordered_set( : table_(other.table_, a) { if (other.table_.size_) { - table_.copy_buckets(other.table_); + table_.copy_buckets_unique(other.table_); } } @@ -1483,7 +1483,7 @@ unordered_multiset::unordered_multiset( : table_(other.table_) { if (other.table_.size_) { - table_.copy_buckets(other.table_); + table_.copy_buckets_equiv(other.table_); } } @@ -1500,7 +1500,7 @@ unordered_multiset::unordered_multiset( : table_(other.table_, a) { if (other.table_.size_) { - table_.copy_buckets(other.table_); + table_.copy_buckets_equiv(other.table_); } } From b070bb5e49a30824a39afe5a820ca82084e595e6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 24 Apr 2017 09:46:05 +0100 Subject: [PATCH 074/147] Move everything from table_unique/table_equiv into table --- .../boost/unordered/detail/implementation.hpp | 1361 ++++++++--------- include/boost/unordered/detail/map.hpp | 12 +- include/boost/unordered/detail/set.hpp | 12 +- include/boost/unordered/unordered_map.hpp | 15 +- include/boost/unordered/unordered_set.hpp | 15 +- test/unordered/incomplete_test.cpp | 5 + 6 files changed, 663 insertions(+), 757 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 662af550..25a7e615 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -185,9 +185,6 @@ template struct table; template struct bucket; struct ptr_bucket; -template struct table_unique; -template struct table_equiv; - template struct unique_node; template struct ptr_node; template struct node_algo; @@ -198,13 +195,21 @@ template struct grouped_node_algo; static const float minimum_max_load_factor = 1e-3f; static const std::size_t default_bucket_count = 11; + struct move_tag { }; + struct empty_emplace { }; +struct no_key +{ + no_key() {} + template no_key(T const&) {} +}; + namespace func { template inline void ignore_unused_variable_warning(T const&) {} } @@ -2041,8 +2046,6 @@ struct iterator : public std::iterator friend struct boost::unordered::iterator_detail::c_iterator; template friend struct boost::unordered::detail::table; - template friend struct boost::unordered::detail::table_unique; - template friend struct boost::unordered::detail::table_equiv; private: #endif @@ -2097,8 +2100,6 @@ struct c_iterator #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template friend struct boost::unordered::detail::table; - template friend struct boost::unordered::detail::table_unique; - template friend struct boost::unordered::detail::table_equiv; private: #endif @@ -2694,6 +2695,8 @@ struct table : boost::unordered::detail::functions node_tmp; + typedef std::pair emplace_return; + //////////////////////////////////////////////////////////////////////// // Members @@ -3116,7 +3119,12 @@ struct table : boost::unordered::detail::functions(this)->assign_buckets(x); + + if (Types::is_unique) { + assign_buckets_unique(x); + } else { + assign_buckets_equiv(x); + } } void assign(table const& x, true_type) @@ -3140,7 +3148,11 @@ struct table : boost::unordered::detail::functions(this)->copy_buckets(x); + if (Types::is_unique) { + copy_buckets_unique(x); + } else { + copy_buckets_equiv(x); + } } } } @@ -3194,7 +3206,12 @@ struct table : boost::unordered::detail::functions(this)->move_assign_buckets(x); + + if (Types::is_unique) { + move_assign_buckets_unique(x); + } else { + move_assign_buckets_equiv(x); + } } } @@ -3298,453 +3315,9 @@ struct table : boost::unordered::detail::functions -inline void table::reserve_for_insert(std::size_t size) -{ - if (!buckets_) { - create_buckets((std::max)(bucket_count_, min_buckets_for_size(size))); - } else if (size > max_load_) { - std::size_t num_buckets = - min_buckets_for_size((std::max)(size, size_ + (size_ >> 1))); - - if (num_buckets != bucket_count_) - this->rehash_impl(num_buckets); - } -} - -// if hash function throws, basic exception safety -// strong otherwise. - -template -inline void table::rehash(std::size_t min_buckets) -{ - using namespace std; - - if (!size_) { - delete_buckets(); - bucket_count_ = policy::new_bucket_count(min_buckets); - } else { - min_buckets = policy::new_bucket_count((std::max)(min_buckets, - boost::unordered::detail::double_to_size( - floor(static_cast(size_) / static_cast(mlf_))) + - 1)); - - if (min_buckets != bucket_count_) - this->rehash_impl(min_buckets); - } -} - -template -inline void table::rehash_impl(std::size_t num_buckets) -{ - BOOST_ASSERT(this->buckets_); - - this->create_buckets(num_buckets); - link_pointer prev = this->get_previous_start(); - while (prev->next_) { - node_pointer group_last = node_algo::last_for_rehash(prev); - bucket_pointer b = - this->get_bucket(this->hash_to_bucket(group_last->hash_)); - if (!b->next_) { - b->next_ = prev; - prev = group_last; - } else { - link_pointer next = group_last->next_; - group_last->next_ = b->next_->next_; - b->next_->next_ = prev->next_; - prev->next_ = next; - } - } -} - -#if defined(BOOST_MSVC) -#pragma warning(pop) -#endif - -//////////////////////////////////////////////////////////////////////// -// key extractors -// -// no throw -// -// 'extract_key' is called with the emplace parameters to return a -// key if available or 'no_key' is one isn't and will need to be -// constructed. This could be done by overloading the emplace implementation -// for the different cases, but that's a bit tricky on compilers without -// variadic templates. - -struct no_key -{ - no_key() {} - template no_key(T const&) {} -}; - -template struct is_key -{ - template static choice1::type test(T2 const&); - static choice2::type test(Key const&); - - enum - { - value = sizeof(test(boost::unordered::detail::make())) == - sizeof(choice2::type) - }; - - typedef typename boost::detail::if_true::BOOST_NESTED_TEMPLATE - then::type type; -}; - -template struct set_extractor -{ - typedef ValueType value_type; - typedef ValueType key_type; - - static key_type const& extract(value_type const& v) { return v; } - - static no_key extract() { return no_key(); } - - template static no_key extract(Arg const&) { return no_key(); } - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template - static no_key extract(Arg1 const&, Arg2 const&, Args const&...) - { - return no_key(); - } -#else - template - static no_key extract(Arg1 const&, Arg2 const&) - { - return no_key(); - } -#endif -}; - -template struct map_extractor -{ - typedef ValueType value_type; - typedef typename boost::remove_const::first_type>::type key_type; - - static key_type const& extract(value_type const& v) { return v.first; } - - template - static key_type const& extract(std::pair const& v) - { - return v.first; - } - - template - static key_type const& extract(std::pair const& v) - { - return v.first; - } - - template - static key_type const& extract(key_type const& k, Arg1 const&) - { - return k; - } - - static no_key extract() { return no_key(); } - - template static no_key extract(Arg const&) { return no_key(); } - - template - static no_key extract(Arg1 const&, Arg2 const&) - { - return no_key(); - } - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template - static no_key extract(Arg1 const&, Arg2 const&, Arg3 const&, Args const&...) - { - return no_key(); - } -#endif - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - -#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \ - template \ - static no_key extract(boost::unordered::piecewise_construct_t, \ - namespace_ tuple<> const&, T2 const&) \ - { \ - return no_key(); \ - } \ - \ - template \ - static typename is_key::type extract( \ - boost::unordered::piecewise_construct_t, namespace_ tuple const& k, \ - T2 const&) \ - { \ - return typename is_key::type(namespace_ get<0>(k)); \ - } - -#else - -#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \ - static no_key extract( \ - boost::unordered::piecewise_construct_t, namespace_ tuple<> const&) \ - { \ - return no_key(); \ - } \ - \ - template \ - static typename is_key::type extract( \ - boost::unordered::piecewise_construct_t, namespace_ tuple const& k) \ - { \ - return typename is_key::type(namespace_ get<0>(k)); \ - } - -#endif - - BOOST_UNORDERED_KEY_FROM_TUPLE(boost::) - -#if BOOST_UNORDERED_TUPLE_ARGS - BOOST_UNORDERED_KEY_FROM_TUPLE(std::) -#endif -}; - -//////////////////////////////////////////////////////////////////////// -// Unique nodes - -template -struct unique_node : boost::unordered::detail::value_base -{ - typedef typename ::boost::unordered::detail::rebind_wrap >::type allocator; - typedef typename ::boost::unordered::detail::allocator_traits< - allocator>::pointer node_pointer; - typedef node_pointer link_pointer; - typedef typename ::boost::unordered::detail::rebind_wrap >::type bucket_allocator; - typedef typename ::boost::unordered::detail::allocator_traits< - bucket_allocator>::pointer bucket_pointer; - - link_pointer next_; - std::size_t hash_; - - unique_node() : next_(), hash_(0) {} - - void init(node_pointer) {} - - private: - unique_node& operator=(unique_node const&); -}; - -template struct ptr_node : boost::unordered::detail::ptr_bucket -{ - typedef T value_type; - typedef boost::unordered::detail::ptr_bucket bucket_base; - typedef ptr_node* node_pointer; - typedef ptr_bucket* link_pointer; - typedef ptr_bucket* bucket_pointer; - - std::size_t hash_; - boost::unordered::detail::value_base value_base_; - - ptr_node() : bucket_base(), hash_(0) {} - - void init(node_pointer) {} - - void* address() { return value_base_.address(); } - value_type& value() { return value_base_.value(); } - value_type* value_ptr() { return value_base_.value_ptr(); } - - private: - ptr_node& operator=(ptr_node const&); -}; - -template struct node_algo -{ - typedef typename N::node_pointer node_pointer; - typedef typename N::link_pointer link_pointer; - typedef typename N::bucket_pointer bucket_pointer; - - static node_pointer next_node(link_pointer n) - { - return static_cast(n->next_); - } - - static node_pointer next_for_find(node_pointer n) - { - return static_cast(n->next_); - } - - static link_pointer next_for_erase(link_pointer prev) - { - return prev->next_; - } - - // Group together all nodes with equal hash value, this may - // include nodes with different keys, but that's okay because - // they will end up in the same bucket. - static node_pointer last_for_rehash(link_pointer prev) - { - node_pointer n = next_node(prev); - std::size_t hash = n->hash_; - for (;;) { - node_pointer next = next_node(n); - if (!next || next->hash_ != hash) { - return n; - } - n = next; - } - } - - template - static node_pointer next_group(node_pointer n, Table const* t) - { - node_pointer n1 = n; - do { - n1 = next_node(n1); - } while (n1 && t->key_eq()(t->get_key(n), t->get_key(n1))); - return n1; - } - - template - static std::size_t count(node_pointer n, Table const* t) - { - std::size_t x = 0; - node_pointer it = n; - do { - ++x; - it = next_node(it); - } while (it && t->key_eq()(t->get_key(n), t->get_key(it))); - - return x; - } - - // Add node 'n' after 'pos'. - // This results in a different order to the grouped implementation. - static inline void add_to_node(node_pointer n, node_pointer pos) - { - n->next_ = pos->next_; - pos->next_ = n; - } - - static inline node_pointer extract_first_node(link_pointer prev) - { - node_pointer n = next_node(prev); - prev->next_ = n->next_; - return n; - } - - static link_pointer split_groups(node_pointer, node_pointer) - { - return link_pointer(); - } -}; - -// If the allocator uses raw pointers use ptr_node -// Otherwise use node. - -template -struct pick_node2 -{ - typedef boost::unordered::detail::unique_node node; - - typedef typename boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap::type>::pointer - node_pointer; - - typedef boost::unordered::detail::bucket bucket; - typedef node_pointer link_pointer; -}; - -template -struct pick_node2*, - boost::unordered::detail::ptr_bucket*> -{ - typedef boost::unordered::detail::ptr_node node; - typedef boost::unordered::detail::ptr_bucket bucket; - typedef bucket* link_pointer; -}; - -template struct pick_node -{ - typedef typename boost::remove_const::type nonconst; - - typedef boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap >::type> - tentative_node_traits; - - typedef boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap::type> - tentative_bucket_traits; - - typedef pick_node2 - pick; - - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - typedef boost::unordered::detail::node_algo node_algo; -}; - -template -struct table_unique : boost::unordered::detail::table -{ - typedef boost::unordered::detail::table table; - typedef typename table::value_type value_type; - typedef typename table::node node; - typedef typename table::bucket bucket; - typedef typename table::policy policy; - typedef typename table::node_pointer node_pointer; - typedef typename table::node_allocator node_allocator; - typedef typename table::node_allocator_traits node_allocator_traits; - typedef typename table::bucket_pointer bucket_pointer; - typedef typename table::link_pointer link_pointer; - typedef typename table::hasher hasher; - typedef typename table::key_equal key_equal; - typedef typename table::const_key_type const_key_type; - typedef typename table::node_constructor node_constructor; - typedef typename table::node_tmp node_tmp; - typedef typename table::extractor extractor; - typedef typename table::iterator iterator; - typedef typename table::c_iterator c_iterator; - typedef typename table::node_algo node_algo; - - typedef std::pair emplace_return; - - // Constructors - - table_unique(std::size_t n, hasher const& hf, key_equal const& eq, - node_allocator const& a) - : table(n, hf, eq, a) - { - } - - table_unique(table_unique const& x) - : table(x, node_allocator_traits::select_on_container_copy_construction( - x.node_alloc())) - { - } - - table_unique(table_unique const& x, node_allocator const& a) : table(x, a) - { - } - - table_unique(table_unique& x, boost::unordered::detail::move_tag m) - : table(x, m) - { - } - - table_unique(table_unique& x, node_allocator const& a, - boost::unordered::detail::move_tag m) - : table(x, a, m) - { - } + //////////////////////////////////////////////////////////////////////// + // Unique keys // equals @@ -4146,11 +3719,6 @@ struct table_unique : boost::unordered::detail::table //////////////////////////////////////////////////////////////////////// // fill_buckets_unique - BOOST_FORCEINLINE void copy_buckets(table const& src) - { - this->copy_buckets_unique(src); - } - void copy_buckets_unique(table const& src) { this->create_buckets(this->bucket_count_); @@ -4163,6 +3731,7 @@ struct table_unique : boost::unordered::detail::table } } + // TODO: Should be move_buckets_uniq void move_buckets(table const& src) { this->create_buckets(this->bucket_count_); @@ -4175,11 +3744,6 @@ struct table_unique : boost::unordered::detail::table } } - BOOST_FORCEINLINE void assign_buckets(table const& src) - { - this->assign_buckets_unique(src); - } - void assign_buckets_unique(table const& src) { node_holder holder(*this); @@ -4188,11 +3752,6 @@ struct table_unique : boost::unordered::detail::table } } - BOOST_FORCEINLINE void move_assign_buckets(table const& src) - { - this->move_assign_buckets_unique(src); - } - void move_assign_buckets_unique(table& src) { node_holder holder(*this); @@ -4200,260 +3759,9 @@ struct table_unique : boost::unordered::detail::table this->add_node_unique(holder.move_copy_of(n->value()), n->hash_); } } -}; -//////////////////////////////////////////////////////////////////////// -// Grouped nodes - -template -struct grouped_node : boost::unordered::detail::value_base -{ - typedef typename ::boost::unordered::detail::rebind_wrap >::type allocator; - typedef typename ::boost::unordered::detail::allocator_traits< - allocator>::pointer node_pointer; - typedef node_pointer link_pointer; - typedef typename ::boost::unordered::detail::rebind_wrap >::type bucket_allocator; - typedef typename ::boost::unordered::detail::allocator_traits< - bucket_allocator>::pointer bucket_pointer; - - link_pointer next_; - node_pointer group_prev_; - std::size_t hash_; - - grouped_node() : next_(), group_prev_(), hash_(0) {} - - void init(node_pointer self) { group_prev_ = self; } - - private: - grouped_node& operator=(grouped_node const&); -}; - -template -struct grouped_ptr_node : boost::unordered::detail::ptr_bucket -{ - typedef T value_type; - typedef boost::unordered::detail::ptr_bucket bucket_base; - typedef grouped_ptr_node* node_pointer; - typedef ptr_bucket* link_pointer; - typedef ptr_bucket* bucket_pointer; - - node_pointer group_prev_; - std::size_t hash_; - boost::unordered::detail::value_base value_base_; - - grouped_ptr_node() : bucket_base(), group_prev_(0), hash_(0) {} - - void init(node_pointer self) { group_prev_ = self; } - - void* address() { return value_base_.address(); } - value_type& value() { return value_base_.value(); } - value_type* value_ptr() { return value_base_.value_ptr(); } - - private: - grouped_ptr_node& operator=(grouped_ptr_node const&); -}; - -template struct grouped_node_algo -{ - typedef typename N::node_pointer node_pointer; - typedef typename N::link_pointer link_pointer; - typedef typename N::bucket_pointer bucket_pointer; - - static node_pointer next_node(link_pointer n) - { - return static_cast(n->next_); - } - - static node_pointer next_for_find(node_pointer n) - { - return static_cast(n->group_prev_->next_); - } - - static link_pointer next_for_erase(link_pointer prev) - { - return static_cast(prev->next_)->group_prev_; - } - - static node_pointer last_for_rehash(link_pointer prev) - { - return static_cast(prev->next_)->group_prev_; - } - - // The 'void*' arguments are pointers to the table, which we - // will ignore, but without groups they could be used to - // access the various functions for dealing with values and keys. - static node_pointer next_group(node_pointer n, void const*) - { - return static_cast(n->group_prev_->next_); - } - - static std::size_t count(node_pointer n, void const*) - { - std::size_t x = 0; - node_pointer it = n; - do { - it = it->group_prev_; - ++x; - } while (it != n); - - return x; - } - - // Adds node 'n' to the group containing 'pos'. - // If 'pos' is the first node in group, add to the end of the group, - // otherwise add before 'pos'. Other versions will probably behave - // differently. - static inline void add_to_node(node_pointer n, node_pointer pos) - { - n->next_ = pos->group_prev_->next_; - n->group_prev_ = pos->group_prev_; - pos->group_prev_->next_ = n; - pos->group_prev_ = n; - } - - static inline node_pointer extract_first_node(link_pointer prev) - { - node_pointer n = next_node(prev); - if (n->group_prev_ != n) { - node_pointer next = next_node(n); - next->group_prev_ = n->group_prev_; - n->group_prev_ = n; - } - prev->next_ = n->next_; - return n; - } - - // Split the groups containing 'i' and 'j' so that they can - // be safely erased/extracted. - static link_pointer split_groups(node_pointer i, node_pointer j) - { - node_pointer prev = i->group_prev_; - if (prev->next_ != i) - prev = node_pointer(); - - if (j) { - node_pointer first = j; - while (first != i && first->group_prev_->next_ == first) { - first = first->group_prev_; - } - - boost::swap(first->group_prev_, j->group_prev_); - if (first == i) - return prev; - } - - if (prev) { - node_pointer first = prev; - while (first->group_prev_->next_ == first) { - first = first->group_prev_; - } - boost::swap(first->group_prev_, i->group_prev_); - } - - return prev; - } -}; - -// If the allocator uses raw pointers use grouped_ptr_node -// Otherwise use grouped_node. - -template -struct pick_grouped_node2 -{ - typedef boost::unordered::detail::grouped_node node; - - typedef typename boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap::type>::pointer - node_pointer; - - typedef boost::unordered::detail::bucket bucket; - typedef node_pointer link_pointer; -}; - -template -struct pick_grouped_node2*, - boost::unordered::detail::ptr_bucket*> -{ - typedef boost::unordered::detail::grouped_ptr_node node; - typedef boost::unordered::detail::ptr_bucket bucket; - typedef bucket* link_pointer; -}; - -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> - tentative_node_traits; - - typedef boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap::type> - tentative_bucket_traits; - - typedef pick_grouped_node2 - pick; - - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - typedef boost::unordered::detail::grouped_node_algo node_algo; -}; - -template -struct table_equiv : boost::unordered::detail::table -{ - typedef boost::unordered::detail::table table; - typedef typename table::value_type value_type; - typedef typename table::bucket bucket; - typedef typename table::policy policy; - typedef typename table::node_pointer node_pointer; - typedef typename table::node_allocator node_allocator; - typedef typename table::node_allocator_traits node_allocator_traits; - typedef typename table::bucket_pointer bucket_pointer; - typedef typename table::link_pointer link_pointer; - typedef typename table::hasher hasher; - typedef typename table::key_equal key_equal; - typedef typename table::const_key_type const_key_type; - typedef typename table::node_constructor node_constructor; - typedef typename table::node_tmp node_tmp; - typedef typename table::extractor extractor; - typedef typename table::iterator iterator; - typedef typename table::c_iterator c_iterator; - typedef typename table::node_algo node_algo; - - // Constructors - - table_equiv(std::size_t n, hasher const& hf, key_equal const& eq, - node_allocator const& a) - : table(n, hf, eq, a) - { - } - - table_equiv(table_equiv const& x) - : table(x, node_allocator_traits::select_on_container_copy_construction( - x.node_alloc())) - { - } - - table_equiv(table_equiv const& x, node_allocator const& a) : table(x, a) {} - - table_equiv(table_equiv& x, boost::unordered::detail::move_tag m) - : table(x, m) - { - } - - table_equiv(table_equiv& x, node_allocator const& a, - boost::unordered::detail::move_tag m) - : table(x, a, m) - { - } + //////////////////////////////////////////////////////////////////////// + // Equivalent keys // Equality @@ -4803,11 +4111,6 @@ struct table_equiv : boost::unordered::detail::table //////////////////////////////////////////////////////////////////////// // fill_buckets - BOOST_FORCEINLINE void copy_buckets(table const& src) - { - this->copy_buckets_equiv(src); - } - void copy_buckets_equiv(table const& src) { this->create_buckets(this->bucket_count_); @@ -4850,11 +4153,6 @@ struct table_equiv : boost::unordered::detail::table } } - BOOST_FORCEINLINE void assign_buckets(table const& src) - { - this->assign_buckets_equiv(src); - } - void assign_buckets_equiv(table const& src) { node_holder holder(*this); @@ -4870,11 +4168,6 @@ struct table_equiv : boost::unordered::detail::table } } - BOOST_FORCEINLINE void move_assign_buckets(table const& src) - { - this->move_assign_buckets_equiv(src); - } - void move_assign_buckets_equiv(table& src) { node_holder holder(*this); @@ -4891,6 +4184,596 @@ struct table_equiv : boost::unordered::detail::table } } }; + +//////////////////////////////////////////////////////////////////////////// +// Reserve & Rehash + +// basic exception safety +template +inline void table::reserve_for_insert(std::size_t size) +{ + if (!buckets_) { + create_buckets((std::max)(bucket_count_, min_buckets_for_size(size))); + } else if (size > max_load_) { + std::size_t num_buckets = + min_buckets_for_size((std::max)(size, size_ + (size_ >> 1))); + + if (num_buckets != bucket_count_) + this->rehash_impl(num_buckets); + } +} + +// if hash function throws, basic exception safety +// strong otherwise. + +template +inline void table::rehash(std::size_t min_buckets) +{ + using namespace std; + + if (!size_) { + delete_buckets(); + bucket_count_ = policy::new_bucket_count(min_buckets); + } else { + min_buckets = policy::new_bucket_count((std::max)(min_buckets, + boost::unordered::detail::double_to_size( + floor(static_cast(size_) / static_cast(mlf_))) + + 1)); + + if (min_buckets != bucket_count_) + this->rehash_impl(min_buckets); + } +} + +template +inline void table::rehash_impl(std::size_t num_buckets) +{ + BOOST_ASSERT(this->buckets_); + + this->create_buckets(num_buckets); + link_pointer prev = this->get_previous_start(); + while (prev->next_) { + node_pointer group_last = node_algo::last_for_rehash(prev); + bucket_pointer b = + this->get_bucket(this->hash_to_bucket(group_last->hash_)); + if (!b->next_) { + b->next_ = prev; + prev = group_last; + } else { + link_pointer next = group_last->next_; + group_last->next_ = b->next_->next_; + b->next_->next_ = prev->next_; + prev->next_ = next; + } + } +} + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +//////////////////////////////////////////////////////////////////////// +// key extractors +// +// no throw +// +// 'extract_key' is called with the emplace parameters to return a +// key if available or 'no_key' is one isn't and will need to be +// constructed. This could be done by overloading the emplace implementation +// for the different cases, but that's a bit tricky on compilers without +// variadic templates. + +template struct is_key +{ + template static choice1::type test(T2 const&); + static choice2::type test(Key const&); + + enum + { + value = sizeof(test(boost::unordered::detail::make())) == + sizeof(choice2::type) + }; + + typedef typename boost::detail::if_true::BOOST_NESTED_TEMPLATE + then::type type; +}; + +template struct set_extractor +{ + typedef ValueType value_type; + typedef ValueType key_type; + + static key_type const& extract(value_type const& v) { return v; } + + static no_key extract() { return no_key(); } + + template static no_key extract(Arg const&) { return no_key(); } + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + static no_key extract(Arg1 const&, Arg2 const&, Args const&...) + { + return no_key(); + } +#else + template + static no_key extract(Arg1 const&, Arg2 const&) + { + return no_key(); + } +#endif +}; + +template struct map_extractor +{ + typedef ValueType value_type; + typedef typename boost::remove_const::first_type>::type key_type; + + static key_type const& extract(value_type const& v) { return v.first; } + + template + static key_type const& extract(std::pair const& v) + { + return v.first; + } + + template + static key_type const& extract(std::pair const& v) + { + return v.first; + } + + template + static key_type const& extract(key_type const& k, Arg1 const&) + { + return k; + } + + static no_key extract() { return no_key(); } + + template static no_key extract(Arg const&) { return no_key(); } + + template + static no_key extract(Arg1 const&, Arg2 const&) + { + return no_key(); + } + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + static no_key extract(Arg1 const&, Arg2 const&, Arg3 const&, Args const&...) + { + return no_key(); + } +#endif + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \ + template \ + static no_key extract(boost::unordered::piecewise_construct_t, \ + namespace_ tuple<> const&, T2 const&) \ + { \ + return no_key(); \ + } \ + \ + template \ + static typename is_key::type extract( \ + boost::unordered::piecewise_construct_t, namespace_ tuple const& k, \ + T2 const&) \ + { \ + return typename is_key::type(namespace_ get<0>(k)); \ + } + +#else + +#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \ + static no_key extract( \ + boost::unordered::piecewise_construct_t, namespace_ tuple<> const&) \ + { \ + return no_key(); \ + } \ + \ + template \ + static typename is_key::type extract( \ + boost::unordered::piecewise_construct_t, namespace_ tuple const& k) \ + { \ + return typename is_key::type(namespace_ get<0>(k)); \ + } + +#endif + + BOOST_UNORDERED_KEY_FROM_TUPLE(boost::) + +#if BOOST_UNORDERED_TUPLE_ARGS + BOOST_UNORDERED_KEY_FROM_TUPLE(std::) +#endif +}; + +//////////////////////////////////////////////////////////////////////// +// Unique nodes + +template +struct unique_node : boost::unordered::detail::value_base +{ + typedef typename ::boost::unordered::detail::rebind_wrap >::type allocator; + typedef typename ::boost::unordered::detail::allocator_traits< + allocator>::pointer node_pointer; + typedef node_pointer link_pointer; + typedef typename ::boost::unordered::detail::rebind_wrap >::type bucket_allocator; + typedef typename ::boost::unordered::detail::allocator_traits< + bucket_allocator>::pointer bucket_pointer; + + link_pointer next_; + std::size_t hash_; + + unique_node() : next_(), hash_(0) {} + + void init(node_pointer) {} + + private: + unique_node& operator=(unique_node const&); +}; + +template struct ptr_node : boost::unordered::detail::ptr_bucket +{ + typedef T value_type; + typedef boost::unordered::detail::ptr_bucket bucket_base; + typedef ptr_node* node_pointer; + typedef ptr_bucket* link_pointer; + typedef ptr_bucket* bucket_pointer; + + std::size_t hash_; + boost::unordered::detail::value_base value_base_; + + ptr_node() : bucket_base(), hash_(0) {} + + void init(node_pointer) {} + + void* address() { return value_base_.address(); } + value_type& value() { return value_base_.value(); } + value_type* value_ptr() { return value_base_.value_ptr(); } + + private: + ptr_node& operator=(ptr_node const&); +}; + +template struct node_algo +{ + typedef typename N::node_pointer node_pointer; + typedef typename N::link_pointer link_pointer; + typedef typename N::bucket_pointer bucket_pointer; + + static node_pointer next_node(link_pointer n) + { + return static_cast(n->next_); + } + + static node_pointer next_for_find(node_pointer n) + { + return static_cast(n->next_); + } + + static link_pointer next_for_erase(link_pointer prev) + { + return prev->next_; + } + + // Group together all nodes with equal hash value, this may + // include nodes with different keys, but that's okay because + // they will end up in the same bucket. + static node_pointer last_for_rehash(link_pointer prev) + { + node_pointer n = next_node(prev); + std::size_t hash = n->hash_; + for (;;) { + node_pointer next = next_node(n); + if (!next || next->hash_ != hash) { + return n; + } + n = next; + } + } + + template + static node_pointer next_group(node_pointer n, Table const* t) + { + node_pointer n1 = n; + do { + n1 = next_node(n1); + } while (n1 && t->key_eq()(t->get_key(n), t->get_key(n1))); + return n1; + } + + template + static std::size_t count(node_pointer n, Table const* t) + { + std::size_t x = 0; + node_pointer it = n; + do { + ++x; + it = next_node(it); + } while (it && t->key_eq()(t->get_key(n), t->get_key(it))); + + return x; + } + + // Add node 'n' after 'pos'. + // This results in a different order to the grouped implementation. + static inline void add_to_node(node_pointer n, node_pointer pos) + { + n->next_ = pos->next_; + pos->next_ = n; + } + + static inline node_pointer extract_first_node(link_pointer prev) + { + node_pointer n = next_node(prev); + prev->next_ = n->next_; + return n; + } + + static link_pointer split_groups(node_pointer, node_pointer) + { + return link_pointer(); + } +}; + +// If the allocator uses raw pointers use ptr_node +// Otherwise use node. + +template +struct pick_node2 +{ + typedef boost::unordered::detail::unique_node node; + + typedef typename boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap::type>::pointer + node_pointer; + + typedef boost::unordered::detail::bucket bucket; + typedef node_pointer link_pointer; +}; + +template +struct pick_node2*, + boost::unordered::detail::ptr_bucket*> +{ + typedef boost::unordered::detail::ptr_node node; + typedef boost::unordered::detail::ptr_bucket bucket; + typedef bucket* link_pointer; +}; + +template struct pick_node +{ + typedef typename boost::remove_const::type nonconst; + + typedef boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap >::type> + tentative_node_traits; + + typedef boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap::type> + tentative_bucket_traits; + + typedef pick_node2 + pick; + + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + typedef boost::unordered::detail::node_algo node_algo; +}; + +//////////////////////////////////////////////////////////////////////// +// Grouped nodes + +template +struct grouped_node : boost::unordered::detail::value_base +{ + typedef typename ::boost::unordered::detail::rebind_wrap >::type allocator; + typedef typename ::boost::unordered::detail::allocator_traits< + allocator>::pointer node_pointer; + typedef node_pointer link_pointer; + typedef typename ::boost::unordered::detail::rebind_wrap >::type bucket_allocator; + typedef typename ::boost::unordered::detail::allocator_traits< + bucket_allocator>::pointer bucket_pointer; + + link_pointer next_; + node_pointer group_prev_; + std::size_t hash_; + + grouped_node() : next_(), group_prev_(), hash_(0) {} + + void init(node_pointer self) { group_prev_ = self; } + + private: + grouped_node& operator=(grouped_node const&); +}; + +template +struct grouped_ptr_node : boost::unordered::detail::ptr_bucket +{ + typedef T value_type; + typedef boost::unordered::detail::ptr_bucket bucket_base; + typedef grouped_ptr_node* node_pointer; + typedef ptr_bucket* link_pointer; + typedef ptr_bucket* bucket_pointer; + + node_pointer group_prev_; + std::size_t hash_; + boost::unordered::detail::value_base value_base_; + + grouped_ptr_node() : bucket_base(), group_prev_(0), hash_(0) {} + + void init(node_pointer self) { group_prev_ = self; } + + void* address() { return value_base_.address(); } + value_type& value() { return value_base_.value(); } + value_type* value_ptr() { return value_base_.value_ptr(); } + + private: + grouped_ptr_node& operator=(grouped_ptr_node const&); +}; + +template struct grouped_node_algo +{ + typedef typename N::node_pointer node_pointer; + typedef typename N::link_pointer link_pointer; + typedef typename N::bucket_pointer bucket_pointer; + + static node_pointer next_node(link_pointer n) + { + return static_cast(n->next_); + } + + static node_pointer next_for_find(node_pointer n) + { + return static_cast(n->group_prev_->next_); + } + + static link_pointer next_for_erase(link_pointer prev) + { + return static_cast(prev->next_)->group_prev_; + } + + static node_pointer last_for_rehash(link_pointer prev) + { + return static_cast(prev->next_)->group_prev_; + } + + // The 'void*' arguments are pointers to the table, which we + // will ignore, but without groups they could be used to + // access the various functions for dealing with values and keys. + static node_pointer next_group(node_pointer n, void const*) + { + return static_cast(n->group_prev_->next_); + } + + static std::size_t count(node_pointer n, void const*) + { + std::size_t x = 0; + node_pointer it = n; + do { + it = it->group_prev_; + ++x; + } while (it != n); + + return x; + } + + // Adds node 'n' to the group containing 'pos'. + // If 'pos' is the first node in group, add to the end of the group, + // otherwise add before 'pos'. Other versions will probably behave + // differently. + static inline void add_to_node(node_pointer n, node_pointer pos) + { + n->next_ = pos->group_prev_->next_; + n->group_prev_ = pos->group_prev_; + pos->group_prev_->next_ = n; + pos->group_prev_ = n; + } + + static inline node_pointer extract_first_node(link_pointer prev) + { + node_pointer n = next_node(prev); + if (n->group_prev_ != n) { + node_pointer next = next_node(n); + next->group_prev_ = n->group_prev_; + n->group_prev_ = n; + } + prev->next_ = n->next_; + return n; + } + + // Split the groups containing 'i' and 'j' so that they can + // be safely erased/extracted. + static link_pointer split_groups(node_pointer i, node_pointer j) + { + node_pointer prev = i->group_prev_; + if (prev->next_ != i) + prev = node_pointer(); + + if (j) { + node_pointer first = j; + while (first != i && first->group_prev_->next_ == first) { + first = first->group_prev_; + } + + boost::swap(first->group_prev_, j->group_prev_); + if (first == i) + return prev; + } + + if (prev) { + node_pointer first = prev; + while (first->group_prev_->next_ == first) { + first = first->group_prev_; + } + boost::swap(first->group_prev_, i->group_prev_); + } + + return prev; + } +}; + +// If the allocator uses raw pointers use grouped_ptr_node +// Otherwise use grouped_node. + +template +struct pick_grouped_node2 +{ + typedef boost::unordered::detail::grouped_node node; + + typedef typename boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap::type>::pointer + node_pointer; + + typedef boost::unordered::detail::bucket bucket; + typedef node_pointer link_pointer; +}; + +template +struct pick_grouped_node2*, + boost::unordered::detail::ptr_bucket*> +{ + typedef boost::unordered::detail::grouped_ptr_node node; + typedef boost::unordered::detail::ptr_bucket bucket; + typedef bucket* link_pointer; +}; + +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> + tentative_node_traits; + + typedef boost::unordered::detail::allocator_traits< + typename boost::unordered::detail::rebind_wrap::type> + tentative_bucket_traits; + + typedef pick_grouped_node2 + pick; + + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + typedef boost::unordered::detail::grouped_node_algo node_algo; +}; } } } diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index a8bf9f3a..1d963965 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -29,8 +29,12 @@ template struct map typedef typename pick::link_pointer link_pointer; typedef typename pick::node_algo node_algo; - typedef boost::unordered::detail::table_unique table; + typedef boost::unordered::detail::table table; typedef boost::unordered::detail::map_extractor extractor; + enum + { + is_unique = true + }; typedef typename boost::unordered::detail::pick_policy::type policy; @@ -71,8 +75,12 @@ struct multimap typedef typename pick::link_pointer link_pointer; typedef typename pick::node_algo node_algo; - typedef boost::unordered::detail::table_equiv table; + typedef boost::unordered::detail::table table; typedef boost::unordered::detail::map_extractor extractor; + enum + { + is_unique = false + }; typedef typename boost::unordered::detail::pick_policy::type policy; diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index 2e7d6ef5..7b9bdca3 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -29,8 +29,12 @@ template struct set typedef typename pick::link_pointer link_pointer; typedef typename pick::node_algo node_algo; - typedef boost::unordered::detail::table_unique table; + typedef boost::unordered::detail::table table; typedef boost::unordered::detail::set_extractor extractor; + enum + { + is_unique = true + }; typedef typename boost::unordered::detail::pick_policy::type policy; @@ -70,8 +74,12 @@ template struct multiset typedef typename pick::link_pointer link_pointer; typedef typename pick::node_algo node_algo; - typedef boost::unordered::detail::table_equiv table; + typedef boost::unordered::detail::table table; typedef boost::unordered::detail::set_extractor extractor; + enum + { + is_unique = false + }; typedef typename boost::unordered::detail::pick_policy::type policy; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 7972cc89..57798ca5 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1378,7 +1378,9 @@ unordered_map::unordered_map(InputIt f, InputIt l, size_type n, template unordered_map::unordered_map(unordered_map const& other) - : table_(other.table_) + : table_(other.table_, + unordered_map::value_allocator_traits:: + select_on_container_copy_construction(other.get_allocator())) { if (other.table_.size_) { table_.copy_buckets_unique(other.table_); @@ -1866,7 +1868,9 @@ unordered_multimap::unordered_multimap(InputIt f, InputIt l, template unordered_multimap::unordered_multimap( unordered_multimap const& other) - : table_(other.table_) + : table_(other.table_, + unordered_multimap::value_allocator_traits:: + select_on_container_copy_construction(other.get_allocator())) { if (other.table_.size_) { table_.copy_buckets_equiv(other.table_); @@ -1897,7 +1901,7 @@ unordered_multimap::unordered_multimap( { if (table_.node_alloc() == other.table_.node_alloc()) { table_.move_buckets_from(other.table_); - } else if (other.table_.size()) { + } else if (other.table_.size_) { // TODO: Could pick new bucket size? table_.move_buckets_equiv(other.table_); } @@ -2294,10 +2298,7 @@ template class node_handle_map { BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle_map) - template - friend struct ::boost::unordered::detail::table_unique; - template - friend struct ::boost::unordered::detail::table_equiv; + template friend struct ::boost::unordered::detail::table; template friend class boost::unordered::unordered_map; template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 273975ab..36645b99 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1077,7 +1077,9 @@ unordered_set::unordered_set(InputIt f, InputIt l, size_type n, template unordered_set::unordered_set(unordered_set const& other) - : table_(other.table_) + : table_(other.table_, + unordered_set::value_allocator_traits:: + select_on_container_copy_construction(other.get_allocator())) { if (other.table_.size_) { table_.copy_buckets_unique(other.table_); @@ -1480,7 +1482,9 @@ unordered_multiset::unordered_multiset(InputIt f, InputIt l, template unordered_multiset::unordered_multiset( unordered_multiset const& other) - : table_(other.table_) + : table_(other.table_, + unordered_multiset::value_allocator_traits:: + select_on_container_copy_construction(other.get_allocator())) { if (other.table_.size_) { table_.copy_buckets_equiv(other.table_); @@ -1511,7 +1515,7 @@ unordered_multiset::unordered_multiset( { if (table_.node_alloc() == other.table_.node_alloc()) { table_.move_buckets_from(other.table_); - } else if (other.table_.size()) { + } else if (other.table_.size_) { // TODO: Could pick new bucket size? table_.move_buckets_equiv(other.table_); } @@ -1869,10 +1873,7 @@ template class node_handle_set { BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle_set) - template - friend struct ::boost::unordered::detail::table_unique; - template - friend struct ::boost::unordered::detail::table_equiv; + template friend struct ::boost::unordered::detail::table; template friend class unordered_set; template diff --git a/test/unordered/incomplete_test.cpp b/test/unordered/incomplete_test.cpp index 8848fe80..860606b3 100644 --- a/test/unordered/incomplete_test.cpp +++ b/test/unordered/incomplete_test.cpp @@ -65,6 +65,11 @@ template struct allocator : std::allocator allocator(const allocator& other) : std::allocator(other) { } + + template + allocator(const std::allocator& other) : std::allocator(other) + { + } }; // Declare some members of a structs. From 0c3c738614c3ed99727253d1449f56b662b6b7e2 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Apr 2017 01:09:07 +0100 Subject: [PATCH 075/147] Better C++ version info --- test/helpers/test.hpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/helpers/test.hpp b/test/helpers/test.hpp index e02647fe..84e900f2 100644 --- a/test/helpers/test.hpp +++ b/test/helpers/test.hpp @@ -78,18 +78,17 @@ static inline void run_tests() } } -// TODO: Detect C++11 on more compilers -#if defined(BOOST_GCC_CXX11) -#define BOOST_UNORDERED_TEST_CXX11 "true" +#if defined(__cplusplus) +#define BOOST_UNORDERED_CPLUSPLUS __cplusplus #else -#define BOOST_UNORDERED_TEST_CXX11 "false" +#define BOOST_UNORDERED_CPLUSPLUS "(not defined)" #endif #define BOOST_UNORDERED_TEST_COMPILER_INFO() \ { \ std::cout << "Compiler: " << BOOST_COMPILER << "\n" \ << "Library: " << BOOST_STDLIB << "\n" \ - << "C++11: " << BOOST_UNORDERED_TEST_CXX11 << "\n\n" \ + << "__cplusplus: " << BOOST_UNORDERED_CPLUSPLUS << "\n\n" \ << "BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT: " \ << BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT << "\n" \ << "BOOST_UNORDERED_EMPLACE_LIMIT: " \ From 60127d86e007300063a9dd2efd01ecad267b9b3e Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Apr 2017 01:10:53 +0100 Subject: [PATCH 076/147] After 5 failures stop running an exception test --- test/helpers/exception_test.hpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/helpers/exception_test.hpp b/test/helpers/exception_test.hpp index 3bc0f734..39490776 100644 --- a/test/helpers/exception_test.hpp +++ b/test/helpers/exception_test.hpp @@ -241,8 +241,10 @@ template void exception_safety(Test const& f, char const* /*name*/) iteration = 0; bool success = false; + unsigned int failure_count = 0; char const* error_msg = 0; do { + int error_count = boost::detail::test_errors(); ++iteration; count = 0; @@ -253,12 +255,15 @@ template void exception_safety(Test const& f, char const* /*name*/) error_msg = "test_failure caught."; break; } catch (test_exception) { - continue; } catch (...) { error_msg = "Unexpected exception."; break; } - } while (!success); + + if (error_count != boost::detail::test_errors()) { + ++failure_count; + } + } while (!success && failure_count < 5); if (error_msg) { BOOST_ERROR(error_msg); From 9c8980e6a16769167f3f088a6a116726be73fb75 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Apr 2017 01:11:18 +0100 Subject: [PATCH 077/147] Write out epoint that threw an exception after failure --- test/helpers/exception_test.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/helpers/exception_test.hpp b/test/helpers/exception_test.hpp index 39490776..842de8b1 100644 --- a/test/helpers/exception_test.hpp +++ b/test/helpers/exception_test.hpp @@ -254,7 +254,12 @@ template void exception_safety(Test const& f, char const* /*name*/) } catch (test_failure) { error_msg = "test_failure caught."; break; - } catch (test_exception) { + } catch (test_exception e) { + if (error_count != boost::detail::test_errors()) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM + << "Iteration: " << iteration + << " Error found for epoint: " << e.name << std::endl; + } } catch (...) { error_msg = "Unexpected exception."; break; From 07b9a7d60e42d80bfdc8d0a63907a4377fdfe16b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Apr 2017 01:39:06 +0100 Subject: [PATCH 078/147] Fix incorrect try_emplace call --- include/boost/unordered/unordered_map.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 57798ca5..a966c61f 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -523,7 +523,7 @@ template class unordered_map std::pair try_emplace( BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) { - return table_.try_emplace_hint_unique( + return table_.try_emplace_unique( boost::move(k), boost::unordered::detail::create_emplace_args( boost::forward(a0))); } From 1c8edf0298b2f49aaf73b6aa948556595e7858c9 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Apr 2017 09:54:28 +0100 Subject: [PATCH 079/147] Remove early exit for empty containers --- include/boost/unordered/detail/implementation.hpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 25a7e615..78b9dd94 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3107,14 +3107,9 @@ struct table : boost::unordered::detail::functions= max_load_) { create_buckets(min_buckets_for_size(x.size_)); - } else { + } else if (size_) { clear_buckets(); } @@ -3194,14 +3189,9 @@ struct table : boost::unordered::detail::functions= max_load_) { create_buckets(min_buckets_for_size(x.size_)); - } else { + } else if (size_) { clear_buckets(); } From cba643fc51d2119390cab45e4bbe496ee15f002a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Apr 2017 09:54:28 +0100 Subject: [PATCH 080/147] Make setting max_load_ a tad more consistent --- include/boost/unordered/detail/implementation.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 78b9dd94..518001c8 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -2852,7 +2852,7 @@ struct table : boost::unordered::detail::functions Date: Tue, 25 Apr 2017 09:54:28 +0100 Subject: [PATCH 081/147] Option to use grouped nodes everywhere Seems to work okay, but I'm not happy with and of the options. So I'm going to look into doing something else before the next release. --- .travis.yml | 4 ++-- include/boost/unordered/detail/implementation.hpp | 1 + include/boost/unordered/detail/map.hpp | 10 +++++++--- include/boost/unordered/detail/set.hpp | 10 +++++++--- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index eaa2200a..03f49936 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,8 +44,8 @@ matrix: user_config="using gcc : : g++-4.8 -fsanitize=address -Werror --std=c++03 -DBOOST_UNORDERED_INTEROPERABLE_NODES=1 ;" - compiler: clang env: | - label="gcc C++11 interopable1"; - user_config="using clang : : clang++ -fsanitize=address -Werror --std=c++03 -DBOOST_UNORDERED_INTEROPERABLE_NODES=1 ;" + label="gcc C++11 interopable2"; + user_config="using clang : : clang++ -fsanitize=address -Werror --std=c++03 -DBOOST_UNORDERED_INTEROPERABLE_NODES=2 ;" before_script: - cd ${TRAVIS_BUILD_DIR} diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 518001c8..81d2936b 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -71,6 +71,7 @@ // // 0 = Use different nodes // 1 = Use ungrouped nodes everywhere +// 2 = Use grouped nodes everywhere // // Might add an extra value to use grouped nodes everywhere later. diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index 1d963965..9b059d18 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -23,7 +23,11 @@ template struct map typedef boost::unordered::detail::allocator_traits value_allocator_traits; +#if BOOST_UNORDERED_INTEROPERABLE_NODES != 2 typedef boost::unordered::detail::pick_node pick; +#else + typedef boost::unordered::detail::pick_grouped_node pick; +#endif typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; @@ -65,10 +69,10 @@ struct multimap typedef boost::unordered::detail::allocator_traits value_allocator_traits; -#if BOOST_UNORDERED_INTEROPERABLE_NODES - typedef boost::unordered::detail::pick_node pick; -#else +#if BOOST_UNORDERED_INTEROPERABLE_NODES != 1 typedef boost::unordered::detail::pick_grouped_node pick; +#else + typedef boost::unordered::detail::pick_node pick; #endif typedef typename pick::node node; typedef typename pick::bucket bucket; diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index 7b9bdca3..6de4423c 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -23,7 +23,11 @@ template struct set typedef boost::unordered::detail::allocator_traits value_allocator_traits; +#if BOOST_UNORDERED_INTEROPERABLE_NODES != 2 typedef boost::unordered::detail::pick_node pick; +#else + typedef boost::unordered::detail::pick_grouped_node pick; +#endif typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; @@ -64,10 +68,10 @@ template struct multiset typedef boost::unordered::detail::allocator_traits value_allocator_traits; -#if BOOST_UNORDERED_INTEROPERABLE_NODES - typedef boost::unordered::detail::pick_node pick; -#else +#if BOOST_UNORDERED_INTEROPERABLE_NODES != 1 typedef boost::unordered::detail::pick_grouped_node pick; +#else + typedef boost::unordered::detail::pick_node pick; #endif typedef typename pick::node node; typedef typename pick::bucket bucket; From e3ab7b5d2e7f60210262806d8007dd73126ecbea Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Apr 2017 20:20:11 +0100 Subject: [PATCH 082/147] Remove BOOST_UNORDERED_EMPLACE_ARGSn macros They're not used anywhere now. --- include/boost/unordered/detail/implementation.hpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 81d2936b..fbd297a0 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -514,20 +514,12 @@ struct convert_from_anything #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) -#define BOOST_UNORDERED_EMPLACE_ARGS1(a0) a0 -#define BOOST_UNORDERED_EMPLACE_ARGS2(a0, a1) a0, a1 -#define BOOST_UNORDERED_EMPLACE_ARGS3(a0, a1, a2) a0, a1, a2 - #define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args #define BOOST_UNORDERED_EMPLACE_ARGS BOOST_FWD_REF(Args)... args #define BOOST_UNORDERED_EMPLACE_FORWARD boost::forward(args)... #else -#define BOOST_UNORDERED_EMPLACE_ARGS1 create_emplace_args -#define BOOST_UNORDERED_EMPLACE_ARGS2 create_emplace_args -#define BOOST_UNORDERED_EMPLACE_ARGS3 create_emplace_args - #define BOOST_UNORDERED_EMPLACE_TEMPLATE typename Args #define BOOST_UNORDERED_EMPLACE_ARGS Args const& args #define BOOST_UNORDERED_EMPLACE_FORWARD args From 61df9479e57fb0885c4315d0580d16d914fd422b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Apr 2017 20:20:11 +0100 Subject: [PATCH 083/147] Rename unique_node --- include/boost/unordered/detail/implementation.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index fbd297a0..61cefa83 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -186,7 +186,7 @@ template struct table; template struct bucket; struct ptr_bucket; -template struct unique_node; +template struct node; template struct ptr_node; template struct node_algo; @@ -4376,10 +4376,10 @@ template struct map_extractor // Unique nodes template -struct unique_node : boost::unordered::detail::value_base +struct node : boost::unordered::detail::value_base { typedef typename ::boost::unordered::detail::rebind_wrap >::type allocator; + node >::type allocator; typedef typename ::boost::unordered::detail::allocator_traits< allocator>::pointer node_pointer; typedef node_pointer link_pointer; @@ -4391,12 +4391,12 @@ struct unique_node : boost::unordered::detail::value_base link_pointer next_; std::size_t hash_; - unique_node() : next_(), hash_(0) {} + node() : next_(), hash_(0) {} void init(node_pointer) {} private: - unique_node& operator=(unique_node const&); + node& operator=(node const&); }; template struct ptr_node : boost::unordered::detail::ptr_bucket @@ -4509,7 +4509,7 @@ template struct node_algo template struct pick_node2 { - typedef boost::unordered::detail::unique_node node; + typedef boost::unordered::detail::node node; typedef typename boost::unordered::detail::allocator_traits< typename boost::unordered::detail::rebind_wrap::type>::pointer From bea4c6e29b928b36da3342086af392bf187f8d65 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Apr 2017 20:20:11 +0100 Subject: [PATCH 084/147] undef some macros --- include/boost/unordered/detail/implementation.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 61cefa83..1c746f49 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -4370,6 +4370,8 @@ template struct map_extractor #if BOOST_UNORDERED_TUPLE_ARGS BOOST_UNORDERED_KEY_FROM_TUPLE(std::) #endif + +#undef BOOST_UNORDERED_KEY_FROM_TUPLE }; //////////////////////////////////////////////////////////////////////// @@ -4759,4 +4761,11 @@ template struct pick_grouped_node } } +#undef BOOST_UNORDERED_EMPLACE_TEMPLATE +#undef BOOST_UNORDERED_EMPLACE_ARGS +#undef BOOST_UNORDERED_EMPLACE_FORWARD +#undef BOOST_UNORDERED_CALL_CONSTRUCT0 +#undef BOOST_UNORDERED_CALL_CONSTRUCT1 +#undef BOOST_UNORDERED_CALL_DESTROY + #endif From ed326e2c8741f7146d68877c91e718466b6fd986 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Apr 2017 20:20:11 +0100 Subject: [PATCH 085/147] Expand out more preprocessor repeats --- .../boost/unordered/detail/implementation.hpp | 16 ++++++++++++++-- include/boost/unordered/unordered_map.hpp | 8 +++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 1c746f49..50baa8ff 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -616,8 +616,14 @@ inline emplace_args3 create_emplace_args( return e; \ } +BOOST_UNORDERED_EARGS(1, 4, _) +BOOST_UNORDERED_EARGS(1, 5, _) +BOOST_UNORDERED_EARGS(1, 6, _) +BOOST_UNORDERED_EARGS(1, 7, _) +BOOST_UNORDERED_EARGS(1, 8, _) +BOOST_UNORDERED_EARGS(1, 9, _) BOOST_PP_REPEAT_FROM_TO( - 4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_EARGS, _) + 10, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_EARGS, _) #undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS #undef BOOST_UNORDERED_EARGS_MEMBER @@ -1588,7 +1594,13 @@ inline void construct_from_args( num_params, BOOST_UNORDERED_CALL_FORWARD, args.a)); \ } -BOOST_PP_REPEAT_FROM_TO(4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), +BOOST_UNORDERED_CONSTRUCT_IMPL(1, 4, _) +BOOST_UNORDERED_CONSTRUCT_IMPL(1, 5, _) +BOOST_UNORDERED_CONSTRUCT_IMPL(1, 6, _) +BOOST_UNORDERED_CONSTRUCT_IMPL(1, 7, _) +BOOST_UNORDERED_CONSTRUCT_IMPL(1, 8, _) +BOOST_UNORDERED_CONSTRUCT_IMPL(1, 9, _) +BOOST_PP_REPEAT_FROM_TO(10, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_CONSTRUCT_IMPL, _) #undef BOOST_UNORDERED_CONSTRUCT_IMPL diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index a966c61f..8ef037ae 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -656,7 +656,13 @@ template class unordered_map n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } - BOOST_PP_REPEAT_FROM_TO(4, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), + BOOST_UNORDERED_TRY_EMPLACE(1, 4, _) + BOOST_UNORDERED_TRY_EMPLACE(1, 5, _) + BOOST_UNORDERED_TRY_EMPLACE(1, 6, _) + BOOST_UNORDERED_TRY_EMPLACE(1, 7, _) + BOOST_UNORDERED_TRY_EMPLACE(1, 8, _) + BOOST_UNORDERED_TRY_EMPLACE(1, 9, _) + BOOST_PP_REPEAT_FROM_TO(10, BOOST_PP_INC(BOOST_UNORDERED_EMPLACE_LIMIT), BOOST_UNORDERED_TRY_EMPLACE, _) #undef BOOST_UNORDERED_TRY_EMPLACE From da27ae4de65bf75a78410c2749f40ed46dcf627e Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Apr 2017 20:20:11 +0100 Subject: [PATCH 086/147] Group together similar overloads of try_emplace --- include/boost/unordered/unordered_map.hpp | 128 ++++++++++++---------- 1 file changed, 72 insertions(+), 56 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 8ef037ae..5c941f75 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -489,18 +489,28 @@ template class unordered_map #else + // In order to make this a template, this handles both: + // try_emplace(key const&) + // try_emplace(key&&) + template std::pair try_emplace(BOOST_FWD_REF(Key) k) { return table_.try_emplace_unique(boost::forward(k)); } + // In order to make this a template, this handles both: + // try_emplace(const_iterator hint, key const&) + // try_emplace(const_iterator hint, key&&) + template iterator try_emplace(const_iterator hint, BOOST_FWD_REF(Key) k) { return table_.try_emplace_hint_unique(hint, boost::forward(k)); } + // try_emplace(key const&, Args&&...) + template std::pair try_emplace( key_type const& k, BOOST_FWD_REF(A0) a0) @@ -510,33 +520,6 @@ template class unordered_map boost::forward(a0))); } - template - iterator try_emplace( - const_iterator hint, key_type const& k, BOOST_FWD_REF(A0) a0) - { - return table_.try_emplace_hint_unique( - hint, k, boost::unordered::detail::create_emplace_args( - boost::forward(a0))); - } - - template - std::pair try_emplace( - BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) - { - return table_.try_emplace_unique( - boost::move(k), boost::unordered::detail::create_emplace_args( - boost::forward(a0))); - } - - template - iterator try_emplace( - const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) - { - return table_.try_emplace_hint_unique( - hint, boost::move(k), boost::unordered::detail::create_emplace_args( - boost::forward(a0))); - } - template std::pair try_emplace( key_type const& k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) @@ -546,35 +529,6 @@ template class unordered_map boost::forward(a0), boost::forward(a1))); } - template - iterator try_emplace(const_iterator hint, key_type const& k, - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) - { - return table_.try_emplace_hint_unique( - hint, k, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); - } - - template - std::pair try_emplace( - BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) - { - return table_.try_emplace_unique( - boost::move(k), - boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); - } - - template - iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) - { - return table_.try_emplace_hint_unique( - hint, boost::move(k), - boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); - } - template std::pair try_emplace(key_type const& k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) @@ -585,6 +539,26 @@ template class unordered_map boost::forward(a2))); } + // try_emplace(const_iterator hint, key const&, Args&&...) + + template + iterator try_emplace( + const_iterator hint, key_type const& k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_hint_unique( + hint, k, boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + iterator try_emplace(const_iterator hint, key_type const& k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_hint_unique( + hint, k, boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + template iterator try_emplace(const_iterator hint, key_type const& k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) @@ -597,6 +571,27 @@ template class unordered_map .first; } + // try_emplace(key&&, Args&&...) + + template + std::pair try_emplace( + BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_unique( + boost::move(k), boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + std::pair try_emplace( + BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_unique( + boost::move(k), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + template std::pair try_emplace(BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) @@ -607,6 +602,27 @@ template class unordered_map boost::forward(a2))); } + // try_emplace(const_iterator hint, key&&, Args&&...) + + template + iterator try_emplace( + const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_hint_unique( + hint, boost::move(k), boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_hint_unique( + hint, boost::move(k), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + template iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) From 94a3a9baf94ad86a1f94c1d7f4452e2e6451492c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Apr 2017 21:14:11 +0100 Subject: [PATCH 087/147] Fix some quickbook markup --- doc/compliance.qbk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/compliance.qbk b/doc/compliance.qbk index 1553d987..711ab3f8 100644 --- a/doc/compliance.qbk +++ b/doc/compliance.qbk @@ -64,9 +64,9 @@ Due to imperfect move emulation, some assignments might check The following support is required for full use of C++11 style construction/destruction: - * Variadic templates. - * Piecewise construction of `std::pair`. - * Either `std::allocator_traits` or expression SFINAE. +* Variadic templates. +* Piecewise construction of `std::pair`. +* Either `std::allocator_traits` or expression SFINAE. This is detected using Boost.Config. The macro `BOOST_UNORDERED_CXX11_CONSTRUCTION` will be set to 1 if it is found, or 0 From ea64f2e46ee6cd36335ae3b8680ec3dd0dffa527 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 27 Apr 2017 18:22:43 +0100 Subject: [PATCH 088/147] Remove the grouped node stuff --- .travis.yml | 8 - .../boost/unordered/detail/implementation.hpp | 221 ------------------ include/boost/unordered/detail/map.hpp | 8 - include/boost/unordered/detail/set.hpp | 8 - include/boost/unordered/unordered_map.hpp | 8 - include/boost/unordered/unordered_set.hpp | 8 - test/helpers/test.hpp | 2 - test/unordered/insert_stable_tests.cpp | 6 +- test/unordered/merge_tests.cpp | 2 - 9 files changed, 3 insertions(+), 268 deletions(-) diff --git a/.travis.yml b/.travis.yml index 03f49936..db516156 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,14 +38,6 @@ matrix: env: | label="clang 32 bit"; user_config="using clang : : clang++ -m32 -Werror --std=c++03 ;" - - compiler: gcc - env: | - label="gcc C++03 interopable1"; - user_config="using gcc : : g++-4.8 -fsanitize=address -Werror --std=c++03 -DBOOST_UNORDERED_INTEROPERABLE_NODES=1 ;" - - compiler: clang - env: | - label="gcc C++11 interopable2"; - user_config="using clang : : clang++ -fsanitize=address -Werror --std=c++03 -DBOOST_UNORDERED_INTEROPERABLE_NODES=2 ;" before_script: - cd ${TRAVIS_BUILD_DIR} diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 50baa8ff..f92f3ec5 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -66,19 +66,6 @@ #define BOOST_UNORDERED_EMPLACE_LIMIT 10 #endif -// BOOST_UNORDERED_INTEROPERABLE_NODES - Use the same node type for -// containers with unique and equivalent keys. -// -// 0 = Use different nodes -// 1 = Use ungrouped nodes everywhere -// 2 = Use grouped nodes everywhere -// -// Might add an extra value to use grouped nodes everywhere later. - -#if !defined(BOOST_UNORDERED_INTEROPERABLE_NODES) -#define BOOST_UNORDERED_INTEROPERABLE_NODES 0 -#endif - // BOOST_UNORDERED_USE_ALLOCATOR_TRAITS - Pick which version of // allocator_traits to use. // @@ -190,10 +177,6 @@ template struct node; template struct ptr_node; template struct node_algo; -template struct grouped_node; -template struct grouped_ptr_node; -template struct grouped_node_algo; - static const float minimum_max_load_factor = 1e-3f; static const std::size_t default_bucket_count = 11; @@ -4565,210 +4548,6 @@ template struct pick_node typedef typename pick::link_pointer link_pointer; typedef boost::unordered::detail::node_algo node_algo; }; - -//////////////////////////////////////////////////////////////////////// -// Grouped nodes - -template -struct grouped_node : boost::unordered::detail::value_base -{ - typedef typename ::boost::unordered::detail::rebind_wrap >::type allocator; - typedef typename ::boost::unordered::detail::allocator_traits< - allocator>::pointer node_pointer; - typedef node_pointer link_pointer; - typedef typename ::boost::unordered::detail::rebind_wrap >::type bucket_allocator; - typedef typename ::boost::unordered::detail::allocator_traits< - bucket_allocator>::pointer bucket_pointer; - - link_pointer next_; - node_pointer group_prev_; - std::size_t hash_; - - grouped_node() : next_(), group_prev_(), hash_(0) {} - - void init(node_pointer self) { group_prev_ = self; } - - private: - grouped_node& operator=(grouped_node const&); -}; - -template -struct grouped_ptr_node : boost::unordered::detail::ptr_bucket -{ - typedef T value_type; - typedef boost::unordered::detail::ptr_bucket bucket_base; - typedef grouped_ptr_node* node_pointer; - typedef ptr_bucket* link_pointer; - typedef ptr_bucket* bucket_pointer; - - node_pointer group_prev_; - std::size_t hash_; - boost::unordered::detail::value_base value_base_; - - grouped_ptr_node() : bucket_base(), group_prev_(0), hash_(0) {} - - void init(node_pointer self) { group_prev_ = self; } - - void* address() { return value_base_.address(); } - value_type& value() { return value_base_.value(); } - value_type* value_ptr() { return value_base_.value_ptr(); } - - private: - grouped_ptr_node& operator=(grouped_ptr_node const&); -}; - -template struct grouped_node_algo -{ - typedef typename N::node_pointer node_pointer; - typedef typename N::link_pointer link_pointer; - typedef typename N::bucket_pointer bucket_pointer; - - static node_pointer next_node(link_pointer n) - { - return static_cast(n->next_); - } - - static node_pointer next_for_find(node_pointer n) - { - return static_cast(n->group_prev_->next_); - } - - static link_pointer next_for_erase(link_pointer prev) - { - return static_cast(prev->next_)->group_prev_; - } - - static node_pointer last_for_rehash(link_pointer prev) - { - return static_cast(prev->next_)->group_prev_; - } - - // The 'void*' arguments are pointers to the table, which we - // will ignore, but without groups they could be used to - // access the various functions for dealing with values and keys. - static node_pointer next_group(node_pointer n, void const*) - { - return static_cast(n->group_prev_->next_); - } - - static std::size_t count(node_pointer n, void const*) - { - std::size_t x = 0; - node_pointer it = n; - do { - it = it->group_prev_; - ++x; - } while (it != n); - - return x; - } - - // Adds node 'n' to the group containing 'pos'. - // If 'pos' is the first node in group, add to the end of the group, - // otherwise add before 'pos'. Other versions will probably behave - // differently. - static inline void add_to_node(node_pointer n, node_pointer pos) - { - n->next_ = pos->group_prev_->next_; - n->group_prev_ = pos->group_prev_; - pos->group_prev_->next_ = n; - pos->group_prev_ = n; - } - - static inline node_pointer extract_first_node(link_pointer prev) - { - node_pointer n = next_node(prev); - if (n->group_prev_ != n) { - node_pointer next = next_node(n); - next->group_prev_ = n->group_prev_; - n->group_prev_ = n; - } - prev->next_ = n->next_; - return n; - } - - // Split the groups containing 'i' and 'j' so that they can - // be safely erased/extracted. - static link_pointer split_groups(node_pointer i, node_pointer j) - { - node_pointer prev = i->group_prev_; - if (prev->next_ != i) - prev = node_pointer(); - - if (j) { - node_pointer first = j; - while (first != i && first->group_prev_->next_ == first) { - first = first->group_prev_; - } - - boost::swap(first->group_prev_, j->group_prev_); - if (first == i) - return prev; - } - - if (prev) { - node_pointer first = prev; - while (first->group_prev_->next_ == first) { - first = first->group_prev_; - } - boost::swap(first->group_prev_, i->group_prev_); - } - - return prev; - } -}; - -// If the allocator uses raw pointers use grouped_ptr_node -// Otherwise use grouped_node. - -template -struct pick_grouped_node2 -{ - typedef boost::unordered::detail::grouped_node node; - - typedef typename boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap::type>::pointer - node_pointer; - - typedef boost::unordered::detail::bucket bucket; - typedef node_pointer link_pointer; -}; - -template -struct pick_grouped_node2*, - boost::unordered::detail::ptr_bucket*> -{ - typedef boost::unordered::detail::grouped_ptr_node node; - typedef boost::unordered::detail::ptr_bucket bucket; - typedef bucket* link_pointer; -}; - -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> - tentative_node_traits; - - typedef boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap::type> - tentative_bucket_traits; - - typedef pick_grouped_node2 - pick; - - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - typedef boost::unordered::detail::grouped_node_algo node_algo; -}; } } } diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index 9b059d18..13e223f3 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -23,11 +23,7 @@ template struct map typedef boost::unordered::detail::allocator_traits value_allocator_traits; -#if BOOST_UNORDERED_INTEROPERABLE_NODES != 2 typedef boost::unordered::detail::pick_node pick; -#else - typedef boost::unordered::detail::pick_grouped_node pick; -#endif typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; @@ -69,11 +65,7 @@ struct multimap typedef boost::unordered::detail::allocator_traits value_allocator_traits; -#if BOOST_UNORDERED_INTEROPERABLE_NODES != 1 - typedef boost::unordered::detail::pick_grouped_node pick; -#else typedef boost::unordered::detail::pick_node pick; -#endif typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index 6de4423c..edb98ece 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -23,11 +23,7 @@ template struct set typedef boost::unordered::detail::allocator_traits value_allocator_traits; -#if BOOST_UNORDERED_INTEROPERABLE_NODES != 2 typedef boost::unordered::detail::pick_node pick; -#else - typedef boost::unordered::detail::pick_grouped_node pick; -#endif typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; @@ -68,11 +64,7 @@ template struct multiset typedef boost::unordered::detail::allocator_traits value_allocator_traits; -#if BOOST_UNORDERED_INTEROPERABLE_NODES != 1 - typedef boost::unordered::detail::pick_grouped_node pick; -#else typedef boost::unordered::detail::pick_node pick; -#endif typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 5c941f75..ab20642c 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -740,14 +740,12 @@ template class unordered_map void merge(boost::unordered_map&& source); #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template void merge(boost::unordered_multimap& source); #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template void merge(boost::unordered_multimap&& source); -#endif #endif // observers @@ -1277,14 +1275,12 @@ template class unordered_multimap void merge(boost::unordered_multimap&& source); #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template void merge(boost::unordered_map& source); #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template void merge(boost::unordered_map&& source); -#endif #endif // observers @@ -1644,7 +1640,6 @@ void unordered_map::merge( } #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template template void unordered_map::merge( @@ -1662,7 +1657,6 @@ void unordered_map::merge( table_.merge_unique(source.table_); } #endif -#endif // observers @@ -2152,7 +2146,6 @@ void unordered_multimap::merge( } #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template template void unordered_multimap::merge( @@ -2174,7 +2167,6 @@ void unordered_multimap::merge( } } #endif -#endif // lookup diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 36645b99..674d4e67 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -457,14 +457,12 @@ template class unordered_set void merge(boost::unordered_set&& source); #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template void merge(boost::unordered_multiset& source); #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template void merge(boost::unordered_multiset&& source); -#endif #endif // observers @@ -962,14 +960,12 @@ template class unordered_multiset void merge(boost::unordered_multiset&& source); #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template void merge(boost::unordered_set& source); #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template void merge(boost::unordered_set&& source); -#endif #endif // observers @@ -1322,7 +1318,6 @@ void unordered_set::merge( } #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template template void unordered_set::merge( @@ -1340,7 +1335,6 @@ void unordered_set::merge( table_.merge_unique(source.table_); } #endif -#endif // lookup @@ -1732,7 +1726,6 @@ void unordered_multiset::merge( } #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template template void unordered_multiset::merge( @@ -1754,7 +1747,6 @@ void unordered_multiset::merge( } } #endif -#endif // lookup diff --git a/test/helpers/test.hpp b/test/helpers/test.hpp index 84e900f2..4f21f0b9 100644 --- a/test/helpers/test.hpp +++ b/test/helpers/test.hpp @@ -93,8 +93,6 @@ static inline void run_tests() << BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT << "\n" \ << "BOOST_UNORDERED_EMPLACE_LIMIT: " \ << BOOST_UNORDERED_EMPLACE_LIMIT << "\n" \ - << "BOOST_UNORDERED_INTEROPERABLE_NODES: " \ - << BOOST_UNORDERED_INTEROPERABLE_NODES << "\n" \ << "BOOST_UNORDERED_USE_ALLOCATOR_TRAITS: " \ << BOOST_UNORDERED_USE_ALLOCATOR_TRAITS << "\n" \ << "BOOST_UNORDERED_CXX11_CONSTRUCTION: " \ diff --git a/test/unordered/insert_stable_tests.cpp b/test/unordered/insert_stable_tests.cpp index c85dd188..afba2239 100644 --- a/test/unordered/insert_stable_tests.cpp +++ b/test/unordered/insert_stable_tests.cpp @@ -47,9 +47,9 @@ std::size_t hash_value(insert_stable::member const& x) } } -// This is now only supported when using grouped nodes. I can't see any -// efficient way to do it otherwise. -#if !BOOST_UNORDERED_INTEROPERABLE_NODES +// This is no longer supported, as there's no longer an efficient way to get to +// the end of a group of equivalent nodes. +#if 0 UNORDERED_AUTO_TEST(stable_insert_test1) { diff --git a/test/unordered/merge_tests.cpp b/test/unordered/merge_tests.cpp index 15755ab8..3d5e7f97 100644 --- a/test/unordered/merge_tests.cpp +++ b/test/unordered/merge_tests.cpp @@ -99,7 +99,6 @@ UNORDERED_AUTO_TEST(merge_multiset) test::check_equivalent_keys(y); } -#if BOOST_UNORDERED_INTEROPERABLE_NODES UNORDERED_AUTO_TEST(merge_set_and_multiset) { boost::unordered_set x; @@ -139,7 +138,6 @@ UNORDERED_AUTO_TEST(merge_set_and_multiset) test::check_equivalent_keys(x); test::check_equivalent_keys(y); } -#endif template void merge_empty_test(X*, test::random_generator generator) { From e9c4696544f11376d7dfe23dcc171d2852b4437c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 27 Apr 2017 18:22:43 +0100 Subject: [PATCH 089/147] Get rid of node_algo --- .../boost/unordered/detail/implementation.hpp | 257 ++++++++---------- include/boost/unordered/detail/map.hpp | 2 - include/boost/unordered/detail/set.hpp | 2 - include/boost/unordered/unordered_map.hpp | 24 +- include/boost/unordered/unordered_set.hpp | 14 +- 5 files changed, 124 insertions(+), 175 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index f92f3ec5..13c549e1 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -175,7 +175,6 @@ struct ptr_bucket; template struct node; template struct ptr_node; -template struct node_algo; static const float minimum_max_load_factor = 1e-3f; static const std::size_t default_bucket_count = 11; @@ -2660,7 +2659,6 @@ struct table : boost::unordered::detail::functions @@ -2701,6 +2699,42 @@ struct table : boost::unordered::detail::functions(n->next_); + } + + static node_pointer next_for_find(link_pointer n) + { + return static_cast(n->next_); + } + + static link_pointer next_for_erase(link_pointer prev) + { + return prev->next_; + } + + node_pointer next_group(node_pointer n) const + { + node_pointer n1 = n; + do { + n1 = next_node(n1); + } while (n1 && this->key_eq()(get_key(n), get_key(n1))); + return n1; + } + + std::size_t group_count(node_pointer n) const + { + std::size_t x = 0; + node_pointer it = n; + do { + ++x; + it = next_node(it); + } while (it && this->key_eq()(get_key(n), get_key(it))); + + return x; + } + bucket_allocator const& bucket_alloc() const { return allocators_.first(); } node_allocator const& node_alloc() const { return allocators_.second(); } @@ -2734,8 +2768,7 @@ struct table : boost::unordered::detail::functionshash_) == index) { ++count; - n = node_algo::next_node(n); + n = next_node(n); } return count; @@ -3235,7 +3268,7 @@ struct table : boost::unordered::detail::functionsnext_) { return link_pointer(); } - std::size_t node_hash = node_algo::next_node(prev)->hash_; + std::size_t node_hash = next_node(prev)->hash_; if (this->hash_to_bucket(node_hash) != bucket_index) { return link_pointer(); } if (node_hash == key_hash && - this->key_eq()(k, this->get_key(node_algo::next_node(prev)))) { + this->key_eq()(k, this->get_key(next_node(prev)))) { return prev; } - prev = node_algo::next_for_erase(prev); + prev = next_for_erase(prev); } } @@ -3277,7 +3310,8 @@ struct table : boost::unordered::detail::functionsnext_ = n->next_; --this->size_; this->fix_bucket(bucket_index, prev); n->next_ = link_pointer(); @@ -3302,8 +3336,7 @@ struct table : boost::unordered::detail::functionssize_ != other.size_) return false; - for (node_pointer n1 = this->begin(); n1; - n1 = node_algo::next_node(n1)) { + for (node_pointer n1 = this->begin(); n1; n1 = next_node(n1)) { node_pointer n2 = other.find_node(other.get_key(n1)); if (!n2 || n1->value() != n2->value()) @@ -3325,8 +3358,8 @@ struct table : boost::unordered::detail::functionsget_previous_start(); if (start_node->next_) { - this->get_bucket(this->hash_to_bucket( - node_algo::next_node(start_node)->hash_)) + this->get_bucket( + this->hash_to_bucket(next_node(start_node)->hash_)) ->next_ = n; } @@ -3551,7 +3584,7 @@ struct table : boost::unordered::detail::functionsnext_) { - node_pointer n = other_table::node_algo::next_node(prev); + node_pointer n = other_table::next_node(prev); const_key_type& k = this->get_key(n); std::size_t key_hash = this->hash(k); node_pointer pos = this->find_node(key_hash, k); @@ -3560,8 +3593,7 @@ struct table : boost::unordered::detail::functionsreserve_for_insert(this->size_ + 1); - other_table::node_algo::split_groups( - n, other_table::node_algo::next_node(n)); + // other_table::split_groups(n, other_table::next_node(n)); prev->next_ = n->next_; --other.size_; other.fix_bucket(other.hash_to_bucket(n->hash_), prev); @@ -3670,7 +3702,7 @@ struct table : boost::unordered::detail::functionsfind_previous_node(k, key_hash, bucket_index); if (!prev) return 0; - link_pointer end = node_algo::next_node(prev)->next_; + link_pointer end = next_node(prev)->next_; this->delete_nodes(prev, end); this->fix_bucket(bucket_index, prev); return 1; @@ -3699,7 +3731,7 @@ struct table : boost::unordered::detail::functionscreate_buckets(this->bucket_count_); - for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + for (node_pointer n = src.begin(); n; n = next_node(n)) { this->add_node_unique( boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), @@ -3712,7 +3744,7 @@ struct table : boost::unordered::detail::functionscreate_buckets(this->bucket_count_); - for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + for (node_pointer n = src.begin(); n; n = next_node(n)) { this->add_node_unique( boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), @@ -3723,7 +3755,7 @@ struct table : boost::unordered::detail::functions holder(*this); - for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + for (node_pointer n = src.begin(); n; n = next_node(n)) { this->add_node_unique(holder.copy_of(n->value()), n->hash_); } } @@ -3731,7 +3763,7 @@ struct table : boost::unordered::detail::functions holder(*this); - for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + for (node_pointer n = src.begin(); n; n = next_node(n)) { this->add_node_unique(holder.move_copy_of(n->value()), n->hash_); } } @@ -3750,8 +3782,8 @@ struct table : boost::unordered::detail::functionsvalue() != n2->value()) break; - n1 = node_algo::next_node(n1); - n2 = node_algo::next_node(n2); + n1 = next_node(n1); + n2 = next_node(n2); if (n1 == end1) return n2 == end2; @@ -3777,8 +3809,8 @@ struct table : boost::unordered::detail::functionsvalue(); if (!find_equiv(start, n1, v)) { std::size_t matches = count_equal_equiv(n2, end2, v); if (!matches) return false; - if (matches != - 1 + count_equal_equiv(node_algo::next_node(n1), end1, v)) + if (matches != 1 + count_equal_equiv(next_node(n1), end1, v)) return false; } } @@ -3810,7 +3841,7 @@ struct table : boost::unordered::detail::functionsvalue() == v) return true; return false; @@ -3820,7 +3851,7 @@ struct table : boost::unordered::detail::functionsvalue() == v) ++count; return count; @@ -3833,10 +3864,11 @@ struct table : boost::unordered::detail::functionshash_ = key_hash; if (pos) { - node_algo::add_to_node(n, pos); + n->next_ = pos->next_; + pos->next_ = n; if (n->next_) { std::size_t next_bucket = - this->hash_to_bucket(node_algo::next_node(n)->hash_); + this->hash_to_bucket(next_node(n)->hash_); if (next_bucket != this->hash_to_bucket(key_hash)) { this->get_bucket(next_bucket)->next_ = n; } @@ -3849,8 +3881,7 @@ struct table : boost::unordered::detail::functionsnext_) { this->get_bucket( - this->hash_to_bucket( - node_algo::next_node(start_node)->hash_)) + this->hash_to_bucket(next_node(start_node)->hash_)) ->next_ = n; } @@ -3869,10 +3900,10 @@ struct table : boost::unordered::detail::functionshash_ = hint->hash_; - node_algo::add_to_node(n, hint); + n->next_ = hint->next_; + hint->next_ = n; if (n->next_ != hint && n->next_) { - std::size_t next_bucket = - this->hash_to_bucket(node_algo::next_node(n)->hash_); + std::size_t next_bucket = this->hash_to_bucket(next_node(n)->hash_); if (next_bucket != this->hash_to_bucket(n->hash_)) { this->get_bucket(next_bucket)->next_ = n; } @@ -4006,21 +4037,19 @@ struct table : boost::unordered::detail::functionshash_to_bucket(i->hash_); // Split the groups containing 'i' and 'j'. // And get the pointer to the node before i while // we're at it. - link_pointer prev = node_algo::split_groups(i, j); + // link_pointer prev = split_groups(i, j); // If we don't have a 'prev' it means that i is at the // beginning of a block, so search through the blocks in the // same bucket. - if (!prev) { - prev = this->get_previous_start(bucket_index); - while (prev->next_ != i) { - prev = node_algo::next_for_erase(prev); - } + link_pointer prev = this->get_previous_start(bucket_index); + while (prev->next_ != i) { + prev = next_for_erase(prev); } prev->next_ = i->next_; @@ -4047,8 +4076,8 @@ struct table : boost::unordered::detail::functionsdelete_nodes(prev, end); this->fix_bucket(bucket_index, prev); @@ -4062,16 +4091,14 @@ struct table : boost::unordered::detail::functionsget_previous_start(bucket_index); - while (prev->next_ != i) { - prev = node_algo::next_for_erase(prev); - } + link_pointer prev = this->get_previous_start(bucket_index); + while (prev->next_ != i) { + prev = next_for_erase(prev); } // Delete the nodes. @@ -4093,13 +4120,12 @@ struct table : boost::unordered::detail::functionshash_; - node_pointer group_end(node_algo::next_group(n, this)); + node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), key_hash, node_pointer()); - for (n = node_algo::next_node(n); n != group_end; - n = node_algo::next_node(n)) { + for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node_equiv( boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), @@ -4114,13 +4140,12 @@ struct table : boost::unordered::detail::functionshash_; - node_pointer group_end(node_algo::next_group(n, this)); + node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), key_hash, node_pointer()); - for (n = node_algo::next_node(n); n != group_end; - n = node_algo::next_node(n)) { + for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node_equiv( boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), @@ -4134,11 +4159,10 @@ struct table : boost::unordered::detail::functions holder(*this); for (node_pointer n = src.begin(); n;) { std::size_t key_hash = n->hash_; - node_pointer group_end(node_algo::next_group(n, this)); + node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( holder.copy_of(n->value()), key_hash, node_pointer()); - for (n = node_algo::next_node(n); n != group_end; - n = node_algo::next_node(n)) { + for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node_equiv(holder.copy_of(n->value()), key_hash, pos); } } @@ -4149,11 +4173,10 @@ struct table : boost::unordered::detail::functions holder(*this); for (node_pointer n = src.begin(); n;) { std::size_t key_hash = n->hash_; - node_pointer group_end(node_algo::next_group(n, this)); + node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( holder.move_copy_of(n->value()), key_hash, node_pointer()); - for (n = node_algo::next_node(n); n != group_end; - n = node_algo::next_node(n)) { + for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node_equiv( holder.move_copy_of(n->value()), key_hash, pos); } @@ -4209,7 +4232,21 @@ inline void table::rehash_impl(std::size_t num_buckets) this->create_buckets(num_buckets); link_pointer prev = this->get_previous_start(); while (prev->next_) { - node_pointer group_last = node_algo::last_for_rehash(prev); + // Group together all nodes with equal hash value, this may + // include nodes with different keys, but that's okay because + // they will end up in the same bucket. + // + // TODO: Don't do this for unique keys? + node_pointer group_last = next_node(prev); + std::size_t hash = group_last->hash_; + for (;;) { + node_pointer next = next_node(group_last); + if (!next || next->hash_ != hash) { + break; + } + group_last = next; + } + bucket_pointer b = this->get_bucket(this->hash_to_bucket(group_last->hash_)); if (!b->next_) { @@ -4419,87 +4456,6 @@ template struct ptr_node : boost::unordered::detail::ptr_bucket ptr_node& operator=(ptr_node const&); }; -template struct node_algo -{ - typedef typename N::node_pointer node_pointer; - typedef typename N::link_pointer link_pointer; - typedef typename N::bucket_pointer bucket_pointer; - - static node_pointer next_node(link_pointer n) - { - return static_cast(n->next_); - } - - static node_pointer next_for_find(node_pointer n) - { - return static_cast(n->next_); - } - - static link_pointer next_for_erase(link_pointer prev) - { - return prev->next_; - } - - // Group together all nodes with equal hash value, this may - // include nodes with different keys, but that's okay because - // they will end up in the same bucket. - static node_pointer last_for_rehash(link_pointer prev) - { - node_pointer n = next_node(prev); - std::size_t hash = n->hash_; - for (;;) { - node_pointer next = next_node(n); - if (!next || next->hash_ != hash) { - return n; - } - n = next; - } - } - - template - static node_pointer next_group(node_pointer n, Table const* t) - { - node_pointer n1 = n; - do { - n1 = next_node(n1); - } while (n1 && t->key_eq()(t->get_key(n), t->get_key(n1))); - return n1; - } - - template - static std::size_t count(node_pointer n, Table const* t) - { - std::size_t x = 0; - node_pointer it = n; - do { - ++x; - it = next_node(it); - } while (it && t->key_eq()(t->get_key(n), t->get_key(it))); - - return x; - } - - // Add node 'n' after 'pos'. - // This results in a different order to the grouped implementation. - static inline void add_to_node(node_pointer n, node_pointer pos) - { - n->next_ = pos->next_; - pos->next_ = n; - } - - static inline node_pointer extract_first_node(link_pointer prev) - { - node_pointer n = next_node(prev); - prev->next_ = n->next_; - return n; - } - - static link_pointer split_groups(node_pointer, node_pointer) - { - return link_pointer(); - } -}; - // If the allocator uses raw pointers use ptr_node // Otherwise use node. @@ -4546,7 +4502,6 @@ template struct pick_node typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; - typedef boost::unordered::detail::node_algo node_algo; }; } } diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index 13e223f3..30d8151c 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -27,7 +27,6 @@ template struct map typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; - typedef typename pick::node_algo node_algo; typedef boost::unordered::detail::table table; typedef boost::unordered::detail::map_extractor extractor; @@ -69,7 +68,6 @@ struct multimap typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; - typedef typename pick::node_algo node_algo; typedef boost::unordered::detail::table table; typedef boost::unordered::detail::map_extractor extractor; diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index edb98ece..edeeaa86 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -27,7 +27,6 @@ template struct set typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; - typedef typename pick::node_algo node_algo; typedef boost::unordered::detail::table table; typedef boost::unordered::detail::set_extractor extractor; @@ -68,7 +67,6 @@ template struct multiset typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; - typedef typename pick::node_algo node_algo; typedef boost::unordered::detail::table table; typedef boost::unordered::detail::set_extractor extractor; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index ab20642c..b268cb19 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1569,7 +1569,7 @@ unordered_map::erase(iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1580,7 +1580,7 @@ unordered_map::erase(const_iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1723,8 +1723,7 @@ std::pair::iterator, unordered_map::equal_range(const key_type& k) { node_pointer n = table_.find_node(k); - return std::make_pair( - iterator(n), iterator(n ? table::node_algo::next_node(n) : n)); + return std::make_pair(iterator(n), iterator(n ? table::next_node(n) : n)); } template @@ -1733,8 +1732,8 @@ std::pair::const_iterator, unordered_map::equal_range(const key_type& k) const { node_pointer n = table_.find_node(k); - return std::make_pair(const_iterator(n), - const_iterator(n ? table::node_algo::next_node(n) : n)); + return std::make_pair( + const_iterator(n), const_iterator(n ? table::next_node(n) : n)); } template @@ -2054,7 +2053,7 @@ unordered_multimap::erase(iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -2065,7 +2064,7 @@ unordered_multimap::erase(const_iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -2209,7 +2208,7 @@ typename unordered_multimap::size_type unordered_multimap::count(const key_type& k) const { node_pointer n = table_.find_node(k); - return n ? table::node_algo::count(n, &table_) : 0; + return n ? table_.group_count(n) : 0; } template @@ -2218,8 +2217,7 @@ std::pair::iterator, unordered_multimap::equal_range(const key_type& k) { node_pointer n = table_.find_node(k); - return std::make_pair(iterator(n), - iterator(n ? table::node_algo::next_group(n, &table_) : n)); + return std::make_pair(iterator(n), iterator(n ? table_.next_group(n) : n)); } template @@ -2228,8 +2226,8 @@ std::pair::const_iterator, unordered_multimap::equal_range(const key_type& k) const { node_pointer n = table_.find_node(k); - return std::make_pair(const_iterator(n), - const_iterator(n ? table::node_algo::next_group(n, &table_) : n)); + return std::make_pair( + const_iterator(n), const_iterator(n ? table_.next_group(n) : n)); } template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 674d4e67..b5775a77 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1242,7 +1242,7 @@ typename unordered_set::iterator unordered_set::erase( { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1368,8 +1368,8 @@ std::pair::const_iterator, unordered_set::equal_range(const key_type& k) const { node_pointer n = table_.find_node(k); - return std::make_pair(const_iterator(n), - const_iterator(n ? table::node_algo::next_node(n) : n)); + return std::make_pair( + const_iterator(n), const_iterator(n ? table::next_node(n) : n)); } template @@ -1646,7 +1646,7 @@ unordered_multiset::erase(const_iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -1772,7 +1772,7 @@ typename unordered_multiset::size_type unordered_multiset::count(const key_type& k) const { node_pointer n = table_.find_node(k); - return n ? table::node_algo::count(n, &table_) : 0; + return n ? table_.group_count(n) : 0; } template @@ -1781,8 +1781,8 @@ std::pair::const_iterator, unordered_multiset::equal_range(const key_type& k) const { node_pointer n = table_.find_node(k); - return std::make_pair(const_iterator(n), - const_iterator(n ? table::node_algo::next_group(n, &table_) : n)); + return std::make_pair( + const_iterator(n), const_iterator(n ? table_.next_group(n) : n)); } template From 408ebd0a0ad5f29b6a89f0d05f2f9756458eb37a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 27 Apr 2017 18:22:44 +0100 Subject: [PATCH 090/147] Add node_bucket function --- .../boost/unordered/detail/implementation.hpp | 65 ++++++++----------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 13c549e1..0763b567 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -2735,6 +2735,11 @@ struct table : boost::unordered::detail::functionshash_to_bucket(n->hash_); + } + bucket_allocator const& bucket_alloc() const { return allocators_.first(); } node_allocator const& node_alloc() const { return allocators_.second(); } @@ -2791,7 +2796,7 @@ struct table : boost::unordered::detail::functionshash_) == index) { + while (n && node_bucket(n) == index) { ++count; n = next_node(n); } @@ -3090,8 +3095,7 @@ struct table : boost::unordered::detail::functions(end)->hash_); + bucket_index2 = node_bucket(static_cast(end)); // If begin and end are in the same bucket, then // there's nothing to do. @@ -3259,13 +3263,10 @@ struct table : boost::unordered::detail::functionshash_; - if (key_hash == node_hash) { - if (eq(k, this->get_key(n))) - return n; - } else { - if (this->hash_to_bucket(node_hash) != bucket_index) - return node_pointer(); + if (eq(k, this->get_key(n))) { + return n; + } else if (this->node_bucket(n) != bucket_index) { + return node_pointer(); } n = next_for_find(n); @@ -3273,8 +3274,7 @@ struct table : boost::unordered::detail::functionsget_previous_start(bucket_index); if (!prev) { @@ -3285,12 +3285,9 @@ struct table : boost::unordered::detail::functionsnext_) { return link_pointer(); } - std::size_t node_hash = next_node(prev)->hash_; - if (this->hash_to_bucket(node_hash) != bucket_index) { + if (node_bucket(next_node(prev)) != bucket_index) { return link_pointer(); - } - if (node_hash == key_hash && - this->key_eq()(k, this->get_key(next_node(prev)))) { + } else if (this->key_eq()(k, this->get_key(next_node(prev)))) { return prev; } prev = next_for_erase(prev); @@ -3306,7 +3303,7 @@ struct table : boost::unordered::detail::functionshash(k); std::size_t bucket_index = this->hash_to_bucket(key_hash); - link_pointer prev = this->find_previous_node(k, key_hash, bucket_index); + link_pointer prev = this->find_previous_node(k, bucket_index); if (!prev) { return node_pointer(); } @@ -3358,9 +3355,7 @@ struct table : boost::unordered::detail::functionsget_previous_start(); if (start_node->next_) { - this->get_bucket( - this->hash_to_bucket(next_node(start_node)->hash_)) - ->next_ = n; + this->get_bucket(node_bucket(next_node(start_node)))->next_ = n; } b->next_ = start_node; @@ -3596,7 +3591,7 @@ struct table : boost::unordered::detail::functionsnext_ = n->next_; --other.size_; - other.fix_bucket(other.hash_to_bucket(n->hash_), prev); + other.fix_bucket(other.node_bucket(n), prev); this->add_node_unique(n, key_hash); } } @@ -3675,8 +3670,7 @@ struct table : boost::unordered::detail::functionshash_; - std::size_t bucket_index = this->hash_to_bucket(key_hash); + std::size_t bucket_index = this->node_bucket(n); link_pointer prev = this->get_previous_start(bucket_index); while (prev->next_ != n) { prev = prev->next_; @@ -3699,7 +3693,7 @@ struct table : boost::unordered::detail::functionshash(k); std::size_t bucket_index = this->hash_to_bucket(key_hash); - link_pointer prev = this->find_previous_node(k, key_hash, bucket_index); + link_pointer prev = this->find_previous_node(k, bucket_index); if (!prev) return 0; link_pointer end = next_node(prev)->next_; @@ -3710,7 +3704,7 @@ struct table : boost::unordered::detail::functionshash_to_bucket(i->hash_); + std::size_t bucket_index = this->node_bucket(i); // Find the node before i. link_pointer prev = this->get_previous_start(bucket_index); @@ -3867,8 +3861,7 @@ struct table : boost::unordered::detail::functionsnext_ = pos->next_; pos->next_ = n; if (n->next_) { - std::size_t next_bucket = - this->hash_to_bucket(next_node(n)->hash_); + std::size_t next_bucket = this->node_bucket(next_node(n)); if (next_bucket != this->hash_to_bucket(key_hash)) { this->get_bucket(next_bucket)->next_ = n; } @@ -3880,8 +3873,7 @@ struct table : boost::unordered::detail::functionsget_previous_start(); if (start_node->next_) { - this->get_bucket( - this->hash_to_bucket(next_node(start_node)->hash_)) + this->get_bucket(this->node_bucket(next_node(start_node))) ->next_ = n; } @@ -3903,8 +3895,8 @@ struct table : boost::unordered::detail::functionsnext_ = hint->next_; hint->next_ = n; if (n->next_ != hint && n->next_) { - std::size_t next_bucket = this->hash_to_bucket(next_node(n)->hash_); - if (next_bucket != this->hash_to_bucket(n->hash_)) { + std::size_t next_bucket = this->node_bucket(next_node(n)); + if (next_bucket != this->node_bucket(n)) { this->get_bucket(next_bucket)->next_ = n; } } @@ -4038,7 +4030,7 @@ struct table : boost::unordered::detail::functionshash_to_bucket(i->hash_); + std::size_t bucket_index = this->node_bucket(i); // Split the groups containing 'i' and 'j'. // And get the pointer to the node before i while // we're at it. @@ -4072,7 +4064,7 @@ struct table : boost::unordered::detail::functionshash(k); std::size_t bucket_index = this->hash_to_bucket(key_hash); - link_pointer prev = this->find_previous_node(k, key_hash, bucket_index); + link_pointer prev = this->find_previous_node(k, bucket_index); if (!prev) return 0; @@ -4086,7 +4078,7 @@ struct table : boost::unordered::detail::functionshash_to_bucket(i->hash_); + std::size_t bucket_index = this->node_bucket(i); // Split the groups containing 'i' and 'j'. // And get the pointer to the node before i while @@ -4247,8 +4239,7 @@ inline void table::rehash_impl(std::size_t num_buckets) group_last = next; } - bucket_pointer b = - this->get_bucket(this->hash_to_bucket(group_last->hash_)); + bucket_pointer b = this->get_bucket(this->node_bucket(group_last)); if (!b->next_) { b->next_ = prev; prev = group_last; From a1b1df84a0014cb5f0d148f72614c692d1307ce5 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 27 Apr 2017 18:22:44 +0100 Subject: [PATCH 091/147] Store bucket + whether first in group in node Instead of the hash value. --- .../boost/unordered/detail/implementation.hpp | 216 ++++++++++++------ test/helpers/invariants.hpp | 34 +-- 2 files changed, 162 insertions(+), 88 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 0763b567..1f4c9166 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1935,7 +1935,7 @@ struct l_iterator : public std::iterator(ptr_->next_); - if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) != bucket_) + if (ptr_ && ptr_->get_bucket() != bucket_) ptr_ = node_pointer(); return *this; } @@ -1999,7 +1999,7 @@ struct cl_iterator cl_iterator& operator++() { ptr_ = static_cast(ptr_->next_); - if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) != bucket_) + if (ptr_ && ptr_->get_bucket() != bucket_) ptr_ = node_pointer(); return *this; } @@ -2706,7 +2706,11 @@ struct table : boost::unordered::detail::functions(n->next_); + node_pointer n2 = static_cast(n); + do { + n2 = next_node(n2); + } while (n2 && !n2->is_first_in_group()); + return n2; } static link_pointer next_for_erase(link_pointer prev) @@ -2719,7 +2723,7 @@ struct table : boost::unordered::detail::functionskey_eq()(get_key(n), get_key(n1))); + } while (n1 && !n1->is_first_in_group()); return n1; } @@ -2730,15 +2734,12 @@ struct table : boost::unordered::detail::functionskey_eq()(get_key(n), get_key(it))); + } while (it && !it->is_first_in_group()); return x; } - std::size_t node_bucket(node_pointer n) const - { - return this->hash_to_bucket(n->hash_); - } + std::size_t node_bucket(node_pointer n) const { return n->get_bucket(); } bucket_allocator const& bucket_alloc() const { return allocators_.first(); } @@ -3282,15 +3283,17 @@ struct table : boost::unordered::detail::functionsnext_) { + node_pointer n = next_node(prev); + if (!n) { return link_pointer(); + } else if (n->is_first_in_group()) { + if (node_bucket(n) != bucket_index) { + return link_pointer(); + } else if (this->key_eq()(k, this->get_key(n))) { + return prev; + } } - if (node_bucket(next_node(prev)) != bucket_index) { - return link_pointer(); - } else if (this->key_eq()(k, this->get_key(next_node(prev)))) { - return prev; - } - prev = next_for_erase(prev); + prev = n; } } @@ -3308,7 +3311,11 @@ struct table : boost::unordered::detail::functionsnext_ = n->next_; + node_pointer n2 = next_node(n); + if (n2) { + n2->set_first_in_group(); + } + prev->next_ = n2; --this->size_; this->fix_bucket(bucket_index, prev); n->next_ = link_pointer(); @@ -3347,9 +3354,12 @@ struct table : boost::unordered::detail::functionshash_ = key_hash; + std::size_t bucket = this->hash_to_bucket(key_hash); + bucket_pointer b = this->get_bucket(bucket); - bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash)); + // TODO: Do this need to set_first_in_group ? + n->bucket_info_ = bucket; + n->set_first_in_group(); if (!b->next_) { link_pointer start_node = this->get_previous_start(); @@ -3567,6 +3577,8 @@ struct table : boost::unordered::detail::functions void merge_unique(boost::unordered::detail::table& other) { @@ -3588,8 +3600,10 @@ struct table : boost::unordered::detail::functionsreserve_for_insert(this->size_ + 1); - // other_table::split_groups(n, other_table::next_node(n)); prev->next_ = n->next_; + if (prev->next_ && n->is_first_in_group()) { + next_node(prev)->set_first_in_group(); + } --other.size_; other.fix_bucket(other.node_bucket(n), prev); this->add_node_unique(n, key_hash); @@ -3726,10 +3740,11 @@ struct table : boost::unordered::detail::functionscreate_buckets(this->bucket_count_); for (node_pointer n = src.begin(); n; n = next_node(n)) { + std::size_t key_hash = this->hash(this->get_key(n)); this->add_node_unique( boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), - n->hash_); + key_hash); } } @@ -3739,10 +3754,11 @@ struct table : boost::unordered::detail::functionscreate_buckets(this->bucket_count_); for (node_pointer n = src.begin(); n; n = next_node(n)) { + std::size_t key_hash = this->hash(this->get_key(n)); this->add_node_unique( boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), - n->hash_); + key_hash); } } @@ -3750,7 +3766,8 @@ struct table : boost::unordered::detail::functions holder(*this); for (node_pointer n = src.begin(); n; n = next_node(n)) { - this->add_node_unique(holder.copy_of(n->value()), n->hash_); + std::size_t key_hash = this->hash(this->get_key(n)); + this->add_node_unique(holder.copy_of(n->value()), key_hash); } } @@ -3758,7 +3775,8 @@ struct table : boost::unordered::detail::functions holder(*this); for (node_pointer n = src.begin(); n; n = next_node(n)) { - this->add_node_unique(holder.move_copy_of(n->value()), n->hash_); + std::size_t key_hash = this->hash(this->get_key(n)); + this->add_node_unique(holder.move_copy_of(n->value()), key_hash); } } @@ -3856,18 +3874,21 @@ struct table : boost::unordered::detail::functionshash_ = key_hash; + std::size_t bucket = this->hash_to_bucket(key_hash); + n->bucket_info_ = bucket; + if (pos) { n->next_ = pos->next_; pos->next_ = n; if (n->next_) { std::size_t next_bucket = this->node_bucket(next_node(n)); - if (next_bucket != this->hash_to_bucket(key_hash)) { + if (next_bucket != bucket) { this->get_bucket(next_bucket)->next_ = n; } } } else { - bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash)); + n->set_first_in_group(); + bucket_pointer b = this->get_bucket(bucket); if (!b->next_) { link_pointer start_node = this->get_previous_start(); @@ -3891,7 +3912,8 @@ struct table : boost::unordered::detail::functionshash_ = hint->hash_; + n->bucket_info_ = hint->bucket_info_; + n->reset_first_in_group(); n->next_ = hint->next_; hint->next_ = n; if (n->next_ != hint && n->next_) { @@ -4031,20 +4053,16 @@ struct table : boost::unordered::detail::functionsnode_bucket(i); - // Split the groups containing 'i' and 'j'. - // And get the pointer to the node before i while - // we're at it. - // link_pointer prev = split_groups(i, j); - // If we don't have a 'prev' it means that i is at the - // beginning of a block, so search through the blocks in the - // same bucket. link_pointer prev = this->get_previous_start(bucket_index); while (prev->next_ != i) { prev = next_for_erase(prev); } prev->next_ = i->next_; + if (j && i->is_first_in_group()) { + j->set_first_in_group(); + } --this->size_; this->fix_bucket(bucket_index, prev); i->next_ = link_pointer(); @@ -4080,14 +4098,6 @@ struct table : boost::unordered::detail::functionsnode_bucket(i); - // Split the groups containing 'i' and 'j'. - // And get the pointer to the node before i while - // we're at it. - // link_pointer prev = split_groups(i, j); - - // If we don't have a 'prev' it means that i is at the - // beginning of a block, so search through the blocks in the - // same bucket. link_pointer prev = this->get_previous_start(bucket_index); while (prev->next_ != i) { prev = next_for_erase(prev); @@ -4095,10 +4105,16 @@ struct table : boost::unordered::detail::functionsis_first_in_group(); this->delete_node(prev); bucket_index = this->fix_bucket(bucket_index, prev); } while (prev->next_ != j); + if (j && includes_first) { + j->set_first_in_group(); + } return prev; } @@ -4111,7 +4127,7 @@ struct table : boost::unordered::detail::functionscreate_buckets(this->bucket_count_); for (node_pointer n = src.begin(); n;) { - std::size_t key_hash = n->hash_; + std::size_t key_hash = this->hash(this->get_key(n)); node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( boost::unordered::detail::func::construct_node( @@ -4131,7 +4147,7 @@ struct table : boost::unordered::detail::functionscreate_buckets(this->bucket_count_); for (node_pointer n = src.begin(); n;) { - std::size_t key_hash = n->hash_; + std::size_t key_hash = this->hash(this->get_key(n)); node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( boost::unordered::detail::func::construct_node( @@ -4150,7 +4166,7 @@ struct table : boost::unordered::detail::functions holder(*this); for (node_pointer n = src.begin(); n;) { - std::size_t key_hash = n->hash_; + std::size_t key_hash = this->hash(this->get_key(n)); node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( holder.copy_of(n->value()), key_hash, node_pointer()); @@ -4164,7 +4180,7 @@ struct table : boost::unordered::detail::functions holder(*this); for (node_pointer n = src.begin(); n;) { - std::size_t key_hash = n->hash_; + std::size_t key_hash = this->hash(this->get_key(n)); node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( holder.move_copy_of(n->value()), key_hash, node_pointer()); @@ -4223,33 +4239,43 @@ inline void table::rehash_impl(std::size_t num_buckets) this->create_buckets(num_buckets); link_pointer prev = this->get_previous_start(); - while (prev->next_) { - // Group together all nodes with equal hash value, this may - // include nodes with different keys, but that's okay because - // they will end up in the same bucket. - // - // TODO: Don't do this for unique keys? - node_pointer group_last = next_node(prev); - std::size_t hash = group_last->hash_; - for (;;) { - node_pointer next = next_node(group_last); - if (!next || next->hash_ != hash) { - break; - } - group_last = next; - } + BOOST_TRY + { + while (prev->next_) { + node_pointer n = next_node(prev); + std::size_t key_hash = this->hash(this->get_key(n)); + std::size_t bucket_index = this->hash_to_bucket(key_hash); - bucket_pointer b = this->get_bucket(this->node_bucket(group_last)); - if (!b->next_) { - b->next_ = prev; - prev = group_last; - } else { - link_pointer next = group_last->next_; - group_last->next_ = b->next_->next_; - b->next_->next_ = prev->next_; - prev->next_ = next; + n->bucket_info_ = bucket_index; + n->set_first_in_group(); + + // Iterator through the rest of the group of equal nodes, + // setting the bucket. + for (;;) { + node_pointer next = next_node(n); + if (!next || next->is_first_in_group()) { + break; + } + n = next; + n->bucket_info_ = bucket_index; + // n->reset_first_in_group(); + } + + // n is now the last node in the group + bucket_pointer b = this->get_bucket(bucket_index); + if (!b->next_) { + b->next_ = prev; + prev = n; + } else { + link_pointer next = n->next_; + n->next_ = b->next_->next_; + b->next_->next_ = prev->next_; + prev->next_ = next; + } } } + BOOST_CATCH(...) { delete_nodes(prev, link_pointer()); } + BOOST_CATCH_END } #if defined(BOOST_MSVC) @@ -4414,12 +4440,32 @@ struct node : boost::unordered::detail::value_base bucket_allocator>::pointer bucket_pointer; link_pointer next_; - std::size_t hash_; + std::size_t bucket_info_; - node() : next_(), hash_(0) {} + node() : next_(), bucket_info_(0) {} void init(node_pointer) {} + std::size_t get_bucket() const + { + return bucket_info_ & ((std::size_t)-1 >> 1); + } + + std::size_t is_first_in_group() const + { + return bucket_info_ & ~((std::size_t)-1 >> 1); + } + + void set_first_in_group() + { + bucket_info_ = bucket_info_ | ~((std::size_t)-1 >> 1); + } + + void reset_first_in_group() + { + bucket_info_ = bucket_info_ & ((std::size_t)-1 >> 1); + } + private: node& operator=(node const&); }; @@ -4432,10 +4478,10 @@ template struct ptr_node : boost::unordered::detail::ptr_bucket typedef ptr_bucket* link_pointer; typedef ptr_bucket* bucket_pointer; - std::size_t hash_; + std::size_t bucket_info_; boost::unordered::detail::value_base value_base_; - ptr_node() : bucket_base(), hash_(0) {} + ptr_node() : bucket_base(), bucket_info_(0) {} void init(node_pointer) {} @@ -4443,6 +4489,26 @@ template struct ptr_node : boost::unordered::detail::ptr_bucket value_type& value() { return value_base_.value(); } value_type* value_ptr() { return value_base_.value_ptr(); } + std::size_t get_bucket() const + { + return bucket_info_ & ((std::size_t)-1 >> 1); + } + + std::size_t is_first_in_group() const + { + return bucket_info_ & ~((std::size_t)-1 >> 1); + } + + void set_first_in_group() + { + bucket_info_ = bucket_info_ | ~((std::size_t)-1 >> 1); + } + + void reset_first_in_group() + { + bucket_info_ = bucket_info_ & ((std::size_t)-1 >> 1); + } + private: ptr_node& operator=(ptr_node const&); }; diff --git a/test/helpers/invariants.hpp b/test/helpers/invariants.hpp index ffc5de4e..06091b94 100644 --- a/test/helpers/invariants.hpp +++ b/test/helpers/invariants.hpp @@ -63,20 +63,28 @@ template void check_equivalent_keys(X const& x1) BOOST_DEDUCED_TYPENAME X::size_type bucket = x1.bucket(key); BOOST_DEDUCED_TYPENAME X::const_local_iterator lit = x1.begin(bucket), lend = x1.end(bucket); - for (; lit != lend && !eq(get_key(*lit), key); ++lit) - continue; - if (lit == lend) + + unsigned int count_checked = 0; + for (; lit != lend && !eq(get_key(*lit), key); ++lit) { + ++count_checked; + } + + if (lit == lend) { BOOST_ERROR("Unable to find element with a local_iterator"); - unsigned int count2 = 0; - for (; lit != lend && eq(get_key(*lit), key); ++lit) - ++count2; - if (count != count2) - BOOST_ERROR("Element count doesn't match local_iterator."); - for (; lit != lend; ++lit) { - if (eq(get_key(*lit), key)) { - BOOST_ERROR("Non-adjacent element with equivalent key " - "in bucket."); - break; + std::cerr << "Checked: " << count_checked << " elements" + << std::endl; + } else { + unsigned int count2 = 0; + for (; lit != lend && eq(get_key(*lit), key); ++lit) + ++count2; + if (count != count2) + BOOST_ERROR("Element count doesn't match local_iterator."); + for (; lit != lend; ++lit) { + if (eq(get_key(*lit), key)) { + BOOST_ERROR("Non-adjacent element with equivalent key " + "in bucket."); + break; + } } } }; From 20b0c0a6d8cf70faefe5dac5cea23218a76344d3 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 27 Apr 2017 18:22:44 +0100 Subject: [PATCH 092/147] Only consider one node from each group in merge_unique --- .../boost/unordered/detail/implementation.hpp | 55 ++++++++++++------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 1f4c9166..25aa1f34 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3577,8 +3577,6 @@ struct table : boost::unordered::detail::functions void merge_unique(boost::unordered::detail::table& other) { @@ -3587,26 +3585,45 @@ struct table : boost::unordered::detail::functions::value)); BOOST_ASSERT(this->node_alloc() == other.node_alloc()); - if (other.size_) { - link_pointer prev = other.get_previous_start(); + if (!other.size_) { + return; + } - while (prev->next_) { - node_pointer n = other_table::next_node(prev); - const_key_type& k = this->get_key(n); - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); + link_pointer prev = other.get_previous_start(); + node_pointer n = other_table::next_node(prev); + while (n) { + const_key_type& k = this->get_key(n); + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); - if (pos) { + if (pos) { + prev = n; + n = other_table::next_node(prev); + } else { + this->reserve_for_insert(this->size_ + 1); + + prev->next_ = n->next_; + --other.size_; + other.fix_bucket(other.node_bucket(n), prev); + this->add_node_unique(n, key_hash); + n = other_table::next_node(prev); + + // If the next node was from the same group, it's now + // the first node in the group. + if (n && !n->is_first_in_group()) { + n->set_first_in_group(); prev = n; - } else { - this->reserve_for_insert(this->size_ + 1); - prev->next_ = n->next_; - if (prev->next_ && n->is_first_in_group()) { - next_node(prev)->set_first_in_group(); - } - --other.size_; - other.fix_bucket(other.node_bucket(n), prev); - this->add_node_unique(n, key_hash); + n = other_table::next_node(prev); + } + } + + // Skip over rest of group of nodes with equivalent keys, + // as we know there's already one in the container. + while (n && !n->is_first_in_group()) { + prev = n; + n = other_table::next_node(prev); + if (!n) { + return; } } } From f1435d53d4b421b8692cc3903de9db2a2a2db777 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 27 Apr 2017 18:22:44 +0100 Subject: [PATCH 093/147] Remove 'init' method from nodes --- include/boost/unordered/detail/implementation.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 25aa1f34..0f5f6807 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1691,7 +1691,6 @@ template void node_constructor::create_node() BOOST_UNORDERED_CALL_CONSTRUCT0( node_allocator_traits, alloc_, boost::addressof(*node_)); - node_->init(node_); node_constructed_ = true; } @@ -2182,7 +2181,6 @@ template struct node_holder { node_pointer n = nodes_; nodes_ = static_cast(nodes_->next_); - n->init(n); n->next_ = link_pointer(); return n; } @@ -4461,8 +4459,6 @@ struct node : boost::unordered::detail::value_base node() : next_(), bucket_info_(0) {} - void init(node_pointer) {} - std::size_t get_bucket() const { return bucket_info_ & ((std::size_t)-1 >> 1); @@ -4500,8 +4496,6 @@ template struct ptr_node : boost::unordered::detail::ptr_bucket ptr_node() : bucket_base(), bucket_info_(0) {} - void init(node_pointer) {} - void* address() { return value_base_.address(); } value_type& value() { return value_base_.value(); } value_type* value_ptr() { return value_base_.value_ptr(); } From 03baef8b2865bf897061fa11db40c6398447cb52 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 27 Apr 2017 18:22:44 +0100 Subject: [PATCH 094/147] Remove Types::is_unique --- .../boost/unordered/detail/implementation.hpp | 34 ++++++++++--------- include/boost/unordered/detail/map.hpp | 8 ----- include/boost/unordered/detail/set.hpp | 8 ----- include/boost/unordered/unordered_map.hpp | 16 ++++----- include/boost/unordered/unordered_set.hpp | 16 ++++----- 5 files changed, 34 insertions(+), 48 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 0f5f6807..ae4ba6ca 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3116,16 +3116,17 @@ struct table : boost::unordered::detail::functions:: - propagate_on_container_copy_assignment::value>()); + assign(x, is_unique, + boost::unordered::detail::integral_constant:: + propagate_on_container_copy_assignment::value>()); } } - void assign(table const& x, false_type) + void assign(table const& x, bool is_unique, false_type) { // Strong exception safety. set_hash_functions new_func_this(*this, x); @@ -3140,18 +3141,18 @@ struct table : boost::unordered::detail::functions:: - propagate_on_container_move_assignment::value>()); + x, is_unique, + boost::unordered::detail::integral_constant:: + propagate_on_container_move_assignment::value>()); } } - void move_assign(table& x, true_type) + void move_assign(table& x, bool /* is_unique */, true_type) { delete_buckets(); set_hash_functions new_func_this(*this, x); @@ -3197,7 +3199,7 @@ struct table : boost::unordered::detail::functions struct map typedef boost::unordered::detail::table table; typedef boost::unordered::detail::map_extractor extractor; - enum - { - is_unique = true - }; typedef typename boost::unordered::detail::pick_policy::type policy; @@ -71,10 +67,6 @@ struct multimap typedef boost::unordered::detail::table table; typedef boost::unordered::detail::map_extractor extractor; - enum - { - is_unique = false - }; typedef typename boost::unordered::detail::pick_policy::type policy; diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index edeeaa86..12949652 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -30,10 +30,6 @@ template struct set typedef boost::unordered::detail::table table; typedef boost::unordered::detail::set_extractor extractor; - enum - { - is_unique = true - }; typedef typename boost::unordered::detail::pick_policy::type policy; @@ -70,10 +66,6 @@ template struct multiset typedef boost::unordered::detail::table table; typedef boost::unordered::detail::set_extractor extractor; - enum - { - is_unique = false - }; typedef typename boost::unordered::detail::pick_policy::type policy; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index b268cb19..d0e3eae6 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -146,7 +146,7 @@ template class unordered_map #if defined(BOOST_UNORDERED_USE_MOVE) unordered_map& operator=(BOOST_COPY_ASSIGN_REF(unordered_map) x) { - table_.assign(x.table_); + table_.assign(x.table_, true); return *this; } @@ -156,13 +156,13 @@ template class unordered_map // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, true); return *this; } #else unordered_map& operator=(unordered_map const& x) { - table_.assign(x.table_); + table_.assign(x.table_, true); return *this; } @@ -173,7 +173,7 @@ template class unordered_map // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, true); return *this; } #endif @@ -950,7 +950,7 @@ template class unordered_multimap #if defined(BOOST_UNORDERED_USE_MOVE) unordered_multimap& operator=(BOOST_COPY_ASSIGN_REF(unordered_multimap) x) { - table_.assign(x.table_); + table_.assign(x.table_, false); return *this; } @@ -960,13 +960,13 @@ template class unordered_multimap // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, false); return *this; } #else unordered_multimap& operator=(unordered_multimap const& x) { - table_.assign(x.table_); + table_.assign(x.table_, false); return *this; } @@ -977,7 +977,7 @@ template class unordered_multimap // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, false); return *this; } #endif diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index b5775a77..1821b3ca 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -144,7 +144,7 @@ template class unordered_set #if defined(BOOST_UNORDERED_USE_MOVE) unordered_set& operator=(BOOST_COPY_ASSIGN_REF(unordered_set) x) { - table_.assign(x.table_); + table_.assign(x.table_, true); return *this; } @@ -154,13 +154,13 @@ template class unordered_set // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, true); return *this; } #else unordered_set& operator=(unordered_set const& x) { - table_.assign(x.table_); + table_.assign(x.table_, true); return *this; } @@ -171,7 +171,7 @@ template class unordered_set // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, true); return *this; } #endif @@ -654,7 +654,7 @@ template class unordered_multiset #if defined(BOOST_UNORDERED_USE_MOVE) unordered_multiset& operator=(BOOST_COPY_ASSIGN_REF(unordered_multiset) x) { - table_.assign(x.table_); + table_.assign(x.table_, false); return *this; } @@ -664,13 +664,13 @@ template class unordered_multiset // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, false); return *this; } #else unordered_multiset& operator=(unordered_multiset const& x) { - table_.assign(x.table_); + table_.assign(x.table_, false); return *this; } @@ -681,7 +681,7 @@ template class unordered_multiset // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, false); return *this; } #endif From 6466ce0b518b02a490edcb569edf06799248d212 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 27 Apr 2017 18:22:44 +0100 Subject: [PATCH 095/147] Make table the same for unique and equivalent keys --- include/boost/unordered/detail/map.hpp | 35 ----------------------- include/boost/unordered/detail/set.hpp | 34 ---------------------- include/boost/unordered/unordered_map.hpp | 2 +- include/boost/unordered/unordered_set.hpp | 2 +- 4 files changed, 2 insertions(+), 71 deletions(-) diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index 2547196e..4568e75f 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -45,41 +45,6 @@ template struct map insert_return_type; }; -template -struct multimap -{ - typedef boost::unordered::detail::multimap types; - - typedef std::pair value_type; - typedef H hasher; - typedef P key_equal; - typedef K const const_key_type; - - typedef typename ::boost::unordered::detail::rebind_wrap::type value_allocator; - typedef boost::unordered::detail::allocator_traits - value_allocator_traits; - - typedef boost::unordered::detail::pick_node pick; - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - - typedef boost::unordered::detail::table table; - typedef boost::unordered::detail::map_extractor 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; - - typedef boost::unordered::node_handle_map node_type; -}; - template class instantiate_map { diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index 12949652..fc13fa17 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -45,40 +45,6 @@ template struct set insert_return_type; }; -template struct multiset -{ - typedef boost::unordered::detail::multiset types; - - typedef T value_type; - typedef H hasher; - typedef P key_equal; - typedef T const const_key_type; - - typedef typename ::boost::unordered::detail::rebind_wrap::type value_allocator; - typedef boost::unordered::detail::allocator_traits - value_allocator_traits; - - typedef boost::unordered::detail::pick_node pick; - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - - typedef boost::unordered::detail::table table; - 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; - - typedef boost::unordered::node_handle_set node_type; -}; - template class instantiate_set { typedef boost::unordered_set container; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index d0e3eae6..6291c3dc 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -856,7 +856,7 @@ template class unordered_multimap typedef A allocator_type; private: - typedef boost::unordered::detail::multimap types; + typedef boost::unordered::detail::map types; typedef typename types::value_allocator_traits value_allocator_traits; typedef typename types::table table; typedef typename table::node_pointer node_pointer; diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 1821b3ca..bbd07f60 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -560,7 +560,7 @@ template class unordered_multiset typedef A allocator_type; private: - typedef boost::unordered::detail::multiset types; + typedef boost::unordered::detail::set types; typedef typename types::value_allocator_traits value_allocator_traits; typedef typename types::table table; typedef typename table::node_pointer node_pointer; From 0b61e6defb3bed12e16ade2b0cf5b722be3f0f05 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 27 Apr 2017 18:51:38 +0100 Subject: [PATCH 096/147] Stop using allocators to construct/destroy internal types The standard doesn't allow it. I should have known that. --- .../boost/unordered/detail/implementation.hpp | 40 +++++++------------ 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index ae4ba6ca..50d4fb0f 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1674,8 +1674,7 @@ template node_constructor::~node_constructor() { if (node_) { if (node_constructed_) { - BOOST_UNORDERED_CALL_DESTROY( - node_allocator_traits, alloc_, boost::addressof(*node_)); + boost::unordered::detail::func::destroy(boost::addressof(*node_)); } node_allocator_traits::deallocate(alloc_, node_, 1); @@ -1689,8 +1688,7 @@ template void node_constructor::create_node() node_ = node_allocator_traits::allocate(alloc_, 1); - BOOST_UNORDERED_CALL_CONSTRUCT0( - node_allocator_traits, alloc_, boost::addressof(*node_)); + new (boost::addressof(*node_)) node(); node_constructed_ = true; } @@ -1721,8 +1719,7 @@ template node_tmp::~node_tmp() if (node_) { BOOST_UNORDERED_CALL_DESTROY( node_allocator_traits, alloc_, node_->value_ptr()); - BOOST_UNORDERED_CALL_DESTROY( - node_allocator_traits, alloc_, boost::addressof(*node_)); + boost::unordered::detail::func::destroy(boost::addressof(*node_)); node_allocator_traits::deallocate(alloc_, node_, 1); } } @@ -2221,8 +2218,7 @@ template node_holder::~node_holder() BOOST_UNORDERED_CALL_DESTROY( node_allocator_traits, constructor_.alloc_, p->value_ptr()); - BOOST_UNORDERED_CALL_DESTROY( - node_allocator_traits, constructor_.alloc_, boost::addressof(*p)); + boost::unordered::detail::func::destroy(boost::addressof(*p)); node_allocator_traits::deallocate(constructor_.alloc_, p, 1); } } @@ -2913,20 +2909,21 @@ struct table : boost::unordered::detail::functions(new_count); for (; constructed != end; ++constructed) { - BOOST_UNORDERED_CALL_CONSTRUCT0(bucket_allocator_traits, - bucket_alloc(), boost::addressof(*constructed)); + new (boost::addressof(*constructed)) bucket(); } if (buckets_) { // Copy the nodes to the new buckets, including the dummy // node if there is one. - BOOST_UNORDERED_CALL_CONSTRUCT1(bucket_allocator_traits, - bucket_alloc(), boost::addressof(*constructed), + new (boost::addressof(*constructed)) bucket( (buckets_ + static_cast(bucket_count_)) ->next_); ++constructed; @@ -2935,21 +2932,17 @@ struct table : boost::unordered::detail::functionsvalue_ptr()); - BOOST_UNORDERED_CALL_DESTROY( - node_allocator_traits, node_alloc(), boost::addressof(*n)); + boost::unordered::detail::func::destroy(boost::addressof(*n)); node_allocator_traits::deallocate(node_alloc(), n, 1); --size_; } @@ -3059,8 +3051,7 @@ struct table : boost::unordered::detail::functions(get_bucket(bucket_count_)->next_); - BOOST_UNORDERED_CALL_DESTROY( - node_allocator_traits, node_alloc(), boost::addressof(*n)); + boost::unordered::detail::func::destroy(boost::addressof(*n)); node_allocator_traits::deallocate(node_alloc(), n, 1); } @@ -3076,8 +3067,7 @@ struct table : boost::unordered::detail::functions Date: Fri, 28 Apr 2017 09:53:50 +0100 Subject: [PATCH 097/147] Remove BOOST_UNORDERED_CALL_CONSTRUCT0 --- include/boost/unordered/detail/implementation.hpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 50d4fb0f..ee6d8d0c 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1263,8 +1263,6 @@ namespace func { #if BOOST_UNORDERED_CXX11_CONSTRUCTION -#define BOOST_UNORDERED_CALL_CONSTRUCT0(Traits, alloc, address) \ - Traits::construct(alloc, address) #define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \ Traits::construct(alloc, address, a0) #define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) Traits::destroy(alloc, x) @@ -1277,8 +1275,6 @@ inline void construct_value(T* address, BOOST_FWD_REF(Args)... args) new ((void*)address) T(boost::forward(args)...); } -#define BOOST_UNORDERED_CALL_CONSTRUCT0(Traits, alloc, address) \ - boost::unordered::detail::func::construct_value(address) #define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \ boost::unordered::detail::func::construct_value(address, a0) #define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) \ @@ -1297,8 +1293,6 @@ inline void construct_value(T* address, BOOST_FWD_REF(A0) a0) new ((void*)address) T(boost::forward(a0)); } -#define BOOST_UNORDERED_CALL_CONSTRUCT0(Traits, alloc, address) \ - boost::unordered::detail::func::construct_value(address) #define BOOST_UNORDERED_CALL_CONSTRUCT1(Traits, alloc, address, a0) \ boost::unordered::detail::func::construct_value(address, a0) #define BOOST_UNORDERED_CALL_DESTROY(Traits, alloc, x) \ @@ -4570,7 +4564,6 @@ template struct pick_node #undef BOOST_UNORDERED_EMPLACE_TEMPLATE #undef BOOST_UNORDERED_EMPLACE_ARGS #undef BOOST_UNORDERED_EMPLACE_FORWARD -#undef BOOST_UNORDERED_CALL_CONSTRUCT0 #undef BOOST_UNORDERED_CALL_CONSTRUCT1 #undef BOOST_UNORDERED_CALL_DESTROY From bfcdd51b4ac799821fb5c86167923d4bf94f039f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 28 Apr 2017 09:53:50 +0100 Subject: [PATCH 098/147] Fix try_emplace overload --- include/boost/unordered/unordered_map.hpp | 10 ++++------ test/unordered/insert_tests.cpp | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 6291c3dc..4cd2ebe7 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -563,12 +563,10 @@ template class unordered_map iterator try_emplace(const_iterator hint, key_type const& k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_ - .try_emplace_unique( - hint, k, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))) - .first; + return table_.try_emplace_hint_unique( + hint, k, boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))); } // try_emplace(key&&, Args&&...) diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index a53f43c3..b5c2fffb 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -1172,6 +1172,23 @@ UNORDERED_AUTO_TEST(map_emplace_test2) BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && x.find(overloaded_constructor(2, 3))->second == overloaded_constructor(4, 5, 6)); + + x.clear(); + + x.try_emplace(x.begin(), overloaded_constructor()); + BOOST_TEST(x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == + overloaded_constructor()); + + x.try_emplace(x.end(), 1); + BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == + overloaded_constructor()); + + x.try_emplace(x.begin(), overloaded_constructor(2, 3), 4, 5, 6); + BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && + x.find(overloaded_constructor(2, 3))->second == + overloaded_constructor(4, 5, 6)); } { From 5f6ee3da9c9b8b65fcdc65410f2c7715ce961be7 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 28 Apr 2017 09:53:50 +0100 Subject: [PATCH 099/147] Use coveralls --- .travis.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index db516156..14c0168a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,11 +20,13 @@ matrix: - compiler: gcc env: | label="gcc C++03"; - user_config="using gcc : : g++-4.8 -fsanitize=address -Werror --std=c++03 ;" + user_config="using gcc : : g++-4.8 --coverage -fsanitize=address -Werror --std=c++03 ;" + enable_coverage=1 - compiler: gcc env: | label="gcc C++11"; - user_config="using gcc : : g++-4.8 -fsanitize=address -Werror --std=c++11 ;" + user_config="using gcc : : g++-4.8 --coverage -fsanitize=address -Werror --std=c++11 ;" + enable_coverage=1 - compiler: gcc env: | label="gcc 32 bit C++11"; @@ -39,6 +41,9 @@ matrix: label="clang 32 bit"; user_config="using clang : : clang++ -m32 -Werror --std=c++03 ;" +before_install: + - if [ -n $enable_coverage ]; then pip install --user cpp-coveralls; fi + before_script: - cd ${TRAVIS_BUILD_DIR} - touch Jamroot.jam @@ -50,6 +55,9 @@ before_script: - mv boost_1_64_0 boost - rm -r boost/boost/unordered +after_success: + if [ -n $enable_coverage ]; then coveralls -r ${TRAVIS_BUILD_DIR} -b ${TRAVIS_BUILD_DIR}/test --gcov-options '\-lp' --include include/boost/unordered/ ; fi + script: - cd ${TRAVIS_BUILD_DIR}/test - bjam -q include=${HOME}/boost include=${TRAVIS_BUILD_DIR}/include From cae6b121b2b19077e1aeca720f7bdbf9e66ba099 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 28 Apr 2017 21:06:03 +0100 Subject: [PATCH 100/147] Improve test coverage a little --- test/Jamfile.v2 | 1 + test/unordered/at_tests.cpp | 23 ++++ test/unordered/compile_tests.hpp | 30 +++++- test/unordered/detail_tests.cpp | 104 ++++++++++++++++++ test/unordered/insert_tests.cpp | 176 +++++++++++++++++++++++++------ 5 files changed, 298 insertions(+), 36 deletions(-) create mode 100644 test/unordered/detail_tests.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 72c09867..25d1cde4 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -62,6 +62,7 @@ test-suite unordered [ run unordered/rehash_tests.cpp ] [ run unordered/equality_tests.cpp ] [ run unordered/swap_tests.cpp ] + [ run unordered/detail_tests.cpp ] [ run unordered/compile_set.cpp : : : BOOST_UNORDERED_USE_MOVE diff --git a/test/unordered/at_tests.cpp b/test/unordered/at_tests.cpp index 11c0aa75..a948aeff 100644 --- a/test/unordered/at_tests.cpp +++ b/test/unordered/at_tests.cpp @@ -19,6 +19,21 @@ UNORDERED_AUTO_TEST(at_tests) BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Create Map" << std::endl; boost::unordered_map x; + boost::unordered_map const& x_const(x); + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check empty container" << std::endl; + + try { + x.at("one"); + BOOST_ERROR("Should have thrown."); + } catch (std::out_of_range) { + } + + try { + x_const.at("one"); + BOOST_ERROR("Should have thrown."); + } catch (std::out_of_range) { + } BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Add elements" << std::endl; @@ -29,6 +44,8 @@ UNORDERED_AUTO_TEST(at_tests) BOOST_TEST(x.at("one") == 1); BOOST_TEST(x.at("two") == 2); + BOOST_TEST(x_const.at("one") == 1); + BOOST_TEST(x_const.at("two") == 2); BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check missing element" << std::endl; @@ -38,6 +55,12 @@ UNORDERED_AUTO_TEST(at_tests) } catch (std::out_of_range) { } + try { + x_const.at("three"); + BOOST_ERROR("Should have thrown."); + } catch (std::out_of_range) { + } + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Finished" << std::endl; } } diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 12759c16..af913614 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -339,10 +339,16 @@ void unordered_map_test(X& r, Key const& k, T const& v) // Calling functions r.insert(std::pair(k, v)); + r.insert(r.begin(), std::pair(k, v)); + std::pair const value(k, v); + r.insert(value); + r.insert(r.end(), value); Key k_lvalue(k); T v_lvalue(v); + // Emplace + r.emplace(k, v); r.emplace(k_lvalue, v_lvalue); r.emplace(rvalue(k), rvalue(v)); @@ -350,6 +356,17 @@ void unordered_map_test(X& r, Key const& k, T const& v) r.emplace(boost::unordered::piecewise_construct, boost::make_tuple(k), boost::make_tuple(v)); + // Emplace with hint + + r.emplace_hint(r.begin(), k, v); + r.emplace_hint(r.begin(), k_lvalue, v_lvalue); + r.emplace_hint(r.begin(), rvalue(k), rvalue(v)); + + r.emplace_hint(r.begin(), boost::unordered::piecewise_construct, + boost::make_tuple(k), boost::make_tuple(v)); + + // Extract + test::check_return_type::equals(r.extract(r.begin())); r.emplace(k, v); @@ -360,7 +377,11 @@ void unordered_map_test(X& r, Key const& k, T const& v) test::check_return_type::equals_ref(n1.key()); test::check_return_type::equals_ref(n1.mapped()); - r.insert(boost::move(n1)); + node_type n2 = boost::move(n1); + r.insert(boost::move(n2)); + r.insert(r.extract(r.begin())); + n2 = r.extract(r.begin()); + r.insert(r.begin(), boost::move(n2)); r.insert(r.end(), r.extract(r.begin())); node_type n = r.extract(r.begin()); @@ -666,6 +687,13 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) sink(X(b, m)); X a9a(b, m); + X b1; + b1.insert(t); + X a9b(b1); + sink(a9b); + X a9c(b1, m); + sink(a9c); + const_iterator q = a.cbegin(); test::check_return_type::equals(a.insert(q, t)); diff --git a/test/unordered/detail_tests.cpp b/test/unordered/detail_tests.cpp new file mode 100644 index 00000000..b87bf943 --- /dev/null +++ b/test/unordered/detail_tests.cpp @@ -0,0 +1,104 @@ + +// Copyright 2017 Daniel James. +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +// clang-format off +#include "../helpers/prefix.hpp" +#include +#include +#include "../helpers/postfix.hpp" +// clang-format on + +#include "../helpers/test.hpp" +#include + +// Pretty inefficient, but the test is fast enough. +// Might be too slow if we had larger primes? +bool is_prime(std::size_t x) +{ + if (x == 2) { + return true; + } else if (x == 1 || x % 2 == 0) { + return false; + } else { + // y*y <= x had rounding errors, so instead use y <= (x/y). + for (std::size_t y = 3; y <= (x / y); y += 2) { + if (x % y == 0) { + return false; + break; + } + } + + return true; + } +} + +void test_next_prime(std::size_t value) +{ + std::size_t x = boost::unordered::detail::next_prime(value); + BOOST_TEST(is_prime(x)); + BOOST_TEST(x >= value); +} + +void test_prev_prime(std::size_t value) +{ + std::size_t x = boost::unordered::detail::prev_prime(value); + BOOST_TEST(is_prime(x)); + BOOST_TEST(x <= value); + if (x > value) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << x << "," << value << std::endl; + } +} + +UNORDERED_AUTO_TEST(next_prime_test) +{ + BOOST_TEST(!is_prime(0)); + BOOST_TEST(!is_prime(1)); + BOOST_TEST(is_prime(2)); + BOOST_TEST(is_prime(3)); + BOOST_TEST(is_prime(13)); + BOOST_TEST(!is_prime(4)); + BOOST_TEST(!is_prime(100)); + + BOOST_TEST(boost::unordered::detail::next_prime(0) > 0); + + // test_prev_prime doesn't work for values less than 17. + // Which should be okay, unless an allocator has a really tiny + // max_size? + const std::size_t min_prime = 17; + + // test_next_prime doesn't work for values greater than this, + // which might be a problem if you've got terrabytes of memory? + // I seriously doubt the container would work well at such sizes + // regardless. + const std::size_t max_prime = 4294967291ul; + + std::size_t i; + + BOOST_TEST(is_prime(min_prime)); + BOOST_TEST(is_prime(max_prime)); + + for (i = 0; i < 10000; ++i) { + if (i < min_prime) { + BOOST_TEST(boost::unordered::detail::prev_prime(i) == min_prime); + } else { + test_prev_prime(i); + } + test_next_prime(i); + } + + std::size_t last = i - 1; + for (; i > last; last = i, i += i / 5) { + if (i > max_prime) { + BOOST_TEST(boost::unordered::detail::next_prime(i) == max_prime); + } else { + test_next_prime(i); + } + test_prev_prime(i); + } +} + +RUN_TESTS() diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index b5c2fffb..f55ca90e 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -35,64 +35,138 @@ void unique_insert_tests1(X*, test::random_generator generator) std::cerr << "insert(value) tests for containers with unique keys.\n"; - X x; - test::ordered tracker = test::create_ordered(x); + { + X x; + test::ordered tracker = test::create_ordered(x); - test::random_values v(1000, generator); + test::random_values v(1000, generator); - for (BOOST_DEDUCED_TYPENAME test::random_values::iterator it = v.begin(); - it != v.end(); ++it) { + for (BOOST_DEDUCED_TYPENAME test::random_values::iterator it = + v.begin(); + it != v.end(); ++it) { - BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count(); - float b = x.max_load_factor(); + BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = + x.bucket_count(); + float b = x.max_load_factor(); - std::pair r1 = x.insert(*it); - std::pair r2 = - tracker.insert(*it); + std::pair r1 = x.insert(*it); + std::pair r2 = + tracker.insert(*it); - BOOST_TEST(r1.second == r2.second); - BOOST_TEST(*r1.first == *r2.first); + BOOST_TEST(r1.second == r2.second); + BOOST_TEST(*r1.first == *r2.first); - tracker.compare_key(x, *it); + tracker.compare_key(x, *it); - if (static_cast(x.size()) <= - b * static_cast(old_bucket_count)) - BOOST_TEST(x.bucket_count() == old_bucket_count); + if (static_cast(x.size()) <= + b * static_cast(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); } - test::check_equivalent_keys(x); + std::cerr << "insert(rvalue) tests for containers with unique keys.\n"; + + { + X x; + test::ordered tracker = test::create_ordered(x); + + test::random_values v(1000, generator); + + for (BOOST_DEDUCED_TYPENAME test::random_values::iterator it = + v.begin(); + it != v.end(); ++it) { + + BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = + x.bucket_count(); + float b = x.max_load_factor(); + + typename X::value_type value = *it; + std::pair r1 = x.insert(boost::move(value)); + std::pair r2 = + tracker.insert(*it); + + BOOST_TEST(r1.second == r2.second); + BOOST_TEST(*r1.first == *r2.first); + + tracker.compare_key(x, *it); + + if (static_cast(x.size()) <= + b * static_cast(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); + } } template void equivalent_insert_tests1(X*, test::random_generator generator) { - std::cerr << "insert(value) tests for containers with equivalent keys.\n"; - test::check_instances check_; - X x; - test::ordered tracker = test::create_ordered(x); + std::cerr << "insert(value) tests for containers with equivalent keys.\n"; - test::random_values v(1000, generator); - for (BOOST_DEDUCED_TYPENAME test::random_values::iterator it = v.begin(); - it != v.end(); ++it) { - BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count(); - float b = x.max_load_factor(); + { + X x; + test::ordered tracker = test::create_ordered(x); - BOOST_DEDUCED_TYPENAME X::iterator r1 = x.insert(*it); - BOOST_DEDUCED_TYPENAME test::ordered::iterator r2 = - tracker.insert(*it); + test::random_values v(1000, generator); + for (BOOST_DEDUCED_TYPENAME test::random_values::iterator it = + v.begin(); + it != v.end(); ++it) { + BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = + x.bucket_count(); + float b = x.max_load_factor(); - BOOST_TEST(*r1 == *r2); + BOOST_DEDUCED_TYPENAME X::iterator r1 = x.insert(*it); + BOOST_DEDUCED_TYPENAME test::ordered::iterator r2 = + tracker.insert(*it); - tracker.compare_key(x, *it); + BOOST_TEST(*r1 == *r2); - if (static_cast(x.size()) <= - b * static_cast(old_bucket_count)) - BOOST_TEST(x.bucket_count() == old_bucket_count); + tracker.compare_key(x, *it); + + if (static_cast(x.size()) <= + b * static_cast(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); } - test::check_equivalent_keys(x); + std::cerr << "insert(rvalue) tests for containers with equivalent keys.\n"; + + { + X x; + test::ordered tracker = test::create_ordered(x); + + test::random_values v(1000, generator); + for (BOOST_DEDUCED_TYPENAME test::random_values::iterator it = + v.begin(); + it != v.end(); ++it) { + BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = + x.bucket_count(); + float b = x.max_load_factor(); + + typename X::value_type value = *it; + BOOST_DEDUCED_TYPENAME X::iterator r1 = + x.insert(boost::move(value)); + BOOST_DEDUCED_TYPENAME test::ordered::iterator r2 = + tracker.insert(*it); + + BOOST_TEST(*r1 == *r2); + + tracker.compare_key(x, *it); + + if (static_cast(x.size()) <= + b * static_cast(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); + } } template void insert_tests2(X*, test::random_generator generator) @@ -194,6 +268,38 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } + std::cerr << "insert(pos, rvalue) tests.\n"; + + { + test::check_instances check_; + + X x; + const_iterator pos = x.begin(); + tracker_type tracker = test::create_ordered(x); + + test::random_values v(1000, generator); + for (BOOST_DEDUCED_TYPENAME test::random_values::iterator it = + v.begin(); + it != v.end(); ++it) { + BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = + x.bucket_count(); + float b = x.max_load_factor(); + + typename X::value_type value = *it; + pos = x.insert(pos, boost::move(value)); + tracker_iterator r2 = tracker.insert(tracker.begin(), *it); + BOOST_TEST(*pos == *r2); + tracker.compare_key(x, *it); + + if (static_cast(x.size()) <= + b * static_cast(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + tracker.compare(x); + test::check_equivalent_keys(x); + } + std::cerr << "insert single item range tests.\n"; { From 899248acbfdf984fdcd89f44867d3fcd73b30eb0 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 29 Apr 2017 09:31:17 +0100 Subject: [PATCH 101/147] Avoid shadow warning on older versions off GCC --- include/boost/unordered/detail/implementation.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index ee6d8d0c..815ee916 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3338,11 +3338,11 @@ struct table : boost::unordered::detail::functionshash_to_bucket(key_hash); - bucket_pointer b = this->get_bucket(bucket); + std::size_t bucket_index = this->hash_to_bucket(key_hash); + bucket_pointer b = this->get_bucket(bucket_index); // TODO: Do this need to set_first_in_group ? - n->bucket_info_ = bucket; + n->bucket_info_ = bucket_index; n->set_first_in_group(); if (!b->next_) { @@ -3875,21 +3875,21 @@ struct table : boost::unordered::detail::functionshash_to_bucket(key_hash); - n->bucket_info_ = bucket; + std::size_t bucket_index = this->hash_to_bucket(key_hash); + n->bucket_info_ = bucket_index; if (pos) { n->next_ = pos->next_; pos->next_ = n; if (n->next_) { std::size_t next_bucket = this->node_bucket(next_node(n)); - if (next_bucket != bucket) { + if (next_bucket != bucket_index) { this->get_bucket(next_bucket)->next_ = n; } } } else { n->set_first_in_group(); - bucket_pointer b = this->get_bucket(bucket); + bucket_pointer b = this->get_bucket(bucket_index); if (!b->next_) { link_pointer start_node = this->get_previous_start(); From c75b33224006c42b76d17015472f09bc80f2fa0e Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 30 Apr 2017 10:41:22 +0100 Subject: [PATCH 102/147] Cleaner create_buckets implementation --- .../boost/unordered/detail/implementation.hpp | 72 +++++++------------ 1 file changed, 26 insertions(+), 46 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 815ee916..1a24c4c2 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -2898,57 +2898,37 @@ struct table : boost::unordered::detail::functions(new_count); - for (; constructed != end; ++constructed) { - new (boost::addressof(*constructed)) bucket(); - } - - if (buckets_) { - // Copy the nodes to the new buckets, including the dummy - // node if there is one. - new (boost::addressof(*constructed)) bucket( - (buckets_ + static_cast(bucket_count_)) - ->next_); - ++constructed; - destroy_buckets(); - } else if (bucket::extra_node) { - node_constructor a(node_alloc()); - a.create_node(); - - new (boost::addressof(*constructed)) bucket(a.release()); - ++constructed; - } else { - new (boost::addressof(*constructed)) bucket(); - ++constructed; - } + // Construct the new buckets and dummy node, and destroy the old buckets + if (buckets_) { + dummy_node = + (buckets_ + static_cast(bucket_count_))->next_; + bucket_pointer new_buckets = bucket_allocator_traits::allocate( + bucket_alloc(), new_count + 1); + destroy_buckets(); + buckets_ = new_buckets; + } else if (bucket::extra_node) { + node_constructor a(node_alloc()); + a.create_node(); + buckets_ = bucket_allocator_traits::allocate( + bucket_alloc(), new_count + 1); + dummy_node = a.release(); + } else { + dummy_node = link_pointer(); + buckets_ = bucket_allocator_traits::allocate( + bucket_alloc(), new_count + 1); } - BOOST_CATCH(...) - { - for (bucket_pointer p = new_buckets; p != constructed; ++p) { - boost::unordered::detail::func::destroy(boost::addressof(*p)); - } - - bucket_allocator_traits::deallocate( - bucket_alloc(), new_buckets, length); - - BOOST_RETHROW; - } - BOOST_CATCH_END + // nothrow from here... bucket_count_ = new_count; - buckets_ = new_buckets; recalculate_max_load(); + + bucket_pointer end = buckets_ + static_cast(new_count); + for (bucket_pointer i = buckets_; i != end; ++i) { + new (boost::addressof(*i)) bucket(); + } + new (boost::addressof(*end)) bucket(dummy_node); } //////////////////////////////////////////////////////////////////////// From 451d0f2fc5d5b43249a1aeb47450840505a79766 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 30 Apr 2017 10:41:22 +0100 Subject: [PATCH 103/147] Constructing nodes is nothrow, so no need to track --- .../boost/unordered/detail/implementation.hpp | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 1a24c4c2..23098b43 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1630,12 +1630,8 @@ template struct node_constructor node_allocator& alloc_; node_pointer node_; - bool node_constructed_; - node_constructor(node_allocator& n) - : alloc_(n), node_(), node_constructed_(false) - { - } + node_constructor(node_allocator& n) : alloc_(n), node_() {} ~node_constructor(); @@ -1644,7 +1640,7 @@ template struct node_constructor // no throw node_pointer release() { - BOOST_ASSERT(node_ && node_constructed_); + BOOST_ASSERT(node_); node_pointer p = node_; node_ = node_pointer(); return p; @@ -1654,7 +1650,6 @@ template struct node_constructor { BOOST_ASSERT(!node_); node_ = p; - node_constructed_ = true; BOOST_UNORDERED_CALL_DESTROY( node_allocator_traits, alloc_, node_->value_ptr()); } @@ -1667,10 +1662,7 @@ template struct node_constructor template node_constructor::~node_constructor() { if (node_) { - if (node_constructed_) { - boost::unordered::detail::func::destroy(boost::addressof(*node_)); - } - + boost::unordered::detail::func::destroy(boost::addressof(*node_)); node_allocator_traits::deallocate(alloc_, node_, 1); } } @@ -1678,12 +1670,8 @@ template node_constructor::~node_constructor() template void node_constructor::create_node() { BOOST_ASSERT(!node_); - node_constructed_ = false; - node_ = node_allocator_traits::allocate(alloc_, 1); - new (boost::addressof(*node_)) node(); - node_constructed_ = true; } template struct node_tmp From c243895fc046a582e9911b0050289d67482b4640 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 30 Apr 2017 10:41:22 +0100 Subject: [PATCH 104/147] Remove odd check that should never be true I think it was left over from the old grouped node implementation. --- include/boost/unordered/detail/implementation.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 23098b43..09aad21e 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3885,7 +3885,7 @@ struct table : boost::unordered::detail::functionsreset_first_in_group(); n->next_ = hint->next_; hint->next_ = n; - if (n->next_ != hint && n->next_) { + if (n->next_) { std::size_t next_bucket = this->node_bucket(next_node(n)); if (next_bucket != this->node_bucket(n)) { this->get_bucket(next_bucket)->next_ = n; From e7a3487df49d965bb47ddcf84986fb983f425609 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 30 Apr 2017 10:41:22 +0100 Subject: [PATCH 105/147] Remove policy template parameter from local iterators --- include/boost/unordered/detail/implementation.hpp | 14 +++++++------- include/boost/unordered/detail/map.hpp | 6 ++---- include/boost/unordered/detail/set.hpp | 4 ++-- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 09aad21e..0c1a71ea 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -159,8 +159,8 @@ namespace unordered { namespace iterator_detail { template struct iterator; template struct c_iterator; -template struct l_iterator; -template struct cl_iterator; +template struct l_iterator; +template struct cl_iterator; } } } @@ -1878,13 +1878,13 @@ namespace iterator_detail { // // all no throw -template +template struct l_iterator : public std::iterator { #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) - template + template friend struct boost::unordered::iterator_detail::cl_iterator; private: @@ -1936,13 +1936,13 @@ struct l_iterator : public std::iterator +template struct cl_iterator : public std::iterator { - friend struct boost::unordered::iterator_detail::l_iterator; + friend struct boost::unordered::iterator_detail::l_iterator; private: typedef typename Node::node_pointer node_pointer; @@ -1963,7 +1963,7 @@ struct cl_iterator } cl_iterator( - boost::unordered::iterator_detail::l_iterator const& x) + boost::unordered::iterator_detail::l_iterator const& x) BOOST_NOEXCEPT : ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_) diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index 4568e75f..172b4f4b 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -35,10 +35,8 @@ template struct map 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; + typedef boost::unordered::iterator_detail::l_iterator l_iterator; + typedef boost::unordered::iterator_detail::cl_iterator cl_iterator; typedef boost::unordered::node_handle_map node_type; typedef boost::unordered::insert_return_type_map diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index fc13fa17..634ebd46 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -35,9 +35,9 @@ template struct set typedef boost::unordered::iterator_detail::c_iterator iterator; typedef boost::unordered::iterator_detail::c_iterator c_iterator; - typedef boost::unordered::iterator_detail::cl_iterator + typedef boost::unordered::iterator_detail::cl_iterator l_iterator; - typedef boost::unordered::iterator_detail::cl_iterator + typedef boost::unordered::iterator_detail::cl_iterator cl_iterator; typedef boost::unordered::node_handle_set node_type; From 7b5f73f6c296eece53f156be96d554f676fc6de3 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 30 Apr 2017 10:41:22 +0100 Subject: [PATCH 106/147] Disable all sunpro workarounds on latest version I have no idea if they're still working. I wasn't able to run the latest solaris in a virtual machine on my computer, so this is the only way to test. --- include/boost/unordered/detail/implementation.hpp | 11 +++++++---- include/boost/unordered/unordered_map.hpp | 8 ++++---- include/boost/unordered/unordered_set.hpp | 8 ++++---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 0c1a71ea..6774ce00 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -13,6 +13,7 @@ #pragma once #endif +#include #include #include #include @@ -113,7 +114,9 @@ // #if defined(BOOST_UNORDERED_TUPLE_ARGS) -#elif defined(__SUNPRO_CC) +#elif BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0) +// I had problems with tuples on older versions of the sunpro. +// Might be fixed in an earlier version than I specified here. #define BOOST_UNORDERED_TUPLE_ARGS 0 #elif !defined(BOOST_NO_CXX11_HDR_TUPLE) #define BOOST_UNORDERED_TUPLE_ARGS 10 @@ -239,7 +242,7 @@ template struct prime_list_template { static std::size_t const value[]; -#if !defined(SUNPRO_CC) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) static std::ptrdiff_t const length; #else static std::ptrdiff_t const length = @@ -251,7 +254,7 @@ template std::size_t const prime_list_template::value[] = { BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES)}; -#if !defined(SUNPRO_CC) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) template std::ptrdiff_t const prime_list_template::length = BOOST_PP_SEQ_SIZE( BOOST_UNORDERED_PRIMES); @@ -1305,7 +1308,7 @@ inline void construct_value(T* address, BOOST_FWD_REF(A0) a0) // // Used to emulate piecewise construction. -#if !defined(__SUNPRO_CC) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) #define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(z, n, namespace_) \ template class unordered_map #else -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) // 0 argument emplace requires special treatment in case // the container is instantiated with a value type that @@ -292,7 +292,7 @@ template class unordered_map #else -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = @@ -1031,7 +1031,7 @@ template class unordered_multimap #else -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) // 0 argument emplace requires special treatment in case // the container is instantiated with a value type that @@ -1091,7 +1091,7 @@ template class unordered_multimap #else -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index bbd07f60..de8b6ea7 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -228,7 +228,7 @@ template class unordered_set #else -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) // 0 argument emplace requires special treatment in case // the container is instantiated with a value type that @@ -290,7 +290,7 @@ template class unordered_set #else -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = @@ -737,7 +737,7 @@ template class unordered_multiset #else -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) // 0 argument emplace requires special treatment in case // the container is instantiated with a value type that @@ -797,7 +797,7 @@ template class unordered_multiset #else -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = From 8c139940e7c556da53323793f22e8eeed4118503 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 30 Apr 2017 14:27:03 +0100 Subject: [PATCH 107/147] More merge tests between compatible containers --- test/unordered/merge_tests.cpp | 124 +++++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 29 deletions(-) diff --git a/test/unordered/merge_tests.cpp b/test/unordered/merge_tests.cpp index 3d5e7f97..b848e4f3 100644 --- a/test/unordered/merge_tests.cpp +++ b/test/unordered/merge_tests.cpp @@ -139,12 +139,14 @@ UNORDERED_AUTO_TEST(merge_set_and_multiset) test::check_equivalent_keys(y); } -template void merge_empty_test(X*, test::random_generator generator) +template +void merge_empty_test(X1*, X2*, test::random_generator generator) { test::check_instances check_; - test::random_values v(1000, generator); - X x1(v.begin(), v.end()), x2; + test::random_values v(1000, generator); + X1 x1(v.begin(), v.end()); + X2 x2; x1.merge(x2); test::check_container(x1, v); BOOST_TEST(x2.empty()); @@ -158,7 +160,8 @@ void merge_into_empty_test(X*, test::random_generator generator) test::check_instances check_; test::random_values v(1000, generator); - X x1, x2(v.begin(), v.end()); + X x1; + X x2(v.begin(), v.end()); x1.merge(x2); test::check_container(x1, v); BOOST_TEST(x2.empty()); @@ -166,24 +169,26 @@ void merge_into_empty_test(X*, test::random_generator generator) test::check_equivalent_keys(x2); } -template void unique_merge_test(X*, test::random_generator generator) +template +void merge_into_unique_keys_test(X1*, X2*, test::random_generator generator) { test::check_instances check_; - test::random_values v1(1000, generator); - test::random_values v2(1000, generator); + test::random_values v1(1000, generator); + test::random_values v2(1000, generator); v1.insert(v2.begin(), boost::next(v2.begin(), 100)); v2.insert(v1.begin(), boost::next(v1.begin(), 100)); - X x1(v1.begin(), v1.end()), x2(v2.begin(), v2.end()); + X1 x1(v1.begin(), v1.end()); + X2 x2(v2.begin(), v2.end()); x1.merge(x2); - test::ordered tracker1 = test::create_ordered(x1); - test::ordered tracker2 = test::create_ordered(x2); - test::ordered tracker_tmp = test::create_ordered(x2); + test::ordered tracker1 = test::create_ordered(x1); + test::ordered tracker2 = test::create_ordered(x2); + test::ordered tracker_tmp = test::create_ordered(x2); tracker1.insert(v1.begin(), v1.end()); tracker_tmp.insert(v2.begin(), v2.end()); - for (BOOST_DEDUCED_TYPENAME test::ordered::iterator it = + for (BOOST_DEDUCED_TYPENAME test::ordered::iterator it = tracker_tmp.begin(); it != tracker_tmp.end(); ++it) { if (!tracker1.insert(*it).second) { @@ -197,19 +202,21 @@ template void unique_merge_test(X*, test::random_generator generator) test::check_equivalent_keys(x2); } -template void equiv_merge_test(X*, test::random_generator generator) +template +void merge_into_equiv_keys_test(X1*, X2*, test::random_generator generator) { test::check_instances check_; - test::random_values v1(1000, generator); - test::random_values v2(1000, generator); + test::random_values v1(1000, generator); + test::random_values v2(1000, generator); v1.insert(v2.begin(), boost::next(v2.begin(), 100)); v2.insert(v1.begin(), boost::next(v1.begin(), 100)); - X x1(v1.begin(), v1.end()), x2(v2.begin(), v2.end()); + X1 x1(v1.begin(), v1.end()); + X2 x2(v2.begin(), v2.end()); x1.merge(x2); - test::ordered tracker1 = test::create_ordered(x1); + test::ordered tracker1 = test::create_ordered(x1); tracker1.insert(v1.begin(), v1.end()); tracker1.insert(v2.begin(), v2.end()); @@ -221,34 +228,93 @@ template void equiv_merge_test(X*, test::random_generator generator) boost::unordered_set >* test_set_std_alloc; +boost::unordered_multiset >* test_multiset_std_alloc; + +boost::unordered_map >* test_map_std_alloc; boost::unordered_multimap >* test_multimap_std_alloc; boost::unordered_set >* test_set; -boost::unordered_multiset >* test_multiset; +boost::unordered_multiset >* test_multiset; + boost::unordered_map >* test_map; -boost::unordered_multimap >* test_multimap; +boost::unordered_multimap >* test_multimap; using test::default_generator; using test::generate_collisions; +// clang-format off UNORDERED_TEST(merge_empty_test, - ((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_multiset)( - test_map)(test_multimap))((default_generator)(generate_collisions))) + ((test_set_std_alloc)(test_multiset_std_alloc)) + ((test_set_std_alloc)(test_multiset_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_empty_test, + ((test_map_std_alloc)(test_multimap_std_alloc)) + ((test_map_std_alloc)(test_multimap_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_empty_test, + ((test_set)(test_multiset)) + ((test_set)(test_multiset)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_empty_test, + ((test_map)(test_multimap)) + ((test_map)(test_multimap)) + ((default_generator)(generate_collisions))) UNORDERED_TEST(merge_into_empty_test, - ((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_multiset)( - test_map)(test_multimap))((default_generator)(generate_collisions))) + ((test_set_std_alloc)(test_multiset_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_empty_test, + ((test_map_std_alloc)(test_multimap_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_empty_test, + ((test_set)(test_multiset)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_empty_test, + ((test_map)(test_multimap)) + ((default_generator)(generate_collisions))) -UNORDERED_TEST(unique_merge_test, - ((test_set_std_alloc)(test_set)(test_map))((default_generator))) +UNORDERED_TEST(merge_into_unique_keys_test, + ((test_set_std_alloc)) + ((test_set_std_alloc)(test_multiset_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_unique_keys_test, + ((test_map_std_alloc)) + ((test_map_std_alloc)(test_multimap_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_unique_keys_test, + ((test_set)) + ((test_set)(test_multiset)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_unique_keys_test, + ((test_map)) + ((test_map)(test_multimap)) + ((default_generator)(generate_collisions))) + +UNORDERED_TEST(merge_into_equiv_keys_test, + ((test_multiset_std_alloc)) + ((test_set_std_alloc)(test_multiset_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_equiv_keys_test, + ((test_multimap_std_alloc)) + ((test_map_std_alloc)(test_multimap_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_equiv_keys_test, + ((test_multiset)) + ((test_set)(test_multiset)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_equiv_keys_test, + ((test_multimap)) + ((test_map)(test_multimap)) + ((default_generator)(generate_collisions))) +// clang-format on -UNORDERED_TEST(equiv_merge_test, ((test_multimap_std_alloc)(test_multiset)( - test_multimap))((default_generator))) } RUN_TESTS() From 35522d3ee08f9f00641fb5ecd0fd54b589260b24 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 30 Apr 2017 14:27:03 +0100 Subject: [PATCH 108/147] Fix merging between containers with different hash/equality This reverts commit 20b0c0a6d8cf70faefe5dac5cea23218a76344d3. --- .../boost/unordered/detail/implementation.hpp | 53 ++++++------------- test/unordered/merge_tests.cpp | 45 ++++++++++++---- 2 files changed, 52 insertions(+), 46 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 6774ce00..f006a03b 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3540,45 +3540,26 @@ struct table : boost::unordered::detail::functions::value)); BOOST_ASSERT(this->node_alloc() == other.node_alloc()); - if (!other.size_) { - return; - } + if (other.size_) { + link_pointer prev = other.get_previous_start(); - link_pointer prev = other.get_previous_start(); - node_pointer n = other_table::next_node(prev); - while (n) { - const_key_type& k = this->get_key(n); - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); + while (prev->next_) { + node_pointer n = other_table::next_node(prev); + const_key_type& k = this->get_key(n); + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); - if (pos) { - prev = n; - n = other_table::next_node(prev); - } else { - this->reserve_for_insert(this->size_ + 1); - - prev->next_ = n->next_; - --other.size_; - other.fix_bucket(other.node_bucket(n), prev); - this->add_node_unique(n, key_hash); - n = other_table::next_node(prev); - - // If the next node was from the same group, it's now - // the first node in the group. - if (n && !n->is_first_in_group()) { - n->set_first_in_group(); + if (pos) { prev = n; - n = other_table::next_node(prev); - } - } - - // Skip over rest of group of nodes with equivalent keys, - // as we know there's already one in the container. - while (n && !n->is_first_in_group()) { - prev = n; - n = other_table::next_node(prev); - if (!n) { - return; + } else { + this->reserve_for_insert(this->size_ + 1); + prev->next_ = n->next_; + if (prev->next_ && n->is_first_in_group()) { + next_node(prev)->set_first_in_group(); + } + --other.size_; + other.fix_bucket(other.node_bucket(n), prev); + this->add_node_unique(n, key_hash); } } } diff --git a/test/unordered/merge_tests.cpp b/test/unordered/merge_tests.cpp index b848e4f3..59b0b4a5 100644 --- a/test/unordered/merge_tests.cpp +++ b/test/unordered/merge_tests.cpp @@ -170,7 +170,8 @@ void merge_into_empty_test(X*, test::random_generator generator) } template -void merge_into_unique_keys_test(X1*, X2*, test::random_generator generator) +void merge_into_unique_keys_test( + X1*, X2*, int hash_equal1, int hash_equal2, test::random_generator generator) { test::check_instances check_; @@ -179,8 +180,10 @@ void merge_into_unique_keys_test(X1*, X2*, test::random_generator generator) v1.insert(v2.begin(), boost::next(v2.begin(), 100)); v2.insert(v1.begin(), boost::next(v1.begin(), 100)); - X1 x1(v1.begin(), v1.end()); - X2 x2(v2.begin(), v2.end()); + X1 x1(v1.begin(), v1.end(), 0, test::hash(hash_equal1), + test::equal_to(hash_equal1)); + X2 x2(v2.begin(), v2.end(), 0, test::hash(hash_equal2), + test::equal_to(hash_equal2)); x1.merge(x2); test::ordered tracker1 = test::create_ordered(x1); @@ -203,7 +206,8 @@ void merge_into_unique_keys_test(X1*, X2*, test::random_generator generator) } template -void merge_into_equiv_keys_test(X1*, X2*, test::random_generator generator) +void merge_into_equiv_keys_test( + X1*, X2*, int hash_equal1, int hash_equal2, test::random_generator generator) { test::check_instances check_; @@ -212,16 +216,21 @@ void merge_into_equiv_keys_test(X1*, X2*, test::random_generator generator) v1.insert(v2.begin(), boost::next(v2.begin(), 100)); v2.insert(v1.begin(), boost::next(v1.begin(), 100)); - X1 x1(v1.begin(), v1.end()); - X2 x2(v2.begin(), v2.end()); + X1 x1(v1.begin(), v1.end(), 0, test::hash(hash_equal1), + test::equal_to(hash_equal1)); + X2 x2(v2.begin(), v2.end(), 0, test::hash(hash_equal2), + test::equal_to(hash_equal2)); x1.merge(x2); test::ordered tracker1 = test::create_ordered(x1); + test::ordered tracker2 = test::create_ordered(x2); tracker1.insert(v1.begin(), v1.end()); - tracker1.insert(v2.begin(), v2.end()); + tracker2.insert(v2.begin(), v2.end()); + tracker1.insert(tracker2.begin(), tracker2.end()); + tracker2.clear(); tracker1.compare(x1); - BOOST_TEST(x2.empty()); + tracker2.compare(x2); test::check_equivalent_keys(x1); test::check_equivalent_keys(x2); } @@ -231,8 +240,8 @@ boost::unordered_set >* test_multiset_std_alloc; -boost::unordered_map >* test_map_std_alloc; +boost::unordered_map >* test_map_std_alloc; boost::unordered_multimap >* test_multimap_std_alloc; @@ -283,35 +292,51 @@ UNORDERED_TEST(merge_into_empty_test, UNORDERED_TEST(merge_into_unique_keys_test, ((test_set_std_alloc)) ((test_set_std_alloc)(test_multiset_std_alloc)) + ((0)(1)(2)) + ((0)(1)(2)) ((default_generator)(generate_collisions))) UNORDERED_TEST(merge_into_unique_keys_test, ((test_map_std_alloc)) ((test_map_std_alloc)(test_multimap_std_alloc)) + ((0)(1)(2)) + ((0)(1)(2)) ((default_generator)(generate_collisions))) UNORDERED_TEST(merge_into_unique_keys_test, ((test_set)) ((test_set)(test_multiset)) + ((0)(1)(2)) + ((0)(1)(2)) ((default_generator)(generate_collisions))) UNORDERED_TEST(merge_into_unique_keys_test, ((test_map)) ((test_map)(test_multimap)) + ((0)(1)(2)) + ((0)(1)(2)) ((default_generator)(generate_collisions))) UNORDERED_TEST(merge_into_equiv_keys_test, ((test_multiset_std_alloc)) ((test_set_std_alloc)(test_multiset_std_alloc)) + ((0)(1)(2)) + ((0)(1)(2)) ((default_generator)(generate_collisions))) UNORDERED_TEST(merge_into_equiv_keys_test, ((test_multimap_std_alloc)) ((test_map_std_alloc)(test_multimap_std_alloc)) + ((0)(1)(2)) + ((0)(1)(2)) ((default_generator)(generate_collisions))) UNORDERED_TEST(merge_into_equiv_keys_test, ((test_multiset)) ((test_set)(test_multiset)) + ((0)(1)(2)) + ((0)(1)(2)) ((default_generator)(generate_collisions))) UNORDERED_TEST(merge_into_equiv_keys_test, ((test_multimap)) ((test_map)(test_multimap)) + ((0)(1)(2)) + ((0)(1)(2)) ((default_generator)(generate_collisions))) // clang-format on From 2e14c340a8da5429af0d5699e1b8f675d43c5428 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 1 May 2017 21:03:11 +0100 Subject: [PATCH 109/147] Reformat --- include/boost/unordered/detail/implementation.hpp | 13 ++++++------- include/boost/unordered/detail/set.hpp | 6 ++---- include/boost/unordered/unordered_map.hpp | 8 ++++---- include/boost/unordered/unordered_set.hpp | 8 ++++---- test/unordered/merge_tests.cpp | 9 ++++----- 5 files changed, 20 insertions(+), 24 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index f006a03b..c6aa43cf 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -13,13 +13,13 @@ #pragma once #endif -#include #include #include #include #include #include #include +#include #include #include #include @@ -114,7 +114,7 @@ // #if defined(BOOST_UNORDERED_TUPLE_ARGS) -#elif BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0) +#elif BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0) // I had problems with tuples on older versions of the sunpro. // Might be fixed in an earlier version than I specified here. #define BOOST_UNORDERED_TUPLE_ARGS 0 @@ -242,7 +242,7 @@ template struct prime_list_template { static std::size_t const value[]; -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) static std::ptrdiff_t const length; #else static std::ptrdiff_t const length = @@ -254,7 +254,7 @@ template std::size_t const prime_list_template::value[] = { BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES)}; -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) template std::ptrdiff_t const prime_list_template::length = BOOST_PP_SEQ_SIZE( BOOST_UNORDERED_PRIMES); @@ -1308,7 +1308,7 @@ inline void construct_value(T* address, BOOST_FWD_REF(A0) a0) // // Used to emulate piecewise construction. -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) #define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(z, n, namespace_) \ template const& x) + cl_iterator(boost::unordered::iterator_detail::l_iterator const& x) BOOST_NOEXCEPT : ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_) diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index 634ebd46..a1649917 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -35,10 +35,8 @@ template struct set 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; + typedef boost::unordered::iterator_detail::cl_iterator l_iterator; + typedef boost::unordered::iterator_detail::cl_iterator cl_iterator; typedef boost::unordered::node_handle_set node_type; typedef boost::unordered::insert_return_type_set diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 95e614ba..4a90d667 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -230,7 +230,7 @@ template class unordered_map #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) // 0 argument emplace requires special treatment in case // the container is instantiated with a value type that @@ -292,7 +292,7 @@ template class unordered_map #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = @@ -1031,7 +1031,7 @@ template class unordered_multimap #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) // 0 argument emplace requires special treatment in case // the container is instantiated with a value type that @@ -1091,7 +1091,7 @@ template class unordered_multimap #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index de8b6ea7..4d6dd544 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -228,7 +228,7 @@ template class unordered_set #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) // 0 argument emplace requires special treatment in case // the container is instantiated with a value type that @@ -290,7 +290,7 @@ template class unordered_set #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = @@ -737,7 +737,7 @@ template class unordered_multiset #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) // 0 argument emplace requires special treatment in case // the container is instantiated with a value type that @@ -797,7 +797,7 @@ template class unordered_multiset #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5,21,0)) +#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = diff --git a/test/unordered/merge_tests.cpp b/test/unordered/merge_tests.cpp index 59b0b4a5..39f986f6 100644 --- a/test/unordered/merge_tests.cpp +++ b/test/unordered/merge_tests.cpp @@ -170,8 +170,8 @@ void merge_into_empty_test(X*, test::random_generator generator) } template -void merge_into_unique_keys_test( - X1*, X2*, int hash_equal1, int hash_equal2, test::random_generator generator) +void merge_into_unique_keys_test(X1*, X2*, int hash_equal1, int hash_equal2, + test::random_generator generator) { test::check_instances check_; @@ -206,8 +206,8 @@ void merge_into_unique_keys_test( } template -void merge_into_equiv_keys_test( - X1*, X2*, int hash_equal1, int hash_equal2, test::random_generator generator) +void merge_into_equiv_keys_test(X1*, X2*, int hash_equal1, int hash_equal2, + test::random_generator generator) { test::check_instances check_; @@ -339,7 +339,6 @@ UNORDERED_TEST(merge_into_equiv_keys_test, ((0)(1)(2)) ((default_generator)(generate_collisions))) // clang-format on - } RUN_TESTS() From 338a94e577a5ed4f84b1532e605f1c6525252cb8 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 1 May 2017 21:03:11 +0100 Subject: [PATCH 110/147] Better rvalue emulation support in extractors Means that inserting rvalues into unordered_set/unordered_map won't create a node if no insert is required. --- .../boost/unordered/detail/implementation.hpp | 21 +++++++ test/unordered/unnecessary_copy_tests.cpp | 61 +++++++++++++++---- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index c6aa43cf..879e0a15 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -4267,6 +4267,11 @@ template struct set_extractor static key_type const& extract(value_type const& v) { return v; } + static key_type const& extract(BOOST_UNORDERED_RV_REF(value_type) v) + { + return v; + } + static no_key extract() { return no_key(); } template static no_key extract(Arg const&) { return no_key(); } @@ -4306,6 +4311,22 @@ template struct map_extractor return v.first; } +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + static key_type const& extract( + boost::rv > const& v) + { + return v.first; + } + + template + static key_type const& extract( + boost::rv > const& v) + { + return v.first; + } +#endif + template static key_type const& extract(key_type const& k, Arg1 const&) { diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index 9618778b..3a5424bb 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -180,6 +180,53 @@ template void unnecessary_copy_insert_test(T*) reset(); x.insert(a); COPY_COUNT(1); + MOVE_COUNT(0); +} + +template void unnecessary_copy_insert_rvalue_set_test(T*) +{ + T x; + BOOST_DEDUCED_TYPENAME T::value_type a; + reset(); + x.insert(boost::move(a)); + COPY_COUNT(0); + MOVE_COUNT(1); + + BOOST_DEDUCED_TYPENAME T::value_type a2; + reset(); + x.insert(boost::move(a)); + COPY_COUNT(0); + MOVE_COUNT((x.size() == 2 ? 1 : 0)); +} + +template void unnecessary_copy_insert_rvalue_map_test(T*) +{ + // Doesn't currently try to emulate std::pair move construction, + // so std::pair's require a copy. Could try emulating it in + // construct_from_args. + + T x; + BOOST_DEDUCED_TYPENAME T::value_type a; + reset(); + x.insert(boost::move(a)); +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + COPY_COUNT(1); + MOVE_COUNT(0); +#else + COPY_COUNT(0); + MOVE_COUNT(1); +#endif + + BOOST_DEDUCED_TYPENAME T::value_type a2; + reset(); + x.insert(boost::move(a)); +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + COPY_COUNT((x.size() == 2 ? 1 : 0)); + MOVE_COUNT(0); +#else + COPY_COUNT(0); + MOVE_COUNT((x.size() == 2 ? 1 : 0)); +#endif } boost::unordered_set* set; @@ -188,6 +235,8 @@ boost::unordered_map* map; boost::unordered_multimap* multimap; UNORDERED_TEST(unnecessary_copy_insert_test, ((set)(multiset)(map)(multimap))) +UNORDERED_TEST(unnecessary_copy_insert_rvalue_set_test, ((set)(multiset))) +UNORDERED_TEST(unnecessary_copy_insert_rvalue_map_test, ((map)(multimap))) template void unnecessary_copy_emplace_test(T*) { @@ -315,15 +364,10 @@ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test) // the existing element. reset(); x.emplace(); -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || \ - !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + // source_cost doesn't make much sense here, but it seems to fit. COPY_COUNT(1); MOVE_COUNT(source_cost); -#else - COPY_COUNT(1); - MOVE_COUNT(1 + source_cost); -#endif #endif // @@ -347,13 +391,8 @@ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test) // No move should take place. reset(); x.emplace(boost::move(a)); -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) COPY_COUNT(0); MOVE_COUNT(0); -#else - COPY_COUNT(0); - MOVE_COUNT(1); -#endif // Use a new value for cases where a did get moved... count_copies b; From b8c754d230192b19dc1da744605aaa4343b9e5f2 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 1 May 2017 21:03:11 +0100 Subject: [PATCH 111/147] Set the high bit in bucket_info_ to false for first node in group And true for the reset, so that in containers with unique keys bucket_info_ is always just the bucket index. --- .../boost/unordered/detail/implementation.hpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 879e0a15..49bc321e 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3313,7 +3313,7 @@ struct table : boost::unordered::detail::functionsbucket_info_ = bucket_index; - n->set_first_in_group(); + // n->set_first_in_group(); if (!b->next_) { link_pointer start_node = this->get_previous_start(); @@ -3830,6 +3830,7 @@ struct table : boost::unordered::detail::functionsbucket_info_ = bucket_index; if (pos) { + n->reset_first_in_group(); n->next_ = pos->next_; pos->next_ = n; if (n->next_) { @@ -3839,7 +3840,7 @@ struct table : boost::unordered::detail::functionsset_first_in_group(); + // n->set_first_in_group(); bucket_pointer b = this->get_bucket(bucket_index); if (!b->next_) { @@ -4210,7 +4211,7 @@ inline void table::rehash_impl(std::size_t num_buckets) } n = next; n->bucket_info_ = bucket_index; - // n->reset_first_in_group(); + n->reset_first_in_group(); } // n is now the last node in the group @@ -4424,17 +4425,17 @@ struct node : boost::unordered::detail::value_base std::size_t is_first_in_group() const { - return bucket_info_ & ~((std::size_t)-1 >> 1); + return !(bucket_info_ & ~((std::size_t)-1 >> 1)); } void set_first_in_group() { - bucket_info_ = bucket_info_ | ~((std::size_t)-1 >> 1); + bucket_info_ = bucket_info_ & ((std::size_t)-1 >> 1); } void reset_first_in_group() { - bucket_info_ = bucket_info_ & ((std::size_t)-1 >> 1); + bucket_info_ = bucket_info_ | ~((std::size_t)-1 >> 1); } private: @@ -4465,17 +4466,17 @@ template struct ptr_node : boost::unordered::detail::ptr_bucket std::size_t is_first_in_group() const { - return bucket_info_ & ~((std::size_t)-1 >> 1); + return !(bucket_info_ & ~((std::size_t)-1 >> 1)); } void set_first_in_group() { - bucket_info_ = bucket_info_ | ~((std::size_t)-1 >> 1); + bucket_info_ = bucket_info_ & ((std::size_t)-1 >> 1); } void reset_first_in_group() { - bucket_info_ = bucket_info_ & ((std::size_t)-1 >> 1); + bucket_info_ = bucket_info_ | ~((std::size_t)-1 >> 1); } private: From d84a57441be5d24893c8aa74c04522a6a2673d7e Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 1 May 2017 22:16:13 +0100 Subject: [PATCH 112/147] Use the unordered container for the fake merge in merge test The merge tests into containers with unique keys are failing on some platforms. My guess is that because of differences between ordering of nodes with equivalent keys that different nodes are being 'merged' in the unordered containers and the tracker containers. So when creating the fake merge, use the unordered container as a reference. This is a little less pure, but should be a good enough test. --- test/unordered/merge_tests.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/unordered/merge_tests.cpp b/test/unordered/merge_tests.cpp index 39f986f6..8d0d4915 100644 --- a/test/unordered/merge_tests.cpp +++ b/test/unordered/merge_tests.cpp @@ -184,21 +184,18 @@ void merge_into_unique_keys_test(X1*, X2*, int hash_equal1, int hash_equal2, test::equal_to(hash_equal1)); X2 x2(v2.begin(), v2.end(), 0, test::hash(hash_equal2), test::equal_to(hash_equal2)); - x1.merge(x2); test::ordered tracker1 = test::create_ordered(x1); test::ordered tracker2 = test::create_ordered(x2); - test::ordered tracker_tmp = test::create_ordered(x2); tracker1.insert(v1.begin(), v1.end()); - tracker_tmp.insert(v2.begin(), v2.end()); - for (BOOST_DEDUCED_TYPENAME test::ordered::iterator it = - tracker_tmp.begin(); - it != tracker_tmp.end(); ++it) { + for (typename X2::iterator it = x2.begin(); it != x2.end(); ++it) { if (!tracker1.insert(*it).second) { tracker2.insert(*it); } } + x1.merge(x2); + tracker1.compare(x1); tracker2.compare(x2); test::check_equivalent_keys(x1); From 7911f491f6fabac85121acbdb8e1ea1e379e2df3 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 3 May 2017 04:21:52 +0100 Subject: [PATCH 113/147] Try using own allocator_traits with Sun compiler The good news is that the old Sun workarounds aren't needed any more. Unfortunately, there are a lot of exception test errors for unordered_map and unordered_multimap when using libstdc++, which probably means that std::pair isn't exception safe, which is a bit odd. But first try using our allocator_traits implementation instead of the standard one to see if that makes a difference. If it doesn't then I'll probably just disable C++11 construction on this compiler, which should fix the problem but will make allocators less useful. --- include/boost/unordered/detail/implementation.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 49bc321e..d436613b 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -75,7 +75,7 @@ // 2 = boost::container::allocator_traits #if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS) -#if !defined(BOOST_NO_CXX11_ALLOCATOR) +#if !defined(BOOST_NO_CXX11_ALLOCATOR) && !BOOST_COMP_SUNPRO #define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1 #elif defined(BOOST_MSVC) #if BOOST_MSVC < 1400 From 2f8492d7209de7a25ef83e5e4082fb34419d1073 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 3 May 2017 04:21:52 +0100 Subject: [PATCH 114/147] Fix libc++ configuration --- include/boost/unordered/detail/fwd.hpp | 2 +- include/boost/unordered/detail/implementation.hpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 6a842042..0e725d7c 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -20,7 +20,7 @@ #endif #elif defined(_LIBCPP_VERSION) // https://github.com/llvm-mirror/libcxx/blob/release_30/include/utility#L206 -#if LIBCPP_VERSION >= 3000 +#if _LIBCPP_VERSION >= 3000 #define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1 #endif #elif defined(BOOST_MSVC) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index d436613b..f7998380 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -120,8 +120,10 @@ #define BOOST_UNORDERED_TUPLE_ARGS 0 #elif !defined(BOOST_NO_CXX11_HDR_TUPLE) #define BOOST_UNORDERED_TUPLE_ARGS 10 -#elif BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT -#if defined(BOOST_MSVC) && defined(_VARIADIC_MAX) +#elif defined(BOOST_MSVC) +#if !BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT +#define BOOST_UNORDERED_TUPLE_ARGS 0 +#elif defined(_VARIADIC_MAX) #define BOOST_UNORDERED_TUPLE_ARGS _VARIADIC_MAX #else #define BOOST_UNORDERED_TUPLE_ARGS 5 From d05619095c00fb5af8f537b64047022c072e60b7 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 3 May 2017 04:21:52 +0100 Subject: [PATCH 115/147] Workaround problems with forward_as_tuple in older versions of clang --- include/boost/unordered/detail/implementation.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index f7998380..704203b0 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1779,10 +1779,21 @@ construct_node_pair_from_args( { node_constructor a(alloc); a.create_node(); +#if !(BOOST_COMP_CLANG && BOOST_COMP_CLANG < BOOST_VERSION_NUMBER(3, 8, 0) && \ + defined(BOOST_LIBSTDCXX11)) boost::unordered::detail::allocator_traits::construct(alloc, a.node_->value_ptr(), std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(args)...)); +#else + // It doesn't seem to be possible to construct a tuple with 3 variadic + // rvalue reference members when using older versions of clang with + // libstdc++, so just use std::make_tuple instead of std::forward_as_tuple. + boost::unordered::detail::allocator_traits::construct(alloc, + a.node_->value_ptr(), std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::make_tuple(boost::forward(args)...)); +#endif return a.release(); } From 41f6a051ef5f3f780ca95535ca9e6fb1e536b945 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 3 May 2017 04:21:53 +0100 Subject: [PATCH 116/147] Some more configuration comments --- .../boost/unordered/detail/implementation.hpp | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 704203b0..1e315189 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -113,13 +113,28 @@ // Other configuration macros // +// BOOST_UNORDERED_TUPLE_ARGS +// +// Maximum number of std::tuple members to support, or 0 if std::tuple +// isn't avaiable. More are supported when full C++11 is used. + +// Already defined, so do nothing #if defined(BOOST_UNORDERED_TUPLE_ARGS) -#elif BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0) + // I had problems with tuples on older versions of the sunpro. // Might be fixed in an earlier version than I specified here. +#elif BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0) #define BOOST_UNORDERED_TUPLE_ARGS 0 + +// Assume if we have C++11 tuple it's properly variadic, +// and just use a max number of 10 arguments. #elif !defined(BOOST_NO_CXX11_HDR_TUPLE) #define BOOST_UNORDERED_TUPLE_ARGS 10 + +// Visual C++ has a decent enough tuple for piecewise construction, +// so use that if available, using _VARIADIC_MAX for the maximum +// number of parameters. Note that this comes after the check +// for a full C++11 tuple. #elif defined(BOOST_MSVC) #if !BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT #define BOOST_UNORDERED_TUPLE_ARGS 0 @@ -128,6 +143,8 @@ #else #define BOOST_UNORDERED_TUPLE_ARGS 5 #endif + +// Assume that we don't have std::tuple #else #define BOOST_UNORDERED_TUPLE_ARGS 0 #endif @@ -136,10 +153,18 @@ #include #endif +// BOOST_UNORDERED_SUPPRESS_DEPRECATED +// +// Define to stop deprecation attributes + #if defined(BOOST_UNORDERED_SUPPRESS_DEPRECATED) #define BOOST_UNORDERED_DEPRECATED(msg) #endif +// BOOST_UNORDERED_DEPRECATED +// +// Wrapper around various depreaction attributes. + #if defined(__has_cpp_attribute) && \ (!defined(__cplusplus) || __cplusplus >= 201402) #if __has_cpp_attribute(deprecated) && !defined(BOOST_UNORDERED_DEPRECATED) From 622dff50df38a5d00fa9b29a25e0a9b810768089 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 3 May 2017 23:36:09 +0100 Subject: [PATCH 117/147] Fix some code that could be using next_node --- .../boost/unordered/detail/implementation.hpp | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 1e315189..7173e8cc 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -2729,11 +2729,6 @@ struct table : boost::unordered::detail::functionsnext_; - } - node_pointer next_group(node_pointer n) const { node_pointer n1 = n; @@ -3020,7 +3015,7 @@ struct table : boost::unordered::detail::functions(prev->next_); + node_pointer n = next_node(prev); prev->next_ = n->next_; BOOST_UNORDERED_CALL_DESTROY( @@ -3082,25 +3077,26 @@ struct table : boost::unordered::detail::functionsnext_; + node_pointer next = next_node(prev); std::size_t bucket_index2 = bucket_index; - if (end) { - bucket_index2 = node_bucket(static_cast(end)); + if (next) { + bucket_index2 = node_bucket(next); - // If begin and end are in the same bucket, then - // there's nothing to do. - if (bucket_index == bucket_index2) + // If next is in the same bucket, then there's nothing to do. + if (bucket_index == bucket_index2) { return bucket_index2; + } - // Update the bucket containing end. + // Update the bucket containing next. get_bucket(bucket_index2)->next_ = prev; } // Check if this bucket is now empty. bucket_pointer this_bucket = get_bucket(bucket_index); - if (this_bucket->next_ == prev) + if (this_bucket->next_ == prev) { this_bucket->next_ = link_pointer(); + } return bucket_index2; } @@ -4047,7 +4043,7 @@ struct table : boost::unordered::detail::functionsget_previous_start(bucket_index); while (prev->next_ != i) { - prev = next_for_erase(prev); + prev = next_node(prev); } prev->next_ = i->next_; @@ -4091,7 +4087,7 @@ struct table : boost::unordered::detail::functionsget_previous_start(bucket_index); while (prev->next_ != i) { - prev = next_for_erase(prev); + prev = next_node(prev); } // Delete the nodes. From 77bd45b1fa948a691442683188228184156f6c22 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 3 May 2017 23:37:42 +0100 Subject: [PATCH 118/147] Make second parameter of delete_nodes a node_pointer --- include/boost/unordered/detail/implementation.hpp | 10 +++++----- include/boost/unordered/unordered_map.hpp | 4 ++-- include/boost/unordered/unordered_set.hpp | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 7173e8cc..ed547a31 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3025,7 +3025,7 @@ struct table : boost::unordered::detail::functionsnext_ != end); @@ -3043,7 +3043,7 @@ struct table : boost::unordered::detail::functionsfind_previous_node(k, bucket_index); if (!prev) return 0; - link_pointer end = next_node(prev)->next_; + node_pointer end = next_node(next_node(prev)); this->delete_nodes(prev, end); this->fix_bucket(bucket_index, prev); return 1; @@ -4074,7 +4074,7 @@ struct table : boost::unordered::detail::functionsdelete_nodes(prev, end); this->fix_bucket(bucket_index, prev); @@ -4261,7 +4261,7 @@ inline void table::rehash_impl(std::size_t num_buckets) } } } - BOOST_CATCH(...) { delete_nodes(prev, link_pointer()); } + BOOST_CATCH(...) { delete_nodes(prev, node_pointer()); } BOOST_CATCH_END } diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 4a90d667..134d31a8 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1616,7 +1616,7 @@ void unordered_map::clear() BOOST_NOEXCEPT { if (table_.size_) { table_.clear_buckets(); - table_.delete_nodes(table_.get_previous_start(), link_pointer()); + table_.delete_nodes(table_.get_previous_start(), node_pointer()); } } @@ -2101,7 +2101,7 @@ void unordered_multimap::clear() BOOST_NOEXCEPT { if (table_.size_) { table_.clear_buckets(); - table_.delete_nodes(table_.get_previous_start(), link_pointer()); + table_.delete_nodes(table_.get_previous_start(), node_pointer()); } } diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 4d6dd544..58ea6417 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1280,7 +1280,7 @@ void unordered_set::clear() BOOST_NOEXCEPT { if (table_.size_) { table_.clear_buckets(); - table_.delete_nodes(table_.get_previous_start(), link_pointer()); + table_.delete_nodes(table_.get_previous_start(), node_pointer()); } } @@ -1684,7 +1684,7 @@ void unordered_multiset::clear() BOOST_NOEXCEPT { if (table_.size_) { table_.clear_buckets(); - table_.delete_nodes(table_.get_previous_start(), link_pointer()); + table_.delete_nodes(table_.get_previous_start(), node_pointer()); } } From d49d0e90a8737e91f378573421ffb134a08e358c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 3 May 2017 23:37:42 +0100 Subject: [PATCH 119/147] Delete nodes directly instead of through previous node --- .../boost/unordered/detail/implementation.hpp | 71 +++++++++++-------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index ed547a31..4849bdfa 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3013,16 +3013,12 @@ struct table : boost::unordered::detail::functionsnext_ = n->next_; - BOOST_UNORDERED_CALL_DESTROY( node_allocator_traits, node_alloc(), n->value_ptr()); boost::unordered::detail::func::destroy(boost::addressof(*n)); node_allocator_traits::deallocate(node_alloc(), n, 1); - --size_; } std::size_t delete_nodes(link_pointer prev, node_pointer end) @@ -3031,11 +3027,16 @@ struct table : boost::unordered::detail::functionsnext_ = end; do { - delete_node(prev); + node_pointer next = next_node(n); + destroy_node(n); + n = next; ++count; - } while (prev->next_ != end); + } while (n != end); + size_ -= count; return count; } @@ -3072,12 +3073,14 @@ struct table : boost::unordered::detail::functionsnext_ = n2; --this->size_; - this->fix_bucket(bucket_index, prev); + this->fix_bucket(bucket_index, prev, n2); n->next_ = link_pointer(); return n; @@ -3586,12 +3589,14 @@ struct table : boost::unordered::detail::functionsreserve_for_insert(this->size_ + 1); - prev->next_ = n->next_; - if (prev->next_ && n->is_first_in_group()) { - next_node(prev)->set_first_in_group(); + node_pointer n2 = next_node(n); + prev->next_ = n2; + if (n2 && n->is_first_in_group()) { + n2->set_first_in_group(); } --other.size_; - other.fix_bucket(other.node_bucket(n), prev); + other.fix_bucket( + other.node_bucket(n), prev, n2); this->add_node_unique(n, key_hash); } } @@ -3675,9 +3680,10 @@ struct table : boost::unordered::detail::functionsnext_ != n) { prev = prev->next_; } - prev->next_ = n->next_; + node_pointer n2 = next_node(n); + prev->next_ = n2; --this->size_; - this->fix_bucket(bucket_index, prev); + this->fix_bucket(bucket_index, prev, n2); n->next_ = link_pointer(); return n; } @@ -3698,7 +3704,7 @@ struct table : boost::unordered::detail::functionsdelete_nodes(prev, end); - this->fix_bucket(bucket_index, prev); + this->fix_bucket(bucket_index, prev, end); return 1; } @@ -3712,10 +3718,14 @@ struct table : boost::unordered::detail::functionsnext_; // Delete the nodes. + prev->next_ = j; do { - this->delete_node(prev); - bucket_index = this->fix_bucket(bucket_index, prev); - } while (prev->next_ != j); + node_pointer next = next_node(i); + destroy_node(i); + --size_; + bucket_index = this->fix_bucket(bucket_index, prev, next); + i = next; + } while (i != j); } //////////////////////////////////////////////////////////////////////// @@ -4046,12 +4056,12 @@ struct table : boost::unordered::detail::functionsnext_ = i->next_; + prev->next_ = j; if (j && i->is_first_in_group()) { j->set_first_in_group(); } --this->size_; - this->fix_bucket(bucket_index, prev); + this->fix_bucket(bucket_index, prev, j); i->next_ = link_pointer(); return i; @@ -4077,7 +4087,7 @@ struct table : boost::unordered::detail::functionsdelete_nodes(prev, end); - this->fix_bucket(bucket_index, prev); + this->fix_bucket(bucket_index, prev, end); return deleted_count; } @@ -4093,12 +4103,15 @@ struct table : boost::unordered::detail::functionsnext_ = j; do { - includes_first = - includes_first || next_node(prev)->is_first_in_group(); - this->delete_node(prev); - bucket_index = this->fix_bucket(bucket_index, prev); - } while (prev->next_ != j); + includes_first = includes_first || i->is_first_in_group(); + node_pointer next = next_node(i); + destroy_node(i); + --size_; + bucket_index = this->fix_bucket(bucket_index, prev, next); + i = next; + } while (i != j); if (j && includes_first) { j->set_first_in_group(); } From 47a8c3fc67c0260c02a1223c823067fc17452c91 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 4 May 2017 19:30:18 +0100 Subject: [PATCH 120/147] Fix exception handling in rehash_impl And improve tests so they will catch the error, and other similar errors. --- .../boost/unordered/detail/implementation.hpp | 17 +++-- test/exception/assign_exception_tests.cpp | 17 ++++- .../exception/constructor_exception_tests.cpp | 41 ++++++---- test/exception/copy_exception_tests.cpp | 14 +++- test/exception/erase_exception_tests.cpp | 3 + test/exception/insert_exception_tests.cpp | 74 ++++++++++++++++++- .../exception/move_assign_exception_tests.cpp | 5 ++ test/exception/rehash_exception_tests.cpp | 57 ++++++++++++-- test/exception/swap_exception_tests.cpp | 18 ++++- test/objects/exception.hpp | 58 +++++++++++++++ 10 files changed, 268 insertions(+), 36 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 4849bdfa..8b3b7a5a 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1516,7 +1516,7 @@ construct_from_args(Alloc& alloc, std::pair* address, BOOST_FWD_REF(A0), { boost::unordered::detail::func::destroy( boost::addressof(address->first)); - BOOST_RETHROW; + BOOST_RETHROW } BOOST_CATCH_END } @@ -1551,7 +1551,7 @@ inline typename enable_if, void>::type construct_from_args( { boost::unordered::detail::func::destroy( boost::addressof(address->first)); - BOOST_RETHROW; + BOOST_RETHROW } BOOST_CATCH_END } @@ -1630,7 +1630,7 @@ inline void construct_from_args(Alloc& alloc, std::pair* address, { boost::unordered::detail::func::destroy( boost::addressof(address->first)); - BOOST_RETHROW; + BOOST_RETHROW } BOOST_CATCH_END } @@ -1841,7 +1841,7 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) { boost::unordered::detail::func::destroy( boost::addressof(a.node_->value_ptr()->first)); - BOOST_RETHROW; + BOOST_RETHROW } BOOST_CATCH_END return a.release(); @@ -1865,7 +1865,7 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) { boost::unordered::detail::func::destroy( boost::addressof(a.node_->value_ptr()->first)); - BOOST_RETHROW; + BOOST_RETHROW } BOOST_CATCH_END return a.release(); @@ -1890,7 +1890,7 @@ construct_node_pair_from_args( { boost::unordered::detail::func::destroy( boost::addressof(a.node_->value_ptr()->first)); - BOOST_RETHROW; + BOOST_RETHROW } BOOST_CATCH_END return a.release(); @@ -4274,7 +4274,10 @@ inline void table::rehash_impl(std::size_t num_buckets) } } } - BOOST_CATCH(...) { delete_nodes(prev, node_pointer()); } + BOOST_CATCH(...) { + delete_nodes(prev, node_pointer()); + BOOST_RETHROW + } BOOST_CATCH_END } diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index 3295a4e8..2b39bf74 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -7,6 +7,7 @@ #include "../helpers/invariants.hpp" #include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" #if defined(BOOST_MSVC) #pragma warning(disable : 4512) // assignment operator could not be generated @@ -21,7 +22,13 @@ template struct self_assign_base : public test::exception_base typedef T data_type; T init() const { return T(values.begin(), values.end()); } - void run(T& x) const { x = x; } + + void run(T& x) const { + x = x; + test::check_container(x, values); + test::check_equivalent_keys(x); + } + void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const { test::check_equivalent_keys(x); @@ -57,7 +64,13 @@ template struct assign_base : public test::exception_base typedef T data_type; T init() const { return T(x); } - void run(T& x1) const { x1 = y; } + + void run(T& x1) const { + x1 = y; + test::check_container(x1, y_values); + test::check_equivalent_keys(x1); + } + void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const { test::check_equivalent_keys(x1); diff --git a/test/exception/constructor_exception_tests.cpp b/test/exception/constructor_exception_tests.cpp index db5023f7..e4a12420 100644 --- a/test/exception/constructor_exception_tests.cpp +++ b/test/exception/constructor_exception_tests.cpp @@ -7,6 +7,8 @@ #include "../helpers/input_iterator.hpp" #include "../helpers/random_values.hpp" +#include "../helpers/invariants.hpp" +#include "../helpers/tracker.hpp" template inline void avoid_unused_warning(T const&) {} @@ -25,7 +27,8 @@ template struct construct_test1 : public objects, test::exception_base void run() const { T x; - avoid_unused_warning(x); + BOOST_TEST(x.empty()); + test::check_equivalent_keys(x); } }; @@ -34,7 +37,8 @@ template struct construct_test2 : public objects, test::exception_base void run() const { T x(300); - avoid_unused_warning(x); + BOOST_TEST(x.empty()); + test::check_equivalent_keys(x); } }; @@ -43,7 +47,8 @@ template struct construct_test3 : public objects, test::exception_base void run() const { T x(0, hash); - avoid_unused_warning(x); + BOOST_TEST(x.empty()); + test::check_equivalent_keys(x); } }; @@ -52,7 +57,8 @@ template struct construct_test4 : public objects, test::exception_base void run() const { T x(0, hash, equal_to); - avoid_unused_warning(x); + BOOST_TEST(x.empty()); + test::check_equivalent_keys(x); } }; @@ -61,7 +67,8 @@ template struct construct_test5 : public objects, test::exception_base void run() const { T x(50, hash, equal_to, allocator); - avoid_unused_warning(x); + BOOST_TEST(x.empty()); + test::check_equivalent_keys(x); } }; @@ -70,7 +77,8 @@ template struct construct_test6 : public objects, test::exception_base void run() const { T x(allocator); - avoid_unused_warning(x); + BOOST_TEST(x.empty()); + test::check_equivalent_keys(x); } }; @@ -87,7 +95,8 @@ template struct range_construct_test1 : public range, objects void run() const { T x(this->values.begin(), this->values.end()); - avoid_unused_warning(x); + test::check_container(x, this->values); + test::check_equivalent_keys(x); } }; @@ -96,7 +105,8 @@ template struct range_construct_test2 : public range, objects void run() const { T x(this->values.begin(), this->values.end(), 0); - avoid_unused_warning(x); + test::check_container(x, this->values); + test::check_equivalent_keys(x); } }; @@ -105,7 +115,8 @@ template struct range_construct_test3 : public range, objects void run() const { T x(this->values.begin(), this->values.end(), 0, hash); - avoid_unused_warning(x); + test::check_container(x, this->values); + test::check_equivalent_keys(x); } }; @@ -114,7 +125,8 @@ template struct range_construct_test4 : public range, objects void run() const { T x(this->values.begin(), this->values.end(), 100, hash, equal_to); - avoid_unused_warning(x); + test::check_container(x, this->values); + test::check_equivalent_keys(x); } }; @@ -128,7 +140,8 @@ template struct range_construct_test5 : public range, objects { T x(this->values.begin(), this->values.end(), 0, hash, equal_to, allocator); - avoid_unused_warning(x); + test::check_container(x, this->values); + test::check_equivalent_keys(x); } }; @@ -143,7 +156,8 @@ template struct input_range_construct_test : public range, objects end = this->values.end(); T x(test::input_iterator(begin), test::input_iterator(end), 0, hash, equal_to, allocator); - avoid_unused_warning(x); + test::check_container(x, this->values); + test::check_equivalent_keys(x); } }; @@ -156,7 +170,8 @@ template struct copy_range_construct_test : public range, objects T x(test::copy_iterator(this->values.begin()), test::copy_iterator(this->values.end()), 0, hash, equal_to, allocator); - avoid_unused_warning(x); + test::check_container(x, this->values); + test::check_equivalent_keys(x); } }; diff --git a/test/exception/copy_exception_tests.cpp b/test/exception/copy_exception_tests.cpp index 9bb87eca..2faa7e84 100644 --- a/test/exception/copy_exception_tests.cpp +++ b/test/exception/copy_exception_tests.cpp @@ -6,6 +6,8 @@ #include "./containers.hpp" #include "../helpers/random_values.hpp" +#include "../helpers/invariants.hpp" +#include "../helpers/tracker.hpp" template inline void avoid_unused_warning(T const&) {} @@ -18,7 +20,8 @@ template struct copy_test1 : public test::exception_base void run() const { T y(x); - avoid_unused_warning(y); + BOOST_TEST(y.empty()); + test::check_equivalent_keys(y); } }; @@ -32,7 +35,8 @@ template struct copy_test2 : public test::exception_base void run() const { T y(x); - avoid_unused_warning(y); + test::check_container(y, this->values); + test::check_equivalent_keys(y); } }; @@ -46,7 +50,8 @@ template struct copy_test3 : public test::exception_base void run() const { T y(x); - avoid_unused_warning(y); + test::check_container(y, this->values); + test::check_equivalent_keys(y); } }; @@ -61,7 +66,8 @@ template struct copy_with_allocator_test : public test::exception_base void run() const { T y(x, allocator); - avoid_unused_warning(y); + test::check_container(y, this->values); + test::check_equivalent_keys(y); } }; diff --git a/test/exception/erase_exception_tests.cpp b/test/exception/erase_exception_tests.cpp index a939ded3..719ceb87 100644 --- a/test/exception/erase_exception_tests.cpp +++ b/test/exception/erase_exception_tests.cpp @@ -43,6 +43,9 @@ template struct erase_by_key_test1 : public erase_test_base it != end; ++it) { x.erase(test::get_key(*it)); } + + BOOST_TEST(x.empty()); + test::check_equivalent_keys(x); } }; diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index f8d635de..b43ece5c 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -2,13 +2,14 @@ // Copyright 2006-2009 Daniel James. // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - #include "./containers.hpp" +#include #include "../helpers/helpers.hpp" #include "../helpers/invariants.hpp" #include "../helpers/random_values.hpp" #include "../helpers/strong.hpp" +#include "../helpers/tracker.hpp" #include #include @@ -54,6 +55,10 @@ template struct emplace_test1 : public insert_test_base strong.store(x, test::detail::tracker.count_allocations); x.emplace(*it); } + + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); } }; @@ -72,6 +77,10 @@ template struct insert_test1 : public insert_test_base strong.store(x, test::detail::tracker.count_allocations); x.insert(*it); } + + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); } }; @@ -88,12 +97,23 @@ template struct insert_test2 : public insert_test_base strong.store(x, test::detail::tracker.count_allocations); x.insert(x.begin(), *it); } + + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); } }; template struct insert_test3 : public insert_test_base { - void run(T& x) const { x.insert(this->values.begin(), this->values.end()); } + void run(T& x) const + { + x.insert(this->values.begin(), this->values.end()); + + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); + } void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const { @@ -114,6 +134,10 @@ template struct insert_test4 : public insert_test_base strong.store(x, test::detail::tracker.count_allocations); x.insert(it, test::next(it)); } + + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); } }; @@ -147,17 +171,30 @@ template struct insert_test_rehash1 : public insert_test_base int count = 0; BOOST_DEDUCED_TYPENAME T::const_iterator pos = x.cbegin(); + test::list v; + { + DISABLE_EXCEPTIONS; + v.insert(x.begin(), x.end()); + } + for (BOOST_DEDUCED_TYPENAME test::random_values::const_iterator it = test::next(this->values.begin(), x.size()), end = this->values.end(); it != end && count < 10; ++it, ++count) { strong.store(x, test::detail::tracker.count_allocations); pos = x.insert(pos, *it); + + DISABLE_EXCEPTIONS; + v.push_back(*it); } // This isn't actually a failure, but it means the test isn't doing its // job. BOOST_TEST(x.bucket_count() != bucket_count); + + DISABLE_EXCEPTIONS; + test::check_container(x, v); + test::check_equivalent_keys(x); } }; @@ -170,17 +207,30 @@ template struct insert_test_rehash2 : public insert_test_rehash1 BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count(); int count = 0; + test::list v; + { + DISABLE_EXCEPTIONS; + v.insert(x.begin(), x.end()); + } + for (BOOST_DEDUCED_TYPENAME test::random_values::const_iterator it = test::next(this->values.begin(), x.size()), end = this->values.end(); it != end && count < 10; ++it, ++count) { strong.store(x, test::detail::tracker.count_allocations); x.insert(*it); + + DISABLE_EXCEPTIONS; + v.push_back(*it); } // This isn't actually a failure, but it means the test isn't doing its // job. BOOST_TEST(x.bucket_count() != bucket_count); + + DISABLE_EXCEPTIONS; + test::check_container(x, v); + test::check_equivalent_keys(x); } }; @@ -218,6 +268,14 @@ template struct insert_test_rehash3 : public insert_test_base void run(T& x) const { BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count(); + test::list v; + + { + DISABLE_EXCEPTIONS; + v.insert(x.begin(), x.end()); + v.insert(test::next(this->values.begin(), x.size()), + test::next(this->values.begin(), x.size() + 20)); + } x.insert(test::next(this->values.begin(), x.size()), test::next(this->values.begin(), x.size() + 20)); @@ -225,6 +283,10 @@ template struct insert_test_rehash3 : public insert_test_base // This isn't actually a failure, but it means the test isn't doing its // job. BOOST_TEST(x.bucket_count() != bucket_count); + + DISABLE_EXCEPTIONS; + test::check_container(x, v); + test::check_equivalent_keys(x); } void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const @@ -263,6 +325,10 @@ template struct pair_emplace_test1 : public insert_test_base x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(it->first), boost::make_tuple(it->second)); } + + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); } }; @@ -281,6 +347,10 @@ template struct pair_emplace_test2 : public insert_test_base boost::make_tuple(it->first), boost::make_tuple(it->second.tag1_, it->second.tag2_)); } + + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); } }; diff --git a/test/exception/move_assign_exception_tests.cpp b/test/exception/move_assign_exception_tests.cpp index 9a8d122b..048ab102 100644 --- a/test/exception/move_assign_exception_tests.cpp +++ b/test/exception/move_assign_exception_tests.cpp @@ -7,6 +7,7 @@ #include "../helpers/invariants.hpp" #include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" #include #if defined(BOOST_MSVC) @@ -42,7 +43,11 @@ template struct move_assign_base : public test::exception_base T y1 = y; disable_exceptions.release(); x1 = boost::move(y1); + + test::check_container(x1, y_values); + test::check_equivalent_keys(x1); } + void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const { test::check_equivalent_keys(x1); diff --git a/test/exception/rehash_exception_tests.cpp b/test/exception/rehash_exception_tests.cpp index a65ebae9..ae31f397 100644 --- a/test/exception/rehash_exception_tests.cpp +++ b/test/exception/rehash_exception_tests.cpp @@ -8,6 +8,7 @@ #include "../helpers/invariants.hpp" #include "../helpers/random_values.hpp" #include "../helpers/strong.hpp" +#include "../helpers/tracker.hpp" #include #include @@ -49,34 +50,76 @@ template struct rehash_test_base : public test::exception_base template struct rehash_test0 : rehash_test_base { rehash_test0() : rehash_test_base(0) {} - void run(T& x) const { x.rehash(0); } + void run(T& x) const + { + x.rehash(0); + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); + } }; template struct rehash_test1 : rehash_test_base { rehash_test1() : rehash_test_base(0) {} - void run(T& x) const { x.rehash(200); } + void run(T& x) const + { + x.rehash(200); + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); + } }; template struct rehash_test2 : rehash_test_base { rehash_test2() : rehash_test_base(0, 200) {} - void run(T& x) const { x.rehash(0); } + void run(T& x) const + { + x.rehash(0); + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); + } }; template struct rehash_test3 : rehash_test_base { rehash_test3() : rehash_test_base(10, 0) {} - void run(T& x) const { x.rehash(200); } + void run(T& x) const + { + x.rehash(200); + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); + } }; template struct rehash_test4 : rehash_test_base { rehash_test4() : rehash_test_base(10, 200) {} - void run(T& x) const { x.rehash(0); } + void run(T& x) const + { + x.rehash(0); + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); + } }; -EXCEPTION_TESTS( - (rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(rehash_test4), +template struct rehash_test5 : rehash_test_base +{ + rehash_test5() : rehash_test_base(200, 10) {} + void run(T& x) const + { + x.rehash(0); + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); + } +}; + +EXCEPTION_TESTS((rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)( + rehash_test4)(rehash_test5), CONTAINER_SEQ) RUN_TESTS() diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index 12ba6403..13ee18b3 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_exception_tests.cpp @@ -7,6 +7,7 @@ #include "../helpers/invariants.hpp" #include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" #if defined(BOOST_MSVC) #pragma warning(disable : 4512) // assignment operator could not be generated @@ -21,7 +22,15 @@ template struct self_swap_base : public test::exception_base typedef T data_type; T init() const { return T(values.begin(), values.end()); } - void run(T& x) const { x.swap(x); } + + void run(T& x) const { + x.swap(x); + + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); + } + void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const { std::string scope(test::scope); @@ -82,7 +91,14 @@ template struct swap_base : public test::exception_base d.x.swap(d.y); } catch (std::runtime_error) { } + + DISABLE_EXCEPTIONS; + test::check_container(d.x, this->y_values); + test::check_equivalent_keys(d.x); + test::check_container(d.y, this->x_values); + test::check_equivalent_keys(d.y); } + void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const { std::string scope(test::scope); diff --git a/test/objects/exception.hpp b/test/objects/exception.hpp index e76ac477..017c88da 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -11,6 +11,7 @@ #include "../helpers/count.hpp" #include "../helpers/fwd.hpp" #include "../helpers/memory.hpp" +#include "../objects/fwd.hpp" #include #include #include @@ -311,6 +312,55 @@ class equal_to } }; +class less +{ + int tag_; + + public: + less(int t = 0) : tag_(t) {} + + less(less const& x) : tag_(x.tag_) {} + + bool operator()(object const& x1, object const& x2) const + { + return less_impl(x1, x2); + } + + bool operator()(std::pair const& x1, + std::pair const& x2) const + { + if (less_impl(x1.first, x2.first)) { + return true; + } + if (!less_impl(x1.first, x2.first)) { + return false; + } + return less_impl(x1.second, x2.second); + } + + bool less_impl(object const& x1, object const& x2) const + { + switch (tag_) { + case 1: + return x1.tag1_ < x2.tag1_; + case 2: + return x1.tag2_ < x2.tag2_; + default: + return x1 < x2; + } + } + + friend bool operator==(less const& x1, less const& x2) + { + return x1.tag_ == x2.tag_; + } + + friend bool operator!=(less const& x1, less const& x2) + { + return x1.tag_ != x2.tag_; + } +}; + template class allocator { public: @@ -672,6 +722,14 @@ inline bool operator!=(allocator2 const& x, allocator2 const& y) } } +namespace test { +template struct equals_to_compare; +template <> struct equals_to_compare +{ + typedef test::exception::less type; +}; +} + // Workaround for ADL deficient compilers #if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) namespace test { From 6ef17a0f0ef05d69ca2e96b59732cd13f49a5f83 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 5 May 2017 00:46:07 +0100 Subject: [PATCH 121/147] Remember to disable exceptions before checking final value --- .../boost/unordered/detail/implementation.hpp | 6 ++-- test/exception/assign_exception_tests.cpp | 10 +++++-- .../exception/constructor_exception_tests.cpp | 28 ++++++++++++++++++- test/exception/copy_exception_tests.cpp | 10 ++++++- test/exception/erase_exception_tests.cpp | 3 +- .../exception/move_assign_exception_tests.cpp | 1 + test/exception/rehash_exception_tests.cpp | 6 ++++ test/exception/swap_exception_tests.cpp | 3 +- 8 files changed, 58 insertions(+), 9 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 8b3b7a5a..0bd7a20e 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3595,8 +3595,7 @@ struct table : boost::unordered::detail::functionsset_first_in_group(); } --other.size_; - other.fix_bucket( - other.node_bucket(n), prev, n2); + other.fix_bucket(other.node_bucket(n), prev, n2); this->add_node_unique(n, key_hash); } } @@ -4274,7 +4273,8 @@ inline void table::rehash_impl(std::size_t num_buckets) } } } - BOOST_CATCH(...) { + BOOST_CATCH(...) + { delete_nodes(prev, node_pointer()); BOOST_RETHROW } diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index 2b39bf74..49019fdd 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -23,8 +23,11 @@ template struct self_assign_base : public test::exception_base typedef T data_type; T init() const { return T(values.begin(), values.end()); } - void run(T& x) const { + void run(T& x) const + { x = x; + + DISABLE_EXCEPTIONS; test::check_container(x, values); test::check_equivalent_keys(x); } @@ -65,8 +68,11 @@ template struct assign_base : public test::exception_base typedef T data_type; T init() const { return T(x); } - void run(T& x1) const { + void run(T& x1) const + { x1 = y; + + DISABLE_EXCEPTIONS; test::check_container(x1, y_values); test::check_equivalent_keys(x1); } diff --git a/test/exception/constructor_exception_tests.cpp b/test/exception/constructor_exception_tests.cpp index e4a12420..503cce0e 100644 --- a/test/exception/constructor_exception_tests.cpp +++ b/test/exception/constructor_exception_tests.cpp @@ -6,8 +6,8 @@ #include "./containers.hpp" #include "../helpers/input_iterator.hpp" -#include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" +#include "../helpers/random_values.hpp" #include "../helpers/tracker.hpp" template inline void avoid_unused_warning(T const&) {} @@ -27,6 +27,8 @@ template struct construct_test1 : public objects, test::exception_base void run() const { T x; + + DISABLE_EXCEPTIONS; BOOST_TEST(x.empty()); test::check_equivalent_keys(x); } @@ -37,6 +39,8 @@ template struct construct_test2 : public objects, test::exception_base void run() const { T x(300); + + DISABLE_EXCEPTIONS; BOOST_TEST(x.empty()); test::check_equivalent_keys(x); } @@ -47,6 +51,8 @@ template struct construct_test3 : public objects, test::exception_base void run() const { T x(0, hash); + + DISABLE_EXCEPTIONS; BOOST_TEST(x.empty()); test::check_equivalent_keys(x); } @@ -57,6 +63,8 @@ template struct construct_test4 : public objects, test::exception_base void run() const { T x(0, hash, equal_to); + + DISABLE_EXCEPTIONS; BOOST_TEST(x.empty()); test::check_equivalent_keys(x); } @@ -67,6 +75,8 @@ template struct construct_test5 : public objects, test::exception_base void run() const { T x(50, hash, equal_to, allocator); + + DISABLE_EXCEPTIONS; BOOST_TEST(x.empty()); test::check_equivalent_keys(x); } @@ -77,6 +87,8 @@ template struct construct_test6 : public objects, test::exception_base void run() const { T x(allocator); + + DISABLE_EXCEPTIONS; BOOST_TEST(x.empty()); test::check_equivalent_keys(x); } @@ -95,6 +107,8 @@ template struct range_construct_test1 : public range, objects void run() const { T x(this->values.begin(), this->values.end()); + + DISABLE_EXCEPTIONS; test::check_container(x, this->values); test::check_equivalent_keys(x); } @@ -105,6 +119,8 @@ template struct range_construct_test2 : public range, objects void run() const { T x(this->values.begin(), this->values.end(), 0); + + DISABLE_EXCEPTIONS; test::check_container(x, this->values); test::check_equivalent_keys(x); } @@ -115,6 +131,8 @@ template struct range_construct_test3 : public range, objects void run() const { T x(this->values.begin(), this->values.end(), 0, hash); + + DISABLE_EXCEPTIONS; test::check_container(x, this->values); test::check_equivalent_keys(x); } @@ -125,6 +143,8 @@ template struct range_construct_test4 : public range, objects void run() const { T x(this->values.begin(), this->values.end(), 100, hash, equal_to); + + DISABLE_EXCEPTIONS; test::check_container(x, this->values); test::check_equivalent_keys(x); } @@ -140,6 +160,8 @@ template struct range_construct_test5 : public range, objects { T x(this->values.begin(), this->values.end(), 0, hash, equal_to, allocator); + + DISABLE_EXCEPTIONS; test::check_container(x, this->values); test::check_equivalent_keys(x); } @@ -156,6 +178,8 @@ template struct input_range_construct_test : public range, objects end = this->values.end(); T x(test::input_iterator(begin), test::input_iterator(end), 0, hash, equal_to, allocator); + + DISABLE_EXCEPTIONS; test::check_container(x, this->values); test::check_equivalent_keys(x); } @@ -170,6 +194,8 @@ template struct copy_range_construct_test : public range, objects T x(test::copy_iterator(this->values.begin()), test::copy_iterator(this->values.end()), 0, hash, equal_to, allocator); + + DISABLE_EXCEPTIONS; test::check_container(x, this->values); test::check_equivalent_keys(x); } diff --git a/test/exception/copy_exception_tests.cpp b/test/exception/copy_exception_tests.cpp index 2faa7e84..1e57872c 100644 --- a/test/exception/copy_exception_tests.cpp +++ b/test/exception/copy_exception_tests.cpp @@ -5,8 +5,8 @@ #include "./containers.hpp" -#include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" +#include "../helpers/random_values.hpp" #include "../helpers/tracker.hpp" template inline void avoid_unused_warning(T const&) {} @@ -20,6 +20,8 @@ template struct copy_test1 : public test::exception_base void run() const { T y(x); + + DISABLE_EXCEPTIONS; BOOST_TEST(y.empty()); test::check_equivalent_keys(y); } @@ -35,6 +37,8 @@ template struct copy_test2 : public test::exception_base void run() const { T y(x); + + DISABLE_EXCEPTIONS; test::check_container(y, this->values); test::check_equivalent_keys(y); } @@ -50,6 +54,8 @@ template struct copy_test3 : public test::exception_base void run() const { T y(x); + + DISABLE_EXCEPTIONS; test::check_container(y, this->values); test::check_equivalent_keys(y); } @@ -66,6 +72,8 @@ template struct copy_with_allocator_test : public test::exception_base void run() const { T y(x, allocator); + + DISABLE_EXCEPTIONS; test::check_container(y, this->values); test::check_equivalent_keys(y); } diff --git a/test/exception/erase_exception_tests.cpp b/test/exception/erase_exception_tests.cpp index 719ceb87..f400bdd9 100644 --- a/test/exception/erase_exception_tests.cpp +++ b/test/exception/erase_exception_tests.cpp @@ -44,8 +44,9 @@ template struct erase_by_key_test1 : public erase_test_base x.erase(test::get_key(*it)); } + DISABLE_EXCEPTIONS; BOOST_TEST(x.empty()); - test::check_equivalent_keys(x); + test::check_equivalent_keys(x); } }; diff --git a/test/exception/move_assign_exception_tests.cpp b/test/exception/move_assign_exception_tests.cpp index 048ab102..ac0eaf1c 100644 --- a/test/exception/move_assign_exception_tests.cpp +++ b/test/exception/move_assign_exception_tests.cpp @@ -44,6 +44,7 @@ template struct move_assign_base : public test::exception_base disable_exceptions.release(); x1 = boost::move(y1); + DISABLE_EXCEPTIONS; test::check_container(x1, y_values); test::check_equivalent_keys(x1); } diff --git a/test/exception/rehash_exception_tests.cpp b/test/exception/rehash_exception_tests.cpp index ae31f397..6781508b 100644 --- a/test/exception/rehash_exception_tests.cpp +++ b/test/exception/rehash_exception_tests.cpp @@ -53,6 +53,7 @@ template struct rehash_test0 : rehash_test_base void run(T& x) const { x.rehash(0); + DISABLE_EXCEPTIONS; test::check_container(x, this->values); test::check_equivalent_keys(x); @@ -65,6 +66,7 @@ template struct rehash_test1 : rehash_test_base void run(T& x) const { x.rehash(200); + DISABLE_EXCEPTIONS; test::check_container(x, this->values); test::check_equivalent_keys(x); @@ -77,6 +79,7 @@ template struct rehash_test2 : rehash_test_base void run(T& x) const { x.rehash(0); + DISABLE_EXCEPTIONS; test::check_container(x, this->values); test::check_equivalent_keys(x); @@ -89,6 +92,7 @@ template struct rehash_test3 : rehash_test_base void run(T& x) const { x.rehash(200); + DISABLE_EXCEPTIONS; test::check_container(x, this->values); test::check_equivalent_keys(x); @@ -101,6 +105,7 @@ template struct rehash_test4 : rehash_test_base void run(T& x) const { x.rehash(0); + DISABLE_EXCEPTIONS; test::check_container(x, this->values); test::check_equivalent_keys(x); @@ -113,6 +118,7 @@ template struct rehash_test5 : rehash_test_base void run(T& x) const { x.rehash(0); + DISABLE_EXCEPTIONS; test::check_container(x, this->values); test::check_equivalent_keys(x); diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index 13ee18b3..341e67d5 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_exception_tests.cpp @@ -23,7 +23,8 @@ template struct self_swap_base : public test::exception_base typedef T data_type; T init() const { return T(values.begin(), values.end()); } - void run(T& x) const { + void run(T& x) const + { x.swap(x); DISABLE_EXCEPTIONS; From 3fe259a79e5a42f4cc2d991cfffd8b07a36355d5 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 5 May 2017 12:54:29 +0100 Subject: [PATCH 122/147] Fix creating exception::less from exception::equal_to --- test/objects/exception.hpp | 98 +++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/test/objects/exception.hpp b/test/objects/exception.hpp index 017c88da..8471bd29 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -226,6 +226,55 @@ class hash } }; +class less +{ + int tag_; + + public: + less(int t = 0) : tag_(t) {} + + less(less const& x) : tag_(x.tag_) {} + + bool operator()(object const& x1, object const& x2) const + { + return less_impl(x1, x2); + } + + bool operator()(std::pair const& x1, + std::pair const& x2) const + { + if (less_impl(x1.first, x2.first)) { + return true; + } + if (!less_impl(x1.first, x2.first)) { + return false; + } + return less_impl(x1.second, x2.second); + } + + bool less_impl(object const& x1, object const& x2) const + { + switch (tag_) { + case 1: + return x1.tag1_ < x2.tag1_; + case 2: + return x1.tag2_ < x2.tag2_; + default: + return x1 < x2; + } + } + + friend bool operator==(less const& x1, less const& x2) + { + return x1.tag_ == x2.tag_; + } + + friend bool operator!=(less const& x1, less const& x2) + { + return x1.tag_ != x2.tag_; + } +}; + class equal_to { int tag_; @@ -310,55 +359,8 @@ class equal_to } return x1.tag_ != x2.tag_; } -}; -class less -{ - int tag_; - - public: - less(int t = 0) : tag_(t) {} - - less(less const& x) : tag_(x.tag_) {} - - bool operator()(object const& x1, object const& x2) const - { - return less_impl(x1, x2); - } - - bool operator()(std::pair const& x1, - std::pair const& x2) const - { - if (less_impl(x1.first, x2.first)) { - return true; - } - if (!less_impl(x1.first, x2.first)) { - return false; - } - return less_impl(x1.second, x2.second); - } - - bool less_impl(object const& x1, object const& x2) const - { - switch (tag_) { - case 1: - return x1.tag1_ < x2.tag1_; - case 2: - return x1.tag2_ < x2.tag2_; - default: - return x1 < x2; - } - } - - friend bool operator==(less const& x1, less const& x2) - { - return x1.tag_ == x2.tag_; - } - - friend bool operator!=(less const& x1, less const& x2) - { - return x1.tag_ != x2.tag_; - } + friend less create_compare(equal_to x) { return less(x.tag_); } }; template class allocator From 597eb5a3fd66c5393626b4f51456596d666b6a8a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 6 May 2017 04:47:59 +0100 Subject: [PATCH 123/147] Repeat the assign/insert exception tests a few times --- test/exception/assign_exception_tests.cpp | 6 +++--- test/exception/insert_exception_tests.cpp | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index 49019fdd..b6b580ad 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -150,8 +150,8 @@ template struct equivalent_test1 : assign_base } }; -EXCEPTION_TESTS((self_assign_test1)(self_assign_test2)(assign_test1)( - assign_test2)(assign_test3)(assign_test4)(assign_test4a)( - assign_test5)(equivalent_test1), +EXCEPTION_TESTS_REPEAT(5, (self_assign_test1)(self_assign_test2)(assign_test1)( + assign_test2)(assign_test3)(assign_test4)( + assign_test4a)(assign_test5)(equivalent_test1), CONTAINER_SEQ) RUN_TESTS() diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index b43ece5c..44e1e545 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -309,7 +309,7 @@ template struct insert_test_rehash3 : public insert_test_base #define ALL_TESTS BASIC_TESTS #endif -EXCEPTION_TESTS(ALL_TESTS, CONTAINER_SEQ) +EXCEPTION_TESTS_REPEAT(5, ALL_TESTS, CONTAINER_SEQ) template struct pair_emplace_test1 : public insert_test_base { @@ -354,7 +354,8 @@ template struct pair_emplace_test2 : public insert_test_base } }; -EXCEPTION_TESTS((pair_emplace_test1)(pair_emplace_test2), CONTAINER_PAIR_SEQ) +EXCEPTION_TESTS_REPEAT( + 5, (pair_emplace_test1)(pair_emplace_test2), CONTAINER_PAIR_SEQ) template struct index_insert_test1 : public insert_test_base { @@ -372,6 +373,6 @@ template struct index_insert_test1 : public insert_test_base } }; -EXCEPTION_TESTS((index_insert_test1), (test_map)) +EXCEPTION_TESTS_REPEAT(5, (index_insert_test1), (test_map)) RUN_TESTS() From 0489069419bc96f7d86a857cdc654baecd706c3b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 6 May 2017 04:47:59 +0100 Subject: [PATCH 124/147] Use 'limited_range' to catch error in exception tests This would have caught the error fixed in 3fe259a79e5. --- test/exception/assign_exception_tests.cpp | 44 +++++++++++++++---- .../exception/constructor_exception_tests.cpp | 4 +- test/exception/copy_exception_tests.cpp | 31 ++++++++++++- test/exception/erase_exception_tests.cpp | 4 +- .../exception/move_assign_exception_tests.cpp | 8 ++-- test/exception/rehash_exception_tests.cpp | 2 +- test/exception/swap_exception_tests.cpp | 7 ++- 7 files changed, 80 insertions(+), 20 deletions(-) diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index b6b580ad..cad7fb35 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -18,7 +18,9 @@ test::seed_t initialize_seed(12847); template struct self_assign_base : public test::exception_base { test::random_values values; - self_assign_base(std::size_t count = 0) : values(count) {} + self_assign_base(std::size_t count = 0) : values(count, test::limited_range) + { + } typedef T data_type; T init() const { return T(values.begin(), values.end()); } @@ -95,11 +97,12 @@ template struct assign_base : public test::exception_base template struct assign_values : assign_base { assign_values(unsigned int count1, unsigned int count2, int tag1, int tag2, - float mlf1 = 1.0, float mlf2 = 1.0) + test::random_generator gen = test::default_generator, float mlf1 = 1.0, + float mlf2 = 1.0) : assign_base(tag1, tag2, mlf1, mlf2) { - this->x_values.fill(count1); - this->y_values.fill(count2); + this->x_values.fill(count1, gen); + this->y_values.fill(count2, gen); this->x.insert(this->x_values.begin(), this->x_values.end()); this->y.insert(this->y_values.begin(), this->y_values.end()); } @@ -115,11 +118,21 @@ template struct assign_test2 : assign_values assign_test2() : assign_values(60, 0, 0, 0) {} }; +template struct assign_test2a : assign_values +{ + assign_test2a() : assign_values(60, 0, 0, 0, test::limited_range) {} +}; + template struct assign_test3 : assign_values { assign_test3() : assign_values(0, 60, 0, 0) {} }; +template struct assign_test3a : assign_values +{ + assign_test3a() : assign_values(0, 60, 0, 0, test::limited_range) {} +}; + template struct assign_test4 : assign_values { assign_test4() : assign_values(10, 10, 1, 2) {} @@ -130,9 +143,17 @@ template struct assign_test4a : assign_values assign_test4a() : assign_values(10, 100, 1, 2) {} }; +template struct assign_test4b : assign_values +{ + assign_test4b() : assign_values(10, 100, 1, 2, test::limited_range) {} +}; + template struct assign_test5 : assign_values { - assign_test5() : assign_values(5, 60, 0, 0, 1.0f, 0.1f) {} + assign_test5() + : assign_values(5, 60, 0, 0, test::default_generator, 1.0f, 0.1f) + { + } }; template struct equivalent_test1 : assign_base @@ -150,8 +171,15 @@ template struct equivalent_test1 : assign_base } }; -EXCEPTION_TESTS_REPEAT(5, (self_assign_test1)(self_assign_test2)(assign_test1)( - assign_test2)(assign_test3)(assign_test4)( - assign_test4a)(assign_test5)(equivalent_test1), +// clang-format off +EXCEPTION_TESTS_REPEAT(5, + (self_assign_test1)(self_assign_test2) + (assign_test1)(assign_test2)(assign_test2a) + (assign_test3)(assign_test3a) + (assign_test4)(assign_test4a)(assign_test4b) + (assign_test5) + (equivalent_test1), CONTAINER_SEQ) +// clang-format on + RUN_TESTS() diff --git a/test/exception/constructor_exception_tests.cpp b/test/exception/constructor_exception_tests.cpp index 503cce0e..39468054 100644 --- a/test/exception/constructor_exception_tests.cpp +++ b/test/exception/constructor_exception_tests.cpp @@ -98,8 +98,8 @@ template struct range : public test::exception_base { test::random_values values; - range() : values(5) {} - range(unsigned int count) : values(count) {} + range() : values(5, test::limited_range) {} + range(unsigned int count) : values(count, test::limited_range) {} }; template struct range_construct_test1 : public range, objects diff --git a/test/exception/copy_exception_tests.cpp b/test/exception/copy_exception_tests.cpp index 1e57872c..ba6b2bcf 100644 --- a/test/exception/copy_exception_tests.cpp +++ b/test/exception/copy_exception_tests.cpp @@ -32,7 +32,10 @@ template struct copy_test2 : public test::exception_base test::random_values values; T x; - copy_test2() : values(5), x(values.begin(), values.end()) {} + copy_test2() + : values(5, test::limited_range), x(values.begin(), values.end()) + { + } void run() const { @@ -61,6 +64,26 @@ template struct copy_test3 : public test::exception_base } }; +template struct copy_test3a : public test::exception_base +{ + test::random_values values; + T x; + + copy_test3a() + : values(100, test::limited_range), x(values.begin(), values.end()) + { + } + + void run() const + { + T y(x); + + DISABLE_EXCEPTIONS; + test::check_container(y, this->values); + test::check_equivalent_keys(y); + } +}; + template struct copy_with_allocator_test : public test::exception_base { test::random_values values; @@ -79,6 +102,10 @@ template struct copy_with_allocator_test : public test::exception_base } }; -EXCEPTION_TESTS((copy_test1)(copy_test2)(copy_test3)(copy_with_allocator_test), +// clang-format off +EXCEPTION_TESTS( + (copy_test1)(copy_test2)(copy_test3)(copy_test3a)(copy_with_allocator_test), CONTAINER_SEQ) +// clang-format on + RUN_TESTS() diff --git a/test/exception/erase_exception_tests.cpp b/test/exception/erase_exception_tests.cpp index f400bdd9..93e09439 100644 --- a/test/exception/erase_exception_tests.cpp +++ b/test/exception/erase_exception_tests.cpp @@ -14,7 +14,9 @@ test::seed_t initialize_seed(835193); template struct erase_test_base : public test::exception_base { test::random_values values; - erase_test_base(unsigned int count = 5) : values(count) {} + erase_test_base(unsigned int count = 5) : values(count, test::limited_range) + { + } typedef T data_type; diff --git a/test/exception/move_assign_exception_tests.cpp b/test/exception/move_assign_exception_tests.cpp index ac0eaf1c..8e363f89 100644 --- a/test/exception/move_assign_exception_tests.cpp +++ b/test/exception/move_assign_exception_tests.cpp @@ -70,8 +70,8 @@ template struct move_assign_values : move_assign_base int tag2, float mlf1 = 1.0, float mlf2 = 1.0) : move_assign_base(tag1, tag2, mlf1, mlf2) { - this->x_values.fill(count1); - this->y_values.fill(count2); + this->x_values.fill(count1, test::limited_range); + this->y_values.fill(count2, test::limited_range); this->x.insert(this->x_values.begin(), this->x_values.end()); this->y.insert(this->y_values.begin(), this->y_values.end()); } @@ -111,10 +111,10 @@ template struct equivalent_test1 : move_assign_base { equivalent_test1() : move_assign_base(0, 0) { - test::random_values x_values2(10); + test::random_values x_values2(10, test::limited_range); this->x_values.insert(x_values2.begin(), x_values2.end()); this->x_values.insert(x_values2.begin(), x_values2.end()); - test::random_values y_values2(10); + test::random_values y_values2(10, test::limited_range); this->y_values.insert(y_values2.begin(), y_values2.end()); this->y_values.insert(y_values2.begin(), y_values2.end()); this->x.insert(this->x_values.begin(), this->x_values.end()); diff --git a/test/exception/rehash_exception_tests.cpp b/test/exception/rehash_exception_tests.cpp index 6781508b..c6355071 100644 --- a/test/exception/rehash_exception_tests.cpp +++ b/test/exception/rehash_exception_tests.cpp @@ -20,7 +20,7 @@ template struct rehash_test_base : public test::exception_base test::random_values values; unsigned int n; rehash_test_base(unsigned int count = 100, unsigned int n_ = 0) - : values(count), n(n_) + : values(count, test::limited_range), n(n_) { } diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index 341e67d5..d8b81128 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_exception_tests.cpp @@ -18,7 +18,9 @@ test::seed_t initialize_seed(9387); template struct self_swap_base : public test::exception_base { test::random_values values; - self_swap_base(std::size_t count = 0) : values(count) {} + self_swap_base(std::size_t count = 0) : values(count, test::limited_range) + { + } typedef T data_type; T init() const { return T(values.begin(), values.end()); } @@ -65,7 +67,8 @@ template struct swap_base : public test::exception_base typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type; swap_base(unsigned int count1, unsigned int count2, int tag1, int tag2) - : x_values(count1), y_values(count2), + : x_values(count1, test::limited_range), + y_values(count2, test::limited_range), initial_x(x_values.begin(), x_values.end(), 0, hasher(tag1), key_equal(tag1), allocator_type(tag1)), initial_y( From 6e074d7165e0471897a0ed7ea9691bed11dbdef2 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 6 May 2017 04:58:57 +0100 Subject: [PATCH 125/147] Get rid of delete_nodes --- .../boost/unordered/detail/implementation.hpp | 99 ++++++++++++------- include/boost/unordered/unordered_map.hpp | 22 +---- include/boost/unordered/unordered_set.hpp | 22 +---- 3 files changed, 69 insertions(+), 74 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 0bd7a20e..419d7d5e 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3021,44 +3021,30 @@ struct table : boost::unordered::detail::functionsnext_ != end); - - std::size_t count = 0; - - node_pointer n = next_node(prev); - prev->next_ = end; - do { - node_pointer next = next_node(n); - destroy_node(n); - n = next; - ++count; - } while (n != end); - - size_ -= count; - return count; - } - void delete_buckets() { if (buckets_) { - if (size_) - delete_nodes(get_previous_start(), node_pointer()); + node_pointer n = + static_cast(get_bucket(bucket_count_)->next_); if (bucket::extra_node) { - node_pointer n = - static_cast(get_bucket(bucket_count_)->next_); + node_pointer next = next_node(n); boost::unordered::detail::func::destroy(boost::addressof(*n)); node_allocator_traits::deallocate(node_alloc(), n, 1); + n = next; + } + + while (n) { + node_pointer next = next_node(n); + destroy_node(n); + n = next; } destroy_buckets(); buckets_ = bucket_pointer(); max_load_ = 0; + size_ = 0; } - - BOOST_ASSERT(!size_); } void destroy_buckets() @@ -3104,6 +3090,11 @@ struct table : boost::unordered::detail::functionsfind_previous_node(k, bucket_index); if (!prev) return 0; - node_pointer end = next_node(next_node(prev)); - this->delete_nodes(prev, end); - this->fix_bucket(bucket_index, prev, end); + node_pointer n = next_node(prev); + node_pointer n2 = next_node(n); + prev->next_ = n2; + --size_; + this->fix_bucket(bucket_index, prev, n2); + this->destroy_node(n); return 1; } @@ -4082,11 +4076,17 @@ struct table : boost::unordered::detail::functionsdelete_nodes(prev, end); - this->fix_bucket(bucket_index, prev, end); + std::size_t deleted_count = 0; + node_pointer n = next_node(prev); + do { + node_pointer n2 = next_node(n); + destroy_node(n); + ++deleted_count; + n = n2; + } while (n && !n->is_first_in_group()); + size_ -= deleted_count; + prev->next_ = n; + this->fix_bucket(bucket_index, prev, n); return deleted_count; } @@ -4191,6 +4191,30 @@ struct table : boost::unordered::detail::functions inline void table::clear_impl() +{ + if (size_) { + bucket_pointer end = get_bucket(bucket_count_); + for (bucket_pointer it = buckets_; it != end; ++it) { + it->next_ = node_pointer(); + } + + link_pointer prev = end->first_from_start(); + node_pointer n = next_node(prev); + prev->next_ = node_pointer(); + size_ = 0; + + while (n) { + node_pointer next = next_node(n); + destroy_node(n); + n = next; + } + } +} + //////////////////////////////////////////////////////////////////////////// // Reserve & Rehash @@ -4275,7 +4299,14 @@ inline void table::rehash_impl(std::size_t num_buckets) } BOOST_CATCH(...) { - delete_nodes(prev, node_pointer()); + node_pointer n = next_node(prev); + prev->next_ = node_pointer(); + while (n) { + node_pointer next = next_node(n); + destroy_node(n); + --size_; + n = next; + } BOOST_RETHROW } BOOST_CATCH_END diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 134d31a8..a5d3ffa2 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -728,7 +728,7 @@ template class unordered_map // value_allocator_traits::is_always_equal::value && // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) - void clear() BOOST_NOEXCEPT; + void clear() BOOST_NOEXCEPT { table_.clear_impl(); } template void merge(boost::unordered_map& source); @@ -1263,7 +1263,7 @@ template class unordered_multimap // value_allocator_traits::is_always_equal::value && // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) - void clear() BOOST_NOEXCEPT; + void clear() BOOST_NOEXCEPT { table_.clear_impl(); } template void merge(boost::unordered_multimap& source); @@ -1611,15 +1611,6 @@ void unordered_map::swap(unordered_map& other) table_.swap(other.table_); } -template -void unordered_map::clear() BOOST_NOEXCEPT -{ - if (table_.size_) { - table_.clear_buckets(); - table_.delete_nodes(table_.get_previous_start(), node_pointer()); - } -} - template template void unordered_map::merge( @@ -2096,15 +2087,6 @@ void unordered_multimap::swap(unordered_multimap& other) table_.swap(other.table_); } -template -void unordered_multimap::clear() BOOST_NOEXCEPT -{ - if (table_.size_) { - table_.clear_buckets(); - table_.delete_nodes(table_.get_previous_start(), node_pointer()); - } -} - // observers template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 58ea6417..b160c76e 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -447,7 +447,7 @@ template class unordered_set // value_allocator_traits::is_always_equal::value && // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) - void clear() BOOST_NOEXCEPT; + void clear() BOOST_NOEXCEPT { table_.clear_impl(); } template void merge(boost::unordered_set& source); @@ -950,7 +950,7 @@ template class unordered_multiset // value_allocator_traits::is_always_equal::value && // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) - void clear() BOOST_NOEXCEPT; + void clear() BOOST_NOEXCEPT { table_.clear_impl(); } template void merge(boost::unordered_multiset& source); @@ -1275,15 +1275,6 @@ void unordered_set::swap(unordered_set& other) table_.swap(other.table_); } -template -void unordered_set::clear() BOOST_NOEXCEPT -{ - if (table_.size_) { - table_.clear_buckets(); - table_.delete_nodes(table_.get_previous_start(), node_pointer()); - } -} - // observers template @@ -1679,15 +1670,6 @@ void unordered_multiset::swap(unordered_multiset& other) table_.swap(other.table_); } -template -void unordered_multiset::clear() BOOST_NOEXCEPT -{ - if (table_.size_) { - table_.clear_buckets(); - table_.delete_nodes(table_.get_previous_start(), node_pointer()); - } -} - // observers template From b6c6bfbe7f652ee032d3ae22c0a3e084e7f47f86 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 6 May 2017 04:58:57 +0100 Subject: [PATCH 126/147] Statically handle 'is_unique' in assignments --- .../boost/unordered/detail/implementation.hpp | 48 ++++++++----------- include/boost/unordered/unordered_map.hpp | 28 ++++++----- include/boost/unordered/unordered_set.hpp | 28 ++++++----- 3 files changed, 53 insertions(+), 51 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 419d7d5e..0d3128a5 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3098,7 +3098,8 @@ struct table : boost::unordered::detail::functions + void assign(table const& x, UniqueType is_unique) { if (this != boost::addressof(x)) { assign(x, is_unique, @@ -3108,7 +3109,8 @@ struct table : boost::unordered::detail::functions + void assign(table const& x, UniqueType is_unique, false_type) { // Strong exception safety. set_hash_functions new_func_this(*this, x); @@ -3123,14 +3125,11 @@ struct table : boost::unordered::detail::functions + void assign(table const& x, UniqueType is_unique, true_type) { if (node_alloc() == x.node_alloc()) { allocators_.assign(x.allocators_); @@ -3150,16 +3149,13 @@ struct table : boost::unordered::detail::functions + void move_assign(table& x, UniqueType is_unique) { if (this != boost::addressof(x)) { move_assign( @@ -3170,7 +3166,8 @@ struct table : boost::unordered::detail::functions + void move_assign(table& x, UniqueType, true_type) { delete_buckets(); set_hash_functions new_func_this(*this, x); @@ -3181,7 +3178,8 @@ struct table : boost::unordered::detail::functions + void move_assign(table& x, UniqueType is_unique, false_type) { if (node_alloc() == x.node_alloc()) { delete_buckets(); @@ -3203,11 +3201,7 @@ struct table : boost::unordered::detail::functionscreate_buckets(this->bucket_count_); @@ -3751,7 +3745,7 @@ struct table : boost::unordered::detail::functions holder(*this); for (node_pointer n = src.begin(); n; n = next_node(n)) { @@ -3760,7 +3754,7 @@ struct table : boost::unordered::detail::functions holder(*this); for (node_pointer n = src.begin(); n; n = next_node(n)) { @@ -4121,7 +4115,7 @@ struct table : boost::unordered::detail::functionscreate_buckets(this->bucket_count_); @@ -4161,7 +4155,7 @@ struct table : boost::unordered::detail::functions holder(*this); for (node_pointer n = src.begin(); n;) { @@ -4175,7 +4169,7 @@ struct table : boost::unordered::detail::functions holder(*this); for (node_pointer n = src.begin(); n;) { diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index a5d3ffa2..25c731ec 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -146,7 +146,7 @@ template class unordered_map #if defined(BOOST_UNORDERED_USE_MOVE) unordered_map& operator=(BOOST_COPY_ASSIGN_REF(unordered_map) x) { - table_.assign(x.table_, true); + table_.assign(x.table_, boost::unordered::detail::true_type()); return *this; } @@ -156,13 +156,13 @@ template class unordered_map // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_, true); + table_.move_assign(x.table_, boost::unordered::detail::true_type()); return *this; } #else unordered_map& operator=(unordered_map const& x) { - table_.assign(x.table_, true); + table_.assign(x.table_, boost::unordered::detail::true_type()); return *this; } @@ -173,7 +173,7 @@ template class unordered_map // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_, true); + table_.move_assign(x.table_, boost::unordered::detail::true_type()); return *this; } #endif @@ -948,7 +948,7 @@ template class unordered_multimap #if defined(BOOST_UNORDERED_USE_MOVE) unordered_multimap& operator=(BOOST_COPY_ASSIGN_REF(unordered_multimap) x) { - table_.assign(x.table_, false); + table_.assign(x.table_, boost::unordered::detail::false_type()); return *this; } @@ -958,13 +958,13 @@ template class unordered_multimap // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_, false); + table_.move_assign(x.table_, boost::unordered::detail::false_type()); return *this; } #else unordered_multimap& operator=(unordered_multimap const& x) { - table_.assign(x.table_, false); + table_.assign(x.table_, boost::unordered::detail::false_type()); return *this; } @@ -975,7 +975,7 @@ template class unordered_multimap // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_, false); + table_.move_assign(x.table_, boost::unordered::detail::false_type()); return *this; } #endif @@ -1399,7 +1399,8 @@ unordered_map::unordered_map(unordered_map const& other) select_on_container_copy_construction(other.get_allocator())) { if (other.table_.size_) { - table_.copy_buckets_unique(other.table_); + table_.copy_buckets( + other.table_, boost::unordered::detail::true_type()); } } @@ -1416,7 +1417,8 @@ unordered_map::unordered_map( : table_(other.table_, a) { if (other.table_.size_) { - table_.copy_buckets_unique(other.table_); + table_.copy_buckets( + other.table_, boost::unordered::detail::true_type()); } } @@ -1877,7 +1879,8 @@ unordered_multimap::unordered_multimap( select_on_container_copy_construction(other.get_allocator())) { if (other.table_.size_) { - table_.copy_buckets_equiv(other.table_); + table_.copy_buckets( + other.table_, boost::unordered::detail::false_type()); } } @@ -1894,7 +1897,8 @@ unordered_multimap::unordered_multimap( : table_(other.table_, a) { if (other.table_.size_) { - table_.copy_buckets_equiv(other.table_); + table_.copy_buckets( + other.table_, boost::unordered::detail::false_type()); } } diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index b160c76e..80137565 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -144,7 +144,7 @@ template class unordered_set #if defined(BOOST_UNORDERED_USE_MOVE) unordered_set& operator=(BOOST_COPY_ASSIGN_REF(unordered_set) x) { - table_.assign(x.table_, true); + table_.assign(x.table_, boost::unordered::detail::true_type()); return *this; } @@ -154,13 +154,13 @@ template class unordered_set // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_, true); + table_.move_assign(x.table_, boost::unordered::detail::true_type()); return *this; } #else unordered_set& operator=(unordered_set const& x) { - table_.assign(x.table_, true); + table_.assign(x.table_, boost::unordered::detail::true_type()); return *this; } @@ -171,7 +171,7 @@ template class unordered_set // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_, true); + table_.move_assign(x.table_, boost::unordered::detail::true_type()); return *this; } #endif @@ -654,7 +654,7 @@ template class unordered_multiset #if defined(BOOST_UNORDERED_USE_MOVE) unordered_multiset& operator=(BOOST_COPY_ASSIGN_REF(unordered_multiset) x) { - table_.assign(x.table_, false); + table_.assign(x.table_, boost::unordered::detail::false_type()); return *this; } @@ -664,13 +664,13 @@ template class unordered_multiset // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_, false); + table_.move_assign(x.table_, boost::unordered::detail::false_type()); return *this; } #else unordered_multiset& operator=(unordered_multiset const& x) { - table_.assign(x.table_, false); + table_.assign(x.table_, boost::unordered::detail::false_type()); return *this; } @@ -681,7 +681,7 @@ template class unordered_multiset // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_, false); + table_.move_assign(x.table_, boost::unordered::detail::false_type()); return *this; } #endif @@ -1078,7 +1078,8 @@ unordered_set::unordered_set(unordered_set const& other) select_on_container_copy_construction(other.get_allocator())) { if (other.table_.size_) { - table_.copy_buckets_unique(other.table_); + table_.copy_buckets( + other.table_, boost::unordered::detail::true_type()); } } @@ -1095,7 +1096,8 @@ unordered_set::unordered_set( : table_(other.table_, a) { if (other.table_.size_) { - table_.copy_buckets_unique(other.table_); + table_.copy_buckets( + other.table_, boost::unordered::detail::true_type()); } } @@ -1472,7 +1474,8 @@ unordered_multiset::unordered_multiset( select_on_container_copy_construction(other.get_allocator())) { if (other.table_.size_) { - table_.copy_buckets_equiv(other.table_); + table_.copy_buckets( + other.table_, boost::unordered::detail::false_type()); } } @@ -1489,7 +1492,8 @@ unordered_multiset::unordered_multiset( : table_(other.table_, a) { if (other.table_.size_) { - table_.copy_buckets_equiv(other.table_); + table_.copy_buckets( + other.table_, boost::unordered::detail::false_type()); } } From 31c5b5bfa1dd08051b2f91d729c324e84f8af121 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 7 May 2017 17:54:34 +0100 Subject: [PATCH 127/147] Merge exception tests --- test/Jamfile.v2 | 1 + test/exception/merge_exception_tests.cpp | 108 +++++++++++++++++++++++ test/helpers/exception_test.hpp | 71 +++++++++++++++ test/objects/exception.hpp | 3 +- 4 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 test/exception/merge_exception_tests.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 25d1cde4..e06b569f 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -92,4 +92,5 @@ test-suite unordered-exception [ run exception/rehash_exception_tests.cpp framework ] [ run exception/swap_exception_tests.cpp framework : : : BOOST_UNORDERED_SWAP_METHOD=2 ] + [ run exception/merge_exception_tests.cpp framework ] ; diff --git a/test/exception/merge_exception_tests.cpp b/test/exception/merge_exception_tests.cpp new file mode 100644 index 00000000..496c01e7 --- /dev/null +++ b/test/exception/merge_exception_tests.cpp @@ -0,0 +1,108 @@ +#include "../helpers/exception_test.hpp" +#include "../helpers/invariants.hpp" +#include "../helpers/metafunctions.hpp" +#include "../helpers/random_values.hpp" +#include "./containers.hpp" + +template void merge_exception_test(T1 x, T2 y) +{ + std::size_t size = x.size() + y.size(); + + try { + ENABLE_EXCEPTIONS; + x.merge(y); + } catch (...) { + test::check_equivalent_keys(x); + test::check_equivalent_keys(y); + throw; + } + + // Not a full check, just want to make sure the merge completed. + BOOST_TEST(size == x.size() + y.size()); + if (y.size()) { + BOOST_TEST(test::has_unique_keys::value); + for (typename T2::iterator it = y.begin(); it != y.end(); ++it) { + BOOST_TEST(x.find(test::get_key(*it)) != x.end()); + } + } + test::check_equivalent_keys(x); + test::check_equivalent_keys(y); +} + +template +void merge_exception_test(T1 const*, T2 const*, std::size_t count1, + std::size_t count2, int tag1, int tag2, test::random_generator gen1, + test::random_generator gen2) +{ + test::random_values v1(count1, gen1); + test::random_values v2(count2, gen2); + T1 x(v1.begin(), v1.end(), 0, test::exception::hash(tag1), + test::exception::equal_to(tag1)); + T2 y(v2.begin(), v2.end(), 0, test::exception::hash(tag2), + test::exception::equal_to(tag2)); + + EXCEPTION_LOOP(merge_exception_test(x, y)) +} + +boost::unordered_set >* test_set_; +boost::unordered_multiset >* test_multiset_; +boost::unordered_map >* test_map_; +boost::unordered_multimap >* test_multimap_; + +using test::default_generator; +using test::generate_collisions; +using test::limited_range; + +// clang-format off +UNORDERED_TEST(merge_exception_test, + ((test_set_)(test_multiset_)) + ((test_set_)(test_multiset_)) + ((0)(10)(100)) + ((0)(10)(100)) + ((0)(1)(2)) + ((0)(1)(2)) + ((default_generator)(limited_range)) + ((default_generator)(limited_range)) +) +UNORDERED_TEST(merge_exception_test, + ((test_map_)(test_multimap_)) + ((test_map_)(test_multimap_)) + ((0)(10)(100)) + ((0)(10)(100)) + ((0)(1)(2)) + ((0)(1)(2)) + ((default_generator)(limited_range)) + ((default_generator)(limited_range)) +) +// Run fewer generate_collisions tests, as they're slow. +UNORDERED_TEST(merge_exception_test, + ((test_set_)(test_multiset_)) + ((test_set_)(test_multiset_)) + ((10)) + ((10)) + ((0)(1)(2)) + ((0)(1)(2)) + ((generate_collisions)) + ((generate_collisions)) +) +UNORDERED_TEST(merge_exception_test, + ((test_map_)(test_multimap_)) + ((test_map_)(test_multimap_)) + ((10)) + ((10)) + ((0)(1)(2)) + ((0)(1)(2)) + ((generate_collisions)) + ((generate_collisions)) +) +// clang-format on + +RUN_TESTS() diff --git a/test/helpers/exception_test.hpp b/test/helpers/exception_test.hpp index 842de8b1..7edf8848 100644 --- a/test/helpers/exception_test.hpp +++ b/test/helpers/exception_test.hpp @@ -275,6 +275,77 @@ template void exception_safety(Test const& f, char const* /*name*/) } runner.end(); } + +// +// An alternative way to run exception tests. +// See merge_exception_tests.cpp for an example. + +struct exception_looper +{ + bool success; + unsigned int failure_count; + char const* error_msg; + int error_count; + + exception_looper() : success(false), failure_count(0), error_msg(0) {} + + void start() { iteration = 0; } + + bool loop_condition() const + { + return !error_msg && !success && failure_count < 5; + } + + void start_iteration() + { + error_count = boost::detail::test_errors(); + ++iteration; + count = 0; + } + + void successful_run() { success = true; } + + void test_failure_caught(test_failure const&) + { + error_msg = "test_failure caught."; + } + + void test_exception_caught(test_exception const& e) + { + if (error_count != boost::detail::test_errors()) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM + << "Iteration: " << iteration + << " Error found for epoint: " << e.name << std::endl; + } + } + + void unexpected_exception_caught() { error_msg = "Unexpected exception."; } + + void end() + { + if (error_msg) { + BOOST_ERROR(error_msg); + } + } +}; + +#define EXCEPTION_LOOP(op) \ + test::lightweight::exception_looper looper; \ + looper.start(); \ + while (looper.loop_condition()) { \ + looper.start_iteration(); \ + try { \ + op; \ + looper.successful_run(); \ + } catch (test::lightweight::test_failure e) { \ + looper.test_failure_caught(e); \ + } catch (test::lightweight::test_exception e) { \ + looper.test_exception_caught(e); \ + } catch (...) { \ + looper.unexpected_exception_caught(); \ + } \ + } \ + looper.end(); } } diff --git a/test/objects/exception.hpp b/test/objects/exception.hpp index 8471bd29..01b39ee3 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -10,8 +10,9 @@ #include "../helpers/count.hpp" #include "../helpers/fwd.hpp" +#include "../helpers/generators.hpp" #include "../helpers/memory.hpp" -#include "../objects/fwd.hpp" +#include "./fwd.hpp" #include #include #include From 8af4b37d1475cdad5e12d8bee4ba91209ac56649 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 7 May 2017 17:54:34 +0100 Subject: [PATCH 128/147] Rewrite insert exception tests Not going to do this for all the tests. It's more effort than I expected. --- test/exception/insert_exception_tests.cpp | 642 +++++++++++----------- 1 file changed, 324 insertions(+), 318 deletions(-) diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index 44e1e545..82db6774 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -15,364 +15,370 @@ test::seed_t initialize_seed(747373); -template struct insert_test_base : public test::exception_base +// Overload to generate inserters that need type information. + +template +Inserter generate(Inserter inserter, T&) { - test::random_values values; - insert_test_base(unsigned int count = 5) - : values(count, test::limited_range) - { - } + return inserter; +} - typedef T data_type; - typedef test::strong strong_type; +// Get the iterator returned from an insert/emplace. - data_type init() const { return T(); } +template T get_iterator(T const& x) { return x; } - void check BOOST_PREVENT_MACRO_SUBSTITUTION( - T const& x, strong_type const& strong) const - { +template T get_iterator(std::pair const& x) +{ + return x.first; +} + +// Generic insert exception test for typical single element inserts.. + +template +void insert_exception_test_impl(T x, Inserter insert, Values const& v) +{ + test::strong strong; + + test::ordered tracker; + tracker.insert(x.begin(), x.end()); + + try { + ENABLE_EXCEPTIONS; + + for (typename Values::const_iterator it = v.begin(); it != v.end(); + ++it) { + strong.store(x, test::detail::tracker.count_allocations); + insert(x, it); + } + } catch (...) { std::string scope(test::scope); if (scope.find("hash::operator()") == std::string::npos) strong.test(x, test::detail::tracker.count_allocations); test::check_equivalent_keys(x); + + throw; } -}; -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ - !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + test::check_equivalent_keys(x); + tracker.insert(v.begin(), v.end()); + tracker.compare(x); +} -template struct emplace_test1 : public insert_test_base +// Simple insert exception test + +template +void insert_exception_test(T*, Inserter insert, test::random_generator gen) { - typedef BOOST_DEDUCED_TYPENAME insert_test_base::strong_type strong_type; + for (int i = 0; i < 5; ++i) { + test::random_values v(10, gen); + T x; - void run(T& x, strong_type& strong) const - { - for (BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = this->values.begin(), - end = this->values.end(); - it != end; ++it) { - strong.store(x, test::detail::tracker.count_allocations); - x.emplace(*it); - } - - DISABLE_EXCEPTIONS; - test::check_container(x, this->values); - test::check_equivalent_keys(x); + EXCEPTION_LOOP(insert_exception_test_impl(x, generate(insert, x), v)); } -}; +} -#endif +// Insert into a container which is about to hit its max load, so that it +// rehashes. -template struct insert_test1 : public insert_test_base +template +void insert_rehash_exception_test( + T*, Inserter insert, test::random_generator gen) { - typedef BOOST_DEDUCED_TYPENAME insert_test_base::strong_type strong_type; - - void run(T& x, strong_type& strong) const - { - for (BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = this->values.begin(), - end = this->values.end(); - it != end; ++it) { - strong.store(x, test::detail::tracker.count_allocations); - x.insert(*it); - } - - DISABLE_EXCEPTIONS; - test::check_container(x, this->values); - test::check_equivalent_keys(x); - } -}; - -template struct insert_test2 : public insert_test_base -{ - typedef BOOST_DEDUCED_TYPENAME insert_test_base::strong_type strong_type; - - void run(T& x, strong_type& strong) const - { - for (BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = this->values.begin(), - end = this->values.end(); - it != end; ++it) { - strong.store(x, test::detail::tracker.count_allocations); - x.insert(x.begin(), *it); - } - - DISABLE_EXCEPTIONS; - test::check_container(x, this->values); - test::check_equivalent_keys(x); - } -}; - -template struct insert_test3 : public insert_test_base -{ - void run(T& x) const - { - x.insert(this->values.begin(), this->values.end()); - - DISABLE_EXCEPTIONS; - test::check_container(x, this->values); - test::check_equivalent_keys(x); - } - - void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const - { - test::check_equivalent_keys(x); - } -}; - -template struct insert_test4 : public insert_test_base -{ - typedef BOOST_DEDUCED_TYPENAME insert_test_base::strong_type strong_type; - - void run(T& x, strong_type& strong) const - { - for (BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = this->values.begin(), - end = this->values.end(); - it != end; ++it) { - strong.store(x, test::detail::tracker.count_allocations); - x.insert(it, test::next(it)); - } - - DISABLE_EXCEPTIONS; - test::check_container(x, this->values); - test::check_equivalent_keys(x); - } -}; - -template struct insert_test_rehash1 : public insert_test_base -{ - typedef BOOST_DEDUCED_TYPENAME insert_test_base::strong_type strong_type; - - insert_test_rehash1() : insert_test_base(1000) {} - - T init() const - { - using namespace std; - typedef BOOST_DEDUCED_TYPENAME T::size_type size_type; + using namespace std; + typedef BOOST_DEDUCED_TYPENAME T::size_type size_type; + for (int i = 0; i < 5; ++i) { T x; x.max_load_factor(0.25); - // TODO: This doesn't really work is bucket_count is 0 size_type bucket_count = x.bucket_count(); size_type initial_elements = static_cast( ceil((double)bucket_count * (double)x.max_load_factor()) - 1); - BOOST_TEST(initial_elements < this->values.size()); - x.insert(this->values.begin(), - test::next(this->values.begin(), initial_elements)); + test::random_values v(initial_elements); + x.insert(v.begin(), v.end()); BOOST_TEST(bucket_count == x.bucket_count()); - return x; + + test::random_values v2(5, gen); + EXCEPTION_LOOP(insert_exception_test_impl(x, generate(insert, x), v2)); } +} - void run(T& x, strong_type& strong) const - { - BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count(); - int count = 0; - BOOST_DEDUCED_TYPENAME T::const_iterator pos = x.cbegin(); +// Various methods for inserting a single element - test::list v; - { - DISABLE_EXCEPTIONS; - v.insert(x.begin(), x.end()); - } - - for (BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = test::next(this->values.begin(), x.size()), - end = this->values.end(); - it != end && count < 10; ++it, ++count) { - strong.store(x, test::detail::tracker.count_allocations); - pos = x.insert(pos, *it); - - DISABLE_EXCEPTIONS; - v.push_back(*it); - } - - // This isn't actually a failure, but it means the test isn't doing its - // job. - BOOST_TEST(x.bucket_count() != bucket_count); - - DISABLE_EXCEPTIONS; - test::check_container(x, v); - test::check_equivalent_keys(x); - } -}; - -template struct insert_test_rehash2 : public insert_test_rehash1 +struct insert_lvalue_type { - typedef BOOST_DEDUCED_TYPENAME insert_test_base::strong_type strong_type; - - void run(T& x, strong_type& strong) const + template void operator()(T& x, Iterator it) { - BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count(); - int count = 0; - - test::list v; - { - DISABLE_EXCEPTIONS; - v.insert(x.begin(), x.end()); - } - - for (BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = test::next(this->values.begin(), x.size()), - end = this->values.end(); - it != end && count < 10; ++it, ++count) { - strong.store(x, test::detail::tracker.count_allocations); - x.insert(*it); - - DISABLE_EXCEPTIONS; - v.push_back(*it); - } - - // This isn't actually a failure, but it means the test isn't doing its - // job. - BOOST_TEST(x.bucket_count() != bucket_count); - - DISABLE_EXCEPTIONS; - test::check_container(x, v); - test::check_equivalent_keys(x); + x.insert(*it); } -}; +} insert_lvalue; -template struct insert_test_rehash3 : public insert_test_base +struct insert_lvalue_begin_type { - BOOST_DEDUCED_TYPENAME T::size_type mutable rehash_bucket_count, - original_bucket_count; - - insert_test_rehash3() : insert_test_base(1000) {} - - T init() const + template void operator()(T& x, Iterator it) { - using namespace std; - typedef BOOST_DEDUCED_TYPENAME T::size_type size_type; + x.insert(x.begin(), *it); + } +} insert_lvalue_begin; +struct insert_lvalue_end_type +{ + template void operator()(T& x, Iterator it) + { + x.insert(x.end(), *it); + } +} insert_lvalue_end; + +struct insert_lvalue_pos_type +{ + template struct impl + { + typename T::iterator pos; + + impl(T& x) : pos(x.begin()) {} + + template void operator()(T& x, Iterator it) + { + pos = get_iterator(x.insert(pos, *it)); + } + }; + + template friend impl generate(insert_lvalue_pos_type, T& x) + { + return impl(x); + } +} insert_lvalue_pos; + +struct insert_single_item_range_type +{ + template void operator()(T& x, Iterator it) + { + x.insert(it, test::next(it)); + } +} insert_single_item_range; + +struct emplace_lvalue_type +{ + template void operator()(T& x, Iterator it) + { + x.emplace(*it); + } +} emplace_lvalue; + +struct emplace_lvalue_begin_type +{ + template void operator()(T& x, Iterator it) + { + x.emplace_hint(x.begin(), *it); + } +} emplace_lvalue_begin; + +struct emplace_lvalue_end_type +{ + template void operator()(T& x, Iterator it) + { + x.emplace_hint(x.end(), *it); + } +} emplace_lvalue_end; + +struct emplace_lvalue_pos_type +{ + template struct impl + { + typename T::iterator pos; + + impl(T& x) : pos(x.begin()) {} + + template void operator()(T& x, Iterator it) + { + pos = get_iterator(x.emplace_hint(pos, *it)); + } + }; + + template friend impl generate(emplace_lvalue_pos_type, T& x) + { + return impl(x); + } +} emplace_lvalue_pos; + +// Run the exception tests in various combinations. + +test_set* test_set_; +test_multiset* test_multiset_; +test_map* test_map_; +test_multimap* test_multimap_; + +using test::default_generator; +using test::limited_range; +using test::generate_collisions; + +// clang-format off +UNORDERED_TEST(insert_exception_test, + ((test_set_)(test_multiset_)(test_map_)(test_multimap_)) + ((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end) + (insert_lvalue_pos)(insert_single_item_range) + (emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end) + (emplace_lvalue_pos) + ) + ((default_generator)(limited_range)(generate_collisions)) +) + +UNORDERED_TEST(insert_rehash_exception_test, + ((test_set_)(test_multiset_)(test_map_)(test_multimap_)) + ((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end) + (insert_lvalue_pos)(insert_single_item_range) + (emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end) + (emplace_lvalue_pos) + ) + ((default_generator)(limited_range)(generate_collisions)) +) +// clang-format on + +// Repeat insert tests with pairs + +struct pair_emplace_type +{ + template void operator()(T& x, Iterator it) + { + x.emplace(boost::unordered::piecewise_construct, + boost::make_tuple(it->first), boost::make_tuple(it->second)); + } +} pair_emplace; + +struct pair_emplace2_type +{ + template void operator()(T& x, Iterator it) + { + x.emplace_hint(x.begin(), boost::unordered::piecewise_construct, + boost::make_tuple(it->first), + boost::make_tuple(it->second.tag1_, it->second.tag2_)); + } +} pair_emplace2; + +test_pair_set* test_pair_set_; +test_pair_multiset* test_pair_multiset_; + +// clang-format off +UNORDERED_TEST(insert_exception_test, + ((test_pair_set_)(test_pair_multiset_)(test_map_)(test_multimap_)) + ((pair_emplace)(pair_emplace2)) + ((default_generator)(limited_range)(generate_collisions)) +) +UNORDERED_TEST(insert_rehash_exception_test, + ((test_pair_set_)(test_pair_multiset_)(test_map_)(test_multimap_)) + ((pair_emplace)(pair_emplace2)) + ((default_generator)(limited_range)(generate_collisions)) +) +// clang-format on + +// Test inserting using operator[] + +template +void insert_operator_exception_test_impl(T x, Values const& v) +{ + test::ordered tracker; + tracker.insert(x.begin(), x.end()); + + try { + ENABLE_EXCEPTIONS; + + for (typename Values::const_iterator it = v.begin(); it != v.end(); + ++it) { + x[it->first] = it->second; + + DISABLE_EXCEPTIONS; + tracker[it->first] = it->second; + } + } catch (...) { + test::check_equivalent_keys(x); + throw; + } + + test::check_equivalent_keys(x); + tracker.compare(x); +} + +template +void insert_operator_exception_test(T*, test::random_generator gen) +{ + for (int i = 0; i < 5; ++i) { + test::random_values v(10, gen); + T x; + + EXCEPTION_LOOP(insert_operator_exception_test_impl(x, v)); + } +} + +// clang-format off +UNORDERED_TEST(insert_operator_exception_test, + ((test_map_)) + ((default_generator)(limited_range)(generate_collisions)) +) +// clang-format on + +// Range insert tests + +template +void insert_range_exception_test_impl(T x, Values const& v) +{ + test::ordered tracker; + tracker.insert(x.begin(), x.end()); + + try { + ENABLE_EXCEPTIONS; + x.insert(v.begin(), v.end()); + } catch (...) { + test::check_equivalent_keys(x); + throw; + } + + test::check_equivalent_keys(x); + tracker.insert(v.begin(), v.end()); + tracker.compare(x); +} + +template +void insert_range_exception_test(T*, test::random_generator gen) +{ + for (int i = 0; i < 5; ++i) { + test::random_values v(10, gen); + T x; + + EXCEPTION_LOOP(insert_range_exception_test_impl(x, v)); + } +} + +template +void insert_range_rehash_exception_test(T*, test::random_generator gen) +{ + using namespace std; + typedef BOOST_DEDUCED_TYPENAME T::size_type size_type; + + for (int i = 0; i < 5; ++i) { T x; x.max_load_factor(0.25); + size_type bucket_count = x.bucket_count(); + size_type initial_elements = static_cast( + ceil((double)bucket_count * (double)x.max_load_factor()) - 1); + test::random_values v(initial_elements); + x.insert(v.begin(), v.end()); + BOOST_TEST(bucket_count == x.bucket_count()); - original_bucket_count = x.bucket_count(); - rehash_bucket_count = - static_cast(ceil( - (double)original_bucket_count * (double)x.max_load_factor())) - - 1; - - size_type initial_elements = - rehash_bucket_count > 5 ? rehash_bucket_count - 5 : 1; - - BOOST_TEST(initial_elements < this->values.size()); - x.insert(this->values.begin(), - test::next(this->values.begin(), initial_elements)); - BOOST_TEST(original_bucket_count == x.bucket_count()); - return x; + test::random_values v2(5, gen); + EXCEPTION_LOOP(insert_range_exception_test_impl(x, v2)); } +} - void run(T& x) const - { - BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count(); - test::list v; +// clang-format off +UNORDERED_TEST(insert_range_exception_test, + ((test_set_)(test_multiset_)(test_map_)(test_multimap_)) + ((default_generator)(limited_range)(generate_collisions)) +) - { - DISABLE_EXCEPTIONS; - v.insert(x.begin(), x.end()); - v.insert(test::next(this->values.begin(), x.size()), - test::next(this->values.begin(), x.size() + 20)); - } - - x.insert(test::next(this->values.begin(), x.size()), - test::next(this->values.begin(), x.size() + 20)); - - // This isn't actually a failure, but it means the test isn't doing its - // job. - BOOST_TEST(x.bucket_count() != bucket_count); - - DISABLE_EXCEPTIONS; - test::check_container(x, v); - test::check_equivalent_keys(x); - } - - void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const - { - if (x.size() < rehash_bucket_count) { - // BOOST_TEST(x.bucket_count() == original_bucket_count); - } - test::check_equivalent_keys(x); - } -}; - -#define BASIC_TESTS \ - (insert_test1)(insert_test2)(insert_test3)(insert_test4)( \ - insert_test_rehash1)(insert_test_rehash2)(insert_test_rehash3) - -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ - !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) -#define ALL_TESTS (emplace_test1) BASIC_TESTS -#else -#define ALL_TESTS BASIC_TESTS -#endif - -EXCEPTION_TESTS_REPEAT(5, ALL_TESTS, CONTAINER_SEQ) - -template struct pair_emplace_test1 : public insert_test_base -{ - typedef BOOST_DEDUCED_TYPENAME insert_test_base::strong_type strong_type; - - void run(T& x, strong_type& strong) const - { - for (BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = this->values.begin(), - end = this->values.end(); - it != end; ++it) { - strong.store(x, test::detail::tracker.count_allocations); - x.emplace(boost::unordered::piecewise_construct, - boost::make_tuple(it->first), boost::make_tuple(it->second)); - } - - DISABLE_EXCEPTIONS; - test::check_container(x, this->values); - test::check_equivalent_keys(x); - } -}; - -template struct pair_emplace_test2 : public insert_test_base -{ - typedef BOOST_DEDUCED_TYPENAME insert_test_base::strong_type strong_type; - - void run(T& x, strong_type& strong) const - { - for (BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = this->values.begin(), - end = this->values.end(); - it != end; ++it) { - strong.store(x, test::detail::tracker.count_allocations); - x.emplace(boost::unordered::piecewise_construct, - boost::make_tuple(it->first), - boost::make_tuple(it->second.tag1_, it->second.tag2_)); - } - - DISABLE_EXCEPTIONS; - test::check_container(x, this->values); - test::check_equivalent_keys(x); - } -}; - -EXCEPTION_TESTS_REPEAT( - 5, (pair_emplace_test1)(pair_emplace_test2), CONTAINER_PAIR_SEQ) - -template struct index_insert_test1 : public insert_test_base -{ - typedef BOOST_DEDUCED_TYPENAME insert_test_base::strong_type strong_type; - - void run(T& x, strong_type& strong) const - { - for (BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = this->values.begin(), - end = this->values.end(); - it != end; ++it) { - strong.store(x, test::detail::tracker.count_allocations); - x[it->first]; - } - } -}; - -EXCEPTION_TESTS_REPEAT(5, (index_insert_test1), (test_map)) +UNORDERED_TEST(insert_range_rehash_exception_test, + ((test_set_)(test_multiset_)(test_map_)(test_multimap_)) + ((default_generator)(limited_range)(generate_collisions)) +) +// clang-format on RUN_TESTS() From 9119a42b7dabf4b15b0f01fa6b4e71c291851846 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 7 May 2017 18:43:50 +0100 Subject: [PATCH 129/147] Factor insert_exception_tests for better code reuse --- test/exception/insert_exception_tests.cpp | 138 ++++++++++++---------- 1 file changed, 73 insertions(+), 65 deletions(-) diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index 82db6774..07fd1e6b 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -15,6 +15,21 @@ test::seed_t initialize_seed(747373); +// Fill in a container so that it's about to rehash +template void rehash_prep(T& x) +{ + using namespace std; + typedef BOOST_DEDUCED_TYPENAME T::size_type size_type; + + x.max_load_factor(0.25); + size_type bucket_count = x.bucket_count(); + size_type initial_elements = static_cast( + ceil((double)bucket_count * (double)x.max_load_factor()) - 1); + test::random_values v(initial_elements); + x.insert(v.begin(), v.end()); + BOOST_TEST(bucket_count == x.bucket_count()); +} + // Overload to generate inserters that need type information. template @@ -51,17 +66,13 @@ void insert_exception_test_impl(T x, Inserter insert, Values const& v) insert(x, it); } } catch (...) { - std::string scope(test::scope); - - if (scope.find("hash::operator()") == std::string::npos) - strong.test(x, test::detail::tracker.count_allocations); test::check_equivalent_keys(x); - + insert.exception_check(x, strong); throw; } test::check_equivalent_keys(x); - tracker.insert(v.begin(), v.end()); + insert.track(tracker, v.begin(), v.end()); tracker.compare(x); } @@ -85,18 +96,9 @@ template void insert_rehash_exception_test( T*, Inserter insert, test::random_generator gen) { - using namespace std; - typedef BOOST_DEDUCED_TYPENAME T::size_type size_type; - for (int i = 0; i < 5; ++i) { T x; - x.max_load_factor(0.25); - size_type bucket_count = x.bucket_count(); - size_type initial_elements = static_cast( - ceil((double)bucket_count * (double)x.max_load_factor()) - 1); - test::random_values v(initial_elements); - x.insert(v.begin(), v.end()); - BOOST_TEST(bucket_count == x.bucket_count()); + rehash_prep(x); test::random_values v2(5, gen); EXCEPTION_LOOP(insert_exception_test_impl(x, generate(insert, x), v2)); @@ -105,7 +107,24 @@ void insert_rehash_exception_test( // Various methods for inserting a single element -struct insert_lvalue_type +struct inserter_base +{ + template void exception_check(T& x, test::strong& strong) + { + std::string scope(test::scope); + + if (scope.find("hash::operator()") == std::string::npos) + strong.test(x, test::detail::tracker.count_allocations); + } + + template + void track(T& tracker, Iterator begin, Iterator end) + { + tracker.insert(begin, end); + } +}; + +struct insert_lvalue_type : inserter_base { template void operator()(T& x, Iterator it) { @@ -113,7 +132,7 @@ struct insert_lvalue_type } } insert_lvalue; -struct insert_lvalue_begin_type +struct insert_lvalue_begin_type : inserter_base { template void operator()(T& x, Iterator it) { @@ -121,7 +140,7 @@ struct insert_lvalue_begin_type } } insert_lvalue_begin; -struct insert_lvalue_end_type +struct insert_lvalue_end_type : inserter_base { template void operator()(T& x, Iterator it) { @@ -131,7 +150,7 @@ struct insert_lvalue_end_type struct insert_lvalue_pos_type { - template struct impl + template struct impl : inserter_base { typename T::iterator pos; @@ -149,7 +168,7 @@ struct insert_lvalue_pos_type } } insert_lvalue_pos; -struct insert_single_item_range_type +struct insert_single_item_range_type : inserter_base { template void operator()(T& x, Iterator it) { @@ -157,7 +176,7 @@ struct insert_single_item_range_type } } insert_single_item_range; -struct emplace_lvalue_type +struct emplace_lvalue_type : inserter_base { template void operator()(T& x, Iterator it) { @@ -165,7 +184,7 @@ struct emplace_lvalue_type } } emplace_lvalue; -struct emplace_lvalue_begin_type +struct emplace_lvalue_begin_type : inserter_base { template void operator()(T& x, Iterator it) { @@ -173,7 +192,7 @@ struct emplace_lvalue_begin_type } } emplace_lvalue_begin; -struct emplace_lvalue_end_type +struct emplace_lvalue_end_type : inserter_base { template void operator()(T& x, Iterator it) { @@ -183,7 +202,7 @@ struct emplace_lvalue_end_type struct emplace_lvalue_pos_type { - template struct impl + template struct impl : inserter_base { typename T::iterator pos; @@ -236,7 +255,7 @@ UNORDERED_TEST(insert_rehash_exception_test, // Repeat insert tests with pairs -struct pair_emplace_type +struct pair_emplace_type : inserter_base { template void operator()(T& x, Iterator it) { @@ -245,7 +264,7 @@ struct pair_emplace_type } } pair_emplace; -struct pair_emplace2_type +struct pair_emplace2_type : inserter_base { template void operator()(T& x, Iterator it) { @@ -273,45 +292,43 @@ UNORDERED_TEST(insert_rehash_exception_test, // Test inserting using operator[] -template -void insert_operator_exception_test_impl(T x, Values const& v) +struct map_inserter_base { - test::ordered tracker; - tracker.insert(x.begin(), x.end()); + template void exception_check(T& x, test::strong& strong) + { + std::string scope(test::scope); - try { - ENABLE_EXCEPTIONS; + if (scope.find("hash::operator()") == std::string::npos && + scope.find("::operator=") == std::string::npos) + strong.test(x, test::detail::tracker.count_allocations); + } - for (typename Values::const_iterator it = v.begin(); it != v.end(); - ++it) { - x[it->first] = it->second; - - DISABLE_EXCEPTIONS; - tracker[it->first] = it->second; + template + void track(T& tracker, Iterator begin, Iterator end) + { + for (; begin != end; ++begin) { + tracker[begin->first] = begin->second; } - } catch (...) { - test::check_equivalent_keys(x); - throw; } +}; - test::check_equivalent_keys(x); - tracker.compare(x); -} - -template -void insert_operator_exception_test(T*, test::random_generator gen) +struct map_insert_operator_type : map_inserter_base { - for (int i = 0; i < 5; ++i) { - test::random_values v(10, gen); - T x; - - EXCEPTION_LOOP(insert_operator_exception_test_impl(x, v)); + template void operator()(T& x, Iterator it) + { + x[it->first] = it->second; } -} +} map_insert_operator; // clang-format off -UNORDERED_TEST(insert_operator_exception_test, +UNORDERED_TEST(insert_exception_test, ((test_map_)) + ((map_insert_operator)) + ((default_generator)(limited_range)(generate_collisions)) +) +UNORDERED_TEST(insert_rehash_exception_test, + ((test_map_)) + ((map_insert_operator)) ((default_generator)(limited_range)(generate_collisions)) ) // clang-format on @@ -351,18 +368,9 @@ void insert_range_exception_test(T*, test::random_generator gen) template void insert_range_rehash_exception_test(T*, test::random_generator gen) { - using namespace std; - typedef BOOST_DEDUCED_TYPENAME T::size_type size_type; - for (int i = 0; i < 5; ++i) { T x; - x.max_load_factor(0.25); - size_type bucket_count = x.bucket_count(); - size_type initial_elements = static_cast( - ceil((double)bucket_count * (double)x.max_load_factor()) - 1); - test::random_values v(initial_elements); - x.insert(v.begin(), v.end()); - BOOST_TEST(bucket_count == x.bucket_count()); + rehash_prep(x); test::random_values v2(5, gen); EXCEPTION_LOOP(insert_range_exception_test_impl(x, v2)); From 1b0b38a51959b805ae2ba077e81fca0c4a5117ee Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 7 May 2017 18:46:37 +0100 Subject: [PATCH 130/147] try_emplace, insert_or_assign exception tests --- test/exception/insert_exception_tests.cpp | 28 +++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index 07fd1e6b..b7ab6cdf 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -292,6 +292,22 @@ UNORDERED_TEST(insert_rehash_exception_test, // Test inserting using operator[] +struct try_emplace_type : inserter_base +{ + template void operator()(T& x, Iterator it) + { + x.try_emplace(it->first, it->second); + } +} try_emplace; + +struct try_emplace2_type : inserter_base +{ + template void operator()(T& x, Iterator it) + { + x.try_emplace(it->first, it->second.tag1_, it->second.tag2_); + } +} try_emplace2; + struct map_inserter_base { template void exception_check(T& x, test::strong& strong) @@ -320,15 +336,23 @@ struct map_insert_operator_type : map_inserter_base } } map_insert_operator; +struct map_insert_or_assign_type : map_inserter_base +{ + template void operator()(T& x, Iterator it) + { + x.insert_or_assign(it->first, it->second); + } +} map_insert_or_assign; + // clang-format off UNORDERED_TEST(insert_exception_test, ((test_map_)) - ((map_insert_operator)) + ((try_emplace)(try_emplace2)(map_insert_operator)(map_insert_or_assign)) ((default_generator)(limited_range)(generate_collisions)) ) UNORDERED_TEST(insert_rehash_exception_test, ((test_map_)) - ((map_insert_operator)) + ((try_emplace)(try_emplace2)(map_insert_operator)(map_insert_or_assign)) ((default_generator)(limited_range)(generate_collisions)) ) // clang-format on From 3c42138e4539ec3bfe8f21c1b880e522c5f89d6d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 8 May 2017 18:20:42 +0100 Subject: [PATCH 131/147] Fix testing piecewise_construct and tuple For when std::piecewise_construct is available, but std::tuple isn't. In order to test better, just repeat the tests with the four possible combinations. --- test/unordered/insert_tests.cpp | 103 +++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 22 deletions(-) diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index f55ca90e..fd7b461d 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#if !defined(PIECEWISE_TEST_NAME) + // clang-format off #include "../helpers/prefix.hpp" #include @@ -1350,10 +1352,58 @@ UNORDERED_AUTO_TEST(set_emplace_test2) BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); } +// Use the preprocessor to generate tests using different combinations of +// boost/std piecewise_construct_t/tuple. + +#define PIECEWISE_TEST_NAME boost_tuple_piecewise_tests +#define PIECEWISE_NAMESPACE boost::unordered +#define TUPLE_NAMESPACE boost +#define EMULATING_PIECEWISE_CONSTRUCTION 1 +#include "./insert_tests.cpp" + #if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT -UNORDERED_AUTO_TEST(map_std_emplace_test2) +#define PIECEWISE_TEST_NAME boost_tuple_std_piecewise_tests +#define PIECEWISE_NAMESPACE std +#define TUPLE_NAMESPACE boost +#define EMULATING_PIECEWISE_CONSTRUCTION 1 +#include "./insert_tests.cpp" + +#endif + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) + +#define PIECEWISE_TEST_NAME std_tuple_boost_piecewise_tests +#define PIECEWISE_NAMESPACE boost::unordered +#define TUPLE_NAMESPACE std +#define EMULATING_PIECEWISE_CONSTRUCTION 0 +#include "./insert_tests.cpp" + +#endif + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && \ + BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT + +#define PIECEWISE_TEST_NAME std_piecewise_tests +#define PIECEWISE_NAMESPACE std +#define TUPLE_NAMESPACE std +#define EMULATING_PIECEWISE_CONSTRUCTION 0 +#include "./insert_tests.cpp" + +#endif + +} + +RUN_TESTS() + +#else // PIECEWISE_TEST_NAME + +UNORDERED_AUTO_TEST(PIECEWISE_TEST_NAME) { +#if EMULATING_PIECEWISE_CONSTRUCTION + test::detail::disable_construction_tracking _scoped; +#endif + { boost::unordered_map, @@ -1362,26 +1412,27 @@ UNORDERED_AUTO_TEST(map_std_emplace_test2) overloaded_constructor> > > x; - x.emplace( - std::piecewise_construct, std::make_tuple(), std::make_tuple()); + x.emplace(PIECEWISE_NAMESPACE::piecewise_construct, + TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple()); BOOST_TEST(x.find(overloaded_constructor()) != x.end() && x.find(overloaded_constructor())->second == overloaded_constructor()); - x.emplace( - convertible_to_piecewise(), std::make_tuple(1), std::make_tuple()); + x.emplace(convertible_to_piecewise(), TUPLE_NAMESPACE::make_tuple(1), + TUPLE_NAMESPACE::make_tuple()); BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() && x.find(overloaded_constructor(1))->second == overloaded_constructor()); - x.emplace(piecewise_rvalue(), std::make_tuple(2, 3), - std::make_tuple(4, 5, 6)); + x.emplace(piecewise_rvalue(), TUPLE_NAMESPACE::make_tuple(2, 3), + TUPLE_NAMESPACE::make_tuple(4, 5, 6)); BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && x.find(overloaded_constructor(2, 3))->second == overloaded_constructor(4, 5, 6)); derived_from_piecewise_construct_t d; - x.emplace(d, std::make_tuple(9, 3, 1), std::make_tuple(10)); + x.emplace(d, TUPLE_NAMESPACE::make_tuple(9, 3, 1), + TUPLE_NAMESPACE::make_tuple(10)); BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() && x.find(overloaded_constructor(9, 3, 1))->second == overloaded_constructor(10)); @@ -1411,51 +1462,59 @@ UNORDERED_AUTO_TEST(map_std_emplace_test2) overloaded_constructor> > > x; - x.emplace( - std::piecewise_construct, std::make_tuple(), std::make_tuple()); + x.emplace(PIECEWISE_NAMESPACE::piecewise_construct, + TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple()); BOOST_TEST(x.find(overloaded_constructor()) != x.end() && x.find(overloaded_constructor())->second == overloaded_constructor()); - x.emplace( - convertible_to_piecewise(), std::make_tuple(1), std::make_tuple()); + x.emplace(convertible_to_piecewise(), TUPLE_NAMESPACE::make_tuple(1), + TUPLE_NAMESPACE::make_tuple()); BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() && x.find(overloaded_constructor(1))->second == overloaded_constructor()); - x.emplace(piecewise_rvalue(), std::make_tuple(2, 3), - std::make_tuple(4, 5, 6)); + x.emplace(piecewise_rvalue(), TUPLE_NAMESPACE::make_tuple(2, 3), + TUPLE_NAMESPACE::make_tuple(4, 5, 6)); BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && x.find(overloaded_constructor(2, 3))->second == overloaded_constructor(4, 5, 6)); derived_from_piecewise_construct_t d; - x.emplace(d, std::make_tuple(9, 3, 1), std::make_tuple(10)); + x.emplace(d, TUPLE_NAMESPACE::make_tuple(9, 3, 1), + TUPLE_NAMESPACE::make_tuple(10)); BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() && x.find(overloaded_constructor(9, 3, 1))->second == overloaded_constructor(10)); } } -UNORDERED_AUTO_TEST(set_std_emplace_test2) +UNORDERED_AUTO_TEST(BOOST_PP_CAT(PIECEWISE_TEST_NAME, 2)) { +#if EMULATING_PIECEWISE_CONSTRUCTION + test::detail::disable_construction_tracking _scoped; +#endif + boost::unordered_set< std::pair > x; std::pair check; - x.emplace(std::piecewise_construct, std::make_tuple(), std::make_tuple()); + x.emplace(PIECEWISE_NAMESPACE::piecewise_construct, + TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple()); BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); x.clear(); - x.emplace( - std::piecewise_construct, std::make_tuple(1), std::make_tuple(2, 3)); + x.emplace(PIECEWISE_NAMESPACE::piecewise_construct, + TUPLE_NAMESPACE::make_tuple(1), TUPLE_NAMESPACE::make_tuple(2, 3)); check = std::make_pair(overloaded_constructor(1), overloaded_constructor(2, 3)); BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); } -#endif -} +#undef PIECEWISE_TEST_NAME +#undef PIECEWISE_NAMESPACE +#undef TUPLE_NAMESPACE +#undef EMULATING_PIECEWISE_CONSTRUCTION -RUN_TESTS() +#endif From 76e7322262e6568fd3434d0768a3bdfb42265665 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 10 May 2017 19:02:47 +0100 Subject: [PATCH 132/147] Use streams from lightweight test --- test/exception/insert_exception_tests.cpp | 1 - .../exception/move_assign_exception_tests.cpp | 1 - test/exception/rehash_exception_tests.cpp | 2 - test/helpers/count.hpp | 1 - test/helpers/test.hpp | 32 ++++----- test/objects/exception.hpp | 1 - test/unordered/assign_tests.cpp | 22 +++--- test/unordered/bucket_tests.cpp | 3 +- test/unordered/compile_map.cpp | 13 ++-- test/unordered/compile_set.cpp | 25 ++++--- test/unordered/constructor_tests.cpp | 58 ++++++++-------- test/unordered/detail_tests.cpp | 2 - test/unordered/equivalent_keys_tests.cpp | 2 - test/unordered/erase_equiv_tests.cpp | 25 +++---- test/unordered/erase_tests.cpp | 25 +++---- test/unordered/extract_tests.cpp | 10 ++- test/unordered/insert_hint_tests.cpp | 1 - test/unordered/insert_stable_tests.cpp | 2 - test/unordered/insert_tests.cpp | 69 ++++++++++--------- test/unordered/noexcept_tests.cpp | 3 +- test/unordered/simple_tests.cpp | 8 +-- test/unordered/unnecessary_copy_tests.cpp | 29 ++++---- 22 files changed, 163 insertions(+), 172 deletions(-) diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index b7ab6cdf..d5fc3f10 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -3,7 +3,6 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "./containers.hpp" -#include #include "../helpers/helpers.hpp" #include "../helpers/invariants.hpp" diff --git a/test/exception/move_assign_exception_tests.cpp b/test/exception/move_assign_exception_tests.cpp index 8e363f89..5fe909a2 100644 --- a/test/exception/move_assign_exception_tests.cpp +++ b/test/exception/move_assign_exception_tests.cpp @@ -8,7 +8,6 @@ #include "../helpers/invariants.hpp" #include "../helpers/random_values.hpp" #include "../helpers/tracker.hpp" -#include #if defined(BOOST_MSVC) #pragma warning( \ diff --git a/test/exception/rehash_exception_tests.cpp b/test/exception/rehash_exception_tests.cpp index c6355071..f1386532 100644 --- a/test/exception/rehash_exception_tests.cpp +++ b/test/exception/rehash_exception_tests.cpp @@ -11,8 +11,6 @@ #include "../helpers/tracker.hpp" #include -#include - test::seed_t initialize_seed(3298597); template struct rehash_test_base : public test::exception_base diff --git a/test/helpers/count.hpp b/test/helpers/count.hpp index c432fd1f..76248617 100644 --- a/test/helpers/count.hpp +++ b/test/helpers/count.hpp @@ -7,7 +7,6 @@ #define BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD #include -#include namespace test { struct object_count diff --git a/test/helpers/test.hpp b/test/helpers/test.hpp index 4f21f0b9..c87a14dd 100644 --- a/test/helpers/test.hpp +++ b/test/helpers/test.hpp @@ -9,7 +9,6 @@ #include #include #include -#include #define UNORDERED_AUTO_TEST(x) \ struct BOOST_PP_CAT(x, _type) : public ::test::registered_test_base \ @@ -69,10 +68,10 @@ static inline void add_test(registered_test_base* test) static inline void run_tests() { for (registered_test_base* i = first(); i; i = i->next) { - std::cout << "Running " << i->name << "\n" << std::flush; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Running " << i->name << "\n" + << std::flush; i->run(); - std::cerr << std::flush; - std::cout << std::flush; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << std::flush; } } } @@ -86,18 +85,19 @@ static inline void run_tests() #define BOOST_UNORDERED_TEST_COMPILER_INFO() \ { \ - std::cout << "Compiler: " << BOOST_COMPILER << "\n" \ - << "Library: " << BOOST_STDLIB << "\n" \ - << "__cplusplus: " << BOOST_UNORDERED_CPLUSPLUS << "\n\n" \ - << "BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT: " \ - << BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT << "\n" \ - << "BOOST_UNORDERED_EMPLACE_LIMIT: " \ - << BOOST_UNORDERED_EMPLACE_LIMIT << "\n" \ - << "BOOST_UNORDERED_USE_ALLOCATOR_TRAITS: " \ - << BOOST_UNORDERED_USE_ALLOCATOR_TRAITS << "\n" \ - << "BOOST_UNORDERED_CXX11_CONSTRUCTION: " \ - << BOOST_UNORDERED_CXX11_CONSTRUCTION << "\n\n" \ - << std::flush; \ + BOOST_LIGHTWEIGHT_TEST_OSTREAM \ + << "Compiler: " << BOOST_COMPILER << "\n" \ + << "Library: " << BOOST_STDLIB << "\n" \ + << "__cplusplus: " << BOOST_UNORDERED_CPLUSPLUS << "\n\n" \ + << "BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT: " \ + << BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT << "\n" \ + << "BOOST_UNORDERED_EMPLACE_LIMIT: " \ + << BOOST_UNORDERED_EMPLACE_LIMIT << "\n" \ + << "BOOST_UNORDERED_USE_ALLOCATOR_TRAITS: " \ + << BOOST_UNORDERED_USE_ALLOCATOR_TRAITS << "\n" \ + << "BOOST_UNORDERED_CXX11_CONSTRUCTION: " \ + << BOOST_UNORDERED_CXX11_CONSTRUCTION << "\n\n" \ + << std::flush; \ } #include diff --git a/test/objects/exception.hpp b/test/objects/exception.hpp index 01b39ee3..d0286797 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -15,7 +15,6 @@ #include "./fwd.hpp" #include #include -#include #include namespace test { diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index f0e3aaae..3aee2198 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -17,8 +17,6 @@ #include "../helpers/tracker.hpp" #include "../helpers/equivalent.hpp" -#include - #if defined(BOOST_MSVC) #pragma warning(disable : 4127) // conditional expression is constant #endif @@ -32,7 +30,7 @@ template void assign_tests1(T*, test::random_generator generator) BOOST_DEDUCED_TYPENAME T::hasher hf; BOOST_DEDUCED_TYPENAME T::key_equal eq; - std::cerr << "assign_tests1.1\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests1.1\n"; { test::check_instances check_; @@ -43,7 +41,7 @@ template void assign_tests1(T*, test::random_generator generator) BOOST_TEST(test::equivalent(x.key_eq(), eq)); } - std::cerr << "assign_tests1.2\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests1.2\n"; { test::check_instances check_; @@ -79,7 +77,7 @@ template void assign_tests2(T*, test::random_generator generator) typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type; - std::cerr << "assign_tests2.0 - empty container\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.0 - empty container\n"; { test::check_instances check_; @@ -93,7 +91,7 @@ template void assign_tests2(T*, test::random_generator generator) test::check_container(x1, x2); } - std::cerr << "assign_tests2.1\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.1\n"; { test::check_instances check_; @@ -110,7 +108,7 @@ template void assign_tests2(T*, test::random_generator generator) BOOST_TEST(x2.load_factor() <= x2.max_load_factor()); } - std::cerr << "assign_tests2.1a\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.1a\n"; { test::check_instances check_; @@ -128,7 +126,7 @@ template void assign_tests2(T*, test::random_generator generator) BOOST_TEST(x2.load_factor() <= x2.max_load_factor()); } - std::cerr << "assign_tests2.2\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.2\n"; { test::check_instances check_; @@ -150,7 +148,7 @@ template void assign_tests2(T*, test::random_generator generator) BOOST_TEST(x2.load_factor() <= x2.max_load_factor()); } - std::cerr << "assign_tests2.3\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.3\n"; { test::check_instances check_; @@ -172,7 +170,7 @@ template void assign_tests2(T*, test::random_generator generator) BOOST_TEST(x2.load_factor() <= x2.max_load_factor()); } - std::cerr << "assign_tests2.4\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.4\n"; { test::check_instances check_; @@ -271,7 +269,7 @@ UNORDERED_TEST( UNORDERED_AUTO_TEST(assign_default_initializer_list) { - std::cerr << "Initializer List Tests\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n"; std::initializer_list > init; boost::unordered_map x1; x1[25] = 3; @@ -286,7 +284,7 @@ UNORDERED_AUTO_TEST(assign_default_initializer_list) #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) UNORDERED_AUTO_TEST(assign_initializer_list) { - std::cerr << "Initializer List Tests\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n"; boost::unordered_set x; x.insert(10); diff --git a/test/unordered/bucket_tests.cpp b/test/unordered/bucket_tests.cpp index 280c013e..9cb5bdd4 100644 --- a/test/unordered/bucket_tests.cpp +++ b/test/unordered/bucket_tests.cpp @@ -37,7 +37,8 @@ template void tests(X*, test::random_generator generator) BOOST_TEST(x.bucket_count() <= x.max_bucket_count()); if (!(x.bucket_count() <= x.max_bucket_count())) { - std::cerr << x.bucket_count() << "<=" << x.max_bucket_count() << "\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << x.bucket_count() + << "<=" << x.max_bucket_count() << "\n"; } for (BOOST_DEDUCED_TYPENAME test::random_values::const_iterator diff --git a/test/unordered/compile_map.cpp b/test/unordered/compile_map.cpp index 6293dfb8..863b56c1 100644 --- a/test/unordered/compile_map.cpp +++ b/test/unordered/compile_map.cpp @@ -12,7 +12,6 @@ #include "../helpers/postfix.hpp" // clang-format on -#include #include "../helpers/test.hpp" #include "../objects/minimal.hpp" #include "./compile_tests.hpp" @@ -46,7 +45,7 @@ UNORDERED_AUTO_TEST(test0) value_type; value_type value(x, x); - std::cout << "Test unordered_map.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n"; boost::unordered_map int_map; @@ -64,7 +63,7 @@ UNORDERED_AUTO_TEST(test0) container_test(int_map2, std::pair(0, 0)); container_test(map, value); - std::cout << "Test unordered_multimap.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n"; boost::unordered_multimap int_multimap; @@ -139,7 +138,7 @@ UNORDERED_AUTO_TEST(test1) int value = 0; std::pair map_value(0, 0); - std::cout << "Test unordered_map.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n"; boost::unordered_map map; @@ -157,7 +156,7 @@ UNORDERED_AUTO_TEST(test1) unordered_copyable_test(map2, value, map_value, hash, equal_to); unordered_map_functions(map2, value, value); - std::cout << "Test unordered_multimap.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n"; boost::unordered_multimap multimap; @@ -188,7 +187,7 @@ UNORDERED_AUTO_TEST(test2) map_value_type; map_value_type map_value(assignable, assignable); - std::cout << "Test unordered_map.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n"; boost::unordered_map, @@ -212,7 +211,7 @@ UNORDERED_AUTO_TEST(test2) unordered_map_functions(map2, assignable, default_assignable); - std::cout << "Test unordered_multimap.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n"; boost::unordered_multimap #include "../helpers/test.hpp" #include "../objects/minimal.hpp" #include "./compile_tests.hpp" @@ -42,7 +41,7 @@ UNORDERED_AUTO_TEST(test0) test::minimal::assignable assignable(x); - std::cout << "Test unordered_set.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n"; boost::unordered_set int_set; @@ -60,7 +59,7 @@ UNORDERED_AUTO_TEST(test0) container_test(int_set2, 0); container_test(set, assignable); - std::cout << "Test unordered_multiset.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n"; boost::unordered_multiset int_multiset; @@ -128,7 +127,7 @@ UNORDERED_AUTO_TEST(test1) std::equal_to equal_to; int value = 0; - std::cout << "Test unordered_set." << std::endl; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set." << std::endl; boost::unordered_set set; @@ -144,7 +143,7 @@ UNORDERED_AUTO_TEST(test1) unordered_set_test(set2, value); unordered_copyable_test(set2, value, value, hash, equal_to); - std::cout << "Test unordered_multiset." << std::endl; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset." << std::endl; boost::unordered_multiset multiset; @@ -170,7 +169,7 @@ UNORDERED_AUTO_TEST(test2) test::minimal::hash hash(x); test::minimal::equal_to equal_to(x); - std::cout << "Test unordered_set.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n"; boost::unordered_set, @@ -183,7 +182,7 @@ UNORDERED_AUTO_TEST(test2) unordered_copyable_test(set, assignable, assignable, hash, equal_to); unordered_set_member_test(set, assignable); - std::cout << "Test unordered_multiset.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n"; boost::unordered_multiset, @@ -205,7 +204,7 @@ UNORDERED_AUTO_TEST(movable1_tests) test::minimal::hash hash(x); test::minimal::equal_to equal_to(x); - std::cout << "Test unordered_set.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n"; boost::unordered_set, @@ -217,7 +216,7 @@ UNORDERED_AUTO_TEST(movable1_tests) unordered_set_test(set, movable1); unordered_movable_test(set, movable1, movable1, hash, equal_to); - std::cout << "Test unordered_multiset.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n"; boost::unordered_multiset, @@ -238,7 +237,7 @@ UNORDERED_AUTO_TEST(movable2_tests) test::minimal::hash hash(x); test::minimal::equal_to equal_to(x); - std::cout << "Test unordered_set.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n"; boost::unordered_set, @@ -250,7 +249,7 @@ UNORDERED_AUTO_TEST(movable2_tests) unordered_set_test(set, movable2); unordered_movable_test(set, movable2, movable2, hash, equal_to); - std::cout << "Test unordered_multiset.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n"; boost::unordered_multiset, @@ -271,7 +270,7 @@ UNORDERED_AUTO_TEST(destructible_tests) test::minimal::hash hash(x); test::minimal::equal_to equal_to(x); - std::cout << "Test unordered_set.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n"; boost::unordered_set, @@ -280,7 +279,7 @@ UNORDERED_AUTO_TEST(destructible_tests) unordered_destructible_test(set); - std::cout << "Test unordered_multiset.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n"; boost::unordered_multiset, diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 25901353..a12d57ef 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -28,7 +28,7 @@ template void constructor_tests1(T*, test::random_generator generator) BOOST_DEDUCED_TYPENAME T::key_equal eq; BOOST_DEDUCED_TYPENAME T::allocator_type al; - std::cerr << "Construct 1\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 1\n"; { test::check_instances check_; @@ -40,7 +40,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "Construct 2\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 2\n"; { test::check_instances check_; @@ -53,7 +53,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "Construct 3\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 3\n"; { test::check_instances check_; @@ -66,7 +66,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "Construct 4\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 4\n"; { test::check_instances check_; @@ -78,7 +78,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "Construct 5\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 5\n"; { test::check_instances check_; @@ -92,7 +92,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "Construct 6\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 6\n"; { test::check_instances check_; @@ -106,7 +106,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "Construct 7\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 7\n"; { test::check_instances check_; @@ -120,7 +120,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "Construct 8\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 8\n"; { test::check_instances check_; @@ -133,7 +133,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "Construct 9\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 9\n"; { test::check_instances check_; @@ -145,7 +145,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "Construct 10\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 10\n"; { test::check_instances check_; @@ -159,7 +159,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "Construct 11\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 11\n"; { test::check_instances check_; @@ -185,7 +185,7 @@ void constructor_tests2(T*, test::random_generator const& generator) BOOST_DEDUCED_TYPENAME T::allocator_type al1(1); BOOST_DEDUCED_TYPENAME T::allocator_type al2(2); - std::cerr << "Construct 1\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 1\n"; { test::check_instances check_; T x(10000, hf1, eq1); @@ -196,7 +196,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(x); } - std::cerr << "Construct 2\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 2\n"; { test::check_instances check_; T x(100, hf1); @@ -208,7 +208,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(x); } - std::cerr << "Construct 3\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 3\n"; { test::check_instances check_; test::random_values v(100, generator); @@ -220,7 +220,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(x); } - std::cerr << "Construct 4\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 4\n"; { test::check_instances check_; test::random_values v(5, generator); @@ -233,7 +233,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(x); } - std::cerr << "Construct 5\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 5\n"; { test::check_instances check_; test::random_values v(100, generator); @@ -245,7 +245,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(y); } - std::cerr << "Construct 6\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 6\n"; { test::check_instances check_; test::random_values v(100, generator); @@ -257,7 +257,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(y); } - std::cerr << "Construct 7\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 7\n"; { test::check_instances check_; test::random_values v(100, generator); @@ -269,7 +269,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(y); } - std::cerr << "Construct 8 - from input iterator\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 8 - from input iterator\n"; { test::check_instances check_; test::random_values v(100, generator); @@ -288,7 +288,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(y); } - std::cerr << "Construct 8.5 - from copy iterator\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 8.5 - from copy iterator\n"; { test::check_instances check_; test::random_values v(100, generator); @@ -302,7 +302,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(y); } - std::cerr << "Construct 9\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 9\n"; { test::check_instances check_; @@ -320,7 +320,7 @@ void constructor_tests2(T*, test::random_generator const& generator) #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) std::initializer_list list; - std::cerr << "Initializer list construct 1\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer list construct 1\n"; { test::check_instances check_; @@ -331,7 +331,7 @@ void constructor_tests2(T*, test::random_generator const& generator) BOOST_TEST(test::equivalent(x.get_allocator(), al)); } - std::cerr << "Initializer list construct 2\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer list construct 2\n"; { test::check_instances check_; @@ -343,7 +343,7 @@ void constructor_tests2(T*, test::random_generator const& generator) BOOST_TEST(test::equivalent(x.get_allocator(), al)); } - std::cerr << "Initializer list construct 3\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer list construct 3\n"; { test::check_instances check_; @@ -355,7 +355,7 @@ void constructor_tests2(T*, test::random_generator const& generator) BOOST_TEST(test::equivalent(x.get_allocator(), al)); } - std::cerr << "Initializer list construct 4\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer list construct 4\n"; { test::check_instances check_; @@ -367,7 +367,7 @@ void constructor_tests2(T*, test::random_generator const& generator) BOOST_TEST(test::equivalent(x.get_allocator(), al)); } - std::cerr << "Initializer list construct 5\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer list construct 5\n"; { test::check_instances check_; @@ -384,7 +384,7 @@ void constructor_tests2(T*, test::random_generator const& generator) template void map_constructor_test(T*, test::random_generator const& generator) { - std::cerr << "map_constructor_test\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "map_constructor_test\n"; typedef test::list > @@ -429,7 +429,7 @@ UNORDERED_TEST(map_constructor_test, UNORDERED_AUTO_TEST(test_default_initializer_list) { - std::cerr << "Initializer List Tests\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n"; std::initializer_list init; boost::unordered_set x1 = init; BOOST_TEST(x1.empty()); @@ -441,7 +441,7 @@ UNORDERED_AUTO_TEST(test_default_initializer_list) UNORDERED_AUTO_TEST(test_initializer_list) { - std::cerr << "Initializer List Tests\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n"; boost::unordered_set x1 = {2, 10, 45, -5}; BOOST_TEST(x1.find(10) != x1.end()); BOOST_TEST(x1.find(46) == x1.end()); diff --git a/test/unordered/detail_tests.cpp b/test/unordered/detail_tests.cpp index b87bf943..2af4c4fb 100644 --- a/test/unordered/detail_tests.cpp +++ b/test/unordered/detail_tests.cpp @@ -3,8 +3,6 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include - // clang-format off #include "../helpers/prefix.hpp" #include diff --git a/test/unordered/equivalent_keys_tests.cpp b/test/unordered/equivalent_keys_tests.cpp index 72ab057e..8e48d68c 100644 --- a/test/unordered/equivalent_keys_tests.cpp +++ b/test/unordered/equivalent_keys_tests.cpp @@ -17,8 +17,6 @@ #include "../helpers/tracker.hpp" #include "../helpers/invariants.hpp" -#include - template void test_equal_insertion(Iterator begin, Iterator end) { diff --git a/test/unordered/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp index 1907ddd1..64510394 100644 --- a/test/unordered/erase_equiv_tests.cpp +++ b/test/unordered/erase_equiv_tests.cpp @@ -17,7 +17,6 @@ #include "../helpers/invariants.hpp" #include "../helpers/helpers.hpp" #include -#include #include #include "../objects/test.hpp" @@ -31,14 +30,15 @@ struct write_pair_type template void operator()(std::pair const& x) const { - std::cout << "(" << x.first << "," << x.second << ")"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "(" << x.first << "," << x.second + << ")"; } } write_pair; template void write_container(Container const& x) { std::for_each(x.begin(), x.end(), write_pair); - std::cout << "\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n"; } // Make everything collide - for testing erase in a single bucket. @@ -165,8 +165,8 @@ template void erase_subrange_tests(Container const& x) collide_list init(y.begin(), y.end()); if (!general_erase_range_test(y, position, position + length)) { BOOST_ERROR("general_erase_range_test failed."); - std::cout << "Erase: [" << position << "," << position + length - << ")\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Erase: [" << position << "," + << position + length << ")\n"; write_container(init); write_container(y); } @@ -185,7 +185,8 @@ void x_by_y_erase_range_tests(Container*, int values, int duplicates) } } - std::cout << "Values: " << values << ", Duplicates: " << duplicates << "\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Values: " << values + << ", Duplicates: " << duplicates << "\n"; erase_subrange_tests(y); } @@ -201,24 +202,24 @@ void exhaustive_erase_tests(Container* x, int num_values, int num_duplicated) UNORDERED_AUTO_TEST(exhaustive_collide_tests) { - std::cout << "exhaustive_collide_tests:\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide_tests:\n"; collide_map m; exhaustive_erase_tests((collide_map*)0, 4, 4); - std::cout << "\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n"; } UNORDERED_AUTO_TEST(exhaustive_collide2_tests) { - std::cout << "exhaustive_collide2_tests:\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide2_tests:\n"; exhaustive_erase_tests((collide_map2*)0, 8, 4); - std::cout << "\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n"; } UNORDERED_AUTO_TEST(exhaustive_collide3_tests) { - std::cout << "exhaustive_collide3_tests:\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide3_tests:\n"; exhaustive_erase_tests((collide_map3*)0, 8, 4); - std::cout << "\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n"; } RUN_TESTS() diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index c763c66f..843e64f2 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -18,7 +18,6 @@ #include "../helpers/helpers.hpp" #include "../helpers/invariants.hpp" #include -#include #include namespace erase_tests { @@ -31,7 +30,7 @@ void erase_tests1(Container*, test::random_generator generator) typedef BOOST_DEDUCED_TYPENAME Container::iterator iterator; typedef BOOST_DEDUCED_TYPENAME Container::const_iterator c_iterator; - std::cerr << "Erase by key.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Erase by key.\n"; { test::check_instances check_; @@ -52,7 +51,7 @@ void erase_tests1(Container*, test::random_generator generator) } } - std::cerr << "erase(begin()).\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(begin()).\n"; { test::check_instances check_; @@ -75,7 +74,7 @@ void erase_tests1(Container*, test::random_generator generator) BOOST_TEST(x.empty()); } - std::cerr << "erase(random position).\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(random position).\n"; { test::check_instances check_; @@ -104,7 +103,8 @@ void erase_tests1(Container*, test::random_generator generator) index == 0 ? next == x.begin() : next == test::next(prev)); BOOST_TEST(x.count(key) == count - 1); if (x.count(key) != count - 1) { - std::cerr << count << " => " << x.count(key) << std::endl; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << count << " => " + << x.count(key) << std::endl; } BOOST_TEST(x.size() == size); if (++iterations % 20 == 0) @@ -113,7 +113,7 @@ void erase_tests1(Container*, test::random_generator generator) BOOST_TEST(x.empty()); } - std::cerr << "erase(ranges).\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(ranges).\n"; { test::check_instances check_; @@ -140,7 +140,7 @@ void erase_tests1(Container*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "erase(random ranges).\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(random ranges).\n"; { test::check_instances check_; Container x; @@ -179,7 +179,7 @@ void erase_tests1(Container*, test::random_generator generator) } } - std::cerr << "quick_erase(begin()).\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "quick_erase(begin()).\n"; { test::check_instances check_; @@ -201,7 +201,7 @@ void erase_tests1(Container*, test::random_generator generator) BOOST_TEST(x.empty()); } - std::cerr << "quick_erase(random position).\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "quick_erase(random position).\n"; { test::check_instances check_; @@ -230,7 +230,8 @@ void erase_tests1(Container*, test::random_generator generator) index == 0 ? next == x.begin() : next == test::next(prev)); BOOST_TEST(x.count(key) == count - 1); if (x.count(key) != count - 1) { - std::cerr << count << " => " << x.count(key) << std::endl; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << count << " => " + << x.count(key) << std::endl; } BOOST_TEST(x.size() == size); if (++iterations % 20 == 0) @@ -239,7 +240,7 @@ void erase_tests1(Container*, test::random_generator generator) BOOST_TEST(x.empty()); } - std::cerr << "clear().\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "clear().\n"; { test::check_instances check_; @@ -250,7 +251,7 @@ void erase_tests1(Container*, test::random_generator generator) BOOST_TEST(x.begin() == x.end()); } - std::cerr << "\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n"; } boost::unordered_set -#include - namespace extract_tests { test::seed_t initialize_seed(85638); @@ -28,7 +26,7 @@ test::seed_t initialize_seed(85638); template void extract_tests1(Container*, test::random_generator generator) { - std::cerr << "Extract by key.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Extract by key.\n"; { test::check_instances check_; @@ -58,7 +56,7 @@ void extract_tests1(Container*, test::random_generator generator) BOOST_TEST(x.empty()); } - std::cerr << "extract(begin()).\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "extract(begin()).\n"; { test::check_instances check_; @@ -81,7 +79,7 @@ void extract_tests1(Container*, test::random_generator generator) BOOST_TEST(x.empty()); } - std::cerr << "extract(random position).\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "extract(random position).\n"; { test::check_instances check_; @@ -117,7 +115,7 @@ void extract_tests1(Container*, test::random_generator generator) BOOST_TEST(x.empty()); } - std::cerr << "\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n"; } boost::unordered_set #include -#include namespace insert_hint { UNORDERED_AUTO_TEST(insert_hint_empty) diff --git a/test/unordered/insert_stable_tests.cpp b/test/unordered/insert_stable_tests.cpp index afba2239..9915c10b 100644 --- a/test/unordered/insert_stable_tests.cpp +++ b/test/unordered/insert_stable_tests.cpp @@ -12,8 +12,6 @@ #include "../helpers/test.hpp" -#include - namespace insert_stable { struct member { diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index fd7b461d..fb4f78d9 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -21,8 +21,6 @@ #include "../helpers/input_iterator.hpp" #include "../helpers/helpers.hpp" -#include - namespace insert_tests { test::seed_t initialize_seed(243432); @@ -35,7 +33,8 @@ void unique_insert_tests1(X*, test::random_generator generator) typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; typedef test::ordered ordered; - std::cerr << "insert(value) tests for containers with unique keys.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM + << "insert(value) tests for containers with unique keys.\n"; { X x; @@ -68,7 +67,8 @@ void unique_insert_tests1(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert(rvalue) tests for containers with unique keys.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM + << "insert(rvalue) tests for containers with unique keys.\n"; { X x; @@ -108,7 +108,8 @@ void equivalent_insert_tests1(X*, test::random_generator generator) { test::check_instances check_; - std::cerr << "insert(value) tests for containers with equivalent keys.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM + << "insert(value) tests for containers with equivalent keys.\n"; { X x; @@ -138,7 +139,8 @@ void equivalent_insert_tests1(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert(rvalue) tests for containers with equivalent keys.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM + << "insert(rvalue) tests for containers with equivalent keys.\n"; { X x; @@ -178,7 +180,7 @@ template void insert_tests2(X*, test::random_generator generator) typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator; typedef BOOST_DEDUCED_TYPENAME tracker_type::iterator tracker_iterator; - std::cerr << "insert(begin(), value) tests.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert(begin(), value) tests.\n"; { test::check_instances check_; @@ -208,7 +210,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert(end(), value) tests.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert(end(), value) tests.\n"; { test::check_instances check_; @@ -239,7 +241,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert(pos, value) tests.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert(pos, value) tests.\n"; { test::check_instances check_; @@ -270,7 +272,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert(pos, rvalue) tests.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert(pos, rvalue) tests.\n"; { test::check_instances check_; @@ -302,7 +304,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert single item range tests.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert single item range tests.\n"; { test::check_instances check_; @@ -331,7 +333,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert range tests.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert range tests.\n"; { test::check_instances check_; @@ -345,7 +347,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert range with rehash tests.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert range with rehash tests.\n"; { test::check_instances check_; @@ -363,7 +365,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert input iterator range tests.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert input iterator range tests.\n"; { test::check_instances check_; @@ -380,7 +382,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert copy iterator range tests.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert copy iterator range tests.\n"; { test::check_instances check_; @@ -394,7 +396,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert copy iterator range test 2.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert copy iterator range test 2.\n"; { test::check_instances check_; @@ -411,7 +413,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert various ranges.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert various ranges.\n"; { for (int i = 0; i < 100; ++i) { @@ -458,7 +460,8 @@ void unique_emplace_tests1(X*, test::random_generator generator) typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; typedef test::ordered ordered; - std::cerr << "emplace(value) tests for containers with unique keys.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM + << "emplace(value) tests for containers with unique keys.\n"; X x; test::ordered tracker = test::create_ordered(x); @@ -492,7 +495,8 @@ void unique_emplace_tests1(X*, test::random_generator generator) template void equivalent_emplace_tests1(X*, test::random_generator generator) { - std::cerr << "emplace(value) tests for containers with equivalent keys.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM + << "emplace(value) tests for containers with equivalent keys.\n"; X x; test::ordered tracker = test::create_ordered(x); @@ -522,7 +526,7 @@ void equivalent_emplace_tests1(X*, test::random_generator generator) template void move_emplace_tests(X*, test::random_generator generator) { - std::cerr + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "emplace(move(value)) tests for containers with unique keys.\n"; X x; @@ -553,7 +557,7 @@ template 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"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "emplace() tests.\n"; bool is_unique = test::has_unique_keys::value; X x; @@ -588,7 +592,7 @@ template void default_emplace_tests(X*, test::random_generator) template void map_tests(X*, test::random_generator generator) { - std::cerr << "map tests.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "map tests.\n"; X x; test::ordered tracker = test::create_ordered(x); @@ -616,7 +620,7 @@ template void map_tests(X*, test::random_generator generator) template void map_tests2(X*, test::random_generator generator) { typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; - std::cerr << "insert_or_assign\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert_or_assign\n"; { test::check_instances check_; @@ -648,7 +652,7 @@ template void map_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert_or_assign(begin)\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert_or_assign(begin)\n"; { test::check_instances check_; @@ -679,7 +683,7 @@ template void map_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert_or_assign(end)\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert_or_assign(end)\n"; { test::check_instances check_; @@ -710,7 +714,7 @@ template void map_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "insert_or_assign(last)\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert_or_assign(last)\n"; { test::check_instances check_; @@ -747,7 +751,7 @@ template void map_tests2(X*, test::random_generator generator) template void try_emplace_tests(X*, test::random_generator generator) { - std::cerr << "try_emplace(key, value)\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "try_emplace(key, value)\n"; typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; @@ -790,7 +794,7 @@ template void try_emplace_tests(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "try_emplace(begin(), key, value)\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "try_emplace(begin(), key, value)\n"; typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; @@ -830,7 +834,7 @@ template void try_emplace_tests(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "try_emplace(end(), key, value)\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "try_emplace(end(), key, value)\n"; typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; @@ -870,7 +874,7 @@ template void try_emplace_tests(X*, test::random_generator generator) test::check_equivalent_keys(x); } - std::cerr << "try_emplace(pos, key, value)\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "try_emplace(pos, key, value)\n"; typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; @@ -916,7 +920,7 @@ template void try_emplace_tests(X*, test::random_generator generator) template void map_insert_range_test1(X*, test::random_generator generator) { - std::cerr << "map_insert_range_test1\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "map_insert_range_test1\n"; test::check_instances check_; @@ -935,7 +939,7 @@ void map_insert_range_test1(X*, test::random_generator generator) template void map_insert_range_test2(X*, test::random_generator generator) { - std::cerr << "map_insert_range_test2\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "map_insert_range_test2\n"; test::check_instances check_; @@ -1391,7 +1395,6 @@ UNORDERED_AUTO_TEST(set_emplace_test2) #include "./insert_tests.cpp" #endif - } RUN_TESTS() diff --git a/test/unordered/noexcept_tests.cpp b/test/unordered/noexcept_tests.cpp index cadf8b70..d801ae1c 100644 --- a/test/unordered/noexcept_tests.cpp +++ b/test/unordered/noexcept_tests.cpp @@ -36,7 +36,8 @@ bool throwing_test_exception = false; void test_throw(char const* name) { if (throwing_test_exception) { - std::cerr << "Throw exception in: " << name << std::endl; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Throw exception in: " << name + << std::endl; throw test_exception(); } } diff --git a/test/unordered/simple_tests.cpp b/test/unordered/simple_tests.cpp index 05d5523d..40ba5fc3 100644 --- a/test/unordered/simple_tests.cpp +++ b/test/unordered/simple_tests.cpp @@ -93,7 +93,7 @@ UNORDERED_AUTO_TEST(simple_tests) using namespace std; srand(14878); - std::cout << "Test unordered_set.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n"; boost::unordered_set set; simple_test(set); @@ -102,7 +102,7 @@ UNORDERED_AUTO_TEST(simple_tests) set.insert(1456); simple_test(set); - std::cout << "Test unordered_multiset.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n"; boost::unordered_multiset multiset; simple_test(multiset); @@ -113,7 +113,7 @@ UNORDERED_AUTO_TEST(simple_tests) } simple_test(multiset); - std::cout << "Test unordered_map.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n"; boost::unordered_map map; for (int i2 = 0; i2 < 1000; ++i2) { @@ -121,7 +121,7 @@ UNORDERED_AUTO_TEST(simple_tests) } simple_test(map); - std::cout << "Test unordered_multimap.\n"; + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n"; boost::unordered_multimap multimap; for (int i3 = 0; i3 < 1000; ++i3) { diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index 3a5424bb..0322eade 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -10,7 +10,6 @@ #include "../helpers/postfix.hpp" // clang-format on -#include #include "../helpers/test.hpp" namespace unnecessary_copy_tests { @@ -138,32 +137,36 @@ std::size_t hash_value(unnecessary_copy_tests::count_copies const& x) #define COPY_COUNT(n) \ if (::unnecessary_copy_tests::count_copies::copies != n) { \ BOOST_ERROR("Wrong number of copies."); \ - std::cerr << "Number of copies: " \ - << ::unnecessary_copy_tests::count_copies::copies \ - << " expecting: " << n << std::endl; \ + BOOST_LIGHTWEIGHT_TEST_OSTREAM \ + << "Number of copies: " \ + << ::unnecessary_copy_tests::count_copies::copies \ + << " expecting: " << n << std::endl; \ } #define MOVE_COUNT(n) \ if (::unnecessary_copy_tests::count_copies::moves != n) { \ BOOST_ERROR("Wrong number of moves."); \ - std::cerr << "Number of moves: " \ - << ::unnecessary_copy_tests::count_copies::moves \ - << " expecting: " << n << std::endl; \ + BOOST_LIGHTWEIGHT_TEST_OSTREAM \ + << "Number of moves: " \ + << ::unnecessary_copy_tests::count_copies::moves \ + << " expecting: " << n << std::endl; \ } #define COPY_COUNT_RANGE(a, b) \ if (::unnecessary_copy_tests::count_copies::copies < a || \ ::unnecessary_copy_tests::count_copies::copies > b) { \ BOOST_ERROR("Wrong number of copies."); \ - std::cerr << "Number of copies: " \ - << ::unnecessary_copy_tests::count_copies::copies \ - << " expecting: [" << a << ", " << b << "]" << std::endl; \ + BOOST_LIGHTWEIGHT_TEST_OSTREAM \ + << "Number of copies: " \ + << ::unnecessary_copy_tests::count_copies::copies \ + << " expecting: [" << a << ", " << b << "]" << std::endl; \ } #define MOVE_COUNT_RANGE(a, b) \ if (::unnecessary_copy_tests::count_copies::moves < a || \ ::unnecessary_copy_tests::count_copies::moves > b) { \ BOOST_ERROR("Wrong number of moves."); \ - std::cerr << "Number of moves: " \ - << ::unnecessary_copy_tests::count_copies::moves \ - << " expecting: [" << a << ", " << b << "]" << std::endl; \ + BOOST_LIGHTWEIGHT_TEST_OSTREAM \ + << "Number of moves: " \ + << ::unnecessary_copy_tests::count_copies::moves \ + << " expecting: [" << a << ", " << b << "]" << std::endl; \ } #define COPY_COUNT_EXTRA(a, b) COPY_COUNT_RANGE(a, a + b * EXTRA_CONSTRUCT_COST) #define MOVE_COUNT_EXTRA(a, b) MOVE_COUNT_RANGE(a, a + b * EXTRA_CONSTRUCT_COST) From b95ef6de0460d98d2105ef6b7e0d8f2d30c675cc Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 10 May 2017 19:02:47 +0100 Subject: [PATCH 133/147] Generate less output in merge_exception_tests --- test/exception/merge_exception_tests.cpp | 2 +- test/helpers/test.hpp | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/test/exception/merge_exception_tests.cpp b/test/exception/merge_exception_tests.cpp index 496c01e7..f22f0c36 100644 --- a/test/exception/merge_exception_tests.cpp +++ b/test/exception/merge_exception_tests.cpp @@ -105,4 +105,4 @@ UNORDERED_TEST(merge_exception_test, ) // clang-format on -RUN_TESTS() +RUN_TESTS_QUIET() diff --git a/test/helpers/test.hpp b/test/helpers/test.hpp index c87a14dd..92d4cc1a 100644 --- a/test/helpers/test.hpp +++ b/test/helpers/test.hpp @@ -31,6 +31,14 @@ return boost::report_errors(); \ } +#define RUN_TESTS_QUIET() \ + int main(int, char**) \ + { \ + BOOST_UNORDERED_TEST_COMPILER_INFO() \ + ::test::test_list::run_tests(true); \ + return boost::report_errors(); \ + } + namespace test { struct registered_test_base { @@ -65,13 +73,20 @@ static inline void add_test(registered_test_base* test) last() = test; } -static inline void run_tests() +static inline void run_tests(bool quiet = false) { for (registered_test_base* i = first(); i; i = i->next) { - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Running " << i->name << "\n" - << std::flush; + int error_count = boost::detail::test_errors(); + if (!quiet) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Running " << i->name << "\n" + << std::flush; + } i->run(); BOOST_LIGHTWEIGHT_TEST_OSTREAM << std::flush; + if (quiet && error_count != boost::detail::test_errors()) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in: " << i->name << "\n" + << std::flush; + } } } } From ca80237191f2f3fca5f42503db4a30628c5dd48c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 10 May 2017 19:02:47 +0100 Subject: [PATCH 134/147] Create fewer classes in merge_exception_tests Will need better error reporting capabilities. Makes RUN_TESTS_QUIET redundant? --- test/exception/merge_exception_tests.cpp | 8 ++++---- test/helpers/test.hpp | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/test/exception/merge_exception_tests.cpp b/test/exception/merge_exception_tests.cpp index f22f0c36..442e364f 100644 --- a/test/exception/merge_exception_tests.cpp +++ b/test/exception/merge_exception_tests.cpp @@ -62,7 +62,7 @@ using test::generate_collisions; using test::limited_range; // clang-format off -UNORDERED_TEST(merge_exception_test, +UNORDERED_MULTI_TEST(set_merge, merge_exception_test, ((test_set_)(test_multiset_)) ((test_set_)(test_multiset_)) ((0)(10)(100)) @@ -72,7 +72,7 @@ UNORDERED_TEST(merge_exception_test, ((default_generator)(limited_range)) ((default_generator)(limited_range)) ) -UNORDERED_TEST(merge_exception_test, +UNORDERED_MULTI_TEST(map_merge, merge_exception_test, ((test_map_)(test_multimap_)) ((test_map_)(test_multimap_)) ((0)(10)(100)) @@ -83,7 +83,7 @@ UNORDERED_TEST(merge_exception_test, ((default_generator)(limited_range)) ) // Run fewer generate_collisions tests, as they're slow. -UNORDERED_TEST(merge_exception_test, +UNORDERED_MULTI_TEST(set_merge_collisions, merge_exception_test, ((test_set_)(test_multiset_)) ((test_set_)(test_multiset_)) ((10)) @@ -93,7 +93,7 @@ UNORDERED_TEST(merge_exception_test, ((generate_collisions)) ((generate_collisions)) ) -UNORDERED_TEST(merge_exception_test, +UNORDERED_MULTI_TEST(map_merge_collisions, merge_exception_test, ((test_map_)(test_multimap_)) ((test_map_)(test_multimap_)) ((10)) diff --git a/test/helpers/test.hpp b/test/helpers/test.hpp index 92d4cc1a..c65701b6 100644 --- a/test/helpers/test.hpp +++ b/test/helpers/test.hpp @@ -144,4 +144,25 @@ static inline void run_tests(bool quiet = false) #define UNORDERED_TEST_OP_JOIN(s, state, elem) \ BOOST_PP_CAT(state, BOOST_PP_CAT(_, elem)) +#define UNORDERED_MULTI_TEST(name, impl, parameters) \ + UNORDERED_MULTI_TEST_REPEAT(name, impl, 1, parameters) + +#define UNORDERED_MULTI_TEST_REPEAT(name, impl, n, parameters) \ + UNORDERED_AUTO_TEST(name) \ + { \ + BOOST_PP_SEQ_FOR_EACH_PRODUCT( \ + UNORDERED_MULTI_TEST_OP, ((impl))((n))parameters) \ + } + +#define UNORDERED_MULTI_TEST_OP(r, product) \ + UNORDERED_MULTI_TEST_OP2(BOOST_PP_SEQ_ELEM(0, product), \ + BOOST_PP_SEQ_ELEM(1, product), \ + BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_TAIL(product))) + +#define UNORDERED_MULTI_TEST_OP2(name, n, params) \ + { \ + for (int i = 0; i < n; ++i) \ + name BOOST_PP_SEQ_TO_TUPLE(params); \ + } + #endif From 242e91a9fdc29e0eeb44e16d406762044f2fd771 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 10 May 2017 19:02:47 +0100 Subject: [PATCH 135/147] "Sub-test" reporting mechanism --- test/helpers/test.hpp | 36 +++++++++++ test/unordered/constructor_tests.cpp | 58 ++++++++---------- test/unordered/insert_tests.cpp | 92 ++++++++-------------------- 3 files changed, 89 insertions(+), 97 deletions(-) diff --git a/test/helpers/test.hpp b/test/helpers/test.hpp index c65701b6..617946c7 100644 --- a/test/helpers/test.hpp +++ b/test/helpers/test.hpp @@ -39,7 +39,39 @@ return boost::report_errors(); \ } +#define UNORDERED_SUB_TEST(x) \ + for (int UNORDERED_SUB_TEST_VALUE = ::test::start_sub_test(x); \ + UNORDERED_SUB_TEST_VALUE; \ + UNORDERED_SUB_TEST_VALUE = \ + ::test::end_sub_test(x, UNORDERED_SUB_TEST_VALUE)) + namespace test { + +static inline bool& is_quiet() +{ + static bool value = false; + return value; +} + +static inline int start_sub_test(char const* name) +{ + if (!is_quiet()) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Sub-test: " << name << "\n" + << std::flush; + } + // Add one because it's used as a loop condition. + return boost::detail::test_errors() + 1; +} + +static inline int end_sub_test(char const* name, int value) +{ + if (is_quiet() && value != boost::detail::test_errors() + 1) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in sub-test: " << name << "\n" + << std::flush; + } + return 0; +} + struct registered_test_base { registered_test_base* next; @@ -75,6 +107,8 @@ static inline void add_test(registered_test_base* test) static inline void run_tests(bool quiet = false) { + test::is_quiet() = quiet; + for (registered_test_base* i = first(); i; i = i->next) { int error_count = boost::detail::test_errors(); if (!quiet) { @@ -160,6 +194,8 @@ static inline void run_tests(bool quiet = false) BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_TAIL(product))) #define UNORDERED_MULTI_TEST_OP2(name, n, params) \ + UNORDERED_SUB_TEST(BOOST_PP_STRINGIZE( \ + BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params))) \ { \ for (int i = 0; i < n; ++i) \ name BOOST_PP_SEQ_TO_TUPLE(params); \ diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index a12d57ef..4c967ded 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -28,7 +28,7 @@ template void constructor_tests1(T*, test::random_generator generator) BOOST_DEDUCED_TYPENAME T::key_equal eq; BOOST_DEDUCED_TYPENAME T::allocator_type al; - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 1\n"; + UNORDERED_SUB_TEST("Construct 1") { test::check_instances check_; @@ -40,7 +40,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 2\n"; + UNORDERED_SUB_TEST("Construct 2") { test::check_instances check_; @@ -53,7 +53,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 3\n"; + UNORDERED_SUB_TEST("Construct 3") { test::check_instances check_; @@ -66,7 +66,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 4\n"; + UNORDERED_SUB_TEST("Construct 4") { test::check_instances check_; @@ -78,7 +78,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 5\n"; + UNORDERED_SUB_TEST("Construct 5") { test::check_instances check_; @@ -92,7 +92,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 6\n"; + UNORDERED_SUB_TEST("Construct 6") { test::check_instances check_; @@ -106,7 +106,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 7\n"; + UNORDERED_SUB_TEST("Construct 7") { test::check_instances check_; @@ -120,7 +120,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 8\n"; + UNORDERED_SUB_TEST("Construct 8") { test::check_instances check_; @@ -133,7 +133,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 9\n"; + UNORDERED_SUB_TEST("Construct 9") { test::check_instances check_; @@ -145,7 +145,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 10\n"; + UNORDERED_SUB_TEST("Construct 10") { test::check_instances check_; @@ -159,7 +159,7 @@ template void constructor_tests1(T*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 11\n"; + UNORDERED_SUB_TEST("Construct 11") { test::check_instances check_; @@ -185,7 +185,7 @@ void constructor_tests2(T*, test::random_generator const& generator) BOOST_DEDUCED_TYPENAME T::allocator_type al1(1); BOOST_DEDUCED_TYPENAME T::allocator_type al2(2); - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 1\n"; + UNORDERED_SUB_TEST("Construct 1") { test::check_instances check_; T x(10000, hf1, eq1); @@ -196,7 +196,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 2\n"; + UNORDERED_SUB_TEST("Construct 2") { test::check_instances check_; T x(100, hf1); @@ -208,7 +208,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 3\n"; + UNORDERED_SUB_TEST("Construct 3") { test::check_instances check_; test::random_values v(100, generator); @@ -220,7 +220,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 4\n"; + UNORDERED_SUB_TEST("Construct 4") { test::check_instances check_; test::random_values v(5, generator); @@ -233,7 +233,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 5\n"; + UNORDERED_SUB_TEST("Construct 5") { test::check_instances check_; test::random_values v(100, generator); @@ -245,7 +245,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(y); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 6\n"; + UNORDERED_SUB_TEST("Construct 6") { test::check_instances check_; test::random_values v(100, generator); @@ -257,7 +257,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(y); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 7\n"; + UNORDERED_SUB_TEST("Construct 7") { test::check_instances check_; test::random_values v(100, generator); @@ -269,7 +269,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(y); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 8 - from input iterator\n"; + UNORDERED_SUB_TEST("Construct 8 - from input iterator") { test::check_instances check_; test::random_values v(100, generator); @@ -288,7 +288,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(y); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 8.5 - from copy iterator\n"; + UNORDERED_SUB_TEST("Construct 8.5 - from copy iterator") { test::check_instances check_; test::random_values v(100, generator); @@ -302,7 +302,7 @@ void constructor_tests2(T*, test::random_generator const& generator) test::check_equivalent_keys(y); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Construct 9\n"; + UNORDERED_SUB_TEST("Construct 9") { test::check_instances check_; @@ -320,7 +320,7 @@ void constructor_tests2(T*, test::random_generator const& generator) #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) std::initializer_list list; - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer list construct 1\n"; + UNORDERED_SUB_TEST("Initializer list construct 1") { test::check_instances check_; @@ -331,7 +331,7 @@ void constructor_tests2(T*, test::random_generator const& generator) BOOST_TEST(test::equivalent(x.get_allocator(), al)); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer list construct 2\n"; + UNORDERED_SUB_TEST("Initializer list construct 2") { test::check_instances check_; @@ -343,7 +343,7 @@ void constructor_tests2(T*, test::random_generator const& generator) BOOST_TEST(test::equivalent(x.get_allocator(), al)); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer list construct 3\n"; + UNORDERED_SUB_TEST("Initializer list construct 3") { test::check_instances check_; @@ -355,7 +355,7 @@ void constructor_tests2(T*, test::random_generator const& generator) BOOST_TEST(test::equivalent(x.get_allocator(), al)); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer list construct 4\n"; + UNORDERED_SUB_TEST("Initializer list construct 4") { test::check_instances check_; @@ -367,7 +367,7 @@ void constructor_tests2(T*, test::random_generator const& generator) BOOST_TEST(test::equivalent(x.get_allocator(), al)); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer list construct 5\n"; + UNORDERED_SUB_TEST("Initializer list construct 5") { test::check_instances check_; @@ -384,8 +384,6 @@ void constructor_tests2(T*, test::random_generator const& generator) template void map_constructor_test(T*, test::random_generator const& generator) { - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "map_constructor_test\n"; - typedef test::list > list; @@ -429,7 +427,6 @@ UNORDERED_TEST(map_constructor_test, UNORDERED_AUTO_TEST(test_default_initializer_list) { - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n"; std::initializer_list init; boost::unordered_set x1 = init; BOOST_TEST(x1.empty()); @@ -441,7 +438,6 @@ UNORDERED_AUTO_TEST(test_default_initializer_list) UNORDERED_AUTO_TEST(test_initializer_list) { - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n"; boost::unordered_set x1 = {2, 10, 45, -5}; BOOST_TEST(x1.find(10) != x1.end()); BOOST_TEST(x1.find(46) == x1.end()); @@ -450,4 +446,4 @@ UNORDERED_AUTO_TEST(test_initializer_list) #endif } -RUN_TESTS() +RUN_TESTS_QUIET() diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index fb4f78d9..26141d0e 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -33,9 +33,7 @@ void unique_insert_tests1(X*, test::random_generator generator) typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; typedef test::ordered ordered; - BOOST_LIGHTWEIGHT_TEST_OSTREAM - << "insert(value) tests for containers with unique keys.\n"; - + UNORDERED_SUB_TEST("insert(value) tests for containers with unique keys") { X x; test::ordered tracker = test::create_ordered(x); @@ -67,9 +65,7 @@ void unique_insert_tests1(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM - << "insert(rvalue) tests for containers with unique keys.\n"; - + UNORDERED_SUB_TEST("insert(rvalue) tests for containers with unique keys") { X x; test::ordered tracker = test::create_ordered(x); @@ -108,9 +104,8 @@ void equivalent_insert_tests1(X*, test::random_generator generator) { test::check_instances check_; - BOOST_LIGHTWEIGHT_TEST_OSTREAM - << "insert(value) tests for containers with equivalent keys.\n"; - + UNORDERED_SUB_TEST( + "insert(value) tests for containers with equivalent keys") { X x; test::ordered tracker = test::create_ordered(x); @@ -139,9 +134,8 @@ void equivalent_insert_tests1(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM - << "insert(rvalue) tests for containers with equivalent keys.\n"; - + UNORDERED_SUB_TEST( + "insert(rvalue) tests for containers with equivalent keys") { X x; test::ordered tracker = test::create_ordered(x); @@ -180,8 +174,7 @@ template void insert_tests2(X*, test::random_generator generator) typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator; typedef BOOST_DEDUCED_TYPENAME tracker_type::iterator tracker_iterator; - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert(begin(), value) tests.\n"; - + UNORDERED_SUB_TEST("insert(begin(), value) tests") { test::check_instances check_; @@ -210,8 +203,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert(end(), value) tests.\n"; - + UNORDERED_SUB_TEST("insert(end(), value) tests") { test::check_instances check_; @@ -241,8 +233,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert(pos, value) tests.\n"; - + UNORDERED_SUB_TEST("insert(pos, value) tests") { test::check_instances check_; @@ -272,8 +263,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert(pos, rvalue) tests.\n"; - + UNORDERED_SUB_TEST("insert(pos, rvalue) tests") { test::check_instances check_; @@ -304,8 +294,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert single item range tests.\n"; - + UNORDERED_SUB_TEST("insert single item range tests") { test::check_instances check_; @@ -333,8 +322,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert range tests.\n"; - + UNORDERED_SUB_TEST("insert range tests") { test::check_instances check_; @@ -347,8 +335,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert range with rehash tests.\n"; - + UNORDERED_SUB_TEST("insert range with rehash tests") { test::check_instances check_; @@ -365,8 +352,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert input iterator range tests.\n"; - + UNORDERED_SUB_TEST("insert input iterator range tests") { test::check_instances check_; @@ -382,8 +368,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert copy iterator range tests.\n"; - + UNORDERED_SUB_TEST("insert copy iterator range tests") { test::check_instances check_; @@ -396,8 +381,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert copy iterator range test 2.\n"; - + UNORDERED_SUB_TEST("insert copy iterator range test 2") { test::check_instances check_; @@ -413,8 +397,7 @@ template void insert_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert various ranges.\n"; - + UNORDERED_SUB_TEST("insert various ranges") { for (int i = 0; i < 100; ++i) { X x; @@ -460,9 +443,6 @@ void unique_emplace_tests1(X*, test::random_generator generator) typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; typedef test::ordered ordered; - BOOST_LIGHTWEIGHT_TEST_OSTREAM - << "emplace(value) tests for containers with unique keys.\n"; - X x; test::ordered tracker = test::create_ordered(x); @@ -495,9 +475,6 @@ void unique_emplace_tests1(X*, test::random_generator generator) template void equivalent_emplace_tests1(X*, test::random_generator generator) { - BOOST_LIGHTWEIGHT_TEST_OSTREAM - << "emplace(value) tests for containers with equivalent keys.\n"; - X x; test::ordered tracker = test::create_ordered(x); @@ -526,9 +503,6 @@ void equivalent_emplace_tests1(X*, test::random_generator generator) template void move_emplace_tests(X*, test::random_generator generator) { - BOOST_LIGHTWEIGHT_TEST_OSTREAM - << "emplace(move(value)) tests for containers with unique keys.\n"; - X x; test::ordered tracker = test::create_ordered(x); @@ -557,7 +531,6 @@ template 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)) - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "emplace() tests.\n"; bool is_unique = test::has_unique_keys::value; X x; @@ -592,8 +565,6 @@ template void default_emplace_tests(X*, test::random_generator) template void map_tests(X*, test::random_generator generator) { - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "map tests.\n"; - X x; test::ordered tracker = test::create_ordered(x); @@ -620,8 +591,8 @@ template void map_tests(X*, test::random_generator generator) template void map_tests2(X*, test::random_generator generator) { typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert_or_assign\n"; + UNORDERED_SUB_TEST("insert_or_assign") { test::check_instances check_; @@ -652,8 +623,7 @@ template void map_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert_or_assign(begin)\n"; - + UNORDERED_SUB_TEST("insert_or_assign(begin)") { test::check_instances check_; @@ -683,8 +653,7 @@ template void map_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert_or_assign(end)\n"; - + UNORDERED_SUB_TEST("insert_or_assign(end)") { test::check_instances check_; @@ -714,8 +683,7 @@ template void map_tests2(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "insert_or_assign(last)\n"; - + UNORDERED_SUB_TEST("insert_or_assign(last)") { test::check_instances check_; @@ -751,10 +719,9 @@ template void map_tests2(X*, test::random_generator generator) template void try_emplace_tests(X*, test::random_generator generator) { - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "try_emplace(key, value)\n"; - typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; + UNORDERED_SUB_TEST("try_emplace(key, value)") { test::check_instances check_; @@ -794,10 +761,9 @@ template void try_emplace_tests(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "try_emplace(begin(), key, value)\n"; - typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; + UNORDERED_SUB_TEST("try_emplace(begin(), key, value)") { test::check_instances check_; @@ -834,10 +800,9 @@ template void try_emplace_tests(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "try_emplace(end(), key, value)\n"; - typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; + UNORDERED_SUB_TEST("try_emplace(end(), key, value)") { test::check_instances check_; @@ -874,10 +839,9 @@ template void try_emplace_tests(X*, test::random_generator generator) test::check_equivalent_keys(x); } - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "try_emplace(pos, key, value)\n"; - typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; + UNORDERED_SUB_TEST("try_emplace(pos, key, value)") { test::check_instances check_; @@ -920,8 +884,6 @@ template void try_emplace_tests(X*, test::random_generator generator) template void map_insert_range_test1(X*, test::random_generator generator) { - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "map_insert_range_test1\n"; - test::check_instances check_; typedef test::list void map_insert_range_test2(X*, test::random_generator generator) { - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "map_insert_range_test2\n"; - test::check_instances check_; typedef test::list Date: Wed, 10 May 2017 19:02:47 +0100 Subject: [PATCH 136/147] Move test state + functions into single class --- test/helpers/test.hpp | 125 +++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 64 deletions(-) diff --git a/test/helpers/test.hpp b/test/helpers/test.hpp index 617946c7..4b94ef5d 100644 --- a/test/helpers/test.hpp +++ b/test/helpers/test.hpp @@ -16,7 +16,7 @@ BOOST_PP_CAT(x, _type) \ () : ::test::registered_test_base(BOOST_PP_STRINGIZE(x)) \ { \ - ::test::test_list::add_test(this); \ + ::test::get_state().add_test(this); \ } \ void run(); \ }; \ @@ -27,7 +27,7 @@ int main(int, char**) \ { \ BOOST_UNORDERED_TEST_COMPILER_INFO() \ - ::test::test_list::run_tests(); \ + ::test::get_state().run_tests(); \ return boost::report_errors(); \ } @@ -35,43 +35,18 @@ int main(int, char**) \ { \ BOOST_UNORDERED_TEST_COMPILER_INFO() \ - ::test::test_list::run_tests(true); \ + ::test::get_state().run_tests(true); \ return boost::report_errors(); \ } #define UNORDERED_SUB_TEST(x) \ - for (int UNORDERED_SUB_TEST_VALUE = ::test::start_sub_test(x); \ + for (int UNORDERED_SUB_TEST_VALUE = ::test::get_state().start_sub_test(x); \ UNORDERED_SUB_TEST_VALUE; \ UNORDERED_SUB_TEST_VALUE = \ - ::test::end_sub_test(x, UNORDERED_SUB_TEST_VALUE)) + ::test::get_state().end_sub_test(x, UNORDERED_SUB_TEST_VALUE)) namespace test { -static inline bool& is_quiet() -{ - static bool value = false; - return value; -} - -static inline int start_sub_test(char const* name) -{ - if (!is_quiet()) { - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Sub-test: " << name << "\n" - << std::flush; - } - // Add one because it's used as a loop condition. - return boost::detail::test_errors() + 1; -} - -static inline int end_sub_test(char const* name, int value) -{ - if (is_quiet() && value != boost::detail::test_errors() + 1) { - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in sub-test: " << name << "\n" - << std::flush; - } - return 0; -} - struct registered_test_base { registered_test_base* next; @@ -81,48 +56,70 @@ struct registered_test_base virtual ~registered_test_base() {} }; -namespace test_list { -static inline registered_test_base*& first() +struct state { - static registered_test_base* ptr = 0; - return ptr; -} + bool is_quiet; + registered_test_base* first_test; + registered_test_base* last_test; -static inline registered_test_base*& last() -{ - static registered_test_base* ptr = 0; - return ptr; -} + state() : is_quiet(false), first_test(0), last_test(0) {} -static inline void add_test(registered_test_base* test) -{ - if (last()) { - last()->next = test; - } else { - first() = test; + void add_test(registered_test_base* test) + { + if (last_test) { + last_test->next = test; + } else { + first_test = test; + } + last_test = test; } - last() = test; -} + void run_tests(bool quiet = false) + { + is_quiet = quiet; -static inline void run_tests(bool quiet = false) -{ - test::is_quiet() = quiet; - - for (registered_test_base* i = first(); i; i = i->next) { - int error_count = boost::detail::test_errors(); - if (!quiet) { - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Running " << i->name << "\n" - << std::flush; - } - i->run(); - BOOST_LIGHTWEIGHT_TEST_OSTREAM << std::flush; - if (quiet && error_count != boost::detail::test_errors()) { - BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in: " << i->name << "\n" - << std::flush; + for (registered_test_base* i = first_test; i; i = i->next) { + int error_count = boost::detail::test_errors(); + if (!quiet) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Running " << i->name << "\n" + << std::flush; + } + i->run(); + BOOST_LIGHTWEIGHT_TEST_OSTREAM << std::flush; + if (quiet && error_count != boost::detail::test_errors()) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in: " << i->name + << "\n" + << std::flush; + } } } -} + + int start_sub_test(char const* name) + { + if (!is_quiet) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Sub-test: " << name << "\n" + << std::flush; + } + // Add one because it's used as a loop condition. + return boost::detail::test_errors() + 1; + } + + int end_sub_test(char const* name, int value) + { + if (is_quiet && value != boost::detail::test_errors() + 1) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in sub-test: " << name + << "\n" + << std::flush; + } + return 0; + } +}; + +// Get the currnet translation unit's test state. +static inline state& get_state() +{ + static state instance; + return instance; } } From a897843f6c5495f8e90aaaed82884ee0dc29ef7e Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 11 May 2017 00:36:31 +0100 Subject: [PATCH 137/147] Try to work around an MSVC bug Although, perhaps I shouldn't be generating over 1000 runs for a test. --- test/helpers/test.hpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/helpers/test.hpp b/test/helpers/test.hpp index 4b94ef5d..eaaa83f1 100644 --- a/test/helpers/test.hpp +++ b/test/helpers/test.hpp @@ -190,12 +190,16 @@ static inline state& get_state() BOOST_PP_SEQ_ELEM(1, product), \ BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_TAIL(product))) +// Need to wrap UNORDERED_SUB_TEST in a block to avoid an msvc bug. +// https://support.microsoft.com/en-gb/help/315481/bug-too-many-unnested-loops-incorrectly-causes-a-c1061-compiler-error-in-visual-c #define UNORDERED_MULTI_TEST_OP2(name, n, params) \ - UNORDERED_SUB_TEST(BOOST_PP_STRINGIZE( \ - BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params))) \ { \ - for (int i = 0; i < n; ++i) \ - name BOOST_PP_SEQ_TO_TUPLE(params); \ + UNORDERED_SUB_TEST(BOOST_PP_STRINGIZE( \ + BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params))) \ + { \ + for (int i = 0; i < n; ++i) \ + name BOOST_PP_SEQ_TO_TUPLE(params); \ + } \ } #endif From 12ee29579d4cc11fcc69b0b3c010b799b515e245 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 12 May 2017 11:10:34 +0100 Subject: [PATCH 138/147] Don't use full construction on Sun C++ w. libstdc++ There's an exception safety issue. Which is a pity as other than that it seems fine. I'd assumed that support would be pretty good on all C++11 compilers, so I made it an 'all or nothing' feature, partly because there are issues with pre-C++11 allocators, but this suggests partial support might be desirable. Not sure I'll be able to (or want to) put the time in though. --- include/boost/unordered/detail/implementation.hpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 0d3128a5..5368320d 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -75,7 +75,7 @@ // 2 = boost::container::allocator_traits #if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS) -#if !defined(BOOST_NO_CXX11_ALLOCATOR) && !BOOST_COMP_SUNPRO +#if !defined(BOOST_NO_CXX11_ALLOCATOR) #define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1 #elif defined(BOOST_MSVC) #if BOOST_MSVC < 1400 @@ -98,7 +98,12 @@ #if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT && \ !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) -#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 && !defined(BOOST_NO_SFINAE_EXPR) +#if BOOST_COMP_SUNPRO && BOOST_LIB_STD_GNU +// Sun C++ std::pair piecewise construction doesn't seem to be exception safe. +// (At least for Sun C++ 12.5 using libstdc++). +#define BOOST_UNORDERED_CXX11_CONSTRUCTION 0 +#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 && \ + !defined(BOOST_NO_SFINAE_EXPR) #define BOOST_UNORDERED_CXX11_CONSTRUCTION 1 #elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 #define BOOST_UNORDERED_CXX11_CONSTRUCTION 1 From dc611fc8282024b95bcd1de6963a7805adb5a1ad Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 May 2017 02:52:59 +0100 Subject: [PATCH 139/147] Run fewer test in merge_exception_tests It's timing out on some platforms because it's too slow. This reduces the tag combinations for 9 to 3, which should reduce the execution time by a third. Also slightly reduces the count combinations, but that won't make much of a difference really - the slowest tests are still there (when the right hand side is large). --- test/exception/merge_exception_tests.cpp | 33 ++++++++++-------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/test/exception/merge_exception_tests.cpp b/test/exception/merge_exception_tests.cpp index 442e364f..48f6b697 100644 --- a/test/exception/merge_exception_tests.cpp +++ b/test/exception/merge_exception_tests.cpp @@ -30,10 +30,13 @@ template void merge_exception_test(T1 x, T2 y) } template -void merge_exception_test(T1 const*, T2 const*, std::size_t count1, - std::size_t count2, int tag1, int tag2, test::random_generator gen1, - test::random_generator gen2) +void merge_exception_test(T1 const*, T2 const*, std::size_t count12, int tag12, + test::random_generator gen1, test::random_generator gen2) { + std::size_t count1 = count12 / 256; + std::size_t count2 = count12 % 256; + int tag1 = tag12 / 256; + int tag2 = tag12 % 256; test::random_values v1(count1, gen1); test::random_values v2(count2, gen2); T1 x(v1.begin(), v1.end(), 0, test::exception::hash(tag1), @@ -65,20 +68,16 @@ using test::limited_range; UNORDERED_MULTI_TEST(set_merge, merge_exception_test, ((test_set_)(test_multiset_)) ((test_set_)(test_multiset_)) - ((0)(10)(100)) - ((0)(10)(100)) - ((0)(1)(2)) - ((0)(1)(2)) + ((0x0000)(0x6400)(0x0064)(0x0a64)(0x3232)) + ((0x0000)(0x0001)(0x0102)) ((default_generator)(limited_range)) ((default_generator)(limited_range)) ) UNORDERED_MULTI_TEST(map_merge, merge_exception_test, ((test_map_)(test_multimap_)) ((test_map_)(test_multimap_)) - ((0)(10)(100)) - ((0)(10)(100)) - ((0)(1)(2)) - ((0)(1)(2)) + ((0x0000)(0x6400)(0x0064)(0x0a64)(0x3232)) + ((0x0101)(0x0200)(0x0201)) ((default_generator)(limited_range)) ((default_generator)(limited_range)) ) @@ -86,20 +85,16 @@ UNORDERED_MULTI_TEST(map_merge, merge_exception_test, UNORDERED_MULTI_TEST(set_merge_collisions, merge_exception_test, ((test_set_)(test_multiset_)) ((test_set_)(test_multiset_)) - ((10)) - ((10)) - ((0)(1)(2)) - ((0)(1)(2)) + ((0x0a0a)) + ((0x0202)(0x0100)(0x0201)) ((generate_collisions)) ((generate_collisions)) ) UNORDERED_MULTI_TEST(map_merge_collisions, merge_exception_test, ((test_map_)(test_multimap_)) ((test_map_)(test_multimap_)) - ((10)) - ((10)) - ((0)(1)(2)) - ((0)(1)(2)) + ((0x0a0a)) + ((0x0000)(0x0002)(0x0102)) ((generate_collisions)) ((generate_collisions)) ) From 6fffc738f78e3a748b268fc9112d3beea82fa8fc Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 16 May 2017 18:15:56 +0100 Subject: [PATCH 140/147] Require std::tuple for full C++11 construction --- .../boost/unordered/detail/implementation.hpp | 52 +++++++++---------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 5368320d..a55afddb 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -90,34 +90,6 @@ #define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0 #endif -// BOOST_UNORDERED_CXX11_CONSTRUCTION -// -// Use C++11 construction, requires variadic arguments, good construct support -// in allocator_traits and piecewise construction of std::pair -// Otherwise allocators aren't used for construction/destruction - -#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT && \ - !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) -#if BOOST_COMP_SUNPRO && BOOST_LIB_STD_GNU -// Sun C++ std::pair piecewise construction doesn't seem to be exception safe. -// (At least for Sun C++ 12.5 using libstdc++). -#define BOOST_UNORDERED_CXX11_CONSTRUCTION 0 -#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 && \ - !defined(BOOST_NO_SFINAE_EXPR) -#define BOOST_UNORDERED_CXX11_CONSTRUCTION 1 -#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 -#define BOOST_UNORDERED_CXX11_CONSTRUCTION 1 -#endif -#endif - -#if !defined(BOOST_UNORDERED_CXX11_CONSTRUCTION) -#define BOOST_UNORDERED_CXX11_CONSTRUCTION 0 -#endif - -// -// Other configuration macros -// - // BOOST_UNORDERED_TUPLE_ARGS // // Maximum number of std::tuple members to support, or 0 if std::tuple @@ -158,6 +130,30 @@ #include #endif +// BOOST_UNORDERED_CXX11_CONSTRUCTION +// +// Use C++11 construction, requires variadic arguments, good construct support +// in allocator_traits and piecewise construction of std::pair +// Otherwise allocators aren't used for construction/destruction + +#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT && \ + !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && BOOST_UNORDERED_TUPLE_ARGS +#if BOOST_COMP_SUNPRO && BOOST_LIB_STD_GNU +// Sun C++ std::pair piecewise construction doesn't seem to be exception safe. +// (At least for Sun C++ 12.5 using libstdc++). +#define BOOST_UNORDERED_CXX11_CONSTRUCTION 0 +#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 && \ + !defined(BOOST_NO_SFINAE_EXPR) +#define BOOST_UNORDERED_CXX11_CONSTRUCTION 1 +#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 +#define BOOST_UNORDERED_CXX11_CONSTRUCTION 1 +#endif +#endif + +#if !defined(BOOST_UNORDERED_CXX11_CONSTRUCTION) +#define BOOST_UNORDERED_CXX11_CONSTRUCTION 0 +#endif + // BOOST_UNORDERED_SUPPRESS_DEPRECATED // // Define to stop deprecation attributes From ee9a5a2c77f28009a1c8c917079087a9533ea655 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 16 May 2017 18:23:23 +0100 Subject: [PATCH 141/147] Add a configuration macro for Sun C++ workarounds --- .../boost/unordered/detail/implementation.hpp | 23 +++++++++++++++---- include/boost/unordered/unordered_map.hpp | 8 +++---- include/boost/unordered/unordered_set.hpp | 8 +++---- test/unordered/insert_tests.cpp | 8 +++---- test/unordered/unnecessary_copy_tests.cpp | 4 ++-- 5 files changed, 32 insertions(+), 19 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index a55afddb..f70e6fbf 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -59,6 +59,19 @@ // Unless documented elsewhere these configuration macros should be considered // an implementation detail, I'll try not to break them, but you never know. +// Use Sun C++ workarounds +// I'm not sure which versions of the compiler require these workarounds, so +// I'm just using them of everything older than the current test compilers +// (as of May 2017). + +#if !defined(BOOST_UNORDERED_SUN_WORKAROUNDS1) +#if BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0) +#define BOOST_UNORDERED_SUN_WORKAROUNDS1 1 +#else +#define BOOST_UNORDERED_SUN_WORKAROUNDS1 0 +#endif +#endif + // BOOST_UNORDERED_EMPLACE_LIMIT = The maximum number of parameters in // emplace (not including things like hints). Don't set it to a lower value, as // that might break something. @@ -100,7 +113,7 @@ // I had problems with tuples on older versions of the sunpro. // Might be fixed in an earlier version than I specified here. -#elif BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0) +#elif BOOST_UNORDERED_SUN_WORKAROUNDS1 #define BOOST_UNORDERED_TUPLE_ARGS 0 // Assume if we have C++11 tuple it's properly variadic, @@ -270,7 +283,7 @@ template struct prime_list_template { static std::size_t const value[]; -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 static std::ptrdiff_t const length; #else static std::ptrdiff_t const length = @@ -282,7 +295,7 @@ template std::size_t const prime_list_template::value[] = { BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES)}; -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 template std::ptrdiff_t const prime_list_template::length = BOOST_PP_SEQ_SIZE( BOOST_UNORDERED_PRIMES); @@ -1336,7 +1349,7 @@ inline void construct_value(T* address, BOOST_FWD_REF(A0) a0) // // Used to emulate piecewise construction. -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 #define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(z, n, namespace_) \ template struct length { diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 25c731ec..c8bd5bb4 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -230,7 +230,7 @@ template class unordered_map #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 // 0 argument emplace requires special treatment in case // the container is instantiated with a value type that @@ -292,7 +292,7 @@ template class unordered_map #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = @@ -1031,7 +1031,7 @@ template class unordered_multimap #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 // 0 argument emplace requires special treatment in case // the container is instantiated with a value type that @@ -1091,7 +1091,7 @@ template class unordered_multimap #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 80137565..f2be1176 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -228,7 +228,7 @@ template class unordered_set #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 // 0 argument emplace requires special treatment in case // the container is instantiated with a value type that @@ -290,7 +290,7 @@ template class unordered_set #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = @@ -737,7 +737,7 @@ template class unordered_multiset #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 // 0 argument emplace requires special treatment in case // the container is instantiated with a value type that @@ -797,7 +797,7 @@ template class unordered_multiset #else -#if !(BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 iterator emplace_hint(const_iterator hint, boost::unordered::detail::empty_emplace = diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 26141d0e..3f68d316 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -530,7 +530,7 @@ template 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)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 bool is_unique = test::has_unique_keys::value; X x; @@ -1108,7 +1108,7 @@ UNORDERED_AUTO_TEST(map_emplace_test) test::allocator1 > > x; -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 x.emplace(); BOOST_TEST(x.find(0) != x.end() && x.find(0)->second == overloaded_constructor()); @@ -1129,7 +1129,7 @@ UNORDERED_AUTO_TEST(map_emplace_test) test::allocator1 > > x; -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 x.emplace(); BOOST_TEST(x.find(0) != x.end() && x.find(0)->second == overloaded_constructor()); @@ -1146,7 +1146,7 @@ UNORDERED_AUTO_TEST(set_emplace_test) boost::unordered_set x; overloaded_constructor check; -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 x.emplace(); BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); #endif diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index 0322eade..1e22dd66 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -362,7 +362,7 @@ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test) // 0 arguments // -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 // The container will have to create a copy in order to compare with // the existing element. reset(); @@ -451,7 +451,7 @@ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_map_test) // 0 arguments // -#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 // COPY_COUNT(1) would be okay here. reset(); x.emplace(); From e0227618bba0bbc92cf008736a28f0b3d231c8a7 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 17 May 2017 16:46:56 +0100 Subject: [PATCH 142/147] Move a few things around to match the order in the standard --- include/boost/unordered/unordered_map.hpp | 106 +++++++++++----------- include/boost/unordered/unordered_set.hpp | 18 ++-- 2 files changed, 60 insertions(+), 64 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index c8bd5bb4..30ebe4cd 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -45,8 +45,8 @@ template class unordered_map public: typedef K key_type; - typedef std::pair value_type; typedef T mapped_type; + typedef std::pair value_type; typedef H hasher; typedef P key_equal; typedef A allocator_type; @@ -68,10 +68,10 @@ template class unordered_map typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef typename table::cl_iterator const_local_iterator; - typedef typename table::l_iterator local_iterator; - typedef typename table::c_iterator const_iterator; typedef typename table::iterator iterator; + typedef typename table::c_iterator const_iterator; + typedef typename table::l_iterator local_iterator; + typedef typename table::cl_iterator const_local_iterator; typedef typename types::node_type node_type; typedef typename types::insert_return_type insert_return_type; @@ -463,14 +463,6 @@ template class unordered_map return table_.try_emplace_unique(k, boost::forward(args)...); } - template - iterator try_emplace( - const_iterator hint, key_type const& k, BOOST_FWD_REF(Args)... args) - { - return table_.try_emplace_hint_unique( - hint, k, boost::forward(args)...); - } - template std::pair try_emplace( BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) @@ -479,6 +471,14 @@ template class unordered_map boost::move(k), boost::forward(args)...); } + template + iterator try_emplace( + const_iterator hint, key_type const& k, BOOST_FWD_REF(Args)... args) + { + return table_.try_emplace_hint_unique( + hint, k, boost::forward(args)...); + } + template iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) @@ -539,36 +539,6 @@ template class unordered_map boost::forward(a2))); } - // try_emplace(const_iterator hint, key const&, Args&&...) - - template - iterator try_emplace( - const_iterator hint, key_type const& k, BOOST_FWD_REF(A0) a0) - { - return table_.try_emplace_hint_unique( - hint, k, boost::unordered::detail::create_emplace_args( - boost::forward(a0))); - } - - template - iterator try_emplace(const_iterator hint, key_type const& k, - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) - { - return table_.try_emplace_hint_unique( - hint, k, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1))); - } - - template - iterator try_emplace(const_iterator hint, key_type const& k, - BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) - { - return table_.try_emplace_hint_unique( - hint, k, boost::unordered::detail::create_emplace_args( - boost::forward(a0), boost::forward(a1), - boost::forward(a2))); - } - // try_emplace(key&&, Args&&...) template @@ -600,6 +570,36 @@ template class unordered_map boost::forward(a2))); } + // try_emplace(const_iterator hint, key const&, Args&&...) + + template + iterator try_emplace( + const_iterator hint, key_type const& k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_hint_unique( + hint, k, boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + iterator try_emplace(const_iterator hint, key_type const& k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_hint_unique( + hint, k, boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + + template + iterator try_emplace(const_iterator hint, key_type const& k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.try_emplace_hint_unique( + hint, k, boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1), + boost::forward(a2))); + } + // try_emplace(const_iterator hint, key&&, Args&&...) template @@ -644,19 +644,19 @@ template class unordered_map } \ \ template \ - iterator try_emplace(const_iterator hint, key_type const& k, \ + std::pair try_emplace(BOOST_RV_REF(key_type) k, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.try_emplace_hint_unique(hint, k, \ + return table_.try_emplace_unique(boost::move(k), \ boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } \ \ template \ - std::pair try_emplace(BOOST_RV_REF(key_type) k, \ + iterator try_emplace(const_iterator hint, key_type const& k, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.try_emplace_unique(boost::move(k), \ + return table_.try_emplace_hint_unique(hint, k, \ boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } \ @@ -822,9 +822,8 @@ template class unordered_map // hash policy - float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } - float load_factor() const BOOST_NOEXCEPT; + float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } void max_load_factor(float) BOOST_NOEXCEPT; void rehash(size_type); void reserve(size_type); @@ -847,8 +846,8 @@ template class unordered_multimap public: typedef K key_type; - typedef std::pair value_type; typedef T mapped_type; + typedef std::pair value_type; typedef H hasher; typedef P key_equal; typedef A allocator_type; @@ -870,10 +869,10 @@ template class unordered_multimap typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef typename table::cl_iterator const_local_iterator; - typedef typename table::l_iterator local_iterator; - typedef typename table::c_iterator const_iterator; typedef typename table::iterator iterator; + typedef typename table::c_iterator const_iterator; + typedef typename table::l_iterator local_iterator; + typedef typename table::cl_iterator const_local_iterator; typedef typename types::node_type node_type; private: @@ -1352,9 +1351,8 @@ template class unordered_multimap // hash policy - float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } - float load_factor() const BOOST_NOEXCEPT; + float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } void max_load_factor(float) BOOST_NOEXCEPT; void rehash(size_type); void reserve(size_type); diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index f2be1176..03bcf9a4 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -66,10 +66,10 @@ template class unordered_set typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef typename table::cl_iterator const_local_iterator; - typedef typename table::l_iterator local_iterator; - typedef typename table::c_iterator const_iterator; typedef typename table::iterator iterator; + typedef typename table::c_iterator const_iterator; + typedef typename table::l_iterator local_iterator; + typedef typename table::cl_iterator const_local_iterator; typedef typename types::node_type node_type; typedef typename types::insert_return_type insert_return_type; @@ -529,9 +529,8 @@ template class unordered_set // hash policy - float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } - float load_factor() const BOOST_NOEXCEPT; + float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } void max_load_factor(float) BOOST_NOEXCEPT; void rehash(size_type); void reserve(size_type); @@ -576,10 +575,10 @@ template class unordered_multiset typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef typename table::cl_iterator const_local_iterator; - typedef typename table::l_iterator local_iterator; - typedef typename table::c_iterator const_iterator; typedef typename table::iterator iterator; + typedef typename table::c_iterator const_iterator; + typedef typename table::l_iterator local_iterator; + typedef typename table::cl_iterator const_local_iterator; typedef typename types::node_type node_type; private: @@ -1032,9 +1031,8 @@ template class unordered_multiset // hash policy - float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } - float load_factor() const BOOST_NOEXCEPT; + float max_load_factor() const BOOST_NOEXCEPT { return table_.mlf_; } void max_load_factor(float) BOOST_NOEXCEPT; void rehash(size_type); void reserve(size_type); From 4f5a2dabe924168fae63d59b55d4d4bc6d3ac993 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 19 May 2017 08:46:54 +0100 Subject: [PATCH 143/147] Try to fix std::tuple on old Sun compilers In order to use the workaround for both `boost::tuple` and `std::tuple` the function would need to detect which was being used, in order to decide whether to use `boost::tuples::length` or `std::tuple_size`. Probably not difficult, but I don't have any way to test an implementation. So instead Just assume that if `std::tuple` is available it will work without any workaround. Presumably once the compiler was able to support `std::tuple` it will also support the necessary overloads. I've left the version check as 5.21 so that failures will still show up in the tests, but I'm sure it can be 5.20 and probably earlier. Will change before release. --- .../boost/unordered/detail/implementation.hpp | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index f70e6fbf..a681f9a3 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -111,11 +111,6 @@ // Already defined, so do nothing #if defined(BOOST_UNORDERED_TUPLE_ARGS) -// I had problems with tuples on older versions of the sunpro. -// Might be fixed in an earlier version than I specified here. -#elif BOOST_UNORDERED_SUN_WORKAROUNDS1 -#define BOOST_UNORDERED_TUPLE_ARGS 0 - // Assume if we have C++11 tuple it's properly variadic, // and just use a max number of 10 arguments. #elif !defined(BOOST_NO_CXX11_HDR_TUPLE) @@ -1349,8 +1344,6 @@ inline void construct_value(T* address, BOOST_FWD_REF(A0) a0) // // Used to emulate piecewise construction. -#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 - #define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(z, n, namespace_) \ template \ @@ -1364,6 +1357,9 @@ inline void construct_value(T* address, BOOST_FWD_REF(A0) a0) #define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_::get(x) // construct_from_tuple for boost::tuple +// The workaround for old Sun compilers comes later in the file. + +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 template void construct_from_tuple(Alloc&, T* ptr, boost::tuple<>) @@ -1382,6 +1378,8 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 8, boost) BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 9, boost) BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(1, 10, boost) +#endif + // construct_from_tuple for std::tuple #if !BOOST_UNORDERED_CXX11_CONSTRUCTION && BOOST_UNORDERED_TUPLE_ARGS @@ -1408,7 +1406,14 @@ BOOST_PP_REPEAT_FROM_TO(6, BOOST_PP_INC(BOOST_UNORDERED_TUPLE_ARGS), #undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE #undef BOOST_UNORDERED_GET_TUPLE_ARG -#else // BOOST_UNORDERED_SUN_WORKAROUNDS1 +// construct_from_tuple for boost::tuple on old versions of sunpro. +// +// Old versions of Sun C++ had problems with template overloads of +// boost::tuple, so to fix it I added a distinct type for each length to +// the overloads. That means there's no possible ambiguity between the +// different overloads, so that the compiler doesn't get confused + +#if BOOST_UNORDERED_SUN_WORKAROUNDS1 template struct length { @@ -1427,8 +1432,6 @@ template struct length #define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) namespace_::get(x) -// construct_from_tuple for boost::tuple - template void construct_from_tuple_impl( boost::unordered::detail::func::length<0>, Alloc&, T* ptr, boost::tuple<>) From 5b97fbc29289745c6bea2ef74341992b060fc2a1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 19 May 2017 09:42:56 +0100 Subject: [PATCH 144/147] Make insert from node_handle move only on old GCC --- include/boost/unordered/unordered_map.hpp | 6 ++++-- include/boost/unordered/unordered_set.hpp | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 30ebe4cd..a0b4d532 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -445,7 +445,8 @@ template class unordered_map return table_.move_insert_node_type_with_hint_unique(hint, np); } -#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \ + (BOOST_COMP_GNUC && BOOST_COMP_GNUC < BOOST_VERSION_NUMBER(4, 6, 0)) private: // Note: Use r-value node_type to insert. insert_return_type insert(node_type&); @@ -1239,7 +1240,8 @@ template class unordered_multimap return table_.move_insert_node_type_with_hint_equiv(hint, np); } -#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \ + (BOOST_COMP_GNUC && BOOST_COMP_GNUC < BOOST_VERSION_NUMBER(4, 6, 0)) private: // Note: Use r-value node_type to insert. iterator insert(node_type&); diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 03bcf9a4..985742ff 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -425,7 +425,8 @@ template class unordered_set return table_.move_insert_node_type_with_hint_unique(hint, np); } -#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \ + (BOOST_COMP_GNUC && BOOST_COMP_GNUC < BOOST_VERSION_NUMBER(4, 6, 0)) private: // Note: Use r-value node_type to insert. insert_return_type insert(node_type&); @@ -927,7 +928,8 @@ template class unordered_multiset return table_.move_insert_node_type_with_hint_equiv(hint, np); } -#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \ + (BOOST_COMP_GNUC && BOOST_COMP_GNUC < BOOST_VERSION_NUMBER(4, 6, 0)) private: // Note: Use r-value node_type to insert. iterator insert(node_type&); From fc1604f2c8a1c3b28dd43d5202e58197796f8fff Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 19 May 2017 17:24:44 +0100 Subject: [PATCH 145/147] Don't use allocator_traits::construct on GCC 4.6 Piecewise construction doesn't work uncopyable types. --- include/boost/unordered/detail/implementation.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index a681f9a3..54333400 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -150,6 +150,9 @@ // Sun C++ std::pair piecewise construction doesn't seem to be exception safe. // (At least for Sun C++ 12.5 using libstdc++). #define BOOST_UNORDERED_CXX11_CONSTRUCTION 0 +#elif BOOST_COMP_GNUC && BOOST_COMP_GNUC < BOOST_VERSION_NUMBER(4, 7, 0) +// Piecewise construction in GCC 4.6 doesn't work for uncopyable types. +#define BOOST_UNORDERED_CXX11_CONSTRUCTION 0 #elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 && \ !defined(BOOST_NO_SFINAE_EXPR) #define BOOST_UNORDERED_CXX11_CONSTRUCTION 1 From 7775aa83df4504f3b5e5544a928cc644a51cc97d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 25 May 2017 08:53:34 +0100 Subject: [PATCH 146/147] Decrease the limit for SunOS workaround We have tests for 12.5 (5,20,0), and 12.5_next (5,21,0), I think both are good enough to not require workarounds. --- include/boost/unordered/detail/implementation.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 54333400..ecb05226 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -65,7 +65,7 @@ // (as of May 2017). #if !defined(BOOST_UNORDERED_SUN_WORKAROUNDS1) -#if BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 21, 0) +#if BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 20, 0) #define BOOST_UNORDERED_SUN_WORKAROUNDS1 1 #else #define BOOST_UNORDERED_SUN_WORKAROUNDS1 0 From 5190a5d7f88de7a3f0162147d14f7f90e8ee6209 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 4 Jun 2017 08:46:59 +0100 Subject: [PATCH 147/147] Stop dereferencing pointers to uninitialized memory It's undefined behaviour. Still happens for piecewise construction emultation for std::pair, I don't think there's anyway to avoid it. I had considered using offsetof to get a pointer to a member, but that's also undefined behaviour when a pair member doesn't have standard layout. Piecewise construction emulation has other problems anyway. So, this mostly fixes PR #5. I also stopped using addressof in self-asssignment checks as operator& is fine. --- include/boost/unordered/detail/fwd.hpp | 2 + .../boost/unordered/detail/implementation.hpp | 39 ++++++++++++------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 0e725d7c..2e0c6307 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -32,6 +32,8 @@ #endif #endif +// TODO: Use piecewise construction by default? Is it safe to assume that an +// unknown library has it? #if !defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT) #define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 0 #endif diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index ecb05226..5750a4c6 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1,4 +1,3 @@ - // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. // Copyright (C) 2005-2016 Daniel James // @@ -530,6 +529,18 @@ struct convert_from_anything template convert_from_anything(T const&); }; +// Get a pointer from a smart pointer, a bit simpler than pointer_traits +// as we already know the pointer type that we want. +template struct pointer +{ + template static T* get(Ptr const& x) + { + return static_cast(x.operator->()); + } + + template static T* get(T2* x) { return static_cast(x); } +}; + //////////////////////////////////////////////////////////////////////////// // emplace_args // @@ -563,7 +574,8 @@ struct convert_from_anything #endif -template struct emplace_args1 +template +struct emplace_args1 { BOOST_UNORDERED_EARGS_MEMBER(1, 0, _) @@ -1712,7 +1724,7 @@ template struct node_constructor template node_constructor::~node_constructor() { if (node_) { - boost::unordered::detail::func::destroy(boost::addressof(*node_)); + boost::unordered::detail::func::destroy(pointer::get(node_)); node_allocator_traits::deallocate(alloc_, node_, 1); } } @@ -1721,7 +1733,7 @@ template void node_constructor::create_node() { BOOST_ASSERT(!node_); node_ = node_allocator_traits::allocate(alloc_, 1); - new (boost::addressof(*node_)) node(); + new (pointer::get(node_)) node(); } template struct node_tmp @@ -1729,6 +1741,7 @@ template struct node_tmp typedef boost::unordered::detail::allocator_traits node_allocator_traits; typedef typename node_allocator_traits::pointer node_pointer; + typedef typename node_allocator_traits::value_type node; NodeAlloc& alloc_; node_pointer node_; @@ -1751,7 +1764,7 @@ template node_tmp::~node_tmp() if (node_) { BOOST_UNORDERED_CALL_DESTROY( node_allocator_traits, alloc_, node_->value_ptr()); - boost::unordered::detail::func::destroy(boost::addressof(*node_)); + boost::unordered::detail::func::destroy(pointer::get(node_)); node_allocator_traits::deallocate(alloc_, node_, 1); } } @@ -2260,7 +2273,7 @@ template node_holder::~node_holder() BOOST_UNORDERED_CALL_DESTROY( node_allocator_traits, constructor_.alloc_, p->value_ptr()); - boost::unordered::detail::func::destroy(boost::addressof(*p)); + boost::unordered::detail::func::destroy(pointer::get(p)); node_allocator_traits::deallocate(constructor_.alloc_, p, 1); } } @@ -2969,9 +2982,9 @@ struct table : boost::unordered::detail::functions(new_count); for (bucket_pointer i = buckets_; i != end; ++i) { - new (boost::addressof(*i)) bucket(); + new (pointer::get(i)) bucket(); } - new (boost::addressof(*end)) bucket(dummy_node); + new (pointer::get(end)) bucket(dummy_node); } //////////////////////////////////////////////////////////////////////// @@ -3037,7 +3050,7 @@ struct table : boost::unordered::detail::functionsvalue_ptr()); - boost::unordered::detail::func::destroy(boost::addressof(*n)); + boost::unordered::detail::func::destroy(pointer::get(n)); node_allocator_traits::deallocate(node_alloc(), n, 1); } @@ -3049,7 +3062,7 @@ struct table : boost::unordered::detail::functions::get(n)); node_allocator_traits::deallocate(node_alloc(), n, 1); n = next; } @@ -3071,7 +3084,7 @@ struct table : boost::unordered::detail::functions::get(it)); } bucket_allocator_traits::deallocate( @@ -3121,7 +3134,7 @@ struct table : boost::unordered::detail::functions void assign(table const& x, UniqueType is_unique) { - if (this != boost::addressof(x)) { + if (this != &x) { assign(x, is_unique, boost::unordered::detail::integral_constant:: @@ -3177,7 +3190,7 @@ struct table : boost::unordered::detail::functions void move_assign(table& x, UniqueType is_unique) { - if (this != boost::addressof(x)) { + if (this != &x) { move_assign( x, is_unique, boost::unordered::detail::integral_constant