monotonic_resource.hpp 9.5 KB

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