cereal.hpp 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
  1. /*! \file cereal.hpp
  2. \brief Main cereal functionality */
  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_CEREAL_HPP_
  28. #define CEREAL_CEREAL_HPP_
  29. #include <type_traits>
  30. #include <string>
  31. #include <memory>
  32. #include <functional>
  33. #include <unordered_map>
  34. #include <unordered_set>
  35. #include <vector>
  36. #include <cstddef>
  37. #include <cstdint>
  38. #include <functional>
  39. #include "cereal/macros.hpp"
  40. #include "cereal/details/traits.hpp"
  41. #include "cereal/details/helpers.hpp"
  42. #include "cereal/types/base_class.hpp"
  43. namespace cereal
  44. {
  45. // ######################################################################
  46. //! Creates a name value pair
  47. /*! @relates NameValuePair
  48. @ingroup Utility */
  49. template <class T> inline
  50. NameValuePair<T> make_nvp( std::string const & name, T && value )
  51. {
  52. return {name.c_str(), std::forward<T>(value)};
  53. }
  54. //! Creates a name value pair
  55. /*! @relates NameValuePair
  56. @ingroup Utility */
  57. template <class T> inline
  58. NameValuePair<T> make_nvp( const char * name, T && value )
  59. {
  60. return {name, std::forward<T>(value)};
  61. }
  62. //! Creates a name value pair for the variable T with the same name as the variable
  63. /*! @relates NameValuePair
  64. @ingroup Utility */
  65. #define CEREAL_NVP(T) ::cereal::make_nvp(#T, T)
  66. // ######################################################################
  67. //! Convenience function to create binary data for both const and non const pointers
  68. /*! @param data Pointer to beginning of the data
  69. @param size The size in bytes of the data
  70. @relates BinaryData
  71. @ingroup Utility */
  72. template <class T> inline
  73. BinaryData<T> binary_data( T && data, size_t size )
  74. {
  75. return {std::forward<T>(data), size};
  76. }
  77. // ######################################################################
  78. //! Creates a size tag from some variable.
  79. /*! Will normally be used to serialize size (e.g. size()) information for
  80. variable size containers. If you have a variable sized container,
  81. the very first thing it serializes should be its size, wrapped in
  82. a SizeTag.
  83. @relates SizeTag
  84. @ingroup Utility */
  85. template <class T> inline
  86. SizeTag<T> make_size_tag( T && sz )
  87. {
  88. return {std::forward<T>(sz)};
  89. }
  90. // ######################################################################
  91. //! Marks data for deferred serialization
  92. /*! cereal performs a recursive depth-first traversal of data it serializes. When
  93. serializing smart pointers to large, nested, or cyclical data structures, it
  94. is possible to encounter a stack overflow from excessive recursion when following
  95. a chain of pointers.
  96. Deferment can help in these situations if the data can be serialized separately from
  97. the pointers used to traverse the structure. For example, a graph structure can have its
  98. nodes serialized before its edges:
  99. @code{.cpp}
  100. struct MyEdge
  101. {
  102. std::shared_ptr<MyNode> connection;
  103. int some_value;
  104. template<class Archive>
  105. void serialize(Archive & archive)
  106. {
  107. // when we serialize an edge, we'll defer serializing the associated node
  108. archive( cereal::defer( connection ),
  109. some_value );
  110. }
  111. };
  112. struct MyGraphStructure
  113. {
  114. std::vector<MyEdge> edges;
  115. std::vector<MyNodes> nodes;
  116. template<class Archive>
  117. void serialize(Archive & archive)
  118. {
  119. // because of the deferment, we ensure all nodes are fully serialized
  120. // before any connection pointers to those nodes are serialized
  121. archive( edges, nodes );
  122. // we have to explicitly inform the archive when it is safe to serialize
  123. // the deferred data
  124. archive.serializeDeferments();
  125. }
  126. };
  127. @endcode
  128. @relates DeferredData
  129. @ingroup Utility */
  130. template <class T> inline
  131. DeferredData<T> defer( T && value )
  132. {
  133. return {std::forward<T>(value)};
  134. }
  135. // ######################################################################
  136. //! Called before a type is serialized to set up any special archive state
  137. //! for processing some type
  138. /*! If designing a serializer that needs to set up any kind of special
  139. state or output extra information for a type, specialize this function
  140. for the archive type and the types that require the extra information.
  141. @ingroup Internal */
  142. template <class Archive, class T> inline
  143. void prologue( Archive & /* archive */, T const & /* data */)
  144. { }
  145. //! Called after a type is serialized to tear down any special archive state
  146. //! for processing some type
  147. /*! @ingroup Internal */
  148. template <class Archive, class T> inline
  149. void epilogue( Archive & /* archive */, T const & /* data */)
  150. { }
  151. // ######################################################################
  152. //! Special flags for archives
  153. /*! AllowEmptyClassElision
  154. This allows for empty classes to be serialized even if they do not provide
  155. a serialization function. Classes with no data members are considered to be
  156. empty. Be warned that if this is enabled and you attempt to serialize an
  157. empty class with improperly formed serialize or load/save functions, no
  158. static error will occur - the error will propagate silently and your
  159. intended serialization functions may not be called. You can manually
  160. ensure that your classes that have custom serialization are correct
  161. by using the traits is_output_serializable and is_input_serializable
  162. in cereal/details/traits.hpp.
  163. @ingroup Internal */
  164. enum Flags { AllowEmptyClassElision = 1 };
  165. // ######################################################################
  166. //! Registers a specific Archive type with cereal
  167. /*! This registration should be done once per archive. A good place to
  168. put this is immediately following the definition of your archive.
  169. Archive registration is only strictly necessary if you wish to
  170. support pointers to polymorphic data types. All archives that
  171. come with cereal are already registered.
  172. @ingroup Internal */
  173. #define CEREAL_REGISTER_ARCHIVE(Archive) \
  174. namespace cereal { namespace detail { \
  175. template <class T, class BindingTag> \
  176. typename polymorphic_serialization_support<Archive, T>::type \
  177. instantiate_polymorphic_binding( T*, Archive*, BindingTag, adl_tag ); \
  178. } } /* end namespaces */
  179. //! Helper macro to omit unused warning
  180. #if defined(__GNUC__)
  181. // GCC / clang don't want the function
  182. #define CEREAL_UNUSED_FUNCTION
  183. #else
  184. #define CEREAL_UNUSED_FUNCTION static void unused() { (void)version; }
  185. #endif
  186. // ######################################################################
  187. //! Defines a class version for some type
  188. /*! Versioning information is optional and adds some small amount of
  189. overhead to serialization. This overhead will occur both in terms of
  190. space in the archive (the version information for each class will be
  191. stored exactly once) as well as runtime (versioned serialization functions
  192. must check to see if they need to load or store version information).
  193. Versioning is useful if you plan on fundamentally changing the way some
  194. type is serialized in the future. Versioned serialization functions
  195. cannot be used to load non-versioned data.
  196. By default, all types have an assumed version value of zero. By
  197. using this macro, you may change the version number associated with
  198. some type. cereal will then use this value as a second parameter
  199. to your serialization functions.
  200. The interface for the serialization functions is nearly identical
  201. to non-versioned serialization with the addition of a second parameter,
  202. const std::uint32_t version, which will be supplied with the correct
  203. version number. Serializing the version number on a save happens
  204. automatically.
  205. Versioning cannot be mixed with non-versioned serialization functions.
  206. Having both types will result result in a compile time error. Data
  207. serialized without versioning cannot be loaded by a serialization
  208. function with added versioning support.
  209. Example interface for versioning on a non-member serialize function:
  210. @code{cpp}
  211. CEREAL_CLASS_VERSION( Mytype, 77 ); // register class version
  212. template <class Archive>
  213. void serialize( Archive & ar, Mytype & t, const std::uint32_t version )
  214. {
  215. // When performing a load, the version associated with the class
  216. // is whatever it was when that data was originally serialized
  217. //
  218. // When we save, we'll use the version that is defined in the macro
  219. if( version >= some_number )
  220. // do this
  221. else
  222. // do that
  223. }
  224. @endcode
  225. Interfaces for other forms of serialization functions is similar. This
  226. macro should be placed at global scope.
  227. @ingroup Utility */
  228. //! On C++17, define the StaticObject as inline to merge the definitions across TUs
  229. //! This prevents multiple definition errors when this macro appears in a header file
  230. //! included in multiple TUs.
  231. #ifdef CEREAL_HAS_CPP17
  232. #define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER) \
  233. namespace cereal { namespace detail { \
  234. template <> struct Version<TYPE> \
  235. { \
  236. static std::uint32_t registerVersion() \
  237. { \
  238. ::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
  239. std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER ); \
  240. return VERSION_NUMBER; \
  241. } \
  242. static inline const std::uint32_t version = registerVersion(); \
  243. CEREAL_UNUSED_FUNCTION \
  244. }; /* end Version */ \
  245. } } // end namespaces
  246. #else
  247. #define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER) \
  248. namespace cereal { namespace detail { \
  249. template <> struct Version<TYPE> \
  250. { \
  251. static const std::uint32_t version; \
  252. static std::uint32_t registerVersion() \
  253. { \
  254. ::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
  255. std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER ); \
  256. return VERSION_NUMBER; \
  257. } \
  258. CEREAL_UNUSED_FUNCTION \
  259. }; /* end Version */ \
  260. const std::uint32_t Version<TYPE>::version = \
  261. Version<TYPE>::registerVersion(); \
  262. } } // end namespaces
  263. #endif
  264. // ######################################################################
  265. //! The base output archive class
  266. /*! This is the base output archive for all output archives. If you create
  267. a custom archive class, it should derive from this, passing itself as
  268. a template parameter for the ArchiveType.
  269. The base class provides all of the functionality necessary to
  270. properly forward data to the correct serialization functions.
  271. Individual archives should use a combination of prologue and
  272. epilogue functions together with specializations of serialize, save,
  273. and load to alter the functionality of their serialization.
  274. @tparam ArchiveType The archive type that derives from OutputArchive
  275. @tparam Flags Flags to control advanced functionality. See the Flags
  276. enum for more information.
  277. @ingroup Internal */
  278. template<class ArchiveType, std::uint32_t Flags = 0>
  279. class OutputArchive : public detail::OutputArchiveBase
  280. {
  281. public:
  282. //! Construct the output archive
  283. /*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
  284. OutputArchive(ArchiveType * const derived) : self(derived), itsCurrentPointerId(1), itsCurrentPolymorphicTypeId(1)
  285. { }
  286. OutputArchive & operator=( OutputArchive const & ) = delete;
  287. //! Serializes all passed in data
  288. /*! This is the primary interface for serializing data with an archive */
  289. template <class ... Types> inline
  290. ArchiveType & operator()( Types && ... args )
  291. {
  292. self->process( std::forward<Types>( args )... );
  293. return *self;
  294. }
  295. //! Serializes any data marked for deferment using defer
  296. /*! This will cause any data wrapped in DeferredData to be immediately serialized */
  297. void serializeDeferments()
  298. {
  299. for( auto & deferment : itsDeferments )
  300. deferment();
  301. }
  302. /*! @name Boost Transition Layer
  303. Functionality that mirrors the syntax for Boost. This is useful if you are transitioning
  304. a large project from Boost to cereal. The preferred interface for cereal is using operator(). */
  305. //! @{
  306. //! Indicates this archive is not intended for loading
  307. /*! This ensures compatibility with boost archive types. If you are transitioning
  308. from boost, you can check this value within a member or external serialize function
  309. (i.e., Archive::is_loading::value) to disable behavior specific to loading, until
  310. you can transition to split save/load or save_minimal/load_minimal functions */
  311. using is_loading = std::false_type;
  312. //! Indicates this archive is intended for saving
  313. /*! This ensures compatibility with boost archive types. If you are transitioning
  314. from boost, you can check this value within a member or external serialize function
  315. (i.e., Archive::is_saving::value) to enable behavior specific to loading, until
  316. you can transition to split save/load or save_minimal/load_minimal functions */
  317. using is_saving = std::true_type;
  318. //! Serializes passed in data
  319. /*! This is a boost compatability layer and is not the preferred way of using
  320. cereal. If you are transitioning from boost, use this until you can
  321. transition to the operator() overload */
  322. template <class T> inline
  323. ArchiveType & operator&( T && arg )
  324. {
  325. self->process( std::forward<T>( arg ) );
  326. return *self;
  327. }
  328. //! Serializes passed in data
  329. /*! This is a boost compatability layer and is not the preferred way of using
  330. cereal. If you are transitioning from boost, use this until you can
  331. transition to the operator() overload */
  332. template <class T> inline
  333. ArchiveType & operator<<( T && arg )
  334. {
  335. self->process( std::forward<T>( arg ) );
  336. return *self;
  337. }
  338. //! @}
  339. //! Registers a shared pointer with the archive
  340. /*! This function is used to track shared pointer targets to prevent
  341. unnecessary saves from taking place if multiple shared pointers
  342. point to the same data.
  343. @internal
  344. @param sharedPointer The shared pointer itself (the address is taken via get()).
  345. The archive takes a copy to prevent the memory location to be freed
  346. as long as the address is used as id. This is needed to prevent CVE-2020-11105.
  347. @return A key that uniquely identifies the pointer */
  348. inline std::uint32_t registerSharedPointer(const std::shared_ptr<const void>& sharedPointer)
  349. {
  350. void const * addr = sharedPointer.get();
  351. // Handle null pointers by just returning 0
  352. if(addr == 0) return 0;
  353. itsSharedPointerStorage.push_back(sharedPointer);
  354. auto id = itsSharedPointerMap.find( addr );
  355. if( id == itsSharedPointerMap.end() )
  356. {
  357. auto ptrId = itsCurrentPointerId++;
  358. itsSharedPointerMap.insert( {addr, ptrId} );
  359. return ptrId | detail::msb_32bit; // mask MSB to be 1
  360. }
  361. else
  362. return id->second;
  363. }
  364. //! Registers a polymorphic type name with the archive
  365. /*! This function is used to track polymorphic types to prevent
  366. unnecessary saves of identifying strings used by the polymorphic
  367. support functionality.
  368. @internal
  369. @param name The name to associate with a polymorphic type
  370. @return A key that uniquely identifies the polymorphic type name */
  371. inline std::uint32_t registerPolymorphicType( char const * name )
  372. {
  373. auto id = itsPolymorphicTypeMap.find( name );
  374. if( id == itsPolymorphicTypeMap.end() )
  375. {
  376. auto polyId = itsCurrentPolymorphicTypeId++;
  377. itsPolymorphicTypeMap.insert( {name, polyId} );
  378. return polyId | detail::msb_32bit; // mask MSB to be 1
  379. }
  380. else
  381. return id->second;
  382. }
  383. private:
  384. //! Serializes data after calling prologue, then calls epilogue
  385. template <class T> inline
  386. void process( T && head )
  387. {
  388. prologue( *self, head );
  389. self->processImpl( head );
  390. epilogue( *self, head );
  391. }
  392. //! Unwinds to process all data
  393. template <class T, class ... Other> inline
  394. void process( T && head, Other && ... tail )
  395. {
  396. self->process( std::forward<T>( head ) );
  397. self->process( std::forward<Other>( tail )... );
  398. }
  399. //! Serialization of a virtual_base_class wrapper
  400. /*! \sa virtual_base_class */
  401. template <class T> inline
  402. ArchiveType & processImpl(virtual_base_class<T> const & b)
  403. {
  404. traits::detail::base_class_id id(b.base_ptr);
  405. if(itsBaseClassSet.count(id) == 0)
  406. {
  407. itsBaseClassSet.insert(id);
  408. self->processImpl( *b.base_ptr );
  409. }
  410. return *self;
  411. }
  412. //! Serialization of a base_class wrapper
  413. /*! \sa base_class */
  414. template <class T> inline
  415. ArchiveType & processImpl(base_class<T> const & b)
  416. {
  417. self->processImpl( *b.base_ptr );
  418. return *self;
  419. }
  420. std::vector<std::function<void(void)>> itsDeferments;
  421. template <class T> inline
  422. ArchiveType & processImpl(DeferredData<T> const & d)
  423. {
  424. std::function<void(void)> deferment( [this, d](){ self->process( d.value ); } );
  425. itsDeferments.emplace_back( std::move(deferment) );
  426. return *self;
  427. }
  428. //! Helper macro that expands the requirements for activating an overload
  429. /*! Requirements:
  430. Has the requested serialization function
  431. Does not have version and unversioned at the same time
  432. Is output serializable AND
  433. is specialized for this type of function OR
  434. has no specialization at all */
  435. #define PROCESS_IF(name) \
  436. traits::EnableIf<traits::has_##name<T, ArchiveType>::value, \
  437. !traits::has_invalid_output_versioning<T, ArchiveType>::value, \
  438. (traits::is_output_serializable<T, ArchiveType>::value && \
  439. (traits::is_specialized_##name<T, ArchiveType>::value || \
  440. !traits::is_specialized<T, ArchiveType>::value))> = traits::sfinae
  441. //! Member serialization
  442. template <class T, PROCESS_IF(member_serialize)> inline
  443. ArchiveType & processImpl(T const & t)
  444. {
  445. access::member_serialize(*self, const_cast<T &>(t));
  446. return *self;
  447. }
  448. //! Non member serialization
  449. template <class T, PROCESS_IF(non_member_serialize)> inline
  450. ArchiveType & processImpl(T const & t)
  451. {
  452. CEREAL_SERIALIZE_FUNCTION_NAME(*self, const_cast<T &>(t));
  453. return *self;
  454. }
  455. //! Member split (save)
  456. template <class T, PROCESS_IF(member_save)> inline
  457. ArchiveType & processImpl(T const & t)
  458. {
  459. access::member_save(*self, t);
  460. return *self;
  461. }
  462. //! Non member split (save)
  463. template <class T, PROCESS_IF(non_member_save)> inline
  464. ArchiveType & processImpl(T const & t)
  465. {
  466. CEREAL_SAVE_FUNCTION_NAME(*self, t);
  467. return *self;
  468. }
  469. //! Member split (save_minimal)
  470. template <class T, PROCESS_IF(member_save_minimal)> inline
  471. ArchiveType & processImpl(T const & t)
  472. {
  473. self->process( access::member_save_minimal(*self, t) );
  474. return *self;
  475. }
  476. //! Non member split (save_minimal)
  477. template <class T, PROCESS_IF(non_member_save_minimal)> inline
  478. ArchiveType & processImpl(T const & t)
  479. {
  480. self->process( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(*self, t) );
  481. return *self;
  482. }
  483. //! Empty class specialization
  484. template <class T, traits::EnableIf<(Flags & AllowEmptyClassElision),
  485. !traits::is_output_serializable<T, ArchiveType>::value,
  486. std::is_empty<T>::value> = traits::sfinae> inline
  487. ArchiveType & processImpl(T const &)
  488. {
  489. return *self;
  490. }
  491. //! No matching serialization
  492. /*! Invalid if we have invalid output versioning or
  493. we are not output serializable, and either
  494. don't allow empty class ellision or allow it but are not serializing an empty class */
  495. template <class T, traits::EnableIf<traits::has_invalid_output_versioning<T, ArchiveType>::value ||
  496. (!traits::is_output_serializable<T, ArchiveType>::value &&
  497. (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae> inline
  498. ArchiveType & processImpl(T const &)
  499. {
  500. static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value != 0,
  501. "cereal could not find any output serialization functions for the provided type and archive combination. \n\n "
  502. "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
  503. "Serialize functions generally have the following signature: \n\n "
  504. "template<class Archive> \n "
  505. " void serialize(Archive & ar) \n "
  506. " { \n "
  507. " ar( member1, member2, member3 ); \n "
  508. " } \n\n " );
  509. static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value < 2,
  510. "cereal found more than one compatible output serialization function for the provided type and archive combination. \n\n "
  511. "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
  512. "Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions. \n "
  513. "Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
  514. "In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
  515. return *self;
  516. }
  517. //! Registers a class version with the archive and serializes it if necessary
  518. /*! If this is the first time this class has been serialized, we will record its
  519. version number and serialize that.
  520. @tparam T The type of the class being serialized */
  521. template <class T> inline
  522. std::uint32_t registerClassVersion()
  523. {
  524. static const auto hash = std::type_index(typeid(T)).hash_code();
  525. const auto insertResult = itsVersionedTypes.insert( hash );
  526. const auto lock = detail::StaticObject<detail::Versions>::lock();
  527. const auto version =
  528. detail::StaticObject<detail::Versions>::getInstance().find( hash, detail::Version<T>::version );
  529. if( insertResult.second ) // insertion took place, serialize the version number
  530. process( make_nvp<ArchiveType>("cereal_class_version", version) );
  531. return version;
  532. }
  533. //! Member serialization
  534. /*! Versioning implementation */
  535. template <class T, PROCESS_IF(member_versioned_serialize)> inline
  536. ArchiveType & processImpl(T const & t)
  537. {
  538. access::member_serialize(*self, const_cast<T &>(t), registerClassVersion<T>());
  539. return *self;
  540. }
  541. //! Non member serialization
  542. /*! Versioning implementation */
  543. template <class T, PROCESS_IF(non_member_versioned_serialize)> inline
  544. ArchiveType & processImpl(T const & t)
  545. {
  546. CEREAL_SERIALIZE_FUNCTION_NAME(*self, const_cast<T &>(t), registerClassVersion<T>());
  547. return *self;
  548. }
  549. //! Member split (save)
  550. /*! Versioning implementation */
  551. template <class T, PROCESS_IF(member_versioned_save)> inline
  552. ArchiveType & processImpl(T const & t)
  553. {
  554. access::member_save(*self, t, registerClassVersion<T>());
  555. return *self;
  556. }
  557. //! Non member split (save)
  558. /*! Versioning implementation */
  559. template <class T, PROCESS_IF(non_member_versioned_save)> inline
  560. ArchiveType & processImpl(T const & t)
  561. {
  562. CEREAL_SAVE_FUNCTION_NAME(*self, t, registerClassVersion<T>());
  563. return *self;
  564. }
  565. //! Member split (save_minimal)
  566. /*! Versioning implementation */
  567. template <class T, PROCESS_IF(member_versioned_save_minimal)> inline
  568. ArchiveType & processImpl(T const & t)
  569. {
  570. self->process( access::member_save_minimal(*self, t, registerClassVersion<T>()) );
  571. return *self;
  572. }
  573. //! Non member split (save_minimal)
  574. /*! Versioning implementation */
  575. template <class T, PROCESS_IF(non_member_versioned_save_minimal)> inline
  576. ArchiveType & processImpl(T const & t)
  577. {
  578. self->process( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(*self, t, registerClassVersion<T>()) );
  579. return *self;
  580. }
  581. #undef PROCESS_IF
  582. private:
  583. ArchiveType * const self;
  584. //! A set of all base classes that have been serialized
  585. std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
  586. //! Maps from addresses to pointer ids
  587. std::unordered_map<void const *, std::uint32_t> itsSharedPointerMap;
  588. //! Copy of shared pointers used in #itsSharedPointerMap to make sure they are kept alive
  589. // during lifetime of itsSharedPointerMap to prevent CVE-2020-11105.
  590. std::vector<std::shared_ptr<const void>> itsSharedPointerStorage;
  591. //! The id to be given to the next pointer
  592. std::uint32_t itsCurrentPointerId;
  593. //! Maps from polymorphic type name strings to ids
  594. std::unordered_map<char const *, std::uint32_t> itsPolymorphicTypeMap;
  595. //! The id to be given to the next polymorphic type name
  596. std::uint32_t itsCurrentPolymorphicTypeId;
  597. //! Keeps track of classes that have versioning information associated with them
  598. std::unordered_set<size_type> itsVersionedTypes;
  599. }; // class OutputArchive
  600. // ######################################################################
  601. //! The base input archive class
  602. /*! This is the base input archive for all input archives. If you create
  603. a custom archive class, it should derive from this, passing itself as
  604. a template parameter for the ArchiveType.
  605. The base class provides all of the functionality necessary to
  606. properly forward data to the correct serialization functions.
  607. Individual archives should use a combination of prologue and
  608. epilogue functions together with specializations of serialize, save,
  609. and load to alter the functionality of their serialization.
  610. @tparam ArchiveType The archive type that derives from InputArchive
  611. @tparam Flags Flags to control advanced functionality. See the Flags
  612. enum for more information.
  613. @ingroup Internal */
  614. template<class ArchiveType, std::uint32_t Flags = 0>
  615. class InputArchive : public detail::InputArchiveBase
  616. {
  617. public:
  618. //! Construct the output archive
  619. /*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
  620. InputArchive(ArchiveType * const derived) :
  621. self(derived),
  622. itsBaseClassSet(),
  623. itsSharedPointerMap(),
  624. itsPolymorphicTypeMap(),
  625. itsVersionedTypes()
  626. { }
  627. InputArchive & operator=( InputArchive const & ) = delete;
  628. //! Serializes all passed in data
  629. /*! This is the primary interface for serializing data with an archive */
  630. template <class ... Types> inline
  631. ArchiveType & operator()( Types && ... args )
  632. {
  633. process( std::forward<Types>( args )... );
  634. return *self;
  635. }
  636. //! Serializes any data marked for deferment using defer
  637. /*! This will cause any data wrapped in DeferredData to be immediately serialized */
  638. void serializeDeferments()
  639. {
  640. for( auto & deferment : itsDeferments )
  641. deferment();
  642. }
  643. /*! @name Boost Transition Layer
  644. Functionality that mirrors the syntax for Boost. This is useful if you are transitioning
  645. a large project from Boost to cereal. The preferred interface for cereal is using operator(). */
  646. //! @{
  647. //! Indicates this archive is intended for loading
  648. /*! This ensures compatibility with boost archive types. If you are transitioning
  649. from boost, you can check this value within a member or external serialize function
  650. (i.e., Archive::is_loading::value) to enable behavior specific to loading, until
  651. you can transition to split save/load or save_minimal/load_minimal functions */
  652. using is_loading = std::true_type;
  653. //! Indicates this archive is not intended for saving
  654. /*! This ensures compatibility with boost archive types. If you are transitioning
  655. from boost, you can check this value within a member or external serialize function
  656. (i.e., Archive::is_saving::value) to disable behavior specific to loading, until
  657. you can transition to split save/load or save_minimal/load_minimal functions */
  658. using is_saving = std::false_type;
  659. //! Serializes passed in data
  660. /*! This is a boost compatability layer and is not the preferred way of using
  661. cereal. If you are transitioning from boost, use this until you can
  662. transition to the operator() overload */
  663. template <class T> inline
  664. ArchiveType & operator&( T && arg )
  665. {
  666. self->process( std::forward<T>( arg ) );
  667. return *self;
  668. }
  669. //! Serializes passed in data
  670. /*! This is a boost compatability layer and is not the preferred way of using
  671. cereal. If you are transitioning from boost, use this until you can
  672. transition to the operator() overload */
  673. template <class T> inline
  674. ArchiveType & operator>>( T && arg )
  675. {
  676. self->process( std::forward<T>( arg ) );
  677. return *self;
  678. }
  679. //! @}
  680. //! Retrieves a shared pointer given a unique key for it
  681. /*! This is used to retrieve a previously registered shared_ptr
  682. which has already been loaded.
  683. @internal
  684. @param id The unique id that was serialized for the pointer
  685. @return A shared pointer to the data
  686. @throw Exception if the id does not exist */
  687. inline std::shared_ptr<void> getSharedPointer(std::uint32_t const id)
  688. {
  689. if(id == 0) return std::shared_ptr<void>(nullptr);
  690. auto iter = itsSharedPointerMap.find( id );
  691. if(iter == itsSharedPointerMap.end())
  692. throw Exception("Error while trying to deserialize a smart pointer. Could not find id " + std::to_string(id));
  693. return iter->second;
  694. }
  695. //! Registers a shared pointer to its unique identifier
  696. /*! After a shared pointer has been allocated for the first time, it should
  697. be registered with its loaded id for future references to it.
  698. @internal
  699. @param id The unique identifier for the shared pointer
  700. @param ptr The actual shared pointer */
  701. inline void registerSharedPointer(std::uint32_t const id, std::shared_ptr<void> ptr)
  702. {
  703. std::uint32_t const stripped_id = id & ~detail::msb_32bit;
  704. itsSharedPointerMap[stripped_id] = ptr;
  705. }
  706. //! Retrieves the string for a polymorphic type given a unique key for it
  707. /*! This is used to retrieve a string previously registered during
  708. a polymorphic load.
  709. @internal
  710. @param id The unique id that was serialized for the polymorphic type
  711. @return The string identifier for the type */
  712. inline std::string getPolymorphicName(std::uint32_t const id)
  713. {
  714. auto name = itsPolymorphicTypeMap.find( id );
  715. if(name == itsPolymorphicTypeMap.end())
  716. {
  717. throw Exception("Error while trying to deserialize a polymorphic pointer. Could not find type id " + std::to_string(id));
  718. }
  719. return name->second;
  720. }
  721. //! Registers a polymorphic name string to its unique identifier
  722. /*! After a polymorphic type has been loaded for the first time, it should
  723. be registered with its loaded id for future references to it.
  724. @internal
  725. @param id The unique identifier for the polymorphic type
  726. @param name The name associated with the type */
  727. inline void registerPolymorphicName(std::uint32_t const id, std::string const & name)
  728. {
  729. std::uint32_t const stripped_id = id & ~detail::msb_32bit;
  730. itsPolymorphicTypeMap.insert( {stripped_id, name} );
  731. }
  732. private:
  733. //! Serializes data after calling prologue, then calls epilogue
  734. template <class T> inline
  735. void process( T && head )
  736. {
  737. prologue( *self, head );
  738. self->processImpl( head );
  739. epilogue( *self, head );
  740. }
  741. //! Unwinds to process all data
  742. template <class T, class ... Other> inline
  743. void process( T && head, Other && ... tail )
  744. {
  745. process( std::forward<T>( head ) );
  746. process( std::forward<Other>( tail )... );
  747. }
  748. //! Serialization of a virtual_base_class wrapper
  749. /*! \sa virtual_base_class */
  750. template <class T> inline
  751. ArchiveType & processImpl(virtual_base_class<T> & b)
  752. {
  753. traits::detail::base_class_id id(b.base_ptr);
  754. if(itsBaseClassSet.count(id) == 0)
  755. {
  756. itsBaseClassSet.insert(id);
  757. self->processImpl( *b.base_ptr );
  758. }
  759. return *self;
  760. }
  761. //! Serialization of a base_class wrapper
  762. /*! \sa base_class */
  763. template <class T> inline
  764. ArchiveType & processImpl(base_class<T> & b)
  765. {
  766. self->processImpl( *b.base_ptr );
  767. return *self;
  768. }
  769. std::vector<std::function<void(void)>> itsDeferments;
  770. template <class T> inline
  771. ArchiveType & processImpl(DeferredData<T> const & d)
  772. {
  773. std::function<void(void)> deferment( [this, d](){ self->process( d.value ); } );
  774. itsDeferments.emplace_back( std::move(deferment) );
  775. return *self;
  776. }
  777. //! Helper macro that expands the requirements for activating an overload
  778. /*! Requirements:
  779. Has the requested serialization function
  780. Does not have version and unversioned at the same time
  781. Is input serializable AND
  782. is specialized for this type of function OR
  783. has no specialization at all */
  784. #define PROCESS_IF(name) \
  785. traits::EnableIf<traits::has_##name<T, ArchiveType>::value, \
  786. !traits::has_invalid_input_versioning<T, ArchiveType>::value, \
  787. (traits::is_input_serializable<T, ArchiveType>::value && \
  788. (traits::is_specialized_##name<T, ArchiveType>::value || \
  789. !traits::is_specialized<T, ArchiveType>::value))> = traits::sfinae
  790. //! Member serialization
  791. template <class T, PROCESS_IF(member_serialize)> inline
  792. ArchiveType & processImpl(T & t)
  793. {
  794. access::member_serialize(*self, t);
  795. return *self;
  796. }
  797. //! Non member serialization
  798. template <class T, PROCESS_IF(non_member_serialize)> inline
  799. ArchiveType & processImpl(T & t)
  800. {
  801. CEREAL_SERIALIZE_FUNCTION_NAME(*self, t);
  802. return *self;
  803. }
  804. //! Member split (load)
  805. template <class T, PROCESS_IF(member_load)> inline
  806. ArchiveType & processImpl(T & t)
  807. {
  808. access::member_load(*self, t);
  809. return *self;
  810. }
  811. //! Non member split (load)
  812. template <class T, PROCESS_IF(non_member_load)> inline
  813. ArchiveType & processImpl(T & t)
  814. {
  815. CEREAL_LOAD_FUNCTION_NAME(*self, t);
  816. return *self;
  817. }
  818. //! Member split (load_minimal)
  819. template <class T, PROCESS_IF(member_load_minimal)> inline
  820. ArchiveType & processImpl(T & t)
  821. {
  822. using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
  823. typename traits::has_member_save_minimal<T, OutArchiveType>::type value;
  824. self->process( value );
  825. access::member_load_minimal(*self, t, value);
  826. return *self;
  827. }
  828. //! Non member split (load_minimal)
  829. template <class T, PROCESS_IF(non_member_load_minimal)> inline
  830. ArchiveType & processImpl(T & t)
  831. {
  832. using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
  833. typename traits::has_non_member_save_minimal<T, OutArchiveType>::type value;
  834. self->process( value );
  835. CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value);
  836. return *self;
  837. }
  838. //! Empty class specialization
  839. template <class T, traits::EnableIf<(Flags & AllowEmptyClassElision),
  840. !traits::is_input_serializable<T, ArchiveType>::value,
  841. std::is_empty<T>::value> = traits::sfinae> inline
  842. ArchiveType & processImpl(T const &)
  843. {
  844. return *self;
  845. }
  846. //! No matching serialization
  847. /*! Invalid if we have invalid input versioning or
  848. we are not input serializable, and either
  849. don't allow empty class ellision or allow it but are not serializing an empty class */
  850. template <class T, traits::EnableIf<traits::has_invalid_input_versioning<T, ArchiveType>::value ||
  851. (!traits::is_input_serializable<T, ArchiveType>::value &&
  852. (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae> inline
  853. ArchiveType & processImpl(T const &)
  854. {
  855. static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value != 0,
  856. "cereal could not find any input serialization functions for the provided type and archive combination. \n\n "
  857. "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
  858. "Serialize functions generally have the following signature: \n\n "
  859. "template<class Archive> \n "
  860. " void serialize(Archive & ar) \n "
  861. " { \n "
  862. " ar( member1, member2, member3 ); \n "
  863. " } \n\n " );
  864. static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value < 2,
  865. "cereal found more than one compatible input serialization function for the provided type and archive combination. \n\n "
  866. "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
  867. "Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions. \n "
  868. "Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
  869. "In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
  870. return *self;
  871. }
  872. //! Befriend for versioning in load_and_construct
  873. template <class A, class B, bool C, bool D, bool E, bool F> friend struct detail::Construct;
  874. //! Registers a class version with the archive and serializes it if necessary
  875. /*! If this is the first time this class has been serialized, we will record its
  876. version number and serialize that.
  877. @tparam T The type of the class being serialized */
  878. template <class T> inline
  879. std::uint32_t loadClassVersion()
  880. {
  881. static const auto hash = std::type_index(typeid(T)).hash_code();
  882. auto lookupResult = itsVersionedTypes.find( hash );
  883. if( lookupResult != itsVersionedTypes.end() ) // already exists
  884. return lookupResult->second;
  885. else // need to load
  886. {
  887. std::uint32_t version;
  888. process( make_nvp<ArchiveType>("cereal_class_version", version) );
  889. itsVersionedTypes.emplace_hint( lookupResult, hash, version );
  890. return version;
  891. }
  892. }
  893. //! Member serialization
  894. /*! Versioning implementation */
  895. template <class T, PROCESS_IF(member_versioned_serialize)> inline
  896. ArchiveType & processImpl(T & t)
  897. {
  898. const auto version = loadClassVersion<T>();
  899. access::member_serialize(*self, t, version);
  900. return *self;
  901. }
  902. //! Non member serialization
  903. /*! Versioning implementation */
  904. template <class T, PROCESS_IF(non_member_versioned_serialize)> inline
  905. ArchiveType & processImpl(T & t)
  906. {
  907. const auto version = loadClassVersion<T>();
  908. CEREAL_SERIALIZE_FUNCTION_NAME(*self, t, version);
  909. return *self;
  910. }
  911. //! Member split (load)
  912. /*! Versioning implementation */
  913. template <class T, PROCESS_IF(member_versioned_load)> inline
  914. ArchiveType & processImpl(T & t)
  915. {
  916. const auto version = loadClassVersion<T>();
  917. access::member_load(*self, t, version);
  918. return *self;
  919. }
  920. //! Non member split (load)
  921. /*! Versioning implementation */
  922. template <class T, PROCESS_IF(non_member_versioned_load)> inline
  923. ArchiveType & processImpl(T & t)
  924. {
  925. const auto version = loadClassVersion<T>();
  926. CEREAL_LOAD_FUNCTION_NAME(*self, t, version);
  927. return *self;
  928. }
  929. //! Member split (load_minimal)
  930. /*! Versioning implementation */
  931. template <class T, PROCESS_IF(member_versioned_load_minimal)> inline
  932. ArchiveType & processImpl(T & t)
  933. {
  934. using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
  935. const auto version = loadClassVersion<T>();
  936. typename traits::has_member_versioned_save_minimal<T, OutArchiveType>::type value;
  937. self->process(value);
  938. access::member_load_minimal(*self, t, value, version);
  939. return *self;
  940. }
  941. //! Non member split (load_minimal)
  942. /*! Versioning implementation */
  943. template <class T, PROCESS_IF(non_member_versioned_load_minimal)> inline
  944. ArchiveType & processImpl(T & t)
  945. {
  946. using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
  947. const auto version = loadClassVersion<T>();
  948. typename traits::has_non_member_versioned_save_minimal<T, OutArchiveType>::type value;
  949. self->process(value);
  950. CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value, version);
  951. return *self;
  952. }
  953. #undef PROCESS_IF
  954. private:
  955. ArchiveType * const self;
  956. //! A set of all base classes that have been serialized
  957. std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
  958. //! Maps from pointer ids to metadata
  959. std::unordered_map<std::uint32_t, std::shared_ptr<void>> itsSharedPointerMap;
  960. //! Maps from name ids to names
  961. std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap;
  962. //! Maps from type hash codes to version numbers
  963. std::unordered_map<std::size_t, std::uint32_t> itsVersionedTypes;
  964. }; // class InputArchive
  965. } // namespace cereal
  966. // This include needs to come after things such as binary_data, make_nvp, etc
  967. #include "cereal/types/common.hpp"
  968. #endif // CEREAL_CEREAL_HPP_