| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 |
- //
- // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- // Official repository: https://github.com/boostorg/json
- //
- #ifndef BOOST_JSON_VALUE_STACK_HPP
- #define BOOST_JSON_VALUE_STACK_HPP
- #include <boost/json/detail/config.hpp>
- #include <boost/json/error.hpp>
- #include <boost/json/storage_ptr.hpp>
- #include <boost/json/value.hpp>
- #include <stddef.h>
- namespace boost {
- namespace json {
- //----------------------------------------------------------
- /** A stack of @ref value elements, for building a document.
- This stack of @ref value allows iterative construction of a JSON document
- in memory. The implementation uses temporary internal storage to buffer
- elements so that arrays, objects, and strings in the document are
- constructed using a single memory allocation. This improves performance and
- makes efficient use of the @ref boost::container::pmr::memory_resource used
- to create the resulting @ref value.
- Temporary storage used by the implementation initially comes from an
- optional memory buffer owned by the caller. If that storage is exhausted,
- then memory is obtained dynamically from the
- `boost::container::pmr::memory_resource` provided on construction.
- @par Usage
- Construct the stack with an optional initial temporary buffer, and a @ref
- storage_ptr to use for more storage when the initial buffer is exhausted.
- Then to build a @ref value, first call @ref reset and optionally specify
- the `boost::container::pmr::memory_resource` which will be used for the
- value. Then push elements onto the stack by calling the corresponding
- functions. After the document has been fully created, call @ref release to
- acquire ownership of the top-level @ref value.
- @par Performance
- The initial buffer and any dynamically allocated temporary buffers are
- retained until the stack is destroyed. This improves performance when using
- a single stack instance to produce multiple values.
- @par Example
- The following code constructs a @ref value which when serialized produces
- a JSON object with three elements. It uses a local buffer for the temporary
- storage, and a separate local buffer for the storage of the resulting
- value. No memory is dynamically allocated; this shows how to construct
- a value without using the heap.
- @code
- // This example builds a json::value without any dynamic memory allocations:
- // Construct the value stack using a local buffer
- unsigned char temp[4096];
- value_stack st( storage_ptr(), temp, sizeof(temp) );
- // Create a static resource with a local initial buffer
- unsigned char buf[4096];
- static_resource mr( buf, sizeof(buf) );
- // All values on the stack will use `mr`
- st.reset(&mr);
- // Push the key/value pair "a":1.
- st.push_key("a");
- st.push_int64(1);
- // Push "b":null
- st.push_key("b");
- st.push_null();
- // Push "c":"hello"
- st.push_key("c");
- st.push_string("hello");
- // Pop the three key/value pairs and push an object with those three values.
- st.push_object(3);
- // Pop the object from the stack and take ownership.
- value jv = st.release();
- assert( serialize(jv) == "{\"a\":1,\"b\":null,\"c\":\"hello\"}" );
- // At this point we could re-use the stack by calling reset
- @endcode
- @par Thread Safety
- Distinct instances may be accessed concurrently. Non-const member functions
- of a shared instance may not be called concurrently with any other member
- functions of that instance.
- */
- class value_stack
- {
- class stack
- {
- enum
- {
- min_size_ = 16
- };
- storage_ptr sp_;
- void* temp_;
- value* begin_;
- value* top_;
- value* end_;
- // string starts at top_+1
- std::size_t chars_ = 0;
- bool run_dtors_ = true;
- public:
- inline ~stack();
- inline stack(
- storage_ptr sp,
- void* temp, std::size_t size) noexcept;
- inline void run_dtors(bool b) noexcept;
- inline std::size_t size() const noexcept;
- inline bool has_chars();
- inline void clear() noexcept;
- inline void maybe_grow();
- inline void grow_one();
- inline void grow(std::size_t nchars);
- inline void append(string_view s);
- inline string_view release_string() noexcept;
- inline value* release(std::size_t n) noexcept;
- template<class... Args> value& push(Args&&... args);
- template<class Unchecked> void exchange(Unchecked&& u);
- };
- stack st_;
- storage_ptr sp_;
- public:
- /** Assignment operator.
- This type is neither copyable nor movable.
- */
- value_stack& operator=(
- value_stack const&) = delete;
- /** Destructor.
- All dynamically allocated memory and
- partial or complete elements is freed.
- @par Complexity
- Linear in the size of partial results.
- @par Exception Safety
- No-throw guarantee.
- */
- BOOST_JSON_DECL
- ~value_stack();
- /** Constructors.
- The copy constructor **(2)** is deleted: the type is neither copyable
- nor movable.
- The other overload constructs an empty stack. Before any @ref value can
- be built, the function @ref reset must be called.
- The `sp` parameter is only used to allocate intermediate storage; it
- will not be used for the @ref value returned by @ref release.
- @param sp A pointer to the @ref boost::container::pmr::memory_resource
- to use for intermediate storage allocations. If this argument is
- omitted, the default memory resource is used.
- @param temp_buffer A pointer to a caller-owned buffer which will be
- used to store temporary data used while building the value. If
- this pointer is null, the builder will use the storage pointer
- to allocate temporary data.
- @param temp_size The number of valid bytes of storage pointed to by
- `temp_buffer`.
- @{
- */
- BOOST_JSON_DECL
- value_stack(
- storage_ptr sp = {},
- unsigned char* temp_buffer = nullptr,
- std::size_t temp_size = 0) noexcept;
- /// Overload
- value_stack(
- value_stack const&) = delete;
- /// @}
- /** Prepare to build a new document.
- This function must be called before constructing a new top-level @ref
- value. Any previously existing partial or complete elements are
- destroyed, but internal dynamically allocated memory is preserved which
- may be reused to build new values.
- The stack will acquire shared ownership of the memory resource pointed
- to by `sp` until @ref release or @ref reset is called, or when the
- stack is destroyed.
- @par Exception Safety
- No-throw guarantee.
- @param sp A pointer to the @ref boost::container::pmr::memory_resource
- to use for top-level @ref value and all child values.
- */
- BOOST_JSON_DECL
- void
- reset(storage_ptr sp = {}) noexcept;
- /** Return the top-level @ref value.
- This function transfers ownership of the constructed top-level value to
- the caller. The behavior is undefined if there is not a single,
- top-level element. Ownership of the memory resource used in the last
- call to @ref reset is released.
- @par Exception Safety
- No-throw guarantee.
- @return A `value` holding the result. Ownership of this value is
- transferred to the caller.
- */
- BOOST_JSON_DECL value release() noexcept;
- //--------------------------------------------
- /** Push an array onto the stack.
- This function pushes an @ref array value onto the stack. The array is
- formed by first popping the top `n` values from the stack. If the stack
- contains fewer than `n` values, or if any of the top `n` values on the
- stack is a key, the behavior is undefined.
- @par Example
- The following statements produce an array with the contents 1, 2, 3:
- @code
- value_stack st;
- // reset must be called first or else the behavior is undefined
- st.reset();
- // Place three values on the stack
- st.push_int64( 1 );
- st.push_int64( 2 );
- st.push_int64( 3 );
- // Remove the 3 values, and push an array with those 3 elements on the stack
- st.push_array( 3 );
- // Pop the object from the stack and take ownership.
- value jv = st.release();
- assert( serialize(jv) == "[1,2,3]" );
- // At this point, reset must be called again to use the stack
- @endcode
- @par Exception Safety
- Basic guarantee. Calls to `memory_resource::allocate` may throw.
- @param n The number of values to pop from the top of the stack to form
- the array.
- */
- BOOST_JSON_DECL
- void
- push_array(std::size_t n);
- /** Push an object onto the stack.
- This function pushes an @ref object value onto the stack. The object is
- formed by first popping the top `n` key/value pairs from the stack. If
- the stack contains fewer than `n` key/value pairs, or if any of the top
- `n` key/value pairs on the stack does not consist of exactly one key
- followed by one value, the behavior is undefined.
- @note A key/value pair is formed by pushing a key, and then
- pushing a value.
- @par Example
- The following code creates an object on the stack with a single
- element, where key is "x" and value is true:
- @code
- value_stack st;
- // reset must be called first or else the behavior is undefined
- st.reset();
- // Place a key/value pair onto the stack
- st.push_key( "x" );
- st.push_bool( true );
- // Replace the key/value pair with an object containing a single element
- st.push_object( 1 );
- // Pop the object from the stack and take ownership.
- value jv = st.release();
- assert( serialize(jv) == "{\"x\",true}" );
- // At this point, reset must be called again to use the stack
- @endcode
- @par Duplicate Keys
- If there are object elements with duplicate keys; that is, if multiple
- elements in an object have keys that compare equal, only the last
- equivalent element will be inserted.
- @par Exception Safety
- Basic guarantee. Calls to `memory_resource::allocate` may throw.
- @param n The number of key/value pairs to pop from the top of the stack
- to form the array.
- */
- BOOST_JSON_DECL
- void
- push_object(std::size_t n);
- /** Push a part of a key or a string onto the stack.
- This function pushes the characters in `s` onto the stack, appending to
- any existing characters or creating new characters as needed. Once
- a string part is placed onto the stack, the only valid stack operations
- are:
- @li `push_chars` to append additional characters to the key or string
- being built,
- @li @ref push_key or @ref push_string to finish building the key or
- string and place the value onto the stack.
- @par Exception Safety
- Basic guarantee. Calls to `memory_resource::allocate` may throw.
- @param s The characters to append. This may be empty.
- */
- BOOST_JSON_DECL
- void
- push_chars(
- string_view s);
- /** Push an @ref object key onto the stack.
- This function notionally pops all of the characters currently on top of
- the stack, then pushes a @ref value containing a key onto the stack
- formed by appending `s` to the removed characters.
- @par Exception Safety
- Basic guarantee. Calls to `memory_resource::allocate` may throw.
- @param s The characters to append. This may be empty.
- */
- BOOST_JSON_DECL
- void
- push_key(
- string_view s);
- /** Place a string value onto the stack.
- This function notionally removes all the characters currently on top of
- the stack, then pushes a @ref value containing a @ref string onto the
- stack formed by appending `s` to the removed characters.
- @par Exception Safety
- Basic guarantee. Calls to `memory_resource::allocate` may throw.
- @param s The characters to append. This may be empty.
- */
- BOOST_JSON_DECL
- void
- push_string(
- string_view s);
- /** Push a `std::int64_t` onto the stack.
- This function pushes a number value onto the stack.
- @par Exception Safety
- Basic guarantee. Calls to `memory_resource::allocate` may throw.
- @param i The number to insert.
- */
- BOOST_JSON_DECL
- void
- push_int64(
- std::int64_t i);
- /** Push a `std::uint64_t` onto the stack.
- This function pushes a number value onto the stack.
- @par Exception Safety
- Basic guarantee. Calls to `memory_resource::allocate` may throw.
- @param u The number to insert.
- */
- BOOST_JSON_DECL
- void
- push_uint64(
- std::uint64_t u);
- /** Push a `double` onto the stack.
- This function pushes a number value onto the stack.
- @par Exception Safety
- Basic guarantee. Calls to `memory_resource::allocate` may throw.
- @param d The number to insert.
- */
- BOOST_JSON_DECL
- void
- push_double(
- double d);
- /** Push a `bool` onto the stack.
- This function pushes a boolean value onto the stack.
- @par Exception Safety
- Basic guarantee. Calls to `memory_resource::allocate` may throw.
- @param b The boolean to insert.
- */
- BOOST_JSON_DECL
- void
- push_bool(
- bool b);
- /** Push a null onto the stack.
- This function pushes a null value onto the stack.
- @par Exception Safety
- Basic guarantee. Calls to `memory_resource::allocate` may throw.
- */
- BOOST_JSON_DECL
- void
- push_null();
- };
- } // namespace json
- } // namespace boost
- #endif
|