]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | //----------------------------------------------------------------------------- |
2 | // boost-libs variant/test/rvalue_test.cpp source file | |
3 | // See http://www.boost.org for updates, documentation, and revision history. | |
4 | //----------------------------------------------------------------------------- | |
5 | // | |
f67539c2 | 6 | // Copyright (c) 2012-2020 Antony Polukhin |
7c673cae FG |
7 | // |
8 | // Distributed under the Boost Software License, Version 1.0. (See | |
9 | // accompanying file LICENSE_1_0.txt or copy at | |
10 | // http://www.boost.org/LICENSE_1_0.txt) | |
11 | ||
12 | #include "boost/config.hpp" | |
13 | ||
92f5a8d4 | 14 | #include "boost/core/lightweight_test.hpp" |
7c673cae FG |
15 | #include "boost/variant.hpp" |
16 | #include "boost/type_traits/is_nothrow_move_assignable.hpp" | |
17 | #include "boost/mpl/bool.hpp" | |
18 | ||
19 | #include <boost/blank.hpp> | |
20 | #include <boost/swap.hpp> | |
21 | ||
22 | namespace swap_ambiguouty_test_ns { | |
23 | struct A {}; | |
24 | struct B {}; | |
25 | ||
26 | void swap_ambiguouty_test() { | |
27 | // If boost::blank is not used, then it compiles. | |
28 | typedef boost::variant<boost::blank, A, B> Variant; | |
29 | Variant v1, v2; | |
30 | swap(v1, v2); | |
31 | } | |
32 | } // namespace swap_ambiguouty_test_ns | |
33 | ||
34 | // Most part of tests from this file require rvalue references support | |
35 | ||
36 | class move_copy_conting_class { | |
37 | public: | |
38 | static unsigned int moves_count; | |
39 | static unsigned int copy_count; | |
40 | ||
41 | move_copy_conting_class(){} | |
42 | move_copy_conting_class(BOOST_RV_REF(move_copy_conting_class) ) { | |
43 | ++ moves_count; | |
44 | } | |
45 | ||
46 | move_copy_conting_class& operator=(BOOST_RV_REF(move_copy_conting_class) ) { | |
47 | ++ moves_count; | |
48 | return *this; | |
49 | } | |
50 | ||
51 | move_copy_conting_class(const move_copy_conting_class&) { | |
52 | ++ copy_count; | |
53 | } | |
54 | move_copy_conting_class& operator=(BOOST_COPY_ASSIGN_REF(move_copy_conting_class) ) { | |
55 | ++ copy_count; | |
56 | return *this; | |
57 | } | |
58 | }; | |
59 | ||
60 | unsigned int move_copy_conting_class::moves_count = 0; | |
61 | unsigned int move_copy_conting_class::copy_count = 0; | |
62 | ||
63 | #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES | |
64 | ||
65 | void run() | |
66 | { | |
67 | // Making sure that internals of Boost.Move do not interfere with | |
68 | // internals of Boost.Variant and in case of C++03 or C++98 compilation | |
69 | // is still possible. | |
70 | typedef boost::variant<int, move_copy_conting_class> variant_I_type; | |
71 | variant_I_type v1, v2; | |
72 | v1 = move_copy_conting_class(); | |
73 | v2 = v1; | |
74 | v2 = boost::move(v1); | |
75 | v1.swap(v2); | |
76 | ||
77 | move_copy_conting_class val; | |
78 | v2 = boost::move(val); | |
79 | v2 = 10; | |
80 | ||
81 | variant_I_type v3(boost::move(val)); | |
82 | variant_I_type v4(boost::move(v1)); | |
83 | } | |
84 | ||
85 | void run1() | |
86 | { | |
92f5a8d4 | 87 | BOOST_TEST(true); |
7c673cae FG |
88 | } |
89 | ||
90 | void run_move_only() | |
91 | { | |
92f5a8d4 | 92 | BOOST_TEST(true); |
7c673cae FG |
93 | } |
94 | ||
95 | void run_moves_are_noexcept() | |
96 | { | |
92f5a8d4 | 97 | BOOST_TEST(true); |
7c673cae FG |
98 | } |
99 | ||
100 | ||
101 | void run_const_rvalues() | |
102 | { | |
92f5a8d4 | 103 | BOOST_TEST(true); |
7c673cae FG |
104 | } |
105 | ||
106 | ||
107 | #else | |
108 | ||
109 | ||
110 | void run() | |
111 | { | |
112 | typedef boost::variant<int, move_copy_conting_class> variant_I_type; | |
113 | variant_I_type v1, v2; | |
114 | ||
115 | // Assuring that `move_copy_conting_class` was not created | |
92f5a8d4 TL |
116 | BOOST_TEST(move_copy_conting_class::copy_count == 0); |
117 | BOOST_TEST(move_copy_conting_class::moves_count == 0); | |
7c673cae FG |
118 | |
119 | v1 = move_copy_conting_class(); | |
120 | // Assuring that `move_copy_conting_class` was moved at least once | |
92f5a8d4 | 121 | BOOST_TEST(move_copy_conting_class::moves_count != 0); |
7c673cae FG |
122 | |
123 | unsigned int total_count = move_copy_conting_class::moves_count + move_copy_conting_class::copy_count; | |
124 | move_copy_conting_class var; | |
125 | v1 = 0; | |
126 | move_copy_conting_class::moves_count = 0; | |
127 | move_copy_conting_class::copy_count = 0; | |
128 | v1 = var; | |
129 | // Assuring that move assignment operator moves/copyes value not more times than copy assignment operator | |
92f5a8d4 | 130 | BOOST_TEST(total_count <= move_copy_conting_class::moves_count + move_copy_conting_class::copy_count); |
7c673cae FG |
131 | |
132 | move_copy_conting_class::moves_count = 0; | |
133 | move_copy_conting_class::copy_count = 0; | |
134 | v2 = boost::move(v1); | |
135 | // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied | |
92f5a8d4 TL |
136 | BOOST_TEST(move_copy_conting_class::moves_count != 0); |
137 | BOOST_TEST(move_copy_conting_class::copy_count == 0); | |
7c673cae FG |
138 | |
139 | v1 = move_copy_conting_class(); | |
140 | move_copy_conting_class::moves_count = 0; | |
141 | move_copy_conting_class::copy_count = 0; | |
142 | v2 = boost::move(v1); | |
143 | // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied | |
92f5a8d4 TL |
144 | BOOST_TEST(move_copy_conting_class::moves_count != 0); |
145 | BOOST_TEST(move_copy_conting_class::copy_count == 0); | |
7c673cae FG |
146 | total_count = move_copy_conting_class::moves_count + move_copy_conting_class::copy_count; |
147 | move_copy_conting_class::moves_count = 0; | |
148 | move_copy_conting_class::copy_count = 0; | |
149 | v1 = v2; | |
150 | // Assuring that move assignment operator moves/copyes value not more times than copy assignment operator | |
92f5a8d4 | 151 | BOOST_TEST(total_count <= move_copy_conting_class::moves_count + move_copy_conting_class::copy_count); |
7c673cae FG |
152 | |
153 | ||
154 | typedef boost::variant<move_copy_conting_class, int> variant_II_type; | |
155 | variant_II_type v3; | |
156 | move_copy_conting_class::moves_count = 0; | |
157 | move_copy_conting_class::copy_count = 0; | |
158 | v1 = boost::move(v3); | |
159 | // Assuring that `move_copy_conting_class` in v3 was moved at least once (v1 and v3 have different types) | |
92f5a8d4 | 160 | BOOST_TEST(move_copy_conting_class::moves_count != 0); |
7c673cae FG |
161 | |
162 | move_copy_conting_class::moves_count = 0; | |
163 | move_copy_conting_class::copy_count = 0; | |
164 | v2 = boost::move(v1); | |
165 | // Assuring that `move_copy_conting_class` in v1 was moved at least once (v1 and v3 have different types) | |
92f5a8d4 | 166 | BOOST_TEST(move_copy_conting_class::moves_count != 0); |
7c673cae FG |
167 | |
168 | move_copy_conting_class::moves_count = 0; | |
169 | move_copy_conting_class::copy_count = 0; | |
170 | variant_I_type v5(boost::move(v1)); | |
171 | // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied | |
92f5a8d4 TL |
172 | BOOST_TEST(move_copy_conting_class::moves_count != 0); |
173 | BOOST_TEST(move_copy_conting_class::copy_count == 0); | |
7c673cae FG |
174 | |
175 | total_count = move_copy_conting_class::moves_count + move_copy_conting_class::copy_count; | |
176 | move_copy_conting_class::moves_count = 0; | |
177 | move_copy_conting_class::copy_count = 0; | |
178 | variant_I_type v6(v1); | |
179 | // Assuring that move constructor moves/copyes value not more times than copy constructor | |
92f5a8d4 | 180 | BOOST_TEST(total_count <= move_copy_conting_class::moves_count + move_copy_conting_class::copy_count); |
7c673cae FG |
181 | } |
182 | ||
183 | void run1() | |
184 | { | |
185 | move_copy_conting_class::moves_count = 0; | |
186 | move_copy_conting_class::copy_count = 0; | |
187 | ||
188 | move_copy_conting_class c1; | |
189 | typedef boost::variant<int, move_copy_conting_class> variant_I_type; | |
190 | variant_I_type v1(boost::move(c1)); | |
191 | ||
192 | // Assuring that `move_copy_conting_class` was not copyied | |
92f5a8d4 TL |
193 | BOOST_TEST(move_copy_conting_class::copy_count == 0); |
194 | BOOST_TEST(move_copy_conting_class::moves_count > 0); | |
7c673cae FG |
195 | } |
196 | ||
197 | struct move_only_structure { | |
198 | move_only_structure(){} | |
199 | move_only_structure(move_only_structure&&){} | |
200 | move_only_structure& operator=(move_only_structure&&) { return *this; } | |
201 | ||
202 | private: | |
203 | move_only_structure(const move_only_structure&); | |
204 | move_only_structure& operator=(const move_only_structure&); | |
205 | }; | |
206 | ||
207 | struct visitor_returning_move_only_type: boost::static_visitor<move_only_structure> { | |
208 | template <class T> | |
209 | move_only_structure operator()(const T&) const { | |
210 | return move_only_structure(); | |
211 | } | |
212 | }; | |
213 | ||
214 | void run_move_only() | |
215 | { | |
216 | move_only_structure mo; | |
217 | boost::variant<int, move_only_structure > vi, vi2(static_cast<move_only_structure&&>(mo)); | |
92f5a8d4 TL |
218 | BOOST_TEST(vi.which() == 0); |
219 | BOOST_TEST(vi2.which() == 1); | |
7c673cae FG |
220 | |
221 | vi = 10; | |
222 | vi2 = 10; | |
92f5a8d4 TL |
223 | BOOST_TEST(vi.which() == 0); |
224 | BOOST_TEST(vi2.which() == 0); | |
7c673cae FG |
225 | |
226 | vi = static_cast<move_only_structure&&>(mo); | |
227 | vi2 = static_cast<move_only_structure&&>(mo); | |
92f5a8d4 | 228 | BOOST_TEST(vi.which() == 1); |
7c673cae FG |
229 | |
230 | boost::variant<move_only_structure, int > rvi (1); | |
92f5a8d4 | 231 | BOOST_TEST(rvi.which() == 1); |
7c673cae | 232 | rvi = static_cast<move_only_structure&&>(mo); |
92f5a8d4 | 233 | BOOST_TEST(rvi.which() == 0); |
7c673cae | 234 | rvi = 1; |
92f5a8d4 | 235 | BOOST_TEST(rvi.which() == 1); |
7c673cae | 236 | rvi = static_cast<boost::variant<int, move_only_structure >&&>(vi2); |
92f5a8d4 | 237 | BOOST_TEST(rvi.which() == 0); |
7c673cae FG |
238 | |
239 | move_only_structure from_visitor = boost::apply_visitor(visitor_returning_move_only_type(), vi); | |
240 | (void)from_visitor; | |
241 | } | |
242 | ||
243 | void run_moves_are_noexcept() { | |
244 | #if !defined(BOOST_NO_CXX11_NOEXCEPT) && (!defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || __GNUC_MINOR__ >= 8) | |
245 | typedef boost::variant<int, short, double> variant_noexcept_t; | |
92f5a8d4 TL |
246 | BOOST_TEST(boost::is_nothrow_move_assignable<variant_noexcept_t>::value); |
247 | BOOST_TEST(boost::is_nothrow_move_constructible<variant_noexcept_t>::value); | |
7c673cae FG |
248 | |
249 | typedef boost::variant<int, short, double, move_only_structure> variant_except_t; | |
92f5a8d4 TL |
250 | BOOST_TEST(!boost::is_nothrow_move_assignable<variant_except_t>::value); |
251 | BOOST_TEST(!boost::is_nothrow_move_constructible<variant_except_t>::value); | |
7c673cae FG |
252 | #endif |
253 | } | |
254 | ||
255 | inline const std::string get_string() { return "test"; } | |
256 | inline const boost::variant<int, std::string> get_variant() { return std::string("test"); } | |
257 | inline const boost::variant<std::string, int> get_variant2() { return std::string("test"); } | |
258 | ||
259 | void run_const_rvalues() | |
260 | { | |
261 | typedef boost::variant<int, std::string> variant_t; | |
262 | const variant_t v1(get_string()); | |
263 | const variant_t v2(get_variant()); | |
264 | const variant_t v3(get_variant2()); | |
265 | ||
266 | variant_t v4, v5, v6, v7; | |
267 | v4 = get_string(); | |
268 | v5 = get_variant(); | |
269 | v6 = get_variant2(); | |
270 | v7 = boost::move(v1); | |
271 | } | |
272 | ||
273 | #endif | |
274 | ||
275 | struct nothrow_copyable_throw_movable { | |
276 | nothrow_copyable_throw_movable(){} | |
277 | nothrow_copyable_throw_movable(const nothrow_copyable_throw_movable&) BOOST_NOEXCEPT {} | |
278 | nothrow_copyable_throw_movable& operator=(const nothrow_copyable_throw_movable&) BOOST_NOEXCEPT { return *this; } | |
279 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | |
280 | nothrow_copyable_throw_movable(nothrow_copyable_throw_movable&&) BOOST_NOEXCEPT_IF(false) {} | |
281 | nothrow_copyable_throw_movable& operator=(nothrow_copyable_throw_movable&&) BOOST_NOEXCEPT_IF(false) { return *this; } | |
282 | #endif | |
283 | }; | |
284 | ||
285 | // This test is created to cover the following situation: | |
286 | // https://svn.boost.org/trac/boost/ticket/8772 | |
287 | void run_tricky_compilation_test() | |
288 | { | |
289 | boost::variant<int, nothrow_copyable_throw_movable> v; | |
290 | v = nothrow_copyable_throw_movable(); | |
291 | } | |
292 | ||
293 | template <typename T> | |
294 | struct is_container : boost::mpl::false_ {}; | |
295 | ||
296 | template <typename T> | |
297 | struct is_container<boost::variant<T> > : is_container<T> {}; | |
298 | ||
299 | template <BOOST_VARIANT_ENUM_PARAMS(typename T)> | |
300 | struct is_container<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > | |
301 | : boost::mpl::bool_<is_container<T0>::value | |
302 | || is_container<boost::variant<BOOST_VARIANT_ENUM_SHIFTED_PARAMS(T)> >::value> | |
303 | {}; | |
304 | ||
305 | void run_is_container_compilation_test() | |
306 | { | |
92f5a8d4 TL |
307 | BOOST_TEST((!is_container<boost::variant<double, int> >::value)); |
308 | BOOST_TEST((!is_container<boost::variant<double, int, char> >::value)); | |
309 | BOOST_TEST((!is_container<boost::variant<double, int, char, float> >::value)); | |
7c673cae FG |
310 | } |
311 | ||
92f5a8d4 | 312 | int main() |
7c673cae FG |
313 | { |
314 | swap_ambiguouty_test_ns::swap_ambiguouty_test(); | |
315 | run(); | |
316 | run1(); | |
317 | run_move_only(); | |
318 | run_moves_are_noexcept(); | |
319 | run_tricky_compilation_test(); | |
320 | run_const_rvalues(); | |
321 | run_is_container_compilation_test(); | |
322 | ||
323 | #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ > 6) | |
324 | # ifdef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES | |
92f5a8d4 | 325 | BOOST_TEST(false && |
7c673cae FG |
326 | "Something wrong with macro definitions. GCC-4.7+ is known to work with variadic templates" |
327 | ); | |
328 | # endif | |
329 | #endif | |
330 | ||
92f5a8d4 | 331 | return boost::report_errors(); |
7c673cae | 332 | } |