File indexing completed on 2025-01-18 09:39:02
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 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 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 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) const&
0346 {
0347 error_code ec;
0348 auto const found = find_pointer(ptr, ec);
0349 if( !found )
0350 detail::throw_system_error( ec );
0351 return *found;
0352 }
0353
0354 value const*
0355 value::find_pointer( string_view sv, error_code& ec ) const noexcept
0356 {
0357 return detail::walk_pointer(
0358 *this,
0359 sv,
0360 ec,
0361 []( object const& obj, detail::pointer_token token )
0362 {
0363 return detail::if_contains_token(obj, token);
0364 },
0365 []( array const& arr, std::size_t index, error_code& ec )
0366 -> value const*
0367 {
0368 if( ec )
0369 return nullptr;
0370
0371 return arr.if_contains(index);
0372 },
0373 []( value const&, string_view)
0374 {
0375 return std::false_type();
0376 });
0377 }
0378
0379 value*
0380 value::find_pointer(string_view ptr, error_code& ec) noexcept
0381 {
0382 value const& self = *this;
0383 return const_cast<value*>(self.find_pointer(ptr, ec));
0384 }
0385
0386 value const*
0387 value::find_pointer(string_view ptr, std::error_code& ec) const noexcept
0388 {
0389 error_code jec;
0390 value const* result = find_pointer(ptr, jec);
0391 ec = jec;
0392 return result;
0393 }
0394
0395 value*
0396 value::find_pointer(string_view ptr, std::error_code& ec) noexcept
0397 {
0398 value const& self = *this;
0399 return const_cast<value*>(self.find_pointer(ptr, ec));
0400 }
0401
0402 value*
0403 value::set_at_pointer(
0404 string_view sv,
0405 value_ref ref,
0406 error_code& ec,
0407 set_pointer_options const& opts )
0408 {
0409 value* result = detail::walk_pointer(
0410 *this,
0411 sv,
0412 ec,
0413 []( object& obj, detail::pointer_token token)
0414 {
0415 if( !obj.empty() )
0416 {
0417 key_value_pair* kv = detail::find_in_object( obj, token ).first;
0418 if( kv )
0419 return &kv->value();
0420 }
0421
0422 string key( token.begin(), token.end(), obj.storage() );
0423 return &obj.emplace( std::move(key), nullptr ).first->value();
0424 },
0425 [ &opts ]( array& arr, std::size_t index, error_code& ec ) -> value*
0426 {
0427 if( ec == error::past_the_end )
0428 index = arr.size();
0429 else if( ec.failed() )
0430 return nullptr;
0431
0432 if( index >= arr.size() )
0433 {
0434 std::size_t const n = index - arr.size();
0435 if( n >= opts.max_created_elements )
0436 return nullptr;
0437
0438 arr.resize( arr.size() + n + 1 );
0439 }
0440
0441 ec.clear();
0442 return arr.data() + index;
0443 },
0444 [ &opts ]( value& jv, string_view segment )
0445 {
0446 if( jv.is_null() || opts.replace_any_scalar )
0447 {
0448 if( opts.create_arrays )
0449 {
0450 error_code ec;
0451 detail::parse_number_token( segment, ec );
0452 if( !ec.failed() || ec == error::past_the_end )
0453 {
0454 jv = array( jv.storage() );
0455 return true;
0456 }
0457 }
0458
0459 if( opts.create_objects )
0460 {
0461 jv = object( jv.storage() );
0462 return true;
0463 }
0464 }
0465
0466 return false;
0467 });
0468
0469 if( result )
0470 *result = ref.make_value( storage() );
0471 return result;
0472 }
0473
0474 value*
0475 value::set_at_pointer(
0476 string_view sv,
0477 value_ref ref,
0478 std::error_code& ec,
0479 set_pointer_options const& opts )
0480 {
0481 error_code jec;
0482 value* result = set_at_pointer( sv, ref, jec, opts );
0483 ec = jec;
0484 return result;
0485 }
0486
0487 value&
0488 value::set_at_pointer(
0489 string_view sv, value_ref ref, set_pointer_options const& opts )
0490 {
0491 error_code ec;
0492 value* result = set_at_pointer( sv, ref, ec, opts );
0493 if( !result )
0494 detail::throw_system_error( ec );
0495 return *result;
0496 }
0497
0498 }
0499 }
0500
0501 #endif