1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #pragma once
6
7 #include <zircon/assert.h>
8 #include <zircon/compiler.h>
9 #include <fbl/alloc_checker.h>
10 #include <fbl/recycler.h>
11 #include <fbl/type_support.h>
12
13 #include <utility>
14
15 namespace fbl {
16
17 template <typename T>
18 class RefPtr;
19
20 template <typename T>
21 RefPtr<T> AdoptRef(T* ptr);
22
23 template <typename T>
24 RefPtr<T> WrapRefPtr(T* ptr);
25
26 namespace internal {
27 template <typename T>
28 RefPtr<T> MakeRefPtrNoAdopt(T* ptr);
29 } // namespace internal
30
31 // RefPtr<T> holds a reference to an intrusively-refcounted object of type
32 // T that deletes the object when the refcount drops to 0.
33 //
34 // T should be a subclass of fbl::RefCounted<>, or something that adheres to
35 // the same contract for AddRef() and Release().
36 //
37 // Except for initial construction (see below), this generally adheres to a
38 // subset of the interface for std::shared_ptr<>. Unlike std::shared_ptr<> this
39 // type does not support vending weak pointers, introspecting the reference
40 // count, or any operations that would result in allocating memory (unless
41 // T::AddRef or T::Release allocate memory).
42 //
43 // Construction: To create a RefPtr around a freshly created object, use the
44 // AdoptRef free function at the bottom of this header. To construct a RefPtr
45 // to hold a reference to an object that already exists use the copy or move
46 // constructor or assignment operator.
47 template <typename T>
48 class RefPtr final {
49 public:
50 using ObjType = T;
51
52 // Constructors
RefPtr()53 constexpr RefPtr()
54 : ptr_(nullptr) {}
RefPtr(decltype (nullptr))55 constexpr RefPtr(decltype(nullptr))
56 : RefPtr() {}
57 // Constructs a RefPtr from a pointer that has already been adopted. See
58 // AdoptRef() below for constructing the very first RefPtr to an object.
RefPtr(T * p)59 explicit RefPtr(T* p)
60 : ptr_(p) {
61 if (ptr_)
62 ptr_->AddRef();
63 }
64
65 // Copy construction.
RefPtr(const RefPtr & r)66 RefPtr(const RefPtr& r)
67 : RefPtr(r.ptr_) {}
68
69 // Implicit upcast via copy construction.
70 //
71 // @see the notes in unique_ptr.h
72 template <typename U,
73 typename = typename enable_if<is_convertible_pointer<U*, T*>::value>::type>
RefPtr(const RefPtr<U> & r)74 RefPtr(const RefPtr<U>& r) : RefPtr(r.ptr_) {
75 static_assert((is_class<T>::value == is_class<U>::value) &&
76 (!is_class<T>::value ||
77 has_virtual_destructor<T>::value ||
78 is_same<T, const U>::value),
79 "Cannot convert RefPtr<U> to RefPtr<T> unless neither T "
80 "nor U are class/struct types, or T has a virtual destructor,"
81 "or T == const U.");
82 }
83
84 // Assignment
85 RefPtr& operator=(const RefPtr& r) {
86 // Ref first so self-assignments work.
87 if (r.ptr_) {
88 r.ptr_->AddRef();
89 }
90 T* old = ptr_;
91 ptr_ = r.ptr_;
92 if (old && old->Release()) {
93 recycle(old);
94 }
95 return *this;
96 }
97
98 // Move construction
RefPtr(RefPtr && r)99 RefPtr(RefPtr&& r)
100 : ptr_(r.ptr_) {
101 r.ptr_ = nullptr;
102 }
103
104 // Implicit upcast via move construction.
105 //
106 // @see the notes in RefPtr.h
107 template <typename U,
108 typename = typename enable_if<is_convertible_pointer<U*, T*>::value>::type>
RefPtr(RefPtr<U> && r)109 RefPtr(RefPtr<U>&& r) : ptr_(r.ptr_) {
110 static_assert((is_class<T>::value == is_class<U>::value) &&
111 (!is_class<T>::value ||
112 has_virtual_destructor<T>::value ||
113 is_same<T, const U>::value),
114 "Cannot convert RefPtr<U> to RefPtr<T> unless neither T "
115 "nor U are class/struct types, or T has a virtual destructor,"
116 "or T == const U");
117
118 r.ptr_ = nullptr;
119 }
120
121 // Move assignment
122 RefPtr& operator=(RefPtr&& r) {
123 RefPtr(std::move(r)).swap(*this);
124 return *this;
125 }
126
127 // Construct via explicit downcast.
128 // ptr must be the same object as base.ptr_.
129 template <typename BaseType>
RefPtr(T * ptr,RefPtr<BaseType> && base)130 RefPtr(T* ptr, RefPtr<BaseType>&& base)
131 : ptr_(ptr) {
132 ZX_ASSERT(static_cast<BaseType*>(ptr_) == base.ptr_);
133 base.ptr_ = nullptr;
134 }
135
136 // Downcast via static method invocation. Depending on use case, the syntax
137 // should look something like...
138 //
139 // fbl::RefPtr<MyBase> foo = MakeBase();
140 // auto bar_copy = fbl::RefPtr<MyDerived>::Downcast(foo);
141 // auto bar_move = fbl::RefPtr<MyDerived>::Downcast(std::move(foo));
142 //
143 template <typename BaseRefPtr>
Downcast(BaseRefPtr base)144 static RefPtr Downcast(BaseRefPtr base) {
145 // Make certain that BaseRefPtr is some form of RefPtr<T>
146 static_assert(is_same<BaseRefPtr, RefPtr<typename BaseRefPtr::ObjType>>::value,
147 "BaseRefPtr must be a RefPtr<T>!");
148
149 if (base != nullptr)
150 return internal::MakeRefPtrNoAdopt<T>(static_cast<T*>(base.leak_ref()));
151
152 return nullptr;
153 }
154
~RefPtr()155 ~RefPtr() {
156 if (ptr_ && ptr_->Release()) {
157 recycle(ptr_);
158 }
159 }
160
161 void reset(T* ptr = nullptr) {
162 RefPtr(ptr).swap(*this);
163 }
164
swap(RefPtr & r)165 void swap(RefPtr& r) {
166 T* p = ptr_;
167 ptr_ = r.ptr_;
168 r.ptr_ = p;
169 }
170
leak_ref()171 T* leak_ref() __WARN_UNUSED_RESULT {
172 T* p = ptr_;
173 ptr_ = nullptr;
174 return p;
175 }
176
get()177 T* get() const {
178 return ptr_;
179 }
180 T& operator*() const {
181 return *ptr_;
182 }
183 T* operator->() const {
184 return ptr_;
185 }
186 explicit operator bool() const {
187 return !!ptr_;
188 }
189
190 // Comparison against nullptr operators (of the form, myptr == nullptr).
191 bool operator==(decltype(nullptr)) const { return (ptr_ == nullptr); }
192 bool operator!=(decltype(nullptr)) const { return (ptr_ != nullptr); }
193
194 bool operator==(const RefPtr<T>& other) const { return ptr_ == other.ptr_; }
195 bool operator!=(const RefPtr<T>& other) const { return ptr_ != other.ptr_; }
196
197 private:
198 template <typename U>
199 friend class RefPtr;
200 friend RefPtr<T> AdoptRef<T>(T*);
201 friend RefPtr<T> internal::MakeRefPtrNoAdopt<T>(T*);
202
203 enum AdoptTag { ADOPT };
204 enum NoAdoptTag { NO_ADOPT };
205
RefPtr(T * ptr,AdoptTag)206 RefPtr(T* ptr, AdoptTag)
207 : ptr_(ptr) {
208 if (ptr_) {
209 ptr_->Adopt();
210 }
211 }
212
RefPtr(T * ptr,NoAdoptTag)213 RefPtr(T* ptr, NoAdoptTag)
214 : ptr_(ptr) {}
215
recycle(T * ptr)216 static void recycle(T* ptr) {
217 if (::fbl::internal::has_fbl_recycle<T>::value) {
218 ::fbl::internal::recycler<T>::recycle(ptr);
219 } else {
220 delete ptr;
221 }
222 }
223
224 T* ptr_;
225 };
226
227 // Comparison against nullptr operator (of the form, nullptr == myptr)
228 template <typename T>
229 static inline bool operator==(decltype(nullptr), const RefPtr<T>& ptr) {
230 return (ptr.get() == nullptr);
231 }
232
233 template <typename T>
234 static inline bool operator!=(decltype(nullptr), const RefPtr<T>& ptr) {
235 return (ptr.get() != nullptr);
236 }
237
238 // Constructs a RefPtr from a fresh object that has not been referenced before.
239 // Use like:
240 //
241 // RefPtr<Happy> h = AdoptRef(new Happy);
242 // if (!h)
243 // // Deal with allocation failure here
244 // h->DoStuff();
245 template <typename T>
AdoptRef(T * ptr)246 inline RefPtr<T> AdoptRef(T* ptr) {
247 return RefPtr<T>(ptr, RefPtr<T>::ADOPT);
248 }
249
250 // Convenience wrappers to construct a RefPtr with argument type deduction.
251 template <typename T>
WrapRefPtr(T * ptr)252 inline RefPtr<T> WrapRefPtr(T* ptr) {
253 return RefPtr<T>(ptr);
254 }
255
256 namespace internal {
257 // Constructs a RefPtr from a T* without attempt to either AddRef or Adopt the
258 // pointer. Used by the internals of some intrusive container classes to store
259 // sentinels (special invalid pointers) in RefPtr<>s.
260 template <typename T>
MakeRefPtrNoAdopt(T * ptr)261 inline RefPtr<T> MakeRefPtrNoAdopt(T* ptr) {
262 return RefPtr<T>(ptr, RefPtr<T>::NO_ADOPT);
263 }
264
265 // This is a wrapper class that can be friended for a particular |T|, if you
266 // want to make |T|'s constructor private, but still use |MakeRefCounted()|
267 // (below). (You can't friend partial specializations.)
268 template <typename T>
269 class MakeRefCountedHelper final {
270 public:
271 template <typename... Args>
MakeRefCounted(Args &&...args)272 static RefPtr<T> MakeRefCounted(Args&&... args) {
273 return AdoptRef<T>(new T(std::forward<Args>(args)...));
274 }
275
276 template <typename... Args>
MakeRefCountedChecked(AllocChecker * ac,Args &&...args)277 static RefPtr<T> MakeRefCountedChecked(AllocChecker* ac, Args&&... args) {
278 return AdoptRef<T>(new (ac) T(std::forward<Args>(args)...));
279 }
280 };
281
282 } // namespace internal
283
284 template <typename T, typename... Args>
MakeRefCounted(Args &&...args)285 RefPtr<T> MakeRefCounted(Args&&... args) {
286 return internal::MakeRefCountedHelper<T>::MakeRefCounted(
287 std::forward<Args>(args)...);
288 }
289
290 template <typename T, typename... Args>
MakeRefCountedChecked(AllocChecker * ac,Args &&...args)291 RefPtr<T> MakeRefCountedChecked(AllocChecker* ac, Args&&... args) {
292 return internal::MakeRefCountedHelper<T>::MakeRefCountedChecked(
293 ac, std::forward<Args>(args)...);
294 }
295
296 } // namespace fbl
297