value_stack.hpp 14 KB

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