GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: storage_ptr.hpp
Date: 2025-12-23 17:15:02
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/detail/shared_resource.hpp>
16 #include <boost/json/detail/default_resource.hpp>
17 #include <boost/json/is_deallocate_trivial.hpp>
18 #include <new>
19 #include <type_traits>
20 #include <utility>
21
22 namespace boost {
23 namespace json {
24
25 /** A smart pointer to a memory resource.
26
27 This class is used to hold a pointer to a memory resource. The pointed-to
28 resource is always valid. Depending on the means of construction, the
29 ownership will be either:
30
31 @li Non-owning, when constructing from a raw pointer to
32 @ref boost::container::pmr::memory_resource or from a
33 @ref boost::container::pmr::polymorphic_allocator. In this case the caller
34 is responsible for ensuring that the lifetime of the memory resource
35 extends until there are no more calls to allocate or deallocate.
36
37 @li Owning, when constructing using the function @ref make_shared_resource.
38 In this case ownership is shared; the lifetime of the memory resource
39 extends until the last copy of the `storage_ptr` is destroyed.
40
41 @par Examples
42 These statements create a memory resource on the stack and construct
43 a pointer from it without taking ownership:
44
45 @code
46 monotonic_resource mr; // Create our memory resource on the stack
47 storage_ptr sp( &mr ); // Construct a non-owning pointer to the resource
48 @endcode
49
50 This function creates a pointer to a memory resource using shared ownership
51 and returns it. The lifetime of the memory resource extends until the last
52 copy of the pointer is destroyed:
53
54 @code
55 // Create a counted memory resource and return it
56 storage_ptr make_storage()
57 {
58 return make_shared_resource< monotonic_resource >();
59 }
60 @endcode
61
62 @par Thread Safety
63 Instances of this type provide the default level of thread safety for all
64 C++ objects. Specifically, it conforms to
65 [16.4.6.10 Data race avoidance](http://eel.is/c++draft/res.on.data.races).
66
67 @see
68 @ref make_shared_resource,
69 @ref boost::container::pmr::polymorphic_allocator,
70 @ref boost::container::pmr::memory_resource.
71
72 */
73 class storage_ptr
74 {
75 #ifndef BOOST_JSON_DOCS
76 // VFALCO doc toolchain shows this when it shouldn't
77 friend struct detail::shared_resource;
78 #endif
79 using shared_resource =
80 detail::shared_resource;
81
82 using default_resource =
83 detail::default_resource;
84
85 std::uintptr_t i_;
86
87 shared_resource*
88 302 get_shared() const noexcept
89 {
90 return static_cast<shared_resource*>(
91 reinterpret_cast<container::pmr::memory_resource*>(
92 302 i_ & ~3));
93 }
94
95 void
96 6352456 addref() const noexcept
97 {
98
2/2
✓ Branch 1 taken 141 times.
✓ Branch 2 taken 6352315 times.
6352456 if(is_shared())
99 141 get_shared()->refs.fetch_add(
100 1, std::memory_order_relaxed);
101 6352456 }
102
103 void
104 43989306 release() const noexcept
105 {
106
2/2
✓ Branch 1 taken 161 times.
✓ Branch 2 taken 43989145 times.
43989306 if(is_shared())
107 {
108 161 auto const p = get_shared();
109 161 if(p->refs.fetch_sub(1,
110
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 141 times.
161 std::memory_order_acq_rel) == 1)
111
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 delete p;
112 }
113 43989306 }
114
115 template<class T>
116 33 storage_ptr(
117 detail::shared_resource_impl<T>* p) noexcept
118 33 : i_(reinterpret_cast<std::uintptr_t>(
119 33 static_cast<container::pmr::memory_resource*>(p)) + 1 +
120 (json::is_deallocate_trivial<T>::value ? 2 : 0))
121 {
122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
33 BOOST_ASSERT(p);
123 33 }
124
125 public:
126 /** Destructor.
127
128 If the pointer has shared ownership of the resource, the shared
129 ownership is released. If this is the last owned copy, the memory
130 resource is destroyed.
131
132 @par Complexity
133 Constant.
134
135 @par Exception Safety
136 No-throw guarantee.
137 */
138 41912656 ~storage_ptr() noexcept
139 {
140 41912656 release();
141 41912656 }
142
143 /** Constructors.
144
145 @li **(1)** constructs a non-owning pointer that refers to the
146 \<\<default_memory_resource,default memory resource\>\>.
147
148 @li **(2)** constructs a non-owning pointer that points to the memory
149 resource `r`.
150
151 @li **(3)** constructs a non-owning pointer that points to the same
152 memory resource as `alloc`, obtained by calling `alloc.resource()`.
153
154 @li **(4)**, **(5)** construct a pointer to the same memory resource as
155 `other`, with the same ownership.
156
157 After **(4)** and **(5)** if `other` was owning, then the constructed
158 pointer is also owning. In particular, **(4)** transfers ownership to
159 the constructed pointer while **(5)** causes it to share ownership with
160 `other`. Otherwise, and with other overloads the constructed pointer
161 doesn't own its memory resource and the caller is responsible for
162 maintaining the lifetime of the pointed-to
163 @ref boost::container::pmr::memory_resource.
164
165 After **(4)**, `other` will point to the default memory resource.
166
167 @par Constraints
168 @code
169 std::is_convertible< T*, boost::container::pmr::memory_resource* >::value == true
170 @endcode
171
172 @pre
173 @code
174 r != nullptr
175 @endcode
176
177 @par Complexity
178 Constant.
179
180 @par Exception Safety
181 No-throw guarantee.
182
183 @{
184 */
185 14653293 storage_ptr() noexcept
186 14653293 : i_(0)
187 {
188 14653293 }
189
190 /** Overload
191
192 @tparam T The type of memory resource.
193 @param r A non-null pointer to the memory resource to use.
194 */
195 template<class T
196 #ifndef BOOST_JSON_DOCS
197 , class = typename std::enable_if<
198 std::is_convertible<T*,
199 container::pmr::memory_resource*>::value>::type
200 #endif
201 >
202 86807 storage_ptr(T* r) noexcept
203 86807 : i_(reinterpret_cast<std::uintptr_t>(
204
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
27 static_cast<container::pmr::memory_resource *>(r)) +
205 (json::is_deallocate_trivial<T>::value ? 2 : 0))
206 {
207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57222 times.
86807 BOOST_ASSERT(r);
208 86807 }
209
210 /** Overload
211
212 @tparam V Any type.
213 @param alloc A @ref boost::container::pmr::polymorphic_allocator to
214 construct from.
215 */
216 template<class V>
217 10 storage_ptr(
218 container::pmr::polymorphic_allocator<V> const& alloc) noexcept
219 10 : i_(reinterpret_cast<std::uintptr_t>(
220 10 alloc.resource()))
221 {
222 10 }
223
224 /** Overload
225
226 @param other Another pointer.
227 */
228 22964880 storage_ptr(
229 storage_ptr&& other) noexcept
230 22964880 : i_(detail::exchange(other.i_, 0))
231 {
232 22964880 }
233
234 /** Overload
235
236 @param other
237 */
238 6352455 storage_ptr(
239 storage_ptr const& other) noexcept
240 6352455 : i_(other.i_)
241 {
242 6352455 addref();
243 6352455 }
244 /// @}
245
246 /** Assignment operators.
247
248 This function assigns a pointer that points to the same memory resource
249 as `other`, with the same ownership:
250
251 @li If `other` is non-owning, then the assigned-to pointer will be be
252 non-owning.
253
254 @li If `other` has shared ownership, then **(1)** transfers ownership
255 to the assigned-to pointer, while after **(2)** it shares the ownership
256 with `other`.
257
258 If the assigned-to pointer previously had shared ownership, it is
259 released before the function returns.
260
261 After **(1)**, `other` will point to the
262 \<\<default_memory_resource,default memory resource\>\>.
263
264 @par Complexity
265 Constant.
266
267 @par Exception Safety
268 No-throw guarantee.
269
270 @param other Another pointer.
271
272 @{
273 */
274 storage_ptr&
275 2076649 operator=(
276 storage_ptr&& other) noexcept
277 {
278 2076649 release();
279 2076649 i_ = detail::exchange(other.i_, 0);
280 2076649 return *this;
281 }
282
283 storage_ptr&
284 1 operator=(
285 storage_ptr const& other) noexcept
286 {
287 1 other.addref();
288 1 release();
289 1 i_ = other.i_;
290 1 return *this;
291 }
292 /// @}
293
294 /** Check if ownership of the memory resource is shared.
295
296 This function returns true for memory resources created using @ref
297 make_shared_resource.
298 */
299 bool
300 50341763 is_shared() const noexcept
301 {
302 50341763 return (i_ & 1) != 0;
303 }
304
305 /** Check if calling `deallocate` on the memory resource has no effect.
306
307 This function is used to determine if the deallocate function of the
308 pointed to memory resource is trivial. The value of @ref
309 is_deallocate_trivial is evaluated and saved when the memory resource
310 is constructed and the type is known, before the type is erased.
311 */
312 bool
313 1 is_deallocate_trivial() const noexcept
314 {
315 1 return (i_ & 2) != 0;
316 }
317
318 /** Check if ownership of the memory resource is not shared and deallocate is trivial.
319
320 This function is used to determine if calls to deallocate can
321 effectively be skipped. Equivalent to `! is_shared() &&
322 is_deallocate_trivial()`.
323 */
324 bool
325 4323313 is_not_shared_and_deallocate_is_trivial() const noexcept
326 {
327 4323313 return (i_ & 3) == 2;
328 }
329
330 /** Return a pointer to the memory resource.
331
332 This function returns a pointer to the
333 referenced @ref boost::container::pmr::memory_resource.
334
335 @par Complexity
336 Constant.
337
338 @par Exception Safety
339 No-throw guarantee.
340 */
341 container::pmr::memory_resource*
342 652979 get() const noexcept
343 {
344
2/2
✓ Branch 0 taken 122565 times.
✓ Branch 1 taken 530414 times.
652979 if(i_ != 0)
345 return reinterpret_cast<
346 122565 container::pmr::memory_resource*>(i_ & ~3);
347 530414 return default_resource::get();
348 }
349
350 /** Return a pointer to the memory resource.
351
352 This function returns a pointer to the referenced @ref
353 boost::container::pmr::memory_resource.
354
355 @par Complexity
356 Constant.
357
358 @par Exception Safety
359 No-throw guarantee.
360 */
361 container::pmr::memory_resource*
362 649491 operator->() const noexcept
363 {
364 649491 return get();
365 }
366
367 /** Return a reference to the memory resource.
368
369 This function returns a reference to the pointed-to @ref
370 boost::container::pmr::memory_resource.
371
372 @par Complexity
373
374 Constant.
375
376 @par Exception Safety
377
378 No-throw guarantee.
379 */
380 container::pmr::memory_resource&
381 3456 operator*() const noexcept
382 {
383 3456 return *get();
384 }
385
386 template<class U, class... Args>
387 friend
388 storage_ptr
389 make_shared_resource(Args&&... args);
390 };
391
392 #if defined(_MSC_VER)
393 # pragma warning( push )
394 # if !defined(__clang__) && _MSC_VER <= 1900
395 # pragma warning( disable : 4702 )
396 # endif
397 #endif
398
399 /** Return a pointer that owns a new, dynamically allocated memory resource.
400
401 This function dynamically allocates a new memory resource as if by
402 `operator new` that uses shared ownership. The lifetime of the memory
403 resource will be extended until the last @ref storage_ptr which points to
404 it is destroyed.
405
406 @par Constraints
407 @code
408 std::is_base_of< boost::container::pmr::memory_resource, U >::value == true
409 @endcode
410
411 @par Complexity
412 Same as `new U( std::forward<Args>(args)... )`.
413
414 @par Exception Safety
415 Strong guarantee.
416
417 @tparam U The type of memory resource to create.
418
419 @param args Parameters forwarded to the constructor of `U`.
420 */
421 template<class U, class... Args>
422 storage_ptr
423 28 make_shared_resource(Args&&... args)
424 {
425 // If this generates an error, it means that
426 // `T` is not a memory resource.
427 BOOST_STATIC_ASSERT(
428 std::is_base_of<
429 container::pmr::memory_resource, U>::value);
430 31 return storage_ptr(new
431 detail::shared_resource_impl<U>(
432
2/3
✓ Branch 1 taken 13 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
29 std::forward<Args>(args)...));
433 }
434 #if defined(_MSC_VER)
435 # pragma warning( pop )
436 #endif
437
438 /// Overload
439 inline
440 bool
441 5 operator==(
442 storage_ptr const& lhs,
443 storage_ptr const& rhs) noexcept
444 {
445 5 return lhs.get() == rhs.get();
446 }
447
448 /// Overload
449 inline
450 bool
451 operator!=(
452 storage_ptr const& lhs,
453 storage_ptr const& rhs) noexcept
454 {
455 return lhs.get() != rhs.get();
456 }
457
458 } // namespace json
459 } // namespace boost
460
461 #endif
462