storage_ptr.hpp

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