1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2014-2014.
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // See http://www.boost.org/libs/move for documentation.
9 //
10 //////////////////////////////////////////////////////////////////////////////
11 #include <boost/move/adl_move_swap.hpp>
12 #include <boost/move/core.hpp>
13 #include <boost/core/lightweight_test.hpp>
14 
15 class swap_stats
16 {
17    public:
reset_stats()18    static void reset_stats()
19    {
20       member_swap_calls = 0;
21       friend_swap_calls = 0;
22       move_cnstor_calls = 0;
23       move_assign_calls = 0;
24       copy_cnstor_calls = 0;
25       copy_assign_calls = 0;
26    }
27 
28    static unsigned int member_swap_calls;
29    static unsigned int friend_swap_calls;
30    static unsigned int move_cnstor_calls;
31    static unsigned int move_assign_calls;
32    static unsigned int copy_cnstor_calls;
33    static unsigned int copy_assign_calls;
34 };
35 
36 unsigned int swap_stats::member_swap_calls = 0;
37 unsigned int swap_stats::friend_swap_calls = 0;
38 unsigned int swap_stats::move_cnstor_calls = 0;
39 unsigned int swap_stats::move_assign_calls = 0;
40 unsigned int swap_stats::copy_cnstor_calls = 0;
41 unsigned int swap_stats::copy_assign_calls = 0;
42 
43 class movable : public swap_stats
44 {
45    BOOST_MOVABLE_BUT_NOT_COPYABLE(movable)
46    public:
movable()47    movable()                                 {}
movable(BOOST_RV_REF (movable))48    movable(BOOST_RV_REF(movable))            { ++move_cnstor_calls; }
operator =(BOOST_RV_REF (movable))49    movable & operator=(BOOST_RV_REF(movable)){ ++move_assign_calls; return *this; }
swap(movable &,movable &)50    friend void swap(movable &, movable &)    { ++friend_swap_calls; }
51 };
52 
53 class movable_swap_member : public swap_stats
54 {
55    BOOST_MOVABLE_BUT_NOT_COPYABLE(movable_swap_member)
56    public:
movable_swap_member()57    movable_swap_member()                                             {}
movable_swap_member(BOOST_RV_REF (movable_swap_member))58    movable_swap_member(BOOST_RV_REF(movable_swap_member))            { ++move_cnstor_calls; }
operator =(BOOST_RV_REF (movable_swap_member))59    movable_swap_member & operator=(BOOST_RV_REF(movable_swap_member)){ ++move_assign_calls; return *this; }
swap(movable_swap_member &)60    void swap(movable_swap_member &)                                  { ++member_swap_calls; }
swap(movable_swap_member &,movable_swap_member &)61    friend void swap(movable_swap_member &, movable_swap_member &)    { ++friend_swap_calls; }
62 };
63 
64 class copyable : public swap_stats
65 {
66    public:
copyable()67    copyable()                                {}
copyable(const copyable &)68    copyable(const copyable &)                { ++copy_cnstor_calls; }
operator =(const copyable &)69    copyable & operator=(const copyable&)     { ++copy_assign_calls; return *this; }
swap(copyable &)70    void swap(copyable &)                     { ++member_swap_calls; }
swap(copyable &,copyable &)71    friend void swap(copyable &, copyable &)  { ++friend_swap_calls; }
72 };
73 
74 class no_swap : public swap_stats
75 {
76    private: unsigned m_state;
77    public:
no_swap(unsigned i)78    explicit no_swap(unsigned i): m_state(i){}
no_swap(const no_swap & x)79    no_swap(const no_swap &x)               { m_state = x.m_state; ++copy_cnstor_calls; }
operator =(const no_swap & x)80    no_swap & operator=(const no_swap& x)   { m_state = x.m_state; ++copy_assign_calls; return *this; }
swap(no_swap &)81    void swap(no_swap &)                    { ++member_swap_calls; }
operator ==(const no_swap & x,const no_swap & y)82    friend bool operator==(const no_swap &x, const no_swap &y) {  return x.m_state == y.m_state; }
operator !=(const no_swap & x,const no_swap & y)83    friend bool operator!=(const no_swap &x, const no_swap &y) {  return !(x==y); }
84 };
85 
86 
main()87 int main()
88 {
89    {  //movable
90       movable x, y;
91       swap_stats::reset_stats();
92       ::boost::adl_move_swap(x, y);
93       #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
94       //In non rvalue reference compilers,
95       //movable classes with no swap() member uses
96       //boost::move() to implement swap.
97       BOOST_TEST(swap_stats::friend_swap_calls == 0);
98       BOOST_TEST(swap_stats::member_swap_calls == 0);
99       BOOST_TEST(swap_stats::member_swap_calls == 0);
100       BOOST_TEST(swap_stats::move_cnstor_calls == 1);
101       BOOST_TEST(swap_stats::move_assign_calls == 2);
102       BOOST_TEST(swap_stats::copy_cnstor_calls == 0);
103       BOOST_TEST(swap_stats::copy_assign_calls == 0);
104       #else
105       //In compilers with rvalue references, this should call friend swap via ADL
106       BOOST_TEST(swap_stats::friend_swap_calls == 1);
107       BOOST_TEST(swap_stats::member_swap_calls == 0);
108       BOOST_TEST(swap_stats::member_swap_calls == 0);
109       BOOST_TEST(swap_stats::move_cnstor_calls == 0);
110       BOOST_TEST(swap_stats::move_assign_calls == 0);
111       BOOST_TEST(swap_stats::copy_cnstor_calls == 0);
112       BOOST_TEST(swap_stats::copy_assign_calls == 0);
113       #endif
114    }
115    {  //movable_swap_member
116       movable_swap_member x, y;
117       swap_stats::reset_stats();
118       ::boost::adl_move_swap(x, y);
119       #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
120       //In non rvalue reference compilers,
121       //movable classes with no swap() member uses
122       //boost::move() to implement swap.
123       BOOST_TEST(swap_stats::friend_swap_calls == 0);
124       BOOST_TEST(swap_stats::member_swap_calls == 1);
125       BOOST_TEST(swap_stats::move_cnstor_calls == 0);
126       BOOST_TEST(swap_stats::move_assign_calls == 0);
127       BOOST_TEST(swap_stats::copy_cnstor_calls == 0);
128       BOOST_TEST(swap_stats::copy_assign_calls == 0);
129       #else
130       //In compilers with rvalue references, this should call friend swap via ADL
131       BOOST_TEST(swap_stats::friend_swap_calls == 1);
132       BOOST_TEST(swap_stats::member_swap_calls == 0);
133       BOOST_TEST(swap_stats::move_cnstor_calls == 0);
134       BOOST_TEST(swap_stats::move_assign_calls == 0);
135       BOOST_TEST(swap_stats::copy_cnstor_calls == 0);
136       BOOST_TEST(swap_stats::copy_assign_calls == 0);
137       #endif
138    }
139    {  //copyable
140       copyable x, y;
141       swap_stats::reset_stats();
142       ::boost::adl_move_swap(x, y);
143       //This should call friend swap via ADL
144       BOOST_TEST(swap_stats::friend_swap_calls == 1);
145       BOOST_TEST(swap_stats::member_swap_calls == 0);
146       BOOST_TEST(swap_stats::move_cnstor_calls == 0);
147       BOOST_TEST(swap_stats::move_assign_calls == 0);
148       BOOST_TEST(swap_stats::copy_cnstor_calls == 0);
149       BOOST_TEST(swap_stats::copy_assign_calls == 0);
150    }
151    {  //no_swap
152       no_swap x(1), y(2), x_back(x), y_back(y);
153       swap_stats::reset_stats();
154       ::boost::adl_move_swap(x, y);
155       //This should call std::swap which uses copies
156       BOOST_TEST(swap_stats::friend_swap_calls == 0);
157       BOOST_TEST(swap_stats::member_swap_calls == 0);
158       BOOST_TEST(swap_stats::move_cnstor_calls == 0);
159       BOOST_TEST(swap_stats::move_assign_calls == 0);
160       BOOST_TEST(swap_stats::copy_cnstor_calls == 1);
161       BOOST_TEST(swap_stats::copy_assign_calls == 2);
162       BOOST_TEST(x == y_back);
163       BOOST_TEST(y == x_back);
164       BOOST_TEST(x != y);
165    }
166    return ::boost::report_errors();
167 }
168