LCOV - code coverage report
Current view: top level - cereal - cereal.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 212 214 99.1 %
Date: 2022-01-16 21:05:07 Functions: 12911 13146 98.2 %

          Line data    Source code
       1             : /*! \file cereal.hpp
       2             :     \brief Main cereal functionality */
       3             : /*
       4             :   Copyright (c) 2014, Randolph Voorhies, Shane Grant
       5             :   All rights reserved.
       6             : 
       7             :   Redistribution and use in source and binary forms, with or without
       8             :   modification, are permitted provided that the following conditions are met:
       9             :       * Redistributions of source code must retain the above copyright
      10             :         notice, this list of conditions and the following disclaimer.
      11             :       * Redistributions in binary form must reproduce the above copyright
      12             :         notice, this list of conditions and the following disclaimer in the
      13             :         documentation and/or other materials provided with the distribution.
      14             :       * Neither the name of the copyright holder nor the
      15             :         names of its contributors may be used to endorse or promote products
      16             :         derived from this software without specific prior written permission.
      17             : 
      18             :   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
      19             :   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
      20             :   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      21             :   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
      22             :   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      23             :   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      24             :   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
      25             :   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      26             :   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      27             :   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      28             : */
      29             : #ifndef CEREAL_CEREAL_HPP_
      30             : #define CEREAL_CEREAL_HPP_
      31             : 
      32             : #include <type_traits>
      33             : #include <string>
      34             : #include <memory>
      35             : #include <functional>
      36             : #include <unordered_map>
      37             : #include <unordered_set>
      38             : #include <vector>
      39             : #include <cstddef>
      40             : #include <cstdint>
      41             : #include <functional>
      42             : 
      43             : #include "cereal/macros.hpp"
      44             : #include "cereal/details/traits.hpp"
      45             : #include "cereal/details/helpers.hpp"
      46             : #include "cereal/types/base_class.hpp"
      47             : 
      48             : namespace cereal
      49             : {
      50             :   // ######################################################################
      51             :   //! Creates a name value pair
      52             :   /*! @relates NameValuePair
      53             :       @ingroup Utility */
      54             :   template <class T> inline
      55        2600 :   NameValuePair<T> make_nvp( std::string const & name, T && value )
      56             :   {
      57        2600 :     return {name.c_str(), std::forward<T>(value)};
      58             :   }
      59             : 
      60             :   //! Creates a name value pair
      61             :   /*! @relates NameValuePair
      62             :       @ingroup Utility */
      63             :   template <class T> inline
      64        1400 :   NameValuePair<T> make_nvp( const char * name, T && value )
      65             :   {
      66        1400 :     return {name, std::forward<T>(value)};
      67             :   }
      68             : 
      69             :   //! Creates a name value pair for the variable T with the same name as the variable
      70             :   /*! @relates NameValuePair
      71             :       @ingroup Utility */
      72             :   #define CEREAL_NVP(T) ::cereal::make_nvp(#T, T)
      73             : 
      74             :   // ######################################################################
      75             :   //! Convenience function to create binary data for both const and non const pointers
      76             :   /*! @param data Pointer to beginning of the data
      77             :       @param size The size in bytes of the data
      78             :       @relates BinaryData
      79             :       @ingroup Utility */
      80             :   template <class T> inline
      81      287486 :   BinaryData<T> binary_data( T && data, size_t size )
      82             :   {
      83      287486 :     return {std::forward<T>(data), size};
      84             :   }
      85             : 
      86             :   // ######################################################################
      87             :   //! Creates a size tag from some variable.
      88             :   /*! Will normally be used to serialize size (e.g. size()) information for
      89             :       variable size containers.  If you have a variable sized container,
      90             :       the very first thing it serializes should be its size, wrapped in
      91             :       a SizeTag.
      92             : 
      93             :       @relates SizeTag
      94             :       @ingroup Utility */
      95             :   template <class T> inline
      96      367086 :   SizeTag<T> make_size_tag( T && sz )
      97             :   {
      98      367086 :     return {std::forward<T>(sz)};
      99             :   }
     100             : 
     101             :   // ######################################################################
     102             :   //! Marks data for deferred serialization
     103             :   /*! cereal performs a recursive depth-first traversal of data it serializes. When
     104             :       serializing smart pointers to large, nested, or cyclical data structures, it
     105             :       is possible to encounter a stack overflow from excessive recursion when following
     106             :       a chain of pointers.
     107             : 
     108             :       Deferment can help in these situations if the data can be serialized separately from
     109             :       the pointers used to traverse the structure. For example, a graph structure can have its
     110             :       nodes serialized before its edges:
     111             : 
     112             :       @code{.cpp}
     113             :       struct MyEdge
     114             :       {
     115             :         std::shared_ptr<MyNode> connection;
     116             :         int some_value;
     117             : 
     118             :         template<class Archive>
     119             :         void serialize(Archive & archive)
     120             :         {
     121             :           // when we serialize an edge, we'll defer serializing the associated node
     122             :           archive( cereal::defer( connection ),
     123             :                    some_value );
     124             :         }
     125             :       };
     126             : 
     127             :       struct MyGraphStructure
     128             :       {
     129             :         std::vector<MyEdge> edges;
     130             :         std::vector<MyNodes> nodes;
     131             : 
     132             :         template<class Archive>
     133             :         void serialize(Archive & archive)
     134             :         {
     135             :           // because of the deferment, we ensure all nodes are fully serialized
     136             :           // before any connection pointers to those nodes are serialized
     137             :           archive( edges, nodes );
     138             : 
     139             :           // we have to explicitly inform the archive when it is safe to serialize
     140             :           // the deferred data
     141             :           archive.serializeDeferments();
     142             :         }
     143             :       };
     144             :       @endcode
     145             : 
     146             :       @relates DeferredData
     147             :       @ingroup Utility */
     148             :   template <class T> inline
     149        8000 :   DeferredData<T> defer( T && value )
     150             :   {
     151        8000 :     return {std::forward<T>(value)};
     152             :   }
     153             : 
     154             :   // ######################################################################
     155             :   //! Called before a type is serialized to set up any special archive state
     156             :   //! for processing some type
     157             :   /*! If designing a serializer that needs to set up any kind of special
     158             :       state or output extra information for a type, specialize this function
     159             :       for the archive type and the types that require the extra information.
     160             :       @ingroup Internal */
     161             :   template <class Archive, class T> inline
     162    17830246 :   void prologue( Archive & /* archive */, T const & /* data */)
     163    17830246 :   { }
     164             : 
     165             :   //! Called after a type is serialized to tear down any special archive state
     166             :   //! for processing some type
     167             :   /*! @ingroup Internal */
     168             :   template <class Archive, class T> inline
     169    17829446 :   void epilogue( Archive & /* archive */, T const & /* data */)
     170    17829446 :   { }
     171             : 
     172             :   // ######################################################################
     173             :   //! Special flags for archives
     174             :   /*! AllowEmptyClassElision
     175             :         This allows for empty classes to be serialized even if they do not provide
     176             :         a serialization function.  Classes with no data members are considered to be
     177             :         empty.  Be warned that if this is enabled and you attempt to serialize an
     178             :         empty class with improperly formed serialize or load/save functions, no
     179             :         static error will occur - the error will propogate silently and your
     180             :         intended serialization functions may not be called.  You can manually
     181             :         ensure that your classes that have custom serialization are correct
     182             :         by using the traits is_output_serializable and is_input_serializable
     183             :         in cereal/details/traits.hpp.
     184             :       @ingroup Internal */
     185             :   enum Flags { AllowEmptyClassElision = 1 };
     186             : 
     187             :   // ######################################################################
     188             :   //! Registers a specific Archive type with cereal
     189             :   /*! This registration should be done once per archive.  A good place to
     190             :       put this is immediately following the definition of your archive.
     191             :       Archive registration is only strictly necessary if you wish to
     192             :       support pointers to polymorphic data types.  All archives that
     193             :       come with cereal are already registered.
     194             :       @ingroup Internal */
     195             :   #define CEREAL_REGISTER_ARCHIVE(Archive)                              \
     196             :   namespace cereal { namespace detail {                                 \
     197             :   template <class T, class BindingTag>                                  \
     198             :   typename polymorphic_serialization_support<Archive, T>::type          \
     199             :   instantiate_polymorphic_binding( T*, Archive*, BindingTag, adl_tag ); \
     200             :   } } /* end namespaces */
     201             : 
     202             :   //! Helper macro to omit unused warning
     203             :   #if defined(__GNUC__)
     204             :     // GCC / clang don't want the function
     205             :     #define CEREAL_UNUSED_FUNCTION
     206             :   #else
     207             :     #define CEREAL_UNUSED_FUNCTION static void unused() { (void)version; }
     208             :   #endif
     209             : 
     210             :   // ######################################################################
     211             :   //! Defines a class version for some type
     212             :   /*! Versioning information is optional and adds some small amount of
     213             :       overhead to serialization.  This overhead will occur both in terms of
     214             :       space in the archive (the version information for each class will be
     215             :       stored exactly once) as well as runtime (versioned serialization functions
     216             :       must check to see if they need to load or store version information).
     217             : 
     218             :       Versioning is useful if you plan on fundamentally changing the way some
     219             :       type is serialized in the future.  Versioned serialization functions
     220             :       cannot be used to load non-versioned data.
     221             : 
     222             :       By default, all types have an assumed version value of zero.  By
     223             :       using this macro, you may change the version number associated with
     224             :       some type.  cereal will then use this value as a second parameter
     225             :       to your serialization functions.
     226             : 
     227             :       The interface for the serialization functions is nearly identical
     228             :       to non-versioned serialization with the addition of a second parameter,
     229             :       const std::uint32_t version, which will be supplied with the correct
     230             :       version number.  Serializing the version number on a save happens
     231             :       automatically.
     232             : 
     233             :       Versioning cannot be mixed with non-versioned serialization functions.
     234             :       Having both types will result result in a compile time error.  Data
     235             :       serialized without versioning cannot be loaded by a serialization
     236             :       function with added versioning support.
     237             : 
     238             :       Example interface for versioning on a non-member serialize function:
     239             : 
     240             :       @code{cpp}
     241             :       CEREAL_CLASS_VERSION( Mytype, 77 ); // register class version
     242             : 
     243             :       template <class Archive>
     244             :       void serialize( Archive & ar, Mytype & t, const std::uint32_t version )
     245             :       {
     246             :         // When performing a load, the version associated with the class
     247             :         // is whatever it was when that data was originally serialized
     248             :         //
     249             :         // When we save, we'll use the version that is defined in the macro
     250             : 
     251             :         if( version >= some_number )
     252             :           // do this
     253             :         else
     254             :           // do that
     255             :       }
     256             :       @endcode
     257             : 
     258             :       Interfaces for other forms of serialization functions is similar.  This
     259             :       macro should be placed at global scope.
     260             :       @ingroup Utility */
     261             : 
     262             :   //! On C++17, define the StaticObject as inline to merge the definitions across TUs
     263             :   //! This prevents multiple definition errors when this macro appears in a header file
     264             :   //! included in multiple TUs.
     265             :   #ifdef CEREAL_HAS_CPP17
     266             :   #define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER)                             \
     267             :   namespace cereal { namespace detail {                                          \
     268             :     template <> struct Version<TYPE>                                             \
     269             :     {                                                                            \
     270             :       static std::uint32_t registerVersion()                                     \
     271             :       {                                                                          \
     272             :         ::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
     273             :              std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER );        \
     274             :         return VERSION_NUMBER;                                                   \
     275             :       }                                                                          \
     276             :       static inline const std::uint32_t version = registerVersion();             \
     277             :       CEREAL_UNUSED_FUNCTION                                                     \
     278             :     }; /* end Version */                                                         \
     279             :   } } // end namespaces
     280             :   #else
     281             :   #define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER)                             \
     282             :   namespace cereal { namespace detail {                                          \
     283             :     template <> struct Version<TYPE>                                             \
     284             :     {                                                                            \
     285             :       static const std::uint32_t version;                                        \
     286             :       static std::uint32_t registerVersion()                                     \
     287             :       {                                                                          \
     288             :         ::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
     289             :              std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER );        \
     290             :         return VERSION_NUMBER;                                                   \
     291             :       }                                                                          \
     292             :       CEREAL_UNUSED_FUNCTION                                                     \
     293             :     }; /* end Version */                                                         \
     294             :     const std::uint32_t Version<TYPE>::version =                                 \
     295             :       Version<TYPE>::registerVersion();                                          \
     296             :   } } // end namespaces
     297             : 
     298             :   #endif
     299             : 
     300             :   // ######################################################################
     301             :   //! The base output archive class
     302             :   /*! This is the base output archive for all output archives.  If you create
     303             :       a custom archive class, it should derive from this, passing itself as
     304             :       a template parameter for the ArchiveType.
     305             : 
     306             :       The base class provides all of the functionality necessary to
     307             :       properly forward data to the correct serialization functions.
     308             : 
     309             :       Individual archives should use a combination of prologue and
     310             :       epilogue functions together with specializations of serialize, save,
     311             :       and load to alter the functionality of their serialization.
     312             : 
     313             :       @tparam ArchiveType The archive type that derives from OutputArchive
     314             :       @tparam Flags Flags to control advanced functionality.  See the Flags
     315             :                     enum for more information.
     316             :       @ingroup Internal */
     317             :   template<class ArchiveType, std::uint32_t Flags = 0>
     318             :   class OutputArchive : public detail::OutputArchiveBase
     319             :   {
     320             :     public:
     321             :       //! Construct the output archive
     322             :       /*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
     323       15160 :       OutputArchive(ArchiveType * const derived) : self(derived), itsCurrentPointerId(1), itsCurrentPolymorphicTypeId(1)
     324       15160 :       { }
     325             : 
     326             :       OutputArchive & operator=( OutputArchive const & ) = delete;
     327             : 
     328             :       //! Serializes all passed in data
     329             :       /*! This is the primary interface for serializing data with an archive */
     330             :       template <class ... Types> inline
     331    13012362 :       ArchiveType & operator()( Types && ... args )
     332             :       {
     333    13012362 :         self->process( std::forward<Types>( args )... );
     334    13012362 :         return *self;
     335             :       }
     336             : 
     337             :       //! Serializes any data marked for deferment using defer
     338             :       /*! This will cause any data wrapped in DeferredData to be immediately serialized */
     339         400 :       void serializeDeferments()
     340             :       {
     341        4400 :         for( auto & deferment : itsDeferments )
     342        4000 :           deferment();
     343         400 :       }
     344             : 
     345             :       /*! @name Boost Transition Layer
     346             :           Functionality that mirrors the syntax for Boost.  This is useful if you are transitioning
     347             :           a large project from Boost to cereal.  The preferred interface for cereal is using operator(). */
     348             :       //! @{
     349             : 
     350             :       //! Indicates this archive is not intended for loading
     351             :       /*! This ensures compatibility with boost archive types.  If you are transitioning
     352             :           from boost, you can check this value within a member or external serialize function
     353             :           (i.e., Archive::is_loading::value) to disable behavior specific to loading, until
     354             :           you can transition to split save/load or save_minimal/load_minimal functions */
     355             :       using is_loading = std::false_type;
     356             : 
     357             :       //! Indicates this archive is intended for saving
     358             :       /*! This ensures compatibility with boost archive types.  If you are transitioning
     359             :           from boost, you can check this value within a member or external serialize function
     360             :           (i.e., Archive::is_saving::value) to enable behavior specific to loading, until
     361             :           you can transition to split save/load or save_minimal/load_minimal functions */
     362             :       using is_saving = std::true_type;
     363             : 
     364             :       //! Serializes passed in data
     365             :       /*! This is a boost compatability layer and is not the preferred way of using
     366             :           cereal.  If you are transitioning from boost, use this until you can
     367             :           transition to the operator() overload */
     368             :       template <class T> inline
     369             :       ArchiveType & operator&( T && arg )
     370             :       {
     371             :         self->process( std::forward<T>( arg ) );
     372             :         return *self;
     373             :       }
     374             : 
     375             :       //! Serializes passed in data
     376             :       /*! This is a boost compatability layer and is not the preferred way of using
     377             :           cereal.  If you are transitioning from boost, use this until you can
     378             :           transition to the operator() overload */
     379             :       template <class T> inline
     380             :       ArchiveType & operator<<( T && arg )
     381             :       {
     382             :         self->process( std::forward<T>( arg ) );
     383             :         return *self;
     384             :       }
     385             : 
     386             :       //! @}
     387             : 
     388             :       //! Registers a shared pointer with the archive
     389             :       /*! This function is used to track shared pointer targets to prevent
     390             :           unnecessary saves from taking place if multiple shared pointers
     391             :           point to the same data.
     392             : 
     393             :           @internal
     394             :           @param sharedPointer The shared pointer itself (the adress is taked via get()).
     395             :                                The archive takes a copy to prevent the memory location to be freed
     396             :                                as long as the address is used as id. This is needed to prevent CVE-2020-11105.
     397             :           @return A key that uniquely identifies the pointer */
     398       94224 :       inline std::uint32_t registerSharedPointer(const std::shared_ptr<const void>& sharedPointer)
     399             :       {
     400       94224 :         void const * addr = sharedPointer.get();
     401             : 
     402             :         // Handle null pointers by just returning 0
     403       94224 :         if(addr == 0) return 0;
     404       93424 :         itsSharedPointerStorage.push_back(sharedPointer);
     405             : 
     406       93424 :         auto id = itsSharedPointerMap.find( addr );
     407       93424 :         if( id == itsSharedPointerMap.end() )
     408             :         {
     409       49608 :           auto ptrId = itsCurrentPointerId++;
     410       49608 :           itsSharedPointerMap.insert( {addr, ptrId} );
     411       49608 :           return ptrId | detail::msb_32bit; // mask MSB to be 1
     412             :         }
     413             :         else
     414       43816 :           return id->second;
     415             :       }
     416             : 
     417             :       //! Registers a polymorphic type name with the archive
     418             :       /*! This function is used to track polymorphic types to prevent
     419             :           unnecessary saves of identifying strings used by the polymorphic
     420             :           support functionality.
     421             : 
     422             :           @internal
     423             :           @param name The name to associate with a polymorphic type
     424             :           @return A key that uniquely identifies the polymorphic type name */
     425        5600 :       inline std::uint32_t registerPolymorphicType( char const * name )
     426             :       {
     427        5600 :         auto id = itsPolymorphicTypeMap.find( name );
     428        5600 :         if( id == itsPolymorphicTypeMap.end() )
     429             :         {
     430        1600 :           auto polyId = itsCurrentPolymorphicTypeId++;
     431        1600 :           itsPolymorphicTypeMap.insert( {name, polyId} );
     432        1600 :           return polyId | detail::msb_32bit; // mask MSB to be 1
     433             :         }
     434             :         else
     435        4000 :           return id->second;
     436             :       }
     437             : 
     438             :     private:
     439             :       //! Serializes data after calling prologue, then calls epilogue
     440             :       template <class T> inline
     441    18166766 :       void process( T && head )
     442             :       {
     443    18166766 :         prologue( *self, head );
     444    18166766 :         self->processImpl( head );
     445    18166766 :         epilogue( *self, head );
     446    18166766 :       }
     447             : 
     448             :       //! Unwinds to process all data
     449             :       template <class T, class ... Other> inline
     450     5139204 :       void process( T && head, Other && ... tail )
     451             :       {
     452     5139204 :         self->process( std::forward<T>( head ) );
     453     5139204 :         self->process( std::forward<Other>( tail )... );
     454     5139204 :       }
     455             : 
     456             :       //! Serialization of a virtual_base_class wrapper
     457             :       /*! \sa virtual_base_class */
     458             :       template <class T> inline
     459        1600 :       ArchiveType & processImpl(virtual_base_class<T> const & b)
     460             :       {
     461        1600 :         traits::detail::base_class_id id(b.base_ptr);
     462        1600 :         if(itsBaseClassSet.count(id) == 0)
     463             :         {
     464         800 :           itsBaseClassSet.insert(id);
     465         800 :           self->processImpl( *b.base_ptr );
     466             :         }
     467        1600 :         return *self;
     468             :       }
     469             : 
     470             :       //! Serialization of a base_class wrapper
     471             :       /*! \sa base_class */
     472             :       template <class T> inline
     473        3200 :       ArchiveType & processImpl(base_class<T> const & b)
     474             :       {
     475        3200 :         self->processImpl( *b.base_ptr );
     476        3200 :         return *self;
     477             :       }
     478             : 
     479             :       std::vector<std::function<void(void)>> itsDeferments;
     480             : 
     481             :       template <class T> inline
     482        4000 :       ArchiveType & processImpl(DeferredData<T> const & d)
     483             :       {
     484        8000 :         std::function<void(void)> deferment( [this, d](){ self->process( d.value ); } );
     485        4000 :         itsDeferments.emplace_back( std::move(deferment) );
     486             : 
     487        8000 :         return *self;
     488             :       }
     489             : 
     490             :       //! Helper macro that expands the requirements for activating an overload
     491             :       /*! Requirements:
     492             :             Has the requested serialization function
     493             :             Does not have version and unversioned at the same time
     494             :             Is output serializable AND
     495             :               is specialized for this type of function OR
     496             :               has no specialization at all */
     497             :       #define PROCESS_IF(name)                                                             \
     498             :       traits::EnableIf<traits::has_##name<T, ArchiveType>::value,                          \
     499             :                        !traits::has_invalid_output_versioning<T, ArchiveType>::value,      \
     500             :                        (traits::is_output_serializable<T, ArchiveType>::value &&           \
     501             :                         (traits::is_specialized_##name<T, ArchiveType>::value ||           \
     502             :                          !traits::is_specialized<T, ArchiveType>::value))> = traits::sfinae
     503             : 
     504             :       //! Member serialization
     505             :       template <class T, PROCESS_IF(member_serialize)> inline
     506     2569570 :       ArchiveType & processImpl(T const & t)
     507             :       {
     508     2569570 :         access::member_serialize(*self, const_cast<T &>(t));
     509     2569570 :         return *self;
     510             :       }
     511             : 
     512             :       //! Non member serialization
     513             :       template <class T, PROCESS_IF(non_member_serialize)> inline
     514     1756792 :       ArchiveType & processImpl(T const & t)
     515             :       {
     516     1756792 :         CEREAL_SERIALIZE_FUNCTION_NAME(*self, const_cast<T &>(t));
     517     1756792 :         return *self;
     518             :       }
     519             : 
     520             :       //! Member split (save)
     521             :       template <class T, PROCESS_IF(member_save)> inline
     522      844979 :       ArchiveType & processImpl(T const & t)
     523             :       {
     524      844979 :         access::member_save(*self, t);
     525      844979 :         return *self;
     526             :       }
     527             : 
     528             :       //! Non member split (save)
     529             :       template <class T, PROCESS_IF(non_member_save)> inline
     530    12978625 :       ArchiveType & processImpl(T const & t)
     531             :       {
     532    12978625 :         CEREAL_SAVE_FUNCTION_NAME(*self, t);
     533    12978625 :         return *self;
     534             :       }
     535             : 
     536             :       //! Member split (save_minimal)
     537             :       template <class T, PROCESS_IF(member_save_minimal)> inline
     538        1200 :       ArchiveType & processImpl(T const & t)
     539             :       {
     540        1200 :         self->process( access::member_save_minimal(*self, t) );
     541        1200 :         return *self;
     542             :       }
     543             : 
     544             :       //! Non member split (save_minimal)
     545             :       template <class T, PROCESS_IF(non_member_save_minimal)> inline
     546        3200 :       ArchiveType & processImpl(T const & t)
     547             :       {
     548        3200 :         self->process( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(*self, t) );
     549        3200 :         return *self;
     550             :       }
     551             : 
     552             :       //! Empty class specialization
     553             :       template <class T, traits::EnableIf<(Flags & AllowEmptyClassElision),
     554             :                                           !traits::is_output_serializable<T, ArchiveType>::value,
     555             :                                           std::is_empty<T>::value> = traits::sfinae> inline
     556             :       ArchiveType & processImpl(T const &)
     557             :       {
     558             :         return *self;
     559             :       }
     560             : 
     561             :       //! No matching serialization
     562             :       /*! Invalid if we have invalid output versioning or
     563             :           we are not output serializable, and either
     564             :           don't allow empty class ellision or allow it but are not serializing an empty class */
     565             :       template <class T, traits::EnableIf<traits::has_invalid_output_versioning<T, ArchiveType>::value ||
     566             :                                           (!traits::is_output_serializable<T, ArchiveType>::value &&
     567             :                                            (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae> inline
     568             :       ArchiveType & processImpl(T const &)
     569             :       {
     570             :         static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value != 0,
     571             :             "cereal could not find any output serialization functions for the provided type and archive combination. \n\n "
     572             :             "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
     573             :             "Serialize functions generally have the following signature: \n\n "
     574             :             "template<class Archive> \n "
     575             :             "  void serialize(Archive & ar) \n "
     576             :             "  { \n "
     577             :             "    ar( member1, member2, member3 ); \n "
     578             :             "  } \n\n " );
     579             : 
     580             :         static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value < 2,
     581             :             "cereal found more than one compatible output serialization function for the provided type and archive combination. \n\n "
     582             :             "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
     583             :             "Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions.  \n "
     584             :             "Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
     585             :             "In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
     586             : 
     587             :         return *self;
     588             :       }
     589             : 
     590             :       //! Registers a class version with the archive and serializes it if necessary
     591             :       /*! If this is the first time this class has been serialized, we will record its
     592             :           version number and serialize that.
     593             : 
     594             :           @tparam T The type of the class being serialized */
     595             :       template <class T> inline
     596        7600 :       std::uint32_t registerClassVersion()
     597             :       {
     598        7600 :         static const auto hash = std::type_index(typeid(T)).hash_code();
     599        7600 :         const auto insertResult = itsVersionedTypes.insert( hash );
     600        7600 :         const auto lock = detail::StaticObject<detail::Versions>::lock();
     601       15200 :         const auto version =
     602        7600 :           detail::StaticObject<detail::Versions>::getInstance().find( hash, detail::Version<T>::version );
     603             : 
     604        7600 :         if( insertResult.second ) // insertion took place, serialize the version number
     605        5200 :           process( make_nvp<ArchiveType>("cereal_class_version", version) );
     606             : 
     607       15200 :         return version;
     608             :       }
     609             : 
     610             :       //! Member serialization
     611             :       /*! Versioning implementation */
     612             :       template <class T, PROCESS_IF(member_versioned_serialize)> inline
     613        2800 :       ArchiveType & processImpl(T const & t)
     614             :       {
     615        2800 :         access::member_serialize(*self, const_cast<T &>(t), registerClassVersion<T>());
     616        2800 :         return *self;
     617             :       }
     618             : 
     619             :       //! Non member serialization
     620             :       /*! Versioning implementation */
     621             :       template <class T, PROCESS_IF(non_member_versioned_serialize)> inline
     622         800 :       ArchiveType & processImpl(T const & t)
     623             :       {
     624         800 :         CEREAL_SERIALIZE_FUNCTION_NAME(*self, const_cast<T &>(t), registerClassVersion<T>());
     625         800 :         return *self;
     626             :       }
     627             : 
     628             :       //! Member split (save)
     629             :       /*! Versioning implementation */
     630             :       template <class T, PROCESS_IF(member_versioned_save)> inline
     631        1200 :       ArchiveType & processImpl(T const & t)
     632             :       {
     633        1200 :         access::member_save(*self, t, registerClassVersion<T>());
     634        1200 :         return *self;
     635             :       }
     636             : 
     637             :       //! Non member split (save)
     638             :       /*! Versioning implementation */
     639             :       template <class T, PROCESS_IF(non_member_versioned_save)> inline
     640        1200 :       ArchiveType & processImpl(T const & t)
     641             :       {
     642        1200 :         CEREAL_SAVE_FUNCTION_NAME(*self, t, registerClassVersion<T>());
     643        1200 :         return *self;
     644             :       }
     645             : 
     646             :       //! Member split (save_minimal)
     647             :       /*! Versioning implementation */
     648             :       template <class T, PROCESS_IF(member_versioned_save_minimal)> inline
     649         800 :       ArchiveType & processImpl(T const & t)
     650             :       {
     651         800 :         self->process( access::member_save_minimal(*self, t, registerClassVersion<T>()) );
     652         800 :         return *self;
     653             :       }
     654             : 
     655             :       //! Non member split (save_minimal)
     656             :       /*! Versioning implementation */
     657             :       template <class T, PROCESS_IF(non_member_versioned_save_minimal)> inline
     658         800 :       ArchiveType & processImpl(T const & t)
     659             :       {
     660         800 :         self->process( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(*self, t, registerClassVersion<T>()) );
     661         800 :         return *self;
     662             :       }
     663             : 
     664             :     #undef PROCESS_IF
     665             : 
     666             :     private:
     667             :       ArchiveType * const self;
     668             : 
     669             :       //! A set of all base classes that have been serialized
     670             :       std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
     671             : 
     672             :       //! Maps from addresses to pointer ids
     673             :       std::unordered_map<void const *, std::uint32_t> itsSharedPointerMap;
     674             : 
     675             :       //! Copy of shared pointers used in #itsSharedPointerMap to make sure they are kept alive
     676             :       //  during lifetime of itsSharedPointerMap to prevent CVE-2020-11105.
     677             :       std::vector<std::shared_ptr<const void>> itsSharedPointerStorage;
     678             : 
     679             :       //! The id to be given to the next pointer
     680             :       std::uint32_t itsCurrentPointerId;
     681             : 
     682             :       //! Maps from polymorphic type name strings to ids
     683             :       std::unordered_map<char const *, std::uint32_t> itsPolymorphicTypeMap;
     684             : 
     685             :       //! The id to be given to the next polymorphic type name
     686             :       std::uint32_t itsCurrentPolymorphicTypeId;
     687             : 
     688             :       //! Keeps track of classes that have versioning information associated with them
     689             :       std::unordered_set<size_type> itsVersionedTypes;
     690             :   }; // class OutputArchive
     691             : 
     692             :   // ######################################################################
     693             :   //! The base input archive class
     694             :   /*! This is the base input archive for all input archives.  If you create
     695             :       a custom archive class, it should derive from this, passing itself as
     696             :       a template parameter for the ArchiveType.
     697             : 
     698             :       The base class provides all of the functionality necessary to
     699             :       properly forward data to the correct serialization functions.
     700             : 
     701             :       Individual archives should use a combination of prologue and
     702             :       epilogue functions together with specializations of serialize, save,
     703             :       and load to alter the functionality of their serialization.
     704             : 
     705             :       @tparam ArchiveType The archive type that derives from InputArchive
     706             :       @tparam Flags Flags to control advanced functionality.  See the Flags
     707             :                     enum for more information.
     708             :       @ingroup Internal */
     709             :   template<class ArchiveType, std::uint32_t Flags = 0>
     710             :   class InputArchive : public detail::InputArchiveBase
     711             :   {
     712             :     public:
     713             :       //! Construct the output archive
     714             :       /*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
     715       15560 :       InputArchive(ArchiveType * const derived) :
     716             :         self(derived),
     717             :         itsBaseClassSet(),
     718             :         itsSharedPointerMap(),
     719             :         itsPolymorphicTypeMap(),
     720       15560 :         itsVersionedTypes()
     721       15560 :       { }
     722             : 
     723             :       InputArchive & operator=( InputArchive const & ) = delete;
     724             : 
     725             :       //! Serializes all passed in data
     726             :       /*! This is the primary interface for serializing data with an archive */
     727             :       template <class ... Types> inline
     728    13014982 :       ArchiveType & operator()( Types && ... args )
     729             :       {
     730    13014982 :         process( std::forward<Types>( args )... );
     731    13013182 :         return *self;
     732             :       }
     733             : 
     734             :       //! Serializes any data marked for deferment using defer
     735             :       /*! This will cause any data wrapped in DeferredData to be immediately serialized */
     736         400 :       void serializeDeferments()
     737             :       {
     738        4400 :         for( auto & deferment : itsDeferments )
     739        4000 :           deferment();
     740         400 :       }
     741             : 
     742             :       /*! @name Boost Transition Layer
     743             :           Functionality that mirrors the syntax for Boost.  This is useful if you are transitioning
     744             :           a large project from Boost to cereal.  The preferred interface for cereal is using operator(). */
     745             :       //! @{
     746             : 
     747             :       //! Indicates this archive is intended for loading
     748             :       /*! This ensures compatibility with boost archive types.  If you are transitioning
     749             :           from boost, you can check this value within a member or external serialize function
     750             :           (i.e., Archive::is_loading::value) to enable behavior specific to loading, until
     751             :           you can transition to split save/load or save_minimal/load_minimal functions */
     752             :       using is_loading = std::true_type;
     753             : 
     754             :       //! Indicates this archive is not intended for saving
     755             :       /*! This ensures compatibility with boost archive types.  If you are transitioning
     756             :           from boost, you can check this value within a member or external serialize function
     757             :           (i.e., Archive::is_saving::value) to disable behavior specific to loading, until
     758             :           you can transition to split save/load or save_minimal/load_minimal functions */
     759             :       using is_saving = std::false_type;
     760             : 
     761             :       //! Serializes passed in data
     762             :       /*! This is a boost compatability layer and is not the preferred way of using
     763             :           cereal.  If you are transitioning from boost, use this until you can
     764             :           transition to the operator() overload */
     765             :       template <class T> inline
     766             :       ArchiveType & operator&( T && arg )
     767             :       {
     768             :         self->process( std::forward<T>( arg ) );
     769             :         return *self;
     770             :       }
     771             : 
     772             :       //! Serializes passed in data
     773             :       /*! This is a boost compatability layer and is not the preferred way of using
     774             :           cereal.  If you are transitioning from boost, use this until you can
     775             :           transition to the operator() overload */
     776             :       template <class T> inline
     777             :       ArchiveType & operator>>( T && arg )
     778             :       {
     779             :         self->process( std::forward<T>( arg ) );
     780             :         return *self;
     781             :       }
     782             : 
     783             :       //! @}
     784             : 
     785             :       //! Retrieves a shared pointer given a unique key for it
     786             :       /*! This is used to retrieve a previously registered shared_ptr
     787             :           which has already been loaded.
     788             : 
     789             :           @internal
     790             :           @param id The unique id that was serialized for the pointer
     791             :           @return A shared pointer to the data
     792             :           @throw Exception if the id does not exist */
     793       44616 :       inline std::shared_ptr<void> getSharedPointer(std::uint32_t const id)
     794             :       {
     795       44616 :         if(id == 0) return std::shared_ptr<void>(nullptr);
     796             : 
     797       43816 :         auto iter = itsSharedPointerMap.find( id );
     798       43816 :         if(iter == itsSharedPointerMap.end())
     799           0 :           throw Exception("Error while trying to deserialize a smart pointer. Could not find id " + std::to_string(id));
     800             : 
     801       43816 :         return iter->second;
     802             :       }
     803             : 
     804             :       //! Registers a shared pointer to its unique identifier
     805             :       /*! After a shared pointer has been allocated for the first time, it should
     806             :           be registered with its loaded id for future references to it.
     807             : 
     808             :           @internal
     809             :           @param id The unique identifier for the shared pointer
     810             :           @param ptr The actual shared pointer */
     811       49608 :       inline void registerSharedPointer(std::uint32_t const id, std::shared_ptr<void> ptr)
     812             :       {
     813       49608 :         std::uint32_t const stripped_id = id & ~detail::msb_32bit;
     814       49608 :         itsSharedPointerMap[stripped_id] = ptr;
     815       49608 :       }
     816             : 
     817             :       //! Retrieves the string for a polymorphic type given a unique key for it
     818             :       /*! This is used to retrieve a string previously registered during
     819             :           a polymorphic load.
     820             : 
     821             :           @internal
     822             :           @param id The unique id that was serialized for the polymorphic type
     823             :           @return The string identifier for the tyep */
     824        4000 :       inline std::string getPolymorphicName(std::uint32_t const id)
     825             :       {
     826        4000 :         auto name = itsPolymorphicTypeMap.find( id );
     827        4000 :         if(name == itsPolymorphicTypeMap.end())
     828             :         {
     829           0 :           throw Exception("Error while trying to deserialize a polymorphic pointer. Could not find type id " + std::to_string(id));
     830             :         }
     831        8000 :         return name->second;
     832             :       }
     833             : 
     834             :       //! Registers a polymorphic name string to its unique identifier
     835             :       /*! After a polymorphic type has been loaded for the first time, it should
     836             :           be registered with its loaded id for future references to it.
     837             : 
     838             :           @internal
     839             :           @param id The unique identifier for the polymorphic type
     840             :           @param name The name associated with the tyep */
     841        1600 :       inline void registerPolymorphicName(std::uint32_t const id, std::string const & name)
     842             :       {
     843        1600 :         std::uint32_t const stripped_id = id & ~detail::msb_32bit;
     844        1600 :         itsPolymorphicTypeMap.insert( {stripped_id, name} );
     845        1600 :       }
     846             : 
     847             :     private:
     848             :       //! Serializes data after calling prologue, then calls epilogue
     849             :       template <class T> inline
     850    18169366 :       void process( T && head )
     851             :       {
     852    18169366 :         prologue( *self, head );
     853    18169366 :         self->processImpl( head );
     854    18167566 :         epilogue( *self, head );
     855    18167566 :       }
     856             : 
     857             :       //! Unwinds to process all data
     858             :       template <class T, class ... Other> inline
     859     5139184 :       void process( T && head, Other && ... tail )
     860             :       {
     861     5139184 :         process( std::forward<T>( head ) );
     862     5139184 :         process( std::forward<Other>( tail )... );
     863     5139184 :       }
     864             : 
     865             :       //! Serialization of a virtual_base_class wrapper
     866             :       /*! \sa virtual_base_class */
     867             :       template <class T> inline
     868        1600 :       ArchiveType & processImpl(virtual_base_class<T> & b)
     869             :       {
     870        1600 :         traits::detail::base_class_id id(b.base_ptr);
     871        1600 :         if(itsBaseClassSet.count(id) == 0)
     872             :         {
     873         800 :           itsBaseClassSet.insert(id);
     874         800 :           self->processImpl( *b.base_ptr );
     875             :         }
     876        1600 :         return *self;
     877             :       }
     878             : 
     879             :       //! Serialization of a base_class wrapper
     880             :       /*! \sa base_class */
     881             :       template <class T> inline
     882        3200 :       ArchiveType & processImpl(base_class<T> & b)
     883             :       {
     884        3200 :         self->processImpl( *b.base_ptr );
     885        3200 :         return *self;
     886             :       }
     887             : 
     888             :       std::vector<std::function<void(void)>> itsDeferments;
     889             : 
     890             :       template <class T> inline
     891        4000 :       ArchiveType & processImpl(DeferredData<T> const & d)
     892             :       {
     893        8000 :         std::function<void(void)> deferment( [this, d](){ self->process( d.value ); } );
     894        4000 :         itsDeferments.emplace_back( std::move(deferment) );
     895             : 
     896        8000 :         return *self;
     897             :       }
     898             : 
     899             :       //! Helper macro that expands the requirements for activating an overload
     900             :       /*! Requirements:
     901             :             Has the requested serialization function
     902             :             Does not have version and unversioned at the same time
     903             :             Is input serializable AND
     904             :               is specialized for this type of function OR
     905             :               has no specialization at all */
     906             :       #define PROCESS_IF(name)                                                              \
     907             :       traits::EnableIf<traits::has_##name<T, ArchiveType>::value,                           \
     908             :                        !traits::has_invalid_input_versioning<T, ArchiveType>::value,        \
     909             :                        (traits::is_input_serializable<T, ArchiveType>::value &&             \
     910             :                         (traits::is_specialized_##name<T, ArchiveType>::value ||            \
     911             :                          !traits::is_specialized<T, ArchiveType>::value))> = traits::sfinae
     912             : 
     913             :       //! Member serialization
     914             :       template <class T, PROCESS_IF(member_serialize)> inline
     915     2571570 :       ArchiveType & processImpl(T & t)
     916             :       {
     917     2571570 :         access::member_serialize(*self, t);
     918     2571170 :         return *self;
     919             :       }
     920             : 
     921             :       //! Non member serialization
     922             :       template <class T, PROCESS_IF(non_member_serialize)> inline
     923     1757092 :       ArchiveType & processImpl(T & t)
     924             :       {
     925     1757092 :         CEREAL_SERIALIZE_FUNCTION_NAME(*self, t);
     926     1756892 :         return *self;
     927             :       }
     928             : 
     929             :       //! Member split (load)
     930             :       template <class T, PROCESS_IF(member_load)> inline
     931      844979 :       ArchiveType & processImpl(T & t)
     932             :       {
     933      844979 :         access::member_load(*self, t);
     934      844979 :         return *self;
     935             :       }
     936             : 
     937             :       //! Non member split (load)
     938             :       template <class T, PROCESS_IF(non_member_load)> inline
     939    12980525 :       ArchiveType & processImpl(T & t)
     940             :       {
     941    12980525 :         CEREAL_LOAD_FUNCTION_NAME(*self, t);
     942    12979325 :         return *self;
     943             :       }
     944             : 
     945             :       //! Member split (load_minimal)
     946             :       template <class T, PROCESS_IF(member_load_minimal)> inline
     947        1200 :       ArchiveType & processImpl(T & t)
     948             :       {
     949             :         using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
     950         600 :         typename traits::has_member_save_minimal<T, OutArchiveType>::type value;
     951        1200 :         self->process( value );
     952        1200 :         access::member_load_minimal(*self, t, value);
     953        1800 :         return *self;
     954             :       }
     955             : 
     956             :       //! Non member split (load_minimal)
     957             :       template <class T, PROCESS_IF(non_member_load_minimal)> inline
     958        3200 :       ArchiveType & processImpl(T & t)
     959             :       {
     960             :         using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
     961         200 :         typename traits::has_non_member_save_minimal<T, OutArchiveType>::type value;
     962        3200 :         self->process( value );
     963        3200 :         CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value);
     964        3400 :         return *self;
     965             :       }
     966             : 
     967             :       //! Empty class specialization
     968             :       template <class T, traits::EnableIf<(Flags & AllowEmptyClassElision),
     969             :                                           !traits::is_input_serializable<T, ArchiveType>::value,
     970             :                                           std::is_empty<T>::value> = traits::sfinae> inline
     971             :       ArchiveType & processImpl(T const &)
     972             :       {
     973             :         return *self;
     974             :       }
     975             : 
     976             :       //! No matching serialization
     977             :       /*! Invalid if we have invalid input versioning or
     978             :           we are not input serializable, and either
     979             :           don't allow empty class ellision or allow it but are not serializing an empty class */
     980             :       template <class T, traits::EnableIf<traits::has_invalid_input_versioning<T, ArchiveType>::value ||
     981             :                                           (!traits::is_input_serializable<T, ArchiveType>::value &&
     982             :                                            (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae> inline
     983             :       ArchiveType & processImpl(T const &)
     984             :       {
     985             :         static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value != 0,
     986             :             "cereal could not find any input serialization functions for the provided type and archive combination. \n\n "
     987             :             "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
     988             :             "Serialize functions generally have the following signature: \n\n "
     989             :             "template<class Archive> \n "
     990             :             "  void serialize(Archive & ar) \n "
     991             :             "  { \n "
     992             :             "    ar( member1, member2, member3 ); \n "
     993             :             "  } \n\n " );
     994             : 
     995             :         static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value < 2,
     996             :             "cereal found more than one compatible input serialization function for the provided type and archive combination. \n\n "
     997             :             "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
     998             :             "Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions.  \n "
     999             :             "Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
    1000             :             "In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
    1001             : 
    1002             :         return *self;
    1003             :       }
    1004             : 
    1005             :       //! Befriend for versioning in load_and_construct
    1006             :       template <class A, class B, bool C, bool D, bool E, bool F> friend struct detail::Construct;
    1007             : 
    1008             :       //! Registers a class version with the archive and serializes it if necessary
    1009             :       /*! If this is the first time this class has been serialized, we will record its
    1010             :           version number and serialize that.
    1011             : 
    1012             :           @tparam T The type of the class being serialized */
    1013             :       template <class T> inline
    1014        7600 :       std::uint32_t loadClassVersion()
    1015             :       {
    1016        7600 :         static const auto hash = std::type_index(typeid(T)).hash_code();
    1017        7600 :         auto lookupResult = itsVersionedTypes.find( hash );
    1018             : 
    1019        7600 :         if( lookupResult != itsVersionedTypes.end() ) // already exists
    1020        2400 :           return lookupResult->second;
    1021             :         else // need to load
    1022             :         {
    1023             :           std::uint32_t version;
    1024             : 
    1025        5200 :           process( make_nvp<ArchiveType>("cereal_class_version", version) );
    1026        5200 :           itsVersionedTypes.emplace_hint( lookupResult, hash, version );
    1027             : 
    1028        5200 :           return version;
    1029             :         }
    1030             :       }
    1031             : 
    1032             :       //! Member serialization
    1033             :       /*! Versioning implementation */
    1034             :       template <class T, PROCESS_IF(member_versioned_serialize)> inline
    1035        1200 :       ArchiveType & processImpl(T & t)
    1036             :       {
    1037        1200 :         const auto version = loadClassVersion<T>();
    1038        1200 :         access::member_serialize(*self, t, version);
    1039        1200 :         return *self;
    1040             :       }
    1041             : 
    1042             :       //! Non member serialization
    1043             :       /*! Versioning implementation */
    1044             :       template <class T, PROCESS_IF(non_member_versioned_serialize)> inline
    1045         800 :       ArchiveType & processImpl(T & t)
    1046             :       {
    1047         800 :         const auto version = loadClassVersion<T>();
    1048         800 :         CEREAL_SERIALIZE_FUNCTION_NAME(*self, t, version);
    1049         800 :         return *self;
    1050             :       }
    1051             : 
    1052             :       //! Member split (load)
    1053             :       /*! Versioning implementation */
    1054             :       template <class T, PROCESS_IF(member_versioned_load)> inline
    1055        1200 :       ArchiveType & processImpl(T & t)
    1056             :       {
    1057        1200 :         const auto version = loadClassVersion<T>();
    1058        1200 :         access::member_load(*self, t, version);
    1059        1200 :         return *self;
    1060             :       }
    1061             : 
    1062             :       //! Non member split (load)
    1063             :       /*! Versioning implementation */
    1064             :       template <class T, PROCESS_IF(non_member_versioned_load)> inline
    1065        1200 :       ArchiveType & processImpl(T & t)
    1066             :       {
    1067        1200 :         const auto version = loadClassVersion<T>();
    1068        1200 :         CEREAL_LOAD_FUNCTION_NAME(*self, t, version);
    1069        1200 :         return *self;
    1070             :       }
    1071             : 
    1072             :       //! Member split (load_minimal)
    1073             :       /*! Versioning implementation */
    1074             :       template <class T, PROCESS_IF(member_versioned_load_minimal)> inline
    1075         800 :       ArchiveType & processImpl(T & t)
    1076             :       {
    1077             :         using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
    1078         800 :         const auto version = loadClassVersion<T>();
    1079             :         typename traits::has_member_versioned_save_minimal<T, OutArchiveType>::type value;
    1080         800 :         self->process(value);
    1081         800 :         access::member_load_minimal(*self, t, value, version);
    1082         800 :         return *self;
    1083             :       }
    1084             : 
    1085             :       //! Non member split (load_minimal)
    1086             :       /*! Versioning implementation */
    1087             :       template <class T, PROCESS_IF(non_member_versioned_load_minimal)> inline
    1088         800 :       ArchiveType & processImpl(T & t)
    1089             :       {
    1090             :         using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
    1091         800 :         const auto version = loadClassVersion<T>();
    1092             :         typename traits::has_non_member_versioned_save_minimal<T, OutArchiveType>::type value;
    1093         800 :         self->process(value);
    1094         800 :         CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value, version);
    1095         800 :         return *self;
    1096             :       }
    1097             : 
    1098             :       #undef PROCESS_IF
    1099             : 
    1100             :     private:
    1101             :       ArchiveType * const self;
    1102             : 
    1103             :       //! A set of all base classes that have been serialized
    1104             :       std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
    1105             : 
    1106             :       //! Maps from pointer ids to metadata
    1107             :       std::unordered_map<std::uint32_t, std::shared_ptr<void>> itsSharedPointerMap;
    1108             : 
    1109             :       //! Maps from name ids to names
    1110             :       std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap;
    1111             : 
    1112             :       //! Maps from type hash codes to version numbers
    1113             :       std::unordered_map<std::size_t, std::uint32_t> itsVersionedTypes;
    1114             :   }; // class InputArchive
    1115             : } // namespace cereal
    1116             : 
    1117             : // This include needs to come after things such as binary_data, make_nvp, etc
    1118             : #include "cereal/types/common.hpp"
    1119             : 
    1120             : #endif // CEREAL_CEREAL_HPP_

Generated by: LCOV version 1.14