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 <utility>
25 
26 #include "src/core/lib/gprpp/memory.h"
27 
28 namespace grpc_core {
29 
30 // A smart pointer class for objects that provide IncrementRefCount() and
31 // Unref() methods, such as those provided by the RefCounted base class.
32 template <typename T>
33 class RefCountedPtr {
34  public:
RefCountedPtr()35   RefCountedPtr() {}
RefCountedPtr(std::nullptr_t)36   RefCountedPtr(std::nullptr_t) {}
37 
38   // If value is non-null, we take ownership of a ref to it.
39   template <typename Y>
RefCountedPtr(Y * value)40   explicit RefCountedPtr(Y* value) {
41     value_ = value;
42   }
43 
44   // Move ctors.
RefCountedPtr(RefCountedPtr && other)45   RefCountedPtr(RefCountedPtr&& other) {
46     value_ = other.value_;
47     other.value_ = nullptr;
48   }
49   template <typename Y>
RefCountedPtr(RefCountedPtr<Y> && other)50   RefCountedPtr(RefCountedPtr<Y>&& other) {
51     value_ = other.value_;
52     other.value_ = nullptr;
53   }
54 
55   // Move assignment.
56   RefCountedPtr& operator=(RefCountedPtr&& other) {
57     if (value_ != nullptr) value_->Unref();
58     value_ = other.value_;
59     other.value_ = nullptr;
60     return *this;
61   }
62   template <typename Y>
63   RefCountedPtr& operator=(RefCountedPtr<Y>&& other) {
64     if (value_ != nullptr) value_->Unref();
65     value_ = other.value_;
66     other.value_ = nullptr;
67     return *this;
68   }
69 
70   // Copy ctors.
RefCountedPtr(const RefCountedPtr & other)71   RefCountedPtr(const RefCountedPtr& other) {
72     if (other.value_ != nullptr) other.value_->IncrementRefCount();
73     value_ = other.value_;
74   }
75   template <typename Y>
RefCountedPtr(const RefCountedPtr<Y> & other)76   RefCountedPtr(const RefCountedPtr<Y>& other) {
77     if (other.value_ != nullptr) other.value_->IncrementRefCount();
78     value_ = other.value_;
79   }
80 
81   // Copy assignment.
82   RefCountedPtr& operator=(const RefCountedPtr& other) {
83     // Note: Order of reffing and unreffing is important here in case value_
84     // and other.value_ are the same object.
85     if (other.value_ != nullptr) other.value_->IncrementRefCount();
86     if (value_ != nullptr) value_->Unref();
87     value_ = other.value_;
88     return *this;
89   }
90   template <typename Y>
91   RefCountedPtr& operator=(const RefCountedPtr<Y>& other) {
92     // Note: Order of reffing and unreffing is important here in case value_
93     // and other.value_ are the same object.
94     if (other.value_ != nullptr) other.value_->IncrementRefCount();
95     if (value_ != nullptr) value_->Unref();
96     value_ = other.value_;
97     return *this;
98   }
99 
~RefCountedPtr()100   ~RefCountedPtr() {
101     if (value_ != nullptr) value_->Unref();
102   }
103 
104   // If value is non-null, we take ownership of a ref to it.
105   template <typename Y>
reset(Y * value)106   void reset(Y* value) {
107     if (value_ != nullptr) value_->Unref();
108     value_ = value;
109   }
110 
reset()111   void reset() {
112     if (value_ != nullptr) value_->Unref();
113     value_ = nullptr;
114   }
115 
116   // TODO(roth): This method exists solely as a transition mechanism to allow
117   // us to pass a ref to idiomatic C code that does not use RefCountedPtr<>.
118   // Once all of our code has been converted to idiomatic C++, this
119   // method should go away.
release()120   T* release() {
121     T* value = value_;
122     value_ = nullptr;
123     return value;
124   }
125 
get()126   T* get() const { return value_; }
127 
128   T& operator*() const { return *value_; }
129   T* operator->() const { return value_; }
130 
131   template <typename Y>
132   bool operator==(const RefCountedPtr<Y>& other) const {
133     return value_ == other.value_;
134   }
135 
136   template <typename Y>
137   bool operator==(const Y* other) const {
138     return value_ == other;
139   }
140 
141   bool operator==(std::nullptr_t) const { return value_ == nullptr; }
142 
143   template <typename Y>
144   bool operator!=(const RefCountedPtr<Y>& other) const {
145     return value_ != other.value_;
146   }
147 
148   template <typename Y>
149   bool operator!=(const Y* other) const {
150     return value_ != other;
151   }
152 
153   bool operator!=(std::nullptr_t) const { return value_ != nullptr; }
154 
155  private:
156   template <typename Y>
157   friend class RefCountedPtr;
158 
159   T* value_ = nullptr;
160 };
161 
162 template <typename T, typename... Args>
MakeRefCounted(Args &&...args)163 inline RefCountedPtr<T> MakeRefCounted(Args&&... args) {
164   return RefCountedPtr<T>(New<T>(std::forward<Args>(args)...));
165 }
166 
167 }  // namespace grpc_core
168 
169 #endif /* GRPC_CORE_LIB_GPRPP_REF_COUNTED_PTR_H */
170