From 09b239ed287e6b959d4739f047b4137fcafe08bc Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 10 May 2009 21:25:09 +0000 Subject: [PATCH] Merge emplace support for sandbox - but without move support. [SVN r52885] --- include/boost/unordered/detail/hash_table.hpp | 20 + .../unordered/detail/hash_table_impl.hpp | 392 +++++++++++++----- include/boost/unordered/unordered_map.hpp | 88 ++++ include/boost/unordered/unordered_set.hpp | 87 ++++ test/unordered/compile_tests.hpp | 8 - test/unordered/unnecessary_copy_tests.cpp | 62 ++- 6 files changed, 519 insertions(+), 138 deletions(-) diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index b6bd9aa6..bb4072c6 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -13,6 +13,10 @@ #include +#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT) +#define BOOST_UNORDERED_EMPLACE_LIMIT 5 +#endif + #include #include #include @@ -32,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +45,21 @@ #include +#if !(defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)) + +#include +#include +#include + +#define BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + BOOST_PP_ENUM_PARAMS_Z(z, n, typename Arg) +#define BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, const& arg) +#define BOOST_UNORDERED_CALL_PARAMS(z, n) \ + BOOST_PP_ENUM_PARAMS_Z(z, n, arg) + +#endif + #if BOOST_WORKAROUND(__BORLANDC__, <= 0x0582) #define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x) #else diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index ece2615e..81327302 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -183,15 +183,19 @@ namespace boost { void construct_preamble() { - BOOST_ASSERT(!node_); - node_constructed_ = false; - value_constructed_ = false; - - node_ = allocators_.node_alloc_.allocate(1); - - allocators_.node_alloc_.construct(node_, node()); - node_constructed_ = true; + if(!node_) { + node_constructed_ = false; + value_constructed_ = false; + node_ = allocators_.node_alloc_.allocate(1); + allocators_.node_alloc_.construct(node_, node()); + node_constructed_ = true; + } + else { + BOOST_ASSERT(node_constructed_ && value_constructed_); + BOOST_UNORDERED_DESTRUCT(&node_->value(), value_type); + value_constructed_ = false; + } } #if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) @@ -202,32 +206,134 @@ namespace boost { new(node_->address()) value_type(std::forward(args)...); value_constructed_ = true; } -#else - template - void construct(V const& v) + +#if defined(__GLIBCPP__) || defined(__GLIBCXX__) + // The GCC C++0x standard library implementation does not have + // a single argument pair constructor, so this works around that. + + template + void construct(Arg&& arg) { construct_preamble(); - new(node_->address()) value_type(v); + construct_impl(std::forward(arg), + (value_type const*) 0, + (typename boost::remove_reference::type const*) 0); value_constructed_ = true; } + + template < + typename Arg, + typename ValueType, + typename Type> + void construct_impl(Arg&& arg, ValueType const*, Type const*) + { + new(node_->address()) value_type(std::forward(arg)); + } + + template < + typename Arg, + typename ValueFirst, typename ValueSecond, + typename TypeFirst, typename TypeSecond> + void construct_impl( + Arg&& arg, + std::pair const*, + std::pair const*) + { + new(node_->address()) value_type(std::forward(arg)); + } + + template < + typename Arg, + typename ValueFirst, typename ValueSecond, + typename Type> + void construct_impl( + Arg&& arg, + std::pair const*, + Type const*) + { + new(node_->address()) value_type(std::forward(arg), ValueSecond()); + } #endif + +#else - template - void construct_pair(K const& k, M*) + void construct() { - BOOST_ASSERT(!node_); - node_constructed_ = false; - value_constructed_ = false; - - node_ = allocators_.node_alloc_.allocate(1); - - allocators_.node_alloc_.construct(node_, node()); - node_constructed_ = true; - - new(node_->address()) value_type(k, M()); + construct_preamble(); + new(node_->address()) value_type; value_constructed_ = true; } +#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + void construct( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + construct_preamble(); \ + construct_impl( \ + (value_type*) 0, \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + ); \ + value_constructed_ = true; \ + } \ + \ + template < \ + typename T, \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + void construct_impl( \ + T*, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + new(node_->address()) value_type( \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + ); \ + } \ + \ + +#define BOOST_UNORDERED_CONSTRUCT_IMPL2(z, n, _) \ + template \ + void construct_impl( \ + std::pair*, \ + Key const& k, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + new(node_->address()) value_type(k, \ + Second( \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + ) \ + ); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_CONSTRUCT_IMPL, _) + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_CONSTRUCT_IMPL2, _) + + template + void construct_impl(std::pair*, + std::pair const& arg0) + { + new(node_->address()) value_type(arg0); + } + + template + void construct_impl(std::pair*, Key const& k) + { + new(node_->address()) value_type(First(k), Second()); + } + +#undef BOOST_UNORDERED_CONSTRUCT_IMPL + +#endif + node_ptr get() const { BOOST_ASSERT(node_); @@ -1424,19 +1530,29 @@ namespace boost { } // 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. struct no_key { no_key() {} template no_key(T const&) {} }; - // no throw - + + // If emplace is called with no arguments then there obviously + // isn't an available key. + static no_key extract_key() { return no_key(); } + // Emplace or insert was called with the value type. + static key_type const& extract_key(value_type const& v) { return extract(v, (type_wrapper*)0); @@ -1454,6 +1570,9 @@ namespace boost { return v.first; } + // For maps, if emplace is called with just a key, then it's the value type + // with the second value default initialised. + template static BOOST_DEDUCED_TYPENAME boost::mpl::if_, key_type const&, no_key>::type @@ -1462,6 +1581,9 @@ namespace boost { return k; } + // For a map, the argument might be a pair with the key as the first + // part and a convertible value as the second part. + template static BOOST_DEDUCED_TYPENAME boost::mpl::if_< @@ -1478,9 +1600,10 @@ namespace boost { return v.first; } -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) + // For maps if there is more than one argument, the key can be the first argument. - template +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) + template static BOOST_DEDUCED_TYPENAME boost::mpl::if_< boost::mpl::and_< @@ -1488,7 +1611,21 @@ namespace boost { boost::is_same >, key_type const&, no_key - >::type extract_key(Arg const& k, Args const&...) + >::type extract_key(Arg const& k, Arg1 const&, Args const&...) + { + return k; + } + +#else + template + static BOOST_DEDUCED_TYPENAME + boost::mpl::if_< + boost::mpl::and_< + boost::mpl::not_ >, + boost::is_same + >, + key_type const&, no_key + >::type extract_key(Arg const& k, Arg1 const&) { return k; } @@ -1632,34 +1769,39 @@ namespace boost { #else - // Emplace (equivalent key containers) - - // if hash function throws, basic exception safety - // strong otherwise - iterator_base emplace(value_type const& v) - { - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(data_.allocators_); - a.construct(v); - - return emplace_impl(a); +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator_base emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + node_constructor a(data_.allocators_); \ + a.construct( \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + ); \ + return emplace_impl(a); \ + } \ + \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator_base emplace_hint(iterator_base const& it, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + node_constructor a(data_.allocators_); \ + a.construct( \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + ); \ + return emplace_hint_impl(it, a); \ } - // Emplace (equivalent key containers) - - // if hash function throws, basic exception safety - // strong otherwise - iterator_base emplace_hint(iterator_base const& it, value_type const& v) - { - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(data_.allocators_); - a.construct(v); - - return emplace_hint_impl(it, a); - } + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) +#undef BOOST_UNORDERED_INSERT_IMPL #endif iterator_base emplace_impl(node_constructor& a) @@ -1788,7 +1930,7 @@ namespace boost { // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). node_constructor a(data_.allocators_); - a.construct_pair(k, (mapped_type*) 0); + a.construct(k); // reserve has basic exception safety if the hash function // throws, strong otherwise. @@ -1805,10 +1947,6 @@ namespace boost { // Emplace (unique keys) // (I'm using an overloaded emplace for both 'insert' and 'emplace') - // - // TODO: - // For sets: create a local key without creating the node? - // For maps: use the first argument as the key. // if hash function throws, basic exception safety // strong otherwise @@ -1878,59 +2016,97 @@ namespace boost { return emplace_impl_with_node(a); } #else - - // Emplace (unique keys) - - // if hash function throws, basic exception safety - // strong otherwise - std::pair emplace(value_type const& v) + template + std::pair emplace(Arg0 const& arg0) { - // No side effects in this initial code - key_type const& k = extract_key(v); - size_type hash_value = hash_function()(k); - bucket_ptr bucket = data_.bucket_ptr_from_hash(hash_value); - link_ptr pos = find_iterator(bucket, k); - - if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { - // Found an existing key, return it (no throw). - return std::pair( - iterator_base(bucket, pos), false); - - } else { - // Doesn't already exist, add to bucket. - // Side effects only in this block. - - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(data_.allocators_); - a.construct(v); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(reserve_for_insert(size() + 1)) - bucket = data_.bucket_ptr_from_hash(hash_value); - - // Nothing after this point can throw. - - link_ptr n = data_.link_node_in_bucket(a, bucket); - - return std::pair( - iterator_base(bucket, n), true); - } + return emplace_impl(extract_key(arg0), arg0); } - // Emplace (unique keys) - - // if hash function throws, basic exception safety - // strong otherwise - iterator_base emplace_hint(iterator_base const& it, value_type const& v) + template + iterator_base emplace_hint(iterator_base const& it, Arg0 const& arg0) { - if(it != data_.end() && equal(extract_key(v), *it)) - return it; - else - return emplace(v).first; + return emplace_impl(extract_key(arg0), arg0).first; } + +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + std::pair emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return emplace_impl( \ + extract_key(arg0, arg1), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + ); \ + } \ + \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator_base emplace_hint(iterator_base const& it, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return emplace_impl( \ + extract_key(arg0, arg1), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + ).first; \ + } \ + BOOST_UNORDERED_INSERT_IMPL2(z, n, _) + +#define BOOST_UNORDERED_INSERT_IMPL2(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + std::pair emplace_impl(key_type const& k, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + size_type hash_value = hash_function()(k); \ + bucket_ptr bucket = data_.bucket_ptr_from_hash(hash_value); \ + link_ptr pos = find_iterator(bucket, k); \ + \ + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \ + return std::pair( \ + iterator_base(bucket, pos), false); \ + } else { \ + node_constructor a(data_.allocators_); \ + a.construct( \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + ); \ + \ + if(reserve_for_insert(size() + 1)) \ + bucket = data_.bucket_ptr_from_hash(hash_value); \ + \ + return std::pair(iterator_base(bucket, \ + data_.link_node_in_bucket(a, bucket)), true); \ + } \ + } \ + \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + std::pair emplace_impl(no_key, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + node_constructor a(data_.allocators_); \ + a.construct( \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + ); \ + return emplace_impl_with_node(a); \ + } + + BOOST_UNORDERED_INSERT_IMPL2(1, 1, _) + + BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) + +#undef BOOST_UNORDERED_INSERT_IMPL + #endif std::pair emplace_impl_with_node(node_constructor& a) @@ -1958,7 +2134,6 @@ namespace boost { } } - // Insert from iterators (unique keys) template @@ -2137,8 +2312,9 @@ namespace boost { key_type const& k) const { link_ptr it = data_.begin(bucket); - while (BOOST_UNORDERED_BORLAND_BOOL(it) && !equal(k, data::get_value(it))) + while (BOOST_UNORDERED_BORLAND_BOOL(it) && !equal(k, data::get_value(it))) { it = data::next_group(it); + } return it; } diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 4d3f7a53..a7ebd691 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -232,6 +232,50 @@ namespace boost { return iterator(base.emplace_hint(get(hint), std::forward(args)...)); } +#else + + std::pair emplace(value_type const& v = value_type()) + { + return boost::unordered_detail::pair_cast( + base.emplace(v)); + } + + iterator emplace_hint(const_iterator hint, value_type const& v = value_type()) + { + return iterator(base.emplace_hint(get(hint), v)); + } + +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + std::pair emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return boost::unordered_detail::pair_cast( \ + base.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ + } \ + \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace_hint(const_iterator hint, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator(base.emplace_hint(get(hint), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_EMPLACE, _) + +#undef BOOST_UNORDERED_EMPLACE + #endif std::pair insert(const value_type& obj) @@ -638,6 +682,50 @@ namespace boost { return iterator(base.emplace_hint(get(hint), std::forward(args)...)); } +#else + + iterator emplace(value_type const& v = value_type()) + { + return iterator(base.emplace(v)); + } + + iterator emplace_hint(const_iterator hint, value_type const& v = value_type()) + { + return iterator(base.emplace_hint(get(hint), v)); + } + + +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator( \ + base.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ + } \ + \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace_hint(const_iterator hint, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator(base.emplace_hint(get(hint), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_EMPLACE, _) + +#undef BOOST_UNORDERED_EMPLACE + #endif iterator insert(const value_type& obj) diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index a99db075..f39a76df 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -231,6 +231,50 @@ namespace boost return iterator( base.emplace_hint(get(hint), std::forward(args)...)); } +#else + + std::pair emplace(value_type const& v = value_type()) + { + return boost::unordered_detail::pair_cast( + base.emplace(v)); + } + + iterator emplace_hint(const_iterator hint, value_type const& v = value_type()) + { + return iterator(base.emplace_hint(get(hint), v)); + } + +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + std::pair emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return boost::unordered_detail::pair_cast( \ + base.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ + } \ + \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace_hint(const_iterator hint, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator(base.emplace_hint(get(hint), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_EMPLACE, _) + +#undef BOOST_UNORDERED_EMPLACE + #endif std::pair insert(const value_type& obj) @@ -607,6 +651,49 @@ namespace boost { return iterator(base.emplace_hint(get(hint), std::forward(args)...)); } +#else + + iterator emplace(value_type const& v = value_type()) + { + return iterator(base.emplace(v)); + } + + iterator emplace_hint(const_iterator hint, value_type const& v = value_type()) + { + return iterator(base.emplace_hint(get(hint), v)); + } + +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator( \ + base.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ + } \ + \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace_hint(const_iterator hint, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator(base.emplace_hint(get(hint), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_EMPLACE, _) + +#undef BOOST_UNORDERED_EMPLACE + #endif iterator insert(const value_type& obj) diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 486d3e2e..3dd00fdf 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -151,14 +151,12 @@ void unordered_map_test(X& r, Key const& k, T const& v) r.insert(std::pair(k, v)); -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) Key k_lvalue(k); T v_lvalue(v); r.emplace(k, v); r.emplace(k_lvalue, v_lvalue); r.emplace(rvalue(k), rvalue(v)); -#endif } template @@ -175,9 +173,7 @@ void unordered_unique_test(X& r, T const& t) { typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; test::check_return_type >::equals(r.insert(t)); -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) test::check_return_type >::equals(r.emplace(t)); -#endif } template @@ -185,9 +181,7 @@ void unordered_equivalent_test(X& r, T const& t) { typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; test::check_return_type::equals(r.insert(t)); -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) test::check_return_type::equals(r.emplace(t)); -#endif } template @@ -289,9 +283,7 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq) const_iterator q = a.cbegin(); test::check_return_type::equals(a.insert(q, t)); -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) test::check_return_type::equals(a.emplace_hint(q, t)); -#endif a.insert(i, j); test::check_return_type::equals(a.erase(k)); diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index d2ab8629..3cf707ef 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -68,12 +68,22 @@ namespace unnecessary_copy_tests #define COPY_COUNT(n) \ if(count_copies::copies != n) { \ BOOST_ERROR("Wrong number of copies."); \ - std::cerr<<"Number of copies: "< b) { \ + BOOST_ERROR("Wrong number of copies."); \ + std::cerr<<"Number of copies: "< b) { \ + BOOST_ERROR("Wrong number of moves."); \ + std::cerr<<"Number of moves: "< void unnecessary_copy_emplace_test(T*) { @@ -117,9 +126,19 @@ namespace unnecessary_copy_tests reset(); T x; x.emplace(source()); +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) COPY_COUNT(1); +#else + COPY_COUNT(2); +#endif } + UNORDERED_TEST(unnecessary_copy_emplace_test, + ((set)(multiset)(map)(multimap))) + UNORDERED_TEST(unnecessary_copy_emplace_rvalue_test, + ((set)(multiset)(map)(multimap))) + +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) template void unnecessary_copy_emplace_move_test(T*) { @@ -131,13 +150,11 @@ namespace unnecessary_copy_tests COPY_COUNT(1); MOVE_COUNT(1); } - UNORDERED_TEST(unnecessary_copy_emplace_test, - ((set)(multiset)(map)(multimap))) - UNORDERED_TEST(unnecessary_copy_emplace_rvalue_test, - ((set)(multiset)(map)(multimap))) UNORDERED_TEST(unnecessary_copy_emplace_move_test, ((set)(multiset)(map)(multimap))) +#endif + UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test) { reset(); @@ -172,10 +189,12 @@ namespace unnecessary_copy_tests x.emplace(source()); COPY_COUNT(1); MOVE_COUNT(0); +#if defined(BOOST_HAS_RVALUE_REFS) // No move should take place. reset(); x.emplace(std::move(a)); COPY_COUNT(0); MOVE_COUNT(0); +#endif // Just in case a did get moved... count_copies b; @@ -194,8 +213,10 @@ namespace unnecessary_copy_tests // the existing element. // // Note to self: If copy_count == 0 it's an error not an optimization. + // TODO: Devise a better test. reset(); + x.emplace(b, b); COPY_COUNT(1); MOVE_COUNT(0); } @@ -232,24 +253,22 @@ namespace unnecessary_copy_tests x.emplace(source >()); COPY_COUNT(2); MOVE_COUNT(0); - count_copies part; - reset(); - std::pair a_ref(part, part); - x.emplace(a_ref); - COPY_COUNT(0); MOVE_COUNT(0); + // TODO: This doesn't work on older versions of gcc. + //count_copies part; + std::pair b; + //reset(); + //std::pair a_ref(part, part); + //x.emplace(a_ref); + //COPY_COUNT(0); MOVE_COUNT(0); +#if defined(BOOST_HAS_RVALUE_REFS) // No move should take place. + // (since a is already in the container) reset(); x.emplace(std::move(a)); COPY_COUNT(0); MOVE_COUNT(0); +#endif - // Just in case a did get moved - std::pair b; - - // This test requires a C++0x std::pair. Which gcc hasn't got yet. - //reset(); - //x.emplace(b.first.tag_); - //COPY_COUNT(2); MOVE_COUNT(0); // // 2 arguments @@ -269,10 +288,9 @@ namespace unnecessary_copy_tests COPY_COUNT(1); MOVE_COUNT(0); reset(); - x.emplace(b.first.tag_, b.second.tag_); - COPY_COUNT(2); MOVE_COUNT(0); + x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_)); + COPY_COUNT(2); MOVE_COUNT(0); } -#endif } RUN_TESTS()