1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // |
3 | // (C) Copyright Ion Gaztanaga 2012-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 | |
12 | //! \file |
13 | //! This header implements macros to define movable classes and |
14 | //! move-aware functions |
15 | |
16 | #ifndef BOOST_MOVE_CORE_HPP |
17 | #define BOOST_MOVE_CORE_HPP |
18 | |
19 | #ifndef BOOST_CONFIG_HPP |
20 | # include <boost/config.hpp> |
21 | #endif |
22 | # |
23 | #if defined(BOOST_HAS_PRAGMA_ONCE) |
24 | # pragma once |
25 | #endif |
26 | |
27 | #include <boost/move/detail/config_begin.hpp> |
28 | #include <boost/move/detail/workaround.hpp> |
29 | |
30 | // @cond |
31 | |
32 | //boost_move_no_copy_constructor_or_assign typedef |
33 | //used to detect noncopyable types for other Boost libraries. |
34 | #if defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
35 | #define BOOST_MOVE_IMPL_NO_COPY_CTOR_OR_ASSIGN(TYPE) \ |
36 | private:\ |
37 | TYPE(TYPE &);\ |
38 | TYPE& operator=(TYPE &);\ |
39 | public:\ |
40 | typedef int boost_move_no_copy_constructor_or_assign; \ |
41 | private:\ |
42 | // |
43 | #else |
44 | #define BOOST_MOVE_IMPL_NO_COPY_CTOR_OR_ASSIGN(TYPE) \ |
45 | public:\ |
46 | TYPE(TYPE const &) = delete;\ |
47 | TYPE& operator=(TYPE const &) = delete;\ |
48 | public:\ |
49 | typedef int boost_move_no_copy_constructor_or_assign; \ |
50 | private:\ |
51 | // |
52 | #endif //BOOST_NO_CXX11_DELETED_FUNCTIONS |
53 | |
54 | // @endcond |
55 | |
56 | #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_MOVE_DOXYGEN_INVOKED) |
57 | |
58 | #include <boost/move/detail/type_traits.hpp> |
59 | |
60 | #define BOOST_MOVE_TO_RV_CAST(RV_TYPE, ARG) reinterpret_cast<RV_TYPE>(ARG) |
61 | #define BOOST_MOVE_TO_LV_CAST(LV_TYPE, ARG) static_cast<LV_TYPE>(ARG) |
62 | |
63 | //Move emulation rv breaks standard aliasing rules so add workarounds for some compilers |
64 | #if defined(BOOST_GCC) && (BOOST_GCC >= 40400) && (BOOST_GCC < 40500) |
65 | #define BOOST_RV_ATTRIBUTE_MAY_ALIAS BOOST_MAY_ALIAS |
66 | #else |
67 | #define BOOST_RV_ATTRIBUTE_MAY_ALIAS |
68 | #endif |
69 | |
70 | namespace boost { |
71 | |
72 | ////////////////////////////////////////////////////////////////////////////// |
73 | // |
74 | // struct rv |
75 | // |
76 | ////////////////////////////////////////////////////////////////////////////// |
77 | template <class T> |
78 | class BOOST_RV_ATTRIBUTE_MAY_ALIAS rv |
79 | : public ::boost::move_detail::if_c |
80 | < ::boost::move_detail::is_class<T>::value |
81 | , T |
82 | , ::boost::move_detail::nat |
83 | >::type |
84 | { |
85 | rv(); |
86 | ~rv() throw(); |
87 | rv(rv const&); |
88 | void operator=(rv const&); |
89 | }; |
90 | |
91 | |
92 | ////////////////////////////////////////////////////////////////////////////// |
93 | // |
94 | // is_rv |
95 | // |
96 | ////////////////////////////////////////////////////////////////////////////// |
97 | |
98 | namespace move_detail { |
99 | |
100 | template <class T> |
101 | struct is_rv |
102 | //Derive from integral constant because some Boost code assummes it has |
103 | //a "type" internal typedef |
104 | : integral_constant<bool, ::boost::move_detail::is_rv_impl<T>::value > |
105 | {}; |
106 | |
107 | template <class T> |
108 | struct is_not_rv |
109 | { |
110 | static const bool value = !is_rv<T>::value; |
111 | }; |
112 | |
113 | } //namespace move_detail { |
114 | |
115 | ////////////////////////////////////////////////////////////////////////////// |
116 | // |
117 | // has_move_emulation_enabled |
118 | // |
119 | ////////////////////////////////////////////////////////////////////////////// |
120 | template<class T> |
121 | struct has_move_emulation_enabled |
122 | : ::boost::move_detail::has_move_emulation_enabled_impl<T> |
123 | {}; |
124 | |
125 | template<class T> |
126 | struct has_move_emulation_disabled |
127 | { |
128 | static const bool value = !::boost::move_detail::has_move_emulation_enabled_impl<T>::value; |
129 | }; |
130 | |
131 | } //namespace boost { |
132 | |
133 | #define BOOST_RV_REF(TYPE)\ |
134 | ::boost::rv< TYPE >& \ |
135 | // |
136 | |
137 | #define BOOST_RV_REF_2_TEMPL_ARGS(TYPE, ARG1, ARG2)\ |
138 | ::boost::rv< TYPE<ARG1, ARG2> >& \ |
139 | // |
140 | |
141 | #define BOOST_RV_REF_3_TEMPL_ARGS(TYPE, ARG1, ARG2, ARG3)\ |
142 | ::boost::rv< TYPE<ARG1, ARG2, ARG3> >& \ |
143 | // |
144 | |
145 | #define BOOST_RV_REF_BEG\ |
146 | ::boost::rv< \ |
147 | // |
148 | |
149 | #define BOOST_RV_REF_END\ |
150 | >& \ |
151 | // |
152 | |
153 | #define BOOST_RV_REF_BEG_IF_CXX11 \ |
154 | \ |
155 | // |
156 | |
157 | #define BOOST_RV_REF_END_IF_CXX11 \ |
158 | \ |
159 | // |
160 | |
161 | #define BOOST_FWD_REF(TYPE)\ |
162 | const TYPE & \ |
163 | // |
164 | |
165 | #define BOOST_COPY_ASSIGN_REF(TYPE)\ |
166 | const ::boost::rv< TYPE >& \ |
167 | // |
168 | |
169 | #define BOOST_COPY_ASSIGN_REF_BEG \ |
170 | const ::boost::rv< \ |
171 | // |
172 | |
173 | #define BOOST_COPY_ASSIGN_REF_END \ |
174 | >& \ |
175 | // |
176 | |
177 | #define BOOST_COPY_ASSIGN_REF_2_TEMPL_ARGS(TYPE, ARG1, ARG2)\ |
178 | const ::boost::rv< TYPE<ARG1, ARG2> >& \ |
179 | // |
180 | |
181 | #define BOOST_COPY_ASSIGN_REF_3_TEMPL_ARGS(TYPE, ARG1, ARG2, ARG3)\ |
182 | const ::boost::rv< TYPE<ARG1, ARG2, ARG3> >& \ |
183 | // |
184 | |
185 | #define BOOST_CATCH_CONST_RLVALUE(TYPE)\ |
186 | const ::boost::rv< TYPE >& \ |
187 | // |
188 | |
189 | namespace boost { |
190 | namespace move_detail { |
191 | |
192 | template <class Ret, class T> |
193 | BOOST_MOVE_FORCEINLINE typename ::boost::move_detail::enable_if_c |
194 | < ::boost::move_detail::is_lvalue_reference<Ret>::value || |
195 | !::boost::has_move_emulation_enabled<T>::value |
196 | , T&>::type |
197 | move_return(T& x) BOOST_NOEXCEPT |
198 | { |
199 | return x; |
200 | } |
201 | |
202 | template <class Ret, class T> |
203 | BOOST_MOVE_FORCEINLINE typename ::boost::move_detail::enable_if_c |
204 | < !::boost::move_detail::is_lvalue_reference<Ret>::value && |
205 | ::boost::has_move_emulation_enabled<T>::value |
206 | , ::boost::rv<T>&>::type |
207 | move_return(T& x) BOOST_NOEXCEPT |
208 | { |
209 | return *BOOST_MOVE_TO_RV_CAST(::boost::rv<T>*, ::boost::move_detail::addressof(x)); |
210 | } |
211 | |
212 | template <class Ret, class T> |
213 | BOOST_MOVE_FORCEINLINE typename ::boost::move_detail::enable_if_c |
214 | < !::boost::move_detail::is_lvalue_reference<Ret>::value && |
215 | ::boost::has_move_emulation_enabled<T>::value |
216 | , ::boost::rv<T>&>::type |
217 | move_return(::boost::rv<T>& x) BOOST_NOEXCEPT |
218 | { |
219 | return x; |
220 | } |
221 | |
222 | template <class T> |
223 | BOOST_MOVE_FORCEINLINE T& unrv(::boost::rv<T> &rv) BOOST_NOEXCEPT |
224 | { return BOOST_MOVE_TO_LV_CAST(T&, rv); } |
225 | |
226 | } //namespace move_detail { |
227 | } //namespace boost { |
228 | |
229 | #define BOOST_MOVE_RET(RET_TYPE, REF)\ |
230 | boost::move_detail::move_return< RET_TYPE >(REF) |
231 | // |
232 | |
233 | #define BOOST_MOVE_BASE(BASE_TYPE, ARG) \ |
234 | ::boost::move((BASE_TYPE&)(ARG)) |
235 | // |
236 | |
237 | #define BOOST_MOVE_TO_LV(ARG) \ |
238 | ::boost::move_detail::unrv(ARG) |
239 | // |
240 | |
241 | |
242 | ////////////////////////////////////////////////////////////////////////////// |
243 | // |
244 | // BOOST_MOVABLE_BUT_NOT_COPYABLE |
245 | // |
246 | ////////////////////////////////////////////////////////////////////////////// |
247 | #define BOOST_MOVABLE_BUT_NOT_COPYABLE(TYPE)\ |
248 | BOOST_MOVE_IMPL_NO_COPY_CTOR_OR_ASSIGN(TYPE)\ |
249 | public:\ |
250 | BOOST_MOVE_FORCEINLINE operator ::boost::rv<TYPE>&() \ |
251 | { return *BOOST_MOVE_TO_RV_CAST(::boost::rv<TYPE>*, this); }\ |
252 | BOOST_MOVE_FORCEINLINE operator const ::boost::rv<TYPE>&() const \ |
253 | { return *BOOST_MOVE_TO_RV_CAST(const ::boost::rv<TYPE>*, this); }\ |
254 | private:\ |
255 | // |
256 | |
257 | ////////////////////////////////////////////////////////////////////////////// |
258 | // |
259 | // BOOST_COPYABLE_AND_MOVABLE |
260 | // |
261 | ////////////////////////////////////////////////////////////////////////////// |
262 | |
263 | #define BOOST_COPYABLE_AND_MOVABLE(TYPE)\ |
264 | public:\ |
265 | inline TYPE& operator=(TYPE &t)\ |
266 | { this->operator=(const_cast<const TYPE&>(t)); return *this;}\ |
267 | public:\ |
268 | inline operator ::boost::rv<TYPE>&() \ |
269 | { return *BOOST_MOVE_TO_RV_CAST(::boost::rv<TYPE>*, this); }\ |
270 | inline operator const ::boost::rv<TYPE>&() const \ |
271 | { return *BOOST_MOVE_TO_RV_CAST(const ::boost::rv<TYPE>*, this); }\ |
272 | private:\ |
273 | // |
274 | |
275 | #define BOOST_COPYABLE_AND_MOVABLE_ALT(TYPE)\ |
276 | public:\ |
277 | BOOST_MOVE_FORCEINLINE operator ::boost::rv<TYPE>&() \ |
278 | { return *BOOST_MOVE_TO_RV_CAST(::boost::rv<TYPE>*, this); }\ |
279 | BOOST_MOVE_FORCEINLINE operator const ::boost::rv<TYPE>&() const \ |
280 | { return *BOOST_MOVE_TO_RV_CAST(const ::boost::rv<TYPE>*, this); }\ |
281 | private:\ |
282 | // |
283 | |
284 | namespace boost{ |
285 | namespace move_detail{ |
286 | |
287 | template< class T> |
288 | struct forward_type |
289 | { typedef const T &type; }; |
290 | |
291 | template< class T> |
292 | struct forward_type< boost::rv<T> > |
293 | { typedef T type; }; |
294 | |
295 | }} |
296 | |
297 | #else //BOOST_NO_CXX11_RVALUE_REFERENCES |
298 | |
299 | //! This macro marks a type as movable but not copyable, disabling copy construction |
300 | //! and assignment. The user will need to write a move constructor/assignment as explained |
301 | //! in the documentation to fully write a movable but not copyable class. |
302 | #define BOOST_MOVABLE_BUT_NOT_COPYABLE(TYPE)\ |
303 | BOOST_MOVE_IMPL_NO_COPY_CTOR_OR_ASSIGN(TYPE)\ |
304 | public:\ |
305 | typedef int boost_move_emulation_t;\ |
306 | private:\ |
307 | // |
308 | |
309 | //! This macro marks a type as copyable and movable. |
310 | //! The user will need to write a move constructor/assignment and a copy assignment |
311 | //! as explained in the documentation to fully write a copyable and movable class. |
312 | #define BOOST_COPYABLE_AND_MOVABLE(TYPE)\ |
313 | // |
314 | |
315 | #if !defined(BOOST_MOVE_DOXYGEN_INVOKED) |
316 | #define BOOST_COPYABLE_AND_MOVABLE_ALT(TYPE)\ |
317 | // |
318 | #endif //#if !defined(BOOST_MOVE_DOXYGEN_INVOKED) |
319 | |
320 | namespace boost { |
321 | |
322 | //!This trait yields to a compile-time true boolean if T was marked as |
323 | //!BOOST_MOVABLE_BUT_NOT_COPYABLE or BOOST_COPYABLE_AND_MOVABLE and |
324 | //!rvalue references are not available on the platform. False otherwise. |
325 | template<class T> |
326 | struct has_move_emulation_enabled |
327 | { |
328 | static const bool value = false; |
329 | }; |
330 | |
331 | template<class T> |
332 | struct has_move_emulation_disabled |
333 | { |
334 | static const bool value = true; |
335 | }; |
336 | |
337 | } //namespace boost{ |
338 | |
339 | //!This macro is used to achieve portable syntax in move |
340 | //!constructors and assignments for classes marked as |
341 | //!BOOST_COPYABLE_AND_MOVABLE or BOOST_MOVABLE_BUT_NOT_COPYABLE |
342 | #define BOOST_RV_REF(TYPE)\ |
343 | TYPE && \ |
344 | // |
345 | |
346 | //!This macro is used to achieve portable syntax in move |
347 | //!constructors and assignments for template classes marked as |
348 | //!BOOST_COPYABLE_AND_MOVABLE or BOOST_MOVABLE_BUT_NOT_COPYABLE. |
349 | //!As macros have problems with comma-separated template arguments, |
350 | //!the template argument must be preceded with BOOST_RV_REF_BEG |
351 | //!and ended with BOOST_RV_REF_END |
352 | #define BOOST_RV_REF_BEG\ |
353 | \ |
354 | // |
355 | |
356 | //!This macro is used to achieve portable syntax in move |
357 | //!constructors and assignments for template classes marked as |
358 | //!BOOST_COPYABLE_AND_MOVABLE or BOOST_MOVABLE_BUT_NOT_COPYABLE. |
359 | //!As macros have problems with comma-separated template arguments, |
360 | //!the template argument must be preceded with BOOST_RV_REF_BEG |
361 | //!and ended with BOOST_RV_REF_END |
362 | #define BOOST_RV_REF_END\ |
363 | && \ |
364 | // |
365 | |
366 | //!This macro expands to BOOST_RV_REF_BEG if BOOST_NO_CXX11_RVALUE_REFERENCES |
367 | //!is not defined, empty otherwise |
368 | #define BOOST_RV_REF_BEG_IF_CXX11 \ |
369 | BOOST_RV_REF_BEG \ |
370 | // |
371 | |
372 | //!This macro expands to BOOST_RV_REF_END if BOOST_NO_CXX11_RVALUE_REFERENCES |
373 | //!is not defined, empty otherwise |
374 | #define BOOST_RV_REF_END_IF_CXX11 \ |
375 | BOOST_RV_REF_END \ |
376 | // |
377 | |
378 | //!This macro is used to achieve portable syntax in copy |
379 | //!assignment for classes marked as BOOST_COPYABLE_AND_MOVABLE. |
380 | #define BOOST_COPY_ASSIGN_REF(TYPE)\ |
381 | const TYPE & \ |
382 | // |
383 | |
384 | //! This macro is used to implement portable perfect forwarding |
385 | //! as explained in the documentation. |
386 | #define BOOST_FWD_REF(TYPE)\ |
387 | TYPE && \ |
388 | // |
389 | |
390 | #if !defined(BOOST_MOVE_DOXYGEN_INVOKED) |
391 | |
392 | #define BOOST_RV_REF_2_TEMPL_ARGS(TYPE, ARG1, ARG2)\ |
393 | TYPE<ARG1, ARG2> && \ |
394 | // |
395 | |
396 | #define BOOST_RV_REF_3_TEMPL_ARGS(TYPE, ARG1, ARG2, ARG3)\ |
397 | TYPE<ARG1, ARG2, ARG3> && \ |
398 | // |
399 | |
400 | #define BOOST_COPY_ASSIGN_REF_BEG \ |
401 | const \ |
402 | // |
403 | |
404 | #define BOOST_COPY_ASSIGN_REF_END \ |
405 | & \ |
406 | // |
407 | |
408 | #define BOOST_COPY_ASSIGN_REF_2_TEMPL_ARGS(TYPE, ARG1, ARG2)\ |
409 | const TYPE<ARG1, ARG2> & \ |
410 | // |
411 | |
412 | #define BOOST_COPY_ASSIGN_REF_3_TEMPL_ARGS(TYPE, ARG1, ARG2, ARG3)\ |
413 | const TYPE<ARG1, ARG2, ARG3>& \ |
414 | // |
415 | |
416 | #define BOOST_CATCH_CONST_RLVALUE(TYPE)\ |
417 | const TYPE & \ |
418 | // |
419 | |
420 | #endif //#if !defined(BOOST_MOVE_DOXYGEN_INVOKED) |
421 | |
422 | #if !defined(BOOST_MOVE_MSVC_AUTO_MOVE_RETURN_BUG) || defined(BOOST_MOVE_DOXYGEN_INVOKED) |
423 | |
424 | //!This macro is used to achieve portable move return semantics. |
425 | //!The C++11 Standard allows implicit move returns when the object to be returned |
426 | //!is designated by a lvalue and: |
427 | //! - The criteria for elision of a copy operation are met OR |
428 | //! - The criteria would be met save for the fact that the source object is a function parameter |
429 | //! |
430 | //!For C++11 conforming compilers this macros only yields to REF: |
431 | //! <code>return BOOST_MOVE_RET(RET_TYPE, REF);</code> -> <code>return REF;</code> |
432 | //! |
433 | //!For compilers without rvalue references |
434 | //!this macro does an explicit move if the move emulation is activated |
435 | //!and the return type (RET_TYPE) is not a reference. |
436 | //! |
437 | //!For non-conforming compilers with rvalue references like Visual 2010 & 2012, |
438 | //!an explicit move is performed if RET_TYPE is not a reference. |
439 | //! |
440 | //! <b>Caution</b>: When using this macro in non-conforming or C++03 |
441 | //!compilers, a move will be performed even if the C++11 standard does not allow it |
442 | //!(e.g. returning a static variable). The user is responsible for using this macro |
443 | //!only to return local objects that met C++11 criteria. |
444 | #define BOOST_MOVE_RET(RET_TYPE, REF)\ |
445 | REF |
446 | // |
447 | |
448 | #else //!defined(BOOST_MOVE_MSVC_AUTO_MOVE_RETURN_BUG) || defined(BOOST_MOVE_DOXYGEN_INVOKED) |
449 | |
450 | #include <boost/move/detail/meta_utils.hpp> |
451 | |
452 | namespace boost { |
453 | namespace move_detail { |
454 | |
455 | template <class Ret, class T> |
456 | BOOST_MOVE_FORCEINLINE typename ::boost::move_detail::enable_if_c |
457 | < ::boost::move_detail::is_lvalue_reference<Ret>::value |
458 | , T&>::type |
459 | move_return(T& x) BOOST_NOEXCEPT |
460 | { |
461 | return x; |
462 | } |
463 | |
464 | template <class Ret, class T> |
465 | BOOST_MOVE_FORCEINLINE typename ::boost::move_detail::enable_if_c |
466 | < !::boost::move_detail::is_lvalue_reference<Ret>::value |
467 | , Ret && >::type |
468 | move_return(T&& t) BOOST_NOEXCEPT |
469 | { |
470 | return static_cast< Ret&& >(t); |
471 | } |
472 | |
473 | } //namespace move_detail { |
474 | } //namespace boost { |
475 | |
476 | #define BOOST_MOVE_RET(RET_TYPE, REF)\ |
477 | boost::move_detail::move_return< RET_TYPE >(REF) |
478 | // |
479 | |
480 | #endif //!defined(BOOST_MOVE_MSVC_AUTO_MOVE_RETURN_BUG) || defined(BOOST_MOVE_DOXYGEN_INVOKED) |
481 | |
482 | //!This macro is used to achieve portable optimal move constructors. |
483 | //! |
484 | //!When implementing the move constructor, in C++03 compilers the moved-from argument must be |
485 | //!cast to the base type before calling `::boost::move()` due to rvalue reference limitations. |
486 | //! |
487 | //!In C++11 compilers the cast from a rvalue reference of a derived type to a rvalue reference of |
488 | //!a base type is implicit. |
489 | #define BOOST_MOVE_BASE(BASE_TYPE, ARG) \ |
490 | ::boost::move((BASE_TYPE&)(ARG)) |
491 | // |
492 | |
493 | //!This macro is used to achieve portable optimal move constructors. |
494 | //! |
495 | //!In C++03 mode, when accessing a member of type through a rvalue (implemented as a `rv<T> &` type, where rv<T> derives |
496 | //!from T) triggers a potential UB as the program never creates objects of type rv<T>. This macro casts back `rv<T>` to |
497 | //!`T&` so that access to member types are done through the original type. |
498 | //! |
499 | //!In C++11 compilers the cast from a rvalue reference of a derived type to a rvalue reference of |
500 | //!a base type is implicit, so it's a no-op. |
501 | #define BOOST_MOVE_TO_LV(ARG) ARG |
502 | // |
503 | |
504 | namespace boost { |
505 | namespace move_detail { |
506 | |
507 | template< class T> struct forward_type { typedef T type; }; |
508 | |
509 | }} |
510 | |
511 | #endif //BOOST_NO_CXX11_RVALUE_REFERENCES |
512 | |
513 | #include <boost/move/detail/config_end.hpp> |
514 | |
515 | #endif //#ifndef BOOST_MOVE_CORE_HPP |
516 | |