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 
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 #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 
101 namespace 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();
266  auto & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
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 
479  struct Serializers
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 
511  struct Serializers
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) );
634  PolymorphicSharedPointerWrapper psptr( 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  {
648  PolymorphicSharedPointerWrapper psptr( dptr );
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  {
720  static const InputBindingCreator<Archive, T> &
721  load(std::true_type)
722  {
724  }
725 
726  static const OutputBindingCreator<Archive, T> &
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)
749  virtual CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
752  #else // NOT _MSC_VER
753  static CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
757  typedef instantiate_function<instantiate> unused;
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>
806  struct init_binding;
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_
cereal::detail::instantiate_polymorphic_binding
void instantiate_polymorphic_binding(T *, int, BindingTag, adl_tag)
Base case overload for instantiation.
Definition: polymorphic_impl.hpp:821
cereal::detail::OutputBindingCreator::PolymorphicSharedPointerWrapper::operator()
const std::shared_ptr< T const > & operator()() const
Get the wrapped shared_ptr *‍/.
Definition: polymorphic_impl.hpp:616
CEREAL_NVP_
#define CEREAL_NVP_(name, value)
Convenience for creating a templated NVP.
Definition: helpers.hpp:201
cereal::detail::InputBindingMap::SharedSerializer
std::function< void(void *, std::shared_ptr< void > &, std::type_info const &)> SharedSerializer
Shared ptr serializer function.
Definition: polymorphic_impl.hpp:506
cereal::detail::InputBindingMap::Serializers::shared_ptr
SharedSerializer shared_ptr
Serializer function for shared/weak pointers.
Definition: polymorphic_impl.hpp:513
cereal::detail::OutputArchiveBase
Definition: helpers.hpp:269
cereal::detail::OutputBindingMap::Serializers::shared_ptr
Serializer shared_ptr
Serializer function for shared/weak pointers.
Definition: polymorphic_impl.hpp:481
cereal::detail::PolymorphicVirtualCaster::upcast
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
cereal::detail::PolymorphicCaster::downcast
virtual const void * downcast(void const *const ptr) const =0
Downcasts to the proper derived type.
cereal::detail::init_binding
Used to hide the static object used to bind T to registered archives.
Definition: polymorphic_impl.hpp:806
cereal::detail::InputBindingCreator
Creates a binding (map entry) between an input archive type and a polymorphic type.
Definition: polymorphic_impl.hpp:530
cereal::detail::PolymorphicCasters::lookup_if_exists
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
memory.hpp
Support for types found in <memory>
cereal::detail::OutputBindingMap::Serializers::unique_ptr
Serializer unique_ptr
Serializer function for unique pointers.
Definition: polymorphic_impl.hpp:482
cereal::detail::polymorphic_serialization_support
Definition: helpers.hpp:294
cereal::detail::PolymorphicCasters
Holds registered mappings between base and derived types for casting.
Definition: polymorphic_impl.hpp:139
cereal::detail::instantiate_function
When specialized, causes the compiler to instantiate its parameter.
Definition: polymorphic_impl.hpp:738
cereal::detail::OutputBindingMap::map
std::map< std::type_index, Serializers > map
A map of serializers for pointers of all registered types.
Definition: polymorphic_impl.hpp:486
string.hpp
Support for types found in <string>
cereal::detail::PolymorphicCaster
Base type for polymorphic void casting.
Definition: polymorphic_impl.hpp:119
CEREAL_DLL_EXPORT
#define CEREAL_DLL_EXPORT
Prevent link optimization from removing non-referenced static objects.
Definition: static_object.hpp:51
cereal::detail::StaticObject
A static, pre-execution object.
Definition: static_object.hpp:67
cereal::detail::PolymorphicCasters::lookup
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
cereal::detail::PolymorphicVirtualCaster
Strongly typed derivation of PolymorphicCaster.
Definition: polymorphic_impl.hpp:253
cereal::detail::StaticObject::lock
static LockGuard lock()
Attempts to lock this static object for the current scope.
Definition: static_object.hpp:110
cereal::detail::InputBindingCreator::InputBindingCreator
InputBindingCreator()
Initialize the binding.
Definition: polymorphic_impl.hpp:533
cereal::detail::OutputBindingCreator::PolymorphicSharedPointerWrapper
Holds a properly typed shared_ptr to the polymorphic type.
Definition: polymorphic_impl.hpp:597
UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION
#define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave)
Error message used for unregistered polymorphic casts.
Definition: polymorphic_impl.hpp:149
cereal::detail::PolymorphicCasters::upcast
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
cereal::detail::adl_tag
Definition: polymorphic_impl.hpp:696
cereal::detail::OutputBindingMap::Serializers
Struct containing the serializer functions for all pointer types.
Definition: polymorphic_impl.hpp:479
cereal::traits::is_output_serializable
Definition: traits.hpp:1111
cereal::detail::InputBindingMap::Serializers::unique_ptr
UniqueSerializer unique_ptr
Serializer function for unique pointers.
Definition: polymorphic_impl.hpp:514
cereal::detail::OutputBindingMap
A structure holding a map from type_indices to output serializer functions.
Definition: polymorphic_impl.hpp:468
cereal::detail::PolymorphicCasters::downcast
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
cereal::detail::binding_name
Binds a compile time type with a user defined string.
Definition: polymorphic_impl.hpp:460
cereal::memory_detail::EnableSharedStateHelper
Definition: memory.hpp:132
cereal::detail::PolymorphicCaster::upcast
virtual void * upcast(void *const ptr) const =0
Upcast to proper base type.
cereal::detail::PolymorphicCasters::DerivedCasterMap
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
cereal::detail::PolymorphicCasters::upcast
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
cereal::detail::OutputBindingCreator::PolymorphicSharedPointerWrapper::PolymorphicSharedPointerWrapper
PolymorphicSharedPointerWrapper(T const *dptr)
Definition: polymorphic_impl.hpp:612
cereal::detail::InputBindingMap::Serializers
Struct containing the serializer functions for all pointer types.
Definition: polymorphic_impl.hpp:511
cereal::detail::bind_to_archives::bind
void bind(std::true_type) const
Binding for abstract types.
Definition: polymorphic_impl.hpp:789
cereal::detail::OutputBindingCreator::writeMetadata
static void writeMetadata(Archive &ar)
Writes appropriate metadata to the archive for this polymorphic type.
Definition: polymorphic_impl.hpp:579
cereal::detail::OutputBindingCreator::OutputBindingCreator
OutputBindingCreator()
Initialize the binding.
Definition: polymorphic_impl.hpp:653
cereal::detail::OutputBindingCreator::savePolymorphicSharedPtr
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
cereal::traits::has_shared_from_this
Determine if T or any base class of T has inherited from std::enable_shared_from_this.
Definition: traits.hpp:1216
CEREAL_NOEXCEPT
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:130
cereal::detail::EmptyDeleter
An empty noop deleter.
Definition: polymorphic_impl.hpp:490
static_object.hpp
Internal polymorphism static object support.
cereal::detail::OutputBindingCreator::savePolymorphicSharedPtr
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
cereal::detail::bind_to_archives::bind
const bind_to_archives & bind() const
Binds the type T to all registered archives.
Definition: polymorphic_impl.hpp:795
cereal::detail::create_bindings
Causes the static object bindings between an archive type and a serializable type T.
Definition: polymorphic_impl.hpp:718
polymorphic_impl_fwd.hpp
Internal polymorphism support forward declarations.
cereal::detail::RegisterPolymorphicCaster
Registers a polymorphic casting relation between a Base and Derived type.
Definition: polymorphic_impl.hpp:438
cereal::detail::OutputBindingCreator
Creates a binding (map entry) between an output archive type and a polymorphic type.
Definition: polymorphic_impl.hpp:576
cereal::detail::InputBindingMap
A structure holding a map from type name strings to input serializer functions.
Definition: polymorphic_impl.hpp:498
cereal::detail::InputBindingMap::map
std::map< std::string, Serializers > map
A map of serializers for pointers of all registered types.
Definition: polymorphic_impl.hpp:518
cereal::detail::PolymorphicCasters::map
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
cereal::detail::RegisterPolymorphicCaster::bind
static const PolymorphicCaster * bind()
Performs registration (binding) between Base and Derived.
Definition: polymorphic_impl.hpp:450
cereal::detail::InputArchiveBase
Definition: helpers.hpp:281
cereal::detail::PolymorphicVirtualCaster::upcast
void * upcast(void *const ptr) const override
Performs the proper upcast with the templated types.
Definition: polymorphic_impl.hpp:418
cereal::detail::bind_to_archives::bind
void bind(std::false_type) const
Binding for non abstract types.
Definition: polymorphic_impl.hpp:783
cereal::detail::PolymorphicVirtualCaster::downcast
const void * downcast(void const *const ptr) const override
Performs the proper downcast with the templated types.
Definition: polymorphic_impl.hpp:412
cereal::traits::is_input_serializable
Definition: traits.hpp:1138
cereal::detail::bind_to_archives
Begins the binding process of a type to all registered archives.
Definition: polymorphic_impl.hpp:780
cereal::detail::PolymorphicVirtualCaster::PolymorphicVirtualCaster
PolymorphicVirtualCaster()
Inserts an entry in the polymorphic casting map for this pairing.
Definition: polymorphic_impl.hpp:259
cereal::detail::InputBindingMap::UniqueSerializer
std::function< void(void *, std::unique_ptr< void, EmptyDeleter< void >> &, std::type_info const &)> UniqueSerializer
Unique ptr serializer function.
Definition: polymorphic_impl.hpp:508
cereal::detail::OutputBindingMap::Serializer
std::function< void(void *, void const *, std::type_info const &)> Serializer
A serializer function.
Definition: polymorphic_impl.hpp:476