100.00% Lines (244/244) 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   158 pointer_token(
26   string_view sv) noexcept 26   string_view sv) noexcept
HITCBC 27   158 : b_( sv.begin() + 1 ) 27   158 : b_( sv.begin() + 1 )
HITCBC 28   158 , e_( sv.end() ) 28   158 , e_( sv.end() )
29   { 29   {
HITCBC 30   158 BOOST_ASSERT( !sv.empty() ); 30   158 BOOST_ASSERT( !sv.empty() );
HITCBC 31   158 BOOST_ASSERT( *sv.data() == '/' ); 31   158 BOOST_ASSERT( *sv.data() == '/' );
HITCBC 32   158 } 32   158 }
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   576 explicit iterator(char const* base) noexcept 51   576 explicit iterator(char const* base) noexcept
HITCBC 52   576 : base_(base) 52   576 : base_(base)
53   { 53   {
HITCBC 54   576 } 54   576 }
55   55  
HITCBC 56   625 char operator*() const noexcept 56   625 char operator*() const noexcept
57   { 57   {
HITCBC 58   625 switch( char c = *base_ ) 58   625 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   623 default: 66   623 default:
HITCBC 67   623 return c; 67   623 return c;
68   } 68   }
69   } 69   }
70   70  
HITCBC 71   827 iterator& operator++() noexcept 71   827 iterator& operator++() noexcept
72   { 72   {
HITCBC 73   827 if( '~' == *base_ ) 73   827 if( '~' == *base_ )
HITCBC 74   2 base_ += 2; 74   2 base_ += 2;
75   else 75   else
HITCBC 76   825 ++base_; 76   825 ++base_;
HITCBC 77   827 return *this; 77   827 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   1678 char const* base() const noexcept 87   1678 char const* base() const noexcept
88   { 88   {
HITCBC 89   1678 return base_; 89   1678 return base_;
90   } 90   }
91   91  
92   private: 92   private:
93   char const* base_; 93   char const* base_;
94   }; 94   };
95   95  
HITCBC 96   619 bool operator==(pointer_token::iterator l, pointer_token::iterator r) noexcept 96   619 bool operator==(pointer_token::iterator l, pointer_token::iterator r) noexcept
97   { 97   {
HITCBC 98   619 return l.base() == r.base(); 98   619 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   288 pointer_token::iterator pointer_token::begin() const noexcept 106   288 pointer_token::iterator pointer_token::begin() const noexcept
107   { 107   {
HITCBC 108   288 return iterator(b_); 108   288 return iterator(b_);
109   } 109   }
110   110  
HITCBC 111   288 pointer_token::iterator pointer_token::end() const noexcept 111   288 pointer_token::iterator pointer_token::end() const noexcept
112   { 112   {
HITCBC 113   288 return iterator(e_); 113   288 return iterator(e_);
114   } 114   }
115   115  
HITCBC 116   249 bool operator==(pointer_token token, string_view sv) noexcept 116   249 bool operator==(pointer_token token, string_view sv) noexcept
117   { 117   {
HITCBC 118   249 auto t_b = token.begin(); 118   249 auto t_b = token.begin();
HITCBC 119   249 auto const t_e = token.end(); 119   249 auto const t_e = token.end();
HITCBC 120   249 auto s_b = sv.begin(); 120   249 auto s_b = sv.begin();
HITCBC 121   249 auto const s_e = sv.end(); 121   249 auto const s_e = sv.end();
HITCBC 122   619 while( s_b != s_e ) 122   619 while( s_b != s_e )
123   { 123   {
HITCBC 124   474 if( t_e == t_b ) 124   474 if( t_e == t_b )
HITCBC 125   4 return false; 125   4 return false;
HITCBC 126   470 if( *t_b != *s_b ) 126   470 if( *t_b != *s_b )
HITCBC 127   100 return false; 127   100 return false;
HITCBC 128   370 ++t_b; 128   370 ++t_b;
HITCBC 129   370 ++s_b; 129   370 ++s_b;
130   } 130   }
HITCBC 131   145 return t_b == t_e; 131   145 return t_b == t_e;
132   } 132   }
133   133  
HITCBC 134   72 bool is_invalid_zero( 134   72 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   72 if( *b != '0' )
HITCBC 140   56 return false; 140   56 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   69 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   69 if( *b != '-' )
HITCBC 157   57 return false; 157   57 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   75 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   75 BOOST_ASSERT( !sv.empty() );
170   170  
HITCBC 171   75 char const* b = sv.begin(); 171   75 char const* b = sv.begin();
HITCBC 172   75 BOOST_ASSERT( *b == '/' ); 172   75 BOOST_ASSERT( *b == '/' );
173   173  
HITCBC 174   75 ++b; 174   75 ++b;
HITCBC 175   75 char const* const e = sv.end(); 175   75 char const* const e = sv.end();
HITCBC 176   75 if( ( b == e ) 176   75 if( ( b == e )
HITCBC 177   75 || is_invalid_zero(b, e) ) 177   75 || 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   69 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   59 std::size_t result = 0;
HITCBC 191   133 for( ; b != e; ++b ) 191   133 for( ; b != e; ++b )
192   { 192   {
HITCBC 193   104 char const c = *b; 193   104 char const c = *b;
HITCBC 194   104 BOOST_ASSERT( c != '/' ); 194   104 BOOST_ASSERT( c != '/' );
195   195  
HITCBC 196   104 unsigned d = c - '0'; 196   104 unsigned d = c - '0';
HITCBC 197   104 if( d > 9 ) 197   104 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   76 std::size_t new_result = result * 10 + d;
HITCBC 204   76 if( new_result < result ) 204   76 if( new_result < result )
205   { 205   {
HITCBC 206   2 BOOST_JSON_FAIL(ec, error::token_overflow); 206   2 BOOST_JSON_FAIL(ec, error::token_overflow);
HITCBC 207   2 return {}; 207   2 return {};
208   } 208   }
209   209  
HITCBC 210   74 result = new_result; 210   74 result = new_result;
211   211  
212   } 212   }
HITCBC 213   29 return result; 213   29 return result;
214   } 214   }
215   215  
216   string_view 216   string_view
HITCBC 217   344 next_segment( 217   344 next_segment(
218   string_view& sv, 218   string_view& sv,
219   system::error_code& ec) noexcept 219   system::error_code& ec) noexcept
220   { 220   {
HITCBC 221   344 if( sv.empty() ) 221   344 if( sv.empty() )
HITCBC 222   108 return sv; 222   108 return sv;
223   223  
HITCBC 224   236 char const* const start = sv.begin(); 224   236 char const* const start = sv.begin();
HITCBC 225   236 char const* b = start; 225   236 char const* b = start;
HITCBC 226   236 if( *b++ != '/' ) 226   236 if( *b++ != '/' )
227   { 227   {
HITCBC 228   5 BOOST_JSON_FAIL( ec, error::missing_slash ); 228   5 BOOST_JSON_FAIL( ec, error::missing_slash );
HITCBC 229   5 return {}; 229   5 return {};
230   } 230   }
231   231  
HITCBC 232   231 char const* e = sv.end(); 232   231 char const* e = sv.end();
HITCBC 233   768 for( ; b < e; ++b ) 233   768 for( ; b < e; ++b )
234   { 234   {
HITCBC 235   655 char const c = *b; 235   655 char const c = *b;
HITCBC 236   655 if( '/' == c ) 236   655 if( '/' == c )
HITCBC 237   112 break; 237   112 break;
238   238  
HITCBC 239   543 if( '~' == c ) 239   543 if( '~' == c )
240   { 240   {
HITCBC 241   8 if( ++b == e ) 241   8 if( ++b == e )
242   { 242   {
HITCBC 243   3 BOOST_JSON_FAIL( ec, error::invalid_escape ); 243   3 BOOST_JSON_FAIL( ec, error::invalid_escape );
HITCBC 244   3 break; 244   3 break;
245   } 245   }
246   246  
HITCBC 247   5 switch (*b) 247   5 switch (*b)
248   { 248   {
HITCBC 249   2 case '0': // fall through 249   2 case '0': // fall through
250   case '1': 250   case '1':
251   // valid escape sequence 251   // valid escape sequence
HITCBC 252   2 continue; 252   2 continue;
HITCBC 253   3 default: { 253   3 default: {
HITCBC 254   3 BOOST_JSON_FAIL( ec, error::invalid_escape ); 254   3 BOOST_JSON_FAIL( ec, error::invalid_escape );
HITCBC 255   3 break; 255   3 break;
256   } 256   }
HITCBC 257   2 } 257   2 }
HITCBC 258   3 break; 258   3 break;
259   } 259   }
260   } 260   }
261   261  
HITCBC 262   231 sv.remove_prefix( b - start ); 262   231 sv.remove_prefix( b - start );
HITCBC 263   231 return string_view( start, b ); 263   231 return string_view( start, b );
264   } 264   }
265   265  
266   value* 266   value*
HITCBC 267   125 if_contains_token(object const& obj, pointer_token token) 267   125 if_contains_token(object const& obj, pointer_token token)
268   { 268   {
HITCBC 269   125 if( obj.empty() ) 269   125 if( obj.empty() )
HITCBC 270   2 return nullptr; 270   2 return nullptr;
271   271  
HITCBC 272   123 auto const it = detail::find_in_object(obj, token).first; 272   123 auto const it = detail::find_in_object(obj, token).first;
HITCBC 273   123 if( !it ) 273   123 if( !it )
HITCBC 274   5 return nullptr; 274   5 return nullptr;
275   275  
HITCBC 276   118 return &it->value(); 276   118 return &it->value();
277   } 277   }
278   278  
279   template< 279   template<
280   class Value, 280   class Value,
281   class OnObject, 281   class OnObject,
282   class OnArray, 282   class OnArray,
283   class OnScalar > 283   class OnScalar >
284   Value* 284   Value*
HITCBC 285   129 walk_pointer( 285   129 walk_pointer(
286   Value& jv, 286   Value& jv,
287   string_view sv, 287   string_view sv,
288   system::error_code& ec, 288   system::error_code& ec,
289   OnObject on_object, 289   OnObject on_object,
290   OnArray on_array, 290   OnArray on_array,
291   OnScalar on_scalar) 291   OnScalar on_scalar)
292   { 292   {
HITCBC 293   129 ec.clear(); 293   129 ec.clear();
294   294  
HITCBC 295   129 string_view segment = detail::next_segment( sv, ec ); 295   129 string_view segment = detail::next_segment( sv, ec );
296   296  
HITCBC 297   129 Value* result = &jv; 297   129 Value* result = &jv;
HITCBC 298   244 while( true ) 298   244 while( true )
299   { 299   {
HITCBC 300   373 if( ec.failed() ) 300   373 if( ec.failed() )
HITCBC 301   43 return nullptr; 301   43 return nullptr;
302   302  
HITCBC 303   330 if( !result ) 303   330 if( !result )
304   { 304   {
HITCBC 305   12 BOOST_JSON_FAIL(ec, error::not_found); 305   12 BOOST_JSON_FAIL(ec, error::not_found);
HITCBC 306   12 return nullptr; 306   12 return nullptr;
307   } 307   }
308   308  
HITCBC 309   318 if( segment.empty() ) 309   318 if( segment.empty() )
HITCBC 310   74 break; 310   74 break;
311   311  
HITCBC 312   244 switch( result->kind() ) 312   244 switch( result->kind() )
313   { 313   {
HITCBC 314   158 case kind::object: { 314   158 case kind::object: {
HITCBC 315   158 auto& obj = result->get_object(); 315   158 auto& obj = result->get_object();
316   316  
HITCBC 317   158 detail::pointer_token const token( segment ); 317   158 detail::pointer_token const token( segment );
HITCBC 318   158 segment = detail::next_segment( sv, ec ); 318   158 segment = detail::next_segment( sv, ec );
319   319  
HITCBC 320   158 result = on_object( obj, token ); 320   158 result = on_object( obj, token );
HITCBC 321   158 break; 321   158 break;
322   } 322   }
HITCBC 323   57 case kind::array: { 323   57 case kind::array: {
HITCBC 324   57 auto const index = detail::parse_number_token( segment, ec ); 324   57 auto const index = detail::parse_number_token( segment, ec );
HITCBC 325   57 segment = detail::next_segment( sv, ec ); 325   57 segment = detail::next_segment( sv, ec );
326   326  
HITCBC 327   57 auto& arr = result->get_array(); 327   57 auto& arr = result->get_array();
HITCBC 328   57 result = on_array( arr, index, ec ); 328   57 result = on_array( arr, index, ec );
HITCBC 329   57 break; 329   57 break;
330   } 330   }
HITCBC 331   29 default: { 331   29 default: {
HITCBC 332   29 if( on_scalar( *result, segment ) ) 332   29 if( on_scalar( *result, segment ) )
HITCBC 333   21 break; 333   21 break;
HITCBC 334   8 BOOST_JSON_FAIL( ec, error::value_is_scalar ); 334   8 BOOST_JSON_FAIL( ec, error::value_is_scalar );
335   }} 335   }}
336   } 336   }
337   337  
HITCBC 338   74 BOOST_ASSERT( result ); 338   74 BOOST_ASSERT( result );
HITCBC 339   74 return result; 339   74 return result;
340   } 340   }
341   341  
342   } // namespace detail 342   } // namespace detail
343   343  
344   value const& 344   value const&
HITCBC 345   56 value::at_pointer(string_view ptr, source_location const& loc) const& 345   56 value::at_pointer(string_view ptr, source_location const& loc) const&
346   { 346   {
HITCBC 347   56 return try_at_pointer(ptr).value(loc); 347   56 return try_at_pointer(ptr).value(loc);
348   } 348   }
349   349  
350   system::result<value const&> 350   system::result<value const&>
HITCBC 351   58 value::try_at_pointer(string_view ptr) const noexcept 351   58 value::try_at_pointer(string_view ptr) const noexcept
352   { 352   {
HITCBC 353   58 system::error_code ec; 353   58 system::error_code ec;
HITCBC 354   58 auto const found = find_pointer(ptr, ec); 354   58 auto const found = find_pointer(ptr, ec);
HITCBC 355   58 if( !found ) 355   58 if( !found )
HITCBC 356   10 return ec; 356   10 return ec;
HITCBC 357   48 return *found; 357   48 return *found;
358   } 358   }
359   359  
360   system::result<value&> 360   system::result<value&>
HITCBC 361   2 value::try_at_pointer(string_view ptr) noexcept 361   2 value::try_at_pointer(string_view ptr) noexcept
362   { 362   {
HITCBC 363   2 system::error_code ec; 363   2 system::error_code ec;
HITCBC 364   2 auto const found = find_pointer(ptr, ec); 364   2 auto const found = find_pointer(ptr, ec);
HITCBC 365   2 if( !found ) 365   2 if( !found )
HITCBC 366   1 return ec; 366   1 return ec;
HITCBC 367   1 return *found; 367   1 return *found;
368   } 368   }
369   369  
370   value const* 370   value const*
HITCBC 371   101 value::find_pointer( string_view sv, system::error_code& ec ) const noexcept 371   101 value::find_pointer( string_view sv, system::error_code& ec ) const noexcept
372   { 372   {
HITCBC 373   101 return detail::walk_pointer( 373   101 return detail::walk_pointer(
374   *this, 374   *this,
375   sv, 375   sv,
376   ec, 376   ec,
HITCBC 377   125 []( object const& obj, detail::pointer_token token ) 377   125 []( object const& obj, detail::pointer_token token )
378   { 378   {
HITCBC 379   125 return detail::if_contains_token(obj, token); 379   125 return detail::if_contains_token(obj, token);
380   }, 380   },
HITCBC 381   37 []( array const& arr, std::size_t index, system::error_code& ec ) 381   37 []( array const& arr, std::size_t index, system::error_code& ec )
382   -> value const* 382   -> value const*
383   { 383   {
HITCBC 384   37 if( ec ) 384   37 if( ec )
HITCBC 385   22 return nullptr; 385   22 return nullptr;
386   386  
HITCBC 387   15 return arr.if_contains(index); 387   15 return arr.if_contains(index);
388   }, 388   },
HITCBC 389   5 []( value const&, string_view) 389   5 []( value const&, string_view)
390   { 390   {
HITCBC 391   5 return std::false_type(); 391   5 return std::false_type();
HITCBC 392   101 }); 392   101 });
393   } 393   }
394   394  
395   value* 395   value*
HITCBC 396   22 value::find_pointer(string_view ptr, system::error_code& ec) noexcept 396   22 value::find_pointer(string_view ptr, system::error_code& ec) noexcept
397   { 397   {
HITCBC 398   22 value const& self = *this; 398   22 value const& self = *this;
HITCBC 399   22 return const_cast<value*>(self.find_pointer(ptr, ec)); 399   22 return const_cast<value*>(self.find_pointer(ptr, ec));
400   } 400   }
401   401  
402   value const* 402   value const*
HITCBC 403   20 value::find_pointer(string_view ptr, std::error_code& ec) const noexcept 403   20 value::find_pointer(string_view ptr, std::error_code& ec) const noexcept
404   { 404   {
HITCBC 405   20 system::error_code jec; 405   20 system::error_code jec;
HITCBC 406   20 value const* result = find_pointer(ptr, jec); 406   20 value const* result = find_pointer(ptr, jec);
HITCBC 407   20 ec = jec; 407   20 ec = jec;
HITCBC 408   20 return result; 408   20 return result;
409   } 409   }
410   410  
411   value* 411   value*
HITCBC 412   19 value::find_pointer(string_view ptr, std::error_code& ec) noexcept 412   19 value::find_pointer(string_view ptr, std::error_code& ec) noexcept
413   { 413   {
HITCBC 414   19 value const& self = *this; 414   19 value const& self = *this;
HITCBC 415   19 return const_cast<value*>(self.find_pointer(ptr, ec)); 415   19 return const_cast<value*>(self.find_pointer(ptr, ec));
416   } 416   }
417   417  
418   value* 418   value*
HITCBC 419   28 value::set_at_pointer( 419   28 value::set_at_pointer(
420   string_view sv, 420   string_view sv,
421   value_ref ref, 421   value_ref ref,
422   system::error_code& ec, 422   system::error_code& ec,
423   set_pointer_options const& opts ) 423   set_pointer_options const& opts )
424   { 424   {
HITCBC 425   28 value* result = detail::walk_pointer( 425   28 value* result = detail::walk_pointer(
426   *this, 426   *this,
427   sv, 427   sv,
428   ec, 428   ec,
HITCBC 429   33 []( object& obj, detail::pointer_token token) 429   33 []( object& obj, detail::pointer_token token)
430   { 430   {
HITCBC 431   33 if( !obj.empty() ) 431   33 if( !obj.empty() )
432   { 432   {
HITCBC 433   13 key_value_pair* kv = detail::find_in_object( obj, token ).first; 433   13 key_value_pair* kv = detail::find_in_object( obj, token ).first;
HITCBC 434   13 if( kv ) 434   13 if( kv )
HITCBC 435   12 return &kv->value(); 435   12 return &kv->value();
436   } 436   }
437   437  
HITCBC 438   21 string key( token.begin(), token.end(), obj.storage() ); 438   21 string key( token.begin(), token.end(), obj.storage() );
HITCBC 439   21 return &obj.emplace( std::move(key), nullptr ).first->value(); 439   21 return &obj.emplace( std::move(key), nullptr ).first->value();
HITCBC 440   21 }, 440   21 },
HITCBC 441   20 [ &opts ]( array& arr, std::size_t index, system::error_code& ec ) -> value* 441   20 [ &opts ]( array& arr, std::size_t index, system::error_code& ec ) -> value*
442   { 442   {
HITCBC 443   20 if( ec == error::past_the_end ) 443   20 if( ec == error::past_the_end )
HITCBC 444   6 index = arr.size(); 444   6 index = arr.size();
HITCBC 445   14 else if( ec.failed() ) 445   14 else if( ec.failed() )
HITCBC 446   2 return nullptr; 446   2 return nullptr;
447   447  
HITCBC 448   18 if( index >= arr.size() ) 448   18 if( index >= arr.size() )
449   { 449   {
HITCBC 450   13 std::size_t const n = index - arr.size(); 450   13 std::size_t const n = index - arr.size();
HITCBC 451   13 if( n >= opts.max_created_elements ) 451   13 if( n >= opts.max_created_elements )
HITCBC 452   3 return nullptr; 452   3 return nullptr;
453   453  
HITCBC 454   10 arr.resize( arr.size() + n + 1 ); 454   10 arr.resize( arr.size() + n + 1 );
455   } 455   }
456   456  
HITCBC 457   15 ec.clear(); 457   15 ec.clear();
HITCBC 458   15 return arr.data() + index; 458   15 return arr.data() + index;
459   }, 459   },
HITCBC 460   24 [ &opts ]( value& jv, string_view segment ) 460   24 [ &opts ]( value& jv, string_view segment )
461   { 461   {
HITCBC 462   24 if( jv.is_null() || opts.replace_any_scalar ) 462   24 if( jv.is_null() || opts.replace_any_scalar )
463   { 463   {
HITCBC 464   21 if( opts.create_arrays ) 464   21 if( opts.create_arrays )
465   { 465   {
HITCBC 466   18 system::error_code ec; 466   18 system::error_code ec;
HITCBC 467   18 detail::parse_number_token( segment, ec ); 467   18 detail::parse_number_token( segment, ec );
HITCBC 468   18 if( !ec.failed() || ec == error::past_the_end ) 468   18 if( !ec.failed() || ec == error::past_the_end )
469   { 469   {
HITCBC 470   2 jv = array( jv.storage() ); 470   2 jv = array( jv.storage() );
HITCBC 471   2 return true; 471   2 return true;
472   } 472   }
473   } 473   }
474   474  
HITCBC 475   19 if( opts.create_objects ) 475   19 if( opts.create_objects )
476   { 476   {
HITCBC 477   19 jv = object( jv.storage() ); 477   19 jv = object( jv.storage() );
HITCBC 478   19 return true; 478   19 return true;
479   } 479   }
480   } 480   }
481   481  
HITCBC 482   3 return false; 482   3 return false;
483   }); 483   });
484   484  
HITCBC 485   28 if( result ) 485   28 if( result )
HITCBC 486   20 *result = ref.make_value( storage() ); 486   20 *result = ref.make_value( storage() );
HITCBC 487   28 return result; 487   28 return result;
488   } 488   }
489   489  
490   value* 490   value*
HITCBC 491   5 value::set_at_pointer( 491   5 value::set_at_pointer(
492   string_view sv, 492   string_view sv,
493   value_ref ref, 493   value_ref ref,
494   std::error_code& ec, 494   std::error_code& ec,
495   set_pointer_options const& opts ) 495   set_pointer_options const& opts )
496   { 496   {
HITCBC 497   5 system::error_code jec; 497   5 system::error_code jec;
HITCBC 498   5 value* result = set_at_pointer( sv, ref, jec, opts ); 498   5 value* result = set_at_pointer( sv, ref, jec, opts );
HITCBC 499   5 ec = jec; 499   5 ec = jec;
HITCBC 500   5 return result; 500   5 return result;
501   } 501   }
502   502  
503   system::result<value&> 503   system::result<value&>
HITCBC 504   18 value::try_set_at_pointer( 504   18 value::try_set_at_pointer(
505   string_view sv, 505   string_view sv,
506   value_ref ref, 506   value_ref ref,
507   set_pointer_options const& opts ) 507   set_pointer_options const& opts )
508   { 508   {
HITCBC 509   18 system::error_code ec; 509   18 system::error_code ec;
HITCBC 510   18 value* result = set_at_pointer( sv, ref, ec, opts ); 510   18 value* result = set_at_pointer( sv, ref, ec, opts );
HITCBC 511   18 if( result ) 511   18 if( result )
HITCBC 512   16 return *result; 512   16 return *result;
HITCBC 513   2 return ec; 513   2 return ec;
514   } 514   }
515   515  
516   value& 516   value&
HITCBC 517   17 value::set_at_pointer( 517   17 value::set_at_pointer(
518   string_view sv, value_ref ref, set_pointer_options const& opts ) 518   string_view sv, value_ref ref, set_pointer_options const& opts )
519   { 519   {
HITCBC 520   17 return try_set_at_pointer(sv, ref, opts).value(); 520   17 return try_set_at_pointer(sv, ref, opts).value();
521   } 521   }
522   522  
523   } // namespace json 523   } // namespace json
524   } // namespace boost 524   } // namespace boost
525   525  
526   #endif // BOOST_JSON_IMPL_POINTER_IPP 526   #endif // BOOST_JSON_IMPL_POINTER_IPP