@@ -410,94 +410,12 @@ namespace tao
410410
411411 const basic_value & at ( const json_pointer & k ) const
412412 {
413- const basic_value * v = this ;
414- const char * p = k.value ().c_str ();
415- const char * e = p + k.value ().size ();
416- while ( p != e ) {
417- switch ( v->m_type ) {
418- case json::type::ARRAY:
419- {
420- const auto t = internal::next_json_pointer_token ( ++p, e );
421- if ( ( t.find_first_not_of ( " 0123456789" ) != std::string::npos ) || ( t.size () > 1 && t[ 0 ] == ' 0' ) ) {
422- throw std::invalid_argument ( " unable to resolve json_pointer '" + k.value () + " ', "
423- " invalid token for const array access '" + t + " ' "
424- " at '" + std::string ( k.value ().c_str (), p - t.size () - 1 ) + ' \' ' );
425- }
426- v = &v->at ( std::stoull ( t ) );
427- }
428- break ;
429- case json::type::OBJECT:
430- v = &v->at ( internal::next_json_pointer_token ( ++p, e ) );
431- break ;
432- case json::type::POINTER:
433- v = v->unsafe_get_pointer ();
434- break ;
435- default :
436- throw std::runtime_error ( " unable to resolve json_pointer '" + k.value () + " ', "
437- " value at '" + std::string ( k.value ().c_str (), p ) + " ' "
438- " is neither 'object', 'array' nor 'pointer', "
439- " but '" + to_string ( v->m_type ) + " '" );
440- }
441- }
442- return *v;
413+ return internal::json_pointer_at ( this , k );
443414 }
444415
445- // Unlike the above pure getter, this adds null elements when the leaf is a missing object key or '-' for an array.
446- // Note: Can not transcend a type::POINTER value as we would modify another value simultaneously.
447-
448- basic_value & operator [] ( const json_pointer & k )
416+ basic_value & at ( const json_pointer & k )
449417 {
450- basic_value * v = this ;
451- const char * p = k.value ().c_str ();
452- const char * e = p + k.value ().size ();
453- while ( p != e ) {
454- switch ( v->m_type ) {
455- case json::type::ARRAY:
456- {
457- const auto t = internal::next_json_pointer_token ( ++p, e );
458- if ( t == " -" ) {
459- if ( p != e ) {
460- throw std::runtime_error ( " unable to resolve json_pointer '" + k.value () + " ' "
461- " at '" + std::string ( k.value ().c_str (), p - t.size () - 1 ) + " ', "
462- " array access via '-'-token must occur as the last fragment" );
463- }
464- v->unsafe_emplace_back ( null );
465- return v->m_union .a .back ();
466- }
467- if ( ( t.find_first_not_of ( " 0123456789" ) != std::string::npos ) || ( t.size () > 1 && t[ 0 ] == ' 0' ) ) {
468- throw std::invalid_argument ( " unable to resolve json_pointer '" + k.value () + " ', "
469- " invalid token for array access '" + t + " ' "
470- " at '" + std::string ( k.value ().c_str (), p - t.size () - 1 ) + ' \' ' );
471- }
472- v = &v->at ( std::stoull ( t ) );
473- }
474- break ;
475- case json::type::OBJECT:
476- {
477- auto t = internal::next_json_pointer_token ( ++p, e );
478- const auto it = v->m_union .o .find ( t );
479- if ( it != v->m_union .o .end () ) {
480- v = & it->second ;
481- }
482- else {
483- if ( p != e ) {
484- throw std::runtime_error ( " unable to resolve json_pointer '" + k.value () + " ' "
485- " at '" + std::string ( k.value ().c_str (), p ) + ' \' ' );
486- }
487- const auto r = v->unsafe_emplace ( std::move ( t ), null );
488- assert ( r.second );
489- return r.first ->second ;
490- }
491- }
492- break ;
493- default :
494- throw std::runtime_error ( " unable to resolve json_pointer '" + k.value () + " ', "
495- " value at '" + std::string ( k.value ().c_str (), p ) + " ' "
496- " is neither 'object' nor 'array', "
497- " but '" + to_string ( v->m_type ) + " '" );
498- }
499- }
500- return *v;
418+ return internal::json_pointer_at ( this , k );
501419 }
502420
503421 basic_value & unsafe_at ( const std::size_t index )
@@ -520,6 +438,46 @@ namespace tao
520438 return m_union.o .find ( key )->second ;
521439 }
522440
441+ // Unlike the above pure getter, this adds null elements when the leaf is a missing object key or '-' for an array.
442+
443+ basic_value & operator [] ( const json_pointer & k )
444+ {
445+ if ( ! k ) {
446+ return * this ;
447+ }
448+ const auto sp = k.split ();
449+ basic_value & v = internal::json_pointer_at ( this , sp.first );
450+ switch ( v.m_type ) {
451+ case json::type::ARRAY:
452+ {
453+ const auto & t = sp.second ;
454+ if ( t == " -" ) {
455+ v.unsafe_emplace_back ( null );
456+ return v.m_union .a .back ();
457+ }
458+ return v.at ( internal::json_pointer_token_to_index ( t ) );
459+ }
460+ break ;
461+ case json::type::OBJECT:
462+ {
463+ auto & t = sp.second ;
464+ const auto it = v.m_union .o .find ( t );
465+ if ( it == v.m_union .o .end () ) {
466+ const auto r = v.unsafe_emplace ( std::move ( t ), null );
467+ assert ( r.second );
468+ return r.first ->second ;
469+ }
470+ return it->second ;
471+ }
472+ break ;
473+ default :
474+ throw std::runtime_error ( " unable to resolve json_pointer '" + k.value () + " ', "
475+ " value at '" + sp.first .value () + " ' "
476+ " is neither 'object' nor 'array', "
477+ " but '" + to_string ( v.m_type ) + " '" );
478+ }
479+ }
480+
523481 template < typename T >
524482 tao::optional< T > optional ( const std::string & key ) const
525483 {
0 commit comments