1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // |
3 | // (C) Copyright David Abrahams, Vicente Botet, Ion Gaztanaga 2010-2012. |
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/utility_core.hpp> |
12 | #include <boost/move/detail/meta_utils.hpp> |
13 | #include <cassert> |
14 | #include <new> |
15 | #include <boost/move/detail/move_helpers.hpp> |
16 | #include <boost/core/lightweight_test.hpp> |
17 | |
18 | |
19 | enum ConstructionType { Copied, Moved, Other }; |
20 | |
21 | class conversion_source |
22 | { |
23 | public: |
24 | conversion_source(){} |
25 | operator int() const { return 0; } |
26 | }; |
27 | |
28 | class conversion_target |
29 | { |
30 | ConstructionType c_type_; |
31 | public: |
32 | conversion_target(conversion_source) |
33 | { c_type_ = Other; } |
34 | conversion_target() |
35 | { c_type_ = Other; } |
36 | conversion_target(const conversion_target &) |
37 | { c_type_ = Copied; } |
38 | ConstructionType construction_type() const |
39 | { return c_type_; } |
40 | }; |
41 | |
42 | |
43 | class conversion_target_copymovable |
44 | { |
45 | ConstructionType c_type_; |
46 | BOOST_COPYABLE_AND_MOVABLE(conversion_target_copymovable) |
47 | public: |
48 | conversion_target_copymovable() |
49 | { c_type_ = Other; } |
50 | conversion_target_copymovable(conversion_source) |
51 | { c_type_ = Other; } |
52 | conversion_target_copymovable(const conversion_target_copymovable &) |
53 | { c_type_ = Copied; } |
54 | conversion_target_copymovable(BOOST_RV_REF(conversion_target_copymovable) ) |
55 | { c_type_ = Moved; } |
56 | conversion_target_copymovable &operator=(BOOST_RV_REF(conversion_target_copymovable) ) |
57 | { c_type_ = Moved; return *this; } |
58 | conversion_target_copymovable &operator=(BOOST_COPY_ASSIGN_REF(conversion_target_copymovable) ) |
59 | { c_type_ = Copied; return *this; } |
60 | ConstructionType construction_type() const |
61 | { return c_type_; } |
62 | }; |
63 | |
64 | class conversion_target_movable |
65 | { |
66 | ConstructionType c_type_; |
67 | BOOST_MOVABLE_BUT_NOT_COPYABLE(conversion_target_movable) |
68 | public: |
69 | conversion_target_movable() |
70 | { c_type_ = Other; } |
71 | conversion_target_movable(conversion_source) |
72 | { c_type_ = Other; } |
73 | conversion_target_movable(BOOST_RV_REF(conversion_target_movable) ) |
74 | { c_type_ = Moved; } |
75 | conversion_target_movable &operator=(BOOST_RV_REF(conversion_target_movable) ) |
76 | { c_type_ = Moved; return *this; } |
77 | ConstructionType construction_type() const |
78 | { return c_type_; } |
79 | }; |
80 | |
81 | |
82 | template<class T> |
83 | class container |
84 | { |
85 | T *storage_; |
86 | public: |
87 | struct const_iterator{}; |
88 | struct iterator : const_iterator{}; |
89 | container() |
90 | : storage_(0) |
91 | {} |
92 | |
93 | ~container() |
94 | { delete storage_; } |
95 | |
96 | container(const container &c) |
97 | : storage_(c.storage_ ? new T(*c.storage_) : 0) |
98 | {} |
99 | |
100 | container &operator=(const container &c) |
101 | { |
102 | if(storage_){ |
103 | delete storage_; |
104 | storage_ = 0; |
105 | } |
106 | storage_ = c.storage_ ? new T(*c.storage_) : 0; |
107 | return *this; |
108 | } |
109 | |
110 | BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) |
111 | |
112 | BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator, const_iterator) |
113 | |
114 | template <class Iterator> |
115 | iterator insert(Iterator, Iterator){ return iterator(); } |
116 | |
117 | ConstructionType construction_type() const |
118 | { return construction_type_impl |
119 | (typename ::boost::move_detail::integral_constant<bool, ::boost::move_detail::is_class_or_union<T>::value>()); |
120 | } |
121 | |
122 | ConstructionType construction_type_impl(::boost::move_detail::true_type) const |
123 | { return storage_->construction_type(); } |
124 | |
125 | ConstructionType construction_type_impl(::boost::move_detail::false_type) const |
126 | { return Copied; } |
127 | |
128 | iterator begin() const { return iterator(); } |
129 | |
130 | private: |
131 | template<class U> |
132 | void priv_construct(BOOST_MOVE_CATCH_FWD(U) x) |
133 | { |
134 | if(storage_){ |
135 | delete storage_; |
136 | storage_ = 0; |
137 | } |
138 | storage_ = new T(::boost::forward<U>(x)); |
139 | } |
140 | |
141 | template<class U> |
142 | void priv_push_back(BOOST_MOVE_CATCH_FWD(U) x) |
143 | { priv_construct(::boost::forward<U>(x)); } |
144 | |
145 | template<class U> |
146 | iterator priv_insert(const_iterator, BOOST_MOVE_CATCH_FWD(U) x) |
147 | { priv_construct(::boost::forward<U>(x)); return iterator(); } |
148 | }; |
149 | |
150 | class recursive_container |
151 | { |
152 | BOOST_COPYABLE_AND_MOVABLE(recursive_container) |
153 | public: |
154 | recursive_container() |
155 | {} |
156 | |
157 | recursive_container(const recursive_container &c) |
158 | : container_(c.container_) |
159 | {} |
160 | |
161 | recursive_container(BOOST_RV_REF(recursive_container) c) |
162 | : container_(::boost::move(t&: c.container_)) |
163 | {} |
164 | |
165 | recursive_container & operator =(BOOST_COPY_ASSIGN_REF(recursive_container) c) |
166 | { |
167 | container_= c.container_; |
168 | return *this; |
169 | } |
170 | |
171 | recursive_container & operator =(BOOST_RV_REF(recursive_container) c) |
172 | { |
173 | container_= ::boost::move(t&: c.container_); |
174 | return *this; |
175 | } |
176 | |
177 | container<recursive_container> container_; |
178 | friend bool operator< (const recursive_container &a, const recursive_container &b) |
179 | { return &a < &b; } |
180 | }; |
181 | |
182 | |
183 | int main() |
184 | { |
185 | conversion_target_movable a; |
186 | conversion_target_movable b(::boost::move(t&: a)); |
187 | { |
188 | container<conversion_target> c; |
189 | { |
190 | conversion_target x; |
191 | c.push_back(x); |
192 | BOOST_TEST(c.construction_type() == Copied); |
193 | c.insert(arg1: c.begin(), x); |
194 | BOOST_TEST(c.construction_type() == Copied); |
195 | } |
196 | { |
197 | const conversion_target x; |
198 | c.push_back(x); |
199 | BOOST_TEST(c.construction_type() == Copied); |
200 | c.insert(arg1: c.begin(), x); |
201 | BOOST_TEST(c.construction_type() == Copied); |
202 | } |
203 | { |
204 | c.push_back(x: conversion_target()); |
205 | BOOST_TEST(c.construction_type() == Copied); |
206 | c.insert(arg1: c.begin(), x: conversion_target()); |
207 | BOOST_TEST(c.construction_type() == Copied); |
208 | } |
209 | { |
210 | conversion_source x; |
211 | c.push_back(x); |
212 | BOOST_TEST(c.construction_type() == Copied); |
213 | c.insert(arg1: c.begin(), x); |
214 | BOOST_TEST(c.construction_type() == Copied); |
215 | } |
216 | { |
217 | const conversion_source x; |
218 | c.push_back(x); |
219 | BOOST_TEST(c.construction_type() == Copied); |
220 | c.insert(arg1: c.begin(), x); |
221 | BOOST_TEST(c.construction_type() == Copied); |
222 | } |
223 | { |
224 | c.push_back(x: conversion_source()); |
225 | BOOST_TEST(c.construction_type() == Copied); |
226 | c.insert(arg1: c.begin(), x: conversion_source()); |
227 | BOOST_TEST(c.construction_type() == Copied); |
228 | } |
229 | } |
230 | |
231 | { |
232 | container<conversion_target_copymovable> c; |
233 | { |
234 | conversion_target_copymovable x; |
235 | c.push_back(x); |
236 | BOOST_TEST(c.construction_type() == Copied); |
237 | c.insert(arg1: c.begin(), x); |
238 | BOOST_TEST(c.construction_type() == Copied); |
239 | } |
240 | { |
241 | const conversion_target_copymovable x; |
242 | c.push_back(x); |
243 | BOOST_TEST(c.construction_type() == Copied); |
244 | c.insert(arg1: c.begin(), x); |
245 | BOOST_TEST(c.construction_type() == Copied); |
246 | } |
247 | { |
248 | c.push_back(x: conversion_target_copymovable()); |
249 | BOOST_TEST(c.construction_type() == Moved); |
250 | c.insert(arg1: c.begin(), x: conversion_target_copymovable()); |
251 | BOOST_TEST(c.construction_type() == Moved); |
252 | } |
253 | { |
254 | conversion_source x; |
255 | c.push_back(x); |
256 | BOOST_TEST(c.construction_type() == Moved); |
257 | c.insert(arg1: c.begin(), x); |
258 | BOOST_TEST(c.construction_type() == Moved); |
259 | } |
260 | { |
261 | const conversion_source x; |
262 | c.push_back(x); |
263 | BOOST_TEST(c.construction_type() == Moved); |
264 | c.insert(arg1: c.begin(), x); |
265 | BOOST_TEST(c.construction_type() == Moved); |
266 | } |
267 | { |
268 | c.push_back(x: conversion_source()); |
269 | BOOST_TEST(c.construction_type() == Moved); |
270 | c.insert(arg1: c.begin(), x: conversion_source()); |
271 | BOOST_TEST(c.construction_type() == Moved); |
272 | } |
273 | } |
274 | { |
275 | container<conversion_target_movable> c; |
276 | //This should not compile |
277 | //{ |
278 | // conversion_target_movable x; |
279 | // c.push_back(x); |
280 | // BOOST_TEST(c.construction_type() == Copied); |
281 | //} |
282 | //{ |
283 | // const conversion_target_movable x; |
284 | // c.push_back(x); |
285 | // BOOST_TEST(c.construction_type() == Copied); |
286 | //} |
287 | { |
288 | c.push_back(x: conversion_target_movable()); |
289 | BOOST_TEST(c.construction_type() == Moved); |
290 | c.insert(arg1: c.begin(), x: conversion_target_movable()); |
291 | BOOST_TEST(c.construction_type() == Moved); |
292 | } |
293 | { |
294 | conversion_source x; |
295 | c.push_back(x); |
296 | BOOST_TEST(c.construction_type() == Moved); |
297 | c.insert(arg1: c.begin(), x); |
298 | BOOST_TEST(c.construction_type() == Moved); |
299 | } |
300 | { |
301 | const conversion_source x; |
302 | c.push_back(x); |
303 | BOOST_TEST(c.construction_type() == Moved); |
304 | c.insert(arg1: c.begin(), x); |
305 | BOOST_TEST(c.construction_type() == Moved); |
306 | } |
307 | { |
308 | c.push_back(x: conversion_source()); |
309 | BOOST_TEST(c.construction_type() == Moved); |
310 | c.insert(arg1: c.begin(), x: conversion_source()); |
311 | BOOST_TEST(c.construction_type() == Moved); |
312 | } |
313 | } |
314 | { |
315 | container<int> c; |
316 | { |
317 | int x = 0; |
318 | c.push_back(x); |
319 | BOOST_TEST(c.construction_type() == Copied); |
320 | c.insert(arg1: c.begin(), x: c.construction_type()); |
321 | BOOST_TEST(c.construction_type() == Copied); |
322 | } |
323 | { |
324 | const int x = 0; |
325 | c.push_back(x); |
326 | BOOST_TEST(c.construction_type() == Copied); |
327 | c.insert(arg1: c.begin(), x); |
328 | BOOST_TEST(c.construction_type() == Copied); |
329 | } |
330 | { |
331 | c.push_back(x: int(0)); |
332 | BOOST_TEST(c.construction_type() == Copied); |
333 | c.insert(arg1: c.begin(), x: int(0)); |
334 | BOOST_TEST(c.construction_type() == Copied); |
335 | } |
336 | { |
337 | conversion_source x; |
338 | c.push_back(x); |
339 | BOOST_TEST(c.construction_type() == Copied); |
340 | c.insert(arg1: c.begin(), x); |
341 | BOOST_TEST(c.construction_type() == Copied); |
342 | } |
343 | |
344 | { |
345 | const conversion_source x; |
346 | c.push_back(x); |
347 | BOOST_TEST(c.construction_type() == Copied); |
348 | c.insert(arg1: c.begin(), x); |
349 | BOOST_TEST(c.construction_type() == Copied); |
350 | } |
351 | { |
352 | c.push_back(x: conversion_source()); |
353 | BOOST_TEST(c.construction_type() == Copied); |
354 | c.insert(arg1: c.begin(), x: conversion_source()); |
355 | BOOST_TEST(c.construction_type() == Copied); |
356 | } |
357 | //c.insert(c.begin(), c.begin()); |
358 | } |
359 | |
360 | { |
361 | container<int> c; |
362 | { |
363 | int x = 0; |
364 | c.push_back(x); |
365 | BOOST_TEST(c.construction_type() == Copied); |
366 | c.insert(arg1: c.begin(), x: c.construction_type()); |
367 | BOOST_TEST(c.construction_type() == Copied); |
368 | } |
369 | { |
370 | const int x = 0; |
371 | c.push_back(x); |
372 | BOOST_TEST(c.construction_type() == Copied); |
373 | c.insert(arg1: c.begin(), x); |
374 | BOOST_TEST(c.construction_type() == Copied); |
375 | } |
376 | { |
377 | c.push_back(x: int(0)); |
378 | BOOST_TEST(c.construction_type() == Copied); |
379 | c.insert(arg1: c.begin(), x: int(0)); |
380 | BOOST_TEST(c.construction_type() == Copied); |
381 | } |
382 | { |
383 | conversion_source x; |
384 | c.push_back(x); |
385 | BOOST_TEST(c.construction_type() == Copied); |
386 | c.insert(arg1: c.begin(), x); |
387 | BOOST_TEST(c.construction_type() == Copied); |
388 | } |
389 | |
390 | { |
391 | const conversion_source x; |
392 | c.push_back(x); |
393 | BOOST_TEST(c.construction_type() == Copied); |
394 | c.insert(arg1: c.begin(), x); |
395 | BOOST_TEST(c.construction_type() == Copied); |
396 | } |
397 | { |
398 | c.push_back(x: conversion_source()); |
399 | BOOST_TEST(c.construction_type() == Copied); |
400 | c.insert(arg1: c.begin(), x: conversion_source()); |
401 | BOOST_TEST(c.construction_type() == Copied); |
402 | } |
403 | c.insert(c.begin(), c.begin()); |
404 | } |
405 | |
406 | { |
407 | recursive_container c; |
408 | recursive_container internal; |
409 | c.container_.insert(arg1: c.container_.begin(), x: recursive_container()); |
410 | c.container_.insert(arg1: c.container_.begin(), x: internal); |
411 | c.container_.insert(c.container_.begin(), c.container_.begin()); |
412 | } |
413 | |
414 | return boost::report_errors(); |
415 | } |
416 | |