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