2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
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)
7 // Official repository: https://github.com/boostorg/json
10 #ifndef BOOST_JSON_STORAGE_PTR_HPP
11 #define BOOST_JSON_STORAGE_PTR_HPP
13 #include <boost/json/detail/config.hpp>
14 #include <boost/json/memory_resource.hpp>
15 #include <boost/json/detail/shared_resource.hpp>
16 #include <boost/json/detail/default_resource.hpp>
19 #include <type_traits>
24 /** A smart pointer to a @ref memory_resource
26 This container is used to hold a pointer to a
27 memory resource. The pointed-to resource is
28 always valid; default-constructed pointers
29 use the default memory resource, which calls
30 into the standard global system heap.
31 Depending on the means of construction, the
32 ownership will be either:
34 @li Non-owning, when constructing from a raw
35 pointer to @ref memory_resource or from a
36 @ref polymorphic_allocator. In this case the
37 caller is responsible for ensuring that the
38 lifetime of the memory resource extends until
39 there are no more calls to allocate or
42 @li Owning, when constructing using the function
43 @ref make_shared_resource. In this case
44 ownership is shared; the lifetime of the memory
45 resource extends until the last copy of the
46 @ref storage_ptr is destroyed.
50 These statements create a memory resource on the
51 stack and construct a pointer from it without
54 monotonic_resource mr; // Create our memory resource on the stack
55 storage_ptr sp( &mr ); // Construct a non-owning pointer to the resource
58 This function creates a pointer to a memory
59 resource using shared ownership and returns it.
60 The lifetime of the memory resource extends until
61 the last copy of the pointer is destroyed:
63 // Create a counted memory resource and return it
64 storage_ptr make_storage()
66 return make_shared_resource< monotonic_resource >();
72 Instances of this type provide the default level of
73 thread safety for all C++ objects. Specifically, it
75 <a href="http://eel.is/c++draft/res.on.data.races">
76 16.4.6.10 Data race avoidance</a>.
79 @ref make_shared_resource,
81 @ref polymorphic_allocator
85 #ifndef BOOST_JSON_DOCS
86 // VFALCO doc toolchain shows this when it shouldn't
87 friend struct detail::shared_resource;
89 using shared_resource =
90 detail::shared_resource;
92 using default_resource =
93 detail::default_resource;
98 get_shared() const noexcept
100 return static_cast<shared_resource*>(
101 reinterpret_cast<memory_resource*>(
106 addref() const noexcept
109 get_shared()->refs.fetch_add(
110 1, std::memory_order_relaxed);
114 release() const noexcept
118 auto const p = get_shared();
119 if(p->refs.fetch_sub(1,
120 std::memory_order_acq_rel) == 1)
127 detail::shared_resource_impl<T>* p) noexcept
128 : i_(reinterpret_cast<std::uintptr_t>(
129 static_cast<memory_resource*>(p)) + 1 +
130 (json::is_deallocate_trivial<T>::value ? 2 : 0))
138 If the pointer has shared ownership of the
139 resource, the shared ownership is released.
140 If this is the last owned copy, the memory
141 resource is destroyed.
146 @par Exception Safety
156 This constructs a non-owning pointer that refers
157 to the default memory resource, which uses the
158 standard global system heap to allocate and
164 @par Exception Safety
167 storage_ptr() noexcept
174 This constructs a non-owning pointer that
175 points to the memory resource `r`.
176 The caller is responsible for maintaining the
177 lifetime of the pointed-to @ref memory_resource.
181 std::is_convertible< T*, memory_resource* >::value == true
189 @par Exception Safety
192 @param r A pointer to the memory resource to use.
193 This may not be null.
196 #ifndef BOOST_JSON_DOCS
197 , class = typename std::enable_if<
198 std::is_convertible<T*,
199 memory_resource*>::value>::type
202 storage_ptr(T* r) noexcept
203 : i_(reinterpret_cast<std::uintptr_t>(
204 static_cast<memory_resource *>(r)) +
205 (json::is_deallocate_trivial<T>::value ? 2 : 0))
212 This constructs a non-owning pointer that
213 points to the same memory resource as `alloc`,
214 obtained by calling `alloc.resource()`.
215 The caller is responsible for maintaining the
216 lifetime of the pointed-to @ref memory_resource.
220 std::is_convertible< T*, memory_resource* >::value == true
223 @par Exception Safety
226 @param alloc A @ref polymorphic_allocator to
231 polymorphic_allocator<T> const& alloc) noexcept
232 : i_(reinterpret_cast<std::uintptr_t>(
239 This function constructs a pointer that
240 points to the same memory resource as `other`,
241 with the same ownership:
243 @li If `other` is non-owning, then `*this`
244 will be be non-owning.
246 @li If `other` has shared ownership, then
247 ownership will be transferred to `*this`.
249 After construction, `other` will point
250 to the default memory resource.
255 @par Exception Safety
258 @param other The pointer to construct from.
261 storage_ptr&& other) noexcept
262 : i_(detail::exchange(other.i_, 0))
268 This function constructs a pointer that
269 points to the same memory resource as `other`,
270 with the same ownership:
272 @li If `other` is non-owning, then `*this`
273 will be be non-owning.
275 @li If `other` has shared ownership, then
276 `*this` will acquire shared ownership.
281 @par Exception Safety
284 @param other The pointer to construct from.
287 storage_ptr const& other) noexcept
295 This function assigns a pointer that
296 points to the same memory resource as `other`,
297 with the same ownership:
299 @li If `other` is non-owning, then `*this`
300 will be be non-owning.
302 @li If `other` has shared ownership, then
303 ownership will be transferred to `*this`.
305 After assignment, `other` will point
306 to the default memory resource.
307 If `*this` previously had shared ownership,
308 it is released before the function returns.
313 @par Exception Safety
316 @param other The storage pointer to move.
320 storage_ptr&& other) noexcept
323 i_ = detail::exchange(other.i_, 0);
329 This function assigns a pointer that
330 points to the same memory resource as `other`,
331 with the same ownership:
333 @li If `other` is non-owning, then `*this`
334 will be be non-owning.
336 @li If `other` has shared ownership, then
337 `*this` will acquire shared ownership.
339 If `*this` previously had shared ownership,
340 it is released before the function returns.
345 @par Exception Safety
348 @param other The storage pointer to copy.
352 storage_ptr const& other) noexcept
360 /** Return `true` if ownership of the memory resource is shared.
362 This function returns true for memory resources
363 created using @ref make_shared_resource.
366 is_shared() const noexcept
368 return (i_ & 1) != 0;
371 /** Return `true` if calling `deallocate` on the memory resource has no effect.
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.
380 is_deallocate_trivial() const noexcept
382 return (i_ & 2) != 0;
385 /** Return `true` if ownership of the memory resource is not shared and deallocate is trivial.
387 This function is used to determine if calls to deallocate
388 can effectively be skipped.
391 Returns `! this->is_shared() && this->is_deallocate_trivial()`
394 is_not_shared_and_deallocate_is_trivial() const noexcept
396 return (i_ & 3) == 2;
399 /** Return a pointer to the memory resource.
401 This function returns a pointer to the
402 referenced @ref memory_resource.
407 @par Exception Safety
414 return reinterpret_cast<
415 memory_resource*>(i_ & ~3);
416 return default_resource::get();
419 /** Return a pointer to the memory resource.
421 This function returns a pointer to the
422 referenced @ref memory_resource.
427 @par Exception Safety
431 operator->() const noexcept
436 /** Return a reference to the memory resource.
438 This function returns a reference to the
439 pointed-to @ref memory_resource.
445 @par Exception Safety
450 operator*() const noexcept
455 template<class U, class... Args>
458 make_shared_resource(Args&&... args);
461 /** Return shared ownership of a new, dynamically allocated memory resource.
463 This function dynamically allocates a new memory resource
464 as if by `operator new` that uses shared ownership. The
465 lifetime of the memory resource will be extended until
466 the last @ref storage_ptr which points to it is destroyed.
470 std::is_base_of< memory_resource, T >::value == true
474 Same as `new T( std::forward<Args>(args)... )`.
476 @par Exception Safety
479 @tparam T The type of memory resource to create.
481 @param args Parameters forwarded to the constructor of `T`.
483 template<class T, class... Args>
485 make_shared_resource(Args&&... args)
487 // If this generates an error, it means that
488 // `T` is not a memory resource.
491 memory_resource, T>::value);
492 return storage_ptr(new
493 detail::shared_resource_impl<T>(
494 std::forward<Args>(args)...));
497 /** Return true if two storage pointers point to the same memory resource.
499 This function returns `true` if the @ref memory_resource
500 objects pointed to by `lhs` and `rhs` have the
506 storage_ptr const& lhs,
507 storage_ptr const& rhs) noexcept
509 return lhs.get() == rhs.get();
512 /** Return true if two storage pointers point to different memory resources.
514 This function returns `true` if the @ref memory_resource
515 objects pointed to by `lhs` and `rhs` have different
521 storage_ptr const& lhs,
522 storage_ptr const& rhs) noexcept
524 return lhs.get() != rhs.get();