GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: storage_ptr.hpp
Date: 2025-12-23 17:22:01
Exec Total Coverage
Lines: 68 68 100.0%
Functions: 29 30 96.7%
Branches: 14 19 73.7%

Line Branch Exec Source
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/json
8 //
9
10 #ifndef BOOST_JSON_STORAGE_PTR_HPP
11 #define BOOST_JSON_STORAGE_PTR_HPP
12
13 #include <boost/container/pmr/polymorphic_allocator.hpp>
14 #include <boost/json/detail/config.hpp>
15 #include <boost/json/memory_resource.hpp>
16 #include <boost/json/detail/shared_resource.hpp>
17 #include <boost/json/detail/default_resource.hpp>
18 #include <boost/json/is_deallocate_trivial.hpp>
19 #include <cstddef>
20 #include <new>
21 #include <type_traits>
22 #include <utility>
23
24 namespace boost {
25 namespace json {
26
27 /** A smart pointer to a memory resource.
28
29 This container is used to hold a pointer to a memory resource. The
30 pointed-to resource is always valid. Depending on the means of
31 construction, the ownership will be either:
32
33 @li Non-owning, when constructing from a raw pointer to
34 `boost::container::pmr::memory_resource` or from a
35 `boost::container::pmr::polymorphic_allocator`. In this case the caller is
36 responsible for ensuring that the lifetime of the memory resource extends
37 until there are no more calls to allocate or deallocate.
38
39 @li Owning, when constructing using the function
40 @ref make_shared_resource. In this case
41 ownership is shared; the lifetime of the memory
42 resource extends until the last copy of the
43 @ref storage_ptr is destroyed.
44
45 @par Examples
46
47 These statements create a memory resource on the
48 stack and construct a pointer from it without
49 taking ownership:
50 @code
51 monotonic_resource mr; // Create our memory resource on the stack
52 storage_ptr sp( &mr ); // Construct a non-owning pointer to the resource
53 @endcode
54
55 This function creates a pointer to a memory
56 resource using shared ownership and returns it.
57 The lifetime of the memory resource extends until
58 the last copy of the pointer is destroyed:
59 @code
60 // Create a counted memory resource and return it
61 storage_ptr make_storage()
62 {
63 return make_shared_resource< monotonic_resource >();
64 }
65 @endcode
66
67 @par Thread Safety
68
69 Instances of this type provide the default level of
70 thread safety for all C++ objects. Specifically, it
71 conforms to
72 <a href="http://eel.is/c++draft/res.on.data.races">
73 16.4.6.10 Data race avoidance</a>.
74
75 @see
76 @ref make_shared_resource,
77 @ref boost::container::pmr::polymorphic_allocator,
78 @ref boost::container::pmr::memory_resource.
79
80 */
81 class storage_ptr
82 {
83 #ifndef BOOST_JSON_DOCS
84 // VFALCO doc toolchain shows this when it shouldn't
85 friend struct detail::shared_resource;
86 #endif
87 using shared_resource =
88 detail::shared_resource;
89
90 using default_resource =
91 detail::default_resource;
92
93 std::uintptr_t i_;
94
95 shared_resource*
96 302 get_shared() const noexcept
97 {
98 return static_cast<shared_resource*>(
99 reinterpret_cast<container::pmr::memory_resource*>(
100 302 i_ & ~3));
101 }
102
103 void
104 6352438 addref() const noexcept
105 {
106
2/2
✓ Branch 1 taken 141 times.
✓ Branch 2 taken 6352297 times.
6352438 if(is_shared())
107 141 get_shared()->refs.fetch_add(
108 1, std::memory_order_relaxed);
109 6352438 }
110
111 void
112 43962422 release() const noexcept
113 {
114
2/2
✓ Branch 1 taken 161 times.
✓ Branch 2 taken 43962261 times.
43962422 if(is_shared())
115 {
116 161 auto const p = get_shared();
117 161 if(p->refs.fetch_sub(1,
118
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 141 times.
161 std::memory_order_acq_rel) == 1)
119
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 delete p;
120 }
121 43962422 }
122
123 template<class T>
124 33 storage_ptr(
125 detail::shared_resource_impl<T>* p) noexcept
126 33 : i_(reinterpret_cast<std::uintptr_t>(
127 33 static_cast<container::pmr::memory_resource*>(p)) + 1 +
128 (json::is_deallocate_trivial<T>::value ? 2 : 0))
129 {
130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
33 BOOST_ASSERT(p);
131 33 }
132
133 public:
134 /** Destructor
135
136 If the pointer has shared ownership of the
137 resource, the shared ownership is released.
138 If this is the last owned copy, the memory
139 resource is destroyed.
140
141 @par Complexity
142 Constant.
143
144 @par Exception Safety
145 No-throw guarantee.
146 */
147 41885772 ~storage_ptr() noexcept
148 {
149 41885772 release();
150 41885772 }
151
152 /** Constructor
153
154 This constructs a non-owning pointer that refers
155 to the [default memory resource].
156
157 @par Complexity
158 Constant.
159
160 @par Exception Safety
161 No-throw guarantee.
162
163 [default memory resource]: json/allocators/storage_ptr.html#json.allocators.storage_ptr.default_memory_resource
164 */
165 14652437 storage_ptr() noexcept
166 14652437 : i_(0)
167 {
168 14652437 }
169
170 /** Constructor
171
172 This constructs a non-owning pointer that points to the memory resource
173 `r`. The caller is responsible for maintaining the lifetime of the
174 pointed-to `boost::container::pmr::memory_resource`.
175
176 @par Constraints
177 @code
178 std::is_convertible< T*, boost::container::pmr::memory_resource* >::value == true
179 @endcode
180
181 @par Preconditions
182 @code
183 r != nullptr
184 @endcode
185
186 @par Exception Safety
187 No-throw guarantee.
188
189 @param r A pointer to the memory resource to use.
190 This may not be null.
191 */
192 template<class T
193 #ifndef BOOST_JSON_DOCS
194 , class = typename std::enable_if<
195 std::is_convertible<T*,
196 container::pmr::memory_resource*>::value>::type
197 #endif
198 >
199 86807 storage_ptr(T* r) noexcept
200 86807 : i_(reinterpret_cast<std::uintptr_t>(
201
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
27 static_cast<container::pmr::memory_resource *>(r)) +
202 (json::is_deallocate_trivial<T>::value ? 2 : 0))
203 {
204
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57222 times.
86807 BOOST_ASSERT(r);
205 86807 }
206
207 /** Constructor
208
209 This constructs a non-owning pointer that points to the same memory
210 resource as `alloc`, obtained by calling `alloc.resource()`. The caller
211 is responsible for maintaining the lifetime of the
212 pointed-to `boost::container::pmr::memory_resource`.
213
214 @par Constraints
215 @code
216 std::is_convertible< T*, boost::container::pmr::memory_resource* >::value == true
217 @endcode
218
219 @par Exception Safety
220 No-throw guarantee.
221
222 @param alloc A `boost::container::pmr::polymorphic_allocator` to
223 construct from.
224 */
225 template<class T>
226 10 storage_ptr(
227 container::pmr::polymorphic_allocator<T> const& alloc) noexcept
228 10 : i_(reinterpret_cast<std::uintptr_t>(
229 10 alloc.resource()))
230 {
231 10 }
232
233 /** Move constructor
234
235 This function constructs a pointer that
236 points to the same memory resource as `other`,
237 with the same ownership:
238
239 @li If `other` is non-owning, then `*this`
240 will be be non-owning.
241
242 @li If `other` has shared ownership, then
243 ownership will be transferred to `*this`.
244
245 After construction, `other` will point
246 to the [default memory resource].
247
248 @par Complexity
249 Constant.
250
251 @par Exception Safety
252 No-throw guarantee.
253
254 @param other The pointer to construct from.
255
256 [default memory resource]: json/allocators/storage_ptr.html#json.allocators.storage_ptr.default_memory_resource
257 */
258 22938870 storage_ptr(
259 storage_ptr&& other) noexcept
260 22938870 : i_(detail::exchange(other.i_, 0))
261 {
262 22938870 }
263
264 /** Copy constructor
265
266 This function constructs a pointer that
267 points to the same memory resource as `other`,
268 with the same ownership:
269
270 @li If `other` is non-owning, then `*this`
271 will be be non-owning.
272
273 @li If `other` has shared ownership, then
274 `*this` will acquire shared ownership.
275
276 @par Complexity
277 Constant.
278
279 @par Exception Safety
280 No-throw guarantee.
281
282 @param other The pointer to construct from.
283 */
284 6352437 storage_ptr(
285 storage_ptr const& other) noexcept
286 6352437 : i_(other.i_)
287 {
288 6352437 addref();
289 6352437 }
290
291 /** Move assignment
292
293 This function assigns a pointer that
294 points to the same memory resource as `other`,
295 with the same ownership:
296
297 @li If `other` is non-owning, then `*this`
298 will be be non-owning.
299
300 @li If `other` has shared ownership, then
301 ownership will be transferred to `*this`.
302
303 After assignment, `other` will point
304 to the [default memory resource].
305 If `*this` previously had shared ownership,
306 it is released before the function returns.
307
308 @par Complexity
309 Constant.
310
311 @par Exception Safety
312 No-throw guarantee.
313
314 @param other The storage pointer to move.
315
316 [default memory resource]: json/allocators/storage_ptr.html#json.allocators.storage_ptr.default_memory_resource
317 */
318 storage_ptr&
319 2076649 operator=(
320 storage_ptr&& other) noexcept
321 {
322 2076649 release();
323 2076649 i_ = detail::exchange(other.i_, 0);
324 2076649 return *this;
325 }
326
327 /** Copy assignment.
328
329 This function assigns a pointer that
330 points to the same memory resource as `other`,
331 with the same ownership:
332
333 @li If `other` is non-owning, then `*this`
334 will be be non-owning.
335
336 @li If `other` has shared ownership, then
337 `*this` will acquire shared ownership.
338
339 If `*this` previously had shared ownership,
340 it is released before the function returns.
341
342 @par Complexity
343 Constant.
344
345 @par Exception Safety
346 No-throw guarantee.
347
348 @param other The storage pointer to copy.
349 */
350 storage_ptr&
351 1 operator=(
352 storage_ptr const& other) noexcept
353 {
354 1 other.addref();
355 1 release();
356 1 i_ = other.i_;
357 1 return *this;
358 }
359
360 /** Return `true` if ownership of the memory resource is shared.
361
362 This function returns true for memory resources
363 created using @ref make_shared_resource.
364 */
365 bool
366 50314861 is_shared() const noexcept
367 {
368 50314861 return (i_ & 1) != 0;
369 }
370
371 /** Return `true` if calling `deallocate` on the memory resource has no effect.
372
373 This function is used to determine if the deallocate
374 function of the pointed to memory resource is trivial.
375 The value of @ref is_deallocate_trivial is evaluated
376 and saved when the memory resource is constructed
377 and the type is known, before the type is erased.
378 */
379 bool
380 1 is_deallocate_trivial() const noexcept
381 {
382 1 return (i_ & 2) != 0;
383 }
384
385 /** Return `true` if ownership of the memory resource is not shared and deallocate is trivial.
386
387 This function is used to determine if calls to deallocate
388 can effectively be skipped.
389
390 @par Effects
391 Returns `! this->is_shared() && this->is_deallocate_trivial()`
392 */
393 bool
394 4323308 is_not_shared_and_deallocate_is_trivial() const noexcept
395 {
396 4323308 return (i_ & 3) == 2;
397 }
398
399 /** Return a pointer to the memory resource.
400
401 This function returns a pointer to the
402 referenced `boost::container::pmr::memory_resource`.
403
404 @par Complexity
405 Constant.
406
407 @par Exception Safety
408 No-throw guarantee.
409 */
410 container::pmr::memory_resource*
411 650557 get() const noexcept
412 {
413
2/2
✓ Branch 0 taken 122565 times.
✓ Branch 1 taken 527992 times.
650557 if(i_ != 0)
414 return reinterpret_cast<
415 122565 container::pmr::memory_resource*>(i_ & ~3);
416 527992 return default_resource::get();
417 }
418
419 /** Return a pointer to the memory resource.
420
421 This function returns a pointer to the
422 referenced `boost::container::pmr::memory_resource`.
423
424 @par Complexity
425 Constant.
426
427 @par Exception Safety
428 No-throw guarantee.
429 */
430 container::pmr::memory_resource*
431 647057 operator->() const noexcept
432 {
433 647057 return get();
434 }
435
436 /** Return a reference to the memory resource.
437
438 This function returns a reference to the
439 pointed-to `boost::container::pmr::memory_resource`.
440
441 @par Complexity
442
443 Constant.
444
445 @par Exception Safety
446
447 No-throw guarantee.
448 */
449 container::pmr::memory_resource&
450 3468 operator*() const noexcept
451 {
452 3468 return *get();
453 }
454
455 template<class U, class... Args>
456 friend
457 storage_ptr
458 make_shared_resource(Args&&... args);
459 };
460
461 #if defined(_MSC_VER)
462 # pragma warning( push )
463 # if !defined(__clang__) && _MSC_VER <= 1900
464 # pragma warning( disable : 4702 )
465 # endif
466 #endif
467 /** Return shared ownership of a new, dynamically allocated memory resource.
468
469 This function dynamically allocates a new memory resource
470 as if by `operator new` that uses shared ownership. The
471 lifetime of the memory resource will be extended until
472 the last @ref storage_ptr which points to it is destroyed.
473
474 @par Mandates
475 @code
476 std::is_base_of< boost::container::pmr::memory_resource, U >::value == true
477 @endcode
478
479 @par Complexity
480 Same as `new U( std::forward<Args>(args)... )`.
481
482 @par Exception Safety
483 Strong guarantee.
484
485 @tparam U The type of memory resource to create.
486
487 @param args Parameters forwarded to the constructor of `U`.
488 */
489 template<class U, class... Args>
490 storage_ptr
491 28 make_shared_resource(Args&&... args)
492 {
493 // If this generates an error, it means that
494 // `T` is not a memory resource.
495 BOOST_STATIC_ASSERT(
496 std::is_base_of<
497 container::pmr::memory_resource, U>::value);
498 31 return storage_ptr(new
499 detail::shared_resource_impl<U>(
500
2/3
✓ Branch 1 taken 13 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
29 std::forward<Args>(args)...));
501 }
502 #if defined(_MSC_VER)
503 # pragma warning( pop )
504 #endif
505
506 /** Return true if two storage pointers point to the same memory resource.
507
508 This function returns `true` if the
509 `boost::container::pmr::memory_resource` objects pointed to by `lhs` and
510 `rhs` have the same address.
511 */
512 inline
513 bool
514 5 operator==(
515 storage_ptr const& lhs,
516 storage_ptr const& rhs) noexcept
517 {
518 5 return lhs.get() == rhs.get();
519 }
520
521 /** Return true if two storage pointers point to different memory resources.
522
523 This function returns `true` if the
524 `boost::container::pmr::memory_resource` objects pointed to by `lhs` and
525 `rhs` have different addresses.
526 */
527 inline
528 bool
529 operator!=(
530 storage_ptr const& lhs,
531 storage_ptr const& rhs) noexcept
532 {
533 return lhs.get() != rhs.get();
534 }
535
536 } // namespace json
537 } // namespace boost
538
539 #endif
540