1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
13 * See the documentation at:
14 * https://firefox-source-docs.mozilla.org/xpcom/refptr.html
18 * better than a raw pointer
23 #include <type_traits>
25 #include "mozilla/AlreadyAddRefed.h"
26 #include "mozilla/Assertions.h"
27 #include "mozilla/Attributes.h"
28 #include "mozilla/RefPtr.h"
29 #include "nsCycleCollectionNoteChild.h"
30 #include "nsDebug.h" // for |NS_ASSERTION|
31 #include "nsISupportsUtils.h" // for |nsresult|, |NS_ADDREF|, |NS_GET_TEMPLATE_IID| et al
34 * WARNING: This file defines several macros for internal use only. These
35 * macros begin with the prefix |NSCAP_|. Do not use these macros in your own
36 * code. They are for internal use only for cross-platform compatibility, and
37 * are subject to change without notice.
41 // Under VC++, we win by inlining StartAssignment.
42 # define NSCAP_FEATURE_INLINE_STARTASSIGNMENT
44 // Also under VC++, at the highest warning level, we are overwhelmed with
45 // warnings about (unused) inline functions being removed. This is to be
46 // expected with templates, so we disable the warning.
47 # pragma warning(disable : 4514)
50 #define NSCAP_FEATURE_USE_BASE
53 # define NSCAP_FEATURE_TEST_DONTQUERY_CASES
54 # undef NSCAP_FEATURE_USE_BASE
58 // Our use of nsCOMPtr_base::mRawPtr violates the C++ standard's aliasing
59 // rules. Mark it with the may_alias attribute so that gcc 3.3 and higher
60 // don't reorder instructions based on aliasing assumptions for
61 // this variable. Fortunately, gcc versions < 3.3 do not do any
62 // optimizations that break nsCOMPtr.
64 # define NS_MAY_ALIAS_PTR(t) t* __attribute__((__may_alias__))
66 # define NS_MAY_ALIAS_PTR(t) t*
69 #if defined(NSCAP_DISABLE_DEBUG_PTR_TYPES)
70 # define NSCAP_FEATURE_USE_BASE
74 * The following three macros (NSCAP_ADDREF, NSCAP_RELEASE, and
75 * NSCAP_LOG_ASSIGNMENT) allow external clients the ability to add logging or
76 * other interesting debug facilities. In fact, if you want |nsCOMPtr| to
77 * participate in the standard logging facility, you provide
78 * (e.g., in "nsISupportsImpl.h") suitable definitions
80 * #define NSCAP_ADDREF(this, ptr) NS_ADDREF(ptr)
81 * #define NSCAP_RELEASE(this, ptr) NS_RELEASE(ptr)
85 # define NSCAP_ADDREF(this, ptr) (ptr)->AddRef()
89 # define NSCAP_RELEASE(this, ptr) (ptr)->Release()
92 // Clients can define |NSCAP_LOG_ASSIGNMENT| to perform logging.
93 #ifdef NSCAP_LOG_ASSIGNMENT
94 // Remember that |NSCAP_LOG_ASSIGNMENT| was defined by some client so that we
95 // know to instantiate |~nsGetterAddRefs| in turn to note the external
96 // assignment into the |nsCOMPtr|.
97 # define NSCAP_LOG_EXTERNAL_ASSIGNMENT
99 // ...otherwise, just strip it out of the code
100 # define NSCAP_LOG_ASSIGNMENT(this, ptr)
103 #ifndef NSCAP_LOG_RELEASE
104 # define NSCAP_LOG_RELEASE(this, ptr)
110 } // namespace mozilla
113 inline already_AddRefed
<T
> dont_AddRef(T
* aRawPtr
) {
114 return already_AddRefed
<T
>(aRawPtr
);
118 inline already_AddRefed
<T
>&& dont_AddRef(
119 already_AddRefed
<T
>&& aAlreadyAddRefedPtr
) {
120 return std::move(aAlreadyAddRefedPtr
);
124 * An nsCOMPtr_helper transforms commonly called getters into typesafe forms
125 * that are more convenient to call, and more efficient to use with |nsCOMPtr|s.
126 * Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc.
128 * Here are the rules for a helper:
129 * - it implements |operator()| to produce an interface pointer
130 * - (except for its name) |operator()| is a valid [XP]COM `getter'
131 * - the interface pointer that it returns is already |AddRef()|ed (as from
133 * - it matches the type requested with the supplied |nsIID| argument
134 * - its constructor provides an optional |nsresult*| that |operator()| can
135 * fill in with an error when it is executed
137 * See |class nsGetInterface| for an example.
139 class MOZ_STACK_CLASS nsCOMPtr_helper
{
141 virtual nsresult NS_FASTCALL
operator()(const nsIID
&, void**) const = 0;
145 * nsQueryInterface could have been implemented as an nsCOMPtr_helper to avoid
146 * adding specialized machinery in nsCOMPtr, but do_QueryInterface is called
147 * often enough that the codesize savings are big enough to warrant the
150 class MOZ_STACK_CLASS nsQueryInterfaceISupports
{
152 explicit nsQueryInterfaceISupports(nsISupports
* aRawPtr
) : mRawPtr(aRawPtr
) {}
154 nsresult NS_FASTCALL
operator()(const nsIID
& aIID
, void**) const;
157 nsISupports
* MOZ_OWNING_REF mRawPtr
;
160 #ifndef NSCAP_FEATURE_USE_BASE
161 template <typename T
>
162 class MOZ_STACK_CLASS nsQueryInterface final
163 : public nsQueryInterfaceISupports
{
165 explicit nsQueryInterface(T
* aRawPtr
)
166 : nsQueryInterfaceISupports(ToSupports(aRawPtr
)) {}
168 nsresult NS_FASTCALL
operator()(const nsIID
& aIID
, void** aAnswer
) const {
169 return nsQueryInterfaceISupports::operator()(aIID
, aAnswer
);
172 #endif // #ifndef NSCAP_FEATURE_USE_BASE
174 class MOZ_STACK_CLASS nsQueryInterfaceISupportsWithError
{
176 nsQueryInterfaceISupportsWithError(nsISupports
* aRawPtr
, nsresult
* aError
)
177 : mRawPtr(aRawPtr
), mErrorPtr(aError
) {}
179 nsresult NS_FASTCALL
operator()(const nsIID
& aIID
, void**) const;
182 nsISupports
* MOZ_OWNING_REF mRawPtr
;
186 #ifndef NSCAP_FEATURE_USE_BASE
187 template <typename T
>
188 class MOZ_STACK_CLASS nsQueryInterfaceWithError final
189 : public nsQueryInterfaceISupportsWithError
{
191 explicit nsQueryInterfaceWithError(T
* aRawPtr
, nsresult
* aError
)
192 : nsQueryInterfaceISupportsWithError(ToSupports(aRawPtr
), aError
) {}
194 nsresult NS_FASTCALL
operator()(const nsIID
& aIID
, void** aAnswer
) const {
195 return nsQueryInterfaceISupportsWithError::operator()(aIID
, aAnswer
);
198 #endif // #ifndef NSCAP_FEATURE_USE_BASE
201 // PointedToType<> is needed so that do_QueryInterface() will work with a
202 // variety of smart pointer types in addition to raw pointers. These types
203 // include RefPtr<>, nsCOMPtr<>, and OwningNonNull<>.
205 using PointedToType
= std::remove_pointer_t
<decltype(&*std::declval
<T
>())>;
206 } // namespace mozilla
208 #ifdef NSCAP_FEATURE_USE_BASE
210 inline nsQueryInterfaceISupports
do_QueryInterface(T aPtr
) {
211 return nsQueryInterfaceISupports(
212 ToSupports(static_cast<mozilla::PointedToType
<T
>*>(aPtr
)));
216 inline nsQueryInterfaceISupportsWithError
do_QueryInterface(T aPtr
,
218 return nsQueryInterfaceISupportsWithError(
219 ToSupports(static_cast<mozilla::PointedToType
<T
>*>(aPtr
)), aError
);
223 inline nsQueryInterface
<mozilla::PointedToType
<T
>> do_QueryInterface(T aPtr
) {
224 return nsQueryInterface
<mozilla::PointedToType
<T
>>(aPtr
);
228 inline nsQueryInterfaceWithError
<mozilla::PointedToType
<T
>> do_QueryInterface(
229 T aRawPtr
, nsresult
* aError
) {
230 return nsQueryInterfaceWithError
<mozilla::PointedToType
<T
>>(aRawPtr
, aError
);
233 #endif // ! #ifdef NSCAP_FEATURE_USE_BASE
236 inline void do_QueryInterface(already_AddRefed
<T
>&) {
237 // This signature exists solely to _stop_ you from doing the bad thing.
238 // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
239 // someone else is an automatic leak. See bug 8221.
243 inline void do_QueryInterface(already_AddRefed
<T
>&, nsresult
*) {
244 // This signature exists solely to _stop_ you from doing the bad thing.
245 // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
246 // someone else is an automatic leak. See bug 8221.
249 ////////////////////////////////////////////////////////////////////////////
250 // Using servicemanager with COMPtrs
251 class nsGetServiceByCID final
{
253 explicit nsGetServiceByCID(const nsCID
& aCID
) : mCID(aCID
) {}
255 nsresult NS_FASTCALL
operator()(const nsIID
&, void**) const;
261 class nsGetServiceByCIDWithError final
{
263 nsGetServiceByCIDWithError(const nsCID
& aCID
, nsresult
* aErrorPtr
)
264 : mCID(aCID
), mErrorPtr(aErrorPtr
) {}
266 nsresult NS_FASTCALL
operator()(const nsIID
&, void**) const;
273 class nsGetServiceByContractID final
{
275 explicit nsGetServiceByContractID(const char* aContractID
)
276 : mContractID(aContractID
) {}
278 nsresult NS_FASTCALL
operator()(const nsIID
&, void**) const;
281 const char* mContractID
;
284 class nsGetServiceByContractIDWithError final
{
286 nsGetServiceByContractIDWithError(const char* aContractID
,
288 : mContractID(aContractID
), mErrorPtr(aErrorPtr
) {}
290 nsresult NS_FASTCALL
operator()(const nsIID
&, void**) const;
293 const char* mContractID
;
297 class nsIWeakReference
;
300 class MOZ_STACK_CLASS nsQueryReferent final
{
302 nsQueryReferent(nsIWeakReference
* aWeakPtr
, nsresult
* aError
)
303 : mWeakPtr(aWeakPtr
), mErrorPtr(aError
) {}
305 nsresult NS_FASTCALL
operator()(const nsIID
& aIID
, void**) const;
308 nsIWeakReference
* MOZ_NON_OWNING_REF mWeakPtr
;
313 * Factors implementation for all template versions of nsCOMPtr.
315 * Here's the way people normally do things like this:
317 * template<class T> class Foo { ... };
318 * template<> class Foo<void*> { ... };
319 * template<class T> class Foo<T*> : private Foo<void*> { ... };
321 class nsCOMPtr_base
{
323 explicit nsCOMPtr_base(nsISupports
* aRawPtr
= nullptr) : mRawPtr(aRawPtr
) {}
325 NS_CONSTRUCTOR_FASTCALL
~nsCOMPtr_base() {
326 NSCAP_LOG_RELEASE(this, mRawPtr
);
328 NSCAP_RELEASE(this, mRawPtr
);
332 void NS_FASTCALL
assign_with_AddRef(nsISupports
*);
333 void NS_FASTCALL
assign_from_qi(const nsQueryInterfaceISupports
,
335 void NS_FASTCALL
assign_from_qi_with_error(
336 const nsQueryInterfaceISupportsWithError
&, const nsIID
&);
337 void NS_FASTCALL
assign_from_gs_cid(const nsGetServiceByCID
, const nsIID
&);
338 void NS_FASTCALL
assign_from_gs_cid_with_error(
339 const nsGetServiceByCIDWithError
&, const nsIID
&);
340 void NS_FASTCALL
assign_from_gs_contractid(const nsGetServiceByContractID
,
342 void NS_FASTCALL
assign_from_gs_contractid_with_error(
343 const nsGetServiceByContractIDWithError
&, const nsIID
&);
344 void NS_FASTCALL
assign_from_query_referent(const nsQueryReferent
&,
346 void NS_FASTCALL
assign_from_helper(const nsCOMPtr_helper
&, const nsIID
&);
347 // Since in most cases, begin_assignment is called on a default-constructed
348 // nsCOMPtr, the call to assign_assuming_AddRef becomes a no-op in release
349 // builds. However, the compiler does not always optimize this away and emits a
350 // call to begin_assignment without MOZ_ALWAYS_INLINE. When logging is enabled,
351 // this might cause code bloat, so we MOZ_NEVER_INLINE in that case.
352 #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
357 void** NS_FASTCALL
begin_assignment() {
358 assign_assuming_AddRef(nullptr);
359 return reinterpret_cast<void**>(&mRawPtr
);
363 NS_MAY_ALIAS_PTR(nsISupports
) MOZ_OWNING_REF mRawPtr
;
365 void assign_assuming_AddRef(nsISupports
* aNewPtr
) {
366 // |AddRef()|ing the new value (before entering this function) before
367 // |Release()|ing the old lets us safely ignore the self-assignment case.
368 // We must, however, be careful only to |Release()| _after_ doing the
369 // assignment, in case the |Release()| leads to our _own_ destruction,
370 // which would, in turn, cause an incorrect second |Release()| of our old
371 // pointer. Thank <waterson@netscape.com> for discovering this.
372 nsISupports
* oldPtr
= mRawPtr
;
374 NSCAP_LOG_ASSIGNMENT(this, aNewPtr
);
375 NSCAP_LOG_RELEASE(this, oldPtr
);
377 NSCAP_RELEASE(this, oldPtr
);
382 // template<class T> class nsGetterAddRefs;
384 // Helper for assert_validity method
386 char (&TestForIID(decltype(&NS_GET_TEMPLATE_IID(T
))))[2];
388 char TestForIID(...);
391 class MOZ_IS_REFPTR nsCOMPtr final
392 #ifdef NSCAP_FEATURE_USE_BASE
393 : private nsCOMPtr_base
397 #ifdef NSCAP_FEATURE_USE_BASE
398 # define NSCAP_CTOR_BASE(x) nsCOMPtr_base(ToSupports(x))
399 void assign_assuming_AddRef(T
* aNewPtr
) {
400 nsCOMPtr_base::assign_assuming_AddRef(ToSupports(aNewPtr
));
403 # define NSCAP_CTOR_BASE(x) mRawPtr(x)
405 void assign_with_AddRef(nsISupports
*);
406 template <typename U
>
407 void assign_from_qi(const nsQueryInterface
<U
>, const nsIID
&);
408 template <typename U
>
409 void assign_from_qi_with_error(const nsQueryInterfaceWithError
<U
>&,
411 void assign_from_gs_cid(const nsGetServiceByCID
, const nsIID
&);
412 void assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError
&,
414 void assign_from_gs_contractid(const nsGetServiceByContractID
, const nsIID
&);
415 void assign_from_gs_contractid_with_error(
416 const nsGetServiceByContractIDWithError
&, const nsIID
&);
417 void assign_from_query_referent(const nsQueryReferent
&, const nsIID
&);
418 void assign_from_helper(const nsCOMPtr_helper
&, const nsIID
&);
419 void** begin_assignment();
421 void assign_assuming_AddRef(T
* aNewPtr
) {
424 NSCAP_LOG_ASSIGNMENT(this, aNewPtr
);
425 NSCAP_LOG_RELEASE(this, oldPtr
);
427 NSCAP_RELEASE(this, oldPtr
);
432 T
* MOZ_OWNING_REF mRawPtr
;
435 void assert_validity() {
436 static_assert(1 < sizeof(TestForIID
<T
>(nullptr)),
437 "nsCOMPtr only works "
438 "for types with IIDs. Either use RefPtr; add an IID to "
439 "your type with NS_DECLARE_STATIC_IID_ACCESSOR/"
440 "NS_DEFINE_STATIC_IID_ACCESSOR; or make the nsCOMPtr point "
441 "to a base class with an IID.");
445 typedef T element_type
;
447 #ifndef NSCAP_FEATURE_USE_BASE
449 NSCAP_LOG_RELEASE(this, mRawPtr
);
451 NSCAP_RELEASE(this, mRawPtr
);
456 #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
457 void Assert_NoQueryNeeded() {
459 // This can't be defined in terms of do_QueryInterface because
460 // that bans casts from a class to itself.
462 mRawPtr
->QueryInterface(NS_GET_TEMPLATE_IID(T
), &out
);
463 T
* query_result
= static_cast<T
*>(out
);
464 MOZ_ASSERT(query_result
== mRawPtr
, "QueryInterface needed");
465 NS_RELEASE(query_result
);
469 # define NSCAP_ASSERT_NO_QUERY_NEEDED() Assert_NoQueryNeeded();
471 # define NSCAP_ASSERT_NO_QUERY_NEEDED()
476 nsCOMPtr() : NSCAP_CTOR_BASE(nullptr) {
478 NSCAP_LOG_ASSIGNMENT(this, nullptr);
481 MOZ_IMPLICIT
nsCOMPtr(decltype(nullptr)) : NSCAP_CTOR_BASE(nullptr) {
483 NSCAP_LOG_ASSIGNMENT(this, nullptr);
486 nsCOMPtr(const nsCOMPtr
<T
>& aSmartPtr
) : NSCAP_CTOR_BASE(aSmartPtr
.mRawPtr
) {
489 NSCAP_ADDREF(this, mRawPtr
);
491 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr
.mRawPtr
);
495 MOZ_IMPLICIT
nsCOMPtr(const nsCOMPtr
<U
>& aSmartPtr
)
496 : NSCAP_CTOR_BASE(aSmartPtr
.get()) {
497 // Make sure that U actually inherits from T
498 static_assert(std::is_base_of
<T
, U
>::value
, "U should be a subclass of T");
501 NSCAP_ADDREF(this, mRawPtr
);
503 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr
.get());
506 nsCOMPtr(nsCOMPtr
<T
>&& aSmartPtr
) : NSCAP_CTOR_BASE(aSmartPtr
.mRawPtr
) {
508 aSmartPtr
.mRawPtr
= nullptr;
509 NSCAP_LOG_ASSIGNMENT(this, mRawPtr
);
513 MOZ_IMPLICIT
nsCOMPtr(nsCOMPtr
<U
>&& aSmartPtr
)
514 : NSCAP_CTOR_BASE(aSmartPtr
.forget().template downcast
<T
>().take()) {
515 // Make sure that U actually inherits from T
516 static_assert(std::is_base_of
<T
, U
>::value
, "U should be a subclass of T");
518 NSCAP_LOG_ASSIGNMENT(this, mRawPtr
);
519 NSCAP_ASSERT_NO_QUERY_NEEDED();
522 MOZ_IMPLICIT
nsCOMPtr(T
* aRawPtr
) : NSCAP_CTOR_BASE(aRawPtr
) {
525 NSCAP_ADDREF(this, mRawPtr
);
527 NSCAP_LOG_ASSIGNMENT(this, aRawPtr
);
528 NSCAP_ASSERT_NO_QUERY_NEEDED();
531 MOZ_IMPLICIT
nsCOMPtr(already_AddRefed
<T
>& aSmartPtr
)
532 : NSCAP_CTOR_BASE(aSmartPtr
.take()) {
534 NSCAP_LOG_ASSIGNMENT(this, mRawPtr
);
535 NSCAP_ASSERT_NO_QUERY_NEEDED();
538 // Construct from |otherComPtr.forget()|.
539 MOZ_IMPLICIT
nsCOMPtr(already_AddRefed
<T
>&& aSmartPtr
)
540 : NSCAP_CTOR_BASE(aSmartPtr
.take()) {
542 NSCAP_LOG_ASSIGNMENT(this, mRawPtr
);
543 NSCAP_ASSERT_NO_QUERY_NEEDED();
546 // Construct from |std::move(otherRefPtr)|.
547 template <typename U
>
548 MOZ_IMPLICIT
nsCOMPtr(RefPtr
<U
>&& aSmartPtr
)
550 static_cast<already_AddRefed
<T
>>(aSmartPtr
.forget()).take()) {
552 // Make sure that U actually inherits from T
553 static_assert(std::is_base_of
<T
, U
>::value
, "U is not a subclass of T");
554 NSCAP_LOG_ASSIGNMENT(this, mRawPtr
);
555 NSCAP_ASSERT_NO_QUERY_NEEDED();
558 // Construct from |already_AddRefed|.
559 template <typename U
>
560 MOZ_IMPLICIT
nsCOMPtr(already_AddRefed
<U
>& aSmartPtr
)
561 : NSCAP_CTOR_BASE(static_cast<T
*>(aSmartPtr
.take())) {
563 // But make sure that U actually inherits from T.
564 static_assert(std::is_base_of
<T
, U
>::value
, "U is not a subclass of T");
565 NSCAP_LOG_ASSIGNMENT(this, static_cast<T
*>(mRawPtr
));
566 NSCAP_ASSERT_NO_QUERY_NEEDED();
569 // Construct from |otherComPtr.forget()|.
570 template <typename U
>
571 MOZ_IMPLICIT
nsCOMPtr(already_AddRefed
<U
>&& aSmartPtr
)
572 : NSCAP_CTOR_BASE(static_cast<T
*>(aSmartPtr
.take())) {
574 // But make sure that U actually inherits from T.
575 static_assert(std::is_base_of
<T
, U
>::value
, "U is not a subclass of T");
576 NSCAP_LOG_ASSIGNMENT(this, static_cast<T
*>(mRawPtr
));
577 NSCAP_ASSERT_NO_QUERY_NEEDED();
580 // Construct from |do_QueryInterface(expr)|.
581 #ifdef NSCAP_FEATURE_USE_BASE
582 MOZ_IMPLICIT
nsCOMPtr(const nsQueryInterfaceISupports aQI
)
584 template <typename U
>
585 MOZ_IMPLICIT
nsCOMPtr(const nsQueryInterface
<U
> aQI
)
586 #endif // ! #ifdef NSCAP_FEATURE_USE_BASE
587 : NSCAP_CTOR_BASE(nullptr) {
589 NSCAP_LOG_ASSIGNMENT(this, nullptr);
590 assign_from_qi(aQI
, NS_GET_TEMPLATE_IID(T
));
593 // Construct from |do_QueryInterface(expr, &rv)|.
594 #ifdef NSCAP_FEATURE_USE_BASE
595 MOZ_IMPLICIT
nsCOMPtr(const nsQueryInterfaceISupportsWithError
& aQI
)
597 template <typename U
>
598 MOZ_IMPLICIT
nsCOMPtr(const nsQueryInterfaceWithError
<U
>& aQI
)
599 #endif // ! #ifdef NSCAP_FEATURE_USE_BASE
600 : NSCAP_CTOR_BASE(nullptr) {
602 NSCAP_LOG_ASSIGNMENT(this, nullptr);
603 assign_from_qi_with_error(aQI
, NS_GET_TEMPLATE_IID(T
));
606 // Construct from |do_GetService(cid_expr)|.
607 MOZ_IMPLICIT
nsCOMPtr(const nsGetServiceByCID aGS
)
608 : NSCAP_CTOR_BASE(nullptr) {
610 NSCAP_LOG_ASSIGNMENT(this, nullptr);
611 assign_from_gs_cid(aGS
, NS_GET_TEMPLATE_IID(T
));
614 // Construct from |do_GetService(cid_expr, &rv)|.
615 MOZ_IMPLICIT
nsCOMPtr(const nsGetServiceByCIDWithError
& aGS
)
616 : NSCAP_CTOR_BASE(nullptr) {
618 NSCAP_LOG_ASSIGNMENT(this, nullptr);
619 assign_from_gs_cid_with_error(aGS
, NS_GET_TEMPLATE_IID(T
));
622 // Construct from |do_GetService(contractid_expr)|.
623 MOZ_IMPLICIT
nsCOMPtr(const nsGetServiceByContractID aGS
)
624 : NSCAP_CTOR_BASE(nullptr) {
626 NSCAP_LOG_ASSIGNMENT(this, nullptr);
627 assign_from_gs_contractid(aGS
, NS_GET_TEMPLATE_IID(T
));
630 // Construct from |do_GetService(contractid_expr, &rv)|.
631 MOZ_IMPLICIT
nsCOMPtr(const nsGetServiceByContractIDWithError
& aGS
)
632 : NSCAP_CTOR_BASE(nullptr) {
634 NSCAP_LOG_ASSIGNMENT(this, nullptr);
635 assign_from_gs_contractid_with_error(aGS
, NS_GET_TEMPLATE_IID(T
));
638 // Construct from |do_QueryReferent(ptr)|
639 MOZ_IMPLICIT
nsCOMPtr(const nsQueryReferent
& aQueryReferent
)
640 : NSCAP_CTOR_BASE(nullptr) {
642 NSCAP_LOG_ASSIGNMENT(this, nullptr);
643 assign_from_query_referent(aQueryReferent
, NS_GET_TEMPLATE_IID(T
));
646 // And finally, anything else we might need to construct from can exploit the
647 // nsCOMPtr_helper facility.
648 MOZ_IMPLICIT
nsCOMPtr(const nsCOMPtr_helper
& aHelper
)
649 : NSCAP_CTOR_BASE(nullptr) {
651 NSCAP_LOG_ASSIGNMENT(this, nullptr);
652 assign_from_helper(aHelper
, NS_GET_TEMPLATE_IID(T
));
653 NSCAP_ASSERT_NO_QUERY_NEEDED();
656 // construct from |mozilla::NotNull|.
657 template <typename I
,
658 typename
= std::enable_if_t
<!std::is_same_v
<I
, nsCOMPtr
<T
>> &&
659 std::is_convertible_v
<I
, nsCOMPtr
<T
>>>>
660 MOZ_IMPLICIT
nsCOMPtr(const mozilla::NotNull
<I
>& aSmartPtr
)
661 : NSCAP_CTOR_BASE(nsCOMPtr
<T
>(aSmartPtr
.get()).forget().take()) {}
663 // construct from |mozilla::MovingNotNull|.
664 template <typename I
,
665 typename
= std::enable_if_t
<!std::is_same_v
<I
, nsCOMPtr
<T
>> &&
666 std::is_convertible_v
<I
, nsCOMPtr
<T
>>>>
667 MOZ_IMPLICIT
nsCOMPtr(mozilla::MovingNotNull
<I
>&& aSmartPtr
)
669 nsCOMPtr
<T
>(std::move(aSmartPtr
).unwrapBasePtr()).forget().take()) {
672 // Defined in OwningNonNull.h
674 MOZ_IMPLICIT
nsCOMPtr(const mozilla::OwningNonNull
<U
>& aOther
);
676 // Assignment operators
678 nsCOMPtr
<T
>& operator=(const nsCOMPtr
<T
>& aRhs
) {
679 assign_with_AddRef(ToSupports(aRhs
.mRawPtr
));
684 nsCOMPtr
<T
>& operator=(const nsCOMPtr
<U
>& aRhs
) {
685 // Make sure that U actually inherits from T
686 static_assert(std::is_base_of
<T
, U
>::value
, "U should be a subclass of T");
687 assign_with_AddRef(ToSupports(static_cast<T
*>(aRhs
.get())));
691 nsCOMPtr
<T
>& operator=(nsCOMPtr
<T
>&& aRhs
) {
692 assign_assuming_AddRef(aRhs
.forget().take());
697 nsCOMPtr
<T
>& operator=(nsCOMPtr
<U
>&& aRhs
) {
698 // Make sure that U actually inherits from T
699 static_assert(std::is_base_of
<T
, U
>::value
, "U should be a subclass of T");
700 assign_assuming_AddRef(aRhs
.forget().template downcast
<T
>().take());
701 NSCAP_ASSERT_NO_QUERY_NEEDED();
705 nsCOMPtr
<T
>& operator=(T
* aRhs
) {
706 assign_with_AddRef(ToSupports(aRhs
));
707 NSCAP_ASSERT_NO_QUERY_NEEDED();
711 nsCOMPtr
<T
>& operator=(decltype(nullptr)) {
712 assign_assuming_AddRef(nullptr);
716 // Assign from |already_AddRefed|.
717 template <typename U
>
718 nsCOMPtr
<T
>& operator=(already_AddRefed
<U
>& aRhs
) {
719 // Make sure that U actually inherits from T
720 static_assert(std::is_base_of
<T
, U
>::value
, "U is not a subclass of T");
721 assign_assuming_AddRef(static_cast<T
*>(aRhs
.take()));
722 NSCAP_ASSERT_NO_QUERY_NEEDED();
726 // Assign from |otherComPtr.forget()|.
727 template <typename U
>
728 nsCOMPtr
<T
>& operator=(already_AddRefed
<U
>&& aRhs
) {
729 // Make sure that U actually inherits from T
730 static_assert(std::is_base_of
<T
, U
>::value
, "U is not a subclass of T");
731 assign_assuming_AddRef(static_cast<T
*>(aRhs
.take()));
732 NSCAP_ASSERT_NO_QUERY_NEEDED();
736 // Assign from |std::move(otherRefPtr)|.
737 template <typename U
>
738 nsCOMPtr
<T
>& operator=(RefPtr
<U
>&& aRhs
) {
739 // Make sure that U actually inherits from T
740 static_assert(std::is_base_of
<T
, U
>::value
, "U is not a subclass of T");
741 assign_assuming_AddRef(static_cast<T
*>(aRhs
.forget().take()));
742 NSCAP_ASSERT_NO_QUERY_NEEDED();
746 // Assign from |do_QueryInterface(expr)|.
747 #ifdef NSCAP_FEATURE_USE_BASE
748 nsCOMPtr
<T
>& operator=(const nsQueryInterfaceISupports aRhs
)
750 template <typename U
>
751 nsCOMPtr
<T
>& operator=(const nsQueryInterface
<U
> aRhs
)
752 #endif // ! #ifdef NSCAP_FEATURE_USE_BASE
754 assign_from_qi(aRhs
, NS_GET_TEMPLATE_IID(T
));
758 // Assign from |do_QueryInterface(expr, &rv)|.
759 #ifdef NSCAP_FEATURE_USE_BASE
760 nsCOMPtr
<T
>& operator=(const nsQueryInterfaceISupportsWithError
& aRhs
)
762 template <typename U
>
763 nsCOMPtr
<T
>& operator=(const nsQueryInterfaceWithError
<U
>& aRhs
)
764 #endif // ! #ifdef NSCAP_FEATURE_USE_BASE
766 assign_from_qi_with_error(aRhs
, NS_GET_TEMPLATE_IID(T
));
770 // Assign from |do_GetService(cid_expr)|.
771 nsCOMPtr
<T
>& operator=(const nsGetServiceByCID aRhs
) {
772 assign_from_gs_cid(aRhs
, NS_GET_TEMPLATE_IID(T
));
776 // Assign from |do_GetService(cid_expr, &rv)|.
777 nsCOMPtr
<T
>& operator=(const nsGetServiceByCIDWithError
& aRhs
) {
778 assign_from_gs_cid_with_error(aRhs
, NS_GET_TEMPLATE_IID(T
));
782 // Assign from |do_GetService(contractid_expr)|.
783 nsCOMPtr
<T
>& operator=(const nsGetServiceByContractID aRhs
) {
784 assign_from_gs_contractid(aRhs
, NS_GET_TEMPLATE_IID(T
));
788 // Assign from |do_GetService(contractid_expr, &rv)|.
789 nsCOMPtr
<T
>& operator=(const nsGetServiceByContractIDWithError
& aRhs
) {
790 assign_from_gs_contractid_with_error(aRhs
, NS_GET_TEMPLATE_IID(T
));
794 // Assign from |do_QueryReferent(ptr)|.
795 nsCOMPtr
<T
>& operator=(const nsQueryReferent
& aRhs
) {
796 assign_from_query_referent(aRhs
, NS_GET_TEMPLATE_IID(T
));
800 // And finally, anything else we might need to assign from can exploit the
801 // nsCOMPtr_helper facility.
802 nsCOMPtr
<T
>& operator=(const nsCOMPtr_helper
& aRhs
) {
803 assign_from_helper(aRhs
, NS_GET_TEMPLATE_IID(T
));
804 NSCAP_ASSERT_NO_QUERY_NEEDED();
808 // Assign from |mozilla::NotNull|.
809 template <typename I
,
810 typename
= std::enable_if_t
<std::is_convertible_v
<I
, nsCOMPtr
<T
>>>>
811 nsCOMPtr
<T
>& operator=(const mozilla::NotNull
<I
>& aSmartPtr
) {
812 assign_assuming_AddRef(nsCOMPtr
<T
>(aSmartPtr
.get()).forget().take());
816 // Assign from |mozilla::MovingNotNull|.
817 template <typename I
,
818 typename
= std::enable_if_t
<std::is_convertible_v
<I
, nsCOMPtr
<T
>>>>
819 nsCOMPtr
<T
>& operator=(mozilla::MovingNotNull
<I
>&& aSmartPtr
) {
820 assign_assuming_AddRef(
821 nsCOMPtr
<T
>(std::move(aSmartPtr
).unwrapBasePtr()).forget().take());
825 // Defined in OwningNonNull.h
827 nsCOMPtr
<T
>& operator=(const mozilla::OwningNonNull
<U
>& aOther
);
829 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
830 void swap(nsCOMPtr
<T
>& aRhs
) {
831 #ifdef NSCAP_FEATURE_USE_BASE
832 nsISupports
* temp
= aRhs
.mRawPtr
;
834 T
* temp
= aRhs
.mRawPtr
;
836 NSCAP_LOG_ASSIGNMENT(&aRhs
, mRawPtr
);
837 NSCAP_LOG_ASSIGNMENT(this, temp
);
838 NSCAP_LOG_RELEASE(this, mRawPtr
);
839 NSCAP_LOG_RELEASE(&aRhs
, temp
);
840 aRhs
.mRawPtr
= mRawPtr
;
842 // |aRhs| maintains the same invariants, so we don't need to
843 // |NSCAP_ASSERT_NO_QUERY_NEEDED|
846 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
847 void swap(T
*& aRhs
) {
848 #ifdef NSCAP_FEATURE_USE_BASE
849 nsISupports
* temp
= ToSupports(aRhs
);
853 NSCAP_LOG_ASSIGNMENT(this, temp
);
854 NSCAP_LOG_RELEASE(this, mRawPtr
);
855 aRhs
= reinterpret_cast<T
*>(mRawPtr
);
857 NSCAP_ASSERT_NO_QUERY_NEEDED();
860 // Other pointer operators
862 // Return the value of mRawPtr and null out mRawPtr. Useful for
863 // already_AddRefed return values.
864 already_AddRefed
<T
> MOZ_MAY_CALL_AFTER_MUST_RETURN
forget() {
867 return already_AddRefed
<T
>(temp
);
870 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
871 // Useful to avoid unnecessary AddRef/Release pairs with "out" parameters
872 // where aRhs bay be a T** or an I** where I is a base class of T.
873 template <typename I
>
874 void forget(I
** aRhs
) {
875 NS_ASSERTION(aRhs
, "Null pointer passed to forget!");
876 NSCAP_LOG_RELEASE(this, mRawPtr
);
881 // Prefer the implicit conversion provided automatically by
882 // |operator T*() const|. Use |get()| to resolve ambiguity or to get a
884 T
* get() const { return reinterpret_cast<T
*>(mRawPtr
); }
886 // Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
887 // used in a context where a raw pointer is expected. It is this operator
888 // that makes an nsCOMPtr substitutable for a raw pointer.
890 // Prefer the implicit use of this operator to calling |get()|, except where
891 // necessary to resolve ambiguity.
892 operator T
*() const& { return get(); }
894 // Don't allow implicit conversion of temporary nsCOMPtr to raw pointer,
895 // because the refcount might be one and the pointer will immediately become
897 operator T
*() const&& = delete;
899 // Needed to avoid the deleted operator above
900 explicit operator bool() const { return !!mRawPtr
; }
902 T
* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
{
903 MOZ_ASSERT(mRawPtr
!= nullptr,
904 "You can't dereference a NULL nsCOMPtr with operator->().");
908 // These are not intended to be used by clients. See |address_of| below.
909 nsCOMPtr
<T
>* get_address() { return this; }
910 const nsCOMPtr
<T
>* get_address() const { return this; }
913 T
& operator*() const {
914 MOZ_ASSERT(mRawPtr
!= nullptr,
915 "You can't dereference a NULL nsCOMPtr with operator*().");
919 T
** StartAssignment() {
920 #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
921 return reinterpret_cast<T
**>(begin_assignment());
923 assign_assuming_AddRef(nullptr);
924 return reinterpret_cast<T
**>(&mRawPtr
);
930 * Specializing nsCOMPtr for nsISupports allows us to use nsCOMPtr<nsISupports>
931 * the same way people use nsISupports* and void*, i.e., as a `catch-all'
932 * pointing to any valid [XP]COM interface. Otherwise, an nsCOMPtr<nsISupports>
933 * would only be able to point to the single [XP]COM-correct nsISupports
934 * instance within an object; extra querying ensues. Clients need to be able to
935 * pass around arbitrary interface pointers, without hassles, through
936 * intermediary code that doesn't know the exact type.
939 class MOZ_IS_REFPTR nsCOMPtr
<nsISupports
> : private nsCOMPtr_base
{
941 typedef nsISupports element_type
;
945 nsCOMPtr() : nsCOMPtr_base(nullptr) { NSCAP_LOG_ASSIGNMENT(this, nullptr); }
947 MOZ_IMPLICIT
nsCOMPtr(decltype(nullptr)) : nsCOMPtr_base(nullptr) {
948 NSCAP_LOG_ASSIGNMENT(this, nullptr);
951 nsCOMPtr(const nsCOMPtr
<nsISupports
>& aSmartPtr
)
952 : nsCOMPtr_base(aSmartPtr
.mRawPtr
) {
954 NSCAP_ADDREF(this, mRawPtr
);
956 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr
.mRawPtr
);
959 MOZ_IMPLICIT
nsCOMPtr(nsISupports
* aRawPtr
) : nsCOMPtr_base(aRawPtr
) {
961 NSCAP_ADDREF(this, mRawPtr
);
963 NSCAP_LOG_ASSIGNMENT(this, aRawPtr
);
966 // Construct from |already_AddRefed|.
967 MOZ_IMPLICIT
nsCOMPtr(already_AddRefed
<nsISupports
>& aSmartPtr
)
968 : nsCOMPtr_base(aSmartPtr
.take()) {
969 NSCAP_LOG_ASSIGNMENT(this, mRawPtr
);
972 // Construct from |otherComPtr.forget()|.
973 MOZ_IMPLICIT
nsCOMPtr(already_AddRefed
<nsISupports
>&& aSmartPtr
)
974 : nsCOMPtr_base(aSmartPtr
.take()) {
975 NSCAP_LOG_ASSIGNMENT(this, mRawPtr
);
978 // Construct from |do_QueryInterface(expr)|.
979 MOZ_IMPLICIT
nsCOMPtr(const nsQueryInterfaceISupports aQI
)
980 : nsCOMPtr_base(nullptr) {
981 NSCAP_LOG_ASSIGNMENT(this, nullptr);
982 assign_from_qi(aQI
, NS_GET_IID(nsISupports
));
985 // Construct from |do_QueryInterface(expr, &rv)|.
986 MOZ_IMPLICIT
nsCOMPtr(const nsQueryInterfaceISupportsWithError
& aQI
)
987 : nsCOMPtr_base(nullptr) {
988 NSCAP_LOG_ASSIGNMENT(this, nullptr);
989 assign_from_qi_with_error(aQI
, NS_GET_IID(nsISupports
));
992 // Construct from |do_GetService(cid_expr)|.
993 MOZ_IMPLICIT
nsCOMPtr(const nsGetServiceByCID aGS
) : nsCOMPtr_base(nullptr) {
994 NSCAP_LOG_ASSIGNMENT(this, nullptr);
995 assign_from_gs_cid(aGS
, NS_GET_IID(nsISupports
));
998 // Construct from |do_GetService(cid_expr, &rv)|.
999 MOZ_IMPLICIT
nsCOMPtr(const nsGetServiceByCIDWithError
& aGS
)
1000 : nsCOMPtr_base(nullptr) {
1001 NSCAP_LOG_ASSIGNMENT(this, nullptr);
1002 assign_from_gs_cid_with_error(aGS
, NS_GET_IID(nsISupports
));
1005 // Construct from |do_GetService(contractid_expr)|.
1006 MOZ_IMPLICIT
nsCOMPtr(const nsGetServiceByContractID aGS
)
1007 : nsCOMPtr_base(nullptr) {
1008 NSCAP_LOG_ASSIGNMENT(this, nullptr);
1009 assign_from_gs_contractid(aGS
, NS_GET_IID(nsISupports
));
1012 // Construct from |do_GetService(contractid_expr, &rv)|.
1013 MOZ_IMPLICIT
nsCOMPtr(const nsGetServiceByContractIDWithError
& aGS
)
1014 : nsCOMPtr_base(nullptr) {
1015 NSCAP_LOG_ASSIGNMENT(this, nullptr);
1016 assign_from_gs_contractid_with_error(aGS
, NS_GET_IID(nsISupports
));
1019 // Construct from |do_QueryReferent(ptr)|
1020 MOZ_IMPLICIT
nsCOMPtr(const nsQueryReferent
& aQueryReferent
)
1021 : nsCOMPtr_base(nullptr) {
1022 NSCAP_LOG_ASSIGNMENT(this, nullptr);
1023 assign_from_query_referent(aQueryReferent
,
1024 NS_GET_TEMPLATE_IID(nsISupports
));
1027 // And finally, anything else we might need to construct from can exploit
1028 // the |nsCOMPtr_helper| facility
1029 MOZ_IMPLICIT
nsCOMPtr(const nsCOMPtr_helper
& aHelper
)
1030 : nsCOMPtr_base(nullptr) {
1031 NSCAP_LOG_ASSIGNMENT(this, nullptr);
1032 assign_from_helper(aHelper
, NS_GET_IID(nsISupports
));
1035 // Assignment operators
1037 nsCOMPtr
<nsISupports
>& operator=(const nsCOMPtr
<nsISupports
>& aRhs
) {
1038 assign_with_AddRef(aRhs
.mRawPtr
);
1042 nsCOMPtr
<nsISupports
>& operator=(nsISupports
* aRhs
) {
1043 assign_with_AddRef(aRhs
);
1047 nsCOMPtr
<nsISupports
>& operator=(decltype(nullptr)) {
1048 assign_assuming_AddRef(nullptr);
1052 // Assign from |already_AddRefed|.
1053 nsCOMPtr
<nsISupports
>& operator=(already_AddRefed
<nsISupports
>& aRhs
) {
1054 assign_assuming_AddRef(aRhs
.take());
1058 // Assign from |otherComPtr.forget()|.
1059 nsCOMPtr
<nsISupports
>& operator=(already_AddRefed
<nsISupports
>&& aRhs
) {
1060 assign_assuming_AddRef(aRhs
.take());
1064 // Assign from |do_QueryInterface(expr)|.
1065 nsCOMPtr
<nsISupports
>& operator=(const nsQueryInterfaceISupports aRhs
) {
1066 assign_from_qi(aRhs
, NS_GET_IID(nsISupports
));
1070 // Assign from |do_QueryInterface(expr, &rv)|.
1071 nsCOMPtr
<nsISupports
>& operator=(
1072 const nsQueryInterfaceISupportsWithError
& aRhs
) {
1073 assign_from_qi_with_error(aRhs
, NS_GET_IID(nsISupports
));
1077 // Assign from |do_GetService(cid_expr)|.
1078 nsCOMPtr
<nsISupports
>& operator=(const nsGetServiceByCID aRhs
) {
1079 assign_from_gs_cid(aRhs
, NS_GET_IID(nsISupports
));
1083 // Assign from |do_GetService(cid_expr, &rv)|.
1084 nsCOMPtr
<nsISupports
>& operator=(const nsGetServiceByCIDWithError
& aRhs
) {
1085 assign_from_gs_cid_with_error(aRhs
, NS_GET_IID(nsISupports
));
1089 // Assign from |do_GetService(contractid_expr)|.
1090 nsCOMPtr
<nsISupports
>& operator=(const nsGetServiceByContractID aRhs
) {
1091 assign_from_gs_contractid(aRhs
, NS_GET_IID(nsISupports
));
1095 // Assign from |do_GetService(contractid_expr, &rv)|.
1096 nsCOMPtr
<nsISupports
>& operator=(
1097 const nsGetServiceByContractIDWithError
& aRhs
) {
1098 assign_from_gs_contractid_with_error(aRhs
, NS_GET_IID(nsISupports
));
1102 // Assign from |do_QueryReferent(ptr)|.
1103 nsCOMPtr
<nsISupports
>& operator=(const nsQueryReferent
& aRhs
) {
1104 assign_from_query_referent(aRhs
, NS_GET_TEMPLATE_IID(nsISupports
));
1108 // And finally, anything else we might need to assign from can exploit the
1109 // nsCOMPtr_helper facility
1110 nsCOMPtr
<nsISupports
>& operator=(const nsCOMPtr_helper
& aRhs
) {
1111 assign_from_helper(aRhs
, NS_GET_IID(nsISupports
));
1115 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
1116 void swap(nsCOMPtr
<nsISupports
>& aRhs
) {
1117 nsISupports
* temp
= aRhs
.mRawPtr
;
1118 NSCAP_LOG_ASSIGNMENT(&aRhs
, mRawPtr
);
1119 NSCAP_LOG_ASSIGNMENT(this, temp
);
1120 NSCAP_LOG_RELEASE(this, mRawPtr
);
1121 NSCAP_LOG_RELEASE(&aRhs
, temp
);
1122 aRhs
.mRawPtr
= mRawPtr
;
1126 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
1127 void swap(nsISupports
*& aRhs
) {
1128 nsISupports
* temp
= aRhs
;
1129 NSCAP_LOG_ASSIGNMENT(this, temp
);
1130 NSCAP_LOG_RELEASE(this, mRawPtr
);
1135 // Return the value of mRawPtr and null out mRawPtr. Useful for
1136 // already_AddRefed return values.
1137 already_AddRefed
<nsISupports
> forget() {
1138 nsISupports
* temp
= nullptr;
1140 return already_AddRefed
<nsISupports
>(temp
);
1143 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
1144 // Useful to avoid unnecessary AddRef/Release pairs with "out"
1146 void forget(nsISupports
** aRhs
) {
1147 NS_ASSERTION(aRhs
, "Null pointer passed to forget!");
1152 // Other pointer operators
1154 // Prefer the implicit conversion provided automatically by
1155 // |operator nsISupports*() const|. Use |get()| to resolve ambiguity or to
1156 // get a castable pointer.
1157 nsISupports
* get() const { return reinterpret_cast<nsISupports
*>(mRawPtr
); }
1159 // Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
1160 // used in a context where a raw pointer is expected. It is this operator
1161 // that makes an nsCOMPtr substitutable for a raw pointer.
1163 // Prefer the implicit use of this operator to calling |get()|, except where
1164 // necessary to resolve ambiguity/
1165 operator nsISupports
*() const { return get(); }
1167 nsISupports
* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
{
1168 MOZ_ASSERT(mRawPtr
!= nullptr,
1169 "You can't dereference a NULL nsCOMPtr with operator->().");
1173 // These are not intended to be used by clients. See |address_of| below.
1174 nsCOMPtr
<nsISupports
>* get_address() { return this; }
1175 const nsCOMPtr
<nsISupports
>* get_address() const { return this; }
1178 nsISupports
& operator*() const {
1179 MOZ_ASSERT(mRawPtr
!= nullptr,
1180 "You can't dereference a NULL nsCOMPtr with operator*().");
1184 nsISupports
** StartAssignment() {
1185 #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
1186 return reinterpret_cast<nsISupports
**>(begin_assignment());
1188 assign_assuming_AddRef(nullptr);
1189 return reinterpret_cast<nsISupports
**>(&mRawPtr
);
1194 template <typename T
>
1195 inline void ImplCycleCollectionUnlink(nsCOMPtr
<T
>& aField
) {
1199 template <typename T
>
1200 inline void ImplCycleCollectionTraverse(
1201 nsCycleCollectionTraversalCallback
& aCallback
, nsCOMPtr
<T
>& aField
,
1202 const char* aName
, uint32_t aFlags
= 0) {
1203 CycleCollectionNoteChild(aCallback
, aField
.get(), aName
, aFlags
);
1206 #ifndef NSCAP_FEATURE_USE_BASE
1208 void nsCOMPtr
<T
>::assign_with_AddRef(nsISupports
* aRawPtr
) {
1210 NSCAP_ADDREF(this, aRawPtr
);
1212 assign_assuming_AddRef(reinterpret_cast<T
*>(aRawPtr
));
1216 template <typename U
>
1217 void nsCOMPtr
<T
>::assign_from_qi(const nsQueryInterface
<U
> aQI
,
1218 const nsIID
& aIID
) {
1220 !(std::is_same_v
<T
, U
> || std::is_base_of
<T
, U
>::value
),
1221 "don't use do_QueryInterface for compile-time-determinable casts");
1223 if (NS_FAILED(aQI(aIID
, &newRawPtr
))) {
1224 newRawPtr
= nullptr;
1226 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1230 template <typename U
>
1231 void nsCOMPtr
<T
>::assign_from_qi_with_error(
1232 const nsQueryInterfaceWithError
<U
>& aQI
, const nsIID
& aIID
) {
1234 !(std::is_same_v
<T
, U
> || std::is_base_of
<T
, U
>::value
),
1235 "don't use do_QueryInterface for compile-time-determinable casts");
1237 if (NS_FAILED(aQI(aIID
, &newRawPtr
))) {
1238 newRawPtr
= nullptr;
1240 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1244 void nsCOMPtr
<T
>::assign_from_gs_cid(const nsGetServiceByCID aGS
,
1245 const nsIID
& aIID
) {
1247 if (NS_FAILED(aGS(aIID
, &newRawPtr
))) {
1248 newRawPtr
= nullptr;
1250 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1254 void nsCOMPtr
<T
>::assign_from_gs_cid_with_error(
1255 const nsGetServiceByCIDWithError
& aGS
, const nsIID
& aIID
) {
1257 if (NS_FAILED(aGS(aIID
, &newRawPtr
))) {
1258 newRawPtr
= nullptr;
1260 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1264 void nsCOMPtr
<T
>::assign_from_gs_contractid(const nsGetServiceByContractID aGS
,
1265 const nsIID
& aIID
) {
1267 if (NS_FAILED(aGS(aIID
, &newRawPtr
))) {
1268 newRawPtr
= nullptr;
1270 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1274 void nsCOMPtr
<T
>::assign_from_gs_contractid_with_error(
1275 const nsGetServiceByContractIDWithError
& aGS
, const nsIID
& aIID
) {
1277 if (NS_FAILED(aGS(aIID
, &newRawPtr
))) {
1278 newRawPtr
= nullptr;
1280 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1284 void nsCOMPtr
<T
>::assign_from_query_referent(
1285 const nsQueryReferent
& aQueryReferent
, const nsIID
& aIID
) {
1287 if (NS_FAILED(aQueryReferent(aIID
, &newRawPtr
))) {
1288 newRawPtr
= nullptr;
1290 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1294 void nsCOMPtr
<T
>::assign_from_helper(const nsCOMPtr_helper
& helper
,
1295 const nsIID
& aIID
) {
1297 if (NS_FAILED(helper(aIID
, &newRawPtr
))) {
1298 newRawPtr
= nullptr;
1300 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1304 void** nsCOMPtr
<T
>::begin_assignment() {
1305 assign_assuming_AddRef(nullptr);
1310 result
.mT
= &mRawPtr
;
1311 return result
.mVoid
;
1316 inline nsCOMPtr
<T
>* address_of(nsCOMPtr
<T
>& aPtr
) {
1317 return aPtr
.get_address();
1321 inline const nsCOMPtr
<T
>* address_of(const nsCOMPtr
<T
>& aPtr
) {
1322 return aPtr
.get_address();
1326 * This class is designed to be used for anonymous temporary objects in the
1327 * argument list of calls that return COM interface pointers, e.g.,
1329 * nsCOMPtr<IFoo> fooP;
1330 * ...->QueryInterface(iid, getter_AddRefs(fooP))
1332 * DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
1334 * When initialized with a |nsCOMPtr|, as in the example above, it returns
1335 * a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call
1336 * (|QueryInterface| in this case) can fill in.
1338 * This type should be a nested class inside |nsCOMPtr<T>|.
1341 class nsGetterAddRefs
{
1343 explicit nsGetterAddRefs(nsCOMPtr
<T
>& aSmartPtr
)
1344 : mTargetSmartPtr(aSmartPtr
) {}
1346 #if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || \
1347 defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT)
1348 ~nsGetterAddRefs() {
1349 # ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
1350 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr
)),
1351 mTargetSmartPtr
.get());
1354 # ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
1355 mTargetSmartPtr
.Assert_NoQueryNeeded();
1361 return reinterpret_cast<void**>(mTargetSmartPtr
.StartAssignment());
1364 operator T
**() { return mTargetSmartPtr
.StartAssignment(); }
1365 T
*& operator*() { return *(mTargetSmartPtr
.StartAssignment()); }
1368 nsCOMPtr
<T
>& mTargetSmartPtr
;
1372 class nsGetterAddRefs
<nsISupports
> {
1374 explicit nsGetterAddRefs(nsCOMPtr
<nsISupports
>& aSmartPtr
)
1375 : mTargetSmartPtr(aSmartPtr
) {}
1377 #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
1378 ~nsGetterAddRefs() {
1379 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr
)),
1380 mTargetSmartPtr
.get());
1385 return reinterpret_cast<void**>(mTargetSmartPtr
.StartAssignment());
1388 operator nsISupports
**() { return mTargetSmartPtr
.StartAssignment(); }
1389 nsISupports
*& operator*() { return *(mTargetSmartPtr
.StartAssignment()); }
1392 nsCOMPtr
<nsISupports
>& mTargetSmartPtr
;
1396 inline nsGetterAddRefs
<T
> getter_AddRefs(nsCOMPtr
<T
>& aSmartPtr
) {
1397 return nsGetterAddRefs
<T
>(aSmartPtr
);
1400 template <class T
, class DestinationType
>
1401 inline nsresult
CallQueryInterface(
1402 T
* aSource
, nsGetterAddRefs
<DestinationType
> aDestination
) {
1403 return CallQueryInterface(aSource
,
1404 static_cast<DestinationType
**>(aDestination
));
1407 // Comparing two |nsCOMPtr|s
1409 template <class T
, class U
>
1410 inline bool operator==(const nsCOMPtr
<T
>& aLhs
, const nsCOMPtr
<U
>& aRhs
) {
1411 return static_cast<const T
*>(aLhs
.get()) == static_cast<const U
*>(aRhs
.get());
1414 template <class T
, class U
>
1415 inline bool operator!=(const nsCOMPtr
<T
>& aLhs
, const nsCOMPtr
<U
>& aRhs
) {
1416 return static_cast<const T
*>(aLhs
.get()) != static_cast<const U
*>(aRhs
.get());
1419 // Comparing an |nsCOMPtr| to a raw pointer
1421 template <class T
, class U
>
1422 inline bool operator==(const nsCOMPtr
<T
>& aLhs
, const U
* aRhs
) {
1423 return static_cast<const T
*>(aLhs
.get()) == aRhs
;
1426 template <class T
, class U
>
1427 inline bool operator==(const U
* aLhs
, const nsCOMPtr
<T
>& aRhs
) {
1428 return aLhs
== static_cast<const T
*>(aRhs
.get());
1431 template <class T
, class U
>
1432 inline bool operator!=(const nsCOMPtr
<T
>& aLhs
, const U
* aRhs
) {
1433 return static_cast<const T
*>(aLhs
.get()) != aRhs
;
1436 template <class T
, class U
>
1437 inline bool operator!=(const U
* aLhs
, const nsCOMPtr
<T
>& aRhs
) {
1438 return aLhs
!= static_cast<const T
*>(aRhs
.get());
1441 template <class T
, class U
>
1442 inline bool operator==(const nsCOMPtr
<T
>& aLhs
, U
* aRhs
) {
1443 return static_cast<const T
*>(aLhs
.get()) == const_cast<const U
*>(aRhs
);
1446 template <class T
, class U
>
1447 inline bool operator==(U
* aLhs
, const nsCOMPtr
<T
>& aRhs
) {
1448 return const_cast<const U
*>(aLhs
) == static_cast<const T
*>(aRhs
.get());
1451 template <class T
, class U
>
1452 inline bool operator!=(const nsCOMPtr
<T
>& aLhs
, U
* aRhs
) {
1453 return static_cast<const T
*>(aLhs
.get()) != const_cast<const U
*>(aRhs
);
1456 template <class T
, class U
>
1457 inline bool operator!=(U
* aLhs
, const nsCOMPtr
<T
>& aRhs
) {
1458 return const_cast<const U
*>(aLhs
) != static_cast<const T
*>(aRhs
.get());
1461 // Comparing an |nsCOMPtr| to |nullptr|
1464 inline bool operator==(const nsCOMPtr
<T
>& aLhs
, decltype(nullptr)) {
1465 return aLhs
.get() == nullptr;
1469 inline bool operator==(decltype(nullptr), const nsCOMPtr
<T
>& aRhs
) {
1470 return nullptr == aRhs
.get();
1474 inline bool operator!=(const nsCOMPtr
<T
>& aLhs
, decltype(nullptr)) {
1475 return aLhs
.get() != nullptr;
1479 inline bool operator!=(decltype(nullptr), const nsCOMPtr
<T
>& aRhs
) {
1480 return nullptr != aRhs
.get();
1483 // Comparing any two [XP]COM objects for identity
1485 inline bool SameCOMIdentity(nsISupports
* aLhs
, nsISupports
* aRhs
) {
1486 return nsCOMPtr
<nsISupports
>(do_QueryInterface(aLhs
)) ==
1487 nsCOMPtr
<nsISupports
>(do_QueryInterface(aRhs
));
1490 template <class SourceType
, class DestinationType
>
1491 inline nsresult
CallQueryInterface(nsCOMPtr
<SourceType
>& aSourcePtr
,
1492 DestinationType
** aDestPtr
) {
1493 return CallQueryInterface(aSourcePtr
.get(), aDestPtr
);
1497 RefPtr
<T
>::RefPtr(const nsQueryReferent
& aQueryReferent
) {
1499 if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T
), &newRawPtr
))) {
1500 newRawPtr
= nullptr;
1502 mRawPtr
= static_cast<T
*>(newRawPtr
);
1506 RefPtr
<T
>::RefPtr(const nsCOMPtr_helper
& aHelper
) {
1508 if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T
), &newRawPtr
))) {
1509 newRawPtr
= nullptr;
1511 mRawPtr
= static_cast<T
*>(newRawPtr
);
1515 RefPtr
<T
>& RefPtr
<T
>::operator=(const nsQueryReferent
& aQueryReferent
) {
1517 if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T
), &newRawPtr
))) {
1518 newRawPtr
= nullptr;
1520 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1525 RefPtr
<T
>& RefPtr
<T
>::operator=(const nsCOMPtr_helper
& aHelper
) {
1527 if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T
), &newRawPtr
))) {
1528 newRawPtr
= nullptr;
1530 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1535 inline already_AddRefed
<T
> do_AddRef(const nsCOMPtr
<T
>& aObj
) {
1536 nsCOMPtr
<T
> ref(aObj
);
1537 return ref
.forget();
1543 std::ostream
& operator<<(std::ostream
& aOut
, const nsCOMPtr
<T
>& aObj
) {
1544 return mozilla::DebugValue(aOut
, aObj
.get());
1547 // ToRefPtr allows to move an nsCOMPtr<T> into a RefPtr<T>. Be mindful when
1548 // using this, because usually RefPtr<T> should only be used with concrete T and
1549 // nsCOMPtr<T> should only be used with XPCOM interface T.
1551 RefPtr
<T
> ToRefPtr(nsCOMPtr
<T
>&& aObj
) {
1552 return aObj
.forget();
1555 // Integration with ResultExtensions.h
1556 template <typename R
>
1557 auto ResultRefAsParam(nsCOMPtr
<R
>& aResult
) {
1558 return getter_AddRefs(aResult
);
1561 namespace mozilla::detail
{
1562 template <typename T
>
1563 struct outparam_as_pointer
;
1565 template <typename T
>
1566 struct outparam_as_pointer
<nsGetterAddRefs
<T
>> {
1569 } // namespace mozilla::detail
1571 #endif // !defined(nsCOMPtr_h___)