• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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