forked from boostorg/unordered
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:
@ -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>
|
template <typename T, typename Arg1 = void>
|
||||||
struct emulated_pair_constructor
|
struct emulated_pair_constructor
|
||||||
@ -587,6 +619,15 @@ namespace boost { namespace unordered { namespace detail {
|
|||||||
std::forward<Arg2>(arg2), std::forward<Args>(args)...));
|
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
|
#else
|
||||||
|
|
||||||
template <class T, class Arg1>
|
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));
|
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, _) \
|
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
|
||||||
template < \
|
template < \
|
||||||
class T, \
|
class T, \
|
||||||
|
@ -27,6 +27,19 @@ namespace detail {
|
|||||||
template <class T> no_key(T const&) {}
|
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>
|
template <class ValueType>
|
||||||
struct set_extractor
|
struct set_extractor
|
||||||
{
|
{
|
||||||
@ -64,8 +77,8 @@ namespace detail {
|
|||||||
return no_key();
|
return no_key();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Arg>
|
template <class Arg1, class Arg2>
|
||||||
static no_key extract(Arg const&, Arg const&)
|
static no_key extract(Arg1 const&, Arg2 const&)
|
||||||
{
|
{
|
||||||
return no_key();
|
return no_key();
|
||||||
}
|
}
|
||||||
@ -127,6 +140,7 @@ namespace detail {
|
|||||||
return no_key();
|
return no_key();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
template <class Arg1>
|
template <class Arg1>
|
||||||
static key_type const& extract(key_type const& k, Arg1 const&)
|
static key_type const& extract(key_type const& k, Arg1 const&)
|
||||||
{
|
{
|
||||||
@ -151,6 +165,58 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
#endif
|
#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)
|
static bool compare_mapped(value_type const& x, value_type const& y)
|
||||||
{
|
{
|
||||||
return x.second == y.second;
|
return x.second == y.second;
|
||||||
|
@ -44,6 +44,9 @@ namespace unordered
|
|||||||
class P = std::equal_to<T>,
|
class P = std::equal_to<T>,
|
||||||
class A = std::allocator<T> >
|
class A = std::allocator<T> >
|
||||||
class unordered_multiset;
|
class unordered_multiset;
|
||||||
|
|
||||||
|
struct piecewise_construct_t {};
|
||||||
|
const piecewise_construct_t piecewise_construct = piecewise_construct_t();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,12 +24,19 @@
|
|||||||
#include <boost/type_traits/remove_const.hpp>
|
#include <boost/type_traits/remove_const.hpp>
|
||||||
#include <boost/type_traits/is_empty.hpp>
|
#include <boost/type_traits/is_empty.hpp>
|
||||||
#include <boost/throw_exception.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/move/move.hpp>
|
||||||
#include <boost/swap.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:
|
// Template parameters:
|
||||||
//
|
//
|
||||||
|
@ -537,8 +537,6 @@ struct overloaded_constructor
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// This will actually be deprecated pretty soon.
|
|
||||||
|
|
||||||
UNORDERED_AUTO_TEST(map_emplace_test)
|
UNORDERED_AUTO_TEST(map_emplace_test)
|
||||||
{
|
{
|
||||||
boost::unordered_map<int, overloaded_constructor> x;
|
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);
|
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()
|
RUN_TESTS()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
|
#include <iostream>
|
||||||
// Copyright 2006-2009 Daniel James.
|
// Copyright 2006-2009 Daniel James.
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// 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();
|
x.emplace();
|
||||||
COPY_COUNT(2); MOVE_COUNT(0);
|
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
|
// 1 argument
|
||||||
//
|
//
|
||||||
@ -345,19 +352,23 @@ namespace unnecessary_copy_tests
|
|||||||
(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ > 2) || \
|
(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ > 2) || \
|
||||||
(defined(BOOST_MSVC) && BOOST_MSVC >= 1600 ) || \
|
(defined(BOOST_MSVC) && BOOST_MSVC >= 1600 ) || \
|
||||||
(!defined(__GNUC__) && !defined(BOOST_MSVC))
|
(!defined(__GNUC__) && !defined(BOOST_MSVC))
|
||||||
|
|
||||||
count_copies part;
|
count_copies part;
|
||||||
reset();
|
reset();
|
||||||
std::pair<count_copies const&, count_copies const&> a_ref(part, part);
|
std::pair<count_copies const&, count_copies const&> a_ref(part, part);
|
||||||
x.emplace(a_ref);
|
x.emplace(a_ref);
|
||||||
COPY_COUNT(2); MOVE_COUNT(0);
|
COPY_COUNT(2); MOVE_COUNT(0);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
|
|
||||||
// No move should take place.
|
// No move should take place.
|
||||||
// (since a is already in the container)
|
// (since a is already in the container)
|
||||||
reset();
|
reset();
|
||||||
x.emplace(std::move(a));
|
x.emplace(std::move(a));
|
||||||
COPY_COUNT(0); MOVE_COUNT(0);
|
COPY_COUNT(0); MOVE_COUNT(0);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -382,6 +393,41 @@ namespace unnecessary_copy_tests
|
|||||||
reset();
|
reset();
|
||||||
x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_));
|
x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_));
|
||||||
COPY_COUNT(2); MOVE_COUNT(0);
|
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
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user