Unordered: Update unnecessary_copy_tests for Boost.Move.

Seems to be better in some cases. For example, better forwarding if
rvalue references are supported but variadic template parameters aren't.
Also can use `boost::move` when inserting.

Older versions of gcc still fail this test. They perform more moves than
expected. It might be a limitation of Boost.Move, or maybe just poor
copy optimization.

[SVN r73539]
This commit is contained in:
Daniel James
2011-08-04 22:54:26 +00:00
parent d86a4b0c2f
commit c9e0fb9730

View File

@@ -13,6 +13,9 @@ namespace unnecessary_copy_tests
{ {
struct count_copies struct count_copies
{ {
private:
BOOST_COPYABLE_AND_MOVABLE(count_copies)
public:
static int copies; static int copies;
static int moves; static int moves;
count_copies() : tag_(0) { ++copies; } count_copies() : tag_(0) { ++copies; }
@@ -31,13 +34,17 @@ namespace unnecessary_copy_tests
: tag_(x.tag_) { ++copies; } : tag_(x.tag_) { ++copies; }
count_copies(count_copies const& x) : tag_(x.tag_) { ++copies; } count_copies(count_copies const& x) : tag_(x.tag_) { ++copies; }
#if !defined(BOOST_NO_RVALUE_REFERENCES) count_copies(BOOST_RV_REF(count_copies) x) : tag_(x.tag_) {
count_copies(count_copies&& x) : tag_(x.tag_) {
x.tag_ = -1; ++moves; x.tag_ = -1; ++moves;
} }
#endif
int tag_; int tag_;
private: private:
// I think the standard might require assignment (or move
// assignment) for some operations. That Boost.Unordered doesn't
// is an implementation detail. But these tests are very specific
// to the implementation, so it's probably okay that this doesn't
// meet the standard requirements.
count_copies& operator=(count_copies const&); count_copies& operator=(count_copies const&);
}; };
@@ -136,7 +143,7 @@ namespace unnecessary_copy_tests
reset(); reset();
T x; T x;
x.emplace(source<BOOST_DEDUCED_TYPENAME T::value_type>()); x.emplace(source<BOOST_DEDUCED_TYPENAME T::value_type>());
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) #if !defined(BOOST_NO_RVALUE_REFERENCES)
COPY_COUNT(1); COPY_COUNT(1);
#else #else
COPY_COUNT(2); COPY_COUNT(2);
@@ -148,7 +155,7 @@ namespace unnecessary_copy_tests
UNORDERED_TEST(unnecessary_copy_emplace_rvalue_test, UNORDERED_TEST(unnecessary_copy_emplace_rvalue_test,
((set)(multiset)(map)(multimap))) ((set)(multiset)(map)(multimap)))
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) #if !defined(BOOST_NO_RVALUE_REFERENCES)
template <class T> template <class T>
void unnecessary_copy_emplace_move_test(T*) void unnecessary_copy_emplace_move_test(T*)
{ {
@@ -162,9 +169,40 @@ namespace unnecessary_copy_tests
UNORDERED_TEST(unnecessary_copy_emplace_move_test, UNORDERED_TEST(unnecessary_copy_emplace_move_test,
((set)(multiset)(map)(multimap))) ((set)(multiset)(map)(multimap)))
#endif #endif
template <class T>
void unnecessary_copy_emplace_boost_move_set_test(T*)
{
reset();
T x;
BOOST_DEDUCED_TYPENAME T::value_type a;
COPY_COUNT(1); MOVE_COUNT(0);
x.emplace(boost::move(a));
COPY_COUNT(1); MOVE_COUNT(1);
}
UNORDERED_TEST(unnecessary_copy_emplace_boost_move_set_test,
((set)(multiset)))
template <class T>
void unnecessary_copy_emplace_boost_move_map_test(T*)
{
reset();
T x;
BOOST_DEDUCED_TYPENAME T::value_type a;
COPY_COUNT(1); MOVE_COUNT(0);
x.emplace(boost::move(a));
#if !defined(BOOST_NO_RVALUE_REFERENCES)
COPY_COUNT(1); MOVE_COUNT(1);
#else
COPY_COUNT(2); MOVE_COUNT(0);
#endif
}
UNORDERED_TEST(unnecessary_copy_emplace_boost_move_map_test,
((map)(multimap)))
UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test) UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test)
{ {
reset(); reset();
@@ -181,7 +219,13 @@ namespace unnecessary_copy_tests
// the existing element. // the existing element.
reset(); reset();
x.emplace(); x.emplace();
#if !defined(BOOST_UNORDERED_STD_FORWARD)
// TODO: I think that in this case the move could be delayed until
// after checking for a collision, giving MOVE_COUNT(0).
COPY_COUNT(1); MOVE_COUNT(1);
#else
COPY_COUNT(1); MOVE_COUNT(0); COPY_COUNT(1); MOVE_COUNT(0);
#endif
// //
// 1 argument // 1 argument