mirror of
https://github.com/boostorg/serialization.git
synced 2026-01-24 06:22:08 +00:00
260 lines
7.2 KiB
C++
260 lines
7.2 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>
|
|
#include <cstddef> // NULL
|
|
|
|
// STL
|
|
#include <vector>
|
|
#include <functional>
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
|
|
// BOOST
|
|
#define BOOST_SERIALIZATION_SOURCE
|
|
#include <boost/serialization/singleton.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 {
|
|
|
|
typedef std::vector<const void_caster *> set_type;
|
|
typedef boost::serialization::singleton<set_type> void_caster_registry;
|
|
|
|
inline bool
|
|
void_caster::operator==(void_caster const & rhs) const{
|
|
if(m_derived != rhs.m_derived)
|
|
return false;
|
|
if(m_base != rhs.m_base)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
// implementation of void caster base class
|
|
BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
|
|
void_caster::void_caster(
|
|
extended_type_info const & derived,
|
|
extended_type_info const & base
|
|
) :
|
|
m_derived(derived),
|
|
m_base(base)
|
|
{}
|
|
|
|
BOOST_SERIALIZATION_DECL(void)
|
|
void_caster::static_register() const {
|
|
void_caster_registry::get_mutable_instance().push_back(this);
|
|
// to do - add new void_caster_derived entries
|
|
// which can be generated by adding this new primitive
|
|
/*
|
|
while(){
|
|
if(!extend_down(this)
|
|
&& !extend_up(this))
|
|
break;
|
|
}
|
|
*/
|
|
}
|
|
|
|
BOOST_SERIALIZATION_DECL(void)
|
|
void_caster::static_unregister() const {
|
|
if(! void_caster_registry::is_destroyed()){
|
|
void_cast_detail::set_type & st
|
|
= void_caster_registry::get_mutable_instance();
|
|
void_cast_detail::set_type::iterator it;
|
|
it = std::find(st.begin(), st.end(), this);
|
|
assert(st.end() != it);
|
|
st.erase(it);
|
|
// to do - remove all void_caster_derived entries
|
|
// which depend upon this primitive
|
|
/*
|
|
while(){
|
|
if(!truncate_down(this)
|
|
&& !truncate_up(this))
|
|
break;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
// implementation of shortcut void caster
|
|
class void_caster_derived : public void_caster
|
|
{
|
|
std::ptrdiff_t difference;
|
|
virtual void const *
|
|
upcast(void const * const t) const{
|
|
return static_cast<const char *> ( t ) + difference;
|
|
}
|
|
virtual void const *
|
|
downcast(void const * const t) const{
|
|
return static_cast<const char *> ( t ) - difference;
|
|
}
|
|
public:
|
|
void_caster_derived(
|
|
extended_type_info const & derived,
|
|
extended_type_info const & base,
|
|
std::ptrdiff_t difference
|
|
) :
|
|
void_caster(derived, base),
|
|
difference( difference )
|
|
{
|
|
this->static_register();
|
|
}
|
|
~void_caster_derived(){
|
|
this->static_unregister();
|
|
}
|
|
};
|
|
#endif
|
|
|
|
// just used as a search key
|
|
class void_caster_argument : public void_caster
|
|
{
|
|
virtual void const *
|
|
upcast(void const * const t) const {
|
|
assert(false);
|
|
return NULL;
|
|
}
|
|
virtual void const *
|
|
downcast( void const * const t) const {
|
|
assert(false);
|
|
return NULL;
|
|
}
|
|
public:
|
|
void_caster_argument(
|
|
extended_type_info const & derived,
|
|
extended_type_info const & base
|
|
) :
|
|
void_caster(derived, base)
|
|
{}
|
|
~void_caster_argument(){};
|
|
};
|
|
|
|
struct match {
|
|
void_cast_detail::void_caster_argument const * const m_ca;
|
|
|
|
match(void_cast_detail::void_caster_argument const * const ca) :
|
|
m_ca(ca)
|
|
{}
|
|
bool operator()(const void_cast_detail::void_caster * vc){
|
|
return * vc == * m_ca;
|
|
};
|
|
};
|
|
|
|
} // namespace void_cast_detail
|
|
|
|
// 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,
|
|
extended_type_info const & base,
|
|
void const * const t
|
|
){
|
|
// same types - trivial case
|
|
if (derived == base)
|
|
return t;
|
|
|
|
// check to see if base/derived pair is found in the registry
|
|
const void_cast_detail::set_type & s
|
|
= void_cast_detail::void_caster_registry::get_const_instance();
|
|
void_cast_detail::set_type::const_iterator it;
|
|
void_cast_detail::void_caster_argument ca(derived, base);
|
|
|
|
it = std::find_if(
|
|
s.begin(),
|
|
s.end(),
|
|
void_cast_detail::match(& ca)
|
|
);
|
|
|
|
// if so
|
|
if (s.end() != it)
|
|
// we're done
|
|
return (*it)->upcast(t);
|
|
|
|
// try to find a chain that gives us what we want
|
|
for(it = s.begin(); it != s.end(); ++it){
|
|
// if the current candidate doesn't cast to the desired target type
|
|
if((*it)->m_base == base){
|
|
// if the current candidate casts from the desired source type
|
|
if ((*it)->m_derived == derived){
|
|
// we have a base/derived match - we're done
|
|
// cast to the intermediate type
|
|
return (*it)->upcast(t);
|
|
}
|
|
const void * t_new;
|
|
t_new = void_upcast(derived, (*it)->m_derived, t);
|
|
if(NULL != t_new)
|
|
return (*it)->upcast(t_new);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BOOST_SERIALIZATION_DECL(void const *)
|
|
void_downcast(
|
|
extended_type_info const & derived,
|
|
extended_type_info const & base,
|
|
void const * const t
|
|
){
|
|
// same types - trivial case
|
|
if (derived == base)
|
|
return t;
|
|
|
|
// check to see if base/derived pair is found in the registry
|
|
const void_cast_detail::set_type & s
|
|
= void_cast_detail::void_caster_registry::get_const_instance();
|
|
void_cast_detail::set_type::const_iterator it;
|
|
void_cast_detail::void_caster_argument ca(derived, base);
|
|
|
|
it = std::find_if(
|
|
s.begin(),
|
|
s.end(),
|
|
void_cast_detail::match(& ca)
|
|
);
|
|
|
|
// if so
|
|
if (s.end() != it)
|
|
// we're done
|
|
return(*it)->downcast(t);
|
|
|
|
// try to find a chain that gives us what we want
|
|
for(it = s.begin(); it != s.end(); ++it){
|
|
// if the current candidate doesn't cast to the desired target type
|
|
if ((*it)->m_derived == derived){
|
|
// if the current candidate casts from the desired source type
|
|
if ((*it)->m_base == base){
|
|
// we have a base/derived match - we're done
|
|
// cast to the intermediate type
|
|
return (*it)->downcast(t);
|
|
}
|
|
const void * t_new;
|
|
t_new = void_downcast((*it)->m_base, base, t);
|
|
if(NULL != t_new)
|
|
return (*it)->downcast(t_new);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
} // namespace serialization
|
|
} // namespace boost
|
|
|
|
// EOF
|