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