]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/boost-lite/include/boost/smart_cast.hpp
Inital import
[l4.git] / l4 / pkg / boost-lite / include / boost / smart_cast.hpp
1 #ifndef BOOST_SMART_CAST_HPP
2 #define BOOST_SMART_CAST_HPP
3
4 // MS compatible compilers support #pragma once
5 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
6 # pragma once
7 #endif
8
9 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
10 // smart_cast.hpp:
11
12 // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
13 // Use, modification and distribution is subject to the Boost Software
14 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
15 // http://www.boost.org/LICENSE_1_0.txt)
16
17 //  See http://www.boost.org/libs/serialization for updates, documentation, and revision history.
18
19 // casting of pointers and references.  
20
21 // In casting between different C++ classes, there are a number of
22 // rules that have to be kept in mind in deciding whether to use
23 // static_cast or dynamic_cast.  
24
25 // a) dynamic casting can only be applied when one of the types is polymorphic
26 // Otherwise static_cast must be used.
27 // b) only dynamic casting can do runtime error checking
28 // use of static_cast is generally un checked even when compiled for debug
29 // c) static_cast would be considered faster than dynamic_cast.
30
31 // If casting is applied to a template parameter, there is no apriori way
32 // to know which of the two casting methods will be permitted or convenient.
33
34 // smart_cast uses C++ type_traits, and program debug mode to select the
35 // most convenient cast to use.
36
37 #include <exception>
38 #include <typeinfo>
39
40 #include <boost/config.hpp>
41 #include <boost/static_assert.hpp>
42
43 #include <boost/type_traits/is_base_and_derived.hpp>
44 #include <boost/type_traits/is_polymorphic.hpp>
45 #include <boost/type_traits/is_pointer.hpp>
46 #include <boost/type_traits/is_reference.hpp>
47 #include <boost/type_traits/is_same.hpp>
48 #include <boost/type_traits/remove_pointer.hpp>
49 #include <boost/type_traits/remove_reference.hpp>
50
51 #include <boost/mpl/eval_if.hpp>
52 #include <boost/mpl/if.hpp>
53 #include <boost/mpl/or.hpp>
54 #include <boost/mpl/and.hpp>
55 #include <boost/mpl/not.hpp>
56 #include <boost/mpl/identity.hpp>
57
58 namespace boost {
59 namespace smart_cast_impl {
60
61     template<class T>
62     struct reference {
63
64         struct polymorphic {
65
66             struct linear {
67                 template<class U>
68                  static T cast(U & u){
69                     return static_cast<T>(u);
70                 }
71             };
72
73             struct cross {
74                  template<class U>
75                 static T cast(U & u){
76                     return dynamic_cast<T>(u);
77                 }
78             };
79
80             template<class U>
81             static T cast(U & u){
82                 // if we're in debug mode
83                 #if ! defined(NDEBUG)                               \
84                 || defined(__BORLANDC__) && (__BORLANDC__ <= 0x560) \
85                 || defined(__MWERKS__)
86                     // do a checked dynamic cast
87                     return cross::cast(u);
88                 #else
89                     // borland 5.51 chokes here so we can't use it
90                     // note: if remove_reference isn't function for these types
91                     // cross casting will be selected this will work but will
92                     // not be the most efficient method. This will conflict with
93                     // the original smart_cast motivation.
94                     typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
95                             BOOST_DEDUCED_TYPENAME mpl::and_<
96                                 mpl::not_<is_base_and_derived<
97                                     BOOST_DEDUCED_TYPENAME remove_reference<T>::type,
98                                     U
99                                 > >,
100                                 mpl::not_<is_base_and_derived<
101                                     U,
102                                     BOOST_DEDUCED_TYPENAME remove_reference<T>::type
103                                 > >
104                             >,
105                             // borland chokes w/o full qualification here
106                             mpl::identity<cross>,
107                             mpl::identity<linear>
108                     >::type typex;
109                     // typex works around gcc 2.95 issue
110                     return typex::cast(u);
111                 #endif
112             }
113         };
114
115         struct non_polymorphic {
116             template<class U>
117              static T cast(U & u){
118                 return static_cast<T>(u);
119             }
120         };
121         template<class U>
122         static T cast(U & u){
123             #if defined(__BORLANDC__)
124                 return mpl::eval_if<
125                     boost::is_polymorphic<U>,
126                     mpl::identity<polymorphic>,
127                     mpl::identity<non_polymorphic>
128                 >::type::cast(u);
129             #else
130                 typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
131                     boost::is_polymorphic<U>,
132                     mpl::identity<polymorphic>,
133                     mpl::identity<non_polymorphic>
134                 >::type typex;
135                 return typex::cast(u);
136             #endif
137         }
138     };
139
140     template<class T>
141     struct pointer {
142
143         struct polymorphic {
144             // unfortunately, this below fails to work for virtual base 
145             // classes.  need has_virtual_base to do this.
146             // Subject for further study
147             #if 0
148             struct linear {
149                 template<class U>
150                  static T cast(U * u){
151                     return static_cast<T>(u);
152                 }
153             };
154
155             struct cross {
156                 template<class U>
157                 static T cast(U * u){
158                     T tmp = dynamic_cast<T>(u);
159                     #ifndef NDEBUG
160                         if ( tmp == 0 ) throw std::bad_cast();
161                     #endif
162                     return tmp;
163                 }
164             };
165
166             template<class U>
167             static T cast(U * u){
168                 // if we're in debug mode
169                 #if ! defined(NDEBUG) || defined(__BORLANDC__) && (__BORLANDC__ <= 0x560)
170                     // do a checked dynamic cast
171                     return cross::cast(u);
172                 #else
173                     // borland 5.51 chokes here so we can't use it
174                     // note: if remove_pointer isn't function for these types
175                     // cross casting will be selected this will work but will
176                     // not be the most efficient method. This will conflict with
177                     // the original smart_cast motivation.
178                     typedef
179                         BOOST_DEDUCED_TYPENAME mpl::eval_if<
180                             BOOST_DEDUCED_TYPENAME mpl::and_<
181                                 mpl::not_<is_base_and_derived<
182                                     BOOST_DEDUCED_TYPENAME remove_pointer<T>::type,
183                                     U
184                                 > >,
185                                 mpl::not_<is_base_and_derived<
186                                     U,
187                                     BOOST_DEDUCED_TYPENAME remove_pointer<T>::type
188                                 > >
189                             >,
190                             // borland chokes w/o full qualification here
191                             mpl::identity<cross>,
192                             mpl::identity<linear>
193                         >::type typex;
194                     return typex::cast(u);
195                 #endif
196             }
197             #else
198             template<class U>
199             static T cast(U * u){
200                 T tmp = dynamic_cast<T>(u);
201                 #ifndef NDEBUG
202                     if ( tmp == 0 ) throw std::bad_cast();
203                 #endif
204                 return tmp;
205             }
206             #endif
207         };
208
209         struct non_polymorphic {
210             template<class U>
211              static T cast(U * u){
212                 return static_cast<T>(u);
213             }
214         };
215
216         template<class U>
217         static T cast(U * u){
218             #if defined(__BORLANDC__)
219                 return mpl::eval_if<
220                     boost::is_polymorphic<U>,
221                     mpl::identity<polymorphic>,
222                     mpl::identity<non_polymorphic>
223                 >::type::cast(u);
224             #else
225                 typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
226                     boost::is_polymorphic<U>,
227                     mpl::identity<polymorphic>,
228                     mpl::identity<non_polymorphic>
229                 >::type typex;
230                 return typex::cast(u);
231             #endif
232         }
233
234     };
235
236     template<class TPtr>
237     struct void_pointer {
238         template<class UPtr>
239         static TPtr cast(UPtr uptr){
240             return static_cast<TPtr>(uptr);
241         }
242     };
243
244     template<class T>
245     struct error {
246         // if we get here, its because we are using one argument in the
247         // cast on a system which doesn't support partial template 
248         // specialization
249         template<class U>
250         static T cast(U u){
251             BOOST_STATIC_ASSERT(sizeof(T)==0);
252             return * static_cast<T *>(NULL);
253         }
254     };
255
256 } // smart_cast_impl
257
258 // this implements:
259 // smart_cast<Target *, Source *>(Source * s)
260 // smart_cast<Target &, Source &>(s)
261 // note that it will fail with
262 // smart_cast<Target &>(s)
263 template<class T, class U>
264 T smart_cast(U u) {
265     typedef
266         BOOST_DEDUCED_TYPENAME mpl::eval_if<
267             BOOST_DEDUCED_TYPENAME mpl::or_<
268                 boost::is_same<void *, U>,
269                 boost::is_same<void *, T>,
270                 boost::is_same<const void *, U>,
271                 boost::is_same<const void *, T>
272             >,
273             mpl::identity<smart_cast_impl::void_pointer<T> >,
274         // else
275         BOOST_DEDUCED_TYPENAME mpl::eval_if<boost::is_pointer<U>,
276             mpl::identity<smart_cast_impl::pointer<T> >,
277         // else
278         BOOST_DEDUCED_TYPENAME mpl::eval_if<boost::is_reference<U>,
279             mpl::identity<smart_cast_impl::reference<T> >,
280         // else
281             mpl::identity<smart_cast_impl::error<T>
282         >
283         >
284         >
285         >::type typex;
286     return typex::cast(u);
287 }
288
289 // this implements:
290 // smart_cast_reference<Target &>(Source & s)
291 template<class T, class U>
292 T smart_cast_reference(U & u) {
293     return smart_cast_impl::reference<T>::cast(u);
294 }
295
296 } // namespace boost
297
298 #endif // BOOST_SMART_CAST_HPP