diff --git a/include/boost/json/detail/value_to.hpp b/include/boost/json/detail/value_to.hpp index 09eff9b11..2a6bb102e 100644 --- a/include/boost/json/detail/value_to.hpp +++ b/include/boost/json/detail/value_to.hpp @@ -12,6 +12,23 @@ #ifndef BOOST_JSON_DETAIL_VALUE_TO_HPP #define BOOST_JSON_DETAIL_VALUE_TO_HPP +#ifndef BOOST_JSON_INTRUSIVE_INDEX_INC +#define BOOST_JSON_INTRUSIVE_INDEX_INC ((void)0); +#endif + +#ifndef BOOST_JSON_INTRUSIVE_PATH_PUSH +#define BOOST_JSON_INTRUSIVE_PATH_PUSH(x) ((void)0); +#endif + +#ifndef BOOST_JSON_INTRUSIVE_PATH_POP +#define BOOST_JSON_INTRUSIVE_PATH_POP ((void)0); +#endif + +#ifndef BOOST_JSON_INTRUSIVE_MESSAGE +#define BOOST_JSON_INTRUSIVE_MESSAGE(x) ((void)0); +#endif + + #include #include #include @@ -270,13 +287,21 @@ value_to_impl( } auto ins = detail::inserter(result, inserter_implementation()); + + BOOST_JSON_INTRUSIVE_PATH_PUSH(-1) + for( value const& val: *arr ) { + BOOST_JSON_INTRUSIVE_INDEX_INC + auto elem_res = try_value_to>( val, ctx ); if( elem_res.has_error() ) return {boost::system::in_place_error, elem_res.error()}; *ins++ = std::move(*elem_res); } + + BOOST_JSON_INTRUSIVE_PATH_POP + return result; } @@ -377,10 +402,14 @@ struct to_described_member system::error_code ec; BOOST_JSON_FAIL(ec, error::size_mismatch); res = {boost::system::in_place_error, ec}; + + BOOST_JSON_INTRUSIVE_MESSAGE(std::format("the key >> {} << is non optional and missing in path {}", D::name, BOOST_JSON_INTRUSIVE::composePath())); } return; } + BOOST_JSON_INTRUSIVE_PATH_PUSH(D::name) + #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000 # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused" @@ -390,8 +419,10 @@ struct to_described_member #if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000 # pragma GCC diagnostic pop #endif - if( member_res ) + if( member_res ){ (*res).* D::pointer = std::move(*member_res); + BOOST_JSON_INTRUSIVE_PATH_POP + } else res = {boost::system::in_place_error, member_res.error()}; } diff --git a/include/boost/json/impl/pointer.ipp b/include/boost/json/impl/pointer.ipp index d07c48082..a3eb12ffd 100644 --- a/include/boost/json/impl/pointer.ipp +++ b/include/boost/json/impl/pointer.ipp @@ -415,6 +415,105 @@ value::find_pointer(string_view ptr, std::error_code& ec) noexcept return const_cast(self.find_pointer(ptr, ec)); } +bool +value::erase_at_pointer( + string_view sv, + system::error_code& ec) +{ + ec.clear(); + if(sv.empty()){ + BOOST_JSON_FAIL(ec, error::syntax); + return false; + } + + string_view previous_segment; + + string_view segment = detail::next_segment(sv, ec); + + auto result = this; + auto previous_result = this; + + while (true) + { + if (ec.failed()) + return false; + + if (!result) + { + BOOST_JSON_FAIL(ec, error::not_found); + return false; + } + + if( segment.empty() ) + break; + + previous_segment = segment; + previous_result = result; + + switch (result->kind()) + { + case boost::json::kind::object: { + auto& obj = result->get_object(); + + detail::pointer_token const token(segment); + segment = detail::next_segment(sv, ec); + + result = detail::if_contains_token(obj, token); + if( !result ) + { + BOOST_JSON_FAIL(ec, error::not_found); + return false; + } + break; + } + case boost::json::kind::array: { + auto const index = detail::parse_number_token(segment, ec); + segment = detail::next_segment(sv, ec); + + auto& arr = result->get_array(); + result = arr.if_contains(index); + if( !result ) + { + BOOST_JSON_FAIL(ec, error::past_the_end); + return false; + } + break; + } + default: { + BOOST_JSON_FAIL(ec, error::value_is_scalar); + return false; + } + } + } + + switch (previous_result->kind()) + { + case boost::json::kind::object: { + auto& obj = previous_result->get_object(); + detail::pointer_token const token(previous_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(previous_segment, ec); + auto& arr = previous_result->get_array(); + if (arr.if_contains(index)){ + arr.erase(arr.begin() + index); + return true; + } + return false; + } + default: { + BOOST_JSON_FAIL(ec, error::value_is_scalar); + return false; + } + } +} + value* value::set_at_pointer( string_view sv, diff --git a/include/boost/json/value.hpp b/include/boost/json/value.hpp index 74fa42aaa..59e4ebc92 100644 --- a/include/boost/json/value.hpp +++ b/include/boost/json/value.hpp @@ -3032,6 +3032,12 @@ class value set_pointer_options const& opts = {} ); /// @} + /** Remove an element via JSON Pointer. + */ + BOOST_JSON_DECL + bool erase_at_pointer( + string_view sv, + system::error_code& ec); //------------------------------------------------------ /** Check if two values are equal.