mirror of
https://github.com/USCiLab/cereal.git
synced 2025-10-18 01:45:52 +02:00
xml working 100% assuming no weird bugs
This commit is contained in:
@@ -38,8 +38,7 @@
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
@@ -88,23 +87,6 @@ namespace cereal
|
||||
itsXML.clear();
|
||||
}
|
||||
|
||||
//! Saves some data, encoded as a string
|
||||
/*! The data will be be named with the most recent name if one exists,
|
||||
otherwise it will be given some default delimited value that depends upon
|
||||
the parent node */
|
||||
template <class T> inline
|
||||
void saveValue( T const & value )
|
||||
{
|
||||
itsOS.clear(); itsOS.seekp(0);
|
||||
itsOS << value << std::ends;
|
||||
|
||||
// allocate strings for all of the data in the XML object
|
||||
auto dataPtr = itsXML.allocate_string( itsOS.str().c_str() );
|
||||
|
||||
// insert into the XML
|
||||
itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
|
||||
}
|
||||
|
||||
//! Creates a new node that is a child of the node at the top of the stack
|
||||
/*! Nodes will be given a name that has either been pre-set by a name value pair,
|
||||
or generated based upon a counter unique to the parent node.
|
||||
@@ -124,22 +106,6 @@ namespace cereal
|
||||
itsNodes.emplace( node );
|
||||
}
|
||||
|
||||
//! Causes the type to be appended to the most recently made node if output type is set to true
|
||||
template <class T> inline
|
||||
void insertType()
|
||||
{
|
||||
if( !itsOutputType )
|
||||
return;
|
||||
|
||||
// generate a name for this new node
|
||||
const auto nameString = util::demangledName<T>();
|
||||
|
||||
// allocate strings for all of the data in the XML object
|
||||
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.size() );
|
||||
|
||||
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
|
||||
}
|
||||
|
||||
//! Designates the most recently added node as finished
|
||||
void finishNode()
|
||||
{
|
||||
@@ -152,6 +118,23 @@ namespace cereal
|
||||
itsNodes.top().name = name;
|
||||
}
|
||||
|
||||
//! Saves some data, encoded as a string
|
||||
/*! The data will be be named with the most recent name if one exists,
|
||||
otherwise it will be given some default delimited value that depends upon
|
||||
the parent node */
|
||||
template <class T> inline
|
||||
void saveValue( T const & value )
|
||||
{
|
||||
itsOS.clear(); itsOS.seekp(0);
|
||||
itsOS << value << std::ends;
|
||||
|
||||
// allocate strings for all of the data in the XML object
|
||||
auto dataPtr = itsXML.allocate_string( itsOS.str().c_str() );
|
||||
|
||||
// insert into the XML
|
||||
itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
|
||||
}
|
||||
|
||||
//! Saves some binary data, encoded as a base64 string, with an optional name
|
||||
/*! This will create a new node, optionally named, and insert a value that consists of
|
||||
the data encoded as a base64 string */
|
||||
@@ -170,6 +153,22 @@ namespace cereal
|
||||
finishNode();
|
||||
};
|
||||
|
||||
//! Causes the type to be appended to the most recently made node if output type is set to true
|
||||
template <class T> inline
|
||||
void insertType()
|
||||
{
|
||||
if( !itsOutputType )
|
||||
return;
|
||||
|
||||
// generate a name for this new node
|
||||
const auto nameString = util::demangledName<T>();
|
||||
|
||||
// allocate strings for all of the data in the XML object
|
||||
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.size() );
|
||||
|
||||
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
|
||||
}
|
||||
|
||||
protected:
|
||||
//! A struct that contains metadata about a node
|
||||
struct NodeInfo
|
||||
@@ -240,17 +239,100 @@ namespace cereal
|
||||
itsNodes.emplace( root );
|
||||
}
|
||||
|
||||
//! Prepares to start reading the next node
|
||||
void startNode()
|
||||
{
|
||||
itsNodes.emplace( itsNodes.top().child );
|
||||
}
|
||||
|
||||
//! Finishes reading the current node
|
||||
void finishNode()
|
||||
{
|
||||
// remove current
|
||||
itsNodes.pop();
|
||||
|
||||
// advance parent
|
||||
itsNodes.top().advance();
|
||||
}
|
||||
|
||||
//! Loads a value from the current node
|
||||
template <class T> inline
|
||||
void loadValue( T & value )
|
||||
{
|
||||
std::istringstream is( itsNodes.top().node->value() );
|
||||
is.setf( std::ios::boolalpha );
|
||||
is >> value;
|
||||
}
|
||||
|
||||
//! Loads a string from the current node
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
|
||||
{
|
||||
std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
|
||||
|
||||
str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
|
||||
std::istreambuf_iterator<CharT, Traits>() );
|
||||
}
|
||||
|
||||
//! Loads some binary data, encoded as a base64 string
|
||||
/*! This will automatically start and finish a node to load the data */
|
||||
void loadBinaryValue( void * data, size_t size )
|
||||
{
|
||||
startNode();
|
||||
|
||||
std::string encoded;
|
||||
loadValue( encoded );
|
||||
|
||||
auto decoded = base64::decode( encoded );
|
||||
std::memcpy( data, decoded.data(), decoded.size() );
|
||||
|
||||
finishNode();
|
||||
};
|
||||
|
||||
//! Loads the size of the current node
|
||||
template <class T> inline
|
||||
void loadSize( T & value )
|
||||
{
|
||||
value = getNumChildren( itsNodes.top().node );
|
||||
}
|
||||
|
||||
//! Gets the number of children (usually interpreted as size) for the specified node
|
||||
static size_t getNumChildren( rapidxml::xml_node<> * node = nullptr )
|
||||
{
|
||||
size_t size = 0;
|
||||
node = node->first_node(); // get first child
|
||||
|
||||
while( node != nullptr )
|
||||
{
|
||||
++size;
|
||||
node = node->next_sibling();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
protected:
|
||||
//! A struct that contains metadata about a node
|
||||
struct NodeInfo
|
||||
{
|
||||
NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
|
||||
node( n ),
|
||||
counter( 0 )
|
||||
child( n ? n->first_node() : nullptr ),
|
||||
size( XMLInputArchive::getNumChildren( n ) )
|
||||
{ }
|
||||
|
||||
void advance()
|
||||
{
|
||||
if( size )
|
||||
{
|
||||
--size;
|
||||
child = child->next_sibling();
|
||||
}
|
||||
}
|
||||
|
||||
rapidxml::xml_node<> * node; //!< A pointer to this node
|
||||
size_t counter; //!< The counter for naming child nodes
|
||||
rapidxml::xml_node<> * child; //!< A pointer to its current child
|
||||
size_t size;
|
||||
}; // NodeInfo
|
||||
|
||||
private:
|
||||
@@ -261,32 +343,55 @@ namespace cereal
|
||||
|
||||
// ######################################################################
|
||||
// XMLArchive prologue and epilogue functions
|
||||
// ######################################################################
|
||||
|
||||
//! Prologue for NVPs for XML archives
|
||||
// ######################################################################
|
||||
//! Prologue for NVPs for XML output archives
|
||||
/*! NVPs do not start or finish nodes - they just set up the names */
|
||||
template <class T>
|
||||
void prologue( XMLOutputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
//! Epilogue for NVPs for XML archives
|
||||
//! Prologue for NVPs for XML input archives
|
||||
template <class T>
|
||||
void prologue( XMLInputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Epilogue for NVPs for XML output archives
|
||||
/*! NVPs do not start or finish nodes - they just set up the names */
|
||||
template <class T>
|
||||
void epilogue( XMLOutputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
//! Prologue for SizeTags for XML archives
|
||||
/*! SizeTags are strictly ignored for XML */
|
||||
//! Epilogue for NVPs for XML input archives
|
||||
template <class T>
|
||||
void epilogue( XMLInputArchive &, NameValuePair<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for SizeTags for XML output archives
|
||||
/*! SizeTags do not start or finish nodes */
|
||||
template <class T>
|
||||
void prologue( XMLOutputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
//! Epilogue for SizeTags for XML archives
|
||||
/*! SizeTags are strictly ignored for XML */
|
||||
template <class T>
|
||||
void prologue( XMLInputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
//! Epilogue for SizeTags for XML output archives
|
||||
/*! SizeTags do not start or finish nodes */
|
||||
template <class T>
|
||||
void epilogue( XMLOutputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
//! Prologue for all other types for XML archives
|
||||
template <class T>
|
||||
void epilogue( XMLInputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for all other types for XML output archives
|
||||
/*! Starts a new node, named either automatically or by some NVP,
|
||||
that may be given data by the type about to be archived */
|
||||
template <class T>
|
||||
@@ -296,7 +401,15 @@ namespace cereal
|
||||
ar.insertType<T>();
|
||||
}
|
||||
|
||||
//! Epilogue for all other types other for XML archives
|
||||
//! Prologue for all other types for XML input archives
|
||||
template <class T>
|
||||
void prologue( XMLInputArchive & ar, T const & data )
|
||||
{
|
||||
ar.startNode();
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Epilogue for all other types other for XML output archives
|
||||
/*! Finishes the node created in the prologue */
|
||||
template <class T>
|
||||
void epilogue( XMLOutputArchive & ar, T const & data )
|
||||
@@ -304,24 +417,46 @@ namespace cereal
|
||||
ar.finishNode();
|
||||
}
|
||||
|
||||
//! Epilogue for all other types other for XML output archives
|
||||
template <class T>
|
||||
void epilogue( XMLInputArchive & ar, T const & data )
|
||||
{
|
||||
ar.finishNode();
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
// Common XMLArchive serialization functions
|
||||
// ######################################################################
|
||||
|
||||
//! Serializing NVP types to XML
|
||||
template <class Archive, class T> inline
|
||||
CEREAL_ARCHIVE_RESTRICT(XMLInputArchive, XMLOutputArchive)
|
||||
serialize( Archive & ar, NameValuePair<T> & t )
|
||||
//! Saving NVP types to XML
|
||||
template <class T> inline
|
||||
void save( XMLOutputArchive & ar, NameValuePair<T> const & t )
|
||||
{
|
||||
ar.setNextName( t.name );
|
||||
ar( t.value );
|
||||
}
|
||||
|
||||
//! Serializing SizeTags to XML
|
||||
template <class Archive, class T> inline
|
||||
CEREAL_ARCHIVE_RESTRICT(XMLInputArchive, XMLOutputArchive)
|
||||
serialize( Archive & ar, SizeTag<T> & )
|
||||
//! Loading NVP types from XML
|
||||
template <class T> inline
|
||||
void load( XMLInputArchive & ar, NameValuePair<T> & t )
|
||||
{
|
||||
ar( t.value );
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Saving SizeTags to XML
|
||||
template <class T> inline
|
||||
void save( XMLOutputArchive & ar, SizeTag<T> const & )
|
||||
{ }
|
||||
|
||||
//! Loading SizeTags from XML
|
||||
template <class T> inline
|
||||
void load( XMLInputArchive & ar, SizeTag<T> & st )
|
||||
{
|
||||
ar.loadSize( st.size );
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Saving for POD types to xml
|
||||
template<class T> inline
|
||||
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
||||
@@ -330,6 +465,15 @@ namespace cereal
|
||||
ar.saveValue( t );
|
||||
}
|
||||
|
||||
//! Loading for POD types from xml
|
||||
template<class T> inline
|
||||
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
||||
load(XMLInputArchive & ar, T & t)
|
||||
{
|
||||
ar.loadValue( t );
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! saving string to xml
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void save(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
|
||||
@@ -337,9 +481,16 @@ namespace cereal
|
||||
ar.saveValue( str );
|
||||
}
|
||||
|
||||
//! loading string from xml
|
||||
template<class CharT, class Traits, class Alloc> inline
|
||||
void load(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
|
||||
{
|
||||
ar.loadValue( str );
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
// register archives for polymorphic support
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive);
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive);
|
||||
|
||||
#endif // CEREAL_ARCHIVES_XML_HPP_
|
||||
|
||||
@@ -249,9 +249,9 @@ namespace cereal
|
||||
using is_empty_class = std::integral_constant<bool, detail::is_empty_class_impl<T>::value>;
|
||||
|
||||
// ######################################################################
|
||||
//! A macro to use to restrict which types of archives your serialize function will work for.
|
||||
//! A macro to use to restrict which types of archives your function will work for.
|
||||
/*! This requires you to have a template class parameter named Archive and replaces the void return
|
||||
type for your serialize function.
|
||||
type for your function.
|
||||
|
||||
INTYPE refers to the input archive type you wish to restrict on.
|
||||
OUTTYPE refers to the output archive type you wish to restrict on.
|
||||
@@ -265,6 +265,8 @@ namespace cereal
|
||||
{
|
||||
ar & m;
|
||||
}
|
||||
|
||||
If you need to do more restrictions in your enable_if, you will need to do this by hand.
|
||||
@endcode
|
||||
*/
|
||||
#define CEREAL_ARCHIVE_RESTRICT(INTYPE, OUTTYPE) \
|
||||
|
||||
62
sandbox.cpp
62
sandbox.cpp
@@ -321,8 +321,7 @@ int main()
|
||||
|
||||
std::vector<std::vector<std::string>> vec2 = {vec, vec, vec};
|
||||
|
||||
Everything e;
|
||||
oar( cereal::make_nvp("EVERYTHING", e) );
|
||||
oar( cereal::make_nvp("EVERYTHING", e_out) );
|
||||
oar( vec );
|
||||
oar( vec2 );
|
||||
|
||||
@@ -335,8 +334,63 @@ int main()
|
||||
std::ifstream is("out.xml");
|
||||
cereal::XMLInputArchive iar( is );
|
||||
|
||||
//int z;
|
||||
//iar( cereal::make_nvp("hello", z) );
|
||||
int hello;
|
||||
iar( cereal::make_nvp("hello", hello) );
|
||||
assert( hello == 5 );
|
||||
|
||||
std::string bla;
|
||||
iar( bla );
|
||||
assert( bla == "bla" );
|
||||
|
||||
int x;
|
||||
iar( CEREAL_NVP(x) );
|
||||
assert( x == 3 );
|
||||
|
||||
int x5;
|
||||
iar( x5 );
|
||||
assert( x5 == 5 );
|
||||
|
||||
double x33;
|
||||
iar( x33 );
|
||||
assert( x33 == 3.3 );
|
||||
|
||||
float x32;
|
||||
iar( x32 );
|
||||
assert( x32 == 3.2f );
|
||||
|
||||
bool xtrue;
|
||||
iar( xtrue );
|
||||
assert( xtrue == true );
|
||||
|
||||
std::array<int,5> arr;
|
||||
iar( arr );
|
||||
for( size_t i = 0; i < 5; ++i )
|
||||
assert( arr[i] == (i+1) );
|
||||
|
||||
Everything e;
|
||||
iar( cereal::make_nvp("EVERYTHING", e) );
|
||||
assert( e == e_out );
|
||||
|
||||
std::vector<std::string> vec;
|
||||
iar( vec );
|
||||
assert( vec[0] == "hey" );
|
||||
assert( vec[1] == "there" );
|
||||
assert( vec[2] == "buddy" );
|
||||
|
||||
std::vector<std::vector<std::string>> vec2;
|
||||
iar( vec2 );
|
||||
for( auto & v : vec2 )
|
||||
{
|
||||
assert( v[0] == "hey" );
|
||||
assert( v[1] == "there" );
|
||||
assert( v[2] == "buddy" );
|
||||
}
|
||||
|
||||
int xxx[3];
|
||||
iar.loadBinaryValue( xxx, sizeof(int)*3 );
|
||||
assert( xxx[0] == -1 );
|
||||
assert( xxx[1] == 95 );
|
||||
assert( xxx[2] == 3 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user