monotonic_resource.hpp 9.6 KB

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