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