/* -*- 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/. */
#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
#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.
/* * 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)
*/
// 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
/* * 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) {}
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
template <class T> inlinevoid 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> inlinevoid 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) {}
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.");
}
#ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES void Assert_NoQueryNeeded() { if (!mRawPtr) { return;
} if constexpr (std::is_same_v<T, nsISupports>) { // FIXME: nsCOMPtr<nsISupports> never asserted this, and it currently // fails... return;
} // 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);
}
template <class U>
MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr<U>& aSmartPtr)
: mRawPtr(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());
}
template <class U>
MOZ_IMPLICIT nsCOMPtr(nsCOMPtr<U>&& aSmartPtr)
: mRawPtr(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();
}
// Construct from |std::move(otherRefPtr)|. template <typename U>
MOZ_IMPLICIT nsCOMPtr(RefPtr<U>&& aSmartPtr)
: mRawPtr(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)
: mRawPtr(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)
: mRawPtr(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();
}
// And finally, anything else we might need to construct from can exploit the // nsCOMPtr_helper facility.
MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper) : mRawPtr(nullptr) {
assert_validity();
NSCAP_LOG_ASSIGNMENT(this, nullptr);
assign_from_helper(aHelper, NS_GET_TEMPLATE_IID(T));
NSCAP_ASSERT_NO_QUERY_NEEDED();
}
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(aRhs.get()); 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;
}
// 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;
}
// 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;
}
// Assign from |mozilla::NotNull|. template <typename I, typename = std::enable_if_t<std::is_convertible_v<I, nsCOMPtr<T>>>>
nsCOMPtr<T>& operator=(const mozilla::NotNull<I>& aSmartPtr) {
assign_assuming_AddRef(nsCOMPtr<T>(aSmartPtr.get()).forget().take()); return *this;
}
// Assign from |mozilla::MovingNotNull|. template <typename I, typename = std::enable_if_t<std::is_convertible_v<I, nsCOMPtr<T>>>>
nsCOMPtr<T>& operator=(mozilla::MovingNotNull<I>&& aSmartPtr) {
assign_assuming_AddRef(
nsCOMPtr<T>(std::move(aSmartPtr).unwrapBasePtr()).forget().take()); 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) {
T* 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; // |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) {
T* temp = aRhs;
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 { returnreinterpret_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 explicitoperatorbool() 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() { returnthis; } const nsCOMPtr<T>* get_address() const { returnthis; }
public:
T& operator*() const {
MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL nsCOMPtr with operator*()."); return *get();
}
/** * 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) {}
// 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);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.