cereal
A C++11 library for serialization
polymorphic_impl.hpp
Go to the documentation of this file.
1
4/*
5 Copyright (c) 2014, Randolph Voorhies, Shane Grant
6 All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 * Neither the name of the copyright holder nor the
16 names of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29*/
30
31/* This code is heavily inspired by the boost serialization implementation by the following authors
32
33 (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
34 Use, modification and distribution is subject to the Boost Software
35 License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)
36
37 See http://www.boost.org for updates, documentation, and revision history.
38
39 (C) Copyright 2006 David Abrahams - http://www.boost.org.
40
41 See /boost/serialization/export.hpp, /boost/archive/detail/register_archive.hpp,
42 and /boost/serialization/void_cast.hpp for their implementation. Additional details
43 found in other files split across serialization and archive.
44*/
45#ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
46#define CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
47
52#include <functional>
53#include <typeindex>
54#include <map>
55#include <limits>
56#include <set>
57#include <stack>
58
60#if defined(__GNUC__)
61 // GCC / clang don't want the function
62 #define CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION
63#else
64 #define CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION static void unused() { (void)b; }
65#endif
66
68
72#ifdef CEREAL_HAS_CPP17
73#define CEREAL_BIND_TO_ARCHIVES(...) \
74 namespace cereal { \
75 namespace detail { \
76 template<> \
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 \
83 }; \
84 }} /* end namespaces */
85#else
86#define CEREAL_BIND_TO_ARCHIVES(...) \
87 namespace cereal { \
88 namespace detail { \
89 template<> \
90 struct init_binding<__VA_ARGS__> { \
91 static bind_to_archives<__VA_ARGS__> const& b; \
92 CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION \
93 }; \
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(); \
98 }} /* end namespaces */
99#endif
100
101namespace cereal
102{
103 /* Polymorphic casting support */
104 namespace detail
105 {
107
120 {
121 PolymorphicCaster() = default;
122 PolymorphicCaster( const PolymorphicCaster & ) = default;
123 PolymorphicCaster & operator=( const PolymorphicCaster & ) = default;
125 PolymorphicCaster & operator=( PolymorphicCaster && ) CEREAL_NOEXCEPT { return *this; }
126 virtual ~PolymorphicCaster() CEREAL_NOEXCEPT = default;
127
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;
134 };
135
137
140 {
142 using DerivedCasterMap = std::unordered_map<std::type_index, std::vector<PolymorphicCaster const *>>;
144 std::unordered_map<std::type_index, DerivedCasterMap> map;
145
146 std::multimap<std::type_index, std::type_index> reverseMap;
147
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.");
154
156
159 static std::pair<bool, std::vector<PolymorphicCaster const *> const &>
160 lookup_if_exists( std::type_index const & baseIndex, std::type_index const & derivedIndex )
161 {
162 // First phase of lookup - match base type index
163 auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
164 auto baseIter = baseMap.find( baseIndex );
165 if (baseIter == baseMap.end())
166 return {false, {}};
167
168 // Second phase - find a match from base to derived
169 auto const & derivedMap = baseIter->second;
170 auto derivedIter = derivedMap.find( derivedIndex );
171 if (derivedIter == derivedMap.end())
172 return {false, {}};
173
174 return {true, derivedIter->second};
175 }
176
178
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 )
184 {
185 // First phase of lookup - match base type index
186 auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
187 auto baseIter = baseMap.find( baseIndex );
188 if( baseIter == baseMap.end() )
189 exceptionFunc();
190
191 // Second phase - find a match from base to derived
192 auto const & derivedMap = baseIter->second;
193 auto derivedIter = derivedMap.find( derivedIndex );
194 if( derivedIter == derivedMap.end() )
195 exceptionFunc();
196
197 return derivedIter->second;
198 }
199
201 template <class Derived> inline
202 static const Derived * downcast( const void * dptr, std::type_info const & baseInfo )
203 {
204 auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(save) } );
205
206 for( auto const * dmap : mapping )
207 dptr = dmap->downcast( dptr );
208
209 return static_cast<Derived const *>( dptr );
210 }
211
213
215 template <class Derived> inline
216 static void * upcast( Derived * const dptr, std::type_info const & baseInfo )
217 {
218 auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } );
219
220 void * uptr = dptr;
221 for( auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
222 uptr = (*mIter)->upcast( uptr );
223
224 return uptr;
225 }
226
228 template <class Derived> inline
229 static std::shared_ptr<void> upcast( std::shared_ptr<Derived> const & dptr, std::type_info const & baseInfo )
230 {
231 auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } );
232
233 std::shared_ptr<void> uptr = dptr;
234 for( auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
235 uptr = (*mIter)->upcast( uptr );
236
237 return uptr;
238 }
239
240 #undef UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION
241 };
242
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
250
252 template <class Base, class Derived>
254 {
256
260 {
261 const auto baseKey = std::type_index(typeid(Base));
262 const auto derivedKey = std::type_index(typeid(Derived));
263
264 // First insert the relation Base->Derived
265 const auto lock = StaticObject<PolymorphicCasters>::lock();
267
268 {
269 auto & derivedMap = baseMap.insert( {baseKey, PolymorphicCasters::DerivedCasterMap{}} ).first->second;
270 auto & derivedVec = derivedMap.insert( {derivedKey, {}} ).first->second;
271 derivedVec.push_back( this );
272 }
273
274 // Insert reverse relation Derived->Base
275 auto & reverseMap = StaticObject<PolymorphicCasters>::getInstance().reverseMap;
276 CEREAL_EMPLACE_MAP(reverseMap, derivedKey, baseKey);
277
278 // Find all chainable unregistered relations
279 /* The strategy here is to process only the nodes in the class hierarchy graph that have been
280 affected by the new insertion. The aglorithm iteratively processes a node an ensures that it
281 is updated with all new shortest length paths. It then rocesses the parents of the active node,
282 with the knowledge that all children have already been processed.
283
284 Note that for the following, we'll use the nomenclature of parent and child to not confuse with
285 the inserted base derived relationship */
286 {
287 // Checks whether there is a path from parent->child and returns a <dist, path> pair
288 // dist is set to MAX if the path does not exist
289 auto checkRelation = [](std::type_index const & parentInfo, std::type_index const & childInfo) ->
290 std::pair<size_t, std::vector<PolymorphicCaster const *> const &>
291 {
292 auto result = PolymorphicCasters::lookup_if_exists( parentInfo, childInfo );
293 if( result.first )
294 {
295 auto const & path = result.second;
296 return {path.size(), path};
297 }
298 else
299 return {(std::numeric_limits<size_t>::max)(), {}};
300 };
301
302 std::stack<std::type_index> parentStack; // Holds the parent nodes to be processed
303 std::vector<std::type_index> dirtySet; // Marks child nodes that have been changed
304 std::unordered_set<std::type_index> processedParents; // Marks parent nodes that have been processed
305
306 // Checks if a child has been marked dirty
307 auto isDirty = [&](std::type_index const & c)
308 {
309 auto const dirtySetSize = dirtySet.size();
310 for( size_t i = 0; i < dirtySetSize; ++i )
311 if( dirtySet[i] == c )
312 return true;
313
314 return false;
315 };
316
317 // Begin processing the base key and mark derived as dirty
318 parentStack.push( baseKey );
319 dirtySet.emplace_back( derivedKey );
320
321 while( !parentStack.empty() )
322 {
323 using Relations = std::unordered_multimap<std::type_index, std::pair<std::type_index, std::vector<PolymorphicCaster const *>>>;
324 Relations unregisteredRelations; // Defer insertions until after main loop to prevent iterator invalidation
325
326 const auto parent = parentStack.top();
327 parentStack.pop();
328
329 // Update paths to all children marked dirty
330 for( auto const & childPair : baseMap[parent] )
331 {
332 const auto child = childPair.first;
333 if( isDirty( child ) && baseMap.count( child ) )
334 {
335 auto parentChildPath = checkRelation( parent, child );
336
337 // Search all paths from the child to its own children (finalChild),
338 // looking for a shorter parth from parent to finalChild
339 for( auto const & finalChildPair : baseMap[child] )
340 {
341 const auto finalChild = finalChildPair.first;
342
343 auto parentFinalChildPath = checkRelation( parent, finalChild );
344 auto childFinalChildPath = checkRelation( child, finalChild );
345
346 const size_t newLength = 1u + parentChildPath.first;
347
348 if( newLength < parentFinalChildPath.first )
349 {
350 std::vector<PolymorphicCaster const *> path = parentChildPath.second;
351 path.insert( path.end(), childFinalChildPath.second.begin(), childFinalChildPath.second.end() );
352
353 // Check to see if we have a previous uncommitted path in unregisteredRelations
354 // that is shorter. If so, ignore this path
355 auto hintRange = unregisteredRelations.equal_range( parent );
356 auto hint = hintRange.first;
357 for( ; hint != hintRange.second; ++hint )
358 if( hint->second.first == finalChild )
359 break;
360
361 const bool uncommittedExists = hint != unregisteredRelations.end();
362 if( uncommittedExists && (hint->second.second.size() <= newLength) )
363 continue;
364
365 auto newPath = std::pair<std::type_index, std::vector<PolymorphicCaster const *>>{finalChild, std::move(path)};
366
367 // Insert the new path if it doesn't exist, otherwise this will just lookup where to do the
368 // replacement
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
374
375 // If there was an uncommitted path, we need to perform a replacement
376 if( uncommittedExists )
377 old->second = newPath;
378 }
379 } // end loop over child's children
380 } // end if dirty and child has children
381 } // end loop over children
382
383 // Insert chained relations
384 for( auto const & it : unregisteredRelations )
385 {
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 );
389 }
390
391 // Mark current parent as modified
392 dirtySet.emplace_back( parent );
393
394 // Insert all parents of the current parent node that haven't yet been processed
395 auto parentRange = reverseMap.equal_range( parent );
396 for( auto pIter = parentRange.first; pIter != parentRange.second; ++pIter )
397 {
398 const auto pParent = pIter->second;
399 if( !processedParents.count( pParent ) )
400 {
401 parentStack.push( pParent );
402 processedParents.insert( pParent );
403 }
404 }
405 } // end loop over parent stack
406 } // end chainable relations
407 } // end PolymorphicVirtualCaster()
408
409 #undef CEREAL_EMPLACE_MAP
410
412 void const * downcast( void const * const ptr ) const override
413 {
414 return dynamic_cast<Derived const*>( static_cast<Base const*>( ptr ) );
415 }
416
418 void * upcast( void * const ptr ) const override
419 {
420 return dynamic_cast<Base*>( static_cast<Derived*>( ptr ) );
421 }
422
424 std::shared_ptr<void> upcast( std::shared_ptr<void> const & ptr ) const override
425 {
426 return std::dynamic_pointer_cast<Base>( std::static_pointer_cast<Derived>( ptr ) );
427 }
428 };
429
431
437 template <class Base, class Derived>
439 {
440 static PolymorphicCaster const * bind( std::true_type /* is_polymorphic<Base> */)
441 {
443 }
444
445 static PolymorphicCaster const * bind( std::false_type /* is_polymorphic<Base> */ )
446 { return nullptr; }
447
449
450 static PolymorphicCaster const * bind()
451 { return bind( typename std::is_polymorphic<Base>::type() ); }
452 };
453 }
454
455 /* General polymorphism support */
456 namespace detail
457 {
459 template <class T>
460 struct binding_name {};
461
463
467 template <class Archive>
469 {
471
476 typedef std::function<void(void*, void const *, std::type_info const &)> Serializer;
477
480 {
483 };
484
486 std::map<std::type_index, Serializers> map;
487 };
488
490 template<class T> struct EmptyDeleter { void operator()(T *) const {} };
491
493
497 template <class Archive>
499 {
501
506 typedef std::function<void(void*, std::shared_ptr<void> &, std::type_info const &)> SharedSerializer;
508 typedef std::function<void(void*, std::unique_ptr<void, EmptyDeleter<void>> &, std::type_info const &)> UniqueSerializer;
509
512 {
515 };
516
518 std::map<std::string, Serializers> map;
519 };
520
521 // forward decls for archives from cereal.hpp
522 class InputArchiveBase;
523 class OutputArchiveBase;
524
526
530 template <class Archive, class T> struct InputBindingCreator
531 {
534 {
535 auto & map = StaticObject<InputBindingMap<Archive>>::getInstance().map;
536 auto lock = StaticObject<InputBindingMap<Archive>>::lock();
537 auto key = std::string(binding_name<T>::name());
538 auto lb = map.lower_bound(key);
539
540 if (lb != map.end() && lb->first == key)
541 return;
542
543 typename InputBindingMap<Archive>::Serializers serializers;
544
545 serializers.shared_ptr =
546 [](void * arptr, std::shared_ptr<void> & dptr, std::type_info const & baseInfo)
547 {
548 Archive & ar = *static_cast<Archive*>(arptr);
549 std::shared_ptr<T> ptr;
550
551 ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
552
553 dptr = PolymorphicCasters::template upcast<T>( ptr, baseInfo );
554 };
555
556 serializers.unique_ptr =
557 [](void * arptr, std::unique_ptr<void, EmptyDeleter<void>> & dptr, std::type_info const & baseInfo)
558 {
559 Archive & ar = *static_cast<Archive*>(arptr);
560 std::unique_ptr<T> ptr;
561
562 ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
563
564 dptr.reset( PolymorphicCasters::template upcast<T>( ptr.release(), baseInfo ));
565 };
566
567 map.insert( lb, { std::move(key), std::move(serializers) } );
568 }
569 };
570
572
576 template <class Archive, class T> struct OutputBindingCreator
577 {
579 static void writeMetadata(Archive & ar)
580 {
581 // Register the polymorphic type name with the archive, and get the id
582 char const * name = binding_name<T>::name();
583 std::uint32_t id = ar.registerPolymorphicType(name);
584
585 // Serialize the id
586 ar( CEREAL_NVP_("polymorphic_id", id) );
587
588 // If the msb of the id is 1, then the type name is new, and we should serialize it
589 if( id & detail::msb_32bit )
590 {
591 std::string namestring(name);
592 ar( CEREAL_NVP_("polymorphic_name", namestring) );
593 }
594 }
595
598 {
599 public:
612 PolymorphicSharedPointerWrapper( T const * dptr ) : refCount(), wrappedPtr( refCount, dptr )
613 { }
614
616 inline std::shared_ptr<T const> const & operator()() const { return wrappedPtr; }
617
618 private:
619 std::shared_ptr<void> refCount;
620 std::shared_ptr<T const> wrappedPtr;
621 };
622
624
631 static inline void savePolymorphicSharedPtr( Archive & ar, T const * dptr, std::true_type /* has_shared_from_this */ )
632 {
633 ::cereal::memory_detail::EnableSharedStateHelper<T> state( const_cast<T *>(dptr) );
635 ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
636 }
637
639
646 static inline void savePolymorphicSharedPtr( Archive & ar, T const * dptr, std::false_type /* has_shared_from_this */ )
647 {
649 ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
650 }
651
654 {
655 auto & map = StaticObject<OutputBindingMap<Archive>>::getInstance().map;
656 auto key = std::type_index(typeid(T));
657 auto lb = map.lower_bound(key);
658
659 if (lb != map.end() && lb->first == key)
660 return;
661
662 typename OutputBindingMap<Archive>::Serializers serializers;
663
664 serializers.shared_ptr =
665 [&](void * arptr, void const * dptr, std::type_info const & baseInfo)
666 {
667 Archive & ar = *static_cast<Archive*>(arptr);
668 writeMetadata(ar);
669
670 auto ptr = PolymorphicCasters::template downcast<T>( dptr, baseInfo );
671
672 #if defined(_MSC_VER) && _MSC_VER < 1916 && !defined(__clang__)
673 savePolymorphicSharedPtr( ar, ptr, ::cereal::traits::has_shared_from_this<T>::type() ); // MSVC doesn't like typename here
674 #else // not _MSC_VER
675 savePolymorphicSharedPtr( ar, ptr, typename ::cereal::traits::has_shared_from_this<T>::type() );
676 #endif // _MSC_VER
677 };
678
679 serializers.unique_ptr =
680 [&](void * arptr, void const * dptr, std::type_info const & baseInfo)
681 {
682 Archive & ar = *static_cast<Archive*>(arptr);
683 writeMetadata(ar);
684
685 std::unique_ptr<T const, EmptyDeleter<T const>> const ptr( PolymorphicCasters::template downcast<T>( dptr, baseInfo ) );
686
687 ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
688 };
689
690 map.insert( { std::move(key), std::move(serializers) } );
691 }
692 };
693
696 struct adl_tag {};
697
709#ifdef CEREAL_HAS_CPP17
710 struct polymorphic_binding_tag {};
711#else
712 namespace { struct polymorphic_binding_tag {}; }
713#endif
714
715
717 template <class Archive, class T>
719 {
721 load(std::true_type)
722 {
724 }
725
727 save(std::true_type)
728 {
730 }
731
732 inline static void load(std::false_type) {}
733 inline static void save(std::false_type) {}
734 };
735
737 template <void(*)()>
739
745 template <class Archive, class T>
747 {
748 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
751 virtual CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
752 #else // NOT _MSC_VER
755 static CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
758 #endif // _MSC_VER
759 };
760
761 // instantiate implementation
762 template <class Archive, class T>
764 {
765 create_bindings<Archive,T>::save( std::integral_constant<bool,
766 std::is_base_of<detail::OutputArchiveBase, Archive>::value &&
768
769 create_bindings<Archive,T>::load( std::integral_constant<bool,
770 std::is_base_of<detail::InputArchiveBase, Archive>::value &&
772 }
773
775
779 template <class T, class Tag = polymorphic_binding_tag>
781 {
783 void bind(std::false_type) const
784 {
785 instantiate_polymorphic_binding(static_cast<T*>(nullptr), 0, Tag{}, adl_tag{});
786 }
787
789 void bind(std::true_type) const
790 { }
791
793
795 bind_to_archives const & bind() const
796 {
797 static_assert( std::is_polymorphic<T>::value,
798 "Attempting to register non polymorphic type" );
799 bind( std::is_abstract<T>() );
800 return *this;
801 }
802 };
803
805 template <class T, class Tag = polymorphic_binding_tag>
807
809
820 template <class T, typename BindingTag>
821 void instantiate_polymorphic_binding( T*, int, BindingTag, adl_tag ) {}
822 } // namespace detail
823} // namespace cereal
824
825#endif // CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
Definition: helpers.hpp:282
Definition: helpers.hpp:270
Holds a properly typed shared_ptr to the polymorphic type.
Definition: polymorphic_impl.hpp:598
PolymorphicSharedPointerWrapper(T const *dptr)
Definition: polymorphic_impl.hpp:612
std::shared_ptr< T const > const & operator()() const
Get the wrapped shared_ptr *‍/.
Definition: polymorphic_impl.hpp:616
A static, pre-execution object.
Definition: static_object.hpp:68
static LockGuard lock()
Attempts to lock this static object for the current scope.
Definition: static_object.hpp:110
#define CEREAL_NVP_(name, value)
Convenience for creating a templated NVP.
Definition: helpers.hpp:201
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:130
Support for types found in <memory>
void instantiate_polymorphic_binding(T *, int, BindingTag, adl_tag)
Base case overload for instantiation.
Definition: polymorphic_impl.hpp:821
#define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave)
Error message used for unregistered polymorphic casts.
Definition: polymorphic_impl.hpp:149
Internal polymorphism support forward declarations.
Internal polymorphism static object support.
#define CEREAL_DLL_EXPORT
Prevent link optimization from removing non-referenced static objects.
Definition: static_object.hpp:51
Support for types found in <string>
An empty noop deleter.
Definition: polymorphic_impl.hpp:490
Creates a binding (map entry) between an input archive type and a polymorphic type.
Definition: polymorphic_impl.hpp:531
InputBindingCreator()
Initialize the binding.
Definition: polymorphic_impl.hpp:533
Struct containing the serializer functions for all pointer types.
Definition: polymorphic_impl.hpp:512
UniqueSerializer unique_ptr
Serializer function for unique pointers.
Definition: polymorphic_impl.hpp:514
SharedSerializer shared_ptr
Serializer function for shared/weak pointers.
Definition: polymorphic_impl.hpp:513
A structure holding a map from type name strings to input serializer functions.
Definition: polymorphic_impl.hpp:499
std::function< void(void *, std::unique_ptr< void, EmptyDeleter< void > > &, std::type_info const &)> UniqueSerializer
Unique ptr serializer function.
Definition: polymorphic_impl.hpp:508
std::function< void(void *, std::shared_ptr< void > &, std::type_info const &)> SharedSerializer
Shared ptr serializer function.
Definition: polymorphic_impl.hpp:506
std::map< std::string, Serializers > map
A map of serializers for pointers of all registered types.
Definition: polymorphic_impl.hpp:518
Creates a binding (map entry) between an output archive type and a polymorphic type.
Definition: polymorphic_impl.hpp:577
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
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
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
Struct containing the serializer functions for all pointer types.
Definition: polymorphic_impl.hpp:480
Serializer shared_ptr
Serializer function for shared/weak pointers.
Definition: polymorphic_impl.hpp:481
Serializer unique_ptr
Serializer function for unique pointers.
Definition: polymorphic_impl.hpp:482
A structure holding a map from type_indices to output serializer functions.
Definition: polymorphic_impl.hpp:469
std::function< void(void *, void const *, std::type_info const &)> Serializer
A serializer function.
Definition: polymorphic_impl.hpp:476
std::map< std::type_index, Serializers > map
A map of serializers for pointers of all registered types.
Definition: polymorphic_impl.hpp:486
Base type for polymorphic void casting.
Definition: polymorphic_impl.hpp:120
virtual std::shared_ptr< void > upcast(std::shared_ptr< void > const &ptr) const =0
Upcast to proper base type, shared_ptr version.
virtual void * upcast(void *const ptr) const =0
Upcast to proper base type.
virtual void const * downcast(void const *const ptr) const =0
Downcasts to the proper derived type.
Holds registered mappings between base and derived types for casting.
Definition: polymorphic_impl.hpp:140
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
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 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
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
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 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
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:183
Strongly typed derivation of PolymorphicCaster.
Definition: polymorphic_impl.hpp:254
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
PolymorphicVirtualCaster()
Inserts an entry in the polymorphic casting map for this pairing.
Definition: polymorphic_impl.hpp:259
void const * downcast(void const *const ptr) const override
Performs the proper downcast with the templated types.
Definition: polymorphic_impl.hpp:412
void * upcast(void *const ptr) const override
Performs the proper upcast with the templated types.
Definition: polymorphic_impl.hpp:418
Registers a polymorphic casting relation between a Base and Derived type.
Definition: polymorphic_impl.hpp:439
static PolymorphicCaster const * bind()
Performs registration (binding) between Base and Derived.
Definition: polymorphic_impl.hpp:450
Definition: polymorphic_impl.hpp:696
Begins the binding process of a type to all registered archives.
Definition: polymorphic_impl.hpp:781
bind_to_archives const & bind() const
Binds the type T to all registered archives.
Definition: polymorphic_impl.hpp:795
void bind(std::false_type) const
Binding for non abstract types.
Definition: polymorphic_impl.hpp:783
void bind(std::true_type) const
Binding for abstract types.
Definition: polymorphic_impl.hpp:789
Binds a compile time type with a user defined string.
Definition: polymorphic_impl.hpp:460
Causes the static object bindings between an archive type and a serializable type T.
Definition: polymorphic_impl.hpp:719
Used to hide the static object used to bind T to registered archives.
Definition: polymorphic_impl.hpp:806
When specialized, causes the compiler to instantiate its parameter.
Definition: polymorphic_impl.hpp:738
Definition: polymorphic_impl.hpp:747
instantiate_function< instantiate > unused
This typedef causes the compiler to instantiate this static function.
Definition: polymorphic_impl.hpp:757
Determine if T or any base class of T has inherited from std::enable_shared_from_this.
Definition: traits.hpp:1217
Definition: traits.hpp:1139
Definition: traits.hpp:1112