1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // |
3 | // (C) Copyright Ion Gaztanaga 2012-2015. |
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 | |
14 | #ifndef BOOST_MOVE_DETAIL_META_UTILS_HPP |
15 | #define BOOST_MOVE_DETAIL_META_UTILS_HPP |
16 | |
17 | #ifndef BOOST_CONFIG_HPP |
18 | # include <boost/config.hpp> |
19 | #endif |
20 | # |
21 | #if defined(BOOST_HAS_PRAGMA_ONCE) |
22 | # pragma once |
23 | #endif |
24 | #include <boost/move/detail/meta_utils_core.hpp> |
25 | #include <cstddef> //for std::size_t |
26 | |
27 | //Small meta-typetraits to support move |
28 | |
29 | namespace boost { |
30 | |
31 | //Forward declare boost::rv |
32 | template <class T> class rv; |
33 | |
34 | namespace move_detail { |
35 | |
36 | ////////////////////////////////////// |
37 | // nat |
38 | ////////////////////////////////////// |
39 | struct nat{}; |
40 | |
41 | ////////////////////////////////////// |
42 | // natify |
43 | ////////////////////////////////////// |
44 | template <class T> struct natify{}; |
45 | |
46 | ////////////////////////////////////// |
47 | // remove_reference |
48 | ////////////////////////////////////// |
49 | template<class T> |
50 | struct remove_reference |
51 | { |
52 | typedef T type; |
53 | }; |
54 | |
55 | template<class T> |
56 | struct remove_reference<T&> |
57 | { |
58 | typedef T type; |
59 | }; |
60 | |
61 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
62 | |
63 | template<class T> |
64 | struct remove_reference<T&&> |
65 | { |
66 | typedef T type; |
67 | }; |
68 | |
69 | #else |
70 | |
71 | template<class T> |
72 | struct remove_reference< rv<T> > |
73 | { |
74 | typedef T type; |
75 | }; |
76 | |
77 | template<class T> |
78 | struct remove_reference< rv<T> &> |
79 | { |
80 | typedef T type; |
81 | }; |
82 | |
83 | template<class T> |
84 | struct remove_reference< const rv<T> &> |
85 | { |
86 | typedef T type; |
87 | }; |
88 | |
89 | |
90 | #endif |
91 | |
92 | ////////////////////////////////////// |
93 | // add_const |
94 | ////////////////////////////////////// |
95 | template<class T> |
96 | struct add_const |
97 | { |
98 | typedef const T type; |
99 | }; |
100 | |
101 | template<class T> |
102 | struct add_const<T&> |
103 | { |
104 | typedef const T& type; |
105 | }; |
106 | |
107 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
108 | |
109 | template<class T> |
110 | struct add_const<T&&> |
111 | { |
112 | typedef T&& type; |
113 | }; |
114 | |
115 | #endif |
116 | |
117 | ////////////////////////////////////// |
118 | // add_lvalue_reference |
119 | ////////////////////////////////////// |
120 | template<class T> |
121 | struct add_lvalue_reference |
122 | { typedef T& type; }; |
123 | |
124 | template<class T> struct add_lvalue_reference<T&> { typedef T& type; }; |
125 | template<> struct add_lvalue_reference<void> { typedef void type; }; |
126 | template<> struct add_lvalue_reference<const void> { typedef const void type; }; |
127 | template<> struct add_lvalue_reference<volatile void> { typedef volatile void type; }; |
128 | template<> struct add_lvalue_reference<const volatile void>{ typedef const volatile void type; }; |
129 | |
130 | template<class T> |
131 | struct add_const_lvalue_reference |
132 | { |
133 | typedef typename remove_reference<T>::type t_unreferenced; |
134 | typedef typename add_const<t_unreferenced>::type t_unreferenced_const; |
135 | typedef typename add_lvalue_reference |
136 | <t_unreferenced_const>::type type; |
137 | }; |
138 | |
139 | ////////////////////////////////////// |
140 | // is_lvalue_reference |
141 | ////////////////////////////////////// |
142 | template<class T> |
143 | struct is_lvalue_reference |
144 | { |
145 | static const bool value = false; |
146 | }; |
147 | |
148 | template<class T> |
149 | struct is_lvalue_reference<T&> |
150 | { |
151 | static const bool value = true; |
152 | }; |
153 | |
154 | ////////////////////////////////////// |
155 | // is_class_or_union |
156 | ////////////////////////////////////// |
157 | template<class T> |
158 | struct is_class_or_union |
159 | { |
160 | struct twochar { char dummy[2]; }; |
161 | template <class U> |
162 | static char is_class_or_union_tester(void(U::*)(void)); |
163 | template <class U> |
164 | static twochar is_class_or_union_tester(...); |
165 | static const bool value = sizeof(is_class_or_union_tester<T>(0)) == sizeof(char); |
166 | }; |
167 | |
168 | ////////////////////////////////////// |
169 | // addressof |
170 | ////////////////////////////////////// |
171 | template<class T> |
172 | struct addr_impl_ref |
173 | { |
174 | T & v_; |
175 | inline addr_impl_ref( T & v ): v_( v ) {} |
176 | inline operator T& () const { return v_; } |
177 | |
178 | private: |
179 | addr_impl_ref & operator=(const addr_impl_ref &); |
180 | }; |
181 | |
182 | template<class T> |
183 | struct addressof_impl |
184 | { |
185 | static inline T * f( T & v, long ) |
186 | { |
187 | return reinterpret_cast<T*>( |
188 | &const_cast<char&>(reinterpret_cast<const volatile char &>(v))); |
189 | } |
190 | |
191 | static inline T * f( T * v, int ) |
192 | { return v; } |
193 | }; |
194 | |
195 | template<class T> |
196 | inline T * addressof( T & v ) |
197 | { |
198 | return ::boost::move_detail::addressof_impl<T>::f |
199 | ( ::boost::move_detail::addr_impl_ref<T>( v ), 0 ); |
200 | } |
201 | |
202 | ////////////////////////////////////// |
203 | // has_pointer_type |
204 | ////////////////////////////////////// |
205 | template <class T> |
206 | struct has_pointer_type |
207 | { |
208 | struct two { char c[2]; }; |
209 | template <class U> static two test(...); |
210 | template <class U> static char test(typename U::pointer* = 0); |
211 | static const bool value = sizeof(test<T>(0)) == 1; |
212 | }; |
213 | |
214 | ////////////////////////////////////// |
215 | // is_convertible |
216 | ////////////////////////////////////// |
217 | #if defined(_MSC_VER) && (_MSC_VER >= 1400) |
218 | |
219 | //use intrinsic since in MSVC |
220 | //overaligned types can't go through ellipsis |
221 | template <class T, class U> |
222 | struct is_convertible |
223 | { |
224 | static const bool value = __is_convertible_to(T, U); |
225 | }; |
226 | |
227 | #else |
228 | |
229 | template <class T, class U> |
230 | class is_convertible |
231 | { |
232 | typedef typename add_lvalue_reference<T>::type t_reference; |
233 | typedef char true_t; |
234 | class false_t { char dummy[2]; }; |
235 | static false_t dispatch(...); |
236 | static true_t dispatch(U); |
237 | static t_reference trigger(); |
238 | public: |
239 | static const bool value = sizeof(dispatch(trigger())) == sizeof(true_t); |
240 | }; |
241 | |
242 | #endif |
243 | |
244 | ////////////////////////////////////////////////////////////////////////////// |
245 | // |
246 | // has_move_emulation_enabled_impl |
247 | // |
248 | ////////////////////////////////////////////////////////////////////////////// |
249 | template<class T> |
250 | struct has_move_emulation_enabled_impl |
251 | : is_convertible< T, ::boost::rv<T>& > |
252 | {}; |
253 | |
254 | template<class T> |
255 | struct has_move_emulation_enabled_impl<T&> |
256 | { static const bool value = false; }; |
257 | |
258 | template<class T> |
259 | struct has_move_emulation_enabled_impl< ::boost::rv<T> > |
260 | { static const bool value = false; }; |
261 | |
262 | ////////////////////////////////////////////////////////////////////////////// |
263 | // |
264 | // is_rv_impl |
265 | // |
266 | ////////////////////////////////////////////////////////////////////////////// |
267 | |
268 | template <class T> |
269 | struct is_rv_impl |
270 | { static const bool value = false; }; |
271 | |
272 | template <class T> |
273 | struct is_rv_impl< rv<T> > |
274 | { static const bool value = true; }; |
275 | |
276 | template <class T> |
277 | struct is_rv_impl< const rv<T> > |
278 | { static const bool value = true; }; |
279 | |
280 | // Code from Jeffrey Lee Hellrung, many thanks |
281 | |
282 | template< class T > |
283 | struct is_rvalue_reference |
284 | { static const bool value = false; }; |
285 | |
286 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
287 | |
288 | template< class T > |
289 | struct is_rvalue_reference< T&& > |
290 | { static const bool value = true; }; |
291 | |
292 | #else // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
293 | |
294 | template< class T > |
295 | struct is_rvalue_reference< boost::rv<T>& > |
296 | { static const bool value = true; }; |
297 | |
298 | template< class T > |
299 | struct is_rvalue_reference< const boost::rv<T>& > |
300 | { static const bool value = true; }; |
301 | |
302 | #endif // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
303 | |
304 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
305 | |
306 | template< class T > |
307 | struct add_rvalue_reference |
308 | { typedef T&& type; }; |
309 | |
310 | #else // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
311 | |
312 | namespace detail_add_rvalue_reference |
313 | { |
314 | template< class T |
315 | , bool emulation = has_move_emulation_enabled_impl<T>::value |
316 | , bool rv = is_rv_impl<T>::value > |
317 | struct add_rvalue_reference_impl { typedef T type; }; |
318 | |
319 | template< class T, bool emulation> |
320 | struct add_rvalue_reference_impl< T, emulation, true > { typedef T & type; }; |
321 | |
322 | template< class T, bool rv > |
323 | struct add_rvalue_reference_impl< T, true, rv > { typedef ::boost::rv<T>& type; }; |
324 | } // namespace detail_add_rvalue_reference |
325 | |
326 | template< class T > |
327 | struct add_rvalue_reference |
328 | : detail_add_rvalue_reference::add_rvalue_reference_impl<T> |
329 | { }; |
330 | |
331 | template< class T > |
332 | struct add_rvalue_reference<T &> |
333 | { typedef T & type; }; |
334 | |
335 | #endif // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
336 | |
337 | template< class T > struct remove_rvalue_reference { typedef T type; }; |
338 | |
339 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
340 | template< class T > struct remove_rvalue_reference< T&& > { typedef T type; }; |
341 | #else // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
342 | template< class T > struct remove_rvalue_reference< rv<T> > { typedef T type; }; |
343 | template< class T > struct remove_rvalue_reference< const rv<T> > { typedef T type; }; |
344 | template< class T > struct remove_rvalue_reference< volatile rv<T> > { typedef T type; }; |
345 | template< class T > struct remove_rvalue_reference< const volatile rv<T> > { typedef T type; }; |
346 | template< class T > struct remove_rvalue_reference< rv<T>& > { typedef T type; }; |
347 | template< class T > struct remove_rvalue_reference< const rv<T>& > { typedef T type; }; |
348 | template< class T > struct remove_rvalue_reference< volatile rv<T>& > { typedef T type; }; |
349 | template< class T > struct remove_rvalue_reference< const volatile rv<T>& >{ typedef T type; }; |
350 | #endif // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
351 | |
352 | // Ideas from Boost.Move review, Jeffrey Lee Hellrung: |
353 | // |
354 | //- TypeTraits metafunctions is_lvalue_reference, add_lvalue_reference, and remove_lvalue_reference ? |
355 | // Perhaps add_reference and remove_reference can be modified so that they behave wrt emulated rvalue |
356 | // references the same as wrt real rvalue references, i.e., add_reference< rv<T>& > -> T& rather than |
357 | // rv<T>& (since T&& & -> T&). |
358 | // |
359 | //- Add'l TypeTraits has_[trivial_]move_{constructor,assign}...? |
360 | // |
361 | //- An as_lvalue(T& x) function, which amounts to an identity operation in C++0x, but strips emulated |
362 | // rvalue references in C++03. This may be necessary to prevent "accidental moves". |
363 | |
364 | } //namespace move_detail { |
365 | } //namespace boost { |
366 | |
367 | #endif //#ifndef BOOST_MOVE_DETAIL_META_UTILS_HPP |
368 | |