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