LCOV - code coverage report
Current view: top level - cereal/details - helpers.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 26 29 89.7 %
Date: 2017-02-12 13:57:59 Functions: 922 978 94.3 %

          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        1200 :   struct Exception : public std::runtime_error
      49             :   {
      50           0 :     explicit Exception( const std::string & what_ ) : std::runtime_error(what_) {}
      51         400 :     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     4288034 :     struct NameValuePairCore {}; //!< Traits struct for NVPs
      71             :   }
      72             : 
      73             :   //! For holding name value pairs
      74             :   /*! This pairs a name (some string) with some value such that an archive
      75             :       can potentially take advantage of the pairing.
      76             : 
      77             :       In serialization functions, NameValuePairs are usually created like so:
      78             :       @code{.cpp}
      79             :       struct MyStruct
      80             :       {
      81             :         int a, b, c, d, e;
      82             : 
      83             :         template<class Archive>
      84             :         void serialize(Archive & archive)
      85             :         {
      86             :           archive( CEREAL_NVP(a),
      87             :                    CEREAL_NVP(b),
      88             :                    CEREAL_NVP(c),
      89             :                    CEREAL_NVP(d),
      90             :                    CEREAL_NVP(e) );
      91             :         }
      92             :       };
      93             :       @endcode
      94             : 
      95             :       Alternatively, you can give you data members custom names like so:
      96             :       @code{.cpp}
      97             :       struct MyStruct
      98             :       {
      99             :         int a, b, my_embarrassing_variable_name, d, e;
     100             : 
     101             :         template<class Archive>
     102             :         void serialize(Archive & archive)
     103             :         {
     104             :           archive( CEREAL_NVP(a),
     105             :                    CEREAL_NVP(b),
     106             :                    cereal::make_nvp("var", my_embarrassing_variable_name) );
     107             :                    CEREAL_NVP(d),
     108             :                    CEREAL_NVP(e) );
     109             :         }
     110             :       };
     111             :       @endcode
     112             : 
     113             :       There is a slight amount of overhead to creating NameValuePairs, so there
     114             :       is a third method which will elide the names when they are not used by
     115             :       the Archive:
     116             : 
     117             :       @code{.cpp}
     118             :       struct MyStruct
     119             :       {
     120             :         int a, b;
     121             : 
     122             :         template<class Archive>
     123             :         void serialize(Archive & archive)
     124             :         {
     125             :           archive( cereal::make_nvp<Archive>(a),
     126             :                    cereal::make_nvp<Archive>(b) );
     127             :         }
     128             :       };
     129             :       @endcode
     130             : 
     131             :       This third method is generally only used when providing generic type
     132             :       support.  Users writing their own serialize functions will normally
     133             :       explicitly control whether they want to use NVPs or not.
     134             : 
     135             :       @internal */
     136             :   template <class T>
     137         494 :   class NameValuePair : detail::NameValuePairCore
     138             :   {
     139             :     private:
     140             :       // If we get passed an array, keep the type as is, otherwise store
     141             :       // a reference if we were passed an l value reference, else copy the value
     142             :       using Type = typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
     143             :                                              typename std::remove_cv<T>::type,
     144             :                                              typename std::conditional<std::is_lvalue_reference<T>::value,
     145             :                                                                        T,
     146             :                                                                        typename std::decay<T>::type>::type>::type;
     147             : 
     148             :       // prevent nested nvps
     149             :       static_assert( !std::is_base_of<detail::NameValuePairCore, T>::value,
     150             :                      "Cannot pair a name to a NameValuePair" );
     151             : 
     152             :       NameValuePair & operator=( NameValuePair const & ) = delete;
     153             : 
     154             :     public:
     155             :       //! Constructs a new NameValuePair
     156             :       /*! @param n The name of the pair
     157             :           @param v The value to pair.  Ideally this should be an l-value reference so that
     158             :                    the value can be both loaded and saved to.  If you pass an r-value reference,
     159             :                    the NameValuePair will store a copy of it instead of a reference.  Thus you should
     160             :                    only pass r-values in cases where this makes sense, such as the result of some
     161             :                    size() call.
     162             :           @internal */
     163     4288034 :       NameValuePair( char const * n, T && v ) : name(n), value(std::forward<T>(v)) {}
     164             : 
     165             :       char const * name;
     166             :       Type value;
     167             :   };
     168             : 
     169             :   //! A specialization of make_nvp<> that simply forwards the value for binary archives
     170             :   /*! @relates NameValuePair
     171             :       @internal */
     172             :   template<class Archive, class T> inline
     173             :   typename
     174             :   std::enable_if<std::is_same<Archive, ::cereal::BinaryInputArchive>::value ||
     175             :                  std::is_same<Archive, ::cereal::BinaryOutputArchive>::value,
     176             :   T && >::type
     177     1427054 :   make_nvp( const char *, T && value )
     178             :   {
     179     1427054 :     return std::forward<T>(value);
     180             :   }
     181             : 
     182             :   //! A specialization of make_nvp<> that actually creates an nvp for non-binary archives
     183             :   /*! @relates NameValuePair
     184             :       @internal */
     185             :   template<class Archive, class T> inline
     186             :   typename
     187             :   std::enable_if<!std::is_same<Archive, ::cereal::BinaryInputArchive>::value &&
     188             :                  !std::is_same<Archive, ::cereal::BinaryOutputArchive>::value,
     189             :   NameValuePair<T> >::type
     190     4284034 :   make_nvp( const char * name, T && value)
     191             :   {
     192     4284034 :     return {name, std::forward<T>(value)};
     193             :   }
     194             : 
     195             :   //! Convenience for creating a templated NVP
     196             :   /*! For use in internal generic typing functions which have an
     197             :       Archive type declared
     198             :       @internal */
     199             :   #define CEREAL_NVP_(name, value) ::cereal::make_nvp<Archive>(name, value)
     200             : 
     201             :   // ######################################################################
     202             :   //! A wrapper around data that can be serialized in a binary fashion
     203             :   /*! This class is used to demarcate data that can safely be serialized
     204             :       as a binary chunk of data.  Individual archives can then choose how
     205             :       best represent this during serialization.
     206             : 
     207             :       @internal */
     208             :   template <class T>
     209             :   struct BinaryData
     210             :   {
     211             :     //! Internally store the pointer as a void *, keeping const if created with
     212             :     //! a const pointer
     213             :     using PT = typename std::conditional<std::is_const<typename std::remove_pointer<T>::type>::value,
     214             :                                          const void *,
     215             :                                          void *>::type;
     216             : 
     217      246804 :     BinaryData( T && d, uint64_t s ) : data(std::forward<T>(d)), size(s) {}
     218             : 
     219             :     PT data;       //!< pointer to beginning of data
     220             :     uint64_t size; //!< size in bytes
     221             :   };
     222             : 
     223             :   // ######################################################################
     224             :   namespace detail
     225             :   {
     226             :     // base classes for type checking
     227             :     /* The rtti virtual function only exists to enable an archive to
     228             :        be used in a polymorphic fashion, if necessary.  See the
     229             :        archive adapters for an example of this */
     230             :     class OutputArchiveBase
     231             :     {
     232             :       public:
     233       14352 :         OutputArchiveBase() = default;
     234             :         OutputArchiveBase( OutputArchiveBase && ) CEREAL_NOEXCEPT {}
     235             :         OutputArchiveBase & operator=( OutputArchiveBase && ) CEREAL_NOEXCEPT { return *this; }
     236       14352 :         virtual ~OutputArchiveBase() CEREAL_NOEXCEPT = default;
     237             : 
     238             :       private:
     239           0 :         virtual void rtti() {}
     240             :     };
     241             : 
     242             :     class InputArchiveBase
     243             :     {
     244             :       public:
     245       14752 :         InputArchiveBase() = default;
     246             :         InputArchiveBase( InputArchiveBase && ) CEREAL_NOEXCEPT {}
     247             :         InputArchiveBase & operator=( InputArchiveBase && ) CEREAL_NOEXCEPT { return *this; }
     248       14752 :         virtual ~InputArchiveBase() CEREAL_NOEXCEPT = default;
     249             : 
     250             :       private:
     251           0 :         virtual void rtti() {}
     252             :     };
     253             : 
     254             :     // forward decls for polymorphic support
     255             :     template <class Archive, class T> struct polymorphic_serialization_support;
     256             :     struct adl_tag;
     257             : 
     258             :     // used during saving pointers
     259             :     static const int32_t msb_32bit  = 0x80000000;
     260             :     static const int32_t msb2_32bit = 0x40000000;
     261             :   }
     262             : 
     263             :   // ######################################################################
     264             :   //! A wrapper around size metadata
     265             :   /*! This class provides a way for archives to have more flexibility over how
     266             :       they choose to serialize size metadata for containers.  For some archive
     267             :       types, the size may be implicitly encoded in the output (e.g. JSON) and
     268             :       not need an explicit entry.  Specializing serialize or load/save for
     269             :       your archive and SizeTags allows you to choose what happens.
     270             : 
     271             :       @internal */
     272             :   template <class T>
     273             :   class SizeTag
     274             :   {
     275             :     private:
     276             :       // Store a reference if passed an lvalue reference, otherwise
     277             :       // make a copy of the data
     278             :       using Type = typename std::conditional<std::is_lvalue_reference<T>::value,
     279             :                                              T,
     280             :                                              typename std::decay<T>::type>::type;
     281             : 
     282             :       SizeTag & operator=( SizeTag const & ) = delete;
     283             : 
     284             :     public:
     285      321604 :       SizeTag( T && sz ) : size(std::forward<T>(sz)) {}
     286             : 
     287             :       Type size;
     288             :   };
     289             : 
     290             :   // ######################################################################
     291             :   //! A wrapper around a key and value for serializing data into maps.
     292             :   /*! This class just provides a grouping of keys and values into a struct for
     293             :       human readable archives. For example, XML archives will use this wrapper
     294             :       to write maps like so:
     295             : 
     296             :       @code{.xml}
     297             :       <mymap>
     298             :         <item0>
     299             :           <key>MyFirstKey</key>
     300             :           <value>MyFirstValue</value>
     301             :         </item0>
     302             :         <item1>
     303             :           <key>MySecondKey</key>
     304             :           <value>MySecondValue</value>
     305             :         </item1>
     306             :       </mymap>
     307             :       @endcode
     308             : 
     309             :       \sa make_map_item
     310             :       @internal */
     311             :   template <class Key, class Value>
     312             :   struct MapItem
     313             :   {
     314             :     using KeyType = typename std::conditional<
     315             :       std::is_lvalue_reference<Key>::value,
     316             :       Key,
     317             :       typename std::decay<Key>::type>::type;
     318             : 
     319             :     using ValueType = typename std::conditional<
     320             :       std::is_lvalue_reference<Value>::value,
     321             :       Value,
     322             :       typename std::decay<Value>::type>::type;
     323             : 
     324             :     //! Construct a MapItem from a key and a value
     325             :     /*! @internal */
     326     2540708 :     MapItem( Key && key_, Value && value_ ) : key(std::forward<Key>(key_)), value(std::forward<Value>(value_)) {}
     327             : 
     328             :     MapItem & operator=( MapItem const & ) = delete;
     329             : 
     330             :     KeyType key;
     331             :     ValueType value;
     332             : 
     333             :     //! Serialize the MapItem with the NVPs "key" and "value"
     334             :     template <class Archive> inline
     335     2540708 :     void CEREAL_SERIALIZE_FUNCTION_NAME(Archive & archive)
     336             :     {
     337     2540708 :       archive( make_nvp<Archive>("key",   key),
     338     2540708 :                make_nvp<Archive>("value", value) );
     339     2540708 :     }
     340             :   };
     341             : 
     342             :   //! Create a MapItem so that human readable archives will group keys and values together
     343             :   /*! @internal
     344             :       @relates MapItem */
     345             :   template <class KeyType, class ValueType> inline
     346     2540708 :   MapItem<KeyType, ValueType> make_map_item(KeyType && key, ValueType && value)
     347             :   {
     348     2540708 :     return {std::forward<KeyType>(key), std::forward<ValueType>(value)};
     349             :   }
     350             : 
     351             :   namespace detail
     352             :   {
     353             :     //! Tag for Version, which due to its anonymous namespace, becomes a different
     354             :     //! type in each translation unit
     355             :     /*! This allows CEREAL_CLASS_VERSION to be safely called in a header file */
     356             :     namespace{ struct version_binding_tag {}; }
     357             : 
     358             :     // ######################################################################
     359             :     //! Version information class
     360             :     /*! This is the base case for classes that have not been explicitly
     361             :         registered */
     362             :     template <class T, class BindingTag = version_binding_tag> struct Version
     363             :     {
     364             :       static const std::uint32_t version = 0;
     365             :       // we don't need to explicitly register these types since they
     366             :       // always get a version number of 0
     367             :     };
     368             : 
     369             :     //! Holds all registered version information
     370           4 :     struct Versions
     371             :     {
     372             :       std::unordered_map<std::size_t, std::uint32_t> mapping;
     373             : 
     374        6800 :       std::uint32_t find( std::size_t hash, std::uint32_t version )
     375             :       {
     376        6800 :         const auto result = mapping.emplace( hash, version );
     377        6800 :         return result.first->second;
     378             :       }
     379             :     }; // struct Versions
     380             :   } // namespace detail
     381             : } // namespace cereal
     382             : 
     383             : #endif // CEREAL_DETAILS_HELPERS_HPP_

Generated by: LCOV version 1.11