]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* |
2 | * This file is open source software, licensed to you under the terms | |
3 | * of the Apache License, Version 2.0 (the "License"). See the NOTICE file | |
4 | * distributed with this work for additional information regarding copyright | |
5 | * ownership. You may not use this file except in compliance with the License. | |
6 | * | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, | |
12 | * software distributed under the License is distributed on an | |
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
14 | * KIND, either express or implied. See the License for the | |
15 | * specific language governing permissions and limitations | |
16 | * under the License. | |
17 | */ | |
18 | /* | |
19 | * Copyright (C) 2014 Cloudius Systems, Ltd. | |
20 | */ | |
21 | ||
22 | #pragma once | |
23 | ||
24 | #include <seastar/core/shared_ptr_debug_helper.hh> | |
25 | #include <utility> | |
26 | #include <type_traits> | |
27 | #include <functional> | |
28 | #include <ostream> | |
29 | #include <seastar/util/is_smart_ptr.hh> | |
30 | #include <seastar/util/indirect.hh> | |
31 | ||
32 | #include <boost/intrusive/parent_from_member.hpp> | |
33 | ||
1e59de90 TL |
34 | #if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 12) |
35 | // to silence the false alarm from GCC 12, see | |
36 | // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105204 | |
37 | #define SEASTAR_IGNORE_USE_AFTER_FREE | |
38 | #endif | |
39 | ||
11fdf7f2 TL |
40 | namespace seastar { |
41 | ||
42 | // This header defines two shared pointer facilities, lw_shared_ptr<> and | |
43 | // shared_ptr<>, both modeled after std::shared_ptr<>. | |
44 | // | |
45 | // Unlike std::shared_ptr<>, neither of these implementations are thread | |
46 | // safe, and two pointers sharing the same object must not be used in | |
47 | // different threads. | |
48 | // | |
49 | // lw_shared_ptr<> is the more lightweight variant, with a lw_shared_ptr<> | |
50 | // occupying just one machine word, and adding just one word to the shared | |
51 | // object. However, it does not support polymorphism. | |
52 | // | |
53 | // shared_ptr<> is more expensive, with a pointer occupying two machine | |
54 | // words, and with two words of overhead in the shared object. In return, | |
55 | // it does support polymorphism. | |
56 | // | |
57 | // Both variants support shared_from_this() via enable_shared_from_this<> | |
58 | // and lw_enable_shared_from_this<>(). | |
59 | // | |
60 | ||
61 | #ifndef SEASTAR_DEBUG_SHARED_PTR | |
62 | using shared_ptr_counter_type = long; | |
63 | #else | |
64 | using shared_ptr_counter_type = debug_shared_ptr_counter_type; | |
65 | #endif | |
66 | ||
67 | template <typename T> | |
68 | class lw_shared_ptr; | |
69 | ||
70 | template <typename T> | |
71 | class shared_ptr; | |
72 | ||
73 | template <typename T> | |
74 | class enable_lw_shared_from_this; | |
75 | ||
76 | template <typename T> | |
77 | class enable_shared_from_this; | |
78 | ||
79 | template <typename T, typename... A> | |
80 | lw_shared_ptr<T> make_lw_shared(A&&... a); | |
81 | ||
82 | template <typename T> | |
83 | lw_shared_ptr<T> make_lw_shared(T&& a); | |
84 | ||
85 | template <typename T> | |
86 | lw_shared_ptr<T> make_lw_shared(T& a); | |
87 | ||
88 | template <typename T, typename... A> | |
89 | shared_ptr<T> make_shared(A&&... a); | |
90 | ||
91 | template <typename T> | |
92 | shared_ptr<T> make_shared(T&& a); | |
93 | ||
94 | template <typename T, typename U> | |
95 | shared_ptr<T> static_pointer_cast(const shared_ptr<U>& p); | |
96 | ||
97 | template <typename T, typename U> | |
98 | shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& p); | |
99 | ||
100 | template <typename T, typename U> | |
101 | shared_ptr<T> const_pointer_cast(const shared_ptr<U>& p); | |
102 | ||
103 | struct lw_shared_ptr_counter_base { | |
104 | shared_ptr_counter_type _count = 0; | |
105 | }; | |
106 | ||
107 | ||
108 | namespace internal { | |
109 | ||
110 | template <class T, class U> | |
111 | struct lw_shared_ptr_accessors; | |
112 | ||
113 | template <class T> | |
114 | struct lw_shared_ptr_accessors_esft; | |
115 | ||
116 | template <class T> | |
117 | struct lw_shared_ptr_accessors_no_esft; | |
118 | ||
119 | } | |
120 | ||
121 | ||
122 | // We want to support two use cases for shared_ptr<T>: | |
123 | // | |
124 | // 1. T is any type (primitive or class type) | |
125 | // | |
126 | // 2. T is a class type that inherits from enable_shared_from_this<T>. | |
127 | // | |
128 | // In the first case, we must wrap T in an object containing the counter, | |
129 | // since T may be a primitive type and cannot be a base class. | |
130 | // | |
131 | // In the second case, we want T to reach the counter through its | |
132 | // enable_shared_from_this<> base class, so that we can implement | |
133 | // shared_from_this(). | |
134 | // | |
135 | // To implement those two conflicting requirements (T alongside its counter; | |
136 | // T inherits from an object containing the counter) we use std::conditional<> | |
137 | // and some accessor functions to select between two implementations. | |
138 | ||
139 | ||
140 | // CRTP from this to enable shared_from_this: | |
141 | template <typename T> | |
142 | class enable_lw_shared_from_this : private lw_shared_ptr_counter_base { | |
143 | using ctor = T; | |
144 | protected: | |
145 | enable_lw_shared_from_this() noexcept {} | |
146 | enable_lw_shared_from_this(enable_lw_shared_from_this&&) noexcept {} | |
147 | enable_lw_shared_from_this(const enable_lw_shared_from_this&) noexcept {} | |
148 | enable_lw_shared_from_this& operator=(const enable_lw_shared_from_this&) noexcept { return *this; } | |
149 | enable_lw_shared_from_this& operator=(enable_lw_shared_from_this&&) noexcept { return *this; } | |
150 | public: | |
20effc67 TL |
151 | lw_shared_ptr<T> shared_from_this() noexcept; |
152 | lw_shared_ptr<const T> shared_from_this() const noexcept; | |
f67539c2 | 153 | long use_count() const noexcept { return _count; } |
11fdf7f2 TL |
154 | |
155 | template <typename X> | |
156 | friend class lw_shared_ptr; | |
157 | template <typename X> | |
9f95a23c | 158 | friend struct internal::lw_shared_ptr_accessors_esft; |
11fdf7f2 | 159 | template <typename X, class Y> |
9f95a23c | 160 | friend struct internal::lw_shared_ptr_accessors; |
11fdf7f2 TL |
161 | }; |
162 | ||
163 | template <typename T> | |
1e59de90 | 164 | struct lw_shared_ptr_no_esft : private lw_shared_ptr_counter_base { |
11fdf7f2 TL |
165 | T _value; |
166 | ||
1e59de90 TL |
167 | lw_shared_ptr_no_esft() = default; |
168 | lw_shared_ptr_no_esft(const T& x) : _value(x) {} | |
169 | lw_shared_ptr_no_esft(T&& x) : _value(std::move(x)) {} | |
11fdf7f2 | 170 | template <typename... A> |
1e59de90 | 171 | lw_shared_ptr_no_esft(A&&... a) : _value(std::forward<A>(a)...) {} |
11fdf7f2 TL |
172 | |
173 | template <typename X> | |
174 | friend class lw_shared_ptr; | |
175 | template <typename X> | |
9f95a23c | 176 | friend struct internal::lw_shared_ptr_accessors_no_esft; |
11fdf7f2 | 177 | template <typename X, class Y> |
9f95a23c | 178 | friend struct internal::lw_shared_ptr_accessors; |
11fdf7f2 TL |
179 | }; |
180 | ||
181 | ||
182 | /// Extension point: the user may override this to change how \ref lw_shared_ptr objects are destroyed, | |
183 | /// primarily so that incomplete classes can be used. | |
184 | /// | |
185 | /// Customizing the deleter requires that \c T be derived from \c enable_lw_shared_from_this<T>. | |
186 | /// The specialization must be visible for all uses of \c lw_shared_ptr<T>. | |
187 | /// | |
188 | /// To customize, the template must have a `static void dispose(T*)` operator that disposes of | |
189 | /// the object. | |
190 | template <typename T> | |
191 | struct lw_shared_ptr_deleter; // No generic implementation | |
192 | ||
193 | namespace internal { | |
194 | ||
195 | template <typename T> | |
196 | struct lw_shared_ptr_accessors_esft { | |
197 | using concrete_type = std::remove_const_t<T>; | |
198 | static T* to_value(lw_shared_ptr_counter_base* counter) { | |
199 | return static_cast<T*>(counter); | |
200 | } | |
201 | static void dispose(lw_shared_ptr_counter_base* counter) { | |
202 | dispose(static_cast<T*>(counter)); | |
203 | } | |
204 | static void dispose(T* value_ptr) { | |
205 | delete value_ptr; | |
206 | } | |
1e59de90 | 207 | static void instantiate_to_value(lw_shared_ptr_counter_base*) { |
11fdf7f2 TL |
208 | // since to_value() is defined above, we don't need to do anything special |
209 | // to force-instantiate it | |
210 | } | |
211 | }; | |
212 | ||
213 | template <typename T> | |
214 | struct lw_shared_ptr_accessors_no_esft { | |
1e59de90 | 215 | using concrete_type = lw_shared_ptr_no_esft<T>; |
11fdf7f2 TL |
216 | static T* to_value(lw_shared_ptr_counter_base* counter) { |
217 | return &static_cast<concrete_type*>(counter)->_value; | |
218 | } | |
219 | static void dispose(lw_shared_ptr_counter_base* counter) { | |
220 | delete static_cast<concrete_type*>(counter); | |
221 | } | |
222 | static void dispose(T* value_ptr) { | |
223 | delete boost::intrusive::get_parent_from_member(value_ptr, &concrete_type::_value); | |
224 | } | |
1e59de90 | 225 | static void instantiate_to_value(lw_shared_ptr_counter_base*) { |
11fdf7f2 TL |
226 | // since to_value() is defined above, we don't need to do anything special |
227 | // to force-instantiate it | |
228 | } | |
229 | }; | |
230 | ||
231 | // Generic case: lw_shared_ptr_deleter<T> is not specialized, select | |
232 | // implementation based on whether T inherits from enable_lw_shared_from_this<T>. | |
233 | template <typename T, typename U = void> | |
234 | struct lw_shared_ptr_accessors : std::conditional_t< | |
235 | std::is_base_of<enable_lw_shared_from_this<T>, T>::value, | |
236 | lw_shared_ptr_accessors_esft<T>, | |
237 | lw_shared_ptr_accessors_no_esft<T>> { | |
238 | }; | |
239 | ||
240 | // void_t is C++17, use this temporarily | |
241 | template <typename... T> | |
242 | using void_t = void; | |
243 | ||
244 | // Overload when lw_shared_ptr_deleter<T> specialized | |
245 | template <typename T> | |
246 | struct lw_shared_ptr_accessors<T, void_t<decltype(lw_shared_ptr_deleter<T>{})>> { | |
247 | using concrete_type = T; | |
248 | static T* to_value(lw_shared_ptr_counter_base* counter); | |
249 | static void dispose(lw_shared_ptr_counter_base* counter) { | |
250 | lw_shared_ptr_deleter<T>::dispose(to_value(counter)); | |
251 | } | |
252 | static void instantiate_to_value(lw_shared_ptr_counter_base* p) { | |
253 | // instantiate to_value(); must be defined by shared_ptr_incomplete.hh | |
254 | to_value(p); | |
255 | } | |
256 | }; | |
257 | ||
258 | } | |
259 | ||
260 | template <typename T> | |
261 | class lw_shared_ptr { | |
1e59de90 TL |
262 | template <typename U> |
263 | using accessors = internal::lw_shared_ptr_accessors<std::remove_const_t<U>>; | |
264 | ||
11fdf7f2 TL |
265 | mutable lw_shared_ptr_counter_base* _p = nullptr; |
266 | private: | |
267 | lw_shared_ptr(lw_shared_ptr_counter_base* p) noexcept : _p(p) { | |
268 | if (_p) { | |
269 | ++_p->_count; | |
270 | } | |
271 | } | |
272 | template <typename... A> | |
273 | static lw_shared_ptr make(A&&... a) { | |
1e59de90 TL |
274 | auto p = new typename accessors<T>::concrete_type(std::forward<A>(a)...); |
275 | accessors<T>::instantiate_to_value(p); | |
11fdf7f2 TL |
276 | return lw_shared_ptr(p); |
277 | } | |
278 | public: | |
279 | using element_type = T; | |
280 | ||
281 | // Destroys the object pointed to by p and disposes of its storage. | |
282 | // The pointer to the object must have been obtained through release(). | |
283 | static void dispose(T* p) noexcept { | |
1e59de90 | 284 | accessors<T>::dispose(const_cast<std::remove_const_t<T>*>(p)); |
11fdf7f2 TL |
285 | } |
286 | ||
287 | // A functor which calls dispose(). | |
288 | class disposer { | |
289 | public: | |
290 | void operator()(T* p) const noexcept { | |
291 | dispose(p); | |
292 | } | |
293 | }; | |
294 | ||
295 | lw_shared_ptr() noexcept = default; | |
296 | lw_shared_ptr(std::nullptr_t) noexcept : lw_shared_ptr() {} | |
297 | lw_shared_ptr(const lw_shared_ptr& x) noexcept : _p(x._p) { | |
298 | if (_p) { | |
1e59de90 TL |
299 | #pragma GCC diagnostic push |
300 | #ifdef SEASTAR_IGNORE_USE_AFTER_FREE | |
301 | #pragma GCC diagnostic ignored "-Wuse-after-free" | |
302 | #endif | |
11fdf7f2 | 303 | ++_p->_count; |
1e59de90 | 304 | #pragma GCC diagnostic pop |
11fdf7f2 TL |
305 | } |
306 | } | |
307 | lw_shared_ptr(lw_shared_ptr&& x) noexcept : _p(x._p) { | |
308 | x._p = nullptr; | |
309 | } | |
310 | [[gnu::always_inline]] | |
311 | ~lw_shared_ptr() { | |
1e59de90 TL |
312 | #pragma GCC diagnostic push |
313 | #ifdef SEASTAR_IGNORE_USE_AFTER_FREE | |
314 | #pragma GCC diagnostic ignored "-Wuse-after-free" | |
315 | #endif | |
11fdf7f2 | 316 | if (_p && !--_p->_count) { |
1e59de90 | 317 | accessors<T>::dispose(_p); |
11fdf7f2 | 318 | } |
1e59de90 | 319 | #pragma GCC diagnostic pop |
11fdf7f2 TL |
320 | } |
321 | lw_shared_ptr& operator=(const lw_shared_ptr& x) noexcept { | |
322 | if (_p != x._p) { | |
323 | this->~lw_shared_ptr(); | |
324 | new (this) lw_shared_ptr(x); | |
325 | } | |
326 | return *this; | |
327 | } | |
328 | lw_shared_ptr& operator=(lw_shared_ptr&& x) noexcept { | |
329 | if (_p != x._p) { | |
330 | this->~lw_shared_ptr(); | |
331 | new (this) lw_shared_ptr(std::move(x)); | |
332 | } | |
333 | return *this; | |
334 | } | |
335 | lw_shared_ptr& operator=(std::nullptr_t) noexcept { | |
336 | return *this = lw_shared_ptr(); | |
337 | } | |
338 | lw_shared_ptr& operator=(T&& x) noexcept { | |
339 | this->~lw_shared_ptr(); | |
340 | new (this) lw_shared_ptr(make_lw_shared<T>(std::move(x))); | |
341 | return *this; | |
342 | } | |
343 | ||
1e59de90 TL |
344 | T& operator*() const noexcept { return *accessors<T>::to_value(_p); } |
345 | T* operator->() const noexcept { return accessors<T>::to_value(_p); } | |
11fdf7f2 TL |
346 | T* get() const noexcept { |
347 | if (_p) { | |
1e59de90 | 348 | return accessors<T>::to_value(_p); |
11fdf7f2 TL |
349 | } else { |
350 | return nullptr; | |
351 | } | |
352 | } | |
353 | ||
354 | // Releases ownership of the object without destroying it. | |
355 | // If this was the last owner then returns an engaged unique_ptr | |
356 | // which is now the sole owner of the object. | |
357 | // Returns a disengaged pointer if there are still some owners. | |
358 | // | |
359 | // Note that in case the raw pointer is extracted from the unique_ptr | |
360 | // using unique_ptr::release(), it must be still destroyed using | |
361 | // lw_shared_ptr::disposer or lw_shared_ptr::dispose(). | |
362 | std::unique_ptr<T, disposer> release() noexcept { | |
363 | auto p = std::exchange(_p, nullptr); | |
364 | if (--p->_count) { | |
365 | return nullptr; | |
366 | } else { | |
1e59de90 | 367 | return std::unique_ptr<T, disposer>(accessors<T>::to_value(p)); |
11fdf7f2 TL |
368 | } |
369 | } | |
370 | ||
371 | long int use_count() const noexcept { | |
372 | if (_p) { | |
373 | return _p->_count; | |
374 | } else { | |
375 | return 0; | |
376 | } | |
377 | } | |
378 | ||
379 | operator lw_shared_ptr<const T>() const noexcept { | |
380 | return lw_shared_ptr<const T>(_p); | |
381 | } | |
382 | ||
383 | explicit operator bool() const noexcept { | |
384 | return _p; | |
385 | } | |
386 | ||
387 | bool owned() const noexcept { | |
388 | return _p->_count == 1; | |
389 | } | |
390 | ||
391 | bool operator==(const lw_shared_ptr<const T>& x) const { | |
392 | return _p == x._p; | |
393 | } | |
394 | ||
395 | bool operator!=(const lw_shared_ptr<const T>& x) const { | |
396 | return !operator==(x); | |
397 | } | |
398 | ||
399 | bool operator==(const lw_shared_ptr<std::remove_const_t<T>>& x) const { | |
400 | return _p == x._p; | |
401 | } | |
402 | ||
403 | bool operator!=(const lw_shared_ptr<std::remove_const_t<T>>& x) const { | |
404 | return !operator==(x); | |
405 | } | |
406 | ||
407 | bool operator<(const lw_shared_ptr<const T>& x) const { | |
408 | return _p < x._p; | |
409 | } | |
410 | ||
411 | bool operator<(const lw_shared_ptr<std::remove_const_t<T>>& x) const { | |
412 | return _p < x._p; | |
413 | } | |
414 | ||
415 | template <typename U> | |
416 | friend class lw_shared_ptr; | |
417 | ||
418 | template <typename X, typename... A> | |
419 | friend lw_shared_ptr<X> make_lw_shared(A&&...); | |
420 | ||
421 | template <typename U> | |
422 | friend lw_shared_ptr<U> make_lw_shared(U&&); | |
423 | ||
424 | template <typename U> | |
425 | friend lw_shared_ptr<U> make_lw_shared(U&); | |
426 | ||
427 | template <typename U> | |
428 | friend class enable_lw_shared_from_this; | |
429 | }; | |
430 | ||
431 | template <typename T, typename... A> | |
432 | inline | |
433 | lw_shared_ptr<T> make_lw_shared(A&&... a) { | |
434 | return lw_shared_ptr<T>::make(std::forward<A>(a)...); | |
435 | } | |
436 | ||
437 | template <typename T> | |
438 | inline | |
439 | lw_shared_ptr<T> make_lw_shared(T&& a) { | |
440 | return lw_shared_ptr<T>::make(std::move(a)); | |
441 | } | |
442 | ||
443 | template <typename T> | |
444 | inline | |
445 | lw_shared_ptr<T> make_lw_shared(T& a) { | |
446 | return lw_shared_ptr<T>::make(a); | |
447 | } | |
448 | ||
449 | template <typename T> | |
450 | inline | |
451 | lw_shared_ptr<T> | |
20effc67 | 452 | enable_lw_shared_from_this<T>::shared_from_this() noexcept { |
11fdf7f2 TL |
453 | return lw_shared_ptr<T>(this); |
454 | } | |
455 | ||
456 | template <typename T> | |
457 | inline | |
458 | lw_shared_ptr<const T> | |
20effc67 | 459 | enable_lw_shared_from_this<T>::shared_from_this() const noexcept { |
11fdf7f2 TL |
460 | return lw_shared_ptr<const T>(const_cast<enable_lw_shared_from_this*>(this)); |
461 | } | |
462 | ||
463 | template <typename T> | |
464 | static inline | |
465 | std::ostream& operator<<(std::ostream& out, const lw_shared_ptr<T>& p) { | |
466 | if (!p) { | |
467 | return out << "null"; | |
468 | } | |
469 | return out << *p; | |
470 | } | |
471 | ||
472 | // Polymorphic shared pointer class | |
473 | ||
474 | struct shared_ptr_count_base { | |
475 | // destructor is responsible for fully-typed deletion | |
476 | virtual ~shared_ptr_count_base() {} | |
477 | shared_ptr_counter_type count = 0; | |
478 | }; | |
479 | ||
480 | template <typename T> | |
481 | struct shared_ptr_count_for : shared_ptr_count_base { | |
482 | T data; | |
483 | template <typename... A> | |
484 | shared_ptr_count_for(A&&... a) : data(std::forward<A>(a)...) {} | |
485 | }; | |
486 | ||
487 | template <typename T> | |
488 | class enable_shared_from_this : private shared_ptr_count_base { | |
489 | public: | |
20effc67 TL |
490 | shared_ptr<T> shared_from_this() noexcept; |
491 | shared_ptr<const T> shared_from_this() const noexcept; | |
f67539c2 | 492 | long use_count() const noexcept { return count; } |
11fdf7f2 TL |
493 | |
494 | template <typename U> | |
495 | friend class shared_ptr; | |
496 | ||
497 | template <typename U, bool esft> | |
498 | friend struct shared_ptr_make_helper; | |
499 | }; | |
500 | ||
501 | template <typename T> | |
502 | class shared_ptr { | |
503 | mutable shared_ptr_count_base* _b = nullptr; | |
504 | mutable T* _p = nullptr; | |
505 | private: | |
506 | explicit shared_ptr(shared_ptr_count_for<T>* b) noexcept : _b(b), _p(&b->data) { | |
507 | ++_b->count; | |
508 | } | |
509 | shared_ptr(shared_ptr_count_base* b, T* p) noexcept : _b(b), _p(p) { | |
510 | if (_b) { | |
511 | ++_b->count; | |
512 | } | |
513 | } | |
514 | explicit shared_ptr(enable_shared_from_this<std::remove_const_t<T>>* p) noexcept : _b(p), _p(static_cast<T*>(p)) { | |
515 | if (_b) { | |
516 | ++_b->count; | |
517 | } | |
518 | } | |
519 | public: | |
520 | using element_type = T; | |
521 | ||
522 | shared_ptr() noexcept = default; | |
523 | shared_ptr(std::nullptr_t) noexcept : shared_ptr() {} | |
524 | shared_ptr(const shared_ptr& x) noexcept | |
525 | : _b(x._b) | |
526 | , _p(x._p) { | |
527 | if (_b) { | |
528 | ++_b->count; | |
529 | } | |
530 | } | |
531 | shared_ptr(shared_ptr&& x) noexcept | |
532 | : _b(x._b) | |
533 | , _p(x._p) { | |
534 | x._b = nullptr; | |
535 | x._p = nullptr; | |
536 | } | |
537 | template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>> | |
538 | shared_ptr(const shared_ptr<U>& x) noexcept | |
539 | : _b(x._b) | |
540 | , _p(x._p) { | |
541 | if (_b) { | |
542 | ++_b->count; | |
543 | } | |
544 | } | |
545 | template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>> | |
546 | shared_ptr(shared_ptr<U>&& x) noexcept | |
547 | : _b(x._b) | |
548 | , _p(x._p) { | |
549 | x._b = nullptr; | |
550 | x._p = nullptr; | |
551 | } | |
552 | ~shared_ptr() { | |
1e59de90 TL |
553 | #pragma GCC diagnostic push |
554 | #ifdef SEASTAR_IGNORE_USE_AFTER_FREE | |
555 | #pragma GCC diagnostic ignored "-Wuse-after-free" | |
556 | #endif | |
11fdf7f2 TL |
557 | if (_b && !--_b->count) { |
558 | delete _b; | |
559 | } | |
1e59de90 | 560 | #pragma GCC diagnostic pop |
11fdf7f2 TL |
561 | } |
562 | shared_ptr& operator=(const shared_ptr& x) noexcept { | |
563 | if (this != &x) { | |
564 | this->~shared_ptr(); | |
565 | new (this) shared_ptr(x); | |
566 | } | |
567 | return *this; | |
568 | } | |
569 | shared_ptr& operator=(shared_ptr&& x) noexcept { | |
570 | if (this != &x) { | |
571 | this->~shared_ptr(); | |
572 | new (this) shared_ptr(std::move(x)); | |
573 | } | |
574 | return *this; | |
575 | } | |
576 | shared_ptr& operator=(std::nullptr_t) noexcept { | |
577 | return *this = shared_ptr(); | |
578 | } | |
579 | template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>> | |
580 | shared_ptr& operator=(const shared_ptr<U>& x) noexcept { | |
581 | if (*this != x) { | |
582 | this->~shared_ptr(); | |
583 | new (this) shared_ptr(x); | |
584 | } | |
585 | return *this; | |
586 | } | |
587 | template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>> | |
588 | shared_ptr& operator=(shared_ptr<U>&& x) noexcept { | |
589 | if (*this != x) { | |
590 | this->~shared_ptr(); | |
591 | new (this) shared_ptr(std::move(x)); | |
592 | } | |
593 | return *this; | |
594 | } | |
595 | explicit operator bool() const noexcept { | |
596 | return _p; | |
597 | } | |
598 | T& operator*() const noexcept { | |
599 | return *_p; | |
600 | } | |
601 | T* operator->() const noexcept { | |
602 | return _p; | |
603 | } | |
604 | T* get() const noexcept { | |
605 | return _p; | |
606 | } | |
607 | long use_count() const noexcept { | |
608 | if (_b) { | |
609 | return _b->count; | |
610 | } else { | |
611 | return 0; | |
612 | } | |
613 | } | |
614 | ||
615 | template <bool esft> | |
616 | struct make_helper; | |
617 | ||
618 | template <typename U, typename... A> | |
619 | friend shared_ptr<U> make_shared(A&&... a); | |
620 | ||
621 | template <typename U> | |
622 | friend shared_ptr<U> make_shared(U&& a); | |
623 | ||
624 | template <typename V, typename U> | |
625 | friend shared_ptr<V> static_pointer_cast(const shared_ptr<U>& p); | |
626 | ||
627 | template <typename V, typename U> | |
628 | friend shared_ptr<V> dynamic_pointer_cast(const shared_ptr<U>& p); | |
629 | ||
630 | template <typename V, typename U> | |
631 | friend shared_ptr<V> const_pointer_cast(const shared_ptr<U>& p); | |
632 | ||
633 | template <bool esft, typename... A> | |
634 | static shared_ptr make(A&&... a); | |
635 | ||
636 | template <typename U> | |
637 | friend class enable_shared_from_this; | |
638 | ||
639 | template <typename U, bool esft> | |
640 | friend struct shared_ptr_make_helper; | |
641 | ||
642 | template <typename U> | |
643 | friend class shared_ptr; | |
644 | }; | |
645 | ||
646 | template <typename U, bool esft> | |
647 | struct shared_ptr_make_helper; | |
648 | ||
649 | template <typename T> | |
650 | struct shared_ptr_make_helper<T, false> { | |
651 | template <typename... A> | |
652 | static shared_ptr<T> make(A&&... a) { | |
653 | return shared_ptr<T>(new shared_ptr_count_for<T>(std::forward<A>(a)...)); | |
654 | } | |
655 | }; | |
656 | ||
657 | template <typename T> | |
658 | struct shared_ptr_make_helper<T, true> { | |
659 | template <typename... A> | |
660 | static shared_ptr<T> make(A&&... a) { | |
661 | auto p = new T(std::forward<A>(a)...); | |
662 | return shared_ptr<T>(p, p); | |
663 | } | |
664 | }; | |
665 | ||
666 | template <typename T, typename... A> | |
667 | inline | |
668 | shared_ptr<T> | |
669 | make_shared(A&&... a) { | |
670 | using helper = shared_ptr_make_helper<T, std::is_base_of<shared_ptr_count_base, T>::value>; | |
671 | return helper::make(std::forward<A>(a)...); | |
672 | } | |
673 | ||
674 | template <typename T> | |
675 | inline | |
676 | shared_ptr<T> | |
677 | make_shared(T&& a) { | |
678 | using helper = shared_ptr_make_helper<T, std::is_base_of<shared_ptr_count_base, T>::value>; | |
679 | return helper::make(std::forward<T>(a)); | |
680 | } | |
681 | ||
682 | template <typename T, typename U> | |
683 | inline | |
684 | shared_ptr<T> | |
685 | static_pointer_cast(const shared_ptr<U>& p) { | |
686 | return shared_ptr<T>(p._b, static_cast<T*>(p._p)); | |
687 | } | |
688 | ||
689 | template <typename T, typename U> | |
690 | inline | |
691 | shared_ptr<T> | |
692 | dynamic_pointer_cast(const shared_ptr<U>& p) { | |
693 | auto q = dynamic_cast<T*>(p._p); | |
694 | return shared_ptr<T>(q ? p._b : nullptr, q); | |
695 | } | |
696 | ||
697 | template <typename T, typename U> | |
698 | inline | |
699 | shared_ptr<T> | |
700 | const_pointer_cast(const shared_ptr<U>& p) { | |
701 | return shared_ptr<T>(p._b, const_cast<T*>(p._p)); | |
702 | } | |
703 | ||
704 | template <typename T> | |
705 | inline | |
706 | shared_ptr<T> | |
20effc67 | 707 | enable_shared_from_this<T>::shared_from_this() noexcept { |
11fdf7f2 TL |
708 | auto unconst = reinterpret_cast<enable_shared_from_this<std::remove_const_t<T>>*>(this); |
709 | return shared_ptr<T>(unconst); | |
710 | } | |
711 | ||
712 | template <typename T> | |
713 | inline | |
714 | shared_ptr<const T> | |
20effc67 | 715 | enable_shared_from_this<T>::shared_from_this() const noexcept { |
11fdf7f2 TL |
716 | auto esft = const_cast<enable_shared_from_this*>(this); |
717 | auto unconst = reinterpret_cast<enable_shared_from_this<std::remove_const_t<T>>*>(esft); | |
718 | return shared_ptr<const T>(unconst); | |
719 | } | |
720 | ||
721 | template <typename T, typename U> | |
722 | inline | |
723 | bool | |
724 | operator==(const shared_ptr<T>& x, const shared_ptr<U>& y) { | |
725 | return x.get() == y.get(); | |
726 | } | |
727 | ||
728 | template <typename T> | |
729 | inline | |
730 | bool | |
731 | operator==(const shared_ptr<T>& x, std::nullptr_t) { | |
732 | return x.get() == nullptr; | |
733 | } | |
734 | ||
735 | template <typename T> | |
736 | inline | |
737 | bool | |
738 | operator==(std::nullptr_t, const shared_ptr<T>& y) { | |
739 | return nullptr == y.get(); | |
740 | } | |
741 | ||
1e59de90 TL |
742 | template <typename T> |
743 | inline | |
744 | bool | |
745 | operator==(const lw_shared_ptr<T>& x, std::nullptr_t) { | |
746 | return x.get() == nullptr; | |
747 | } | |
748 | ||
749 | template <typename T> | |
750 | inline | |
751 | bool | |
752 | operator==(std::nullptr_t, const lw_shared_ptr<T>& y) { | |
753 | return nullptr == y.get(); | |
754 | } | |
755 | ||
11fdf7f2 TL |
756 | template <typename T, typename U> |
757 | inline | |
758 | bool | |
759 | operator!=(const shared_ptr<T>& x, const shared_ptr<U>& y) { | |
760 | return x.get() != y.get(); | |
761 | } | |
762 | ||
763 | template <typename T> | |
764 | inline | |
765 | bool | |
766 | operator!=(const shared_ptr<T>& x, std::nullptr_t) { | |
767 | return x.get() != nullptr; | |
768 | } | |
769 | ||
770 | template <typename T> | |
771 | inline | |
772 | bool | |
773 | operator!=(std::nullptr_t, const shared_ptr<T>& y) { | |
774 | return nullptr != y.get(); | |
775 | } | |
776 | ||
1e59de90 TL |
777 | template <typename T> |
778 | inline | |
779 | bool | |
780 | operator!=(const lw_shared_ptr<T>& x, std::nullptr_t) { | |
781 | return x.get() != nullptr; | |
782 | } | |
783 | ||
784 | template <typename T> | |
785 | inline | |
786 | bool | |
787 | operator!=(std::nullptr_t, const lw_shared_ptr<T>& y) { | |
788 | return nullptr != y.get(); | |
789 | } | |
790 | ||
11fdf7f2 TL |
791 | template <typename T, typename U> |
792 | inline | |
793 | bool | |
794 | operator<(const shared_ptr<T>& x, const shared_ptr<U>& y) { | |
795 | return x.get() < y.get(); | |
796 | } | |
797 | ||
798 | template <typename T> | |
799 | inline | |
800 | bool | |
801 | operator<(const shared_ptr<T>& x, std::nullptr_t) { | |
802 | return x.get() < nullptr; | |
803 | } | |
804 | ||
805 | template <typename T> | |
806 | inline | |
807 | bool | |
808 | operator<(std::nullptr_t, const shared_ptr<T>& y) { | |
809 | return nullptr < y.get(); | |
810 | } | |
811 | ||
812 | template <typename T, typename U> | |
813 | inline | |
814 | bool | |
815 | operator<=(const shared_ptr<T>& x, const shared_ptr<U>& y) { | |
816 | return x.get() <= y.get(); | |
817 | } | |
818 | ||
819 | template <typename T> | |
820 | inline | |
821 | bool | |
822 | operator<=(const shared_ptr<T>& x, std::nullptr_t) { | |
823 | return x.get() <= nullptr; | |
824 | } | |
825 | ||
826 | template <typename T> | |
827 | inline | |
828 | bool | |
829 | operator<=(std::nullptr_t, const shared_ptr<T>& y) { | |
830 | return nullptr <= y.get(); | |
831 | } | |
832 | ||
833 | template <typename T, typename U> | |
834 | inline | |
835 | bool | |
836 | operator>(const shared_ptr<T>& x, const shared_ptr<U>& y) { | |
837 | return x.get() > y.get(); | |
838 | } | |
839 | ||
840 | template <typename T> | |
841 | inline | |
842 | bool | |
843 | operator>(const shared_ptr<T>& x, std::nullptr_t) { | |
844 | return x.get() > nullptr; | |
845 | } | |
846 | ||
847 | template <typename T> | |
848 | inline | |
849 | bool | |
850 | operator>(std::nullptr_t, const shared_ptr<T>& y) { | |
851 | return nullptr > y.get(); | |
852 | } | |
853 | ||
854 | template <typename T, typename U> | |
855 | inline | |
856 | bool | |
857 | operator>=(const shared_ptr<T>& x, const shared_ptr<U>& y) { | |
858 | return x.get() >= y.get(); | |
859 | } | |
860 | ||
861 | template <typename T> | |
862 | inline | |
863 | bool | |
864 | operator>=(const shared_ptr<T>& x, std::nullptr_t) { | |
865 | return x.get() >= nullptr; | |
866 | } | |
867 | ||
868 | template <typename T> | |
869 | inline | |
870 | bool | |
871 | operator>=(std::nullptr_t, const shared_ptr<T>& y) { | |
872 | return nullptr >= y.get(); | |
873 | } | |
874 | ||
875 | template <typename T> | |
876 | static inline | |
877 | std::ostream& operator<<(std::ostream& out, const shared_ptr<T>& p) { | |
878 | if (!p) { | |
879 | return out << "null"; | |
880 | } | |
881 | return out << *p; | |
882 | } | |
883 | ||
884 | template<typename T> | |
885 | using shared_ptr_equal_by_value = indirect_equal_to<shared_ptr<T>>; | |
886 | ||
887 | template<typename T> | |
888 | using shared_ptr_value_hash = indirect_hash<shared_ptr<T>>; | |
889 | ||
890 | } | |
891 | ||
892 | namespace std { | |
893 | ||
894 | template <typename T> | |
895 | struct hash<seastar::lw_shared_ptr<T>> : private hash<T*> { | |
896 | size_t operator()(const seastar::lw_shared_ptr<T>& p) const { | |
897 | return hash<T*>::operator()(p.get()); | |
898 | } | |
899 | }; | |
900 | ||
901 | template <typename T> | |
902 | struct hash<seastar::shared_ptr<T>> : private hash<T*> { | |
903 | size_t operator()(const seastar::shared_ptr<T>& p) const { | |
904 | return hash<T*>::operator()(p.get()); | |
905 | } | |
906 | }; | |
907 | ||
908 | } | |
909 | ||
1e59de90 TL |
910 | namespace fmt { |
911 | ||
912 | template<typename T> | |
913 | const void* ptr(const seastar::lw_shared_ptr<T>& p) { | |
914 | return p.get(); | |
915 | } | |
916 | ||
917 | template<typename T> | |
918 | const void* ptr(const seastar::shared_ptr<T>& p) { | |
919 | return p.get(); | |
920 | } | |
921 | ||
922 | } | |
923 | ||
11fdf7f2 TL |
924 | namespace seastar { |
925 | ||
926 | template<typename T> | |
927 | struct is_smart_ptr<shared_ptr<T>> : std::true_type {}; | |
928 | ||
929 | template<typename T> | |
930 | struct is_smart_ptr<lw_shared_ptr<T>> : std::true_type {}; | |
931 | ||
932 | } |