29 #ifndef CEREAL_CEREAL_HPP_
30 #define CEREAL_CEREAL_HPP_
32 #include <type_traits>
36 #include <unordered_map>
37 #include <unordered_set>
54 template <
class T>
inline
57 return {name.c_str(), std::forward<T>(value)};
63 template <
class T>
inline
66 return {name, std::forward<T>(value)};
72 #define CEREAL_NVP(T) ::cereal::make_nvp(#T, T)
80 template <
class T>
inline
83 return {std::forward<T>(data), size};
95 template <
class T>
inline
98 return {std::forward<T>(sz)};
148 template <
class T>
inline
151 return {std::forward<T>(value)};
161 template <
class Archive,
class T>
inline
168 template <
class Archive,
class T>
inline
185 enum Flags { AllowEmptyClassElision = 1 };
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 ); \
203 #if defined(__GNUC__)
205 #define CEREAL_UNUSED_FUNCTION
207 #define CEREAL_UNUSED_FUNCTION static void unused() { (void)version; }
262 #ifdef CEREAL_HAS_CPP17
266 #define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER) \
267 namespace cereal { namespace detail { \
268 template <> struct Version<TYPE> \
270 static std::uint32_t registerVersion() \
272 ::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
273 std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER ); \
274 return VERSION_NUMBER; \
276 static inline const std::uint32_t version = registerVersion(); \
277 CEREAL_UNUSED_FUNCTION \
279 } } // end namespaces
281 #define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER) \
282 namespace cereal { namespace detail { \
283 template <> struct Version<TYPE> \
285 static const std::uint32_t version; \
286 static std::uint32_t registerVersion() \
288 ::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
289 std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER ); \
290 return VERSION_NUMBER; \
292 CEREAL_UNUSED_FUNCTION \
294 const std::uint32_t Version<TYPE>::version = \
295 Version<TYPE>::registerVersion(); \
296 } } // end namespaces
317 template<
class ArchiveType, std::u
int32_t Flags = 0>
323 OutputArchive(ArchiveType *
const derived) : self(derived), itsCurrentPointerId(1), itsCurrentPolymorphicTypeId(1)
330 template <
class ... Types>
inline
333 self->process( std::forward<Types>( args )... );
341 for(
auto & deferment : itsDeferments )
368 template <
class T>
inline
371 self->process( std::forward<T>( arg ) );
379 template <
class T>
inline
382 self->process( std::forward<T>( arg ) );
400 void const * addr = sharedPointer.get();
403 if(addr == 0)
return 0;
404 itsSharedPointerStorage.push_back(sharedPointer);
406 auto id = itsSharedPointerMap.find( addr );
407 if(
id == itsSharedPointerMap.end() )
409 auto ptrId = itsCurrentPointerId++;
410 itsSharedPointerMap.insert( {addr, ptrId} );
411 return ptrId | detail::msb_32bit;
427 auto id = itsPolymorphicTypeMap.find( name );
428 if(
id == itsPolymorphicTypeMap.end() )
430 auto polyId = itsCurrentPolymorphicTypeId++;
431 itsPolymorphicTypeMap.insert( {name, polyId} );
432 return polyId | detail::msb_32bit;
440 template <
class T>
inline
441 void process( T && head )
444 self->processImpl( head );
449 template <
class T,
class ... Other>
inline
450 void process( T && head, Other && ... tail )
452 self->process( std::forward<T>( head ) );
453 self->process( std::forward<Other>( tail )... );
458 template <
class T>
inline
459 ArchiveType & processImpl(virtual_base_class<T>
const & b)
461 traits::detail::base_class_id id(b.base_ptr);
462 if(itsBaseClassSet.count(
id) == 0)
464 itsBaseClassSet.insert(
id);
465 self->processImpl( *b.base_ptr );
472 template <
class T>
inline
473 ArchiveType & processImpl(base_class<T>
const & b)
475 self->processImpl( *b.base_ptr );
479 std::vector<std::function<void(
void)>> itsDeferments;
481 template <
class T>
inline
482 ArchiveType & processImpl(DeferredData<T>
const & d)
484 std::function<void(
void)> deferment( [
this, d](){
self->process( d.value ); } );
485 itsDeferments.emplace_back( std::move(deferment) );
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
505 template <
class T, PROCESS_IF(member_serialize)>
inline
506 ArchiveType & processImpl(T
const & t)
508 access::member_serialize(*
self,
const_cast<T &
>(t));
513 template <
class T, PROCESS_IF(non_member_serialize)>
inline
514 ArchiveType & processImpl(T
const & t)
521 template <
class T, PROCESS_IF(member_save)>
inline
522 ArchiveType & processImpl(T
const & t)
524 access::member_save(*
self, t);
529 template <
class T, PROCESS_IF(non_member_save)>
inline
530 ArchiveType & processImpl(T
const & t)
537 template <
class T, PROCESS_IF(member_save_minimal)>
inline
538 ArchiveType & processImpl(T
const & t)
540 self->process( access::member_save_minimal(*
self, t) );
545 template <
class T, PROCESS_IF(non_member_save_minimal)>
inline
546 ArchiveType & processImpl(T
const & t)
554 !traits::is_output_serializable<T, ArchiveType>::value,
555 std::is_empty<T>::value> = traits::sfinae>
inline
556 ArchiveType & processImpl(T
const &)
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 &)
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 "
577 " ar( member1, member2, member3 ); \n "
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 ");
595 template <
class T>
inline
596 std::uint32_t registerClassVersion()
598 static const auto hash = std::type_index(
typeid(T)).hash_code();
599 const auto insertResult = itsVersionedTypes.insert( hash );
602 detail::StaticObject<detail::Versions>::getInstance().find( hash, detail::Version<T>::version );
604 if( insertResult.second )
605 process( make_nvp<ArchiveType>(
"cereal_class_version", version) );
612 template <
class T, PROCESS_IF(member_versioned_serialize)>
inline
613 ArchiveType & processImpl(T
const & t)
615 access::member_serialize(*
self,
const_cast<T &
>(t), registerClassVersion<T>());
621 template <
class T, PROCESS_IF(non_member_versioned_serialize)>
inline
622 ArchiveType & processImpl(T
const & t)
630 template <
class T, PROCESS_IF(member_versioned_save)>
inline
631 ArchiveType & processImpl(T
const & t)
633 access::member_save(*
self, t, registerClassVersion<T>());
639 template <
class T, PROCESS_IF(non_member_versioned_save)>
inline
640 ArchiveType & processImpl(T
const & t)
648 template <
class T, PROCESS_IF(member_versioned_save_minimal)>
inline
649 ArchiveType & processImpl(T
const & t)
651 self->process( access::member_save_minimal(*
self, t, registerClassVersion<T>()) );
657 template <
class T, PROCESS_IF(non_member_versioned_save_minimal)>
inline
658 ArchiveType & processImpl(T
const & t)
667 ArchiveType *
const self;
670 std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
673 std::unordered_map<void const *, std::uint32_t> itsSharedPointerMap;
677 std::vector<std::shared_ptr<const void>> itsSharedPointerStorage;
680 std::uint32_t itsCurrentPointerId;
683 std::unordered_map<char const *, std::uint32_t> itsPolymorphicTypeMap;
686 std::uint32_t itsCurrentPolymorphicTypeId;
689 std::unordered_set<size_type> itsVersionedTypes;
709 template<
class ArchiveType, std::u
int32_t Flags = 0>
718 itsSharedPointerMap(),
719 itsPolymorphicTypeMap(),
727 template <
class ... Types>
inline
730 process( std::forward<Types>( args )... );
738 for(
auto & deferment : itsDeferments )
765 template <
class T>
inline
768 self->process( std::forward<T>( arg ) );
776 template <
class T>
inline
779 self->process( std::forward<T>( arg ) );
795 if(
id == 0)
return std::shared_ptr<void>(
nullptr);
797 auto iter = itsSharedPointerMap.find(
id );
798 if(iter == itsSharedPointerMap.end())
799 throw Exception(
"Error while trying to deserialize a smart pointer. Could not find id " + std::to_string(
id));
813 std::uint32_t
const stripped_id =
id & ~detail::msb_32bit;
814 itsSharedPointerMap[stripped_id] = ptr;
826 auto name = itsPolymorphicTypeMap.find(
id );
827 if(name == itsPolymorphicTypeMap.end())
829 throw Exception(
"Error while trying to deserialize a polymorphic pointer. Could not find type id " + std::to_string(
id));
843 std::uint32_t
const stripped_id =
id & ~detail::msb_32bit;
844 itsPolymorphicTypeMap.insert( {stripped_id, name} );
849 template <
class T>
inline
850 void process( T && head )
853 self->processImpl( head );
858 template <
class T,
class ... Other>
inline
859 void process( T && head, Other && ... tail )
861 process( std::forward<T>( head ) );
862 process( std::forward<Other>( tail )... );
867 template <
class T>
inline
868 ArchiveType & processImpl(virtual_base_class<T> & b)
870 traits::detail::base_class_id id(b.base_ptr);
871 if(itsBaseClassSet.count(
id) == 0)
873 itsBaseClassSet.insert(
id);
874 self->processImpl( *b.base_ptr );
881 template <
class T>
inline
882 ArchiveType & processImpl(base_class<T> & b)
884 self->processImpl( *b.base_ptr );
888 std::vector<std::function<void(
void)>> itsDeferments;
890 template <
class T>
inline
891 ArchiveType & processImpl(DeferredData<T>
const & d)
893 std::function<void(
void)> deferment( [
this, d](){
self->process( d.value ); } );
894 itsDeferments.emplace_back( std::move(deferment) );
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
914 template <
class T, PROCESS_IF(member_serialize)>
inline
915 ArchiveType & processImpl(T & t)
917 access::member_serialize(*
self, t);
922 template <
class T, PROCESS_IF(non_member_serialize)>
inline
923 ArchiveType & processImpl(T & t)
930 template <
class T, PROCESS_IF(member_load)>
inline
931 ArchiveType & processImpl(T & t)
933 access::member_load(*
self, t);
938 template <
class T, PROCESS_IF(non_member_load)>
inline
939 ArchiveType & processImpl(T & t)
946 template <
class T, PROCESS_IF(member_load_minimal)>
inline
947 ArchiveType & processImpl(T & t)
949 using OutArchiveType =
typename traits::detail::get_output_from_input<ArchiveType>::type;
950 typename traits::has_member_save_minimal<T, OutArchiveType>::type value;
951 self->process( value );
952 access::member_load_minimal(*
self, t, value);
957 template <
class T, PROCESS_IF(non_member_load_minimal)>
inline
958 ArchiveType & processImpl(T & t)
960 using OutArchiveType =
typename traits::detail::get_output_from_input<ArchiveType>::type;
961 typename traits::has_non_member_save_minimal<T, OutArchiveType>::type value;
962 self->process( value );
969 !traits::is_input_serializable<T, ArchiveType>::value,
970 std::is_empty<T>::value> = traits::sfinae>
inline
971 ArchiveType & processImpl(T
const &)
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 &)
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 "
992 " ar( member1, member2, member3 ); \n "
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 ");
1013 template <
class T>
inline
1014 std::uint32_t loadClassVersion()
1016 static const auto hash = std::type_index(
typeid(T)).hash_code();
1017 auto lookupResult = itsVersionedTypes.find( hash );
1019 if( lookupResult != itsVersionedTypes.end() )
1020 return lookupResult->second;
1023 std::uint32_t version;
1025 process( make_nvp<ArchiveType>(
"cereal_class_version", version) );
1026 itsVersionedTypes.emplace_hint( lookupResult, hash, version );
1034 template <
class T, PROCESS_IF(member_versioned_serialize)>
inline
1035 ArchiveType & processImpl(T & t)
1037 const auto version = loadClassVersion<T>();
1038 access::member_serialize(*
self, t, version);
1044 template <
class T, PROCESS_IF(non_member_versioned_serialize)>
inline
1045 ArchiveType & processImpl(T & t)
1047 const auto version = loadClassVersion<T>();
1054 template <
class T, PROCESS_IF(member_versioned_load)>
inline
1055 ArchiveType & processImpl(T & t)
1057 const auto version = loadClassVersion<T>();
1058 access::member_load(*
self, t, version);
1064 template <
class T, PROCESS_IF(non_member_versioned_load)>
inline
1065 ArchiveType & processImpl(T & t)
1067 const auto version = loadClassVersion<T>();
1074 template <
class T, PROCESS_IF(member_versioned_load_minimal)>
inline
1075 ArchiveType & processImpl(T & t)
1077 using OutArchiveType =
typename traits::detail::get_output_from_input<ArchiveType>::type;
1078 const auto version = loadClassVersion<T>();
1079 typename traits::has_member_versioned_save_minimal<T, OutArchiveType>::type value;
1080 self->process(value);
1081 access::member_load_minimal(*
self, t, value, version);
1087 template <
class T, PROCESS_IF(non_member_versioned_load_minimal)>
inline
1088 ArchiveType & processImpl(T & t)
1090 using OutArchiveType =
typename traits::detail::get_output_from_input<ArchiveType>::type;
1091 const auto version = loadClassVersion<T>();
1092 typename traits::has_non_member_versioned_save_minimal<T, OutArchiveType>::type value;
1093 self->process(value);
1101 ArchiveType *
const self;
1104 std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
1107 std::unordered_map<std::uint32_t, std::shared_ptr<void>> itsSharedPointerMap;
1110 std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap;
1113 std::unordered_map<std::size_t, std::uint32_t> itsVersionedTypes;
1120 #endif // CEREAL_CEREAL_HPP_