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 nsAutoPtr_h___ michael@0: #define nsAutoPtr_h___ michael@0: michael@0: #include "nsCOMPtr.h" michael@0: michael@0: #include "nsCycleCollectionNoteChild.h" michael@0: #include "mozilla/MemoryReporting.h" michael@0: michael@0: /*****************************************************************************/ michael@0: michael@0: // template class nsAutoPtrGetterTransfers; michael@0: michael@0: template michael@0: class nsAutoPtr michael@0: { michael@0: private: michael@0: void** michael@0: begin_assignment() michael@0: { michael@0: assign(0); michael@0: return reinterpret_cast(&mRawPtr); michael@0: } michael@0: michael@0: void michael@0: assign( T* newPtr ) michael@0: { michael@0: T* oldPtr = mRawPtr; michael@0: michael@0: if (newPtr != nullptr && newPtr == oldPtr) { michael@0: NS_RUNTIMEABORT("Logic flaw in the caller"); michael@0: } michael@0: michael@0: mRawPtr = newPtr; michael@0: delete oldPtr; michael@0: } michael@0: michael@0: // |class Ptr| helps us prevent implicit "copy construction" michael@0: // through |operator T*() const| from a |const nsAutoPtr| michael@0: // because two implicit conversions in a row aren't allowed. michael@0: // It still allows assignment from T* through implicit conversion michael@0: // from |T*| to |nsAutoPtr::Ptr| michael@0: class Ptr michael@0: { michael@0: public: michael@0: Ptr( T* aPtr ) michael@0: : mPtr(aPtr) michael@0: { michael@0: } michael@0: michael@0: operator T*() const michael@0: { michael@0: return mPtr; michael@0: } michael@0: michael@0: private: michael@0: T* mPtr; 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: ~nsAutoPtr() michael@0: { michael@0: delete mRawPtr; michael@0: } michael@0: michael@0: // Constructors michael@0: michael@0: nsAutoPtr() michael@0: : mRawPtr(0) michael@0: // default constructor michael@0: { michael@0: } michael@0: michael@0: nsAutoPtr( Ptr aRawPtr ) michael@0: : mRawPtr(aRawPtr) michael@0: // construct from a raw pointer (of the right type) michael@0: { michael@0: } michael@0: michael@0: // This constructor shouldn't exist; we should just use the && michael@0: // constructor. michael@0: nsAutoPtr( nsAutoPtr& aSmartPtr ) michael@0: : mRawPtr( aSmartPtr.forget() ) michael@0: // Construct by transferring ownership from another smart pointer. michael@0: { michael@0: } michael@0: michael@0: nsAutoPtr( nsAutoPtr&& aSmartPtr ) michael@0: : mRawPtr( aSmartPtr.forget() ) michael@0: // Construct by transferring ownership from another smart pointer. michael@0: { michael@0: } michael@0: michael@0: // Assignment operators michael@0: michael@0: nsAutoPtr& michael@0: operator=( T* rhs ) michael@0: // assign from a raw pointer (of the right type) michael@0: { michael@0: assign(rhs); michael@0: return *this; michael@0: } michael@0: michael@0: nsAutoPtr& operator=( nsAutoPtr& rhs ) michael@0: // assign by transferring ownership from another smart pointer. michael@0: { michael@0: assign(rhs.forget()); michael@0: return *this; michael@0: } michael@0: michael@0: // Other pointer operators michael@0: michael@0: T* michael@0: get() const michael@0: /* michael@0: Prefer the implicit conversion provided automatically by michael@0: |operator T*() const|. Use |get()| _only_ to resolve michael@0: ambiguity. michael@0: */ michael@0: { michael@0: return mRawPtr; michael@0: } michael@0: michael@0: operator T*() const michael@0: /* michael@0: ...makes an |nsAutoPtr| act like its underlying raw pointer michael@0: type whenever it is used in a context where a raw pointer michael@0: is expected. It is this operator that makes an |nsAutoPtr| michael@0: substitutable for a raw pointer. michael@0: michael@0: Prefer the implicit use of this operator to calling |get()|, michael@0: except where necessary to resolve ambiguity. michael@0: */ michael@0: { michael@0: return get(); michael@0: } michael@0: michael@0: T* michael@0: forget() michael@0: { michael@0: T* temp = mRawPtr; michael@0: mRawPtr = 0; michael@0: return temp; 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 nsAutoPtr with operator->()."); michael@0: return get(); michael@0: } michael@0: michael@0: // This operator is needed for gcc <= 4.0.* and for Sun Studio; it michael@0: // causes internal compiler errors for some MSVC versions. (It's not michael@0: // clear to me whether it should be needed.) michael@0: #ifndef _MSC_VER michael@0: template michael@0: U& michael@0: operator->*(U V::* aMember) michael@0: { michael@0: NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsAutoPtr with operator->*()."); michael@0: return get()->*aMember; michael@0: } michael@0: #endif michael@0: michael@0: nsAutoPtr* 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 nsAutoPtr* 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 nsAutoPtr 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(0); michael@0: return reinterpret_cast(&mRawPtr); michael@0: #endif michael@0: } michael@0: }; michael@0: michael@0: template michael@0: inline michael@0: nsAutoPtr* michael@0: address_of( nsAutoPtr& aPtr ) michael@0: { michael@0: return aPtr.get_address(); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: const nsAutoPtr* michael@0: address_of( const nsAutoPtr& aPtr ) michael@0: { michael@0: return aPtr.get_address(); michael@0: } michael@0: michael@0: template michael@0: class nsAutoPtrGetterTransfers 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: nsAutoPtr fooP; michael@0: ...->GetTransferedPointer(getter_Transfers(fooP)) michael@0: michael@0: DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_Transfers()| instead. michael@0: michael@0: When initialized with a |nsAutoPtr|, as in the example above, it returns michael@0: a |void**|, a |T**|, or an |nsISupports**| as needed, that the michael@0: outer call (|GetTransferedPointer| in this case) can fill in. michael@0: michael@0: This type should be a nested class inside |nsAutoPtr|. michael@0: */ michael@0: { michael@0: public: michael@0: explicit michael@0: nsAutoPtrGetterTransfers( nsAutoPtr& 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: nsAutoPtr& mTargetSmartPtr; michael@0: }; michael@0: michael@0: template michael@0: inline michael@0: nsAutoPtrGetterTransfers michael@0: getter_Transfers( nsAutoPtr& aSmartPtr ) michael@0: /* michael@0: Used around a |nsAutoPtr| when michael@0: ...makes the class |nsAutoPtrGetterTransfers| invisible. michael@0: */ michael@0: { michael@0: return nsAutoPtrGetterTransfers(aSmartPtr); michael@0: } michael@0: michael@0: michael@0: michael@0: // Comparing two |nsAutoPtr|s michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsAutoPtr& lhs, const nsAutoPtr& 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 nsAutoPtr& lhs, const nsAutoPtr& rhs ) michael@0: { michael@0: return static_cast(lhs.get()) != static_cast(rhs.get()); michael@0: } michael@0: michael@0: michael@0: // Comparing an |nsAutoPtr| to a raw pointer michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsAutoPtr& 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 nsAutoPtr& 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 nsAutoPtr& 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 nsAutoPtr& 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 nsAutoPtr& 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 nsAutoPtr& 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 nsAutoPtr& 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 nsAutoPtr& 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 |nsAutoPtr| to |0| michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsAutoPtr& 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 nsAutoPtr& 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 nsAutoPtr& 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 nsAutoPtr& 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 nsAutoPtr& 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 nsAutoPtr& 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: /*****************************************************************************/ michael@0: michael@0: // template class nsAutoArrayPtrGetterTransfers; michael@0: michael@0: template michael@0: class nsAutoArrayPtr michael@0: { michael@0: private: michael@0: void** michael@0: begin_assignment() michael@0: { michael@0: assign(0); michael@0: return reinterpret_cast(&mRawPtr); michael@0: } michael@0: michael@0: void michael@0: assign( T* newPtr ) michael@0: { michael@0: T* oldPtr = mRawPtr; michael@0: mRawPtr = newPtr; michael@0: delete [] oldPtr; 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: ~nsAutoArrayPtr() michael@0: { michael@0: delete [] mRawPtr; michael@0: } michael@0: michael@0: // Constructors michael@0: michael@0: nsAutoArrayPtr() michael@0: : mRawPtr(0) michael@0: // default constructor michael@0: { michael@0: } michael@0: michael@0: nsAutoArrayPtr( T* aRawPtr ) michael@0: : mRawPtr(aRawPtr) michael@0: // construct from a raw pointer (of the right type) michael@0: { michael@0: } michael@0: michael@0: nsAutoArrayPtr( nsAutoArrayPtr& aSmartPtr ) michael@0: : mRawPtr( aSmartPtr.forget() ) michael@0: // Construct by transferring ownership from another smart pointer. michael@0: { michael@0: } michael@0: michael@0: michael@0: // Assignment operators michael@0: michael@0: nsAutoArrayPtr& michael@0: operator=( T* rhs ) michael@0: // assign from a raw pointer (of the right type) michael@0: { michael@0: assign(rhs); michael@0: return *this; michael@0: } michael@0: michael@0: nsAutoArrayPtr& operator=( nsAutoArrayPtr& rhs ) michael@0: // assign by transferring ownership from another smart pointer. michael@0: { michael@0: assign(rhs.forget()); michael@0: return *this; michael@0: } michael@0: michael@0: // Other pointer operators michael@0: michael@0: T* michael@0: get() const michael@0: /* michael@0: Prefer the implicit conversion provided automatically by michael@0: |operator T*() const|. Use |get()| _only_ to resolve michael@0: ambiguity. michael@0: */ michael@0: { michael@0: return mRawPtr; michael@0: } michael@0: michael@0: operator T*() const michael@0: /* michael@0: ...makes an |nsAutoArrayPtr| act like its underlying raw pointer michael@0: type whenever it is used in a context where a raw pointer michael@0: is expected. It is this operator that makes an |nsAutoArrayPtr| michael@0: substitutable for a raw pointer. michael@0: michael@0: Prefer the implicit use of this operator to calling |get()|, michael@0: except where necessary to resolve ambiguity. michael@0: */ michael@0: { michael@0: return get(); michael@0: } michael@0: michael@0: T* michael@0: forget() michael@0: { michael@0: T* temp = mRawPtr; michael@0: mRawPtr = 0; michael@0: return temp; 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 nsAutoArrayPtr with operator->()."); michael@0: return get(); michael@0: } michael@0: michael@0: nsAutoArrayPtr* 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 nsAutoArrayPtr* 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 nsAutoArrayPtr 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(0); michael@0: return reinterpret_cast(&mRawPtr); michael@0: #endif michael@0: } michael@0: michael@0: size_t michael@0: SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const michael@0: { michael@0: return aMallocSizeOf(mRawPtr); michael@0: } michael@0: michael@0: size_t michael@0: SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const michael@0: { michael@0: return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: inline michael@0: nsAutoArrayPtr* michael@0: address_of( nsAutoArrayPtr& aPtr ) michael@0: { michael@0: return aPtr.get_address(); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: const nsAutoArrayPtr* michael@0: address_of( const nsAutoArrayPtr& aPtr ) michael@0: { michael@0: return aPtr.get_address(); michael@0: } michael@0: michael@0: template michael@0: class nsAutoArrayPtrGetterTransfers 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: nsAutoArrayPtr fooP; michael@0: ...->GetTransferedPointer(getter_Transfers(fooP)) michael@0: michael@0: DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_Transfers()| instead. michael@0: michael@0: When initialized with a |nsAutoArrayPtr|, as in the example above, it returns michael@0: a |void**|, a |T**|, or an |nsISupports**| as needed, that the michael@0: outer call (|GetTransferedPointer| in this case) can fill in. michael@0: michael@0: This type should be a nested class inside |nsAutoArrayPtr|. michael@0: */ michael@0: { michael@0: public: michael@0: explicit michael@0: nsAutoArrayPtrGetterTransfers( nsAutoArrayPtr& 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: nsAutoArrayPtr& mTargetSmartPtr; michael@0: }; michael@0: michael@0: template michael@0: inline michael@0: nsAutoArrayPtrGetterTransfers michael@0: getter_Transfers( nsAutoArrayPtr& aSmartPtr ) michael@0: /* michael@0: Used around a |nsAutoArrayPtr| when michael@0: ...makes the class |nsAutoArrayPtrGetterTransfers| invisible. michael@0: */ michael@0: { michael@0: return nsAutoArrayPtrGetterTransfers(aSmartPtr); michael@0: } michael@0: michael@0: michael@0: michael@0: // Comparing two |nsAutoArrayPtr|s michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsAutoArrayPtr& lhs, const nsAutoArrayPtr& 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 nsAutoArrayPtr& lhs, const nsAutoArrayPtr& rhs ) michael@0: { michael@0: return static_cast(lhs.get()) != static_cast(rhs.get()); michael@0: } michael@0: michael@0: michael@0: // Comparing an |nsAutoArrayPtr| to a raw pointer michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsAutoArrayPtr& 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 nsAutoArrayPtr& 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 nsAutoArrayPtr& 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 nsAutoArrayPtr& 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 nsAutoArrayPtr& 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 nsAutoArrayPtr& 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 nsAutoArrayPtr& 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 nsAutoArrayPtr& 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 |nsAutoArrayPtr| to |0| michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsAutoArrayPtr& 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 nsAutoArrayPtr& 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 nsAutoArrayPtr& 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 nsAutoArrayPtr& 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 nsAutoArrayPtr& 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 nsAutoArrayPtr& 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: michael@0: /*****************************************************************************/ michael@0: michael@0: // template class nsRefPtrGetterAddRefs; michael@0: michael@0: template michael@0: class nsRefPtr 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: oldPtr->Release(); 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: ~nsRefPtr() michael@0: { michael@0: if ( mRawPtr ) michael@0: mRawPtr->Release(); michael@0: } michael@0: michael@0: // Constructors michael@0: michael@0: nsRefPtr() michael@0: : mRawPtr(0) michael@0: // default constructor michael@0: { michael@0: } michael@0: michael@0: nsRefPtr(const nsRefPtr& 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: nsRefPtr(nsRefPtr&& aRefPtr) michael@0: : mRawPtr(aRefPtr.mRawPtr) michael@0: { michael@0: aRefPtr.mRawPtr = nullptr; michael@0: } michael@0: michael@0: // construct from a raw pointer (of the right type) michael@0: michael@0: nsRefPtr(T* aRawPtr) michael@0: : mRawPtr(aRawPtr) michael@0: { michael@0: if ( mRawPtr ) michael@0: mRawPtr->AddRef(); michael@0: } michael@0: michael@0: template michael@0: nsRefPtr( already_AddRefed& aSmartPtr ) michael@0: : mRawPtr(aSmartPtr.take()) michael@0: // construct from |already_AddRefed| michael@0: { michael@0: } michael@0: michael@0: template michael@0: nsRefPtr( already_AddRefed&& aSmartPtr ) michael@0: : mRawPtr(aSmartPtr.take()) michael@0: // construct from |otherRefPtr.forget()| michael@0: { michael@0: } michael@0: michael@0: nsRefPtr( const nsCOMPtr_helper& helper ) michael@0: { michael@0: void* newRawPtr; michael@0: if (NS_FAILED(helper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) michael@0: newRawPtr = 0; michael@0: mRawPtr = static_cast(newRawPtr); michael@0: } michael@0: michael@0: // Assignment operators michael@0: michael@0: nsRefPtr& michael@0: operator=(const nsRefPtr& 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: nsRefPtr& 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: template michael@0: nsRefPtr& michael@0: operator=( already_AddRefed& rhs ) michael@0: // assign from |already_AddRefed| michael@0: { michael@0: assign_assuming_AddRef(rhs.take()); michael@0: return *this; michael@0: } michael@0: michael@0: template michael@0: nsRefPtr& michael@0: operator=( already_AddRefed&& rhs ) michael@0: // assign from |otherRefPtr.forget()| michael@0: { michael@0: assign_assuming_AddRef(rhs.take()); michael@0: return *this; michael@0: } michael@0: michael@0: nsRefPtr& michael@0: operator=( const nsCOMPtr_helper& helper ) michael@0: { michael@0: void* newRawPtr; michael@0: if (NS_FAILED(helper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) michael@0: newRawPtr = 0; michael@0: assign_assuming_AddRef(static_cast(newRawPtr)); michael@0: return *this; michael@0: } michael@0: michael@0: nsRefPtr& michael@0: operator=(nsRefPtr&& aRefPtr) michael@0: { michael@0: assign_assuming_AddRef(aRefPtr.mRawPtr); michael@0: aRefPtr.mRawPtr = nullptr; michael@0: return *this; michael@0: } michael@0: michael@0: // Other pointer operators michael@0: michael@0: void michael@0: swap( nsRefPtr& 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 already_AddRefed(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 |nsRefPtr| 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 |nsRefPtr| 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 nsRefPtr with operator->()."); michael@0: return get(); michael@0: } michael@0: michael@0: // This operator is needed for gcc <= 4.0.* and for Sun Studio; it michael@0: // causes internal compiler errors for some MSVC versions. (It's not michael@0: // clear to me whether it should be needed.) michael@0: #ifndef _MSC_VER michael@0: template michael@0: U& michael@0: operator->*(U V::* aMember) michael@0: { michael@0: NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsRefPtr with operator->*()."); michael@0: return get()->*aMember; michael@0: } michael@0: #endif michael@0: michael@0: nsRefPtr* 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 nsRefPtr* 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 nsRefPtr 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 void michael@0: ImplCycleCollectionUnlink(nsRefPtr& aField) michael@0: { michael@0: aField = nullptr; michael@0: } michael@0: michael@0: template michael@0: inline void michael@0: ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, michael@0: nsRefPtr& aField, michael@0: const char* aName, michael@0: uint32_t aFlags = 0) michael@0: { michael@0: CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: nsRefPtr* michael@0: address_of( nsRefPtr& aPtr ) michael@0: { michael@0: return aPtr.get_address(); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: const nsRefPtr* michael@0: address_of( const nsRefPtr& aPtr ) michael@0: { michael@0: return aPtr.get_address(); michael@0: } michael@0: michael@0: template michael@0: class nsRefPtrGetterAddRefs 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: nsRefPtr 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 |nsRefPtr|, 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 |nsRefPtr|. michael@0: */ michael@0: { michael@0: public: michael@0: explicit michael@0: nsRefPtrGetterAddRefs( nsRefPtr& 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: nsRefPtr& mTargetSmartPtr; michael@0: }; michael@0: michael@0: template michael@0: inline michael@0: nsRefPtrGetterAddRefs michael@0: getter_AddRefs( nsRefPtr& aSmartPtr ) michael@0: /* michael@0: Used around a |nsRefPtr| when michael@0: ...makes the class |nsRefPtrGetterAddRefs| invisible. michael@0: */ michael@0: { michael@0: return nsRefPtrGetterAddRefs(aSmartPtr); michael@0: } michael@0: michael@0: michael@0: michael@0: // Comparing two |nsRefPtr|s michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsRefPtr& lhs, const nsRefPtr& 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 nsRefPtr& lhs, const nsRefPtr& rhs ) michael@0: { michael@0: return static_cast(lhs.get()) != static_cast(rhs.get()); michael@0: } michael@0: michael@0: michael@0: // Comparing an |nsRefPtr| to a raw pointer michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsRefPtr& 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 nsRefPtr& 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 nsRefPtr& 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 nsRefPtr& 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 nsRefPtr& 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 nsRefPtr& 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 nsRefPtr& 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 nsRefPtr& 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 |nsRefPtr| to |0| michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsRefPtr& 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 nsRefPtr& 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 nsRefPtr& 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 nsRefPtr& 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 nsRefPtr& 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 nsRefPtr& 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: template michael@0: inline michael@0: nsresult michael@0: CallQueryInterface( nsRefPtr& aSourcePtr, DestinationType** aDestPtr ) michael@0: { michael@0: return CallQueryInterface(aSourcePtr.get(), aDestPtr); michael@0: } michael@0: michael@0: /*****************************************************************************/ michael@0: michael@0: template michael@0: class nsQueryObject : public nsCOMPtr_helper michael@0: { michael@0: public: michael@0: nsQueryObject(T* aRawPtr) michael@0: : mRawPtr(aRawPtr) {} michael@0: michael@0: virtual nsresult NS_FASTCALL operator()( const nsIID& aIID, void** aResult ) const { michael@0: nsresult status = mRawPtr ? mRawPtr->QueryInterface(aIID, aResult) michael@0: : NS_ERROR_NULL_POINTER; michael@0: return status; michael@0: } michael@0: private: michael@0: T* mRawPtr; michael@0: }; michael@0: michael@0: template michael@0: class nsQueryObjectWithError : public nsCOMPtr_helper michael@0: { michael@0: public: michael@0: nsQueryObjectWithError(T* aRawPtr, nsresult* aErrorPtr) michael@0: : mRawPtr(aRawPtr), mErrorPtr(aErrorPtr) {} michael@0: michael@0: virtual nsresult NS_FASTCALL operator()( const nsIID& aIID, void** aResult ) const { michael@0: nsresult status = mRawPtr ? mRawPtr->QueryInterface(aIID, aResult) michael@0: : NS_ERROR_NULL_POINTER; michael@0: if (mErrorPtr) michael@0: *mErrorPtr = status; michael@0: return status; michael@0: } michael@0: private: michael@0: T* mRawPtr; michael@0: nsresult* mErrorPtr; michael@0: }; michael@0: michael@0: template michael@0: inline michael@0: nsQueryObject michael@0: do_QueryObject(T* aRawPtr) michael@0: { michael@0: return nsQueryObject(aRawPtr); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: nsQueryObject michael@0: do_QueryObject(nsCOMPtr& aRawPtr) michael@0: { michael@0: return nsQueryObject(aRawPtr); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: nsQueryObject michael@0: do_QueryObject(nsRefPtr& aRawPtr) michael@0: { michael@0: return nsQueryObject(aRawPtr); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: nsQueryObjectWithError michael@0: do_QueryObject(T* aRawPtr, nsresult* aErrorPtr) michael@0: { michael@0: return nsQueryObjectWithError(aRawPtr, aErrorPtr); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: nsQueryObjectWithError michael@0: do_QueryObject(nsCOMPtr& aRawPtr, nsresult* aErrorPtr) michael@0: { michael@0: return nsQueryObjectWithError(aRawPtr, aErrorPtr); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: nsQueryObjectWithError michael@0: do_QueryObject(nsRefPtr& aRawPtr, nsresult* aErrorPtr) michael@0: { michael@0: return nsQueryObjectWithError(aRawPtr, aErrorPtr); michael@0: } michael@0: michael@0: /*****************************************************************************/ michael@0: michael@0: #endif // !defined(nsAutoPtr_h___)