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