Bug 1690340 - Part 4: Insert the "Page Source" before the "Extensions for Developers...
[gecko.git] / xpcom / base / nsCOMPtr.h
blob23682c6155575646758279f6ccc4917e18ac77bd
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/. */
7 #ifndef nsCOMPtr_h___
8 #define nsCOMPtr_h___
11 * Having problems?
13 * See the User Manual at:
14 * https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Using_nsCOMPtr
17 * nsCOMPtr
18 * better than a raw pointer
19 * for owning objects
20 * -- scc
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.
40 #ifdef _MSC_VER
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)
48 #endif
50 #define NSCAP_FEATURE_USE_BASE
52 #ifdef DEBUG
53 # define NSCAP_FEATURE_TEST_DONTQUERY_CASES
54 # undef NSCAP_FEATURE_USE_BASE
55 #endif
57 #ifdef __GNUC__
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__))
65 #else
66 # define NS_MAY_ALIAS_PTR(t) t*
67 #endif
69 #if defined(NSCAP_DISABLE_DEBUG_PTR_TYPES)
70 # define NSCAP_FEATURE_USE_BASE
71 #endif
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)
84 #ifndef NSCAP_ADDREF
85 # define NSCAP_ADDREF(this, ptr) (ptr)->AddRef()
86 #endif
88 #ifndef NSCAP_RELEASE
89 # define NSCAP_RELEASE(this, ptr) (ptr)->Release()
90 #endif
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
98 #else
99 // ...otherwise, just strip it out of the code
100 # define NSCAP_LOG_ASSIGNMENT(this, ptr)
101 #endif
103 #ifndef NSCAP_LOG_RELEASE
104 # define NSCAP_LOG_RELEASE(this, ptr)
105 #endif
107 namespace mozilla {
108 template <class T>
109 class OwningNonNull;
110 } // namespace mozilla
112 template <class T>
113 inline already_AddRefed<T> dont_AddRef(T* aRawPtr) {
114 return already_AddRefed<T>(aRawPtr);
117 template <class T>
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
132 * any good getter)
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 {
140 public:
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
148 * specialcasing.
150 class MOZ_STACK_CLASS nsQueryInterfaceISupports {
151 public:
152 explicit nsQueryInterfaceISupports(nsISupports* aRawPtr) : mRawPtr(aRawPtr) {}
154 nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
156 private:
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 {
164 public:
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 {
175 public:
176 nsQueryInterfaceISupportsWithError(nsISupports* aRawPtr, nsresult* aError)
177 : mRawPtr(aRawPtr), mErrorPtr(aError) {}
179 nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
181 private:
182 nsISupports* MOZ_OWNING_REF mRawPtr;
183 nsresult* mErrorPtr;
186 #ifndef NSCAP_FEATURE_USE_BASE
187 template <typename T>
188 class MOZ_STACK_CLASS nsQueryInterfaceWithError final
189 : public nsQueryInterfaceISupportsWithError {
190 public:
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
200 namespace mozilla {
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<>.
204 template <class T>
205 using PointedToType = std::remove_pointer_t<decltype(&*std::declval<T>())>;
206 } // namespace mozilla
208 #ifdef NSCAP_FEATURE_USE_BASE
209 template <class T>
210 inline nsQueryInterfaceISupports do_QueryInterface(T aPtr) {
211 return nsQueryInterfaceISupports(
212 ToSupports(static_cast<mozilla::PointedToType<T>*>(aPtr)));
215 template <class T>
216 inline nsQueryInterfaceISupportsWithError do_QueryInterface(T aPtr,
217 nsresult* aError) {
218 return nsQueryInterfaceISupportsWithError(
219 ToSupports(static_cast<mozilla::PointedToType<T>*>(aPtr)), aError);
221 #else
222 template <class T>
223 inline nsQueryInterface<mozilla::PointedToType<T>> do_QueryInterface(T aPtr) {
224 return nsQueryInterface<mozilla::PointedToType<T>>(aPtr);
227 template <class T>
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
235 template <class T>
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.
242 template <class T>
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 {
252 public:
253 explicit nsGetServiceByCID(const nsCID& aCID) : mCID(aCID) {}
255 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
257 private:
258 const nsCID& mCID;
261 class nsGetServiceByCIDWithError final {
262 public:
263 nsGetServiceByCIDWithError(const nsCID& aCID, nsresult* aErrorPtr)
264 : mCID(aCID), mErrorPtr(aErrorPtr) {}
266 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
268 private:
269 const nsCID& mCID;
270 nsresult* mErrorPtr;
273 class nsGetServiceByContractID final {
274 public:
275 explicit nsGetServiceByContractID(const char* aContractID)
276 : mContractID(aContractID) {}
278 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
280 private:
281 const char* mContractID;
284 class nsGetServiceByContractIDWithError final {
285 public:
286 nsGetServiceByContractIDWithError(const char* aContractID,
287 nsresult* aErrorPtr)
288 : mContractID(aContractID), mErrorPtr(aErrorPtr) {}
290 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
292 private:
293 const char* mContractID;
294 nsresult* mErrorPtr;
297 class nsIWeakReference;
299 // Weak references
300 class MOZ_STACK_CLASS nsQueryReferent final {
301 public:
302 nsQueryReferent(nsIWeakReference* aWeakPtr, nsresult* aError)
303 : mWeakPtr(aWeakPtr), mErrorPtr(aError) {}
305 nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
307 private:
308 nsIWeakReference* MOZ_NON_OWNING_REF mWeakPtr;
309 nsresult* mErrorPtr;
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 {
322 public:
323 explicit nsCOMPtr_base(nsISupports* aRawPtr = nullptr) : mRawPtr(aRawPtr) {}
325 NS_CONSTRUCTOR_FASTCALL ~nsCOMPtr_base() {
326 NSCAP_LOG_RELEASE(this, mRawPtr);
327 if (mRawPtr) {
328 NSCAP_RELEASE(this, mRawPtr);
332 void NS_FASTCALL assign_with_AddRef(nsISupports*);
333 void NS_FASTCALL assign_from_qi(const nsQueryInterfaceISupports,
334 const nsIID&);
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,
341 const nsIID&);
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&,
345 const nsIID&);
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
353 MOZ_NEVER_INLINE
354 #else
355 MOZ_ALWAYS_INLINE
356 #endif
357 void** NS_FASTCALL begin_assignment() {
358 assign_assuming_AddRef(nullptr);
359 return reinterpret_cast<void**>(&mRawPtr);
362 protected:
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;
373 mRawPtr = aNewPtr;
374 NSCAP_LOG_ASSIGNMENT(this, aNewPtr);
375 NSCAP_LOG_RELEASE(this, oldPtr);
376 if (oldPtr) {
377 NSCAP_RELEASE(this, oldPtr);
382 // template<class T> class nsGetterAddRefs;
384 // Helper for assert_validity method
385 template <class T>
386 char (&TestForIID(decltype(&NS_GET_TEMPLATE_IID(T))))[2];
387 template <class T>
388 char TestForIID(...);
390 template <class T>
391 class MOZ_IS_REFPTR nsCOMPtr final
392 #ifdef NSCAP_FEATURE_USE_BASE
393 : private nsCOMPtr_base
394 #endif
396 private:
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));
402 #else
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>&,
410 const nsIID&);
411 void assign_from_gs_cid(const nsGetServiceByCID, const nsIID&);
412 void assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError&,
413 const nsIID&);
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) {
422 T* oldPtr = mRawPtr;
423 mRawPtr = aNewPtr;
424 NSCAP_LOG_ASSIGNMENT(this, aNewPtr);
425 NSCAP_LOG_RELEASE(this, oldPtr);
426 if (oldPtr) {
427 NSCAP_RELEASE(this, oldPtr);
431 private:
432 T* MOZ_OWNING_REF mRawPtr;
433 #endif
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.");
444 public:
445 typedef T element_type;
447 #ifndef NSCAP_FEATURE_USE_BASE
448 ~nsCOMPtr() {
449 NSCAP_LOG_RELEASE(this, mRawPtr);
450 if (mRawPtr) {
451 NSCAP_RELEASE(this, mRawPtr);
454 #endif
456 #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
457 void Assert_NoQueryNeeded() {
458 if (mRawPtr) {
459 // This can't be defined in terms of do_QueryInterface because
460 // that bans casts from a class to itself.
461 void* out = nullptr;
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();
470 #else
471 # define NSCAP_ASSERT_NO_QUERY_NEEDED()
472 #endif
474 // Constructors
476 nsCOMPtr() : NSCAP_CTOR_BASE(nullptr) {
477 assert_validity();
478 NSCAP_LOG_ASSIGNMENT(this, nullptr);
481 MOZ_IMPLICIT nsCOMPtr(decltype(nullptr)) : NSCAP_CTOR_BASE(nullptr) {
482 assert_validity();
483 NSCAP_LOG_ASSIGNMENT(this, nullptr);
486 nsCOMPtr(const nsCOMPtr<T>& aSmartPtr) : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) {
487 assert_validity();
488 if (mRawPtr) {
489 NSCAP_ADDREF(this, mRawPtr);
491 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr);
494 template <class U>
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");
499 assert_validity();
500 if (mRawPtr) {
501 NSCAP_ADDREF(this, mRawPtr);
503 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.get());
506 nsCOMPtr(nsCOMPtr<T>&& aSmartPtr) : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) {
507 assert_validity();
508 aSmartPtr.mRawPtr = nullptr;
509 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
512 template <class U>
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");
517 assert_validity();
518 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
519 NSCAP_ASSERT_NO_QUERY_NEEDED();
522 MOZ_IMPLICIT nsCOMPtr(T* aRawPtr) : NSCAP_CTOR_BASE(aRawPtr) {
523 assert_validity();
524 if (mRawPtr) {
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()) {
533 assert_validity();
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()) {
541 assert_validity();
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)
549 : NSCAP_CTOR_BASE(
550 static_cast<already_AddRefed<T>>(aSmartPtr.forget()).take()) {
551 assert_validity();
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())) {
562 assert_validity();
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())) {
573 assert_validity();
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)
583 #else
584 template <typename U>
585 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterface<U> aQI)
586 #endif // ! #ifdef NSCAP_FEATURE_USE_BASE
587 : NSCAP_CTOR_BASE(nullptr) {
588 assert_validity();
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)
596 #else
597 template <typename U>
598 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceWithError<U>& aQI)
599 #endif // ! #ifdef NSCAP_FEATURE_USE_BASE
600 : NSCAP_CTOR_BASE(nullptr) {
601 assert_validity();
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) {
609 assert_validity();
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) {
617 assert_validity();
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) {
625 assert_validity();
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) {
633 assert_validity();
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) {
641 assert_validity();
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) {
650 assert_validity();
651 NSCAP_LOG_ASSIGNMENT(this, nullptr);
652 assign_from_helper(aHelper, NS_GET_TEMPLATE_IID(T));
653 NSCAP_ASSERT_NO_QUERY_NEEDED();
656 // Defined in OwningNonNull.h
657 template <class U>
658 MOZ_IMPLICIT nsCOMPtr(const mozilla::OwningNonNull<U>& aOther);
660 // Assignment operators
662 nsCOMPtr<T>& operator=(const nsCOMPtr<T>& aRhs) {
663 assign_with_AddRef(ToSupports(aRhs.mRawPtr));
664 return *this;
667 template <class U>
668 nsCOMPtr<T>& operator=(const nsCOMPtr<U>& aRhs) {
669 // Make sure that U actually inherits from T
670 static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
671 assign_with_AddRef(ToSupports(static_cast<T*>(aRhs.get())));
672 return *this;
675 nsCOMPtr<T>& operator=(nsCOMPtr<T>&& aRhs) {
676 assign_assuming_AddRef(aRhs.forget().take());
677 return *this;
680 template <class U>
681 nsCOMPtr<T>& operator=(nsCOMPtr<U>&& aRhs) {
682 // Make sure that U actually inherits from T
683 static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
684 assign_assuming_AddRef(aRhs.forget().template downcast<T>().take());
685 NSCAP_ASSERT_NO_QUERY_NEEDED();
686 return *this;
689 nsCOMPtr<T>& operator=(T* aRhs) {
690 assign_with_AddRef(ToSupports(aRhs));
691 NSCAP_ASSERT_NO_QUERY_NEEDED();
692 return *this;
695 nsCOMPtr<T>& operator=(decltype(nullptr)) {
696 assign_assuming_AddRef(nullptr);
697 return *this;
700 // Assign from |already_AddRefed|.
701 template <typename U>
702 nsCOMPtr<T>& operator=(already_AddRefed<U>& aRhs) {
703 // Make sure that U actually inherits from T
704 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
705 assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
706 NSCAP_ASSERT_NO_QUERY_NEEDED();
707 return *this;
710 // Assign from |otherComPtr.forget()|.
711 template <typename U>
712 nsCOMPtr<T>& operator=(already_AddRefed<U>&& aRhs) {
713 // Make sure that U actually inherits from T
714 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
715 assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
716 NSCAP_ASSERT_NO_QUERY_NEEDED();
717 return *this;
720 // Assign from |std::move(otherRefPtr)|.
721 template <typename U>
722 nsCOMPtr<T>& operator=(RefPtr<U>&& aRhs) {
723 // Make sure that U actually inherits from T
724 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
725 assign_assuming_AddRef(static_cast<T*>(aRhs.forget().take()));
726 NSCAP_ASSERT_NO_QUERY_NEEDED();
727 return *this;
730 // Assign from |do_QueryInterface(expr)|.
731 #ifdef NSCAP_FEATURE_USE_BASE
732 nsCOMPtr<T>& operator=(const nsQueryInterfaceISupports aRhs)
733 #else
734 template <typename U>
735 nsCOMPtr<T>& operator=(const nsQueryInterface<U> aRhs)
736 #endif // ! #ifdef NSCAP_FEATURE_USE_BASE
738 assign_from_qi(aRhs, NS_GET_TEMPLATE_IID(T));
739 return *this;
742 // Assign from |do_QueryInterface(expr, &rv)|.
743 #ifdef NSCAP_FEATURE_USE_BASE
744 nsCOMPtr<T>& operator=(const nsQueryInterfaceISupportsWithError& aRhs)
745 #else
746 template <typename U>
747 nsCOMPtr<T>& operator=(const nsQueryInterfaceWithError<U>& aRhs)
748 #endif // ! #ifdef NSCAP_FEATURE_USE_BASE
750 assign_from_qi_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
751 return *this;
754 // Assign from |do_GetService(cid_expr)|.
755 nsCOMPtr<T>& operator=(const nsGetServiceByCID aRhs) {
756 assign_from_gs_cid(aRhs, NS_GET_TEMPLATE_IID(T));
757 return *this;
760 // Assign from |do_GetService(cid_expr, &rv)|.
761 nsCOMPtr<T>& operator=(const nsGetServiceByCIDWithError& aRhs) {
762 assign_from_gs_cid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
763 return *this;
766 // Assign from |do_GetService(contractid_expr)|.
767 nsCOMPtr<T>& operator=(const nsGetServiceByContractID aRhs) {
768 assign_from_gs_contractid(aRhs, NS_GET_TEMPLATE_IID(T));
769 return *this;
772 // Assign from |do_GetService(contractid_expr, &rv)|.
773 nsCOMPtr<T>& operator=(const nsGetServiceByContractIDWithError& aRhs) {
774 assign_from_gs_contractid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
775 return *this;
778 // Assign from |do_QueryReferent(ptr)|.
779 nsCOMPtr<T>& operator=(const nsQueryReferent& aRhs) {
780 assign_from_query_referent(aRhs, NS_GET_TEMPLATE_IID(T));
781 return *this;
784 // And finally, anything else we might need to assign from can exploit the
785 // nsCOMPtr_helper facility.
786 nsCOMPtr<T>& operator=(const nsCOMPtr_helper& aRhs) {
787 assign_from_helper(aRhs, NS_GET_TEMPLATE_IID(T));
788 NSCAP_ASSERT_NO_QUERY_NEEDED();
789 return *this;
792 // Defined in OwningNonNull.h
793 template <class U>
794 nsCOMPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
796 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
797 void swap(nsCOMPtr<T>& aRhs) {
798 #ifdef NSCAP_FEATURE_USE_BASE
799 nsISupports* temp = aRhs.mRawPtr;
800 #else
801 T* temp = aRhs.mRawPtr;
802 #endif
803 NSCAP_LOG_ASSIGNMENT(&aRhs, mRawPtr);
804 NSCAP_LOG_ASSIGNMENT(this, temp);
805 NSCAP_LOG_RELEASE(this, mRawPtr);
806 NSCAP_LOG_RELEASE(&aRhs, temp);
807 aRhs.mRawPtr = mRawPtr;
808 mRawPtr = temp;
809 // |aRhs| maintains the same invariants, so we don't need to
810 // |NSCAP_ASSERT_NO_QUERY_NEEDED|
813 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
814 void swap(T*& aRhs) {
815 #ifdef NSCAP_FEATURE_USE_BASE
816 nsISupports* temp = ToSupports(aRhs);
817 #else
818 T* temp = aRhs;
819 #endif
820 NSCAP_LOG_ASSIGNMENT(this, temp);
821 NSCAP_LOG_RELEASE(this, mRawPtr);
822 aRhs = reinterpret_cast<T*>(mRawPtr);
823 mRawPtr = temp;
824 NSCAP_ASSERT_NO_QUERY_NEEDED();
827 // Other pointer operators
829 // Return the value of mRawPtr and null out mRawPtr. Useful for
830 // already_AddRefed return values.
831 already_AddRefed<T> MOZ_MAY_CALL_AFTER_MUST_RETURN forget() {
832 T* temp = nullptr;
833 swap(temp);
834 return already_AddRefed<T>(temp);
837 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
838 // Useful to avoid unnecessary AddRef/Release pairs with "out" parameters
839 // where aRhs bay be a T** or an I** where I is a base class of T.
840 template <typename I>
841 void forget(I** aRhs) {
842 NS_ASSERTION(aRhs, "Null pointer passed to forget!");
843 NSCAP_LOG_RELEASE(this, mRawPtr);
844 *aRhs = get();
845 mRawPtr = nullptr;
848 // Prefer the implicit conversion provided automatically by
849 // |operator T*() const|. Use |get()| to resolve ambiguity or to get a
850 // castable pointer.
851 T* get() const { return reinterpret_cast<T*>(mRawPtr); }
853 // Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
854 // used in a context where a raw pointer is expected. It is this operator
855 // that makes an nsCOMPtr substitutable for a raw pointer.
857 // Prefer the implicit use of this operator to calling |get()|, except where
858 // necessary to resolve ambiguity.
859 operator T*() const& { return get(); }
861 // Don't allow implicit conversion of temporary nsCOMPtr to raw pointer,
862 // because the refcount might be one and the pointer will immediately become
863 // invalid.
864 operator T*() const&& = delete;
866 // Needed to avoid the deleted operator above
867 explicit operator bool() const { return !!mRawPtr; }
869 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
870 MOZ_ASSERT(mRawPtr != nullptr,
871 "You can't dereference a NULL nsCOMPtr with operator->().");
872 return get();
875 // These are not intended to be used by clients. See |address_of| below.
876 nsCOMPtr<T>* get_address() { return this; }
877 const nsCOMPtr<T>* get_address() const { return this; }
879 public:
880 T& operator*() const {
881 MOZ_ASSERT(mRawPtr != nullptr,
882 "You can't dereference a NULL nsCOMPtr with operator*().");
883 return *get();
886 T** StartAssignment() {
887 #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
888 return reinterpret_cast<T**>(begin_assignment());
889 #else
890 assign_assuming_AddRef(nullptr);
891 return reinterpret_cast<T**>(&mRawPtr);
892 #endif
897 * Specializing nsCOMPtr for nsISupports allows us to use nsCOMPtr<nsISupports>
898 * the same way people use nsISupports* and void*, i.e., as a `catch-all'
899 * pointing to any valid [XP]COM interface. Otherwise, an nsCOMPtr<nsISupports>
900 * would only be able to point to the single [XP]COM-correct nsISupports
901 * instance within an object; extra querying ensues. Clients need to be able to
902 * pass around arbitrary interface pointers, without hassles, through
903 * intermediary code that doesn't know the exact type.
905 template <>
906 class MOZ_IS_REFPTR nsCOMPtr<nsISupports> : private nsCOMPtr_base {
907 public:
908 typedef nsISupports element_type;
910 // Constructors
912 nsCOMPtr() : nsCOMPtr_base(nullptr) { NSCAP_LOG_ASSIGNMENT(this, nullptr); }
914 MOZ_IMPLICIT nsCOMPtr(decltype(nullptr)) : nsCOMPtr_base(nullptr) {
915 NSCAP_LOG_ASSIGNMENT(this, nullptr);
918 nsCOMPtr(const nsCOMPtr<nsISupports>& aSmartPtr)
919 : nsCOMPtr_base(aSmartPtr.mRawPtr) {
920 if (mRawPtr) {
921 NSCAP_ADDREF(this, mRawPtr);
923 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr);
926 MOZ_IMPLICIT nsCOMPtr(nsISupports* aRawPtr) : nsCOMPtr_base(aRawPtr) {
927 if (mRawPtr) {
928 NSCAP_ADDREF(this, mRawPtr);
930 NSCAP_LOG_ASSIGNMENT(this, aRawPtr);
933 // Construct from |already_AddRefed|.
934 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<nsISupports>& aSmartPtr)
935 : nsCOMPtr_base(aSmartPtr.take()) {
936 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
939 // Construct from |otherComPtr.forget()|.
940 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<nsISupports>&& aSmartPtr)
941 : nsCOMPtr_base(aSmartPtr.take()) {
942 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
945 // Construct from |do_QueryInterface(expr)|.
946 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceISupports aQI)
947 : nsCOMPtr_base(nullptr) {
948 NSCAP_LOG_ASSIGNMENT(this, nullptr);
949 assign_from_qi(aQI, NS_GET_IID(nsISupports));
952 // Construct from |do_QueryInterface(expr, &rv)|.
953 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceISupportsWithError& aQI)
954 : nsCOMPtr_base(nullptr) {
955 NSCAP_LOG_ASSIGNMENT(this, nullptr);
956 assign_from_qi_with_error(aQI, NS_GET_IID(nsISupports));
959 // Construct from |do_GetService(cid_expr)|.
960 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCID aGS) : nsCOMPtr_base(nullptr) {
961 NSCAP_LOG_ASSIGNMENT(this, nullptr);
962 assign_from_gs_cid(aGS, NS_GET_IID(nsISupports));
965 // Construct from |do_GetService(cid_expr, &rv)|.
966 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCIDWithError& aGS)
967 : nsCOMPtr_base(nullptr) {
968 NSCAP_LOG_ASSIGNMENT(this, nullptr);
969 assign_from_gs_cid_with_error(aGS, NS_GET_IID(nsISupports));
972 // Construct from |do_GetService(contractid_expr)|.
973 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractID aGS)
974 : nsCOMPtr_base(nullptr) {
975 NSCAP_LOG_ASSIGNMENT(this, nullptr);
976 assign_from_gs_contractid(aGS, NS_GET_IID(nsISupports));
979 // Construct from |do_GetService(contractid_expr, &rv)|.
980 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
981 : nsCOMPtr_base(nullptr) {
982 NSCAP_LOG_ASSIGNMENT(this, nullptr);
983 assign_from_gs_contractid_with_error(aGS, NS_GET_IID(nsISupports));
986 // Construct from |do_QueryReferent(ptr)|
987 MOZ_IMPLICIT nsCOMPtr(const nsQueryReferent& aQueryReferent)
988 : nsCOMPtr_base(nullptr) {
989 NSCAP_LOG_ASSIGNMENT(this, nullptr);
990 assign_from_query_referent(aQueryReferent,
991 NS_GET_TEMPLATE_IID(nsISupports));
994 // And finally, anything else we might need to construct from can exploit
995 // the |nsCOMPtr_helper| facility
996 MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper)
997 : nsCOMPtr_base(nullptr) {
998 NSCAP_LOG_ASSIGNMENT(this, nullptr);
999 assign_from_helper(aHelper, NS_GET_IID(nsISupports));
1002 // Assignment operators
1004 nsCOMPtr<nsISupports>& operator=(const nsCOMPtr<nsISupports>& aRhs) {
1005 assign_with_AddRef(aRhs.mRawPtr);
1006 return *this;
1009 nsCOMPtr<nsISupports>& operator=(nsISupports* aRhs) {
1010 assign_with_AddRef(aRhs);
1011 return *this;
1014 nsCOMPtr<nsISupports>& operator=(decltype(nullptr)) {
1015 assign_assuming_AddRef(nullptr);
1016 return *this;
1019 // Assign from |already_AddRefed|.
1020 nsCOMPtr<nsISupports>& operator=(already_AddRefed<nsISupports>& aRhs) {
1021 assign_assuming_AddRef(aRhs.take());
1022 return *this;
1025 // Assign from |otherComPtr.forget()|.
1026 nsCOMPtr<nsISupports>& operator=(already_AddRefed<nsISupports>&& aRhs) {
1027 assign_assuming_AddRef(aRhs.take());
1028 return *this;
1031 // Assign from |do_QueryInterface(expr)|.
1032 nsCOMPtr<nsISupports>& operator=(const nsQueryInterfaceISupports aRhs) {
1033 assign_from_qi(aRhs, NS_GET_IID(nsISupports));
1034 return *this;
1037 // Assign from |do_QueryInterface(expr, &rv)|.
1038 nsCOMPtr<nsISupports>& operator=(
1039 const nsQueryInterfaceISupportsWithError& aRhs) {
1040 assign_from_qi_with_error(aRhs, NS_GET_IID(nsISupports));
1041 return *this;
1044 // Assign from |do_GetService(cid_expr)|.
1045 nsCOMPtr<nsISupports>& operator=(const nsGetServiceByCID aRhs) {
1046 assign_from_gs_cid(aRhs, NS_GET_IID(nsISupports));
1047 return *this;
1050 // Assign from |do_GetService(cid_expr, &rv)|.
1051 nsCOMPtr<nsISupports>& operator=(const nsGetServiceByCIDWithError& aRhs) {
1052 assign_from_gs_cid_with_error(aRhs, NS_GET_IID(nsISupports));
1053 return *this;
1056 // Assign from |do_GetService(contractid_expr)|.
1057 nsCOMPtr<nsISupports>& operator=(const nsGetServiceByContractID aRhs) {
1058 assign_from_gs_contractid(aRhs, NS_GET_IID(nsISupports));
1059 return *this;
1062 // Assign from |do_GetService(contractid_expr, &rv)|.
1063 nsCOMPtr<nsISupports>& operator=(
1064 const nsGetServiceByContractIDWithError& aRhs) {
1065 assign_from_gs_contractid_with_error(aRhs, NS_GET_IID(nsISupports));
1066 return *this;
1069 // Assign from |do_QueryReferent(ptr)|.
1070 nsCOMPtr<nsISupports>& operator=(const nsQueryReferent& aRhs) {
1071 assign_from_query_referent(aRhs, NS_GET_TEMPLATE_IID(nsISupports));
1072 return *this;
1075 // And finally, anything else we might need to assign from can exploit the
1076 // nsCOMPtr_helper facility
1077 nsCOMPtr<nsISupports>& operator=(const nsCOMPtr_helper& aRhs) {
1078 assign_from_helper(aRhs, NS_GET_IID(nsISupports));
1079 return *this;
1082 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
1083 void swap(nsCOMPtr<nsISupports>& aRhs) {
1084 nsISupports* temp = aRhs.mRawPtr;
1085 NSCAP_LOG_ASSIGNMENT(&aRhs, mRawPtr);
1086 NSCAP_LOG_ASSIGNMENT(this, temp);
1087 NSCAP_LOG_RELEASE(this, mRawPtr);
1088 NSCAP_LOG_RELEASE(&aRhs, temp);
1089 aRhs.mRawPtr = mRawPtr;
1090 mRawPtr = temp;
1093 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
1094 void swap(nsISupports*& aRhs) {
1095 nsISupports* temp = aRhs;
1096 NSCAP_LOG_ASSIGNMENT(this, temp);
1097 NSCAP_LOG_RELEASE(this, mRawPtr);
1098 aRhs = mRawPtr;
1099 mRawPtr = temp;
1102 // Return the value of mRawPtr and null out mRawPtr. Useful for
1103 // already_AddRefed return values.
1104 already_AddRefed<nsISupports> forget() {
1105 nsISupports* temp = nullptr;
1106 swap(temp);
1107 return already_AddRefed<nsISupports>(temp);
1110 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
1111 // Useful to avoid unnecessary AddRef/Release pairs with "out"
1112 // parameters.
1113 void forget(nsISupports** aRhs) {
1114 NS_ASSERTION(aRhs, "Null pointer passed to forget!");
1115 *aRhs = nullptr;
1116 swap(*aRhs);
1119 // Other pointer operators
1121 // Prefer the implicit conversion provided automatically by
1122 // |operator nsISupports*() const|. Use |get()| to resolve ambiguity or to
1123 // get a castable pointer.
1124 nsISupports* get() const { return reinterpret_cast<nsISupports*>(mRawPtr); }
1126 // Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
1127 // used in a context where a raw pointer is expected. It is this operator
1128 // that makes an nsCOMPtr substitutable for a raw pointer.
1130 // Prefer the implicit use of this operator to calling |get()|, except where
1131 // necessary to resolve ambiguity/
1132 operator nsISupports*() const { return get(); }
1134 nsISupports* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
1135 MOZ_ASSERT(mRawPtr != nullptr,
1136 "You can't dereference a NULL nsCOMPtr with operator->().");
1137 return get();
1140 // These are not intended to be used by clients. See |address_of| below.
1141 nsCOMPtr<nsISupports>* get_address() { return this; }
1142 const nsCOMPtr<nsISupports>* get_address() const { return this; }
1144 public:
1145 nsISupports& operator*() const {
1146 MOZ_ASSERT(mRawPtr != nullptr,
1147 "You can't dereference a NULL nsCOMPtr with operator*().");
1148 return *get();
1151 nsISupports** StartAssignment() {
1152 #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
1153 return reinterpret_cast<nsISupports**>(begin_assignment());
1154 #else
1155 assign_assuming_AddRef(nullptr);
1156 return reinterpret_cast<nsISupports**>(&mRawPtr);
1157 #endif
1161 template <typename T>
1162 inline void ImplCycleCollectionUnlink(nsCOMPtr<T>& aField) {
1163 aField = nullptr;
1166 template <typename T>
1167 inline void ImplCycleCollectionTraverse(
1168 nsCycleCollectionTraversalCallback& aCallback, nsCOMPtr<T>& aField,
1169 const char* aName, uint32_t aFlags = 0) {
1170 CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
1173 #ifndef NSCAP_FEATURE_USE_BASE
1174 template <class T>
1175 void nsCOMPtr<T>::assign_with_AddRef(nsISupports* aRawPtr) {
1176 if (aRawPtr) {
1177 NSCAP_ADDREF(this, aRawPtr);
1179 assign_assuming_AddRef(reinterpret_cast<T*>(aRawPtr));
1182 template <class T>
1183 template <typename U>
1184 void nsCOMPtr<T>::assign_from_qi(const nsQueryInterface<U> aQI,
1185 const nsIID& aIID) {
1186 static_assert(
1187 !(std::is_same_v<T, U> || std::is_base_of<T, U>::value),
1188 "don't use do_QueryInterface for compile-time-determinable casts");
1189 void* newRawPtr;
1190 if (NS_FAILED(aQI(aIID, &newRawPtr))) {
1191 newRawPtr = nullptr;
1193 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1196 template <class T>
1197 template <typename U>
1198 void nsCOMPtr<T>::assign_from_qi_with_error(
1199 const nsQueryInterfaceWithError<U>& aQI, const nsIID& aIID) {
1200 static_assert(
1201 !(std::is_same_v<T, U> || std::is_base_of<T, U>::value),
1202 "don't use do_QueryInterface for compile-time-determinable casts");
1203 void* newRawPtr;
1204 if (NS_FAILED(aQI(aIID, &newRawPtr))) {
1205 newRawPtr = nullptr;
1207 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1210 template <class T>
1211 void nsCOMPtr<T>::assign_from_gs_cid(const nsGetServiceByCID aGS,
1212 const nsIID& aIID) {
1213 void* newRawPtr;
1214 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1215 newRawPtr = nullptr;
1217 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1220 template <class T>
1221 void nsCOMPtr<T>::assign_from_gs_cid_with_error(
1222 const nsGetServiceByCIDWithError& aGS, const nsIID& aIID) {
1223 void* newRawPtr;
1224 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1225 newRawPtr = nullptr;
1227 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1230 template <class T>
1231 void nsCOMPtr<T>::assign_from_gs_contractid(const nsGetServiceByContractID aGS,
1232 const nsIID& aIID) {
1233 void* newRawPtr;
1234 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1235 newRawPtr = nullptr;
1237 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1240 template <class T>
1241 void nsCOMPtr<T>::assign_from_gs_contractid_with_error(
1242 const nsGetServiceByContractIDWithError& aGS, const nsIID& aIID) {
1243 void* newRawPtr;
1244 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1245 newRawPtr = nullptr;
1247 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1250 template <class T>
1251 void nsCOMPtr<T>::assign_from_query_referent(
1252 const nsQueryReferent& aQueryReferent, const nsIID& aIID) {
1253 void* newRawPtr;
1254 if (NS_FAILED(aQueryReferent(aIID, &newRawPtr))) {
1255 newRawPtr = nullptr;
1257 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1260 template <class T>
1261 void nsCOMPtr<T>::assign_from_helper(const nsCOMPtr_helper& helper,
1262 const nsIID& aIID) {
1263 void* newRawPtr;
1264 if (NS_FAILED(helper(aIID, &newRawPtr))) {
1265 newRawPtr = nullptr;
1267 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1270 template <class T>
1271 void** nsCOMPtr<T>::begin_assignment() {
1272 assign_assuming_AddRef(nullptr);
1273 union {
1274 T** mT;
1275 void** mVoid;
1276 } result;
1277 result.mT = &mRawPtr;
1278 return result.mVoid;
1280 #endif
1282 template <class T>
1283 inline nsCOMPtr<T>* address_of(nsCOMPtr<T>& aPtr) {
1284 return aPtr.get_address();
1287 template <class T>
1288 inline const nsCOMPtr<T>* address_of(const nsCOMPtr<T>& aPtr) {
1289 return aPtr.get_address();
1293 * This class is designed to be used for anonymous temporary objects in the
1294 * argument list of calls that return COM interface pointers, e.g.,
1296 * nsCOMPtr<IFoo> fooP;
1297 * ...->QueryInterface(iid, getter_AddRefs(fooP))
1299 * DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
1301 * When initialized with a |nsCOMPtr|, as in the example above, it returns
1302 * a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call
1303 * (|QueryInterface| in this case) can fill in.
1305 * This type should be a nested class inside |nsCOMPtr<T>|.
1307 template <class T>
1308 class nsGetterAddRefs {
1309 public:
1310 explicit nsGetterAddRefs(nsCOMPtr<T>& aSmartPtr)
1311 : mTargetSmartPtr(aSmartPtr) {}
1313 #if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || \
1314 defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT)
1315 ~nsGetterAddRefs() {
1316 # ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
1317 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),
1318 mTargetSmartPtr.get());
1319 # endif
1321 # ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
1322 mTargetSmartPtr.Assert_NoQueryNeeded();
1323 # endif
1325 #endif
1327 operator void**() {
1328 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
1331 operator T**() { return mTargetSmartPtr.StartAssignment(); }
1332 T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
1334 private:
1335 nsCOMPtr<T>& mTargetSmartPtr;
1338 template <>
1339 class nsGetterAddRefs<nsISupports> {
1340 public:
1341 explicit nsGetterAddRefs(nsCOMPtr<nsISupports>& aSmartPtr)
1342 : mTargetSmartPtr(aSmartPtr) {}
1344 #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
1345 ~nsGetterAddRefs() {
1346 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),
1347 mTargetSmartPtr.get());
1349 #endif
1351 operator void**() {
1352 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
1355 operator nsISupports**() { return mTargetSmartPtr.StartAssignment(); }
1356 nsISupports*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
1358 private:
1359 nsCOMPtr<nsISupports>& mTargetSmartPtr;
1362 template <class T>
1363 inline nsGetterAddRefs<T> getter_AddRefs(nsCOMPtr<T>& aSmartPtr) {
1364 return nsGetterAddRefs<T>(aSmartPtr);
1367 template <class T, class DestinationType>
1368 inline nsresult CallQueryInterface(
1369 T* aSource, nsGetterAddRefs<DestinationType> aDestination) {
1370 return CallQueryInterface(aSource,
1371 static_cast<DestinationType**>(aDestination));
1374 // Comparing two |nsCOMPtr|s
1376 template <class T, class U>
1377 inline bool operator==(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs) {
1378 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
1381 template <class T, class U>
1382 inline bool operator!=(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs) {
1383 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
1386 // Comparing an |nsCOMPtr| to a raw pointer
1388 template <class T, class U>
1389 inline bool operator==(const nsCOMPtr<T>& aLhs, const U* aRhs) {
1390 return static_cast<const T*>(aLhs.get()) == aRhs;
1393 template <class T, class U>
1394 inline bool operator==(const U* aLhs, const nsCOMPtr<T>& aRhs) {
1395 return aLhs == static_cast<const T*>(aRhs.get());
1398 template <class T, class U>
1399 inline bool operator!=(const nsCOMPtr<T>& aLhs, const U* aRhs) {
1400 return static_cast<const T*>(aLhs.get()) != aRhs;
1403 template <class T, class U>
1404 inline bool operator!=(const U* aLhs, const nsCOMPtr<T>& aRhs) {
1405 return aLhs != static_cast<const T*>(aRhs.get());
1408 template <class T, class U>
1409 inline bool operator==(const nsCOMPtr<T>& aLhs, U* aRhs) {
1410 return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
1413 template <class T, class U>
1414 inline bool operator==(U* aLhs, const nsCOMPtr<T>& aRhs) {
1415 return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
1418 template <class T, class U>
1419 inline bool operator!=(const nsCOMPtr<T>& aLhs, U* aRhs) {
1420 return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
1423 template <class T, class U>
1424 inline bool operator!=(U* aLhs, const nsCOMPtr<T>& aRhs) {
1425 return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
1428 // Comparing an |nsCOMPtr| to |nullptr|
1430 template <class T>
1431 inline bool operator==(const nsCOMPtr<T>& aLhs, decltype(nullptr)) {
1432 return aLhs.get() == nullptr;
1435 template <class T>
1436 inline bool operator==(decltype(nullptr), const nsCOMPtr<T>& aRhs) {
1437 return nullptr == aRhs.get();
1440 template <class T>
1441 inline bool operator!=(const nsCOMPtr<T>& aLhs, decltype(nullptr)) {
1442 return aLhs.get() != nullptr;
1445 template <class T>
1446 inline bool operator!=(decltype(nullptr), const nsCOMPtr<T>& aRhs) {
1447 return nullptr != aRhs.get();
1450 // Comparing any two [XP]COM objects for identity
1452 inline bool SameCOMIdentity(nsISupports* aLhs, nsISupports* aRhs) {
1453 return nsCOMPtr<nsISupports>(do_QueryInterface(aLhs)) ==
1454 nsCOMPtr<nsISupports>(do_QueryInterface(aRhs));
1457 template <class SourceType, class DestinationType>
1458 inline nsresult CallQueryInterface(nsCOMPtr<SourceType>& aSourcePtr,
1459 DestinationType** aDestPtr) {
1460 return CallQueryInterface(aSourcePtr.get(), aDestPtr);
1463 template <class T>
1464 RefPtr<T>::RefPtr(const nsQueryReferent& aQueryReferent) {
1465 void* newRawPtr;
1466 if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1467 newRawPtr = nullptr;
1469 mRawPtr = static_cast<T*>(newRawPtr);
1472 template <class T>
1473 RefPtr<T>::RefPtr(const nsCOMPtr_helper& aHelper) {
1474 void* newRawPtr;
1475 if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1476 newRawPtr = nullptr;
1478 mRawPtr = static_cast<T*>(newRawPtr);
1481 template <class T>
1482 RefPtr<T>& RefPtr<T>::operator=(const nsQueryReferent& aQueryReferent) {
1483 void* newRawPtr;
1484 if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1485 newRawPtr = nullptr;
1487 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1488 return *this;
1491 template <class T>
1492 RefPtr<T>& RefPtr<T>::operator=(const nsCOMPtr_helper& aHelper) {
1493 void* newRawPtr;
1494 if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1495 newRawPtr = nullptr;
1497 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1498 return *this;
1501 template <class T>
1502 inline already_AddRefed<T> do_AddRef(const nsCOMPtr<T>& aObj) {
1503 nsCOMPtr<T> ref(aObj);
1504 return ref.forget();
1507 // MOZ_DBG support
1509 template <class T>
1510 std::ostream& operator<<(std::ostream& aOut, const nsCOMPtr<T>& aObj) {
1511 return mozilla::DebugValue(aOut, aObj.get());
1514 // ToRefPtr allows to move an nsCOMPtr<T> into a RefPtr<T>. Be mindful when
1515 // using this, because usually RefPtr<T> should only be used with concrete T and
1516 // nsCOMPtr<T> should only be used with XPCOM interface T.
1517 template <class T>
1518 RefPtr<T> ToRefPtr(nsCOMPtr<T>&& aObj) {
1519 return aObj.forget();
1522 // Integration with ResultExtensions.h
1523 template <typename R>
1524 auto ResultRefAsParam(nsCOMPtr<R>& aResult) {
1525 return getter_AddRefs(aResult);
1528 namespace mozilla::detail {
1529 template <typename T>
1530 struct outparam_as_pointer;
1532 template <typename T>
1533 struct outparam_as_pointer<nsGetterAddRefs<T>> {
1534 using type = T**;
1536 } // namespace mozilla::detail
1538 #endif // !defined(nsCOMPtr_h___)