Line data Source code
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 2001563 : ~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 53 : parser() noexcept
161 53 : : parser({}, {})
162 : {
163 53 : }
164 :
165 : /** Overload
166 :
167 : @param sp The memory resource to use for temporary storage.
168 : */
169 : explicit
170 1 : parser(storage_ptr sp) noexcept
171 1 : : parser(std::move(sp), {})
172 : {
173 1 : }
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 2001506 : parser(
208 : storage_ptr sp,
209 : parse_options const& opt,
210 : unsigned char(&buffer)[N]) noexcept
211 2001506 : : parser(std::move(sp),
212 2001506 : opt, &buffer[0], N)
213 : {
214 2001506 : }
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 : {
232 : }
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 2 : write_some(
384 : string_view s,
385 : system::error_code& ec)
386 : {
387 2 : return write_some(
388 2 : s.data(), s.size(), ec);
389 : }
390 :
391 : /** Overload
392 :
393 : @param s
394 : @param ec
395 : */
396 : std::size_t
397 2 : write_some(
398 : string_view s,
399 : std::error_code& ec)
400 : {
401 2 : return write_some(
402 2 : s.data(), s.size(), ec);
403 : }
404 :
405 : /** Overload
406 :
407 : @param s
408 : */
409 : std::size_t
410 4 : write_some(
411 : string_view s)
412 : {
413 4 : return write_some(
414 2 : s.data(), s.size());
415 : }
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 2001508 : write(
485 : string_view s,
486 : system::error_code& ec)
487 : {
488 2001508 : return write(
489 2001507 : s.data(), s.size(), ec);
490 : }
491 :
492 : /** Overload
493 :
494 : @param s
495 : @param ec
496 : */
497 : std::size_t
498 3 : write(
499 : string_view s,
500 : std::error_code& ec)
501 : {
502 3 : return write(
503 3 : s.data(), s.size(), ec);
504 : }
505 :
506 : /** Overload
507 :
508 : @param s
509 : */
510 : std::size_t
511 8 : write(
512 : string_view s)
513 : {
514 8 : return write(
515 4 : s.data(), s.size());
516 : }
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
|