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]
This commit is contained in:
Daniel James
2011-08-29 09:40:41 +00:00
parent 4dcf34c264
commit 155077cba0
6 changed files with 212 additions and 11 deletions

View File

@ -515,7 +515,39 @@ namespace boost { namespace unordered { namespace detail {
};
////////////////////////////////////////////////////////////////////////////
// Node Constructors
//
// Value Construction
#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \
template<typename T> \
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<typename T BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename Arg)>\
void construct_from_tuple(T* ptr, \
namespace_::tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, Arg)> 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<n>(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 <typename T, typename Arg1 = void>
struct emulated_pair_constructor
@ -587,6 +619,15 @@ namespace boost { namespace unordered { namespace detail {
std::forward<Arg2>(arg2), std::forward<Args>(args)...));
}
template <class T, class Tuple1, class Tuple2>
inline typename boost::enable_if<emulated_pair_constructor<T> >::type
construct_impl(void* address, boost::unordered::piecewise_construct_t,
Tuple1&& tuple1, Tuple2&& tuple2)
{
construct_from_tuple(&static_cast<T*>(address)->first, tuple1);
construct_from_tuple(&static_cast<T*>(address)->second, tuple2);
}
#else
template <class T, class Arg1>
@ -612,7 +653,16 @@ namespace boost { namespace unordered { namespace detail {
{
new(address) T(boost::forward<Arg1>(a1), boost::forward<Arg2>(a2));
}
template <class T, class Tuple1, class Tuple2>
inline typename boost::enable_if<emulated_pair_constructor<T> >::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<T*>(address)->first, tuple1);
construct_from_tuple(&static_cast<T*>(address)->second, tuple2);
}
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
template < \
class T, \

View File

@ -27,6 +27,19 @@ namespace detail {
template <class T> no_key(T const&) {}
};
template <typename Key, typename T>
struct is_key {
template <typename T2>
static choice1::type test(T2 const&);
static choice2::type test(Key const&);
enum { value = sizeof(test(make<T>())) == sizeof(choice2::type) };
typedef BOOST_DEDUCED_TYPENAME
boost::detail::if_true<value>::
BOOST_NESTED_TEMPLATE then<Key const&, no_key>::type type;
};
template <class ValueType>
struct set_extractor
{
@ -64,8 +77,8 @@ namespace detail {
return no_key();
}
template <class Arg>
static no_key extract(Arg const&, Arg const&)
template <class Arg1, class Arg2>
static no_key extract(Arg1 const&, Arg2 const&)
{
return no_key();
}
@ -127,6 +140,7 @@ namespace detail {
return no_key();
}
#else
template <class Arg1>
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 <typename T>
choice2::type is_key_test(T const&);
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \
template <typename T2> \
static no_key extract(boost::unordered::piecewise_construct_t, \
namespace_::tuple<> const&, T2&&) \
{ \
return no_key(); \
} \
\
template <typename T, typename T2> \
static BOOST_DEDUCED_TYPENAME is_key<key_type, T>::type \
extract(boost::unordered::piecewise_construct_t, \
namespace_::tuple<T> const& k, T2&&) \
{ \
return BOOST_DEDUCED_TYPENAME is_key<key_type, T>::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 <typename T> \
static BOOST_DEDUCED_TYPENAME is_key<key_type, T>::type \
extract(boost::unordered::piecewise_construct_t, \
namespace_::tuple<T> const& k) \
{ \
return BOOST_DEDUCED_TYPENAME is_key<key_type, T>::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;

View File

@ -44,6 +44,9 @@ namespace unordered
class P = std::equal_to<T>,
class A = std::allocator<T> >
class unordered_multiset;
struct piecewise_construct_t {};
const piecewise_construct_t piecewise_construct = piecewise_construct_t();
}
}

View File

@ -24,12 +24,19 @@
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/is_empty.hpp>
#include <boost/throw_exception.hpp>
#include <boost/unordered/detail/allocator_helpers.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/move/move.hpp>
#include <boost/swap.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/tuple/tuple.hpp>
#if !defined(BOOST_NO_0X_HDR_TUPLE) || defined(BOOST_HAS_TR1_TUPLE)
#include <tuple>
#endif
#include <boost/unordered/detail/allocator_helpers.hpp>
// Template parameters:
//

View File

@ -537,8 +537,6 @@ struct overloaded_constructor
}
};
// This will actually be deprecated pretty soon.
UNORDERED_AUTO_TEST(map_emplace_test)
{
boost::unordered_map<int, overloaded_constructor> 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<overloaded_constructor, overloaded_constructor> 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<std::pair<overloaded_constructor, overloaded_constructor> > x;
std::pair<overloaded_constructor, overloaded_constructor> 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()

View File

@ -1,4 +1,4 @@
#include <iostream>
// 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<count_copies const&, count_copies const&> 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<count_copies const, count_copies> 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
}
}