From 338a94e577a5ed4f84b1532e605f1c6525252cb8 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 1 May 2017 21:03:11 +0100 Subject: [PATCH] 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;