Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions include/boost/json/impl/pointer.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,84 @@ value::set_at_pointer(
return try_set_at_pointer(sv, ref, opts).value();
}

bool
value::erase_at_pointer (
string_view sv,
system::error_code& ec) noexcept
{
ec.clear();
if(sv.empty()){
BOOST_JSON_FAIL(ec, error::missing_slash);
return false;
}

string_view walk = sv;
string_view last_segment;
while (true)
{
last_segment = detail::next_segment(walk, ec);
if (ec.failed())
return false;
if (walk.empty())
break;
}

string_view const parent_sv(
sv.data(),
static_cast<std::size_t>(last_segment.data() - sv.data()));

value* parent = detail::walk_pointer(
*this,
parent_sv,
Comment on lines +549 to +551
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it make more sense to just walk the entire pointer string and in object and array handlers update a value* parent variable (in the case of object you'd have to also store the key)? Then, after you finished walking:

  • parent is a pointer to array, object or nullptr (you can rely on that later in the switch case).
  • You don't have to check for missing slash manually.
  • You don't have to walk the pointer string twice.
  • You don't have to do manually look up the pointed-to element in the parent.

ec,
[]( object& obj, detail::pointer_token token )
{
return detail::if_contains_token(obj, token);
},
[]( array& arr, std::size_t index, system::error_code& ec ) -> value*
{
if( ec )
return nullptr;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not covered by tests. See here: https://1161.json.prtest2.cppalliance.org/diff-report/include/boost/json/impl/pointer.ipp.html. There are also other lines that miss coverage.


return arr.if_contains(index);
},
[]( value&, string_view)
{
return std::false_type();
});

if (!parent)
return false;

switch (parent->kind())
{
case boost::json::kind::object: {
auto& obj = parent->get_object();
detail::pointer_token const token(last_segment);
key_value_pair* kv = detail::find_in_object(obj, token).first;
if (kv) {
obj.erase(kv);
return true;
}
return false;
}
case boost::json::kind::array: {
auto const index = detail::parse_number_token(last_segment, ec);
auto& arr = parent->get_array();
if (arr.if_contains(index)){
arr.erase(arr.begin() + index);
return true;
}
return false;
}
default: {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://1161.json.prtest2.cppalliance.org/diff-report/include/boost/json/impl/pointer.ipp.html#NL593

I am pretty sure this switch case is unreachable, so replace it with

default: // LCOV_EXCL_LINE
   BOOST_JSON_UNREACHABLE(); // LCOV_EXCL_LINE

BOOST_JSON_FAIL(ec, error::value_is_scalar);
return false;
}
}
}


} // namespace json
} // namespace boost

Expand Down
13 changes: 13 additions & 0 deletions include/boost/json/value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3035,6 +3035,19 @@ class value

//------------------------------------------------------

/** Remove an element via JSON Pointer.

@{
*/
BOOST_JSON_DECL
bool
erase_at_pointer(
string_view sv,
system::error_code& ec) noexcept;

/// @}
//------------------------------------------------------

/** Check if two values are equal.

Two values are equal when they are the same kind and their referenced
Expand Down
Loading
Loading