cereal.hpp 46 KB

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