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