1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef PARTITION_ALLOC_PARTITION_ALLOC_BASE_MEMORY_SCOPED_REFPTR_H_
6 #define PARTITION_ALLOC_PARTITION_ALLOC_BASE_MEMORY_SCOPED_REFPTR_H_
7
8 #include <cstddef>
9 #include <iosfwd>
10 #include <type_traits>
11 #include <utility>
12
13 #include "partition_alloc/partition_alloc_base/check.h"
14 #include "partition_alloc/partition_alloc_base/compiler_specific.h"
15
16 namespace partition_alloc::internal {
17
18 template <class T>
19 class scoped_refptr;
20
21 namespace base {
22
23 template <class, typename>
24 class RefCountedThreadSafe;
25
26 template <typename T>
27 scoped_refptr<T> AdoptRef(T* t);
28
29 namespace subtle {
30
31 enum AdoptRefTag { kAdoptRefTag };
32 enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag };
33 enum StartRefCountFromOneTag { kStartRefCountFromOneTag };
34
35 // scoped_refptr<T> is typically used with one of several RefCounted<T> base
36 // classes or with custom AddRef and Release methods. These overloads dispatch
37 // on which was used.
38
39 template <typename T, typename U, typename V>
IsRefCountPreferenceOverridden(const T *,const RefCountedThreadSafe<U,V> *)40 constexpr bool IsRefCountPreferenceOverridden(
41 const T*,
42 const RefCountedThreadSafe<U, V>*) {
43 return !std::is_same_v<std::decay_t<decltype(T::kRefCountPreference)>,
44 std::decay_t<decltype(U::kRefCountPreference)>>;
45 }
46
IsRefCountPreferenceOverridden(...)47 constexpr bool IsRefCountPreferenceOverridden(...) {
48 return false;
49 }
50
51 template <typename T, typename U, typename V>
AssertRefCountBaseMatches(const T *,const RefCountedThreadSafe<U,V> *)52 constexpr void AssertRefCountBaseMatches(const T*,
53 const RefCountedThreadSafe<U, V>*) {
54 static_assert(
55 std::is_base_of_v<U, T>,
56 "T implements RefCountedThreadSafe<U>, but U is not a base of T.");
57 }
58
AssertRefCountBaseMatches(...)59 constexpr void AssertRefCountBaseMatches(...) {}
60
61 } // namespace subtle
62
63 // Creates a scoped_refptr from a raw pointer without incrementing the reference
64 // count. Use this only for a newly created object whose reference count starts
65 // from 1 instead of 0.
66 template <typename T>
AdoptRef(T * obj)67 scoped_refptr<T> AdoptRef(T* obj) {
68 using Tag = std::decay_t<decltype(T::kRefCountPreference)>;
69 static_assert(std::is_same_v<subtle::StartRefCountFromOneTag, Tag>,
70 "Use AdoptRef only if the reference count starts from one.");
71
72 PA_BASE_DCHECK(obj);
73 PA_BASE_DCHECK(obj->HasOneRef());
74 obj->Adopted();
75 return scoped_refptr<T>(obj, subtle::kAdoptRefTag);
76 }
77
78 namespace subtle {
79
80 template <typename T>
AdoptRefIfNeeded(T * obj,StartRefCountFromZeroTag)81 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) {
82 return scoped_refptr<T>(obj);
83 }
84
85 template <typename T>
AdoptRefIfNeeded(T * obj,StartRefCountFromOneTag)86 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) {
87 return AdoptRef(obj);
88 }
89
90 } // namespace subtle
91
92 // Constructs an instance of T, which is a ref counted type, and wraps the
93 // object into a scoped_refptr<T>.
94 template <typename T, typename... Args>
MakeRefCounted(Args &&...args)95 scoped_refptr<T> MakeRefCounted(Args&&... args) {
96 T* obj = new T(std::forward<Args>(args)...);
97 return subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference);
98 }
99
100 // Takes an instance of T, which is a ref counted type, and wraps the object
101 // into a scoped_refptr<T>.
102 template <typename T>
WrapRefCounted(T * t)103 scoped_refptr<T> WrapRefCounted(T* t) {
104 return scoped_refptr<T>(t);
105 }
106
107 } // namespace base
108
109 //
110 // A smart pointer class for reference counted objects. Use this class instead
111 // of calling AddRef and Release manually on a reference counted object to
112 // avoid common memory leaks caused by forgetting to Release an object
113 // reference. Sample usage:
114 //
115 // class MyFoo : public RefCounted<MyFoo> {
116 // ...
117 // private:
118 // friend class RefCounted<MyFoo>; // Allow destruction by RefCounted<>.
119 // ~MyFoo(); // Destructor must be private/protected.
120 // };
121 //
122 // void some_function() {
123 // scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
124 // foo->Method(param);
125 // // |foo| is released when this function returns
126 // }
127 //
128 // void some_other_function() {
129 // scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
130 // ...
131 // foo.reset(); // explicitly releases |foo|
132 // ...
133 // if (foo)
134 // foo->Method(param);
135 // }
136 //
137 // The above examples show how scoped_refptr<T> acts like a pointer to T.
138 // Given two scoped_refptr<T> classes, it is also possible to exchange
139 // references between the two objects, like so:
140 //
141 // {
142 // scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
143 // scoped_refptr<MyFoo> b;
144 //
145 // b.swap(a);
146 // // now, |b| references the MyFoo object, and |a| references nullptr.
147 // }
148 //
149 // To make both |a| and |b| in the above example reference the same MyFoo
150 // object, simply use the assignment operator:
151 //
152 // {
153 // scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
154 // scoped_refptr<MyFoo> b;
155 //
156 // b = a;
157 // // now, |a| and |b| each own a reference to the same MyFoo object.
158 // }
159 //
160 // Also see Chromium's ownership and calling conventions:
161 // https://chromium.googlesource.com/chromium/src/+/lkgr/styleguide/c++/c++.md#object-ownership-and-calling-conventions
162 // Specifically:
163 // If the function (at least sometimes) takes a ref on a refcounted object,
164 // declare the param as scoped_refptr<T>. The caller can decide whether it
165 // wishes to transfer ownership (by calling std::move(t) when passing t) or
166 // retain its ref (by simply passing t directly).
167 // In other words, use scoped_refptr like you would a std::unique_ptr except
168 // in the odd case where it's required to hold on to a ref while handing one
169 // to another component (if a component merely needs to use t on the stack
170 // without keeping a ref: pass t as a raw T*).
171 template <class T>
172 class PA_TRIVIAL_ABI scoped_refptr {
173 public:
174 typedef T element_type;
175
176 constexpr scoped_refptr() = default;
177
178 // Allow implicit construction from nullptr.
scoped_refptr(std::nullptr_t)179 constexpr scoped_refptr(std::nullptr_t) {}
180
181 // Constructs from a raw pointer. Note that this constructor allows implicit
182 // conversion from T* to scoped_refptr<T> which is strongly discouraged. If
183 // you are creating a new ref-counted object please use
184 // base::MakeRefCounted<T>() or base::WrapRefCounted<T>(). Otherwise you
185 // should move or copy construct from an existing scoped_refptr<T> to the
186 // ref-counted object.
scoped_refptr(T * p)187 scoped_refptr(T* p) : ptr_(p) {
188 if (ptr_) {
189 AddRef(ptr_);
190 }
191 }
192
193 // Copy constructor. This is required in addition to the copy conversion
194 // constructor below.
scoped_refptr(const scoped_refptr & r)195 scoped_refptr(const scoped_refptr& r) : scoped_refptr(r.ptr_) {}
196
197 // Copy conversion constructor.
198 template <
199 typename U,
200 typename = typename std::enable_if<std::is_convertible_v<U*, T*>>::type>
scoped_refptr(const scoped_refptr<U> & r)201 scoped_refptr(const scoped_refptr<U>& r) : scoped_refptr(r.ptr_) {}
202
203 // Move constructor. This is required in addition to the move conversion
204 // constructor below.
scoped_refptr(scoped_refptr && r)205 scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.ptr_) { r.ptr_ = nullptr; }
206
207 // Move conversion constructor.
208 template <
209 typename U,
210 typename = typename std::enable_if<std::is_convertible_v<U*, T*>>::type>
scoped_refptr(scoped_refptr<U> && r)211 scoped_refptr(scoped_refptr<U>&& r) noexcept : ptr_(r.ptr_) {
212 r.ptr_ = nullptr;
213 }
214
~scoped_refptr()215 ~scoped_refptr() {
216 static_assert(!base::subtle::IsRefCountPreferenceOverridden(
217 static_cast<T*>(nullptr), static_cast<T*>(nullptr)),
218 "It's unsafe to override the ref count preference."
219 " Please remove REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE"
220 " from subclasses.");
221 if (ptr_) {
222 Release(ptr_);
223 }
224 }
225
get()226 T* get() const { return ptr_; }
227
228 T& operator*() const {
229 PA_BASE_DCHECK(ptr_);
230 return *ptr_;
231 }
232
233 T* operator->() const {
234 PA_BASE_DCHECK(ptr_);
235 return ptr_;
236 }
237
238 scoped_refptr& operator=(std::nullptr_t) {
239 reset();
240 return *this;
241 }
242
243 scoped_refptr& operator=(T* p) { return *this = scoped_refptr(p); }
244
245 // Unified assignment operator.
246 scoped_refptr& operator=(scoped_refptr r) noexcept {
247 swap(r);
248 return *this;
249 }
250
251 // Sets managed object to null and releases reference to the previous managed
252 // object, if it existed.
reset()253 void reset() { scoped_refptr().swap(*this); }
254
255 // Returns the owned pointer (if any), releasing ownership to the caller. The
256 // caller is responsible for managing the lifetime of the reference.
257 [[nodiscard]] T* release();
258
swap(scoped_refptr & r)259 void swap(scoped_refptr& r) noexcept { std::swap(ptr_, r.ptr_); }
260
261 explicit operator bool() const { return ptr_ != nullptr; }
262
263 template <typename U>
264 bool operator==(const scoped_refptr<U>& rhs) const {
265 return ptr_ == rhs.get();
266 }
267
268 template <typename U>
269 bool operator!=(const scoped_refptr<U>& rhs) const {
270 return !operator==(rhs);
271 }
272
273 template <typename U>
274 bool operator<(const scoped_refptr<U>& rhs) const {
275 return ptr_ < rhs.get();
276 }
277
278 protected:
279 T* ptr_ = nullptr;
280
281 private:
282 template <typename U>
283 friend scoped_refptr<U> base::AdoptRef(U*);
284
scoped_refptr(T * p,base::subtle::AdoptRefTag)285 scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {}
286
287 // Friend required for move constructors that set r.ptr_ to null.
288 template <typename U>
289 friend class scoped_refptr;
290
291 // Non-inline helpers to allow:
292 // class Opaque;
293 // extern template class scoped_refptr<Opaque>;
294 // Otherwise the compiler will complain that Opaque is an incomplete type.
295 static void AddRef(T* ptr);
296 static void Release(T* ptr);
297 };
298
299 template <typename T>
release()300 T* scoped_refptr<T>::release() {
301 T* ptr = ptr_;
302 ptr_ = nullptr;
303 return ptr;
304 }
305
306 // static
307 template <typename T>
AddRef(T * ptr)308 void scoped_refptr<T>::AddRef(T* ptr) {
309 base::subtle::AssertRefCountBaseMatches(ptr, ptr);
310 ptr->AddRef();
311 }
312
313 // static
314 template <typename T>
Release(T * ptr)315 void scoped_refptr<T>::Release(T* ptr) {
316 base::subtle::AssertRefCountBaseMatches(ptr, ptr);
317 ptr->Release();
318 }
319
320 template <typename T, typename U>
321 bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
322 return lhs.get() == rhs;
323 }
324
325 template <typename T, typename U>
326 bool operator==(const T* lhs, const scoped_refptr<U>& rhs) {
327 return lhs == rhs.get();
328 }
329
330 template <typename T>
331 bool operator==(const scoped_refptr<T>& lhs, std::nullptr_t null) {
332 return !static_cast<bool>(lhs);
333 }
334
335 template <typename T>
336 bool operator==(std::nullptr_t null, const scoped_refptr<T>& rhs) {
337 return !static_cast<bool>(rhs);
338 }
339
340 template <typename T, typename U>
341 bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) {
342 return !operator==(lhs, rhs);
343 }
344
345 template <typename T, typename U>
346 bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) {
347 return !operator==(lhs, rhs);
348 }
349
350 template <typename T>
351 bool operator!=(const scoped_refptr<T>& lhs, std::nullptr_t null) {
352 return !operator==(lhs, null);
353 }
354
355 template <typename T>
356 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) {
357 return !operator==(null, rhs);
358 }
359
360 template <typename T>
361 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
362 return out << p.get();
363 }
364
365 template <typename T>
swap(scoped_refptr<T> & lhs,scoped_refptr<T> & rhs)366 void swap(scoped_refptr<T>& lhs, scoped_refptr<T>& rhs) noexcept {
367 lhs.swap(rhs);
368 }
369
370 } // namespace partition_alloc::internal
371
372 #endif // PARTITION_ALLOC_PARTITION_ALLOC_BASE_MEMORY_SCOPED_REFPTR_H_
373