monotonic_resource.hpp 9.5 KB

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