]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/include/seastar/core/weak_ptr.hh
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / seastar / include / seastar / core / weak_ptr.hh
CommitLineData
11fdf7f2
TL
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) 2016 ScyllaDB
20 */
21
22#pragma once
23
24#include <boost/intrusive/list.hpp>
25
26namespace seastar {
27
28/// A non-owning reference to an object.
29///
30/// weak_ptr allows one to keep a non-owning reference to an object. When the
31/// object is destroyed, it notifies all weak_ptr instances pointing to it.
32/// A weak_ptr instance pointing to a destroyed object is equivalent to a
33/// `nullptr`.
34///
35/// The referenced object must inherit from weakly_referencable.
36/// weak_ptr instances can only be obtained by calling weak_from_this() on
37/// the to-be-referenced object.
38///
39/// \see weakly_referencable
40template<typename T>
41class weak_ptr {
42 template<typename U>
43 friend class weakly_referencable;
44private:
45 using hook_type = boost::intrusive::list_member_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>;
46 hook_type _hook;
47 T* _ptr = nullptr;
f67539c2 48 weak_ptr(T* p) noexcept : _ptr(p) {}
20effc67
TL
49 void clear() noexcept {
50 _hook = {};
51 _ptr = nullptr;
52 }
53 void swap(weak_ptr&& o) noexcept {
54 _hook.swap_nodes(o._hook);
55 std::swap(_ptr, o._ptr);
56 }
11fdf7f2 57public:
f67539c2
TL
58 // Note: The default constructor's body is implemented as no-op
59 // rather than `noexcept = default` due to a bug with gcc 9.3.1
60 // that deletes the constructor since boost::intrusive::list_member_hook
61 // is not default_nothrow_constructible.
62 weak_ptr() noexcept {}
63 weak_ptr(std::nullptr_t) noexcept : weak_ptr() {}
11fdf7f2 64 weak_ptr(weak_ptr&& o) noexcept
11fdf7f2 65 {
20effc67
TL
66 swap(std::move(o));
67 }
68 weak_ptr(const weak_ptr& o) noexcept {
69 if (o._ptr) {
70 swap(o._ptr->weak_from_this());
71 }
11fdf7f2
TL
72 }
73 weak_ptr& operator=(weak_ptr&& o) noexcept {
74 if (this != &o) {
20effc67
TL
75 clear();
76 swap(std::move(o));
77 }
78 return *this;
79 }
80 weak_ptr& operator=(const weak_ptr& o) noexcept {
81 if (this != &o) {
82 clear();
83 if (o._ptr) {
84 swap(o._ptr->weak_from_this());
85 }
11fdf7f2
TL
86 }
87 return *this;
88 }
f67539c2 89 explicit operator bool() const noexcept { return _ptr != nullptr; }
11fdf7f2
TL
90 T* operator->() const noexcept { return _ptr; }
91 T& operator*() const noexcept { return *_ptr; }
92 T* get() const noexcept { return _ptr; }
f67539c2
TL
93 bool operator==(const weak_ptr& o) const noexcept { return _ptr == o._ptr; }
94 bool operator!=(const weak_ptr& o) const noexcept { return _ptr != o._ptr; }
11fdf7f2
TL
95};
96
97/// Allows obtaining a non-owning reference (weak_ptr) to the object.
98///
99/// A live weak_ptr object doesn't prevent the referenced object form being destroyed.
100///
101/// The underlying pointer held by weak_ptr is valid as long as the referenced object is alive.
102/// When the object dies, all weak_ptr objects associated with it are emptied.
103///
104/// A weak reference is obtained like this:
105///
106/// class X : public weakly_referencable<X> {};
107/// auto x = std::make_unique<X>();
108/// weak_ptr<X> ptr = x->weak_from_this();
109///
110/// The user of weak_ptr can check if it still holds a valid pointer like this:
111///
112/// if (ptr) ptr->do_something();
113///
114template<typename T>
115class weakly_referencable {
116 boost::intrusive::list<weak_ptr<T>,
117 boost::intrusive::member_hook<weak_ptr<T>, typename weak_ptr<T>::hook_type, &weak_ptr<T>::_hook>,
118 boost::intrusive::constant_time_size<false>> _ptr_list;
119public:
f67539c2
TL
120 // Note: The default constructor's body is implemented as no-op
121 // rather than `noexcept = default` due to a bug with gcc 9.3.1
122 // that deletes the constructor since boost::intrusive::member_hook
123 // is not default_nothrow_constructible.
124 weakly_referencable() noexcept {}
11fdf7f2
TL
125 weakly_referencable(weakly_referencable&&) = delete; // pointer to this is captured and passed to weak_ptr
126 weakly_referencable(const weakly_referencable&) = delete;
127 ~weakly_referencable() noexcept {
128 _ptr_list.clear_and_dispose([] (weak_ptr<T>* wp) noexcept {
129 wp->_ptr = nullptr;
130 });
131 }
132 weak_ptr<T> weak_from_this() noexcept {
133 weak_ptr<T> ptr(static_cast<T*>(this));
134 _ptr_list.push_back(ptr);
135 return ptr;
136 }
137};
138
139}
140