100.00% Lines (247/247) 100.00% Functions (34/34)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.com) 2   // Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.com)
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 4   // Distributed under the Boost Software License, Version 1.0. (See accompanying
5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/boostorg/json 7   // Official repository: https://github.com/boostorg/json
8   // 8   //
9   9  
10   #ifndef BOOST_JSON_IMPL_POINTER_IPP 10   #ifndef BOOST_JSON_IMPL_POINTER_IPP
11   #define BOOST_JSON_IMPL_POINTER_IPP 11   #define BOOST_JSON_IMPL_POINTER_IPP
12   12  
13   #include <boost/json/value.hpp> 13   #include <boost/json/value.hpp>
14   14  
15   namespace boost { 15   namespace boost {
16   namespace json { 16   namespace json {
17   17  
18   namespace detail { 18   namespace detail {
19   19  
20   class pointer_token 20   class pointer_token
21   { 21   {
22   public: 22   public:
23   class iterator; 23   class iterator;
24   24  
HITCBC 25   158 pointer_token( 25   160 pointer_token(
26   string_view sv) noexcept 26   string_view sv) noexcept
HITCBC 27   158 : b_( sv.begin() + 1 ) 27   160 : b_( sv.begin() + 1 )
HITCBC 28   158 , e_( sv.end() ) 28   160 , e_( sv.end() )
29   { 29   {
HITCBC 30   158 BOOST_ASSERT( !sv.empty() ); 30   160 BOOST_ASSERT( !sv.empty() );
HITCBC 31   158 BOOST_ASSERT( *sv.data() == '/' ); 31   160 BOOST_ASSERT( *sv.data() == '/' );
HITCBC 32   158 } 32   160 }
33   33  
34   iterator begin() const noexcept; 34   iterator begin() const noexcept;
35   iterator end() const noexcept; 35   iterator end() const noexcept;
36   36  
37   private: 37   private:
38   char const* b_; 38   char const* b_;
39   char const* e_; 39   char const* e_;
40   }; 40   };
41   41  
42   class pointer_token::iterator 42   class pointer_token::iterator
43   { 43   {
44   public: 44   public:
45   using value_type = char; 45   using value_type = char;
46   using reference = char; 46   using reference = char;
47   using pointer = value_type*; 47   using pointer = value_type*;
48   using difference_type = std::ptrdiff_t; 48   using difference_type = std::ptrdiff_t;
49   using iterator_category = std::forward_iterator_tag; 49   using iterator_category = std::forward_iterator_tag;
50   50  
HITCBC 51   584 explicit iterator(char const* base) noexcept 51   580 explicit iterator(char const* base) noexcept
HITCBC 52   584 : base_(base) 52   580 : base_(base)
53   { 53   {
HITCBC 54   584 } 54   580 }
55   55  
HITCBC 56   629 char operator*() const noexcept 56   631 char operator*() const noexcept
57   { 57   {
HITCBC 58   629 switch( char c = *base_ ) 58   631 switch( char c = *base_ )
59   { 59   {
HITCBC 60   2 case '~': 60   2 case '~':
HITCBC 61   2 c = base_[1]; 61   2 c = base_[1];
HITCBC 62   2 if( '0' == c ) 62   2 if( '0' == c )
HITCBC 63   1 return '~'; 63   1 return '~';
HITCBC 64   1 BOOST_ASSERT('1' == c); 64   1 BOOST_ASSERT('1' == c);
HITCBC 65   1 return '/'; 65   1 return '/';
HITCBC 66   627 default: 66   629 default:
HITCBC 67   627 return c; 67   629 return c;
68   } 68   }
69   } 69   }
70   70  
HITCBC 71   827 iterator& operator++() noexcept 71   833 iterator& operator++() noexcept
72   { 72   {
HITCBC 73   827 if( '~' == *base_ ) 73   833 if( '~' == *base_ )
HITCBC 74   2 base_ += 2; 74   2 base_ += 2;
75   else 75   else
HITCBC 76   825 ++base_; 76   831 ++base_;
HITCBC 77   827 return *this; 77   833 return *this;
78   } 78   }
79   79  
HITCBC 80   29 iterator operator++(int) noexcept 80   29 iterator operator++(int) noexcept
81   { 81   {
HITCBC 82   29 iterator result = *this; 82   29 iterator result = *this;
HITCBC 83   29 ++(*this); 83   29 ++(*this);
HITCBC 84   29 return result; 84   29 return result;
85   } 85   }
86   86  
HITCBC 87   1686 char const* base() const noexcept 87   1694 char const* base() const noexcept
88   { 88   {
HITCBC 89   1686 return base_; 89   1694 return base_;
90   } 90   }
91   91  
92   private: 92   private:
93   char const* base_; 93   char const* base_;
94   }; 94   };
95   95  
HITCBC 96   623 bool operator==(pointer_token::iterator l, pointer_token::iterator r) noexcept 96   627 bool operator==(pointer_token::iterator l, pointer_token::iterator r) noexcept
97   { 97   {
HITCBC 98   623 return l.base() == r.base(); 98   627 return l.base() == r.base();
99   } 99   }
100   100  
HITCBC 101   220 bool operator!=(pointer_token::iterator l, pointer_token::iterator r) noexcept 101   220 bool operator!=(pointer_token::iterator l, pointer_token::iterator r) noexcept
102   { 102   {
HITCBC 103   220 return l.base() != r.base(); 103   220 return l.base() != r.base();
104   } 104   }
105   105  
HITCBC 106   292 pointer_token::iterator pointer_token::begin() const noexcept 106   290 pointer_token::iterator pointer_token::begin() const noexcept
107   { 107   {
HITCBC 108   292 return iterator(b_); 108   290 return iterator(b_);
109   } 109   }
110   110  
HITCBC 111   292 pointer_token::iterator pointer_token::end() const noexcept 111   290 pointer_token::iterator pointer_token::end() const noexcept
112   { 112   {
HITCBC 113   292 return iterator(e_); 113   290 return iterator(e_);
114   } 114   }
115   115  
HITCBC 116   253 bool operator==(pointer_token token, string_view sv) noexcept 116   251 bool operator==(pointer_token token, string_view sv) noexcept
117   { 117   {
HITCBC 118   253 auto t_b = token.begin(); 118   251 auto t_b = token.begin();
HITCBC 119   253 auto const t_e = token.end(); 119   251 auto const t_e = token.end();
HITCBC 120   253 auto s_b = sv.begin(); 120   251 auto s_b = sv.begin();
HITCBC 121   253 auto const s_e = sv.end(); 121   251 auto const s_e = sv.end();
HITCBC 122   623 while( s_b != s_e ) 122   627 while( s_b != s_e )
123   { 123   {
HITCBC 124   478 if( t_e == t_b ) 124   480 if( t_e == t_b )
HITCBC 125   4 return false; 125   4 return false;
HITCBC 126   474 if( *t_b != *s_b ) 126   476 if( *t_b != *s_b )
HITCBC 127   104 return false; 127   100 return false;
HITCBC 128   370 ++t_b; 128   376 ++t_b;
HITCBC 129   370 ++s_b; 129   376 ++s_b;
130   } 130   }
HITCBC 131   145 return t_b == t_e; 131   147 return t_b == t_e;
132   } 132   }
133   133  
HITCBC 134   72 bool is_invalid_zero( 134   74 bool is_invalid_zero(
135   char const* b, 135   char const* b,
136   char const* e) noexcept 136   char const* e) noexcept
137   { 137   {
138   // in JSON Pointer only zero index can start character '0' 138   // in JSON Pointer only zero index can start character '0'
HITCBC 139   72 if( *b != '0' ) 139   74 if( *b != '0' )
HITCBC 140   56 return false; 140   58 return false;
141   141  
142   // if an index token starts with '0', then it should not have any more 142   // if an index token starts with '0', then it should not have any more
143   // characters: either the string should end, or new token should start 143   // characters: either the string should end, or new token should start
HITCBC 144   16 ++b; 144   16 ++b;
HITCBC 145   16 if( b == e ) 145   16 if( b == e )
HITCBC 146   13 return false; 146   13 return false;
147   147  
HITCBC 148   3 BOOST_ASSERT( *b != '/' ); 148   3 BOOST_ASSERT( *b != '/' );
HITCBC 149   3 return true; 149   3 return true;
150   } 150   }
151   151  
HITCBC 152   69 bool is_past_the_end_token( 152   71 bool is_past_the_end_token(
153   char const* b, 153   char const* b,
154   char const* e) noexcept 154   char const* e) noexcept
155   { 155   {
HITCBC 156   69 if( *b != '-' ) 156   71 if( *b != '-' )
HITCBC 157   57 return false; 157   59 return false;
158   158  
HITCBC 159   12 ++b; 159   12 ++b;
HITCBC 160   12 BOOST_ASSERT( (b == e) || (*b != '/') ); 160   12 BOOST_ASSERT( (b == e) || (*b != '/') );
HITCBC 161   12 return b == e; 161   12 return b == e;
162   } 162   }
163   163  
164   std::size_t 164   std::size_t
HITCBC 165   75 parse_number_token( 165   77 parse_number_token(
166   string_view sv, 166   string_view sv,
167   system::error_code& ec) noexcept 167   system::error_code& ec) noexcept
168   { 168   {
HITCBC 169   75 BOOST_ASSERT( !sv.empty() ); 169   77 BOOST_ASSERT( !sv.empty() );
170   170  
HITCBC 171   75 char const* b = sv.begin(); 171   77 char const* b = sv.begin();
HITCBC 172   75 BOOST_ASSERT( *b == '/' ); 172   77 BOOST_ASSERT( *b == '/' );
173   173  
HITCBC 174   75 ++b; 174   77 ++b;
HITCBC 175   75 char const* const e = sv.end(); 175   77 char const* const e = sv.end();
HITCBC 176   75 if( ( b == e ) 176   77 if( ( b == e )
HITCBC 177   75 || is_invalid_zero(b, e) ) 177   77 || is_invalid_zero(b, e) )
178   { 178   {
HITCBC 179   6 BOOST_JSON_FAIL(ec, error::token_not_number); 179   6 BOOST_JSON_FAIL(ec, error::token_not_number);
HITCBC 180   6 return {}; 180   6 return {};
181   } 181   }
182   182  
HITCBC 183   69 if( is_past_the_end_token(b, e) ) 183   71 if( is_past_the_end_token(b, e) )
184   { 184   {
HITCBC 185   10 ++b; 185   10 ++b;
HITCBC 186   10 BOOST_JSON_FAIL(ec, error::past_the_end); 186   10 BOOST_JSON_FAIL(ec, error::past_the_end);
HITCBC 187   10 return {}; 187   10 return {};
188   } 188   }
189   189  
HITCBC 190   59 std::size_t result = 0; 190   61 std::size_t result = 0;
HITCBC 191   133 for( ; b != e; ++b ) 191   175 for( ; b != e; ++b )
192   { 192   {
HITCBC 193   104 char const c = *b; 193   146 char const c = *b;
HITCBC 194   104 BOOST_ASSERT( c != '/' ); 194   146 BOOST_ASSERT( c != '/' );
195   195  
HITCBC 196   104 unsigned d = c - '0'; 196   146 unsigned d = c - '0';
HITCBC 197   104 if( d > 9 ) 197   146 if( d > 9 )
198   { 198   {
HITCBC 199   28 BOOST_JSON_FAIL(ec, error::token_not_number); 199   28 BOOST_JSON_FAIL(ec, error::token_not_number);
HITCBC 200   28 return {}; 200   28 return {};
201   } 201   }
202   202  
HITCBC 203 - 76 std::size_t new_result = result * 10 + d; 203 + 118 if( result > std::size_t(-1) / 10 )
DCB 204 - 76 if( new_result < result )  
205   { 204   {
HITCBC 206   2 BOOST_JSON_FAIL(ec, error::token_overflow); 205   2 BOOST_JSON_FAIL(ec, error::token_overflow);
HITCBC 207   2 return {}; 206   2 return {};
208   } 207   }
HITGNC   208 + 116 result *= 10;
209   209  
HITCBC 210 - 74 result = new_result; 210 + 116 if( result > std::size_t(-1) - d )
211 - 211 + {
HITGNC   212 + 2 BOOST_JSON_FAIL(ec, error::token_overflow);
HITGNC   213 + 2 return {};
  214 + }
HITGNC   215 + 114 result += d;
212   } 216   }
HITCBC 213   29 return result; 217   29 return result;
214   } 218   }
215   219  
216   string_view 220   string_view
HITCBC 217   344 next_segment( 221   350 next_segment(
218   string_view& sv, 222   string_view& sv,
219   system::error_code& ec) noexcept 223   system::error_code& ec) noexcept
220   { 224   {
HITCBC 221   344 if( sv.empty() ) 225   350 if( sv.empty() )
HITCBC 222   108 return sv; 226   110 return sv;
223   227  
HITCBC 224   236 char const* const start = sv.begin(); 228   240 char const* const start = sv.begin();
HITCBC 225   236 char const* b = start; 229   240 char const* b = start;
HITCBC 226   236 if( *b++ != '/' ) 230   240 if( *b++ != '/' )
227   { 231   {
HITCBC 228   5 BOOST_JSON_FAIL( ec, error::missing_slash ); 232   5 BOOST_JSON_FAIL( ec, error::missing_slash );
HITCBC 229   5 return {}; 233   5 return {};
230   } 234   }
231   235  
HITCBC 232   231 char const* e = sv.end(); 236   235 char const* e = sv.end();
HITCBC 233   768 for( ; b < e; ++b ) 237   820 for( ; b < e; ++b )
234   { 238   {
HITCBC 235   655 char const c = *b; 239   705 char const c = *b;
HITCBC 236   655 if( '/' == c ) 240   705 if( '/' == c )
HITCBC 237   112 break; 241   114 break;
238   242  
HITCBC 239   543 if( '~' == c ) 243   591 if( '~' == c )
240   { 244   {
HITCBC 241   8 if( ++b == e ) 245   8 if( ++b == e )
242   { 246   {
HITCBC 243   3 BOOST_JSON_FAIL( ec, error::invalid_escape ); 247   3 BOOST_JSON_FAIL( ec, error::invalid_escape );
HITCBC 244   3 break; 248   3 break;
245   } 249   }
246   250  
HITCBC 247   5 switch (*b) 251   5 switch (*b)
248   { 252   {
HITCBC 249   2 case '0': // fall through 253   2 case '0': // fall through
250   case '1': 254   case '1':
251   // valid escape sequence 255   // valid escape sequence
HITCBC 252   2 continue; 256   2 continue;
HITCBC 253   3 default: { 257   3 default: {
HITCBC 254   3 BOOST_JSON_FAIL( ec, error::invalid_escape ); 258   3 BOOST_JSON_FAIL( ec, error::invalid_escape );
HITCBC 255   3 break; 259   3 break;
256   } 260   }
HITCBC 257   2 } 261   2 }
HITCBC 258   3 break; 262   3 break;
259   } 263   }
260   } 264   }
261   265  
HITCBC 262   231 sv.remove_prefix( b - start ); 266   235 sv.remove_prefix( b - start );
HITCBC 263   231 return string_view( start, b ); 267   235 return string_view( start, b );
264   } 268   }
265   269  
266   value* 270   value*
HITCBC 267   125 if_contains_token(object const& obj, pointer_token token) 271   127 if_contains_token(object const& obj, pointer_token token)
268   { 272   {
HITCBC 269   125 if( obj.empty() ) 273   127 if( obj.empty() )
HITCBC 270   2 return nullptr; 274   2 return nullptr;
271   275  
HITCBC 272   123 auto const it = detail::find_in_object(obj, token).first; 276   125 auto const it = detail::find_in_object(obj, token).first;
HITCBC 273   123 if( !it ) 277   125 if( !it )
HITCBC 274   5 return nullptr; 278   5 return nullptr;
275   279  
HITCBC 276   118 return &it->value(); 280   120 return &it->value();
277   } 281   }
278   282  
279   template< 283   template<
280   class Value, 284   class Value,
281   class OnObject, 285   class OnObject,
282   class OnArray, 286   class OnArray,
283   class OnScalar > 287   class OnScalar >
284   Value* 288   Value*
HITCBC 285   129 walk_pointer( 289   131 walk_pointer(
286   Value& jv, 290   Value& jv,
287   string_view sv, 291   string_view sv,
288   system::error_code& ec, 292   system::error_code& ec,
289   OnObject on_object, 293   OnObject on_object,
290   OnArray on_array, 294   OnArray on_array,
291   OnScalar on_scalar) 295   OnScalar on_scalar)
292   { 296   {
HITCBC 293   129 ec.clear(); 297   131 ec.clear();
294   298  
HITCBC 295   129 string_view segment = detail::next_segment( sv, ec ); 299   131 string_view segment = detail::next_segment( sv, ec );
296   300  
HITCBC 297   129 Value* result = &jv; 301   131 Value* result = &jv;
HITCBC 298   244 while( true ) 302   248 while( true )
299   { 303   {
HITCBC 300   373 if( ec.failed() ) 304   379 if( ec.failed() )
HITCBC 301   43 return nullptr; 305   45 return nullptr;
302   306  
HITCBC 303   330 if( !result ) 307   334 if( !result )
304   { 308   {
HITCBC 305   12 BOOST_JSON_FAIL(ec, error::not_found); 309   12 BOOST_JSON_FAIL(ec, error::not_found);
HITCBC 306   12 return nullptr; 310   12 return nullptr;
307   } 311   }
308   312  
HITCBC 309   318 if( segment.empty() ) 313   322 if( segment.empty() )
HITCBC 310   74 break; 314   74 break;
311   315  
HITCBC 312   244 switch( result->kind() ) 316   248 switch( result->kind() )
313   { 317   {
HITCBC 314   158 case kind::object: { 318   160 case kind::object: {
HITCBC 315   158 auto& obj = result->get_object(); 319   160 auto& obj = result->get_object();
316   320  
HITCBC 317   158 detail::pointer_token const token( segment ); 321   160 detail::pointer_token const token( segment );
HITCBC 318   158 segment = detail::next_segment( sv, ec ); 322   160 segment = detail::next_segment( sv, ec );
319   323  
HITCBC 320   158 result = on_object( obj, token ); 324   160 result = on_object( obj, token );
HITCBC 321   158 break; 325   160 break;
322   } 326   }
HITCBC 323   57 case kind::array: { 327   59 case kind::array: {
HITCBC 324   57 auto const index = detail::parse_number_token( segment, ec ); 328   59 auto const index = detail::parse_number_token( segment, ec );
HITCBC 325   57 segment = detail::next_segment( sv, ec ); 329   59 segment = detail::next_segment( sv, ec );
326   330  
HITCBC 327   57 auto& arr = result->get_array(); 331   59 auto& arr = result->get_array();
HITCBC 328   57 result = on_array( arr, index, ec ); 332   59 result = on_array( arr, index, ec );
HITCBC 329   57 break; 333   59 break;
330   } 334   }
HITCBC 331   29 default: { 335   29 default: {
HITCBC 332   29 if( on_scalar( *result, segment ) ) 336   29 if( on_scalar( *result, segment ) )
HITCBC 333   21 break; 337   21 break;
HITCBC 334   8 BOOST_JSON_FAIL( ec, error::value_is_scalar ); 338   8 BOOST_JSON_FAIL( ec, error::value_is_scalar );
335   }} 339   }}
336   } 340   }
337   341  
HITCBC 338   74 BOOST_ASSERT( result ); 342   74 BOOST_ASSERT( result );
HITCBC 339   74 return result; 343   74 return result;
340   } 344   }
341   345  
342   } // namespace detail 346   } // namespace detail
343   347  
344   value const& 348   value const&
HITCBC 345   56 value::at_pointer(string_view ptr, source_location const& loc) const& 349   56 value::at_pointer(string_view ptr, source_location const& loc) const&
346   { 350   {
HITCBC 347   56 return try_at_pointer(ptr).value(loc); 351   56 return try_at_pointer(ptr).value(loc);
348   } 352   }
349   353  
350   system::result<value const&> 354   system::result<value const&>
HITCBC 351   58 value::try_at_pointer(string_view ptr) const noexcept 355   58 value::try_at_pointer(string_view ptr) const noexcept
352   { 356   {
HITCBC 353   58 system::error_code ec; 357   58 system::error_code ec;
HITCBC 354   58 auto const found = find_pointer(ptr, ec); 358   58 auto const found = find_pointer(ptr, ec);
HITCBC 355   58 if( !found ) 359   58 if( !found )
HITCBC 356   10 return ec; 360   10 return ec;
HITCBC 357   48 return *found; 361   48 return *found;
358   } 362   }
359   363  
360   system::result<value&> 364   system::result<value&>
HITCBC 361   2 value::try_at_pointer(string_view ptr) noexcept 365   2 value::try_at_pointer(string_view ptr) noexcept
362   { 366   {
HITCBC 363   2 system::error_code ec; 367   2 system::error_code ec;
HITCBC 364   2 auto const found = find_pointer(ptr, ec); 368   2 auto const found = find_pointer(ptr, ec);
HITCBC 365   2 if( !found ) 369   2 if( !found )
HITCBC 366   1 return ec; 370   1 return ec;
HITCBC 367   1 return *found; 371   1 return *found;
368   } 372   }
369   373  
370   value const* 374   value const*
HITCBC 371   101 value::find_pointer( string_view sv, system::error_code& ec ) const noexcept 375   103 value::find_pointer( string_view sv, system::error_code& ec ) const noexcept
372   { 376   {
HITCBC 373   101 return detail::walk_pointer( 377   103 return detail::walk_pointer(
374   *this, 378   *this,
375   sv, 379   sv,
376   ec, 380   ec,
HITCBC 377   125 []( object const& obj, detail::pointer_token token ) 381   127 []( object const& obj, detail::pointer_token token )
378   { 382   {
HITCBC 379   125 return detail::if_contains_token(obj, token); 383   127 return detail::if_contains_token(obj, token);
380   }, 384   },
HITCBC 381   37 []( array const& arr, std::size_t index, system::error_code& ec ) 385   39 []( array const& arr, std::size_t index, system::error_code& ec )
382   -> value const* 386   -> value const*
383   { 387   {
HITCBC 384   37 if( ec ) 388   39 if( ec )
HITCBC 385   22 return nullptr; 389   24 return nullptr;
386   390  
HITCBC 387   15 return arr.if_contains(index); 391   15 return arr.if_contains(index);
388   }, 392   },
HITCBC 389   5 []( value const&, string_view) 393   5 []( value const&, string_view)
390   { 394   {
HITCBC 391   5 return std::false_type(); 395   5 return std::false_type();
HITCBC 392   101 }); 396   103 });
393   } 397   }
394   398  
395   value* 399   value*
HITCBC 396   22 value::find_pointer(string_view ptr, system::error_code& ec) noexcept 400   23 value::find_pointer(string_view ptr, system::error_code& ec) noexcept
397   { 401   {
HITCBC 398   22 value const& self = *this; 402   23 value const& self = *this;
HITCBC 399   22 return const_cast<value*>(self.find_pointer(ptr, ec)); 403   23 return const_cast<value*>(self.find_pointer(ptr, ec));
400   } 404   }
401   405  
402   value const* 406   value const*
HITCBC 403   20 value::find_pointer(string_view ptr, std::error_code& ec) const noexcept 407   21 value::find_pointer(string_view ptr, std::error_code& ec) const noexcept
404   { 408   {
HITCBC 405   20 system::error_code jec; 409   21 system::error_code jec;
HITCBC 406   20 value const* result = find_pointer(ptr, jec); 410   21 value const* result = find_pointer(ptr, jec);
HITCBC 407   20 ec = jec; 411   21 ec = jec;
HITCBC 408   20 return result; 412   21 return result;
409   } 413   }
410   414  
411   value* 415   value*
HITCBC 412   19 value::find_pointer(string_view ptr, std::error_code& ec) noexcept 416   20 value::find_pointer(string_view ptr, std::error_code& ec) noexcept
413   { 417   {
HITCBC 414   19 value const& self = *this; 418   20 value const& self = *this;
HITCBC 415   19 return const_cast<value*>(self.find_pointer(ptr, ec)); 419   20 return const_cast<value*>(self.find_pointer(ptr, ec));
416   } 420   }
417   421  
418   value* 422   value*
HITCBC 419   28 value::set_at_pointer( 423   28 value::set_at_pointer(
420   string_view sv, 424   string_view sv,
421   value_ref ref, 425   value_ref ref,
422   system::error_code& ec, 426   system::error_code& ec,
423   set_pointer_options const& opts ) 427   set_pointer_options const& opts )
424   { 428   {
HITCBC 425   28 value* result = detail::walk_pointer( 429   28 value* result = detail::walk_pointer(
426   *this, 430   *this,
427   sv, 431   sv,
428   ec, 432   ec,
HITCBC 429   33 []( object& obj, detail::pointer_token token) 433   33 []( object& obj, detail::pointer_token token)
430   { 434   {
HITCBC 431   33 if( !obj.empty() ) 435   33 if( !obj.empty() )
432   { 436   {
HITCBC 433   13 key_value_pair* kv = detail::find_in_object( obj, token ).first; 437   13 key_value_pair* kv = detail::find_in_object( obj, token ).first;
HITCBC 434   13 if( kv ) 438   13 if( kv )
HITCBC 435   12 return &kv->value(); 439   12 return &kv->value();
436   } 440   }
437   441  
HITCBC 438   21 string key( token.begin(), token.end(), obj.storage() ); 442   21 string key( token.begin(), token.end(), obj.storage() );
HITCBC 439   21 return &obj.emplace( std::move(key), nullptr ).first->value(); 443   21 return &obj.emplace( std::move(key), nullptr ).first->value();
HITCBC 440   21 }, 444   21 },
HITCBC 441   20 [ &opts ]( array& arr, std::size_t index, system::error_code& ec ) -> value* 445   20 [ &opts ]( array& arr, std::size_t index, system::error_code& ec ) -> value*
442   { 446   {
HITCBC 443   20 if( ec == error::past_the_end ) 447   20 if( ec == error::past_the_end )
HITCBC 444   6 index = arr.size(); 448   6 index = arr.size();
HITCBC 445   14 else if( ec.failed() ) 449   14 else if( ec.failed() )
HITCBC 446   2 return nullptr; 450   2 return nullptr;
447   451  
HITCBC 448   18 if( index >= arr.size() ) 452   18 if( index >= arr.size() )
449   { 453   {
HITCBC 450   13 std::size_t const n = index - arr.size(); 454   13 std::size_t const n = index - arr.size();
HITCBC 451   13 if( n >= opts.max_created_elements ) 455   13 if( n >= opts.max_created_elements )
HITCBC 452   3 return nullptr; 456   3 return nullptr;
453   457  
HITCBC 454   10 arr.resize( arr.size() + n + 1 ); 458   10 arr.resize( arr.size() + n + 1 );
455   } 459   }
456   460  
HITCBC 457   15 ec.clear(); 461   15 ec.clear();
HITCBC 458   15 return arr.data() + index; 462   15 return arr.data() + index;
459   }, 463   },
HITCBC 460   24 [ &opts ]( value& jv, string_view segment ) 464   24 [ &opts ]( value& jv, string_view segment )
461   { 465   {
HITCBC 462   24 if( jv.is_null() || opts.replace_any_scalar ) 466   24 if( jv.is_null() || opts.replace_any_scalar )
463   { 467   {
HITCBC 464   21 if( opts.create_arrays ) 468   21 if( opts.create_arrays )
465   { 469   {
HITCBC 466   18 system::error_code ec; 470   18 system::error_code ec;
HITCBC 467   18 detail::parse_number_token( segment, ec ); 471   18 detail::parse_number_token( segment, ec );
HITCBC 468   18 if( !ec.failed() || ec == error::past_the_end ) 472   18 if( !ec.failed() || ec == error::past_the_end )
469   { 473   {
HITCBC 470   2 jv = array( jv.storage() ); 474   2 jv = array( jv.storage() );
HITCBC 471   2 return true; 475   2 return true;
472   } 476   }
473   } 477   }
474   478  
HITCBC 475   19 if( opts.create_objects ) 479   19 if( opts.create_objects )
476   { 480   {
HITCBC 477   19 jv = object( jv.storage() ); 481   19 jv = object( jv.storage() );
HITCBC 478   19 return true; 482   19 return true;
479   } 483   }
480   } 484   }
481   485  
HITCBC 482   3 return false; 486   3 return false;
483   }); 487   });
484   488  
HITCBC 485   28 if( result ) 489   28 if( result )
HITCBC 486   20 *result = ref.make_value( storage() ); 490   20 *result = ref.make_value( storage() );
HITCBC 487   28 return result; 491   28 return result;
488   } 492   }
489   493  
490   value* 494   value*
HITCBC 491   5 value::set_at_pointer( 495   5 value::set_at_pointer(
492   string_view sv, 496   string_view sv,
493   value_ref ref, 497   value_ref ref,
494   std::error_code& ec, 498   std::error_code& ec,
495   set_pointer_options const& opts ) 499   set_pointer_options const& opts )
496   { 500   {
HITCBC 497   5 system::error_code jec; 501   5 system::error_code jec;
HITCBC 498   5 value* result = set_at_pointer( sv, ref, jec, opts ); 502   5 value* result = set_at_pointer( sv, ref, jec, opts );
HITCBC 499   5 ec = jec; 503   5 ec = jec;
HITCBC 500   5 return result; 504   5 return result;
501   } 505   }
502   506  
503   system::result<value&> 507   system::result<value&>
HITCBC 504   18 value::try_set_at_pointer( 508   18 value::try_set_at_pointer(
505   string_view sv, 509   string_view sv,
506   value_ref ref, 510   value_ref ref,
507   set_pointer_options const& opts ) 511   set_pointer_options const& opts )
508   { 512   {
HITCBC 509   18 system::error_code ec; 513   18 system::error_code ec;
HITCBC 510   18 value* result = set_at_pointer( sv, ref, ec, opts ); 514   18 value* result = set_at_pointer( sv, ref, ec, opts );
HITCBC 511   18 if( result ) 515   18 if( result )
HITCBC 512   16 return *result; 516   16 return *result;
HITCBC 513   2 return ec; 517   2 return ec;
514   } 518   }
515   519  
516   value& 520   value&
HITCBC 517   17 value::set_at_pointer( 521   17 value::set_at_pointer(
518   string_view sv, value_ref ref, set_pointer_options const& opts ) 522   string_view sv, value_ref ref, set_pointer_options const& opts )
519   { 523   {
HITCBC 520   17 return try_set_at_pointer(sv, ref, opts).value(); 524   17 return try_set_at_pointer(sv, ref, opts).value();
521   } 525   }
522   526  
523   } // namespace json 527   } // namespace json
524   } // namespace boost 528   } // namespace boost
525   529  
526   #endif // BOOST_JSON_IMPL_POINTER_IPP 530   #endif // BOOST_JSON_IMPL_POINTER_IPP