mirror of
https://github.com/RPCS3/cereal.git
synced 2025-03-04 13:37:05 +00:00
First pass at inline doc for new polymorphic casting
Also some changes to make sandbox things work with the new casting Made it so base_class doesn't need to know about polymorphism to work All relates to #188
This commit is contained in:
parent
480de61173
commit
37380fa6ff
@ -77,18 +77,34 @@ namespace cereal
|
||||
namespace detail
|
||||
{
|
||||
//! Base type for polymorphic void casting
|
||||
/*! Contains functions for casting between registered base and derived types.
|
||||
|
||||
This class will be allocated as a StaticObject and only referenced by pointer,
|
||||
allowing a templated derived version of it to define strongly typed functions
|
||||
that cast between registered base and derived types.
|
||||
|
||||
This is necessary so that cereal can properly cast between polymorphic types
|
||||
even though void pointers are used, which normally have no type information.
|
||||
Runtime type information is used instead to index a compile-time made mapping
|
||||
that can perform the proper cast.
|
||||
*/
|
||||
struct PolymorphicCaster
|
||||
{
|
||||
//! Casts to the proper derived type
|
||||
//! Downcasts to the proper derived type
|
||||
/*! This should be overrriden in derived types, which can
|
||||
be templated to allow the proper base derived type
|
||||
paring to be used, while allowing generic access
|
||||
through a void pointer. */
|
||||
virtual void const * downcast( void const * const ptr ) const = 0;
|
||||
//! Upcast to proper base type
|
||||
virtual void * upcast( void * const ptr ) const = 0;
|
||||
//! Upcast to proper base type, shared_ptr version
|
||||
virtual std::shared_ptr<void> upcast( std::shared_ptr<void> const & ptr ) const = 0;
|
||||
};
|
||||
|
||||
//! Holds registered mappings between base and derived types for casting
|
||||
/*! This will be allocated as a StaticObject and holds a map containing
|
||||
all registered mappings between base and derived types. */
|
||||
struct PolymorphicCasters
|
||||
{
|
||||
//! Maps a derived type index to a polymorphic caster
|
||||
@ -105,6 +121,10 @@ namespace cereal
|
||||
"Alternatively, manually register the association with XXX.");
|
||||
|
||||
//! Gets the mapping object that can perform the upcast or downcast
|
||||
/*! Uses the type info from the base and derived class to find the matching
|
||||
registered caster. If no matching caster exists, calls the exception function.
|
||||
|
||||
The returned PolymorphicCaster is capable of upcasting or downcasting between the two types */
|
||||
template <class F>
|
||||
static PolymorphicCaster const * lookup( std::type_info const & baseInfo, std::type_info const & derivedInfo, F && exceptionFunc )
|
||||
{
|
||||
@ -125,7 +145,7 @@ namespace cereal
|
||||
}
|
||||
|
||||
//! Performs a downcast to the derived type using a registered mapping
|
||||
template <class Derived>
|
||||
template <class Derived> inline
|
||||
static const Derived * downcast( const void * const dptr, std::type_info const & baseInfo )
|
||||
{
|
||||
auto const * mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(save) } );
|
||||
@ -135,7 +155,7 @@ namespace cereal
|
||||
//! Performs an upcast to the registered base type using the given a derived type
|
||||
/*! The return is untyped because the final casting to the base type must happen in the polymorphic
|
||||
serialization function, where the type is known at compile time */
|
||||
template <class Derived>
|
||||
template <class Derived> inline
|
||||
static void * upcast( Derived * const dptr, std::type_info const & baseInfo )
|
||||
{
|
||||
auto const * mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } );
|
||||
@ -143,7 +163,7 @@ namespace cereal
|
||||
}
|
||||
|
||||
//! Upcasts for shared pointers
|
||||
template <class Derived>
|
||||
template <class Derived> inline
|
||||
static std::shared_ptr<void> upcast( std::shared_ptr<Derived> const & dptr, std::type_info const & baseInfo )
|
||||
{
|
||||
auto const * mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } );
|
||||
@ -153,12 +173,14 @@ namespace cereal
|
||||
#undef UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION
|
||||
};
|
||||
|
||||
//! Strongly typed derivation of PolymorphicCaster
|
||||
template <class Base, class Derived>
|
||||
struct PolymorphicVirtualCaster : PolymorphicCaster
|
||||
{
|
||||
//! Inserts an entry in the polymorphic casting map for this pairing
|
||||
/*! This creates all possible paths from Base to Derived in the mapping
|
||||
given currently registered pairings */
|
||||
/*! Creates an explicit mapping between Base and Derived in both upwards and
|
||||
downwards directions, allowing void pointers to either to be properly cast
|
||||
assuming dynamic type information is available */
|
||||
PolymorphicVirtualCaster()
|
||||
{
|
||||
auto & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
|
||||
@ -181,17 +203,26 @@ namespace cereal
|
||||
return dynamic_cast<Derived const*>( static_cast<Base const*>( ptr ) );
|
||||
}
|
||||
|
||||
//! Performs the proper upcast with the templated types
|
||||
void * upcast( void * const ptr ) const override
|
||||
{
|
||||
return dynamic_cast<Base*>( static_cast<Derived*>( ptr ) );
|
||||
}
|
||||
|
||||
//! Performs the proper upcast with the templated types (shared_ptr version)
|
||||
std::shared_ptr<void> upcast( std::shared_ptr<void> const & ptr ) const override
|
||||
{
|
||||
return std::dynamic_pointer_cast<Base>( std::static_pointer_cast<Derived>( ptr ) );
|
||||
}
|
||||
};
|
||||
|
||||
//! Registers a polymorphic casting relation between a Base and Derived type
|
||||
/*! Registering a relation allows cereal to properly cast between the two types
|
||||
given runtime type information and void pointers.
|
||||
|
||||
Registration happens automatically via cereal::base_class and cereal::virtual_base_class
|
||||
instantiations. For cases where neither is called, see the CEREAL_REGISTER_POLYMORPHIC_RELATION
|
||||
macro */
|
||||
template <class Base, class Derived>
|
||||
struct RegisterPolymorphicCaster
|
||||
{
|
||||
@ -203,6 +234,8 @@ namespace cereal
|
||||
static PolymorphicCaster const * bind( std::false_type /* is_polymorphic<Base> */ )
|
||||
{ return nullptr; }
|
||||
|
||||
//! Performs registration (binding) between Base and Derived
|
||||
/*! If the type is not polymorphic, nothing will happen */
|
||||
static PolymorphicCaster const * bind()
|
||||
{ return bind( typename std::is_polymorphic<Base>::type() ); }
|
||||
};
|
||||
|
@ -49,14 +49,15 @@ namespace cereal
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
//! Forward declaration, see polymorphic_impl.hpp for more information
|
||||
template <class Base, class Derived>
|
||||
struct RegisterPolymorphicCaster;
|
||||
|
||||
//! Forward declaration, see polymorphic_impl.hpp for more information
|
||||
struct PolymorphicCasters;
|
||||
|
||||
namespace { struct polymorphic_relation_tag {}; }
|
||||
|
||||
template <class Base, class Derived, class tag = polymorphic_relation_tag>
|
||||
//! Forward declaration, see polymorphic_impl.hpp for more information
|
||||
template <class Base, class Derived>
|
||||
struct PolymorphicRelation;
|
||||
} // namespace detail
|
||||
} // namespace cereal
|
||||
|
@ -35,10 +35,31 @@
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace base_class_detail
|
||||
{
|
||||
template <class Base, class Derived, bool IsPolymorphic = std::is_polymorphic<Base>::value>
|
||||
struct RegisterPolymorphicBaseClass
|
||||
{
|
||||
static void bind()
|
||||
{ }
|
||||
};
|
||||
|
||||
template <class Base, class Derived>
|
||||
struct RegisterPolymorphicBaseClass<Base, Derived, true>
|
||||
{
|
||||
static void bind()
|
||||
{ detail::RegisterPolymorphicCaster<Base, Derived>::bind(); }
|
||||
};
|
||||
}
|
||||
|
||||
//! Casts a derived class to its non-virtual base class in a way that safely supports abstract classes
|
||||
/*! This should be used in cases when a derived type needs to serialize its base type. This is better than directly
|
||||
using static_cast, as it allows for serialization of pure virtual (abstract) base classes.
|
||||
|
||||
This also automatically registers polymorphic relation between the base and derived class, assuming they
|
||||
are indeed polymorphic. Note this is not the same as polymorphic type registration. For more information
|
||||
see the documentation on polymorphism.
|
||||
|
||||
\sa virtual_base_class
|
||||
|
||||
@code{.cpp}
|
||||
@ -77,7 +98,7 @@ namespace cereal
|
||||
base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
|
||||
{
|
||||
static_assert( std::is_base_of<Base, Derived>::value, "Can only use base_class on a valid base class" );
|
||||
detail::RegisterPolymorphicCaster<Base, Derived>::bind();
|
||||
base_class_detail::RegisterPolymorphicBaseClass<Base, Derived>::bind();
|
||||
}
|
||||
|
||||
Base * base_ptr;
|
||||
@ -92,6 +113,10 @@ namespace cereal
|
||||
where virtual inheritance does not take place, though it may be slightly faster to utilize
|
||||
cereal::base_class<> if you do not need to worry about virtual inheritance.
|
||||
|
||||
This also automatically registers polymorphic relation between the base and derived class, assuming they
|
||||
are indeed polymorphic. Note this is not the same as polymorphic type registration. For more information
|
||||
see the documentation on polymorphism.
|
||||
|
||||
\sa base_class
|
||||
|
||||
@code{.cpp}
|
||||
@ -158,7 +183,10 @@ namespace cereal
|
||||
template<class Derived>
|
||||
virtual_base_class(Derived const * derived) :
|
||||
base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
|
||||
{ static_assert( std::is_base_of<Base, Derived>::value, "Can only use base_class on a valid base class" ); }
|
||||
{
|
||||
static_assert( std::is_base_of<Base, Derived>::value, "Can only use virtual_base_class on a valid base class" );
|
||||
base_class_detail::RegisterPolymorphicBaseClass<Base, Derived>::bind();
|
||||
}
|
||||
|
||||
Base * base_ptr;
|
||||
};
|
||||
|
@ -115,7 +115,7 @@
|
||||
|
||||
The Derived class should be the most derived type that will be serialized,
|
||||
and the Base type any possible base that has not been covered under a base
|
||||
class serialization
|
||||
class serialization that will be used to store a Derived pointer.
|
||||
|
||||
Placement of this is the same as for CEREAL_REGISTER_TYPE. */
|
||||
#define CEREAL_REGISTER_POLYMORPHIC_RELATION(Base, Derived) \
|
||||
|
@ -97,7 +97,9 @@ struct YourType : public Base
|
||||
ar( x );
|
||||
}
|
||||
};
|
||||
|
||||
CEREAL_REGISTER_TYPE(YourType)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Base, YourType)
|
||||
|
||||
struct OurBase
|
||||
{
|
||||
|
@ -144,6 +144,7 @@ struct C
|
||||
};
|
||||
|
||||
CEREAL_REGISTER_TYPE(B)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(A, B)
|
||||
|
||||
class MemberMinimal
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user