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