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 cereal 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 RANDOLPH VOORHIES OR SHANE GRANT 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 
50 #include "cereal/types/memory.hpp"
51 #include "cereal/types/string.hpp"
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 #define CEREAL_BIND_TO_ARCHIVES(...) \
73  namespace cereal { \
74  namespace detail { \
75  template<> \
76  struct init_binding<__VA_ARGS__> { \
77  static bind_to_archives<__VA_ARGS__> const & b; \
78  CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION \
79  }; \
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(); \
84  }} /* end namespaces */
85 
86 namespace cereal
87 {
88  /* Polymorphic casting support */
89  namespace detail
90  {
92 
105  {
106  PolymorphicCaster() = default;
107  PolymorphicCaster( const PolymorphicCaster & ) = default;
108  PolymorphicCaster & operator=( const PolymorphicCaster & ) = default;
110  PolymorphicCaster & operator=( PolymorphicCaster && ) CEREAL_NOEXCEPT { return *this; }
111  virtual ~PolymorphicCaster() CEREAL_NOEXCEPT = default;
112 
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;
119  };
120 
122 
125  {
127  using DerivedCasterMap = std::unordered_map<std::type_index, std::vector<PolymorphicCaster const *>>;
129  std::unordered_map<std::type_index, DerivedCasterMap> map;
130 
131  std::multimap<std::type_index, std::type_index> reverseMap;
132 
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.");
139 
141 
144  static std::pair<bool, std::vector<PolymorphicCaster const *> const &>
145  lookup_if_exists( std::type_index const & baseIndex, std::type_index const & derivedIndex )
146  {
147  // First phase of lookup - match base type index
148  auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
149  auto baseIter = baseMap.find( baseIndex );
150  if (baseIter == baseMap.end())
151  return {false, {}};
152 
153  // Second phase - find a match from base to derived
154  auto const & derivedMap = baseIter->second;
155  auto derivedIter = derivedMap.find( derivedIndex );
156  if (derivedIter == derivedMap.end())
157  return {false, {}};
158 
159  return {true, derivedIter->second};
160  }
161 
163 
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 )
169  {
170  // First phase of lookup - match base type index
171  auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
172  auto baseIter = baseMap.find( baseIndex );
173  if( baseIter == baseMap.end() )
174  exceptionFunc();
175 
176  // Second phase - find a match from base to derived
177  auto const & derivedMap = baseIter->second;
178  auto derivedIter = derivedMap.find( derivedIndex );
179  if( derivedIter == derivedMap.end() )
180  exceptionFunc();
181 
182  return derivedIter->second;
183  }
184 
186  template <class Derived> inline
187  static const Derived * downcast( const void * dptr, std::type_info const & baseInfo )
188  {
189  auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(save) } );
190 
191  for( auto const * dmap : mapping )
192  dptr = dmap->downcast( dptr );
193 
194  return static_cast<Derived const *>( dptr );
195  }
196 
198 
200  template <class Derived> inline
201  static void * upcast( Derived * const dptr, std::type_info const & baseInfo )
202  {
203  auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } );
204 
205  void * uptr = dptr;
206  for( auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
207  uptr = (*mIter)->upcast( uptr );
208 
209  return uptr;
210  }
211 
213  template <class Derived> inline
214  static std::shared_ptr<void> upcast( std::shared_ptr<Derived> const & dptr, std::type_info const & baseInfo )
215  {
216  auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } );
217 
218  std::shared_ptr<void> uptr = dptr;
219  for( auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
220  uptr = (*mIter)->upcast( uptr );
221 
222  return uptr;
223  }
224 
225  #undef UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION
226  };
227 
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
235 
237  template <class Base, class Derived>
239  {
241 
245  {
246  const auto baseKey = std::type_index(typeid(Base));
247  const auto derivedKey = std::type_index(typeid(Derived));
248 
249  // First insert the relation Base->Derived
250  const auto lock = StaticObject<PolymorphicCasters>::lock();
251  auto & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
252 
253  {
254  auto & derivedMap = baseMap.insert( {baseKey, PolymorphicCasters::DerivedCasterMap{}} ).first->second;
255  auto & derivedVec = derivedMap.insert( {derivedKey, {}} ).first->second;
256  derivedVec.push_back( this );
257  }
258 
259  // Insert reverse relation Derived->Base
260  auto & reverseMap = StaticObject<PolymorphicCasters>::getInstance().reverseMap;
261  CEREAL_EMPLACE_MAP(reverseMap, derivedKey, baseKey);
262 
263  // Find all chainable unregistered relations
264  /* The strategy here is to process only the nodes in the class hierarchy graph that have been
265  affected by the new insertion. The aglorithm iteratively processes a node an ensures that it
266  is updated with all new shortest length paths. It then rocesses the parents of the active node,
267  with the knowledge that all children have already been processed.
268 
269  Note that for the following, we'll use the nomenclature of parent and child to not confuse with
270  the inserted base derived relationship */
271  {
272  // Checks whether there is a path from parent->child and returns a <dist, path> pair
273  // dist is set to MAX if the path does not exist
274  auto checkRelation = [](std::type_index const & parentInfo, std::type_index const & childInfo) ->
275  std::pair<size_t, std::vector<PolymorphicCaster const *> const &>
276  {
277  auto result = PolymorphicCasters::lookup_if_exists( parentInfo, childInfo );
278  if( result.first )
279  {
280  auto const & path = result.second;
281  return {path.size(), path};
282  }
283  else
284  return {(std::numeric_limits<size_t>::max)(), {}};
285  };
286 
287  std::stack<std::type_index> parentStack; // Holds the parent nodes to be processed
288  std::vector<std::type_index> dirtySet; // Marks child nodes that have been changed
289  std::unordered_set<std::type_index> processedParents; // Marks parent nodes that have been processed
290 
291  // Checks if a child has been marked dirty
292  auto isDirty = [&](std::type_index const & c)
293  {
294  auto const dirtySetSize = dirtySet.size();
295  for( size_t i = 0; i < dirtySetSize; ++i )
296  if( dirtySet[i] == c )
297  return true;
298 
299  return false;
300  };
301 
302  // Begin processing the base key and mark derived as dirty
303  parentStack.push( baseKey );
304  dirtySet.emplace_back( derivedKey );
305 
306  while( !parentStack.empty() )
307  {
308  using Relations = std::unordered_multimap<std::type_index, std::pair<std::type_index, std::vector<PolymorphicCaster const *>>>;
309  Relations unregisteredRelations; // Defer insertions until after main loop to prevent iterator invalidation
310 
311  const auto parent = parentStack.top();
312  parentStack.pop();
313 
314  // Update paths to all children marked dirty
315  for( auto const & childPair : baseMap[parent] )
316  {
317  const auto child = childPair.first;
318  if( isDirty( child ) && baseMap.count( child ) )
319  {
320  auto parentChildPath = checkRelation( parent, child );
321 
322  // Search all paths from the child to its own children (finalChild),
323  // looking for a shorter parth from parent to finalChild
324  for( auto const & finalChildPair : baseMap[child] )
325  {
326  const auto finalChild = finalChildPair.first;
327 
328  auto parentFinalChildPath = checkRelation( parent, finalChild );
329  auto childFinalChildPath = checkRelation( child, finalChild );
330 
331  const size_t newLength = 1u + parentChildPath.first;
332 
333  if( newLength < parentFinalChildPath.first )
334  {
335  std::vector<PolymorphicCaster const *> path = parentChildPath.second;
336  path.insert( path.end(), childFinalChildPath.second.begin(), childFinalChildPath.second.end() );
337 
338  // Check to see if we have a previous uncommitted path in unregisteredRelations
339  // that is shorter. If so, ignore this path
340  auto hintRange = unregisteredRelations.equal_range( parent );
341  auto hint = hintRange.first;
342  for( ; hint != hintRange.second; ++hint )
343  if( hint->second.first == finalChild )
344  break;
345 
346  const bool uncommittedExists = hint != unregisteredRelations.end();
347  if( uncommittedExists && (hint->second.second.size() <= newLength) )
348  continue;
349 
350  auto newPath = std::pair<std::type_index, std::vector<PolymorphicCaster const *>>{finalChild, std::move(path)};
351 
352  // Insert the new path if it doesn't exist, otherwise this will just lookup where to do the
353  // replacement
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
359 
360  // If there was an uncommitted path, we need to perform a replacement
361  if( uncommittedExists )
362  old->second = newPath;
363  }
364  } // end loop over child's children
365  } // end if dirty and child has children
366  } // end loop over children
367 
368  // Insert chained relations
369  for( auto const & it : unregisteredRelations )
370  {
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 );
374  }
375 
376  // Mark current parent as modified
377  dirtySet.emplace_back( parent );
378 
379  // Insert all parents of the current parent node that haven't yet been processed
380  auto parentRange = reverseMap.equal_range( parent );
381  for( auto pIter = parentRange.first; pIter != parentRange.second; ++pIter )
382  {
383  const auto pParent = pIter->second;
384  if( !processedParents.count( pParent ) )
385  {
386  parentStack.push( pParent );
387  processedParents.insert( pParent );
388  }
389  }
390  } // end loop over parent stack
391  } // end chainable relations
392  } // end PolymorphicVirtualCaster()
393 
394  #undef CEREAL_EMPLACE_MAP
395 
397  void const * downcast( void const * const ptr ) const override
398  {
399  return dynamic_cast<Derived const*>( static_cast<Base const*>( ptr ) );
400  }
401 
403  void * upcast( void * const ptr ) const override
404  {
405  return dynamic_cast<Base*>( static_cast<Derived*>( ptr ) );
406  }
407 
409  std::shared_ptr<void> upcast( std::shared_ptr<void> const & ptr ) const override
410  {
411  return std::dynamic_pointer_cast<Base>( std::static_pointer_cast<Derived>( ptr ) );
412  }
413  };
414 
416 
422  template <class Base, class Derived>
424  {
425  static PolymorphicCaster const * bind( std::true_type /* is_polymorphic<Base> */)
426  {
428  }
429 
430  static PolymorphicCaster const * bind( std::false_type /* is_polymorphic<Base> */ )
431  { return nullptr; }
432 
434 
435  static PolymorphicCaster const * bind()
436  { return bind( typename std::is_polymorphic<Base>::type() ); }
437  };
438  }
439 
440  /* General polymorphism support */
441  namespace detail
442  {
444  template <class T>
445  struct binding_name {};
446 
448 
452  template <class Archive>
454  {
456 
461  typedef std::function<void(void*, void const *, std::type_info const &)> Serializer;
462 
464  struct Serializers
465  {
468  };
469 
471  std::map<std::type_index, Serializers> map;
472  };
473 
475  template<class T> struct EmptyDeleter { void operator()(T *) const {} };
476 
478 
482  template <class Archive>
484  {
486 
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;
494 
496  struct Serializers
497  {
500  };
501 
503  std::map<std::string, Serializers> map;
504  };
505 
506  // forward decls for archives from cereal.hpp
507  class InputArchiveBase;
508  class OutputArchiveBase;
509 
511 
515  template <class Archive, class T> struct InputBindingCreator
516  {
519  {
520  auto & map = StaticObject<InputBindingMap<Archive>>::getInstance().map;
521  auto lock = StaticObject<InputBindingMap<Archive>>::lock();
522  auto key = std::string(binding_name<T>::name());
523  auto lb = map.lower_bound(key);
524 
525  if (lb != map.end() && lb->first == key)
526  return;
527 
528  typename InputBindingMap<Archive>::Serializers serializers;
529 
530  serializers.shared_ptr =
531  [](void * arptr, std::shared_ptr<void> & dptr, std::type_info const & baseInfo)
532  {
533  Archive & ar = *static_cast<Archive*>(arptr);
534  std::shared_ptr<T> ptr;
535 
536  ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
537 
538  dptr = PolymorphicCasters::template upcast<T>( ptr, baseInfo );
539  };
540 
541  serializers.unique_ptr =
542  [](void * arptr, std::unique_ptr<void, EmptyDeleter<void>> & dptr, std::type_info const & baseInfo)
543  {
544  Archive & ar = *static_cast<Archive*>(arptr);
545  std::unique_ptr<T> ptr;
546 
547  ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
548 
549  dptr.reset( PolymorphicCasters::template upcast<T>( ptr.release(), baseInfo ));
550  };
551 
552  map.insert( lb, { std::move(key), std::move(serializers) } );
553  }
554  };
555 
557 
561  template <class Archive, class T> struct OutputBindingCreator
562  {
564  static void writeMetadata(Archive & ar)
565  {
566  // Register the polymorphic type name with the archive, and get the id
567  char const * name = binding_name<T>::name();
568  std::uint32_t id = ar.registerPolymorphicType(name);
569 
570  // Serialize the id
571  ar( CEREAL_NVP_("polymorphic_id", id) );
572 
573  // If the msb of the id is 1, then the type name is new, and we should serialize it
574  if( id & detail::msb_32bit )
575  {
576  std::string namestring(name);
577  ar( CEREAL_NVP_("polymorphic_name", namestring) );
578  }
579  }
580 
583  {
584  public:
597  PolymorphicSharedPointerWrapper( T const * dptr ) : refCount(), wrappedPtr( refCount, dptr )
598  { }
599 
601  inline std::shared_ptr<T const> const & operator()() const { return wrappedPtr; }
602 
603  private:
604  std::shared_ptr<void> refCount;
605  std::shared_ptr<T const> wrappedPtr;
606  };
607 
609 
616  static inline void savePolymorphicSharedPtr( Archive & ar, T const * dptr, std::true_type /* has_shared_from_this */ )
617  {
618  ::cereal::memory_detail::EnableSharedStateHelper<T> state( const_cast<T *>(dptr) );
619  PolymorphicSharedPointerWrapper psptr( dptr );
620  ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
621  }
622 
624 
631  static inline void savePolymorphicSharedPtr( Archive & ar, T const * dptr, std::false_type /* has_shared_from_this */ )
632  {
633  PolymorphicSharedPointerWrapper psptr( dptr );
634  ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
635  }
636 
639  {
640  auto & map = StaticObject<OutputBindingMap<Archive>>::getInstance().map;
641  auto key = std::type_index(typeid(T));
642  auto lb = map.lower_bound(key);
643 
644  if (lb != map.end() && lb->first == key)
645  return;
646 
647  typename OutputBindingMap<Archive>::Serializers serializers;
648 
649  serializers.shared_ptr =
650  [&](void * arptr, void const * dptr, std::type_info const & baseInfo)
651  {
652  Archive & ar = *static_cast<Archive*>(arptr);
653  writeMetadata(ar);
654 
655  auto ptr = PolymorphicCasters::template downcast<T>( dptr, baseInfo );
656 
657  #ifdef _MSC_VER
658  savePolymorphicSharedPtr( ar, ptr, ::cereal::traits::has_shared_from_this<T>::type() ); // MSVC doesn't like typename here
659  #else // not _MSC_VER
660  savePolymorphicSharedPtr( ar, ptr, typename ::cereal::traits::has_shared_from_this<T>::type() );
661  #endif // _MSC_VER
662  };
663 
664  serializers.unique_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  std::unique_ptr<T const, EmptyDeleter<T const>> const ptr( PolymorphicCasters::template downcast<T>( dptr, baseInfo ) );
671 
672  ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
673  };
674 
675  map.insert( { std::move(key), std::move(serializers) } );
676  }
677  };
678 
681  struct adl_tag {};
682 
685  namespace { struct polymorphic_binding_tag {}; }
686 
688  template <class Archive, class T>
690  {
691  static const InputBindingCreator<Archive, T> &
692  load(std::true_type)
693  {
695  }
696 
697  static const OutputBindingCreator<Archive, T> &
698  save(std::true_type)
699  {
701  }
702 
703  inline static void load(std::false_type) {}
704  inline static void save(std::false_type) {}
705  };
706 
708  template <void(*)()>
710 
716  template <class Archive, class T>
718  {
719  #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
722  virtual CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
723  #else // NOT _MSC_VER
726  static CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
729  #endif // _MSC_VER
730  };
731 
732  // instantiate implementation
733  template <class Archive, class T>
735  {
736  create_bindings<Archive,T>::save( std::integral_constant<bool,
737  std::is_base_of<detail::OutputArchiveBase, Archive>::value &&
739 
740  create_bindings<Archive,T>::load( std::integral_constant<bool,
741  std::is_base_of<detail::InputArchiveBase, Archive>::value &&
743  }
744 
746 
750  template <class T, class Tag = polymorphic_binding_tag>
752  {
754  void bind(std::false_type) const
755  {
756  instantiate_polymorphic_binding(static_cast<T*>(nullptr), 0, Tag{}, adl_tag{});
757  }
758 
760  void bind(std::true_type) const
761  { }
762 
764 
766  bind_to_archives const & bind() const
767  {
768  static_assert( std::is_polymorphic<T>::value,
769  "Attempting to register non polymorphic type" );
770  bind( std::is_abstract<T>() );
771  return *this;
772  }
773  };
774 
776  template <class T, class Tag = polymorphic_binding_tag>
777  struct init_binding;
778 
780 
791  template <class T, typename BindingTag>
792  void instantiate_polymorphic_binding( T*, int, BindingTag, adl_tag ) {}
793  } // namespace detail
794 } // namespace cereal
795 
796 #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:583
PolymorphicSharedPointerWrapper(T const *dptr)
Definition: polymorphic_impl.hpp:597
std::shared_ptr< T const > const & operator()() const
Get the wrapped shared_ptr *‍/.
Definition: polymorphic_impl.hpp:601
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:109
#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:792
#define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave)
Error message used for unregistered polymorphic casts.
Definition: polymorphic_impl.hpp:134
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:475
Creates a binding (map entry) between an input archive type and a polymorphic type.
Definition: polymorphic_impl.hpp:516
InputBindingCreator()
Initialize the binding.
Definition: polymorphic_impl.hpp:518
Struct containing the serializer functions for all pointer types.
Definition: polymorphic_impl.hpp:497
UniqueSerializer unique_ptr
Serializer function for unique pointers.
Definition: polymorphic_impl.hpp:499
SharedSerializer shared_ptr
Serializer function for shared/weak pointers.
Definition: polymorphic_impl.hpp:498
A structure holding a map from type name strings to input serializer functions.
Definition: polymorphic_impl.hpp:484
std::function< void(void *, std::unique_ptr< void, EmptyDeleter< void >> &, std::type_info const &)> UniqueSerializer
Unique ptr serializer function.
Definition: polymorphic_impl.hpp:493
std::function< void(void *, std::shared_ptr< void > &, std::type_info const &)> SharedSerializer
Shared ptr serializer function.
Definition: polymorphic_impl.hpp:491
std::map< std::string, Serializers > map
A map of serializers for pointers of all registered types.
Definition: polymorphic_impl.hpp:503
Creates a binding (map entry) between an output archive type and a polymorphic type.
Definition: polymorphic_impl.hpp:562
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
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
static void writeMetadata(Archive &ar)
Writes appropriate metadata to the archive for this polymorphic type.
Definition: polymorphic_impl.hpp:564
OutputBindingCreator()
Initialize the binding.
Definition: polymorphic_impl.hpp:638
Struct containing the serializer functions for all pointer types.
Definition: polymorphic_impl.hpp:465
Serializer shared_ptr
Serializer function for shared/weak pointers.
Definition: polymorphic_impl.hpp:466
Serializer unique_ptr
Serializer function for unique pointers.
Definition: polymorphic_impl.hpp:467
A structure holding a map from type_indices to output serializer functions.
Definition: polymorphic_impl.hpp:454
std::function< void(void *, void const *, std::type_info const &)> Serializer
A serializer function.
Definition: polymorphic_impl.hpp:461
std::map< std::type_index, Serializers > map
A map of serializers for pointers of all registered types.
Definition: polymorphic_impl.hpp:471
Base type for polymorphic void casting.
Definition: polymorphic_impl.hpp:105
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:125
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
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
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
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 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
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
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
Strongly typed derivation of PolymorphicCaster.
Definition: polymorphic_impl.hpp:239
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
PolymorphicVirtualCaster()
Inserts an entry in the polymorphic casting map for this pairing.
Definition: polymorphic_impl.hpp:244
void * upcast(void *const ptr) const override
Performs the proper upcast with the templated types.
Definition: polymorphic_impl.hpp:403
void const * downcast(void const *const ptr) const override
Performs the proper downcast with the templated types.
Definition: polymorphic_impl.hpp:397
Registers a polymorphic casting relation between a Base and Derived type.
Definition: polymorphic_impl.hpp:424
static PolymorphicCaster const * bind()
Performs registration (binding) between Base and Derived.
Definition: polymorphic_impl.hpp:435
Definition: polymorphic_impl.hpp:681
Begins the binding process of a type to all registered archives.
Definition: polymorphic_impl.hpp:752
void bind(std::false_type) const
Binding for non abstract types.
Definition: polymorphic_impl.hpp:754
void bind(std::true_type) const
Binding for abstract types.
Definition: polymorphic_impl.hpp:760
bind_to_archives const & bind() const
Binds the type T to all registered archives.
Definition: polymorphic_impl.hpp:766
Binds a compile time type with a user defined string.
Definition: polymorphic_impl.hpp:445
Causes the static object bindings between an archive type and a serializable type T.
Definition: polymorphic_impl.hpp:690
Used to hide the static object used to bind T to registered archives.
Definition: polymorphic_impl.hpp:777
When specialized, causes the compiler to instantiate its parameter.
Definition: polymorphic_impl.hpp:709
Definition: polymorphic_impl.hpp:718
instantiate_function< instantiate > unused
This typedef causes the compiler to instantiate this static function.
Definition: polymorphic_impl.hpp:728
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