value_stack.hpp 14 KB

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