mirror of
https://github.com/USCiLab/cereal.git
synced 2025-10-18 01:45:52 +02:00
Case for serializing true polymorphic pointers
This commit is contained in:
@@ -163,6 +163,7 @@ namespace cereal
|
|||||||
|
|
||||||
// used during saving pointers
|
// used during saving pointers
|
||||||
static const int32_t msb_32bit = 0x80000000;
|
static const int32_t msb_32bit = 0x80000000;
|
||||||
|
static const int32_t msb2_32bit = 0x40000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Registers a specific Archive type with cereal
|
//! Registers a specific Archive type with cereal
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include <cereal/types/memory.hpp>
|
#include <cereal/types/memory.hpp>
|
||||||
#include <cereal/details/polymorphic_impl.hpp>
|
#include <cereal/details/polymorphic_impl.hpp>
|
||||||
#include <cereal/details/util.hpp>
|
#include <cereal/details/util.hpp>
|
||||||
|
#include <cereal/details/traits.hpp>
|
||||||
|
|
||||||
//! Registers a polymorphic type with cereal
|
//! Registers a polymorphic type with cereal
|
||||||
/*! Polymorphic types must be registered before pointers
|
/*! Polymorphic types must be registered before pointers
|
||||||
@@ -79,11 +80,8 @@ namespace cereal
|
|||||||
{
|
{
|
||||||
//! Get an input binding from the given archive by deserializing the type meta data
|
//! Get an input binding from the given archive by deserializing the type meta data
|
||||||
template<class Archive>
|
template<class Archive>
|
||||||
typename ::cereal::detail::InputBindingMap<Archive>::Serializers getInputBinding(Archive & ar)
|
typename ::cereal::detail::InputBindingMap<Archive>::Serializers getInputBinding(Archive & ar, std::uint32_t const nameid)
|
||||||
{
|
{
|
||||||
std::uint32_t nameid;
|
|
||||||
ar( nameid );
|
|
||||||
|
|
||||||
if(nameid == 0)
|
if(nameid == 0)
|
||||||
{
|
{
|
||||||
typename ::cereal::detail::InputBindingMap<Archive>::Serializers emptySerializers;
|
typename ::cereal::detail::InputBindingMap<Archive>::Serializers emptySerializers;
|
||||||
@@ -108,6 +106,50 @@ namespace cereal
|
|||||||
throw cereal::Exception("Trying to load an unregistered polymorphic type (" + name + ")");
|
throw cereal::Exception("Trying to load an unregistered polymorphic type (" + name + ")");
|
||||||
return binding->second;
|
return binding->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Serialize a shared_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
|
||||||
|
template<class Archive, class T> inline
|
||||||
|
typename std::enable_if<std::is_default_constructible<T>::value || traits::has_load_and_allocate<T, Archive>(), bool>::type
|
||||||
|
serialize_wrapper(Archive & ar, std::shared_ptr<T> & ptr, std::uint32_t const nameid)
|
||||||
|
{
|
||||||
|
if(nameid & detail::msb2_32bit)
|
||||||
|
{
|
||||||
|
ar( detail::make_ptr_wrapper(ptr) );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Serialize a unique_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
|
||||||
|
template<class Archive, class T, class D> inline
|
||||||
|
typename std::enable_if<std::is_default_constructible<T>::value || traits::has_load_and_allocate<T, Archive>(), bool>::type
|
||||||
|
serialize_wrapper(Archive & ar, std::unique_ptr<T, D> & ptr, std::uint32_t const nameid)
|
||||||
|
{
|
||||||
|
if(nameid & detail::msb2_32bit)
|
||||||
|
{
|
||||||
|
ar( detail::make_ptr_wrapper(ptr) );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive, class T> inline
|
||||||
|
typename std::enable_if<!std::is_default_constructible<T>::value && !traits::has_load_and_allocate<T, Archive>(), bool>::type
|
||||||
|
serialize_wrapper(Archive & ar, std::shared_ptr<T> & ptr, std::uint32_t const nameid)
|
||||||
|
{
|
||||||
|
if(nameid & detail::msb2_32bit)
|
||||||
|
throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_allocate function");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive, class T, class D> inline
|
||||||
|
typename std::enable_if<!std::is_default_constructible<T>::value && !traits::has_load_and_allocate<T, Archive>(), bool>::type
|
||||||
|
serialize_wrapper(Archive & ar, std::unique_ptr<T, D> & ptr, std::uint32_t const nameid)
|
||||||
|
{
|
||||||
|
if(nameid & detail::msb2_32bit)
|
||||||
|
throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_allocate function");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
@@ -125,11 +167,25 @@ namespace cereal
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::type_info const & ptrinfo = typeid(*ptr.get());
|
||||||
|
static std::type_info const & tinfo = typeid(T);
|
||||||
|
|
||||||
|
if(ptrinfo == tinfo)
|
||||||
|
{
|
||||||
|
// The 2nd msb signals that the following pointer does not need to be
|
||||||
|
// cast with our polymorphic machinery
|
||||||
|
ar( detail::msb2_32bit );
|
||||||
|
|
||||||
|
ar( detail::make_ptr_wrapper(ptr) );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
||||||
|
|
||||||
auto binding = bindingMap.find(std::type_index(typeid(*ptr.get())));
|
auto binding = bindingMap.find(std::type_index(ptrinfo));
|
||||||
if(binding == bindingMap.end())
|
if(binding == bindingMap.end())
|
||||||
throw cereal::Exception("Trying to save an unregistered polymorphic type (" + cereal::util::demangle(typeid(*ptr.get()).name()) + ")");
|
throw cereal::Exception("Trying to save an unregistered polymorphic type (" + cereal::util::demangle(ptrinfo.name()) + ")");
|
||||||
|
|
||||||
binding->second.shared_ptr(&ar, ptr.get());
|
binding->second.shared_ptr(&ar, ptr.get());
|
||||||
}
|
}
|
||||||
@@ -139,7 +195,14 @@ namespace cereal
|
|||||||
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
|
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
|
||||||
load( Archive & ar, std::shared_ptr<T> & ptr )
|
load( Archive & ar, std::shared_ptr<T> & ptr )
|
||||||
{
|
{
|
||||||
auto binding = polymorphic_detail::getInputBinding(ar);
|
std::uint32_t nameid;
|
||||||
|
ar( nameid );
|
||||||
|
|
||||||
|
// Check to see if we can skip all of this polymorphism business
|
||||||
|
if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto binding = polymorphic_detail::getInputBinding(ar, nameid);
|
||||||
std::shared_ptr<void> result;
|
std::shared_ptr<void> result;
|
||||||
binding.shared_ptr(&ar, result);
|
binding.shared_ptr(&ar, result);
|
||||||
ptr = std::static_pointer_cast<T>(result);
|
ptr = std::static_pointer_cast<T>(result);
|
||||||
@@ -176,11 +239,25 @@ namespace cereal
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::type_info const & ptrinfo = typeid(*ptr.get());
|
||||||
|
static std::type_info const & tinfo = typeid(T);
|
||||||
|
|
||||||
|
if(ptrinfo == tinfo)
|
||||||
|
{
|
||||||
|
// The 2nd msb signals that the following pointer does not need to be
|
||||||
|
// cast with our polymorphic machinery
|
||||||
|
ar( detail::msb2_32bit );
|
||||||
|
|
||||||
|
ar( detail::make_ptr_wrapper(ptr) );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
|
||||||
|
|
||||||
auto binding = bindingMap.find(std::type_index(typeid(*ptr.get())));
|
auto binding = bindingMap.find(std::type_index(ptrinfo));
|
||||||
if(binding == bindingMap.end())
|
if(binding == bindingMap.end())
|
||||||
throw cereal::Exception("Trying to save an unregistered polymorphic type (" + cereal::util::demangle(typeid(*ptr.get()).name()) + ")");
|
throw cereal::Exception("Trying to save an unregistered polymorphic type (" + cereal::util::demangle(ptrinfo.name()) + ")");
|
||||||
|
|
||||||
binding->second.unique_ptr(&ar, ptr.get());
|
binding->second.unique_ptr(&ar, ptr.get());
|
||||||
}
|
}
|
||||||
@@ -190,7 +267,14 @@ namespace cereal
|
|||||||
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
|
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
|
||||||
load( Archive & ar, std::unique_ptr<T, D> & ptr )
|
load( Archive & ar, std::unique_ptr<T, D> & ptr )
|
||||||
{
|
{
|
||||||
auto binding = polymorphic_detail::getInputBinding(ar);
|
std::uint32_t nameid;
|
||||||
|
ar( nameid );
|
||||||
|
|
||||||
|
// Check to see if we can skip all of this polymorphism business
|
||||||
|
if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto binding = polymorphic_detail::getInputBinding(ar, nameid);
|
||||||
std::unique_ptr<void> result;
|
std::unique_ptr<void> result;
|
||||||
binding.unique_ptr(&ar, result);
|
binding.unique_ptr(&ar, result);
|
||||||
ptr.reset(static_cast<T*>(result.release()));
|
ptr.reset(static_cast<T*>(result.release()));
|
||||||
|
|||||||
@@ -98,6 +98,31 @@ struct YourType : public Base
|
|||||||
};
|
};
|
||||||
CEREAL_REGISTER_TYPE(YourType);
|
CEREAL_REGISTER_TYPE(YourType);
|
||||||
|
|
||||||
|
struct OurBase
|
||||||
|
{
|
||||||
|
virtual void foo() {}
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive & ar)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OurType : public OurBase
|
||||||
|
{
|
||||||
|
OurType() = default;
|
||||||
|
OurType(int x_) : x(x_) {}
|
||||||
|
void foo() {}
|
||||||
|
|
||||||
|
int x;
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive & ar)
|
||||||
|
{
|
||||||
|
ar( x );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <class T> void nop(T&&t) {}
|
template <class T> void nop(T&&t) {}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
@@ -111,10 +136,13 @@ int main()
|
|||||||
std::unique_ptr<Base> ptr3(new MyType);
|
std::unique_ptr<Base> ptr3(new MyType);
|
||||||
std::weak_ptr<Base> ptr4 = ptr2;
|
std::weak_ptr<Base> ptr4 = ptr2;
|
||||||
|
|
||||||
oarchive(ptr1);
|
std::shared_ptr<OurType> ptr5 = std::make_shared<OurType>(99);
|
||||||
oarchive(ptr2);
|
|
||||||
oarchive(ptr3);
|
//oarchive(ptr1);
|
||||||
oarchive(ptr4);
|
//oarchive(ptr2);
|
||||||
|
//oarchive(ptr3);
|
||||||
|
//oarchive(ptr4);
|
||||||
|
oarchive(ptr5);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -126,10 +154,13 @@ int main()
|
|||||||
std::unique_ptr<Base> ptr3;
|
std::unique_ptr<Base> ptr3;
|
||||||
std::weak_ptr<Base> ptr4;
|
std::weak_ptr<Base> ptr4;
|
||||||
|
|
||||||
iarchive(ptr1);
|
std::shared_ptr<OurType> ptr5;
|
||||||
iarchive(ptr2);
|
|
||||||
iarchive(ptr3);
|
//iarchive(ptr1);
|
||||||
iarchive(ptr4);
|
//iarchive(ptr2);
|
||||||
|
//iarchive(ptr3);
|
||||||
|
//iarchive(ptr4);
|
||||||
|
iarchive(ptr5);
|
||||||
}
|
}
|
||||||
|
|
||||||
//std::remove("rtti.txt");
|
//std::remove("rtti.txt");
|
||||||
|
|||||||
Reference in New Issue
Block a user