libs/serialization/src/void_cast.cpp
/////////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
#include <boost/shared_ptr.hpp>
#define BOOST_SERIALIZATION_SOURCE
#include <boost/serialization/extended_type_info.hpp>
#include <boost/serialization/void_cast.hpp>
namespace boost {
namespace serialization {
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(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<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(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<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(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<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