mirror of
https://github.com/USCiLab/cereal.git
synced 2025-10-18 01:45:52 +02:00
Made unit tests work for XML, needed to put scope around output archives since they flush on destruction.
Added some documentation to XML output archive describing how it works. Added attribute size="dynamic" to types that specify a size tag for XML, making it easier for a human to figure out what they can add or remove data from. Documentation updates on a few other things.
This commit is contained in:
@@ -52,16 +52,43 @@ namespace cereal
|
||||
|
||||
// ######################################################################
|
||||
//! An output archive designed to save data to XML
|
||||
/*! This archive uses RapidXML to build an in memory XML tree of the
|
||||
data it serializes before outputting it to its stream upon destruction.
|
||||
The envisioned way of using this archive is in an RAII fashion, letting
|
||||
the automatic destruction of the object cause the flush to its stream.
|
||||
|
||||
XML archives provides a human readable output but at decreased
|
||||
performance (both in time and space) compared to binary archives.
|
||||
|
||||
XML benefits greatly from name-value pairs, which if present, will
|
||||
name the nodes in the output. If these are not present, each level
|
||||
of the output tree will be given an automatically generated delimited name.
|
||||
|
||||
The precision of the output archive controls the number of decimals output
|
||||
for floating point numbers and should be sufficiently large (i.e. at least 20)
|
||||
if there is a desire to have binary equality between the numbers output and
|
||||
those read in.
|
||||
|
||||
XML archives can optionally print the type of everything they serialize, which
|
||||
adds an attribute to each node.
|
||||
|
||||
XML archives do not output the size information for any dynamically sized structure
|
||||
and instead infer it from the number of children for a node. This means that data
|
||||
can be hand edited for dynamic sized structures and will still be readable. This
|
||||
is accomplished through the cereal::SizeTag object, which will also add an attribute
|
||||
to its parent field. */
|
||||
/*! \ingroup Archives */
|
||||
class XMLOutputArchive : public OutputArchive<XMLOutputArchive>
|
||||
{
|
||||
public:
|
||||
//! Construct, outputting to the provided stream
|
||||
//! Construct, outputting to the provided stream upon destruction
|
||||
/*! @param stream The stream to output to. Can be a stringstream, a file stream, or
|
||||
even cout!
|
||||
@param precision The precision for floating point output
|
||||
even cout! Note that since this archive builds a tree in memory,
|
||||
it will not output to the stream until its destructor is called.
|
||||
@param precision The precision for floating point output. For input and output
|
||||
floating point to test equal, this should be at least 20
|
||||
@param outputType Controls whether type information will be printed in attributes */
|
||||
XMLOutputArchive(std::ostream & stream, size_t precision = 10, bool outputType = false ) :
|
||||
XMLOutputArchive(std::ostream & stream, size_t precision = 20, bool outputType = false ) :
|
||||
OutputArchive<XMLOutputArchive>(this),
|
||||
itsStream(stream),
|
||||
itsOutputType( outputType )
|
||||
@@ -185,6 +212,11 @@ namespace cereal
|
||||
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
|
||||
}
|
||||
|
||||
void markDynamicSize()
|
||||
{
|
||||
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "size", "dynamic" ) );
|
||||
}
|
||||
|
||||
protected:
|
||||
//! A struct that contains metadata about a node
|
||||
struct NodeInfo
|
||||
@@ -383,9 +415,13 @@ namespace cereal
|
||||
}
|
||||
|
||||
//! Gets the number of children (usually interpreted as size) for the specified node
|
||||
static size_t getNumChildren( rapidxml::xml_node<> * node = nullptr )
|
||||
static size_t getNumChildren( rapidxml::xml_node<> * node )
|
||||
{
|
||||
size_t size = 0;
|
||||
if( node == nullptr )
|
||||
{
|
||||
std::cerr << "NUM CHILDREN CALLED ON NULL NODE" << std::endl;
|
||||
}
|
||||
node = node->first_node(); // get first child
|
||||
|
||||
while( node != nullptr )
|
||||
@@ -459,8 +495,10 @@ namespace cereal
|
||||
//! Prologue for SizeTags for XML output archives
|
||||
/*! SizeTags do not start or finish nodes */
|
||||
template <class T>
|
||||
void prologue( XMLOutputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
void prologue( XMLOutputArchive & ar, SizeTag<T> const & )
|
||||
{
|
||||
ar.markDynamicSize();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void prologue( XMLInputArchive &, SizeTag<T> const & )
|
||||
|
||||
@@ -33,11 +33,11 @@
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <map>
|
||||
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace map_detail
|
||||
{
|
||||
//! @internal
|
||||
template <class Archive, class MapT> inline
|
||||
void save( Archive & ar, MapT const & map )
|
||||
{
|
||||
@@ -49,6 +49,7 @@ namespace cereal
|
||||
}
|
||||
}
|
||||
|
||||
//! @internal
|
||||
template <class Archive, class MapT> inline
|
||||
void load( Archive & ar, MapT & map )
|
||||
{
|
||||
@@ -69,28 +70,30 @@ namespace cereal
|
||||
}
|
||||
}
|
||||
|
||||
//! Saving for std::map to binary
|
||||
//! Saving for std::map
|
||||
template <class Archive, class K, class T, class C, class A> inline
|
||||
void save( Archive & ar, std::map<K, T, C, A> const & map )
|
||||
{
|
||||
map_detail::save( ar, map );
|
||||
}
|
||||
|
||||
//! Loading for std::map to binary
|
||||
//! Loading for std::map
|
||||
template <class Archive, class K, class T, class C, class A> inline
|
||||
void load( Archive & ar, std::map<K, T, C, A> & map )
|
||||
{
|
||||
map_detail::load( ar, map );
|
||||
}
|
||||
|
||||
//! Saving for std::multimap to binary
|
||||
//! Saving for std::multimap
|
||||
/*! @note serialization for this type is not guaranteed to preserve ordering */
|
||||
template <class Archive, class K, class T, class C, class A> inline
|
||||
void save( Archive & ar, std::multimap<K, T, C, A> const & multimap )
|
||||
{
|
||||
map_detail::save( ar, multimap );
|
||||
}
|
||||
|
||||
//! Loading for std::multimap to binary
|
||||
//! Loading for std::multimap
|
||||
/*! @note serialization for this type is not guaranteed to preserve ordering */
|
||||
template <class Archive, class K, class T, class C, class A> inline
|
||||
void load( Archive & ar, std::multimap<K, T, C, A> & multimap )
|
||||
{
|
||||
|
||||
@@ -84,6 +84,7 @@ namespace cereal
|
||||
namespace polymorphic_detail
|
||||
{
|
||||
//! Get an input binding from the given archive by deserializing the type meta data
|
||||
/*! @internal */
|
||||
template<class Archive> inline
|
||||
typename ::cereal::detail::InputBindingMap<Archive>::Serializers getInputBinding(Archive & ar, std::uint32_t const nameid)
|
||||
{
|
||||
@@ -113,6 +114,7 @@ namespace cereal
|
||||
}
|
||||
|
||||
//! Serialize a shared_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
|
||||
/*! @internal */
|
||||
template<class Archive, class T> inline
|
||||
typename std::enable_if<std::is_default_constructible<T>::value || traits::has_load_and_allocate<T, Archive>(), bool>::type
|
||||
serialize_wrapper(Archive & ar, std::shared_ptr<T> & ptr, std::uint32_t const nameid)
|
||||
@@ -126,6 +128,7 @@ namespace cereal
|
||||
}
|
||||
|
||||
//! Serialize a unique_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
|
||||
/*! @internal */
|
||||
template<class Archive, class T, class D> inline
|
||||
typename std::enable_if<std::is_default_constructible<T>::value || traits::has_load_and_allocate<T, Archive>(), bool>::type
|
||||
serialize_wrapper(Archive & ar, std::unique_ptr<T, D> & ptr, std::uint32_t const nameid)
|
||||
@@ -138,6 +141,7 @@ namespace cereal
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! @internal */
|
||||
template<class Archive, class T> inline
|
||||
typename std::enable_if<!std::is_default_constructible<T>::value && !traits::has_load_and_allocate<T, Archive>(), bool>::type
|
||||
serialize_wrapper(Archive &, std::shared_ptr<T> &, std::uint32_t const nameid)
|
||||
@@ -147,6 +151,7 @@ namespace cereal
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! @internal */
|
||||
template<class Archive, class T, class D> inline
|
||||
typename std::enable_if<!std::is_default_constructible<T>::value && !traits::has_load_and_allocate<T, Archive>(), bool>::type
|
||||
serialize_wrapper(Archive &, std::unique_ptr<T, D> &, std::uint32_t const nameid)
|
||||
|
||||
@@ -314,8 +314,11 @@ int main()
|
||||
int xxx[] = {-1, 95, 3};
|
||||
archive( xxx );
|
||||
|
||||
cereal::XMLOutputArchive archive2(std::cout);
|
||||
cereal::XMLOutputArchive archive2(std::cout, 10, true);
|
||||
archive2( xxx );
|
||||
|
||||
std::vector<int> yyy = {1, 2, 3};
|
||||
archive2( yyy );
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -104,9 +104,8 @@ struct OurBase
|
||||
virtual void foo() {}
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar)
|
||||
void serialize(Archive &)
|
||||
{ }
|
||||
|
||||
};
|
||||
|
||||
struct OurType : public OurBase
|
||||
@@ -169,7 +168,10 @@ namespace cereal
|
||||
template <class Archive> struct specialize<Archive, TestType, cereal::specialization::member_serialize> {};
|
||||
}
|
||||
|
||||
CEREAL_REGISTER_TYPE(DerivedVirtual);
|
||||
struct AAA
|
||||
{
|
||||
virtual void foo() = 0;
|
||||
};
|
||||
|
||||
template <class T> void nop(T&&) {}
|
||||
|
||||
|
||||
812
unittests.cpp
812
unittests.cpp
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user