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  

25  
    pointer_token(
25  
    pointer_token(
26  
        string_view sv) noexcept
26  
        string_view sv) noexcept
27  
        : b_( sv.begin() + 1 )
27  
        : b_( sv.begin() + 1 )
28  
        , e_( sv.end() )
28  
        , e_( sv.end() )
29  
    {
29  
    {
30  
        BOOST_ASSERT( !sv.empty() );
30  
        BOOST_ASSERT( !sv.empty() );
31  
        BOOST_ASSERT( *sv.data() == '/' );
31  
        BOOST_ASSERT( *sv.data() == '/' );
32  
    }
32  
    }
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  

51  
    explicit iterator(char const* base) noexcept
51  
    explicit iterator(char const* base) noexcept
52  
        : base_(base)
52  
        : base_(base)
53  
    {
53  
    {
54  
    }
54  
    }
55  

55  

56  
    char operator*() const noexcept
56  
    char operator*() const noexcept
57  
    {
57  
    {
58  
        switch( char c = *base_ )
58  
        switch( char c = *base_ )
59  
        {
59  
        {
60  
        case '~':
60  
        case '~':
61  
            c = base_[1];
61  
            c = base_[1];
62  
            if( '0' == c )
62  
            if( '0' == c )
63  
                return '~';
63  
                return '~';
64  
            BOOST_ASSERT('1' == c);
64  
            BOOST_ASSERT('1' == c);
65  
            return '/';
65  
            return '/';
66  
        default:
66  
        default:
67  
            return c;
67  
            return c;
68  
        }
68  
        }
69  
    }
69  
    }
70  

70  

71  
    iterator& operator++() noexcept
71  
    iterator& operator++() noexcept
72  
    {
72  
    {
73  
        if( '~' == *base_ )
73  
        if( '~' == *base_ )
74  
            base_ += 2;
74  
            base_ += 2;
75  
        else
75  
        else
76  
            ++base_;
76  
            ++base_;
77  
        return *this;
77  
        return *this;
78  
    }
78  
    }
79  

79  

80  
    iterator operator++(int) noexcept
80  
    iterator operator++(int) noexcept
81  
    {
81  
    {
82  
        iterator result = *this;
82  
        iterator result = *this;
83  
        ++(*this);
83  
        ++(*this);
84  
        return result;
84  
        return result;
85  
    }
85  
    }
86  

86  

87  
    char const* base() const noexcept
87  
    char const* base() const noexcept
88  
    {
88  
    {
89  
        return base_;
89  
        return base_;
90  
    }
90  
    }
91  

91  

92  
private:
92  
private:
93  
    char const* base_;
93  
    char const* base_;
94  
};
94  
};
95  

95  

96  
bool operator==(pointer_token::iterator l, pointer_token::iterator r) noexcept
96  
bool operator==(pointer_token::iterator l, pointer_token::iterator r) noexcept
97  
{
97  
{
98  
    return l.base() == r.base();
98  
    return l.base() == r.base();
99  
}
99  
}
100  

100  

101  
bool operator!=(pointer_token::iterator l, pointer_token::iterator r) noexcept
101  
bool operator!=(pointer_token::iterator l, pointer_token::iterator r) noexcept
102  
{
102  
{
103  
    return l.base() != r.base();
103  
    return l.base() != r.base();
104  
}
104  
}
105  

105  

106  
pointer_token::iterator pointer_token::begin() const noexcept
106  
pointer_token::iterator pointer_token::begin() const noexcept
107  
{
107  
{
108  
    return iterator(b_);
108  
    return iterator(b_);
109  
}
109  
}
110  

110  

111  
pointer_token::iterator pointer_token::end() const noexcept
111  
pointer_token::iterator pointer_token::end() const noexcept
112  
{
112  
{
113  
    return iterator(e_);
113  
    return iterator(e_);
114  
}
114  
}
115  

115  

116  
bool operator==(pointer_token token, string_view sv) noexcept
116  
bool operator==(pointer_token token, string_view sv) noexcept
117  
{
117  
{
118  
    auto t_b = token.begin();
118  
    auto t_b = token.begin();
119  
    auto const t_e = token.end();
119  
    auto const t_e = token.end();
120  
    auto s_b = sv.begin();
120  
    auto s_b = sv.begin();
121  
    auto const s_e = sv.end();
121  
    auto const s_e = sv.end();
122  
    while( s_b != s_e )
122  
    while( s_b != s_e )
123  
    {
123  
    {
124  
        if( t_e == t_b )
124  
        if( t_e == t_b )
125  
            return false;
125  
            return false;
126  
        if( *t_b != *s_b )
126  
        if( *t_b != *s_b )
127  
            return false;
127  
            return false;
128  
        ++t_b;
128  
        ++t_b;
129  
        ++s_b;
129  
        ++s_b;
130  
    }
130  
    }
131  
    return t_b == t_e;
131  
    return t_b == t_e;
132  
}
132  
}
133  

133  

134  
bool is_invalid_zero(
134  
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'
139  
    if( *b != '0' )
139  
    if( *b != '0' )
140  
        return false;
140  
        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
144  
    ++b;
144  
    ++b;
145  
    if( b == e )
145  
    if( b == e )
146  
        return false;
146  
        return false;
147  

147  

148  
    BOOST_ASSERT( *b != '/' );
148  
    BOOST_ASSERT( *b != '/' );
149  
    return true;
149  
    return true;
150  
}
150  
}
151  

151  

152  
bool is_past_the_end_token(
152  
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  
{
156  
    if( *b != '-' )
156  
    if( *b != '-' )
157  
        return false;
157  
        return false;
158  

158  

159  
    ++b;
159  
    ++b;
160  
    BOOST_ASSERT( (b == e) || (*b != '/') );
160  
    BOOST_ASSERT( (b == e) || (*b != '/') );
161  
    return b == e;
161  
    return b == e;
162  
}
162  
}
163  

163  

164  
std::size_t
164  
std::size_t
165  
parse_number_token(
165  
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  
{
169  
    BOOST_ASSERT( !sv.empty() );
169  
    BOOST_ASSERT( !sv.empty() );
170  

170  

171  
    char const* b = sv.begin();
171  
    char const* b = sv.begin();
172  
    BOOST_ASSERT( *b == '/' );
172  
    BOOST_ASSERT( *b == '/' );
173  

173  

174  
    ++b;
174  
    ++b;
175  
    char const* const e = sv.end();
175  
    char const* const e = sv.end();
176  
    if( ( b == e )
176  
    if( ( b == e )
177  
        || is_invalid_zero(b, e) )
177  
        || is_invalid_zero(b, e) )
178  
    {
178  
    {
179  
        BOOST_JSON_FAIL(ec, error::token_not_number);
179  
        BOOST_JSON_FAIL(ec, error::token_not_number);
180  
        return {};
180  
        return {};
181  
    }
181  
    }
182  

182  

183  
    if( is_past_the_end_token(b, e) )
183  
    if( is_past_the_end_token(b, e) )
184  
    {
184  
    {
185  
        ++b;
185  
        ++b;
186  
        BOOST_JSON_FAIL(ec, error::past_the_end);
186  
        BOOST_JSON_FAIL(ec, error::past_the_end);
187  
        return {};
187  
        return {};
188  
    }
188  
    }
189  

189  

190  
    std::size_t result = 0;
190  
    std::size_t result = 0;
191  
    for( ; b != e; ++b )
191  
    for( ; b != e; ++b )
192  
    {
192  
    {
193  
        char const c = *b;
193  
        char const c = *b;
194  
        BOOST_ASSERT( c != '/' );
194  
        BOOST_ASSERT( c != '/' );
195  

195  

196  
        unsigned d = c - '0';
196  
        unsigned d = c - '0';
197  
        if( d > 9 )
197  
        if( d > 9 )
198  
        {
198  
        {
199  
            BOOST_JSON_FAIL(ec, error::token_not_number);
199  
            BOOST_JSON_FAIL(ec, error::token_not_number);
200  
            return {};
200  
            return {};
201  
        }
201  
        }
202  

202  

203  
        std::size_t new_result = result * 10 + d;
203  
        std::size_t new_result = result * 10 + d;
204  
        if( new_result < result )
204  
        if( new_result < result )
205  
        {
205  
        {
206  
            BOOST_JSON_FAIL(ec, error::token_overflow);
206  
            BOOST_JSON_FAIL(ec, error::token_overflow);
207  
            return {};
207  
            return {};
208  
        }
208  
        }
209  

209  

210  
        result = new_result;
210  
        result = new_result;
211  

211  

212  
    }
212  
    }
213  
    return result;
213  
    return result;
214  
}
214  
}
215  

215  

216  
string_view
216  
string_view
217  
next_segment(
217  
next_segment(
218  
    string_view& sv,
218  
    string_view& sv,
219  
    system::error_code& ec) noexcept
219  
    system::error_code& ec) noexcept
220  
{
220  
{
221  
    if( sv.empty() )
221  
    if( sv.empty() )
222  
        return sv;
222  
        return sv;
223  

223  

224  
    char const* const start = sv.begin();
224  
    char const* const start = sv.begin();
225  
    char const* b = start;
225  
    char const* b = start;
226  
    if( *b++ != '/' )
226  
    if( *b++ != '/' )
227  
    {
227  
    {
228  
        BOOST_JSON_FAIL( ec, error::missing_slash );
228  
        BOOST_JSON_FAIL( ec, error::missing_slash );
229  
        return {};
229  
        return {};
230  
    }
230  
    }
231  

231  

232  
    char const* e = sv.end();
232  
    char const* e = sv.end();
233  
    for( ; b < e; ++b )
233  
    for( ; b < e; ++b )
234  
    {
234  
    {
235  
        char const c = *b;
235  
        char const c = *b;
236  
        if( '/' == c )
236  
        if( '/' == c )
237  
            break;
237  
            break;
238  

238  

239  
        if( '~' == c )
239  
        if( '~' == c )
240  
        {
240  
        {
241  
            if( ++b == e )
241  
            if( ++b == e )
242  
            {
242  
            {
243  
                BOOST_JSON_FAIL( ec, error::invalid_escape );
243  
                BOOST_JSON_FAIL( ec, error::invalid_escape );
244  
                break;
244  
                break;
245  
            }
245  
            }
246  

246  

247  
            switch (*b)
247  
            switch (*b)
248  
            {
248  
            {
249  
            case '0': // fall through
249  
            case '0': // fall through
250  
            case '1':
250  
            case '1':
251  
                // valid escape sequence
251  
                // valid escape sequence
252  
                continue;
252  
                continue;
253  
            default: {
253  
            default: {
254  
                BOOST_JSON_FAIL( ec, error::invalid_escape );
254  
                BOOST_JSON_FAIL( ec, error::invalid_escape );
255  
                break;
255  
                break;
256  
            }
256  
            }
257  
            }
257  
            }
258  
            break;
258  
            break;
259  
        }
259  
        }
260  
    }
260  
    }
261  

261  

262  
    sv.remove_prefix( b - start );
262  
    sv.remove_prefix( b - start );
263  
    return string_view( start, b );
263  
    return string_view( start, b );
264  
}
264  
}
265  

265  

266  
value*
266  
value*
267  
if_contains_token(object const& obj, pointer_token token)
267  
if_contains_token(object const& obj, pointer_token token)
268  
{
268  
{
269  
    if( obj.empty() )
269  
    if( obj.empty() )
270  
        return nullptr;
270  
        return nullptr;
271  

271  

272  
    auto const it = detail::find_in_object(obj, token).first;
272  
    auto const it = detail::find_in_object(obj, token).first;
273  
    if( !it )
273  
    if( !it )
274  
        return nullptr;
274  
        return nullptr;
275  

275  

276  
    return &it->value();
276  
    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*
285  
walk_pointer(
285  
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  
{
293  
    ec.clear();
293  
    ec.clear();
294  

294  

295  
    string_view segment = detail::next_segment( sv, ec );
295  
    string_view segment = detail::next_segment( sv, ec );
296  

296  

297  
    Value* result = &jv;
297  
    Value* result = &jv;
298  
    while( true )
298  
    while( true )
299  
    {
299  
    {
300  
        if( ec.failed() )
300  
        if( ec.failed() )
301  
            return nullptr;
301  
            return nullptr;
302  

302  

303  
        if( !result )
303  
        if( !result )
304  
        {
304  
        {
305  
            BOOST_JSON_FAIL(ec, error::not_found);
305  
            BOOST_JSON_FAIL(ec, error::not_found);
306  
            return nullptr;
306  
            return nullptr;
307  
        }
307  
        }
308  

308  

309  
        if( segment.empty() )
309  
        if( segment.empty() )
310  
            break;
310  
            break;
311  

311  

312  
        switch( result->kind() )
312  
        switch( result->kind() )
313  
        {
313  
        {
314  
        case kind::object: {
314  
        case kind::object: {
315  
            auto& obj = result->get_object();
315  
            auto& obj = result->get_object();
316  

316  

317  
            detail::pointer_token const token( segment );
317  
            detail::pointer_token const token( segment );
318  
            segment = detail::next_segment( sv, ec );
318  
            segment = detail::next_segment( sv, ec );
319  

319  

320  
            result = on_object( obj, token );
320  
            result = on_object( obj, token );
321  
            break;
321  
            break;
322  
        }
322  
        }
323  
        case kind::array: {
323  
        case kind::array: {
324  
            auto const index = detail::parse_number_token( segment, ec );
324  
            auto const index = detail::parse_number_token( segment, ec );
325  
            segment = detail::next_segment( sv, ec );
325  
            segment = detail::next_segment( sv, ec );
326  

326  

327  
            auto& arr = result->get_array();
327  
            auto& arr = result->get_array();
328  
            result = on_array( arr, index, ec );
328  
            result = on_array( arr, index, ec );
329  
            break;
329  
            break;
330  
        }
330  
        }
331  
        default: {
331  
        default: {
332  
            if( on_scalar( *result, segment ) )
332  
            if( on_scalar( *result, segment ) )
333  
                break;
333  
                break;
334  
            BOOST_JSON_FAIL( ec, error::value_is_scalar );
334  
            BOOST_JSON_FAIL( ec, error::value_is_scalar );
335  
        }}
335  
        }}
336  
    }
336  
    }
337  

337  

338  
    BOOST_ASSERT( result );
338  
    BOOST_ASSERT( result );
339  
    return result;
339  
    return result;
340  
}
340  
}
341  

341  

342  
} // namespace detail
342  
} // namespace detail
343  

343  

344  
value const&
344  
value const&
345  
value::at_pointer(string_view ptr, source_location const& loc) const&
345  
value::at_pointer(string_view ptr, source_location const& loc) const&
346  
{
346  
{
347  
    return try_at_pointer(ptr).value(loc);
347  
    return try_at_pointer(ptr).value(loc);
348  
}
348  
}
349  

349  

350  
system::result<value const&>
350  
system::result<value const&>
351  
value::try_at_pointer(string_view ptr) const noexcept
351  
value::try_at_pointer(string_view ptr) const noexcept
352  
{
352  
{
353  
    system::error_code ec;
353  
    system::error_code ec;
354  
    auto const found = find_pointer(ptr, ec);
354  
    auto const found = find_pointer(ptr, ec);
355  
    if( !found )
355  
    if( !found )
356  
        return ec;
356  
        return ec;
357  
    return *found;
357  
    return *found;
358  
}
358  
}
359  

359  

360  
system::result<value&>
360  
system::result<value&>
361  
value::try_at_pointer(string_view ptr) noexcept
361  
value::try_at_pointer(string_view ptr) noexcept
362  
{
362  
{
363  
    system::error_code ec;
363  
    system::error_code ec;
364  
    auto const found = find_pointer(ptr, ec);
364  
    auto const found = find_pointer(ptr, ec);
365  
    if( !found )
365  
    if( !found )
366  
        return ec;
366  
        return ec;
367  
    return *found;
367  
    return *found;
368  
}
368  
}
369  

369  

370  
value const*
370  
value const*
371  
value::find_pointer( string_view sv, system::error_code& ec ) const noexcept
371  
value::find_pointer( string_view sv, system::error_code& ec ) const noexcept
372  
{
372  
{
373  
    return detail::walk_pointer(
373  
    return detail::walk_pointer(
374  
        *this,
374  
        *this,
375  
        sv,
375  
        sv,
376  
        ec,
376  
        ec,
377  
        []( object const& obj, detail::pointer_token token )
377  
        []( object const& obj, detail::pointer_token token )
378  
        {
378  
        {
379  
            return detail::if_contains_token(obj, token);
379  
            return detail::if_contains_token(obj, token);
380  
        },
380  
        },
381  
        []( array const& arr, std::size_t index, system::error_code& ec )
381  
        []( array const& arr, std::size_t index, system::error_code& ec )
382  
            -> value const*
382  
            -> value const*
383  
        {
383  
        {
384  
            if( ec )
384  
            if( ec )
385  
                return nullptr;
385  
                return nullptr;
386  

386  

387  
            return arr.if_contains(index);
387  
            return arr.if_contains(index);
388  
        },
388  
        },
389  
        []( value const&, string_view)
389  
        []( value const&, string_view)
390  
        {
390  
        {
391  
            return std::false_type();
391  
            return std::false_type();
392  
        });
392  
        });
393  
}
393  
}
394  

394  

395  
value*
395  
value*
396  
value::find_pointer(string_view ptr, system::error_code& ec) noexcept
396  
value::find_pointer(string_view ptr, system::error_code& ec) noexcept
397  
{
397  
{
398  
    value const& self = *this;
398  
    value const& self = *this;
399  
    return const_cast<value*>(self.find_pointer(ptr, ec));
399  
    return const_cast<value*>(self.find_pointer(ptr, ec));
400  
}
400  
}
401  

401  

402  
value const*
402  
value const*
403  
value::find_pointer(string_view ptr, std::error_code& ec) const noexcept
403  
value::find_pointer(string_view ptr, std::error_code& ec) const noexcept
404  
{
404  
{
405  
    system::error_code jec;
405  
    system::error_code jec;
406  
    value const* result = find_pointer(ptr, jec);
406  
    value const* result = find_pointer(ptr, jec);
407  
    ec = jec;
407  
    ec = jec;
408  
    return result;
408  
    return result;
409  
}
409  
}
410  

410  

411  
value*
411  
value*
412  
value::find_pointer(string_view ptr, std::error_code& ec) noexcept
412  
value::find_pointer(string_view ptr, std::error_code& ec) noexcept
413  
{
413  
{
414  
    value const& self = *this;
414  
    value const& self = *this;
415  
    return const_cast<value*>(self.find_pointer(ptr, ec));
415  
    return const_cast<value*>(self.find_pointer(ptr, ec));
416  
}
416  
}
417  

417  

418  
value*
418  
value*
419  
value::set_at_pointer(
419  
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  
{
425  
    value* result = detail::walk_pointer(
425  
    value* result = detail::walk_pointer(
426  
        *this,
426  
        *this,
427  
        sv,
427  
        sv,
428  
        ec,
428  
        ec,
429  
        []( object& obj, detail::pointer_token token)
429  
        []( object& obj, detail::pointer_token token)
430  
        {
430  
        {
431  
            if( !obj.empty() )
431  
            if( !obj.empty() )
432  
            {
432  
            {
433  
                key_value_pair* kv = detail::find_in_object( obj, token ).first;
433  
                key_value_pair* kv = detail::find_in_object( obj, token ).first;
434  
                if( kv )
434  
                if( kv )
435  
                    return &kv->value();
435  
                    return &kv->value();
436  
            }
436  
            }
437  

437  

438  
            string key( token.begin(), token.end(), obj.storage() );
438  
            string key( token.begin(), token.end(), obj.storage() );
439  
            return &obj.emplace( std::move(key), nullptr ).first->value();
439  
            return &obj.emplace( std::move(key), nullptr ).first->value();
440  
        },
440  
        },
441  
        [ &opts ]( array& arr, std::size_t index, system::error_code& ec ) -> value*
441  
        [ &opts ]( array& arr, std::size_t index, system::error_code& ec ) -> value*
442  
        {
442  
        {
443  
            if( ec == error::past_the_end )
443  
            if( ec == error::past_the_end )
444  
                index = arr.size();
444  
                index = arr.size();
445  
            else if( ec.failed() )
445  
            else if( ec.failed() )
446  
                return nullptr;
446  
                return nullptr;
447  

447  

448  
            if( index >= arr.size() )
448  
            if( index >= arr.size() )
449  
            {
449  
            {
450  
                std::size_t const n = index - arr.size();
450  
                std::size_t const n = index - arr.size();
451  
                if( n >= opts.max_created_elements )
451  
                if( n >= opts.max_created_elements )
452  
                    return nullptr;
452  
                    return nullptr;
453  

453  

454  
                arr.resize( arr.size() + n + 1 );
454  
                arr.resize( arr.size() + n + 1 );
455  
            }
455  
            }
456  

456  

457  
            ec.clear();
457  
            ec.clear();
458  
            return arr.data() + index;
458  
            return arr.data() + index;
459  
        },
459  
        },
460  
        [ &opts ]( value& jv, string_view segment )
460  
        [ &opts ]( value& jv, string_view segment )
461  
        {
461  
        {
462  
            if( jv.is_null() || opts.replace_any_scalar )
462  
            if( jv.is_null() || opts.replace_any_scalar )
463  
            {
463  
            {
464  
                if( opts.create_arrays )
464  
                if( opts.create_arrays )
465  
                {
465  
                {
466  
                    system::error_code ec;
466  
                    system::error_code ec;
467  
                    detail::parse_number_token( segment, ec );
467  
                    detail::parse_number_token( segment, ec );
468  
                    if( !ec.failed() || ec == error::past_the_end )
468  
                    if( !ec.failed() || ec == error::past_the_end )
469  
                    {
469  
                    {
470  
                        jv = array( jv.storage() );
470  
                        jv = array( jv.storage() );
471  
                        return true;
471  
                        return true;
472  
                    }
472  
                    }
473  
                }
473  
                }
474  

474  

475  
                if( opts.create_objects )
475  
                if( opts.create_objects )
476  
                {
476  
                {
477  
                    jv = object( jv.storage() );
477  
                    jv = object( jv.storage() );
478  
                    return true;
478  
                    return true;
479  
                }
479  
                }
480  
            }
480  
            }
481  

481  

482  
            return false;
482  
            return false;
483  
        });
483  
        });
484  

484  

485  
    if( result )
485  
    if( result )
486  
        *result = ref.make_value( storage() );
486  
        *result = ref.make_value( storage() );
487  
    return result;
487  
    return result;
488  
}
488  
}
489  

489  

490  
value*
490  
value*
491  
value::set_at_pointer(
491  
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  
{
497  
    system::error_code jec;
497  
    system::error_code jec;
498  
    value* result = set_at_pointer( sv, ref, jec, opts );
498  
    value* result = set_at_pointer( sv, ref, jec, opts );
499  
    ec = jec;
499  
    ec = jec;
500  
    return result;
500  
    return result;
501  
}
501  
}
502  

502  

503  
system::result<value&>
503  
system::result<value&>
504  
value::try_set_at_pointer(
504  
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  
{
509  
    system::error_code ec;
509  
    system::error_code ec;
510  
    value* result = set_at_pointer( sv, ref, ec, opts );
510  
    value* result = set_at_pointer( sv, ref, ec, opts );
511  
    if( result )
511  
    if( result )
512  
        return *result;
512  
        return *result;
513  
    return ec;
513  
    return ec;
514  
}
514  
}
515  

515  

516  
value&
516  
value&
517  
value::set_at_pointer(
517  
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  
{
520  
    return try_set_at_pointer(sv, ref, opts).value();
520  
    return try_set_at_pointer(sv, ref, opts).value();
521  
}
521  
}
522  

522  

 
523 +
bool
 
524 +
value::erase_at_pointer(
 
525 +
    string_view         sv,
 
526 +
    system::error_code& ec)
 
527 +
{
 
528 +
    ec.clear();
 
529 +
    if(sv.empty()){
 
530 +
        BOOST_JSON_FAIL(ec, error::syntax);
 
531 +
        return false;
 
532 +
    }
 
533 +

 
534 +
    string_view previous_segment;
 
535 +

 
536 +
    string_view segment = detail::next_segment(sv, ec);
 
537 +

 
538 +
    auto result = this;
 
539 +
    auto previous_result = this;
 
540 +

 
541 +
    while (true)
 
542 +
    {
 
543 +
        if (ec.failed())
 
544 +
            return false;
 
545 +

 
546 +
        if (!result)
 
547 +
        {
 
548 +
            BOOST_JSON_FAIL(ec, error::not_found);
 
549 +
            return false;
 
550 +
        }
 
551 +

 
552 +
        if( segment.empty() )
 
553 +
            break;
 
554 +

 
555 +
        previous_segment = segment;
 
556 +
        previous_result = result;
 
557 +

 
558 +
        switch (result->kind())
 
559 +
        {
 
560 +
            case boost::json::kind::object: {
 
561 +
                auto& obj = result->get_object();
 
562 +

 
563 +
                detail::pointer_token const token(segment);
 
564 +
                segment = detail::next_segment(sv, ec);
 
565 +
                if (ec.failed())
 
566 +
                    return false;
 
567 +
                
 
568 +
                result = detail::if_contains_token(obj, token);
 
569 +
                if( !result )
 
570 +
                {
 
571 +
                    BOOST_JSON_FAIL(ec, error::not_found);
 
572 +
                    return false;
 
573 +
                }
 
574 +
                break;
 
575 +
            }
 
576 +
            case boost::json::kind::array: {
 
577 +
                auto const index = detail::parse_number_token(segment, ec);
 
578 +
                segment          = detail::next_segment(sv, ec);
 
579 +
                if (ec.failed())
 
580 +
                    return false;
 
581 +
                
 
582 +
                auto& arr = result->get_array();
 
583 +
                result    = arr.if_contains(index);
 
584 +
                if( !result )
 
585 +
                {
 
586 +
                    BOOST_JSON_FAIL(ec, error::past_the_end);
 
587 +
                    return false;
 
588 +
                }
 
589 +
                break;
 
590 +
            }
 
591 +
            default: {
 
592 +
                BOOST_JSON_FAIL(ec, error::value_is_scalar);
 
593 +
                return false;
 
594 +
            }
 
595 +
        }
 
596 +
    }
 
597 +

 
598 +
    switch (previous_result->kind())
 
599 +
    {
 
600 +
        case boost::json::kind::object: {
 
601 +
            auto& obj = previous_result->get_object();
 
602 +
            detail::pointer_token const token(previous_segment);
 
603 +
            key_value_pair* kv = detail::find_in_object(obj, token).first;
 
604 +
            if (kv) {
 
605 +
                obj.erase(kv);
 
606 +
                return true;
 
607 +
            }
 
608 +
            return false;
 
609 +
        }
 
610 +
        case boost::json::kind::array: {
 
611 +
            auto const index = detail::parse_number_token(previous_segment, ec);
 
612 +
            auto& arr = previous_result->get_array();
 
613 +
            if (arr.if_contains(index)){
 
614 +
                arr.erase(arr.begin() + index);
 
615 +
                return true;
 
616 +
            }
 
617 +
            return false;
 
618 +
        }
 
619 +
        default: {
 
620 +
            BOOST_JSON_FAIL(ec, error::value_is_scalar);
 
621 +
            return false;
 
622 +
        }
 
623 +
    }
 
624 +
}
 
625 +

 
626 +

523  
} // namespace json
627  
} // namespace json
524  
} // namespace boost
628  
} // namespace boost
525  

629  

526  
#endif // BOOST_JSON_IMPL_POINTER_IPP
630  
#endif // BOOST_JSON_IMPL_POINTER_IPP