////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Ion Gaztanaga 2014-2014. // 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) // // See http://www.boost.org/libs/move for documentation. // ////////////////////////////////////////////////////////////////////////////// #include #include #include #include class swap_stats { public: static void reset_stats() { member_swap_calls = 0; friend_swap_calls = 0; move_cnstor_calls = 0; move_assign_calls = 0; copy_cnstor_calls = 0; copy_assign_calls = 0; } static unsigned int member_swap_calls; static unsigned int friend_swap_calls; static unsigned int move_cnstor_calls; static unsigned int move_assign_calls; static unsigned int copy_cnstor_calls; static unsigned int copy_assign_calls; }; unsigned int swap_stats::member_swap_calls = 0; unsigned int swap_stats::friend_swap_calls = 0; unsigned int swap_stats::move_cnstor_calls = 0; unsigned int swap_stats::move_assign_calls = 0; unsigned int swap_stats::copy_cnstor_calls = 0; unsigned int swap_stats::copy_assign_calls = 0; class movable : public swap_stats { BOOST_MOVABLE_BUT_NOT_COPYABLE(movable) public: movable() {} movable(BOOST_RV_REF(movable)) { ++move_cnstor_calls; } movable & operator=(BOOST_RV_REF(movable)){ ++move_assign_calls; return *this; } friend void swap(movable &, movable &) { ++friend_swap_calls; } }; class movable_swap_member : public swap_stats { BOOST_MOVABLE_BUT_NOT_COPYABLE(movable_swap_member) public: movable_swap_member() {} movable_swap_member(BOOST_RV_REF(movable_swap_member)) { ++move_cnstor_calls; } movable_swap_member & operator=(BOOST_RV_REF(movable_swap_member)){ ++move_assign_calls; return *this; } void swap(movable_swap_member &) { ++member_swap_calls; } friend void swap(movable_swap_member &, movable_swap_member &) { ++friend_swap_calls; } }; class copyable : public swap_stats { public: copyable() {} copyable(const copyable &) { ++copy_cnstor_calls; } copyable & operator=(const copyable&) { ++copy_assign_calls; return *this; } void swap(copyable &) { ++member_swap_calls; } friend void swap(copyable &, copyable &) { ++friend_swap_calls; } }; class no_swap : public swap_stats { private: unsigned m_state; public: explicit no_swap(unsigned i): m_state(i){} no_swap(const no_swap &x) { m_state = x.m_state; ++copy_cnstor_calls; } no_swap & operator=(const no_swap& x) { m_state = x.m_state; ++copy_assign_calls; return *this; } void swap(no_swap &) { ++member_swap_calls; } friend bool operator==(const no_swap &x, const no_swap &y) { return x.m_state == y.m_state; } friend bool operator!=(const no_swap &x, const no_swap &y) { return !(x==y); } }; int main() { { //movable movable x, y; swap_stats::reset_stats(); ::boost::adl_move_swap(x, y); #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) //In non rvalue reference compilers, //movable classes with no swap() member uses //boost::move() to implement swap. BOOST_TEST(swap_stats::friend_swap_calls == 0); BOOST_TEST(swap_stats::member_swap_calls == 0); BOOST_TEST(swap_stats::member_swap_calls == 0); BOOST_TEST(swap_stats::move_cnstor_calls == 1); BOOST_TEST(swap_stats::move_assign_calls == 2); BOOST_TEST(swap_stats::copy_cnstor_calls == 0); BOOST_TEST(swap_stats::copy_assign_calls == 0); #else //In compilers with rvalue references, this should call friend swap via ADL BOOST_TEST(swap_stats::friend_swap_calls == 1); BOOST_TEST(swap_stats::member_swap_calls == 0); BOOST_TEST(swap_stats::member_swap_calls == 0); BOOST_TEST(swap_stats::move_cnstor_calls == 0); BOOST_TEST(swap_stats::move_assign_calls == 0); BOOST_TEST(swap_stats::copy_cnstor_calls == 0); BOOST_TEST(swap_stats::copy_assign_calls == 0); #endif } { //movable_swap_member movable_swap_member x, y; swap_stats::reset_stats(); ::boost::adl_move_swap(x, y); #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) //In non rvalue reference compilers, //movable classes with no swap() member uses //boost::move() to implement swap. BOOST_TEST(swap_stats::friend_swap_calls == 0); BOOST_TEST(swap_stats::member_swap_calls == 1); BOOST_TEST(swap_stats::move_cnstor_calls == 0); BOOST_TEST(swap_stats::move_assign_calls == 0); BOOST_TEST(swap_stats::copy_cnstor_calls == 0); BOOST_TEST(swap_stats::copy_assign_calls == 0); #else //In compilers with rvalue references, this should call friend swap via ADL BOOST_TEST(swap_stats::friend_swap_calls == 1); BOOST_TEST(swap_stats::member_swap_calls == 0); BOOST_TEST(swap_stats::move_cnstor_calls == 0); BOOST_TEST(swap_stats::move_assign_calls == 0); BOOST_TEST(swap_stats::copy_cnstor_calls == 0); BOOST_TEST(swap_stats::copy_assign_calls == 0); #endif } { //copyable copyable x, y; swap_stats::reset_stats(); ::boost::adl_move_swap(x, y); //This should call friend swap via ADL BOOST_TEST(swap_stats::friend_swap_calls == 1); BOOST_TEST(swap_stats::member_swap_calls == 0); BOOST_TEST(swap_stats::move_cnstor_calls == 0); BOOST_TEST(swap_stats::move_assign_calls == 0); BOOST_TEST(swap_stats::copy_cnstor_calls == 0); BOOST_TEST(swap_stats::copy_assign_calls == 0); } { //no_swap no_swap x(1), y(2), x_back(x), y_back(y); swap_stats::reset_stats(); ::boost::adl_move_swap(x, y); //This should call std::swap which uses copies BOOST_TEST(swap_stats::friend_swap_calls == 0); BOOST_TEST(swap_stats::member_swap_calls == 0); BOOST_TEST(swap_stats::move_cnstor_calls == 0); BOOST_TEST(swap_stats::move_assign_calls == 0); BOOST_TEST(swap_stats::copy_cnstor_calls == 1); BOOST_TEST(swap_stats::copy_assign_calls == 2); BOOST_TEST(x == y_back); BOOST_TEST(y == x_back); BOOST_TEST(x != y); } return ::boost::report_errors(); } #include