mirror of
https://github.com/USCiLab/cereal.git
synced 2025-10-18 01:45:52 +02:00
Should close #13
Cleaned up the implementation a little, I'm sure it can still be optimized further. Undid some hacky things in rapidjson that the old implementation utilized.
This commit is contained in:
@@ -279,9 +279,32 @@ namespace cereal
|
|||||||
Input JSON should have been produced by the JSONOutputArchive. Data can
|
Input JSON should have been produced by the JSONOutputArchive. Data can
|
||||||
only be added to dynamically sized containers (marked by JSON arrays) -
|
only be added to dynamically sized containers (marked by JSON arrays) -
|
||||||
the input archive will determine their size by looking at the number of child nodes.
|
the input archive will determine their size by looking at the number of child nodes.
|
||||||
|
Only JSON originating from a JSONOutputArchive is officially supported, but data
|
||||||
|
from other sources may work if properly formatted.
|
||||||
|
|
||||||
The order of the items in the JSON archive must match what is expected in the
|
The JSONInputArchive does not require that nodes are loaded in the same
|
||||||
serialization functions.
|
order they were saved by JSONOutputArchive. 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 JSONInputArchive : public InputArchive<JSONInputArchive>
|
class JSONInputArchive : public InputArchive<JSONInputArchive>
|
||||||
@@ -344,25 +367,20 @@ namespace cereal
|
|||||||
class Iterator
|
class Iterator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Iterator() : itsType(Null) {}
|
Iterator() : itsIndex( 0 ), itsType(Null) {}
|
||||||
|
|
||||||
Iterator(MemberIterator begin, MemberIterator end) :
|
Iterator(MemberIterator begin, MemberIterator end) :
|
||||||
itsMemberIt(begin), itsMemberItEnd(end), itsType(Member)
|
itsMemberItBegin(begin), itsMemberItEnd(end), itsIndex(0), itsType(Member)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
Iterator(ValueIterator begin, ValueIterator end) :
|
Iterator(ValueIterator begin, ValueIterator end) :
|
||||||
itsValueIt(begin), itsValueItEnd(end), itsType(Value)
|
itsValueItBegin(begin), itsValueItEnd(end), itsIndex(0), itsType(Value)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
//! Advance to the next node
|
//! Advance to the next node
|
||||||
Iterator & operator++()
|
Iterator & operator++()
|
||||||
{
|
{
|
||||||
switch(itsType)
|
++itsIndex;
|
||||||
{
|
|
||||||
case Value : ++itsValueIt; break;
|
|
||||||
case Member: /*std::cerr << "Advancing from " << name() << std::endl;*/ ++itsMemberIt; break;
|
|
||||||
default: throw cereal::Exception("Invalid Iterator Type!");
|
|
||||||
}
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,8 +389,8 @@ namespace cereal
|
|||||||
{
|
{
|
||||||
switch(itsType)
|
switch(itsType)
|
||||||
{
|
{
|
||||||
case Value : return *itsValueIt;
|
case Value : return itsValueItBegin[itsIndex];
|
||||||
case Member: return itsMemberIt->value;
|
case Member: return itsMemberItBegin[itsIndex].value;
|
||||||
default: throw cereal::Exception("Invalid Iterator Type!");
|
default: throw cereal::Exception("Invalid Iterator Type!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -380,54 +398,54 @@ namespace cereal
|
|||||||
//! Get the name of the current node, or nullptr if it has no name
|
//! Get the name of the current node, or nullptr if it has no name
|
||||||
const char * name() const
|
const char * name() const
|
||||||
{
|
{
|
||||||
if( itsType == Member && itsMemberIt != itsMemberItEnd )
|
if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
|
||||||
return itsMemberIt->name.GetString();
|
return itsMemberItBegin[itsIndex].name.GetString();
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Adjust our position such that we are at the node with the given name
|
//! Adjust our position such that we are at the node with the given name
|
||||||
/*! @throws Exception if no such named node exists */
|
/*! @throws Exception if no such named node exists */
|
||||||
inline void search( const char * name, GenericValue const & parent )
|
inline void search( const char * name )//, GenericValue const & parent )
|
||||||
{
|
{
|
||||||
auto member = parent.FindMember( name );
|
size_t index = 0;
|
||||||
if( member )
|
for( auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
|
||||||
itsMemberIt = member;
|
if( std::strcmp( name, it->name.GetString() ) == 0 )
|
||||||
else
|
{
|
||||||
throw Exception("JSON Parsing failed - provided NVP not found");
|
itsIndex = index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception("JSON Parsing failed - provided NVP not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MemberIterator itsMemberIt, itsMemberItEnd; //!< The member iterator (object)
|
MemberIterator itsMemberItBegin, itsMemberItEnd; //!< The member iterator (object)
|
||||||
ValueIterator itsValueIt, itsValueItEnd; //!< The value iterator (array)
|
ValueIterator itsValueItBegin, itsValueItEnd; //!< The value iterator (array)
|
||||||
|
size_t itsIndex; //!< The current index of this iterator
|
||||||
enum Type {Value, Member, Null} itsType; //!< Whether this holds values (array) or members (objects) or nothing
|
enum Type {Value, Member, Null} itsType; //!< Whether this holds values (array) or members (objects) or nothing
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Searches for the expectedName node if it doesn't match the actualName
|
//! Searches for the expectedName node if it doesn't match the actualName
|
||||||
/*! @throws Exception if an expectedName is given and not found */
|
/*! This needs to be called before every load or node start occurs. This function will
|
||||||
|
check to see if an NVP has been provided (with setNextName) and if so, see if that name matches the actual
|
||||||
|
next name given. If the names do not match, it will search in the current level of the JSON for that name.
|
||||||
|
If the name is not found, an exception will be thrown.
|
||||||
|
|
||||||
|
Resets the NVP name after called.
|
||||||
|
|
||||||
|
@throws Exception if an expectedName is given and not found */
|
||||||
inline void search()
|
inline void search()
|
||||||
{
|
{
|
||||||
// The name an NVP provided with setNextName()
|
// The name an NVP provided with setNextName()
|
||||||
if( itsNextName )
|
if( itsNextName )
|
||||||
{
|
{
|
||||||
//std::cerr << "Next name is " << itsNextName << std::endl;
|
|
||||||
//std::cerr << itsIteratorStack.size() << std::endl;
|
|
||||||
// The actual name of the current node
|
// The actual name of the current node
|
||||||
auto const actualName = itsIteratorStack.back().name();
|
auto const actualName = itsIteratorStack.back().name();
|
||||||
|
|
||||||
//std::cerr << "Actual name was: " << (actualName?actualName:"null") << std::endl;
|
// Do a search if we don't see a name coming up, or if the names don't match
|
||||||
// when at end of an iterator, the next name will be null
|
if( !actualName || std::strcmp( itsNextName, actualName ) != 0 )
|
||||||
|
itsIteratorStack.back().search( itsNextName );
|
||||||
if( itsIteratorStack.back().value().IsNull() || !actualName || std::strcmp( itsNextName, actualName ) != 0 )
|
|
||||||
{
|
|
||||||
//std::cerr << "Searching for " << itsNextName << std::endl;
|
|
||||||
//std::cerr << itsIteratorStack.size() << std::endl;
|
|
||||||
// names don't match, perform a search and adjust our current iterator
|
|
||||||
itsIteratorStack.back().search( itsNextName,
|
|
||||||
/*if*/ (itsIteratorStack.size() > 1 ?
|
|
||||||
/*then*/ (itsIteratorStack.rbegin() + 1)->value() :
|
|
||||||
/*else*/ itsDocument ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
itsNextName = nullptr;
|
itsNextName = nullptr;
|
||||||
@@ -438,13 +456,12 @@ namespace cereal
|
|||||||
/*! This places an iterator for the next node to be parsed onto the iterator stack. If the next
|
/*! This places an iterator for the next node to be parsed onto the iterator stack. If the next
|
||||||
node is an array, this will be a value iterator, otherwise it will be a member iterator.
|
node is an array, this will be a value iterator, otherwise it will be a member iterator.
|
||||||
|
|
||||||
By default our strategy is to start with the document root node and then recursively iteratoe through
|
By default our strategy is to start with the document root node and then recursively iterate through
|
||||||
all children in the order they show up in the document.
|
all children in the order they show up in the document.
|
||||||
We don't need to know NVPs to do this; we'll just blindly load in the order things appear in.
|
We don't need to know NVPs to do this; we'll just blindly load in the order things appear in.
|
||||||
|
|
||||||
We check to see if the specified NVP matches what the next automatically loaded node is. If they
|
If we were given an NVP, we will search for it if it does not match our the name of the next node
|
||||||
match, we just continue as normal, going in order. If they don't match, we attempt to find a node
|
that would normally be loaded. This functionality is provided by search(). */
|
||||||
named after the NVP that is being loaded. If that NVP does not exist, we throw an exception */
|
|
||||||
void startNode()
|
void startNode()
|
||||||
{
|
{
|
||||||
search();
|
search();
|
||||||
@@ -460,7 +477,6 @@ namespace cereal
|
|||||||
{
|
{
|
||||||
itsIteratorStack.pop_back();
|
itsIteratorStack.pop_back();
|
||||||
++itsIteratorStack.back();
|
++itsIteratorStack.back();
|
||||||
//std::cerr << "Finishing a node " << itsIteratorStack.size() << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Sets the name for the next node created with startNode
|
//! Sets the name for the next node created with startNode
|
||||||
|
|||||||
2
include/cereal/external/rapidjson/document.h
vendored
2
include/cereal/external/rapidjson/document.h
vendored
@@ -614,7 +614,6 @@ private:
|
|||||||
Array a;
|
Array a;
|
||||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
||||||
|
|
||||||
public:
|
|
||||||
//! Find member by name.
|
//! Find member by name.
|
||||||
Member* FindMember(const Ch* name) {
|
Member* FindMember(const Ch* name) {
|
||||||
RAPIDJSON_ASSERT(name);
|
RAPIDJSON_ASSERT(name);
|
||||||
@@ -630,7 +629,6 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const Member* FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
|
const Member* FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
|
||||||
private:
|
|
||||||
|
|
||||||
// Initialize this value as array with initial data, without calling destructor.
|
// Initialize this value as array with initial data, without calling destructor.
|
||||||
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& alloctaor) {
|
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& alloctaor) {
|
||||||
|
|||||||
@@ -583,6 +583,8 @@ int main()
|
|||||||
|
|
||||||
oar( bb, a, x, y, z, d, j );
|
oar( bb, a, x, y, z, d, j );
|
||||||
std::cout << bb << " " << a << " " << x << " " << y << " " << z << " " << d << " " << j << std::endl;
|
std::cout << bb << " " << a << " " << x << " " << y << " " << z << " " << d << " " << j << std::endl;
|
||||||
|
// valgrind will complain about uninitialized bytes here - seems to be the padding caused by the long double and
|
||||||
|
// long long allocations (this padding just exists on the stack and is never used anywhere)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::ifstream b("endian.out");
|
std::ifstream b("endian.out");
|
||||||
|
|||||||
Reference in New Issue
Block a user