mirror of
https://github.com/USCiLab/cereal.git
synced 2025-10-18 01:45:52 +02:00
mostly comment changes
This commit is contained in:
@@ -78,6 +78,10 @@ namespace cereal
|
|||||||
typedef rapidjson::PrettyWriter<WriteStream> JSONWriter;
|
typedef rapidjson::PrettyWriter<WriteStream> JSONWriter;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/*! @name Common Functionality
|
||||||
|
Common use cases for directly interacting with an JSONOutputArchive */
|
||||||
|
//! @{
|
||||||
|
|
||||||
//! Construct, outputting to the provided stream
|
//! Construct, outputting to the provided stream
|
||||||
/*! @param stream The stream to output to. Can be a stringstream, a file stream, or
|
/*! @param stream The stream to output to. Can be a stringstream, a file stream, or
|
||||||
even cout!
|
even cout!
|
||||||
@@ -98,82 +102,27 @@ namespace cereal
|
|||||||
itsWriter.EndObject();
|
itsWriter.EndObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveValue(bool b) { itsWriter.Bool(b); }
|
//! Saves some binary data, encoded as a base64 string, with an optional name
|
||||||
void saveValue(int i) { itsWriter.Int(i); }
|
/*! This will create a new node, optionally named, and insert a value that consists of
|
||||||
void saveValue(unsigned u) { itsWriter.Uint(u); }
|
the data encoded as a base64 string */
|
||||||
void saveValue(int64_t i64) { itsWriter.Int64(i64); }
|
void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
|
||||||
void saveValue(uint64_t u64) { itsWriter.Uint64(u64); }
|
|
||||||
void saveValue(double d) { itsWriter.Double(d); }
|
|
||||||
void saveValue(std::string const & s) { itsWriter.String(s.c_str(), static_cast<rapidjson::SizeType>( s.size() )); }
|
|
||||||
void saveValue(char const * s) { itsWriter.String(s); }
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
// Visual Studio has problems disambiguating the above for unsigned long, so we provide an explicit
|
|
||||||
// overload for long and serialize it as its size necessitates
|
|
||||||
//
|
|
||||||
// When loading we don't need to do this specialization since we catch the types with
|
|
||||||
// templates according to their size
|
|
||||||
|
|
||||||
//! 32 bit long saving
|
|
||||||
template <class T> inline
|
|
||||||
typename std::enable_if<sizeof(T) == sizeof(std::uint32_t), void>::type
|
|
||||||
saveLong(T lu){ saveValue( static_cast<std::uint32_t>( lu ) ); }
|
|
||||||
|
|
||||||
//! non 32 bit long saving
|
|
||||||
template <class T> inline
|
|
||||||
typename std::enable_if<sizeof(T) != sizeof(std::uint32_t), void>::type
|
|
||||||
saveLong(T lu){ saveValue( static_cast<std::uint64_t>( lu ) ); }
|
|
||||||
|
|
||||||
//! MSVC only long overload
|
|
||||||
void saveValue( unsigned long lu ){ saveLong( lu ); };
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//! Save exotic arithmetic types as binary
|
|
||||||
template<class T>
|
|
||||||
typename std::enable_if<std::is_arithmetic<T>::value &&
|
|
||||||
(sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long)), void>::type
|
|
||||||
saveValue(T const & t)
|
|
||||||
{
|
{
|
||||||
auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( &t ), sizeof(T) );
|
setNextName( name );
|
||||||
|
writeName();
|
||||||
|
|
||||||
|
auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
|
||||||
saveValue( base64string );
|
saveValue( base64string );
|
||||||
}
|
};
|
||||||
|
|
||||||
//! Write the name of the upcoming node and prepare object/array state
|
//! @}
|
||||||
/*! Since writeName is called for every value that is output, regardless of
|
/*! @name Internal Functionality
|
||||||
whether it has a name or not, it is the place where we will do a deferred
|
Functionality designed for use by those requiring control over the inner mechanisms of
|
||||||
check of our node state and decide whether we are in an array or an object. */
|
the JSONOutputArchive */
|
||||||
void writeName()
|
//! @{
|
||||||
{
|
|
||||||
NodeType const & nodeType = itsNodeStack.top();
|
|
||||||
|
|
||||||
// Start up either an object or an array, depending on state
|
|
||||||
if(nodeType == NodeType::StartArray)
|
|
||||||
{
|
|
||||||
itsWriter.StartArray();
|
|
||||||
itsNodeStack.top() = NodeType::InArray;
|
|
||||||
}
|
|
||||||
else if(nodeType == NodeType::StartObject)
|
|
||||||
{
|
|
||||||
itsNodeStack.top() = NodeType::InObject;
|
|
||||||
itsWriter.StartObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Array types do not output names
|
|
||||||
if(nodeType == NodeType::InArray) return;
|
|
||||||
|
|
||||||
if(itsNextName == nullptr)
|
|
||||||
{
|
|
||||||
std::string name = "value" + std::to_string( itsNameCounter.top()++ ) + "\0";
|
|
||||||
saveValue(name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
saveValue(itsNextName);
|
|
||||||
itsNextName = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Starts a new node in the JSON output
|
//! Starts a new node in the JSON output
|
||||||
|
/*! The node can optionally be given a name by calling setNextName prior
|
||||||
|
to creating the node */
|
||||||
void startNode()
|
void startNode()
|
||||||
{
|
{
|
||||||
writeName();
|
writeName();
|
||||||
@@ -207,29 +156,111 @@ namespace cereal
|
|||||||
itsNameCounter.pop();
|
itsNameCounter.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Designates that the current node should be output as an array, not an object
|
|
||||||
void makeArray()
|
|
||||||
{
|
|
||||||
itsNodeStack.top() = NodeType::StartArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Sets the name for the next node created with startNode
|
//! Sets the name for the next node created with startNode
|
||||||
void setNextName( const char * name )
|
void setNextName( const char * name )
|
||||||
{
|
{
|
||||||
itsNextName = name;
|
itsNextName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Saves some binary data, encoded as a base64 string, with an optional name
|
//! Saves a bool to the current node
|
||||||
/*! This will create a new node, optionally named, and insert a value that consists of
|
void saveValue(bool b) { itsWriter.Bool(b); }
|
||||||
the data encoded as a base64 string */
|
//! Saves an int to the current node
|
||||||
void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
|
void saveValue(int i) { itsWriter.Int(i); }
|
||||||
{
|
//! Saves a uint to the current node
|
||||||
setNextName( name );
|
void saveValue(unsigned u) { itsWriter.Uint(u); }
|
||||||
writeName();
|
//! Saves an int64 to the current node
|
||||||
|
void saveValue(int64_t i64) { itsWriter.Int64(i64); }
|
||||||
|
//! Saves a uint64 to the current node
|
||||||
|
void saveValue(uint64_t u64) { itsWriter.Uint64(u64); }
|
||||||
|
//! Saves a double to the current node
|
||||||
|
void saveValue(double d) { itsWriter.Double(d); }
|
||||||
|
//! Saves a string to the current node
|
||||||
|
void saveValue(std::string const & s) { itsWriter.String(s.c_str(), static_cast<rapidjson::SizeType>( s.size() )); }
|
||||||
|
//! Saves a const char * to the current node
|
||||||
|
void saveValue(char const * s) { itsWriter.String(s); }
|
||||||
|
|
||||||
auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
|
#ifdef _MSC_VER
|
||||||
|
// Visual Studio has problems disambiguating the above for unsigned long, so we provide an explicit
|
||||||
|
// overload for long and serialize it as its size necessitates
|
||||||
|
//
|
||||||
|
// When loading we don't need to do this specialization since we catch the types with
|
||||||
|
// templates according to their size
|
||||||
|
|
||||||
|
//! 32 bit long saving to current node
|
||||||
|
template <class T> inline
|
||||||
|
typename std::enable_if<sizeof(T) == sizeof(std::uint32_t), void>::type
|
||||||
|
saveLong(T lu){ saveValue( static_cast<std::uint32_t>( lu ) ); }
|
||||||
|
|
||||||
|
//! non 32 bit long saving to current node
|
||||||
|
template <class T> inline
|
||||||
|
typename std::enable_if<sizeof(T) != sizeof(std::uint32_t), void>::type
|
||||||
|
saveLong(T lu){ saveValue( static_cast<std::uint64_t>( lu ) ); }
|
||||||
|
|
||||||
|
//! MSVC only long overload to current node
|
||||||
|
void saveValue( unsigned long lu ){ saveLong( lu ); };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Save exotic arithmetic types as binary to current node
|
||||||
|
template<class T>
|
||||||
|
typename std::enable_if<std::is_arithmetic<T>::value &&
|
||||||
|
(sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long)), void>::type
|
||||||
|
saveValue(T const & t)
|
||||||
|
{
|
||||||
|
auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( &t ), sizeof(T) );
|
||||||
saveValue( base64string );
|
saveValue( base64string );
|
||||||
};
|
}
|
||||||
|
|
||||||
|
//! Write the name of the upcoming node and prepare object/array state
|
||||||
|
/*! Since writeName is called for every value that is output, regardless of
|
||||||
|
whether it has a name or not, it is the place where we will do a deferred
|
||||||
|
check of our node state and decide whether we are in an array or an object.
|
||||||
|
|
||||||
|
The general workflow of saving to the JSON archive is:
|
||||||
|
|
||||||
|
1. (optional) Set the name for the next node to be created, usually done by an NVP
|
||||||
|
2. Start the node
|
||||||
|
3. (if there is data to save) Write the name of the node (this function)
|
||||||
|
4. (if there is data to save) Save the data (with saveValue)
|
||||||
|
5. Finish the node
|
||||||
|
*/
|
||||||
|
void writeName()
|
||||||
|
{
|
||||||
|
NodeType const & nodeType = itsNodeStack.top();
|
||||||
|
|
||||||
|
// Start up either an object or an array, depending on state
|
||||||
|
if(nodeType == NodeType::StartArray)
|
||||||
|
{
|
||||||
|
itsWriter.StartArray();
|
||||||
|
itsNodeStack.top() = NodeType::InArray;
|
||||||
|
}
|
||||||
|
else if(nodeType == NodeType::StartObject)
|
||||||
|
{
|
||||||
|
itsNodeStack.top() = NodeType::InObject;
|
||||||
|
itsWriter.StartObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array types do not output names
|
||||||
|
if(nodeType == NodeType::InArray) return;
|
||||||
|
|
||||||
|
if(itsNextName == nullptr)
|
||||||
|
{
|
||||||
|
std::string name = "value" + std::to_string( itsNameCounter.top()++ ) + "\0";
|
||||||
|
saveValue(name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
saveValue(itsNextName);
|
||||||
|
itsNextName = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Designates that the current node should be output as an array, not an object
|
||||||
|
void makeArray()
|
||||||
|
{
|
||||||
|
itsNodeStack.top() = NodeType::StartArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! @}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WriteStream itsWriteStream; //!< Rapidjson write stream
|
WriteStream itsWriteStream; //!< Rapidjson write stream
|
||||||
@@ -421,7 +452,8 @@ namespace cereal
|
|||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
//! Prologue for SizeTags for JSON archives
|
//! Prologue for SizeTags for JSON archives
|
||||||
/*! SizeTags are strictly ignored for JSON */
|
/*! SizeTags are strictly ignored for JSON, they just indicate
|
||||||
|
that the current node should be made into an array */
|
||||||
template <class T>
|
template <class T>
|
||||||
void prologue( JSONOutputArchive & ar, SizeTag<T> const & )
|
void prologue( JSONOutputArchive & ar, SizeTag<T> const & )
|
||||||
{
|
{
|
||||||
@@ -586,7 +618,9 @@ namespace cereal
|
|||||||
//! Saving SizeTags to JSON
|
//! Saving SizeTags to JSON
|
||||||
template <class T> inline
|
template <class T> inline
|
||||||
void save( JSONOutputArchive &, SizeTag<T> const & )
|
void save( JSONOutputArchive &, SizeTag<T> const & )
|
||||||
{ }
|
{
|
||||||
|
// nothing to do here, we don't explicitly save the size
|
||||||
|
}
|
||||||
|
|
||||||
//! Loading SizeTags from JSON
|
//! Loading SizeTags from JSON
|
||||||
template <class T> inline
|
template <class T> inline
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ namespace cereal
|
|||||||
class XMLOutputArchive : public OutputArchive<XMLOutputArchive>
|
class XMLOutputArchive : public OutputArchive<XMLOutputArchive>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*! @name External Functionality
|
/*! @name Common Functionality
|
||||||
Common use cases for directly interacting with an XMLOutputArchive */
|
Common use cases for directly interacting with an XMLOutputArchive */
|
||||||
//! @{
|
//! @{
|
||||||
|
|
||||||
@@ -122,8 +122,9 @@ namespace cereal
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! 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 can be called directly by users and it will automatically create a child node for
|
||||||
the data encoded as a base64 string */
|
the current XML node, populate it with a base64 encoded string, and optionally name
|
||||||
|
it. The node will be finished after it has been populated. */
|
||||||
void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
|
void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
|
||||||
{
|
{
|
||||||
itsNodes.top().name = name;
|
itsNodes.top().name = name;
|
||||||
@@ -147,7 +148,8 @@ namespace cereal
|
|||||||
|
|
||||||
//! 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. If you want to
|
||||||
|
give a node a specific name, use setNextName prior to calling startNode.
|
||||||
|
|
||||||
The node will then be pushed onto the node stack. */
|
The node will then be pushed onto the node stack. */
|
||||||
void startNode()
|
void startNode()
|
||||||
@@ -205,7 +207,7 @@ namespace cereal
|
|||||||
saveValue( static_cast<int32_t>( value ) );
|
saveValue( static_cast<int32_t>( value ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Causes the type to be appended to the most recently made node if output type is set to true
|
//! Causes the type to be appended as an attribute to the most recently made node if output type is set to true
|
||||||
template <class T> inline
|
template <class T> inline
|
||||||
void insertType()
|
void insertType()
|
||||||
{
|
{
|
||||||
@@ -278,13 +280,39 @@ namespace cereal
|
|||||||
|
|
||||||
Input XML should have been produced by the XMLOutputArchive. Data can
|
Input XML should have been produced by the XMLOutputArchive. Data can
|
||||||
only be added to dynamically sized containers - the input archive will
|
only be added to dynamically sized containers - the input archive will
|
||||||
determine their size by looking at the number of child nodes.
|
determine their size by looking at the number of child nodes. Data that
|
||||||
|
did not originate from an XMLOutputArchive is not officially supported,
|
||||||
|
but may be possible to use if properly formatted.
|
||||||
|
|
||||||
|
The XMLInputArchive does not require that nodes are loaded in the same
|
||||||
|
order they were saved by XMLOutputArchive. Using name value pairs (NVPs),
|
||||||
|
it is possible to load in an out of order fashion or otherwise skip/select
|
||||||
|
specific nodes to load.
|
||||||
|
|
||||||
|
The default behavior of the input archive is to read sequentially starting
|
||||||
|
with the first node and exploring its children. When a given NVP does
|
||||||
|
not match the read in name for a node, the archive will search for that
|
||||||
|
node at the current level and load it if it exists. After loading an out of
|
||||||
|
order node, the archive will then proceed back to loading sequentially from
|
||||||
|
its new position.
|
||||||
|
|
||||||
|
Consider this simple example where loading of some data is skipped:
|
||||||
|
|
||||||
|
@code{cpp}
|
||||||
|
// imagine the input file has someData(1-9) saved in order at the top level node
|
||||||
|
ar( someData1, someData2, someData3 ); // XML loads in the order it sees in the file
|
||||||
|
ar( cereal::make_nvp( "hello", someData6 ) ); // NVP given does not
|
||||||
|
// match expected NVP name, so we search
|
||||||
|
// for the given NVP and load that value
|
||||||
|
ar( someData7, someData8, someData9 ); // with no NVP given, loading resumes at its
|
||||||
|
// current location, proceeding sequentially
|
||||||
|
@endcode
|
||||||
|
|
||||||
\ingroup Archives */
|
\ingroup Archives */
|
||||||
class XMLInputArchive : public InputArchive<XMLInputArchive>
|
class XMLInputArchive : public InputArchive<XMLInputArchive>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*! @name External Functionality
|
/*! @name Common Functionality
|
||||||
Common use cases for directly interacting with an XMLInputArchive */
|
Common use cases for directly interacting with an XMLInputArchive */
|
||||||
//! @{
|
//! @{
|
||||||
|
|
||||||
@@ -322,10 +350,15 @@ namespace cereal
|
|||||||
itsNodes.emplace( root );
|
itsNodes.emplace( root );
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Loads some binary data, encoded as a base64 string
|
//! Loads some binary data, encoded as a base64 string, optionally specified by some name
|
||||||
/*! This will automatically start and finish a node to load the data */
|
/*! This will automatically start and finish a node to load the data, and can be called directly by
|
||||||
void loadBinaryValue( void * data, size_t size )
|
users.
|
||||||
|
|
||||||
|
Note that this follows the same ordering rules specified in the class description in regards
|
||||||
|
to loading in/out of order */
|
||||||
|
void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
|
||||||
{
|
{
|
||||||
|
setNextName( name );
|
||||||
startNode();
|
startNode();
|
||||||
|
|
||||||
std::string encoded;
|
std::string encoded;
|
||||||
@@ -551,6 +584,8 @@ namespace cereal
|
|||||||
const char * name; //!< The NVP name for next next child node
|
const char * name; //!< The NVP name for next next child node
|
||||||
}; // NodeInfo
|
}; // NodeInfo
|
||||||
|
|
||||||
|
//! @}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<char> itsData; //!< The raw data loaded
|
std::vector<char> itsData; //!< The raw data loaded
|
||||||
rapidxml::xml_document<> itsXML; //!< The XML document
|
rapidxml::xml_document<> itsXML; //!< The XML document
|
||||||
|
|||||||
@@ -652,6 +652,5 @@ int main()
|
|||||||
std::cerr << "-------------------------" << std::endl;
|
std::cerr << "-------------------------" << std::endl;
|
||||||
test_unordered_loads<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
|
test_unordered_loads<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user