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