• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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