GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: monotonic_resource.hpp
Date: 2025-12-23 17:20:53
Exec Total Coverage
Lines: 3 3 100.0%
Functions: 1 1 100.0%
Branches: 0 0 -%

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