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