--- /dev/null
+//
+// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
+// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@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_MONOTONIC_RESOURCE_HPP
+#define BOOST_JSON_MONOTONIC_RESOURCE_HPP
+
+#include <boost/json/detail/config.hpp>
+#include <boost/json/memory_resource.hpp>
+#include <boost/json/storage_ptr.hpp>
+#include <cstddef>
+#include <utility>
+
+BOOST_JSON_NS_BEGIN
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4251) // class needs to have dll-interface to be used by clients of class
+#pragma warning(disable: 4275) // non dll-interface class used as base for dll-interface class
+#endif
+
+//----------------------------------------------------------
+
+/** A dynamically allocating resource with a trivial deallocate
+
+ This memory resource is a special-purpose resource
+ that releases allocated memory only when the resource
+ is destroyed (or when @ref release is called).
+ It has a trivial deallocate function; that is, the
+ metafunction @ref is_deallocate_trivial returns `true`.
+\n
+ The resource can be constructed with an initial buffer.
+ If there is no initial buffer, or if the buffer is
+ exhausted, subsequent dynamic allocations are made from
+ the system heap. The size of buffers obtained in this
+ fashion follow a geometric progression.
+\n
+ The purpose of this resource is to optimize the use
+ case for performing many allocations, followed by
+ deallocating everything at once. This is precisely the
+ pattern of memory allocation which occurs when parsing:
+ allocation is performed for each parsed element, and
+ when the the resulting @ref value is no longer needed,
+ the entire structure is destroyed. However, it is not
+ suited for modifying the value after parsing is
+ complete; reallocations waste memory, since the
+ older buffer is not reclaimed until the resource
+ is destroyed.
+
+ @par Example
+
+ This parses a JSON into a value which uses a local
+ stack buffer, then prints the result.
+
+ @code
+
+ unsigned char buf[ 4000 ];
+ monotonic_resource mr( buf );
+
+ // Parse the string, using our memory resource
+ auto const jv = parse( "[1,2,3]", &mr );
+
+ // Print the JSON
+ std::cout << jv;
+
+ @endcode
+
+ @note The total amount of memory dynamically
+ allocated is monotonically increasing; That is,
+ it never decreases.
+
+ @par Thread Safety
+ Members of the same instance may not be
+ called concurrently.
+
+ @see
+ https://en.wikipedia.org/wiki/Region-based_memory_management
+*/
+class BOOST_JSON_CLASS_DECL
+ monotonic_resource final
+ : public memory_resource
+{
+ struct block;
+ struct block_base
+ {
+ void* p;
+ std::size_t avail;
+ std::size_t size;
+ block_base* next;
+ };
+
+ block_base buffer_;
+ block_base* head_ = &buffer_;
+ std::size_t next_size_ = 1024;
+ storage_ptr upstream_;
+
+ static constexpr std::size_t min_size_ = 1024;
+ inline static constexpr std::size_t max_size();
+ inline static std::size_t round_pow2(
+ std::size_t n) noexcept;
+ inline static std::size_t next_pow2(
+ std::size_t n) noexcept;
+
+public:
+ /// Copy constructor (deleted)
+ monotonic_resource(
+ monotonic_resource const&) = delete;
+
+ /// Copy assignment (deleted)
+ monotonic_resource& operator=(
+ monotonic_resource const&) = delete;
+
+ /** Destructor
+
+ Deallocates all the memory owned by this resource.
+
+ @par Effects
+ @code
+ this->release();
+ @endcode
+
+ @par Complexity
+ Linear in the number of deallocations performed.
+
+ @par Exception Safety
+ No-throw guarantee.
+ */
+ ~monotonic_resource();
+
+ /** Constructor
+
+ This constructs the resource and indicates
+ that the first internal dynamic allocation
+ shall be at least `initial_size` bytes.
+ \n
+ This constructor is guaranteed not to perform
+ any dynamic allocations.
+
+ @par Complexity
+ Constant.
+
+ @par Exception Safety
+ No-throw guarantee.
+
+ @param initial_size The size of the first
+ internal dynamic allocation. If this is lower
+ than the implementation-defined lower limit, then
+ the lower limit is used instead.
+
+ @param upstream An optional upstream memory resource
+ to use for performing internal dynamic allocations.
+ If this parameter is omitted, the default resource
+ is used.
+ */
+ explicit
+ monotonic_resource(
+ std::size_t initial_size = 1024,
+ storage_ptr upstream = {}) noexcept;
+
+ /** Constructor
+
+ This constructs the resource and indicates that
+ subsequent allocations should use the specified
+ caller-owned buffer.
+ When this buffer is exhausted, dynamic allocations
+ from the upstream resource are made.
+ \n
+ This constructor is guaranteed not to perform
+ any dynamic allocations.
+
+ @par Complexity
+ Constant.
+
+ @par Exception Safety
+ No-throw guarantee.
+
+ @param buffer The buffer to use.
+ Ownership is not transferred; the caller is
+ responsible for ensuring that the lifetime of
+ the buffer extends until the resource is destroyed.
+
+ @param size The number of valid bytes pointed
+ to by `buffer`.
+
+ @param upstream An optional upstream memory resource
+ to use for performing internal dynamic allocations.
+ If this parameter is omitted, the default resource
+ is used.
+ */
+ /** @{ */
+ monotonic_resource(
+ unsigned char* buffer,
+ std::size_t size,
+ storage_ptr upstream = {}) noexcept;
+
+#if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS)
+ monotonic_resource(
+ std::byte* buffer,
+ std::size_t size,
+ storage_ptr upstream) noexcept
+ : monotonic_resource(reinterpret_cast<
+ unsigned char*>(buffer), size,
+ std::move(upstream))
+ {
+ }
+#endif
+ /** @} */
+
+ /** Constructor
+
+ This constructs the resource and indicates that
+ subsequent allocations should use the specified
+ caller-owned buffer.
+ When this buffer is exhausted, dynamic allocations
+ from the upstream resource are made.
+ \n
+ This constructor is guaranteed not to perform
+ any dynamic allocations.
+
+ @par Complexity
+ Constant.
+
+ @par Exception Safety
+ No-throw guarantee.
+
+ @param buffer The buffer to use.
+ Ownership is not transferred; the caller is
+ responsible for ensuring that the lifetime of
+ the buffer extends until the resource is destroyed.
+
+ @param upstream An optional upstream memory resource
+ to use for performing internal dynamic allocations.
+ If this parameter is omitted, the default resource
+ is used.
+ */
+ /** @{ */
+ template<std::size_t N>
+ explicit
+ monotonic_resource(
+ unsigned char(&buffer)[N],
+ storage_ptr upstream = {}) noexcept
+ : monotonic_resource(&buffer[0],
+ N, std::move(upstream))
+ {
+ }
+
+#if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS)
+ template<std::size_t N>
+ explicit
+ monotonic_resource(
+ std::byte(&buffer)[N],
+ storage_ptr upstream = {}) noexcept
+ : monotonic_resource(&buffer[0],
+ N, std::move(upstream))
+ {
+ }
+#endif
+ /** @} */
+
+#ifndef BOOST_JSON_DOCS
+ // Safety net for accidental buffer overflows
+ template<std::size_t N>
+ monotonic_resource(
+ unsigned char(&buffer)[N],
+ std::size_t n,
+ storage_ptr upstream = {}) noexcept
+ : monotonic_resource(&buffer[0],
+ n, std::move(upstream))
+ {
+ // If this goes off, check your parameters
+ // closely, chances are you passed an array
+ // thinking it was a pointer.
+ BOOST_ASSERT(n <= N);
+ }
+
+#ifdef __cpp_lib_byte
+ // Safety net for accidental buffer overflows
+ template<std::size_t N>
+ monotonic_resource(
+ std::byte(&buffer)[N],
+ std::size_t n,
+ storage_ptr upstream = {}) noexcept
+ : monotonic_resource(&buffer[0],
+ n, std::move(upstream))
+ {
+ // If this goes off, check your parameters
+ // closely, chances are you passed an array
+ // thinking it was a pointer.
+ BOOST_ASSERT(n <= N);
+ }
+#endif
+#endif
+
+ /** Release all allocated memory.
+
+ This function deallocates all allocated memory.
+ If an initial buffer was provided upon construction,
+ then all of the bytes will be available again for
+ allocation. Allocated memory is deallocated even
+ if deallocate has not been called for some of
+ the allocated blocks.
+
+ @par Complexity
+ Linear in the number of deallocations performed.
+
+ @par Exception Safety
+ No-throw guarantee.
+ */
+ void
+ release() noexcept;
+
+protected:
+#ifndef BOOST_JSON_DOCS
+ void*
+ do_allocate(
+ std::size_t n,
+ std::size_t align) override;
+
+ void
+ do_deallocate(
+ void* p,
+ std::size_t n,
+ std::size_t align) override;
+
+ bool
+ do_is_equal(
+ memory_resource const& mr) const noexcept override;
+#endif
+};
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+template<>
+struct is_deallocate_trivial<
+ monotonic_resource>
+{
+ static constexpr bool value = true;
+};
+
+BOOST_JSON_NS_END
+
+#endif