27 #ifndef CEREAL_CEREAL_HPP_
28 #define CEREAL_CEREAL_HPP_
30 #include <type_traits>
31 #include <unordered_map>
32 #include <unordered_set>
36 #include <cereal/details/traits.hpp>
37 #include <cereal/details/helpers.hpp>
38 #include <cereal/types/base_class.hpp>
39 #include <cereal/types/common.hpp>
49 using std::runtime_error::runtime_error;
55 template <
class T>
inline
58 return {name.c_str(), std::forward<T>(value)};
63 template <
class T>
inline
66 return {name, std::forward<T>(value)};
71 #define CEREAL_NVP(T) ::cereal::make_nvp(#T, T)
78 template <
class T>
inline
81 return {std::forward<T>(data), size};
93 return {std::forward<T>(sz)};
102 template <
class Archive,
class T>
103 void prologue( Archive & , T
const & )
108 template <
class Archive,
class T>
109 void epilogue( Archive & , T
const & )
124 enum Flags { AllowEmptyClassElision = 1 };
132 #define CEREAL_REGISTER_ARCHIVE(Archive) \
133 namespace cereal { namespace detail { \
135 typename polymorphic_serialization_support<Archive, T>::type \
136 instantiate_polymorphic_binding( T*, Archive*, adl_tag ); \
137 } } // end namespaces
154 template<
class ArchiveType, std::u
int32_t Flags = 0>
160 OutputArchive(ArchiveType *
const self) : self(self), itsCurrentPointerId(1), itsCurrentPolymorphicTypeId(1)
164 template <
class ... Types>
inline
167 self->process( std::forward<Types>( args )... );
181 if(addr == 0)
return 0;
183 auto id = itsSharedPointerMap.find( addr );
184 if(
id == itsSharedPointerMap.end() )
186 auto ptrId = itsCurrentPointerId++;
187 itsSharedPointerMap.insert( {addr, ptrId} );
188 return ptrId | detail::msb_32bit;
203 auto id = itsPolymorphicTypeMap.find( name );
204 if(
id == itsPolymorphicTypeMap.end() )
206 auto polyId = itsCurrentPolymorphicTypeId++;
207 itsPolymorphicTypeMap.insert( {name, polyId} );
208 return polyId | detail::msb_32bit;
216 template <
class T>
inline
217 void process( T && head )
219 prologue( *
self, head );
220 self->processImpl( head );
221 epilogue( *
self, head );
225 template <
class T,
class ... Other>
inline
226 void process( T && head, Other && ... tail )
228 self->process( std::forward<T>( head ) );
229 self->process( std::forward<Other>( tail )... );
234 template <
class T>
inline
235 ArchiveType & processImpl(virtual_base_class<T>
const & b)
237 traits::detail::base_class_id id(b.base_ptr);
238 if(itsBaseClassSet.count(
id) == 0)
240 itsBaseClassSet.insert(
id);
241 self->processImpl( *b.base_ptr );
248 template <
class T>
inline
249 ArchiveType & processImpl(base_class<T>
const & b)
251 self->processImpl( *b.base_ptr );
256 template <
class T>
inline
257 typename std::enable_if<traits::is_specialized_member_serialize<T, ArchiveType>() ||
258 (traits::is_output_serializable<T, ArchiveType>() && traits::has_member_serialize<T, ArchiveType>()),
260 processImpl(T
const & t)
262 access::member_serialize(*
self, const_cast<T &>(t));
267 template <
class T>
inline
268 typename std::enable_if<traits::is_specialized_non_member_serialize<T, ArchiveType>() ||
269 (traits::is_output_serializable<T, ArchiveType>() && traits::has_non_member_serialize<T, ArchiveType>()),
271 processImpl(T
const & t)
273 serialize(*
self, const_cast<T &>(t));
278 template <
class T>
inline
279 typename std::enable_if<traits::is_specialized_member_save<T, ArchiveType>() ||
280 (traits::is_output_serializable<T, ArchiveType>() && traits::has_member_save<T, ArchiveType>()),
282 processImpl(T
const & t)
284 access::member_save(*
self, t);
289 template <
class T>
inline
290 typename std::enable_if<traits::is_specialized_non_member_save<T, ArchiveType>() ||
291 (traits::is_output_serializable<T, ArchiveType>() && traits::has_non_member_save<T, ArchiveType>()),
293 processImpl(T
const & t)
300 template <
class T>
inline
301 typename std::enable_if<(Flags & AllowEmptyClassElision) &&
302 !traits::is_output_serializable<T, ArchiveType>() && traits::is_empty_class<T>(), ArchiveType &>::type
303 processImpl(T
const &)
309 template <
class T>
inline
310 typename std::enable_if<!traits::is_specialized<T, ArchiveType>() && !traits::is_output_serializable<T, ArchiveType>() &&
311 (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !traits::is_empty_class<T>())),
313 processImpl(T
const &)
315 static_assert(traits::is_output_serializable<T, ArchiveType>(),
"Trying to serialize an unserializable type with an output archive.\n\n"
316 "Types must either have a serialize function, or separate save/load functions (but not both).\n"
317 "Serialize functions generally have the following signature:\n\n"
318 "template<class Archive>\n"
319 " void serialize(Archive & ar)\n"
321 " ar( member1, member2, member3 );\n"
327 ArchiveType *
const self;
330 std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
333 std::unordered_map<void const *, std::uint32_t> itsSharedPointerMap;
336 std::uint32_t itsCurrentPointerId;
339 std::unordered_map<char const *, std::uint32_t> itsPolymorphicTypeMap;
342 std::uint32_t itsCurrentPolymorphicTypeId;
361 template<
class ArchiveType, std::u
int32_t Flags = 0>
370 template <
class ... Types>
inline
373 process( std::forward<Types>( args )... );
385 if(
id == 0)
return std::shared_ptr<void>(
nullptr);
387 auto ptr = itsSharedPointerMap.find(
id );
388 if(ptr == itsSharedPointerMap.end())
389 throw Exception(
"Error while trying to deserialize a smart pointer. Could not find id " + std::to_string(
id));
402 std::uint32_t
const stripped_id =
id & ~detail::msb_32bit;
403 itsSharedPointerMap.insert( {stripped_id, ptr} );
414 auto name = itsPolymorphicTypeMap.find(
id );
415 if(name == itsPolymorphicTypeMap.end())
417 throw Exception(
"Error while trying to deserialize a polymorphic pointer. Could not find type id " + std::to_string(
id));
430 std::uint32_t
const stripped_id =
id & ~detail::msb_32bit;
431 itsPolymorphicTypeMap.insert( {stripped_id, name} );
436 template <
class T>
inline
437 void process( T && head )
439 prologue( *
self, head );
440 self->processImpl( head );
441 epilogue( *
self, head );
445 template <
class T,
class ... Other>
inline
446 void process( T && head, Other && ... tail )
448 process( std::forward<T>( head ) );
449 process( std::forward<Other>( tail )... );
454 template <
class T>
inline
455 ArchiveType & processImpl(virtual_base_class<T> & b)
457 traits::detail::base_class_id id(b.base_ptr);
458 if(itsBaseClassSet.count(
id) == 0)
460 itsBaseClassSet.insert(
id);
461 self->processImpl( *b.base_ptr );
468 template <
class T>
inline
469 ArchiveType & processImpl(base_class<T> & b)
471 self->processImpl( *b.base_ptr );
477 template <
class T>
inline
478 typename std::enable_if<traits::is_specialized_member_serialize<T, ArchiveType>() ||
479 (traits::is_input_serializable<T, ArchiveType>() && traits::has_member_serialize<T, ArchiveType>()),
483 access::member_serialize(*
self, t);
488 template <
class T>
inline
489 typename std::enable_if<traits::is_specialized_non_member_serialize<T, ArchiveType>() ||
490 (traits::is_input_serializable<T, ArchiveType>() && traits::has_non_member_serialize<T, ArchiveType>()),
499 template <
class T>
inline
500 typename std::enable_if<traits::is_specialized_member_load<T, ArchiveType>() ||
501 (traits::is_input_serializable<T, ArchiveType>() && traits::has_member_load<T, ArchiveType>()),
505 access::member_load(*
self, t);
510 template <
class T>
inline
511 typename std::enable_if<traits::is_specialized_non_member_load<T, ArchiveType>() ||
512 (traits::is_input_serializable<T, ArchiveType>() && traits::has_non_member_load<T, ArchiveType>()),
521 template <
class T>
inline
522 typename std::enable_if<(Flags & AllowEmptyClassElision) &&
523 !traits::is_input_serializable<T, ArchiveType>() && traits::is_empty_class<T>(), ArchiveType &>::type
524 processImpl(T
const &)
530 template <
class T>
inline
531 typename std::enable_if<!traits::is_specialized<T, ArchiveType>() && !traits::is_input_serializable<T, ArchiveType>() &&
532 (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !traits::is_empty_class<T>())),
534 processImpl(T
const &)
536 static_assert(traits::is_output_serializable<T, ArchiveType>(),
"Trying to serialize an unserializable type with an output archive.\n\n"
537 "Types must either have a serialize function, or separate save/load functions (but not both).\n"
538 "Serialize functions generally have the following signature:\n\n"
539 "template<class Archive>\n"
540 " void serialize(Archive & ar)\n"
542 " ar( member1, member2, member3 );\n"
548 ArchiveType *
const self;
551 std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
554 std::unordered_map<std::uint32_t, std::shared_ptr<void>> itsSharedPointerMap;
557 std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap;
561 #endif // CEREAL_CEREAL_HPP_