LCOV - code coverage report
Current view: top level - cereal - access.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 44 46 95.7 %
Date: 2017-02-12 13:57:59 Functions: 417 435 95.9 %

          Line data    Source code
       1             : /*! \file access.hpp
       2             :     \brief Access control, default construction, and serialization disambiguation */
       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_ACCESS_HPP_
      30             : #define CEREAL_ACCESS_HPP_
      31             : 
      32             : #include <type_traits>
      33             : #include <iostream>
      34             : #include <cstdint>
      35             : #include <functional>
      36             : 
      37             : #include "cereal/macros.hpp"
      38             : #include "cereal/details/helpers.hpp"
      39             : 
      40             : namespace cereal
      41             : {
      42             :   // ######################################################################
      43             :   //! A class that allows cereal to load smart pointers to types that have no default constructor
      44             :   /*! If your class does not have a default constructor, cereal will not be able
      45             :       to load any smart pointers to it unless you overload LoadAndConstruct
      46             :       for your class, and provide an appropriate load_and_construct method.  You can also
      47             :       choose to define a member static function instead of specializing this class.
      48             : 
      49             :       The specialization of LoadAndConstruct must be placed within the cereal namespace:
      50             : 
      51             :       @code{.cpp}
      52             :       struct MyType
      53             :       {
      54             :         MyType( int x ); // note: no default ctor
      55             :         int myX;
      56             : 
      57             :         // Define a serialize or load/save pair as you normally would
      58             :         template <class Archive>
      59             :         void serialize( Archive & ar )
      60             :         {
      61             :           ar( myX );
      62             :         }
      63             :       };
      64             : 
      65             :       // Provide a specialization for LoadAndConstruct for your type
      66             :       namespace cereal
      67             :       {
      68             :         template <> struct LoadAndConstruct<MyType>
      69             :         {
      70             :           // load_and_construct will be passed the archive that you will be loading
      71             :           // from as well as a construct object which you can use as if it were the
      72             :           // constructor for your type.  cereal will handle all memory management for you.
      73             :           template <class Archive>
      74             :           static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct )
      75             :           {
      76             :             int x;
      77             :             ar( x );
      78             :             construct( x );
      79             :           }
      80             : 
      81             :           // if you require versioning, simply add a const std::uint32_t as the final parameter, e.g.:
      82             :           // load_and_construct( Archive & ar, cereal::construct<MyType> & construct, std::uint32_t const version )
      83             :         };
      84             :       } // end namespace cereal
      85             :       @endcode
      86             : 
      87             :       Please note that just as in using external serialization functions, you cannot get
      88             :       access to non-public members of your class by befriending cereal::access.  If you
      89             :       have the ability to modify the class you wish to serialize, it is recommended that you
      90             :       use member serialize functions and a static member load_and_construct function.
      91             : 
      92             :       load_and_construct functions, regardless of whether they are static members of your class or
      93             :       whether you create one in the LoadAndConstruct specialization, have the following signature:
      94             : 
      95             :       @code{.cpp}
      96             :       // generally Archive will be templated, but it can be specific if desired
      97             :       template <class Archive>
      98             :       static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct );
      99             :       // with an optional last parameter specifying the version: const std::uint32_t version
     100             :       @endcode
     101             : 
     102             :       Versioning behaves the same way as it does for standard serialization functions.
     103             : 
     104             :       @tparam T The type to specialize for
     105             :       @ingroup Access */
     106             :   template <class T>
     107             :   struct LoadAndConstruct
     108             :   { };
     109             : 
     110             :   // forward decl for construct
     111             :   //! @cond PRIVATE_NEVERDEFINED
     112             :   namespace memory_detail{ template <class Ar, class T> struct LoadAndConstructLoadWrapper; }
     113             :   //! @endcond
     114             : 
     115             :   //! Used to construct types with no default constructor
     116             :   /*! When serializing a type that has no default constructor, cereal
     117             :       will attempt to call either the class static function load_and_construct
     118             :       or the appropriate template specialization of LoadAndConstruct.  cereal
     119             :       will pass that function a reference to the archive as well as a reference
     120             :       to a construct object which should be used to perform the allocation once
     121             :       data has been appropriately loaded.
     122             : 
     123             :       @code{.cpp}
     124             :       struct MyType
     125             :       {
     126             :         // note the lack of default constructor
     127             :         MyType( int xx, int yy );
     128             : 
     129             :         int x, y;
     130             :         double notInConstructor;
     131             : 
     132             :         template <class Archive>
     133             :         void serialize( Archive & ar )
     134             :         {
     135             :           ar( x, y );
     136             :           ar( notInConstructor );
     137             :         }
     138             : 
     139             :         template <class Archive>
     140             :         static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct )
     141             :         {
     142             :           int x, y;
     143             :           ar( x, y );
     144             : 
     145             :           // use construct object to initialize with loaded data
     146             :           construct( x, y );
     147             : 
     148             :           // access to member variables and functions via -> operator
     149             :           ar( construct->notInConstructor );
     150             : 
     151             :           // could also do the above section by:
     152             :           double z;
     153             :           ar( z );
     154             :           construct->notInConstructor = z;
     155             :         }
     156             :       };
     157             :       @endcode
     158             : 
     159             :       @tparam T The class type being serialized
     160             :       */
     161             :   template <class T>
     162        4800 :   class construct
     163             :   {
     164             :     public:
     165             :       //! Construct and initialize the type T with the given arguments
     166             :       /*! This will forward all arguments to the underlying type T,
     167             :           calling an appropriate constructor.
     168             : 
     169             :           Calling this function more than once will result in an exception
     170             :           being thrown.
     171             : 
     172             :           @param args The arguments to the constructor for T
     173             :           @throw Exception If called more than once */
     174             :       template <class ... Args>
     175             :       void operator()( Args && ... args );
     176             :       // implementation deferred due to reliance on cereal::access
     177             : 
     178             :       //! Get a reference to the initialized underlying object
     179             :       /*! This must be called after the object has been initialized.
     180             : 
     181             :           @return A reference to the initialized object
     182             :           @throw Exception If called before initialization */
     183         800 :       T * operator->()
     184             :       {
     185         800 :         if( !itsValid )
     186           0 :           throw Exception("Object must be initialized prior to accessing members");
     187             : 
     188         800 :         return itsPtr;
     189             :       }
     190             : 
     191             :       //! Returns a raw pointer to the initialized underlying object
     192             :       /*! This is mainly intended for use with passing an instance of
     193             :           a constructed object to cereal::base_class.
     194             : 
     195             :           It is strongly recommended to avoid using this function in
     196             :           any other circumstance.
     197             : 
     198             :           @return A raw pointer to the initialized type */
     199             :       T * ptr()
     200             :       {
     201             :         return operator->();
     202             :       }
     203             : 
     204             :     private:
     205             :       template <class A, class B> friend struct ::cereal::memory_detail::LoadAndConstructLoadWrapper;
     206             : 
     207        6800 :       construct( T * p ) : itsPtr( p ), itsEnableSharedRestoreFunction( [](){} ), itsValid( false ) {}
     208        1200 :       construct( T * p, std::function<void()> enableSharedFunc ) : // g++4.7 ice with default lambda to std func
     209        1200 :         itsPtr( p ), itsEnableSharedRestoreFunction( enableSharedFunc ), itsValid( false ) {}
     210             :       construct( construct const & ) = delete;
     211             :       construct & operator=( construct const & ) = delete;
     212             : 
     213             :       T * itsPtr;
     214             :       std::function<void()> itsEnableSharedRestoreFunction;
     215             :       bool itsValid;
     216             :   };
     217             : 
     218             :   // ######################################################################
     219             :   //! A class that can be made a friend to give cereal access to non public functions
     220             :   /*! If you desire non-public serialization functions within a class, cereal can only
     221             :       access these if you declare cereal::access a friend.
     222             : 
     223             :       @code{.cpp}
     224             :       class MyClass
     225             :       {
     226             :         private:
     227             :           friend class cereal::access; // gives access to the private serialize
     228             : 
     229             :           template <class Archive>
     230             :           void serialize( Archive & ar )
     231             :           {
     232             :             // some code
     233             :           }
     234             :       };
     235             :       @endcode
     236             :       @ingroup Access */
     237             :   class access
     238             :   {
     239             :     public:
     240             :       // ####### Standard Serialization ########################################
     241             :       template<class Archive, class T> inline
     242     5046672 :       static auto member_serialize(Archive & ar, T & t) -> decltype(t.CEREAL_SERIALIZE_FUNCTION_NAME(ar))
     243     5046672 :       { return t.CEREAL_SERIALIZE_FUNCTION_NAME(ar); }
     244             : 
     245             :       template<class Archive, class T> inline
     246      843780 :       static auto member_save(Archive & ar, T const & t) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar))
     247      843780 :       { return t.CEREAL_SAVE_FUNCTION_NAME(ar); }
     248             : 
     249             :       template<class Archive, class T> inline
     250             :       static auto member_save_non_const(Archive & ar, T & t) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar))
     251             :       { return t.CEREAL_SAVE_FUNCTION_NAME(ar); }
     252             : 
     253             :       template<class Archive, class T> inline
     254      843780 :       static auto member_load(Archive & ar, T & t) -> decltype(t.CEREAL_LOAD_FUNCTION_NAME(ar))
     255      843780 :       { return t.CEREAL_LOAD_FUNCTION_NAME(ar); }
     256             : 
     257             :       template<class Archive, class T> inline
     258        1200 :       static auto member_save_minimal(Archive const & ar, T const & t) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar))
     259        1200 :       { return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar); }
     260             : 
     261             :       template<class Archive, class T> inline
     262             :       static auto member_save_minimal_non_const(Archive const & ar, T & t) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar))
     263             :       { return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar); }
     264             : 
     265             :       template<class Archive, class T, class U> inline
     266        1200 :       static auto member_load_minimal(Archive const & ar, T & t, U && u) -> decltype(t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u)))
     267        1200 :       { return t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u)); }
     268             : 
     269             :       // ####### Versioned Serialization #######################################
     270             :       template<class Archive, class T> inline
     271        3200 :       static auto member_serialize(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_SERIALIZE_FUNCTION_NAME(ar, version))
     272        3200 :       { return t.CEREAL_SERIALIZE_FUNCTION_NAME(ar, version); }
     273             : 
     274             :       template<class Archive, class T> inline
     275        1200 :       static auto member_save(Archive & ar, T const & t, const std::uint32_t version ) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar, version))
     276        1200 :       { return t.CEREAL_SAVE_FUNCTION_NAME(ar, version); }
     277             : 
     278             :       template<class Archive, class T> inline
     279             :       static auto member_save_non_const(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar, version))
     280             :       { return t.CEREAL_SAVE_FUNCTION_NAME(ar, version); }
     281             : 
     282             :       template<class Archive, class T> inline
     283        1200 :       static auto member_load(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_LOAD_FUNCTION_NAME(ar, version))
     284        1200 :       { return t.CEREAL_LOAD_FUNCTION_NAME(ar, version); }
     285             : 
     286             :       template<class Archive, class T> inline
     287         800 :       static auto member_save_minimal(Archive const & ar, T const & t, const std::uint32_t version) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version))
     288         800 :       { return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version); }
     289             : 
     290             :       template<class Archive, class T> inline
     291             :       static auto member_save_minimal_non_const(Archive const & ar, T & t, const std::uint32_t version) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version))
     292             :       { return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version); }
     293             : 
     294             :       template<class Archive, class T, class U> inline
     295         800 :       static auto member_load_minimal(Archive const & ar, T & t, U && u, const std::uint32_t version) -> decltype(t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u), version))
     296         800 :       { return t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u), version); }
     297             : 
     298             :       // ####### Other Functionality ##########################################
     299             :       // for detecting inheritance from enable_shared_from_this
     300             :       template <class T> inline
     301             :       static auto shared_from_this(T & t) -> decltype(t.shared_from_this());
     302             : 
     303             :       // for placement new
     304             :       template <class T, class ... Args> inline
     305        4400 :       static void construct( T *& ptr, Args && ... args )
     306             :       {
     307        4400 :         new (ptr) T( std::forward<Args>( args )... );
     308        4400 :       }
     309             : 
     310             :       // for non-placement new with a default constructor
     311             :       template <class T> inline
     312       83204 :       static T * construct()
     313             :       {
     314       83204 :         return new T();
     315             :       }
     316             : 
     317             :       template <class T> inline
     318             :       static std::false_type load_and_construct(...)
     319             :       { return std::false_type(); }
     320             : 
     321             :       template<class T, class Archive> inline
     322        3200 :       static auto load_and_construct(Archive & ar, ::cereal::construct<T> & construct) -> decltype(T::load_and_construct(ar, construct))
     323             :       {
     324        3200 :         T::load_and_construct( ar, construct );
     325        2800 :       }
     326             : 
     327             :       template<class T, class Archive> inline
     328         400 :       static auto load_and_construct(Archive & ar, ::cereal::construct<T> & construct, const std::uint32_t version) -> decltype(T::load_and_construct(ar, construct, version))
     329             :       {
     330         400 :         T::load_and_construct( ar, construct, version );
     331         400 :       }
     332             :   }; // end class access
     333             : 
     334             :   // ######################################################################
     335             :   //! A specifier used in conjunction with cereal::specialize to disambiguate
     336             :   //! serialization in special cases
     337             :   /*! @relates specialize
     338             :       @ingroup Access */
     339             :   enum class specialization
     340             :   {
     341             :     member_serialize,            //!< Force the use of a member serialize function
     342             :     member_load_save,            //!< Force the use of a member load/save pair
     343             :     member_load_save_minimal,    //!< Force the use of a member minimal load/save pair
     344             :     non_member_serialize,        //!< Force the use of a non-member serialize function
     345             :     non_member_load_save,        //!< Force the use of a non-member load/save pair
     346             :     non_member_load_save_minimal //!< Force the use of a non-member minimal load/save pair
     347             :   };
     348             : 
     349             :   //! A class used to disambiguate cases where cereal cannot detect a unique way of serializing a class
     350             :   /*! cereal attempts to figure out which method of serialization (member vs. non-member serialize
     351             :       or load/save pair) at compile time.  If for some reason cereal cannot find a non-ambiguous way
     352             :       of serializing a type, it will produce a static assertion complaining about this.
     353             : 
     354             :       This can happen because you have both a serialize and load/save pair, or even because a base
     355             :       class has a serialize (public or private with friend access) and a derived class does not
     356             :       overwrite this due to choosing some other serialization type.
     357             : 
     358             :       Specializing this class will tell cereal to explicitly use the serialization type you specify
     359             :       and it will not complain about ambiguity in its compile time selection.  However, if cereal detects
     360             :       an ambiguity in specializations, it will continue to issue a static assertion.
     361             : 
     362             :       @code{.cpp}
     363             :       class MyParent
     364             :       {
     365             :         friend class cereal::access;
     366             :         template <class Archive>
     367             :         void serialize( Archive & ar ) {}
     368             :       };
     369             : 
     370             :       // Although serialize is private in MyParent, to cereal::access it will look public,
     371             :       // even through MyDerived
     372             :       class MyDerived : public MyParent
     373             :       {
     374             :         public:
     375             :           template <class Archive>
     376             :           void load( Archive & ar ) {}
     377             : 
     378             :           template <class Archive>
     379             :           void save( Archive & ar ) {}
     380             :       };
     381             : 
     382             :       // The load/save pair in MyDerived is ambiguous because serialize in MyParent can
     383             :       // be accessed from cereal::access.  This looks the same as making serialize public
     384             :       // in MyParent, making it seem as though MyDerived has both a serialize and a load/save pair.
     385             :       // cereal will complain about this at compile time unless we disambiguate:
     386             : 
     387             :       namespace cereal
     388             :       {
     389             :         // This struct specialization will tell cereal which is the right way to serialize the ambiguity
     390             :         template <class Archive> struct specialize<Archive, MyDerived, cereal::specialization::member_load_save> {};
     391             : 
     392             :         // If we only had a disambiguation for a specific archive type, it would look something like this
     393             :         template <> struct specialize<cereal::BinaryOutputArchive, MyDerived, cereal::specialization::member_load_save> {};
     394             :       }
     395             :       @endcode
     396             : 
     397             :       You can also choose to use the macros CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES or
     398             :       CEREAL_SPECIALIZE_FOR_ARCHIVE if you want to type a little bit less.
     399             : 
     400             :       @tparam T The type to specialize the serialization for
     401             :       @tparam S The specialization type to use for T
     402             :       @ingroup Access */
     403             :   template <class Archive, class T, specialization S>
     404             :   struct specialize : public std::false_type {};
     405             : 
     406             :   //! Convenient macro for performing specialization for all archive types
     407             :   /*! This performs specialization for the specific type for all types of archives.
     408             :       This macro should be placed at the global namespace.
     409             : 
     410             :       @code{cpp}
     411             :       struct MyType {};
     412             :       CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( MyType, cereal::specialization::member_load_save );
     413             :       @endcode
     414             : 
     415             :       @relates specialize
     416             :       @ingroup Access */
     417             :   #define CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( Type, Specialization )                                \
     418             :   namespace cereal { template <class Archive> struct specialize<Archive, Type, Specialization> {}; }
     419             : 
     420             :   //! Convenient macro for performing specialization for a single archive type
     421             :   /*! This performs specialization for the specific type for a single type of archive.
     422             :       This macro should be placed at the global namespace.
     423             : 
     424             :       @code{cpp}
     425             :       struct MyType {};
     426             :       CEREAL_SPECIALIZE_FOR_ARCHIVE( cereal::XMLInputArchive, MyType, cereal::specialization::member_load_save );
     427             :       @endcode
     428             : 
     429             :       @relates specialize
     430             :       @ingroup Access */
     431             :   #define CEREAL_SPECIALIZE_FOR_ARCHIVE( Archive, Type, Specialization )               \
     432             :   namespace cereal { template <> struct specialize<Archive, Type, Specialization> {}; }
     433             : 
     434             :   // ######################################################################
     435             :   // Deferred Implementation, see construct for more information
     436             :   template <class T> template <class ... Args> inline
     437        4400 :   void construct<T>::operator()( Args && ... args )
     438             :   {
     439        4400 :     if( itsValid )
     440           0 :       throw Exception("Attempting to construct an already initialized object");
     441             : 
     442        4400 :     ::cereal::access::construct( itsPtr, std::forward<Args>( args )... );
     443        4400 :     itsEnableSharedRestoreFunction();
     444        4400 :     itsValid = true;
     445        4400 :   }
     446             : } // namespace cereal
     447             : 
     448             : #endif // CEREAL_ACCESS_HPP_

Generated by: LCOV version 1.11