]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/json/storage_ptr.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / json / storage_ptr.hpp
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/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>
17 #include <cstddef>
18 #include <new>
19 #include <type_traits>
20 #include <utility>
21
22 BOOST_JSON_NS_BEGIN
23
24 /** A smart pointer to a @ref memory_resource
25
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:
33
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
40 deallocate.
41
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.
47
48 @par Examples
49
50 These statements create a memory resource on the
51 stack and construct a pointer from it without
52 taking ownership:
53 @code
54 monotonic_resource mr; // Create our memory resource on the stack
55 storage_ptr sp( &mr ); // Construct a non-owning pointer to the resource
56 @endcode
57
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:
62 @code
63 // Create a counted memory resource and return it
64 storage_ptr make_storage()
65 {
66 return make_shared_resource< monotonic_resource >();
67 }
68 @endcode
69
70 @par Thread Safety
71
72 Instances of this type provide the default level of
73 thread safety for all C++ objects. Specifically, it
74 conforms to
75 <a href="http://eel.is/c++draft/res.on.data.races">
76 16.4.6.10 Data race avoidance</a>.
77
78 @see
79 @ref make_shared_resource,
80 @ref memory_resource,
81 @ref polymorphic_allocator
82 */
83 class storage_ptr
84 {
85 #ifndef BOOST_JSON_DOCS
86 // VFALCO doc toolchain shows this when it shouldn't
87 friend struct detail::shared_resource;
88 #endif
89 using shared_resource =
90 detail::shared_resource;
91
92 using default_resource =
93 detail::default_resource;
94
95 std::uintptr_t i_;
96
97 shared_resource*
98 get_shared() const noexcept
99 {
100 return static_cast<shared_resource*>(
101 reinterpret_cast<memory_resource*>(
102 i_ & ~3));
103 }
104
105 void
106 addref() const noexcept
107 {
108 if(is_shared())
109 get_shared()->refs.fetch_add(
110 1, std::memory_order_relaxed);
111 }
112
113 void
114 release() const noexcept
115 {
116 if(is_shared())
117 {
118 auto const p = get_shared();
119 if(p->refs.fetch_sub(1,
120 std::memory_order_acq_rel) == 1)
121 delete p;
122 }
123 }
124
125 template<class T>
126 storage_ptr(
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))
131 {
132 BOOST_ASSERT(p);
133 }
134
135 public:
136 /** Destructor
137
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.
142
143 @par Complexity
144 Constant.
145
146 @par Exception Safety
147 No-throw guarantee.
148 */
149 ~storage_ptr()
150 {
151 release();
152 }
153
154 /** Constructor
155
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
159 free memory.
160
161 @par Complexity
162 Constant.
163
164 @par Exception Safety
165 No-throw guarantee.
166 */
167 storage_ptr() noexcept
168 : i_(0)
169 {
170 }
171
172 /** Constructor
173
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.
178
179 @par Constraints
180 @code
181 std::is_convertible< T*, memory_resource* >::value == true
182 @endcode
183
184 @par Preconditions
185 @code
186 r != nullptr
187 @endcode
188
189 @par Exception Safety
190 No-throw guarantee.
191
192 @param r A pointer to the memory resource to use.
193 This may not be null.
194 */
195 template<class T
196 #ifndef BOOST_JSON_DOCS
197 , class = typename std::enable_if<
198 std::is_convertible<T*,
199 memory_resource*>::value>::type
200 #endif
201 >
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))
206 {
207 BOOST_ASSERT(r);
208 }
209
210 /** Constructor
211
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.
217
218 @par Constraints
219 @code
220 std::is_convertible< T*, memory_resource* >::value == true
221 @endcode
222
223 @par Exception Safety
224 No-throw guarantee.
225
226 @param alloc A @ref polymorphic_allocator to
227 construct from.
228 */
229 template<class T>
230 storage_ptr(
231 polymorphic_allocator<T> const& alloc) noexcept
232 : i_(reinterpret_cast<std::uintptr_t>(
233 alloc.resource()))
234 {
235 }
236
237 /** Move constructor
238
239 This function constructs a pointer that
240 points to the same memory resource as `other`,
241 with the same ownership:
242
243 @li If `other` is non-owning, then `*this`
244 will be be non-owning.
245
246 @li If `other` has shared ownership, then
247 ownership will be transferred to `*this`.
248
249 After construction, `other` will point
250 to the default memory resource.
251
252 @par Complexity
253 Constant.
254
255 @par Exception Safety
256 No-throw guarantee.
257
258 @param other The pointer to construct from.
259 */
260 storage_ptr(
261 storage_ptr&& other) noexcept
262 : i_(detail::exchange(other.i_, 0))
263 {
264 }
265
266 /** Copy constructor
267
268 This function constructs a pointer that
269 points to the same memory resource as `other`,
270 with the same ownership:
271
272 @li If `other` is non-owning, then `*this`
273 will be be non-owning.
274
275 @li If `other` has shared ownership, then
276 `*this` will acquire shared ownership.
277
278 @par Complexity
279 Constant.
280
281 @par Exception Safety
282 No-throw guarantee.
283
284 @param other The pointer to construct from.
285 */
286 storage_ptr(
287 storage_ptr const& other) noexcept
288 : i_(other.i_)
289 {
290 addref();
291 }
292
293 /** Move assignment
294
295 This function assigns a pointer that
296 points to the same memory resource as `other`,
297 with the same ownership:
298
299 @li If `other` is non-owning, then `*this`
300 will be be non-owning.
301
302 @li If `other` has shared ownership, then
303 ownership will be transferred to `*this`.
304
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.
309
310 @par Complexity
311 Constant.
312
313 @par Exception Safety
314 No-throw guarantee.
315
316 @param other The storage pointer to move.
317 */
318 storage_ptr&
319 operator=(
320 storage_ptr&& other) noexcept
321 {
322 release();
323 i_ = detail::exchange(other.i_, 0);
324 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 operator=(
352 storage_ptr const& other) noexcept
353 {
354 other.addref();
355 release();
356 i_ = other.i_;
357 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 is_shared() const noexcept
367 {
368 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 is_deallocate_trivial() const noexcept
381 {
382 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 is_not_shared_and_deallocate_is_trivial() const noexcept
395 {
396 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 @ref memory_resource.
403
404 @par Complexity
405 Constant.
406
407 @par Exception Safety
408 No-throw guarantee.
409 */
410 memory_resource*
411 get() const noexcept
412 {
413 if(i_ != 0)
414 return reinterpret_cast<
415 memory_resource*>(i_ & ~3);
416 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 @ref memory_resource.
423
424 @par Complexity
425 Constant.
426
427 @par Exception Safety
428 No-throw guarantee.
429 */
430 memory_resource*
431 operator->() const noexcept
432 {
433 return get();
434 }
435
436 /** Return a reference to the memory resource.
437
438 This function returns a reference to the
439 pointed-to @ref memory_resource.
440
441 @par Complexity
442
443 Constant.
444
445 @par Exception Safety
446
447 No-throw guarantee.
448 */
449 memory_resource&
450 operator*() const noexcept
451 {
452 return *get();
453 }
454
455 template<class U, class... Args>
456 friend
457 storage_ptr
458 make_shared_resource(Args&&... args);
459 };
460
461 /** Return shared ownership of a new, dynamically allocated memory resource.
462
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.
467
468 @par Mandates
469 @code
470 std::is_base_of< memory_resource, T >::value == true
471 @endcode
472
473 @par Complexity
474 Same as `new T( std::forward<Args>(args)... )`.
475
476 @par Exception Safety
477 Strong guarantee.
478
479 @tparam T The type of memory resource to create.
480
481 @param args Parameters forwarded to the constructor of `T`.
482 */
483 template<class T, class... Args>
484 storage_ptr
485 make_shared_resource(Args&&... args)
486 {
487 // If this generates an error, it means that
488 // `T` is not a memory resource.
489 BOOST_STATIC_ASSERT(
490 std::is_base_of<
491 memory_resource, T>::value);
492 return storage_ptr(new
493 detail::shared_resource_impl<T>(
494 std::forward<Args>(args)...));
495 }
496
497 /** Return true if two storage pointers point to the same memory resource.
498
499 This function returns `true` if the @ref memory_resource
500 objects pointed to by `lhs` and `rhs` have the
501 same address.
502 */
503 inline
504 bool
505 operator==(
506 storage_ptr const& lhs,
507 storage_ptr const& rhs) noexcept
508 {
509 return lhs.get() == rhs.get();
510 }
511
512 /** Return true if two storage pointers point to different memory resources.
513
514 This function returns `true` if the @ref memory_resource
515 objects pointed to by `lhs` and `rhs` have different
516 addresses.
517 */
518 inline
519 bool
520 operator!=(
521 storage_ptr const& lhs,
522 storage_ptr const& rhs) noexcept
523 {
524 return lhs.get() != rhs.get();
525 }
526
527 BOOST_JSON_NS_END
528
529 #endif