• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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