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