access.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /*! \file access.hpp
  2. \brief Access control and default construction */
  3. /*
  4. Copyright (c) 2014, Randolph Voorhies, Shane Grant
  5. All rights reserved.
  6. Redistribution and use in source and binary forms, with or without
  7. modification, are permitted provided that the following conditions are met:
  8. * Redistributions of source code must retain the above copyright
  9. notice, this list of conditions and the following disclaimer.
  10. * Redistributions in binary form must reproduce the above copyright
  11. notice, this list of conditions and the following disclaimer in the
  12. documentation and/or other materials provided with the distribution.
  13. * Neither the name of the copyright holder nor the
  14. names of its contributors may be used to endorse or promote products
  15. derived from this software without specific prior written permission.
  16. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  17. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
  20. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #ifndef CEREAL_ACCESS_HPP_
  28. #define CEREAL_ACCESS_HPP_
  29. #include <type_traits>
  30. #include <iostream>
  31. #include <cstdint>
  32. #include <functional>
  33. #include "cereal/macros.hpp"
  34. #include "cereal/specialize.hpp"
  35. #include "cereal/details/helpers.hpp"
  36. namespace cereal
  37. {
  38. // ######################################################################
  39. //! A class that allows cereal to load smart pointers to types that have no default constructor
  40. /*! If your class does not have a default constructor, cereal will not be able
  41. to load any smart pointers to it unless you overload LoadAndConstruct
  42. for your class, and provide an appropriate load_and_construct method. You can also
  43. choose to define a member static function instead of specializing this class.
  44. The specialization of LoadAndConstruct must be placed within the cereal namespace:
  45. @code{.cpp}
  46. struct MyType
  47. {
  48. MyType( int x ); // note: no default ctor
  49. int myX;
  50. // Define a serialize or load/save pair as you normally would
  51. template <class Archive>
  52. void serialize( Archive & ar )
  53. {
  54. ar( myX );
  55. }
  56. };
  57. // Provide a specialization for LoadAndConstruct for your type
  58. namespace cereal
  59. {
  60. template <> struct LoadAndConstruct<MyType>
  61. {
  62. // load_and_construct will be passed the archive that you will be loading
  63. // from as well as a construct object which you can use as if it were the
  64. // constructor for your type. cereal will handle all memory management for you.
  65. template <class Archive>
  66. static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct )
  67. {
  68. int x;
  69. ar( x );
  70. construct( x );
  71. }
  72. // if you require versioning, simply add a const std::uint32_t as the final parameter, e.g.:
  73. // load_and_construct( Archive & ar, cereal::construct<MyType> & construct, std::uint32_t const version )
  74. };
  75. } // end namespace cereal
  76. @endcode
  77. Please note that just as in using external serialization functions, you cannot get
  78. access to non-public members of your class by befriending cereal::access. If you
  79. have the ability to modify the class you wish to serialize, it is recommended that you
  80. use member serialize functions and a static member load_and_construct function.
  81. load_and_construct functions, regardless of whether they are static members of your class or
  82. whether you create one in the LoadAndConstruct specialization, have the following signature:
  83. @code{.cpp}
  84. // generally Archive will be templated, but it can be specific if desired
  85. template <class Archive>
  86. static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct );
  87. // with an optional last parameter specifying the version: const std::uint32_t version
  88. @endcode
  89. Versioning behaves the same way as it does for standard serialization functions.
  90. @tparam T The type to specialize for
  91. @ingroup Access */
  92. template <class T>
  93. struct LoadAndConstruct
  94. { };
  95. // forward decl for construct
  96. //! @cond PRIVATE_NEVERDEFINED
  97. namespace memory_detail{ template <class Ar, class T> struct LoadAndConstructLoadWrapper; }
  98. namespace boost_variant_detail{ template <class Ar, class T> struct LoadAndConstructLoadWrapper; }
  99. //! @endcond
  100. //! Used to construct types with no default constructor
  101. /*! When serializing a type that has no default constructor, cereal
  102. will attempt to call either the class static function load_and_construct
  103. or the appropriate template specialization of LoadAndConstruct. cereal
  104. will pass that function a reference to the archive as well as a reference
  105. to a construct object which should be used to perform the allocation once
  106. data has been appropriately loaded.
  107. @code{.cpp}
  108. struct MyType
  109. {
  110. // note the lack of default constructor
  111. MyType( int xx, int yy );
  112. int x, y;
  113. double notInConstructor;
  114. template <class Archive>
  115. void serialize( Archive & ar )
  116. {
  117. ar( x, y );
  118. ar( notInConstructor );
  119. }
  120. template <class Archive>
  121. static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct )
  122. {
  123. int x, y;
  124. ar( x, y );
  125. // use construct object to initialize with loaded data
  126. construct( x, y );
  127. // access to member variables and functions via -> operator
  128. ar( construct->notInConstructor );
  129. // could also do the above section by:
  130. double z;
  131. ar( z );
  132. construct->notInConstructor = z;
  133. }
  134. };
  135. @endcode
  136. @tparam T The class type being serialized
  137. */
  138. template <class T>
  139. class construct
  140. {
  141. public:
  142. //! Construct and initialize the type T with the given arguments
  143. /*! This will forward all arguments to the underlying type T,
  144. calling an appropriate constructor.
  145. Calling this function more than once will result in an exception
  146. being thrown.
  147. @param args The arguments to the constructor for T
  148. @throw Exception If called more than once */
  149. template <class ... Args>
  150. void operator()( Args && ... args );
  151. // implementation deferred due to reliance on cereal::access
  152. //! Get a reference to the initialized underlying object
  153. /*! This must be called after the object has been initialized.
  154. @return A reference to the initialized object
  155. @throw Exception If called before initialization */
  156. T * operator->()
  157. {
  158. if( !itsValid )
  159. throw Exception("Object must be initialized prior to accessing members");
  160. return itsPtr;
  161. }
  162. //! Returns a raw pointer to the initialized underlying object
  163. /*! This is mainly intended for use with passing an instance of
  164. a constructed object to cereal::base_class.
  165. It is strongly recommended to avoid using this function in
  166. any other circumstance.
  167. @return A raw pointer to the initialized type */
  168. T * ptr()
  169. {
  170. return operator->();
  171. }
  172. private:
  173. template <class Ar, class TT> friend struct ::cereal::memory_detail::LoadAndConstructLoadWrapper;
  174. template <class Ar, class TT> friend struct ::cereal::boost_variant_detail::LoadAndConstructLoadWrapper;
  175. construct( T * p ) : itsPtr( p ), itsEnableSharedRestoreFunction( [](){} ), itsValid( false ) {}
  176. construct( T * p, std::function<void()> enableSharedFunc ) : // g++4.7 ice with default lambda to std func
  177. itsPtr( p ), itsEnableSharedRestoreFunction( enableSharedFunc ), itsValid( false ) {}
  178. construct( construct const & ) = delete;
  179. construct & operator=( construct const & ) = delete;
  180. T * itsPtr;
  181. std::function<void()> itsEnableSharedRestoreFunction;
  182. bool itsValid;
  183. };
  184. // ######################################################################
  185. //! A class that can be made a friend to give cereal access to non public functions
  186. /*! If you desire non-public serialization functions within a class, cereal can only
  187. access these if you declare cereal::access a friend.
  188. @code{.cpp}
  189. class MyClass
  190. {
  191. private:
  192. friend class cereal::access; // gives access to the private serialize
  193. template <class Archive>
  194. void serialize( Archive & ar )
  195. {
  196. // some code
  197. }
  198. };
  199. @endcode
  200. @ingroup Access */
  201. class access
  202. {
  203. public:
  204. // ####### Standard Serialization ########################################
  205. template<class Archive, class T> inline
  206. static auto member_serialize(Archive & ar, T & t) -> decltype(t.CEREAL_SERIALIZE_FUNCTION_NAME(ar))
  207. { return t.CEREAL_SERIALIZE_FUNCTION_NAME(ar); }
  208. template<class Archive, class T> inline
  209. static auto member_save(Archive & ar, T const & t) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar))
  210. { return t.CEREAL_SAVE_FUNCTION_NAME(ar); }
  211. template<class Archive, class T> inline
  212. static auto member_save_non_const(Archive & ar, T & t) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar))
  213. { return t.CEREAL_SAVE_FUNCTION_NAME(ar); }
  214. template<class Archive, class T> inline
  215. static auto member_load(Archive & ar, T & t) -> decltype(t.CEREAL_LOAD_FUNCTION_NAME(ar))
  216. { return t.CEREAL_LOAD_FUNCTION_NAME(ar); }
  217. template<class Archive, class T> inline
  218. static auto member_save_minimal(Archive const & ar, T const & t) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar))
  219. { return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar); }
  220. template<class Archive, class T> inline
  221. static auto member_save_minimal_non_const(Archive const & ar, T & t) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar))
  222. { return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar); }
  223. template<class Archive, class T, class U> inline
  224. static auto member_load_minimal(Archive const & ar, T & t, U && u) -> decltype(t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u)))
  225. { return t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u)); }
  226. // ####### Versioned Serialization #######################################
  227. template<class Archive, class T> inline
  228. static auto member_serialize(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_SERIALIZE_FUNCTION_NAME(ar, version))
  229. { return t.CEREAL_SERIALIZE_FUNCTION_NAME(ar, version); }
  230. template<class Archive, class T> inline
  231. static auto member_save(Archive & ar, T const & t, const std::uint32_t version ) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar, version))
  232. { return t.CEREAL_SAVE_FUNCTION_NAME(ar, version); }
  233. template<class Archive, class T> inline
  234. static auto member_save_non_const(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar, version))
  235. { return t.CEREAL_SAVE_FUNCTION_NAME(ar, version); }
  236. template<class Archive, class T> inline
  237. static auto member_load(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_LOAD_FUNCTION_NAME(ar, version))
  238. { return t.CEREAL_LOAD_FUNCTION_NAME(ar, version); }
  239. template<class Archive, class T> inline
  240. 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))
  241. { return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version); }
  242. template<class Archive, class T> inline
  243. 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))
  244. { return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version); }
  245. template<class Archive, class T, class U> inline
  246. 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))
  247. { return t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u), version); }
  248. // ####### Other Functionality ##########################################
  249. // for detecting inheritance from enable_shared_from_this
  250. template <class T> inline
  251. static auto shared_from_this(T & t) -> decltype(t.shared_from_this());
  252. // for placement new
  253. template <class T, class ... Args> inline
  254. static void construct( T *& ptr, Args && ... args )
  255. {
  256. new (ptr) T( std::forward<Args>( args )... );
  257. }
  258. // for non-placement new with a default constructor
  259. template <class T> inline
  260. static T * construct()
  261. {
  262. return new T();
  263. }
  264. template <class T> inline
  265. static std::false_type load_and_construct(...)
  266. { return std::false_type(); }
  267. template<class T, class Archive> inline
  268. static auto load_and_construct(Archive & ar, ::cereal::construct<T> & construct) -> decltype(T::load_and_construct(ar, construct))
  269. {
  270. T::load_and_construct( ar, construct );
  271. }
  272. template<class T, class Archive> inline
  273. static auto load_and_construct(Archive & ar, ::cereal::construct<T> & construct, const std::uint32_t version) -> decltype(T::load_and_construct(ar, construct, version))
  274. {
  275. T::load_and_construct( ar, construct, version );
  276. }
  277. }; // end class access
  278. // ######################################################################
  279. // Deferred Implementation, see construct for more information
  280. template <class T> template <class ... Args> inline
  281. void construct<T>::operator()( Args && ... args )
  282. {
  283. if( itsValid )
  284. throw Exception("Attempting to construct an already initialized object");
  285. ::cereal::access::construct( itsPtr, std::forward<Args>( args )... );
  286. itsEnableSharedRestoreFunction();
  287. itsValid = true;
  288. }
  289. } // namespace cereal
  290. #endif // CEREAL_ACCESS_HPP_