29 #ifndef CEREAL_CEREAL_HPP_
30 #define CEREAL_CEREAL_HPP_
32 #include <type_traits>
35 #include <unordered_map>
36 #include <unordered_set>
53 template <
class T>
inline
56 return {name.c_str(), std::forward<T>(value)};
62 template <
class T>
inline
65 return {name, std::forward<T>(value)};
71 #define CEREAL_NVP(T) ::cereal::make_nvp(#T, T)
79 template <
class T>
inline
82 return {std::forward<T>(data), size};
97 return {std::forward<T>(sz)};
107 template <
class Archive,
class T>
114 template <
class Archive,
class T>
131 enum Flags { AllowEmptyClassElision = 1 };
141 #define CEREAL_REGISTER_ARCHIVE(Archive) \
142 namespace cereal { namespace detail { \
143 template <class T, class BindingTag> \
144 typename polymorphic_serialization_support<Archive, T>::type \
145 instantiate_polymorphic_binding( T*, Archive*, BindingTag, adl_tag ); \
199 #define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER) \
200 namespace cereal { namespace detail { \
201 template <> struct Version<TYPE> \
203 static const std::uint32_t version; \
204 static std::uint32_t registerVersion() \
206 ::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
207 std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER ); \
208 return VERSION_NUMBER; \
210 static void unused() { (void)version; } \
212 const std::uint32_t Version<TYPE>::version = \
213 Version<TYPE>::registerVersion(); \
214 } } // end namespaces
233 template<
class ArchiveType, std::u
int32_t Flags = 0>
239 OutputArchive(ArchiveType *
const derived) : self(derived), itsCurrentPointerId(1), itsCurrentPolymorphicTypeId(1)
246 template <
class ... Types>
inline
249 self->process( std::forward<Types>( args )... );
262 template <
class T>
inline
265 self->process( std::forward<T>( arg ) );
273 template <
class T>
inline
276 self->process( std::forward<T>( arg ) );
293 if(addr == 0)
return 0;
295 auto id = itsSharedPointerMap.find( addr );
296 if(
id == itsSharedPointerMap.end() )
298 auto ptrId = itsCurrentPointerId++;
299 itsSharedPointerMap.insert( {addr, ptrId} );
300 return ptrId | detail::msb_32bit;
316 auto id = itsPolymorphicTypeMap.find( name );
317 if(
id == itsPolymorphicTypeMap.end() )
319 auto polyId = itsCurrentPolymorphicTypeId++;
320 itsPolymorphicTypeMap.insert( {name, polyId} );
321 return polyId | detail::msb_32bit;
329 template <
class T>
inline
330 void process( T && head )
333 self->processImpl( head );
338 template <
class T,
class ... Other>
inline
339 void process( T && head, Other && ... tail )
341 self->process( std::forward<T>( head ) );
342 self->process( std::forward<Other>( tail )... );
347 template <
class T>
inline
348 ArchiveType & processImpl(virtual_base_class<T>
const & b)
350 traits::detail::base_class_id id(b.base_ptr);
351 if(itsBaseClassSet.count(
id) == 0)
353 itsBaseClassSet.insert(
id);
354 self->processImpl( *b.base_ptr );
361 template <
class T>
inline
362 ArchiveType & processImpl(base_class<T>
const & b)
364 self->processImpl( *b.base_ptr );
375 #define PROCESS_IF(name) \
376 traits::EnableIf<traits::has_##name<T, ArchiveType>::value, \
377 !traits::has_invalid_output_versioning<T, ArchiveType>::value, \
378 (traits::is_output_serializable<T, ArchiveType>::value && \
379 (traits::is_specialized_##name<T, ArchiveType>::value || \
380 !traits::is_specialized<T, ArchiveType>::value))> = traits::sfinae
383 template <
class T, PROCESS_IF(member_serialize)>
inline
384 ArchiveType & processImpl(T
const & t)
386 access::member_serialize(*
self, const_cast<T &>(t));
391 template <
class T, PROCESS_IF(non_member_serialize)>
inline
392 ArchiveType & processImpl(T
const & t)
399 template <
class T, PROCESS_IF(member_save)>
inline
400 ArchiveType & processImpl(T
const & t)
402 access::member_save(*
self, t);
407 template <
class T, PROCESS_IF(non_member_save)>
inline
408 ArchiveType & processImpl(T
const & t)
415 template <
class T, PROCESS_IF(member_save_minimal)>
inline
416 ArchiveType & processImpl(T
const & t)
418 self->process( access::member_save_minimal(*
self, t) );
423 template <
class T, PROCESS_IF(non_member_save_minimal)>
inline
424 ArchiveType & processImpl(T
const & t)
432 !traits::is_output_serializable<T, ArchiveType>::value,
433 std::is_empty<T>::value> = traits::sfinae>
inline
434 ArchiveType & processImpl(T
const &)
443 template <class T, traits::EnableIf<traits::has_invalid_output_versioning<T, ArchiveType>::value ||
444 (!traits::is_output_serializable<T, ArchiveType>::value &&
445 (!(
Flags & AllowEmptyClassElision) || ((
Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae>
inline
446 ArchiveType & processImpl(T
const &)
448 static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value != 0,
449 "cereal could not find any output serialization functions for the provided type and archive combination. \n\n "
450 "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
451 "Serialize functions generally have the following signature: \n\n "
452 "template<class Archive> \n "
453 " void serialize(Archive & ar) \n "
455 " ar( member1, member2, member3 ); \n "
458 static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value < 2,
459 "cereal found more than one compatible output serialization function for the provided type and archive combination. \n\n "
460 "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
461 "Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions. \n "
462 "Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
463 "In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
474 template <
class T>
inline
475 std::uint32_t registerClassVersion()
477 static const auto hash = std::type_index(
typeid(T)).hash_code();
478 const auto insertResult = itsVersionedTypes.insert( hash );
480 detail::StaticObject<detail::Versions>::getInstance().find( hash, detail::Version<T>::version );
482 if( insertResult.second )
483 process( make_nvp<ArchiveType>(
"cereal_class_version", version) );
490 template <
class T, PROCESS_IF(member_versioned_serialize)>
inline
491 ArchiveType & processImpl(T
const & t)
493 access::member_serialize(*
self, const_cast<T &>(t), registerClassVersion<T>());
499 template <
class T, PROCESS_IF(non_member_versioned_serialize)>
inline
500 ArchiveType & processImpl(T
const & t)
508 template <
class T, PROCESS_IF(member_versioned_save)>
inline
509 ArchiveType & processImpl(T
const & t)
511 access::member_save(*
self, t, registerClassVersion<T>());
517 template <
class T, PROCESS_IF(non_member_versioned_save)>
inline
518 ArchiveType & processImpl(T
const & t)
526 template <
class T, PROCESS_IF(member_versioned_save_minimal)>
inline
527 ArchiveType & processImpl(T
const & t)
529 self->process( access::member_save_minimal(*
self, t, registerClassVersion<T>()) );
535 template <
class T, PROCESS_IF(non_member_versioned_save_minimal)>
inline
536 ArchiveType & processImpl(T
const & t)
545 ArchiveType *
const self;
548 std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
551 std::unordered_map<void const *, std::uint32_t> itsSharedPointerMap;
554 std::uint32_t itsCurrentPointerId;
557 std::unordered_map<char const *, std::uint32_t> itsPolymorphicTypeMap;
560 std::uint32_t itsCurrentPolymorphicTypeId;
563 std::unordered_set<size_type> itsVersionedTypes;
583 template<
class ArchiveType, std::u
int32_t Flags = 0>
592 itsSharedPointerMap(),
593 itsPolymorphicTypeMap(),
601 template <
class ... Types>
inline
604 process( std::forward<Types>( args )... );
617 template <
class T>
inline
620 self->process( std::forward<T>( arg ) );
628 template <
class T>
inline
631 self->process( std::forward<T>( arg ) );
646 if(
id == 0)
return std::shared_ptr<void>(
nullptr);
648 auto iter = itsSharedPointerMap.find(
id );
649 if(iter == itsSharedPointerMap.end())
650 throw Exception(
"Error while trying to deserialize a smart pointer. Could not find id " + std::to_string(
id));
663 std::uint32_t
const stripped_id =
id & ~detail::msb_32bit;
664 itsSharedPointerMap[stripped_id] = ptr;
675 auto name = itsPolymorphicTypeMap.find(
id );
676 if(name == itsPolymorphicTypeMap.end())
678 throw Exception(
"Error while trying to deserialize a polymorphic pointer. Could not find type id " + std::to_string(
id));
691 std::uint32_t
const stripped_id =
id & ~detail::msb_32bit;
692 itsPolymorphicTypeMap.insert( {stripped_id, name} );
697 template <
class T>
inline
698 void process( T && head )
701 self->processImpl( head );
706 template <
class T,
class ... Other>
inline
707 void process( T && head, Other && ... tail )
709 process( std::forward<T>( head ) );
710 process( std::forward<Other>( tail )... );
715 template <
class T>
inline
716 ArchiveType & processImpl(virtual_base_class<T> & b)
718 traits::detail::base_class_id id(b.base_ptr);
719 if(itsBaseClassSet.count(
id) == 0)
721 itsBaseClassSet.insert(
id);
722 self->processImpl( *b.base_ptr );
729 template <
class T>
inline
730 ArchiveType & processImpl(base_class<T> & b)
732 self->processImpl( *b.base_ptr );
743 #define PROCESS_IF(name) \
744 traits::EnableIf<traits::has_##name<T, ArchiveType>::value, \
745 !traits::has_invalid_input_versioning<T, ArchiveType>::value, \
746 (traits::is_input_serializable<T, ArchiveType>::value && \
747 (traits::is_specialized_##name<T, ArchiveType>::value || \
748 !traits::is_specialized<T, ArchiveType>::value))> = traits::sfinae
751 template <
class T, PROCESS_IF(member_serialize)>
inline
752 ArchiveType & processImpl(T & t)
754 access::member_serialize(*
self, t);
759 template <
class T, PROCESS_IF(non_member_serialize)>
inline
760 ArchiveType & processImpl(T & t)
767 template <
class T, PROCESS_IF(member_load)>
inline
768 ArchiveType & processImpl(T & t)
770 access::member_load(*
self, t);
775 template <
class T, PROCESS_IF(non_member_load)>
inline
776 ArchiveType & processImpl(T & t)
783 template <
class T, PROCESS_IF(member_load_minimal)>
inline
784 ArchiveType & processImpl(T & t)
786 using OutArchiveType =
typename traits::detail::get_output_from_input<ArchiveType>::type;
787 typename traits::has_member_save_minimal<T, OutArchiveType>::type value;
788 self->process( value );
789 access::member_load_minimal(*
self, t, value);
794 template <
class T, PROCESS_IF(non_member_load_minimal)>
inline
795 ArchiveType & processImpl(T & t)
797 using OutArchiveType =
typename traits::detail::get_output_from_input<ArchiveType>::type;
798 typename traits::has_non_member_save_minimal<T, OutArchiveType>::type value;
799 self->process( value );
806 !traits::is_input_serializable<T, ArchiveType>::value,
807 std::is_empty<T>::value> = traits::sfinae>
inline
808 ArchiveType & processImpl(T
const &)
817 template <class T, traits::EnableIf<traits::has_invalid_input_versioning<T, ArchiveType>::value ||
818 (!traits::is_input_serializable<T, ArchiveType>::value &&
819 (!(
Flags & AllowEmptyClassElision) || ((
Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae>
inline
820 ArchiveType & processImpl(T
const &)
822 static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value != 0,
823 "cereal could not find any input serialization functions for the provided type and archive combination. \n\n "
824 "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
825 "Serialize functions generally have the following signature: \n\n "
826 "template<class Archive> \n "
827 " void serialize(Archive & ar) \n "
829 " ar( member1, member2, member3 ); \n "
832 static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value < 2,
833 "cereal found more than one compatible input serialization function for the provided type and archive combination. \n\n "
834 "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
835 "Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions. \n "
836 "Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
837 "In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
848 template <
class T>
inline
849 std::uint32_t loadClassVersion()
851 static const auto hash = std::type_index(
typeid(T)).hash_code();
852 auto lookupResult = itsVersionedTypes.find( hash );
854 if( lookupResult != itsVersionedTypes.end() )
855 return lookupResult->second;
858 std::uint32_t version;
860 process( make_nvp<ArchiveType>(
"cereal_class_version", version) );
861 itsVersionedTypes.emplace_hint( lookupResult, hash, version );
869 template <
class T, PROCESS_IF(member_versioned_serialize)>
inline
870 ArchiveType & processImpl(T & t)
872 const auto version = loadClassVersion<T>();
873 access::member_serialize(*
self, t, version);
879 template <
class T, PROCESS_IF(non_member_versioned_serialize)>
inline
880 ArchiveType & processImpl(T & t)
882 const auto version = loadClassVersion<T>();
889 template <
class T, PROCESS_IF(member_versioned_load)>
inline
890 ArchiveType & processImpl(T & t)
892 const auto version = loadClassVersion<T>();
893 access::member_load(*
self, t, version);
899 template <
class T, PROCESS_IF(non_member_versioned_load)>
inline
900 ArchiveType & processImpl(T & t)
902 const auto version = loadClassVersion<T>();
909 template <
class T, PROCESS_IF(member_versioned_load_minimal)>
inline
910 ArchiveType & processImpl(T & t)
912 using OutArchiveType =
typename traits::detail::get_output_from_input<ArchiveType>::type;
913 const auto version = loadClassVersion<T>();
914 typename traits::has_member_versioned_save_minimal<T, OutArchiveType>::type value;
915 self->process(value);
916 access::member_load_minimal(*
self, t, value, version);
922 template <
class T, PROCESS_IF(non_member_versioned_load_minimal)>
inline
923 ArchiveType & processImpl(T & t)
925 using OutArchiveType =
typename traits::detail::get_output_from_input<ArchiveType>::type;
926 const auto version = loadClassVersion<T>();
927 typename traits::has_non_member_versioned_save_minimal<T, OutArchiveType>::type value;
928 self->process(value);
936 ArchiveType *
const self;
939 std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
942 std::unordered_map<std::uint32_t, std::shared_ptr<void>> itsSharedPointerMap;
945 std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap;
948 std::unordered_map<std::size_t, std::uint32_t> itsVersionedTypes;
955 #endif // CEREAL_CEREAL_HPP_
A wrapper around size metadata.
Definition: helpers.hpp:250
Support for base classes (virtual and non-virtual)
typename detail::EnableIfHelper< Conditions...>::type EnableIf
Provides a way to enable a function if conditions are met.
Definition: traits.hpp:116
NameValuePair< T > make_nvp(std::string const &name, T &&value)
Creates a name value pair.
Definition: cereal.hpp:54
Internal type trait support.
#define CEREAL_SERIALIZE_FUNCTION_NAME
The serialization/deserialization function name to search for.
Definition: macros.hpp:51
#define CEREAL_SAVE_MINIMAL_FUNCTION_NAME
The serialization (save_minimal) function name to search for.
Definition: macros.hpp:79
void prologue(Archive &, T const &)
Definition: cereal.hpp:108
SizeTag< T > make_size_tag(T &&sz)
Creates a size tag from some variable.
Definition: cereal.hpp:95
std::uint32_t registerPolymorphicType(char const *name)
Registers a polymorphic type name with the archive.
Definition: cereal.hpp:314
Support common types - always included automatically.
Internal helper functionality.
Flags
Special flags for archives.
Definition: cereal.hpp:131
Definition: access.hpp:39
NameValuePair< T > make_nvp(const char *name, T &&value)
Creates a name value pair.
Definition: cereal.hpp:63
ArchiveType & operator&(T &&arg)
Serializes passed in data.
Definition: cereal.hpp:263
For holding name value pairs.
Definition: helpers.hpp:135
Preprocessor macros that can customise the cereal library.
#define CEREAL_LOAD_FUNCTION_NAME
The deserialization (load) function name to search for.
Definition: macros.hpp:58
#define CEREAL_LOAD_MINIMAL_FUNCTION_NAME
The deserialization (load_minimal) function name to search for.
Definition: macros.hpp:72
std::uint32_t registerSharedPointer(void const *addr)
Registers a shared pointer with the archive.
Definition: cereal.hpp:290
A wrapper around data that can be serialized in a binary fashion.
Definition: helpers.hpp:207
OutputArchive(ArchiveType *const derived)
Construct the output archive.
Definition: cereal.hpp:239
Definition: helpers.hpp:228
ArchiveType & operator()(Types &&...args)
Serializes all passed in data.
Definition: cereal.hpp:247
The base output archive class.
Definition: cereal.hpp:234
#define CEREAL_SAVE_FUNCTION_NAME
The serialization (save) function name to search for.
Definition: macros.hpp:65
ArchiveType & operator<<(T &&arg)
Serializes passed in data.
Definition: cereal.hpp:274
An exception class thrown when things go wrong at runtime.
Definition: helpers.hpp:48
BinaryData< T > binary_data(T &&data, size_t size)
Convenience function to create binary data for both const and non const pointers. ...
Definition: cereal.hpp:80
void epilogue(Archive &, T const &)
Definition: cereal.hpp:115