2 \brief Main cereal functionality */
4 Copyright (c) 2014, Randolph Voorhies, Shane Grant
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 * Neither the name of cereal nor the
15 names of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
22 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #ifndef CEREAL_CEREAL_HPP_
30 #define CEREAL_CEREAL_HPP_
32 #include <type_traits>
35 #include <unordered_map>
36 #include <unordered_set>
42 #include <cereal/details/traits.hpp>
43 #include <cereal/details/helpers.hpp>
44 #include <cereal/types/base_class.hpp>
48 // ######################################################################
49 //! Creates a name value pair
50 /*! @relates NameValuePair
52 template <class T> inline
53 NameValuePair<T> make_nvp( std::string const & name, T && value )
55 return {name.c_str(), std::forward<T>(value)};
58 //! Creates a name value pair
59 /*! @relates NameValuePair
61 template <class T> inline
62 NameValuePair<T> make_nvp( const char * name, T && value )
64 return {name, std::forward<T>(value)};
67 //! Creates a name value pair for the variable T with the same name as the variable
68 /*! @relates NameValuePair
70 #define CEREAL_NVP(T) ::cereal::make_nvp(#T, T)
72 // ######################################################################
73 //! Convenience function to create binary data for both const and non const pointers
74 /*! @param data Pointer to beginning of the data
75 @param size The size in bytes of the data
78 template <class T> inline
79 BinaryData<T> binary_data( T && data, size_t size )
81 return {std::forward<T>(data), size};
84 // ######################################################################
85 //! Creates a size tag from some variable.
86 /*! Will normally be used to serialize size (e.g. size()) information for
87 variable size containers. If you have a variable sized container,
88 the very first thing it serializes should be its size, wrapped in
94 SizeTag<T> make_size_tag( T && sz )
96 return {std::forward<T>(sz)};
99 // ######################################################################
100 //! Called before a type is serialized to set up any special archive state
101 //! for processing some type
102 /*! If designing a serializer that needs to set up any kind of special
103 state or output extra information for a type, specialize this function
104 for the archive type and the types that require the extra information.
106 template <class Archive, class T>
107 void prologue( Archive & /* archive */, T const & /* data */)
110 //! Called after a type is serialized to tear down any special archive state
111 //! for processing some type
112 /*! @ingroup Internal */
113 template <class Archive, class T>
114 void epilogue( Archive & /* archive */, T const & /* data */)
117 // ######################################################################
118 //! Special flags for archives
119 /*! AllowEmptyClassElision
120 This allows for empty classes to be serialized even if they do not provide
121 a serialization function. Classes with no data members are considered to be
122 empty. Be warned that if this is enabled and you attempt to serialize an
123 empty class with improperly formed serialize or load/save functions, no
124 static error will occur - the error will propogate silently and your
125 intended serialization functions may not be called. You can manually
126 ensure that your classes that have custom serialization are correct
127 by using the traits is_output_serializable and is_input_serializable
128 in cereal/details/traits.hpp.
130 enum Flags { AllowEmptyClassElision = 1 };
132 // ######################################################################
133 //! Registers a specific Archive type with cereal
134 /*! This registration should be done once per archive. A good place to
135 put this is immediately following the definition of your archive.
136 Archive registration is only strictly necessary if you wish to
137 support pointers to polymorphic data types. All archives that
138 come with cereal are already registered.
140 #define CEREAL_REGISTER_ARCHIVE(Archive) \
141 namespace cereal { namespace detail { \
143 typename polymorphic_serialization_support<Archive, T>::type \
144 instantiate_polymorphic_binding( T*, Archive*, adl_tag ); \
145 } } // end namespaces
147 //! Defines a class version for some type
148 /*! Versioning information is optional and adds some small amount of
149 overhead to serialization. This overhead will occur both in terms of
150 space in the archive (the version information for each class will be
151 stored exactly once) as well as runtime (versioned serialization functions
152 must check to see if they need to load or store version information).
154 Versioning is useful if you plan on fundamentally changing the way some
155 type is serialized in the future. Versioned serialization functions
156 cannot be used to load non-versioned data.
158 By default, all types have an assumed version value of zero. By
159 using this macro, you may change the version number associated with
160 some type. cereal will then use this value as a second parameter
161 to your serialization functions.
163 The interface for the serialization functions is nearly identical
164 to non-versioned serialization with the addition of a second parameter,
165 const std::uint32_t version, which will be supplied with the correct
166 version number. Serializing the version number on a save happens
169 Versioning cannot be mixed with non-versioned serialization functions.
170 Having both types will result result in a compile time error.
172 Example interface for versioning on a non-member serialize function:
175 CEREAL_CLASS_VERSION( Mytype, 77 ); // register class version
177 template <class Archive>
178 void serialize( Archive & ar, Mytype & t, const std::uint32_t version )
180 // When performing a load, the version associated with the class
181 // is whatever it was when that data was originally serialized
183 // When we save, we'll use the version that is defined in the macro
185 if( version >= some_number )
192 Interfaces for other forms of serialization functions is similar. This
193 macro should be placed at global scope.
195 #define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER) \
196 namespace cereal { namespace detail { \
197 template <> struct Version<TYPE> \
199 static const std::uint32_t version = VERSION_NUMBER; \
200 static Version<TYPE> registerVersion() \
202 ::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
203 std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER ); \
206 }; /* end Version */ \
207 static const auto CEREAL_CLASS_VERSION_REGISTER##TYPE##VERSION_NUMBER = \
208 Version<TYPE>::registerVersion(); \
209 } } // end namespaces
211 //! The base output archive class
212 /*! This is the base output archive for all output archives. If you create
213 a custom archive class, it should derive from this, passing itself as
214 a template parameter for the ArchiveType.
216 The base class provides all of the functionality necessary to
217 properly forward data to the correct serialization functions.
219 Individual archives should use a combination of prologue and
220 epilogue functions together with specializations of serialize, save,
221 and load to alter the functionality of their serialization.
223 @tparam ArchiveType The archive type that derives from OutputArchive
224 @tparam Flags Flags to control advanced functionality. See the Flags
225 enum for more information.
227 template<class ArchiveType, std::uint32_t Flags = 0>
228 class OutputArchive : public detail::OutputArchiveBase
231 //! Construct the output archive
232 /*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
233 OutputArchive(ArchiveType * const derived) : self(derived), itsCurrentPointerId(1), itsCurrentPolymorphicTypeId(1)
236 //! Serializes all passed in data
237 /*! This is the primary interface for serializing data with an archive */
238 template <class ... Types> inline
239 ArchiveType & operator()( Types && ... args )
241 self->process( std::forward<Types>( args )... );
245 /*! @name Boost Transition Layer
246 Functionality that mirrors the syntax for Boost. This is useful if you are transitioning
247 a large project from Boost to cereal. The preferred interface for cereal is using operator(). */
250 //! Serializes passed in data
251 /*! This is a boost compatability layer and is not the preferred way of using
252 cereal. If you are transitioning from boost, use this until you can
253 transition to the operator() overload */
254 template <class T> inline
255 ArchiveType & operator&( T && arg )
257 self->process( std::forward<T>( arg ) );
261 //! Serializes passed in data
262 /*! This is a boost compatability layer and is not the preferred way of using
263 cereal. If you are transitioning from boost, use this until you can
264 transition to the operator() overload */
265 template <class T> inline
266 ArchiveType & operator<<( T && arg )
268 self->process( std::forward<T>( arg ) );
274 //! Registers a shared pointer with the archive
275 /*! This function is used to track shared pointer targets to prevent
276 unnecessary saves from taking place if multiple shared pointers
277 point to the same data.
280 @param addr The address (see shared_ptr get()) pointed to by the shared pointer
281 @return A key that uniquely identifies the pointer */
282 inline std::uint32_t registerSharedPointer( void const * addr )
284 // Handle null pointers by just returning 0
285 if(addr == 0) return 0;
287 auto id = itsSharedPointerMap.find( addr );
288 if( id == itsSharedPointerMap.end() )
290 auto ptrId = itsCurrentPointerId++;
291 itsSharedPointerMap.insert( {addr, ptrId} );
292 return ptrId | detail::msb_32bit; // mask MSB to be 1
298 //! Registers a polymorphic type name with the archive
299 /*! This function is used to track polymorphic types to prevent
300 unnecessary saves of identifying strings used by the polymorphic
301 support functionality.
304 @param name The name to associate with a polymorphic type
305 @return A key that uniquely identifies the polymorphic type name */
306 inline std::uint32_t registerPolymorphicType( char const * name )
308 auto id = itsPolymorphicTypeMap.find( name );
309 if( id == itsPolymorphicTypeMap.end() )
311 auto polyId = itsCurrentPolymorphicTypeId++;
312 itsPolymorphicTypeMap.insert( {name, polyId} );
313 return polyId | detail::msb_32bit; // mask MSB to be 1
320 //! Serializes data after calling prologue, then calls epilogue
321 template <class T> inline
322 void process( T && head )
324 prologue( *self, head );
325 self->processImpl( head );
326 epilogue( *self, head );
329 //! Unwinds to process all data
330 template <class T, class ... Other> inline
331 void process( T && head, Other && ... tail )
333 self->process( std::forward<T>( head ) );
334 self->process( std::forward<Other>( tail )... );
337 //! Serialization of a virtual_base_class wrapper
338 /*! \sa virtual_base_class */
339 template <class T> inline
340 ArchiveType & processImpl(virtual_base_class<T> const & b)
342 traits::detail::base_class_id id(b.base_ptr);
343 if(itsBaseClassSet.count(id) == 0)
345 itsBaseClassSet.insert(id);
346 self->processImpl( *b.base_ptr );
351 //! Serialization of a base_class wrapper
352 /*! \sa base_class */
353 template <class T> inline
354 ArchiveType & processImpl(base_class<T> const & b)
356 self->processImpl( *b.base_ptr );
360 //! Member serialization
361 template <class T> inline
362 typename std::enable_if<traits::has_member_serialize<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
363 (traits::is_specialized_member_serialize<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
365 processImpl(T const & t)
367 access::member_serialize(*self, const_cast<T &>(t));
371 //! Non member serialization
372 template <class T> inline
373 typename std::enable_if<traits::has_non_member_serialize<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
374 (traits::is_specialized_non_member_serialize<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
376 processImpl(T const & t)
378 serialize(*self, const_cast<T &>(t));
382 //! Member split (save)
383 template <class T> inline
384 typename std::enable_if<traits::has_member_save<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
385 (traits::is_specialized_member_save<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
387 processImpl(T const & t)
389 access::member_save(*self, t);
393 //! Non member split (save)
394 template <class T> inline
395 typename std::enable_if<traits::has_non_member_save<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
396 (traits::is_specialized_non_member_save<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
398 processImpl(T const & t)
404 //! Member split (save_minimal)
405 template <class T> inline
406 typename std::enable_if<traits::has_member_save_minimal<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
407 (traits::is_specialized_member_save_minimal<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
409 processImpl(T const & t)
411 self->process( access::member_save_minimal(*self, t) );
415 //! Non member split (save_minimal)
416 template <class T> inline
417 typename std::enable_if<traits::has_non_member_save_minimal<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
418 (traits::is_specialized_non_member_save_minimal<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
420 processImpl(T const & t)
422 self->process( save_minimal(*self, t) );
426 //! Empty class specialization
427 template <class T> inline
428 typename std::enable_if<(Flags & AllowEmptyClassElision) &&
429 !traits::is_specialized<T, ArchiveType>::value &&
430 !traits::is_output_serializable<T, ArchiveType>::value && std::is_empty<T>::value, ArchiveType &>::type
431 processImpl(T const &)
436 //! No matching serialization
437 template <class T> inline
438 typename std::enable_if<traits::has_invalid_output_versioning<T, ArchiveType>::value ||
439 (!traits::is_specialized<T, ArchiveType>::value && !traits::is_output_serializable<T, ArchiveType>::value &&
440 (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value))),
442 processImpl(T const &)
444 static_assert(traits::is_output_serializable<T, ArchiveType>::value, "Trying to serialize an unserializable type with an output archive. \n\n "
445 "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
446 "Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions. \n "
447 "In addition, you may not mix versioned with non-versioned serialization functions. \n "
448 "Serialize functions generally have the following signature: \n\n "
449 "template<class Archive> \n "
450 " void serialize(Archive & ar) \n "
452 " ar( member1, member2, member3 ); \n "
457 //! Registers a class version with the archive and serializes it if necessary
458 /*! If this is the first time this class has been serialized, we will record its
459 version number and serialize that.
461 @tparam T The type of the class being serialized
462 @param version The version number associated with it */
463 template <class T> inline
464 void registerClassVersion( const std::uint32_t version )
466 static const auto hash = std::type_index(typeid(T)).hash_code();
467 const auto insertResult = itsVersionedTypes.insert( hash );
468 if( insertResult.second ) // insertion took place, serialize the version number
469 process( make_nvp<ArchiveType>("cereal_class_version", version) );
472 //! Member serialization
473 /*! Versioning implementation */
474 template <class T> inline
475 typename std::enable_if<traits::has_member_versioned_serialize<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
476 (traits::is_specialized_member_serialize<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
478 processImpl(T const & t)
480 registerClassVersion<T>( detail::Version<T>::version );
481 access::member_serialize(*self, const_cast<T &>(t), detail::Version<T>::version);
485 //! Non member serialization
486 /*! Versioning implementation */
487 template <class T> inline
488 typename std::enable_if<traits::has_non_member_versioned_serialize<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
489 (traits::is_specialized_non_member_serialize<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
491 processImpl(T const & t)
493 registerClassVersion<T>( detail::Version<T>::version );
494 serialize(*self, const_cast<T &>(t), detail::Version<T>::version);
498 //! Member split (save)
499 /*! Versioning implementation */
500 template <class T> inline
501 typename std::enable_if<traits::has_member_versioned_save<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
502 (traits::is_specialized_member_save<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
504 processImpl(T const & t)
506 registerClassVersion<T>( detail::Version<T>::version );
507 access::member_save(*self, t, detail::Version<T>::version);
511 //! Non member split (save)
512 /*! Versioning implementation */
513 template <class T> inline
514 typename std::enable_if<traits::has_non_member_versioned_save<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
515 (traits::is_specialized_non_member_save<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
517 processImpl(T const & t)
519 registerClassVersion<T>( detail::Version<T>::version );
520 save(*self, t, detail::Version<T>::version);
524 //! Member split (save_minimal)
525 /*! Versioning implementation */
526 template <class T> inline
527 typename std::enable_if<traits::has_member_versioned_save_minimal<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
528 (traits::is_specialized_member_save_minimal<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
530 processImpl(T const & t)
532 registerClassVersion<T>( detail::Version<T>::version );
533 self->process( access::member_save_minimal(*self, t, detail::Version<T>::version) );
537 //! Non member split (save_minimal)
538 /*! Versioning implementation */
539 template <class T> inline
540 typename std::enable_if<traits::has_non_member_versioned_save_minimal<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
541 (traits::is_specialized_non_member_save_minimal<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
543 processImpl(T const & t)
545 registerClassVersion<T>( detail::Version<T>::version );
546 self->process( save_minimal(*self, t, detail::Version<T>::version) );
551 ArchiveType * const self;
553 //! A set of all base classes that have been serialized
554 std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
556 //! Maps from addresses to pointer ids
557 std::unordered_map<void const *, std::uint32_t> itsSharedPointerMap;
559 //! The id to be given to the next pointer
560 std::uint32_t itsCurrentPointerId;
562 //! Maps from polymorphic type name strings to ids
563 std::unordered_map<char const *, std::uint32_t> itsPolymorphicTypeMap;
565 //! The id to be given to the next polymorphic type name
566 std::uint32_t itsCurrentPolymorphicTypeId;
568 //! Keeps track of classes that have versioning information associated with them
569 std::unordered_set<size_type> itsVersionedTypes;
570 }; // class OutputArchive
572 // ######################################################################
573 //! The base input archive class
574 /*! This is the base input archive for all input archives. If you create
575 a custom archive class, it should derive from this, passing itself as
576 a template parameter for the ArchiveType.
578 The base class provides all of the functionality necessary to
579 properly forward data to the correct serialization functions.
581 Individual archives should use a combination of prologue and
582 epilogue functions together with specializations of serialize, save,
583 and load to alter the functionality of their serialization.
585 @tparam ArchiveType The archive type that derives from InputArchive
586 @tparam Flags Flags to control advanced functionality. See the Flags
587 enum for more information.
589 template<class ArchiveType, std::uint32_t Flags = 0>
590 class InputArchive : public detail::InputArchiveBase
593 //! Construct the output archive
594 /*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
595 InputArchive(ArchiveType * const derived) :
598 itsSharedPointerMap(),
599 itsPolymorphicTypeMap(),
603 //! Serializes all passed in data
604 /*! This is the primary interface for serializing data with an archive */
605 template <class ... Types> inline
606 ArchiveType & operator()( Types && ... args )
608 process( std::forward<Types>( args )... );
612 /*! @name Boost Transition Layer
613 Functionality that mirrors the syntax for Boost. This is useful if you are transitioning
614 a large project from Boost to cereal. The preferred interface for cereal is using operator(). */
617 //! Serializes passed in data
618 /*! This is a boost compatability layer and is not the preferred way of using
619 cereal. If you are transitioning from boost, use this until you can
620 transition to the operator() overload */
621 template <class T> inline
622 ArchiveType & operator&( T && arg )
624 self->process( std::forward<T>( arg ) );
628 //! Serializes passed in data
629 /*! This is a boost compatability layer and is not the preferred way of using
630 cereal. If you are transitioning from boost, use this until you can
631 transition to the operator() overload */
632 template <class T> inline
633 ArchiveType & operator>>( T && arg )
635 self->process( std::forward<T>( arg ) );
641 //! Retrieves a shared pointer given a unique key for it
642 /*! This is used to retrieve a previously registered shared_ptr
643 which has already been loaded.
645 @param id The unique id that was serialized for the pointer
646 @return A shared pointer to the data
647 @throw Exception if the id does not exist */
648 inline std::shared_ptr<void> getSharedPointer(std::uint32_t const id)
650 if(id == 0) return std::shared_ptr<void>(nullptr);
652 auto iter = itsSharedPointerMap.find( id );
653 if(iter == itsSharedPointerMap.end())
654 throw Exception("Error while trying to deserialize a smart pointer. Could not find id " + std::to_string(id));
659 //! Registers a shared pointer to its unique identifier
660 /*! After a shared pointer has been allocated for the first time, it should
661 be registered with its loaded id for future references to it.
663 @param id The unique identifier for the shared pointer
664 @param ptr The actual shared pointer */
665 inline void registerSharedPointer(std::uint32_t const id, std::shared_ptr<void> ptr)
667 std::uint32_t const stripped_id = id & ~detail::msb_32bit;
668 itsSharedPointerMap[stripped_id] = ptr;
671 //! Retrieves the string for a polymorphic type given a unique key for it
672 /*! This is used to retrieve a string previously registered during
675 @param id The unique id that was serialized for the polymorphic type
676 @return The string identifier for the tyep */
677 inline std::string getPolymorphicName(std::uint32_t const id)
679 auto name = itsPolymorphicTypeMap.find( id );
680 if(name == itsPolymorphicTypeMap.end())
682 throw Exception("Error while trying to deserialize a polymorphic pointer. Could not find type id " + std::to_string(id));
687 //! Registers a polymorphic name string to its unique identifier
688 /*! After a polymorphic type has been loaded for the first time, it should
689 be registered with its loaded id for future references to it.
691 @param id The unique identifier for the polymorphic type
692 @param name The name associated with the tyep */
693 inline void registerPolymorphicName(std::uint32_t const id, std::string const & name)
695 std::uint32_t const stripped_id = id & ~detail::msb_32bit;
696 itsPolymorphicTypeMap.insert( {stripped_id, name} );
700 //! Serializes data after calling prologue, then calls epilogue
701 template <class T> inline
702 void process( T && head )
704 prologue( *self, head );
705 self->processImpl( head );
706 epilogue( *self, head );
709 //! Unwinds to process all data
710 template <class T, class ... Other> inline
711 void process( T && head, Other && ... tail )
713 process( std::forward<T>( head ) );
714 process( std::forward<Other>( tail )... );
717 //! Serialization of a virtual_base_class wrapper
718 /*! \sa virtual_base_class */
719 template <class T> inline
720 ArchiveType & processImpl(virtual_base_class<T> & b)
722 traits::detail::base_class_id id(b.base_ptr);
723 if(itsBaseClassSet.count(id) == 0)
725 itsBaseClassSet.insert(id);
726 self->processImpl( *b.base_ptr );
731 //! Serialization of a base_class wrapper
732 /*! \sa base_class */
733 template <class T> inline
734 ArchiveType & processImpl(base_class<T> & b)
736 self->processImpl( *b.base_ptr );
740 //! Member serialization
741 template <class T> inline
742 typename std::enable_if<traits::has_member_serialize<T, ArchiveType>::value &&
743 (traits::is_specialized_member_serialize<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
747 access::member_serialize(*self, t);
751 //! Non member serialization
752 template <class T> inline
753 typename std::enable_if<traits::has_non_member_serialize<T, ArchiveType>::value &&
754 (traits::is_specialized_non_member_serialize<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
762 //! Member split (load)
763 template <class T> inline
764 typename std::enable_if<traits::has_member_load<T, ArchiveType>::value &&
765 (traits::is_specialized_member_load<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
769 access::member_load(*self, t);
773 //! Non member split (load)
774 template <class T> inline
775 typename std::enable_if<traits::has_non_member_load<T, ArchiveType>::value &&
776 (traits::is_specialized_non_member_load<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
784 //! Member split (load_minimal)
785 template <class T> inline
786 typename std::enable_if<traits::has_member_load_minimal<T, ArchiveType>::value &&
787 (traits::is_specialized_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
791 typename traits::has_member_save_minimal<T, ArchiveType>::type value;
792 self->process( value );
793 access::member_load_minimal(*self, t, value);
797 //! Non member split (load_minimal)
798 template <class T> inline
799 typename std::enable_if<traits::has_non_member_load_minimal<T, ArchiveType>::value &&
800 (traits::is_specialized_non_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
804 typename traits::has_non_member_save_minimal<T, ArchiveType>::type value;
805 self->process( value );
806 load_minimal(*self, t, value);
810 //! Empty class specialization
811 template <class T> inline
812 typename std::enable_if<(Flags & AllowEmptyClassElision) &&
813 !traits::is_specialized<T, ArchiveType>::value &&
814 !traits::is_input_serializable<T, ArchiveType>::value && std::is_empty<T>::value, ArchiveType &>::type
815 processImpl(T const &)
820 //! No matching serialization
821 template <class T> inline
822 typename std::enable_if<!traits::is_specialized<T, ArchiveType>::value && !traits::is_input_serializable<T, ArchiveType>::value &&
823 (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)),
825 processImpl(T const &)
827 static_assert(traits::is_output_serializable<T, ArchiveType>::value, "Trying to serialize an unserializable type with an output archive. \n\n "
828 "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
829 "Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions. \n "
830 "In addition, you may not mix versioned with non-versioned serialization functions. \n "
831 "Serialize functions generally have the following signature: \n\n "
832 "template<class Archive> \n "
833 " void serialize(Archive & ar) \n "
835 " ar( member1, member2, member3 ); \n "
840 //! Registers a class version with the archive and serializes it if necessary
841 /*! If this is the first time this class has been serialized, we will record its
842 version number and serialize that.
844 @tparam T The type of the class being serialized
845 @param version The version number associated with it */
846 template <class T> inline
847 std::uint32_t loadClassVersion()
849 static const auto hash = std::type_index(typeid(T)).hash_code();
850 auto lookupResult = itsVersionedTypes.find( hash );
852 if( lookupResult != itsVersionedTypes.end() ) // already exists
853 return lookupResult->second;
856 std::uint32_t version;
858 process( make_nvp<ArchiveType>("cereal_class_version", version) );
859 itsVersionedTypes.insert( lookupResult, std::pair<std::size_t, std::uint32_t>(hash, version) );
865 //! Member serialization
866 /*! Versioning implementation */
867 template <class T> inline
868 typename std::enable_if<traits::has_member_versioned_serialize<T, ArchiveType>::value &&
869 (traits::is_specialized_member_serialize<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
873 const auto version = loadClassVersion<T>();
874 access::member_serialize(*self, t, version);
878 //! Non member serialization
879 /*! Versioning implementation */
880 template <class T> inline
881 typename std::enable_if<traits::has_non_member_versioned_serialize<T, ArchiveType>::value &&
882 (traits::is_specialized_non_member_serialize<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
886 const auto version = loadClassVersion<T>();
887 serialize(*self, t, version);
891 //! Member split (load)
892 /*! Versioning implementation */
893 template <class T> inline
894 typename std::enable_if<traits::has_member_versioned_load<T, ArchiveType>::value &&
895 (traits::is_specialized_member_load<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
899 const auto version = loadClassVersion<T>();
900 access::member_load(*self, t, version);
904 //! Non member split (load)
905 /*! Versioning implementation */
906 template <class T> inline
907 typename std::enable_if<traits::has_non_member_versioned_load<T, ArchiveType>::value &&
908 (traits::is_specialized_non_member_load<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
912 const auto version = loadClassVersion<T>();
913 load(*self, t, version);
917 //! Member split (load_minimal)
918 /*! Versioning implementation */
919 template <class T> inline
920 typename std::enable_if<traits::has_member_versioned_load_minimal<T, ArchiveType>::value &&
921 (traits::is_specialized_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
925 const auto version = loadClassVersion<T>();
926 typename traits::has_member_versioned_save_minimal<T, ArchiveType>::type value;
927 self->process(value);
928 access::member_load_minimal(*self, t, value, version);
932 //! Non member split (load_minimal)
933 /*! Versioning implementation */
934 template <class T> inline
935 typename std::enable_if<traits::has_non_member_versioned_load_minimal<T, ArchiveType>::value &&
936 (traits::is_specialized_non_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
940 const auto version = loadClassVersion<T>();
941 typename traits::has_non_member_versioned_save_minimal<T, ArchiveType>::type value;
942 self->process(value);
943 load_minimal(*self, t, value, version);
948 ArchiveType * const self;
950 //! A set of all base classes that have been serialized
951 std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
953 //! Maps from pointer ids to metadata
954 std::unordered_map<std::uint32_t, std::shared_ptr<void>> itsSharedPointerMap;
956 //! Maps from name ids to names
957 std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap;
959 //! Maps from type hash codes to version numbers
960 std::unordered_map<std::size_t, std::uint32_t> itsVersionedTypes;
961 }; // class InputArchive
962 } // namespace cereal
964 // This include needs to come after things such as binary_data, make_nvp, etc
965 #include <cereal/types/common.hpp>
967 #endif // CEREAL_CEREAL_HPP_