Coverage Report

Created: 2026-06-21 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boost/boost/json/parser.hpp
Line
Count
Source
1
//
2
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3
//
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)
6
//
7
// Official repository: https://github.com/boostorg/json
8
//
9
10
#ifndef BOOST_JSON_PARSER_HPP
11
#define BOOST_JSON_PARSER_HPP
12
13
#include <boost/json/detail/config.hpp>
14
#include <boost/json/basic_parser.hpp>
15
#include <boost/json/storage_ptr.hpp>
16
#include <boost/json/value.hpp>
17
#include <boost/json/detail/handler.hpp>
18
#include <type_traits>
19
#include <cstddef>
20
21
namespace boost {
22
namespace json {
23
24
//----------------------------------------------------------
25
26
/** A DOM parser for JSON contained in a single buffer.
27
28
    This class is used to parse a JSON text contained in a single character
29
    buffer, into a @ref value container.
30
31
    @par Usage
32
    To use the parser first construct it, then optionally call @ref reset to
33
    specify a @ref storage_ptr to use for the resulting @ref value. Then call
34
    @ref write to parse a character buffer containing a complete JSON text. If
35
    the parse is successful, call @ref release to take ownership of the value:
36
    @code
37
    parser p;                                       // construct a parser
38
    size_t n = p.write( "[1,2,3]" );                // parse a complete JSON text
39
    assert( n == 7 );                               // all characters consumed
40
    value jv = p.release();                         // take ownership of the value
41
    @endcode
42
43
    @par Extra Data
44
    When the character buffer provided as input contains additional data that
45
    is not part of the complete JSON text, an error is returned. The @ref
46
    write_some function is an alternative which allows the parse to finish
47
    early, without consuming all the characters in the buffer. This allows
48
    parsing of a buffer containing multiple individual JSON texts or containing
49
    different protocol data:
50
    @code
51
    parser p;                                       // construct a parser
52
    size_t n = p.write_some( "[1,2,3] null" );      // parse a complete JSON text
53
    assert( n == 8 );                               // only some characters consumed
54
    value jv = p.release();                         // take ownership of the value
55
    @endcode
56
57
    @par Temporary Storage
58
    The parser may dynamically allocate temporary storage as needed to
59
    accommodate the nesting level of the JSON text being parsed. Temporary
60
    storage is first obtained from an optional, caller-owned buffer specified
61
    upon construction. When that is exhausted, the next allocation uses the
62
    @ref boost::container::pmr::memory_resource passed to the constructor; if
63
    no such argument is specified, the default memory resource is used.
64
    Temporary storage is freed only when the parser is destroyed; The
65
    performance of parsing multiple JSON texts may be improved by reusing the
66
    same parser instance.
67
68
    It is important to note that the `boost::container::pmr::memory_resource`
69
    supplied upon construction is used for temporary storage only, and not for
70
    allocating the elements which make up the parsed value. That other memory
71
    resource is optionally supplied in each call to @ref reset.
72
73
    @par Duplicate Keys
74
    If there are object elements with duplicate keys; that is, if multiple
75
    elements in an object have keys that compare equal, only the last
76
    equivalent element will be inserted.
77
78
    @par Non-Standard JSON
79
    The @ref parse_options structure optionally provided upon construction is
80
    used to customize some parameters of the parser, including which
81
    non-standard JSON extensions should be allowed. A default-constructed parse
82
    options allows only standard JSON.
83
84
    @par Thread Safety
85
    Distinct instances may be accessed concurrently. Non-const member functions
86
    of a shared instance may not be called concurrently with any other member
87
    functions of that instance.
88
89
    @see @ref parse, @ref stream_parser.
90
*/
91
class parser
92
{
93
    basic_parser<detail::handler> p_;
94
95
public:
96
    /** Assignment operator.
97
98
        This type is neither copyable nor movable. The operator is deleted.
99
    */
100
    parser& operator=(
101
        parser const&) = delete;
102
103
    /** Destructor.
104
105
        All dynamically allocated memory, including
106
        any incomplete parsing results, is freed.
107
108
        @par Complexity
109
        Linear in the size of partial results.
110
111
        @par Exception Safety
112
        No-throw guarantee.
113
    */
114
6.79k
    ~parser() = default;
115
116
    /** Constructors.
117
118
        Construct a new parser.
119
120
        The parser will only support standard JSON if overloads **(1)**
121
        or **(2)** are used. Otherwise the parser will support extensions
122
        specified by the parameter `opt`.
123
124
        The parsed value will use the \<\<default_memory_resource,default
125
        memory resource\>\> for storage. To use a different resource, call @ref
126
        reset after construction.
127
128
        The main difference between the overloads is in what the constructed
129
        parser will use for temporary storage:
130
131
        @li **(1)** the constructed parser uses the default memory resource for
132
        temporary storage.
133
134
        @li **(2)**, **(3)** the constructed parser uses the memory resource of
135
        `sp` for temporary storage.
136
137
        @li **(4)**, **(6)** the constructed parser first uses the caller-owned
138
        storage `[buffer, buffer + size)` for temporary storage, falling back
139
        to the memory resource of `sp` if needed.
140
141
        @li **(5)**, **(7)** the constructed parser first uses the caller-owned
142
        storage `[buffer, buffer + N)` for temporary storage, falling back to
143
        the memory resource of `sp` if needed.
144
145
        @note Ownership of `buffer` is not transferred. The caller is
146
        responsible for ensuring the lifetime of the storage pointed to by
147
        `buffer` extends until the parser is destroyed.
148
149
        Overload **(8)** is the copy constructor. The type is neither copyable
150
        nor movable, so the overload is deleted.
151
152
        @par Complexity
153
        Constant.
154
155
        @par Exception Safety
156
        No-throw guarantee.
157
158
        @{
159
    */
160
    parser() noexcept
161
        : parser({}, {})
162
0
    {
163
0
    }
164
165
    /** Overload
166
167
        @param sp The memory resource to use for temporary storage.
168
    */
169
    explicit
170
    parser(storage_ptr sp) noexcept
171
        : parser(std::move(sp), {})
172
0
    {
173
0
    }
174
175
    /** Overload
176
177
        @param opt The parsing options to use.
178
        @param sp
179
    */
180
    BOOST_JSON_DECL
181
    parser(
182
        storage_ptr sp,
183
        parse_options const& opt) noexcept;
184
185
    /** Overload
186
187
        @param buffer A pointer to valid storage.
188
        @param size The number of valid bytes in `buffer`.
189
        @param sp
190
        @param opt
191
    */
192
    BOOST_JSON_DECL
193
    parser(
194
        storage_ptr sp,
195
        parse_options const& opt,
196
        unsigned char* buffer,
197
        std::size_t size) noexcept;
198
199
    /** Overload
200
201
        @tparam N The number of valid bytes in `buffer`.
202
        @param sp
203
        @param opt
204
        @param buffer
205
    */
206
    template<std::size_t N>
207
    parser(
208
        storage_ptr sp,
209
        parse_options const& opt,
210
        unsigned char(&buffer)[N]) noexcept
211
6.79k
        : parser(std::move(sp),
212
6.79k
            opt, &buffer[0], N)
213
6.79k
    {
214
6.79k
    }
215
216
#if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS)
217
    /** Overload
218
219
        @param buffer
220
        @param size
221
        @param sp
222
        @param opt
223
    */
224
    parser(
225
        storage_ptr sp,
226
        parse_options const& opt,
227
        std::byte* buffer,
228
        std::size_t size) noexcept
229
        : parser(sp, opt, reinterpret_cast<
230
            unsigned char*>(buffer), size)
231
0
    {
232
0
    }
233
234
    /** Overload
235
236
        @tparam N
237
        @param sp
238
        @param opt
239
        @param buffer
240
    */
241
    template<std::size_t N>
242
    parser(
243
        storage_ptr sp,
244
        parse_options const& opt,
245
        std::byte(&buffer)[N]) noexcept
246
        : parser(std::move(sp),
247
            opt, &buffer[0], N)
248
    {
249
    }
250
#endif
251
252
#ifndef BOOST_JSON_DOCS
253
    // Safety net for accidental buffer overflows
254
    template<std::size_t N>
255
    parser(
256
        storage_ptr sp,
257
        parse_options const& opt,
258
        unsigned char(&buffer)[N],
259
        std::size_t n) noexcept
260
        : parser(std::move(sp),
261
            opt, &buffer[0], n)
262
    {
263
        // If this goes off, check your parameters
264
        // closely, chances are you passed an array
265
        // thinking it was a pointer.
266
        BOOST_ASSERT(n <= N);
267
    }
268
269
#ifdef __cpp_lib_byte
270
    // Safety net for accidental buffer overflows
271
    template<std::size_t N>
272
    parser(
273
        storage_ptr sp,
274
        parse_options const& opt,
275
        std::byte(&buffer)[N], std::size_t n) noexcept
276
        : parser(std::move(sp),
277
            opt, &buffer[0], n)
278
    {
279
        // If this goes off, check your parameters
280
        // closely, chances are you passed an array
281
        // thinking it was a pointer.
282
        BOOST_ASSERT(n <= N);
283
    }
284
#endif
285
#endif
286
287
    /// Overload
288
    parser(
289
        parser const&) = delete;
290
    /// @}
291
292
293
    /** Reset the parser for a new JSON text.
294
295
        This function is used to reset the parser to
296
        prepare it for parsing a new complete JSON text.
297
        Any previous partial results are destroyed.
298
299
        @par Complexity
300
        Constant or linear in the size of any previous
301
        partial parsing results.
302
303
        @par Exception Safety
304
        No-throw guarantee.
305
306
        @param sp A pointer to the @ref boost::container::pmr::memory_resource
307
        to use for the resulting @ref value. The parser will acquire shared
308
        ownership.
309
    */
310
    BOOST_JSON_DECL
311
    void
312
    reset(storage_ptr sp = {}) noexcept;
313
314
    /** Parse a buffer containing a complete JSON text.
315
316
        This function parses a complete JSON text contained in the specified
317
        character buffer. Additional characters past the end of the complete
318
        JSON text are ignored. The function returns the actual number of
319
        characters parsed, which may be less than the size of the input. This
320
        allows parsing of a buffer containing multiple individual JSON texts or
321
        containing different protocol data:
322
323
        @par Example
324
        @code
325
        parser p;                                       // construct a parser
326
        size_t n = p.write_some( "[1,2,3] null" );      // parse a complete JSON text
327
        assert( n == 8 );                               // only some characters consumed
328
        value jv = p.release();                         // take ownership of the value
329
        @endcode
330
331
        Overloads **(1)**, **(2)**, **(4)**, and **(5)** report errors by
332
        setting `ec`. Overloads **(3)** and **(6)** report errors by throwing
333
        exceptions.
334
335
        @par Complexity
336
        @li **(1)**--**(3)** linear in `size`.
337
        @li **(4)**--**(6)** linear in `s.size()`.
338
339
        @par Exception Safety
340
        Basic guarantee. Calls to `memory_resource::allocate` may throw. Upon
341
        error or exception, subsequent calls will fail until @ref reset is
342
        called to parse a new JSON text.
343
344
        @return The number of characters consumed from the buffer.
345
346
        @param data A pointer to a buffer of `size` characters to parse.
347
        @param size The number of characters pointed to by `data`.
348
        @param ec Set to the error, if any occurred.
349
350
        @{
351
    */
352
    BOOST_JSON_DECL
353
    std::size_t
354
    write_some(
355
        char const* data,
356
        std::size_t size,
357
        system::error_code& ec);
358
359
    BOOST_JSON_DECL
360
    std::size_t
361
    write_some(
362
        char const* data,
363
        std::size_t size,
364
        std::error_code& ec);
365
366
    /** Overload
367
368
        @param data
369
        @param size
370
    */
371
    BOOST_JSON_DECL
372
    std::size_t
373
    write_some(
374
        char const* data,
375
        std::size_t size);
376
377
    /** Overload
378
379
        @param s The character string to parse.
380
        @param ec
381
    */
382
    std::size_t
383
    write_some(
384
        string_view s,
385
        system::error_code& ec)
386
0
    {
387
0
        return write_some(
388
0
            s.data(), s.size(), ec);
389
0
    }
390
391
    /** Overload
392
393
        @param s
394
        @param ec
395
    */
396
    std::size_t
397
    write_some(
398
        string_view s,
399
        std::error_code& ec)
400
0
    {
401
0
        return write_some(
402
0
            s.data(), s.size(), ec);
403
0
    }
404
405
    /** Overload
406
407
        @param s
408
    */
409
    std::size_t
410
    write_some(
411
        string_view s)
412
0
    {
413
0
        return write_some(
414
0
            s.data(), s.size());
415
0
    }
416
    /// @}
417
418
    /** Parse a buffer containing a complete JSON text.
419
420
        This function parses a complete JSON text contained in the specified
421
        character buffer. The entire buffer must be consumed; if there are
422
        additional characters past the end of the complete JSON text, the parse
423
        fails and an error is returned.
424
425
        @par Example
426
        @code
427
        parser p;                                       // construct a parser
428
        size_t n = p.write( "[1,2,3]" );                // parse a complete JSON text
429
        assert( n == 7 );                               // all characters consumed
430
        value jv = p.release();                         // take ownership of the value
431
        @endcode
432
433
        Overloads **(1)**, **(2)**, **(4)**, and **(5)** report errors by
434
        setting `ec`. Overloads **(3)** and **(6)** report errors by throwing
435
        exceptions.
436
437
        @par Complexity
438
        @li **(1)**--**(3)** linear in `size`.
439
        @li **(4)**--**(6)** linear in `s.size()`.
440
441
        @par Exception Safety
442
        Basic guarantee. Calls to `memory_resource::allocate` may throw. Upon
443
        error or exception, subsequent calls will fail until @ref reset is
444
        called to parse a new JSON text.
445
446
        @return The number of characters consumed from the buffer.
447
448
        @param data A pointer to a buffer of `size` characters to parse.
449
        @param size The number of characters pointed to by `data`.
450
        @param ec Set to the error, if any occurred.
451
452
        @{
453
    */
454
    BOOST_JSON_DECL
455
    std::size_t
456
    write(
457
        char const* data,
458
        std::size_t size,
459
        system::error_code& ec);
460
461
    BOOST_JSON_DECL
462
    std::size_t
463
    write(
464
        char const* data,
465
        std::size_t size,
466
        std::error_code& ec);
467
468
    /** Overload
469
470
        @throw `boost::system::system_error` Thrown on error.
471
    */
472
    BOOST_JSON_DECL
473
    std::size_t
474
    write(
475
        char const* data,
476
        std::size_t size);
477
478
    /** Overload
479
480
        @param s The character string to parse.
481
        @param ec
482
    */
483
    std::size_t
484
    write(
485
        string_view s,
486
        system::error_code& ec)
487
6.79k
    {
488
6.79k
        return write(
489
6.79k
            s.data(), s.size(), ec);
490
6.79k
    }
491
492
    /** Overload
493
494
        @param s
495
        @param ec
496
    */
497
    std::size_t
498
    write(
499
        string_view s,
500
        std::error_code& ec)
501
0
    {
502
0
        return write(
503
0
            s.data(), s.size(), ec);
504
0
    }
505
506
    /** Overload
507
508
        @param s
509
    */
510
    std::size_t
511
    write(
512
        string_view s)
513
0
    {
514
0
        return write(
515
0
            s.data(), s.size());
516
0
    }
517
    /// @}
518
519
    /** Return the parsed JSON text as a @ref value.
520
521
        This returns the parsed value, or throws an exception if the parsing is
522
        incomplete or failed. It is necessary to call @ref reset after calling
523
        this function in order to parse another JSON text.
524
525
        @par Complexity
526
        Constant.
527
528
        @return The parsed value. Ownership of this value is transferred to the
529
        caller.
530
531
        @throw boost::system::system_error A complete JSON text hasn't been
532
               parsed, or parsing failed.
533
    */
534
    BOOST_JSON_DECL
535
    value
536
    release();
537
};
538
539
} // namespace json
540
} // namespace boost
541
542
#endif