Apply patch for [CVE-2012-2677][boost] ordered_malloc() overflow
[external/boost.git] / boost / serialization / smart_cast.hpp
1 #ifndef BOOST_SERIALIZATION_SMART_CAST_HPP
2 #define BOOST_SERIALIZATION_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 #include <cstddef> // NULL
40
41 #include <boost/config.hpp>
42 #include <boost/static_assert.hpp>
43
44 #include <boost/type_traits/is_base_and_derived.hpp>
45 #include <boost/type_traits/is_polymorphic.hpp>
46 #include <boost/type_traits/is_pointer.hpp>
47 #include <boost/type_traits/is_reference.hpp>
48 #include <boost/type_traits/is_same.hpp>
49 #include <boost/type_traits/remove_pointer.hpp>
50 #include <boost/type_traits/remove_reference.hpp>
51
52 #include <boost/mpl/eval_if.hpp>
53 #include <boost/mpl/if.hpp>
54 #include <boost/mpl/or.hpp>
55 #include <boost/mpl/and.hpp>
56 #include <boost/mpl/not.hpp>
57 #include <boost/mpl/identity.hpp>
58
59 namespace boost {
60 namespace serialization {
61 namespace smart_cast_impl {
62
63     template<class T>
64     struct reference {
65
66         struct polymorphic {
67
68             struct linear {
69                 template<class U>
70                  static T cast(U & u){
71                     return static_cast< T >(u);
72                 }
73             };
74
75             struct cross {
76                  template<class U>
77                 static T cast(U & u){
78                     return dynamic_cast< T >(u);
79                 }
80             };
81
82             template<class U>
83             static T cast(U & u){
84                 // if we're in debug mode
85                 #if ! defined(NDEBUG)                               \
86                 || defined(__BORLANDC__) && (__BORLANDC__ <= 0x560) \
87                 || defined(__MWERKS__)
88                     // do a checked dynamic cast
89                     return cross::cast(u);
90                 #else
91                     // borland 5.51 chokes here so we can't use it
92                     // note: if remove_reference isn't function for these types
93                     // cross casting will be selected this will work but will
94                     // not be the most efficient method. This will conflict with
95                     // the original smart_cast motivation.
96                     typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
97                             BOOST_DEDUCED_TYPENAME mpl::and_<
98                                 mpl::not_<is_base_and_derived<
99                                     BOOST_DEDUCED_TYPENAME remove_reference< T >::type,
100                                     U
101                                 > >,
102                                 mpl::not_<is_base_and_derived<
103                                     U,
104                                     BOOST_DEDUCED_TYPENAME remove_reference< T >::type
105                                 > >
106                             >,
107                             // borland chokes w/o full qualification here
108                             mpl::identity<cross>,
109                             mpl::identity<linear>
110                     >::type typex;
111                     // typex works around gcc 2.95 issue
112                     return typex::cast(u);
113                 #endif
114             }
115         };
116
117         struct non_polymorphic {
118             template<class U>
119              static T cast(U & u){
120                 return static_cast< T >(u);
121             }
122         };
123         template<class U>
124         static T cast(U & u){
125             #if defined(__BORLANDC__)
126                 return mpl::eval_if<
127                     boost::is_polymorphic<U>,
128                     mpl::identity<polymorphic>,
129                     mpl::identity<non_polymorphic>
130                 >::type::cast(u);
131             #else
132                 typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
133                     boost::is_polymorphic<U>,
134                     mpl::identity<polymorphic>,
135                     mpl::identity<non_polymorphic>
136                 >::type typex;
137                 return typex::cast(u);
138             #endif
139         }
140     };
141
142     template<class T>
143     struct pointer {
144
145         struct polymorphic {
146             // unfortunately, this below fails to work for virtual base 
147             // classes.  need has_virtual_base to do this.
148             // Subject for further study
149             #if 0
150             struct linear {
151                 template<class U>
152                  static T cast(U * u){
153                     return static_cast< T >(u);
154                 }
155             };
156
157             struct cross {
158                 template<class U>
159                 static T cast(U * u){
160                     T tmp = dynamic_cast< T >(u);
161                     #ifndef NDEBUG
162                         if ( tmp == 0 ) throw std::bad_cast();
163                     #endif
164                     return tmp;
165                 }
166             };
167
168             template<class U>
169             static T cast(U * u){
170                 // if we're in debug mode
171                 #if ! defined(NDEBUG) || defined(__BORLANDC__) && (__BORLANDC__ <= 0x560)
172                     // do a checked dynamic cast
173                     return cross::cast(u);
174                 #else
175                     // borland 5.51 chokes here so we can't use it
176                     // note: if remove_pointer isn't function for these types
177                     // cross casting will be selected this will work but will
178                     // not be the most efficient method. This will conflict with
179                     // the original smart_cast motivation.
180                     typedef
181                         BOOST_DEDUCED_TYPENAME mpl::eval_if<
182                             BOOST_DEDUCED_TYPENAME mpl::and_<
183                                 mpl::not_<is_base_and_derived<
184                                     BOOST_DEDUCED_TYPENAME remove_pointer< T >::type,
185                                     U
186                                 > >,
187                                 mpl::not_<is_base_and_derived<
188                                     U,
189                                     BOOST_DEDUCED_TYPENAME remove_pointer< T >::type
190                                 > >
191                             >,
192                             // borland chokes w/o full qualification here
193                             mpl::identity<cross>,
194                             mpl::identity<linear>
195                         >::type typex;
196                     return typex::cast(u);
197                 #endif
198             }
199             #else
200             template<class U>
201             static T cast(U * u){
202                 T tmp = dynamic_cast< T >(u);
203                 #ifndef NDEBUG
204                     if ( tmp == 0 ) throw std::bad_cast();
205                 #endif
206                 return tmp;
207             }
208             #endif
209         };
210
211         struct non_polymorphic {
212             template<class U>
213              static T cast(U * u){
214                 return static_cast< T >(u);
215             }
216         };
217
218         template<class U>
219         static T cast(U * u){
220             #if defined(__BORLANDC__)
221                 return mpl::eval_if<
222                     boost::is_polymorphic<U>,
223                     mpl::identity<polymorphic>,
224                     mpl::identity<non_polymorphic>
225                 >::type::cast(u);
226             #else
227                 typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
228                     boost::is_polymorphic<U>,
229                     mpl::identity<polymorphic>,
230                     mpl::identity<non_polymorphic>
231                 >::type typex;
232                 return typex::cast(u);
233             #endif
234         }
235
236     };
237
238     template<class TPtr>
239     struct void_pointer {
240         template<class UPtr>
241         static TPtr cast(UPtr uptr){
242             return static_cast<TPtr>(uptr);
243         }
244     };
245
246     template<class T>
247     struct error {
248         // if we get here, its because we are using one argument in the
249         // cast on a system which doesn't support partial template 
250         // specialization
251         template<class U>
252         static T cast(U u){
253             BOOST_STATIC_ASSERT(sizeof(T)==0);
254             return * static_cast<T *>(NULL);
255         }
256     };
257
258 } // smart_cast_impl
259
260 // this implements:
261 // smart_cast<Target *, Source *>(Source * s)
262 // smart_cast<Target &, Source &>(s)
263 // note that it will fail with
264 // smart_cast<Target &>(s)
265 template<class T, class U>
266 T smart_cast(U u) {
267     typedef
268         BOOST_DEDUCED_TYPENAME mpl::eval_if<
269             BOOST_DEDUCED_TYPENAME mpl::or_<
270                 boost::is_same<void *, U>,
271                 boost::is_same<void *, T>,
272                 boost::is_same<const void *, U>,
273                 boost::is_same<const void *, T>
274             >,
275             mpl::identity<smart_cast_impl::void_pointer< T > >,
276         // else
277         BOOST_DEDUCED_TYPENAME mpl::eval_if<boost::is_pointer<U>,
278             mpl::identity<smart_cast_impl::pointer< T > >,
279         // else
280         BOOST_DEDUCED_TYPENAME mpl::eval_if<boost::is_reference<U>,
281             mpl::identity<smart_cast_impl::reference< T > >,
282         // else
283             mpl::identity<smart_cast_impl::error< T >
284         >
285         >
286         >
287         >::type typex;
288     return typex::cast(u);
289 }
290
291 // this implements:
292 // smart_cast_reference<Target &>(Source & s)
293 template<class T, class U>
294 T smart_cast_reference(U & u) {
295     return smart_cast_impl::reference< T >::cast(u);
296 }
297
298 } // namespace serialization
299 } // namespace boost
300
301 #endif // BOOST_SERIALIZATION_SMART_CAST_HPP