cereal
A C++11 library for serialization
|
Go to the documentation of this file.
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 #ifdef CEREAL_HAS_CPP17
73 #define CEREAL_BIND_TO_ARCHIVES(...) \
77 struct init_binding<__VA_ARGS__> { \
78 static inline bind_to_archives<__VA_ARGS__> const & b= \
79 ::cereal::detail::StaticObject< \
80 bind_to_archives<__VA_ARGS__> \
81 >::getInstance().bind(); \
82 CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION \
86 #define CEREAL_BIND_TO_ARCHIVES(...) \
90 struct init_binding<__VA_ARGS__> { \
91 static bind_to_archives<__VA_ARGS__> const& b; \
92 CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION \
94 bind_to_archives<__VA_ARGS__> const & init_binding<__VA_ARGS__>::b = \
95 ::cereal::detail::StaticObject< \
96 bind_to_archives<__VA_ARGS__> \
97 >::getInstance().bind(); \
129 virtual void const *
downcast(
void const *
const ptr )
const = 0;
131 virtual void *
upcast(
void *
const ptr )
const = 0;
133 virtual std::shared_ptr<void>
upcast( std::shared_ptr<void>
const & ptr )
const = 0;
142 using DerivedCasterMap = std::unordered_map<std::type_index, std::vector<PolymorphicCaster const *>>;
144 std::unordered_map<std::type_index, DerivedCasterMap>
map;
146 std::multimap<std::type_index, std::type_index> reverseMap;
149 #define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave) \
150 throw cereal::Exception("Trying to " #LoadSave " a registered polymorphic type with an unregistered polymorphic cast.\n" \
151 "Could not find a path to a base class (" + util::demangle(baseInfo.name()) + ") for type: " + ::cereal::util::demangledName<Derived>() + "\n" \
152 "Make sure you either serialize the base class at some point via cereal::base_class or cereal::virtual_base_class.\n" \
153 "Alternatively, manually register the association with CEREAL_REGISTER_POLYMORPHIC_RELATION.");
159 static std::pair<bool, std::vector<PolymorphicCaster const *>
const &>
160 lookup_if_exists( std::type_index
const & baseIndex, std::type_index
const & derivedIndex )
164 auto baseIter = baseMap.find( baseIndex );
165 if (baseIter == baseMap.end())
169 auto const & derivedMap = baseIter->second;
170 auto derivedIter = derivedMap.find( derivedIndex );
171 if (derivedIter == derivedMap.end())
174 return {
true, derivedIter->second};
182 template <
class F>
inline
183 static std::vector<PolymorphicCaster const *>
const &
lookup( std::type_index
const & baseIndex, std::type_index
const & derivedIndex, F && exceptionFunc )
187 auto baseIter = baseMap.find( baseIndex );
188 if( baseIter == baseMap.end() )
192 auto const & derivedMap = baseIter->second;
193 auto derivedIter = derivedMap.find( derivedIndex );
194 if( derivedIter == derivedMap.end() )
197 return derivedIter->second;
201 template <
class Derived>
inline
202 static const Derived *
downcast(
const void * dptr, std::type_info
const & baseInfo )
206 for(
auto const * dmap : mapping )
207 dptr = dmap->downcast( dptr );
209 return static_cast<Derived
const *
>( dptr );
215 template <
class Derived>
inline
216 static void *
upcast( Derived *
const dptr, std::type_info
const & baseInfo )
221 for(
auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
222 uptr = (*mIter)->upcast( uptr );
228 template <
class Derived>
inline
229 static std::shared_ptr<void>
upcast( std::shared_ptr<Derived>
const & dptr, std::type_info
const & baseInfo )
233 std::shared_ptr<void> uptr = dptr;
234 for(
auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
235 uptr = (*mIter)->upcast( uptr );
240 #undef UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION
243 #ifdef CEREAL_OLDER_GCC
244 #define CEREAL_EMPLACE_MAP(map, key, value) \
245 map.insert( std::make_pair(std::move(key), std::move(value)) );
246 #else // NOT CEREAL_OLDER_GCC
247 #define CEREAL_EMPLACE_MAP(map, key, value) \
248 map.emplace( key, value );
249 #endif // NOT_CEREAL_OLDER_GCC
252 template <
class Base,
class Derived>
261 const auto baseKey = std::type_index(
typeid(Base));
262 const auto derivedKey = std::type_index(
typeid(Derived));
270 auto & derivedVec = derivedMap.insert( {derivedKey, {}} ).first->second;
271 derivedVec.push_back(
this );
276 CEREAL_EMPLACE_MAP(reverseMap, derivedKey, baseKey);
289 auto checkRelation = [](std::type_index
const & parentInfo, std::type_index
const & childInfo) ->
290 std::pair<
size_t, std::vector<PolymorphicCaster const *>
const &>
295 auto const & path = result.second;
296 return {path.size(), path};
299 return {(std::numeric_limits<size_t>::max)(), {}};
302 std::stack<std::type_index> parentStack;
303 std::vector<std::type_index> dirtySet;
304 std::unordered_set<std::type_index> processedParents;
307 auto isDirty = [&](std::type_index
const & c)
309 auto const dirtySetSize = dirtySet.size();
310 for(
size_t i = 0; i < dirtySetSize; ++i )
311 if( dirtySet[i] == c )
318 parentStack.push( baseKey );
319 dirtySet.emplace_back( derivedKey );
321 while( !parentStack.empty() )
323 using Relations = std::unordered_multimap<std::type_index, std::pair<std::type_index, std::vector<PolymorphicCaster const *>>>;
324 Relations unregisteredRelations;
326 const auto parent = parentStack.top();
330 for(
auto const & childPair : baseMap[parent] )
332 const auto child = childPair.first;
333 if( isDirty( child ) && baseMap.count( child ) )
335 auto parentChildPath = checkRelation( parent, child );
339 for(
auto const & finalChildPair : baseMap[child] )
341 const auto finalChild = finalChildPair.first;
343 auto parentFinalChildPath = checkRelation( parent, finalChild );
344 auto childFinalChildPath = checkRelation( child, finalChild );
346 const size_t newLength = 1u + parentChildPath.first;
348 if( newLength < parentFinalChildPath.first )
350 std::vector<PolymorphicCaster const *> path = parentChildPath.second;
351 path.insert( path.end(), childFinalChildPath.second.begin(), childFinalChildPath.second.end() );
355 auto hintRange = unregisteredRelations.equal_range( parent );
356 auto hint = hintRange.first;
357 for( ; hint != hintRange.second; ++hint )
358 if( hint->second.first == finalChild )
361 const bool uncommittedExists = hint != unregisteredRelations.end();
362 if( uncommittedExists && (hint->second.second.size() <= newLength) )
365 auto newPath = std::pair<std::type_index, std::vector<PolymorphicCaster const *>>{finalChild, std::move(path)};
369 #ifdef CEREAL_OLDER_GCC
370 auto old = unregisteredRelations.insert( hint, std::make_pair(parent, newPath) );
371 #else // NOT CEREAL_OLDER_GCC
372 auto old = unregisteredRelations.emplace_hint( hint, parent, newPath );
373 #endif // NOT CEREAL_OLDER_GCC
376 if( uncommittedExists )
377 old->second = newPath;
384 for(
auto const & it : unregisteredRelations )
386 auto & derivedMap = baseMap.find( it.first )->second;
387 derivedMap[it.second.first] = it.second.second;
388 CEREAL_EMPLACE_MAP(reverseMap, it.second.first, it.first );
392 dirtySet.emplace_back( parent );
395 auto parentRange = reverseMap.equal_range( parent );
396 for(
auto pIter = parentRange.first; pIter != parentRange.second; ++pIter )
398 const auto pParent = pIter->second;
399 if( !processedParents.count( pParent ) )
401 parentStack.push( pParent );
402 processedParents.insert( pParent );
409 #undef CEREAL_EMPLACE_MAP
412 void const *
downcast(
void const *
const ptr )
const override
414 return dynamic_cast<Derived const*
>(
static_cast<Base const*
>( ptr ) );
418 void *
upcast(
void *
const ptr )
const override
420 return dynamic_cast<Base*
>(
static_cast<Derived*
>( ptr ) );
424 std::shared_ptr<void>
upcast( std::shared_ptr<void>
const & ptr )
const override
426 return std::dynamic_pointer_cast<Base>( std::static_pointer_cast<Derived>( ptr ) );
437 template <
class Base,
class Derived>
451 {
return bind(
typename std::is_polymorphic<Base>::type() ); }
467 template <
class Archive>
476 typedef std::function<void(
void*,
void const *, std::type_info
const &)>
Serializer;
486 std::map<std::type_index, Serializers>
map;
490 template<
class T>
struct EmptyDeleter {
void operator()(T *)
const {} };
497 template <
class Archive>
506 typedef std::function<void(
void*, std::shared_ptr<void> &, std::type_info
const &)>
SharedSerializer;
518 std::map<std::string, Serializers>
map;
538 auto lb = map.lower_bound(key);
540 if (lb != map.end() && lb->first == key)
546 [](
void * arptr, std::shared_ptr<void> & dptr, std::type_info
const & baseInfo)
548 Archive & ar = *
static_cast<Archive*
>(arptr);
549 std::shared_ptr<T> ptr;
551 ar(
CEREAL_NVP_(
"ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
553 dptr = PolymorphicCasters::template upcast<T>( ptr, baseInfo );
557 [](
void * arptr, std::unique_ptr<void, EmptyDeleter<void>> & dptr, std::type_info
const & baseInfo)
559 Archive & ar = *
static_cast<Archive*
>(arptr);
560 std::unique_ptr<T> ptr;
562 ar(
CEREAL_NVP_(
"ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
564 dptr.reset( PolymorphicCasters::template upcast<T>( ptr.release(), baseInfo ));
567 map.insert( lb, { std::move(key), std::move(serializers) } );
583 std::uint32_t
id = ar.registerPolymorphicType(name);
589 if(
id & detail::msb_32bit )
591 std::string namestring(name);
616 inline std::shared_ptr<T const>
const &
operator()()
const {
return wrappedPtr; }
619 std::shared_ptr<void> refCount;
620 std::shared_ptr<T const> wrappedPtr;
635 ar(
CEREAL_NVP_(
"ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
649 ar(
CEREAL_NVP_(
"ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
656 auto key = std::type_index(
typeid(T));
657 auto lb = map.lower_bound(key);
659 if (lb != map.end() && lb->first == key)
665 [&](
void * arptr,
void const * dptr, std::type_info
const & baseInfo)
667 Archive & ar = *
static_cast<Archive*
>(arptr);
670 auto ptr = PolymorphicCasters::template downcast<T>( dptr, baseInfo );
672 #if defined(_MSC_VER) && _MSC_VER < 1916 && !defined(__clang__)
674 #else // not _MSC_VER
675 savePolymorphicSharedPtr( ar, ptr, typename ::cereal::traits::has_shared_from_this<T>::type() );
680 [&](
void * arptr,
void const * dptr, std::type_info
const & baseInfo)
682 Archive & ar = *
static_cast<Archive*
>(arptr);
685 std::unique_ptr<T const, EmptyDeleter<T const>>
const ptr( PolymorphicCasters::template downcast<T>( dptr, baseInfo ) );
687 ar(
CEREAL_NVP_(
"ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
690 map.insert( { std::move(key), std::move(serializers) } );
709 #ifdef CEREAL_HAS_CPP17
710 struct polymorphic_binding_tag {};
712 namespace {
struct polymorphic_binding_tag {}; }
717 template <
class Archive,
class T>
732 inline static void load(std::false_type) {}
733 inline static void save(std::false_type) {}
745 template <
class Archive,
class T>
748 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
752 #else // NOT _MSC_VER
762 template <
class Archive,
class T>
766 std::is_base_of<detail::OutputArchiveBase, Archive>::value &&
770 std::is_base_of<detail::InputArchiveBase, Archive>::value &&
779 template <
class T,
class Tag = polymorphic_binding_tag>
783 void bind(std::false_type)
const
789 void bind(std::true_type)
const
797 static_assert( std::is_polymorphic<T>::value,
798 "Attempting to register non polymorphic type" );
799 bind( std::is_abstract<T>() );
805 template <
class T,
class Tag = polymorphic_binding_tag>
820 template <
class T,
typename BindingTag>
825 #endif // CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
void instantiate_polymorphic_binding(T *, int, BindingTag, adl_tag)
Base case overload for instantiation.
Definition: polymorphic_impl.hpp:821
const std::shared_ptr< T const > & operator()() const
Get the wrapped shared_ptr */.
Definition: polymorphic_impl.hpp:616
#define CEREAL_NVP_(name, value)
Convenience for creating a templated NVP.
Definition: helpers.hpp:201
Definition: helpers.hpp:269
Serializer shared_ptr
Serializer function for shared/weak pointers.
Definition: polymorphic_impl.hpp:481
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:424
virtual const void * downcast(void const *const ptr) const =0
Downcasts to the proper derived type.
Used to hide the static object used to bind T to registered archives.
Definition: polymorphic_impl.hpp:806
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:160
Support for types found in <memory>
Serializer unique_ptr
Serializer function for unique pointers.
Definition: polymorphic_impl.hpp:482
Definition: helpers.hpp:294
Holds registered mappings between base and derived types for casting.
Definition: polymorphic_impl.hpp:139
When specialized, causes the compiler to instantiate its parameter.
Definition: polymorphic_impl.hpp:738
std::map< std::type_index, Serializers > map
A map of serializers for pointers of all registered types.
Definition: polymorphic_impl.hpp:486
Support for types found in <string>
Base type for polymorphic void casting.
Definition: polymorphic_impl.hpp:119
#define CEREAL_DLL_EXPORT
Prevent link optimization from removing non-referenced static objects.
Definition: static_object.hpp:51
A static, pre-execution object.
Definition: static_object.hpp:67
static const std::vector< PolymorphicCaster 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:183
Strongly typed derivation of PolymorphicCaster.
Definition: polymorphic_impl.hpp:253
static LockGuard lock()
Attempts to lock this static object for the current scope.
Definition: static_object.hpp:110
Holds a properly typed shared_ptr to the polymorphic type.
Definition: polymorphic_impl.hpp:597
#define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave)
Error message used for unregistered polymorphic casts.
Definition: polymorphic_impl.hpp:149
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:229
Definition: polymorphic_impl.hpp:696
Struct containing the serializer functions for all pointer types.
Definition: polymorphic_impl.hpp:479
Definition: traits.hpp:1111
A structure holding a map from type_indices to output serializer functions.
Definition: polymorphic_impl.hpp:468
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:202
Binds a compile time type with a user defined string.
Definition: polymorphic_impl.hpp:460
Definition: memory.hpp:132
virtual void * upcast(void *const ptr) const =0
Upcast to proper base 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:142
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:216
PolymorphicSharedPointerWrapper(T const *dptr)
Definition: polymorphic_impl.hpp:612
void bind(std::true_type) const
Binding for abstract types.
Definition: polymorphic_impl.hpp:789
static void writeMetadata(Archive &ar)
Writes appropriate metadata to the archive for this polymorphic type.
Definition: polymorphic_impl.hpp:579
OutputBindingCreator()
Initialize the binding.
Definition: polymorphic_impl.hpp:653
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:631
Determine if T or any base class of T has inherited from std::enable_shared_from_this.
Definition: traits.hpp:1216
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:130
An empty noop deleter.
Definition: polymorphic_impl.hpp:490
Internal polymorphism static object support.
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:646
const bind_to_archives & bind() const
Binds the type T to all registered archives.
Definition: polymorphic_impl.hpp:795
Causes the static object bindings between an archive type and a serializable type T.
Definition: polymorphic_impl.hpp:718
Internal polymorphism support forward declarations.
Registers a polymorphic casting relation between a Base and Derived type.
Definition: polymorphic_impl.hpp:438
Creates a binding (map entry) between an output archive type and a polymorphic type.
Definition: polymorphic_impl.hpp:576
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:144
static const PolymorphicCaster * bind()
Performs registration (binding) between Base and Derived.
Definition: polymorphic_impl.hpp:450
void * upcast(void *const ptr) const override
Performs the proper upcast with the templated types.
Definition: polymorphic_impl.hpp:418
void bind(std::false_type) const
Binding for non abstract types.
Definition: polymorphic_impl.hpp:783
const void * downcast(void const *const ptr) const override
Performs the proper downcast with the templated types.
Definition: polymorphic_impl.hpp:412
Begins the binding process of a type to all registered archives.
Definition: polymorphic_impl.hpp:780
PolymorphicVirtualCaster()
Inserts an entry in the polymorphic casting map for this pairing.
Definition: polymorphic_impl.hpp:259
std::function< void(void *, void const *, std::type_info const &)> Serializer
A serializer function.
Definition: polymorphic_impl.hpp:476