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() {}
RefCountedPtr(std::nullptr_t)38 RefCountedPtr(std::nullptr_t) {}
39
40 // If value is non-null, we take ownership of a ref to it.
41 template <typename Y>
RefCountedPtr(Y * value)42 explicit RefCountedPtr(Y* value) {
43 value_ = value;
44 }
45
46 // Move ctors.
RefCountedPtr(RefCountedPtr && other)47 RefCountedPtr(RefCountedPtr&& other) {
48 value_ = other.value_;
49 other.value_ = nullptr;
50 }
51 template <typename Y>
RefCountedPtr(RefCountedPtr<Y> && other)52 RefCountedPtr(RefCountedPtr<Y>&& other) {
53 value_ = static_cast<T*>(other.value_);
54 other.value_ = nullptr;
55 }
56
57 // Move assignment.
58 RefCountedPtr& operator=(RefCountedPtr&& other) {
59 reset(other.value_);
60 other.value_ = nullptr;
61 return *this;
62 }
63 template <typename Y>
64 RefCountedPtr& operator=(RefCountedPtr<Y>&& other) {
65 reset(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 static_assert(std::has_virtual_destructor<T>::value,
78 "T does not have a virtual dtor");
79 if (other.value_ != nullptr) other.value_->IncrementRefCount();
80 value_ = static_cast<T*>(other.value_);
81 }
82
83 // Copy 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 if (value_ != nullptr) value_->Unref();
111 value_ = value;
112 }
113 void reset(const DebugLocation& location, const char* reason,
114 T* value = nullptr) {
115 if (value_ != nullptr) value_->Unref(location, reason);
116 value_ = value;
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 if (value_ != nullptr) value_->Unref();
123 value_ = static_cast<T*>(value);
124 }
125 template <typename Y>
126 void reset(const DebugLocation& location, const char* reason,
127 Y* value = nullptr) {
128 static_assert(std::has_virtual_destructor<T>::value,
129 "T does not have a virtual dtor");
130 if (value_ != nullptr) value_->Unref(location, reason);
131 value_ = static_cast<T*>(value);
132 }
133
134 // TODO(roth): This method exists solely as a transition mechanism to allow
135 // us to pass a ref to idiomatic C code that does not use RefCountedPtr<>.
136 // Once all of our code has been converted to idiomatic C++, this
137 // method should go away.
release()138 T* release() {
139 T* value = value_;
140 value_ = nullptr;
141 return value;
142 }
143
get()144 T* get() const { return value_; }
145
146 T& operator*() const { return *value_; }
147 T* operator->() const { return value_; }
148
149 template <typename Y>
150 bool operator==(const RefCountedPtr<Y>& other) const {
151 return value_ == other.value_;
152 }
153
154 template <typename Y>
155 bool operator==(const Y* other) const {
156 return value_ == other;
157 }
158
159 bool operator==(std::nullptr_t) const { return value_ == nullptr; }
160
161 template <typename Y>
162 bool operator!=(const RefCountedPtr<Y>& other) const {
163 return value_ != other.value_;
164 }
165
166 template <typename Y>
167 bool operator!=(const Y* other) const {
168 return value_ != other;
169 }
170
171 bool operator!=(std::nullptr_t) const { return value_ != nullptr; }
172
173 private:
174 template <typename Y>
175 friend class RefCountedPtr;
176
177 T* value_ = nullptr;
178 };
179
180 template <typename T, typename... Args>
MakeRefCounted(Args &&...args)181 inline RefCountedPtr<T> MakeRefCounted(Args&&... args) {
182 return RefCountedPtr<T>(new T(std::forward<Args>(args)...));
183 }
184
185 template <typename T>
186 bool operator<(const RefCountedPtr<T>& p1, const RefCountedPtr<T>& p2) {
187 return p1.get() < p2.get();
188 }
189
190 } // namespace grpc_core
191
192 #endif /* GRPC_CORE_LIB_GPRPP_REF_COUNTED_PTR_H */
193