michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsHtml5RefPtr_h michael@0: #define nsHtml5RefPtr_h michael@0: michael@0: #include "nsThreadUtils.h" michael@0: michael@0: template michael@0: class nsHtml5RefPtrReleaser : public nsRunnable michael@0: { michael@0: private: michael@0: T* mPtr; michael@0: public: michael@0: nsHtml5RefPtrReleaser(T* aPtr) michael@0: : mPtr(aPtr) michael@0: {} michael@0: NS_IMETHODIMP Run() michael@0: { michael@0: mPtr->Release(); michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: michael@0: // template class nsHtml5RefPtrGetterAddRefs; michael@0: michael@0: /** michael@0: * Like nsRefPtr except release is proxied to the main thread. Mostly copied michael@0: * from nsRefPtr. michael@0: */ michael@0: template michael@0: class nsHtml5RefPtr michael@0: { michael@0: private: michael@0: michael@0: void michael@0: assign_with_AddRef( T* rawPtr ) michael@0: { michael@0: if ( rawPtr ) michael@0: rawPtr->AddRef(); michael@0: assign_assuming_AddRef(rawPtr); michael@0: } michael@0: michael@0: void** michael@0: begin_assignment() michael@0: { michael@0: assign_assuming_AddRef(0); michael@0: return reinterpret_cast(&mRawPtr); michael@0: } michael@0: michael@0: void michael@0: assign_assuming_AddRef( T* newPtr ) michael@0: { michael@0: T* oldPtr = mRawPtr; michael@0: mRawPtr = newPtr; michael@0: if ( oldPtr ) michael@0: release(oldPtr); michael@0: } michael@0: michael@0: void michael@0: release( T* aPtr ) michael@0: { michael@0: nsCOMPtr releaser = new nsHtml5RefPtrReleaser(aPtr); michael@0: if (NS_FAILED(NS_DispatchToMainThread(releaser))) michael@0: { michael@0: NS_WARNING("Failed to dispatch releaser event."); michael@0: } michael@0: } michael@0: michael@0: private: michael@0: T* mRawPtr; michael@0: michael@0: public: michael@0: typedef T element_type; michael@0: michael@0: ~nsHtml5RefPtr() michael@0: { michael@0: if ( mRawPtr ) michael@0: release(mRawPtr); michael@0: } michael@0: michael@0: // Constructors michael@0: michael@0: nsHtml5RefPtr() michael@0: : mRawPtr(0) michael@0: // default constructor michael@0: { michael@0: } michael@0: michael@0: nsHtml5RefPtr( const nsHtml5RefPtr& aSmartPtr ) michael@0: : mRawPtr(aSmartPtr.mRawPtr) michael@0: // copy-constructor michael@0: { michael@0: if ( mRawPtr ) michael@0: mRawPtr->AddRef(); michael@0: } michael@0: michael@0: nsHtml5RefPtr( T* aRawPtr ) michael@0: : mRawPtr(aRawPtr) michael@0: // construct from a raw pointer (of the right type) michael@0: { michael@0: if ( mRawPtr ) michael@0: mRawPtr->AddRef(); michael@0: } michael@0: michael@0: nsHtml5RefPtr( const already_AddRefed& aSmartPtr ) michael@0: : mRawPtr(aSmartPtr.mRawPtr) michael@0: // construct from |dont_AddRef(expr)| michael@0: { michael@0: } michael@0: michael@0: // Assignment operators michael@0: michael@0: nsHtml5RefPtr& michael@0: operator=( const nsHtml5RefPtr& rhs ) michael@0: // copy assignment operator michael@0: { michael@0: assign_with_AddRef(rhs.mRawPtr); michael@0: return *this; michael@0: } michael@0: michael@0: nsHtml5RefPtr& michael@0: operator=( T* rhs ) michael@0: // assign from a raw pointer (of the right type) michael@0: { michael@0: assign_with_AddRef(rhs); michael@0: return *this; michael@0: } michael@0: michael@0: nsHtml5RefPtr& michael@0: operator=( const already_AddRefed& rhs ) michael@0: // assign from |dont_AddRef(expr)| michael@0: { michael@0: assign_assuming_AddRef(rhs.mRawPtr); michael@0: return *this; michael@0: } michael@0: michael@0: // Other pointer operators michael@0: michael@0: void michael@0: swap( nsHtml5RefPtr& rhs ) michael@0: // ...exchange ownership with |rhs|; can save a pair of refcount operations michael@0: { michael@0: T* temp = rhs.mRawPtr; michael@0: rhs.mRawPtr = mRawPtr; michael@0: mRawPtr = temp; michael@0: } michael@0: michael@0: void michael@0: swap( T*& rhs ) michael@0: // ...exchange ownership with |rhs|; can save a pair of refcount operations michael@0: { michael@0: T* temp = rhs; michael@0: rhs = mRawPtr; michael@0: mRawPtr = temp; michael@0: } michael@0: michael@0: already_AddRefed michael@0: forget() michael@0: // return the value of mRawPtr and null out mRawPtr. Useful for michael@0: // already_AddRefed return values. michael@0: { michael@0: T* temp = 0; michael@0: swap(temp); michael@0: return temp; michael@0: } michael@0: michael@0: template michael@0: void michael@0: forget( I** rhs) michael@0: // Set the target of rhs to the value of mRawPtr and null out mRawPtr. michael@0: // Useful to avoid unnecessary AddRef/Release pairs with "out" michael@0: // parameters where rhs bay be a T** or an I** where I is a base class michael@0: // of T. michael@0: { michael@0: NS_ASSERTION(rhs, "Null pointer passed to forget!"); michael@0: *rhs = mRawPtr; michael@0: mRawPtr = 0; michael@0: } michael@0: michael@0: T* michael@0: get() const michael@0: /* michael@0: Prefer the implicit conversion provided automatically by |operator T*() const|. michael@0: Use |get()| to resolve ambiguity or to get a castable pointer. michael@0: */ michael@0: { michael@0: return const_cast(mRawPtr); michael@0: } michael@0: michael@0: operator T*() const michael@0: /* michael@0: ...makes an |nsHtml5RefPtr| act like its underlying raw pointer type whenever it michael@0: is used in a context where a raw pointer is expected. It is this operator michael@0: that makes an |nsHtml5RefPtr| substitutable for a raw pointer. michael@0: michael@0: Prefer the implicit use of this operator to calling |get()|, except where michael@0: necessary to resolve ambiguity. michael@0: */ michael@0: { michael@0: return get(); michael@0: } michael@0: michael@0: T* michael@0: operator->() const michael@0: { michael@0: NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsHtml5RefPtr with operator->()."); michael@0: return get(); michael@0: } michael@0: michael@0: nsHtml5RefPtr* michael@0: get_address() michael@0: // This is not intended to be used by clients. See |address_of| michael@0: // below. michael@0: { michael@0: return this; michael@0: } michael@0: michael@0: const nsHtml5RefPtr* michael@0: get_address() const michael@0: // This is not intended to be used by clients. See |address_of| michael@0: // below. michael@0: { michael@0: return this; michael@0: } michael@0: michael@0: public: michael@0: T& michael@0: operator*() const michael@0: { michael@0: NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsHtml5RefPtr with operator*()."); michael@0: return *get(); michael@0: } michael@0: michael@0: T** michael@0: StartAssignment() michael@0: { michael@0: #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT michael@0: return reinterpret_cast(begin_assignment()); michael@0: #else michael@0: assign_assuming_AddRef(0); michael@0: return reinterpret_cast(&mRawPtr); michael@0: #endif michael@0: } michael@0: }; michael@0: michael@0: template michael@0: inline michael@0: nsHtml5RefPtr* michael@0: address_of( nsHtml5RefPtr& aPtr ) michael@0: { michael@0: return aPtr.get_address(); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: const nsHtml5RefPtr* michael@0: address_of( const nsHtml5RefPtr& aPtr ) michael@0: { michael@0: return aPtr.get_address(); michael@0: } michael@0: michael@0: template michael@0: class nsHtml5RefPtrGetterAddRefs michael@0: /* michael@0: ... michael@0: michael@0: This class is designed to be used for anonymous temporary objects in the michael@0: argument list of calls that return COM interface pointers, e.g., michael@0: michael@0: nsHtml5RefPtr fooP; michael@0: ...->GetAddRefedPointer(getter_AddRefs(fooP)) michael@0: michael@0: DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead. michael@0: michael@0: When initialized with a |nsHtml5RefPtr|, as in the example above, it returns michael@0: a |void**|, a |T**|, or an |nsISupports**| as needed, that the michael@0: outer call (|GetAddRefedPointer| in this case) can fill in. michael@0: michael@0: This type should be a nested class inside |nsHtml5RefPtr|. michael@0: */ michael@0: { michael@0: public: michael@0: explicit michael@0: nsHtml5RefPtrGetterAddRefs( nsHtml5RefPtr& aSmartPtr ) michael@0: : mTargetSmartPtr(aSmartPtr) michael@0: { michael@0: // nothing else to do michael@0: } michael@0: michael@0: operator void**() michael@0: { michael@0: return reinterpret_cast(mTargetSmartPtr.StartAssignment()); michael@0: } michael@0: michael@0: operator T**() michael@0: { michael@0: return mTargetSmartPtr.StartAssignment(); michael@0: } michael@0: michael@0: T*& michael@0: operator*() michael@0: { michael@0: return *(mTargetSmartPtr.StartAssignment()); michael@0: } michael@0: michael@0: private: michael@0: nsHtml5RefPtr& mTargetSmartPtr; michael@0: }; michael@0: michael@0: template michael@0: inline michael@0: nsHtml5RefPtrGetterAddRefs michael@0: getter_AddRefs( nsHtml5RefPtr& aSmartPtr ) michael@0: /* michael@0: Used around a |nsHtml5RefPtr| when michael@0: ...makes the class |nsHtml5RefPtrGetterAddRefs| invisible. michael@0: */ michael@0: { michael@0: return nsHtml5RefPtrGetterAddRefs(aSmartPtr); michael@0: } michael@0: michael@0: michael@0: michael@0: // Comparing two |nsHtml5RefPtr|s michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsHtml5RefPtr& lhs, const nsHtml5RefPtr& rhs ) michael@0: { michael@0: return static_cast(lhs.get()) == static_cast(rhs.get()); michael@0: } michael@0: michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator!=( const nsHtml5RefPtr& lhs, const nsHtml5RefPtr& rhs ) michael@0: { michael@0: return static_cast(lhs.get()) != static_cast(rhs.get()); michael@0: } michael@0: michael@0: michael@0: // Comparing an |nsHtml5RefPtr| to a raw pointer michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsHtml5RefPtr& lhs, const U* rhs ) michael@0: { michael@0: return static_cast(lhs.get()) == static_cast(rhs); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const U* lhs, const nsHtml5RefPtr& rhs ) michael@0: { michael@0: return static_cast(lhs) == static_cast(rhs.get()); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator!=( const nsHtml5RefPtr& lhs, const U* rhs ) michael@0: { michael@0: return static_cast(lhs.get()) != static_cast(rhs); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator!=( const U* lhs, const nsHtml5RefPtr& rhs ) michael@0: { michael@0: return static_cast(lhs) != static_cast(rhs.get()); michael@0: } michael@0: michael@0: // To avoid ambiguities caused by the presence of builtin |operator==|s michael@0: // creating a situation where one of the |operator==| defined above michael@0: // has a better conversion for one argument and the builtin has a michael@0: // better conversion for the other argument, define additional michael@0: // |operator==| without the |const| on the raw pointer. michael@0: // See bug 65664 for details. michael@0: michael@0: #ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsHtml5RefPtr& lhs, U* rhs ) michael@0: { michael@0: return static_cast(lhs.get()) == const_cast(rhs); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( U* lhs, const nsHtml5RefPtr& rhs ) michael@0: { michael@0: return const_cast(lhs) == static_cast(rhs.get()); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator!=( const nsHtml5RefPtr& lhs, U* rhs ) michael@0: { michael@0: return static_cast(lhs.get()) != const_cast(rhs); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator!=( U* lhs, const nsHtml5RefPtr& rhs ) michael@0: { michael@0: return const_cast(lhs) != static_cast(rhs.get()); michael@0: } michael@0: #endif michael@0: michael@0: michael@0: michael@0: // Comparing an |nsHtml5RefPtr| to |0| michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsHtml5RefPtr& lhs, NSCAP_Zero* rhs ) michael@0: // specifically to allow |smartPtr == 0| michael@0: { michael@0: return static_cast(lhs.get()) == reinterpret_cast(rhs); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( NSCAP_Zero* lhs, const nsHtml5RefPtr& rhs ) michael@0: // specifically to allow |0 == smartPtr| michael@0: { michael@0: return reinterpret_cast(lhs) == static_cast(rhs.get()); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator!=( const nsHtml5RefPtr& lhs, NSCAP_Zero* rhs ) michael@0: // specifically to allow |smartPtr != 0| michael@0: { michael@0: return static_cast(lhs.get()) != reinterpret_cast(rhs); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator!=( NSCAP_Zero* lhs, const nsHtml5RefPtr& rhs ) michael@0: // specifically to allow |0 != smartPtr| michael@0: { michael@0: return reinterpret_cast(lhs) != static_cast(rhs.get()); michael@0: } michael@0: michael@0: michael@0: #ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO michael@0: michael@0: // We need to explicitly define comparison operators for `int' michael@0: // because the compiler is lame. michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsHtml5RefPtr& lhs, int rhs ) michael@0: // specifically to allow |smartPtr == 0| michael@0: { michael@0: return static_cast(lhs.get()) == reinterpret_cast(rhs); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( int lhs, const nsHtml5RefPtr& rhs ) michael@0: // specifically to allow |0 == smartPtr| michael@0: { michael@0: return reinterpret_cast(lhs) == static_cast(rhs.get()); michael@0: } michael@0: michael@0: #endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO) michael@0: michael@0: #endif // !defined(nsHtml5RefPtr_h)