From 155077cba09ea8887924a4847e693312052ac908 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 29 Aug 2011 09:40:41 +0000 Subject: [PATCH] Unordered: Support piecewise pair construction. Will need to deprecate the old variadic style pair construction, also should look into extract_key, was written for compatibility with older compilers that are no longer supported. [SVN r74119] --- include/boost/unordered/detail/buckets.hpp | 54 +++++++++++++- .../boost/unordered/detail/extract_key.hpp | 70 ++++++++++++++++++- include/boost/unordered/detail/fwd.hpp | 3 + include/boost/unordered/detail/util.hpp | 15 ++-- test/unordered/insert_tests.cpp | 33 ++++++++- test/unordered/unnecessary_copy_tests.cpp | 48 ++++++++++++- 6 files changed, 212 insertions(+), 11 deletions(-) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 4fb1f503..6596c97b 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -515,7 +515,39 @@ namespace boost { namespace unordered { namespace detail { }; //////////////////////////////////////////////////////////////////////////// - // Node Constructors + // + // Value Construction + +#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template \ + void construct_from_tuple(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_) \ + template\ + void construct_from_tuple(T* ptr, \ + 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) + +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost) + +#if !defined(BOOST_NO_0X_HDR_TUPLE) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std) +#elif defined(BOOST_HAS_TR1_TUPLE) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::tr1) +#endif template struct emulated_pair_constructor @@ -587,6 +619,15 @@ namespace boost { namespace unordered { namespace detail { std::forward(arg2), std::forward(args)...)); } + template + inline typename boost::enable_if >::type + construct_impl(void* address, boost::unordered::piecewise_construct_t, + Tuple1&& tuple1, Tuple2&& tuple2) + { + construct_from_tuple(&static_cast(address)->first, tuple1); + construct_from_tuple(&static_cast(address)->second, tuple2); + } + #else template @@ -612,7 +653,16 @@ namespace boost { namespace unordered { namespace detail { { new(address) T(boost::forward(a1), boost::forward(a2)); } - + + template + inline typename boost::enable_if >::type + construct_impl(void* address, boost::unordered::piecewise_construct_t, + BOOST_FWD_REF(Tuple1) tuple1, BOOST_FWD_REF(Tuple2) tuple2) + { + construct_from_tuple(&static_cast(address)->first, tuple1); + construct_from_tuple(&static_cast(address)->second, tuple2); + } + #define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \ template < \ class T, \ diff --git a/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp index 9f3d605d..a412e6bc 100644 --- a/include/boost/unordered/detail/extract_key.hpp +++ b/include/boost/unordered/detail/extract_key.hpp @@ -27,6 +27,19 @@ namespace detail { 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(make())) == sizeof(choice2::type) }; + + typedef BOOST_DEDUCED_TYPENAME + boost::detail::if_true:: + BOOST_NESTED_TEMPLATE then::type type; + }; + template struct set_extractor { @@ -64,8 +77,8 @@ namespace detail { return no_key(); } - template - static no_key extract(Arg const&, Arg const&) + template + static no_key extract(Arg1 const&, Arg2 const&) { return no_key(); } @@ -127,6 +140,7 @@ namespace detail { return no_key(); } #else + template static key_type const& extract(key_type const& k, Arg1 const&) { @@ -151,6 +165,58 @@ namespace detail { } #endif + choice1::type is_key_test(key_type const&); + template + choice2::type is_key_test(T const&); + +#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) + +#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \ + template \ + static no_key extract(boost::unordered::piecewise_construct_t, \ + namespace_::tuple<> const&, T2&&) \ + { \ + return no_key(); \ + } \ + \ + template \ + static BOOST_DEDUCED_TYPENAME is_key::type \ + extract(boost::unordered::piecewise_construct_t, \ + namespace_::tuple const& k, T2&&) \ + { \ + return BOOST_DEDUCED_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 BOOST_DEDUCED_TYPENAME is_key::type \ + extract(boost::unordered::piecewise_construct_t, \ + namespace_::tuple const& k) \ + { \ + return BOOST_DEDUCED_TYPENAME is_key::type( \ + namespace_::get<0>(k)); \ + } + +#endif + +BOOST_UNORDERED_KEY_FROM_TUPLE(boost) + +#if !defined(BOOST_NO_0X_HDR_TUPLE) +BOOST_UNORDERED_KEY_FROM_TUPLE(std) +#elif defined(BOOST_HAS_TR1_TUPLE) +BOOST_UNORDERED_KEY_FROM_TUPLE(std::tr1) +#endif + + static bool compare_mapped(value_type const& x, value_type const& y) { return x.second == y.second; diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 8185e4f5..395b4057 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -44,6 +44,9 @@ namespace unordered class P = std::equal_to, class A = std::allocator > class unordered_multiset; + + struct piecewise_construct_t {}; + const piecewise_construct_t piecewise_construct = piecewise_construct_t(); } } diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index 52cf48d4..7cfe8dbc 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -24,12 +24,19 @@ #include #include #include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_NO_0X_HDR_TUPLE) || defined(BOOST_HAS_TR1_TUPLE) +#include +#endif +#include // Template parameters: // diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 2ea3a40a..bc4b70cc 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -537,8 +537,6 @@ struct overloaded_constructor } }; -// This will actually be deprecated pretty soon. - UNORDERED_AUTO_TEST(map_emplace_test) { boost::unordered_map x; @@ -593,6 +591,37 @@ UNORDERED_AUTO_TEST(set_emplace_test) BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); } +UNORDERED_AUTO_TEST(map_emplace_test2) +{ + boost::unordered_map 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(1), boost::make_tuple()); + BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == overloaded_constructor()); + + x.emplace(boost::unordered::piecewise_construct, 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)); +} + +UNORDERED_AUTO_TEST(set_emplace_test2) +{ + boost::unordered_set > x; + std::pair check; + + x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(), boost::make_tuple()); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); + + x.clear(); + x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(1), 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); +} + } RUN_TESTS() diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index 6ebfd8b5..a7742386 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -1,4 +1,4 @@ - +#include // 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) @@ -327,6 +327,13 @@ namespace unnecessary_copy_tests x.emplace(); COPY_COUNT(2); MOVE_COUNT(0); + reset(); + x.emplace(boost::unordered::piecewise_construct, + boost::make_tuple(), + boost::make_tuple()); + COPY_COUNT(2); MOVE_COUNT(0); + + // // 1 argument // @@ -345,19 +352,23 @@ namespace unnecessary_copy_tests (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ > 2) || \ (defined(BOOST_MSVC) && BOOST_MSVC >= 1600 ) || \ (!defined(__GNUC__) && !defined(BOOST_MSVC)) + count_copies part; reset(); std::pair a_ref(part, part); x.emplace(a_ref); COPY_COUNT(2); MOVE_COUNT(0); + #endif #if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) + // 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 // @@ -382,6 +393,41 @@ namespace unnecessary_copy_tests reset(); x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_)); COPY_COUNT(2); MOVE_COUNT(0); + + reset(); + x.emplace(boost::unordered::piecewise_construct, + boost::make_tuple(boost::ref(b.first)), + boost::make_tuple(boost::ref(b.second))); + COPY_COUNT(0); MOVE_COUNT(0); + +#if !defined(BOOST_NO_0X_HDR_TUPLE) || defined(BOOST_HAS_TR1_TUPLE) + + reset(); + x.emplace(boost::unordered::piecewise_construct, + std::make_tuple(std::ref(b.first)), + std::make_tuple(std::ref(b.second))); + COPY_COUNT(0); MOVE_COUNT(0); + + // first is const so it is copied. + // second is not const so it is moved. + std::pair move_source; + reset(); + x.emplace(boost::unordered::piecewise_construct, + std::make_tuple(std::move(move_source.first)), + std::make_tuple(std::move(move_source.second))); + COPY_COUNT(1); MOVE_COUNT(1); + +#if defined(__GNUC__) && __GNUC__ > 4 || \ + defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 6 + reset(); + x.emplace(boost::unordered::piecewise_construct, + std::forward_as_tuple(b.first), + std::forward_as_tuple(b.second)); + COPY_COUNT(0); MOVE_COUNT(0); +#endif + +#endif + } }