File indexing completed on 2025-07-14 08:35:00
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_JSON_IMPL_POINTER_IPP
0011 #define BOOST_JSON_IMPL_POINTER_IPP
0012
0013 #include <boost/json/value.hpp>
0014
0015 namespace boost {
0016 namespace json {
0017
0018 namespace detail {
0019
0020 class pointer_token
0021 {
0022 public:
0023 class iterator;
0024
0025 pointer_token(
0026 string_view sv) noexcept
0027 : b_( sv.begin() + 1 )
0028 , e_( sv.end() )
0029 {
0030 BOOST_ASSERT( !sv.empty() );
0031 BOOST_ASSERT( *sv.data() == '/' );
0032 }
0033
0034 iterator begin() const noexcept;
0035 iterator end() const noexcept;
0036
0037 private:
0038 char const* b_;
0039 char const* e_;
0040 };
0041
0042 class pointer_token::iterator
0043 {
0044 public:
0045 using value_type = char;
0046 using reference = char;
0047 using pointer = value_type*;
0048 using difference_type = std::ptrdiff_t;
0049 using iterator_category = std::forward_iterator_tag;
0050
0051 explicit iterator(char const* base) noexcept
0052 : base_(base)
0053 {
0054 }
0055
0056 char operator*() const noexcept
0057 {
0058 switch( char c = *base_ )
0059 {
0060 case '~':
0061 c = base_[1];
0062 if( '0' == c )
0063 return '~';
0064 BOOST_ASSERT('1' == c);
0065 return '/';
0066 default:
0067 return c;
0068 }
0069 }
0070
0071 iterator& operator++() noexcept
0072 {
0073 if( '~' == *base_ )
0074 base_ += 2;
0075 else
0076 ++base_;
0077 return *this;
0078 }
0079
0080 iterator operator++(int) noexcept
0081 {
0082 iterator result = *this;
0083 ++(*this);
0084 return result;
0085 }
0086
0087 char const* base() const noexcept
0088 {
0089 return base_;
0090 }
0091
0092 private:
0093 char const* base_;
0094 };
0095
0096 bool operator==(pointer_token::iterator l, pointer_token::iterator r) noexcept
0097 {
0098 return l.base() == r.base();
0099 }
0100
0101 bool operator!=(pointer_token::iterator l, pointer_token::iterator r) noexcept
0102 {
0103 return l.base() != r.base();
0104 }
0105
0106 pointer_token::iterator pointer_token::begin() const noexcept
0107 {
0108 return iterator(b_);
0109 }
0110
0111 pointer_token::iterator pointer_token::end() const noexcept
0112 {
0113 return iterator(e_);
0114 }
0115
0116 bool operator==(pointer_token token, string_view sv) noexcept
0117 {
0118 auto t_b = token.begin();
0119 auto const t_e = token.end();
0120 auto s_b = sv.begin();
0121 auto const s_e = sv.end();
0122 while( s_b != s_e )
0123 {
0124 if( t_e == t_b )
0125 return false;
0126 if( *t_b != *s_b )
0127 return false;
0128 ++t_b;
0129 ++s_b;
0130 }
0131 return t_b == t_e;
0132 }
0133
0134 bool is_invalid_zero(
0135 char const* b,
0136 char const* e) noexcept
0137 {
0138
0139 if( *b != '0' )
0140 return false;
0141
0142
0143
0144 ++b;
0145 if( b == e )
0146 return false;
0147
0148 BOOST_ASSERT( *b != '/' );
0149 return true;
0150 }
0151
0152 bool is_past_the_end_token(
0153 char const* b,
0154 char const* e) noexcept
0155 {
0156 if( *b != '-' )
0157 return false;
0158
0159 ++b;
0160 BOOST_ASSERT( (b == e) || (*b != '/') );
0161 return b == e;
0162 }
0163
0164 std::size_t
0165 parse_number_token(
0166 string_view sv,
0167 system::error_code& ec) noexcept
0168 {
0169 BOOST_ASSERT( !sv.empty() );
0170
0171 char const* b = sv.begin();
0172 BOOST_ASSERT( *b == '/' );
0173
0174 ++b;
0175 char const* const e = sv.end();
0176 if( ( b == e )
0177 || is_invalid_zero(b, e) )
0178 {
0179 BOOST_JSON_FAIL(ec, error::token_not_number);
0180 return {};
0181 }
0182
0183 if( is_past_the_end_token(b, e) )
0184 {
0185 ++b;
0186 BOOST_JSON_FAIL(ec, error::past_the_end);
0187 return {};
0188 }
0189
0190 std::size_t result = 0;
0191 for( ; b != e; ++b )
0192 {
0193 char const c = *b;
0194 BOOST_ASSERT( c != '/' );
0195
0196 unsigned d = c - '0';
0197 if( d > 9 )
0198 {
0199 BOOST_JSON_FAIL(ec, error::token_not_number);
0200 return {};
0201 }
0202
0203 std::size_t new_result = result * 10 + d;
0204 if( new_result < result )
0205 {
0206 BOOST_JSON_FAIL(ec, error::token_overflow);
0207 return {};
0208 }
0209
0210 result = new_result;
0211
0212 }
0213 return result;
0214 }
0215
0216 string_view
0217 next_segment(
0218 string_view& sv,
0219 system::error_code& ec) noexcept
0220 {
0221 if( sv.empty() )
0222 return sv;
0223
0224 char const* const start = sv.begin();
0225 char const* b = start;
0226 if( *b++ != '/' )
0227 {
0228 BOOST_JSON_FAIL( ec, error::missing_slash );
0229 return {};
0230 }
0231
0232 char const* e = sv.end();
0233 for( ; b < e; ++b )
0234 {
0235 char const c = *b;
0236 if( '/' == c )
0237 break;
0238
0239 if( '~' == c )
0240 {
0241 if( ++b == e )
0242 {
0243 BOOST_JSON_FAIL( ec, error::invalid_escape );
0244 break;
0245 }
0246
0247 switch (*b)
0248 {
0249 case '0':
0250 case '1':
0251
0252 continue;
0253 default: {
0254 BOOST_JSON_FAIL( ec, error::invalid_escape );
0255 break;
0256 }
0257 }
0258 break;
0259 }
0260 }
0261
0262 sv.remove_prefix( b - start );
0263 return string_view( start, b );
0264 }
0265
0266 value*
0267 if_contains_token(object const& obj, pointer_token token)
0268 {
0269 if( obj.empty() )
0270 return nullptr;
0271
0272 auto const it = detail::find_in_object(obj, token).first;
0273 if( !it )
0274 return nullptr;
0275
0276 return &it->value();
0277 }
0278
0279 template<
0280 class Value,
0281 class OnObject,
0282 class OnArray,
0283 class OnScalar >
0284 Value*
0285 walk_pointer(
0286 Value& jv,
0287 string_view sv,
0288 system::error_code& ec,
0289 OnObject on_object,
0290 OnArray on_array,
0291 OnScalar on_scalar)
0292 {
0293 ec.clear();
0294
0295 string_view segment = detail::next_segment( sv, ec );
0296
0297 Value* result = &jv;
0298 while( true )
0299 {
0300 if( ec.failed() )
0301 return nullptr;
0302
0303 if( !result )
0304 {
0305 BOOST_JSON_FAIL(ec, error::not_found);
0306 return nullptr;
0307 }
0308
0309 if( segment.empty() )
0310 break;
0311
0312 switch( result->kind() )
0313 {
0314 case kind::object: {
0315 auto& obj = result->get_object();
0316
0317 detail::pointer_token const token( segment );
0318 segment = detail::next_segment( sv, ec );
0319
0320 result = on_object( obj, token );
0321 break;
0322 }
0323 case kind::array: {
0324 auto const index = detail::parse_number_token( segment, ec );
0325 segment = detail::next_segment( sv, ec );
0326
0327 auto& arr = result->get_array();
0328 result = on_array( arr, index, ec );
0329 break;
0330 }
0331 default: {
0332 if( on_scalar( *result, segment ) )
0333 break;
0334 BOOST_JSON_FAIL( ec, error::value_is_scalar );
0335 }}
0336 }
0337
0338 BOOST_ASSERT( result );
0339 return result;
0340 }
0341
0342 }
0343
0344 value const&
0345 value::at_pointer(string_view ptr, source_location const& loc) const&
0346 {
0347 return try_at_pointer(ptr).value(loc);
0348 }
0349
0350 system::result<value const&>
0351 value::try_at_pointer(string_view ptr) const noexcept
0352 {
0353 system::error_code ec;
0354 auto const found = find_pointer(ptr, ec);
0355 if( !found )
0356 return ec;
0357 return *found;
0358 }
0359
0360 system::result<value&>
0361 value::try_at_pointer(string_view ptr) noexcept
0362 {
0363 system::error_code ec;
0364 auto const found = find_pointer(ptr, ec);
0365 if( !found )
0366 return ec;
0367 return *found;
0368 }
0369
0370 value const*
0371 value::find_pointer( string_view sv, system::error_code& ec ) const noexcept
0372 {
0373 return detail::walk_pointer(
0374 *this,
0375 sv,
0376 ec,
0377 []( object const& obj, detail::pointer_token token )
0378 {
0379 return detail::if_contains_token(obj, token);
0380 },
0381 []( array const& arr, std::size_t index, system::error_code& ec )
0382 -> value const*
0383 {
0384 if( ec )
0385 return nullptr;
0386
0387 return arr.if_contains(index);
0388 },
0389 []( value const&, string_view)
0390 {
0391 return std::false_type();
0392 });
0393 }
0394
0395 value*
0396 value::find_pointer(string_view ptr, system::error_code& ec) noexcept
0397 {
0398 value const& self = *this;
0399 return const_cast<value*>(self.find_pointer(ptr, ec));
0400 }
0401
0402 value const*
0403 value::find_pointer(string_view ptr, std::error_code& ec) const noexcept
0404 {
0405 system::error_code jec;
0406 value const* result = find_pointer(ptr, jec);
0407 ec = jec;
0408 return result;
0409 }
0410
0411 value*
0412 value::find_pointer(string_view ptr, std::error_code& ec) noexcept
0413 {
0414 value const& self = *this;
0415 return const_cast<value*>(self.find_pointer(ptr, ec));
0416 }
0417
0418 value*
0419 value::set_at_pointer(
0420 string_view sv,
0421 value_ref ref,
0422 system::error_code& ec,
0423 set_pointer_options const& opts )
0424 {
0425 value* result = detail::walk_pointer(
0426 *this,
0427 sv,
0428 ec,
0429 []( object& obj, detail::pointer_token token)
0430 {
0431 if( !obj.empty() )
0432 {
0433 key_value_pair* kv = detail::find_in_object( obj, token ).first;
0434 if( kv )
0435 return &kv->value();
0436 }
0437
0438 string key( token.begin(), token.end(), obj.storage() );
0439 return &obj.emplace( std::move(key), nullptr ).first->value();
0440 },
0441 [ &opts ]( array& arr, std::size_t index, system::error_code& ec ) -> value*
0442 {
0443 if( ec == error::past_the_end )
0444 index = arr.size();
0445 else if( ec.failed() )
0446 return nullptr;
0447
0448 if( index >= arr.size() )
0449 {
0450 std::size_t const n = index - arr.size();
0451 if( n >= opts.max_created_elements )
0452 return nullptr;
0453
0454 arr.resize( arr.size() + n + 1 );
0455 }
0456
0457 ec.clear();
0458 return arr.data() + index;
0459 },
0460 [ &opts ]( value& jv, string_view segment )
0461 {
0462 if( jv.is_null() || opts.replace_any_scalar )
0463 {
0464 if( opts.create_arrays )
0465 {
0466 system::error_code ec;
0467 detail::parse_number_token( segment, ec );
0468 if( !ec.failed() || ec == error::past_the_end )
0469 {
0470 jv = array( jv.storage() );
0471 return true;
0472 }
0473 }
0474
0475 if( opts.create_objects )
0476 {
0477 jv = object( jv.storage() );
0478 return true;
0479 }
0480 }
0481
0482 return false;
0483 });
0484
0485 if( result )
0486 *result = ref.make_value( storage() );
0487 return result;
0488 }
0489
0490 value*
0491 value::set_at_pointer(
0492 string_view sv,
0493 value_ref ref,
0494 std::error_code& ec,
0495 set_pointer_options const& opts )
0496 {
0497 system::error_code jec;
0498 value* result = set_at_pointer( sv, ref, jec, opts );
0499 ec = jec;
0500 return result;
0501 }
0502
0503 system::result<value&>
0504 value::try_set_at_pointer(
0505 string_view sv,
0506 value_ref ref,
0507 set_pointer_options const& opts )
0508 {
0509 system::error_code ec;
0510 value* result = set_at_pointer( sv, ref, ec, opts );
0511 if( result )
0512 return *result;
0513 return ec;
0514 }
0515
0516 value&
0517 value::set_at_pointer(
0518 string_view sv, value_ref ref, set_pointer_options const& opts )
0519 {
0520 return try_set_at_pointer(sv, ref, opts).value();
0521 }
0522
0523 }
0524 }
0525
0526 #endif