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