2
0
mirror of https://github.com/boostorg/json.git synced 2026-01-19 04:12:14 +00:00

try_at_pointer and try_set_at_pointer

This commit is contained in:
Dmitry Arkhipov
2024-04-05 17:18:23 +03:00
parent 274a0f5537
commit 4ebd252a13
4 changed files with 166 additions and 12 deletions

View File

@@ -341,13 +341,23 @@ walk_pointer(
} // namespace detail
value const&
value::at_pointer(string_view ptr) const&
system::result<value const&>
value::try_at_pointer(string_view ptr) const noexcept
{
system::error_code ec;
auto const found = find_pointer(ptr, ec);
if( !found )
detail::throw_system_error( ec );
return ec;
return *found;
}
system::result<value&>
value::try_at_pointer(string_view ptr) noexcept
{
system::error_code ec;
auto const found = find_pointer(ptr, ec);
if( !found )
return ec;
return *found;
}
@@ -484,15 +494,24 @@ value::set_at_pointer(
return result;
}
system::result<value&>
value::try_set_at_pointer(
string_view sv,
value_ref ref,
set_pointer_options const& opts )
{
system::error_code ec;
value* result = set_at_pointer( sv, ref, ec, opts );
if( result )
return *result;
return ec;
}
value&
value::set_at_pointer(
string_view sv, value_ref ref, set_pointer_options const& opts )
{
system::error_code ec;
value* result = set_at_pointer( sv, ref, ec, opts );
if( !result )
detail::throw_system_error( ec );
return *result;
return try_set_at_pointer(sv, ref, opts).value();
}
} // namespace json

View File

@@ -13,17 +13,22 @@
namespace boost {
namespace json {
value const&
value::at_pointer(string_view ptr) const&
{
return try_at_pointer(ptr).value();
}
value&
value::at_pointer(string_view ptr) &
{
auto const& self = *this;
return const_cast<value&>( self.at_pointer(ptr) );
return try_at_pointer(ptr).value();
}
value&&
value::at_pointer(string_view ptr) &&
{
return std::move( this->at_pointer(ptr) );
return std::move( try_at_pointer(ptr).value() );
}
} // namespace json

View File

@@ -3284,6 +3284,53 @@ public:
}
/** @} */
/** Access an element via JSON Pointer.
This function is used to access a (potentially nested) element of the
value using a JSON Pointer string.
@par Complexity
Linear in the sizes of `ptr` and underlying array, object, or string.
@par Exception Safety
No-throw guarantee.
@param ptr JSON Pointer string.
@return `boost::system::result<value&>` containing either a reference
to the element identified by `ptr` or a corresponding `error_code`.
@see
[RFC 6901 - JavaScript Object Notation (JSON) Pointer](https://datatracker.ietf.org/doc/html/rfc6901).
*/
BOOST_JSON_DECL
system::result<value const&>
try_at_pointer(string_view ptr) const noexcept;
/** Access an element via JSON Pointer.
This function is used to access a (potentially nested) element of the
value using a JSON Pointer string.
@par Complexity
Linear in the sizes of `ptr` and underlying array, object, or string.
@par Exception Safety
No-throw guarantee.
@param ptr JSON Pointer string.
@return `boost::system::result<value const&>` containing either a
reference to the element identified by `ptr` or a corresponding
`error_code`.
@see
[RFC 6901 - JavaScript Object Notation (JSON) Pointer](https://datatracker.ietf.org/doc/html/rfc6901).
*/
BOOST_JSON_DECL
system::result<value&>
try_at_pointer(string_view ptr) noexcept;
/** Access an element via JSON Pointer.
This function is used to access a (potentially nested)
@@ -3306,7 +3353,7 @@ public:
RFC 6901 - JavaScript Object Notation (JSON) Pointer</a>
*/
/** @{ */
BOOST_JSON_DECL
inline
value const&
at_pointer(string_view ptr) const&;
@@ -3360,6 +3407,72 @@ public:
//------------------------------------------------------
/** Set an element via JSON Pointer.
This function is used to insert or assign to a potentially nested
element of the value using a JSON Pointer string. The function may
create intermediate elements corresponding to pointer segments.
<br/>
The particular conditions when and what kind of intermediate element
is created is governed by the `ptr` parameter.
Each pointer token is considered in sequence. For each token
- if the containing value is an @ref object, then a new `null`
element is created with key equal to unescaped token string;
otherwise
- if the containing value is an @ref array, and the token represents a
past-the-end marker, then a `null` element is appended to the array;
otherwise
- if the containing value is an @ref array, and the token represents a
number, then if the difference between the number and array's size
is smaller than `opts.max_created_elements`, then the size of the
array is increased, so that the number can reference an element in the
array; otherwise
- if the containing value is of different @ref kind and
`opts.replace_any_scalar` is `true`, or the value is `null`, then
- if `opts.create_arrays` is `true` and the token either represents
past-the-end marker or a number, then the value is replaced with
an empty array and the token is considered again; otherwise
- if `opts.create_objects` is `true`, then the value is replaced
with an empty object and the token is considered again; otherwise
- an error is produced.
@par Complexity
Linear in the sum of size of `ptr`, size of underlying array, object,
or string and `opts.max_created_elements`.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param sv JSON Pointer string.
@param ref The value to assign to pointed element.
@param opts The options for the algorithm.
@return `boost::json::result<value&>` containing either a reference to
the element identified by `ptr` or a corresponding `error_code`.
@see
@ref set_pointer_options,
[RFC 6901 - JavaScript Object Notation (JSON) Pointer](https://datatracker.ietf.org/doc/html/rfc6901).
*/
BOOST_JSON_DECL
system::result<value&>
try_set_at_pointer(
string_view sv,
value_ref ref,
set_pointer_options const& opts = {} );
/** Set an element via JSON Pointer.
This function is used to insert or assign to a potentially nested

View File

@@ -346,6 +346,22 @@ public:
BOOST_TEST( hasLocation(ec) );
}
void
testTry()
{
value jv = testValue();
BOOST_TEST( &jv.try_at_pointer("/foo").value() == &jv.at("foo") );
BOOST_TEST_THROWS_WITH_LOCATION( jv.try_at_pointer("foo").value() );
value const& cjv = jv;
BOOST_TEST( &cjv.try_at_pointer("/foo").value() == &cjv.at("foo") );
BOOST_TEST_THROWS_WITH_LOCATION( cjv.try_at_pointer("foo").value() );
auto result = jv.try_set_at_pointer("", array());
BOOST_TEST(( jv == array() ));
BOOST_TEST( &*result == &jv );
}
void
run()
{
@@ -359,6 +375,7 @@ public:
testSet();
testSetNonThrowing<system::error_code>();
testSetNonThrowing<std::error_code>();
testTry();
}
};