45 #ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_ 46 #define CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_ 61 #define CEREAL_BIND_TO_ARCHIVES(...) \ 65 struct init_binding<__VA_ARGS__> { \ 66 static bind_to_archives<__VA_ARGS__> const & b; \ 67 static void unused() { (void)b; } \ 69 bind_to_archives<__VA_ARGS__> const & init_binding<__VA_ARGS__>::b = \ 70 ::cereal::detail::StaticObject< \ 71 bind_to_archives<__VA_ARGS__> \ 72 >::getInstance().bind(); \ 103 virtual void const *
downcast(
void const *
const ptr )
const = 0;
105 virtual void *
upcast(
void *
const ptr )
const = 0;
107 virtual std::shared_ptr<void>
upcast( std::shared_ptr<void>
const & ptr )
const = 0;
116 std::map<std::type_index, std::map<std::type_index, std::vector<PolymorphicCaster const*>>>
map;
119 #define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave) \ 120 throw cereal::Exception("Trying to " #LoadSave " a registered polymorphic type with an unregistered polymorphic cast.\n" \ 121 "Could not find a path to a base class (" + util::demangle(baseInfo.name()) + ") for type: " + ::cereal::util::demangledName<Derived>() + "\n" \ 122 "Make sure you either serialize the base class at some point via cereal::base_class or cereal::virtual_base_class.\n" \ 123 "Alternatively, manually register the association with CEREAL_REGISTER_POLYMORPHIC_RELATION."); 128 static bool exists( std::type_index
const & baseIndex, std::type_index
const & derivedIndex )
132 auto baseIter = baseMap.find( baseIndex );
133 if (baseIter == baseMap.end())
137 auto & derivedMap = baseIter->second;
138 auto derivedIter = derivedMap.find( derivedIndex );
139 if (derivedIter == derivedMap.end())
150 template <
class F>
inline 151 static std::vector<PolymorphicCaster const *>
const &
lookup( std::type_index
const & baseIndex, std::type_index
const & derivedIndex, F && exceptionFunc )
155 auto baseIter = baseMap.find( baseIndex );
156 if( baseIter == baseMap.end() )
160 auto & derivedMap = baseIter->second;
161 auto derivedIter = derivedMap.find( derivedIndex );
162 if( derivedIter == derivedMap.end() )
165 return derivedIter->second;
169 template <
class Derived>
inline 170 static const Derived *
downcast(
const void * dptr, std::type_info
const & baseInfo )
174 for(
auto const * map : mapping )
175 dptr = map->downcast( dptr );
177 return static_cast<Derived
const *
>( dptr );
183 template <
class Derived>
inline 184 static void *
upcast( Derived *
const dptr, std::type_info
const & baseInfo )
189 for(
auto const * map : mapping )
190 uptr = map->upcast( uptr );
196 template <
class Derived>
inline 197 static std::shared_ptr<void>
upcast( std::shared_ptr<Derived>
const & dptr, std::type_info
const & baseInfo )
201 std::shared_ptr<void> uptr = dptr;
202 for(
auto const * map : mapping )
203 uptr = map->upcast( uptr );
208 #undef UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION 212 template <
class Base,
class Derived>
223 auto baseKey = std::type_index(
typeid(Base));
224 auto lb = baseMap.lower_bound(baseKey);
227 auto & derivedMap = baseMap.insert( lb, {baseKey, {}} )->second;
228 auto derivedKey = std::type_index(
typeid(Derived));
229 auto lbd = derivedMap.lower_bound(derivedKey);
230 auto & derivedVec = derivedMap.insert( lbd, { std::move(derivedKey), {}} )->second;
231 derivedVec.push_back(
this );
235 std::map<std::type_index, std::pair<std::type_index, std::vector<PolymorphicCaster const *>>> unregisteredRelations;
237 auto checkRelation = [](std::type_index
const & baseInfo, std::type_index
const & derivedInfo)
241 std::vector<PolymorphicCaster const *>{} );
244 for(
auto baseIt : baseMap )
245 for(
auto derivedIt : baseIt.second )
247 for(
auto otherBaseIt : baseMap )
249 if( baseIt.first == otherBaseIt.first )
254 auto otherBaseItToDerived = checkRelation( otherBaseIt.first, derivedIt.first );
255 auto baseToDerived = checkRelation( baseIt.first, derivedIt.first );
256 auto otherBaseToBase = checkRelation( otherBaseIt.first, baseIt.first );
258 const size_t newLength = otherBaseToBase.second.size() + baseToDerived.second.size();
259 const bool isShorterOrFirstPath = !otherBaseItToDerived.first || (newLength < derivedIt.second.size());
261 if( isShorterOrFirstPath &&
262 baseToDerived.first &&
263 otherBaseToBase.first )
265 std::vector<PolymorphicCaster const *> path = otherBaseToBase.second;
266 path.insert( path.end(), baseToDerived.second.begin(), baseToDerived.second.end() );
268 #ifdef CEREAL_OLDER_GCC 269 unregisteredRelations.insert( std::make_pair(otherBaseIt.first,
270 std::pair<std::type_index, std::vector<PolymorphicCaster const *>>{derivedIt.first, std::move(path)}) );
271 #else // NOT CEREAL_OLDER_GCC 272 unregisteredRelations.emplace( otherBaseIt.first,
273 std::pair<std::type_index, std::vector<PolymorphicCaster const *>>{derivedIt.first, std::move(path)} );
274 #endif // NOT CEREAL_OLDER_GCC 281 for(
auto it : unregisteredRelations )
283 auto & derivedMap = baseMap.find( it.first )->second;
284 derivedMap[it.second.first] = it.second.second;
289 void const *
downcast(
void const *
const ptr )
const override 291 return dynamic_cast<Derived const*
>(
static_cast<Base const*
>( ptr ) );
295 void *
upcast(
void *
const ptr )
const override 297 return dynamic_cast<Base*
>(
static_cast<Derived*
>( ptr ) );
301 std::shared_ptr<void>
upcast( std::shared_ptr<void>
const & ptr )
const override 303 return std::dynamic_pointer_cast<Base>( std::static_pointer_cast<Derived>( ptr ) );
314 template <
class Base,
class Derived>
328 {
return bind(
typename std::is_polymorphic<Base>::type() ); }
344 template <
class Archive>
353 typedef std::function<void(void*, void const *, std::type_info const &)>
Serializer;
358 Serializer shared_ptr,
363 std::map<std::type_index, Serializers>
map;
367 template<
class T>
struct EmptyDeleter {
void operator()(T *)
const {} };
374 template <
class Archive>
383 typedef std::function<void(void*, std::shared_ptr<void> &, std::type_info
const &)>
SharedSerializer;
385 typedef std::function<void(void*, std::unique_ptr<void, EmptyDeleter<void>> &, std::type_info
const &)>
UniqueSerializer;
395 std::map<std::string, Serializers>
map;
415 auto lb = map.lower_bound(key);
417 if (lb != map.end() && lb->first == key)
423 [](
void * arptr, std::shared_ptr<void> & dptr, std::type_info
const & baseInfo)
425 Archive & ar = *
static_cast<Archive*
>(arptr);
426 std::shared_ptr<T> ptr;
428 ar(
CEREAL_NVP_(
"ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
430 dptr = PolymorphicCasters::template upcast<T>( ptr, baseInfo );
434 [](
void * arptr, std::unique_ptr<void, EmptyDeleter<void>> & dptr, std::type_info
const & baseInfo)
436 Archive & ar = *
static_cast<Archive*
>(arptr);
437 std::unique_ptr<T> ptr;
439 ar(
CEREAL_NVP_(
"ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
441 dptr.reset( PolymorphicCasters::template upcast<T>( ptr.release(), baseInfo ));
444 map.insert( lb, { std::move(key), std::move(serializers) } );
460 std::uint32_t
id = ar.registerPolymorphicType(name);
466 if(
id & detail::msb_32bit )
468 std::string namestring(name);
493 inline std::shared_ptr<T const>
const &
operator()()
const {
return wrappedPtr; }
496 std::shared_ptr<void> refCount;
497 std::shared_ptr<T const> wrappedPtr;
512 ar(
CEREAL_NVP_(
"ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
526 ar(
CEREAL_NVP_(
"ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
533 auto key = std::type_index(
typeid(T));
534 auto lb = map.lower_bound(key);
536 if (lb != map.end() && lb->first == key)
542 [&](
void * arptr,
void const * dptr, std::type_info
const & baseInfo)
544 Archive & ar = *
static_cast<Archive*
>(arptr);
547 auto ptr = PolymorphicCasters::template downcast<T>( dptr, baseInfo );
551 #else // not _MSC_VER 552 savePolymorphicSharedPtr( ar, ptr, typename ::cereal::traits::has_shared_from_this<T>::type() );
557 [&](
void * arptr,
void const * dptr, std::type_info
const & baseInfo)
559 Archive & ar = *
static_cast<Archive*
>(arptr);
562 std::unique_ptr<T const, EmptyDeleter<T const>>
const ptr( PolymorphicCasters::template downcast<T>( dptr, baseInfo ) );
564 ar(
CEREAL_NVP_(
"ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
567 map.insert( { std::move(key), std::move(serializers) } );
577 namespace {
struct polymorphic_binding_tag {}; }
580 template <
class Archive,
class T>
595 inline static void load(std::false_type) {}
596 inline static void save(std::false_type) {}
608 template <
class Archive,
class T>
611 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 615 #else // NOT _MSC_VER 625 template <
class Archive,
class T>
629 std::is_base_of<detail::OutputArchiveBase, Archive>::value &&
633 std::is_base_of<detail::InputArchiveBase, Archive>::value &&
642 template <
class T,
class Tag = polymorphic_binding_tag>
646 void bind(std::false_type)
const 652 void bind(std::true_type)
const 660 static_assert( std::is_polymorphic<T>::value,
661 "Attempting to register non polymorphic type" );
662 bind( std::is_abstract<T>() );
668 template <
class T,
class Tag = polymorphic_binding_tag>
683 template <
class T,
typename BindingTag>
688 #endif // CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_ #define CEREAL_NVP_(name, value)
Convenience for creating a templated NVP.
Definition: helpers.hpp:197
void instantiate_polymorphic_binding(T *, int, BindingTag, adl_tag)
Base case overload for instantiation.
Definition: polymorphic_impl.hpp:684
Definition: helpers.hpp:253
static void * upcast(Derived *const dptr, std::type_info const &baseInfo)
Performs an upcast to the registered base type using the given a derived type.
Definition: polymorphic_impl.hpp:184
virtual void * upcast(void *const ptr) const =0
Upcast to proper base type.
Struct containing the serializer functions for all pointer types.
Definition: polymorphic_impl.hpp:356
When specialized, causes the compiler to instantiate its parameter.
Definition: polymorphic_impl.hpp:601
static PolymorphicCaster const * bind()
Performs registration (binding) between Base and Derived.
Definition: polymorphic_impl.hpp:327
Used to hide the static object used to bind T to registered archives.
Definition: polymorphic_impl.hpp:669
Definition: memory.hpp:133
Base type for polymorphic void casting.
Definition: polymorphic_impl.hpp:93
Holds registered mappings between base and derived types for casting.
Definition: polymorphic_impl.hpp:113
Strongly typed derivation of PolymorphicCaster.
Definition: polymorphic_impl.hpp:213
PolymorphicVirtualCaster()
Inserts an entry in the polymorphic casting map for this pairing.
Definition: polymorphic_impl.hpp:219
Serializer unique_ptr
Serializer function for unique pointers.
Definition: polymorphic_impl.hpp:358
Holds a properly typed shared_ptr to the polymorphic type.
Definition: polymorphic_impl.hpp:474
std::shared_ptr< T const > const & operator()() const
Get the wrapped shared_ptr */.
Definition: polymorphic_impl.hpp:493
Registers a polymorphic casting relation between a Base and Derived type.
Definition: polymorphic_impl.hpp:315
static LockGuard lock()
Attempts to lock this static object for the current scope.
Definition: static_object.hpp:109
bind_to_archives const & bind() const
Binds the type T to all registered archives.
Definition: polymorphic_impl.hpp:658
Determine if T or any base class of T has inherited from std::enable_shared_from_this.
Definition: traits.hpp:1194
void bind(std::false_type) const
Binding for non abstract types.
Definition: polymorphic_impl.hpp:646
PolymorphicSharedPointerWrapper(T const *dptr)
Definition: polymorphic_impl.hpp:489
Definition: access.hpp:40
Serializer shared_ptr
Serializer function for shared/weak pointers.
Definition: polymorphic_impl.hpp:358
#define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave)
Error message used for unregistered polymorphic casts.
Definition: polymorphic_impl.hpp:119
std::function< void(void *, void const *, std::type_info const &)> Serializer
A serializer function.
Definition: polymorphic_impl.hpp:353
static void savePolymorphicSharedPtr(Archive &ar, T const *dptr, std::true_type)
Does the actual work of saving a polymorphic shared_ptr.
Definition: polymorphic_impl.hpp:508
OutputBindingCreator()
Initialize the binding.
Definition: polymorphic_impl.hpp:530
static CEREAL_DLL_EXPORT void instantiate() CEREAL_USED
Definition: polymorphic_impl.hpp:626
Definition: traits.hpp:1089
Definition: polymorphic_impl.hpp:573
Creates a binding (map entry) between an output archive type and a polymorphic type.
Definition: polymorphic_impl.hpp:453
static bool exists(std::type_index const &baseIndex, std::type_index const &derivedIndex)
Checks if the mapping object that can perform the upcast or downcast.
Definition: polymorphic_impl.hpp:128
Support for types found in <string>
Causes the static object bindings between an archive type and a serializable type T...
Definition: polymorphic_impl.hpp:581
static void writeMetadata(Archive &ar)
Writes appropriate metadata to the archive for this polymorphic type.
Definition: polymorphic_impl.hpp:456
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:116
void * upcast(void *const ptr) const override
Performs the proper upcast with the templated types.
Definition: polymorphic_impl.hpp:295
An empty noop deleter.
Definition: polymorphic_impl.hpp:367
static void savePolymorphicSharedPtr(Archive &ar, T const *dptr, std::false_type)
Does the actual work of saving a polymorphic shared_ptr.
Definition: polymorphic_impl.hpp:523
Internal polymorphism support forward declarations.
std::map< std::type_index, std::map< std::type_index, std::vector< PolymorphicCaster const * > > > map
Maps from base type index to a map from derived type index to caster.
Definition: polymorphic_impl.hpp:116
std::map< std::type_index, Serializers > map
A map of serializers for pointers of all registered types.
Definition: polymorphic_impl.hpp:363
instantiate_function< instantiate > unused
This typedef causes the compiler to instantiate this static function.
Definition: polymorphic_impl.hpp:620
Binds a compile time type with a user defined string.
Definition: polymorphic_impl.hpp:337
Definition: helpers.hpp:228
#define CEREAL_DLL_EXPORT
Prevent link optimization from removing non-referenced static objects.
Definition: static_object.hpp:51
static std::shared_ptr< void > upcast(std::shared_ptr< Derived > const &dptr, std::type_info const &baseInfo)
Upcasts for shared pointers.
Definition: polymorphic_impl.hpp:197
static const Derived * downcast(const void *dptr, std::type_info const &baseInfo)
Performs a downcast to the derived type using a registered mapping.
Definition: polymorphic_impl.hpp:170
static std::vector< PolymorphicCaster const * > const & lookup(std::type_index const &baseIndex, std::type_index const &derivedIndex, F &&exceptionFunc)
Gets the mapping object that can perform the upcast or downcast.
Definition: polymorphic_impl.hpp:151
Begins the binding process of a type to all registered archives.
Definition: polymorphic_impl.hpp:643
A static, pre-execution object.
Definition: static_object.hpp:67
void const * downcast(void const *const ptr) const override
Performs the proper downcast with the templated types.
Definition: polymorphic_impl.hpp:289
A structure holding a map from type_indices to output serializer functions.
Definition: polymorphic_impl.hpp:345
Support for types found in <memory>
Internal polymorphism static object support.
virtual void const * downcast(void const *const ptr) const =0
Downcasts to the proper derived type.
void bind(std::true_type) const
Binding for abstract types.
Definition: polymorphic_impl.hpp:652
std::shared_ptr< void > upcast(std::shared_ptr< void > const &ptr) const override
Performs the proper upcast with the templated types (shared_ptr version)
Definition: polymorphic_impl.hpp:301