LCOV - code coverage report
Current view: top level - cereal - cereal.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 193 195 99.0 %
Date: 2017-02-12 13:57:59 Functions: 10275 10521 97.7 %

          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 cereal 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 RANDOLPH VOORHIES OR SHANE GRANT 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 <unordered_map>
      36             : #include <unordered_set>
      37             : #include <vector>
      38             : #include <cstddef>
      39             : #include <cstdint>
      40             : #include <functional>
      41             : 
      42             : #include "cereal/macros.hpp"
      43             : #include "cereal/details/traits.hpp"
      44             : #include "cereal/details/helpers.hpp"
      45             : #include "cereal/types/base_class.hpp"
      46             : 
      47             : namespace cereal
      48             : {
      49             :   // ######################################################################
      50             :   //! Creates a name value pair
      51             :   /*! @relates NameValuePair
      52             :       @ingroup Utility */
      53             :   template <class T> inline
      54        2600 :   NameValuePair<T> make_nvp( std::string const & name, T && value )
      55             :   {
      56        2600 :     return {name.c_str(), std::forward<T>(value)};
      57             :   }
      58             : 
      59             :   //! Creates a name value pair
      60             :   /*! @relates NameValuePair
      61             :       @ingroup Utility */
      62             :   template <class T> inline
      63        1400 :   NameValuePair<T> make_nvp( const char * name, T && value )
      64             :   {
      65        1400 :     return {name, std::forward<T>(value)};
      66             :   }
      67             : 
      68             :   //! Creates a name value pair for the variable T with the same name as the variable
      69             :   /*! @relates NameValuePair
      70             :       @ingroup Utility */
      71             :   #define CEREAL_NVP(T) ::cereal::make_nvp(#T, T)
      72             : 
      73             :   // ######################################################################
      74             :   //! Convenience function to create binary data for both const and non const pointers
      75             :   /*! @param data Pointer to beginning of the data
      76             :       @param size The size in bytes of the data
      77             :       @relates BinaryData
      78             :       @ingroup Utility */
      79             :   template <class T> inline
      80      246804 :   BinaryData<T> binary_data( T && data, size_t size )
      81             :   {
      82      246804 :     return {std::forward<T>(data), size};
      83             :   }
      84             : 
      85             :   // ######################################################################
      86             :   //! Creates a size tag from some variable.
      87             :   /*! Will normally be used to serialize size (e.g. size()) information for
      88             :       variable size containers.  If you have a variable sized container,
      89             :       the very first thing it serializes should be its size, wrapped in
      90             :       a SizeTag.
      91             : 
      92             :       @relates SizeTag
      93             :       @ingroup Utility */
      94             :   template <class T> inline
      95      321604 :   SizeTag<T> make_size_tag( T && sz )
      96             :   {
      97      321604 :     return {std::forward<T>(sz)};
      98             :   }
      99             : 
     100             :   // ######################################################################
     101             :   //! Called before a type is serialized to set up any special archive state
     102             :   //! for processing some type
     103             :   /*! If designing a serializer that needs to set up any kind of special
     104             :       state or output extra information for a type, specialize this function
     105             :       for the archive type and the types that require the extra information.
     106             :       @ingroup Internal */
     107             :   template <class Archive, class T> inline
     108    17337856 :   void prologue( Archive & /* archive */, T const & /* data */)
     109    17337856 :   { }
     110             : 
     111             :   //! Called after a type is serialized to tear down any special archive state
     112             :   //! for processing some type
     113             :   /*! @ingroup Internal */
     114             :   template <class Archive, class T> inline
     115    17337056 :   void epilogue( Archive & /* archive */, T const & /* data */)
     116    17337056 :   { }
     117             : 
     118             :   // ######################################################################
     119             :   //! Special flags for archives
     120             :   /*! AllowEmptyClassElision
     121             :         This allows for empty classes to be serialized even if they do not provide
     122             :         a serialization function.  Classes with no data members are considered to be
     123             :         empty.  Be warned that if this is enabled and you attempt to serialize an
     124             :         empty class with improperly formed serialize or load/save functions, no
     125             :         static error will occur - the error will propogate silently and your
     126             :         intended serialization functions may not be called.  You can manually
     127             :         ensure that your classes that have custom serialization are correct
     128             :         by using the traits is_output_serializable and is_input_serializable
     129             :         in cereal/details/traits.hpp.
     130             :       @ingroup Internal */
     131             :   enum Flags { AllowEmptyClassElision = 1 };
     132             : 
     133             :   // ######################################################################
     134             :   //! Registers a specific Archive type with cereal
     135             :   /*! This registration should be done once per archive.  A good place to
     136             :       put this is immediately following the definition of your archive.
     137             :       Archive registration is only strictly necessary if you wish to
     138             :       support pointers to polymorphic data types.  All archives that
     139             :       come with cereal are already registered.
     140             :       @ingroup Internal */
     141             :   #define CEREAL_REGISTER_ARCHIVE(Archive)                              \
     142             :   namespace cereal { namespace detail {                                 \
     143             :   template <class T, class BindingTag>                                  \
     144             :   typename polymorphic_serialization_support<Archive, T>::type          \
     145             :   instantiate_polymorphic_binding( T*, Archive*, BindingTag, adl_tag ); \
     146             :   } } /* end namespaces */
     147             : 
     148             :   // ######################################################################
     149             :   //! Defines a class version for some type
     150             :   /*! Versioning information is optional and adds some small amount of
     151             :       overhead to serialization.  This overhead will occur both in terms of
     152             :       space in the archive (the version information for each class will be
     153             :       stored exactly once) as well as runtime (versioned serialization functions
     154             :       must check to see if they need to load or store version information).
     155             : 
     156             :       Versioning is useful if you plan on fundamentally changing the way some
     157             :       type is serialized in the future.  Versioned serialization functions
     158             :       cannot be used to load non-versioned data.
     159             : 
     160             :       By default, all types have an assumed version value of zero.  By
     161             :       using this macro, you may change the version number associated with
     162             :       some type.  cereal will then use this value as a second parameter
     163             :       to your serialization functions.
     164             : 
     165             :       The interface for the serialization functions is nearly identical
     166             :       to non-versioned serialization with the addition of a second parameter,
     167             :       const std::uint32_t version, which will be supplied with the correct
     168             :       version number.  Serializing the version number on a save happens
     169             :       automatically.
     170             : 
     171             :       Versioning cannot be mixed with non-versioned serialization functions.
     172             :       Having both types will result result in a compile time error.  Data
     173             :       serialized without versioning cannot be loaded by a serialization
     174             :       function with added versioning support.
     175             : 
     176             :       Example interface for versioning on a non-member serialize function:
     177             : 
     178             :       @code{cpp}
     179             :       CEREAL_CLASS_VERSION( Mytype, 77 ); // register class version
     180             : 
     181             :       template <class Archive>
     182             :       void serialize( Archive & ar, Mytype & t, const std::uint32_t version )
     183             :       {
     184             :         // When performing a load, the version associated with the class
     185             :         // is whatever it was when that data was originally serialized
     186             :         //
     187             :         // When we save, we'll use the version that is defined in the macro
     188             : 
     189             :         if( version >= some_number )
     190             :           // do this
     191             :         else
     192             :           // do that
     193             :       }
     194             :       @endcode
     195             : 
     196             :       Interfaces for other forms of serialization functions is similar.  This
     197             :       macro should be placed at global scope.
     198             :       @ingroup Utility */
     199             :   #define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER)                             \
     200             :   namespace cereal { namespace detail {                                          \
     201             :     template <> struct Version<TYPE>                                             \
     202             :     {                                                                            \
     203             :       static const std::uint32_t version;                                        \
     204             :       static std::uint32_t registerVersion()                                     \
     205             :       {                                                                          \
     206             :         ::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
     207             :              std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER );        \
     208             :         return VERSION_NUMBER;                                                   \
     209             :       }                                                                          \
     210             :       static void unused() { (void)version; }                                    \
     211             :     }; /* end Version */                                                         \
     212             :     const std::uint32_t Version<TYPE>::version =                                 \
     213             :       Version<TYPE>::registerVersion();                                          \
     214             :   } } // end namespaces
     215             : 
     216             :   // ######################################################################
     217             :   //! The base output archive class
     218             :   /*! This is the base output archive for all output archives.  If you create
     219             :       a custom archive class, it should derive from this, passing itself as
     220             :       a template parameter for the ArchiveType.
     221             : 
     222             :       The base class provides all of the functionality necessary to
     223             :       properly forward data to the correct serialization functions.
     224             : 
     225             :       Individual archives should use a combination of prologue and
     226             :       epilogue functions together with specializations of serialize, save,
     227             :       and load to alter the functionality of their serialization.
     228             : 
     229             :       @tparam ArchiveType The archive type that derives from OutputArchive
     230             :       @tparam Flags Flags to control advanced functionality.  See the Flags
     231             :                     enum for more information.
     232             :       @ingroup Internal */
     233             :   template<class ArchiveType, std::uint32_t Flags = 0>
     234       14352 :   class OutputArchive : public detail::OutputArchiveBase
     235             :   {
     236             :     public:
     237             :       //! Construct the output archive
     238             :       /*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
     239       14352 :       OutputArchive(ArchiveType * const derived) : self(derived), itsCurrentPointerId(1), itsCurrentPolymorphicTypeId(1)
     240       14352 :       { }
     241             : 
     242             :       OutputArchive & operator=( OutputArchive const & ) = delete;
     243             : 
     244             :       //! Serializes all passed in data
     245             :       /*! This is the primary interface for serializing data with an archive */
     246             :       template <class ... Types> inline
     247    12654143 :       ArchiveType & operator()( Types && ... args )
     248             :       {
     249    12654143 :         self->process( std::forward<Types>( args )... );
     250    12654143 :         return *self;
     251             :       }
     252             : 
     253             :       /*! @name Boost Transition Layer
     254             :           Functionality that mirrors the syntax for Boost.  This is useful if you are transitioning
     255             :           a large project from Boost to cereal.  The preferred interface for cereal is using operator(). */
     256             :       //! @{
     257             : 
     258             :       //! Indicates this archive is not intended for loading
     259             :       /*! This ensures compatibility with boost archive types.  If you are transitioning
     260             :           from boost, you can check this value within a member or external serialize function
     261             :           (i.e., Archive::is_loading::value) to disable behavior specific to loading, until 
     262             :           you can transition to split save/load or save_minimal/load_minimal functions */
     263             :       using is_loading = std::false_type;
     264             : 
     265             :       //! Indicates this archive is intended for saving
     266             :       /*! This ensures compatibility with boost archive types.  If you are transitioning
     267             :           from boost, you can check this value within a member or external serialize function
     268             :           (i.e., Archive::is_saving::value) to enable behavior specific to loading, until 
     269             :           you can transition to split save/load or save_minimal/load_minimal functions */
     270             :       using is_saving = std::true_type;
     271             : 
     272             :       //! Serializes passed in data
     273             :       /*! This is a boost compatability layer and is not the preferred way of using
     274             :           cereal.  If you are transitioning from boost, use this until you can
     275             :           transition to the operator() overload */
     276             :       template <class T> inline
     277             :       ArchiveType & operator&( T && arg )
     278             :       {
     279             :         self->process( std::forward<T>( arg ) );
     280             :         return *self;
     281             :       }
     282             : 
     283             :       //! Serializes passed in data
     284             :       /*! This is a boost compatability layer and is not the preferred way of using
     285             :           cereal.  If you are transitioning from boost, use this until you can
     286             :           transition to the operator() overload */
     287             :       template <class T> inline
     288             :       ArchiveType & operator<<( T && arg )
     289             :       {
     290             :         self->process( std::forward<T>( arg ) );
     291             :         return *self;
     292             :       }
     293             : 
     294             :       //! @}
     295             : 
     296             :       //! Registers a shared pointer with the archive
     297             :       /*! This function is used to track shared pointer targets to prevent
     298             :           unnecessary saves from taking place if multiple shared pointers
     299             :           point to the same data.
     300             : 
     301             :           @internal
     302             :           @param addr The address (see shared_ptr get()) pointed to by the shared pointer
     303             :           @return A key that uniquely identifies the pointer */
     304       48804 :       inline std::uint32_t registerSharedPointer( void const * addr )
     305             :       {
     306             :         // Handle null pointers by just returning 0
     307       48804 :         if(addr == 0) return 0;
     308             : 
     309       48004 :         auto id = itsSharedPointerMap.find( addr );
     310       48004 :         if( id == itsSharedPointerMap.end() )
     311             :         {
     312       45604 :           auto ptrId = itsCurrentPointerId++;
     313       45604 :           itsSharedPointerMap.insert( {addr, ptrId} );
     314       45604 :           return ptrId | detail::msb_32bit; // mask MSB to be 1
     315             :         }
     316             :         else
     317        2400 :           return id->second;
     318             :       }
     319             : 
     320             :       //! Registers a polymorphic type name with the archive
     321             :       /*! This function is used to track polymorphic types to prevent
     322             :           unnecessary saves of identifying strings used by the polymorphic
     323             :           support functionality.
     324             : 
     325             :           @internal
     326             :           @param name The name to associate with a polymorphic type
     327             :           @return A key that uniquely identifies the polymorphic type name */
     328        3600 :       inline std::uint32_t registerPolymorphicType( char const * name )
     329             :       {
     330        3600 :         auto id = itsPolymorphicTypeMap.find( name );
     331        3600 :         if( id == itsPolymorphicTypeMap.end() )
     332             :         {
     333        1600 :           auto polyId = itsCurrentPolymorphicTypeId++;
     334        1600 :           itsPolymorphicTypeMap.insert( {name, polyId} );
     335        1600 :           return polyId | detail::msb_32bit; // mask MSB to be 1
     336             :         }
     337             :         else
     338        2000 :           return id->second;
     339             :       }
     340             : 
     341             :     private:
     342             :       //! Serializes data after calling prologue, then calls epilogue
     343             :       template <class T> inline
     344    17711251 :       void process( T && head )
     345             :       {
     346    17711251 :         prologue( *self, head );
     347    17711251 :         self->processImpl( head );
     348    17711251 :         epilogue( *self, head );
     349    17711251 :       }
     350             : 
     351             :       //! Unwinds to process all data
     352             :       template <class T, class ... Other> inline
     353     5045908 :       void process( T && head, Other && ... tail )
     354             :       {
     355     5045908 :         self->process( std::forward<T>( head ) );
     356     5045908 :         self->process( std::forward<Other>( tail )... );
     357     5045908 :       }
     358             : 
     359             :       //! Serialization of a virtual_base_class wrapper
     360             :       /*! \sa virtual_base_class */
     361             :       template <class T> inline
     362        1600 :       ArchiveType & processImpl(virtual_base_class<T> const & b)
     363             :       {
     364        1600 :         traits::detail::base_class_id id(b.base_ptr);
     365        1600 :         if(itsBaseClassSet.count(id) == 0)
     366             :         {
     367         800 :           itsBaseClassSet.insert(id);
     368         800 :           self->processImpl( *b.base_ptr );
     369             :         }
     370        1600 :         return *self;
     371             :       }
     372             : 
     373             :       //! Serialization of a base_class wrapper
     374             :       /*! \sa base_class */
     375             :       template <class T> inline
     376        2400 :       ArchiveType & processImpl(base_class<T> const & b)
     377             :       {
     378        2400 :         self->processImpl( *b.base_ptr );
     379        2400 :         return *self;
     380             :       }
     381             : 
     382             :       //! Helper macro that expands the requirements for activating an overload
     383             :       /*! Requirements:
     384             :             Has the requested serialization function
     385             :             Does not have version and unversioned at the same time
     386             :             Is output serializable AND
     387             :               is specialized for this type of function OR
     388             :               has no specialization at all */
     389             :       #define PROCESS_IF(name)                                                             \
     390             :       traits::EnableIf<traits::has_##name<T, ArchiveType>::value,                          \
     391             :                        !traits::has_invalid_output_versioning<T, ArchiveType>::value,      \
     392             :                        (traits::is_output_serializable<T, ArchiveType>::value &&           \
     393             :                         (traits::is_specialized_##name<T, ArchiveType>::value ||           \
     394             :                          !traits::is_specialized<T, ArchiveType>::value))> = traits::sfinae
     395             : 
     396             :       //! Member serialization
     397             :       template <class T, PROCESS_IF(member_serialize)> inline
     398     2522736 :       ArchiveType & processImpl(T const & t)
     399             :       {
     400     2522736 :         access::member_serialize(*self, const_cast<T &>(t));
     401     2522736 :         return *self;
     402             :       }
     403             : 
     404             :       //! Non member serialization
     405             :       template <class T, PROCESS_IF(non_member_serialize)> inline
     406     1706629 :       ArchiveType & processImpl(T const & t)
     407             :       {
     408     1706629 :         CEREAL_SERIALIZE_FUNCTION_NAME(*self, const_cast<T &>(t));
     409     1706629 :         return *self;
     410             :       }
     411             : 
     412             :       //! Member split (save)
     413             :       template <class T, PROCESS_IF(member_save)> inline
     414      843780 :       ArchiveType & processImpl(T const & t)
     415             :       {
     416      843780 :         access::member_save(*self, t);
     417      843780 :         return *self;
     418             :       }
     419             : 
     420             :       //! Non member split (save)
     421             :       template <class T, PROCESS_IF(non_member_save)> inline
     422    12626106 :       ArchiveType & processImpl(T const & t)
     423             :       {
     424    12626106 :         CEREAL_SAVE_FUNCTION_NAME(*self, t);
     425    12626106 :         return *self;
     426             :       }
     427             : 
     428             :       //! Member split (save_minimal)
     429             :       template <class T, PROCESS_IF(member_save_minimal)> inline
     430        1200 :       ArchiveType & processImpl(T const & t)
     431             :       {
     432        1200 :         self->process( access::member_save_minimal(*self, t) );
     433        1200 :         return *self;
     434             :       }
     435             : 
     436             :       //! Non member split (save_minimal)
     437             :       template <class T, PROCESS_IF(non_member_save_minimal)> inline
     438        3200 :       ArchiveType & processImpl(T const & t)
     439             :       {
     440        3200 :         self->process( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(*self, t) );
     441        3200 :         return *self;
     442             :       }
     443             : 
     444             :       //! Empty class specialization
     445             :       template <class T, traits::EnableIf<(Flags & AllowEmptyClassElision),
     446             :                                           !traits::is_output_serializable<T, ArchiveType>::value,
     447             :                                           std::is_empty<T>::value> = traits::sfinae> inline
     448             :       ArchiveType & processImpl(T const &)
     449             :       {
     450             :         return *self;
     451             :       }
     452             : 
     453             :       //! No matching serialization
     454             :       /*! Invalid if we have invalid output versioning or
     455             :           we are not output serializable, and either
     456             :           don't allow empty class ellision or allow it but are not serializing an empty class */
     457             :       template <class T, traits::EnableIf<traits::has_invalid_output_versioning<T, ArchiveType>::value ||
     458             :                                           (!traits::is_output_serializable<T, ArchiveType>::value &&
     459             :                                            (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae> inline
     460             :       ArchiveType & processImpl(T const &)
     461             :       {
     462             :         static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value != 0,
     463             :             "cereal could not find any output serialization functions for the provided type and archive combination. \n\n "
     464             :             "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
     465             :             "Serialize functions generally have the following signature: \n\n "
     466             :             "template<class Archive> \n "
     467             :             "  void serialize(Archive & ar) \n "
     468             :             "  { \n "
     469             :             "    ar( member1, member2, member3 ); \n "
     470             :             "  } \n\n " );
     471             : 
     472             :         static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value < 2,
     473             :             "cereal found more than one compatible output serialization function for the provided type and archive combination. \n\n "
     474             :             "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
     475             :             "Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions.  \n "
     476             :             "Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
     477             :             "In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
     478             : 
     479             :         return *self;
     480             :       }
     481             : 
     482             :       //! Registers a class version with the archive and serializes it if necessary
     483             :       /*! If this is the first time this class has been serialized, we will record its
     484             :           version number and serialize that.
     485             : 
     486             :           @tparam T The type of the class being serialized
     487             :           @param version The version number associated with it */
     488             :       template <class T> inline
     489        6800 :       std::uint32_t registerClassVersion()
     490             :       {
     491        6800 :         static const auto hash = std::type_index(typeid(T)).hash_code();
     492        6800 :         const auto insertResult = itsVersionedTypes.insert( hash );
     493       13600 :         const auto lock = detail::StaticObject<detail::Versions>::lock();
     494             :         const auto version =
     495        6800 :           detail::StaticObject<detail::Versions>::getInstance().find( hash, detail::Version<T>::version );
     496             : 
     497        6800 :         if( insertResult.second ) // insertion took place, serialize the version number
     498        5200 :           process( make_nvp<ArchiveType>("cereal_class_version", version) );
     499             : 
     500       13600 :         return version;
     501             :       }
     502             : 
     503             :       //! Member serialization
     504             :       /*! Versioning implementation */
     505             :       template <class T, PROCESS_IF(member_versioned_serialize)> inline
     506        2000 :       ArchiveType & processImpl(T const & t)
     507             :       {
     508        2000 :         access::member_serialize(*self, const_cast<T &>(t), registerClassVersion<T>());
     509        2000 :         return *self;
     510             :       }
     511             : 
     512             :       //! Non member serialization
     513             :       /*! Versioning implementation */
     514             :       template <class T, PROCESS_IF(non_member_versioned_serialize)> inline
     515         800 :       ArchiveType & processImpl(T const & t)
     516             :       {
     517         800 :         CEREAL_SERIALIZE_FUNCTION_NAME(*self, const_cast<T &>(t), registerClassVersion<T>());
     518         800 :         return *self;
     519             :       }
     520             : 
     521             :       //! Member split (save)
     522             :       /*! Versioning implementation */
     523             :       template <class T, PROCESS_IF(member_versioned_save)> inline
     524        1200 :       ArchiveType & processImpl(T const & t)
     525             :       {
     526        1200 :         access::member_save(*self, t, registerClassVersion<T>());
     527        1200 :         return *self;
     528             :       }
     529             : 
     530             :       //! Non member split (save)
     531             :       /*! Versioning implementation */
     532             :       template <class T, PROCESS_IF(non_member_versioned_save)> inline
     533        1200 :       ArchiveType & processImpl(T const & t)
     534             :       {
     535        1200 :         CEREAL_SAVE_FUNCTION_NAME(*self, t, registerClassVersion<T>());
     536        1200 :         return *self;
     537             :       }
     538             : 
     539             :       //! Member split (save_minimal)
     540             :       /*! Versioning implementation */
     541             :       template <class T, PROCESS_IF(member_versioned_save_minimal)> inline
     542         800 :       ArchiveType & processImpl(T const & t)
     543             :       {
     544         800 :         self->process( access::member_save_minimal(*self, t, registerClassVersion<T>()) );
     545         800 :         return *self;
     546             :       }
     547             : 
     548             :       //! Non member split (save_minimal)
     549             :       /*! Versioning implementation */
     550             :       template <class T, PROCESS_IF(non_member_versioned_save_minimal)> inline
     551         800 :       ArchiveType & processImpl(T const & t)
     552             :       {
     553         800 :         self->process( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(*self, t, registerClassVersion<T>()) );
     554         800 :         return *self;
     555             :       }
     556             : 
     557             :     #undef PROCESS_IF
     558             : 
     559             :     private:
     560             :       ArchiveType * const self;
     561             : 
     562             :       //! A set of all base classes that have been serialized
     563             :       std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
     564             : 
     565             :       //! Maps from addresses to pointer ids
     566             :       std::unordered_map<void const *, std::uint32_t> itsSharedPointerMap;
     567             : 
     568             :       //! The id to be given to the next pointer
     569             :       std::uint32_t itsCurrentPointerId;
     570             : 
     571             :       //! Maps from polymorphic type name strings to ids
     572             :       std::unordered_map<char const *, std::uint32_t> itsPolymorphicTypeMap;
     573             : 
     574             :       //! The id to be given to the next polymorphic type name
     575             :       std::uint32_t itsCurrentPolymorphicTypeId;
     576             : 
     577             :       //! Keeps track of classes that have versioning information associated with them
     578             :       std::unordered_set<size_type> itsVersionedTypes;
     579             :   }; // class OutputArchive
     580             : 
     581             :   // ######################################################################
     582             :   //! The base input archive class
     583             :   /*! This is the base input archive for all input archives.  If you create
     584             :       a custom archive class, it should derive from this, passing itself as
     585             :       a template parameter for the ArchiveType.
     586             : 
     587             :       The base class provides all of the functionality necessary to
     588             :       properly forward data to the correct serialization functions.
     589             : 
     590             :       Individual archives should use a combination of prologue and
     591             :       epilogue functions together with specializations of serialize, save,
     592             :       and load to alter the functionality of their serialization.
     593             : 
     594             :       @tparam ArchiveType The archive type that derives from InputArchive
     595             :       @tparam Flags Flags to control advanced functionality.  See the Flags
     596             :                     enum for more information.
     597             :       @ingroup Internal */
     598             :   template<class ArchiveType, std::uint32_t Flags = 0>
     599       14752 :   class InputArchive : public detail::InputArchiveBase
     600             :   {
     601             :     public:
     602             :       //! Construct the output archive
     603             :       /*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
     604       14752 :       InputArchive(ArchiveType * const derived) :
     605             :         self(derived),
     606             :         itsBaseClassSet(),
     607             :         itsSharedPointerMap(),
     608             :         itsPolymorphicTypeMap(),
     609       14752 :         itsVersionedTypes()
     610       14752 :       { }
     611             : 
     612             :       InputArchive & operator=( InputArchive const & ) = delete;
     613             : 
     614             :       //! Serializes all passed in data
     615             :       /*! This is the primary interface for serializing data with an archive */
     616             :       template <class ... Types> inline
     617    12656743 :       ArchiveType & operator()( Types && ... args )
     618             :       {
     619    12656743 :         process( std::forward<Types>( args )... );
     620    12654943 :         return *self;
     621             :       }
     622             : 
     623             :       /*! @name Boost Transition Layer
     624             :           Functionality that mirrors the syntax for Boost.  This is useful if you are transitioning
     625             :           a large project from Boost to cereal.  The preferred interface for cereal is using operator(). */
     626             :       //! @{
     627             : 
     628             :       //! Indicates this archive is intended for loading
     629             :       /*! This ensures compatibility with boost archive types.  If you are transitioning
     630             :           from boost, you can check this value within a member or external serialize function
     631             :           (i.e., Archive::is_loading::value) to enable behavior specific to loading, until 
     632             :           you can transition to split save/load or save_minimal/load_minimal functions */
     633             :       using is_loading = std::true_type;
     634             : 
     635             :       //! Indicates this archive is not intended for saving
     636             :       /*! This ensures compatibility with boost archive types.  If you are transitioning
     637             :           from boost, you can check this value within a member or external serialize function
     638             :           (i.e., Archive::is_saving::value) to disable behavior specific to loading, until 
     639             :           you can transition to split save/load or save_minimal/load_minimal functions */
     640             :       using is_saving = std::false_type;
     641             : 
     642             :       //! Serializes passed in data
     643             :       /*! This is a boost compatability layer and is not the preferred way of using
     644             :           cereal.  If you are transitioning from boost, use this until you can
     645             :           transition to the operator() overload */
     646             :       template <class T> inline
     647             :       ArchiveType & operator&( T && arg )
     648             :       {
     649             :         self->process( std::forward<T>( arg ) );
     650             :         return *self;
     651             :       }
     652             : 
     653             :       //! Serializes passed in data
     654             :       /*! This is a boost compatability layer and is not the preferred way of using
     655             :           cereal.  If you are transitioning from boost, use this until you can
     656             :           transition to the operator() overload */
     657             :       template <class T> inline
     658             :       ArchiveType & operator>>( T && arg )
     659             :       {
     660             :         self->process( std::forward<T>( arg ) );
     661             :         return *self;
     662             :       }
     663             : 
     664             :       //! @}
     665             : 
     666             :       //! Retrieves a shared pointer given a unique key for it
     667             :       /*! This is used to retrieve a previously registered shared_ptr
     668             :           which has already been loaded.
     669             : 
     670             :           @param id The unique id that was serialized for the pointer
     671             :           @return A shared pointer to the data
     672             :           @throw Exception if the id does not exist */
     673        3200 :       inline std::shared_ptr<void> getSharedPointer(std::uint32_t const id)
     674             :       {
     675        3200 :         if(id == 0) return std::shared_ptr<void>(nullptr);
     676             : 
     677        2400 :         auto iter = itsSharedPointerMap.find( id );
     678        2400 :         if(iter == itsSharedPointerMap.end())
     679           0 :           throw Exception("Error while trying to deserialize a smart pointer. Could not find id " + std::to_string(id));
     680             : 
     681        2400 :         return iter->second;
     682             :       }
     683             : 
     684             :       //! Registers a shared pointer to its unique identifier
     685             :       /*! After a shared pointer has been allocated for the first time, it should
     686             :           be registered with its loaded id for future references to it.
     687             : 
     688             :           @param id The unique identifier for the shared pointer
     689             :           @param ptr The actual shared pointer */
     690       45604 :       inline void registerSharedPointer(std::uint32_t const id, std::shared_ptr<void> ptr)
     691             :       {
     692       45604 :         std::uint32_t const stripped_id = id & ~detail::msb_32bit;
     693       45604 :         itsSharedPointerMap[stripped_id] = ptr;
     694       45604 :       }
     695             : 
     696             :       //! Retrieves the string for a polymorphic type given a unique key for it
     697             :       /*! This is used to retrieve a string previously registered during
     698             :           a polymorphic load.
     699             : 
     700             :           @param id The unique id that was serialized for the polymorphic type
     701             :           @return The string identifier for the tyep */
     702        2000 :       inline std::string getPolymorphicName(std::uint32_t const id)
     703             :       {
     704        2000 :         auto name = itsPolymorphicTypeMap.find( id );
     705        2000 :         if(name == itsPolymorphicTypeMap.end())
     706             :         {
     707           0 :           throw Exception("Error while trying to deserialize a polymorphic pointer. Could not find type id " + std::to_string(id));
     708             :         }
     709        2000 :         return name->second;
     710             :       }
     711             : 
     712             :       //! Registers a polymorphic name string to its unique identifier
     713             :       /*! After a polymorphic type has been loaded for the first time, it should
     714             :           be registered with its loaded id for future references to it.
     715             : 
     716             :           @param id The unique identifier for the polymorphic type
     717             :           @param name The name associated with the tyep */
     718        1600 :       inline void registerPolymorphicName(std::uint32_t const id, std::string const & name)
     719             :       {
     720        1600 :         std::uint32_t const stripped_id = id & ~detail::msb_32bit;
     721        1600 :         itsPolymorphicTypeMap.insert( {stripped_id, name} );
     722        1600 :       }
     723             : 
     724             :     private:
     725             :       //! Serializes data after calling prologue, then calls epilogue
     726             :       template <class T> inline
     727    17713851 :       void process( T && head )
     728             :       {
     729    17713851 :         prologue( *self, head );
     730    17713851 :         self->processImpl( head );
     731    17712051 :         epilogue( *self, head );
     732    17712051 :       }
     733             : 
     734             :       //! Unwinds to process all data
     735             :       template <class T, class ... Other> inline
     736     5045908 :       void process( T && head, Other && ... tail )
     737             :       {
     738     5045908 :         process( std::forward<T>( head ) );
     739     5045908 :         process( std::forward<Other>( tail )... );
     740     5045908 :       }
     741             : 
     742             :       //! Serialization of a virtual_base_class wrapper
     743             :       /*! \sa virtual_base_class */
     744             :       template <class T> inline
     745        1600 :       ArchiveType & processImpl(virtual_base_class<T> & b)
     746             :       {
     747        1600 :         traits::detail::base_class_id id(b.base_ptr);
     748        1600 :         if(itsBaseClassSet.count(id) == 0)
     749             :         {
     750         800 :           itsBaseClassSet.insert(id);
     751         800 :           self->processImpl( *b.base_ptr );
     752             :         }
     753        1600 :         return *self;
     754             :       }
     755             : 
     756             :       //! Serialization of a base_class wrapper
     757             :       /*! \sa base_class */
     758             :       template <class T> inline
     759        2400 :       ArchiveType & processImpl(base_class<T> & b)
     760             :       {
     761        2400 :         self->processImpl( *b.base_ptr );
     762        2400 :         return *self;
     763             :       }
     764             : 
     765             :       //! Helper macro that expands the requirements for activating an overload
     766             :       /*! Requirements:
     767             :             Has the requested serialization function
     768             :             Does not have version and unversioned at the same time
     769             :             Is input serializable AND
     770             :               is specialized for this type of function OR
     771             :               has no specialization at all */
     772             :       #define PROCESS_IF(name)                                                              \
     773             :       traits::EnableIf<traits::has_##name<T, ArchiveType>::value,                           \
     774             :                        !traits::has_invalid_input_versioning<T, ArchiveType>::value,        \
     775             :                        (traits::is_input_serializable<T, ArchiveType>::value &&             \
     776             :                         (traits::is_specialized_##name<T, ArchiveType>::value ||            \
     777             :                          !traits::is_specialized<T, ArchiveType>::value))> = traits::sfinae
     778             : 
     779             :       //! Member serialization
     780             :       template <class T, PROCESS_IF(member_serialize)> inline
     781     2523936 :       ArchiveType & processImpl(T & t)
     782             :       {
     783     2523936 :         access::member_serialize(*self, t);
     784     2523536 :         return *self;
     785             :       }
     786             : 
     787             :       //! Non member serialization
     788             :       template <class T, PROCESS_IF(non_member_serialize)> inline
     789     1706929 :       ArchiveType & processImpl(T & t)
     790             :       {
     791     1706929 :         CEREAL_SERIALIZE_FUNCTION_NAME(*self, t);
     792     1706729 :         return *self;
     793             :       }
     794             : 
     795             :       //! Member split (load)
     796             :       template <class T, PROCESS_IF(member_load)> inline
     797      843780 :       ArchiveType & processImpl(T & t)
     798             :       {
     799      843780 :         access::member_load(*self, t);
     800      843780 :         return *self;
     801             :       }
     802             : 
     803             :       //! Non member split (load)
     804             :       template <class T, PROCESS_IF(non_member_load)> inline
     805    12628006 :       ArchiveType & processImpl(T & t)
     806             :       {
     807    12628006 :         CEREAL_LOAD_FUNCTION_NAME(*self, t);
     808    12626806 :         return *self;
     809             :       }
     810             : 
     811             :       //! Member split (load_minimal)
     812             :       template <class T, PROCESS_IF(member_load_minimal)> inline
     813        1200 :       ArchiveType & processImpl(T & t)
     814             :       {
     815             :         using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
     816        1200 :         typename traits::has_member_save_minimal<T, OutArchiveType>::type value;
     817        1200 :         self->process( value );
     818        1200 :         access::member_load_minimal(*self, t, value);
     819        1800 :         return *self;
     820             :       }
     821             : 
     822             :       //! Non member split (load_minimal)
     823             :       template <class T, PROCESS_IF(non_member_load_minimal)> inline
     824        3200 :       ArchiveType & processImpl(T & t)
     825             :       {
     826             :         using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
     827         400 :         typename traits::has_non_member_save_minimal<T, OutArchiveType>::type value;
     828        3200 :         self->process( value );
     829        3200 :         CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value);
     830        3400 :         return *self;
     831             :       }
     832             : 
     833             :       //! Empty class specialization
     834             :       template <class T, traits::EnableIf<(Flags & AllowEmptyClassElision),
     835             :                                           !traits::is_input_serializable<T, ArchiveType>::value,
     836             :                                           std::is_empty<T>::value> = traits::sfinae> inline
     837             :       ArchiveType & processImpl(T const &)
     838             :       {
     839             :         return *self;
     840             :       }
     841             : 
     842             :       //! No matching serialization
     843             :       /*! Invalid if we have invalid input versioning or
     844             :           we are not input serializable, and either
     845             :           don't allow empty class ellision or allow it but are not serializing an empty class */
     846             :       template <class T, traits::EnableIf<traits::has_invalid_input_versioning<T, ArchiveType>::value ||
     847             :                                           (!traits::is_input_serializable<T, ArchiveType>::value &&
     848             :                                            (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae> inline
     849             :       ArchiveType & processImpl(T const &)
     850             :       {
     851             :         static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value != 0,
     852             :             "cereal could not find any input serialization functions for the provided type and archive combination. \n\n "
     853             :             "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
     854             :             "Serialize functions generally have the following signature: \n\n "
     855             :             "template<class Archive> \n "
     856             :             "  void serialize(Archive & ar) \n "
     857             :             "  { \n "
     858             :             "    ar( member1, member2, member3 ); \n "
     859             :             "  } \n\n " );
     860             : 
     861             :         static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value < 2,
     862             :             "cereal found more than one compatible input serialization function for the provided type and archive combination. \n\n "
     863             :             "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
     864             :             "Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions.  \n "
     865             :             "Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
     866             :             "In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
     867             : 
     868             :         return *self;
     869             :       }
     870             : 
     871             :       //! Befriend for versioning in load_and_construct
     872             :       template <class A, class B, bool C, bool D, bool E, bool F> friend struct detail::Construct;
     873             : 
     874             :       //! Registers a class version with the archive and serializes it if necessary
     875             :       /*! If this is the first time this class has been serialized, we will record its
     876             :           version number and serialize that.
     877             : 
     878             :           @tparam T The type of the class being serialized
     879             :           @param version The version number associated with it */
     880             :       template <class T> inline
     881        6800 :       std::uint32_t loadClassVersion()
     882             :       {
     883        6800 :         static const auto hash = std::type_index(typeid(T)).hash_code();
     884        6800 :         auto lookupResult = itsVersionedTypes.find( hash );
     885             : 
     886        6800 :         if( lookupResult != itsVersionedTypes.end() ) // already exists
     887        1600 :           return lookupResult->second;
     888             :         else // need to load
     889             :         {
     890             :           std::uint32_t version;
     891             : 
     892        5200 :           process( make_nvp<ArchiveType>("cereal_class_version", version) );
     893        5200 :           itsVersionedTypes.emplace_hint( lookupResult, hash, version );
     894             : 
     895        5200 :           return version;
     896             :         }
     897             :       }
     898             : 
     899             :       //! Member serialization
     900             :       /*! Versioning implementation */
     901             :       template <class T, PROCESS_IF(member_versioned_serialize)> inline
     902        1200 :       ArchiveType & processImpl(T & t)
     903             :       {
     904        1200 :         const auto version = loadClassVersion<T>();
     905        1200 :         access::member_serialize(*self, t, version);
     906        1200 :         return *self;
     907             :       }
     908             : 
     909             :       //! Non member serialization
     910             :       /*! Versioning implementation */
     911             :       template <class T, PROCESS_IF(non_member_versioned_serialize)> inline
     912         800 :       ArchiveType & processImpl(T & t)
     913             :       {
     914         800 :         const auto version = loadClassVersion<T>();
     915         800 :         CEREAL_SERIALIZE_FUNCTION_NAME(*self, t, version);
     916         800 :         return *self;
     917             :       }
     918             : 
     919             :       //! Member split (load)
     920             :       /*! Versioning implementation */
     921             :       template <class T, PROCESS_IF(member_versioned_load)> inline
     922        1200 :       ArchiveType & processImpl(T & t)
     923             :       {
     924        1200 :         const auto version = loadClassVersion<T>();
     925        1200 :         access::member_load(*self, t, version);
     926        1200 :         return *self;
     927             :       }
     928             : 
     929             :       //! Non member split (load)
     930             :       /*! Versioning implementation */
     931             :       template <class T, PROCESS_IF(non_member_versioned_load)> inline
     932        1200 :       ArchiveType & processImpl(T & t)
     933             :       {
     934        1200 :         const auto version = loadClassVersion<T>();
     935        1200 :         CEREAL_LOAD_FUNCTION_NAME(*self, t, version);
     936        1200 :         return *self;
     937             :       }
     938             : 
     939             :       //! Member split (load_minimal)
     940             :       /*! Versioning implementation */
     941             :       template <class T, PROCESS_IF(member_versioned_load_minimal)> inline
     942         800 :       ArchiveType & processImpl(T & t)
     943             :       {
     944             :         using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
     945         800 :         const auto version = loadClassVersion<T>();
     946             :         typename traits::has_member_versioned_save_minimal<T, OutArchiveType>::type value;
     947         800 :         self->process(value);
     948         800 :         access::member_load_minimal(*self, t, value, version);
     949         800 :         return *self;
     950             :       }
     951             : 
     952             :       //! Non member split (load_minimal)
     953             :       /*! Versioning implementation */
     954             :       template <class T, PROCESS_IF(non_member_versioned_load_minimal)> inline
     955         800 :       ArchiveType & processImpl(T & t)
     956             :       {
     957             :         using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
     958         800 :         const auto version = loadClassVersion<T>();
     959             :         typename traits::has_non_member_versioned_save_minimal<T, OutArchiveType>::type value;
     960         800 :         self->process(value);
     961         800 :         CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value, version);
     962         800 :         return *self;
     963             :       }
     964             : 
     965             :       #undef PROCESS_IF
     966             : 
     967             :     private:
     968             :       ArchiveType * const self;
     969             : 
     970             :       //! A set of all base classes that have been serialized
     971             :       std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
     972             : 
     973             :       //! Maps from pointer ids to metadata
     974             :       std::unordered_map<std::uint32_t, std::shared_ptr<void>> itsSharedPointerMap;
     975             : 
     976             :       //! Maps from name ids to names
     977             :       std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap;
     978             : 
     979             :       //! Maps from type hash codes to version numbers
     980             :       std::unordered_map<std::size_t, std::uint32_t> itsVersionedTypes;
     981             :   }; // class InputArchive
     982             : } // namespace cereal
     983             : 
     984             : // This include needs to come after things such as binary_data, make_nvp, etc
     985             : #include "cereal/types/common.hpp"
     986             : 
     987             : #endif // CEREAL_CEREAL_HPP_

Generated by: LCOV version 1.11