/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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 nsHtml5RefPtr_h #define nsHtml5RefPtr_h #include "nsThreadUtils.h" template class nsHtml5RefPtrReleaser : public nsRunnable { private: T* mPtr; public: explicit nsHtml5RefPtrReleaser(T* aPtr) : mPtr(aPtr) {} NS_IMETHODIMP Run() { mPtr->Release(); return NS_OK; } }; // template class nsHtml5RefPtrGetterAddRefs; /** * Like nsRefPtr except release is proxied to the main thread. Mostly copied * from nsRefPtr. */ template class nsHtml5RefPtr { private: void assign_with_AddRef( T* rawPtr ) { if ( rawPtr ) rawPtr->AddRef(); assign_assuming_AddRef(rawPtr); } void** begin_assignment() { assign_assuming_AddRef(0); return reinterpret_cast(&mRawPtr); } void assign_assuming_AddRef( T* newPtr ) { T* oldPtr = mRawPtr; mRawPtr = newPtr; if ( oldPtr ) release(oldPtr); } void release( T* aPtr ) { nsCOMPtr releaser = new nsHtml5RefPtrReleaser(aPtr); if (NS_FAILED(NS_DispatchToMainThread(releaser))) { NS_WARNING("Failed to dispatch releaser event."); } } private: T* mRawPtr; public: typedef T element_type; ~nsHtml5RefPtr() { if ( mRawPtr ) release(mRawPtr); } // Constructors nsHtml5RefPtr() : mRawPtr(0) // default constructor { } nsHtml5RefPtr( const nsHtml5RefPtr& aSmartPtr ) : mRawPtr(aSmartPtr.mRawPtr) // copy-constructor { if ( mRawPtr ) mRawPtr->AddRef(); } explicit nsHtml5RefPtr( T* aRawPtr ) : mRawPtr(aRawPtr) // construct from a raw pointer (of the right type) { if ( mRawPtr ) mRawPtr->AddRef(); } explicit nsHtml5RefPtr( const already_AddRefed& aSmartPtr ) : mRawPtr(aSmartPtr.mRawPtr) // construct from |dont_AddRef(expr)| { } // Assignment operators nsHtml5RefPtr& operator=( const nsHtml5RefPtr& rhs ) // copy assignment operator { assign_with_AddRef(rhs.mRawPtr); return *this; } nsHtml5RefPtr& operator=( T* rhs ) // assign from a raw pointer (of the right type) { assign_with_AddRef(rhs); return *this; } nsHtml5RefPtr& operator=( const already_AddRefed& rhs ) // assign from |dont_AddRef(expr)| { assign_assuming_AddRef(rhs.mRawPtr); return *this; } // Other pointer operators void swap( nsHtml5RefPtr& rhs ) // ...exchange ownership with |rhs|; can save a pair of refcount operations { T* temp = rhs.mRawPtr; rhs.mRawPtr = mRawPtr; mRawPtr = temp; } void swap( T*& rhs ) // ...exchange ownership with |rhs|; can save a pair of refcount operations { T* temp = rhs; rhs = mRawPtr; mRawPtr = temp; } already_AddRefed forget() // return the value of mRawPtr and null out mRawPtr. Useful for // already_AddRefed return values. { T* temp = 0; swap(temp); return temp; } template void forget( I** rhs) // Set the target of rhs to the value of mRawPtr and null out mRawPtr. // Useful to avoid unnecessary AddRef/Release pairs with "out" // parameters where rhs bay be a T** or an I** where I is a base class // of T. { NS_ASSERTION(rhs, "Null pointer passed to forget!"); *rhs = mRawPtr; mRawPtr = 0; } 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(mRawPtr); } operator T*() const /* ...makes an |nsHtml5RefPtr| 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 |nsHtml5RefPtr| substitutable for a raw pointer. Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. */ { return get(); } T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsHtml5RefPtr with operator->()."); return get(); } nsHtml5RefPtr* get_address() // This is not intended to be used by clients. See |address_of| // below. { return this; } const nsHtml5RefPtr* get_address() const // This is not intended to be used by clients. See |address_of| // below. { return this; } public: T& operator*() const { NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsHtml5RefPtr with operator*()."); return *get(); } T** StartAssignment() { #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT return reinterpret_cast(begin_assignment()); #else assign_assuming_AddRef(0); return reinterpret_cast(&mRawPtr); #endif } }; template inline nsHtml5RefPtr* address_of( nsHtml5RefPtr& aPtr ) { return aPtr.get_address(); } template inline const nsHtml5RefPtr* address_of( const nsHtml5RefPtr& aPtr ) { return aPtr.get_address(); } template class nsHtml5RefPtrGetterAddRefs /* ... This class is designed to be used for anonymous temporary objects in the argument list of calls that return COM interface pointers, e.g., nsHtml5RefPtr fooP; ...->GetAddRefedPointer(getter_AddRefs(fooP)) DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead. When initialized with a |nsHtml5RefPtr|, 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 |nsHtml5RefPtr|. */ { public: explicit nsHtml5RefPtrGetterAddRefs( nsHtml5RefPtr& aSmartPtr ) : mTargetSmartPtr(aSmartPtr) { // nothing else to do } operator void**() { return reinterpret_cast(mTargetSmartPtr.StartAssignment()); } operator T**() { return mTargetSmartPtr.StartAssignment(); } T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } private: nsHtml5RefPtr& mTargetSmartPtr; }; template inline nsHtml5RefPtrGetterAddRefs getter_AddRefs( nsHtml5RefPtr& aSmartPtr ) /* Used around a |nsHtml5RefPtr| when ...makes the class |nsHtml5RefPtrGetterAddRefs| invisible. */ { return nsHtml5RefPtrGetterAddRefs(aSmartPtr); } // Comparing two |nsHtml5RefPtr|s template inline bool operator==( const nsHtml5RefPtr& lhs, const nsHtml5RefPtr& rhs ) { return static_cast(lhs.get()) == static_cast(rhs.get()); } template inline bool operator!=( const nsHtml5RefPtr& lhs, const nsHtml5RefPtr& rhs ) { return static_cast(lhs.get()) != static_cast(rhs.get()); } // Comparing an |nsHtml5RefPtr| to a raw pointer template inline bool operator==( const nsHtml5RefPtr& lhs, const U* rhs ) { return static_cast(lhs.get()) == static_cast(rhs); } template inline bool operator==( const U* lhs, const nsHtml5RefPtr& rhs ) { return static_cast(lhs) == static_cast(rhs.get()); } template inline bool operator!=( const nsHtml5RefPtr& lhs, const U* rhs ) { return static_cast(lhs.get()) != static_cast(rhs); } template inline bool operator!=( const U* lhs, const nsHtml5RefPtr& rhs ) { return static_cast(lhs) != static_cast(rhs.get()); } template inline bool operator==( const nsHtml5RefPtr& lhs, U* rhs ) { return static_cast(lhs.get()) == const_cast(rhs); } template inline bool operator==( U* lhs, const nsHtml5RefPtr& rhs ) { return const_cast(lhs) == static_cast(rhs.get()); } template inline bool operator!=( const nsHtml5RefPtr& lhs, U* rhs ) { return static_cast(lhs.get()) != const_cast(rhs); } template inline bool operator!=( U* lhs, const nsHtml5RefPtr& rhs ) { return const_cast(lhs) != static_cast(rhs.get()); } // Comparing an |nsHtml5RefPtr| to |0| template inline bool operator==( const nsHtml5RefPtr& lhs, decltype(nullptr) ) { return lhs.get() == nullptr; } template inline bool operator==( decltype(nullptr), const nsHtml5RefPtr& rhs ) { return nullptr == rhs.get(); } template inline bool operator!=( const nsHtml5RefPtr& lhs, decltype(nullptr) ) { return lhs.get() != nullptr; } template inline bool operator!=( decltype(nullptr), const nsHtml5RefPtr& rhs ) { return nullptr != rhs.get(); } #endif // !defined(nsHtml5RefPtr_h)