Bug 1936278 - Prevent search mode chiclet from being dismissed when clicking in page...
[gecko.git] / dom / indexedDB / SafeRefPtr.h
blobe03ed4181b3e49eaa78b55b732fa5b6d5ba024c6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_saferefptr_h__
8 #define mozilla_saferefptr_h__
10 #include "mozilla/ArrayAlgorithm.h"
11 #include "mozilla/Maybe.h"
12 #include "mozilla/NotNull.h"
13 #include "mozilla/RefCounted.h"
14 #include "mozilla/RefPtr.h"
15 #include "nsCOMPtr.h"
16 #include "nsTObserverArray.h"
18 namespace mozilla {
19 template <typename T>
20 class SafeRefPtr;
22 template <typename T, typename... Args>
23 SafeRefPtr<T> MakeSafeRefPtr(Args&&... aArgs);
25 namespace detail {
26 struct InitialConstructionTag {};
28 class SafeRefCountedBase {
29 template <typename U, typename... Args>
30 friend SafeRefPtr<U> mozilla::MakeSafeRefPtr(Args&&... aArgs);
32 template <typename T>
33 friend class SafeRefPtr;
35 void* operator new(size_t aSize) { return ::operator new(aSize); }
37 protected:
38 void operator delete(void* aPtr) { ::operator delete(aPtr); }
40 public:
41 void* operator new[](size_t) = delete;
44 // SafeRefCounted is similar to RefCounted, but they differ in their initial
45 // refcount (here 1), and the visibility of operator new (here private). The
46 // rest is mostly a copy of RefCounted.
47 template <typename T, RefCountAtomicity Atomicity>
48 class SafeRefCounted : public SafeRefCountedBase {
49 protected:
50 SafeRefCounted() = default;
51 #ifdef DEBUG
52 ~SafeRefCounted() { MOZ_ASSERT(mRefCnt == detail::DEAD); }
53 #endif
55 public:
56 // Compatibility with nsRefPtr.
57 MozRefCountType AddRef() const {
58 // Note: this method must be thread safe for AtomicRefCounted.
59 MOZ_ASSERT(int32_t(mRefCnt) >= 0);
60 const MozRefCountType cnt = ++mRefCnt;
61 detail::RefCountLogger::logAddRef(static_cast<const T*>(this), cnt);
62 return cnt;
65 MozRefCountType Release() const {
66 // Note: this method must be thread safe for AtomicRefCounted.
67 MOZ_ASSERT(int32_t(mRefCnt) > 0);
68 detail::RefCountLogger::ReleaseLogger logger(static_cast<const T*>(this));
69 const MozRefCountType cnt = --mRefCnt;
70 // Note: it's not safe to touch |this| after decrementing the refcount,
71 // except for below.
72 logger.logRelease(cnt);
73 if (0 == cnt) {
74 // Because we have atomically decremented the refcount above, only
75 // one thread can get a 0 count here, so as long as we can assume that
76 // everything else in the system is accessing this object through
77 // RefPtrs, it's safe to access |this| here.
78 #ifdef DEBUG
79 mRefCnt = detail::DEAD;
80 #endif
81 delete static_cast<const T*>(this);
83 return cnt;
86 // Compatibility with wtf::RefPtr.
87 void ref() { AddRef(); }
88 void deref() { Release(); }
89 MozRefCountType refCount() const { return mRefCnt; }
90 bool hasOneRef() const {
91 MOZ_ASSERT(mRefCnt > 0);
92 return mRefCnt == 1;
95 protected:
96 SafeRefPtr<T> SafeRefPtrFromThis();
98 private:
99 mutable RC<MozRefCountType, Atomicity> mRefCnt =
100 RC<MozRefCountType, Atomicity>{1};
102 } // namespace detail
104 template <typename T>
105 class SafeRefCounted
106 : public detail::SafeRefCounted<T, detail::NonAtomicRefCount> {
107 public:
108 ~SafeRefCounted() {
109 static_assert(std::is_base_of<SafeRefCounted, T>::value,
110 "T must derive from SafeRefCounted<T>");
114 template <typename T>
115 class AtomicSafeRefCounted
116 : public detail::SafeRefCounted<T, detail::AtomicRefCount> {
117 public:
118 ~AtomicSafeRefCounted() {
119 static_assert(std::is_base_of<AtomicSafeRefCounted, T>::value,
120 "T must derive from AtomicSafeRefCounted<T>");
124 struct AcquireStrongRefFromRawPtr {};
126 // XXX for Apple, clang::trivial_abi is probably also supported, but we need to
127 // find out the correct version number
128 #if defined(__clang__) && !defined(__apple_build_version__) && \
129 __clang_major__ >= 7
130 # define MOZ_TRIVIAL_ABI [[clang::trivial_abi]]
131 #else
132 # define MOZ_TRIVIAL_ABI
133 #endif
135 // A restricted variant of mozilla::RefPtr<T>, which prohibits some unsafe or
136 // unperformant misuses, in particular:
137 // * It is not implicitly convertible from a raw pointer. Unsafe acquisitions
138 // from a raw pointer must be made using the verbose
139 // AcquireStrongRefFromRawPtr. To create a new object on the heap, use
140 // MakeSafeRefPtr.
141 // * It does not implicitly decay to a raw pointer. unsafeGetRawPtr() must be
142 // called
143 // explicitly.
144 // * It is not copyable, but must be explicitly copied using clonePtr().
145 // * Temporaries cannot be dereferenced using operator* or operator->.
146 template <typename T>
147 class MOZ_IS_REFPTR MOZ_TRIVIAL_ABI SafeRefPtr {
148 template <typename U>
149 friend class SafeRefPtr;
151 template <typename U, typename... Args>
152 friend SafeRefPtr<U> mozilla::MakeSafeRefPtr(Args&&... aArgs);
154 T* MOZ_OWNING_REF mRawPtr = nullptr;
156 // BEGIN Some things copied from RefPtr.
157 // We cannot simply use a RefPtr member because we want to be trivial_abi,
158 // which RefPtr is not.
159 void assign_with_AddRef(T* aRawPtr) {
160 if (aRawPtr) {
161 ConstRemovingRefPtrTraits<T>::AddRef(aRawPtr);
163 assign_assuming_AddRef(aRawPtr);
166 void assign_assuming_AddRef(T* aNewPtr) {
167 T* oldPtr = mRawPtr;
168 mRawPtr = aNewPtr;
169 if (oldPtr) {
170 ConstRemovingRefPtrTraits<T>::Release(oldPtr);
174 template <class U>
175 struct ConstRemovingRefPtrTraits {
176 static void AddRef(U* aPtr) { mozilla::RefPtrTraits<U>::AddRef(aPtr); }
177 static void Release(U* aPtr) { mozilla::RefPtrTraits<U>::Release(aPtr); }
179 template <class U>
180 struct ConstRemovingRefPtrTraits<const U> {
181 static void AddRef(const U* aPtr) {
182 mozilla::RefPtrTraits<U>::AddRef(const_cast<U*>(aPtr));
184 static void Release(const U* aPtr) {
185 mozilla::RefPtrTraits<U>::Release(const_cast<U*>(aPtr));
188 // END Some things copied from RefPtr.
190 SafeRefPtr(T* aRawPtr, mozilla::detail::InitialConstructionTag);
192 public:
193 SafeRefPtr() = default;
195 template <typename U,
196 typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
197 MOZ_IMPLICIT SafeRefPtr(SafeRefPtr<U>&& aSrc) : mRawPtr(aSrc.mRawPtr) {
198 aSrc.mRawPtr = nullptr;
201 explicit SafeRefPtr(RefPtr<T>&& aRefPtr) : mRawPtr(aRefPtr.forget().take()) {}
203 // To prevent implicit conversion of raw pointer to RefPtr and then
204 // calling the previous overload.
205 SafeRefPtr(T* const aRawPtr) = delete;
207 SafeRefPtr(T* const aRawPtr, const AcquireStrongRefFromRawPtr&) {
208 assign_with_AddRef(aRawPtr);
211 MOZ_IMPLICIT SafeRefPtr(std::nullptr_t) {}
213 // Prevent implicit copying, use clonePtr() instead.
214 SafeRefPtr(const SafeRefPtr&) = delete;
215 SafeRefPtr& operator=(const SafeRefPtr&) = delete;
217 // Allow moving.
218 SafeRefPtr(SafeRefPtr&& aOther) noexcept : mRawPtr(aOther.mRawPtr) {
219 aOther.mRawPtr = nullptr;
221 SafeRefPtr& operator=(SafeRefPtr&& aOther) noexcept {
222 assign_assuming_AddRef(aOther.forget().take());
223 return *this;
226 ~SafeRefPtr() {
227 static_assert(!std::is_copy_constructible_v<T>);
228 static_assert(!std::is_copy_assignable_v<T>);
229 static_assert(!std::is_move_constructible_v<T>);
230 static_assert(!std::is_move_assignable_v<T>);
232 if (mRawPtr) {
233 ConstRemovingRefPtrTraits<T>::Release(mRawPtr);
237 typedef T element_type;
239 explicit operator bool() const { return mRawPtr; }
240 bool operator!() const { return !mRawPtr; }
242 T& operator*() const&& = delete;
244 T& operator*() const& {
245 MOZ_ASSERT(mRawPtr);
246 return *mRawPtr;
249 T* operator->() const&& = delete;
251 T* operator->() const& MOZ_NO_ADDREF_RELEASE_ON_RETURN {
252 MOZ_ASSERT(mRawPtr);
253 return mRawPtr;
256 Maybe<T&> maybeDeref() const { return ToMaybeRef(mRawPtr); }
258 T* unsafeGetRawPtr() const { return mRawPtr; }
260 SafeRefPtr<T> clonePtr() const {
261 return SafeRefPtr{mRawPtr, AcquireStrongRefFromRawPtr{}};
264 already_AddRefed<T> forget() {
265 auto* const res = mRawPtr;
266 mRawPtr = nullptr;
267 return dont_AddRef(res);
270 bool operator==(const SafeRefPtr<T>& aOther) const {
271 return mRawPtr == aOther.mRawPtr;
274 bool operator!=(const SafeRefPtr<T>& aOther) const {
275 return mRawPtr != aOther.mRawPtr;
278 template <typename U, typename = std::enable_if_t<std::is_base_of_v<T, U>>>
279 SafeRefPtr<U> downcast() && {
280 SafeRefPtr<U> res;
281 res.mRawPtr = static_cast<U*>(mRawPtr);
282 mRawPtr = nullptr;
283 return res;
286 template <typename U>
287 friend RefPtr<U> AsRefPtr(SafeRefPtr<U>&& aSafeRefPtr);
290 template <typename T>
291 SafeRefPtr(RefPtr<T>&&) -> SafeRefPtr<T>;
293 template <typename T>
294 SafeRefPtr(already_AddRefed<T>&&) -> SafeRefPtr<T>;
296 template <typename T>
297 class CheckedUnsafePtr;
299 template <typename T>
300 SafeRefPtr(const CheckedUnsafePtr<T>&,
301 const AcquireStrongRefFromRawPtr&) -> SafeRefPtr<T>;
303 template <typename T>
304 SafeRefPtr<T>::SafeRefPtr(T* aRawPtr, detail::InitialConstructionTag)
305 : mRawPtr(aRawPtr) {
306 if (!std::is_base_of_v<detail::SafeRefCountedBase, T> && mRawPtr) {
307 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
311 template <typename T>
312 bool operator==(std::nullptr_t aLhs, const SafeRefPtr<T>& aRhs) {
313 return !aRhs;
316 template <typename T>
317 bool operator!=(std::nullptr_t aLhs, const SafeRefPtr<T>& aRhs) {
318 return static_cast<bool>(aRhs);
321 template <typename T>
322 bool operator==(const SafeRefPtr<T>& aLhs, std::nullptr_t aRhs) {
323 return !aLhs;
326 template <typename T>
327 bool operator!=(const SafeRefPtr<T>& aLhs, std::nullptr_t aRhs) {
328 return static_cast<bool>(aLhs);
331 template <typename T, typename U, typename = std::common_type_t<T*, U*>>
332 bool operator==(T* const aLhs, const SafeRefPtr<U>& aRhs) {
333 return aLhs == aRhs.unsafeGetRawPtr();
336 template <typename T, typename U, typename = std::common_type_t<T*, U*>>
337 bool operator!=(T* const aLhs, const SafeRefPtr<U>& aRhs) {
338 return !(aLhs == aRhs);
341 template <typename T, typename U, typename = std::common_type_t<T*, U*>>
342 bool operator==(const SafeRefPtr<T>& aLhs, U* const aRhs) {
343 return aRhs == aLhs;
346 template <typename T, typename U, typename = std::common_type_t<T*, U*>>
347 bool operator!=(const SafeRefPtr<T>& aLhs, U* const aRhs) {
348 return aRhs != aLhs;
351 template <typename T, typename U, typename = std::common_type_t<T*, U*>>
352 bool operator==(const Maybe<T&> aLhs, const SafeRefPtr<U>& aRhs) {
353 return &aLhs.ref() == aRhs.unsafeGetRawPtr();
356 template <typename T, typename U, typename = std::common_type_t<T*, U*>>
357 bool operator!=(const Maybe<T&> aLhs, const SafeRefPtr<U>& aRhs) {
358 return !(aLhs == aRhs);
361 template <typename T, typename U, typename = std::common_type_t<T*, U*>>
362 bool operator==(const SafeRefPtr<T>& aLhs, const Maybe<U&> aRhs) {
363 return aRhs == aLhs;
366 template <typename T, typename U, typename = std::common_type_t<T*, U*>>
367 bool operator!=(const SafeRefPtr<T>& aLhs, const Maybe<U&> aRhs) {
368 return aRhs != aLhs;
371 template <typename T>
372 RefPtr<T> AsRefPtr(SafeRefPtr<T>&& aSafeRefPtr) {
373 return aSafeRefPtr.forget();
376 template <typename T, typename... Args>
377 SafeRefPtr<T> MakeSafeRefPtr(Args&&... aArgs) {
378 return SafeRefPtr{new T(std::forward<Args>(aArgs)...),
379 detail::InitialConstructionTag{}};
382 template <typename T>
383 void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
384 const SafeRefPtr<T>& aField, const char* aName,
385 uint32_t aFlags = 0) {
386 CycleCollectionNoteChild(aCallback, aField.unsafeGetRawPtr(), aName, aFlags);
389 template <typename T>
390 void ImplCycleCollectionUnlink(SafeRefPtr<T>& aField) {
391 aField = nullptr;
394 namespace detail {
396 template <typename T, RefCountAtomicity Atomicity>
397 SafeRefPtr<T> SafeRefCounted<T, Atomicity>::SafeRefPtrFromThis() {
398 // this actually is safe
399 return {static_cast<T*>(this), AcquireStrongRefFromRawPtr{}};
402 template <typename T>
403 struct CopyablePtr<SafeRefPtr<T>> {
404 SafeRefPtr<T> mPtr;
406 explicit CopyablePtr(SafeRefPtr<T> aPtr) : mPtr{std::move(aPtr)} {}
408 CopyablePtr(const CopyablePtr& aOther) : mPtr{aOther.mPtr.clonePtr()} {}
409 CopyablePtr& operator=(const CopyablePtr& aOther) {
410 if (this != &aOther) {
411 mPtr = aOther.mPtr.clonePtr();
413 return *this;
415 CopyablePtr(CopyablePtr&&) = default;
416 CopyablePtr& operator=(CopyablePtr&&) = default;
419 } // namespace detail
421 namespace dom {
422 /// XXX Move this to BindingUtils.h later on
423 template <class T, class S>
424 inline RefPtr<T> StrongOrRawPtr(SafeRefPtr<S>&& aPtr) {
425 return AsRefPtr(std::move(aPtr));
428 } // namespace dom
430 } // namespace mozilla
432 template <class T>
433 class nsTObserverArray<mozilla::SafeRefPtr<T>>
434 : public nsAutoTObserverArray<mozilla::SafeRefPtr<T>, 0> {
435 public:
436 using base_type = nsAutoTObserverArray<mozilla::SafeRefPtr<T>, 0>;
437 using size_type = nsTObserverArray_base::size_type;
439 // Initialization methods
440 nsTObserverArray() = default;
442 // Initialize this array and pre-allocate some number of elements.
443 explicit nsTObserverArray(size_type aCapacity) {
444 base_type::mArray.SetCapacity(aCapacity);
447 nsTObserverArray Clone() const {
448 auto result = nsTObserverArray{};
449 result.mArray = mozilla::TransformIntoNewArray(
450 this->mArray, [](const auto& ptr) { return ptr.clonePtr(); });
451 return result;
455 // Use MOZ_INLINE_DECL_SAFEREFCOUNTING_INHERITED in a 'Class' derived from a
456 // 'Super' class which derives from (Atomic)SafeRefCounted, and from some other
457 // class using NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING.
458 #if defined(NS_BUILD_REFCNT_LOGGING)
459 # define MOZ_INLINE_DECL_SAFEREFCOUNTING_INHERITED(Class, Super) \
460 template <typename T, ::mozilla::detail::RefCountAtomicity Atomicity> \
461 friend class ::mozilla::detail::SafeRefCounted; \
462 NS_IMETHOD_(MozExternalRefCountType) AddRef() override { \
463 NS_IMPL_ADDREF_INHERITED_GUTS(Class, Super); \
465 NS_IMETHOD_(MozExternalRefCountType) Release() override { \
466 NS_IMPL_RELEASE_INHERITED_GUTS(Class, Super); \
468 #else // NS_BUILD_REFCNT_LOGGING
469 # define MOZ_INLINE_DECL_SAFEREFCOUNTING_INHERITED(Class, Super) \
470 template <typename T, ::mozilla::detail::RefCountAtomicity Atomicity> \
471 friend class ::mozilla::detail::SafeRefCounted; \
472 NS_IMETHOD_(MozExternalRefCountType) AddRef() override { \
473 return Super::AddRef(); \
475 NS_IMETHOD_(MozExternalRefCountType) Release() override { \
476 return Super::Release(); \
478 #endif
480 #endif