mirror of
https://github.com/boostorg/serialization.git
synced 2026-01-23 18:12:09 +00:00
337 lines
10 KiB
C++
337 lines
10 KiB
C++
/////////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)
|
|
// <gennadiy.rozental@tfn.com>
|
|
|
|
// 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 <cassert>
|
|
|
|
// STL
|
|
#include <set>
|
|
#include <functional>
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
|
|
// BOOST
|
|
#define BOOST_SERIALIZATION_SOURCE
|
|
// specify the default type_info implementation if it hasn't been done already
|
|
#ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO
|
|
#include <boost/serialization/extended_type_info_typeid.hpp>
|
|
#endif
|
|
#include <boost/shared_ptr.hpp>
|
|
#include <boost/serialization/void_cast.hpp>
|
|
|
|
namespace boost {
|
|
namespace serialization {
|
|
|
|
class extended_type_info;
|
|
|
|
namespace void_cast_detail {
|
|
|
|
struct void_caster_compare
|
|
{
|
|
bool
|
|
operator()(
|
|
shared_ptr<const void_caster> lhs,
|
|
shared_ptr<const void_caster> 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<const void_caster> value_type;
|
|
typedef std::set<value_type, void_caster_compare> 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<iterator, bool>
|
|
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(! 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
|
|
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
|
|
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
|
|
void_caster::static_register(const void_caster * vcp)
|
|
{
|
|
void_caster_registry::insert(shared_ptr<const void_caster>(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<const char*> ( t ) + difference;
|
|
}
|
|
virtual void const*
|
|
downcast( void const* t ) const{
|
|
return static_cast<const char*> ( 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
|
|
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 const void *
|
|
void_upcast(
|
|
const extended_type_info & derived_type,
|
|
const extended_type_info & base_type,
|
|
const void * 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<const char*>(t_new) - static_cast<const char*>(t)
|
|
);
|
|
void_cast_detail::void_caster_registry::insert(
|
|
shared_ptr<const void_cast_detail::void_caster>(vcp)
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return t_new;
|
|
}
|
|
|
|
BOOST_SERIALIZATION_DECL const void *
|
|
void_downcast(
|
|
const extended_type_info & derived_type,
|
|
const extended_type_info & base_type,
|
|
const void * 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<const char*>(t) - static_cast<const char*>(t_new)
|
|
);
|
|
void_cast_detail::void_caster_registry::insert(
|
|
shared_ptr<const void_cast_detail::void_caster>(vcp)
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return t_new;
|
|
}
|
|
|
|
} // namespace serialization
|
|
} // namespace boost
|
|
|
|
// EOF
|