1 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2 // void_cast.cpp: implementation of run-time casting of void pointers
3
4 // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
5 // Use, modification and distribution is subject to the Boost Software
6 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 // <gennadiy.rozental@tfn.com>
9
10 // See http://www.boost.org for updates, documentation, and revision history.
11
12 #if (defined _MSC_VER) && (_MSC_VER == 1200)
13 # pragma warning (disable : 4786) // too long name, harmless warning
14 #endif
15
16 // STL
17 #include <set>
18 #include <functional>
19 #include <algorithm>
20 #include <cstddef> // NULL
21 #ifdef BOOST_SERIALIZATION_LOG
22 #include <iostream>
23 #endif
24
25 // BOOST
26 #include <boost/config.hpp>
27 #include <boost/assert.hpp>
28
29 #define BOOST_SERIALIZATION_SOURCE
30 #include <boost/serialization/config.hpp>
31 // it marks our code with proper attributes as being exported when
32 // we're compiling it while marking it import when just the headers
33 // is being included.
34 #include <boost/serialization/singleton.hpp>
35 #include <boost/serialization/extended_type_info.hpp>
36 #include <boost/serialization/void_cast.hpp>
37
38 namespace boost {
39 namespace serialization {
40 namespace void_cast_detail {
41
42 // note that void_casters are keyed on value of
43 // member extended type info records - NOT their
44 // addresses. This is necessary in order for the
45 // void cast operations to work across dll and exe
46 // module boundaries.
operator <(const void_caster & rhs) const47 bool void_caster::operator<(const void_caster & rhs) const {
48 // include short cut to save time and eliminate
49 // problems when when base class aren't virtual
50 if(m_derived != rhs.m_derived){
51 if(*m_derived < *rhs.m_derived)
52 return true;
53 if(*rhs.m_derived < *m_derived)
54 return false;
55 }
56 // m_derived == rhs.m_derived
57 if(m_base != rhs.m_base)
58 return *m_base < *rhs.m_base;
59 else
60 return false;
61 }
62
63 struct void_caster_compare {
operator ()boost::serialization::void_cast_detail::void_caster_compare64 bool operator()(const void_caster * lhs, const void_caster * rhs) const {
65 return *lhs < *rhs;
66 }
67 };
68
69 typedef std::set<const void_caster *, void_caster_compare> set_type;
70 typedef boost::serialization::singleton<set_type> void_caster_registry;
71
72 #ifdef BOOST_MSVC
73 # pragma warning(push)
74 # pragma warning(disable : 4511 4512)
75 #endif
76
77 // implementation of shortcut void caster
78 class void_caster_shortcut : public void_caster
79 {
80 bool m_includes_virtual_base;
81
82 void const *
83 vbc_upcast(
84 void const * const t
85 ) const;
86 void const *
87 vbc_downcast(
88 void const * const t
89 ) const;
90 void const *
upcast(void const * const t) const91 upcast(void const * const t) const BOOST_OVERRIDE {
92 if(m_includes_virtual_base)
93 return vbc_upcast(t);
94 return static_cast<const char *> ( t ) - m_difference;
95 }
96 void const *
downcast(void const * const t) const97 downcast(void const * const t) const BOOST_OVERRIDE {
98 if(m_includes_virtual_base)
99 return vbc_downcast(t);
100 return static_cast<const char *> ( t ) + m_difference;
101 }
is_shortcut() const102 virtual bool is_shortcut() const {
103 return true;
104 }
has_virtual_base() const105 bool has_virtual_base() const BOOST_OVERRIDE {
106 return m_includes_virtual_base;
107 }
108 public:
void_caster_shortcut(extended_type_info const * derived,extended_type_info const * base,std::ptrdiff_t difference,bool includes_virtual_base,void_caster const * const parent)109 void_caster_shortcut(
110 extended_type_info const * derived,
111 extended_type_info const * base,
112 std::ptrdiff_t difference,
113 bool includes_virtual_base,
114 void_caster const * const parent
115 ) :
116 void_caster(derived, base, difference, parent),
117 m_includes_virtual_base(includes_virtual_base)
118 {
119 recursive_register(includes_virtual_base);
120 }
~void_caster_shortcut()121 ~void_caster_shortcut() BOOST_OVERRIDE {
122 recursive_unregister();
123 }
124 };
125
126 #ifdef BOOST_MSVC
127 # pragma warning(pop)
128 #endif
129
130 void const *
vbc_downcast(void const * const t) const131 void_caster_shortcut::vbc_downcast(
132 void const * const t
133 ) const {
134 // try to find a chain that gives us what we want
135 const void_cast_detail::set_type & s
136 = void_cast_detail::void_caster_registry::get_const_instance();
137 void_cast_detail::set_type::const_iterator it;
138 for(it = s.begin(); it != s.end(); ++it){
139 // if the current candidate casts to the desired target type
140 if ((*it)->m_derived == m_derived){
141 // and if it's not us
142 if ((*it)->m_base != m_base){
143 // try to cast from the candidate base to our base
144 const void * t_new;
145 t_new = void_downcast(*(*it)->m_base, *m_base, t);
146 // if we were successful
147 if(NULL != t_new){
148 // recast to our derived
149 const void_caster * vc = *it;
150 return vc->downcast(t_new);
151 }
152 }
153 }
154 }
155 return NULL;
156 }
157
158 void const *
vbc_upcast(void const * const t) const159 void_caster_shortcut::vbc_upcast(
160 void const * const t
161 ) const {
162 // try to find a chain that gives us what we want
163 const void_cast_detail::set_type & s
164 = void_cast_detail::void_caster_registry::get_const_instance();
165 void_cast_detail::set_type::const_iterator it;
166 for(it = s.begin(); it != s.end(); ++it){
167 // if the current candidate casts from the desired base type
168 if((*it)->m_base == m_base){
169 // and if it's not us
170 if ((*it)->m_derived != m_derived){
171 // try to cast from the candidate derived to our our derived
172 const void * t_new;
173 t_new = void_upcast(*m_derived, *(*it)->m_derived, t);
174 if(NULL != t_new)
175 return (*it)->upcast(t_new);
176 }
177 }
178 }
179 return NULL;
180 }
181
182 #ifdef BOOST_MSVC
183 # pragma warning(push)
184 # pragma warning(disable : 4511 4512)
185 #endif
186
187 // just used as a search key
188 class void_caster_argument : public void_caster
189 {
190 void const *
upcast(void const * const) const191 upcast(void const * const /*t*/) const BOOST_OVERRIDE {
192 BOOST_ASSERT(false);
193 return NULL;
194 }
195 void const *
downcast(void const * const) const196 downcast( void const * const /*t*/) const BOOST_OVERRIDE {
197 BOOST_ASSERT(false);
198 return NULL;
199 }
has_virtual_base() const200 bool has_virtual_base() const BOOST_OVERRIDE {
201 BOOST_ASSERT(false);
202 return false;
203 }
204 public:
void_caster_argument(extended_type_info const * derived,extended_type_info const * base)205 void_caster_argument(
206 extended_type_info const * derived,
207 extended_type_info const * base
208 ) :
209 void_caster(derived, base)
210 {}
~void_caster_argument()211 ~void_caster_argument() BOOST_OVERRIDE {}
212 };
213
214 #ifdef BOOST_MSVC
215 # pragma warning(pop)
216 #endif
217
218 // implementation of void caster base class
219 BOOST_SERIALIZATION_DECL void
recursive_register(bool includes_virtual_base) const220 void_caster::recursive_register(bool includes_virtual_base) const {
221 void_cast_detail::set_type & s
222 = void_cast_detail::void_caster_registry::get_mutable_instance();
223
224 #ifdef BOOST_SERIALIZATION_LOG
225 std::clog << "recursive_register\n";
226 std::clog << m_derived->get_debug_info();
227 std::clog << "<-";
228 std::clog << m_base->get_debug_info();
229 std::clog << "\n";
230 #endif
231
232 std::pair<void_cast_detail::set_type::const_iterator, bool> result;
233 // comment this out for now.
234 result = s.insert(this);
235 //assert(result.second);
236
237 // generate all implied void_casts.
238 void_cast_detail::set_type::const_iterator it;
239 for(it = s.begin(); it != s.end(); ++it){
240 if(* m_derived == * (*it)->m_base){
241 const void_caster_argument vca(
242 (*it)->m_derived,
243 m_base
244 );
245 void_cast_detail::set_type::const_iterator i;
246 i = s.find(& vca);
247 if(i == s.end()){
248 new void_caster_shortcut(
249 (*it)->m_derived,
250 m_base,
251 m_difference + (*it)->m_difference,
252 (*it)->has_virtual_base() || includes_virtual_base,
253 this
254 );
255 }
256 }
257 if(* (*it)->m_derived == * m_base){
258 const void_caster_argument vca(
259 m_derived,
260 (*it)->m_base
261 );
262 void_cast_detail::set_type::const_iterator i;
263 i = s.find(& vca);
264 if(i == s.end()){
265 new void_caster_shortcut(
266 m_derived,
267 (*it)->m_base,
268 m_difference + (*it)->m_difference,
269 (*it)->has_virtual_base() || includes_virtual_base,
270 this
271 );
272 }
273 }
274 }
275 }
276
277 BOOST_SERIALIZATION_DECL void
recursive_unregister() const278 void_caster::recursive_unregister() const {
279 // note: it's been discovered that at least one platform is not guaranteed
280 // to destroy singletons reverse order of construction. So we can't
281 // use a runtime assert here. Leave this in a reminder not to do this!
282 // BOOST_ASSERT(! void_caster_registry::is_destroyed());
283 if(void_caster_registry::is_destroyed())
284 return;
285
286 #ifdef BOOST_SERIALIZATION_LOG
287 std::clog << "recursive_unregister\n";
288 std::clog << m_derived->get_debug_info();
289 std::clog << "<-";
290 std::clog << m_base->get_debug_info();
291 std::clog << "\n";
292 #endif
293
294 void_cast_detail::set_type & s
295 = void_caster_registry::get_mutable_instance();
296
297 // delete all shortcuts which use this primitive
298 void_cast_detail::set_type::iterator it;
299 for(it = s.begin(); it != s.end();){
300 const void_caster * vc = *it;
301 if(vc == this){
302 s.erase(it++);
303 }
304 else
305 if(vc->m_parent == this){
306 s.erase(it);
307 delete vc;
308 it = s.begin();
309 }
310 else
311 it++;
312 }
313 }
314
315 } // namespace void_cast_detail
316
317 BOOST_SYMBOL_VISIBLE void const *
318 void_upcast(
319 extended_type_info const & derived,
320 extended_type_info const & base,
321 void const * const t
322 );
323
324 // Given a void *, assume that it really points to an instance of one type
325 // and alter it so that it would point to an instance of a related type.
326 // Return the altered pointer. If there exists no sequence of casts that
327 // can transform from_type to to_type, return a NULL.
328 BOOST_SERIALIZATION_DECL void const *
void_upcast(extended_type_info const & derived,extended_type_info const & base,void const * const t)329 void_upcast(
330 extended_type_info const & derived,
331 extended_type_info const & base,
332 void const * const t
333 ){
334 // same types - trivial case
335 if (derived == base)
336 return t;
337
338 // check to see if base/derived pair is found in the registry
339 const void_cast_detail::set_type & s
340 = void_cast_detail::void_caster_registry::get_const_instance();
341 const void_cast_detail::void_caster_argument ca(& derived, & base);
342
343 void_cast_detail::set_type::const_iterator it;
344 it = s.find(& ca);
345 if (s.end() != it)
346 return (*it)->upcast(t);
347
348 return NULL;
349 }
350
351 BOOST_SYMBOL_VISIBLE void const *
352 void_downcast(
353 extended_type_info const & derived,
354 extended_type_info const & base,
355 void const * const t
356 );
357
358 BOOST_SERIALIZATION_DECL void const *
void_downcast(extended_type_info const & derived,extended_type_info const & base,void const * const t)359 void_downcast(
360 extended_type_info const & derived,
361 extended_type_info const & base,
362 void const * const t
363 ){
364 // same types - trivial case
365 if (derived == base)
366 return t;
367
368 // check to see if base/derived pair is found in the registry
369 const void_cast_detail::set_type & s
370 = void_cast_detail::void_caster_registry::get_const_instance();
371 const void_cast_detail::void_caster_argument ca(& derived, & base);
372
373 void_cast_detail::set_type::const_iterator it;
374 it = s.find(&ca);
375 if (s.end() != it)
376 return(*it)->downcast(t);
377
378 return NULL;
379 }
380
381 } // namespace serialization
382 } // namespace boost
383