GCC Code Coverage Report


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