monotonic_resource.hpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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
  70. BOOST_JSON_DECL
  71. BOOST_SYMBOL_VISIBLE
  72. monotonic_resource final
  73. : public memory_resource
  74. {
  75. struct block;
  76. struct block_base
  77. {
  78. void* p;
  79. std::size_t avail;
  80. std::size_t size;
  81. block_base* next;
  82. };
  83. block_base buffer_;
  84. block_base* head_ = &buffer_;
  85. std::size_t next_size_ = 1024;
  86. storage_ptr upstream_;
  87. static constexpr std::size_t min_size_ = 1024;
  88. inline static constexpr std::size_t max_size();
  89. inline static std::size_t round_pow2(
  90. std::size_t n) noexcept;
  91. inline static std::size_t next_pow2(
  92. std::size_t n) noexcept;
  93. public:
  94. /// Copy constructor (deleted)
  95. monotonic_resource(
  96. monotonic_resource const&) = delete;
  97. /// Copy assignment (deleted)
  98. monotonic_resource& operator=(
  99. monotonic_resource const&) = delete;
  100. /** Destructor
  101. Deallocates all the memory owned by this resource.
  102. @par Effects
  103. @code
  104. this->release();
  105. @endcode
  106. @par Complexity
  107. Linear in the number of deallocations performed.
  108. @par Exception Safety
  109. No-throw guarantee.
  110. */
  111. ~monotonic_resource();
  112. /** Constructor
  113. This constructs the resource and indicates
  114. that the first internal dynamic allocation
  115. shall be at least `initial_size` bytes.
  116. \n
  117. This constructor is guaranteed not to perform
  118. any dynamic allocations.
  119. @par Complexity
  120. Constant.
  121. @par Exception Safety
  122. No-throw guarantee.
  123. @param initial_size The size of the first
  124. internal dynamic allocation. If this is lower
  125. than the implementation-defined lower limit, then
  126. the lower limit is used instead.
  127. @param upstream An optional upstream memory resource
  128. to use for performing internal dynamic allocations.
  129. If this parameter is omitted, the default resource
  130. is used.
  131. */
  132. explicit
  133. monotonic_resource(
  134. std::size_t initial_size = 1024,
  135. storage_ptr upstream = {}) noexcept;
  136. /** Constructor
  137. This constructs the resource and indicates that
  138. subsequent allocations should use the specified
  139. caller-owned buffer.
  140. When this buffer is exhausted, dynamic allocations
  141. from the upstream resource are made.
  142. \n
  143. This constructor is guaranteed not to perform
  144. any dynamic allocations.
  145. @par Complexity
  146. Constant.
  147. @par Exception Safety
  148. No-throw guarantee.
  149. @param buffer The buffer to use.
  150. Ownership is not transferred; the caller is
  151. responsible for ensuring that the lifetime of
  152. the buffer extends until the resource is destroyed.
  153. @param size The number of valid bytes pointed
  154. to by `buffer`.
  155. @param upstream An optional upstream memory resource
  156. to use for performing internal dynamic allocations.
  157. If this parameter is omitted, the default resource
  158. is used.
  159. */
  160. /** @{ */
  161. monotonic_resource(
  162. unsigned char* buffer,
  163. std::size_t size,
  164. storage_ptr upstream = {}) noexcept;
  165. #if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS)
  166. monotonic_resource(
  167. std::byte* buffer,
  168. std::size_t size,
  169. storage_ptr upstream) noexcept
  170. : monotonic_resource(reinterpret_cast<
  171. unsigned char*>(buffer), size,
  172. std::move(upstream))
  173. {
  174. }
  175. #endif
  176. /** @} */
  177. /** Constructor
  178. This constructs the resource and indicates that
  179. subsequent allocations should use the specified
  180. caller-owned buffer.
  181. When this buffer is exhausted, dynamic allocations
  182. from the upstream resource are made.
  183. \n
  184. This constructor is guaranteed not to perform
  185. any dynamic allocations.
  186. @par Complexity
  187. Constant.
  188. @par Exception Safety
  189. No-throw guarantee.
  190. @param buffer The buffer to use.
  191. Ownership is not transferred; the caller is
  192. responsible for ensuring that the lifetime of
  193. the buffer extends until the resource is destroyed.
  194. @param upstream An optional upstream memory resource
  195. to use for performing internal dynamic allocations.
  196. If this parameter is omitted, the default resource
  197. is used.
  198. */
  199. /** @{ */
  200. template<std::size_t N>
  201. explicit
  202. monotonic_resource(
  203. unsigned char(&buffer)[N],
  204. storage_ptr upstream = {}) noexcept
  205. : monotonic_resource(&buffer[0],
  206. N, std::move(upstream))
  207. {
  208. }
  209. #if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS)
  210. template<std::size_t N>
  211. explicit
  212. monotonic_resource(
  213. std::byte(&buffer)[N],
  214. storage_ptr upstream = {}) noexcept
  215. : monotonic_resource(&buffer[0],
  216. N, std::move(upstream))
  217. {
  218. }
  219. #endif
  220. /** @} */
  221. #ifndef BOOST_JSON_DOCS
  222. // Safety net for accidental buffer overflows
  223. template<std::size_t N>
  224. monotonic_resource(
  225. unsigned char(&buffer)[N],
  226. std::size_t n,
  227. storage_ptr upstream = {}) noexcept
  228. : monotonic_resource(&buffer[0],
  229. n, std::move(upstream))
  230. {
  231. // If this goes off, check your parameters
  232. // closely, chances are you passed an array
  233. // thinking it was a pointer.
  234. BOOST_ASSERT(n <= N);
  235. }
  236. #ifdef __cpp_lib_byte
  237. // Safety net for accidental buffer overflows
  238. template<std::size_t N>
  239. monotonic_resource(
  240. std::byte(&buffer)[N],
  241. std::size_t n,
  242. storage_ptr upstream = {}) noexcept
  243. : monotonic_resource(&buffer[0],
  244. n, std::move(upstream))
  245. {
  246. // If this goes off, check your parameters
  247. // closely, chances are you passed an array
  248. // thinking it was a pointer.
  249. BOOST_ASSERT(n <= N);
  250. }
  251. #endif
  252. #endif
  253. /** Release all allocated memory.
  254. This function deallocates all allocated memory.
  255. If an initial buffer was provided upon construction,
  256. then all of the bytes will be available again for
  257. allocation. Allocated memory is deallocated even
  258. if deallocate has not been called for some of
  259. the allocated blocks.
  260. @par Complexity
  261. Linear in the number of deallocations performed.
  262. @par Exception Safety
  263. No-throw guarantee.
  264. */
  265. void
  266. release() noexcept;
  267. protected:
  268. #ifndef BOOST_JSON_DOCS
  269. void*
  270. do_allocate(
  271. std::size_t n,
  272. std::size_t align) override;
  273. void
  274. do_deallocate(
  275. void* p,
  276. std::size_t n,
  277. std::size_t align) override;
  278. bool
  279. do_is_equal(
  280. memory_resource const& mr) const noexcept override;
  281. #endif
  282. };
  283. #ifdef _MSC_VER
  284. #pragma warning(pop)
  285. #endif
  286. template<>
  287. struct is_deallocate_trivial<
  288. monotonic_resource>
  289. {
  290. static constexpr bool value = true;
  291. };
  292. } // namespace json
  293. } // namespace boost
  294. #endif