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