LCOV - code coverage report

Current view: | top level - cereal/details - helpers.hpp (source / functions) |  |  | Hit | Total | Coverage
Test: | coverage.info |  | Lines: | 23 | 26 | 88.5 %
Date: | 2022-01-16 21:05:07 |  | Functions: | 1183 | 1235 | 95.8 %

              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 the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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         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             :     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     4450698 :       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     1480734 :   make_nvp( const char *, T && value )
         180             :   {
         181     1480734 :     return std::forward<T>(value);
         182             :   }
         183             :
         184             :   //! A specialization of make_nvp<> that actually creates an nvp for non-binary archives
         185             :   /*! @relates NameValuePair
         186             :       @internal */
         187             :   template<class Archive, class T> inline
         188             :   typename
         189             :   std::enable_if<!std::is_same<Archive, ::cereal::BinaryInputArchive>::value &&
         190             :                  !std::is_same<Archive, ::cereal::BinaryOutputArchive>::value,
         191             :   NameValuePair<T> >::type
         192     4446698 :   make_nvp( const char * name, T && value)
         193             :   {
         194     4446698 :     return {name, std::forward<T>(value)};
         195             :   }
         196             :
         197             :   //! Convenience for creating a templated NVP
         198             :   /*! For use in internal generic typing functions which have an
         199             :       Archive type declared
         200             :       @internal */
         201             :   #define CEREAL_NVP_(name, value) ::cereal::make_nvp<Archive>(name, value)
         202             :
         203             :   // ######################################################################
         204             :   //! A wrapper around data that can be serialized in a binary fashion
         205             :   /*! This class is used to demarcate data that can safely be serialized
         206             :       as a binary chunk of data.  Individual archives can then choose how
         207             :       best represent this during serialization.
         208             :
         209             :       @internal */
         210             :   template <class T>
         211             :   struct BinaryData
         212             :   {
         213             :     //! Internally store the pointer as a void *, keeping const if created with
         214             :     //! a const pointer
         215             :     using PT = typename std::conditional<std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
         216             :                                          const void *,
         217             :                                          void *>::type;
         218             :
         219      287486 :     BinaryData( T && d, uint64_t s ) : data(std::forward<T>(d)), size(s) {}
         220             :
         221             :     PT data;       //!< pointer to beginning of data
         222             :     uint64_t size; //!< size in bytes
         223             :   };
         224             :
         225             :   // ######################################################################
         226             :   //! A wrapper around data that should be serialized after all non-deferred data
         227             :   /*! This class is used to demarcate data that can only be safely serialized after
         228             :       any data not wrapped in this class.
         229             :
         230             :       @internal */
         231             :   template <class T>
         232             :   class DeferredData : detail::DeferredDataCore
         233             :   {
         234             :     private:
         235             :       // If we get passed an array, keep the type as is, otherwise store
         236             :       // a reference if we were passed an l value reference, else copy the value
         237             :       using Type = typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
         238             :                                              typename std::remove_cv<T>::type,
         239             :                                              typename std::conditional<std::is_lvalue_reference<T>::value,
         240             :                                                                        T,
         241             :                                                                        typename std::decay<T>::type>::type>::type;
         242             :
         243             :       // prevent nested nvps
         244             :       static_assert( !std::is_base_of<detail::DeferredDataCore, T>::value,
         245             :                      "Cannot defer DeferredData" );
         246             :
         247             :       DeferredData & operator=( DeferredData const & ) = delete;
         248             :
         249             :     public:
         250             :       //! Constructs a new NameValuePair
         251             :       /*! @param v The value to defer.  Ideally this should be an l-value reference so that
         252             :                    the value can be both loaded and saved to.  If you pass an r-value reference,
         253             :                    the DeferredData will store a copy of it instead of a reference.  Thus you should
         254             :                    only pass r-values in cases where this makes sense, such as the result of some
         255             :                    size() call.
         256             :           @internal */
         257        8000 :       DeferredData( T && v ) : value(std::forward<T>(v)) {}
         258             :
         259             :       Type value;
         260             :   };
         261             :
         262             :   // ######################################################################
         263             :   namespace detail
         264             :   {
         265             :     // base classes for type checking
         266             :     /* The rtti virtual function only exists to enable an archive to
         267             :        be used in a polymorphic fashion, if necessary.  See the
         268             :        archive adapters for an example of this */
         269             :     class OutputArchiveBase
         270             :     {
         271             :       public:
         272       15160 :         OutputArchiveBase() = default;
         273             :         OutputArchiveBase( OutputArchiveBase && ) CEREAL_NOEXCEPT {}
         274             :         OutputArchiveBase & operator=( OutputArchiveBase && ) CEREAL_NOEXCEPT { return *this; }
         275       15160 :         virtual ~OutputArchiveBase() CEREAL_NOEXCEPT = default;
         276             :
         277             :       private:
         278           0 :         virtual void rtti() {}
         279             :     };
         280             :
         281             :     class InputArchiveBase
         282             :     {
         283             :       public:
         284       15560 :         InputArchiveBase() = default;
         285             :         InputArchiveBase( InputArchiveBase && ) CEREAL_NOEXCEPT {}
         286             :         InputArchiveBase & operator=( InputArchiveBase && ) CEREAL_NOEXCEPT { return *this; }
         287       15560 :         virtual ~InputArchiveBase() CEREAL_NOEXCEPT = default;
         288             :
         289             :       private:
         290           0 :         virtual void rtti() {}
         291             :     };
         292             :
         293             :     // forward decls for polymorphic support
         294             :     template <class Archive, class T> struct polymorphic_serialization_support;
         295             :     struct adl_tag;
         296             :
         297             :     // used during saving pointers
         298             :     static const uint32_t msb_32bit  = 0x80000000;
         299             :     static const int32_t msb2_32bit = 0x40000000;
         300             :   }
         301             :
         302             :   // ######################################################################
         303             :   //! A wrapper around size metadata
         304             :   /*! This class provides a way for archives to have more flexibility over how
         305             :       they choose to serialize size metadata for containers.  For some archive
         306             :       types, the size may be implicitly encoded in the output (e.g. JSON) and
         307             :       not need an explicit entry.  Specializing serialize or load/save for
         308             :       your archive and SizeTags allows you to choose what happens.
         309             :
         310             :       @internal */
         311             :   template <class T>
         312             :   class SizeTag
         313             :   {
         314             :     private:
         315             :       // Store a reference if passed an lvalue reference, otherwise
         316             :       // make a copy of the data
         317             :       using Type = typename std::conditional<std::is_lvalue_reference<T>::value,
         318             :                                              T,
         319             :                                              typename std::decay<T>::type>::type;
         320             :
         321             :       SizeTag & operator=( SizeTag const & ) = delete;
         322             :
         323             :     public:
         324      367086 :       SizeTag( T && sz ) : size(std::forward<T>(sz)) {}
         325             :
         326             :       Type size;
         327             :   };
         328             :
         329             :   // ######################################################################
         330             :   //! A wrapper around a key and value for serializing data into maps.
         331             :   /*! This class just provides a grouping of keys and values into a struct for
         332             :       human readable archives. For example, XML archives will use this wrapper
         333             :       to write maps like so:
         334             :
         335             :       @code{.xml}
         336             :       <mymap>
         337             :         <item0>
         338             :           <key>MyFirstKey</key>
         339             :           <value>MyFirstValue</value>
         340             :         </item0>
         341             :         <item1>
         342             :           <key>MySecondKey</key>
         343             :           <value>MySecondValue</value>
         344             :         </item1>
         345             :       </mymap>
         346             :       @endcode
         347             :
         348             :       \sa make_map_item
         349             :       @internal */
         350             :   template <class Key, class Value>
         351             :   struct MapItem
         352             :   {
         353             :     using KeyType = typename std::conditional<
         354             :       std::is_lvalue_reference<Key>::value,
         355             :       Key,
         356             :       typename std::decay<Key>::type>::type;
         357             :
         358             :     using ValueType = typename std::conditional<
         359             :       std::is_lvalue_reference<Value>::value,
         360             :       Value,
         361             :       typename std::decay<Value>::type>::type;
         362             :
         363             :     //! Construct a MapItem from a key and a value
         364             :     /*! @internal */
         365     2540352 :     MapItem( Key && key_, Value && value_ ) : key(std::forward<Key>(key_)), value(std::forward<Value>(value_)) {}
         366             :
         367             :     MapItem & operator=( MapItem const & ) = delete;
         368             :
         369             :     KeyType key;
         370             :     ValueType value;
         371             :
         372             :     //! Serialize the MapItem with the NVPs "key" and "value"
         373             :     template <class Archive> inline
         374     2540352 :     void CEREAL_SERIALIZE_FUNCTION_NAME(Archive & archive)
         375             :     {
         376     2540352 :       archive( make_nvp<Archive>("key",   key),
         377     2540352 :                make_nvp<Archive>("value", value) );
         378     2540352 :     }
         379             :   };
         380             :
         381             :   //! Create a MapItem so that human readable archives will group keys and values together
         382             :   /*! @internal
         383             :       @relates MapItem */
         384             :   template <class KeyType, class ValueType> inline
         385     2540352 :   MapItem<KeyType, ValueType> make_map_item(KeyType && key, ValueType && value)
         386             :   {
         387     2540352 :     return {std::forward<KeyType>(key), std::forward<ValueType>(value)};
         388             :   }
         389             :
         390             :   namespace detail
         391             :   {
         392             :     //! Tag for Version, which due to its anonymous namespace, becomes a different
         393             :     //! type in each translation unit
         394             :     /*! This allows CEREAL_CLASS_VERSION to be safely called in a header file */
         395             :     namespace{ struct version_binding_tag {}; }
         396             :
         397             :     // ######################################################################
         398             :     //! Version information class
         399             :     /*! This is the base case for classes that have not been explicitly
         400             :         registered */
         401             :     template <class T, class BindingTag = version_binding_tag> struct Version
         402             :     {
         403             :       static const std::uint32_t version = 0;
         404             :       // we don't need to explicitly register these types since they
         405             :       // always get a version number of 0
         406             :     };
         407             :
         408             :     //! Holds all registered version information
         409             :     struct Versions
         410             :     {
         411             :       std::unordered_map<std::size_t, std::uint32_t> mapping;
         412             :
         413        7600 :       std::uint32_t find( std::size_t hash, std::uint32_t version )
         414             :       {
         415        7600 :         const auto result = mapping.emplace( hash, version );
         416        7600 :         return result.first->second;
         417             :       }
         418             :     }; // struct Versions
         419             :   } // namespace detail
         420             : } // namespace cereal
         421             :
         422             : #endif // CEREAL_DETAILS_HELPERS_HPP_

Generated by: LCOV version 1.14