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