value_stack.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  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_VALUE_STACK_HPP
  10. #define BOOST_JSON_VALUE_STACK_HPP
  11. #include <boost/json/detail/config.hpp>
  12. #include <boost/json/error.hpp>
  13. #include <boost/json/storage_ptr.hpp>
  14. #include <boost/json/value.hpp>
  15. #include <stddef.h>
  16. namespace boost {
  17. namespace json {
  18. //----------------------------------------------------------
  19. /** A stack of @ref value elements, for building a document.
  20. This stack of @ref value allows iterative
  21. construction of a JSON document in memory.
  22. The implementation uses temporary internal
  23. storage to buffer elements so that arrays, objects,
  24. and strings in the document are constructed using a
  25. single memory allocation. This improves performance
  26. and makes efficient use of the @ref memory_resource
  27. used to create the resulting @ref value.
  28. Temporary storage used by the implementation
  29. initially comes from an optional memory buffer
  30. owned by the caller. If that storage is exhausted,
  31. then memory is obtained dynamically from the
  32. @ref memory_resource provided on construction.
  33. @par Usage
  34. Construct the stack with an optional initial
  35. temporary buffer, and a @ref storage_ptr to use for
  36. more storage when the initial buffer is exhausted.
  37. Then to build a @ref value, first call @ref reset
  38. and optionally specify the @ref memory_resource
  39. which will be used for the value. Then push elements
  40. onto the stack by calling the corresponding functions.
  41. After the document has been fully created, call
  42. @ref release to acquire ownership of the top-level
  43. @ref value.
  44. @par Performance
  45. The initial buffer and any dynamically allocated
  46. temporary buffers are retained until the stack
  47. is destroyed. This improves performance when using
  48. a single stack instance to produce multiple
  49. values.
  50. @par Example
  51. The following code constructs a @ref value which
  52. when serialized produces a JSON object with three
  53. elements. It uses a local buffer for the temporary
  54. storage, and a separate local buffer for the storage
  55. of the resulting value. No memory is dynamically
  56. allocated; this shows how to construct a value
  57. without using the heap.
  58. @code
  59. // This example builds a json::value without any dynamic memory allocations:
  60. // Construct the value stack using a local buffer
  61. unsigned char temp[4096];
  62. value_stack st( storage_ptr(), temp, sizeof(temp) );
  63. // Create a static resource with a local initial buffer
  64. unsigned char buf[4096];
  65. static_resource mr( buf, sizeof(buf) );
  66. // All values on the stack will use `mr`
  67. st.reset(&mr);
  68. // Push the key/value pair "a":1.
  69. st.push_key("a");
  70. st.push_int64(1);
  71. // Push "b":null
  72. st.push_key("b");
  73. st.push_null();
  74. // Push "c":"hello"
  75. st.push_key("c");
  76. st.push_string("hello");
  77. // Pop the three key/value pairs and push an object with those three values.
  78. st.push_object(3);
  79. // Pop the object from the stack and take ownership.
  80. value jv = st.release();
  81. assert( serialize(jv) == "{\"a\":1,\"b\":null,\"c\":\"hello\"}" );
  82. // At this point we could re-use the stack by calling reset
  83. @endcode
  84. @par Thread Safety
  85. Distinct instances may be accessed concurrently.
  86. Non-const member functions of a shared instance
  87. may not be called concurrently with any other
  88. member functions of that instance.
  89. */
  90. class value_stack
  91. {
  92. class stack
  93. {
  94. enum
  95. {
  96. min_size_ = 16
  97. };
  98. storage_ptr sp_;
  99. void* temp_;
  100. value* begin_;
  101. value* top_;
  102. value* end_;
  103. // string starts at top_+1
  104. std::size_t chars_ = 0;
  105. bool run_dtors_ = true;
  106. public:
  107. inline ~stack();
  108. inline stack(
  109. storage_ptr sp,
  110. void* temp, std::size_t size) noexcept;
  111. inline void run_dtors(bool b) noexcept;
  112. inline std::size_t size() const noexcept;
  113. inline bool has_chars();
  114. inline void clear() noexcept;
  115. inline void maybe_grow();
  116. inline void grow_one();
  117. inline void grow(std::size_t nchars);
  118. inline void append(string_view s);
  119. inline string_view release_string() noexcept;
  120. inline value* release(std::size_t n) noexcept;
  121. template<class... Args> value& push(Args&&... args);
  122. template<class Unchecked> void exchange(Unchecked&& u);
  123. };
  124. stack st_;
  125. storage_ptr sp_;
  126. public:
  127. /// Copy constructor (deleted)
  128. value_stack(
  129. value_stack const&) = delete;
  130. /// Copy assignment (deleted)
  131. value_stack& operator=(
  132. value_stack const&) = delete;
  133. /** Destructor.
  134. All dynamically allocated memory and
  135. partial or complete elements is freed.
  136. @par Complexity
  137. Linear in the size of partial results.
  138. @par Exception Safety
  139. No-throw guarantee.
  140. */
  141. BOOST_JSON_DECL
  142. ~value_stack();
  143. /** Constructor.
  144. Constructs an empty stack. Before any
  145. @ref value can be built, the function
  146. @ref reset must be called.
  147. The `sp` parameter is only used to allocate
  148. intermediate storage; it will not be used
  149. for the @ref value returned by @ref release.
  150. @param sp A pointer to the @ref memory_resource
  151. to use for intermediate storage allocations. If
  152. this argument is omitted, the default memory
  153. resource is used.
  154. @param temp_buffer A pointer to a caller-owned
  155. buffer which will be used to store temporary
  156. data used while building the value. If this
  157. pointer is null, the builder will use the
  158. storage pointer to allocate temporary data.
  159. @param temp_size The number of valid bytes of
  160. storage pointed to by `temp_buffer`.
  161. */
  162. BOOST_JSON_DECL
  163. value_stack(
  164. storage_ptr sp = {},
  165. unsigned char* temp_buffer = nullptr,
  166. std::size_t temp_size = 0) noexcept;
  167. /** Prepare to build a new document.
  168. This function must be called before constructing
  169. a new top-level @ref value. Any previously existing
  170. partial or complete elements are destroyed, but
  171. internal dynamically allocated memory is preserved
  172. which may be reused to build new values.
  173. @par Exception Safety
  174. No-throw guarantee.
  175. @param sp A pointer to the @ref memory_resource
  176. to use for top-level @ref value and all child
  177. values. The stack will acquire shared ownership
  178. of the memory resource until @ref release or
  179. @ref reset is called, or when the stack is
  180. destroyed.
  181. */
  182. BOOST_JSON_DECL
  183. void
  184. reset(storage_ptr sp = {}) noexcept;
  185. /** Return the top-level @ref value.
  186. This function transfers ownership of the
  187. constructed top-level value to the caller.
  188. The behavior is undefined if there is not
  189. a single, top-level element.
  190. @par Exception Safety
  191. No-throw guarantee.
  192. @return A __value__ holding the result.
  193. Ownership of this value is transferred
  194. to the caller. Ownership of the memory
  195. resource used in the last call to @ref reset
  196. is released.
  197. */
  198. BOOST_JSON_DECL
  199. value
  200. release() noexcept;
  201. //--------------------------------------------
  202. /** Push an array formed by popping `n` values from the stack.
  203. This function pushes an @ref array value
  204. onto the stack. The array is formed by first
  205. popping the top `n` values from the stack.
  206. If the stack contains fewer than `n` values,
  207. or if any of the top `n` values on the stack
  208. is a key, the behavior is undefined.
  209. @par Example
  210. The following statements produce an array
  211. with the contents 1, 2, 3:
  212. @code
  213. value_stack st;
  214. // reset must be called first or else the behavior is undefined
  215. st.reset();
  216. // Place three values on the stack
  217. st.push_int64( 1 );
  218. st.push_int64( 2 );
  219. st.push_int64( 3 );
  220. // Remove the 3 values, and push an array with those 3 elements on the stack
  221. st.push_array( 3 );
  222. // Pop the object from the stack and take ownership.
  223. value jv = st.release();
  224. assert( serialize(jv) == "[1,2,3]" );
  225. // At this point, reset must be called again to use the stack
  226. @endcode
  227. @param n The number of values to pop from the
  228. top of the stack to form the array.
  229. */
  230. BOOST_JSON_DECL
  231. void
  232. push_array(std::size_t n);
  233. /** Push an object formed by popping `n` key/value pairs from the stack.
  234. This function pushes an @ref object value
  235. onto the stack. The object is formed by first
  236. popping the top `n` key/value pairs from the
  237. stack. If the stack contains fewer than `n`
  238. key/value pairs, or if any of the top `n` key/value
  239. pairs on the stack does not consist of exactly one
  240. key followed by one value, the behavior is undefined.
  241. @note
  242. A key/value pair is formed by pushing a key, and then
  243. pushing a value.
  244. @par Example
  245. The following code creates an object on the stack
  246. with a single element, where key is "x" and value
  247. is true:
  248. @code
  249. value_stack st;
  250. // reset must be called first or else the behavior is undefined
  251. st.reset();
  252. // Place a key/value pair onto the stack
  253. st.push_key( "x" );
  254. st.push_bool( true );
  255. // Replace the key/value pair with an object containing a single element
  256. st.push_object( 1 );
  257. // Pop the object from the stack and take ownership.
  258. value jv = st.release();
  259. assert( serialize(jv) == "{\"x\",true}" );
  260. // At this point, reset must be called again to use the stack
  261. @endcode
  262. @par Duplicate Keys
  263. If there are object elements with duplicate keys;
  264. that is, if multiple elements in an object have
  265. keys that compare equal, only the last equivalent
  266. element will be inserted.
  267. @param n The number of key/value pairs to pop from the
  268. top of the stack to form the array.
  269. */
  270. BOOST_JSON_DECL
  271. void
  272. push_object(std::size_t n);
  273. /** Push part of a key or string onto the stack.
  274. This function pushes the characters in `s` onto
  275. the stack, appending to any existing characters
  276. or creating new characters as needed. Once a
  277. string part is placed onto the stack, the only
  278. valid stack operations are:
  279. @li @ref push_chars to append additional
  280. characters to the key or string being built,
  281. @li @ref push_key or @ref push_string to
  282. finish building the key or string and place
  283. the value onto the stack.
  284. @par Exception Safety
  285. Basic guarantee.
  286. Calls to `memory_resource::allocate` may throw.
  287. @param s The characters to append. This may be empty.
  288. */
  289. BOOST_JSON_DECL
  290. void
  291. push_chars(
  292. string_view s);
  293. /** Push a key onto the stack.
  294. This function notionally removes all the
  295. characters currently on the stack, then
  296. pushes a @ref value containing a key onto
  297. the stack formed by appending `s` to the
  298. removed characters.
  299. @par Exception Safety
  300. Basic guarantee.
  301. Calls to `memory_resource::allocate` may throw.
  302. @param s The characters to append. This may be empty.
  303. */
  304. BOOST_JSON_DECL
  305. void
  306. push_key(
  307. string_view s);
  308. /** Place a string value onto the stack.
  309. This function notionally removes all the
  310. characters currently on the stack, then
  311. pushes a @ref value containing a @ref string
  312. onto the stack formed by appending `s` to the
  313. removed characters.
  314. @par Exception Safety
  315. Basic guarantee.
  316. Calls to `memory_resource::allocate` may throw.
  317. @param s The characters to append. This may be empty.
  318. */
  319. BOOST_JSON_DECL
  320. void
  321. push_string(
  322. string_view s);
  323. /** Push a number onto the stack
  324. This function pushes a number value onto the stack.
  325. @par Exception Safety
  326. Basic guarantee.
  327. Calls to `memory_resource::allocate` may throw.
  328. @param i The number to insert.
  329. */
  330. BOOST_JSON_DECL
  331. void
  332. push_int64(
  333. int64_t i);
  334. /** Push a number onto the stack
  335. This function pushes a number value onto the stack.
  336. @par Exception Safety
  337. Basic guarantee.
  338. Calls to `memory_resource::allocate` may throw.
  339. @param u The number to insert.
  340. */
  341. BOOST_JSON_DECL
  342. void
  343. push_uint64(
  344. uint64_t u);
  345. /** Push a number onto the stack
  346. This function pushes a number value onto the stack.
  347. @par Exception Safety
  348. Basic guarantee.
  349. Calls to `memory_resource::allocate` may throw.
  350. @param d The number to insert.
  351. */
  352. BOOST_JSON_DECL
  353. void
  354. push_double(
  355. double d);
  356. /** Push a `bool` onto the stack
  357. This function pushes a boolean value onto the stack.
  358. @par Exception Safety
  359. Basic guarantee.
  360. Calls to `memory_resource::allocate` may throw.
  361. @param b The boolean to insert.
  362. */
  363. BOOST_JSON_DECL
  364. void
  365. push_bool(
  366. bool b);
  367. /** Push a null onto the stack
  368. This function pushes a boolean value onto the stack.
  369. @par Exception Safety
  370. Basic guarantee.
  371. Calls to `memory_resource::allocate` may throw.
  372. */
  373. BOOST_JSON_DECL
  374. void
  375. push_null();
  376. };
  377. } // namespace json
  378. } // namespace boost
  379. #endif