monotonic_resource.hpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. //
  2. // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
  3. // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  6. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. // Official repository: https://github.com/boostorg/json
  9. //
  10. #ifndef BOOST_JSON_MONOTONIC_RESOURCE_HPP
  11. #define BOOST_JSON_MONOTONIC_RESOURCE_HPP
  12. #include <boost/container/pmr/memory_resource.hpp>
  13. #include <boost/json/detail/config.hpp>
  14. #include <boost/json/storage_ptr.hpp>
  15. #include <cstddef>
  16. #include <utility>
  17. namespace boost {
  18. namespace json {
  19. #ifdef _MSC_VER
  20. #pragma warning(push)
  21. #pragma warning(disable: 4251) // class needs to have dll-interface to be used by clients of class
  22. #pragma warning(disable: 4275) // non dll-interface class used as base for dll-interface class
  23. #endif
  24. //----------------------------------------------------------
  25. /** A dynamically allocating resource with a trivial deallocate.
  26. This memory resource is a special-purpose resource that releases allocated
  27. memory only when the resource is destroyed (or when @ref release is
  28. called). It has a trivial deallocate function; that is, the metafunction
  29. @ref is_deallocate_trivial returns `true`.
  30. The resource can be constructed with an initial buffer. If there is no
  31. initial buffer, or if the buffer is exhausted, subsequent dynamic
  32. allocations are made from the system heap. The size of buffers obtained in
  33. this fashion follow a geometric progression.
  34. The purpose of this resource is to optimize the use case for performing
  35. many allocations, followed by deallocating everything at once. This is
  36. precisely the pattern of memory allocation which occurs when parsing:
  37. allocation is performed for each parsed element, and when the the resulting
  38. @ref value is no longer needed, the entire structure is destroyed. However,
  39. it is not suited for modifying the value after parsing is complete;
  40. reallocations waste memory, since the older buffer is not reclaimed until
  41. the resource is destroyed.
  42. @par Example
  43. This parses a JSON text into a value which uses a local stack buffer, then
  44. prints the result.
  45. @code
  46. unsigned char buf[ 4000 ];
  47. monotonic_resource mr( buf );
  48. // Parse the string, using our memory resource
  49. auto const jv = parse( "[1,2,3]", &mr );
  50. // Print the JSON
  51. std::cout << jv;
  52. @endcode
  53. @note The total amount of memory dynamically allocated is monotonically
  54. increasing; That is, it never decreases.
  55. @par Thread Safety
  56. Members of the same instance may not be
  57. called concurrently.
  58. @see
  59. https://en.wikipedia.org/wiki/Region-based_memory_management
  60. */
  61. class
  62. BOOST_JSON_DECL
  63. BOOST_SYMBOL_VISIBLE
  64. monotonic_resource final
  65. : public container::pmr::memory_resource
  66. {
  67. struct block;
  68. struct block_base
  69. {
  70. void* p;
  71. std::size_t avail;
  72. std::size_t size;
  73. block_base* next;
  74. };
  75. block_base buffer_;
  76. block_base* head_ = &buffer_;
  77. std::size_t next_size_ = 1024;
  78. storage_ptr upstream_;
  79. static constexpr std::size_t min_size_ = 1024;
  80. inline static constexpr std::size_t max_size();
  81. inline static std::size_t round_pow2(
  82. std::size_t n) noexcept;
  83. inline static std::size_t next_pow2(
  84. std::size_t n) noexcept;
  85. public:
  86. /** Assignment operator.
  87. Copy assignment operator is deleted. This type is not copyable or
  88. movable.
  89. */
  90. monotonic_resource& operator=(
  91. monotonic_resource const&) = delete;
  92. /** Destructor.
  93. Deallocates all the memory owned by this resource.
  94. @par Effects
  95. @code
  96. release();
  97. @endcode
  98. @par Complexity
  99. Linear in the number of deallocations performed.
  100. @par Exception Safety
  101. No-throw guarantee.
  102. */
  103. ~monotonic_resource();
  104. /** Constructors.
  105. Construct the resource.
  106. @li **(1)** indicates that the first internal dynamic allocation shall
  107. be at least `initial_size` bytes.
  108. @li **(2)**--**(5)** indicate that subsequent allocations should use
  109. the specified caller-owned buffer. When this buffer is exhausted,
  110. dynamic allocations from the upstream resource are made.
  111. @li **(6)** copy constructor is deleted. This type is not copyable or
  112. movable.
  113. None of the constructors performs any dynamic allocations.
  114. @par Complexity
  115. Constant.
  116. @par Exception Safety
  117. No-throw guarantee.
  118. @param initial_size The size of the first internal dynamic allocation.
  119. If this is lower than the implementation-defined lower limit,
  120. then the lower limit is used instead.
  121. @param upstream An optional upstream memory resource to use for
  122. performing internal dynamic allocations. If this parameter is
  123. omitted, the \<\<default_memory_resource,default resource\>\> is
  124. used.
  125. @{
  126. */
  127. explicit
  128. monotonic_resource(
  129. std::size_t initial_size = 1024,
  130. storage_ptr upstream = {}) noexcept;
  131. /** Overload
  132. @param buffer The buffer to use. Ownership is not transferred; the
  133. caller is responsible for ensuring that the lifetime of the
  134. buffer extends until the resource is destroyed.
  135. @param size The number of valid bytes pointed to by `buffer`.
  136. @param upstream
  137. */
  138. monotonic_resource(
  139. unsigned char* buffer,
  140. std::size_t size,
  141. storage_ptr upstream = {}) noexcept;
  142. #if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS)
  143. /// Overload
  144. monotonic_resource(
  145. std::byte* buffer,
  146. std::size_t size,
  147. storage_ptr upstream) noexcept
  148. : monotonic_resource(reinterpret_cast<
  149. unsigned char*>(buffer), size,
  150. std::move(upstream))
  151. {
  152. }
  153. #endif
  154. /// Overload
  155. template<std::size_t N>
  156. explicit
  157. monotonic_resource(
  158. unsigned char(&buffer)[N],
  159. storage_ptr upstream = {}) noexcept
  160. : monotonic_resource(&buffer[0],
  161. N, std::move(upstream))
  162. {
  163. }
  164. #if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS)
  165. /// Overload
  166. template<std::size_t N>
  167. explicit
  168. monotonic_resource(
  169. std::byte(&buffer)[N],
  170. storage_ptr upstream = {}) noexcept
  171. : monotonic_resource(&buffer[0],
  172. N, std::move(upstream))
  173. {
  174. }
  175. #endif
  176. #ifndef BOOST_JSON_DOCS
  177. // Safety net for accidental buffer overflows
  178. template<std::size_t N>
  179. monotonic_resource(
  180. unsigned char(&buffer)[N],
  181. std::size_t n,
  182. storage_ptr upstream = {}) noexcept
  183. : monotonic_resource(&buffer[0],
  184. n, std::move(upstream))
  185. {
  186. // If this goes off, check your parameters
  187. // closely, chances are you passed an array
  188. // thinking it was a pointer.
  189. BOOST_ASSERT(n <= N);
  190. }
  191. #ifdef __cpp_lib_byte
  192. // Safety net for accidental buffer overflows
  193. template<std::size_t N>
  194. monotonic_resource(
  195. std::byte(&buffer)[N],
  196. std::size_t n,
  197. storage_ptr upstream = {}) noexcept
  198. : monotonic_resource(&buffer[0],
  199. n, std::move(upstream))
  200. {
  201. // If this goes off, check your parameters
  202. // closely, chances are you passed an array
  203. // thinking it was a pointer.
  204. BOOST_ASSERT(n <= N);
  205. }
  206. #endif
  207. #endif
  208. /// Overload
  209. monotonic_resource(
  210. monotonic_resource const&) = delete;
  211. /// @}
  212. /** Release all allocated memory.
  213. This function deallocates all allocated memory.
  214. If an initial buffer was provided upon construction,
  215. then all of the bytes will be available again for
  216. allocation. Allocated memory is deallocated even
  217. if deallocate has not been called for some of
  218. the allocated blocks.
  219. @par Complexity
  220. Linear in the number of deallocations performed.
  221. @par Exception Safety
  222. No-throw guarantee.
  223. */
  224. void
  225. release() noexcept;
  226. protected:
  227. #ifndef BOOST_JSON_DOCS
  228. void*
  229. do_allocate(
  230. std::size_t n,
  231. std::size_t align) override;
  232. void
  233. do_deallocate(
  234. void* p,
  235. std::size_t n,
  236. std::size_t align) override;
  237. bool
  238. do_is_equal(
  239. memory_resource const& mr) const noexcept override;
  240. #endif
  241. };
  242. #ifdef _MSC_VER
  243. #pragma warning(pop)
  244. #endif
  245. template<>
  246. struct is_deallocate_trivial<
  247. monotonic_resource>
  248. {
  249. static constexpr bool value = true;
  250. };
  251. } // namespace json
  252. } // namespace boost
  253. #endif