123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 |
- //
- // Copyright (c) 2019 Vinnie Falco ([email protected])
- //
- // 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 `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:
- /// Copy constructor (deleted)
- value_stack(
- value_stack const&) = delete;
- /// Copy assignment (deleted)
- 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();
- /** Constructor.
- 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 `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;
- /** 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.
- @par Exception Safety
- No-throw guarantee.
- @param sp A pointer to the `boost::container::pmr::memory_resource` to
- use for top-level @ref value and all child values. The stack will
- acquire shared ownership of the memory resource until @ref release or
- @ref reset is called, or when the stack is destroyed.
- */
- 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.
- @par Exception Safety
- No-throw guarantee.
- @return A __value__ holding the result.
- Ownership of this value is transferred
- to the caller. Ownership of the memory
- resource used in the last call to @ref reset
- is released.
- */
- BOOST_JSON_DECL
- value
- release() noexcept;
- //--------------------------------------------
- /** Push an array formed by popping `n` values from 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
- @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 formed by popping `n` key/value pairs from 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.
- @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 part of a key or 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 @ref 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 a key onto the stack.
- This function notionally removes all the
- characters currently on 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 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 number 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(
- int64_t i);
- /** Push a number 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(
- uint64_t u);
- /** Push a number 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 boolean 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
|