1 /*
2 *
3 * Copyright 2017 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
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, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 #ifndef GRPC_CORE_LIB_GPRPP_REF_COUNTED_PTR_H
20 #define GRPC_CORE_LIB_GPRPP_REF_COUNTED_PTR_H
21
22 #include <grpc/support/port_platform.h>
23
24 #include <type_traits>
25 #include <utility>
26
27 #include "src/core/lib/gprpp/debug_location.h"
28 #include "src/core/lib/gprpp/memory.h"
29
30 namespace grpc_core {
31
32 // A smart pointer class for objects that provide IncrementRefCount() and
33 // Unref() methods, such as those provided by the RefCounted base class.
34 template <typename T>
35 class RefCountedPtr {
36 public:
RefCountedPtr()37 RefCountedPtr() {}
38 // NOLINTNEXTLINE(google-explicit-constructor)
RefCountedPtr(std::nullptr_t)39 RefCountedPtr(std::nullptr_t) {}
40
41 // If value is non-null, we take ownership of a ref to it.
42 template <typename Y>
43 // NOLINTNEXTLINE(google-explicit-constructor)
RefCountedPtr(Y * value)44 RefCountedPtr(Y* value) : value_(value) {}
45
46 // Move ctors.
RefCountedPtr(RefCountedPtr && other)47 RefCountedPtr(RefCountedPtr&& other) noexcept {
48 value_ = other.value_;
49 other.value_ = nullptr;
50 }
51 template <typename Y>
52 // NOLINTNEXTLINE(google-explicit-constructor)
RefCountedPtr(RefCountedPtr<Y> && other)53 RefCountedPtr(RefCountedPtr<Y>&& other) noexcept {
54 value_ = static_cast<T*>(other.value_);
55 other.value_ = nullptr;
56 }
57
58 // Move assignment.
59 RefCountedPtr& operator=(RefCountedPtr&& other) noexcept {
60 reset(other.value_);
61 other.value_ = nullptr;
62 return *this;
63 }
64 template <typename Y>
65 RefCountedPtr& operator=(RefCountedPtr<Y>&& other) noexcept {
66 reset(other.value_);
67 other.value_ = nullptr;
68 return *this;
69 }
70
71 // Copy ctors.
RefCountedPtr(const RefCountedPtr & other)72 RefCountedPtr(const RefCountedPtr& other) {
73 if (other.value_ != nullptr) other.value_->IncrementRefCount();
74 value_ = other.value_;
75 }
76 template <typename Y>
77 // NOLINTNEXTLINE(google-explicit-constructor)
RefCountedPtr(const RefCountedPtr<Y> & other)78 RefCountedPtr(const RefCountedPtr<Y>& other) {
79 static_assert(std::has_virtual_destructor<T>::value,
80 "T does not have a virtual dtor");
81 if (other.value_ != nullptr) other.value_->IncrementRefCount();
82 value_ = static_cast<T*>(other.value_);
83 }
84
85 // Copy assignment.
86 RefCountedPtr& operator=(const RefCountedPtr& other) {
87 // Note: Order of reffing and unreffing is important here in case value_
88 // and other.value_ are the same object.
89 if (other.value_ != nullptr) other.value_->IncrementRefCount();
90 reset(other.value_);
91 return *this;
92 }
93 template <typename Y>
94 RefCountedPtr& operator=(const RefCountedPtr<Y>& other) {
95 static_assert(std::has_virtual_destructor<T>::value,
96 "T does not have a virtual dtor");
97 // Note: Order of reffing and unreffing is important here in case value_
98 // and other.value_ are the same object.
99 if (other.value_ != nullptr) other.value_->IncrementRefCount();
100 reset(other.value_);
101 return *this;
102 }
103
~RefCountedPtr()104 ~RefCountedPtr() {
105 if (value_ != nullptr) value_->Unref();
106 }
107
swap(RefCountedPtr & other)108 void swap(RefCountedPtr& other) { std::swap(value_, other.value_); }
109
110 // If value is non-null, we take ownership of a ref to it.
111 void reset(T* value = nullptr) {
112 if (value_ != nullptr) value_->Unref();
113 value_ = value;
114 }
115 void reset(const DebugLocation& location, const char* reason,
116 T* value = nullptr) {
117 if (value_ != nullptr) value_->Unref(location, reason);
118 value_ = value;
119 }
120 template <typename Y>
121 void reset(Y* value = nullptr) {
122 static_assert(std::has_virtual_destructor<T>::value,
123 "T does not have a virtual dtor");
124 if (value_ != nullptr) value_->Unref();
125 value_ = static_cast<T*>(value);
126 }
127 template <typename Y>
128 void reset(const DebugLocation& location, const char* reason,
129 Y* value = nullptr) {
130 static_assert(std::has_virtual_destructor<T>::value,
131 "T does not have a virtual dtor");
132 if (value_ != nullptr) value_->Unref(location, reason);
133 value_ = static_cast<T*>(value);
134 }
135
136 // TODO(roth): This method exists solely as a transition mechanism to allow
137 // us to pass a ref to idiomatic C code that does not use RefCountedPtr<>.
138 // Once all of our code has been converted to idiomatic C++, this
139 // method should go away.
release()140 T* release() {
141 T* value = value_;
142 value_ = nullptr;
143 return value;
144 }
145
get()146 T* get() const { return value_; }
147
148 T& operator*() const { return *value_; }
149 T* operator->() const { return value_; }
150
151 template <typename Y>
152 bool operator==(const RefCountedPtr<Y>& other) const {
153 return value_ == other.value_;
154 }
155
156 template <typename Y>
157 bool operator==(const Y* other) const {
158 return value_ == other;
159 }
160
161 bool operator==(std::nullptr_t) const { return value_ == nullptr; }
162
163 template <typename Y>
164 bool operator!=(const RefCountedPtr<Y>& other) const {
165 return value_ != other.value_;
166 }
167
168 template <typename Y>
169 bool operator!=(const Y* other) const {
170 return value_ != other;
171 }
172
173 bool operator!=(std::nullptr_t) const { return value_ != nullptr; }
174
175 private:
176 template <typename Y>
177 friend class RefCountedPtr;
178
179 T* value_ = nullptr;
180 };
181
182 // A smart pointer class for objects that provide IncrementWeakRefCount() and
183 // WeakUnref() methods, such as those provided by the DualRefCounted base class.
184 template <typename T>
185 class WeakRefCountedPtr {
186 public:
WeakRefCountedPtr()187 WeakRefCountedPtr() {}
188 // NOLINTNEXTLINE(google-explicit-constructor)
WeakRefCountedPtr(std::nullptr_t)189 WeakRefCountedPtr(std::nullptr_t) {}
190
191 // If value is non-null, we take ownership of a ref to it.
192 template <typename Y>
193 // NOLINTNEXTLINE(google-explicit-constructor)
WeakRefCountedPtr(Y * value)194 WeakRefCountedPtr(Y* value) {
195 value_ = value;
196 }
197
198 // Move ctors.
WeakRefCountedPtr(WeakRefCountedPtr && other)199 WeakRefCountedPtr(WeakRefCountedPtr&& other) noexcept {
200 value_ = other.value_;
201 other.value_ = nullptr;
202 }
203 template <typename Y>
204 // NOLINTNEXTLINE(google-explicit-constructor)
WeakRefCountedPtr(WeakRefCountedPtr<Y> && other)205 WeakRefCountedPtr(WeakRefCountedPtr<Y>&& other) noexcept {
206 value_ = static_cast<T*>(other.value_);
207 other.value_ = nullptr;
208 }
209
210 // Move assignment.
211 WeakRefCountedPtr& operator=(WeakRefCountedPtr&& other) noexcept {
212 reset(other.value_);
213 other.value_ = nullptr;
214 return *this;
215 }
216 template <typename Y>
217 WeakRefCountedPtr& operator=(WeakRefCountedPtr<Y>&& other) noexcept {
218 reset(other.value_);
219 other.value_ = nullptr;
220 return *this;
221 }
222
223 // Copy ctors.
WeakRefCountedPtr(const WeakRefCountedPtr & other)224 WeakRefCountedPtr(const WeakRefCountedPtr& other) {
225 if (other.value_ != nullptr) other.value_->IncrementWeakRefCount();
226 value_ = other.value_;
227 }
228 template <typename Y>
229 // NOLINTNEXTLINE(google-explicit-constructor)
WeakRefCountedPtr(const WeakRefCountedPtr<Y> & other)230 WeakRefCountedPtr(const WeakRefCountedPtr<Y>& other) {
231 static_assert(std::has_virtual_destructor<T>::value,
232 "T does not have a virtual dtor");
233 if (other.value_ != nullptr) other.value_->IncrementWeakRefCount();
234 value_ = static_cast<T*>(other.value_);
235 }
236
237 // Copy assignment.
238 WeakRefCountedPtr& operator=(const WeakRefCountedPtr& other) {
239 // Note: Order of reffing and unreffing is important here in case value_
240 // and other.value_ are the same object.
241 if (other.value_ != nullptr) other.value_->IncrementWeakRefCount();
242 reset(other.value_);
243 return *this;
244 }
245 template <typename Y>
246 WeakRefCountedPtr& operator=(const WeakRefCountedPtr<Y>& other) {
247 static_assert(std::has_virtual_destructor<T>::value,
248 "T does not have a virtual dtor");
249 // Note: Order of reffing and unreffing is important here in case value_
250 // and other.value_ are the same object.
251 if (other.value_ != nullptr) other.value_->IncrementWeakRefCount();
252 reset(other.value_);
253 return *this;
254 }
255
~WeakRefCountedPtr()256 ~WeakRefCountedPtr() {
257 if (value_ != nullptr) value_->WeakUnref();
258 }
259
swap(WeakRefCountedPtr & other)260 void swap(WeakRefCountedPtr& other) { std::swap(value_, other.value_); }
261
262 // If value is non-null, we take ownership of a ref to it.
263 void reset(T* value = nullptr) {
264 if (value_ != nullptr) value_->WeakUnref();
265 value_ = value;
266 }
267 void reset(const DebugLocation& location, const char* reason,
268 T* value = nullptr) {
269 if (value_ != nullptr) value_->WeakUnref(location, reason);
270 value_ = value;
271 }
272 template <typename Y>
273 void reset(Y* value = nullptr) {
274 static_assert(std::has_virtual_destructor<T>::value,
275 "T does not have a virtual dtor");
276 if (value_ != nullptr) value_->WeakUnref();
277 value_ = static_cast<T*>(value);
278 }
279 template <typename Y>
280 void reset(const DebugLocation& location, const char* reason,
281 Y* value = nullptr) {
282 static_assert(std::has_virtual_destructor<T>::value,
283 "T does not have a virtual dtor");
284 if (value_ != nullptr) value_->WeakUnref(location, reason);
285 value_ = static_cast<T*>(value);
286 }
287
288 // TODO(roth): This method exists solely as a transition mechanism to allow
289 // us to pass a ref to idiomatic C code that does not use WeakRefCountedPtr<>.
290 // Once all of our code has been converted to idiomatic C++, this
291 // method should go away.
release()292 T* release() {
293 T* value = value_;
294 value_ = nullptr;
295 return value;
296 }
297
get()298 T* get() const { return value_; }
299
300 T& operator*() const { return *value_; }
301 T* operator->() const { return value_; }
302
303 template <typename Y>
304 bool operator==(const WeakRefCountedPtr<Y>& other) const {
305 return value_ == other.value_;
306 }
307
308 template <typename Y>
309 bool operator==(const Y* other) const {
310 return value_ == other;
311 }
312
313 bool operator==(std::nullptr_t) const { return value_ == nullptr; }
314
315 template <typename Y>
316 bool operator!=(const WeakRefCountedPtr<Y>& other) const {
317 return value_ != other.value_;
318 }
319
320 template <typename Y>
321 bool operator!=(const Y* other) const {
322 return value_ != other;
323 }
324
325 bool operator!=(std::nullptr_t) const { return value_ != nullptr; }
326
327 private:
328 template <typename Y>
329 friend class WeakRefCountedPtr;
330
331 T* value_ = nullptr;
332 };
333
334 template <typename T, typename... Args>
MakeRefCounted(Args &&...args)335 inline RefCountedPtr<T> MakeRefCounted(Args&&... args) {
336 return RefCountedPtr<T>(new T(std::forward<Args>(args)...));
337 }
338
339 template <typename T>
340 bool operator<(const RefCountedPtr<T>& p1, const RefCountedPtr<T>& p2) {
341 return p1.get() < p2.get();
342 }
343
344 template <typename T>
345 bool operator<(const WeakRefCountedPtr<T>& p1, const WeakRefCountedPtr<T>& p2) {
346 return p1.get() < p2.get();
347 }
348
349 } // namespace grpc_core
350
351 #endif /* GRPC_CORE_LIB_GPRPP_REF_COUNTED_PTR_H */
352