/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 // void_cast.cpp: implementation of run-time casting of void pointers // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org for updates, documentation, and revision history. #if (defined _MSC_VER) && (_MSC_VER == 1200) # pragma warning (disable : 4786) // too long name, harmless warning #endif #include // STL #include #include #include #include // BOOST #include #define BOOST_SERIALIZATION_SOURCE #include #include namespace boost { namespace serialization { namespace void_cast_detail { struct void_caster_compare { bool operator()( shared_ptr lhs, shared_ptr rhs ) const { if( lhs.get()->m_derived_type < rhs.get()->m_derived_type ) return true; if( rhs.get()->m_derived_type < lhs.get()->m_derived_type) return false; if( lhs.get()->m_base_type < rhs.get()->m_base_type ) return true; return false; } }; struct null_deleter { void operator()(void const *) const {} }; // it turns out that at least one compiler (msvc 6.0) doesn't guarentee // to destroy static objects in exactly the reverse sequence that they // are constructed. To guarentee this, use a singleton pattern class void_caster_registry { typedef shared_ptr value_type; typedef std::set set_type; set_type m_set; static void_caster_registry * m_self; static void_caster_registry * self(){ if(NULL == m_self){ static void_caster_registry instance; m_self = & instance; } return m_self; } void_caster_registry(){} public: ~void_caster_registry(){ m_self = 0; } typedef set_type::iterator iterator; typedef set_type::const_iterator const_iterator; static iterator begin() { return self()->m_set.begin(); } static iterator end() { return self()->m_set.end(); } static const_iterator find(void_caster * vcp){ return self()->m_set.find(value_type(vcp, null_deleter())); } static std::pair insert(const value_type & vcp){ return self()->m_set.insert(vcp); } static bool empty(){ if(NULL == m_self) return true; return m_self->m_set.empty(); } static void purge(const extended_type_info * eti); }; void_caster_registry * void_caster_registry::m_self = NULL; void void_caster_registry::purge(const extended_type_info * eti){ if(NULL == m_self) return; if(! empty()){ iterator i = m_self->m_set.begin(); while(i != m_self->m_set.end()){ // note that the erase might invalidate i so save it here iterator j = i++; if((*j)->includes(eti)) m_self->m_set.erase(j); } } } BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY()) void_caster::void_caster( extended_type_info const & derived_type_, extended_type_info const & base_type_ ) : m_derived_type( derived_type_), m_base_type(base_type_) {} BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY()) void_caster::~void_caster(){} bool void_caster::includes(const extended_type_info * eti) const { return & m_derived_type == eti || & m_base_type == eti; } void BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY()) void_caster::static_register(const void_caster * vcp) { void_caster_registry::insert(shared_ptr(vcp, null_deleter())); } class void_caster_derived : public void_caster { std::ptrdiff_t difference; virtual void const* upcast( void const* t ) const{ return static_cast ( t ) + difference; } virtual void const* downcast( void const* t ) const{ return static_cast ( t ) - difference; } public: void_caster_derived( extended_type_info const& derived_type_, extended_type_info const& base_type_, std::ptrdiff_t difference_ ) : void_caster(derived_type_, base_type_), difference( difference_ ) {} }; // just used as a search key class void_caster_argument : public void_caster { virtual void const* upcast( void const* /* t */ ) const { assert(false); return NULL; } virtual void const* downcast( void const* /* t */ ) const { assert(false); return NULL; } public: void_caster_argument( extended_type_info const& derived_type_, extended_type_info const& base_type_ ) : void_caster(derived_type_, base_type_) {} }; } // namespace void_cast_detail void BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY()) unregister_void_casts(extended_type_info *eti) { void_cast_detail::void_caster_registry::purge(eti); } // Given a void *, assume that it really points to an instance of one type // and alter it so that it would point to an instance of a related type. // Return the altered pointer. If there exists no sequence of casts that // can transform from_type to to_type, return a NULL. BOOST_SERIALIZATION_DECL(void const *) void_upcast( extended_type_info const & derived_type, extended_type_info const & base_type, void const * const t, bool top ){ // same types - trivial case if (derived_type == base_type) return t; // check to see if base/derived pair is found in the registry void_cast_detail::void_caster_argument ca(derived_type, base_type ); void_cast_detail::void_caster_registry::const_iterator it; it = void_cast_detail::void_caster_registry::find( &ca ); const void * t_new = NULL; // if so if (it != void_cast_detail::void_caster_registry::end()) // we're done return (*it)->upcast(t); // try to find a chain that gives us what we want for( it = void_cast_detail::void_caster_registry::begin(); it != void_cast_detail::void_caster_registry::end(); ++it ){ // if the current candidate doesn't cast to the desired target type if ((*it)->m_base_type == base_type){ // if the current candidate casts from the desired source type if ((*it)->m_derived_type == derived_type){ // we have a base/derived match - we're done // cast to the intermediate type t_new = (*it)->upcast(t); break; } t_new = void_upcast(derived_type, (*it)->m_derived_type, t, false); if (NULL != t_new){ t_new = (*it)->upcast(t_new); assert(NULL != t_new); if(top){ // register the this pair so we will have to go through // keep this expensive search process more than once. void_cast_detail::void_caster * vcp = new void_cast_detail::void_caster_derived( derived_type, base_type, static_cast(t_new) - static_cast(t) ); void_cast_detail::void_caster_registry::insert( shared_ptr(vcp) ); } break; } } } return t_new; } BOOST_SERIALIZATION_DECL(void const *) void_downcast( const extended_type_info & derived_type, const extended_type_info & base_type, const void * const t, bool top ){ // same types - trivial case if (derived_type == base_type) return t; // check to see if base/derived pair is found in the registry void_cast_detail::void_caster_argument ca(derived_type, base_type ); void_cast_detail::void_caster_registry::const_iterator it; it = void_cast_detail::void_caster_registry::find( &ca ); // if so if (it != void_cast_detail::void_caster_registry::end()) // we're done return (*it)->downcast(t); const void * t_new = NULL; // try to find a chain that gives us what we want for( it = void_cast_detail::void_caster_registry::begin(); it != void_cast_detail::void_caster_registry::end(); ++it ){ // if the current candidate doesn't casts from the desired target type if ((*it)->m_derived_type == derived_type){ // if the current candidate casts to the desired source type if ((*it)->m_base_type == base_type){ // we have a base/derived match - we're done // cast to the intermediate type t_new = (*it)->downcast(t); break; } t_new = void_downcast((*it)->m_base_type, base_type, t, false); if (NULL != t_new){ t_new = (*it)->downcast(t_new); assert(NULL != t_new); if(top){ // register the this pair so we will have to go through // keep this expensive search process more than once. void_cast_detail::void_caster * vcp = new void_cast_detail::void_caster_derived( derived_type, base_type, static_cast(t) - static_cast(t_new) ); void_cast_detail::void_caster_registry::insert( shared_ptr(vcp) ); } break; } } } return t_new; } } // namespace serialization } // namespace boost // EOF