LCOV - code coverage report
Current view: top level - cereal/details - helpers.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 899 919 97.8 %
Date: 2019-10-22 20:09:23 Functions: 1159 1211 95.7 %

          Line data    Source code
       1             : /*! \file helpers.hpp
       2             :     \brief Internal helper functionality
       3             :     \ingroup Internal */
       4             : /*
       5             :   Copyright (c) 2014, Randolph Voorhies, Shane Grant
       6             :   All rights reserved.
       7             : 
       8             :   Redistribution and use in source and binary forms, with or without
       9             :   modification, are permitted provided that the following conditions are met:
      10             :       * Redistributions of source code must retain the above copyright
      11             :         notice, this list of conditions and the following disclaimer.
      12             :       * Redistributions in binary form must reproduce the above copyright
      13             :         notice, this list of conditions and the following disclaimer in the
      14             :         documentation and/or other materials provided with the distribution.
      15             :       * Neither the name of cereal nor the
      16             :         names of its contributors may be used to endorse or promote products
      17             :         derived from this software without specific prior written permission.
      18             : 
      19             :   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
      20             :   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
      21             :   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      22             :   DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
      23             :   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      24             :   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      25             :   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
      26             :   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      27             :   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      28             :   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      29             : */
      30             : #ifndef CEREAL_DETAILS_HELPERS_HPP_
      31             : #define CEREAL_DETAILS_HELPERS_HPP_
      32             : 
      33             : #include <type_traits>
      34             : #include <cstdint>
      35             : #include <utility>
      36             : #include <memory>
      37             : #include <unordered_map>
      38             : #include <stdexcept>
      39             : 
      40             : #include "cereal/macros.hpp"
      41             : #include "cereal/details/static_object.hpp"
      42             : 
      43             : namespace cereal
      44             : {
      45             :   // ######################################################################
      46             :   //! An exception class thrown when things go wrong at runtime
      47             :   /*! @ingroup Utility */
      48             :   struct Exception : public std::runtime_error
      49             :   {
      50           0 :     explicit Exception( const std::string & what_ ) : std::runtime_error(what_) {}
      51         800 :     explicit Exception( const char * what_ ) : std::runtime_error(what_) {}
      52             :   };
      53             : 
      54             :   // ######################################################################
      55             :   //! The size type used by cereal
      56             :   /*! To ensure compatability between 32, 64, etc bit machines, we need to use
      57             :       a fixed size type instead of size_t, which may vary from machine to
      58             :       machine.
      59             : 
      60             :       The default value for CEREAL_SIZE_TYPE is specified in cereal/macros.hpp */
      61             :   using size_type = CEREAL_SIZE_TYPE;
      62             : 
      63             :   // forward decls
      64             :   class BinaryOutputArchive;
      65             :   class BinaryInputArchive;
      66             : 
      67             :   // ######################################################################
      68             :   namespace detail
      69             :   {
      70             :     struct NameValuePairCore {}; //!< Traits struct for NVPs
      71             :     struct DeferredDataCore {}; //!< Traits struct for DeferredData
      72             :   }
      73             : 
      74             :   // ######################################################################
      75             :   //! For holding name value pairs
      76             :   /*! This pairs a name (some string) with some value such that an archive
      77             :       can potentially take advantage of the pairing.
      78             : 
      79             :       In serialization functions, NameValuePairs are usually created like so:
      80             :       @code{.cpp}
      81             :       struct MyStruct
      82             :       {
      83             :         int a, b, c, d, e;
      84             : 
      85             :         template<class Archive>
      86             :         void serialize(Archive & archive)
      87             :         {
      88             :           archive( CEREAL_NVP(a),
      89             :                    CEREAL_NVP(b),
      90             :                    CEREAL_NVP(c),
      91             :                    CEREAL_NVP(d),
      92             :                    CEREAL_NVP(e) );
      93             :         }
      94             :       };
      95             :       @endcode
      96             : 
      97             :       Alternatively, you can give you data members custom names like so:
      98             :       @code{.cpp}
      99             :       struct MyStruct
     100             :       {
     101             :         int a, b, my_embarrassing_variable_name, d, e;
     102             : 
     103             :         template<class Archive>
     104             :         void serialize(Archive & archive)
     105             :         {
     106             :           archive( CEREAL_NVP(a),
     107             :                    CEREAL_NVP(b),
     108             :                    cereal::make_nvp("var", my_embarrassing_variable_name) );
     109             :                    CEREAL_NVP(d),
     110             :                    CEREAL_NVP(e) );
     111             :         }
     112             :       };
     113             :       @endcode
     114             : 
     115             :       There is a slight amount of overhead to creating NameValuePairs, so there
     116             :       is a third method which will elide the names when they are not used by
     117             :       the Archive:
     118             : 
     119             :       @code{.cpp}
     120             :       struct MyStruct
     121             :       {
     122             :         int a, b;
     123             : 
     124             :         template<class Archive>
     125             :         void serialize(Archive & archive)
     126             :         {
     127             :           archive( cereal::make_nvp<Archive>(a),
     128             :                    cereal::make_nvp<Archive>(b) );
     129             :         }
     130             :       };
     131             :       @endcode
     132             : 
     133             :       This third method is generally only used when providing generic type
     134             :       support.  Users writing their own serialize functions will normally
     135             :       explicitly control whether they want to use NVPs or not.
     136             : 
     137             :       @internal */
     138             :   template <class T>
     139             :   class NameValuePair : detail::NameValuePairCore
     140             :   {
     141             :     private:
     142             :       // If we get passed an array, keep the type as is, otherwise store
     143             :       // a reference if we were passed an l value reference, else copy the value
     144             :       using Type = typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
     145             :                                              typename std::remove_cv<T>::type,
     146             :                                              typename std::conditional<std::is_lvalue_reference<T>::value,
     147             :                                                                        T,
     148             :                                                                        typename std::decay<T>::type>::type>::type;
     149             : 
     150             :       // prevent nested nvps
     151             :       static_assert( !std::is_base_of<detail::NameValuePairCore, T>::value,
     152             :                      "Cannot pair a name to a NameValuePair" );
     153             : 
     154             :       NameValuePair & operator=( NameValuePair const & ) = delete;
     155             : 
     156             :     public:
     157             :       //! Constructs a new NameValuePair
     158             :       /*! @param n The name of the pair
     159             :           @param v The value to pair.  Ideally this should be an l-value reference so that
     160             :                    the value can be both loaded and saved to.  If you pass an r-value reference,
     161             :                    the NameValuePair will store a copy of it instead of a reference.  Thus you should
     162             :                    only pass r-values in cases where this makes sense, such as the result of some
     163             :                    size() call.
     164             :           @internal */
     165     8894952 :       NameValuePair( char const * n, T && v ) : name(n), value(std::forward<T>(v)) {}
     166             : 
     167             :       char const * name;
     168             :       Type value;
     169             :   };
     170             : 
     171             :   //! A specialization of make_nvp<> that simply forwards the value for binary archives
     172             :   /*! @relates NameValuePair
     173             :       @internal */
     174             :   template<class Archive, class T> inline
     175             :   typename
     176             :   std::enable_if<std::is_same<Archive, ::cereal::BinaryInputArchive>::value ||
     177             :                  std::is_same<Archive, ::cereal::BinaryOutputArchive>::value,
     178             :   T && >::type
     179     2960868 :   make_nvp( const char *, T && value )
     180             :   {
     181     2960868 :     return std::forward<T>(value);
     182             :   }
     183      123564 : 
     184             :   //! A specialization of make_nvp<> that actually creates an nvp for non-binary archives
     185      123564 :   /*! @relates NameValuePair
     186             :       @internal */
     187      127951 :   template<class Archive, class T> inline
     188             :   typename
     189      127951 :   std::enable_if<!std::is_same<Archive, ::cereal::BinaryInputArchive>::value &&
     190             :                  !std::is_same<Archive, ::cereal::BinaryOutputArchive>::value,
     191      112206 :   NameValuePair<T> >::type
     192        1600 :   make_nvp( const char * name, T && value)
     193      112206 :   {
     194        1600 :     return {name, std::forward<T>(value)};
     195      167322 :   }
     196         200 : 
     197      167322 :   //! Convenience for creating a templated NVP
     198         200 :   /*! For use in internal generic typing functions which have an
     199      226539 :       Archive type declared
     200        7400 :       @internal */
     201      226539 :   #define CEREAL_NVP_(name, value) ::cereal::make_nvp<Archive>(name, value)
     202        7400 : 
     203      145545 :   // ######################################################################
     204        1400 :   //! A wrapper around data that can be serialized in a binary fashion
     205      145545 :   /*! This class is used to demarcate data that can safely be serialized
     206        1400 :       as a binary chunk of data.  Individual archives can then choose how
     207      203228 :       best represent this during serialization.
     208       12200 : 
     209      203228 :       @internal */
     210       12200 :   template <class T>
     211      126807 :   struct BinaryData
     212       12600 :   {
     213      126807 :     //! Internally store the pointer as a void *, keeping const if created with
     214       12600 :     //! a const pointer
     215      119164 :     using PT = typename std::conditional<std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
     216      259857 :                                          const void *,
     217      119164 :                                          void *>::type;
     218      259857 : 
     219      123523 :     BinaryData( T && d, uint64_t s ) : data(std::forward<T>(d)), size(s) {}
     220       25605 : 
     221      116323 :     PT data;       //!< pointer to beginning of data
     222       25605 :     uint64_t size; //!< size in bytes
     223      117565 :   };
     224       61900 : 
     225      117565 :   // ######################################################################
     226       61900 :   //! A wrapper around data that should be serialized after all non-deferred data
     227      103616 :   /*! This class is used to demarcate data that can only be safely serialized after
     228       24754 :       any data not wrapped in this class.
     229      103616 : 
     230       24754 :       @internal */
     231      123370 :   template <class T>
     232       60247 :   class DeferredData : detail::DeferredDataCore
     233      123370 :   {
     234       60247 :     private:
     235      121586 :       // If we get passed an array, keep the type as is, otherwise store
     236       23847 :       // a reference if we were passed an l value reference, else copy the value
     237      121586 :       using Type = typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
     238       23847 :                                              typename std::remove_cv<T>::type,
     239      321982 :                                              typename std::conditional<std::is_lvalue_reference<T>::value,
     240       23830 :                                                                        T,
     241      321982 :                                                                        typename std::decay<T>::type>::type>::type;
     242       23830 : 
     243      121400 :       // prevent nested nvps
     244       24777 :       static_assert( !std::is_base_of<detail::DeferredDataCore, T>::value,
     245      121400 :                      "Cannot defer DeferredData" );
     246       24777 : 
     247       82200 :       DeferredData & operator=( DeferredData const & ) = delete;
     248       26516 : 
     249       82200 :     public:
     250       26516 :       //! Constructs a new NameValuePair
     251       99762 :       /*! @param v The value to defer.  Ideally this should be an l-value reference so that
     252        4718 :                    the value can be both loaded and saved to.  If you pass an r-value reference,
     253       98962 :                    the DeferredData will store a copy of it instead of a reference.  Thus you should
     254        4718 :                    only pass r-values in cases where this makes sense, such as the result of some
     255       60802 :                    size() call.
     256     2404810 :           @internal */
     257       60802 :       DeferredData( T && v ) : value(std::forward<T>(v)) {}
     258     2404810 : 
     259       61765 :       Type value;
     260       44501 :   };
     261       61765 : 
     262       44501 :   // ######################################################################
     263       18967 :   namespace detail
     264     1223308 :   {
     265       18967 :     // base classes for type checking
     266     1223308 :     /* The rtti virtual function only exists to enable an archive to
     267       26548 :        be used in a polymorphic fashion, if necessary.  See the
     268       75497 :        archive adapters for an example of this */
     269       20804 :     class OutputArchiveBase
     270       81241 :     {
     271       21000 :       public:
     272     2499111 :         OutputArchiveBase() = default;
     273       21000 :         OutputArchiveBase( OutputArchiveBase && ) CEREAL_NOEXCEPT {}
     274     2493367 :         OutputArchiveBase & operator=( OutputArchiveBase && ) CEREAL_NOEXCEPT { return *this; }
     275       26744 :         virtual ~OutputArchiveBase() CEREAL_NOEXCEPT = default;
     276      104711 : 
     277       21000 :       private:
     278      104711 :         virtual void rtti() {}
     279       26544 :     };
     280      166535 : 
     281       20800 :     class InputArchiveBase
     282      172279 :     {
     283       21000 :       public:
     284      190830 :         InputArchiveBase() = default;
     285       21000 :         InputArchiveBase( InputArchiveBase && ) CEREAL_NOEXCEPT {}
     286      185086 :         InputArchiveBase & operator=( InputArchiveBase && ) CEREAL_NOEXCEPT { return *this; }
     287       26744 :         virtual ~InputArchiveBase() CEREAL_NOEXCEPT = default;
     288      124039 : 
     289       21000 :       private:
     290      124039 :         virtual void rtti() {}
     291       20800 :     };
     292      123686 : 
     293       20800 :     // forward decls for polymorphic support
     294      123686 :     template <class Archive, class T> struct polymorphic_serialization_support;
     295       21600 :     struct adl_tag;
     296      105806 : 
     297       21600 :     // used during saving pointers
     298      105806 :     static const uint32_t msb_32bit  = 0x80000000;
     299       22600 :     static const int32_t msb2_32bit = 0x40000000;
     300      103406 :   }
     301       21600 : 
     302      104406 :   // ######################################################################
     303       41600 :   //! A wrapper around size metadata
     304      101187 :   /*! This class provides a way for archives to have more flexibility over how
     305       41600 :       they choose to serialize size metadata for containers.  For some archive
     306      100187 :       types, the size may be implicitly encoded in the output (e.g. JSON) and
     307       23400 :       not need an explicit entry.  Specializing serialize or load/save for
     308      100584 :       your archive and SizeTags allows you to choose what happens.
     309       22400 : 
     310      100584 :       @internal */
     311        1200 :   template <class T>
     312      106017 :   class SizeTag
     313         200 :   {
     314      107017 :     private:
     315       81484 :       // Store a reference if passed an lvalue reference, otherwise
     316      249603 :       // make a copy of the data
     317         200 :       using Type = typename std::conditional<std::is_lvalue_reference<T>::value,
     318      248603 :                                              T,
     319       39600 :                                              typename std::decay<T>::type>::type;
     320     2486543 : 
     321         200 :       SizeTag & operator=( SizeTag const & ) = delete;
     322     2486543 : 
     323         400 :     public:
     324      157116 :       SizeTag( T && sz ) : size(std::forward<T>(sz)) {}
     325         400 : 
     326      118716 :       Type size;
     327         400 :   };
     328      144989 : 
     329         400 :   // ######################################################################
     330      144989 :   //! A wrapper around a key and value for serializing data into maps.
     331         612 :   /*! This class just provides a grouping of keys and values into a struct for
     332      121803 :       human readable archives. For example, XML archives will use this wrapper
     333         200 :       to write maps like so:
     334      122203 : 
     335         200 :       @code{.xml}
     336      124603 :       <mymap>
     337         200 :         <item0>
     338      124203 :           <key>MyFirstKey</key>
     339         600 :           <value>MyFirstValue</value>
     340      120183 :         </item0>
     341         200 :         <item1>
     342      120183 :           <key>MySecondKey</key>
     343        1200 :           <value>MySecondValue</value>
     344      116335 :         </item1>
     345         800 :       </mymap>
     346      116735 :       @endcode
     347         400 : 
     348      207754 :       \sa make_map_item
     349         400 :       @internal */
     350      199354 :   template <class Key, class Value>
     351        1600 :   struct MapItem
     352      104002 :   {
     353        8400 :     using KeyType = typename std::conditional<
     354      104002 :       std::is_lvalue_reference<Key>::value,
     355        2000 :       Key,
     356      104008 :       typename std::decay<Key>::type>::type;
     357        2000 : 
     358      103208 :     using ValueType = typename std::conditional<
     359         200 :       std::is_lvalue_reference<Value>::value,
     360      121000 :       Value,
     361         200 :       typename std::decay<Value>::type>::type;
     362      121000 : 
     363        1404 :     //! Construct a MapItem from a key and a value
     364      261190 :     /*! @internal */
     365         200 :     MapItem( Key && key_, Value && value_ ) : key(std::forward<Key>(key_)), value(std::forward<Value>(value_)) {}
     366      262390 : 
     367         200 :     MapItem & operator=( MapItem const & ) = delete;
     368      122004 : 
     369         200 :     KeyType key;
     370      120804 :     ValueType value;
     371        1800 : 
     372      201004 :     //! Serialize the MapItem with the NVPs "key" and "value"
     373         200 :     template <class Archive> inline
     374      201404 :     void CEREAL_SERIALIZE_FUNCTION_NAME(Archive & archive)
     375        1600 :     {
     376      141606 :       archive( make_nvp<Archive>("key",   key),
     377           0 :                make_nvp<Archive>("value", value) );
     378      142806 :     }
     379         408 :   };
     380      199207 : 
     381           0 :   //! Create a MapItem so that human readable archives will group keys and values together
     382      197615 :   /*! @internal
     383        2000 :       @relates MapItem */
     384      170160 :   template <class KeyType, class ValueType> inline
     385           0 :   MapItem<KeyType, ValueType> make_map_item(KeyType && key, ValueType && value)
     386      170556 :   {
     387           4 :     return {std::forward<KeyType>(key), std::forward<ValueType>(value)};
     388      117554 :   }
     389           0 : 
     390      117154 :   namespace detail
     391         408 :   {
     392      103787 :     //! Tag for Version, which due to its anonymous namespace, becomes a different
     393             :     //! type in each translation unit
     394      103795 :     /*! This allows CEREAL_CLASS_VERSION to be safely called in a header file */
     395         400 :     namespace{ struct version_binding_tag {}; }
     396      102992 : 
     397           0 :     // ######################################################################
     398      103388 :     //! Version information class
     399           4 :     /*! This is the base case for classes that have not been explicitly
     400      142175 :         registered */
     401           0 :     template <class T, class BindingTag = version_binding_tag> struct Version
     402      141775 :     {
     403         400 :       static const std::uint32_t version = 0;
     404      201000 :       // we don't need to explicitly register these types since they
     405             :       // always get a version number of 0
     406      201000 :     };
     407         400 : 
     408      121000 :     //! Holds all registered version information
     409             :     struct Versions
     410      121400 :     {
     411           8 :       std::unordered_map<std::size_t, std::uint32_t> mapping;
     412      199003 : 
     413           0 :       std::uint32_t find( std::size_t hash, std::uint32_t version )
     414      198603 :       {
     415       44404 :         const auto result = mapping.emplace( hash, version );
     416      117411 :         return result.first->second;
     417             :       }
     418      117407 :     }; // struct Versions
     419           4 :   } // namespace detail
     420      146282 : } // namespace cereal
     421             : 
     422      102602 : #endif // CEREAL_DETAILS_HELPERS_HPP_

Generated by: LCOV version 1.13