/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_RefPtr_h #define mozilla_RefPtr_h #include "mozilla/AlreadyAddRefed.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" /*****************************************************************************/ // template <class T> class RefPtrGetterAddRefs; class nsCOMPtr_helper; namespace mozilla { template<class T> class OwningNonNull; template<class T> class StaticRefPtr; // Traditionally, RefPtr supports automatic refcounting of any pointer type // with AddRef() and Release() methods that follow the traditional semantics. // // This traits class can be specialized to operate on other pointer types. For // example, we specialize this trait for opaque FFI types that represent // refcounted objects in Rust. // // Given the use of ConstRemovingRefPtrTraits below, U should not be a const- // qualified type. template<class U> struct RefPtrTraits { static void AddRef(U* aPtr) { aPtr->AddRef(); } static void Release(U* aPtr) { aPtr->Release(); } }; } // namespace mozilla template <class T> class RefPtr { private: void assign_with_AddRef(T* aRawPtr) { if (aRawPtr) { ConstRemovingRefPtrTraits<T>::AddRef(aRawPtr); } assign_assuming_AddRef(aRawPtr); } void assign_assuming_AddRef(T* aNewPtr) { T* oldPtr = mRawPtr; mRawPtr = aNewPtr; if (oldPtr) { ConstRemovingRefPtrTraits<T>::Release(oldPtr); } } private: T* MOZ_OWNING_REF mRawPtr; public: typedef T element_type; ~RefPtr() { if (mRawPtr) { ConstRemovingRefPtrTraits<T>::Release(mRawPtr); } } // Constructors RefPtr() : mRawPtr(nullptr) // default constructor { } RefPtr(const RefPtr<T>& aSmartPtr) : mRawPtr(aSmartPtr.mRawPtr) // copy-constructor { if (mRawPtr) { ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr); } } RefPtr(RefPtr<T>&& aRefPtr) : mRawPtr(aRefPtr.mRawPtr) { aRefPtr.mRawPtr = nullptr; } // construct from a raw pointer (of the right type) MOZ_IMPLICIT RefPtr(T* aRawPtr) : mRawPtr(aRawPtr) { if (mRawPtr) { ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr); } } MOZ_IMPLICIT RefPtr(decltype(nullptr)) : mRawPtr(nullptr) { } template <typename I> MOZ_IMPLICIT RefPtr(already_AddRefed<I>& aSmartPtr) : mRawPtr(aSmartPtr.take()) // construct from |already_AddRefed| { } template <typename I> MOZ_IMPLICIT RefPtr(already_AddRefed<I>&& aSmartPtr) : mRawPtr(aSmartPtr.take()) // construct from |otherRefPtr.forget()| { } template <typename I> MOZ_IMPLICIT RefPtr(const RefPtr<I>& aSmartPtr) : mRawPtr(aSmartPtr.get()) // copy-construct from a smart pointer with a related pointer type { if (mRawPtr) { ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr); } } template <typename I> MOZ_IMPLICIT RefPtr(RefPtr<I>&& aSmartPtr) : mRawPtr(aSmartPtr.forget().take()) // construct from |Move(RefPtr<SomeSubclassOfT>)|. { } MOZ_IMPLICIT RefPtr(const nsCOMPtr_helper& aHelper); // Defined in OwningNonNull.h template<class U> MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull<U>& aOther); // Defined in StaticPtr.h template<class U> MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr<U>& aOther); // Assignment operators RefPtr<T>& operator=(decltype(nullptr)) { assign_assuming_AddRef(nullptr); return *this; } RefPtr<T>& operator=(const RefPtr<T>& aRhs) // copy assignment operator { assign_with_AddRef(aRhs.mRawPtr); return *this; } template <typename I> RefPtr<T>& operator=(const RefPtr<I>& aRhs) // assign from an RefPtr of a related pointer type { assign_with_AddRef(aRhs.get()); return *this; } RefPtr<T>& operator=(T* aRhs) // assign from a raw pointer (of the right type) { assign_with_AddRef(aRhs); return *this; } template <typename I> RefPtr<T>& operator=(already_AddRefed<I>& aRhs) // assign from |already_AddRefed| { assign_assuming_AddRef(aRhs.take()); return *this; } template <typename I> RefPtr<T>& operator=(already_AddRefed<I> && aRhs) // assign from |otherRefPtr.forget()| { assign_assuming_AddRef(aRhs.take()); return *this; } RefPtr<T>& operator=(const nsCOMPtr_helper& aHelper); RefPtr<T>& operator=(RefPtr<T> && aRefPtr) { assign_assuming_AddRef(aRefPtr.mRawPtr); aRefPtr.mRawPtr = nullptr; return *this; } // Defined in OwningNonNull.h template<class U> RefPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther); // Defined in StaticPtr.h template<class U> RefPtr<T>& operator=(const mozilla::StaticRefPtr<U>& aOther); // Other pointer operators void swap(RefPtr<T>& aRhs) // ...exchange ownership with |aRhs|; can save a pair of refcount operations { T* temp = aRhs.mRawPtr; aRhs.mRawPtr = mRawPtr; mRawPtr = temp; } void swap(T*& aRhs) // ...exchange ownership with |aRhs|; can save a pair of refcount operations { T* temp = aRhs; aRhs = mRawPtr; mRawPtr = temp; } already_AddRefed<T> forget() // return the value of mRawPtr and null out mRawPtr. Useful for // already_AddRefed return values. { T* temp = nullptr; swap(temp); return already_AddRefed<T>(temp); } template <typename I> void forget(I** aRhs) // Set the target of aRhs to the value of mRawPtr and null out mRawPtr. // Useful to avoid unnecessary AddRef/Release pairs with "out" // parameters where aRhs bay be a T** or an I** where I is a base class // of T. { MOZ_ASSERT(aRhs, "Null pointer passed to forget!"); *aRhs = mRawPtr; mRawPtr = nullptr; } T* get() const /* Prefer the implicit conversion provided automatically by |operator T*() const|. Use |get()| to resolve ambiguity or to get a castable pointer. */ { return const_cast<T*>(mRawPtr); } operator T*() const #ifdef MOZ_HAVE_REF_QUALIFIERS & #endif /* ...makes an |RefPtr| act like its underlying raw pointer type whenever it is used in a context where a raw pointer is expected. It is this operator that makes an |RefPtr| substitutable for a raw pointer. Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. */ { return get(); } #ifdef MOZ_HAVE_REF_QUALIFIERS // Don't allow implicit conversion of temporary RefPtr to raw pointer, // because the refcount might be one and the pointer will immediately become // invalid. operator T*() const && = delete; // These are needed to avoid the deleted operator above. XXX Why is operator! // needed separately? Shouldn't the compiler prefer using the non-deleted // operator bool instead of the deleted operator T*? explicit operator bool() const { return !!mRawPtr; } bool operator!() const { return !mRawPtr; } #endif T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator->()."); return get(); } template <typename R, typename... Args> class Proxy { typedef R (T::*member_function)(Args...); T* mRawPtr; member_function mFunction; public: Proxy(T* aRawPtr, member_function aFunction) : mRawPtr(aRawPtr), mFunction(aFunction) { } template<typename... ActualArgs> R operator()(ActualArgs&&... aArgs) { return ((*mRawPtr).*mFunction)(mozilla::Forward<ActualArgs>(aArgs)...); } }; template <typename R, typename... Args> Proxy<R, Args...> operator->*(R (T::*aFptr)(Args...)) const { MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator->*()."); return Proxy<R, Args...>(get(), aFptr); } RefPtr<T>* get_address() // This is not intended to be used by clients. See |address_of| // below. { return this; } const RefPtr<T>* get_address() const // This is not intended to be used by clients. See |address_of| // below. { return this; } public: T& operator*() const { MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator*()."); return *get(); } T** StartAssignment() { assign_assuming_AddRef(nullptr); return reinterpret_cast<T**>(&mRawPtr); } private: // This helper class makes |RefPtr<const T>| possible by casting away // the constness from the pointer when calling AddRef() and Release(). // // This is necessary because AddRef() and Release() implementations can't // generally expected to be const themselves (without heavy use of |mutable| // and |const_cast| in their own implementations). // // This should be sound because while |RefPtr<const T>| provides a // const view of an object, the object itself should not be const (it // would have to be allocated as |new const T| or similar to be const). template<class U> struct ConstRemovingRefPtrTraits { static void AddRef(U* aPtr) { mozilla::RefPtrTraits<U>::AddRef(aPtr); } static void Release(U* aPtr) { mozilla::RefPtrTraits<U>::Release(aPtr); } }; template<class U> struct ConstRemovingRefPtrTraits<const U> { static void AddRef(const U* aPtr) { mozilla::RefPtrTraits<U>::AddRef(const_cast<U*>(aPtr)); } static void Release(const U* aPtr) { mozilla::RefPtrTraits<U>::Release(const_cast<U*>(aPtr)); } }; }; class nsCycleCollectionTraversalCallback; template <typename T> void CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback, T* aChild, const char* aName, uint32_t aFlags); template <typename T> inline void ImplCycleCollectionUnlink(RefPtr<T>& aField) { aField = nullptr; } template <typename T> inline void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, RefPtr<T>& aField, const char* aName, uint32_t aFlags = 0) { CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags); } template <class T> inline RefPtr<T>* address_of(RefPtr<T>& aPtr) { return aPtr.get_address(); } template <class T> inline const RefPtr<T>* address_of(const RefPtr<T>& aPtr) { return aPtr.get_address(); } template <class T> class RefPtrGetterAddRefs /* ... This class is designed to be used for anonymous temporary objects in the argument list of calls that return COM interface pointers, e.g., RefPtr<IFoo> fooP; ...->GetAddRefedPointer(getter_AddRefs(fooP)) DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead. When initialized with a |RefPtr|, as in the example above, it returns a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call (|GetAddRefedPointer| in this case) can fill in. This type should be a nested class inside |RefPtr<T>|. */ { public: explicit RefPtrGetterAddRefs(RefPtr<T>& aSmartPtr) : mTargetSmartPtr(aSmartPtr) { // nothing else to do } operator void**() { return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment()); } operator T**() { return mTargetSmartPtr.StartAssignment(); } T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } private: RefPtr<T>& mTargetSmartPtr; }; template <class T> inline RefPtrGetterAddRefs<T> getter_AddRefs(RefPtr<T>& aSmartPtr) /* Used around a |RefPtr| when ...makes the class |RefPtrGetterAddRefs<T>| invisible. */ { return RefPtrGetterAddRefs<T>(aSmartPtr); } // Comparing two |RefPtr|s template <class T, class U> inline bool operator==(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) { return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get()); } template <class T, class U> inline bool operator!=(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) { return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get()); } // Comparing an |RefPtr| to a raw pointer template <class T, class U> inline bool operator==(const RefPtr<T>& aLhs, const U* aRhs) { return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs); } template <class T, class U> inline bool operator==(const U* aLhs, const RefPtr<T>& aRhs) { return static_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get()); } template <class T, class U> inline bool operator!=(const RefPtr<T>& aLhs, const U* aRhs) { return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs); } template <class T, class U> inline bool operator!=(const U* aLhs, const RefPtr<T>& aRhs) { return static_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get()); } template <class T, class U> inline bool operator==(const RefPtr<T>& aLhs, U* aRhs) { return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs); } template <class T, class U> inline bool operator==(U* aLhs, const RefPtr<T>& aRhs) { return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get()); } template <class T, class U> inline bool operator!=(const RefPtr<T>& aLhs, U* aRhs) { return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs); } template <class T, class U> inline bool operator!=(U* aLhs, const RefPtr<T>& aRhs) { return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get()); } // Comparing an |RefPtr| to |nullptr| template <class T> inline bool operator==(const RefPtr<T>& aLhs, decltype(nullptr)) { return aLhs.get() == nullptr; } template <class T> inline bool operator==(decltype(nullptr), const RefPtr<T>& aRhs) { return nullptr == aRhs.get(); } template <class T> inline bool operator!=(const RefPtr<T>& aLhs, decltype(nullptr)) { return aLhs.get() != nullptr; } template <class T> inline bool operator!=(decltype(nullptr), const RefPtr<T>& aRhs) { return nullptr != aRhs.get(); } /*****************************************************************************/ template <class T> inline already_AddRefed<T> do_AddRef(T* aObj) { RefPtr<T> ref(aObj); return ref.forget(); } template <class T> inline already_AddRefed<T> do_AddRef(const RefPtr<T>& aObj) { RefPtr<T> ref(aObj); return ref.forget(); } namespace mozilla { /** * Helper function to be able to conveniently write things like: * * already_AddRefed<T> * f(...) * { * return MakeAndAddRef<T>(...); * } */ template<typename T, typename... Args> already_AddRefed<T> MakeAndAddRef(Args&&... aArgs) { RefPtr<T> p(new T(Forward<Args>(aArgs)...)); return p.forget(); } } // namespace mozilla #endif /* mozilla_RefPtr_h */