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
346 T& operator*() const noexcept { return *accessors<T>::to_value(_p); }
347 T* operator->() const noexcept { return accessors<T>::to_value(_p); }
348 T* get() const noexcept {
349 if (_p) {
350 return accessors<T>::to_value(_p);
351 } else {
352 return nullptr;
353 }
354 }
355
356 // Releases ownership of the object without destroying it.
357 // If this was the last owner then returns an engaged unique_ptr
358 // which is now the sole owner of the object.
359 // Returns a disengaged pointer if there are still some owners.
360 //
361 // Note that in case the raw pointer is extracted from the unique_ptr
362 // using unique_ptr::release(), it must be still destroyed using
363 // lw_shared_ptr::disposer or lw_shared_ptr::dispose().
364 std::unique_ptr<T, disposer> release() noexcept {
365 auto p = std::exchange(_p, nullptr);
366 if (--p->_count) {
367 return nullptr;
368 } else {
369 return std::unique_ptr<T, disposer>(accessors<T>::to_value(p));
370 }
371 }
372
373 long int use_count() const noexcept {
374 if (_p) {
375 return _p->_count;
376 } else {
377 return 0;
378 }
379 }
380
381 operator lw_shared_ptr<const T>() const noexcept {
382 return lw_shared_ptr<const T>(_p);
383 }
384
385 explicit operator bool() const noexcept {
386 return _p;
387 }
388
389 bool owned() const noexcept {
390 return _p->_count == 1;
391 }
392
393 bool operator==(const lw_shared_ptr<const T>& x) const {
394 return _p == x._p;
395 }
396
397 bool operator!=(const lw_shared_ptr<const T>& x) const {
398 return !operator==(x);
399 }
400
401 bool operator==(const lw_shared_ptr<std::remove_const_t<T>>& x) const {
402 return _p == x._p;
403 }
404
405 bool operator!=(const lw_shared_ptr<std::remove_const_t<T>>& x) const {
406 return !operator==(x);
407 }
408
409 bool operator<(const lw_shared_ptr<const T>& x) const {
410 return _p < x._p;
411 }
412
413 bool operator<(const lw_shared_ptr<std::remove_const_t<T>>& x) const {
414 return _p < x._p;
415 }
416
417 template <typename U>
418 friend class lw_shared_ptr;
419
420 template <typename X, typename... A>
421 friend lw_shared_ptr<X> make_lw_shared(A&&...);
422
423 template <typename U>
424 friend lw_shared_ptr<U> make_lw_shared(U&&);
425
426 template <typename U>
427 friend lw_shared_ptr<U> make_lw_shared(U&);
428
429 template <typename U>
430 friend class enable_lw_shared_from_this;
431};
432
433template <typename T, typename... A>
434inline
435lw_shared_ptr<T> make_lw_shared(A&&... a) {
436 return lw_shared_ptr<T>::make(std::forward<A>(a)...);
437}
438
439template <typename T>
440inline
441lw_shared_ptr<T> make_lw_shared(T&& a) {
442 return lw_shared_ptr<T>::make(std::move(a));
443}
444
445template <typename T>
446inline
447lw_shared_ptr<T> make_lw_shared(T& a) {
448 return lw_shared_ptr<T>::make(a);
449}
450SEASTAR_MODULE_EXPORT_END
451
452template <typename T>
453inline
454lw_shared_ptr<T>
455enable_lw_shared_from_this<T>::shared_from_this() noexcept {
456 return lw_shared_ptr<T>(this);
457}
458
459template <typename T>
460inline
461lw_shared_ptr<const T>
462enable_lw_shared_from_this<T>::shared_from_this() const noexcept {
463 return lw_shared_ptr<const T>(const_cast<enable_lw_shared_from_this*>(this));
464}
465
466SEASTAR_MODULE_EXPORT
467template <typename T>
468inline
469std::ostream& operator<<(std::ostream& out, const lw_shared_ptr<T>& p) {
470 if (!p) {
471 return out << "null";
472 }
473 return out << *p;
474}
475
476// Polymorphic shared pointer class
477
479 // destructor is responsible for fully-typed deletion
480 virtual ~shared_ptr_count_base() {}
481 shared_ptr_counter_type count = 0;
482};
483
484template <typename T>
486 T data;
487 template <typename... A>
488 shared_ptr_count_for(A&&... a) : data(std::forward<A>(a)...) {}
489};
490
491SEASTAR_MODULE_EXPORT_BEGIN
492template <typename T>
494public:
495 shared_ptr<T> shared_from_this() noexcept;
496 shared_ptr<const T> shared_from_this() const noexcept;
497 long use_count() const noexcept { return count; }
498
499 template <typename U>
500 friend class shared_ptr;
501
502 template <typename U, bool esft>
503 friend struct shared_ptr_make_helper;
504};
505
506template <typename T>
508 mutable shared_ptr_count_base* _b = nullptr;
509 mutable T* _p = nullptr;
510private:
511 explicit shared_ptr(shared_ptr_count_for<T>* b) noexcept : _b(b), _p(&b->data) {
512 ++_b->count;
513 }
514 shared_ptr(shared_ptr_count_base* b, T* p) noexcept : _b(b), _p(p) {
515 if (_b) {
516 ++_b->count;
517 }
518 }
519 explicit shared_ptr(enable_shared_from_this<std::remove_const_t<T>>* p) noexcept : _b(p), _p(static_cast<T*>(p)) {
520 if (_b) {
521 ++_b->count;
522 }
523 }
524public:
525 using element_type = T;
526
527 shared_ptr() noexcept = default;
528 shared_ptr(std::nullptr_t) noexcept : shared_ptr() {}
529 shared_ptr(const shared_ptr& x) noexcept
530 : _b(x._b)
531 , _p(x._p) {
532 if (_b) {
533 ++_b->count;
534 }
535 }
536 shared_ptr(shared_ptr&& x) noexcept
537 : _b(x._b)
538 , _p(x._p) {
539 x._b = nullptr;
540 x._p = nullptr;
541 }
542 template <typename U, typename = std::enable_if_t<std::is_base_of_v<T, U>>>
543 shared_ptr(const shared_ptr<U>& x) noexcept
544 : _b(x._b)
545 , _p(x._p) {
546 if (_b) {
547 ++_b->count;
548 }
549 }
550 template <typename U, typename = std::enable_if_t<std::is_base_of_v<T, U>>>
551 shared_ptr(shared_ptr<U>&& x) noexcept
552 : _b(x._b)
553 , _p(x._p) {
554 x._b = nullptr;
555 x._p = nullptr;
556 }
557 ~shared_ptr() {
558#pragma GCC diagnostic push
559#ifdef SEASTAR_IGNORE_USE_AFTER_FREE
560#pragma GCC diagnostic ignored "-Wuse-after-free"
561#endif
562 if (_b && !--_b->count) {
563 delete _b;
564 }
565#pragma GCC diagnostic pop
566 }
567 shared_ptr& operator=(const shared_ptr& x) noexcept {
568 if (this != &x) {
569 this->~shared_ptr();
570 new (this) shared_ptr(x);
571 }
572 return *this;
573 }
574 shared_ptr& operator=(shared_ptr&& x) noexcept {
575 if (this != &x) {
576 this->~shared_ptr();
577 new (this) shared_ptr(std::move(x));
578 }
579 return *this;
580 }
581 shared_ptr& operator=(std::nullptr_t) noexcept {
582 return *this = shared_ptr();
583 }
584 template <typename U, typename = std::enable_if_t<std::is_base_of_v<T, U>>>
585 shared_ptr& operator=(const shared_ptr<U>& x) noexcept {
586 if (*this != x) {
587 this->~shared_ptr();
588 new (this) shared_ptr(x);
589 }
590 return *this;
591 }
592 template <typename U, typename = std::enable_if_t<std::is_base_of_v<T, U>>>
593 shared_ptr& operator=(shared_ptr<U>&& x) noexcept {
594 if (*this != x) {
595 this->~shared_ptr();
596 new (this) shared_ptr(std::move(x));
597 }
598 return *this;
599 }
600 explicit operator bool() const noexcept {
601 return _p;
602 }
603 T& operator*() const noexcept {
604 return *_p;
605 }
606 T* operator->() const noexcept {
607 return _p;
608 }
609 T* get() const noexcept {
610 return _p;
611 }
612 long use_count() const noexcept {
613 if (_b) {
614 return _b->count;
615 } else {
616 return 0;
617 }
618 }
619
620 template <bool esft>
622
623 template <typename U, typename... A>
624 friend shared_ptr<U> make_shared(A&&... a);
625
626 template <typename U>
627 friend shared_ptr<U> make_shared(U&& a);
628
629 template <typename V, typename U>
630 friend shared_ptr<V> static_pointer_cast(const shared_ptr<U>& p);
631
632 template <typename V, typename U>
633 friend shared_ptr<V> dynamic_pointer_cast(const shared_ptr<U>& p);
634
635 template <typename V, typename U>
636 friend shared_ptr<V> const_pointer_cast(const shared_ptr<U>& p);
637
638 template <bool esft, typename... A>
639 static shared_ptr make(A&&... a);
640
641 template <typename U>
642 friend class enable_shared_from_this;
643
644 template <typename U, bool esft>
645 friend struct shared_ptr_make_helper;
646
647 template <typename U>
648 friend class shared_ptr;
649};
650SEASTAR_MODULE_EXPORT_END
651
652template <typename U, bool esft>
654
655template <typename T>
656struct shared_ptr_make_helper<T, false> {
657 template <typename... A>
658 static shared_ptr<T> make(A&&... a) {
659 return shared_ptr<T>(new shared_ptr_count_for<T>(std::forward<A>(a)...));
660 }
661};
662
663template <typename T>
664struct shared_ptr_make_helper<T, true> {
665 template <typename... A>
666 static shared_ptr<T> make(A&&... a) {
667 auto p = new T(std::forward<A>(a)...);
668 return shared_ptr<T>(p, p);
669 }
670};
671
672SEASTAR_MODULE_EXPORT_BEGIN
673template <typename T, typename... A>
674inline
676make_shared(A&&... a) {
678 return helper::make(std::forward<A>(a)...);
679}
680
681template <typename T>
682inline
683shared_ptr<T>
684make_shared(T&& a) {
685 using helper = shared_ptr_make_helper<T, std::is_base_of_v<shared_ptr_count_base, T>>;
686 return helper::make(std::forward<T>(a));
687}
688
689template <typename T, typename U>
690inline
691shared_ptr<T>
692static_pointer_cast(const shared_ptr<U>& p) {
693 return shared_ptr<T>(p._b, static_cast<T*>(p._p));
694}
695
696template <typename T, typename U>
697inline
698shared_ptr<T>
699dynamic_pointer_cast(const shared_ptr<U>& p) {
700 auto q = dynamic_cast<T*>(p._p);
701 return shared_ptr<T>(q ? p._b : nullptr, q);
702}
703
704template <typename T, typename U>
705inline
706shared_ptr<T>
707const_pointer_cast(const shared_ptr<U>& p) {
708 return shared_ptr<T>(p._b, const_cast<T*>(p._p));
709}
710SEASTAR_MODULE_EXPORT_END
711
712template <typename T>
713inline
714shared_ptr<T>
715enable_shared_from_this<T>::shared_from_this() noexcept {
716 auto unconst = reinterpret_cast<enable_shared_from_this<std::remove_const_t<T>>*>(this);
717 return shared_ptr<T>(unconst);
718}
719
720template <typename T>
721inline
722shared_ptr<const T>
723enable_shared_from_this<T>::shared_from_this() const noexcept {
724 auto esft = const_cast<enable_shared_from_this*>(this);
725 auto unconst = reinterpret_cast<enable_shared_from_this<std::remove_const_t<T>>*>(esft);
726 return shared_ptr<const T>(unconst);
727}
728
729SEASTAR_MODULE_EXPORT_BEGIN
730template <typename T, typename U>
731inline
732bool
733operator==(const shared_ptr<T>& x, const shared_ptr<U>& y) {
734 return x.get() == y.get();
735}
736
737template <typename T>
738inline
739bool
740operator==(const shared_ptr<T>& x, std::nullptr_t) {
741 return x.get() == nullptr;
742}
743
744template <typename T>
745inline
746bool
747operator==(std::nullptr_t, const shared_ptr<T>& y) {
748 return nullptr == y.get();
749}
750
751template <typename T>
752inline
753bool
754operator==(const lw_shared_ptr<T>& x, std::nullptr_t) {
755 return x.get() == nullptr;
756}
757
758template <typename T>
759inline
760bool
761operator==(std::nullptr_t, const lw_shared_ptr<T>& y) {
762 return nullptr == y.get();
763}
764
765template <typename T, typename U>
766inline
767bool
768operator!=(const shared_ptr<T>& x, const shared_ptr<U>& y) {
769 return x.get() != y.get();
770}
771
772template <typename T>
773inline
774bool
775operator!=(const shared_ptr<T>& x, std::nullptr_t) {
776 return x.get() != nullptr;
777}
778
779template <typename T>
780inline
781bool
782operator!=(std::nullptr_t, const shared_ptr<T>& y) {
783 return nullptr != y.get();
784}
785
786template <typename T>
787inline
788bool
789operator!=(const lw_shared_ptr<T>& x, std::nullptr_t) {
790 return x.get() != nullptr;
791}
792
793template <typename T>
794inline
795bool
796operator!=(std::nullptr_t, const lw_shared_ptr<T>& y) {
797 return nullptr != y.get();
798}
799
800template <typename T, typename U>
801inline
802bool
803operator<(const shared_ptr<T>& x, const shared_ptr<U>& y) {
804 return x.get() < y.get();
805}
806
807template <typename T>
808inline
809bool
810operator<(const shared_ptr<T>& x, std::nullptr_t) {
811 return x.get() < nullptr;
812}
813
814template <typename T>
815inline
816bool
817operator<(std::nullptr_t, const shared_ptr<T>& y) {
818 return nullptr < y.get();
819}
820
821template <typename T, typename U>
822inline
823bool
824operator<=(const shared_ptr<T>& x, const shared_ptr<U>& y) {
825 return x.get() <= y.get();
826}
827
828template <typename T>
829inline
830bool
831operator<=(const shared_ptr<T>& x, std::nullptr_t) {
832 return x.get() <= nullptr;
833}
834
835template <typename T>
836inline
837bool
838operator<=(std::nullptr_t, const shared_ptr<T>& y) {
839 return nullptr <= y.get();
840}
841
842template <typename T, typename U>
843inline
844bool
845operator>(const shared_ptr<T>& x, const shared_ptr<U>& y) {
846 return x.get() > y.get();
847}
848
849template <typename T>
850inline
851bool
852operator>(const shared_ptr<T>& x, std::nullptr_t) {
853 return x.get() > nullptr;
854}
855
856template <typename T>
857inline
858bool
859operator>(std::nullptr_t, const shared_ptr<T>& y) {
860 return nullptr > y.get();
861}
862
863template <typename T, typename U>
864inline
865bool
866operator>=(const shared_ptr<T>& x, const shared_ptr<U>& y) {
867 return x.get() >= y.get();
868}
869
870template <typename T>
871inline
872bool
873operator>=(const shared_ptr<T>& x, std::nullptr_t) {
874 return x.get() >= nullptr;
875}
876
877template <typename T>
878inline
879bool
880operator>=(std::nullptr_t, const shared_ptr<T>& y) {
881 return nullptr >= y.get();
882}
883
884template <typename T>
885inline
886std::ostream& operator<<(std::ostream& out, const shared_ptr<T>& p) {
887 if (!p) {
888 return out << "null";
889 }
890 return out << *p;
891}
892
893template<typename T>
894using shared_ptr_equal_by_value = indirect_equal_to<shared_ptr<T>>;
895
896template<typename T>
897using shared_ptr_value_hash = indirect_hash<shared_ptr<T>>;
898
899SEASTAR_MODULE_EXPORT_END
900}
901
902namespace std {
903
904SEASTAR_MODULE_EXPORT
905template <typename T>
906struct hash<seastar::lw_shared_ptr<T>> : private hash<T*> {
907 size_t operator()(const seastar::lw_shared_ptr<T>& p) const {
908 return hash<T*>::operator()(p.get());
909 }
910};
911
912SEASTAR_MODULE_EXPORT
913template <typename T>
914struct hash<seastar::shared_ptr<T>> : private hash<T*> {
915 size_t operator()(const seastar::shared_ptr<T>& p) const {
916 return hash<T*>::operator()(p.get());
917 }
918};
919
920}
921
922SEASTAR_MODULE_EXPORT
923namespace fmt {
924
925template<typename T>
926const void* ptr(const seastar::lw_shared_ptr<T>& p) {
927 return p.get();
928}
929
930template<typename T>
931const void* ptr(const seastar::shared_ptr<T>& p) {
932 return p.get();
933}
934
935template <typename T>
936struct formatter<seastar::shared_ptr<T>> {
937 constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
938 auto format(const seastar::shared_ptr<T>& p, fmt::format_context& ctx) const {
939 if (!p) {
940 return fmt::format_to(ctx.out(), "null");
941 }
942 return fmt::format_to(ctx.out(), "{}", *p);
943 }
944};
945
946template <typename T>
947struct formatter<seastar::lw_shared_ptr<T>> {
948 constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
949 auto format(const seastar::lw_shared_ptr<T>& p, fmt::format_context& ctx) const {
950 if (!p) {
951 return fmt::format_to(ctx.out(), "null");
952 }
953 return fmt::format_to(ctx.out(), "{}", *p);
954 }
955};
956}
957
958namespace seastar {
959
960SEASTAR_MODULE_EXPORT
961template<typename T>
962struct is_smart_ptr<shared_ptr<T>> : std::true_type {};
963
964SEASTAR_MODULE_EXPORT
965template<typename T>
966struct is_smart_ptr<lw_shared_ptr<T>> : std::true_type {};
967
968}
Definition: shared_ptr.hh:148
Definition: shared_ptr.hh:493
Definition: shared_ptr.hh:295
Definition: shared_ptr.hh:268
Definition: shared_ptr.hh:507
Definition: shared_ptr.hh:621
Seastar API namespace.
Definition: abort_on_ebadf.hh:26
Definition: shared_ptr.hh:197
Definition: shared_ptr.hh:653
STL namespace.
Definition: is_smart_ptr.hh:30
Definition: shared_ptr.hh:107
Definition: shared_ptr.hh:170
Definition: shared_ptr.hh:478
Definition: shared_ptr.hh:485