45 #ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_ 46 #define CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_ 64 #define CEREAL_BIND_TO_ARCHIVES(...) \ 68 struct init_binding<__VA_ARGS__> { \ 69 static bind_to_archives<__VA_ARGS__> const & b; \ 70 static void unused() { (void)b; } \ 72 bind_to_archives<__VA_ARGS__> const & init_binding<__VA_ARGS__>::b = \ 73 ::cereal::detail::StaticObject< \ 74 bind_to_archives<__VA_ARGS__> \ 75 >::getInstance().bind(); \ 106 virtual void const *
downcast(
void const *
const ptr )
const = 0;
108 virtual void *
upcast(
void *
const ptr )
const = 0;
110 virtual std::shared_ptr<void>
upcast( std::shared_ptr<void>
const & ptr )
const = 0;
119 std::map<std::type_index, std::map<std::type_index, std::vector<PolymorphicCaster const*>>>
map;
121 std::multimap<std::type_index, std::type_index> reverseMap;
124 #define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave) \ 125 throw cereal::Exception("Trying to " #LoadSave " a registered polymorphic type with an unregistered polymorphic cast.\n" \ 126 "Could not find a path to a base class (" + util::demangle(baseInfo.name()) + ") for type: " + ::cereal::util::demangledName<Derived>() + "\n" \ 127 "Make sure you either serialize the base class at some point via cereal::base_class or cereal::virtual_base_class.\n" \ 128 "Alternatively, manually register the association with CEREAL_REGISTER_POLYMORPHIC_RELATION."); 133 static bool exists( std::type_index
const & baseIndex, std::type_index
const & derivedIndex )
137 auto baseIter = baseMap.find( baseIndex );
138 if (baseIter == baseMap.end())
142 auto & derivedMap = baseIter->second;
143 auto derivedIter = derivedMap.find( derivedIndex );
144 if (derivedIter == derivedMap.end())
155 template <
class F>
inline 156 static std::vector<PolymorphicCaster const *>
const &
lookup( std::type_index
const & baseIndex, std::type_index
const & derivedIndex, F && exceptionFunc )
160 auto baseIter = baseMap.find( baseIndex );
161 if( baseIter == baseMap.end() )
165 auto & derivedMap = baseIter->second;
166 auto derivedIter = derivedMap.find( derivedIndex );
167 if( derivedIter == derivedMap.end() )
170 return derivedIter->second;
174 template <
class Derived>
inline 175 static const Derived *
downcast(
const void * dptr, std::type_info
const & baseInfo )
179 for(
auto const * map : mapping )
180 dptr = map->downcast( dptr );
182 return static_cast<Derived
const *
>( dptr );
188 template <
class Derived>
inline 189 static void *
upcast( Derived *
const dptr, std::type_info
const & baseInfo )
194 for(
auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
195 uptr = (*mIter)->upcast( uptr );
201 template <
class Derived>
inline 202 static std::shared_ptr<void>
upcast( std::shared_ptr<Derived>
const & dptr, std::type_info
const & baseInfo )
206 std::shared_ptr<void> uptr = dptr;
207 for(
auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
208 uptr = (*mIter)->upcast( uptr );
213 #undef UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION 217 template <
class Base,
class Derived>
226 const auto baseKey = std::type_index(
typeid(Base));
227 const auto derivedKey = std::type_index(
typeid(Derived));
232 auto lb = baseMap.lower_bound(baseKey);
235 auto & derivedMap = baseMap.insert( lb, {baseKey, {}} )->second;
236 auto lbd = derivedMap.lower_bound(derivedKey);
237 auto & derivedVec = derivedMap.insert( lbd, { std::move(derivedKey), {}} )->second;
238 derivedVec.push_back(
this );
243 reverseMap.insert( {derivedKey, baseKey} );
256 auto checkRelation = [](std::type_index
const & parentInfo, std::type_index
const & childInfo) ->
257 std::pair<
size_t, std::vector<PolymorphicCaster const *>>
262 return {path.size(), path};
265 return {std::numeric_limits<size_t>::max(), {}};
268 std::stack<std::type_index> parentStack;
269 std::set<std::type_index> dirtySet;
270 std::set<std::type_index> processedParents;
273 parentStack.push( baseKey );
274 dirtySet.insert( derivedKey );
276 while( !parentStack.empty() )
278 using Relations = std::multimap<std::type_index, std::pair<std::type_index, std::vector<PolymorphicCaster const *>>>;
279 Relations unregisteredRelations;
281 const auto parent = parentStack.top();
285 for(
auto const & childPair : baseMap[parent] )
287 const auto child = childPair.first;
288 if( dirtySet.count( child ) && baseMap.count( child ) )
290 auto parentChildPath = checkRelation( parent, child );
294 for(
auto const & finalChildPair : baseMap[child] )
296 const auto finalChild = finalChildPair.first;
298 auto parentFinalChildPath = checkRelation( parent, finalChild );
299 auto childFinalChildPath = checkRelation( child, finalChild );
301 const size_t newLength = 1u + parentChildPath.first;
303 if( newLength < parentFinalChildPath.first )
305 std::vector<PolymorphicCaster const *> path = parentChildPath.second;
306 path.insert( path.end(), childFinalChildPath.second.begin(), childFinalChildPath.second.end() );
310 auto hintRange = unregisteredRelations.equal_range( parent );
311 auto hint = hintRange.first;
312 for( ; hint != hintRange.second; ++hint )
313 if( hint->second.first == finalChild )
316 const bool uncommittedExists = hint != unregisteredRelations.end();
317 if( uncommittedExists && (hint->second.second.size() <= newLength) )
320 auto newPath = std::pair<std::type_index, std::vector<PolymorphicCaster const *>>{finalChild, std::move(path)};
324 #ifdef CEREAL_OLDER_GCC 325 auto old = unregisteredRelations.insert( hint, std::make_pair(parent, newPath) );
326 #else // NOT CEREAL_OLDER_GCC 327 auto old = unregisteredRelations.emplace_hint( hint, parent, newPath );
328 #endif // NOT CEREAL_OLDER_GCC 331 if( uncommittedExists )
332 old->second = newPath;
339 for(
auto const & it : unregisteredRelations )
341 auto & derivedMap = baseMap.find( it.first )->second;
342 derivedMap[it.second.first] = it.second.second;
343 reverseMap.insert( {it.second.first, it.first} );
347 dirtySet.insert( parent );
350 auto parentRange = reverseMap.equal_range( parent );
351 for(
auto pIter = parentRange.first; pIter != parentRange.second; ++pIter )
353 const auto pParent = pIter->second;
354 if( !processedParents.count( pParent ) )
356 parentStack.push( pParent );
357 processedParents.insert( pParent );
365 void const *
downcast(
void const *
const ptr )
const override 367 return dynamic_cast<Derived const*
>(
static_cast<Base const*
>( ptr ) );
371 void *
upcast(
void *
const ptr )
const override 373 return dynamic_cast<Base*
>(
static_cast<Derived*
>( ptr ) );
377 std::shared_ptr<void>
upcast( std::shared_ptr<void>
const & ptr )
const override 379 return std::dynamic_pointer_cast<Base>( std::static_pointer_cast<Derived>( ptr ) );
390 template <
class Base,
class Derived>
404 {
return bind(
typename std::is_polymorphic<Base>::type() ); }
420 template <
class Archive>
429 typedef std::function<void(void*, void const *, std::type_info const &)>
Serializer;
434 Serializer shared_ptr,
439 std::map<std::type_index, Serializers>
map;
443 template<
class T>
struct EmptyDeleter {
void operator()(T *)
const {} };
450 template <
class Archive>
459 typedef std::function<void(void*, std::shared_ptr<void> &, std::type_info
const &)>
SharedSerializer;
461 typedef std::function<void(void*, std::unique_ptr<void, EmptyDeleter<void>> &, std::type_info
const &)>
UniqueSerializer;
471 std::map<std::string, Serializers>
map;
491 auto lb = map.lower_bound(key);
493 if (lb != map.end() && lb->first == key)
499 [](
void * arptr, std::shared_ptr<void> & dptr, std::type_info
const & baseInfo)
501 Archive & ar = *
static_cast<Archive*
>(arptr);
502 std::shared_ptr<T> ptr;
504 ar(
CEREAL_NVP_(
"ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
506 dptr = PolymorphicCasters::template upcast<T>( ptr, baseInfo );
510 [](
void * arptr, std::unique_ptr<void, EmptyDeleter<void>> & dptr, std::type_info
const & baseInfo)
512 Archive & ar = *
static_cast<Archive*
>(arptr);
513 std::unique_ptr<T> ptr;
515 ar(
CEREAL_NVP_(
"ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
517 dptr.reset( PolymorphicCasters::template upcast<T>( ptr.release(), baseInfo ));
520 map.insert( lb, { std::move(key), std::move(serializers) } );
536 std::uint32_t
id = ar.registerPolymorphicType(name);
542 if(
id & detail::msb_32bit )
544 std::string namestring(name);
569 inline std::shared_ptr<T const>
const &
operator()()
const {
return wrappedPtr; }
572 std::shared_ptr<void> refCount;
573 std::shared_ptr<T const> wrappedPtr;
588 ar(
CEREAL_NVP_(
"ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
602 ar(
CEREAL_NVP_(
"ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
609 auto key = std::type_index(
typeid(T));
610 auto lb = map.lower_bound(key);
612 if (lb != map.end() && lb->first == key)
618 [&](
void * arptr,
void const * dptr, std::type_info
const & baseInfo)
620 Archive & ar = *
static_cast<Archive*
>(arptr);
623 auto ptr = PolymorphicCasters::template downcast<T>( dptr, baseInfo );
627 #else // not _MSC_VER 628 savePolymorphicSharedPtr( ar, ptr, typename ::cereal::traits::has_shared_from_this<T>::type() );
633 [&](
void * arptr,
void const * dptr, std::type_info
const & baseInfo)
635 Archive & ar = *
static_cast<Archive*
>(arptr);
638 std::unique_ptr<T const, EmptyDeleter<T const>>
const ptr( PolymorphicCasters::template downcast<T>( dptr, baseInfo ) );
640 ar(
CEREAL_NVP_(
"ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
643 map.insert( { std::move(key), std::move(serializers) } );
653 namespace {
struct polymorphic_binding_tag {}; }
656 template <
class Archive,
class T>
671 inline static void load(std::false_type) {}
672 inline static void save(std::false_type) {}
684 template <
class Archive,
class T>
687 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 691 #else // NOT _MSC_VER 701 template <
class Archive,
class T>
705 std::is_base_of<detail::OutputArchiveBase, Archive>::value &&
709 std::is_base_of<detail::InputArchiveBase, Archive>::value &&
718 template <
class T,
class Tag = polymorphic_binding_tag>
722 void bind(std::false_type)
const 728 void bind(std::true_type)
const 736 static_assert( std::is_polymorphic<T>::value,
737 "Attempting to register non polymorphic type" );
738 bind( std::is_abstract<T>() );
744 template <
class T,
class Tag = polymorphic_binding_tag>
759 template <
class T,
typename BindingTag>
764 #endif // CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_ std::shared_ptr< T const > const & operator()() const
Get the wrapped shared_ptr */.
Definition: polymorphic_impl.hpp:569
void bind(std::true_type) const
Binding for abstract types.
Definition: polymorphic_impl.hpp:728
#define CEREAL_NVP_(name, value)
Convenience for creating a templated NVP.
Definition: helpers.hpp:199
void instantiate_polymorphic_binding(T *, int, BindingTag, adl_tag)
Base case overload for instantiation.
Definition: polymorphic_impl.hpp:760
Definition: helpers.hpp:255
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:189
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:432
When specialized, causes the compiler to instantiate its parameter.
Definition: polymorphic_impl.hpp:677
void bind(std::false_type) const
Binding for non abstract types.
Definition: polymorphic_impl.hpp:722
static PolymorphicCaster const * bind()
Performs registration (binding) between Base and Derived.
Definition: polymorphic_impl.hpp:403
Used to hide the static object used to bind T to registered archives.
Definition: polymorphic_impl.hpp:745
Definition: memory.hpp:133
Base type for polymorphic void casting.
Definition: polymorphic_impl.hpp:96
Holds registered mappings between base and derived types for casting.
Definition: polymorphic_impl.hpp:116
Strongly typed derivation of PolymorphicCaster.
Definition: polymorphic_impl.hpp:218
PolymorphicVirtualCaster()
Inserts an entry in the polymorphic casting map for this pairing.
Definition: polymorphic_impl.hpp:224
Serializer unique_ptr
Serializer function for unique pointers.
Definition: polymorphic_impl.hpp:434
Holds a properly typed shared_ptr to the polymorphic type.
Definition: polymorphic_impl.hpp:550
Registers a polymorphic casting relation between a Base and Derived type.
Definition: polymorphic_impl.hpp:391
static LockGuard lock()
Attempts to lock this static object for the current scope.
Definition: static_object.hpp:109
Determine if T or any base class of T has inherited from std::enable_shared_from_this.
Definition: traits.hpp:1194
PolymorphicSharedPointerWrapper(T const *dptr)
Definition: polymorphic_impl.hpp:565
Definition: access.hpp:40
Serializer shared_ptr
Serializer function for shared/weak pointers.
Definition: polymorphic_impl.hpp:434
#define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave)
Error message used for unregistered polymorphic casts.
Definition: polymorphic_impl.hpp:124
std::function< void(void *, void const *, std::type_info const &)> Serializer
A serializer function.
Definition: polymorphic_impl.hpp:429
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:584
OutputBindingCreator()
Initialize the binding.
Definition: polymorphic_impl.hpp:606
static CEREAL_DLL_EXPORT void instantiate() CEREAL_USED
Definition: polymorphic_impl.hpp:702
Definition: traits.hpp:1089
Definition: polymorphic_impl.hpp:649
Creates a binding (map entry) between an output archive type and a polymorphic type.
Definition: polymorphic_impl.hpp:529
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:133
Support for types found in <string>
Causes the static object bindings between an archive type and a serializable type T...
Definition: polymorphic_impl.hpp:657
static void writeMetadata(Archive &ar)
Writes appropriate metadata to the archive for this polymorphic type.
Definition: polymorphic_impl.hpp:532
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:130
void * upcast(void *const ptr) const override
Performs the proper upcast with the templated types.
Definition: polymorphic_impl.hpp:371
An empty noop deleter.
Definition: polymorphic_impl.hpp:443
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:599
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:119
std::map< std::type_index, Serializers > map
A map of serializers for pointers of all registered types.
Definition: polymorphic_impl.hpp:439
instantiate_function< instantiate > unused
This typedef causes the compiler to instantiate this static function.
Definition: polymorphic_impl.hpp:696
Binds a compile time type with a user defined string.
Definition: polymorphic_impl.hpp:413
Definition: helpers.hpp:230
#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:202
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:175
bind_to_archives const & bind() const
Binds the type T to all registered archives.
Definition: polymorphic_impl.hpp:734
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:156
Begins the binding process of a type to all registered archives.
Definition: polymorphic_impl.hpp:719
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:365
A structure holding a map from type_indices to output serializer functions.
Definition: polymorphic_impl.hpp:421
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.
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:377