| 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 |
|
|---|
| 36 | namespace boost {
|
|---|
| 37 | namespace serialization {
|
|---|
| 38 | namespace 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.
|
|---|
| 45 | bool 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 |
|
|---|
| 61 | struct void_caster_compare {
|
|---|
| 62 | bool operator()(const void_caster * lhs, const void_caster * rhs) const {
|
|---|
| 63 | return *lhs < *rhs;
|
|---|
| 64 | }
|
|---|
| 65 | };
|
|---|
| 66 |
|
|---|
| 67 | typedef std::set<const void_caster *, void_caster_compare> set_type;
|
|---|
| 68 | typedef 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
|
|---|
| 76 | class 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 | }
|
|---|
| 106 | public:
|
|---|
| 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(includes_virtual_base);
|
|---|
| 118 | }
|
|---|
| 119 | virtual ~void_caster_shortcut(){
|
|---|
| 120 | recursive_unregister();
|
|---|
| 121 | }
|
|---|
| 122 | };
|
|---|
| 123 |
|
|---|
| 124 | #ifdef BOOST_MSVC
|
|---|
| 125 | # pragma warning(pop)
|
|---|
| 126 | #endif
|
|---|
| 127 |
|
|---|
| 128 | void const *
|
|---|
| 129 | void_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 |
|
|---|
| 156 | void const *
|
|---|
| 157 | void_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
|
|---|
| 186 | class 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 | }
|
|---|
| 202 | public:
|
|---|
| 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
|
|---|
| 217 | BOOST_SERIALIZATION_DECL(void)
|
|---|
| 218 | void_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 | (*it)->has_virtual_base() || 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() || includes_virtual_base,
|
|---|
| 267 | this
|
|---|
| 268 | );
|
|---|
| 269 | }
|
|---|
| 270 | }
|
|---|
| 271 | }
|
|---|
| 272 | }
|
|---|
| 273 |
|
|---|
| 274 | BOOST_SERIALIZATION_DECL(void)
|
|---|
| 275 | void_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.
|
|---|
| 314 | BOOST_SERIALIZATION_DECL(void const *)
|
|---|
| 315 | void_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 |
|
|---|
| 337 | BOOST_SERIALIZATION_DECL(void const *)
|
|---|
| 338 | void_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
|
|---|