/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Netscape Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Scott Collins (original author of nsCOMPtr) * L. David Baron * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the NPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef nsAutoPtr_h___ #define nsAutoPtr_h___ // Wrapping includes can speed up compiles (see "Large Scale C++ Software Design") #ifndef nsCOMPtr_h___ // For |already_AddRefed|, |nsDerivedSafe|, |NSCAP_Zero|. #include "nsCOMPtr.h" #endif #ifdef _MSC_VER #define NSCAP_FEATURE_INLINE_STARTASSIGNMENT // under VC++, we win by inlining StartAssignment // Also under VC++, at the highest warning level, we are overwhelmed with warnings // about (unused) inline functions being removed. This is to be expected with // templates, so we disable the warning. #pragma warning( disable: 4514 ) #endif /*****************************************************************************/ // template class nsAutoPtrGetterTransfers; template class nsAutoPtr { enum { _force_even_compliant_compilers_to_fail_ = sizeof(T) }; /* The declaration above exists specifically to make |nsAutoPtr| _not_ compile with only a forward declaration of |T|. This should prevent Windows and Mac engineers from breaking Solaris and other compilers that naturally have this behavior. Thank for inventing this specific trick. Of course, if you're using |nsAutoPtr| outside the scope of wanting to compile on Solaris and old GCC, you probably want to remove the enum so you can exploit forward declarations. */ private: void** begin_assignment(); void assign( T* newPtr ) { T* oldPtr = mRawPtr; mRawPtr = newPtr; delete oldPtr; } private: T* mRawPtr; public: typedef T element_type; ~nsAutoPtr() { delete mRawPtr; } // Constructors nsAutoPtr() : mRawPtr(0) // default constructor { } nsAutoPtr( T* aRawPtr ) : mRawPtr(aRawPtr) // construct from a raw pointer (of the right type) { } nsAutoPtr( nsAutoPtr& aSmartPtr ) : mRawPtr( aSmartPtr.forget() ) // Construct by transferring ownership from another smart pointer. { } // Assignment operators nsAutoPtr& operator=( T* rhs ) // assign from a raw pointer (of the right type) { assign(rhs); return *this; } nsAutoPtr& operator=( nsAutoPtr& rhs ) // assign by transferring ownership from another smart pointer. { assign(rhs.forget()); return *this; } // Other pointer operators T* get() const /* Prefer the implicit conversion provided automatically by |operator T*() const|. Use |get()| _only_ to resolve ambiguity. */ { return mRawPtr; } operator T*() const /* ...makes an |nsAutoPtr| 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 |nsAutoPtr| substitutable for a raw pointer. Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. */ { return get(); } T* forget() { T* temp = mRawPtr; mRawPtr = 0; return temp; } T* operator->() const { NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsAutoPtr with operator->()."); return get(); } #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY // broken version for IRIX nsAutoPtr* get_address() const // This is not intended to be used by clients. See |address_of| // below. { return NS_CONST_CAST(nsAutoPtr*, this); } #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY nsAutoPtr* get_address() // This is not intended to be used by clients. See |address_of| // below. { return this; } const nsAutoPtr* get_address() const // This is not intended to be used by clients. See |address_of| // below. { return this; } #endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY public: T& operator*() const { NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsAutoPtr with operator*()."); return *get(); } T** StartAssignment() { #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT return NS_REINTERPRET_CAST(T**, begin_assignment()); #else assign(0); return NS_REINTERPRET_CAST(T**, &mRawPtr); #endif } }; template void** nsAutoPtr::begin_assignment() { assign(0); return NS_REINTERPRET_CAST(void**, &mRawPtr); } #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY // This is the broken version for IRIX, which can't handle the version below. template inline nsAutoPtr* address_of( const nsAutoPtr& aPtr ) { return aPtr.get_address(); } #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY template inline nsAutoPtr* address_of( nsAutoPtr& aPtr ) { return aPtr.get_address(); } template inline const nsAutoPtr* address_of( const nsAutoPtr& aPtr ) { return aPtr.get_address(); } #endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY template class nsAutoPtrGetterTransfers /* ... This class is designed to be used for anonymous temporary objects in the argument list of calls that return COM interface pointers, e.g., nsAutoPtr fooP; ...->GetTransferedPointer(getter_Transfers(fooP)) DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_Transfers()| instead. When initialized with a |nsAutoPtr|, as in the example above, it returns a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call (|GetTransferedPointer| in this case) can fill in. This type should be a nested class inside |nsAutoPtr|. */ { public: explicit nsAutoPtrGetterTransfers( nsAutoPtr& aSmartPtr ) : mTargetSmartPtr(aSmartPtr) { // nothing else to do } operator void**() { return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); } operator T**() { return mTargetSmartPtr.StartAssignment(); } T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } private: nsAutoPtr& mTargetSmartPtr; }; template inline nsAutoPtrGetterTransfers getter_Transfers( nsAutoPtr& aSmartPtr ) /* Used around a |nsAutoPtr| when ...makes the class |nsAutoPtrGetterTransfers| invisible. */ { return nsAutoPtrGetterTransfers(aSmartPtr); } // Comparing two |nsAutoPtr|s template inline NSCAP_BOOL operator==( const nsAutoPtr& lhs, const nsAutoPtr& rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsAutoPtr& lhs, const nsAutoPtr& rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs.get()); } // Comparing an |nsAutoPtr| to a raw pointer template inline NSCAP_BOOL operator==( const nsAutoPtr& lhs, const U* rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs); } template inline NSCAP_BOOL operator==( const U* lhs, const nsAutoPtr& rhs ) { return NS_STATIC_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsAutoPtr& lhs, const U* rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs); } template inline NSCAP_BOOL operator!=( const U* lhs, const nsAutoPtr& rhs ) { return NS_STATIC_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); } // To avoid ambiguities caused by the presence of builtin |operator==|s // creating a situation where one of the |operator==| defined above // has a better conversion for one argument and the builtin has a // better conversion for the other argument, define additional // |operator==| without the |const| on the raw pointer. // See bug 65664 for details. // This is defined by an autoconf test, but VC++ also has a bug that // prevents us from using these. (It also, fortunately, has the bug // that we don't need them either.) #ifdef _MSC_VER #define NSCAP_DONT_PROVIDE_NONCONST_OPEQ #endif #ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ template inline NSCAP_BOOL operator==( const nsAutoPtr& lhs, U* rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) == NS_CONST_CAST(const U*, rhs); } template inline NSCAP_BOOL operator==( U* lhs, const nsAutoPtr& rhs ) { return NS_CONST_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsAutoPtr& lhs, U* rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) != NS_CONST_CAST(const U*, rhs); } template inline NSCAP_BOOL operator!=( U* lhs, const nsAutoPtr& rhs ) { return NS_CONST_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); } #endif // Comparing an |nsAutoPtr| to |0| template inline NSCAP_BOOL operator==( const nsAutoPtr& lhs, NSCAP_Zero* rhs ) // specifically to allow |smartPtr == 0| { return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); } template inline NSCAP_BOOL operator==( NSCAP_Zero* lhs, const nsAutoPtr& rhs ) // specifically to allow |0 == smartPtr| { return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsAutoPtr& lhs, NSCAP_Zero* rhs ) // specifically to allow |smartPtr != 0| { return NS_STATIC_CAST(const void*, lhs.get()) != NS_REINTERPRET_CAST(const void*, rhs); } template inline NSCAP_BOOL operator!=( NSCAP_Zero* lhs, const nsAutoPtr& rhs ) // specifically to allow |0 != smartPtr| { return NS_REINTERPRET_CAST(const void*, lhs) != NS_STATIC_CAST(const void*, rhs.get()); } #ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO // We need to explicitly define comparison operators for `int' // because the compiler is lame. template inline NSCAP_BOOL operator==( const nsAutoPtr& lhs, int rhs ) // specifically to allow |smartPtr == 0| { return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); } template inline NSCAP_BOOL operator==( int lhs, const nsAutoPtr& rhs ) // specifically to allow |0 == smartPtr| { return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); } #endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO) /*****************************************************************************/ // template class nsAutoArrayPtrGetterTransfers; template class nsAutoArrayPtr { enum { _force_even_compliant_compilers_to_fail_ = sizeof(T) }; /* The declaration above exists specifically to make |nsAutoArrayPtr| _not_ compile with only a forward declaration of |T|. This should prevent Windows and Mac engineers from breaking Solaris and other compilers that naturally have this behavior. Thank for inventing this specific trick. Of course, if you're using |nsAutoArrayPtr| outside the scope of wanting to compile on Solaris and old GCC, you probably want to remove the enum so you can exploit forward declarations. */ private: void** begin_assignment(); void assign( T* newPtr ) { T* oldPtr = mRawPtr; mRawPtr = newPtr; delete [] oldPtr; } private: T* mRawPtr; public: typedef T element_type; ~nsAutoArrayPtr() { delete [] mRawPtr; } // Constructors nsAutoArrayPtr() : mRawPtr(0) // default constructor { } nsAutoArrayPtr( T* aRawPtr ) : mRawPtr(aRawPtr) // construct from a raw pointer (of the right type) { } nsAutoArrayPtr( nsAutoArrayPtr& aSmartPtr ) : mRawPtr( aSmartPtr.forget() ) // Construct by transferring ownership from another smart pointer. { } // Assignment operators nsAutoArrayPtr& operator=( T* rhs ) // assign from a raw pointer (of the right type) { assign(rhs); return *this; } nsAutoArrayPtr& operator=( nsAutoArrayPtr& rhs ) // assign by transferring ownership from another smart pointer. { assign(rhs.forget()); return *this; } // Other pointer operators T* get() const /* Prefer the implicit conversion provided automatically by |operator T*() const|. Use |get()| _only_ to resolve ambiguity. */ { return mRawPtr; } operator T*() const /* ...makes an |nsAutoArrayPtr| 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 |nsAutoArrayPtr| substitutable for a raw pointer. Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. */ { return get(); } T* forget() { T* temp = mRawPtr; mRawPtr = 0; return temp; } T* operator->() const { NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsAutoArrayPtr with operator->()."); return get(); } #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY // broken version for IRIX nsAutoArrayPtr* get_address() const // This is not intended to be used by clients. See |address_of| // below. { return NS_CONST_CAST(nsAutoArrayPtr*, this); } #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY nsAutoArrayPtr* get_address() // This is not intended to be used by clients. See |address_of| // below. { return this; } const nsAutoArrayPtr* get_address() const // This is not intended to be used by clients. See |address_of| // below. { return this; } #endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY public: T& operator*() const { NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsAutoArrayPtr with operator*()."); return *get(); } T** StartAssignment() { #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT return NS_REINTERPRET_CAST(T**, begin_assignment()); #else assign(0); return NS_REINTERPRET_CAST(T**, &mRawPtr); #endif } }; template void** nsAutoArrayPtr::begin_assignment() { assign(0); return NS_REINTERPRET_CAST(void**, &mRawPtr); } #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY // This is the broken version for IRIX, which can't handle the version below. template inline nsAutoArrayPtr* address_of( const nsAutoArrayPtr& aPtr ) { return aPtr.get_address(); } #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY template inline nsAutoArrayPtr* address_of( nsAutoArrayPtr& aPtr ) { return aPtr.get_address(); } template inline const nsAutoArrayPtr* address_of( const nsAutoArrayPtr& aPtr ) { return aPtr.get_address(); } #endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY template class nsAutoArrayPtrGetterTransfers /* ... This class is designed to be used for anonymous temporary objects in the argument list of calls that return COM interface pointers, e.g., nsAutoArrayPtr fooP; ...->GetTransferedPointer(getter_Transfers(fooP)) DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_Transfers()| instead. When initialized with a |nsAutoArrayPtr|, as in the example above, it returns a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call (|GetTransferedPointer| in this case) can fill in. This type should be a nested class inside |nsAutoArrayPtr|. */ { public: explicit nsAutoArrayPtrGetterTransfers( nsAutoArrayPtr& aSmartPtr ) : mTargetSmartPtr(aSmartPtr) { // nothing else to do } operator void**() { return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); } operator T**() { return mTargetSmartPtr.StartAssignment(); } T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } private: nsAutoArrayPtr& mTargetSmartPtr; }; template inline nsAutoArrayPtrGetterTransfers getter_Transfers( nsAutoArrayPtr& aSmartPtr ) /* Used around a |nsAutoArrayPtr| when ...makes the class |nsAutoArrayPtrGetterTransfers| invisible. */ { return nsAutoArrayPtrGetterTransfers(aSmartPtr); } // Comparing two |nsAutoArrayPtr|s template inline NSCAP_BOOL operator==( const nsAutoArrayPtr& lhs, const nsAutoArrayPtr& rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsAutoArrayPtr& lhs, const nsAutoArrayPtr& rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs.get()); } // Comparing an |nsAutoArrayPtr| to a raw pointer template inline NSCAP_BOOL operator==( const nsAutoArrayPtr& lhs, const U* rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs); } template inline NSCAP_BOOL operator==( const U* lhs, const nsAutoArrayPtr& rhs ) { return NS_STATIC_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsAutoArrayPtr& lhs, const U* rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs); } template inline NSCAP_BOOL operator!=( const U* lhs, const nsAutoArrayPtr& rhs ) { return NS_STATIC_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); } // To avoid ambiguities caused by the presence of builtin |operator==|s // creating a situation where one of the |operator==| defined above // has a better conversion for one argument and the builtin has a // better conversion for the other argument, define additional // |operator==| without the |const| on the raw pointer. // See bug 65664 for details. // This is defined by an autoconf test, but VC++ also has a bug that // prevents us from using these. (It also, fortunately, has the bug // that we don't need them either.) #ifdef _MSC_VER #define NSCAP_DONT_PROVIDE_NONCONST_OPEQ #endif #ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ template inline NSCAP_BOOL operator==( const nsAutoArrayPtr& lhs, U* rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) == NS_CONST_CAST(const U*, rhs); } template inline NSCAP_BOOL operator==( U* lhs, const nsAutoArrayPtr& rhs ) { return NS_CONST_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsAutoArrayPtr& lhs, U* rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) != NS_CONST_CAST(const U*, rhs); } template inline NSCAP_BOOL operator!=( U* lhs, const nsAutoArrayPtr& rhs ) { return NS_CONST_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); } #endif // Comparing an |nsAutoArrayPtr| to |0| template inline NSCAP_BOOL operator==( const nsAutoArrayPtr& lhs, NSCAP_Zero* rhs ) // specifically to allow |smartPtr == 0| { return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); } template inline NSCAP_BOOL operator==( NSCAP_Zero* lhs, const nsAutoArrayPtr& rhs ) // specifically to allow |0 == smartPtr| { return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsAutoArrayPtr& lhs, NSCAP_Zero* rhs ) // specifically to allow |smartPtr != 0| { return NS_STATIC_CAST(const void*, lhs.get()) != NS_REINTERPRET_CAST(const void*, rhs); } template inline NSCAP_BOOL operator!=( NSCAP_Zero* lhs, const nsAutoArrayPtr& rhs ) // specifically to allow |0 != smartPtr| { return NS_REINTERPRET_CAST(const void*, lhs) != NS_STATIC_CAST(const void*, rhs.get()); } #ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO // We need to explicitly define comparison operators for `int' // because the compiler is lame. template inline NSCAP_BOOL operator==( const nsAutoArrayPtr& lhs, int rhs ) // specifically to allow |smartPtr == 0| { return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); } template inline NSCAP_BOOL operator==( int lhs, const nsAutoArrayPtr& rhs ) // specifically to allow |0 == smartPtr| { return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); } #endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO) /*****************************************************************************/ // template class nsRefPtrGetterAddRefs; template class nsRefPtr { enum { _force_even_compliant_compilers_to_fail_ = sizeof(T) }; /* The declaration above exists specifically to make |nsRefPtr| _not_ compile with only a forward declaration of |T|. This should prevent Windows and Mac engineers from breaking Solaris and other compilers that naturally have this behavior. Thank for inventing this specific trick. Of course, if you're using |nsRefPtr| outside the scope of wanting to compile on Solaris and old GCC, you probably want to remove the enum so you can exploit forward declarations. */ private: void assign_with_AddRef( T* ); void** begin_assignment(); void assign_assuming_AddRef( T* newPtr ) { T* oldPtr = mRawPtr; mRawPtr = newPtr; if ( oldPtr ) oldPtr->Release(); } private: T* mRawPtr; public: typedef T element_type; ~nsRefPtr() { if ( mRawPtr ) mRawPtr->Release(); } // Constructors nsRefPtr() : mRawPtr(0) // default constructor { } nsRefPtr( const nsRefPtr& aSmartPtr ) : mRawPtr(aSmartPtr.mRawPtr) // copy-constructor { if ( mRawPtr ) mRawPtr->AddRef(); } nsRefPtr( T* aRawPtr ) : mRawPtr(aRawPtr) // construct from a raw pointer (of the right type) { if ( mRawPtr ) mRawPtr->AddRef(); } nsRefPtr( const already_AddRefed& aSmartPtr ) : mRawPtr(aSmartPtr.mRawPtr) // construct from |dont_AddRef(expr)| { } // Assignment operators nsRefPtr& operator=( const nsRefPtr& rhs ) // copy assignment operator { assign_with_AddRef(rhs.mRawPtr); return *this; } nsRefPtr& operator=( T* rhs ) // assign from a raw pointer (of the right type) { assign_with_AddRef(rhs); return *this; } nsRefPtr& operator=( const already_AddRefed& rhs ) // assign from |dont_AddRef(expr)| { assign_assuming_AddRef(rhs.mRawPtr); return *this; } // Other pointer operators nsDerivedSafe* get() const /* Prefer the implicit conversion provided automatically by |operator nsDerivedSafe*() const|. Use |get()| _only_ to resolve ambiguity. Returns a |nsDerivedSafe*| to deny clients the use of |AddRef| and |Release|. */ { return NS_CONST_CAST(nsDerivedSafe*, NS_REINTERPRET_CAST(const nsDerivedSafe*, mRawPtr)); } operator nsDerivedSafe*() const /* ...makes an |nsRefPtr| act like its underlying raw pointer type (except against |AddRef()|, |Release()|, and |delete|) whenever it is used in a context where a raw pointer is expected. It is this operator that makes an |nsRefPtr| substitutable for a raw pointer. Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. */ { return get(); } nsDerivedSafe* operator->() const { NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsRefPtr with operator->()."); return get(); } #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY // broken version for IRIX nsRefPtr* get_address() const // This is not intended to be used by clients. See |address_of| // below. { return NS_CONST_CAST(nsRefPtr*, this); } #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY nsRefPtr* get_address() // This is not intended to be used by clients. See |address_of| // below. { return this; } const nsRefPtr* get_address() const // This is not intended to be used by clients. See |address_of| // below. { return this; } #endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY public: nsDerivedSafe& operator*() const { NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsRefPtr with operator*()."); return *get(); } T** StartAssignment() { #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT return NS_REINTERPRET_CAST(T**, begin_assignment()); #else assign_assuming_AddRef(0); return NS_REINTERPRET_CAST(T**, &mRawPtr); #endif } }; template void nsRefPtr::assign_with_AddRef( T* rawPtr ) { if ( rawPtr ) rawPtr->AddRef(); assign_assuming_AddRef(rawPtr); } template void** nsRefPtr::begin_assignment() { assign_assuming_AddRef(0); return NS_REINTERPRET_CAST(void**, &mRawPtr); } #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY // This is the broken version for IRIX, which can't handle the version below. template inline nsRefPtr* address_of( const nsRefPtr& aPtr ) { return aPtr.get_address(); } #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY template inline nsRefPtr* address_of( nsRefPtr& aPtr ) { return aPtr.get_address(); } template inline const nsRefPtr* address_of( const nsRefPtr& aPtr ) { return aPtr.get_address(); } #endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY template class nsRefPtrGetterAddRefs /* ... This class is designed to be used for anonymous temporary objects in the argument list of calls that return COM interface pointers, e.g., nsRefPtr fooP; ...->GetAddRefedPointer(getter_AddRefs(fooP)) DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead. When initialized with a |nsRefPtr|, 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 |nsRefPtr|. */ { public: explicit nsRefPtrGetterAddRefs( nsRefPtr& aSmartPtr ) : mTargetSmartPtr(aSmartPtr) { // nothing else to do } operator void**() { return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); } operator T**() { return mTargetSmartPtr.StartAssignment(); } T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } private: nsRefPtr& mTargetSmartPtr; }; template inline nsRefPtrGetterAddRefs getter_AddRefs( nsRefPtr& aSmartPtr ) /* Used around a |nsRefPtr| when ...makes the class |nsRefPtrGetterAddRefs| invisible. */ { return nsRefPtrGetterAddRefs(aSmartPtr); } // Comparing two |nsRefPtr|s template inline NSCAP_BOOL operator==( const nsRefPtr& lhs, const nsRefPtr& rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsRefPtr& lhs, const nsRefPtr& rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs.get()); } // Comparing an |nsRefPtr| to a raw pointer template inline NSCAP_BOOL operator==( const nsRefPtr& lhs, const U* rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs); } template inline NSCAP_BOOL operator==( const U* lhs, const nsRefPtr& rhs ) { return NS_STATIC_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsRefPtr& lhs, const U* rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs); } template inline NSCAP_BOOL operator!=( const U* lhs, const nsRefPtr& rhs ) { return NS_STATIC_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); } // To avoid ambiguities caused by the presence of builtin |operator==|s // creating a situation where one of the |operator==| defined above // has a better conversion for one argument and the builtin has a // better conversion for the other argument, define additional // |operator==| without the |const| on the raw pointer. // See bug 65664 for details. // This is defined by an autoconf test, but VC++ also has a bug that // prevents us from using these. (It also, fortunately, has the bug // that we don't need them either.) #ifdef _MSC_VER #define NSCAP_DONT_PROVIDE_NONCONST_OPEQ #endif #ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ template inline NSCAP_BOOL operator==( const nsRefPtr& lhs, U* rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) == NS_CONST_CAST(const U*, rhs); } template inline NSCAP_BOOL operator==( U* lhs, const nsRefPtr& rhs ) { return NS_CONST_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsRefPtr& lhs, U* rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) != NS_CONST_CAST(const U*, rhs); } template inline NSCAP_BOOL operator!=( U* lhs, const nsRefPtr& rhs ) { return NS_CONST_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); } #endif // Comparing an |nsRefPtr| to |0| template inline NSCAP_BOOL operator==( const nsRefPtr& lhs, NSCAP_Zero* rhs ) // specifically to allow |smartPtr == 0| { return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); } template inline NSCAP_BOOL operator==( NSCAP_Zero* lhs, const nsRefPtr& rhs ) // specifically to allow |0 == smartPtr| { return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsRefPtr& lhs, NSCAP_Zero* rhs ) // specifically to allow |smartPtr != 0| { return NS_STATIC_CAST(const void*, lhs.get()) != NS_REINTERPRET_CAST(const void*, rhs); } template inline NSCAP_BOOL operator!=( NSCAP_Zero* lhs, const nsRefPtr& rhs ) // specifically to allow |0 != smartPtr| { return NS_REINTERPRET_CAST(const void*, lhs) != NS_STATIC_CAST(const void*, rhs.get()); } #ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO // We need to explicitly define comparison operators for `int' // because the compiler is lame. template inline NSCAP_BOOL operator==( const nsRefPtr& lhs, int rhs ) // specifically to allow |smartPtr == 0| { return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); } template inline NSCAP_BOOL operator==( int lhs, const nsRefPtr& rhs ) // specifically to allow |0 == smartPtr| { return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); } #endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO) /*****************************************************************************/ #endif // !defined(nsAutoPtr_h___)