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
29namespace boost {
30
31//Forward declare boost::rv
32template <class T> class rv;
33
34namespace move_detail {
35
36//////////////////////////////////////
37// nat
38//////////////////////////////////////
39struct nat{};
40
41//////////////////////////////////////
42// natify
43//////////////////////////////////////
44template <class T> struct natify{};
45
46//////////////////////////////////////
47// remove_reference
48//////////////////////////////////////
49template<class T>
50struct remove_reference
51{
52 typedef T type;
53};
54
55template<class T>
56struct remove_reference<T&>
57{
58 typedef T type;
59};
60
61#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
62
63template<class T>
64struct remove_reference<T&&>
65{
66 typedef T type;
67};
68
69#else
70
71template<class T>
72struct remove_reference< rv<T> >
73{
74 typedef T type;
75};
76
77template<class T>
78struct remove_reference< rv<T> &>
79{
80 typedef T type;
81};
82
83template<class T>
84struct remove_reference< const rv<T> &>
85{
86 typedef T type;
87};
88
89
90#endif
91
92//////////////////////////////////////
93// add_const
94//////////////////////////////////////
95template<class T>
96struct add_const
97{
98 typedef const T type;
99};
100
101template<class T>
102struct add_const<T&>
103{
104 typedef const T& type;
105};
106
107#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
108
109template<class T>
110struct add_const<T&&>
111{
112 typedef T&& type;
113};
114
115#endif
116
117//////////////////////////////////////
118// add_lvalue_reference
119//////////////////////////////////////
120template<class T>
121struct add_lvalue_reference
122{ typedef T& type; };
123
124template<class T> struct add_lvalue_reference<T&> { typedef T& type; };
125template<> struct add_lvalue_reference<void> { typedef void type; };
126template<> struct add_lvalue_reference<const void> { typedef const void type; };
127template<> struct add_lvalue_reference<volatile void> { typedef volatile void type; };
128template<> struct add_lvalue_reference<const volatile void>{ typedef const volatile void type; };
129
130template<class T>
131struct 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//////////////////////////////////////
142template<class T>
143struct is_lvalue_reference
144{
145 static const bool value = false;
146};
147
148template<class T>
149struct is_lvalue_reference<T&>
150{
151 static const bool value = true;
152};
153
154//////////////////////////////////////
155// is_class_or_union
156//////////////////////////////////////
157template<class T>
158struct 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//////////////////////////////////////
171template<class T>
172struct 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
182template<class T>
183struct 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
195template<class T>
196inline 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//////////////////////////////////////
205template <class T>
206struct 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
221template <class T, class U>
222struct is_convertible
223{
224 static const bool value = __is_convertible_to(T, U);
225};
226
227#else
228
229template <class T, class U>
230class 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//////////////////////////////////////////////////////////////////////////////
249template<class T>
250struct has_move_emulation_enabled_impl
251 : is_convertible< T, ::boost::rv<T>& >
252{};
253
254template<class T>
255struct has_move_emulation_enabled_impl<T&>
256{ static const bool value = false; };
257
258template<class T>
259struct has_move_emulation_enabled_impl< ::boost::rv<T> >
260{ static const bool value = false; };
261
262//////////////////////////////////////////////////////////////////////////////
263//
264// is_rv_impl
265//
266//////////////////////////////////////////////////////////////////////////////
267
268template <class T>
269struct is_rv_impl
270{ static const bool value = false; };
271
272template <class T>
273struct is_rv_impl< rv<T> >
274{ static const bool value = true; };
275
276template <class T>
277struct is_rv_impl< const rv<T> >
278{ static const bool value = true; };
279
280// Code from Jeffrey Lee Hellrung, many thanks
281
282template< class T >
283struct is_rvalue_reference
284{ static const bool value = false; };
285
286#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
287
288template< class T >
289struct is_rvalue_reference< T&& >
290{ static const bool value = true; };
291
292#else // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
293
294template< class T >
295struct is_rvalue_reference< boost::rv<T>& >
296{ static const bool value = true; };
297
298template< class T >
299struct 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
306template< class T >
307struct add_rvalue_reference
308{ typedef T&& type; };
309
310#else // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
311
312namespace 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
326template< class T >
327struct add_rvalue_reference
328 : detail_add_rvalue_reference::add_rvalue_reference_impl<T>
329{ };
330
331template< class T >
332struct add_rvalue_reference<T &>
333{ typedef T & type; };
334
335#endif // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
336
337template< 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