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 <stack>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace cereal
|
namespace cereal
|
||||||
{
|
{
|
||||||
@@ -88,23 +87,6 @@ namespace cereal
|
|||||||
itsXML.clear();
|
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
|
//! 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,
|
/*! 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.
|
or generated based upon a counter unique to the parent node.
|
||||||
@@ -124,22 +106,6 @@ namespace cereal
|
|||||||
itsNodes.emplace( node );
|
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
|
//! Designates the most recently added node as finished
|
||||||
void finishNode()
|
void finishNode()
|
||||||
{
|
{
|
||||||
@@ -152,6 +118,23 @@ namespace cereal
|
|||||||
itsNodes.top().name = name;
|
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
|
//! 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
|
/*! This will create a new node, optionally named, and insert a value that consists of
|
||||||
the data encoded as a base64 string */
|
the data encoded as a base64 string */
|
||||||
@@ -170,6 +153,22 @@ namespace cereal
|
|||||||
finishNode();
|
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:
|
protected:
|
||||||
//! A struct that contains metadata about a node
|
//! A struct that contains metadata about a node
|
||||||
struct NodeInfo
|
struct NodeInfo
|
||||||
@@ -240,17 +239,100 @@ namespace cereal
|
|||||||
itsNodes.emplace( root );
|
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:
|
protected:
|
||||||
//! A struct that contains metadata about a node
|
//! A struct that contains metadata about a node
|
||||||
struct NodeInfo
|
struct NodeInfo
|
||||||
{
|
{
|
||||||
NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
|
NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
|
||||||
node( n ),
|
node( n ),
|
||||||
counter( 0 )
|
child( n ? n->first_node() : nullptr ),
|
||||||
|
size( XMLInputArchive::getNumChildren( n ) )
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
rapidxml::xml_node<> * node; //!< A pointer to this node
|
void advance()
|
||||||
size_t counter; //!< The counter for naming child nodes
|
{
|
||||||
|
if( size )
|
||||||
|
{
|
||||||
|
--size;
|
||||||
|
child = child->next_sibling();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidxml::xml_node<> * node; //!< A pointer to this node
|
||||||
|
rapidxml::xml_node<> * child; //!< A pointer to its current child
|
||||||
|
size_t size;
|
||||||
}; // NodeInfo
|
}; // NodeInfo
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -261,32 +343,55 @@ namespace cereal
|
|||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
// XMLArchive prologue and epilogue functions
|
// 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 */
|
/*! NVPs do not start or finish nodes - they just set up the names */
|
||||||
template <class T>
|
template <class T>
|
||||||
void prologue( XMLOutputArchive &, NameValuePair<T> const & )
|
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 */
|
/*! NVPs do not start or finish nodes - they just set up the names */
|
||||||
template <class T>
|
template <class T>
|
||||||
void epilogue( XMLOutputArchive &, NameValuePair<T> const & )
|
void epilogue( XMLOutputArchive &, NameValuePair<T> const & )
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
//! Prologue for SizeTags for XML archives
|
//! Epilogue for NVPs for XML input archives
|
||||||
/*! SizeTags are strictly ignored for XML */
|
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>
|
template <class T>
|
||||||
void prologue( XMLOutputArchive &, SizeTag<T> const & )
|
void prologue( XMLOutputArchive &, SizeTag<T> const & )
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
//! Epilogue for SizeTags for XML archives
|
template <class T>
|
||||||
/*! SizeTags are strictly ignored for XML */
|
void prologue( XMLInputArchive &, SizeTag<T> const & )
|
||||||
|
{ }
|
||||||
|
|
||||||
|
//! Epilogue for SizeTags for XML output archives
|
||||||
|
/*! SizeTags do not start or finish nodes */
|
||||||
template <class T>
|
template <class T>
|
||||||
void epilogue( XMLOutputArchive &, SizeTag<T> const & )
|
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,
|
/*! Starts a new node, named either automatically or by some NVP,
|
||||||
that may be given data by the type about to be archived */
|
that may be given data by the type about to be archived */
|
||||||
template <class T>
|
template <class T>
|
||||||
@@ -296,7 +401,15 @@ namespace cereal
|
|||||||
ar.insertType<T>();
|
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 */
|
/*! Finishes the node created in the prologue */
|
||||||
template <class T>
|
template <class T>
|
||||||
void epilogue( XMLOutputArchive & ar, T const & data )
|
void epilogue( XMLOutputArchive & ar, T const & data )
|
||||||
@@ -304,24 +417,46 @@ namespace cereal
|
|||||||
ar.finishNode();
|
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
|
// Common XMLArchive serialization functions
|
||||||
|
// ######################################################################
|
||||||
|
|
||||||
//! Serializing NVP types to XML
|
//! Saving NVP types to XML
|
||||||
template <class Archive, class T> inline
|
template <class T> inline
|
||||||
CEREAL_ARCHIVE_RESTRICT(XMLInputArchive, XMLOutputArchive)
|
void save( XMLOutputArchive & ar, NameValuePair<T> const & t )
|
||||||
serialize( Archive & ar, NameValuePair<T> & t )
|
|
||||||
{
|
{
|
||||||
ar.setNextName( t.name );
|
ar.setNextName( t.name );
|
||||||
ar( t.value );
|
ar( t.value );
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Serializing SizeTags to XML
|
//! Loading NVP types from XML
|
||||||
template <class Archive, class T> inline
|
template <class T> inline
|
||||||
CEREAL_ARCHIVE_RESTRICT(XMLInputArchive, XMLOutputArchive)
|
void load( XMLInputArchive & ar, NameValuePair<T> & t )
|
||||||
serialize( Archive & ar, SizeTag<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
|
//! Saving for POD types to xml
|
||||||
template<class T> inline
|
template<class T> inline
|
||||||
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
|
||||||
@@ -330,6 +465,15 @@ namespace cereal
|
|||||||
ar.saveValue( t );
|
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
|
//! saving string to xml
|
||||||
template<class CharT, class Traits, class Alloc> inline
|
template<class CharT, class Traits, class Alloc> inline
|
||||||
void save(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
|
void save(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
|
||||||
@@ -337,9 +481,16 @@ namespace cereal
|
|||||||
ar.saveValue( str );
|
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
|
} // namespace cereal
|
||||||
|
|
||||||
// register archives for polymorphic support
|
// register archives for polymorphic support
|
||||||
CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive);
|
CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive);
|
||||||
|
CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive);
|
||||||
|
|
||||||
#endif // CEREAL_ARCHIVES_XML_HPP_
|
#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>;
|
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
|
/*! 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.
|
INTYPE refers to the input archive type you wish to restrict on.
|
||||||
OUTTYPE refers to the output 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;
|
ar & m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
If you need to do more restrictions in your enable_if, you will need to do this by hand.
|
||||||
@endcode
|
@endcode
|
||||||
*/
|
*/
|
||||||
#define CEREAL_ARCHIVE_RESTRICT(INTYPE, OUTTYPE) \
|
#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};
|
std::vector<std::vector<std::string>> vec2 = {vec, vec, vec};
|
||||||
|
|
||||||
Everything e;
|
oar( cereal::make_nvp("EVERYTHING", e_out) );
|
||||||
oar( cereal::make_nvp("EVERYTHING", e) );
|
|
||||||
oar( vec );
|
oar( vec );
|
||||||
oar( vec2 );
|
oar( vec2 );
|
||||||
|
|
||||||
@@ -335,8 +334,63 @@ int main()
|
|||||||
std::ifstream is("out.xml");
|
std::ifstream is("out.xml");
|
||||||
cereal::XMLInputArchive iar( is );
|
cereal::XMLInputArchive iar( is );
|
||||||
|
|
||||||
//int z;
|
int hello;
|
||||||
//iar( cereal::make_nvp("hello", z) );
|
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