]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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) | |
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(__MWERKS__) | |
89 | // do a checked dynamic cast | |
90 | return cross::cast(u); | |
91 | #else | |
92 | // borland 5.51 chokes here so we can't use it | |
93 | // note: if remove_reference isn't function for these types | |
94 | // cross casting will be selected this will work but will | |
95 | // not be the most efficient method. This will conflict with | |
96 | // the original smart_cast motivation. | |
97 | typedef typename mpl::eval_if< | |
98 | typename mpl::and_< | |
99 | mpl::not_<is_base_and_derived< | |
100 | typename remove_reference< T >::type, | |
101 | U | |
102 | > >, | |
103 | mpl::not_<is_base_and_derived< | |
104 | U, | |
105 | typename remove_reference< T >::type | |
106 | > > | |
107 | >, | |
108 | // borland chokes w/o full qualification here | |
109 | mpl::identity<cross>, | |
110 | mpl::identity<linear> | |
111 | >::type typex; | |
112 | // typex works around gcc 2.95 issue | |
113 | return typex::cast(u); | |
114 | #endif | |
115 | } | |
116 | }; | |
117 | ||
118 | struct non_polymorphic { | |
119 | template<class U> | |
120 | static T cast(U & u){ | |
121 | return static_cast< T >(u); | |
122 | } | |
123 | }; | |
124 | template<class U> | |
125 | static T cast(U & u){ | |
126 | typedef typename mpl::eval_if< | |
127 | boost::is_polymorphic<U>, | |
128 | mpl::identity<polymorphic>, | |
129 | mpl::identity<non_polymorphic> | |
130 | >::type typex; | |
131 | return typex::cast(u); | |
132 | } | |
133 | }; | |
134 | ||
135 | template<class T> | |
136 | struct pointer { | |
137 | ||
138 | struct polymorphic { | |
139 | // unfortunately, this below fails to work for virtual base | |
140 | // classes. need has_virtual_base to do this. | |
141 | // Subject for further study | |
142 | #if 0 | |
143 | struct linear { | |
144 | template<class U> | |
145 | static T cast(U * u){ | |
146 | return static_cast< T >(u); | |
147 | } | |
148 | }; | |
149 | ||
150 | struct cross { | |
151 | template<class U> | |
152 | static T cast(U * u){ | |
153 | T tmp = dynamic_cast< T >(u); | |
154 | #ifndef NDEBUG | |
155 | if ( tmp == 0 ) throw_exception(std::bad_cast()); | |
156 | #endif | |
157 | return tmp; | |
158 | } | |
159 | }; | |
160 | ||
161 | template<class U> | |
162 | static T cast(U * u){ | |
163 | typedef | |
164 | typename mpl::eval_if< | |
165 | typename mpl::and_< | |
166 | mpl::not_<is_base_and_derived< | |
167 | typename remove_pointer< T >::type, | |
168 | U | |
169 | > >, | |
170 | mpl::not_<is_base_and_derived< | |
171 | U, | |
172 | typename remove_pointer< T >::type | |
173 | > > | |
174 | >, | |
175 | // borland chokes w/o full qualification here | |
176 | mpl::identity<cross>, | |
177 | mpl::identity<linear> | |
178 | >::type typex; | |
179 | return typex::cast(u); | |
180 | } | |
181 | #else | |
182 | template<class U> | |
183 | static T cast(U * u){ | |
184 | T tmp = dynamic_cast< T >(u); | |
185 | #ifndef NDEBUG | |
186 | if ( tmp == 0 ) throw_exception(std::bad_cast()); | |
187 | #endif | |
188 | return tmp; | |
189 | } | |
190 | #endif | |
191 | }; | |
192 | ||
193 | struct non_polymorphic { | |
194 | template<class U> | |
195 | static T cast(U * u){ | |
196 | return static_cast< T >(u); | |
197 | } | |
198 | }; | |
199 | ||
200 | template<class U> | |
201 | static T cast(U * u){ | |
202 | typedef typename mpl::eval_if< | |
203 | boost::is_polymorphic<U>, | |
204 | mpl::identity<polymorphic>, | |
205 | mpl::identity<non_polymorphic> | |
206 | >::type typex; | |
207 | return typex::cast(u); | |
208 | } | |
209 | ||
210 | }; | |
211 | ||
212 | template<class TPtr> | |
213 | struct void_pointer { | |
214 | template<class UPtr> | |
215 | static TPtr cast(UPtr uptr){ | |
216 | return static_cast<TPtr>(uptr); | |
217 | } | |
218 | }; | |
219 | ||
220 | template<class T> | |
221 | struct error { | |
222 | // if we get here, its because we are using one argument in the | |
223 | // cast on a system which doesn't support partial template | |
224 | // specialization | |
225 | template<class U> | |
226 | static T cast(U){ | |
227 | BOOST_STATIC_ASSERT(sizeof(T)==0); | |
228 | return * static_cast<T *>(NULL); | |
229 | } | |
230 | }; | |
231 | ||
232 | } // smart_cast_impl | |
233 | ||
234 | // this implements: | |
235 | // smart_cast<Target *, Source *>(Source * s) | |
236 | // smart_cast<Target &, Source &>(s) | |
237 | // note that it will fail with | |
238 | // smart_cast<Target &>(s) | |
239 | template<class T, class U> | |
240 | T smart_cast(U u) { | |
241 | typedef | |
242 | typename mpl::eval_if< | |
243 | typename mpl::or_< | |
244 | boost::is_same<void *, U>, | |
245 | boost::is_same<void *, T>, | |
246 | boost::is_same<const void *, U>, | |
247 | boost::is_same<const void *, T> | |
248 | >, | |
249 | mpl::identity<smart_cast_impl::void_pointer< T > >, | |
250 | // else | |
251 | typename mpl::eval_if<boost::is_pointer<U>, | |
252 | mpl::identity<smart_cast_impl::pointer< T > >, | |
253 | // else | |
254 | typename mpl::eval_if<boost::is_reference<U>, | |
255 | mpl::identity<smart_cast_impl::reference< T > >, | |
256 | // else | |
257 | mpl::identity<smart_cast_impl::error< T > | |
258 | > | |
259 | > | |
260 | > | |
261 | >::type typex; | |
262 | return typex::cast(u); | |
263 | } | |
264 | ||
265 | // this implements: | |
266 | // smart_cast_reference<Target &>(Source & s) | |
267 | template<class T, class U> | |
268 | T smart_cast_reference(U & u) { | |
269 | return smart_cast_impl::reference< T >::cast(u); | |
270 | } | |
271 | ||
272 | } // namespace serialization | |
273 | } // namespace boost | |
274 | ||
275 | #endif // BOOST_SERIALIZATION_SMART_CAST_HPP |