@@ -279,9 +279,32 @@ namespace cereal
279
279
Input JSON should have been produced by the JSONOutputArchive. Data can
280
280
only be added to dynamically sized containers (marked by JSON arrays) -
281
281
the input archive will determine their size by looking at the number of child nodes.
282
-
283
- The order of the items in the JSON archive must match what is expected in the
284
- serialization functions.
282
+ Only JSON originating from a JSONOutputArchive is officially supported, but data
283
+ from other sources may work if properly formatted.
284
+
285
+ The JSONInputArchive does not require that nodes are loaded in the same
286
+ order they were saved by JSONOutputArchive. Using name value pairs (NVPs),
287
+ it is possible to load in an out of order fashion or otherwise skip/select
288
+ specific nodes to load.
289
+
290
+ The default behavior of the input archive is to read sequentially starting
291
+ with the first node and exploring its children. When a given NVP does
292
+ not match the read in name for a node, the archive will search for that
293
+ node at the current level and load it if it exists. After loading an out of
294
+ order node, the archive will then proceed back to loading sequentially from
295
+ its new position.
296
+
297
+ Consider this simple example where loading of some data is skipped:
298
+
299
+ @code{cpp}
300
+ // imagine the input file has someData(1-9) saved in order at the top level node
301
+ ar( someData1, someData2, someData3 ); // XML loads in the order it sees in the file
302
+ ar( cereal::make_nvp( "hello", someData6 ) ); // NVP given does not
303
+ // match expected NVP name, so we search
304
+ // for the given NVP and load that value
305
+ ar( someData7, someData8, someData9 ); // with no NVP given, loading resumes at its
306
+ // current location, proceeding sequentially
307
+ @endcode
285
308
286
309
\ingroup Archives */
287
310
class JSONInputArchive : public InputArchive <JSONInputArchive>
@@ -344,25 +367,20 @@ namespace cereal
344
367
class Iterator
345
368
{
346
369
public:
347
- Iterator () : itsType(Null) {}
370
+ Iterator () : itsIndex( 0 ), itsType(Null) {}
348
371
349
372
Iterator (MemberIterator begin, MemberIterator end) :
350
- itsMemberIt (begin), itsMemberItEnd(end), itsType(Member)
373
+ itsMemberItBegin (begin), itsMemberItEnd(end), itsIndex( 0 ), itsType(Member)
351
374
{ }
352
375
353
376
Iterator (ValueIterator begin, ValueIterator end) :
354
- itsValueIt (begin), itsValueItEnd(end), itsType(Value)
377
+ itsValueItBegin (begin), itsValueItEnd(end), itsIndex( 0 ), itsType(Value)
355
378
{ }
356
379
357
380
// ! Advance to the next node
358
381
Iterator & operator ++()
359
382
{
360
- switch (itsType)
361
- {
362
- case Value : ++itsValueIt; break ;
363
- case Member: /* std::cerr << "Advancing from " << name() << std::endl;*/ ++itsMemberIt; break ;
364
- default : throw cereal::Exception (" Invalid Iterator Type!" );
365
- }
383
+ ++itsIndex;
366
384
return *this ;
367
385
}
368
386
@@ -371,63 +389,63 @@ namespace cereal
371
389
{
372
390
switch (itsType)
373
391
{
374
- case Value : return *itsValueIt ;
375
- case Member: return itsMemberIt-> value ;
392
+ case Value : return itsValueItBegin[itsIndex] ;
393
+ case Member: return itsMemberItBegin[itsIndex]. value ;
376
394
default : throw cereal::Exception (" Invalid Iterator Type!" );
377
395
}
378
396
}
379
397
380
398
// ! Get the name of the current node, or nullptr if it has no name
381
399
const char * name () const
382
400
{
383
- if ( itsType == Member && itsMemberIt != itsMemberItEnd )
384
- return itsMemberIt-> name .GetString ();
401
+ if ( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
402
+ return itsMemberItBegin[itsIndex]. name .GetString ();
385
403
else
386
404
return nullptr ;
387
405
}
388
406
389
407
// ! Adjust our position such that we are at the node with the given name
390
408
/* ! @throws Exception if no such named node exists */
391
- inline void search ( const char * name, GenericValue const & parent )
409
+ inline void search ( const char * name ) // , GenericValue const & parent )
392
410
{
393
- auto member = parent.FindMember ( name );
394
- if ( member )
395
- itsMemberIt = member;
396
- else
397
- throw Exception (" JSON Parsing failed - provided NVP not found" );
411
+ size_t index = 0 ;
412
+ for ( auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
413
+ if ( std::strcmp ( name, it->name .GetString () ) == 0 )
414
+ {
415
+ itsIndex = index;
416
+ return ;
417
+ }
418
+
419
+ throw Exception (" JSON Parsing failed - provided NVP not found" );
398
420
}
399
421
400
422
private:
401
- MemberIterator itsMemberIt, itsMemberItEnd; // !< The member iterator (object)
402
- ValueIterator itsValueIt, itsValueItEnd; // !< The value iterator (array)
423
+ MemberIterator itsMemberItBegin, itsMemberItEnd; // !< The member iterator (object)
424
+ ValueIterator itsValueItBegin, itsValueItEnd; // !< The value iterator (array)
425
+ size_t itsIndex; // !< The current index of this iterator
403
426
enum Type {Value, Member, Null} itsType; // !< Whether this holds values (array) or members (objects) or nothing
404
427
};
405
428
406
429
// ! Searches for the expectedName node if it doesn't match the actualName
407
- /* ! @throws Exception if an expectedName is given and not found */
430
+ /* ! This needs to be called before every load or node start occurs. This function will
431
+ check to see if an NVP has been provided (with setNextName) and if so, see if that name matches the actual
432
+ next name given. If the names do not match, it will search in the current level of the JSON for that name.
433
+ If the name is not found, an exception will be thrown.
434
+
435
+ Resets the NVP name after called.
436
+
437
+ @throws Exception if an expectedName is given and not found */
408
438
inline void search ()
409
439
{
410
440
// The name an NVP provided with setNextName()
411
441
if ( itsNextName )
412
442
{
413
- // std::cerr << "Next name is " << itsNextName << std::endl;
414
- // std::cerr << itsIteratorStack.size() << std::endl;
415
443
// The actual name of the current node
416
444
auto const actualName = itsIteratorStack.back ().name ();
417
445
418
- // std::cerr << "Actual name was: " << (actualName?actualName:"null") << std::endl;
419
- // when at end of an iterator, the next name will be null
420
-
421
- if ( itsIteratorStack.back ().value ().IsNull () || !actualName || std::strcmp ( itsNextName, actualName ) != 0 )
422
- {
423
- // std::cerr << "Searching for " << itsNextName << std::endl;
424
- // std::cerr << itsIteratorStack.size() << std::endl;
425
- // names don't match, perform a search and adjust our current iterator
426
- itsIteratorStack.back ().search ( itsNextName,
427
- /* if*/ (itsIteratorStack.size () > 1 ?
428
- /* then*/ (itsIteratorStack.rbegin () + 1 )->value () :
429
- /* else*/ itsDocument ) );
430
- }
446
+ // Do a search if we don't see a name coming up, or if the names don't match
447
+ if ( !actualName || std::strcmp ( itsNextName, actualName ) != 0 )
448
+ itsIteratorStack.back ().search ( itsNextName );
431
449
}
432
450
433
451
itsNextName = nullptr ;
@@ -438,13 +456,12 @@ namespace cereal
438
456
/* ! This places an iterator for the next node to be parsed onto the iterator stack. If the next
439
457
node is an array, this will be a value iterator, otherwise it will be a member iterator.
440
458
441
- By default our strategy is to start with the document root node and then recursively iteratoe through
459
+ By default our strategy is to start with the document root node and then recursively iterate through
442
460
all children in the order they show up in the document.
443
461
We don't need to know NVPs to do this; we'll just blindly load in the order things appear in.
444
462
445
- We check to see if the specified NVP matches what the next automatically loaded node is. If they
446
- match, we just continue as normal, going in order. If they don't match, we attempt to find a node
447
- named after the NVP that is being loaded. If that NVP does not exist, we throw an exception */
463
+ If we were given an NVP, we will search for it if it does not match our the name of the next node
464
+ that would normally be loaded. This functionality is provided by search(). */
448
465
void startNode ()
449
466
{
450
467
search ();
@@ -460,7 +477,6 @@ namespace cereal
460
477
{
461
478
itsIteratorStack.pop_back ();
462
479
++itsIteratorStack.back ();
463
- // std::cerr << "Finishing a node " << itsIteratorStack.size() << std::endl;
464
480
}
465
481
466
482
// ! Sets the name for the next node created with startNode
0 commit comments