upgrade cereal
This commit is contained in:
@@ -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()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user