зеркало из https://github.com/mozilla/gecko-dev.git
1539 строки
48 KiB
C++
1539 строки
48 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef nsCOMPtr_h___
|
|
#define nsCOMPtr_h___
|
|
|
|
/*
|
|
* Having problems?
|
|
*
|
|
* See the documentation at:
|
|
* https://firefox-source-docs.mozilla.org/xpcom/refptr.html
|
|
*
|
|
*
|
|
* nsCOMPtr
|
|
* better than a raw pointer
|
|
* for owning objects
|
|
* -- scc
|
|
*/
|
|
|
|
#include <type_traits>
|
|
|
|
#include "mozilla/AlreadyAddRefed.h"
|
|
#include "mozilla/Assertions.h"
|
|
#include "mozilla/Attributes.h"
|
|
#include "mozilla/RefPtr.h"
|
|
#include "nsCycleCollectionNoteChild.h"
|
|
#include "nsDebug.h" // for |NS_ASSERTION|
|
|
#include "nsISupportsUtils.h" // for |nsresult|, |NS_ADDREF|, |NS_GET_TEMPLATE_IID| et al
|
|
|
|
/*
|
|
* 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
|
|
// Under VC++, we win by inlining StartAssignment.
|
|
# define NSCAP_FEATURE_INLINE_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 DEBUG
|
|
# define NSCAP_FEATURE_TEST_DONTQUERY_CASES
|
|
# undef NSCAP_FEATURE_USE_BASE
|
|
#endif
|
|
|
|
#ifdef __GNUC__
|
|
// 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
|
|
|
|
/*
|
|
* 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 "nsISupportsImpl.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
|
|
|
|
namespace mozilla {
|
|
template <class T>
|
|
class OwningNonNull;
|
|
} // namespace mozilla
|
|
|
|
template <class T>
|
|
inline already_AddRefed<T> dont_AddRef(T* aRawPtr) {
|
|
return already_AddRefed<T>(aRawPtr);
|
|
}
|
|
|
|
template <class T>
|
|
inline already_AddRefed<T>&& dont_AddRef(
|
|
already_AddRefed<T>&& aAlreadyAddRefedPtr) {
|
|
return std::move(aAlreadyAddRefedPtr);
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
class MOZ_STACK_CLASS nsCOMPtr_helper {
|
|
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 MOZ_STACK_CLASS nsQueryInterfaceISupports {
|
|
public:
|
|
explicit nsQueryInterfaceISupports(nsISupports* aRawPtr) : mRawPtr(aRawPtr) {}
|
|
|
|
nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
|
|
|
|
private:
|
|
nsISupports* MOZ_OWNING_REF mRawPtr;
|
|
};
|
|
|
|
#ifndef NSCAP_FEATURE_USE_BASE
|
|
template <typename T>
|
|
class MOZ_STACK_CLASS nsQueryInterface final
|
|
: public nsQueryInterfaceISupports {
|
|
public:
|
|
explicit nsQueryInterface(T* aRawPtr)
|
|
: nsQueryInterfaceISupports(ToSupports(aRawPtr)) {}
|
|
|
|
nsresult NS_FASTCALL operator()(const nsIID& aIID, void** aAnswer) const {
|
|
return nsQueryInterfaceISupports::operator()(aIID, aAnswer);
|
|
}
|
|
};
|
|
#endif // #ifndef NSCAP_FEATURE_USE_BASE
|
|
|
|
class MOZ_STACK_CLASS nsQueryInterfaceISupportsWithError {
|
|
public:
|
|
nsQueryInterfaceISupportsWithError(nsISupports* aRawPtr, nsresult* aError)
|
|
: mRawPtr(aRawPtr), mErrorPtr(aError) {}
|
|
|
|
nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
|
|
|
|
private:
|
|
nsISupports* MOZ_OWNING_REF mRawPtr;
|
|
nsresult* mErrorPtr;
|
|
};
|
|
|
|
#ifndef NSCAP_FEATURE_USE_BASE
|
|
template <typename T>
|
|
class MOZ_STACK_CLASS nsQueryInterfaceWithError final
|
|
: public nsQueryInterfaceISupportsWithError {
|
|
public:
|
|
explicit nsQueryInterfaceWithError(T* aRawPtr, nsresult* aError)
|
|
: nsQueryInterfaceISupportsWithError(ToSupports(aRawPtr), aError) {}
|
|
|
|
nsresult NS_FASTCALL operator()(const nsIID& aIID, void** aAnswer) const {
|
|
return nsQueryInterfaceISupportsWithError::operator()(aIID, aAnswer);
|
|
}
|
|
};
|
|
#endif // #ifndef NSCAP_FEATURE_USE_BASE
|
|
|
|
namespace mozilla {
|
|
// PointedToType<> is needed so that do_QueryInterface() will work with a
|
|
// variety of smart pointer types in addition to raw pointers. These types
|
|
// include RefPtr<>, nsCOMPtr<>, and OwningNonNull<>.
|
|
template <class T>
|
|
using PointedToType = std::remove_pointer_t<decltype(&*std::declval<T>())>;
|
|
} // namespace mozilla
|
|
|
|
#ifdef NSCAP_FEATURE_USE_BASE
|
|
template <class T>
|
|
inline nsQueryInterfaceISupports do_QueryInterface(T aPtr) {
|
|
return nsQueryInterfaceISupports(
|
|
ToSupports(static_cast<mozilla::PointedToType<T>*>(aPtr)));
|
|
}
|
|
|
|
template <class T>
|
|
inline nsQueryInterfaceISupportsWithError do_QueryInterface(T aPtr,
|
|
nsresult* aError) {
|
|
return nsQueryInterfaceISupportsWithError(
|
|
ToSupports(static_cast<mozilla::PointedToType<T>*>(aPtr)), aError);
|
|
}
|
|
#else
|
|
template <class T>
|
|
inline nsQueryInterface<mozilla::PointedToType<T>> do_QueryInterface(T aPtr) {
|
|
return nsQueryInterface<mozilla::PointedToType<T>>(aPtr);
|
|
}
|
|
|
|
template <class T>
|
|
inline nsQueryInterfaceWithError<mozilla::PointedToType<T>> do_QueryInterface(
|
|
T aRawPtr, nsresult* aError) {
|
|
return nsQueryInterfaceWithError<mozilla::PointedToType<T>>(aRawPtr, aError);
|
|
}
|
|
|
|
#endif // ! #ifdef NSCAP_FEATURE_USE_BASE
|
|
|
|
template <class T>
|
|
inline void do_QueryInterface(already_AddRefed<T>&) {
|
|
// This signature exists solely 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 bug 8221.
|
|
}
|
|
|
|
template <class T>
|
|
inline void do_QueryInterface(already_AddRefed<T>&, nsresult*) {
|
|
// This signature exists solely 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 bug 8221.
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Using servicemanager with COMPtrs
|
|
class nsGetServiceByCID final {
|
|
public:
|
|
explicit nsGetServiceByCID(const nsCID& aCID) : mCID(aCID) {}
|
|
|
|
nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
|
|
|
|
private:
|
|
const nsCID& mCID;
|
|
};
|
|
|
|
class nsGetServiceByCIDWithError final {
|
|
public:
|
|
nsGetServiceByCIDWithError(const nsCID& aCID, nsresult* aErrorPtr)
|
|
: mCID(aCID), mErrorPtr(aErrorPtr) {}
|
|
|
|
nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
|
|
|
|
private:
|
|
const nsCID& mCID;
|
|
nsresult* mErrorPtr;
|
|
};
|
|
|
|
class nsGetServiceByContractID final {
|
|
public:
|
|
explicit nsGetServiceByContractID(const char* aContractID)
|
|
: mContractID(aContractID) {}
|
|
|
|
nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
|
|
|
|
private:
|
|
const char* mContractID;
|
|
};
|
|
|
|
class nsGetServiceByContractIDWithError final {
|
|
public:
|
|
nsGetServiceByContractIDWithError(const char* aContractID,
|
|
nsresult* aErrorPtr)
|
|
: mContractID(aContractID), mErrorPtr(aErrorPtr) {}
|
|
|
|
nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
|
|
|
|
private:
|
|
const char* mContractID;
|
|
nsresult* mErrorPtr;
|
|
};
|
|
|
|
class nsIWeakReference;
|
|
|
|
// Weak references
|
|
class MOZ_STACK_CLASS nsQueryReferent final {
|
|
public:
|
|
nsQueryReferent(nsIWeakReference* aWeakPtr, nsresult* aError)
|
|
: mWeakPtr(aWeakPtr), mErrorPtr(aError) {}
|
|
|
|
nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
|
|
|
|
private:
|
|
nsIWeakReference* MOZ_NON_OWNING_REF mWeakPtr;
|
|
nsresult* mErrorPtr;
|
|
};
|
|
|
|
/**
|
|
* Factors implementation for all template versions of nsCOMPtr.
|
|
*
|
|
* Here's the way people normally do things like this:
|
|
*
|
|
* template<class T> class Foo { ... };
|
|
* template<> class Foo<void*> { ... };
|
|
* template<class T> class Foo<T*> : private Foo<void*> { ... };
|
|
*/
|
|
class nsCOMPtr_base {
|
|
public:
|
|
explicit nsCOMPtr_base(nsISupports* aRawPtr = nullptr) : mRawPtr(aRawPtr) {}
|
|
|
|
NS_CONSTRUCTOR_FASTCALL ~nsCOMPtr_base() {
|
|
NSCAP_LOG_RELEASE(this, mRawPtr);
|
|
if (mRawPtr) {
|
|
NSCAP_RELEASE(this, mRawPtr);
|
|
}
|
|
}
|
|
|
|
void NS_FASTCALL assign_with_AddRef(nsISupports*);
|
|
void NS_FASTCALL assign_from_qi(const nsQueryInterfaceISupports,
|
|
const nsIID&);
|
|
void NS_FASTCALL assign_from_qi_with_error(
|
|
const nsQueryInterfaceISupportsWithError&, const nsIID&);
|
|
void NS_FASTCALL assign_from_gs_cid(const nsGetServiceByCID, const nsIID&);
|
|
void NS_FASTCALL assign_from_gs_cid_with_error(
|
|
const nsGetServiceByCIDWithError&, const nsIID&);
|
|
void NS_FASTCALL assign_from_gs_contractid(const nsGetServiceByContractID,
|
|
const nsIID&);
|
|
void NS_FASTCALL assign_from_gs_contractid_with_error(
|
|
const nsGetServiceByContractIDWithError&, const nsIID&);
|
|
void NS_FASTCALL assign_from_query_referent(const nsQueryReferent&,
|
|
const nsIID&);
|
|
void NS_FASTCALL assign_from_helper(const nsCOMPtr_helper&, const nsIID&);
|
|
// Since in most cases, begin_assignment is called on a default-constructed
|
|
// nsCOMPtr, the call to assign_assuming_AddRef becomes a no-op in release
|
|
// builds. However, the compiler does not always optimize this away and emits a
|
|
// call to begin_assignment without MOZ_ALWAYS_INLINE. When logging is enabled,
|
|
// this might cause code bloat, so we MOZ_NEVER_INLINE in that case.
|
|
#ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
|
|
MOZ_NEVER_INLINE
|
|
#else
|
|
MOZ_ALWAYS_INLINE
|
|
#endif
|
|
void** NS_FASTCALL begin_assignment() {
|
|
assign_assuming_AddRef(nullptr);
|
|
return reinterpret_cast<void**>(&mRawPtr);
|
|
}
|
|
|
|
protected:
|
|
NS_MAY_ALIAS_PTR(nsISupports) MOZ_OWNING_REF mRawPtr;
|
|
|
|
void assign_assuming_AddRef(nsISupports* aNewPtr) {
|
|
// |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 <waterson@netscape.com> for discovering this.
|
|
nsISupports* oldPtr = mRawPtr;
|
|
mRawPtr = aNewPtr;
|
|
NSCAP_LOG_ASSIGNMENT(this, aNewPtr);
|
|
NSCAP_LOG_RELEASE(this, oldPtr);
|
|
if (oldPtr) {
|
|
NSCAP_RELEASE(this, oldPtr);
|
|
}
|
|
}
|
|
};
|
|
|
|
// template<class T> class nsGetterAddRefs;
|
|
|
|
// Helper for assert_validity method
|
|
template <class T>
|
|
char (&TestForIID(decltype(&NS_GET_TEMPLATE_IID(T))))[2];
|
|
template <class T>
|
|
char TestForIID(...);
|
|
|
|
template <class T>
|
|
class MOZ_IS_REFPTR nsCOMPtr final
|
|
#ifdef NSCAP_FEATURE_USE_BASE
|
|
: private nsCOMPtr_base
|
|
#endif
|
|
{
|
|
private:
|
|
#ifdef NSCAP_FEATURE_USE_BASE
|
|
# define NSCAP_CTOR_BASE(x) nsCOMPtr_base(ToSupports(x))
|
|
void assign_assuming_AddRef(T* aNewPtr) {
|
|
nsCOMPtr_base::assign_assuming_AddRef(ToSupports(aNewPtr));
|
|
}
|
|
#else
|
|
# define NSCAP_CTOR_BASE(x) mRawPtr(x)
|
|
|
|
void assign_with_AddRef(nsISupports*);
|
|
template <typename U>
|
|
void assign_from_qi(const nsQueryInterface<U>, const nsIID&);
|
|
template <typename U>
|
|
void assign_from_qi_with_error(const nsQueryInterfaceWithError<U>&,
|
|
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_query_referent(const nsQueryReferent&, const nsIID&);
|
|
void assign_from_helper(const nsCOMPtr_helper&, const nsIID&);
|
|
void** begin_assignment();
|
|
|
|
void assign_assuming_AddRef(T* aNewPtr) {
|
|
T* oldPtr = mRawPtr;
|
|
mRawPtr = aNewPtr;
|
|
NSCAP_LOG_ASSIGNMENT(this, aNewPtr);
|
|
NSCAP_LOG_RELEASE(this, oldPtr);
|
|
if (oldPtr) {
|
|
NSCAP_RELEASE(this, oldPtr);
|
|
}
|
|
}
|
|
|
|
private:
|
|
T* MOZ_OWNING_REF mRawPtr;
|
|
#endif
|
|
|
|
void assert_validity() {
|
|
static_assert(1 < sizeof(TestForIID<T>(nullptr)),
|
|
"nsCOMPtr only works "
|
|
"for types with IIDs. Either use RefPtr; add an IID to "
|
|
"your type with NS_DECLARE_STATIC_IID_ACCESSOR/"
|
|
"NS_DEFINE_STATIC_IID_ACCESSOR; or make the nsCOMPtr point "
|
|
"to a base class with an IID.");
|
|
}
|
|
|
|
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) {
|
|
// This can't be defined in terms of do_QueryInterface because
|
|
// that bans casts from a class to itself.
|
|
void* out = nullptr;
|
|
mRawPtr->QueryInterface(NS_GET_TEMPLATE_IID(T), &out);
|
|
T* query_result = static_cast<T*>(out);
|
|
MOZ_ASSERT(query_result == mRawPtr, "QueryInterface needed");
|
|
NS_RELEASE(query_result);
|
|
}
|
|
}
|
|
|
|
# define NSCAP_ASSERT_NO_QUERY_NEEDED() Assert_NoQueryNeeded();
|
|
#else
|
|
# define NSCAP_ASSERT_NO_QUERY_NEEDED()
|
|
#endif
|
|
|
|
// Constructors
|
|
|
|
nsCOMPtr() : NSCAP_CTOR_BASE(nullptr) {
|
|
assert_validity();
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
}
|
|
|
|
MOZ_IMPLICIT nsCOMPtr(decltype(nullptr)) : NSCAP_CTOR_BASE(nullptr) {
|
|
assert_validity();
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
}
|
|
|
|
nsCOMPtr(const nsCOMPtr<T>& aSmartPtr) : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) {
|
|
assert_validity();
|
|
if (mRawPtr) {
|
|
NSCAP_ADDREF(this, mRawPtr);
|
|
}
|
|
NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr);
|
|
}
|
|
|
|
template <class U>
|
|
MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr<U>& aSmartPtr)
|
|
: NSCAP_CTOR_BASE(aSmartPtr.get()) {
|
|
// Make sure that U actually inherits from T
|
|
static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
|
|
assert_validity();
|
|
if (mRawPtr) {
|
|
NSCAP_ADDREF(this, mRawPtr);
|
|
}
|
|
NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.get());
|
|
}
|
|
|
|
nsCOMPtr(nsCOMPtr<T>&& aSmartPtr) : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) {
|
|
assert_validity();
|
|
aSmartPtr.mRawPtr = nullptr;
|
|
NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
|
|
}
|
|
|
|
template <class U>
|
|
MOZ_IMPLICIT nsCOMPtr(nsCOMPtr<U>&& aSmartPtr)
|
|
: NSCAP_CTOR_BASE(aSmartPtr.forget().template downcast<T>().take()) {
|
|
// Make sure that U actually inherits from T
|
|
static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
|
|
assert_validity();
|
|
NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
}
|
|
|
|
MOZ_IMPLICIT nsCOMPtr(T* aRawPtr) : NSCAP_CTOR_BASE(aRawPtr) {
|
|
assert_validity();
|
|
if (mRawPtr) {
|
|
NSCAP_ADDREF(this, mRawPtr);
|
|
}
|
|
NSCAP_LOG_ASSIGNMENT(this, aRawPtr);
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
}
|
|
|
|
MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T>& aSmartPtr)
|
|
: NSCAP_CTOR_BASE(aSmartPtr.take()) {
|
|
assert_validity();
|
|
NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
}
|
|
|
|
// Construct from |otherComPtr.forget()|.
|
|
MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T>&& aSmartPtr)
|
|
: NSCAP_CTOR_BASE(aSmartPtr.take()) {
|
|
assert_validity();
|
|
NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
}
|
|
|
|
// Construct from |std::move(otherRefPtr)|.
|
|
template <typename U>
|
|
MOZ_IMPLICIT nsCOMPtr(RefPtr<U>&& aSmartPtr)
|
|
: NSCAP_CTOR_BASE(
|
|
static_cast<already_AddRefed<T>>(aSmartPtr.forget()).take()) {
|
|
assert_validity();
|
|
// Make sure that U actually inherits from T
|
|
static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
|
|
NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
}
|
|
|
|
// Construct from |already_AddRefed|.
|
|
template <typename U>
|
|
MOZ_IMPLICIT nsCOMPtr(already_AddRefed<U>& aSmartPtr)
|
|
: NSCAP_CTOR_BASE(static_cast<T*>(aSmartPtr.take())) {
|
|
assert_validity();
|
|
// But make sure that U actually inherits from T.
|
|
static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
|
|
NSCAP_LOG_ASSIGNMENT(this, static_cast<T*>(mRawPtr));
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
}
|
|
|
|
// Construct from |otherComPtr.forget()|.
|
|
template <typename U>
|
|
MOZ_IMPLICIT nsCOMPtr(already_AddRefed<U>&& aSmartPtr)
|
|
: NSCAP_CTOR_BASE(static_cast<T*>(aSmartPtr.take())) {
|
|
assert_validity();
|
|
// But make sure that U actually inherits from T.
|
|
static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
|
|
NSCAP_LOG_ASSIGNMENT(this, static_cast<T*>(mRawPtr));
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
}
|
|
|
|
// Construct from |do_QueryInterface(expr)|.
|
|
#ifdef NSCAP_FEATURE_USE_BASE
|
|
MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceISupports aQI)
|
|
#else
|
|
template <typename U>
|
|
MOZ_IMPLICIT nsCOMPtr(const nsQueryInterface<U> aQI)
|
|
#endif // ! #ifdef NSCAP_FEATURE_USE_BASE
|
|
: NSCAP_CTOR_BASE(nullptr) {
|
|
assert_validity();
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_qi(aQI, NS_GET_TEMPLATE_IID(T));
|
|
}
|
|
|
|
// Construct from |do_QueryInterface(expr, &rv)|.
|
|
#ifdef NSCAP_FEATURE_USE_BASE
|
|
MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceISupportsWithError& aQI)
|
|
#else
|
|
template <typename U>
|
|
MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceWithError<U>& aQI)
|
|
#endif // ! #ifdef NSCAP_FEATURE_USE_BASE
|
|
: NSCAP_CTOR_BASE(nullptr) {
|
|
assert_validity();
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_qi_with_error(aQI, NS_GET_TEMPLATE_IID(T));
|
|
}
|
|
|
|
// Construct from |do_GetService(cid_expr)|.
|
|
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCID aGS)
|
|
: NSCAP_CTOR_BASE(nullptr) {
|
|
assert_validity();
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_gs_cid(aGS, NS_GET_TEMPLATE_IID(T));
|
|
}
|
|
|
|
// Construct from |do_GetService(cid_expr, &rv)|.
|
|
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCIDWithError& aGS)
|
|
: NSCAP_CTOR_BASE(nullptr) {
|
|
assert_validity();
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_gs_cid_with_error(aGS, NS_GET_TEMPLATE_IID(T));
|
|
}
|
|
|
|
// Construct from |do_GetService(contractid_expr)|.
|
|
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractID aGS)
|
|
: NSCAP_CTOR_BASE(nullptr) {
|
|
assert_validity();
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_gs_contractid(aGS, NS_GET_TEMPLATE_IID(T));
|
|
}
|
|
|
|
// Construct from |do_GetService(contractid_expr, &rv)|.
|
|
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
|
|
: NSCAP_CTOR_BASE(nullptr) {
|
|
assert_validity();
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_gs_contractid_with_error(aGS, NS_GET_TEMPLATE_IID(T));
|
|
}
|
|
|
|
// Construct from |do_QueryReferent(ptr)|
|
|
MOZ_IMPLICIT nsCOMPtr(const nsQueryReferent& aQueryReferent)
|
|
: NSCAP_CTOR_BASE(nullptr) {
|
|
assert_validity();
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_query_referent(aQueryReferent, NS_GET_TEMPLATE_IID(T));
|
|
}
|
|
|
|
// And finally, anything else we might need to construct from can exploit the
|
|
// nsCOMPtr_helper facility.
|
|
MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper)
|
|
: NSCAP_CTOR_BASE(nullptr) {
|
|
assert_validity();
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_helper(aHelper, NS_GET_TEMPLATE_IID(T));
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
}
|
|
|
|
// Defined in OwningNonNull.h
|
|
template <class U>
|
|
MOZ_IMPLICIT nsCOMPtr(const mozilla::OwningNonNull<U>& aOther);
|
|
|
|
// Assignment operators
|
|
|
|
nsCOMPtr<T>& operator=(const nsCOMPtr<T>& aRhs) {
|
|
assign_with_AddRef(ToSupports(aRhs.mRawPtr));
|
|
return *this;
|
|
}
|
|
|
|
template <class U>
|
|
nsCOMPtr<T>& operator=(const nsCOMPtr<U>& aRhs) {
|
|
// Make sure that U actually inherits from T
|
|
static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
|
|
assign_with_AddRef(ToSupports(static_cast<T*>(aRhs.get())));
|
|
return *this;
|
|
}
|
|
|
|
nsCOMPtr<T>& operator=(nsCOMPtr<T>&& aRhs) {
|
|
assign_assuming_AddRef(aRhs.forget().take());
|
|
return *this;
|
|
}
|
|
|
|
template <class U>
|
|
nsCOMPtr<T>& operator=(nsCOMPtr<U>&& aRhs) {
|
|
// Make sure that U actually inherits from T
|
|
static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
|
|
assign_assuming_AddRef(aRhs.forget().template downcast<T>().take());
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
return *this;
|
|
}
|
|
|
|
nsCOMPtr<T>& operator=(T* aRhs) {
|
|
assign_with_AddRef(ToSupports(aRhs));
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
return *this;
|
|
}
|
|
|
|
nsCOMPtr<T>& operator=(decltype(nullptr)) {
|
|
assign_assuming_AddRef(nullptr);
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |already_AddRefed|.
|
|
template <typename U>
|
|
nsCOMPtr<T>& operator=(already_AddRefed<U>& aRhs) {
|
|
// Make sure that U actually inherits from T
|
|
static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
|
|
assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |otherComPtr.forget()|.
|
|
template <typename U>
|
|
nsCOMPtr<T>& operator=(already_AddRefed<U>&& aRhs) {
|
|
// Make sure that U actually inherits from T
|
|
static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
|
|
assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |std::move(otherRefPtr)|.
|
|
template <typename U>
|
|
nsCOMPtr<T>& operator=(RefPtr<U>&& aRhs) {
|
|
// Make sure that U actually inherits from T
|
|
static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
|
|
assign_assuming_AddRef(static_cast<T*>(aRhs.forget().take()));
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |do_QueryInterface(expr)|.
|
|
#ifdef NSCAP_FEATURE_USE_BASE
|
|
nsCOMPtr<T>& operator=(const nsQueryInterfaceISupports aRhs)
|
|
#else
|
|
template <typename U>
|
|
nsCOMPtr<T>& operator=(const nsQueryInterface<U> aRhs)
|
|
#endif // ! #ifdef NSCAP_FEATURE_USE_BASE
|
|
{
|
|
assign_from_qi(aRhs, NS_GET_TEMPLATE_IID(T));
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |do_QueryInterface(expr, &rv)|.
|
|
#ifdef NSCAP_FEATURE_USE_BASE
|
|
nsCOMPtr<T>& operator=(const nsQueryInterfaceISupportsWithError& aRhs)
|
|
#else
|
|
template <typename U>
|
|
nsCOMPtr<T>& operator=(const nsQueryInterfaceWithError<U>& aRhs)
|
|
#endif // ! #ifdef NSCAP_FEATURE_USE_BASE
|
|
{
|
|
assign_from_qi_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |do_GetService(cid_expr)|.
|
|
nsCOMPtr<T>& operator=(const nsGetServiceByCID aRhs) {
|
|
assign_from_gs_cid(aRhs, NS_GET_TEMPLATE_IID(T));
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |do_GetService(cid_expr, &rv)|.
|
|
nsCOMPtr<T>& operator=(const nsGetServiceByCIDWithError& aRhs) {
|
|
assign_from_gs_cid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |do_GetService(contractid_expr)|.
|
|
nsCOMPtr<T>& operator=(const nsGetServiceByContractID aRhs) {
|
|
assign_from_gs_contractid(aRhs, NS_GET_TEMPLATE_IID(T));
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |do_GetService(contractid_expr, &rv)|.
|
|
nsCOMPtr<T>& operator=(const nsGetServiceByContractIDWithError& aRhs) {
|
|
assign_from_gs_contractid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |do_QueryReferent(ptr)|.
|
|
nsCOMPtr<T>& operator=(const nsQueryReferent& aRhs) {
|
|
assign_from_query_referent(aRhs, NS_GET_TEMPLATE_IID(T));
|
|
return *this;
|
|
}
|
|
|
|
// And finally, anything else we might need to assign from can exploit the
|
|
// nsCOMPtr_helper facility.
|
|
nsCOMPtr<T>& operator=(const nsCOMPtr_helper& aRhs) {
|
|
assign_from_helper(aRhs, NS_GET_TEMPLATE_IID(T));
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
return *this;
|
|
}
|
|
|
|
// Defined in OwningNonNull.h
|
|
template <class U>
|
|
nsCOMPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
|
|
|
|
// Exchange ownership with |aRhs|; can save a pair of refcount operations.
|
|
void swap(nsCOMPtr<T>& aRhs) {
|
|
#ifdef NSCAP_FEATURE_USE_BASE
|
|
nsISupports* temp = aRhs.mRawPtr;
|
|
#else
|
|
T* temp = aRhs.mRawPtr;
|
|
#endif
|
|
NSCAP_LOG_ASSIGNMENT(&aRhs, mRawPtr);
|
|
NSCAP_LOG_ASSIGNMENT(this, temp);
|
|
NSCAP_LOG_RELEASE(this, mRawPtr);
|
|
NSCAP_LOG_RELEASE(&aRhs, temp);
|
|
aRhs.mRawPtr = mRawPtr;
|
|
mRawPtr = temp;
|
|
// |aRhs| maintains the same invariants, so we don't need to
|
|
// |NSCAP_ASSERT_NO_QUERY_NEEDED|
|
|
}
|
|
|
|
// Exchange ownership with |aRhs|; can save a pair of refcount operations.
|
|
void swap(T*& aRhs) {
|
|
#ifdef NSCAP_FEATURE_USE_BASE
|
|
nsISupports* temp = ToSupports(aRhs);
|
|
#else
|
|
T* temp = aRhs;
|
|
#endif
|
|
NSCAP_LOG_ASSIGNMENT(this, temp);
|
|
NSCAP_LOG_RELEASE(this, mRawPtr);
|
|
aRhs = reinterpret_cast<T*>(mRawPtr);
|
|
mRawPtr = temp;
|
|
NSCAP_ASSERT_NO_QUERY_NEEDED();
|
|
}
|
|
|
|
// Other pointer operators
|
|
|
|
// Return the value of mRawPtr and null out mRawPtr. Useful for
|
|
// already_AddRefed return values.
|
|
already_AddRefed<T> MOZ_MAY_CALL_AFTER_MUST_RETURN forget() {
|
|
T* temp = nullptr;
|
|
swap(temp);
|
|
return already_AddRefed<T>(temp);
|
|
}
|
|
|
|
// Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
|
|
// Useful to avoid unnecessary AddRef/Release pairs with "out" parameters
|
|
// where aRhs bay be a T** or an I** where I is a base class of T.
|
|
template <typename I>
|
|
void forget(I** aRhs) {
|
|
NS_ASSERTION(aRhs, "Null pointer passed to forget!");
|
|
NSCAP_LOG_RELEASE(this, mRawPtr);
|
|
*aRhs = get();
|
|
mRawPtr = nullptr;
|
|
}
|
|
|
|
// Prefer the implicit conversion provided automatically by
|
|
// |operator T*() const|. Use |get()| to resolve ambiguity or to get a
|
|
// castable pointer.
|
|
T* get() const { return reinterpret_cast<T*>(mRawPtr); }
|
|
|
|
// Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
|
|
// used in a context where a raw pointer is expected. It is this operator
|
|
// that makes an nsCOMPtr substitutable for a raw pointer.
|
|
//
|
|
// Prefer the implicit use of this operator to calling |get()|, except where
|
|
// necessary to resolve ambiguity.
|
|
operator T*() const& { return get(); }
|
|
|
|
// Don't allow implicit conversion of temporary nsCOMPtr to raw pointer,
|
|
// because the refcount might be one and the pointer will immediately become
|
|
// invalid.
|
|
operator T*() const&& = delete;
|
|
|
|
// Needed to avoid the deleted operator above
|
|
explicit operator bool() const { return !!mRawPtr; }
|
|
|
|
T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
|
|
MOZ_ASSERT(mRawPtr != nullptr,
|
|
"You can't dereference a NULL nsCOMPtr with operator->().");
|
|
return get();
|
|
}
|
|
|
|
// These are not intended to be used by clients. See |address_of| below.
|
|
nsCOMPtr<T>* get_address() { return this; }
|
|
const nsCOMPtr<T>* get_address() const { return this; }
|
|
|
|
public:
|
|
T& operator*() const {
|
|
MOZ_ASSERT(mRawPtr != nullptr,
|
|
"You can't dereference a NULL nsCOMPtr with operator*().");
|
|
return *get();
|
|
}
|
|
|
|
T** StartAssignment() {
|
|
#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
|
|
return reinterpret_cast<T**>(begin_assignment());
|
|
#else
|
|
assign_assuming_AddRef(nullptr);
|
|
return reinterpret_cast<T**>(&mRawPtr);
|
|
#endif
|
|
}
|
|
};
|
|
|
|
/*
|
|
* Specializing nsCOMPtr for nsISupports allows us to use nsCOMPtr<nsISupports>
|
|
* the same way people use nsISupports* and void*, i.e., as a `catch-all'
|
|
* pointing to any valid [XP]COM interface. Otherwise, an nsCOMPtr<nsISupports>
|
|
* 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.
|
|
*/
|
|
template <>
|
|
class MOZ_IS_REFPTR nsCOMPtr<nsISupports> : private nsCOMPtr_base {
|
|
public:
|
|
typedef nsISupports element_type;
|
|
|
|
// Constructors
|
|
|
|
nsCOMPtr() : nsCOMPtr_base(nullptr) { NSCAP_LOG_ASSIGNMENT(this, nullptr); }
|
|
|
|
MOZ_IMPLICIT nsCOMPtr(decltype(nullptr)) : nsCOMPtr_base(nullptr) {
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
}
|
|
|
|
nsCOMPtr(const nsCOMPtr<nsISupports>& aSmartPtr)
|
|
: nsCOMPtr_base(aSmartPtr.mRawPtr) {
|
|
if (mRawPtr) {
|
|
NSCAP_ADDREF(this, mRawPtr);
|
|
}
|
|
NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr);
|
|
}
|
|
|
|
MOZ_IMPLICIT nsCOMPtr(nsISupports* aRawPtr) : nsCOMPtr_base(aRawPtr) {
|
|
if (mRawPtr) {
|
|
NSCAP_ADDREF(this, mRawPtr);
|
|
}
|
|
NSCAP_LOG_ASSIGNMENT(this, aRawPtr);
|
|
}
|
|
|
|
// Construct from |already_AddRefed|.
|
|
MOZ_IMPLICIT nsCOMPtr(already_AddRefed<nsISupports>& aSmartPtr)
|
|
: nsCOMPtr_base(aSmartPtr.take()) {
|
|
NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
|
|
}
|
|
|
|
// Construct from |otherComPtr.forget()|.
|
|
MOZ_IMPLICIT nsCOMPtr(already_AddRefed<nsISupports>&& aSmartPtr)
|
|
: nsCOMPtr_base(aSmartPtr.take()) {
|
|
NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
|
|
}
|
|
|
|
// Construct from |do_QueryInterface(expr)|.
|
|
MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceISupports aQI)
|
|
: nsCOMPtr_base(nullptr) {
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_qi(aQI, NS_GET_IID(nsISupports));
|
|
}
|
|
|
|
// Construct from |do_QueryInterface(expr, &rv)|.
|
|
MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceISupportsWithError& aQI)
|
|
: nsCOMPtr_base(nullptr) {
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_qi_with_error(aQI, NS_GET_IID(nsISupports));
|
|
}
|
|
|
|
// Construct from |do_GetService(cid_expr)|.
|
|
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCID aGS) : nsCOMPtr_base(nullptr) {
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_gs_cid(aGS, NS_GET_IID(nsISupports));
|
|
}
|
|
|
|
// Construct from |do_GetService(cid_expr, &rv)|.
|
|
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCIDWithError& aGS)
|
|
: nsCOMPtr_base(nullptr) {
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_gs_cid_with_error(aGS, NS_GET_IID(nsISupports));
|
|
}
|
|
|
|
// Construct from |do_GetService(contractid_expr)|.
|
|
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractID aGS)
|
|
: nsCOMPtr_base(nullptr) {
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_gs_contractid(aGS, NS_GET_IID(nsISupports));
|
|
}
|
|
|
|
// Construct from |do_GetService(contractid_expr, &rv)|.
|
|
MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
|
|
: nsCOMPtr_base(nullptr) {
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_gs_contractid_with_error(aGS, NS_GET_IID(nsISupports));
|
|
}
|
|
|
|
// Construct from |do_QueryReferent(ptr)|
|
|
MOZ_IMPLICIT nsCOMPtr(const nsQueryReferent& aQueryReferent)
|
|
: nsCOMPtr_base(nullptr) {
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_query_referent(aQueryReferent,
|
|
NS_GET_TEMPLATE_IID(nsISupports));
|
|
}
|
|
|
|
// And finally, anything else we might need to construct from can exploit
|
|
// the |nsCOMPtr_helper| facility
|
|
MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper)
|
|
: nsCOMPtr_base(nullptr) {
|
|
NSCAP_LOG_ASSIGNMENT(this, nullptr);
|
|
assign_from_helper(aHelper, NS_GET_IID(nsISupports));
|
|
}
|
|
|
|
// Assignment operators
|
|
|
|
nsCOMPtr<nsISupports>& operator=(const nsCOMPtr<nsISupports>& aRhs) {
|
|
assign_with_AddRef(aRhs.mRawPtr);
|
|
return *this;
|
|
}
|
|
|
|
nsCOMPtr<nsISupports>& operator=(nsISupports* aRhs) {
|
|
assign_with_AddRef(aRhs);
|
|
return *this;
|
|
}
|
|
|
|
nsCOMPtr<nsISupports>& operator=(decltype(nullptr)) {
|
|
assign_assuming_AddRef(nullptr);
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |already_AddRefed|.
|
|
nsCOMPtr<nsISupports>& operator=(already_AddRefed<nsISupports>& aRhs) {
|
|
assign_assuming_AddRef(aRhs.take());
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |otherComPtr.forget()|.
|
|
nsCOMPtr<nsISupports>& operator=(already_AddRefed<nsISupports>&& aRhs) {
|
|
assign_assuming_AddRef(aRhs.take());
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |do_QueryInterface(expr)|.
|
|
nsCOMPtr<nsISupports>& operator=(const nsQueryInterfaceISupports aRhs) {
|
|
assign_from_qi(aRhs, NS_GET_IID(nsISupports));
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |do_QueryInterface(expr, &rv)|.
|
|
nsCOMPtr<nsISupports>& operator=(
|
|
const nsQueryInterfaceISupportsWithError& aRhs) {
|
|
assign_from_qi_with_error(aRhs, NS_GET_IID(nsISupports));
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |do_GetService(cid_expr)|.
|
|
nsCOMPtr<nsISupports>& operator=(const nsGetServiceByCID aRhs) {
|
|
assign_from_gs_cid(aRhs, NS_GET_IID(nsISupports));
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |do_GetService(cid_expr, &rv)|.
|
|
nsCOMPtr<nsISupports>& operator=(const nsGetServiceByCIDWithError& aRhs) {
|
|
assign_from_gs_cid_with_error(aRhs, NS_GET_IID(nsISupports));
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |do_GetService(contractid_expr)|.
|
|
nsCOMPtr<nsISupports>& operator=(const nsGetServiceByContractID aRhs) {
|
|
assign_from_gs_contractid(aRhs, NS_GET_IID(nsISupports));
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |do_GetService(contractid_expr, &rv)|.
|
|
nsCOMPtr<nsISupports>& operator=(
|
|
const nsGetServiceByContractIDWithError& aRhs) {
|
|
assign_from_gs_contractid_with_error(aRhs, NS_GET_IID(nsISupports));
|
|
return *this;
|
|
}
|
|
|
|
// Assign from |do_QueryReferent(ptr)|.
|
|
nsCOMPtr<nsISupports>& operator=(const nsQueryReferent& aRhs) {
|
|
assign_from_query_referent(aRhs, NS_GET_TEMPLATE_IID(nsISupports));
|
|
return *this;
|
|
}
|
|
|
|
// And finally, anything else we might need to assign from can exploit the
|
|
// nsCOMPtr_helper facility
|
|
nsCOMPtr<nsISupports>& operator=(const nsCOMPtr_helper& aRhs) {
|
|
assign_from_helper(aRhs, NS_GET_IID(nsISupports));
|
|
return *this;
|
|
}
|
|
|
|
// Exchange ownership with |aRhs|; can save a pair of refcount operations.
|
|
void swap(nsCOMPtr<nsISupports>& aRhs) {
|
|
nsISupports* temp = aRhs.mRawPtr;
|
|
NSCAP_LOG_ASSIGNMENT(&aRhs, mRawPtr);
|
|
NSCAP_LOG_ASSIGNMENT(this, temp);
|
|
NSCAP_LOG_RELEASE(this, mRawPtr);
|
|
NSCAP_LOG_RELEASE(&aRhs, temp);
|
|
aRhs.mRawPtr = mRawPtr;
|
|
mRawPtr = temp;
|
|
}
|
|
|
|
// Exchange ownership with |aRhs|; can save a pair of refcount operations.
|
|
void swap(nsISupports*& aRhs) {
|
|
nsISupports* temp = aRhs;
|
|
NSCAP_LOG_ASSIGNMENT(this, temp);
|
|
NSCAP_LOG_RELEASE(this, mRawPtr);
|
|
aRhs = mRawPtr;
|
|
mRawPtr = temp;
|
|
}
|
|
|
|
// Return the value of mRawPtr and null out mRawPtr. Useful for
|
|
// already_AddRefed return values.
|
|
already_AddRefed<nsISupports> forget() {
|
|
nsISupports* temp = nullptr;
|
|
swap(temp);
|
|
return already_AddRefed<nsISupports>(temp);
|
|
}
|
|
|
|
// Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
|
|
// Useful to avoid unnecessary AddRef/Release pairs with "out"
|
|
// parameters.
|
|
void forget(nsISupports** aRhs) {
|
|
NS_ASSERTION(aRhs, "Null pointer passed to forget!");
|
|
*aRhs = nullptr;
|
|
swap(*aRhs);
|
|
}
|
|
|
|
// Other pointer operators
|
|
|
|
// Prefer the implicit conversion provided automatically by
|
|
// |operator nsISupports*() const|. Use |get()| to resolve ambiguity or to
|
|
// get a castable pointer.
|
|
nsISupports* get() const { return reinterpret_cast<nsISupports*>(mRawPtr); }
|
|
|
|
// Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
|
|
// used in a context where a raw pointer is expected. It is this operator
|
|
// that makes an nsCOMPtr substitutable for a raw pointer.
|
|
//
|
|
// Prefer the implicit use of this operator to calling |get()|, except where
|
|
// necessary to resolve ambiguity/
|
|
operator nsISupports*() const { return get(); }
|
|
|
|
nsISupports* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
|
|
MOZ_ASSERT(mRawPtr != nullptr,
|
|
"You can't dereference a NULL nsCOMPtr with operator->().");
|
|
return get();
|
|
}
|
|
|
|
// These are not intended to be used by clients. See |address_of| below.
|
|
nsCOMPtr<nsISupports>* get_address() { return this; }
|
|
const nsCOMPtr<nsISupports>* get_address() const { return this; }
|
|
|
|
public:
|
|
nsISupports& operator*() const {
|
|
MOZ_ASSERT(mRawPtr != nullptr,
|
|
"You can't dereference a NULL nsCOMPtr with operator*().");
|
|
return *get();
|
|
}
|
|
|
|
nsISupports** StartAssignment() {
|
|
#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
|
|
return reinterpret_cast<nsISupports**>(begin_assignment());
|
|
#else
|
|
assign_assuming_AddRef(nullptr);
|
|
return reinterpret_cast<nsISupports**>(&mRawPtr);
|
|
#endif
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
inline void ImplCycleCollectionUnlink(nsCOMPtr<T>& aField) {
|
|
aField = nullptr;
|
|
}
|
|
|
|
template <typename T>
|
|
inline void ImplCycleCollectionTraverse(
|
|
nsCycleCollectionTraversalCallback& aCallback, nsCOMPtr<T>& aField,
|
|
const char* aName, uint32_t aFlags = 0) {
|
|
CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
|
|
}
|
|
|
|
#ifndef NSCAP_FEATURE_USE_BASE
|
|
template <class T>
|
|
void nsCOMPtr<T>::assign_with_AddRef(nsISupports* aRawPtr) {
|
|
if (aRawPtr) {
|
|
NSCAP_ADDREF(this, aRawPtr);
|
|
}
|
|
assign_assuming_AddRef(reinterpret_cast<T*>(aRawPtr));
|
|
}
|
|
|
|
template <class T>
|
|
template <typename U>
|
|
void nsCOMPtr<T>::assign_from_qi(const nsQueryInterface<U> aQI,
|
|
const nsIID& aIID) {
|
|
static_assert(
|
|
!(std::is_same_v<T, U> || std::is_base_of<T, U>::value),
|
|
"don't use do_QueryInterface for compile-time-determinable casts");
|
|
void* newRawPtr;
|
|
if (NS_FAILED(aQI(aIID, &newRawPtr))) {
|
|
newRawPtr = nullptr;
|
|
}
|
|
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
|
|
}
|
|
|
|
template <class T>
|
|
template <typename U>
|
|
void nsCOMPtr<T>::assign_from_qi_with_error(
|
|
const nsQueryInterfaceWithError<U>& aQI, const nsIID& aIID) {
|
|
static_assert(
|
|
!(std::is_same_v<T, U> || std::is_base_of<T, U>::value),
|
|
"don't use do_QueryInterface for compile-time-determinable casts");
|
|
void* newRawPtr;
|
|
if (NS_FAILED(aQI(aIID, &newRawPtr))) {
|
|
newRawPtr = nullptr;
|
|
}
|
|
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
|
|
}
|
|
|
|
template <class T>
|
|
void nsCOMPtr<T>::assign_from_gs_cid(const nsGetServiceByCID aGS,
|
|
const nsIID& aIID) {
|
|
void* newRawPtr;
|
|
if (NS_FAILED(aGS(aIID, &newRawPtr))) {
|
|
newRawPtr = nullptr;
|
|
}
|
|
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
|
|
}
|
|
|
|
template <class T>
|
|
void nsCOMPtr<T>::assign_from_gs_cid_with_error(
|
|
const nsGetServiceByCIDWithError& aGS, const nsIID& aIID) {
|
|
void* newRawPtr;
|
|
if (NS_FAILED(aGS(aIID, &newRawPtr))) {
|
|
newRawPtr = nullptr;
|
|
}
|
|
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
|
|
}
|
|
|
|
template <class T>
|
|
void nsCOMPtr<T>::assign_from_gs_contractid(const nsGetServiceByContractID aGS,
|
|
const nsIID& aIID) {
|
|
void* newRawPtr;
|
|
if (NS_FAILED(aGS(aIID, &newRawPtr))) {
|
|
newRawPtr = nullptr;
|
|
}
|
|
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
|
|
}
|
|
|
|
template <class T>
|
|
void nsCOMPtr<T>::assign_from_gs_contractid_with_error(
|
|
const nsGetServiceByContractIDWithError& aGS, const nsIID& aIID) {
|
|
void* newRawPtr;
|
|
if (NS_FAILED(aGS(aIID, &newRawPtr))) {
|
|
newRawPtr = nullptr;
|
|
}
|
|
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
|
|
}
|
|
|
|
template <class T>
|
|
void nsCOMPtr<T>::assign_from_query_referent(
|
|
const nsQueryReferent& aQueryReferent, const nsIID& aIID) {
|
|
void* newRawPtr;
|
|
if (NS_FAILED(aQueryReferent(aIID, &newRawPtr))) {
|
|
newRawPtr = nullptr;
|
|
}
|
|
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
|
|
}
|
|
|
|
template <class T>
|
|
void nsCOMPtr<T>::assign_from_helper(const nsCOMPtr_helper& helper,
|
|
const nsIID& aIID) {
|
|
void* newRawPtr;
|
|
if (NS_FAILED(helper(aIID, &newRawPtr))) {
|
|
newRawPtr = nullptr;
|
|
}
|
|
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
|
|
}
|
|
|
|
template <class T>
|
|
void** nsCOMPtr<T>::begin_assignment() {
|
|
assign_assuming_AddRef(nullptr);
|
|
union {
|
|
T** mT;
|
|
void** mVoid;
|
|
} result;
|
|
result.mT = &mRawPtr;
|
|
return result.mVoid;
|
|
}
|
|
#endif
|
|
|
|
template <class T>
|
|
inline nsCOMPtr<T>* address_of(nsCOMPtr<T>& aPtr) {
|
|
return aPtr.get_address();
|
|
}
|
|
|
|
template <class T>
|
|
inline const nsCOMPtr<T>* address_of(const nsCOMPtr<T>& aPtr) {
|
|
return aPtr.get_address();
|
|
}
|
|
|
|
/**
|
|
* 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<IFoo> 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<T>|.
|
|
*/
|
|
template <class T>
|
|
class nsGetterAddRefs {
|
|
public:
|
|
explicit nsGetterAddRefs(nsCOMPtr<T>& aSmartPtr)
|
|
: mTargetSmartPtr(aSmartPtr) {}
|
|
|
|
#if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || \
|
|
defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT)
|
|
~nsGetterAddRefs() {
|
|
# ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
|
|
NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),
|
|
mTargetSmartPtr.get());
|
|
# endif
|
|
|
|
# ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
|
|
mTargetSmartPtr.Assert_NoQueryNeeded();
|
|
# endif
|
|
}
|
|
#endif
|
|
|
|
operator void**() {
|
|
return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
|
|
}
|
|
|
|
operator T**() { return mTargetSmartPtr.StartAssignment(); }
|
|
T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
|
|
|
|
private:
|
|
nsCOMPtr<T>& mTargetSmartPtr;
|
|
};
|
|
|
|
template <>
|
|
class nsGetterAddRefs<nsISupports> {
|
|
public:
|
|
explicit nsGetterAddRefs(nsCOMPtr<nsISupports>& aSmartPtr)
|
|
: mTargetSmartPtr(aSmartPtr) {}
|
|
|
|
#ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
|
|
~nsGetterAddRefs() {
|
|
NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),
|
|
mTargetSmartPtr.get());
|
|
}
|
|
#endif
|
|
|
|
operator void**() {
|
|
return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
|
|
}
|
|
|
|
operator nsISupports**() { return mTargetSmartPtr.StartAssignment(); }
|
|
nsISupports*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
|
|
|
|
private:
|
|
nsCOMPtr<nsISupports>& mTargetSmartPtr;
|
|
};
|
|
|
|
template <class T>
|
|
inline nsGetterAddRefs<T> getter_AddRefs(nsCOMPtr<T>& aSmartPtr) {
|
|
return nsGetterAddRefs<T>(aSmartPtr);
|
|
}
|
|
|
|
template <class T, class DestinationType>
|
|
inline nsresult CallQueryInterface(
|
|
T* aSource, nsGetterAddRefs<DestinationType> aDestination) {
|
|
return CallQueryInterface(aSource,
|
|
static_cast<DestinationType**>(aDestination));
|
|
}
|
|
|
|
// Comparing two |nsCOMPtr|s
|
|
|
|
template <class T, class U>
|
|
inline bool operator==(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs) {
|
|
return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
|
|
}
|
|
|
|
template <class T, class U>
|
|
inline bool operator!=(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs) {
|
|
return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
|
|
}
|
|
|
|
// Comparing an |nsCOMPtr| to a raw pointer
|
|
|
|
template <class T, class U>
|
|
inline bool operator==(const nsCOMPtr<T>& aLhs, const U* aRhs) {
|
|
return static_cast<const T*>(aLhs.get()) == aRhs;
|
|
}
|
|
|
|
template <class T, class U>
|
|
inline bool operator==(const U* aLhs, const nsCOMPtr<T>& aRhs) {
|
|
return aLhs == static_cast<const T*>(aRhs.get());
|
|
}
|
|
|
|
template <class T, class U>
|
|
inline bool operator!=(const nsCOMPtr<T>& aLhs, const U* aRhs) {
|
|
return static_cast<const T*>(aLhs.get()) != aRhs;
|
|
}
|
|
|
|
template <class T, class U>
|
|
inline bool operator!=(const U* aLhs, const nsCOMPtr<T>& aRhs) {
|
|
return aLhs != static_cast<const T*>(aRhs.get());
|
|
}
|
|
|
|
template <class T, class U>
|
|
inline bool operator==(const nsCOMPtr<T>& aLhs, U* aRhs) {
|
|
return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
|
|
}
|
|
|
|
template <class T, class U>
|
|
inline bool operator==(U* aLhs, const nsCOMPtr<T>& aRhs) {
|
|
return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
|
|
}
|
|
|
|
template <class T, class U>
|
|
inline bool operator!=(const nsCOMPtr<T>& aLhs, U* aRhs) {
|
|
return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
|
|
}
|
|
|
|
template <class T, class U>
|
|
inline bool operator!=(U* aLhs, const nsCOMPtr<T>& aRhs) {
|
|
return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
|
|
}
|
|
|
|
// Comparing an |nsCOMPtr| to |nullptr|
|
|
|
|
template <class T>
|
|
inline bool operator==(const nsCOMPtr<T>& aLhs, decltype(nullptr)) {
|
|
return aLhs.get() == nullptr;
|
|
}
|
|
|
|
template <class T>
|
|
inline bool operator==(decltype(nullptr), const nsCOMPtr<T>& aRhs) {
|
|
return nullptr == aRhs.get();
|
|
}
|
|
|
|
template <class T>
|
|
inline bool operator!=(const nsCOMPtr<T>& aLhs, decltype(nullptr)) {
|
|
return aLhs.get() != nullptr;
|
|
}
|
|
|
|
template <class T>
|
|
inline bool operator!=(decltype(nullptr), const nsCOMPtr<T>& aRhs) {
|
|
return nullptr != aRhs.get();
|
|
}
|
|
|
|
// Comparing any two [XP]COM objects for identity
|
|
|
|
inline bool SameCOMIdentity(nsISupports* aLhs, nsISupports* aRhs) {
|
|
return nsCOMPtr<nsISupports>(do_QueryInterface(aLhs)) ==
|
|
nsCOMPtr<nsISupports>(do_QueryInterface(aRhs));
|
|
}
|
|
|
|
template <class SourceType, class DestinationType>
|
|
inline nsresult CallQueryInterface(nsCOMPtr<SourceType>& aSourcePtr,
|
|
DestinationType** aDestPtr) {
|
|
return CallQueryInterface(aSourcePtr.get(), aDestPtr);
|
|
}
|
|
|
|
template <class T>
|
|
RefPtr<T>::RefPtr(const nsQueryReferent& aQueryReferent) {
|
|
void* newRawPtr;
|
|
if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
|
|
newRawPtr = nullptr;
|
|
}
|
|
mRawPtr = static_cast<T*>(newRawPtr);
|
|
}
|
|
|
|
template <class T>
|
|
RefPtr<T>::RefPtr(const nsCOMPtr_helper& aHelper) {
|
|
void* newRawPtr;
|
|
if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
|
|
newRawPtr = nullptr;
|
|
}
|
|
mRawPtr = static_cast<T*>(newRawPtr);
|
|
}
|
|
|
|
template <class T>
|
|
RefPtr<T>& RefPtr<T>::operator=(const nsQueryReferent& aQueryReferent) {
|
|
void* newRawPtr;
|
|
if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
|
|
newRawPtr = nullptr;
|
|
}
|
|
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
|
|
return *this;
|
|
}
|
|
|
|
template <class T>
|
|
RefPtr<T>& RefPtr<T>::operator=(const nsCOMPtr_helper& aHelper) {
|
|
void* newRawPtr;
|
|
if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
|
|
newRawPtr = nullptr;
|
|
}
|
|
assign_assuming_AddRef(static_cast<T*>(newRawPtr));
|
|
return *this;
|
|
}
|
|
|
|
template <class T>
|
|
inline already_AddRefed<T> do_AddRef(const nsCOMPtr<T>& aObj) {
|
|
nsCOMPtr<T> ref(aObj);
|
|
return ref.forget();
|
|
}
|
|
|
|
// MOZ_DBG support
|
|
|
|
template <class T>
|
|
std::ostream& operator<<(std::ostream& aOut, const nsCOMPtr<T>& aObj) {
|
|
return mozilla::DebugValue(aOut, aObj.get());
|
|
}
|
|
|
|
// ToRefPtr allows to move an nsCOMPtr<T> into a RefPtr<T>. Be mindful when
|
|
// using this, because usually RefPtr<T> should only be used with concrete T and
|
|
// nsCOMPtr<T> should only be used with XPCOM interface T.
|
|
template <class T>
|
|
RefPtr<T> ToRefPtr(nsCOMPtr<T>&& aObj) {
|
|
return aObj.forget();
|
|
}
|
|
|
|
// Integration with ResultExtensions.h
|
|
template <typename R>
|
|
auto ResultRefAsParam(nsCOMPtr<R>& aResult) {
|
|
return getter_AddRefs(aResult);
|
|
}
|
|
|
|
namespace mozilla::detail {
|
|
template <typename T>
|
|
struct outparam_as_pointer;
|
|
|
|
template <typename T>
|
|
struct outparam_as_pointer<nsGetterAddRefs<T>> {
|
|
using type = T**;
|
|
};
|
|
} // namespace mozilla::detail
|
|
|
|
#endif // !defined(nsCOMPtr_h___)
|