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 nsCOMPtr_h___ michael@0: #define nsCOMPtr_h___ michael@0: michael@0: /* michael@0: Having problems? michael@0: michael@0: See the User Manual at: michael@0: http://www.mozilla.org/projects/xpcom/nsCOMPtr.html michael@0: michael@0: michael@0: nsCOMPtr michael@0: better than a raw pointer michael@0: for owning objects michael@0: -- scc michael@0: */ michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/TypeTraits.h" michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/NullPtr.h" michael@0: #include "mozilla/Move.h" michael@0: michael@0: #include "nsDebug.h" // for |NS_ABORT_IF_FALSE|, |NS_ASSERTION| michael@0: #include "nsISupportsUtils.h" // for |nsresult|, |NS_ADDREF|, |NS_GET_TEMPLATE_IID| et al michael@0: #include "nscore.h" // for |NS_COM_GLUE| michael@0: michael@0: #include "nsCycleCollectionNoteChild.h" michael@0: michael@0: michael@0: /* michael@0: WARNING: michael@0: This file defines several macros for internal use only. These macros begin with the michael@0: prefix |NSCAP_|. Do not use these macros in your own code. They are for internal use michael@0: only for cross-platform compatibility, and are subject to change without notice. michael@0: */ michael@0: michael@0: michael@0: #ifdef _MSC_VER michael@0: #define NSCAP_FEATURE_INLINE_STARTASSIGNMENT michael@0: // under VC++, we win by inlining StartAssignment michael@0: michael@0: // Also under VC++, at the highest warning level, we are overwhelmed with warnings michael@0: // about (unused) inline functions being removed. This is to be expected with michael@0: // templates, so we disable the warning. michael@0: #pragma warning( disable: 4514 ) michael@0: #endif michael@0: michael@0: #define NSCAP_FEATURE_USE_BASE michael@0: michael@0: #ifdef DEBUG michael@0: #define NSCAP_FEATURE_TEST_DONTQUERY_CASES michael@0: #undef NSCAP_FEATURE_USE_BASE michael@0: //#define NSCAP_FEATURE_TEST_NONNULL_QUERY_SUCCEEDS michael@0: #endif michael@0: michael@0: #ifdef __GNUC__ michael@0: // Our use of nsCOMPtr_base::mRawPtr violates the C++ standard's aliasing michael@0: // rules. Mark it with the may_alias attribute so that gcc 3.3 and higher michael@0: // don't reorder instructions based on aliasing assumptions for michael@0: // this variable. Fortunately, gcc versions < 3.3 do not do any michael@0: // optimizations that break nsCOMPtr. michael@0: michael@0: #define NS_MAY_ALIAS_PTR(t) t* __attribute__((__may_alias__)) michael@0: #else michael@0: #define NS_MAY_ALIAS_PTR(t) t* michael@0: #endif michael@0: michael@0: #if defined(NSCAP_DISABLE_DEBUG_PTR_TYPES) michael@0: #define NSCAP_FEATURE_USE_BASE michael@0: #endif michael@0: michael@0: /* michael@0: The following three macros (|NSCAP_ADDREF|, |NSCAP_RELEASE|, and |NSCAP_LOG_ASSIGNMENT|) michael@0: allow external clients the ability to add logging or other interesting debug facilities. michael@0: In fact, if you want |nsCOMPtr| to participate in the standard logging facility, you michael@0: provide (e.g., in "nsISupportsImpl.h") suitable definitions michael@0: michael@0: #define NSCAP_ADDREF(this, ptr) NS_ADDREF(ptr) michael@0: #define NSCAP_RELEASE(this, ptr) NS_RELEASE(ptr) michael@0: */ michael@0: michael@0: #ifndef NSCAP_ADDREF michael@0: #define NSCAP_ADDREF(this, ptr) (ptr)->AddRef() michael@0: #endif michael@0: michael@0: #ifndef NSCAP_RELEASE michael@0: #define NSCAP_RELEASE(this, ptr) (ptr)->Release() michael@0: #endif michael@0: michael@0: // Clients can define |NSCAP_LOG_ASSIGNMENT| to perform logging. michael@0: #ifdef NSCAP_LOG_ASSIGNMENT michael@0: // Remember that |NSCAP_LOG_ASSIGNMENT| was defined by some client so that we know michael@0: // to instantiate |~nsGetterAddRefs| in turn to note the external assignment into michael@0: // the |nsCOMPtr|. michael@0: #define NSCAP_LOG_EXTERNAL_ASSIGNMENT michael@0: #else michael@0: // ...otherwise, just strip it out of the code michael@0: #define NSCAP_LOG_ASSIGNMENT(this, ptr) michael@0: #endif michael@0: michael@0: #ifndef NSCAP_LOG_RELEASE michael@0: #define NSCAP_LOG_RELEASE(this, ptr) michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: michael@0: struct unused_t; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: template michael@0: struct already_AddRefed michael@0: /* michael@0: ...cooperates with |nsCOMPtr| to allow you to assign in a pointer _without_ michael@0: |AddRef|ing it. You might want to use this as a return type from a function michael@0: that produces an already |AddRef|ed pointer as a result. michael@0: michael@0: See also |getter_AddRefs()|, |dont_AddRef()|, and |class nsGetterAddRefs|. michael@0: michael@0: This type should be a nested class inside |nsCOMPtr|. michael@0: michael@0: Yes, |already_AddRefed| could have been implemented as an |nsCOMPtr_helper| to michael@0: avoid adding specialized machinery to |nsCOMPtr| ... but this is the simplest michael@0: case, and perhaps worth the savings in time and space that its specific michael@0: implementation affords over the more general solution offered by michael@0: |nsCOMPtr_helper|. michael@0: */ michael@0: { michael@0: /* michael@0: * Prohibit all one-argument overloads but already_AddRefed(T*) and michael@0: * already_AddRefed(decltype(nullptr)), and funnel the nullptr case through michael@0: * the T* constructor. michael@0: */ michael@0: template michael@0: already_AddRefed(N, michael@0: typename mozilla::EnableIf::value, michael@0: int>::Type dummy = 0) michael@0: : mRawPtr(nullptr) michael@0: { michael@0: // nothing else to do here michael@0: } michael@0: michael@0: already_AddRefed( T* aRawPtr ) michael@0: : mRawPtr(aRawPtr) michael@0: { michael@0: // nothing else to do here michael@0: } michael@0: michael@0: // Disallowed. Use move semantics instead. michael@0: already_AddRefed(const already_AddRefed& aOther) MOZ_DELETE; michael@0: michael@0: already_AddRefed(already_AddRefed&& aOther) michael@0: : mRawPtr(aOther.take()) michael@0: { michael@0: // nothing else to do here michael@0: } michael@0: michael@0: ~already_AddRefed() michael@0: { michael@0: MOZ_ASSERT(!mRawPtr); michael@0: } michael@0: michael@0: // Specialize the unused operator<< for already_AddRefed, to allow michael@0: // nsCOMPtr foo; michael@0: // unused << foo.forget(); michael@0: friend void operator<<(const mozilla::unused_t& unused, michael@0: const already_AddRefed& rhs) michael@0: { michael@0: auto mutableAlreadyAddRefed = const_cast*>(&rhs); michael@0: unused << mutableAlreadyAddRefed->take(); michael@0: } michael@0: michael@0: MOZ_WARN_UNUSED_RESULT T* take() michael@0: { michael@0: T* rawPtr = mRawPtr; michael@0: mRawPtr = nullptr; michael@0: return rawPtr; michael@0: } michael@0: michael@0: /** michael@0: * This helper is useful in cases like michael@0: * michael@0: * already_AddRefed michael@0: * Foo() michael@0: * { michael@0: * nsRefPtr x = ...; michael@0: * return x.forget(); michael@0: * } michael@0: * michael@0: * The autoconversion allows one to omit the idiom michael@0: * michael@0: * nsRefPtr y = x.forget(); michael@0: * return y.forget(); michael@0: */ michael@0: template michael@0: operator already_AddRefed() michael@0: { michael@0: U* tmp = mRawPtr; michael@0: mRawPtr = nullptr; michael@0: return already_AddRefed(tmp); michael@0: } michael@0: michael@0: /** michael@0: * This helper provides a static_cast replacement for already_AddRefed, so michael@0: * if you have michael@0: * michael@0: * already_AddRefed F(); michael@0: * michael@0: * you can write michael@0: * michael@0: * already_AddRefed michael@0: * G() michael@0: * { michael@0: * return F().downcast(); michael@0: * } michael@0: * michael@0: * instead of michael@0: * michael@0: * return dont_AddRef(static_cast(F().get())); michael@0: */ michael@0: template michael@0: already_AddRefed downcast() michael@0: { michael@0: U* tmp = static_cast(mRawPtr); michael@0: mRawPtr = nullptr; michael@0: return already_AddRefed(tmp); michael@0: } michael@0: michael@0: private: michael@0: T* mRawPtr; michael@0: }; michael@0: michael@0: template michael@0: inline michael@0: already_AddRefed michael@0: dont_AddRef( T* aRawPtr ) michael@0: { michael@0: return already_AddRefed(aRawPtr); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: already_AddRefed&& michael@0: dont_AddRef( already_AddRefed&& aAlreadyAddRefedPtr ) michael@0: { michael@0: return mozilla::Move(aAlreadyAddRefedPtr); michael@0: } michael@0: michael@0: michael@0: michael@0: class nsCOMPtr_helper michael@0: /* michael@0: An |nsCOMPtr_helper| transforms commonly called getters into typesafe forms michael@0: that are more convenient to call, and more efficient to use with |nsCOMPtr|s. michael@0: Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc. michael@0: michael@0: Here are the rules for a helper: michael@0: - it implements |operator()| to produce an interface pointer michael@0: - (except for its name) |operator()| is a valid [XP]COM `getter' michael@0: - the interface pointer that it returns is already |AddRef()|ed (as from any good getter) michael@0: - it matches the type requested with the supplied |nsIID| argument michael@0: - its constructor provides an optional |nsresult*| that |operator()| can fill michael@0: in with an error when it is executed michael@0: michael@0: See |class nsGetInterface| for an example. michael@0: */ michael@0: { michael@0: public: michael@0: virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const = 0; michael@0: }; michael@0: michael@0: /* michael@0: |nsQueryInterface| could have been implemented as an |nsCOMPtr_helper| to michael@0: avoid adding specialized machinery in |nsCOMPtr|, But |do_QueryInterface| michael@0: is called often enough that the codesize savings are big enough to michael@0: warrant the specialcasing. michael@0: */ michael@0: michael@0: class michael@0: NS_COM_GLUE michael@0: MOZ_STACK_CLASS michael@0: nsQueryInterface MOZ_FINAL michael@0: { michael@0: public: michael@0: explicit michael@0: nsQueryInterface( nsISupports* aRawPtr ) michael@0: : mRawPtr(aRawPtr) michael@0: { michael@0: // nothing else to do here michael@0: } michael@0: michael@0: nsresult NS_FASTCALL operator()( const nsIID& aIID, void** ) const; michael@0: michael@0: private: michael@0: nsISupports* mRawPtr; michael@0: }; michael@0: michael@0: class NS_COM_GLUE nsQueryInterfaceWithError michael@0: { michael@0: public: michael@0: nsQueryInterfaceWithError( nsISupports* aRawPtr, nsresult* error ) michael@0: : mRawPtr(aRawPtr), michael@0: mErrorPtr(error) michael@0: { michael@0: // nothing else to do here michael@0: } michael@0: michael@0: nsresult NS_FASTCALL operator()( const nsIID& aIID, void** ) const; michael@0: michael@0: private: michael@0: nsISupports* mRawPtr; michael@0: nsresult* mErrorPtr; michael@0: }; michael@0: michael@0: inline michael@0: nsQueryInterface michael@0: do_QueryInterface( nsISupports* aRawPtr ) michael@0: { michael@0: return nsQueryInterface(aRawPtr); michael@0: } michael@0: michael@0: inline michael@0: nsQueryInterfaceWithError michael@0: do_QueryInterface( nsISupports* aRawPtr, nsresult* error ) michael@0: { michael@0: return nsQueryInterfaceWithError(aRawPtr, error); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: void michael@0: do_QueryInterface( already_AddRefed& ) michael@0: { michael@0: // This signature exists solely to _stop_ you from doing the bad thing. michael@0: // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by michael@0: // someone else is an automatic leak. See . michael@0: } michael@0: michael@0: template michael@0: inline michael@0: void michael@0: do_QueryInterface( already_AddRefed&, nsresult* ) michael@0: { michael@0: // This signature exists solely to _stop_ you from doing the bad thing. michael@0: // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by michael@0: // someone else is an automatic leak. See . michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////// michael@0: // Using servicemanager with COMPtrs michael@0: class NS_COM_GLUE nsGetServiceByCID michael@0: { michael@0: public: michael@0: explicit nsGetServiceByCID(const nsCID& aCID) michael@0: : mCID(aCID) michael@0: { michael@0: // nothing else to do michael@0: } michael@0: michael@0: nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; michael@0: michael@0: private: michael@0: const nsCID& mCID; michael@0: }; michael@0: michael@0: class NS_COM_GLUE nsGetServiceByCIDWithError michael@0: { michael@0: public: michael@0: nsGetServiceByCIDWithError( const nsCID& aCID, nsresult* aErrorPtr ) michael@0: : mCID(aCID), michael@0: mErrorPtr(aErrorPtr) michael@0: { michael@0: // nothing else to do michael@0: } michael@0: michael@0: nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; michael@0: michael@0: private: michael@0: const nsCID& mCID; michael@0: nsresult* mErrorPtr; michael@0: }; michael@0: michael@0: class NS_COM_GLUE nsGetServiceByContractID michael@0: { michael@0: public: michael@0: explicit nsGetServiceByContractID(const char* aContractID) michael@0: : mContractID(aContractID) michael@0: { michael@0: // nothing else to do michael@0: } michael@0: michael@0: nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; michael@0: michael@0: private: michael@0: const char* mContractID; michael@0: }; michael@0: michael@0: class NS_COM_GLUE nsGetServiceByContractIDWithError michael@0: { michael@0: public: michael@0: nsGetServiceByContractIDWithError(const char* aContractID, nsresult* aErrorPtr) michael@0: : mContractID(aContractID), michael@0: mErrorPtr(aErrorPtr) michael@0: { michael@0: // nothing else to do michael@0: } michael@0: michael@0: nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; michael@0: michael@0: private: michael@0: const char* mContractID; michael@0: nsresult* mErrorPtr; michael@0: }; michael@0: michael@0: class michael@0: nsCOMPtr_base michael@0: /* michael@0: ...factors implementation for all template versions of |nsCOMPtr|. michael@0: michael@0: This should really be an |nsCOMPtr|, but this wouldn't work michael@0: because unlike the michael@0: michael@0: Here's the way people normally do things like this michael@0: michael@0: template class Foo { ... }; michael@0: template <> class Foo { ... }; michael@0: template class Foo : private Foo { ... }; michael@0: */ michael@0: { michael@0: public: michael@0: michael@0: nsCOMPtr_base( nsISupports* rawPtr = 0 ) michael@0: : mRawPtr(rawPtr) michael@0: { michael@0: // nothing else to do here michael@0: } michael@0: michael@0: NS_COM_GLUE NS_CONSTRUCTOR_FASTCALL ~nsCOMPtr_base() michael@0: { michael@0: NSCAP_LOG_RELEASE(this, mRawPtr); michael@0: if ( mRawPtr ) michael@0: NSCAP_RELEASE(this, mRawPtr); michael@0: } michael@0: michael@0: NS_COM_GLUE void NS_FASTCALL assign_with_AddRef( nsISupports* ); michael@0: NS_COM_GLUE void NS_FASTCALL assign_from_qi( const nsQueryInterface, const nsIID& ); michael@0: NS_COM_GLUE void NS_FASTCALL assign_from_qi_with_error( const nsQueryInterfaceWithError&, const nsIID& ); michael@0: NS_COM_GLUE void NS_FASTCALL assign_from_gs_cid( const nsGetServiceByCID, const nsIID& ); michael@0: NS_COM_GLUE void NS_FASTCALL assign_from_gs_cid_with_error( const nsGetServiceByCIDWithError&, const nsIID& ); michael@0: NS_COM_GLUE void NS_FASTCALL assign_from_gs_contractid( const nsGetServiceByContractID, const nsIID& ); michael@0: NS_COM_GLUE void NS_FASTCALL assign_from_gs_contractid_with_error( const nsGetServiceByContractIDWithError&, const nsIID& ); michael@0: NS_COM_GLUE void NS_FASTCALL assign_from_helper( const nsCOMPtr_helper&, const nsIID& ); michael@0: NS_COM_GLUE void** NS_FASTCALL begin_assignment(); michael@0: michael@0: protected: michael@0: NS_MAY_ALIAS_PTR(nsISupports) mRawPtr; michael@0: michael@0: void michael@0: assign_assuming_AddRef( nsISupports* newPtr ) michael@0: { michael@0: /* michael@0: |AddRef()|ing the new value (before entering this function) before michael@0: |Release()|ing the old lets us safely ignore the self-assignment case. michael@0: We must, however, be careful only to |Release()| _after_ doing the michael@0: assignment, in case the |Release()| leads to our _own_ destruction, michael@0: which would, in turn, cause an incorrect second |Release()| of our old michael@0: pointer. Thank for discovering this. michael@0: */ michael@0: nsISupports* oldPtr = mRawPtr; michael@0: mRawPtr = newPtr; michael@0: NSCAP_LOG_ASSIGNMENT(this, newPtr); michael@0: NSCAP_LOG_RELEASE(this, oldPtr); michael@0: if ( oldPtr ) michael@0: NSCAP_RELEASE(this, oldPtr); michael@0: } michael@0: }; michael@0: michael@0: // template class nsGetterAddRefs; michael@0: michael@0: template michael@0: class nsCOMPtr MOZ_FINAL michael@0: #ifdef NSCAP_FEATURE_USE_BASE michael@0: : private nsCOMPtr_base michael@0: #endif michael@0: { michael@0: michael@0: #ifdef NSCAP_FEATURE_USE_BASE michael@0: #define NSCAP_CTOR_BASE(x) nsCOMPtr_base(x) michael@0: #else michael@0: #define NSCAP_CTOR_BASE(x) mRawPtr(x) michael@0: michael@0: private: michael@0: void assign_with_AddRef( nsISupports* ); michael@0: void assign_from_qi( const nsQueryInterface, const nsIID& ); michael@0: void assign_from_qi_with_error( const nsQueryInterfaceWithError&, const nsIID& ); michael@0: void assign_from_gs_cid( const nsGetServiceByCID, const nsIID& ); michael@0: void assign_from_gs_cid_with_error( const nsGetServiceByCIDWithError&, const nsIID& ); michael@0: void assign_from_gs_contractid( const nsGetServiceByContractID, const nsIID& ); michael@0: void assign_from_gs_contractid_with_error( const nsGetServiceByContractIDWithError&, const nsIID& ); michael@0: void assign_from_helper( const nsCOMPtr_helper&, const nsIID& ); michael@0: void** begin_assignment(); 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: NSCAP_LOG_ASSIGNMENT(this, newPtr); michael@0: NSCAP_LOG_RELEASE(this, oldPtr); michael@0: if ( oldPtr ) michael@0: NSCAP_RELEASE(this, oldPtr); michael@0: } michael@0: michael@0: private: michael@0: T* mRawPtr; michael@0: #endif michael@0: michael@0: public: michael@0: typedef T element_type; michael@0: michael@0: #ifndef NSCAP_FEATURE_USE_BASE michael@0: ~nsCOMPtr() michael@0: { michael@0: NSCAP_LOG_RELEASE(this, mRawPtr); michael@0: if ( mRawPtr ) michael@0: NSCAP_RELEASE(this, mRawPtr); michael@0: } michael@0: #endif michael@0: michael@0: #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES michael@0: void michael@0: Assert_NoQueryNeeded() michael@0: { michael@0: if ( mRawPtr ) michael@0: { michael@0: nsCOMPtr query_result( do_QueryInterface(mRawPtr) ); michael@0: NS_ASSERTION(query_result.get() == mRawPtr, "QueryInterface needed"); michael@0: } michael@0: } michael@0: michael@0: #define NSCAP_ASSERT_NO_QUERY_NEEDED() Assert_NoQueryNeeded(); michael@0: #else michael@0: #define NSCAP_ASSERT_NO_QUERY_NEEDED() michael@0: #endif michael@0: michael@0: michael@0: // Constructors michael@0: michael@0: nsCOMPtr() michael@0: : NSCAP_CTOR_BASE(0) michael@0: // default constructor michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: } michael@0: michael@0: nsCOMPtr( const nsCOMPtr& aSmartPtr ) michael@0: : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) michael@0: // copy-constructor michael@0: { michael@0: if ( mRawPtr ) michael@0: NSCAP_ADDREF(this, mRawPtr); michael@0: NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr); michael@0: } michael@0: michael@0: nsCOMPtr( T* aRawPtr ) michael@0: : NSCAP_CTOR_BASE(aRawPtr) michael@0: // construct from a raw pointer (of the right type) michael@0: { michael@0: if ( mRawPtr ) michael@0: NSCAP_ADDREF(this, mRawPtr); michael@0: NSCAP_LOG_ASSIGNMENT(this, aRawPtr); michael@0: NSCAP_ASSERT_NO_QUERY_NEEDED(); michael@0: } michael@0: michael@0: nsCOMPtr( already_AddRefed& aSmartPtr ) michael@0: : NSCAP_CTOR_BASE(aSmartPtr.take()) michael@0: // construct from |already_AddRefed| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, mRawPtr); michael@0: NSCAP_ASSERT_NO_QUERY_NEEDED(); michael@0: } michael@0: michael@0: nsCOMPtr( already_AddRefed&& aSmartPtr ) michael@0: : NSCAP_CTOR_BASE(aSmartPtr.take()) michael@0: // construct from |otherComPtr.forget()| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, mRawPtr); michael@0: NSCAP_ASSERT_NO_QUERY_NEEDED(); michael@0: } michael@0: michael@0: template michael@0: nsCOMPtr( already_AddRefed& aSmartPtr ) michael@0: : NSCAP_CTOR_BASE(static_cast(aSmartPtr.take())) michael@0: // construct from |already_AddRefed| michael@0: { michael@0: // But make sure that U actually inherits from T michael@0: static_assert(mozilla::IsBaseOf::value, michael@0: "U is not a subclass of T"); michael@0: NSCAP_LOG_ASSIGNMENT(this, static_cast(mRawPtr)); michael@0: NSCAP_ASSERT_NO_QUERY_NEEDED(); michael@0: } michael@0: michael@0: template michael@0: nsCOMPtr( already_AddRefed&& aSmartPtr ) michael@0: : NSCAP_CTOR_BASE(static_cast(aSmartPtr.take())) michael@0: // construct from |otherComPtr.forget()| michael@0: { michael@0: // But make sure that U actually inherits from T michael@0: static_assert(mozilla::IsBaseOf::value, michael@0: "U is not a subclass of T"); michael@0: NSCAP_LOG_ASSIGNMENT(this, static_cast(mRawPtr)); michael@0: NSCAP_ASSERT_NO_QUERY_NEEDED(); michael@0: } michael@0: michael@0: nsCOMPtr( const nsQueryInterface qi ) michael@0: : NSCAP_CTOR_BASE(0) michael@0: // construct from |do_QueryInterface(expr)| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: assign_from_qi(qi, NS_GET_TEMPLATE_IID(T)); michael@0: } michael@0: michael@0: nsCOMPtr( const nsQueryInterfaceWithError& qi ) michael@0: : NSCAP_CTOR_BASE(0) michael@0: // construct from |do_QueryInterface(expr, &rv)| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: assign_from_qi_with_error(qi, NS_GET_TEMPLATE_IID(T)); michael@0: } michael@0: michael@0: nsCOMPtr( const nsGetServiceByCID gs ) michael@0: : NSCAP_CTOR_BASE(0) michael@0: // construct from |do_GetService(cid_expr)| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: assign_from_gs_cid(gs, NS_GET_TEMPLATE_IID(T)); michael@0: } michael@0: michael@0: nsCOMPtr( const nsGetServiceByCIDWithError& gs ) michael@0: : NSCAP_CTOR_BASE(0) michael@0: // construct from |do_GetService(cid_expr, &rv)| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: assign_from_gs_cid_with_error(gs, NS_GET_TEMPLATE_IID(T)); michael@0: } michael@0: michael@0: nsCOMPtr( const nsGetServiceByContractID gs ) michael@0: : NSCAP_CTOR_BASE(0) michael@0: // construct from |do_GetService(contractid_expr)| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: assign_from_gs_contractid(gs, NS_GET_TEMPLATE_IID(T)); michael@0: } michael@0: michael@0: nsCOMPtr( const nsGetServiceByContractIDWithError& gs ) michael@0: : NSCAP_CTOR_BASE(0) michael@0: // construct from |do_GetService(contractid_expr, &rv)| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: assign_from_gs_contractid_with_error(gs, NS_GET_TEMPLATE_IID(T)); michael@0: } michael@0: michael@0: nsCOMPtr( const nsCOMPtr_helper& helper ) michael@0: : NSCAP_CTOR_BASE(0) michael@0: // ...and finally, anything else we might need to construct from michael@0: // can exploit the |nsCOMPtr_helper| facility michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: assign_from_helper(helper, NS_GET_TEMPLATE_IID(T)); michael@0: NSCAP_ASSERT_NO_QUERY_NEEDED(); michael@0: } michael@0: michael@0: michael@0: // Assignment operators michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsCOMPtr& 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: nsCOMPtr& 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: NSCAP_ASSERT_NO_QUERY_NEEDED(); michael@0: return *this; michael@0: } michael@0: michael@0: template michael@0: nsCOMPtr& michael@0: operator=( already_AddRefed& rhs ) michael@0: // assign from |already_AddRefed| michael@0: { michael@0: // Make sure that U actually inherits from T michael@0: static_assert(mozilla::IsBaseOf::value, michael@0: "U is not a subclass of T"); michael@0: assign_assuming_AddRef(static_cast(rhs.take())); michael@0: NSCAP_ASSERT_NO_QUERY_NEEDED(); michael@0: return *this; michael@0: } michael@0: michael@0: template michael@0: nsCOMPtr& michael@0: operator=( already_AddRefed&& rhs ) michael@0: // assign from |otherComPtr.forget()| michael@0: { michael@0: // Make sure that U actually inherits from T michael@0: static_assert(mozilla::IsBaseOf::value, michael@0: "U is not a subclass of T"); michael@0: assign_assuming_AddRef(static_cast(rhs.take())); michael@0: NSCAP_ASSERT_NO_QUERY_NEEDED(); michael@0: return *this; michael@0: } michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsQueryInterface rhs ) michael@0: // assign from |do_QueryInterface(expr)| michael@0: { michael@0: assign_from_qi(rhs, NS_GET_TEMPLATE_IID(T)); michael@0: return *this; michael@0: } michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsQueryInterfaceWithError& rhs ) michael@0: // assign from |do_QueryInterface(expr, &rv)| michael@0: { michael@0: assign_from_qi_with_error(rhs, NS_GET_TEMPLATE_IID(T)); michael@0: return *this; michael@0: } michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsGetServiceByCID rhs ) michael@0: // assign from |do_GetService(cid_expr)| michael@0: { michael@0: assign_from_gs_cid(rhs, NS_GET_TEMPLATE_IID(T)); michael@0: return *this; michael@0: } michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsGetServiceByCIDWithError& rhs ) michael@0: // assign from |do_GetService(cid_expr, &rv)| michael@0: { michael@0: assign_from_gs_cid_with_error(rhs, NS_GET_TEMPLATE_IID(T)); michael@0: return *this; michael@0: } michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsGetServiceByContractID rhs ) michael@0: // assign from |do_GetService(contractid_expr)| michael@0: { michael@0: assign_from_gs_contractid(rhs, NS_GET_TEMPLATE_IID(T)); michael@0: return *this; michael@0: } michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsGetServiceByContractIDWithError& rhs ) michael@0: // assign from |do_GetService(contractid_expr, &rv)| michael@0: { michael@0: assign_from_gs_contractid_with_error(rhs, NS_GET_TEMPLATE_IID(T)); michael@0: return *this; michael@0: } michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsCOMPtr_helper& rhs ) michael@0: // ...and finally, anything else we might need to assign from michael@0: // can exploit the |nsCOMPtr_helper| facility. michael@0: { michael@0: assign_from_helper(rhs, NS_GET_TEMPLATE_IID(T)); michael@0: NSCAP_ASSERT_NO_QUERY_NEEDED(); michael@0: return *this; michael@0: } michael@0: michael@0: void michael@0: swap( nsCOMPtr& rhs ) michael@0: // ...exchange ownership with |rhs|; can save a pair of refcount operations michael@0: { michael@0: #ifdef NSCAP_FEATURE_USE_BASE michael@0: nsISupports* temp = rhs.mRawPtr; michael@0: #else michael@0: T* temp = rhs.mRawPtr; michael@0: #endif michael@0: NSCAP_LOG_ASSIGNMENT(&rhs, mRawPtr); michael@0: NSCAP_LOG_ASSIGNMENT(this, temp); michael@0: NSCAP_LOG_RELEASE(this, mRawPtr); michael@0: NSCAP_LOG_RELEASE(&rhs, temp); michael@0: rhs.mRawPtr = mRawPtr; michael@0: mRawPtr = temp; michael@0: // |rhs| maintains the same invariants, so we don't need to |NSCAP_ASSERT_NO_QUERY_NEEDED| 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: #ifdef NSCAP_FEATURE_USE_BASE michael@0: nsISupports* temp = rhs; michael@0: #else michael@0: T* temp = rhs; michael@0: #endif michael@0: NSCAP_LOG_ASSIGNMENT(this, temp); michael@0: NSCAP_LOG_RELEASE(this, mRawPtr); michael@0: rhs = reinterpret_cast(mRawPtr); michael@0: mRawPtr = temp; michael@0: NSCAP_ASSERT_NO_QUERY_NEEDED(); michael@0: } michael@0: michael@0: michael@0: // Other pointer operators 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: NSCAP_LOG_RELEASE(this, mRawPtr); michael@0: *rhs = get(); 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 reinterpret_cast(mRawPtr); michael@0: } michael@0: michael@0: operator T*() const michael@0: /* michael@0: ...makes an |nsCOMPtr| 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 |nsCOMPtr| 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_ABORT_IF_FALSE(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator->()."); michael@0: return get(); michael@0: } michael@0: michael@0: nsCOMPtr* 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 nsCOMPtr* 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_ABORT_IF_FALSE(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr 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: michael@0: michael@0: /* michael@0: Specializing |nsCOMPtr| for |nsISupports| allows us to use |nsCOMPtr| the michael@0: same way people use |nsISupports*| and |void*|, i.e., as a `catch-all' pointer pointing michael@0: to any valid [XP]COM interface. Otherwise, an |nsCOMPtr| would only be able michael@0: to point to the single [XP]COM-correct |nsISupports| instance within an object; extra michael@0: querying ensues. Clients need to be able to pass around arbitrary interface pointers, michael@0: without hassles, through intermediary code that doesn't know the exact type. michael@0: */ michael@0: michael@0: template <> michael@0: class nsCOMPtr michael@0: : private nsCOMPtr_base michael@0: { michael@0: public: michael@0: typedef nsISupports element_type; michael@0: michael@0: // Constructors michael@0: michael@0: nsCOMPtr() michael@0: : nsCOMPtr_base(0) michael@0: // default constructor michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: } michael@0: michael@0: nsCOMPtr( const nsCOMPtr& aSmartPtr ) michael@0: : nsCOMPtr_base(aSmartPtr.mRawPtr) michael@0: // copy constructor michael@0: { michael@0: if ( mRawPtr ) michael@0: NSCAP_ADDREF(this, mRawPtr); michael@0: NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr); michael@0: } michael@0: michael@0: nsCOMPtr( nsISupports* aRawPtr ) michael@0: : nsCOMPtr_base(aRawPtr) michael@0: // construct from a raw pointer (of the right type) michael@0: { michael@0: if ( mRawPtr ) michael@0: NSCAP_ADDREF(this, mRawPtr); michael@0: NSCAP_LOG_ASSIGNMENT(this, aRawPtr); michael@0: } michael@0: michael@0: nsCOMPtr( already_AddRefed& aSmartPtr ) michael@0: : nsCOMPtr_base(aSmartPtr.take()) michael@0: // construct from |already_AddRefed| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, mRawPtr); michael@0: } michael@0: michael@0: nsCOMPtr( already_AddRefed&& aSmartPtr ) michael@0: : nsCOMPtr_base(aSmartPtr.take()) michael@0: // construct from |otherComPtr.forget()| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, mRawPtr); michael@0: } michael@0: michael@0: nsCOMPtr( const nsQueryInterface qi ) michael@0: : nsCOMPtr_base(0) michael@0: // assign from |do_QueryInterface(expr)| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: assign_from_qi(qi, NS_GET_IID(nsISupports)); michael@0: } michael@0: michael@0: nsCOMPtr( const nsQueryInterfaceWithError& qi ) michael@0: : nsCOMPtr_base(0) michael@0: // assign from |do_QueryInterface(expr, &rv)| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: assign_from_qi_with_error(qi, NS_GET_IID(nsISupports)); michael@0: } michael@0: michael@0: nsCOMPtr( const nsGetServiceByCID gs ) michael@0: : nsCOMPtr_base(0) michael@0: // assign from |do_GetService(cid_expr)| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: assign_from_gs_cid(gs, NS_GET_IID(nsISupports)); michael@0: } michael@0: michael@0: nsCOMPtr( const nsGetServiceByCIDWithError& gs ) michael@0: : nsCOMPtr_base(0) michael@0: // assign from |do_GetService(cid_expr, &rv)| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: assign_from_gs_cid_with_error(gs, NS_GET_IID(nsISupports)); michael@0: } michael@0: michael@0: nsCOMPtr( const nsGetServiceByContractID gs ) michael@0: : nsCOMPtr_base(0) michael@0: // assign from |do_GetService(contractid_expr)| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: assign_from_gs_contractid(gs, NS_GET_IID(nsISupports)); michael@0: } michael@0: michael@0: nsCOMPtr( const nsGetServiceByContractIDWithError& gs ) michael@0: : nsCOMPtr_base(0) michael@0: // assign from |do_GetService(contractid_expr, &rv)| michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: assign_from_gs_contractid_with_error(gs, NS_GET_IID(nsISupports)); michael@0: } michael@0: michael@0: nsCOMPtr( const nsCOMPtr_helper& helper ) michael@0: : nsCOMPtr_base(0) michael@0: // ...and finally, anything else we might need to construct from michael@0: // can exploit the |nsCOMPtr_helper| facility michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(this, 0); michael@0: assign_from_helper(helper, NS_GET_IID(nsISupports)); michael@0: } michael@0: michael@0: michael@0: // Assignment operators michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsCOMPtr& 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: nsCOMPtr& michael@0: operator=( nsISupports* 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: nsCOMPtr& 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: nsCOMPtr& michael@0: operator=( already_AddRefed&& rhs ) michael@0: // assign from |otherComPtr.forget()| michael@0: { michael@0: assign_assuming_AddRef(rhs.take()); michael@0: return *this; michael@0: } michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsQueryInterface rhs ) michael@0: // assign from |do_QueryInterface(expr)| michael@0: { michael@0: assign_from_qi(rhs, NS_GET_IID(nsISupports)); michael@0: return *this; michael@0: } michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsQueryInterfaceWithError& rhs ) michael@0: // assign from |do_QueryInterface(expr, &rv)| michael@0: { michael@0: assign_from_qi_with_error(rhs, NS_GET_IID(nsISupports)); michael@0: return *this; michael@0: } michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsGetServiceByCID rhs ) michael@0: // assign from |do_GetService(cid_expr)| michael@0: { michael@0: assign_from_gs_cid(rhs, NS_GET_IID(nsISupports)); michael@0: return *this; michael@0: } michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsGetServiceByCIDWithError& rhs ) michael@0: // assign from |do_GetService(cid_expr, &rv)| michael@0: { michael@0: assign_from_gs_cid_with_error(rhs, NS_GET_IID(nsISupports)); michael@0: return *this; michael@0: } michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsGetServiceByContractID rhs ) michael@0: // assign from |do_GetService(contractid_expr)| michael@0: { michael@0: assign_from_gs_contractid(rhs, NS_GET_IID(nsISupports)); michael@0: return *this; michael@0: } michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsGetServiceByContractIDWithError& rhs ) michael@0: // assign from |do_GetService(contractid_expr, &rv)| michael@0: { michael@0: assign_from_gs_contractid_with_error(rhs, NS_GET_IID(nsISupports)); michael@0: return *this; michael@0: } michael@0: michael@0: nsCOMPtr& michael@0: operator=( const nsCOMPtr_helper& rhs ) michael@0: // ...and finally, anything else we might need to assign from michael@0: // can exploit the |nsCOMPtr_helper| facility. michael@0: { michael@0: assign_from_helper(rhs, NS_GET_IID(nsISupports)); michael@0: return *this; michael@0: } michael@0: michael@0: void michael@0: swap( nsCOMPtr& rhs ) michael@0: // ...exchange ownership with |rhs|; can save a pair of refcount operations michael@0: { michael@0: nsISupports* temp = rhs.mRawPtr; michael@0: NSCAP_LOG_ASSIGNMENT(&rhs, mRawPtr); michael@0: NSCAP_LOG_ASSIGNMENT(this, temp); michael@0: NSCAP_LOG_RELEASE(this, mRawPtr); michael@0: NSCAP_LOG_RELEASE(&rhs, temp); michael@0: rhs.mRawPtr = mRawPtr; michael@0: mRawPtr = temp; michael@0: } michael@0: michael@0: void michael@0: swap( nsISupports*& rhs ) michael@0: // ...exchange ownership with |rhs|; can save a pair of refcount operations michael@0: { michael@0: nsISupports* temp = rhs; michael@0: NSCAP_LOG_ASSIGNMENT(this, temp); michael@0: NSCAP_LOG_RELEASE(this, mRawPtr); 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: nsISupports* temp = 0; michael@0: swap(temp); michael@0: return already_AddRefed(temp); michael@0: } michael@0: michael@0: void michael@0: forget( nsISupports** 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. michael@0: { michael@0: NS_ASSERTION(rhs, "Null pointer passed to forget!"); michael@0: *rhs = 0; michael@0: swap(*rhs); michael@0: } michael@0: michael@0: // Other pointer operators michael@0: michael@0: nsISupports* michael@0: get() const michael@0: /* michael@0: Prefer the implicit conversion provided automatically by michael@0: |operator nsISupports*() const|. michael@0: Use |get()| to resolve ambiguity or to get a castable pointer. michael@0: */ michael@0: { michael@0: return reinterpret_cast(mRawPtr); michael@0: } michael@0: michael@0: operator nsISupports*() const michael@0: /* michael@0: ...makes an |nsCOMPtr| 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 |nsCOMPtr| 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: nsISupports* michael@0: operator->() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator->()."); michael@0: return get(); michael@0: } michael@0: michael@0: nsCOMPtr* 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 nsCOMPtr* 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: michael@0: nsISupports& michael@0: operator*() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator*()."); michael@0: return *get(); michael@0: } michael@0: michael@0: nsISupports** 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(nsCOMPtr& 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: nsCOMPtr& 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: #ifndef NSCAP_FEATURE_USE_BASE michael@0: template michael@0: void michael@0: nsCOMPtr::assign_with_AddRef( nsISupports* rawPtr ) michael@0: { michael@0: if ( rawPtr ) michael@0: NSCAP_ADDREF(this, rawPtr); michael@0: assign_assuming_AddRef(reinterpret_cast(rawPtr)); michael@0: } michael@0: michael@0: template michael@0: void michael@0: nsCOMPtr::assign_from_qi( const nsQueryInterface qi, const nsIID& aIID ) michael@0: { michael@0: void* newRawPtr; michael@0: if ( NS_FAILED( qi(aIID, &newRawPtr) ) ) michael@0: newRawPtr = 0; michael@0: assign_assuming_AddRef(static_cast(newRawPtr)); michael@0: } michael@0: michael@0: template michael@0: void michael@0: nsCOMPtr::assign_from_qi_with_error( const nsQueryInterfaceWithError& qi, const nsIID& aIID ) michael@0: { michael@0: void* newRawPtr; michael@0: if ( NS_FAILED( qi(aIID, &newRawPtr) ) ) michael@0: newRawPtr = 0; michael@0: assign_assuming_AddRef(static_cast(newRawPtr)); michael@0: } michael@0: michael@0: template michael@0: void michael@0: nsCOMPtr::assign_from_gs_cid( const nsGetServiceByCID gs, const nsIID& aIID ) michael@0: { michael@0: void* newRawPtr; michael@0: if ( NS_FAILED( gs(aIID, &newRawPtr) ) ) michael@0: newRawPtr = 0; michael@0: assign_assuming_AddRef(static_cast(newRawPtr)); michael@0: } michael@0: michael@0: template michael@0: void michael@0: nsCOMPtr::assign_from_gs_cid_with_error( const nsGetServiceByCIDWithError& gs, const nsIID& aIID ) michael@0: { michael@0: void* newRawPtr; michael@0: if ( NS_FAILED( gs(aIID, &newRawPtr) ) ) michael@0: newRawPtr = 0; michael@0: assign_assuming_AddRef(static_cast(newRawPtr)); michael@0: } michael@0: michael@0: template michael@0: void michael@0: nsCOMPtr::assign_from_gs_contractid( const nsGetServiceByContractID gs, const nsIID& aIID ) michael@0: { michael@0: void* newRawPtr; michael@0: if ( NS_FAILED( gs(aIID, &newRawPtr) ) ) michael@0: newRawPtr = 0; michael@0: assign_assuming_AddRef(static_cast(newRawPtr)); michael@0: } michael@0: michael@0: template michael@0: void michael@0: nsCOMPtr::assign_from_gs_contractid_with_error( const nsGetServiceByContractIDWithError& gs, const nsIID& aIID ) michael@0: { michael@0: void* newRawPtr; michael@0: if ( NS_FAILED( gs(aIID, &newRawPtr) ) ) michael@0: newRawPtr = 0; michael@0: assign_assuming_AddRef(static_cast(newRawPtr)); michael@0: } michael@0: michael@0: template michael@0: void michael@0: nsCOMPtr::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& aIID ) michael@0: { michael@0: void* newRawPtr; michael@0: if ( NS_FAILED( helper(aIID, &newRawPtr) ) ) michael@0: newRawPtr = 0; michael@0: assign_assuming_AddRef(static_cast(newRawPtr)); michael@0: } michael@0: michael@0: template michael@0: void** michael@0: nsCOMPtr::begin_assignment() michael@0: { michael@0: assign_assuming_AddRef(0); michael@0: union { T** mT; void** mVoid; } result; michael@0: result.mT = &mRawPtr; michael@0: return result.mVoid; michael@0: } michael@0: #endif michael@0: michael@0: template michael@0: inline michael@0: nsCOMPtr* michael@0: address_of( nsCOMPtr& aPtr ) michael@0: { michael@0: return aPtr.get_address(); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: const nsCOMPtr* michael@0: address_of( const nsCOMPtr& aPtr ) michael@0: { michael@0: return aPtr.get_address(); michael@0: } michael@0: michael@0: template michael@0: class nsGetterAddRefs 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: nsCOMPtr fooP; michael@0: ...->QueryInterface(iid, 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 |nsCOMPtr|, as in the example above, it returns michael@0: a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call (|QueryInterface| in this michael@0: case) can fill in. michael@0: michael@0: This type should be a nested class inside |nsCOMPtr|. michael@0: */ michael@0: { michael@0: public: michael@0: explicit michael@0: nsGetterAddRefs( nsCOMPtr& aSmartPtr ) michael@0: : mTargetSmartPtr(aSmartPtr) michael@0: { michael@0: // nothing else to do michael@0: } michael@0: michael@0: #if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT) michael@0: ~nsGetterAddRefs() michael@0: { michael@0: #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT michael@0: NSCAP_LOG_ASSIGNMENT(reinterpret_cast(address_of(mTargetSmartPtr)), mTargetSmartPtr.get()); michael@0: #endif michael@0: michael@0: #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES michael@0: mTargetSmartPtr.Assert_NoQueryNeeded(); michael@0: #endif michael@0: } michael@0: #endif michael@0: michael@0: operator void**() michael@0: { michael@0: return reinterpret_cast(mTargetSmartPtr.StartAssignment()); 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: nsCOMPtr& mTargetSmartPtr; michael@0: }; michael@0: michael@0: michael@0: template <> michael@0: class nsGetterAddRefs michael@0: { michael@0: public: michael@0: explicit michael@0: nsGetterAddRefs( nsCOMPtr& aSmartPtr ) michael@0: : mTargetSmartPtr(aSmartPtr) michael@0: { michael@0: // nothing else to do michael@0: } michael@0: michael@0: #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT michael@0: ~nsGetterAddRefs() michael@0: { michael@0: NSCAP_LOG_ASSIGNMENT(reinterpret_cast(address_of(mTargetSmartPtr)), mTargetSmartPtr.get()); michael@0: } michael@0: #endif michael@0: michael@0: operator void**() michael@0: { michael@0: return reinterpret_cast(mTargetSmartPtr.StartAssignment()); michael@0: } michael@0: michael@0: operator nsISupports**() michael@0: { michael@0: return mTargetSmartPtr.StartAssignment(); michael@0: } michael@0: michael@0: nsISupports*& michael@0: operator*() michael@0: { michael@0: return *(mTargetSmartPtr.StartAssignment()); michael@0: } michael@0: michael@0: private: michael@0: nsCOMPtr& mTargetSmartPtr; michael@0: }; michael@0: michael@0: michael@0: template michael@0: inline michael@0: nsGetterAddRefs michael@0: getter_AddRefs( nsCOMPtr& aSmartPtr ) michael@0: /* michael@0: Used around a |nsCOMPtr| when michael@0: ...makes the class |nsGetterAddRefs| invisible. michael@0: */ michael@0: { michael@0: return nsGetterAddRefs(aSmartPtr); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: nsresult michael@0: CallQueryInterface( T* aSource, nsGetterAddRefs aDestination ) michael@0: { michael@0: return CallQueryInterface(aSource, michael@0: static_cast(aDestination)); michael@0: } michael@0: michael@0: michael@0: // Comparing two |nsCOMPtr|s michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsCOMPtr& lhs, const nsCOMPtr& 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 nsCOMPtr& lhs, const nsCOMPtr& rhs ) michael@0: { michael@0: return static_cast(lhs.get()) != static_cast(rhs.get()); michael@0: } michael@0: michael@0: michael@0: // Comparing an |nsCOMPtr| to a raw pointer michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsCOMPtr& lhs, const U* rhs ) michael@0: { michael@0: return static_cast(lhs.get()) == rhs; michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const U* lhs, const nsCOMPtr& rhs ) michael@0: { michael@0: return lhs == static_cast(rhs.get()); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator!=( const nsCOMPtr& lhs, const U* rhs ) michael@0: { michael@0: return static_cast(lhs.get()) != rhs; michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator!=( const U* lhs, const nsCOMPtr& rhs ) michael@0: { michael@0: return 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 nsCOMPtr& 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 nsCOMPtr& 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 nsCOMPtr& 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 nsCOMPtr& 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 |nsCOMPtr| to |0| michael@0: michael@0: class NSCAP_Zero; michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsCOMPtr& 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 nsCOMPtr& 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 nsCOMPtr& 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 nsCOMPtr& 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 nsCOMPtr& 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 nsCOMPtr& 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: // Comparing any two [XP]COM objects for identity michael@0: michael@0: inline michael@0: bool michael@0: SameCOMIdentity( nsISupports* lhs, nsISupports* rhs ) michael@0: { michael@0: return nsCOMPtr( do_QueryInterface(lhs) ) == nsCOMPtr( do_QueryInterface(rhs) ); michael@0: } michael@0: michael@0: michael@0: michael@0: template michael@0: inline michael@0: nsresult michael@0: CallQueryInterface( nsCOMPtr& aSourcePtr, DestinationType** aDestPtr ) michael@0: { michael@0: return CallQueryInterface(aSourcePtr.get(), aDestPtr); michael@0: } michael@0: michael@0: #endif // !defined(nsCOMPtr_h___)