1// Copyright 2013 The Flutter 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// Provides a smart pointer class for intrusively reference-counted objects.
6
7#ifndef FLUTTER_FML_MEMORY_REF_PTR_H_
8#define FLUTTER_FML_MEMORY_REF_PTR_H_
9
10#include <cstddef>
11
12#include <functional>
13#include <utility>
14
15#include "flutter/fml/logging.h"
16#include "flutter/fml/macros.h"
17#include "flutter/fml/memory/ref_ptr_internal.h"
18
19namespace fml {
20
21// A smart pointer class for intrusively reference-counted objects (e.g., those
22// subclassing |RefCountedThreadSafe| -- see ref_counted.h).
23//
24// Such objects require *adoption* to obtain the first |RefPtr|, which is
25// accomplished using |AdoptRef| (see below). (This is due to such objects being
26// constructed with a reference count of 1. The adoption requirement is
27// enforced, at least in Debug builds, by assertions.)
28//
29// E.g., if |Foo| is an intrusively reference-counted class:
30//
31// // The |AdoptRef| may be put in a static factory method (e.g., if |Foo|'s
32// // constructor is private).
33// RefPtr<Foo> my_foo_ptr(AdoptRef(new Foo()));
34//
35// // Now OK, since "my Foo" has been adopted ...
36// RefPtr<Foo> another_ptr_to_my_foo(my_foo_ptr.get());
37//
38// // ... though this would preferable in this situation.
39// RefPtr<Foo> yet_another_ptr_to_my_foo(my_foo_ptr);
40//
41// Unlike Chromium's |scoped_refptr|, |RefPtr| is only explicitly constructible
42// from a plain pointer (and not assignable). It is however implicitly
43// constructible from |nullptr|. So:
44//
45// RefPtr<Foo> foo(plain_ptr_to_adopted_foo); // OK.
46// foo = plain_ptr_to_adopted_foo; // Not OK (doesn't compile).
47// foo = RefPtr<Foo>(plain_ptr_to_adopted_foo); // OK.
48// foo = nullptr; // OK.
49//
50// And if we have |void MyFunction(RefPtr<Foo> foo)|, calling it using
51// |MyFunction(nullptr)| is also valid.
52//
53// Implementation note: For copy/move constructors/operator=s, we often have
54// templated versions, so that the operation can be done on a |RefPtr<U>|, where
55// |U| is a subclass of |T|. However, we also have non-templated versions with
56// |U = T|, since the templated versions don't count as copy/move
57// constructors/operator=s for the purposes of causing the default copy
58// constructor/operator= to be deleted. E.g., if we didn't declare any
59// non-templated versions, we'd get the default copy constructor/operator= (we'd
60// only not get the default move constructor/operator= by virtue of having a
61// destructor)! (In fact, it'd suffice to only declare a non-templated move
62// constructor or move operator=, which would cause the copy
63// constructor/operator= to be deleted, but for clarity we include explicit
64// non-templated versions of everything.)
65template <typename T>
66class RefPtr final {
67 public:
68 RefPtr() : ptr_(nullptr) {}
69 RefPtr(std::nullptr_t)
70 : ptr_(nullptr) {} // NOLINT(google-explicit-constructor)
71
72 // Explicit constructor from a plain pointer (to an object that must have
73 // already been adopted). (Note that in |T::T()|, references to |this| cannot
74 // be taken, since the object being constructed will not have been adopted
75 // yet.)
76 template <typename U>
77 explicit RefPtr(U* p) : ptr_(p) {
78 if (ptr_) {
79 ptr_->AddRef();
80 }
81 }
82
83 // Copy constructor.
84 RefPtr(const RefPtr<T>& r) : ptr_(r.ptr_) {
85 if (ptr_) {
86 ptr_->AddRef();
87 }
88 }
89
90 template <typename U>
91 RefPtr(const RefPtr<U>& r)
92 : ptr_(r.ptr_) { // NOLINT(google-explicit-constructor)
93 if (ptr_) {
94 ptr_->AddRef();
95 }
96 }
97
98 // Move constructor.
99 RefPtr(RefPtr<T>&& r) : ptr_(r.ptr_) { r.ptr_ = nullptr; }
100
101 template <typename U>
102 RefPtr(RefPtr<U>&& r) : ptr_(r.ptr_) { // NOLINT(google-explicit-constructor)
103 r.ptr_ = nullptr;
104 }
105
106 // Destructor.
107 ~RefPtr() {
108 if (ptr_) {
109 ptr_->Release();
110 }
111 }
112
113 T* get() const { return ptr_; }
114
115 T& operator*() const {
116 FML_DCHECK(ptr_);
117 return *ptr_;
118 }
119
120 T* operator->() const {
121 FML_DCHECK(ptr_);
122 return ptr_;
123 }
124
125 // Copy assignment.
126 RefPtr<T>& operator=(const RefPtr<T>& r) {
127 // Handle self-assignment.
128 if (r.ptr_ == ptr_) {
129 return *this;
130 }
131 if (r.ptr_) {
132 r.ptr_->AddRef();
133 }
134 T* old_ptr = ptr_;
135 ptr_ = r.ptr_;
136 if (old_ptr) {
137 old_ptr->Release();
138 }
139 return *this;
140 }
141
142 template <typename U>
143 RefPtr<T>& operator=(const RefPtr<U>& r) {
144 if (reinterpret_cast<T*>(r.ptr_) == ptr_) {
145 return *this;
146 }
147 if (r.ptr_) {
148 r.ptr_->AddRef();
149 }
150 T* old_ptr = ptr_;
151 ptr_ = r.ptr_;
152 if (old_ptr) {
153 old_ptr->Release();
154 }
155 return *this;
156 }
157
158 // Move assignment.
159 // Note: Like |std::shared_ptr|, we support self-move and move assignment is
160 // equivalent to |RefPtr<T>(std::move(r)).swap(*this)|.
161 RefPtr<T>& operator=(RefPtr<T>&& r) {
162 RefPtr<T>(std::move(r)).swap(*this);
163 return *this;
164 }
165
166 template <typename U>
167 RefPtr<T>& operator=(RefPtr<U>&& r) {
168 RefPtr<T>(std::move(r)).swap(*this);
169 return *this;
170 }
171
172 void swap(RefPtr<T>& r) {
173 T* p = ptr_;
174 ptr_ = r.ptr_;
175 r.ptr_ = p;
176 }
177
178 // Returns a new |RefPtr<T>| with the same contents as this pointer. Useful
179 // when a function takes a |RefPtr<T>&&| argument and the caller wants to
180 // retain its reference (rather than moving it).
181 RefPtr<T> Clone() const { return *this; }
182
183 explicit operator bool() const { return !!ptr_; }
184
185 template <typename U>
186 bool operator==(const RefPtr<U>& rhs) const {
187 return ptr_ == rhs.ptr_;
188 }
189
190 template <typename U>
191 bool operator!=(const RefPtr<U>& rhs) const {
192 return !operator==(rhs);
193 }
194
195 template <typename U>
196 bool operator<(const RefPtr<U>& rhs) const {
197 return ptr_ < rhs.ptr_;
198 }
199
200 private:
201 template <typename U>
202 friend class RefPtr;
203
204 friend RefPtr<T> AdoptRef<T>(T*);
205
206 enum AdoptTag { ADOPT };
207 RefPtr(T* ptr, AdoptTag) : ptr_(ptr) { FML_DCHECK(ptr_); }
208
209 T* ptr_;
210};
211
212// Adopts a newly-created |T|. Typically used in a static factory method, like:
213//
214// // static
215// RefPtr<Foo> Foo::Create() {
216// return AdoptRef(new Foo());
217// }
218template <typename T>
219inline RefPtr<T> AdoptRef(T* ptr) {
220#ifndef NDEBUG
221 ptr->Adopt();
222#endif
223 return RefPtr<T>(ptr, RefPtr<T>::ADOPT);
224}
225
226// Constructs a |RefPtr<T>| from a plain pointer (to an object that must
227// have already been adoped). Avoids having to spell out the full type name.
228//
229// Foo* foo = ...;
230// auto foo_ref = Ref(foo);
231//
232// (|foo_ref| will be of type |RefPtr<Foo>|.)
233template <typename T>
234inline RefPtr<T> Ref(T* ptr) {
235 return RefPtr<T>(ptr);
236}
237
238// Creates an intrusively reference counted |T|, producing a |RefPtr<T>| (and
239// performing the required adoption). Use like:
240//
241// auto my_foo = MakeRefCounted<Foo>(ctor_arg1, ctor_arg2);
242//
243// (|my_foo| will be of type |RefPtr<Foo>|.)
244template <typename T, typename... Args>
245RefPtr<T> MakeRefCounted(Args&&... args) {
246 return internal::MakeRefCountedHelper<T>::MakeRefCounted(
247 std::forward<Args>(args)...);
248}
249
250} // namespace fml
251
252// Inject custom std::hash<> function object for |RefPtr<T>|.
253namespace std {
254template <typename T>
255struct hash<fml::RefPtr<T>> {
256 using argument_type = fml::RefPtr<T>;
257 using result_type = std::size_t;
258
259 result_type operator()(const argument_type& ptr) const {
260 return std::hash<T*>()(ptr.get());
261 }
262};
263} // namespace std
264
265#endif // FLUTTER_FML_MEMORY_REF_PTR_H_
266