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: |
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: |
47 | movable() {} |
48 | movable(BOOST_RV_REF(movable)) { ++move_cnstor_calls; } |
49 | movable & operator=(BOOST_RV_REF(movable)){ ++move_assign_calls; return *this; } |
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: |
57 | movable_swap_member() {} |
58 | movable_swap_member(BOOST_RV_REF(movable_swap_member)) { ++move_cnstor_calls; } |
59 | movable_swap_member & operator=(BOOST_RV_REF(movable_swap_member)){ ++move_assign_calls; return *this; } |
60 | void swap(movable_swap_member &) { ++member_swap_calls; } |
61 | friend void swap(movable_swap_member &, movable_swap_member &) { ++friend_swap_calls; } |
62 | }; |
63 | |
64 | class copyable : public swap_stats |
65 | { |
66 | public: |
67 | copyable() {} |
68 | copyable(const copyable &) { ++copy_cnstor_calls; } |
69 | copyable & operator=(const copyable&) { ++copy_assign_calls; return *this; } |
70 | void swap(copyable &) { ++member_swap_calls; } |
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: |
78 | explicit no_swap(unsigned i): m_state(i){} |
79 | no_swap(const no_swap &x) { m_state = x.m_state; ++copy_cnstor_calls; } |
80 | no_swap & operator=(const no_swap& x) { m_state = x.m_state; ++copy_assign_calls; return *this; } |
81 | void swap(no_swap &) { ++member_swap_calls; } |
82 | friend bool operator==(const no_swap &x, const no_swap &y) { return x.m_state == y.m_state; } |
83 | friend bool operator!=(const no_swap &x, const no_swap &y) { return !(x==y); } |
84 | }; |
85 | |
86 | |
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 | |