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