Ticket #3604: void_cast.cpp

File void_cast.cpp, 10.7 KB (added by Robert Ramey, 13 years ago)
Line 
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#include <cassert>
17#include <cstddef> // NULL
18#ifdef BOOST_SERIALIZATION_LOG
19#include <iostream>
20#endif
21
22// STL
23#include <set>
24#include <functional>
25#include <algorithm>
26#include <cassert>
27
28// BOOST
29#define BOOST_SERIALIZATION_SOURCE
30#include <boost/serialization/singleton.hpp>
31
32#define BOOST_SERIALIZATION_SOURCE
33#include <boost/serialization/extended_type_info.hpp>
34#include <boost/serialization/void_cast.hpp>
35
36namespace boost {
37namespace serialization {
38namespace void_cast_detail {
39
40// note that void_casters are keyed on value of
41// member extended type info records - NOT their
42// addresses. This is necessary in order for the
43// void cast operations to work across dll and exe
44// module boundries.
45bool void_caster::operator<(const void_caster & rhs) const {
46 // include short cut to save time and eliminate
47 // problems when when base class aren't virtual
48 if(m_derived != rhs.m_derived){
49 if(*m_derived < *rhs.m_derived)
50 return true;
51 if(*rhs.m_derived < *m_derived)
52 return false;
53 }
54 // m_derived == rhs.m_derived
55 if(m_base != rhs.m_base)
56 return *m_base < *rhs.m_base;
57 else
58 return false;
59}
60
61struct void_caster_compare {
62 bool operator()(const void_caster * lhs, const void_caster * rhs) const {
63 return *lhs < *rhs;
64 }
65};
66
67typedef std::set<const void_caster *, void_caster_compare> set_type;
68typedef boost::serialization::singleton<set_type> void_caster_registry;
69
70#ifdef BOOST_MSVC
71# pragma warning(push)
72# pragma warning(disable : 4511 4512)
73#endif
74
75// implementation of shortcut void caster
76class void_caster_shortcut : public void_caster
77{
78 bool m_includes_virtual_base;
79
80 void const *
81 vbc_upcast(
82 void const * const t
83 ) const;
84 void const *
85 vbc_downcast(
86 void const * const t
87 ) const;
88 virtual void const *
89 upcast(void const * const t) const{
90 if(m_includes_virtual_base)
91 return vbc_upcast(t);
92 return static_cast<const char *> ( t ) - m_difference;
93 }
94 virtual void const *
95 downcast(void const * const t) const{
96 if(m_includes_virtual_base)
97 return vbc_downcast(t);
98 return static_cast<const char *> ( t ) + m_difference;
99 }
100 virtual bool is_shortcut() const {
101 return true;
102 }
103 virtual bool has_virtual_base() const {
104 return m_includes_virtual_base;
105 }
106public:
107 void_caster_shortcut(
108 extended_type_info const * derived,
109 extended_type_info const * base,
110 std::ptrdiff_t difference,
111 bool includes_virtual_base,
112 void_caster const * const parent
113 ) :
114 void_caster(derived, base, difference, parent),
115 m_includes_virtual_base(includes_virtual_base)
116 {
117 recursive_register();
118 }
119 virtual ~void_caster_shortcut(){
120 recursive_unregister();
121 }
122};
123
124#ifdef BOOST_MSVC
125# pragma warning(pop)
126#endif
127
128void const *
129void_caster_shortcut::vbc_downcast(
130 void const * const t
131) const {
132 // try to find a chain that gives us what we want
133 const void_cast_detail::set_type & s
134 = void_cast_detail::void_caster_registry::get_const_instance();
135 void_cast_detail::set_type::const_iterator it;
136 for(it = s.begin(); it != s.end(); ++it){
137 // if the current candidate casts to the desired target type
138 if ((*it)->m_derived == m_derived){
139 // and if it's not us
140 if ((*it)->m_base != m_base){
141 // try to cast from the candidate base to our base
142 const void * t_new;
143 t_new = void_downcast(*(*it)->m_base, *m_base, t);
144 // if we were successful
145 if(NULL != t_new){
146 // recast to our derived
147 const void_caster * vc = *it;
148 return vc->downcast(t_new);
149 }
150 }
151 }
152 }
153 return NULL;
154}
155
156void const *
157void_caster_shortcut::vbc_upcast(
158 void const * const t
159) const {
160 // try to find a chain that gives us what we want
161 const void_cast_detail::set_type & s
162 = void_cast_detail::void_caster_registry::get_const_instance();
163 void_cast_detail::set_type::const_iterator it;
164 for(it = s.begin(); it != s.end(); ++it){
165 // if the current candidate casts from the desired base type
166 if((*it)->m_base == m_base){
167 // and if it's not us
168 if ((*it)->m_derived != m_derived){
169 // try to cast from the candidate derived to our our derived
170 const void * t_new;
171 t_new = void_upcast(*m_derived, *(*it)->m_derived, t);
172 if(NULL != t_new)
173 return (*it)->upcast(t_new);
174 }
175 }
176 }
177 return NULL;
178}
179
180#ifdef BOOST_MSVC
181# pragma warning(push)
182# pragma warning(disable : 4511 4512)
183#endif
184
185// just used as a search key
186class void_caster_argument : public void_caster
187{
188 virtual void const *
189 upcast(void const * const /*t*/) const {
190 assert(false);
191 return NULL;
192 }
193 virtual void const *
194 downcast( void const * const /*t*/) const {
195 assert(false);
196 return NULL;
197 }
198 virtual bool has_virtual_base() const {
199 assert(false);
200 return false;
201 }
202public:
203 void_caster_argument(
204 extended_type_info const * derived,
205 extended_type_info const * base
206 ) :
207 void_caster(derived, base)
208 {}
209 virtual ~void_caster_argument(){};
210};
211
212#ifdef BOOST_MSVC
213# pragma warning(pop)
214#endif
215
216// implementation of void caster base class
217BOOST_SERIALIZATION_DECL(void)
218void_caster::recursive_register(bool includes_virtual_base) const {
219 void_cast_detail::set_type & s
220 = void_cast_detail::void_caster_registry::get_mutable_instance();
221
222 #ifdef BOOST_SERIALIZATION_LOG
223 std::clog << "recursive_register\n";
224 std::clog << m_derived->get_debug_info();
225 std::clog << "<-";
226 std::clog << m_base->get_debug_info();
227 std::clog << "\n";
228 #endif
229
230 std::pair<void_cast_detail::set_type::const_iterator, bool> result;
231 result = s.insert(this);
232 assert(result.second);
233
234 // generate all implied void_casts.
235 void_cast_detail::set_type::const_iterator it;
236 for(it = s.begin(); it != s.end(); ++it){
237 if(* m_derived == * (*it)->m_base){
238 const void_caster_argument vca(
239 (*it)->m_derived,
240 m_base
241 );
242 void_cast_detail::set_type::const_iterator i;
243 i = s.find(& vca);
244 if(i == s.end()){
245 new void_caster_shortcut(
246 (*it)->m_derived,
247 m_base,
248 m_difference + (*it)->m_difference,
249 includes_virtual_base,
250 this
251 );
252 }
253 }
254 if(* (*it)->m_derived == * m_base){
255 const void_caster_argument vca(
256 m_derived,
257 (*it)->m_base
258 );
259 void_cast_detail::set_type::const_iterator i;
260 i = s.find(& vca);
261 if(i == s.end()){
262 new void_caster_shortcut(
263 m_derived,
264 (*it)->m_base,
265 m_difference + (*it)->m_difference,
266 (*it)->has_virtual_base(),
267 this
268 );
269 }
270 }
271 }
272}
273
274BOOST_SERIALIZATION_DECL(void)
275void_caster::recursive_unregister() const {
276 if(void_caster_registry::is_destroyed())
277 return;
278
279 #ifdef BOOST_SERIALIZATION_LOG
280 std::clog << "recursive_unregister\n";
281 std::clog << m_derived->get_debug_info();
282 std::clog << "<-";
283 std::clog << m_base->get_debug_info();
284 std::clog << "\n";
285 #endif
286
287 void_cast_detail::set_type & s
288 = void_caster_registry::get_mutable_instance();
289
290 // delete all shortcuts which use this primitive
291 void_cast_detail::set_type::iterator it;
292 for(it = s.begin(); it != s.end();){
293 const void_caster * vc = *it;
294 if(vc == this){
295 s.erase(it++);
296 }
297 else
298 if(vc->m_parent == this){
299 s.erase(it);
300 delete vc;
301 it = s.begin();
302 }
303 else
304 it++;
305 }
306}
307
308} // namespace void_cast_detail
309
310// Given a void *, assume that it really points to an instance of one type
311// and alter it so that it would point to an instance of a related type.
312// Return the altered pointer. If there exists no sequence of casts that
313// can transform from_type to to_type, return a NULL.
314BOOST_SERIALIZATION_DECL(void const *)
315void_upcast(
316 extended_type_info const & derived,
317 extended_type_info const & base,
318 void const * const t
319){
320 // same types - trivial case
321 if (derived == base)
322 return t;
323
324 // check to see if base/derived pair is found in the registry
325 const void_cast_detail::set_type & s
326 = void_cast_detail::void_caster_registry::get_const_instance();
327 const void_cast_detail::void_caster_argument ca(& derived, & base);
328
329 void_cast_detail::set_type::const_iterator it;
330 it = s.find(& ca);
331 if (s.end() != it)
332 return (*it)->upcast(t);
333
334 return NULL;
335}
336
337BOOST_SERIALIZATION_DECL(void const *)
338void_downcast(
339 extended_type_info const & derived,
340 extended_type_info const & base,
341 void const * const t
342){
343 // same types - trivial case
344 if (derived == base)
345 return t;
346
347 // check to see if base/derived pair is found in the registry
348 const void_cast_detail::set_type & s
349 = void_cast_detail::void_caster_registry::get_const_instance();
350 const void_cast_detail::void_caster_argument ca(& derived, & base);
351
352 void_cast_detail::set_type::const_iterator it;
353 it = s.find(&ca);
354 if (s.end() != it)
355 return(*it)->downcast(t);
356
357 return NULL;
358}
359
360} // namespace serialization
361} // namespace boost