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;
|
||||
|
||||
public:
|
||||
/*! @name Common Functionality
|
||||
Common use cases for directly interacting with an JSONOutputArchive */
|
||||
//! @{
|
||||
|
||||
//! Construct, outputting to the provided stream
|
||||
/*! @param stream The stream to output to. Can be a stringstream, a file stream, or
|
||||
even cout!
|
||||
@@ -98,82 +102,27 @@ namespace cereal
|
||||
itsWriter.EndObject();
|
||||
}
|
||||
|
||||
void saveValue(bool b) { itsWriter.Bool(b); }
|
||||
void saveValue(int i) { itsWriter.Int(i); }
|
||||
void saveValue(unsigned u) { itsWriter.Uint(u); }
|
||||
void saveValue(int64_t i64) { itsWriter.Int64(i64); }
|
||||
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)
|
||||
//! 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 */
|
||||
void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
};
|
||||
|
||||
//! 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. */
|
||||
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;
|
||||
}
|
||||
}
|
||||
//! @}
|
||||
/*! @name Internal Functionality
|
||||
Functionality designed for use by those requiring control over the inner mechanisms of
|
||||
the JSONOutputArchive */
|
||||
//! @{
|
||||
|
||||
//! 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()
|
||||
{
|
||||
writeName();
|
||||
@@ -207,29 +156,111 @@ namespace cereal
|
||||
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
|
||||
void setNextName( const char * name )
|
||||
{
|
||||
itsNextName = 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
|
||||
the data encoded as a base64 string */
|
||||
void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
|
||||
{
|
||||
setNextName( name );
|
||||
writeName();
|
||||
//! Saves a bool to the current node
|
||||
void saveValue(bool b) { itsWriter.Bool(b); }
|
||||
//! Saves an int to the current node
|
||||
void saveValue(int i) { itsWriter.Int(i); }
|
||||
//! Saves a uint to the current node
|
||||
void saveValue(unsigned u) { itsWriter.Uint(u); }
|
||||
//! 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 );
|
||||
};
|
||||
}
|
||||
|
||||
//! 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:
|
||||
WriteStream itsWriteStream; //!< Rapidjson write stream
|
||||
@@ -421,7 +452,8 @@ namespace cereal
|
||||
|
||||
// ######################################################################
|
||||
//! 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>
|
||||
void prologue( JSONOutputArchive & ar, SizeTag<T> const & )
|
||||
{
|
||||
@@ -586,7 +618,9 @@ namespace cereal
|
||||
//! Saving SizeTags to JSON
|
||||
template <class T> inline
|
||||
void save( JSONOutputArchive &, SizeTag<T> const & )
|
||||
{ }
|
||||
{
|
||||
// nothing to do here, we don't explicitly save the size
|
||||
}
|
||||
|
||||
//! Loading SizeTags from JSON
|
||||
template <class T> inline
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace cereal
|
||||
class XMLOutputArchive : public OutputArchive<XMLOutputArchive>
|
||||
{
|
||||
public:
|
||||
/*! @name External Functionality
|
||||
/*! @name Common Functionality
|
||||
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
|
||||
/*! This will create a new node, optionally named, and insert a value that consists of
|
||||
the data encoded as a base64 string */
|
||||
/*! This can be called directly by users and it will automatically create a child node for
|
||||
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 )
|
||||
{
|
||||
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
|
||||
/*! 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. */
|
||||
void startNode()
|
||||
@@ -205,7 +207,7 @@ namespace cereal
|
||||
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
|
||||
void insertType()
|
||||
{
|
||||
@@ -278,13 +280,39 @@ namespace cereal
|
||||
|
||||
Input XML should have been produced by the XMLOutputArchive. Data can
|
||||
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 */
|
||||
class XMLInputArchive : public InputArchive<XMLInputArchive>
|
||||
{
|
||||
public:
|
||||
/*! @name External Functionality
|
||||
/*! @name Common Functionality
|
||||
Common use cases for directly interacting with an XMLInputArchive */
|
||||
//! @{
|
||||
|
||||
@@ -322,10 +350,15 @@ namespace cereal
|
||||
itsNodes.emplace( root );
|
||||
}
|
||||
|
||||
//! 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 )
|
||||
//! 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, and can be called directly by
|
||||
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();
|
||||
|
||||
std::string encoded;
|
||||
@@ -551,6 +584,8 @@ namespace cereal
|
||||
const char * name; //!< The NVP name for next next child node
|
||||
}; // NodeInfo
|
||||
|
||||
//! @}
|
||||
|
||||
private:
|
||||
std::vector<char> itsData; //!< The raw data loaded
|
||||
rapidxml::xml_document<> itsXML; //!< The XML document
|
||||
|
||||
@@ -652,6 +652,5 @@ int main()
|
||||
std::cerr << "-------------------------" << std::endl;
|
||||
test_unordered_loads<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user