parser.hpp 15 KB

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