45 #ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_ 46 #define CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_ 62 #define CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION 64 #define CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION static void unused() { (void)b; } 72 #define CEREAL_BIND_TO_ARCHIVES(...) \ 76 struct init_binding<__VA_ARGS__> { \ 77 static bind_to_archives<__VA_ARGS__> const & b; \ 78 CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION \ 80 bind_to_archives<__VA_ARGS__> const & init_binding<__VA_ARGS__>::b = \ 81 ::cereal::detail::StaticObject< \ 82 bind_to_archives<__VA_ARGS__> \ 83 >::getInstance().bind(); \ 114 virtual void const *
downcast(
void const *
const ptr )
const = 0;
116 virtual void *
upcast(
void *
const ptr )
const = 0;
118 virtual std::shared_ptr<void>
upcast( std::shared_ptr<void>
const & ptr )
const = 0;
127 using DerivedCasterMap = std::unordered_map<std::type_index, std::vector<PolymorphicCaster const *>>;
129 std::unordered_map<std::type_index, DerivedCasterMap>
map;
131 std::multimap<std::type_index, std::type_index> reverseMap;
134 #define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave) \ 135 throw cereal::Exception("Trying to " #LoadSave " a registered polymorphic type with an unregistered polymorphic cast.\n" \ 136 "Could not find a path to a base class (" + util::demangle(baseInfo.name()) + ") for type: " + ::cereal::util::demangledName<Derived>() + "\n" \ 137 "Make sure you either serialize the base class at some point via cereal::base_class or cereal::virtual_base_class.\n" \ 138 "Alternatively, manually register the association with CEREAL_REGISTER_POLYMORPHIC_RELATION."); 144 static std::pair<bool, std::vector<PolymorphicCaster const *>
const &>
145 lookup_if_exists( std::type_index
const & baseIndex, std::type_index
const & derivedIndex )
149 auto baseIter = baseMap.find( baseIndex );
150 if (baseIter == baseMap.end())
154 auto const & derivedMap = baseIter->second;
155 auto derivedIter = derivedMap.find( derivedIndex );
156 if (derivedIter == derivedMap.end())
159 return {
true, derivedIter->second};
167 template <
class F>
inline 168 static std::vector<PolymorphicCaster const *>
const &
lookup( std::type_index
const & baseIndex, std::type_index
const & derivedIndex, F && exceptionFunc )
172 auto baseIter = baseMap.find( baseIndex );
173 if( baseIter == baseMap.end() )
177 auto const & derivedMap = baseIter->second;
178 auto derivedIter = derivedMap.find( derivedIndex );
179 if( derivedIter == derivedMap.end() )
182 return derivedIter->second;
186 template <
class Derived>
inline 187 static const Derived *
downcast(
const void * dptr, std::type_info
const & baseInfo )
191 for(
auto const * dmap : mapping )
192 dptr = dmap->downcast( dptr );
194 return static_cast<Derived
const *
>( dptr );
200 template <
class Derived>
inline 201 static void *
upcast( Derived *
const dptr, std::type_info
const & baseInfo )
206 for(
auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
207 uptr = (*mIter)->upcast( uptr );
213 template <
class Derived>
inline 214 static std::shared_ptr<void>
upcast( std::shared_ptr<Derived>
const & dptr, std::type_info
const & baseInfo )
218 std::shared_ptr<void> uptr = dptr;
219 for(
auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
220 uptr = (*mIter)->upcast( uptr );
225 #undef UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION 228 #ifdef CEREAL_OLDER_GCC 229 #define CEREAL_EMPLACE_MAP(map, key, value) \ 230 map.insert( std::make_pair(std::move(key), std::move(value)) ); 231 #else // NOT CEREAL_OLDER_GCC 232 #define CEREAL_EMPLACE_MAP(map, key, value) \ 233 map.emplace( key, value ); 234 #endif // NOT_CEREAL_OLDER_GCC 237 template <
class Base,
class Derived>
246 const auto baseKey = std::type_index(
typeid(Base));
247 const auto derivedKey = std::type_index(
typeid(Derived));
255 auto & derivedVec = derivedMap.insert( {derivedKey, {}} ).first->second;
256 derivedVec.push_back(
this );
261 CEREAL_EMPLACE_MAP(reverseMap, derivedKey, baseKey);
274 auto checkRelation = [](std::type_index
const & parentInfo, std::type_index
const & childInfo) ->
275 std::pair<
size_t, std::vector<PolymorphicCaster const *>
const &>
280 auto const & path = result.second;
281 return {path.size(), path};
284 return {(std::numeric_limits<size_t>::max)(), {}};
287 std::stack<std::type_index> parentStack;
288 std::vector<std::type_index> dirtySet;
289 std::unordered_set<std::type_index> processedParents;
292 auto isDirty = [&](std::type_index
const & c)
294 auto const dirtySetSize = dirtySet.size();
295 for(
size_t i = 0; i < dirtySetSize; ++i )
296 if( dirtySet[i] == c )
303 parentStack.push( baseKey );
304 dirtySet.emplace_back( derivedKey );
306 while( !parentStack.empty() )
308 using Relations = std::unordered_multimap<std::type_index, std::pair<std::type_index, std::vector<PolymorphicCaster const *>>>;
309 Relations unregisteredRelations;
311 const auto parent = parentStack.top();
315 for(
auto const & childPair : baseMap[parent] )
317 const auto child = childPair.first;
318 if( isDirty( child ) && baseMap.count( child ) )
320 auto parentChildPath = checkRelation( parent, child );
324 for(
auto const & finalChildPair : baseMap[child] )
326 const auto finalChild = finalChildPair.first;
328 auto parentFinalChildPath = checkRelation( parent, finalChild );
329 auto childFinalChildPath = checkRelation( child, finalChild );
331 const size_t newLength = 1u + parentChildPath.first;
333 if( newLength < parentFinalChildPath.first )
335 std::vector<PolymorphicCaster const *> path = parentChildPath.second;
336 path.insert( path.end(), childFinalChildPath.second.begin(), childFinalChildPath.second.end() );
340 auto hintRange = unregisteredRelations.equal_range( parent );
341 auto hint = hintRange.first;
342 for( ; hint != hintRange.second; ++hint )
343 if( hint->second.first == finalChild )
346 const bool uncommittedExists = hint != unregisteredRelations.end();
347 if( uncommittedExists && (hint->second.second.size() <= newLength) )
350 auto newPath = std::pair<std::type_index, std::vector<PolymorphicCaster const *>>{finalChild, std::move(path)};
354 #ifdef CEREAL_OLDER_GCC 355 auto old = unregisteredRelations.insert( hint, std::make_pair(parent, newPath) );
356 #else // NOT CEREAL_OLDER_GCC 357 auto old = unregisteredRelations.emplace_hint( hint, parent, newPath );
358 #endif // NOT CEREAL_OLDER_GCC 361 if( uncommittedExists )
362 old->second = newPath;
369 for(
auto const & it : unregisteredRelations )
371 auto & derivedMap = baseMap.find( it.first )->second;
372 derivedMap[it.second.first] = it.second.second;
373 CEREAL_EMPLACE_MAP(reverseMap, it.second.first, it.first );
377 dirtySet.emplace_back( parent );
380 auto parentRange = reverseMap.equal_range( parent );
381 for(
auto pIter = parentRange.first; pIter != parentRange.second; ++pIter )
383 const auto pParent = pIter->second;
384 if( !processedParents.count( pParent ) )
386 parentStack.push( pParent );
387 processedParents.insert( pParent );
394 #undef CEREAL_EMPLACE_MAP 397 void const *
downcast(
void const *
const ptr )
const override 399 return dynamic_cast<Derived const*
>(
static_cast<Base const*
>( ptr ) );
403 void *
upcast(
void *
const ptr )
const override 405 return dynamic_cast<Base*
>(
static_cast<Derived*
>( ptr ) );
409 std::shared_ptr<void>
upcast( std::shared_ptr<void>
const & ptr )
const override 411 return std::dynamic_pointer_cast<Base>( std::static_pointer_cast<Derived>( ptr ) );
422 template <
class Base,
class Derived>
436 {
return bind(
typename std::is_polymorphic<Base>::type() ); }
452 template <
class Archive>
461 typedef std::function<void(void*, void const *, std::type_info const &)>
Serializer;
466 Serializer shared_ptr,
471 std::map<std::type_index, Serializers>
map;
475 template<
class T>
struct EmptyDeleter {
void operator()(T *)
const {} };
482 template <
class Archive>
491 typedef std::function<void(void*, std::shared_ptr<void> &, std::type_info
const &)>
SharedSerializer;
493 typedef std::function<void(void*, std::unique_ptr<void, EmptyDeleter<void>> &, std::type_info
const &)>
UniqueSerializer;
503 std::map<std::string, Serializers>
map;
523 auto lb = map.lower_bound(key);
525 if (lb != map.end() && lb->first == key)
531 [](
void * arptr, std::shared_ptr<void> & dptr, std::type_info
const & baseInfo)
533 Archive & ar = *
static_cast<Archive*
>(arptr);
534 std::shared_ptr<T> ptr;
536 ar(
CEREAL_NVP_(
"ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
538 dptr = PolymorphicCasters::template upcast<T>( ptr, baseInfo );
542 [](
void * arptr, std::unique_ptr<void, EmptyDeleter<void>> & dptr, std::type_info
const & baseInfo)
544 Archive & ar = *
static_cast<Archive*
>(arptr);
545 std::unique_ptr<T> ptr;
547 ar(
CEREAL_NVP_(
"ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
549 dptr.reset( PolymorphicCasters::template upcast<T>( ptr.release(), baseInfo ));
552 map.insert( lb, { std::move(key), std::move(serializers) } );
568 std::uint32_t
id = ar.registerPolymorphicType(name);
574 if(
id & detail::msb_32bit )
576 std::string namestring(name);
601 inline std::shared_ptr<T const>
const &
operator()()
const {
return wrappedPtr; }
604 std::shared_ptr<void> refCount;
605 std::shared_ptr<T const> wrappedPtr;
620 ar(
CEREAL_NVP_(
"ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
634 ar(
CEREAL_NVP_(
"ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
641 auto key = std::type_index(
typeid(T));
642 auto lb = map.lower_bound(key);
644 if (lb != map.end() && lb->first == key)
650 [&](
void * arptr,
void const * dptr, std::type_info
const & baseInfo)
652 Archive & ar = *
static_cast<Archive*
>(arptr);
655 auto ptr = PolymorphicCasters::template downcast<T>( dptr, baseInfo );
659 #else // not _MSC_VER 660 savePolymorphicSharedPtr( ar, ptr, typename ::cereal::traits::has_shared_from_this<T>::type() );
665 [&](
void * arptr,
void const * dptr, std::type_info
const & baseInfo)
667 Archive & ar = *
static_cast<Archive*
>(arptr);
670 std::unique_ptr<T const, EmptyDeleter<T const>>
const ptr( PolymorphicCasters::template downcast<T>( dptr, baseInfo ) );
672 ar(
CEREAL_NVP_(
"ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
675 map.insert( { std::move(key), std::move(serializers) } );
685 namespace {
struct polymorphic_binding_tag {}; }
688 template <
class Archive,
class T>
703 inline static void load(std::false_type) {}
704 inline static void save(std::false_type) {}
716 template <
class Archive,
class T>
719 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 723 #else // NOT _MSC_VER 733 template <
class Archive,
class T>
737 std::is_base_of<detail::OutputArchiveBase, Archive>::value &&
741 std::is_base_of<detail::InputArchiveBase, Archive>::value &&
750 template <
class T,
class Tag = polymorphic_binding_tag>
754 void bind(std::false_type)
const 760 void bind(std::true_type)
const 768 static_assert( std::is_polymorphic<T>::value,
769 "Attempting to register non polymorphic type" );
770 bind( std::is_abstract<T>() );
776 template <
class T,
class Tag = polymorphic_binding_tag>
791 template <
class T,
typename BindingTag>
796 #endif // CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_ std::shared_ptr< T const > const & operator()() const
Get the wrapped shared_ptr */.
Definition: polymorphic_impl.hpp:601
void bind(std::true_type) const
Binding for abstract types.
Definition: polymorphic_impl.hpp:760
#define CEREAL_NVP_(name, value)
Convenience for creating a templated NVP.
Definition: helpers.hpp:201
std::unordered_map< std::type_index, DerivedCasterMap > map
Maps from base type index to a map from derived type index to caster.
Definition: polymorphic_impl.hpp:129
void instantiate_polymorphic_binding(T *, int, BindingTag, adl_tag)
Base case overload for instantiation.
Definition: polymorphic_impl.hpp:792
Definition: helpers.hpp:294
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:201
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:464
When specialized, causes the compiler to instantiate its parameter.
Definition: polymorphic_impl.hpp:709
void bind(std::false_type) const
Binding for non abstract types.
Definition: polymorphic_impl.hpp:754
static PolymorphicCaster const * bind()
Performs registration (binding) between Base and Derived.
Definition: polymorphic_impl.hpp:435
Used to hide the static object used to bind T to registered archives.
Definition: polymorphic_impl.hpp:777
Definition: memory.hpp:132
Base type for polymorphic void casting.
Definition: polymorphic_impl.hpp:104
Holds registered mappings between base and derived types for casting.
Definition: polymorphic_impl.hpp:124
Strongly typed derivation of PolymorphicCaster.
Definition: polymorphic_impl.hpp:238
PolymorphicVirtualCaster()
Inserts an entry in the polymorphic casting map for this pairing.
Definition: polymorphic_impl.hpp:244
Serializer unique_ptr
Serializer function for unique pointers.
Definition: polymorphic_impl.hpp:466
Holds a properly typed shared_ptr to the polymorphic type.
Definition: polymorphic_impl.hpp:582
Registers a polymorphic casting relation between a Base and Derived type.
Definition: polymorphic_impl.hpp:423
static LockGuard lock()
Attempts to lock this static object for the current scope.
Definition: static_object.hpp:109
static std::pair< bool, std::vector< PolymorphicCaster const * > const & > lookup_if_exists(std::type_index const &baseIndex, std::type_index const &derivedIndex)
Checks if the mapping object that can perform the upcast or downcast exists, and returns it if so...
Definition: polymorphic_impl.hpp:145
Determine if T or any base class of T has inherited from std::enable_shared_from_this.
Definition: traits.hpp:1216
PolymorphicSharedPointerWrapper(T const *dptr)
Definition: polymorphic_impl.hpp:597
Definition: access.hpp:41
Serializer shared_ptr
Serializer function for shared/weak pointers.
Definition: polymorphic_impl.hpp:466
#define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave)
Error message used for unregistered polymorphic casts.
Definition: polymorphic_impl.hpp:134
std::function< void(void *, void const *, std::type_info const &)> Serializer
A serializer function.
Definition: polymorphic_impl.hpp:461
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:616
OutputBindingCreator()
Initialize the binding.
Definition: polymorphic_impl.hpp:638
static CEREAL_DLL_EXPORT void instantiate() CEREAL_USED
Definition: polymorphic_impl.hpp:734
Definition: traits.hpp:1111
Definition: polymorphic_impl.hpp:681
Creates a binding (map entry) between an output archive type and a polymorphic type.
Definition: polymorphic_impl.hpp:561
Support for types found in <string>
Causes the static object bindings between an archive type and a serializable type T...
Definition: polymorphic_impl.hpp:689
static void writeMetadata(Archive &ar)
Writes appropriate metadata to the archive for this polymorphic type.
Definition: polymorphic_impl.hpp:564
#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:403
An empty noop deleter.
Definition: polymorphic_impl.hpp:475
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:631
Internal polymorphism support forward declarations.
std::map< std::type_index, Serializers > map
A map of serializers for pointers of all registered types.
Definition: polymorphic_impl.hpp:471
instantiate_function< instantiate > unused
This typedef causes the compiler to instantiate this static function.
Definition: polymorphic_impl.hpp:728
Binds a compile time type with a user defined string.
Definition: polymorphic_impl.hpp:445
Definition: helpers.hpp:269
#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:214
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:187
bind_to_archives const & bind() const
Binds the type T to all registered archives.
Definition: polymorphic_impl.hpp:766
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:168
Begins the binding process of a type to all registered archives.
Definition: polymorphic_impl.hpp:751
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:397
A structure holding a map from type_indices to output serializer functions.
Definition: polymorphic_impl.hpp:453
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::unordered_map< std::type_index, std::vector< PolymorphicCaster const * > > DerivedCasterMap
Maps from a derived type index to a set of chainable casters.
Definition: polymorphic_impl.hpp:127
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:409