LCOV - code coverage report
Current view: top level - cereal/types - polymorphic.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 65 88 73.9 %
Date: 2017-02-12 13:57:59 Functions: 92 108 85.2 %

          Line data    Source code
       1             : /*! \file polymorphic.hpp
       2             :     \brief Support for pointers to polymorphic base classes
       3             :     \ingroup OtherTypes */
       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             : #ifndef CEREAL_TYPES_POLYMORPHIC_HPP_
      31             : #define CEREAL_TYPES_POLYMORPHIC_HPP_
      32             : 
      33             : #include "cereal/cereal.hpp"
      34             : #include "cereal/types/memory.hpp"
      35             : 
      36             : #include "cereal/details/util.hpp"
      37             : #include "cereal/details/helpers.hpp"
      38             : #include "cereal/details/traits.hpp"
      39             : #include "cereal/details/polymorphic_impl.hpp"
      40             : 
      41             : #ifdef _MSC_VER
      42             : #define CEREAL_STATIC_CONSTEXPR static
      43             : #else
      44             : #define CEREAL_STATIC_CONSTEXPR static constexpr
      45             : #endif
      46             : 
      47             : //! Registers a derived polymorphic type with cereal
      48             : /*! Polymorphic types must be registered before smart
      49             :     pointers to them can be serialized.  Note that base
      50             :     classes do not need to be registered.
      51             : 
      52             :     Registering a type lets cereal know how to properly
      53             :     serialize it when a smart pointer to a base object is
      54             :     used in conjunction with a derived class.
      55             : 
      56             :     This assumes that all relevant archives have also
      57             :     previously been registered.  Registration for archives
      58             :     is usually done in the header file in which they are
      59             :     defined.  This means that type registration needs to
      60             :     happen after specific archives to be used are included.
      61             : 
      62             :     It is recommended that type registration be done in
      63             :     the header file in which the type is declared.
      64             : 
      65             :     Registration can also be placed in a source file,
      66             :     but this may require the use of the
      67             :     CEREAL_REGISTER_DYNAMIC_INIT macro (see below).
      68             : 
      69             :     Registration may be called repeatedly for the same
      70             :     type in different translation units to add support
      71             :     for additional archives if they are not initially
      72             :     available (included and registered).
      73             : 
      74             :     When building serialization support as a DLL on
      75             :     Windows, registration must happen in the header file.
      76             :     On Linux and Mac things should still work properly
      77             :     if placed in a source file, but see the above comments
      78             :     on registering in source files.
      79             : 
      80             :     Polymorphic support in cereal requires RTTI to be
      81             :     enabled */
      82             : #define CEREAL_REGISTER_TYPE(...)                                        \
      83             :   namespace cereal {                                                     \
      84             :   namespace detail {                                                     \
      85             :   template <>                                                            \
      86             :   struct binding_name<__VA_ARGS__>                                       \
      87             :   {                                                                      \
      88             :     CEREAL_STATIC_CONSTEXPR char const * name() { return #__VA_ARGS__; } \
      89             :   };                                                                     \
      90             :   } } /* end namespaces */                                               \
      91             :   CEREAL_BIND_TO_ARCHIVES(__VA_ARGS__)
      92             : 
      93             : //! Registers a polymorphic type with cereal, giving it a
      94             : //! user defined name
      95             : /*! In some cases the default name used with
      96             :     CEREAL_REGISTER_TYPE (the name of the type) may not be
      97             :     suitable.  This macro allows any name to be associated
      98             :     with the type.  The name should be unique */
      99             : #define CEREAL_REGISTER_TYPE_WITH_NAME(T, Name)                     \
     100             :   namespace cereal {                                                \
     101             :   namespace detail {                                                \
     102             :   template <>                                                       \
     103             :   struct binding_name<T>                                            \
     104             :   { CEREAL_STATIC_CONSTEXPR char const * name() { return Name; } }; \
     105             :   } } /* end namespaces */                                          \
     106             :   CEREAL_BIND_TO_ARCHIVES(T)
     107             : 
     108             : //! Registers the base-derived relationship for a polymorphic type
     109             : /*! When polymorphic serialization occurs, cereal needs to know how to
     110             :     properly cast between derived and base types for the polymorphic
     111             :     type. Normally this happens automatically whenever cereal::base_class
     112             :     or cereal::virtual_base_class are used to serialize a base class. In
     113             :     cases where neither of these is ever called but a base class still
     114             :     exists, this explicit registration is required.
     115             : 
     116             :     The Derived class should be the most derived type that will be serialized,
     117             :     and the Base type any possible base that has not been covered under a base
     118             :     class serialization that will be used to store a Derived pointer.
     119             : 
     120             :     Placement of this is the same as for CEREAL_REGISTER_TYPE. */
     121             : #define CEREAL_REGISTER_POLYMORPHIC_RELATION(Base, Derived)                     \
     122             :   namespace cereal {                                                            \
     123             :   namespace detail {                                                            \
     124             :   template <>                                                                   \
     125             :   struct PolymorphicRelation<Base, Derived>                                     \
     126             :   { static void bind() { RegisterPolymorphicCaster<Base, Derived>::bind(); } }; \
     127             :   } } /* end namespaces */
     128             : 
     129             : //! Adds a way to force initialization of a translation unit containing
     130             : //! calls to CEREAL_REGISTER_TYPE
     131             : /*! In C++, dynamic initialization of non-local variables of a translation
     132             :     unit may be deferred until "the first odr-use of any function or variable
     133             :     defined in the same translation unit as the variable to be initialized."
     134             : 
     135             :     Informally, odr-use means that your program takes the address of or binds
     136             :     a reference directly to an object, which must have a definition.
     137             : 
     138             :     Since polymorphic type support in cereal relies on the dynamic
     139             :     initialization of certain global objects happening before
     140             :     serialization is performed, it is important to ensure that something
     141             :     from files that call CEREAL_REGISTER_TYPE is odr-used before serialization
     142             :     occurs, otherwise the registration will never take place.  This may often
     143             :     be the case when serialization is built as a shared library external from
     144             :     your main program.
     145             : 
     146             :     This macro, with any name of your choosing, should be placed into the
     147             :     source file that contains calls to CEREAL_REGISTER_TYPE.
     148             : 
     149             :     Its counterpart, CEREAL_FORCE_DYNAMIC_INIT, should be placed in its
     150             :     associated header file such that it is included in the translation units
     151             :     (source files) in which you want the registration to appear.
     152             : 
     153             :     @relates CEREAL_FORCE_DYNAMIC_INIT
     154             :     */
     155             : #define CEREAL_REGISTER_DYNAMIC_INIT(LibName)                \
     156             :   namespace cereal {                                         \
     157             :   namespace detail {                                         \
     158             :     void CEREAL_DLL_EXPORT dynamic_init_dummy_##LibName() {} \
     159             :   } } /* end namespaces */
     160             : 
     161             : //! Forces dynamic initialization of polymorphic support in a
     162             : //! previously registered source file
     163             : /*! @sa CEREAL_REGISTER_DYNAMIC_INIT
     164             : 
     165             :     See CEREAL_REGISTER_DYNAMIC_INIT for detailed explanation
     166             :     of how this macro should be used.  The name used should
     167             :     match that for CEREAL_REGISTER_DYNAMIC_INIT. */
     168             : #define CEREAL_FORCE_DYNAMIC_INIT(LibName)              \
     169             :   namespace cereal {                                    \
     170             :   namespace detail {                                    \
     171             :     void dynamic_init_dummy_##LibName();                \
     172             :   } /* end detail */                                    \
     173             :   namespace {                                           \
     174             :     void dynamic_init_##LibName()                       \
     175             :     {                                                   \
     176             :       ::cereal::detail::dynamic_init_dummy_##LibName(); \
     177             :     }                                                   \
     178             :   } } /* end namespaces */
     179             : 
     180             : namespace cereal
     181             : {
     182             :   namespace polymorphic_detail
     183             :   {
     184             :     //! Error message used for unregistered polymorphic types
     185             :     /*! @internal */
     186             :     #define UNREGISTERED_POLYMORPHIC_EXCEPTION(LoadSave, Name)                                                                                      \
     187             :       throw cereal::Exception("Trying to " #LoadSave " an unregistered polymorphic type (" + Name + ").\n"                                          \
     188             :                               "Make sure your type is registered with CEREAL_REGISTER_TYPE and that the archive "                                   \
     189             :                               "you are using was included (and registered with CEREAL_REGISTER_ARCHIVE) prior to calling CEREAL_REGISTER_TYPE.\n"   \
     190             :                               "If your type is already registered and you still see this error, you may need to use CEREAL_REGISTER_DYNAMIC_INIT.");
     191             : 
     192             :     //! Get an input binding from the given archive by deserializing the type meta data
     193             :     /*! @internal */
     194             :     template<class Archive> inline
     195        3600 :     typename ::cereal::detail::InputBindingMap<Archive>::Serializers getInputBinding(Archive & ar, std::uint32_t const nameid)
     196             :     {
     197             :       // If the nameid is zero, we serialized a null pointer
     198        3600 :       if(nameid == 0)
     199             :       {
     200           0 :         typename ::cereal::detail::InputBindingMap<Archive>::Serializers emptySerializers;
     201           0 :         emptySerializers.shared_ptr = [](void*, std::shared_ptr<void> & ptr, std::type_info const &) { ptr.reset(); };
     202           0 :         emptySerializers.unique_ptr = [](void*, std::unique_ptr<void, ::cereal::detail::EmptyDeleter<void>> & ptr, std::type_info const &) { ptr.reset( nullptr ); };
     203           0 :         return emptySerializers;
     204             :       }
     205             : 
     206        7200 :       std::string name;
     207        3600 :       if(nameid & detail::msb_32bit)
     208             :       {
     209        1600 :         ar( CEREAL_NVP_("polymorphic_name", name) );
     210        1600 :         ar.registerPolymorphicName(nameid, name);
     211             :       }
     212             :       else
     213        2000 :         name = ar.getPolymorphicName(nameid);
     214             : 
     215        3600 :       auto const & bindingMap = detail::StaticObject<detail::InputBindingMap<Archive>>::getInstance().map;
     216             : 
     217        3600 :       auto binding = bindingMap.find(name);
     218        3600 :       if(binding == bindingMap.end())
     219           0 :         UNREGISTERED_POLYMORPHIC_EXCEPTION(load, name)
     220        3600 :       return binding->second;
     221             :     }
     222             : 
     223             :     //! Serialize a shared_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
     224             :     /*! This check lets us try and skip doing polymorphic machinery if we can get away with
     225             :         using the derived class serialize function
     226             : 
     227             :         Note that on MSVC 2013 preview, is_default_constructible<T> returns true for abstract classes with
     228             :         default constructors, but on clang/gcc this will return false.  So we also need to check for that here.
     229             :         @internal */
     230             :     template<class Archive, class T> inline
     231             :     typename std::enable_if<(traits::is_default_constructible<T>::value
     232             :                              || traits::has_load_and_construct<T, Archive>::value)
     233             :                              && !std::is_abstract<T>::value, bool>::type
     234         400 :     serialize_wrapper(Archive & ar, std::shared_ptr<T> & ptr, std::uint32_t const nameid)
     235             :     {
     236         400 :       if(nameid & detail::msb2_32bit)
     237             :       {
     238           0 :         ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
     239           0 :         return true;
     240             :       }
     241         400 :       return false;
     242             :     }
     243             : 
     244             :     //! Serialize a unique_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
     245             :     /*! This check lets us try and skip doing polymorphic machinery if we can get away with
     246             :         using the derived class serialize function
     247             :         @internal */
     248             :     template<class Archive, class T, class D> inline
     249             :     typename std::enable_if<(traits::is_default_constructible<T>::value
     250             :                              || traits::has_load_and_construct<T, Archive>::value)
     251             :                              && !std::is_abstract<T>::value, bool>::type
     252             :     serialize_wrapper(Archive & ar, std::unique_ptr<T, D> & ptr, std::uint32_t const nameid)
     253             :     {
     254             :       if(nameid & detail::msb2_32bit)
     255             :       {
     256             :         ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
     257             :         return true;
     258             :       }
     259             :       return false;
     260             :     }
     261             : 
     262             :     //! Serialize a shared_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
     263             :     /*! This case is for when we can't actually construct the shared pointer.  Normally this would be caught
     264             :         as the pointer itself is serialized, but since this is a polymorphic pointer, if we tried to serialize
     265             :         the pointer we'd end up back here recursively.  So we have to catch the error here as well, if
     266             :         this was a polymorphic type serialized by its proper pointer type
     267             :         @internal */
     268             :     template<class Archive, class T> inline
     269             :     typename std::enable_if<(!traits::is_default_constructible<T>::value
     270             :                              && !traits::has_load_and_construct<T, Archive>::value)
     271             :                              || std::is_abstract<T>::value, bool>::type
     272        2400 :     serialize_wrapper(Archive &, std::shared_ptr<T> &, std::uint32_t const nameid)
     273             :     {
     274        2400 :       if(nameid & detail::msb2_32bit)
     275           0 :         throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_construct function");
     276        2400 :       return false;
     277             :     }
     278             : 
     279             :     //! Serialize a unique_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
     280             :     /*! This case is for when we can't actually construct the unique pointer.  Normally this would be caught
     281             :         as the pointer itself is serialized, but since this is a polymorphic pointer, if we tried to serialize
     282             :         the pointer we'd end up back here recursively.  So we have to catch the error here as well, if
     283             :         this was a polymorphic type serialized by its proper pointer type
     284             :         @internal */
     285             :     template<class Archive, class T, class D> inline
     286             :      typename std::enable_if<(!traits::is_default_constructible<T>::value
     287             :                                && !traits::has_load_and_construct<T, Archive>::value)
     288             :                                || std::is_abstract<T>::value, bool>::type
     289         800 :     serialize_wrapper(Archive &, std::unique_ptr<T, D> &, std::uint32_t const nameid)
     290             :     {
     291         800 :       if(nameid & detail::msb2_32bit)
     292           0 :         throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_construct function");
     293         800 :       return false;
     294             :     }
     295             :   } // polymorphic_detail
     296             : 
     297             :   // ######################################################################
     298             :   // Pointer serialization for polymorphic types
     299             : 
     300             :   //! Saving std::shared_ptr for polymorphic types, abstract
     301             :   template <class Archive, class T> inline
     302             :   typename std::enable_if<std::is_polymorphic<T>::value && std::is_abstract<T>::value, void>::type
     303        2400 :   CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
     304             :   {
     305        2400 :     if(!ptr)
     306             :     {
     307             :       // same behavior as nullptr in memory implementation
     308           0 :       ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
     309           0 :       return;
     310             :     }
     311             : 
     312        2400 :     std::type_info const & ptrinfo = typeid(*ptr.get());
     313             :     static std::type_info const & tinfo = typeid(T);
     314             :     // ptrinfo can never be equal to T info since we can't have an instance
     315             :     // of an abstract object
     316             :     //  this implies we need to do the lookup
     317             : 
     318        2400 :     auto const & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
     319             : 
     320        2400 :     auto binding = bindingMap.find(std::type_index(ptrinfo));
     321        2400 :     if(binding == bindingMap.end())
     322           0 :       UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
     323             : 
     324        2400 :     binding->second.shared_ptr(&ar, ptr.get(), tinfo);
     325             :   }
     326             : 
     327             :   //! Saving std::shared_ptr for polymorphic types, not abstract
     328             :   template <class Archive, class T> inline
     329             :   typename std::enable_if<std::is_polymorphic<T>::value && !std::is_abstract<T>::value, void>::type
     330         400 :   CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
     331             :   {
     332         400 :     if(!ptr)
     333             :     {
     334             :       // same behavior as nullptr in memory implementation
     335           0 :       ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
     336           0 :       return;
     337             :     }
     338             : 
     339         400 :     std::type_info const & ptrinfo = typeid(*ptr.get());
     340             :     static std::type_info const & tinfo = typeid(T);
     341             : 
     342         400 :     if(ptrinfo == tinfo)
     343             :     {
     344             :       // The 2nd msb signals that the following pointer does not need to be
     345             :       // cast with our polymorphic machinery
     346           0 :       ar( CEREAL_NVP_("polymorphic_id", detail::msb2_32bit) );
     347             : 
     348           0 :       ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
     349             : 
     350           0 :       return;
     351             :     }
     352             : 
     353         400 :     auto const & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
     354             : 
     355         400 :     auto binding = bindingMap.find(std::type_index(ptrinfo));
     356         400 :     if(binding == bindingMap.end())
     357           0 :       UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
     358             : 
     359         400 :     binding->second.shared_ptr(&ar, ptr.get(), tinfo);
     360             :   }
     361             : 
     362             :   //! Loading std::shared_ptr for polymorphic types
     363             :   template <class Archive, class T> inline
     364             :   typename std::enable_if<std::is_polymorphic<T>::value, void>::type
     365        2800 :   CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> & ptr )
     366             :   {
     367             :     std::uint32_t nameid;
     368        2800 :     ar( CEREAL_NVP_("polymorphic_id", nameid) );
     369             : 
     370             :     // Check to see if we can skip all of this polymorphism business
     371        2800 :     if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid))
     372           0 :       return;
     373             : 
     374        5600 :     auto binding = polymorphic_detail::getInputBinding(ar, nameid);
     375        5600 :     std::shared_ptr<void> result;
     376        2800 :     binding.shared_ptr(&ar, result, typeid(T));
     377        2800 :     ptr = std::static_pointer_cast<T>(result);
     378             :   }
     379             : 
     380             :   //! Saving std::weak_ptr for polymorphic types
     381             :   template <class Archive, class T> inline
     382             :   typename std::enable_if<std::is_polymorphic<T>::value, void>::type
     383         800 :   CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> const & ptr )
     384             :   {
     385        1600 :     auto const sptr = ptr.lock();
     386         800 :     ar( CEREAL_NVP_("locked_ptr", sptr) );
     387         800 :   }
     388             : 
     389             :   //! Loading std::weak_ptr for polymorphic types
     390             :   template <class Archive, class T> inline
     391             :   typename std::enable_if<std::is_polymorphic<T>::value, void>::type
     392         800 :   CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> & ptr )
     393             :   {
     394        1600 :     std::shared_ptr<T> sptr;
     395         800 :     ar( CEREAL_NVP_("locked_ptr", sptr) );
     396         800 :     ptr = sptr;
     397         800 :   }
     398             : 
     399             :   //! Saving std::unique_ptr for polymorphic types that are abstract
     400             :   template <class Archive, class T, class D> inline
     401             :   typename std::enable_if<std::is_polymorphic<T>::value && std::is_abstract<T>::value, void>::type
     402         800 :   CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
     403             :   {
     404         800 :     if(!ptr)
     405             :     {
     406             :       // same behavior as nullptr in memory implementation
     407           0 :       ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
     408           0 :       return;
     409             :     }
     410             : 
     411         800 :     std::type_info const & ptrinfo = typeid(*ptr.get());
     412             :     static std::type_info const & tinfo = typeid(T);
     413             :     // ptrinfo can never be equal to T info since we can't have an instance
     414             :     // of an abstract object
     415             :     //  this implies we need to do the lookup
     416             : 
     417         800 :     auto const & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
     418             : 
     419         800 :     auto binding = bindingMap.find(std::type_index(ptrinfo));
     420         800 :     if(binding == bindingMap.end())
     421           0 :       UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
     422             : 
     423         800 :     binding->second.unique_ptr(&ar, ptr.get(), tinfo);
     424             :   }
     425             : 
     426             :   //! Saving std::unique_ptr for polymorphic types, not abstract
     427             :   template <class Archive, class T, class D> inline
     428             :   typename std::enable_if<std::is_polymorphic<T>::value && !std::is_abstract<T>::value, void>::type
     429             :   CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
     430             :   {
     431             :     if(!ptr)
     432             :     {
     433             :       // same behavior as nullptr in memory implementation
     434             :       ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
     435             :       return;
     436             :     }
     437             : 
     438             :     std::type_info const & ptrinfo = typeid(*ptr.get());
     439             :     static std::type_info const & tinfo = typeid(T);
     440             : 
     441             :     if(ptrinfo == tinfo)
     442             :     {
     443             :       // The 2nd msb signals that the following pointer does not need to be
     444             :       // cast with our polymorphic machinery
     445             :       ar( CEREAL_NVP_("polymorphic_id", detail::msb2_32bit) );
     446             : 
     447             :       ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
     448             : 
     449             :       return;
     450             :     }
     451             : 
     452             :     auto const & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
     453             : 
     454             :     auto binding = bindingMap.find(std::type_index(ptrinfo));
     455             :     if(binding == bindingMap.end())
     456             :       UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
     457             : 
     458             :     binding->second.unique_ptr(&ar, ptr.get(), tinfo);
     459             :   }
     460             : 
     461             :   //! Loading std::unique_ptr, case when user provides load_and_construct for polymorphic types
     462             :   template <class Archive, class T, class D> inline
     463             :   typename std::enable_if<std::is_polymorphic<T>::value, void>::type
     464         800 :   CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> & ptr )
     465             :   {
     466             :     std::uint32_t nameid;
     467         800 :     ar( CEREAL_NVP_("polymorphic_id", nameid) );
     468             : 
     469             :     // Check to see if we can skip all of this polymorphism business
     470         800 :     if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid))
     471           0 :       return;
     472             : 
     473        1600 :     auto binding = polymorphic_detail::getInputBinding(ar, nameid);
     474        1600 :     std::unique_ptr<void, ::cereal::detail::EmptyDeleter<void>> result;
     475         800 :     binding.unique_ptr(&ar, result, typeid(T));
     476         800 :     ptr.reset(static_cast<T*>(result.release()));
     477             :   }
     478             : 
     479             :   #undef UNREGISTERED_POLYMORPHIC_EXCEPTION
     480             : } // namespace cereal
     481             : #endif // CEREAL_TYPES_POLYMORPHIC_HPP_

Generated by: LCOV version 1.11