/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla 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/MPL/ * * 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) * L. David Baron * * Alternatively, the contents of this file may be used under the terms of * either of 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 MPL, 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 MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef nsCOMPtr_h___ #define nsCOMPtr_h___ /* Having problems? See the User Manual at: http://www.mozilla.org/projects/xpcom/nsCOMPtr.html nsCOMPtr better than a raw pointer for owning objects -- scc */ // Wrapping includes can speed up compiles (see "Large Scale C++ Software Design") #ifndef nsDebug_h___ #include "nsDebug.h" // for |NS_PRECONDITION| #endif #ifndef nsISupportsUtils_h__ #include "nsISupportsUtils.h" // for |nsresult|, |NS_ADDREF|, |NS_GET_TEMPLATE_IID| et al #endif #ifndef nscore_h___ #include "nscore.h" // for |NS_..._CAST|, |NS_COM_GLUE| #endif /* WARNING: This file defines several macros for internal use only. These macros begin with the prefix |NSCAP_|. Do not use these macros in your own code. They are for internal use only for cross-platform compatibility, and are subject to change without notice. */ #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 #define NSCAP_FEATURE_USE_BASE #ifdef NS_DEBUG #define NSCAP_FEATURE_TEST_DONTQUERY_CASES #undef NSCAP_FEATURE_USE_BASE //#define NSCAP_FEATURE_TEST_NONNULL_QUERY_SUCCEEDS #endif /* |...TEST_DONTQUERY_CASES| and |...DEBUG_PTR_TYPES| introduce some code that is problematic on a select few of our platforms, e.g., QNX. Therefore, I'm providing a mechanism by which these features can be explicitly disabled from the command-line. */ #ifdef NSCAP_DISABLE_TEST_DONTQUERY_CASES #undef NSCAP_FEATURE_TEST_DONTQUERY_CASES #endif #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) // Our use of nsCOMPtr_base::mRawPtr violates the C++ standard's aliasing // rules. Mark it with the may_alias attribute so that gcc 3.3 and higher // don't reorder instructions based on aliasing assumptions for // this variable. Fortunately, gcc versions < 3.3 do not do any // optimizations that break nsCOMPtr. #define NS_MAY_ALIAS_PTR(t) t* __attribute__((__may_alias__)) #else #define NS_MAY_ALIAS_PTR(t) t* #endif #if defined(NSCAP_DISABLE_DEBUG_PTR_TYPES) #define NSCAP_FEATURE_USE_BASE #endif #ifdef HAVE_CPP_BOOL typedef bool NSCAP_BOOL; #else typedef PRBool NSCAP_BOOL; #endif /* The following three macros (|NSCAP_ADDREF|, |NSCAP_RELEASE|, and |NSCAP_LOG_ASSIGNMENT|) allow external clients the ability to add logging or other interesting debug facilities. In fact, if you want |nsCOMPtr| to participate in the standard logging facility, you provide (e.g., in "nsTraceRefcnt.h") suitable definitions #define NSCAP_ADDREF(this, ptr) NS_ADDREF(ptr) #define NSCAP_RELEASE(this, ptr) NS_RELEASE(ptr) */ #ifndef NSCAP_ADDREF #define NSCAP_ADDREF(this, ptr) (ptr)->AddRef() #endif #ifndef NSCAP_RELEASE #define NSCAP_RELEASE(this, ptr) (ptr)->Release() #endif // Clients can define |NSCAP_LOG_ASSIGNMENT| to perform logging. #ifdef NSCAP_LOG_ASSIGNMENT // Remember that |NSCAP_LOG_ASSIGNMENT| was defined by some client so that we know // to instantiate |~nsGetterAddRefs| in turn to note the external assignment into // the |nsCOMPtr|. #define NSCAP_LOG_EXTERNAL_ASSIGNMENT #else // ...otherwise, just strip it out of the code #define NSCAP_LOG_ASSIGNMENT(this, ptr) #endif #ifndef NSCAP_LOG_RELEASE #define NSCAP_LOG_RELEASE(this, ptr) #endif /* WARNING: VC++4.2 is very picky. To compile under VC++4.2, the classes must be defined in an order that satisfies: nsDerivedSafe < nsCOMPtr already_AddRefed < nsCOMPtr nsCOMPtr < nsGetterAddRefs The other compilers probably won't complain, so please don't reorder these classes, on pain of breaking 4.2 compatibility. */ template class nsDerivedSafe : public T /* No client should ever see or have to type the name of this class. It is the artifact that makes it a compile-time error to call |AddRef| and |Release| on a |nsCOMPtr|. DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. See |nsCOMPtr::operator->|, |nsCOMPtr::operator*|, et al. This type should be a nested class inside |nsCOMPtr|. */ { private: #ifdef HAVE_CPP_ACCESS_CHANGING_USING using T::AddRef; using T::Release; #else nsrefcnt AddRef(void); nsrefcnt Release(void); #endif #if !defined(AIX) && !defined(IRIX) void operator delete( void*, size_t ); // NOT TO BE IMPLEMENTED // declaring |operator delete| private makes calling delete on an interface pointer a compile error #endif nsDerivedSafe& operator=( const T& ); // NOT TO BE IMPLEMENTED // you may not call |operator=()| through a dereferenced |nsCOMPtr|, because you'd get the wrong one /* Compiler warnings and errors: nsDerivedSafe operator=() hides inherited operator=(). If you see that, that means somebody checked in a [XP]COM interface class that declares an |operator=()|, and that's _bad_. So bad, in fact, that this declaration exists explicitly to stop people from doing it. */ protected: nsDerivedSafe(); // NOT TO BE IMPLEMENTED /* This ctor exists to avoid compile errors and warnings about nsDeriviedSafe using the default ctor but inheriting classes without an empty ctor. See bug 209667. */ }; #if !defined(HAVE_CPP_ACCESS_CHANGING_USING) && defined(NEED_CPP_UNUSED_IMPLEMENTATIONS) template nsrefcnt nsDerivedSafe::AddRef() { return 0; } template nsrefcnt nsDerivedSafe::Release() { return 0; } #endif template struct already_AddRefed /* ...cooperates with |nsCOMPtr| to allow you to assign in a pointer _without_ |AddRef|ing it. You might want to use this as a return type from a function that produces an already |AddRef|ed pointer as a result. See also |getter_AddRefs()|, |dont_AddRef()|, and |class nsGetterAddRefs|. This type should be a nested class inside |nsCOMPtr|. Yes, |already_AddRefed| could have been implemented as an |nsCOMPtr_helper| to avoid adding specialized machinery to |nsCOMPtr| ... but this is the simplest case, and perhaps worth the savings in time and space that its specific implementation affords over the more general solution offered by |nsCOMPtr_helper|. */ { already_AddRefed( T* aRawPtr ) : mRawPtr(aRawPtr) { // nothing else to do here } T* get() const { return mRawPtr; } T* mRawPtr; }; template inline const already_AddRefed getter_AddRefs( T* aRawPtr ) /* ...makes typing easier, because it deduces the template type, e.g., you write |dont_AddRef(fooP)| instead of |already_AddRefed(fooP)|. */ { return already_AddRefed(aRawPtr); } template inline const already_AddRefed getter_AddRefs( const already_AddRefed aAlreadyAddRefedPtr ) { return aAlreadyAddRefedPtr; } template inline const already_AddRefed dont_AddRef( T* aRawPtr ) { return already_AddRefed(aRawPtr); } template inline const already_AddRefed dont_AddRef( const already_AddRefed aAlreadyAddRefedPtr ) { return aAlreadyAddRefedPtr; } class nsCOMPtr_helper /* An |nsCOMPtr_helper| transforms commonly called getters into typesafe forms that are more convenient to call, and more efficient to use with |nsCOMPtr|s. Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc. Here are the rules for a helper: - it implements |operator()| to produce an interface pointer - (except for its name) |operator()| is a valid [XP]COM `getter' - the interface pointer that it returns is already |AddRef()|ed (as from any good getter) - it matches the type requested with the supplied |nsIID| argument - its constructor provides an optional |nsresult*| that |operator()| can fill in with an error when it is executed See |class nsGetInterface| for an example. */ { public: virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const = 0; }; /* |nsQueryInterface| could have been implemented as an |nsCOMPtr_helper| to avoid adding specialized machinery in |nsCOMPtr|, But |do_QueryInterface| is called often enough that the codesize savings are big enough to warrant the specialcasing. */ class NS_COM_GLUE nsQueryInterface { public: explicit nsQueryInterface( nsISupports* aRawPtr ) : mRawPtr(aRawPtr) { // nothing else to do here } nsresult NS_FASTCALL operator()( const nsIID& aIID, void** ) const; private: nsISupports* mRawPtr; }; class NS_COM_GLUE nsQueryInterfaceWithError { public: nsQueryInterfaceWithError( nsISupports* aRawPtr, nsresult* error ) : mRawPtr(aRawPtr), mErrorPtr(error) { // nothing else to do here } nsresult NS_FASTCALL operator()( const nsIID& aIID, void** ) const; private: nsISupports* mRawPtr; nsresult* mErrorPtr; }; inline nsQueryInterface do_QueryInterface( nsISupports* aRawPtr ) { return nsQueryInterface(aRawPtr); } inline nsQueryInterfaceWithError do_QueryInterface( nsISupports* aRawPtr, nsresult* error ) { return nsQueryInterfaceWithError(aRawPtr, error); } template inline void do_QueryInterface( already_AddRefed& ) { // This signature exists soley to _stop_ you from doing the bad thing. // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by // someone else is an automatic leak. See . } template inline void do_QueryInterface( already_AddRefed&, nsresult* ) { // This signature exists soley to _stop_ you from doing the bad thing. // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by // someone else is an automatic leak. See . } //////////////////////////////////////////////////////////////////////////// // Using servicemanager with COMPtrs class NS_COM_GLUE nsGetServiceByCID { public: explicit nsGetServiceByCID(const nsCID& aCID) : mCID(aCID) { // nothing else to do } nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; private: const nsCID& mCID; }; class NS_COM_GLUE nsGetServiceByCIDWithError { public: nsGetServiceByCIDWithError( const nsCID& aCID, nsresult* aErrorPtr ) : mCID(aCID), mErrorPtr(aErrorPtr) { // nothing else to do } nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; private: const nsCID& mCID; nsresult* mErrorPtr; }; class NS_COM_GLUE nsGetServiceByContractID { public: explicit nsGetServiceByContractID(const char* aContractID) : mContractID(aContractID) { // nothing else to do } nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; private: const char* mContractID; }; class NS_COM_GLUE nsGetServiceByContractIDWithError { public: nsGetServiceByContractIDWithError(const char* aContractID, nsresult* aErrorPtr) : mContractID(aContractID), mErrorPtr(aErrorPtr) { // nothing else to do } nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; private: const char* mContractID; nsresult* mErrorPtr; }; class nsCOMPtr_base /* ...factors implementation for all template versions of |nsCOMPtr|. This should really be an |nsCOMPtr|, but this wouldn't work because unlike the Here's the way people normally do things like this template class Foo { ... }; template <> class Foo { ... }; template class Foo : private Foo { ... }; */ { public: nsCOMPtr_base( nsISupports* rawPtr = 0 ) : mRawPtr(rawPtr) { // nothing else to do here } NS_COM_GLUE NS_CONSTRUCTOR_FASTCALL ~nsCOMPtr_base(); NS_COM_GLUE void NS_FASTCALL assign_with_AddRef( nsISupports* ); NS_COM_GLUE void NS_FASTCALL assign_from_qi( const nsQueryInterface, const nsIID& ); NS_COM_GLUE void NS_FASTCALL assign_from_qi_with_error( const nsQueryInterfaceWithError&, const nsIID& ); NS_COM_GLUE void NS_FASTCALL assign_from_gs_cid( const nsGetServiceByCID, const nsIID& ); NS_COM_GLUE void NS_FASTCALL assign_from_gs_cid_with_error( const nsGetServiceByCIDWithError&, const nsIID& ); NS_COM_GLUE void NS_FASTCALL assign_from_gs_contractid( const nsGetServiceByContractID, const nsIID& ); NS_COM_GLUE void NS_FASTCALL assign_from_gs_contractid_with_error( const nsGetServiceByContractIDWithError&, const nsIID& ); NS_COM_GLUE void NS_FASTCALL assign_from_helper( const nsCOMPtr_helper&, const nsIID& ); NS_COM_GLUE void** NS_FASTCALL begin_assignment(); protected: NS_MAY_ALIAS_PTR(nsISupports) mRawPtr; void assign_assuming_AddRef( nsISupports* newPtr ) { /* |AddRef()|ing the new value (before entering this function) before |Release()|ing the old lets us safely ignore the self-assignment case. We must, however, be careful only to |Release()| _after_ doing the assignment, in case the |Release()| leads to our _own_ destruction, which would, in turn, cause an incorrect second |Release()| of our old pointer. Thank for discovering this. */ nsISupports* oldPtr = mRawPtr; mRawPtr = newPtr; NSCAP_LOG_ASSIGNMENT(this, newPtr); NSCAP_LOG_RELEASE(this, oldPtr); if ( oldPtr ) NSCAP_RELEASE(this, oldPtr); } }; // template class nsGetterAddRefs; template class nsCOMPtr #ifdef NSCAP_FEATURE_USE_BASE : private nsCOMPtr_base #endif { #ifdef NSCAP_FEATURE_USE_BASE #define NSCAP_CTOR_BASE(x) nsCOMPtr_base(x) #else #define NSCAP_CTOR_BASE(x) mRawPtr(x) private: void assign_with_AddRef( nsISupports* ); void assign_from_qi( const nsQueryInterface, const nsIID& ); void assign_from_qi_with_error( const nsQueryInterfaceWithError&, const nsIID& ); void assign_from_gs_cid( const nsGetServiceByCID, const nsIID& ); void assign_from_gs_cid_with_error( const nsGetServiceByCIDWithError&, const nsIID& ); void assign_from_gs_contractid( const nsGetServiceByContractID, const nsIID& ); void assign_from_gs_contractid_with_error( const nsGetServiceByContractIDWithError&, const nsIID& ); void assign_from_helper( const nsCOMPtr_helper&, const nsIID& ); void** begin_assignment(); void assign_assuming_AddRef( T* newPtr ) { T* oldPtr = mRawPtr; mRawPtr = newPtr; NSCAP_LOG_ASSIGNMENT(this, newPtr); NSCAP_LOG_RELEASE(this, oldPtr); if ( oldPtr ) NSCAP_RELEASE(this, oldPtr); } private: T* mRawPtr; #endif public: typedef T element_type; #ifndef NSCAP_FEATURE_USE_BASE ~nsCOMPtr() { NSCAP_LOG_RELEASE(this, mRawPtr); if ( mRawPtr ) NSCAP_RELEASE(this, mRawPtr); } #endif #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES void Assert_NoQueryNeeded() { if ( mRawPtr ) { nsCOMPtr query_result( do_QueryInterface(mRawPtr) ); NS_ASSERTION(query_result.get() == mRawPtr, "QueryInterface needed"); } } #define NSCAP_ASSERT_NO_QUERY_NEEDED() Assert_NoQueryNeeded(); #else #define NSCAP_ASSERT_NO_QUERY_NEEDED() #endif // Constructors nsCOMPtr() : NSCAP_CTOR_BASE(0) // default constructor { NSCAP_LOG_ASSIGNMENT(this, 0); } nsCOMPtr( const nsCOMPtr& aSmartPtr ) : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) // copy-constructor { if ( mRawPtr ) NSCAP_ADDREF(this, mRawPtr); NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr); } nsCOMPtr( T* aRawPtr ) : NSCAP_CTOR_BASE(aRawPtr) // construct from a raw pointer (of the right type) { if ( mRawPtr ) NSCAP_ADDREF(this, mRawPtr); NSCAP_LOG_ASSIGNMENT(this, aRawPtr); NSCAP_ASSERT_NO_QUERY_NEEDED(); } nsCOMPtr( const already_AddRefed& aSmartPtr ) : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) // construct from |dont_AddRef(expr)| { NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr); NSCAP_ASSERT_NO_QUERY_NEEDED(); } nsCOMPtr( const nsQueryInterface qi ) : NSCAP_CTOR_BASE(0) // construct from |do_QueryInterface(expr)| { NSCAP_LOG_ASSIGNMENT(this, 0); assign_from_qi(qi, NS_GET_TEMPLATE_IID(T)); } nsCOMPtr( const nsQueryInterfaceWithError& qi ) : NSCAP_CTOR_BASE(0) // construct from |do_QueryInterface(expr, &rv)| { NSCAP_LOG_ASSIGNMENT(this, 0); assign_from_qi_with_error(qi, NS_GET_TEMPLATE_IID(T)); } nsCOMPtr( const nsGetServiceByCID gs ) : NSCAP_CTOR_BASE(0) // construct from |do_GetService(cid_expr)| { NSCAP_LOG_ASSIGNMENT(this, 0); assign_from_gs_cid(gs, NS_GET_TEMPLATE_IID(T)); } nsCOMPtr( const nsGetServiceByCIDWithError& gs ) : NSCAP_CTOR_BASE(0) // construct from |do_GetService(cid_expr, &rv)| { NSCAP_LOG_ASSIGNMENT(this, 0); assign_from_gs_cid_with_error(gs, NS_GET_TEMPLATE_IID(T)); } nsCOMPtr( const nsGetServiceByContractID gs ) : NSCAP_CTOR_BASE(0) // construct from |do_GetService(contractid_expr)| { NSCAP_LOG_ASSIGNMENT(this, 0); assign_from_gs_contractid(gs, NS_GET_TEMPLATE_IID(T)); } nsCOMPtr( const nsGetServiceByContractIDWithError& gs ) : NSCAP_CTOR_BASE(0) // construct from |do_GetService(contractid_expr, &rv)| { NSCAP_LOG_ASSIGNMENT(this, 0); assign_from_gs_contractid_with_error(gs, NS_GET_TEMPLATE_IID(T)); } nsCOMPtr( const nsCOMPtr_helper& helper ) : NSCAP_CTOR_BASE(0) // ...and finally, anything else we might need to construct from // can exploit the |nsCOMPtr_helper| facility { NSCAP_LOG_ASSIGNMENT(this, 0); assign_from_helper(helper, NS_GET_TEMPLATE_IID(T)); NSCAP_ASSERT_NO_QUERY_NEEDED(); } // Assignment operators nsCOMPtr& operator=( const nsCOMPtr& rhs ) // copy assignment operator { assign_with_AddRef(rhs.mRawPtr); return *this; } nsCOMPtr& operator=( T* rhs ) // assign from a raw pointer (of the right type) { assign_with_AddRef(rhs); NSCAP_ASSERT_NO_QUERY_NEEDED(); return *this; } nsCOMPtr& operator=( const already_AddRefed& rhs ) // assign from |dont_AddRef(expr)| { assign_assuming_AddRef(rhs.mRawPtr); NSCAP_ASSERT_NO_QUERY_NEEDED(); return *this; } nsCOMPtr& operator=( const nsQueryInterface rhs ) // assign from |do_QueryInterface(expr)| { assign_from_qi(rhs, NS_GET_TEMPLATE_IID(T)); return *this; } nsCOMPtr& operator=( const nsQueryInterfaceWithError& rhs ) // assign from |do_QueryInterface(expr, &rv)| { assign_from_qi_with_error(rhs, NS_GET_TEMPLATE_IID(T)); return *this; } nsCOMPtr& operator=( const nsGetServiceByCID rhs ) // assign from |do_GetService(cid_expr)| { assign_from_gs_cid(rhs, NS_GET_TEMPLATE_IID(T)); return *this; } nsCOMPtr& operator=( const nsGetServiceByCIDWithError& rhs ) // assign from |do_GetService(cid_expr, &rv)| { assign_from_gs_cid_with_error(rhs, NS_GET_TEMPLATE_IID(T)); return *this; } nsCOMPtr& operator=( const nsGetServiceByContractID rhs ) // assign from |do_GetService(contractid_expr)| { assign_from_gs_contractid(rhs, NS_GET_TEMPLATE_IID(T)); return *this; } nsCOMPtr& operator=( const nsGetServiceByContractIDWithError& rhs ) // assign from |do_GetService(contractid_expr, &rv)| { assign_from_gs_contractid_with_error(rhs, NS_GET_TEMPLATE_IID(T)); return *this; } nsCOMPtr& operator=( const nsCOMPtr_helper& rhs ) // ...and finally, anything else we might need to assign from // can exploit the |nsCOMPtr_helper| facility. { assign_from_helper(rhs, NS_GET_TEMPLATE_IID(T)); NSCAP_ASSERT_NO_QUERY_NEEDED(); return *this; } void swap( nsCOMPtr& rhs ) // ...exchange ownership with |rhs|; can save a pair of refcount operations { #ifdef NSCAP_FEATURE_USE_BASE nsISupports* temp = rhs.mRawPtr; #else T* temp = rhs.mRawPtr; #endif NSCAP_LOG_ASSIGNMENT(&rhs, mRawPtr); NSCAP_LOG_ASSIGNMENT(this, temp); NSCAP_LOG_RELEASE(this, mRawPtr); NSCAP_LOG_RELEASE(&rhs, temp); rhs.mRawPtr = mRawPtr; mRawPtr = temp; // |rhs| maintains the same invariants, so we don't need to |NSCAP_ASSERT_NO_QUERY_NEEDED| } void swap( T*& rhs ) // ...exchange ownership with |rhs|; can save a pair of refcount operations { #ifdef NSCAP_FEATURE_USE_BASE nsISupports* temp = rhs; #else T* temp = rhs; #endif NSCAP_LOG_ASSIGNMENT(this, temp); NSCAP_LOG_RELEASE(this, mRawPtr); rhs = NS_REINTERPRET_CAST(T*, mRawPtr); mRawPtr = temp; NSCAP_ASSERT_NO_QUERY_NEEDED(); } // Other pointer operators T* get() const /* Prefer the implicit conversion provided automatically by |operator nsDerivedSafe*() const|. Use |get()| to resolve ambiguity or to get a castable pointer. */ { return NS_REINTERPRET_CAST(T*, mRawPtr); } operator nsDerivedSafe*() const /* ...makes an |nsCOMPtr| 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 |nsCOMPtr| substitutable for a raw pointer. Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. */ { return get_DerivedSafe(); } nsDerivedSafe* operator->() const { NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator->()."); return get_DerivedSafe(); } #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY // broken version for IRIX nsCOMPtr* get_address() const // This is not intended to be used by clients. See |address_of| // below. { return NS_CONST_CAST(nsCOMPtr*, this); } #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY nsCOMPtr* get_address() // This is not intended to be used by clients. See |address_of| // below. { return this; } const nsCOMPtr* 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 nsCOMPtr with operator*()."); return *get_DerivedSafe(); } #if 0 private: friend class nsGetterAddRefs; #endif 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 } private: nsDerivedSafe* get_DerivedSafe() const { return NS_REINTERPRET_CAST(nsDerivedSafe*, mRawPtr); } }; /* Specializing |nsCOMPtr| for |nsISupports| allows us to use |nsCOMPtr| the same way people use |nsISupports*| and |void*|, i.e., as a `catch-all' pointer pointing to any valid [XP]COM interface. Otherwise, an |nsCOMPtr| would only be able to point to the single [XP]COM-correct |nsISupports| instance within an object; extra querying ensues. Clients need to be able to pass around arbitrary interface pointers, without hassles, through intermediary code that doesn't know the exact type. */ NS_SPECIALIZE_TEMPLATE class nsCOMPtr : private nsCOMPtr_base { public: typedef nsISupports element_type; // Constructors nsCOMPtr() : nsCOMPtr_base(0) // default constructor { NSCAP_LOG_ASSIGNMENT(this, 0); } nsCOMPtr( const nsCOMPtr& aSmartPtr ) : nsCOMPtr_base(aSmartPtr.mRawPtr) // copy constructor { if ( mRawPtr ) NSCAP_ADDREF(this, mRawPtr); NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr); } nsCOMPtr( nsISupports* aRawPtr ) : nsCOMPtr_base(aRawPtr) // construct from a raw pointer (of the right type) { if ( mRawPtr ) NSCAP_ADDREF(this, mRawPtr); NSCAP_LOG_ASSIGNMENT(this, aRawPtr); } nsCOMPtr( const already_AddRefed& aSmartPtr ) : nsCOMPtr_base(aSmartPtr.mRawPtr) // construct from |dont_AddRef(expr)| { NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr); } nsCOMPtr( const nsQueryInterface qi ) : nsCOMPtr_base(0) // assign from |do_QueryInterface(expr)| { NSCAP_LOG_ASSIGNMENT(this, 0); assign_from_qi(qi, NS_GET_IID(nsISupports)); } nsCOMPtr( const nsQueryInterfaceWithError& qi ) : nsCOMPtr_base(0) // assign from |do_QueryInterface(expr, &rv)| { NSCAP_LOG_ASSIGNMENT(this, 0); assign_from_qi_with_error(qi, NS_GET_IID(nsISupports)); } nsCOMPtr( const nsGetServiceByCID gs ) : nsCOMPtr_base(0) // assign from |do_GetService(cid_expr)| { NSCAP_LOG_ASSIGNMENT(this, 0); assign_from_gs_cid(gs, NS_GET_IID(nsISupports)); } nsCOMPtr( const nsGetServiceByCIDWithError& gs ) : nsCOMPtr_base(0) // assign from |do_GetService(cid_expr, &rv)| { NSCAP_LOG_ASSIGNMENT(this, 0); assign_from_gs_cid_with_error(gs, NS_GET_IID(nsISupports)); } nsCOMPtr( const nsGetServiceByContractID gs ) : nsCOMPtr_base(0) // assign from |do_GetService(contractid_expr)| { NSCAP_LOG_ASSIGNMENT(this, 0); assign_from_gs_contractid(gs, NS_GET_IID(nsISupports)); } nsCOMPtr( const nsGetServiceByContractIDWithError& gs ) : nsCOMPtr_base(0) // assign from |do_GetService(contractid_expr, &rv)| { NSCAP_LOG_ASSIGNMENT(this, 0); assign_from_gs_contractid_with_error(gs, NS_GET_IID(nsISupports)); } nsCOMPtr( const nsCOMPtr_helper& helper ) : nsCOMPtr_base(0) // ...and finally, anything else we might need to construct from // can exploit the |nsCOMPtr_helper| facility { NSCAP_LOG_ASSIGNMENT(this, 0); assign_from_helper(helper, NS_GET_IID(nsISupports)); } // Assignment operators nsCOMPtr& operator=( const nsCOMPtr& rhs ) // copy assignment operator { assign_with_AddRef(rhs.mRawPtr); return *this; } nsCOMPtr& operator=( nsISupports* rhs ) // assign from a raw pointer (of the right type) { assign_with_AddRef(rhs); return *this; } nsCOMPtr& operator=( const already_AddRefed& rhs ) // assign from |dont_AddRef(expr)| { assign_assuming_AddRef(rhs.mRawPtr); return *this; } nsCOMPtr& operator=( const nsQueryInterface rhs ) // assign from |do_QueryInterface(expr)| { assign_from_qi(rhs, NS_GET_IID(nsISupports)); return *this; } nsCOMPtr& operator=( const nsQueryInterfaceWithError& rhs ) // assign from |do_QueryInterface(expr, &rv)| { assign_from_qi_with_error(rhs, NS_GET_IID(nsISupports)); return *this; } nsCOMPtr& operator=( const nsGetServiceByCID rhs ) // assign from |do_GetService(cid_expr)| { assign_from_gs_cid(rhs, NS_GET_IID(nsISupports)); return *this; } nsCOMPtr& operator=( const nsGetServiceByCIDWithError& rhs ) // assign from |do_GetService(cid_expr, &rv)| { assign_from_gs_cid_with_error(rhs, NS_GET_IID(nsISupports)); return *this; } nsCOMPtr& operator=( const nsGetServiceByContractID rhs ) // assign from |do_GetService(contractid_expr)| { assign_from_gs_contractid(rhs, NS_GET_IID(nsISupports)); return *this; } nsCOMPtr& operator=( const nsGetServiceByContractIDWithError& rhs ) // assign from |do_GetService(contractid_expr, &rv)| { assign_from_gs_contractid_with_error(rhs, NS_GET_IID(nsISupports)); return *this; } nsCOMPtr& operator=( const nsCOMPtr_helper& rhs ) // ...and finally, anything else we might need to assign from // can exploit the |nsCOMPtr_helper| facility. { assign_from_helper(rhs, NS_GET_IID(nsISupports)); return *this; } void swap( nsCOMPtr& rhs ) // ...exchange ownership with |rhs|; can save a pair of refcount operations { nsISupports* temp = rhs.mRawPtr; NSCAP_LOG_ASSIGNMENT(&rhs, mRawPtr); NSCAP_LOG_ASSIGNMENT(this, temp); NSCAP_LOG_RELEASE(this, mRawPtr); NSCAP_LOG_RELEASE(&rhs, temp); rhs.mRawPtr = mRawPtr; mRawPtr = temp; } void swap( nsISupports*& rhs ) // ...exchange ownership with |rhs|; can save a pair of refcount operations { nsISupports* temp = rhs; NSCAP_LOG_ASSIGNMENT(this, temp); NSCAP_LOG_RELEASE(this, mRawPtr); rhs = mRawPtr; mRawPtr = temp; } // Other pointer operators nsISupports* get() const /* Prefer the implicit conversion provided automatically by |operator nsDerivedSafe*() const|. Use |get()| to resolve ambiguity or to get a castable pointer. */ { return NS_REINTERPRET_CAST(nsISupports*, mRawPtr); } operator nsDerivedSafe*() const /* ...makes an |nsCOMPtr| 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 |nsCOMPtr| substitutable for a raw pointer. Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. */ { return get_DerivedSafe(); } nsDerivedSafe* operator->() const { NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator->()."); return get_DerivedSafe(); } #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY // broken version for IRIX nsCOMPtr* get_address() const // This is not intended to be used by clients. See |address_of| // below. { return NS_CONST_CAST(nsCOMPtr*, this); } #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY nsCOMPtr* get_address() // This is not intended to be used by clients. See |address_of| // below. { return this; } const nsCOMPtr* 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 nsCOMPtr with operator*()."); return *get_DerivedSafe(); } #if 0 private: friend class nsGetterAddRefs; #endif nsISupports** StartAssignment() { #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT return NS_REINTERPRET_CAST(nsISupports**, begin_assignment()); #else assign_assuming_AddRef(0); return NS_REINTERPRET_CAST(nsISupports**, &mRawPtr); #endif } private: nsDerivedSafe* get_DerivedSafe() const { return NS_REINTERPRET_CAST(nsDerivedSafe*, mRawPtr); } }; #ifndef NSCAP_FEATURE_USE_BASE template void nsCOMPtr::assign_with_AddRef( nsISupports* rawPtr ) { if ( rawPtr ) NSCAP_ADDREF(this, rawPtr); assign_assuming_AddRef(NS_REINTERPRET_CAST(T*, rawPtr)); } template void nsCOMPtr::assign_from_qi( const nsQueryInterface qi, const nsIID& aIID ) { void* newRawPtr; if ( NS_FAILED( qi(aIID, &newRawPtr) ) ) newRawPtr = 0; assign_assuming_AddRef(NS_STATIC_CAST(T*, newRawPtr)); } template void nsCOMPtr::assign_from_qi_with_error( const nsQueryInterfaceWithError& qi, const nsIID& aIID ) { void* newRawPtr; if ( NS_FAILED( qi(aIID, &newRawPtr) ) ) newRawPtr = 0; assign_assuming_AddRef(NS_STATIC_CAST(T*, newRawPtr)); } template void nsCOMPtr::assign_from_gs_cid( const nsGetServiceByCID gs, const nsIID& aIID ) { void* newRawPtr; if ( NS_FAILED( gs(aIID, &newRawPtr) ) ) newRawPtr = 0; assign_assuming_AddRef(NS_STATIC_CAST(T*, newRawPtr)); } template void nsCOMPtr::assign_from_gs_cid_with_error( const nsGetServiceByCIDWithError& gs, const nsIID& aIID ) { void* newRawPtr; if ( NS_FAILED( gs(aIID, &newRawPtr) ) ) newRawPtr = 0; assign_assuming_AddRef(NS_STATIC_CAST(T*, newRawPtr)); } template void nsCOMPtr::assign_from_gs_contractid( const nsGetServiceByContractID gs, const nsIID& aIID ) { void* newRawPtr; if ( NS_FAILED( gs(aIID, &newRawPtr) ) ) newRawPtr = 0; assign_assuming_AddRef(NS_STATIC_CAST(T*, newRawPtr)); } template void nsCOMPtr::assign_from_gs_contractid_with_error( const nsGetServiceByContractIDWithError& gs, const nsIID& aIID ) { void* newRawPtr; if ( NS_FAILED( gs(aIID, &newRawPtr) ) ) newRawPtr = 0; assign_assuming_AddRef(NS_STATIC_CAST(T*, newRawPtr)); } template void nsCOMPtr::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& aIID ) { void* newRawPtr; if ( NS_FAILED( helper(aIID, &newRawPtr) ) ) newRawPtr = 0; assign_assuming_AddRef(NS_STATIC_CAST(T*, newRawPtr)); } template void** nsCOMPtr::begin_assignment() { assign_assuming_AddRef(0); union { T** mT; void** mVoid; } result; result.mT = &mRawPtr; return result.mVoid; } #endif #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY // This is the broken version for IRIX, which can't handle the version below. template inline nsCOMPtr* address_of( const nsCOMPtr& aPtr ) { return aPtr.get_address(); } #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY template inline nsCOMPtr* address_of( nsCOMPtr& aPtr ) { return aPtr.get_address(); } template inline const nsCOMPtr* address_of( const nsCOMPtr& aPtr ) { return aPtr.get_address(); } #endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY template class nsGetterAddRefs /* ... This class is designed to be used for anonymous temporary objects in the argument list of calls that return COM interface pointers, e.g., nsCOMPtr fooP; ...->QueryInterface(iid, getter_AddRefs(fooP)) DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead. When initialized with a |nsCOMPtr|, as in the example above, it returns a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call (|QueryInterface| in this case) can fill in. This type should be a nested class inside |nsCOMPtr|. */ { public: explicit nsGetterAddRefs( nsCOMPtr& aSmartPtr ) : mTargetSmartPtr(aSmartPtr) { // nothing else to do } #if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT) ~nsGetterAddRefs() { #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT NSCAP_LOG_ASSIGNMENT(NS_REINTERPRET_CAST(void *, address_of(mTargetSmartPtr)), mTargetSmartPtr.get()); #endif #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES mTargetSmartPtr.Assert_NoQueryNeeded(); #endif } #endif operator void**() { return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); } operator nsISupports**() { return NS_REINTERPRET_CAST(nsISupports**, mTargetSmartPtr.StartAssignment()); } operator T**() { return mTargetSmartPtr.StartAssignment(); } T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } private: nsCOMPtr& mTargetSmartPtr; }; NS_SPECIALIZE_TEMPLATE class nsGetterAddRefs { public: explicit nsGetterAddRefs( nsCOMPtr& aSmartPtr ) : mTargetSmartPtr(aSmartPtr) { // nothing else to do } #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT ~nsGetterAddRefs() { NSCAP_LOG_ASSIGNMENT(NS_REINTERPRET_CAST(void *, address_of(mTargetSmartPtr)), mTargetSmartPtr.get()); } #endif operator void**() { return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); } operator nsISupports**() { return mTargetSmartPtr.StartAssignment(); } nsISupports*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } private: nsCOMPtr& mTargetSmartPtr; }; template inline nsGetterAddRefs getter_AddRefs( nsCOMPtr& aSmartPtr ) /* Used around a |nsCOMPtr| when ...makes the class |nsGetterAddRefs| invisible. */ { return nsGetterAddRefs(aSmartPtr); } // Comparing two |nsCOMPtr|s template inline NSCAP_BOOL operator==( const nsCOMPtr& lhs, const nsCOMPtr& rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsCOMPtr& lhs, const nsCOMPtr& rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs.get()); } // Comparing an |nsCOMPtr| to a raw pointer template inline NSCAP_BOOL operator==( const nsCOMPtr& lhs, const U* rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) == rhs; } template inline NSCAP_BOOL operator==( const U* lhs, const nsCOMPtr& rhs ) { return lhs == NS_STATIC_CAST(const T*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsCOMPtr& lhs, const U* rhs ) { return NS_STATIC_CAST(const T*, lhs.get()) != rhs; } template inline NSCAP_BOOL operator!=( const U* lhs, const nsCOMPtr& rhs ) { return 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.) #if defined(_MSC_VER) && (_MSC_VER < 1310) #ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ #define NSCAP_DONT_PROVIDE_NONCONST_OPEQ #endif #endif #ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ template inline NSCAP_BOOL operator==( const nsCOMPtr& 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 nsCOMPtr& rhs ) { return NS_CONST_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsCOMPtr& 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 nsCOMPtr& rhs ) { return NS_CONST_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); } #endif // Comparing an |nsCOMPtr| to |0| class NSCAP_Zero; template inline NSCAP_BOOL operator==( const nsCOMPtr& 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 nsCOMPtr& 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 nsCOMPtr& 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 nsCOMPtr& 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 nsCOMPtr& 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 nsCOMPtr& 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) // Comparing any two [XP]COM objects for identity inline NSCAP_BOOL SameCOMIdentity( nsISupports* lhs, nsISupports* rhs ) { return nsCOMPtr( do_QueryInterface(lhs) ) == nsCOMPtr( do_QueryInterface(rhs) ); } template inline nsresult CallQueryInterface( nsCOMPtr& aSourcePtr, DestinationType** aDestPtr ) { return CallQueryInterface(aSourcePtr.get(), aDestPtr); } #endif // !defined(nsCOMPtr_h___)