upgrade cereal

This commit is contained in:
Bassem Girgis
2020-01-22 15:55:26 -06:00
parent d5109aa647
commit 821d5b0a28
56 changed files with 3717 additions and 1624 deletions

View File

@@ -32,6 +32,7 @@
#include <type_traits>
#include <string>
#include <memory>
#include <functional>
#include <unordered_map>
#include <unordered_set>
#include <vector>
@@ -97,6 +98,59 @@ namespace cereal
return {std::forward<T>(sz)};
}
// ######################################################################
//! Marks data for deferred serialization
/*! cereal performs a recursive depth-first traversal of data it serializes. When
serializing smart pointers to large, nested, or cyclical data structures, it
is possible to encounter a stack overflow from excessive recursion when following
a chain of pointers.
Deferment can help in these situations if the data can be serialized separately from
the pointers used to traverse the structure. For example, a graph structure can have its
nodes serialized before its edges:
@code{.cpp}
struct MyEdge
{
std::shared_ptr<MyNode> connection;
int some_value;
template<class Archive>
void serialize(Archive & archive)
{
// when we serialize an edge, we'll defer serializing the associated node
archive( cereal::defer( connection ),
some_value );
}
};
struct MyGraphStructure
{
std::vector<MyEdge> edges;
std::vector<MyNodes> nodes;
template<class Archive>
void serialize(Archive & archive)
{
// because of the deferment, we ensure all nodes are fully serialized
// before any connection pointers to those nodes are serialized
archive( edges, nodes );
// we have to explicitly inform the archive when it is safe to serialize
// the deferred data
archive.serializeDeferments();
}
};
@endcode
@relates DeferredData
@ingroup Utility */
template <class T> inline
DeferredData<T> defer( T && value )
{
return {std::forward<T>(value)};
}
// ######################################################################
//! Called before a type is serialized to set up any special archive state
//! for processing some type
@@ -145,6 +199,14 @@ namespace cereal
instantiate_polymorphic_binding( T*, Archive*, BindingTag, adl_tag ); \
} } /* end namespaces */
//! Helper macro to omit unused warning
#if defined(__GNUC__)
// GCC / clang don't want the function
#define CEREAL_UNUSED_FUNCTION
#else
#define CEREAL_UNUSED_FUNCTION static void unused() { (void)version; }
#endif
// ######################################################################
//! Defines a class version for some type
/*! Versioning information is optional and adds some small amount of
@@ -207,7 +269,7 @@ namespace cereal
std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER ); \
return VERSION_NUMBER; \
} \
static void unused() { (void)version; } \
CEREAL_UNUSED_FUNCTION \
}; /* end Version */ \
const std::uint32_t Version<TYPE>::version = \
Version<TYPE>::registerVersion(); \
@@ -250,6 +312,14 @@ namespace cereal
return *self;
}
//! Serializes any data marked for deferment using defer
/*! This will cause any data wrapped in DeferredData to be immediately serialized */
void serializeDeferments()
{
for( auto & deferment : itsDeferments )
deferment();
}
/*! @name Boost Transition Layer
Functionality that mirrors the syntax for Boost. This is useful if you are transitioning
a large project from Boost to cereal. The preferred interface for cereal is using operator(). */
@@ -258,14 +328,14 @@ namespace cereal
//! Indicates this archive is not intended for loading
/*! This ensures compatibility with boost archive types. If you are transitioning
from boost, you can check this value within a member or external serialize function
(i.e., Archive::is_loading::value) to disable behavior specific to loading, until
(i.e., Archive::is_loading::value) to disable behavior specific to loading, until
you can transition to split save/load or save_minimal/load_minimal functions */
using is_loading = std::false_type;
//! Indicates this archive is intended for saving
/*! This ensures compatibility with boost archive types. If you are transitioning
from boost, you can check this value within a member or external serialize function
(i.e., Archive::is_saving::value) to enable behavior specific to loading, until
(i.e., Archive::is_saving::value) to enable behavior specific to loading, until
you can transition to split save/load or save_minimal/load_minimal functions */
using is_saving = std::true_type;
@@ -379,6 +449,17 @@ namespace cereal
return *self;
}
std::vector<std::function<void(void)>> itsDeferments;
template <class T> inline
ArchiveType & processImpl(DeferredData<T> const & d)
{
std::function<void(void)> deferment( [=](){ self->process( d.value ); } );
itsDeferments.emplace_back( std::move(deferment) );
return *self;
}
//! Helper macro that expands the requirements for activating an overload
/*! Requirements:
Has the requested serialization function
@@ -483,8 +564,7 @@ namespace cereal
/*! If this is the first time this class has been serialized, we will record its
version number and serialize that.
@tparam T The type of the class being serialized
@param version The version number associated with it */
@tparam T The type of the class being serialized */
template <class T> inline
std::uint32_t registerClassVersion()
{
@@ -620,6 +700,14 @@ namespace cereal
return *self;
}
//! Serializes any data marked for deferment using defer
/*! This will cause any data wrapped in DeferredData to be immediately serialized */
void serializeDeferments()
{
for( auto & deferment : itsDeferments )
deferment();
}
/*! @name Boost Transition Layer
Functionality that mirrors the syntax for Boost. This is useful if you are transitioning
a large project from Boost to cereal. The preferred interface for cereal is using operator(). */
@@ -628,14 +716,14 @@ namespace cereal
//! Indicates this archive is intended for loading
/*! This ensures compatibility with boost archive types. If you are transitioning
from boost, you can check this value within a member or external serialize function
(i.e., Archive::is_loading::value) to enable behavior specific to loading, until
(i.e., Archive::is_loading::value) to enable behavior specific to loading, until
you can transition to split save/load or save_minimal/load_minimal functions */
using is_loading = std::true_type;
//! Indicates this archive is not intended for saving
/*! This ensures compatibility with boost archive types. If you are transitioning
from boost, you can check this value within a member or external serialize function
(i.e., Archive::is_saving::value) to disable behavior specific to loading, until
(i.e., Archive::is_saving::value) to disable behavior specific to loading, until
you can transition to split save/load or save_minimal/load_minimal functions */
using is_saving = std::false_type;
@@ -667,6 +755,7 @@ namespace cereal
/*! This is used to retrieve a previously registered shared_ptr
which has already been loaded.
@internal
@param id The unique id that was serialized for the pointer
@return A shared pointer to the data
@throw Exception if the id does not exist */
@@ -685,6 +774,7 @@ namespace cereal
/*! After a shared pointer has been allocated for the first time, it should
be registered with its loaded id for future references to it.
@internal
@param id The unique identifier for the shared pointer
@param ptr The actual shared pointer */
inline void registerSharedPointer(std::uint32_t const id, std::shared_ptr<void> ptr)
@@ -697,6 +787,7 @@ namespace cereal
/*! This is used to retrieve a string previously registered during
a polymorphic load.
@internal
@param id The unique id that was serialized for the polymorphic type
@return The string identifier for the tyep */
inline std::string getPolymorphicName(std::uint32_t const id)
@@ -713,6 +804,7 @@ namespace cereal
/*! After a polymorphic type has been loaded for the first time, it should
be registered with its loaded id for future references to it.
@internal
@param id The unique identifier for the polymorphic type
@param name The name associated with the tyep */
inline void registerPolymorphicName(std::uint32_t const id, std::string const & name)
@@ -762,6 +854,17 @@ namespace cereal
return *self;
}
std::vector<std::function<void(void)>> itsDeferments;
template <class T> inline
ArchiveType & processImpl(DeferredData<T> const & d)
{
std::function<void(void)> deferment( [=](){ self->process( d.value ); } );
itsDeferments.emplace_back( std::move(deferment) );
return *self;
}
//! Helper macro that expands the requirements for activating an overload
/*! Requirements:
Has the requested serialization function
@@ -875,8 +978,7 @@ namespace cereal
/*! If this is the first time this class has been serialized, we will record its
version number and serialize that.
@tparam T The type of the class being serialized
@param version The version number associated with it */
@tparam T The type of the class being serialized */
template <class T> inline
std::uint32_t loadClassVersion()
{