]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/include/seastar/core/shared_ptr.hh
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / seastar / include / seastar / core / shared_ptr.hh
CommitLineData
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
40namespace 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
62using shared_ptr_counter_type = long;
63#else
64using shared_ptr_counter_type = debug_shared_ptr_counter_type;
65#endif
66
67template <typename T>
68class lw_shared_ptr;
69
70template <typename T>
71class shared_ptr;
72
73template <typename T>
74class enable_lw_shared_from_this;
75
76template <typename T>
77class enable_shared_from_this;
78
79template <typename T, typename... A>
80lw_shared_ptr<T> make_lw_shared(A&&... a);
81
82template <typename T>
83lw_shared_ptr<T> make_lw_shared(T&& a);
84
85template <typename T>
86lw_shared_ptr<T> make_lw_shared(T& a);
87
88template <typename T, typename... A>
89shared_ptr<T> make_shared(A&&... a);
90
91template <typename T>
92shared_ptr<T> make_shared(T&& a);
93
94template <typename T, typename U>
95shared_ptr<T> static_pointer_cast(const shared_ptr<U>& p);
96
97template <typename T, typename U>
98shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& p);
99
100template <typename T, typename U>
101shared_ptr<T> const_pointer_cast(const shared_ptr<U>& p);
102
103struct lw_shared_ptr_counter_base {
104 shared_ptr_counter_type _count = 0;
105};
106
107
108namespace internal {
109
110template <class T, class U>
111struct lw_shared_ptr_accessors;
112
113template <class T>
114struct lw_shared_ptr_accessors_esft;
115
116template <class T>
117struct 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:
141template <typename T>
142class enable_lw_shared_from_this : private lw_shared_ptr_counter_base {
143 using ctor = T;
144protected:
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; }
150public:
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
163template <typename T>
1e59de90 164struct 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.
190template <typename T>
191struct lw_shared_ptr_deleter; // No generic implementation
192
193namespace internal {
194
195template <typename T>
196struct 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
213template <typename T>
214struct 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>.
233template <typename T, typename U = void>
234struct 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
241template <typename... T>
242using void_t = void;
243
244// Overload when lw_shared_ptr_deleter<T> specialized
245template <typename T>
246struct 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
260template <typename T>
261class 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;
266private:
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 }
278public:
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
431template <typename T, typename... A>
432inline
433lw_shared_ptr<T> make_lw_shared(A&&... a) {
434 return lw_shared_ptr<T>::make(std::forward<A>(a)...);
435}
436
437template <typename T>
438inline
439lw_shared_ptr<T> make_lw_shared(T&& a) {
440 return lw_shared_ptr<T>::make(std::move(a));
441}
442
443template <typename T>
444inline
445lw_shared_ptr<T> make_lw_shared(T& a) {
446 return lw_shared_ptr<T>::make(a);
447}
448
449template <typename T>
450inline
451lw_shared_ptr<T>
20effc67 452enable_lw_shared_from_this<T>::shared_from_this() noexcept {
11fdf7f2
TL
453 return lw_shared_ptr<T>(this);
454}
455
456template <typename T>
457inline
458lw_shared_ptr<const T>
20effc67 459enable_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
463template <typename T>
464static inline
465std::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
474struct 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
480template <typename T>
481struct 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
487template <typename T>
488class enable_shared_from_this : private shared_ptr_count_base {
489public:
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
501template <typename T>
502class shared_ptr {
503 mutable shared_ptr_count_base* _b = nullptr;
504 mutable T* _p = nullptr;
505private:
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 }
519public:
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
646template <typename U, bool esft>
647struct shared_ptr_make_helper;
648
649template <typename T>
650struct 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
657template <typename T>
658struct 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
666template <typename T, typename... A>
667inline
668shared_ptr<T>
669make_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
674template <typename T>
675inline
676shared_ptr<T>
677make_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
682template <typename T, typename U>
683inline
684shared_ptr<T>
685static_pointer_cast(const shared_ptr<U>& p) {
686 return shared_ptr<T>(p._b, static_cast<T*>(p._p));
687}
688
689template <typename T, typename U>
690inline
691shared_ptr<T>
692dynamic_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
697template <typename T, typename U>
698inline
699shared_ptr<T>
700const_pointer_cast(const shared_ptr<U>& p) {
701 return shared_ptr<T>(p._b, const_cast<T*>(p._p));
702}
703
704template <typename T>
705inline
706shared_ptr<T>
20effc67 707enable_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
712template <typename T>
713inline
714shared_ptr<const T>
20effc67 715enable_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
721template <typename T, typename U>
722inline
723bool
724operator==(const shared_ptr<T>& x, const shared_ptr<U>& y) {
725 return x.get() == y.get();
726}
727
728template <typename T>
729inline
730bool
731operator==(const shared_ptr<T>& x, std::nullptr_t) {
732 return x.get() == nullptr;
733}
734
735template <typename T>
736inline
737bool
738operator==(std::nullptr_t, const shared_ptr<T>& y) {
739 return nullptr == y.get();
740}
741
1e59de90
TL
742template <typename T>
743inline
744bool
745operator==(const lw_shared_ptr<T>& x, std::nullptr_t) {
746 return x.get() == nullptr;
747}
748
749template <typename T>
750inline
751bool
752operator==(std::nullptr_t, const lw_shared_ptr<T>& y) {
753 return nullptr == y.get();
754}
755
11fdf7f2
TL
756template <typename T, typename U>
757inline
758bool
759operator!=(const shared_ptr<T>& x, const shared_ptr<U>& y) {
760 return x.get() != y.get();
761}
762
763template <typename T>
764inline
765bool
766operator!=(const shared_ptr<T>& x, std::nullptr_t) {
767 return x.get() != nullptr;
768}
769
770template <typename T>
771inline
772bool
773operator!=(std::nullptr_t, const shared_ptr<T>& y) {
774 return nullptr != y.get();
775}
776
1e59de90
TL
777template <typename T>
778inline
779bool
780operator!=(const lw_shared_ptr<T>& x, std::nullptr_t) {
781 return x.get() != nullptr;
782}
783
784template <typename T>
785inline
786bool
787operator!=(std::nullptr_t, const lw_shared_ptr<T>& y) {
788 return nullptr != y.get();
789}
790
11fdf7f2
TL
791template <typename T, typename U>
792inline
793bool
794operator<(const shared_ptr<T>& x, const shared_ptr<U>& y) {
795 return x.get() < y.get();
796}
797
798template <typename T>
799inline
800bool
801operator<(const shared_ptr<T>& x, std::nullptr_t) {
802 return x.get() < nullptr;
803}
804
805template <typename T>
806inline
807bool
808operator<(std::nullptr_t, const shared_ptr<T>& y) {
809 return nullptr < y.get();
810}
811
812template <typename T, typename U>
813inline
814bool
815operator<=(const shared_ptr<T>& x, const shared_ptr<U>& y) {
816 return x.get() <= y.get();
817}
818
819template <typename T>
820inline
821bool
822operator<=(const shared_ptr<T>& x, std::nullptr_t) {
823 return x.get() <= nullptr;
824}
825
826template <typename T>
827inline
828bool
829operator<=(std::nullptr_t, const shared_ptr<T>& y) {
830 return nullptr <= y.get();
831}
832
833template <typename T, typename U>
834inline
835bool
836operator>(const shared_ptr<T>& x, const shared_ptr<U>& y) {
837 return x.get() > y.get();
838}
839
840template <typename T>
841inline
842bool
843operator>(const shared_ptr<T>& x, std::nullptr_t) {
844 return x.get() > nullptr;
845}
846
847template <typename T>
848inline
849bool
850operator>(std::nullptr_t, const shared_ptr<T>& y) {
851 return nullptr > y.get();
852}
853
854template <typename T, typename U>
855inline
856bool
857operator>=(const shared_ptr<T>& x, const shared_ptr<U>& y) {
858 return x.get() >= y.get();
859}
860
861template <typename T>
862inline
863bool
864operator>=(const shared_ptr<T>& x, std::nullptr_t) {
865 return x.get() >= nullptr;
866}
867
868template <typename T>
869inline
870bool
871operator>=(std::nullptr_t, const shared_ptr<T>& y) {
872 return nullptr >= y.get();
873}
874
875template <typename T>
876static inline
877std::ostream& operator<<(std::ostream& out, const shared_ptr<T>& p) {
878 if (!p) {
879 return out << "null";
880 }
881 return out << *p;
882}
883
884template<typename T>
885using shared_ptr_equal_by_value = indirect_equal_to<shared_ptr<T>>;
886
887template<typename T>
888using shared_ptr_value_hash = indirect_hash<shared_ptr<T>>;
889
890}
891
892namespace std {
893
894template <typename T>
895struct 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
901template <typename T>
902struct 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
910namespace fmt {
911
912template<typename T>
913const void* ptr(const seastar::lw_shared_ptr<T>& p) {
914 return p.get();
915}
916
917template<typename T>
918const void* ptr(const seastar::shared_ptr<T>& p) {
919 return p.get();
920}
921
922}
923
11fdf7f2
TL
924namespace seastar {
925
926template<typename T>
927struct is_smart_ptr<shared_ptr<T>> : std::true_type {};
928
929template<typename T>
930struct is_smart_ptr<lw_shared_ptr<T>> : std::true_type {};
931
932}