@@ -300,7 +300,7 @@ namespace tao
300300 template < typename T >
301301 tao::optional< T > optional () const
302302 {
303- if ( this ->is_null () ) {
303+ if ( this ->is_null () ) {
304304 return tao::nullopt ;
305305 }
306306 else {
@@ -408,11 +408,6 @@ namespace tao
408408 return m_union.o .at ( key );
409409 }
410410
411- // basic_value & at( const json_pointer & k )
412- // {
413- // // TODO: Implement me!
414- // }
415-
416411 const basic_value & at ( const json_pointer & k ) const
417412 {
418413 const basic_value * v = this ;
@@ -422,9 +417,12 @@ namespace tao
422417 switch ( v->m_type ) {
423418 case json::type::ARRAY:
424419 {
420+ const auto o = p;
425421 const auto t = internal::next_json_pointer_token ( ++p, e );
426422 if ( ( t.find_first_not_of ( " 0123456789" ) != std::string::npos ) || ( t.size () > 1 && t[ 0 ] == ' 0' ) ) {
427- throw std::out_of_range ( " unable to resolve json_pointer, invalid token for const array access '" + t + ' \' ' );
423+ throw std::invalid_argument ( " unable to resolve json_pointer '" + k.value () + " ', "
424+ " invalid token for const array access '" + t + " ' "
425+ " at '" + std::string ( k.value ().c_str (), o ) + ' \' ' );
428426 }
429427 v = &v->at ( std::stoull ( t ) );
430428 }
@@ -436,7 +434,69 @@ namespace tao
436434 v = v->unsafe_get_pointer ();
437435 break ;
438436 default :
439- throw std::out_of_range ( " unable to resolve json_pointer" );
437+ throw std::runtime_error ( " unable to resolve json_pointer '" + k.value () + " ', "
438+ " value at '" + std::string ( k.value ().c_str (), p ) + " ' "
439+ " is neither 'object', 'array' nor 'pointer', "
440+ " but '" + to_string ( v->m_type ) + " '" );
441+ }
442+ }
443+ return *v;
444+ }
445+
446+ // Unlike the above pure getter, this adds null elements when the leaf is a missing object key or '-' for an array.
447+ // Note: Can not transcend a type::POINTER value as we would modify another value simultaneously.
448+
449+ basic_value & operator [] ( const json_pointer & k )
450+ {
451+ basic_value * v = this ;
452+ const char * p = k.value ().c_str ();
453+ const char * e = p + k.value ().size ();
454+ while ( p != e ) {
455+ switch ( v->m_type ) {
456+ case json::type::ARRAY:
457+ {
458+ const auto o = p;
459+ const auto t = internal::next_json_pointer_token ( ++p, e );
460+ if ( t == " -" ) {
461+ if ( p != e ) {
462+ throw std::runtime_error ( " unable to resolve json_pointer '" + k.value () + " ' "
463+ " at '" + std::string ( k.value ().c_str (), o ) + " ', "
464+ " array access via '-'-token must occur as the last fragment" );
465+ }
466+ v->unsafe_emplace_back ( null );
467+ return v->m_union .a .back ();
468+ }
469+ if ( ( t.find_first_not_of ( " 0123456789" ) != std::string::npos ) || ( t.size () > 1 && t[ 0 ] == ' 0' ) ) {
470+ throw std::invalid_argument ( " unable to resolve json_pointer '" + k.value () + " ', "
471+ " invalid token for array access '" + t + " ' "
472+ " at '" + std::string ( k.value ().c_str (), o ) + ' \' ' );
473+ }
474+ v = &v->at ( std::stoull ( t ) );
475+ }
476+ break ;
477+ case json::type::OBJECT:
478+ {
479+ auto t = internal::next_json_pointer_token ( ++p, e );
480+ const auto it = v->m_union .o .find ( t );
481+ if ( it != v->m_union .o .end () ) {
482+ v = & it->second ;
483+ }
484+ else {
485+ if ( p != e ) {
486+ throw std::runtime_error ( " unable to resolve json_pointer '" + k.value () + " ' "
487+ " at '" + std::string ( k.value ().c_str (), p ) + ' \' ' );
488+ }
489+ const auto r = v->unsafe_emplace ( std::move ( t ), null );
490+ assert ( r.second );
491+ return r.first ->second ;
492+ }
493+ }
494+ break ;
495+ default :
496+ throw std::runtime_error ( " unable to resolve json_pointer '" + k.value () + " ', "
497+ " value at '" + std::string ( k.value ().c_str (), p ) + " ' "
498+ " is neither 'object' nor 'array', "
499+ " but '" + to_string ( v->m_type ) + " '" );
440500 }
441501 }
442502 return *v;
@@ -467,7 +527,7 @@ namespace tao
467527 {
468528 TAOCPP_JSON_CHECK_TYPE_ERROR ( m_type, json::type::OBJECT );
469529 const auto it = m_union.o .find ( key );
470- if ( it == m_union.o .end () ) {
530+ if ( it == m_union.o .end () ) {
471531 return tao::nullopt ;
472532 }
473533 else {
@@ -488,7 +548,7 @@ namespace tao
488548 void unsafe_assign ( std::initializer_list< pair< Traits > > && l )
489549 {
490550 unsafe_emplace_object ();
491- for ( auto & e : l ) {
551+ for ( auto & e : l ) {
492552 const auto r = unsafe_emplace ( std::move ( e.key ), std::move ( e.value ) );
493553 if ( ! r.second ) {
494554 throw std::runtime_error ( " duplicate key detected: " + r.first ->first );
@@ -499,7 +559,7 @@ namespace tao
499559 void unsafe_assign ( const std::initializer_list< pair< Traits > > & l )
500560 {
501561 unsafe_emplace_object ();
502- for ( auto & e : l ) {
562+ for ( auto & e : l ) {
503563 const auto r = unsafe_emplace ( e.key , e.value );
504564 if ( ! r.second ) {
505565 throw std::runtime_error ( " duplicate key detected: " + r.first ->first );
@@ -659,7 +719,7 @@ namespace tao
659719 prepare_array ();
660720 auto & v = unsafe_get_array ();
661721 v.reserve ( v.size () + l.size () );
662- for ( auto & e : l ) {
722+ for ( auto & e : l ) {
663723 unsafe_emplace_back ( std::move ( e.value ) );
664724 }
665725 }
@@ -669,15 +729,15 @@ namespace tao
669729 prepare_array ();
670730 auto & v = unsafe_get_array ();
671731 v.reserve ( v.size () + l.size () );
672- for ( const auto & e : l ) {
732+ for ( const auto & e : l ) {
673733 unsafe_emplace_back ( e.value );
674734 }
675735 }
676736
677737 void insert ( std::initializer_list< pair< Traits > > && l )
678738 {
679739 prepare_object ();
680- for ( auto & e : l ) {
740+ for ( auto & e : l ) {
681741 const auto r = unsafe_emplace ( std::move ( e.key ), std::move ( e.value ) );
682742 if ( ! r.second ) {
683743 throw std::runtime_error ( " duplicate key detected: " + r.first ->first );
@@ -688,7 +748,7 @@ namespace tao
688748 void insert ( const std::initializer_list< pair< Traits > > & l )
689749 {
690750 prepare_object ();
691- for ( auto & e : l ) {
751+ for ( auto & e : l ) {
692752 const auto r = unsafe_emplace ( e.key , e.value );
693753 if ( ! r.second ) {
694754 throw std::runtime_error ( " duplicate key detected: " + r.first ->first );
0 commit comments