Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / xpcom / base / nsCOMPtr.h
blobd45209d5aa23792d4f3aaf5dc891558e9759590a
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 documentation at:
14 * https://firefox-source-docs.mozilla.org/xpcom/refptr.html
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 #ifdef DEBUG
51 # define NSCAP_FEATURE_TEST_DONTQUERY_CASES
52 #endif
54 #ifdef __GNUC__
55 // Our use of nsCOMPtr_base::mRawPtr violates the C++ standard's aliasing
56 // rules. Mark it with the may_alias attribute so that gcc 3.3 and higher
57 // don't reorder instructions based on aliasing assumptions for
58 // this variable. Fortunately, gcc versions < 3.3 do not do any
59 // optimizations that break nsCOMPtr.
61 # define NS_MAY_ALIAS_PTR(t) t* __attribute__((__may_alias__))
62 #else
63 # define NS_MAY_ALIAS_PTR(t) t*
64 #endif
67 * The following three macros (NSCAP_ADDREF, NSCAP_RELEASE, and
68 * NSCAP_LOG_ASSIGNMENT) allow external clients the ability to add logging or
69 * other interesting debug facilities. In fact, if you want |nsCOMPtr| to
70 * participate in the standard logging facility, you provide
71 * (e.g., in "nsISupportsImpl.h") suitable definitions
73 * #define NSCAP_ADDREF(this, ptr) NS_ADDREF(ptr)
74 * #define NSCAP_RELEASE(this, ptr) NS_RELEASE(ptr)
77 #ifndef NSCAP_ADDREF
78 # define NSCAP_ADDREF(this, ptr) \
79 mozilla::RefPtrTraits< \
80 typename std::remove_reference<decltype(*ptr)>::type>::AddRef(ptr)
81 #endif
83 #ifndef NSCAP_RELEASE
84 # define NSCAP_RELEASE(this, ptr) \
85 mozilla::RefPtrTraits< \
86 typename std::remove_reference<decltype(*ptr)>::type>::Release(ptr)
87 #endif
89 // Clients can define |NSCAP_LOG_ASSIGNMENT| to perform logging.
90 #ifdef NSCAP_LOG_ASSIGNMENT
91 // Remember that |NSCAP_LOG_ASSIGNMENT| was defined by some client so that we
92 // know to instantiate |~nsGetterAddRefs| in turn to note the external
93 // assignment into the |nsCOMPtr|.
94 # define NSCAP_LOG_EXTERNAL_ASSIGNMENT
95 #else
96 // ...otherwise, just strip it out of the code
97 # define NSCAP_LOG_ASSIGNMENT(this, ptr)
98 #endif
100 #ifndef NSCAP_LOG_RELEASE
101 # define NSCAP_LOG_RELEASE(this, ptr)
102 #endif
104 namespace mozilla {
105 template <class T>
106 class OwningNonNull;
107 } // namespace mozilla
109 template <class T>
110 inline already_AddRefed<T> dont_AddRef(T* aRawPtr) {
111 return already_AddRefed<T>(aRawPtr);
114 template <class T>
115 inline already_AddRefed<T>&& dont_AddRef(
116 already_AddRefed<T>&& aAlreadyAddRefedPtr) {
117 return std::move(aAlreadyAddRefedPtr);
121 * An nsCOMPtr_helper transforms commonly called getters into typesafe forms
122 * that are more convenient to call, and more efficient to use with |nsCOMPtr|s.
123 * Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc.
125 * Here are the rules for a helper:
126 * - it implements |operator()| to produce an interface pointer
127 * - (except for its name) |operator()| is a valid [XP]COM `getter'
128 * - the interface pointer that it returns is already |AddRef()|ed (as from
129 * any good getter)
130 * - it matches the type requested with the supplied |nsIID| argument
131 * - its constructor provides an optional |nsresult*| that |operator()| can
132 * fill in with an error when it is executed
134 * See |class nsGetInterface| for an example.
136 class MOZ_STACK_CLASS nsCOMPtr_helper {
137 public:
138 virtual nsresult NS_FASTCALL operator()(const nsIID&, void**) const = 0;
142 * nsQueryInterface could have been implemented as an nsCOMPtr_helper to avoid
143 * adding specialized machinery in nsCOMPtr, but do_QueryInterface is called
144 * often enough that the codesize savings are big enough to warrant the
145 * specialcasing.
147 class MOZ_STACK_CLASS nsQueryInterfaceISupports {
148 public:
149 explicit nsQueryInterfaceISupports(nsISupports* aRawPtr) : mRawPtr(aRawPtr) {}
151 nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
153 private:
154 nsISupports* MOZ_OWNING_REF mRawPtr;
157 template <typename T>
158 class MOZ_STACK_CLASS nsQueryInterface final
159 : public nsQueryInterfaceISupports {
160 public:
161 explicit nsQueryInterface(T* aRawPtr)
162 : nsQueryInterfaceISupports(ToSupports(aRawPtr)) {}
164 nsresult NS_FASTCALL operator()(const nsIID& aIID, void** aAnswer) const {
165 return nsQueryInterfaceISupports::operator()(aIID, aAnswer);
169 class MOZ_STACK_CLASS nsQueryInterfaceISupportsWithError {
170 public:
171 nsQueryInterfaceISupportsWithError(nsISupports* aRawPtr, nsresult* aError)
172 : mRawPtr(aRawPtr), mErrorPtr(aError) {}
174 nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
176 private:
177 nsISupports* MOZ_OWNING_REF mRawPtr;
178 nsresult* mErrorPtr;
181 template <typename T>
182 class MOZ_STACK_CLASS nsQueryInterfaceWithError final
183 : public nsQueryInterfaceISupportsWithError {
184 public:
185 explicit nsQueryInterfaceWithError(T* aRawPtr, nsresult* aError)
186 : nsQueryInterfaceISupportsWithError(ToSupports(aRawPtr), aError) {}
188 nsresult NS_FASTCALL operator()(const nsIID& aIID, void** aAnswer) const {
189 return nsQueryInterfaceISupportsWithError::operator()(aIID, aAnswer);
193 namespace mozilla {
194 // PointedToType<> is needed so that do_QueryInterface() will work with a
195 // variety of smart pointer types in addition to raw pointers. These types
196 // include RefPtr<>, nsCOMPtr<>, and OwningNonNull<>.
197 template <class T>
198 using PointedToType = std::remove_pointer_t<decltype(&*std::declval<T>())>;
199 } // namespace mozilla
201 template <class T>
202 inline nsQueryInterface<mozilla::PointedToType<T>> do_QueryInterface(T aPtr) {
203 return nsQueryInterface<mozilla::PointedToType<T>>(aPtr);
206 template <class T>
207 inline nsQueryInterfaceWithError<mozilla::PointedToType<T>> do_QueryInterface(
208 T aRawPtr, nsresult* aError) {
209 return nsQueryInterfaceWithError<mozilla::PointedToType<T>>(aRawPtr, aError);
212 template <class T>
213 inline void do_QueryInterface(already_AddRefed<T>&) {
214 // This signature exists solely to _stop_ you from doing the bad thing.
215 // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
216 // someone else is an automatic leak. See bug 8221.
219 template <class T>
220 inline void do_QueryInterface(already_AddRefed<T>&, nsresult*) {
221 // This signature exists solely to _stop_ you from doing the bad thing.
222 // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
223 // someone else is an automatic leak. See bug 8221.
226 ////////////////////////////////////////////////////////////////////////////
227 // Using servicemanager with COMPtrs
228 class nsGetServiceByCID final {
229 public:
230 explicit nsGetServiceByCID(const nsCID& aCID) : mCID(aCID) {}
232 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
234 private:
235 const nsCID& mCID;
238 class nsGetServiceByCIDWithError final {
239 public:
240 nsGetServiceByCIDWithError(const nsCID& aCID, nsresult* aErrorPtr)
241 : mCID(aCID), mErrorPtr(aErrorPtr) {}
243 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
245 private:
246 const nsCID& mCID;
247 nsresult* mErrorPtr;
250 class nsGetServiceByContractID final {
251 public:
252 explicit nsGetServiceByContractID(const char* aContractID)
253 : mContractID(aContractID) {}
255 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
257 private:
258 const char* mContractID;
261 class nsGetServiceByContractIDWithError final {
262 public:
263 nsGetServiceByContractIDWithError(const char* aContractID,
264 nsresult* aErrorPtr)
265 : mContractID(aContractID), mErrorPtr(aErrorPtr) {}
267 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
269 private:
270 const char* mContractID;
271 nsresult* mErrorPtr;
274 class nsIWeakReference;
276 // Weak references
277 class MOZ_STACK_CLASS nsQueryReferent final {
278 public:
279 nsQueryReferent(nsIWeakReference* aWeakPtr, nsresult* aError)
280 : mWeakPtr(aWeakPtr), mErrorPtr(aError) {}
282 nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
284 private:
285 nsIWeakReference* MOZ_NON_OWNING_REF mWeakPtr;
286 nsresult* mErrorPtr;
289 // template<class T> class nsGetterAddRefs;
291 // Helper for assert_validity method
292 template <class T>
293 char (&TestForIID(decltype(&NS_GET_TEMPLATE_IID(T))))[2];
294 template <class T>
295 char TestForIID(...);
297 template <class T>
298 class MOZ_IS_REFPTR nsCOMPtr final {
299 private:
300 void assign_with_AddRef(T*);
301 template <typename U>
302 void assign_from_qi(const nsQueryInterface<U>, const nsIID&);
303 template <typename U>
304 void assign_from_qi_with_error(const nsQueryInterfaceWithError<U>&,
305 const nsIID&);
306 void assign_from_gs_cid(const nsGetServiceByCID, const nsIID&);
307 void assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError&,
308 const nsIID&);
309 void assign_from_gs_contractid(const nsGetServiceByContractID, const nsIID&);
310 void assign_from_gs_contractid_with_error(
311 const nsGetServiceByContractIDWithError&, const nsIID&);
312 void assign_from_query_referent(const nsQueryReferent&, const nsIID&);
313 void assign_from_helper(const nsCOMPtr_helper&, const nsIID&);
314 void** begin_assignment();
316 void assign_assuming_AddRef(T* aNewPtr) {
317 T* oldPtr = mRawPtr;
318 mRawPtr = aNewPtr;
319 NSCAP_LOG_ASSIGNMENT(this, aNewPtr);
320 NSCAP_LOG_RELEASE(this, oldPtr);
321 if (oldPtr) {
322 NSCAP_RELEASE(this, oldPtr);
326 private:
327 T* MOZ_OWNING_REF mRawPtr;
329 void assert_validity() {
330 static_assert(1 < sizeof(TestForIID<T>(nullptr)),
331 "nsCOMPtr only works "
332 "for types with IIDs. Either use RefPtr; add an IID to "
333 "your type with NS_DECLARE_STATIC_IID_ACCESSOR/"
334 "NS_DEFINE_STATIC_IID_ACCESSOR; or make the nsCOMPtr point "
335 "to a base class with an IID.");
338 public:
339 typedef T element_type;
341 ~nsCOMPtr() {
342 NSCAP_LOG_RELEASE(this, mRawPtr);
343 if (mRawPtr) {
344 NSCAP_RELEASE(this, mRawPtr);
348 #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
349 void Assert_NoQueryNeeded() {
350 if (!mRawPtr) {
351 return;
353 if constexpr (std::is_same_v<T, nsISupports>) {
354 // FIXME: nsCOMPtr<nsISupports> never asserted this, and it currently
355 // fails...
356 return;
358 // This can't be defined in terms of do_QueryInterface because
359 // that bans casts from a class to itself.
360 void* out = nullptr;
361 mRawPtr->QueryInterface(NS_GET_TEMPLATE_IID(T), &out);
362 T* query_result = static_cast<T*>(out);
363 MOZ_ASSERT(query_result == mRawPtr, "QueryInterface needed");
364 NS_RELEASE(query_result);
367 # define NSCAP_ASSERT_NO_QUERY_NEEDED() Assert_NoQueryNeeded();
368 #else
369 # define NSCAP_ASSERT_NO_QUERY_NEEDED()
370 #endif
372 // Constructors
374 nsCOMPtr() : mRawPtr(nullptr) {
375 assert_validity();
376 NSCAP_LOG_ASSIGNMENT(this, nullptr);
379 MOZ_IMPLICIT nsCOMPtr(decltype(nullptr)) : mRawPtr(nullptr) {
380 assert_validity();
381 NSCAP_LOG_ASSIGNMENT(this, nullptr);
384 nsCOMPtr(const nsCOMPtr<T>& aSmartPtr) : mRawPtr(aSmartPtr.mRawPtr) {
385 assert_validity();
386 if (mRawPtr) {
387 NSCAP_ADDREF(this, mRawPtr);
389 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr);
392 template <class U>
393 MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr<U>& aSmartPtr)
394 : mRawPtr(aSmartPtr.get()) {
395 // Make sure that U actually inherits from T
396 static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
397 assert_validity();
398 if (mRawPtr) {
399 NSCAP_ADDREF(this, mRawPtr);
401 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.get());
404 nsCOMPtr(nsCOMPtr<T>&& aSmartPtr) : mRawPtr(aSmartPtr.mRawPtr) {
405 assert_validity();
406 aSmartPtr.mRawPtr = nullptr;
407 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
410 template <class U>
411 MOZ_IMPLICIT nsCOMPtr(nsCOMPtr<U>&& aSmartPtr)
412 : mRawPtr(aSmartPtr.forget().template downcast<T>().take()) {
413 // Make sure that U actually inherits from T
414 static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
415 assert_validity();
416 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
417 NSCAP_ASSERT_NO_QUERY_NEEDED();
420 MOZ_IMPLICIT nsCOMPtr(T* aRawPtr) : mRawPtr(aRawPtr) {
421 assert_validity();
422 if (mRawPtr) {
423 NSCAP_ADDREF(this, mRawPtr);
425 NSCAP_LOG_ASSIGNMENT(this, aRawPtr);
426 NSCAP_ASSERT_NO_QUERY_NEEDED();
429 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T>& aSmartPtr)
430 : mRawPtr(aSmartPtr.take()) {
431 assert_validity();
432 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
433 NSCAP_ASSERT_NO_QUERY_NEEDED();
436 // Construct from |otherComPtr.forget()|.
437 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T>&& aSmartPtr)
438 : mRawPtr(aSmartPtr.take()) {
439 assert_validity();
440 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
441 NSCAP_ASSERT_NO_QUERY_NEEDED();
444 // Construct from |std::move(otherRefPtr)|.
445 template <typename U>
446 MOZ_IMPLICIT nsCOMPtr(RefPtr<U>&& aSmartPtr)
447 : mRawPtr(static_cast<already_AddRefed<T>>(aSmartPtr.forget()).take()) {
448 assert_validity();
449 // Make sure that U actually inherits from T
450 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
451 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
452 NSCAP_ASSERT_NO_QUERY_NEEDED();
455 // Construct from |already_AddRefed|.
456 template <typename U>
457 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<U>& aSmartPtr)
458 : mRawPtr(static_cast<T*>(aSmartPtr.take())) {
459 assert_validity();
460 // But make sure that U actually inherits from T.
461 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
462 NSCAP_LOG_ASSIGNMENT(this, static_cast<T*>(mRawPtr));
463 NSCAP_ASSERT_NO_QUERY_NEEDED();
466 // Construct from |otherComPtr.forget()|.
467 template <typename U>
468 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<U>&& aSmartPtr)
469 : mRawPtr(static_cast<T*>(aSmartPtr.take())) {
470 assert_validity();
471 // But make sure that U actually inherits from T.
472 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
473 NSCAP_LOG_ASSIGNMENT(this, static_cast<T*>(mRawPtr));
474 NSCAP_ASSERT_NO_QUERY_NEEDED();
477 // Construct from |do_QueryInterface(expr)|.
478 template <typename U>
479 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterface<U> aQI) : mRawPtr(nullptr) {
480 assert_validity();
481 NSCAP_LOG_ASSIGNMENT(this, nullptr);
482 assign_from_qi(aQI, NS_GET_TEMPLATE_IID(T));
485 // Construct from |do_QueryInterface(expr, &rv)|.
486 template <typename U>
487 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceWithError<U>& aQI)
488 : mRawPtr(nullptr) {
489 assert_validity();
490 NSCAP_LOG_ASSIGNMENT(this, nullptr);
491 assign_from_qi_with_error(aQI, NS_GET_TEMPLATE_IID(T));
494 // Construct from |do_GetService(cid_expr)|.
495 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCID aGS) : mRawPtr(nullptr) {
496 assert_validity();
497 NSCAP_LOG_ASSIGNMENT(this, nullptr);
498 assign_from_gs_cid(aGS, NS_GET_TEMPLATE_IID(T));
501 // Construct from |do_GetService(cid_expr, &rv)|.
502 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCIDWithError& aGS)
503 : mRawPtr(nullptr) {
504 assert_validity();
505 NSCAP_LOG_ASSIGNMENT(this, nullptr);
506 assign_from_gs_cid_with_error(aGS, NS_GET_TEMPLATE_IID(T));
509 // Construct from |do_GetService(contractid_expr)|.
510 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractID aGS) : mRawPtr(nullptr) {
511 assert_validity();
512 NSCAP_LOG_ASSIGNMENT(this, nullptr);
513 assign_from_gs_contractid(aGS, NS_GET_TEMPLATE_IID(T));
516 // Construct from |do_GetService(contractid_expr, &rv)|.
517 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
518 : mRawPtr(nullptr) {
519 assert_validity();
520 NSCAP_LOG_ASSIGNMENT(this, nullptr);
521 assign_from_gs_contractid_with_error(aGS, NS_GET_TEMPLATE_IID(T));
524 // Construct from |do_QueryReferent(ptr)|
525 MOZ_IMPLICIT nsCOMPtr(const nsQueryReferent& aQueryReferent)
526 : mRawPtr(nullptr) {
527 assert_validity();
528 NSCAP_LOG_ASSIGNMENT(this, nullptr);
529 assign_from_query_referent(aQueryReferent, NS_GET_TEMPLATE_IID(T));
532 // And finally, anything else we might need to construct from can exploit the
533 // nsCOMPtr_helper facility.
534 MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper) : mRawPtr(nullptr) {
535 assert_validity();
536 NSCAP_LOG_ASSIGNMENT(this, nullptr);
537 assign_from_helper(aHelper, NS_GET_TEMPLATE_IID(T));
538 NSCAP_ASSERT_NO_QUERY_NEEDED();
541 // construct from |mozilla::NotNull|.
542 template <typename I,
543 typename = std::enable_if_t<!std::is_same_v<I, nsCOMPtr<T>> &&
544 std::is_convertible_v<I, nsCOMPtr<T>>>>
545 MOZ_IMPLICIT nsCOMPtr(const mozilla::NotNull<I>& aSmartPtr)
546 : mRawPtr(nsCOMPtr<T>(aSmartPtr.get()).forget().take()) {}
548 // construct from |mozilla::MovingNotNull|.
549 template <typename I,
550 typename = std::enable_if_t<!std::is_same_v<I, nsCOMPtr<T>> &&
551 std::is_convertible_v<I, nsCOMPtr<T>>>>
552 MOZ_IMPLICIT nsCOMPtr(mozilla::MovingNotNull<I>&& aSmartPtr)
553 : mRawPtr(
554 nsCOMPtr<T>(std::move(aSmartPtr).unwrapBasePtr()).forget().take()) {
557 // Defined in OwningNonNull.h
558 template <class U>
559 MOZ_IMPLICIT nsCOMPtr(const mozilla::OwningNonNull<U>& aOther);
561 // Assignment operators
563 nsCOMPtr<T>& operator=(const nsCOMPtr<T>& aRhs) {
564 assign_with_AddRef(aRhs.mRawPtr);
565 return *this;
568 template <class U>
569 nsCOMPtr<T>& operator=(const nsCOMPtr<U>& aRhs) {
570 // Make sure that U actually inherits from T
571 static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
572 assign_with_AddRef(aRhs.get());
573 return *this;
576 nsCOMPtr<T>& operator=(nsCOMPtr<T>&& aRhs) {
577 assign_assuming_AddRef(aRhs.forget().take());
578 return *this;
581 template <class U>
582 nsCOMPtr<T>& operator=(nsCOMPtr<U>&& aRhs) {
583 // Make sure that U actually inherits from T
584 static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
585 assign_assuming_AddRef(aRhs.forget().template downcast<T>().take());
586 NSCAP_ASSERT_NO_QUERY_NEEDED();
587 return *this;
590 nsCOMPtr<T>& operator=(T* aRhs) {
591 assign_with_AddRef(aRhs);
592 NSCAP_ASSERT_NO_QUERY_NEEDED();
593 return *this;
596 nsCOMPtr<T>& operator=(decltype(nullptr)) {
597 assign_assuming_AddRef(nullptr);
598 return *this;
601 // Assign from |already_AddRefed|.
602 template <typename U>
603 nsCOMPtr<T>& operator=(already_AddRefed<U>& aRhs) {
604 // Make sure that U actually inherits from T
605 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
606 assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
607 NSCAP_ASSERT_NO_QUERY_NEEDED();
608 return *this;
611 // Assign from |otherComPtr.forget()|.
612 template <typename U>
613 nsCOMPtr<T>& operator=(already_AddRefed<U>&& aRhs) {
614 // Make sure that U actually inherits from T
615 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
616 assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
617 NSCAP_ASSERT_NO_QUERY_NEEDED();
618 return *this;
621 // Assign from |std::move(otherRefPtr)|.
622 template <typename U>
623 nsCOMPtr<T>& operator=(RefPtr<U>&& aRhs) {
624 // Make sure that U actually inherits from T
625 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
626 assign_assuming_AddRef(static_cast<T*>(aRhs.forget().take()));
627 NSCAP_ASSERT_NO_QUERY_NEEDED();
628 return *this;
631 // Assign from |do_QueryInterface(expr)|.
632 template <typename U>
633 nsCOMPtr<T>& operator=(const nsQueryInterface<U> aRhs) {
634 assign_from_qi(aRhs, NS_GET_TEMPLATE_IID(T));
635 return *this;
638 // Assign from |do_QueryInterface(expr, &rv)|.
639 template <typename U>
640 nsCOMPtr<T>& operator=(const nsQueryInterfaceWithError<U>& aRhs) {
641 assign_from_qi_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
642 return *this;
645 // Assign from |do_GetService(cid_expr)|.
646 nsCOMPtr<T>& operator=(const nsGetServiceByCID aRhs) {
647 assign_from_gs_cid(aRhs, NS_GET_TEMPLATE_IID(T));
648 return *this;
651 // Assign from |do_GetService(cid_expr, &rv)|.
652 nsCOMPtr<T>& operator=(const nsGetServiceByCIDWithError& aRhs) {
653 assign_from_gs_cid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
654 return *this;
657 // Assign from |do_GetService(contractid_expr)|.
658 nsCOMPtr<T>& operator=(const nsGetServiceByContractID aRhs) {
659 assign_from_gs_contractid(aRhs, NS_GET_TEMPLATE_IID(T));
660 return *this;
663 // Assign from |do_GetService(contractid_expr, &rv)|.
664 nsCOMPtr<T>& operator=(const nsGetServiceByContractIDWithError& aRhs) {
665 assign_from_gs_contractid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
666 return *this;
669 // Assign from |do_QueryReferent(ptr)|.
670 nsCOMPtr<T>& operator=(const nsQueryReferent& aRhs) {
671 assign_from_query_referent(aRhs, NS_GET_TEMPLATE_IID(T));
672 return *this;
675 // And finally, anything else we might need to assign from can exploit the
676 // nsCOMPtr_helper facility.
677 nsCOMPtr<T>& operator=(const nsCOMPtr_helper& aRhs) {
678 assign_from_helper(aRhs, NS_GET_TEMPLATE_IID(T));
679 NSCAP_ASSERT_NO_QUERY_NEEDED();
680 return *this;
683 // Assign from |mozilla::NotNull|.
684 template <typename I,
685 typename = std::enable_if_t<std::is_convertible_v<I, nsCOMPtr<T>>>>
686 nsCOMPtr<T>& operator=(const mozilla::NotNull<I>& aSmartPtr) {
687 assign_assuming_AddRef(nsCOMPtr<T>(aSmartPtr.get()).forget().take());
688 return *this;
691 // Assign from |mozilla::MovingNotNull|.
692 template <typename I,
693 typename = std::enable_if_t<std::is_convertible_v<I, nsCOMPtr<T>>>>
694 nsCOMPtr<T>& operator=(mozilla::MovingNotNull<I>&& aSmartPtr) {
695 assign_assuming_AddRef(
696 nsCOMPtr<T>(std::move(aSmartPtr).unwrapBasePtr()).forget().take());
697 return *this;
700 // Defined in OwningNonNull.h
701 template <class U>
702 nsCOMPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
704 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
705 void swap(nsCOMPtr<T>& aRhs) {
706 T* temp = aRhs.mRawPtr;
707 NSCAP_LOG_ASSIGNMENT(&aRhs, mRawPtr);
708 NSCAP_LOG_ASSIGNMENT(this, temp);
709 NSCAP_LOG_RELEASE(this, mRawPtr);
710 NSCAP_LOG_RELEASE(&aRhs, temp);
711 aRhs.mRawPtr = mRawPtr;
712 mRawPtr = temp;
713 // |aRhs| maintains the same invariants, so we don't need to
714 // |NSCAP_ASSERT_NO_QUERY_NEEDED|
717 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
718 void swap(T*& aRhs) {
719 T* temp = aRhs;
720 NSCAP_LOG_ASSIGNMENT(this, temp);
721 NSCAP_LOG_RELEASE(this, mRawPtr);
722 aRhs = reinterpret_cast<T*>(mRawPtr);
723 mRawPtr = temp;
724 NSCAP_ASSERT_NO_QUERY_NEEDED();
727 // Other pointer operators
729 // Return the value of mRawPtr and null out mRawPtr. Useful for
730 // already_AddRefed return values.
731 already_AddRefed<T> MOZ_MAY_CALL_AFTER_MUST_RETURN forget() {
732 T* temp = nullptr;
733 swap(temp);
734 return already_AddRefed<T>(temp);
737 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
738 // Useful to avoid unnecessary AddRef/Release pairs with "out" parameters
739 // where aRhs bay be a T** or an I** where I is a base class of T.
740 template <typename I>
741 void forget(I** aRhs) {
742 NS_ASSERTION(aRhs, "Null pointer passed to forget!");
743 NSCAP_LOG_RELEASE(this, mRawPtr);
744 *aRhs = get();
745 mRawPtr = nullptr;
748 // Prefer the implicit conversion provided automatically by
749 // |operator T*() const|. Use |get()| to resolve ambiguity or to get a
750 // castable pointer.
751 T* get() const { return reinterpret_cast<T*>(mRawPtr); }
753 // Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
754 // used in a context where a raw pointer is expected. It is this operator
755 // that makes an nsCOMPtr substitutable for a raw pointer.
757 // Prefer the implicit use of this operator to calling |get()|, except where
758 // necessary to resolve ambiguity.
759 operator T*() const& { return get(); }
761 // Don't allow implicit conversion of temporary nsCOMPtr to raw pointer,
762 // because the refcount might be one and the pointer will immediately become
763 // invalid.
764 operator T*() const&& = delete;
766 // Needed to avoid the deleted operator above
767 explicit operator bool() const { return !!mRawPtr; }
769 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
770 MOZ_ASSERT(mRawPtr != nullptr,
771 "You can't dereference a NULL nsCOMPtr with operator->().");
772 return get();
775 // These are not intended to be used by clients. See |address_of| below.
776 nsCOMPtr<T>* get_address() { return this; }
777 const nsCOMPtr<T>* get_address() const { return this; }
779 public:
780 T& operator*() const {
781 MOZ_ASSERT(mRawPtr != nullptr,
782 "You can't dereference a NULL nsCOMPtr with operator*().");
783 return *get();
786 T** StartAssignment() {
787 #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
788 return reinterpret_cast<T**>(begin_assignment());
789 #else
790 assign_assuming_AddRef(nullptr);
791 return reinterpret_cast<T**>(&mRawPtr);
792 #endif
796 template <typename T>
797 inline void ImplCycleCollectionUnlink(nsCOMPtr<T>& aField) {
798 aField = nullptr;
801 template <typename T>
802 inline void ImplCycleCollectionTraverse(
803 nsCycleCollectionTraversalCallback& aCallback, nsCOMPtr<T>& aField,
804 const char* aName, uint32_t aFlags = 0) {
805 CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
808 template <class T>
809 void nsCOMPtr<T>::assign_with_AddRef(T* aRawPtr) {
810 if (aRawPtr) {
811 NSCAP_ADDREF(this, aRawPtr);
813 assign_assuming_AddRef(aRawPtr);
816 template <class T>
817 template <typename U>
818 void nsCOMPtr<T>::assign_from_qi(const nsQueryInterface<U> aQI,
819 const nsIID& aIID) {
820 // Allow QIing to nsISupports from nsISupports as a special-case, since
821 // SameCOMIdentity uses it.
822 static_assert(
823 std::is_same_v<T, nsISupports> ||
824 !(std::is_same_v<T, U> || std::is_base_of<T, U>::value),
825 "don't use do_QueryInterface for compile-time-determinable casts");
826 void* newRawPtr;
827 if (NS_FAILED(aQI(aIID, &newRawPtr))) {
828 newRawPtr = nullptr;
830 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
833 template <class T>
834 template <typename U>
835 void nsCOMPtr<T>::assign_from_qi_with_error(
836 const nsQueryInterfaceWithError<U>& aQI, const nsIID& aIID) {
837 static_assert(
838 !(std::is_same_v<T, U> || std::is_base_of<T, U>::value),
839 "don't use do_QueryInterface for compile-time-determinable casts");
840 void* newRawPtr;
841 if (NS_FAILED(aQI(aIID, &newRawPtr))) {
842 newRawPtr = nullptr;
844 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
847 template <class T>
848 void nsCOMPtr<T>::assign_from_gs_cid(const nsGetServiceByCID aGS,
849 const nsIID& aIID) {
850 void* newRawPtr;
851 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
852 newRawPtr = nullptr;
854 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
857 template <class T>
858 void nsCOMPtr<T>::assign_from_gs_cid_with_error(
859 const nsGetServiceByCIDWithError& aGS, const nsIID& aIID) {
860 void* newRawPtr;
861 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
862 newRawPtr = nullptr;
864 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
867 template <class T>
868 void nsCOMPtr<T>::assign_from_gs_contractid(const nsGetServiceByContractID aGS,
869 const nsIID& aIID) {
870 void* newRawPtr;
871 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
872 newRawPtr = nullptr;
874 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
877 template <class T>
878 void nsCOMPtr<T>::assign_from_gs_contractid_with_error(
879 const nsGetServiceByContractIDWithError& aGS, const nsIID& aIID) {
880 void* newRawPtr;
881 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
882 newRawPtr = nullptr;
884 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
887 template <class T>
888 void nsCOMPtr<T>::assign_from_query_referent(
889 const nsQueryReferent& aQueryReferent, const nsIID& aIID) {
890 void* newRawPtr;
891 if (NS_FAILED(aQueryReferent(aIID, &newRawPtr))) {
892 newRawPtr = nullptr;
894 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
897 template <class T>
898 void nsCOMPtr<T>::assign_from_helper(const nsCOMPtr_helper& helper,
899 const nsIID& aIID) {
900 void* newRawPtr;
901 if (NS_FAILED(helper(aIID, &newRawPtr))) {
902 newRawPtr = nullptr;
904 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
907 template <class T>
908 void** nsCOMPtr<T>::begin_assignment() {
909 assign_assuming_AddRef(nullptr);
910 union {
911 T** mT;
912 void** mVoid;
913 } result;
914 result.mT = &mRawPtr;
915 return result.mVoid;
918 template <class T>
919 inline nsCOMPtr<T>* address_of(nsCOMPtr<T>& aPtr) {
920 return aPtr.get_address();
923 template <class T>
924 inline const nsCOMPtr<T>* address_of(const nsCOMPtr<T>& aPtr) {
925 return aPtr.get_address();
929 * This class is designed to be used for anonymous temporary objects in the
930 * argument list of calls that return COM interface pointers, e.g.,
932 * nsCOMPtr<IFoo> fooP;
933 * ...->QueryInterface(iid, getter_AddRefs(fooP))
935 * DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
937 * When initialized with a |nsCOMPtr|, as in the example above, it returns
938 * a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call
939 * (|QueryInterface| in this case) can fill in.
941 * This type should be a nested class inside |nsCOMPtr<T>|.
943 template <class T>
944 class nsGetterAddRefs {
945 public:
946 explicit nsGetterAddRefs(nsCOMPtr<T>& aSmartPtr)
947 : mTargetSmartPtr(aSmartPtr) {}
949 #if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || \
950 defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT)
951 ~nsGetterAddRefs() {
952 # ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
953 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),
954 mTargetSmartPtr.get());
955 # endif
957 # ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
958 mTargetSmartPtr.Assert_NoQueryNeeded();
959 # endif
961 #endif
963 operator void**() {
964 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
967 operator T**() { return mTargetSmartPtr.StartAssignment(); }
968 T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
970 private:
971 nsCOMPtr<T>& mTargetSmartPtr;
974 template <>
975 class nsGetterAddRefs<nsISupports> {
976 public:
977 explicit nsGetterAddRefs(nsCOMPtr<nsISupports>& aSmartPtr)
978 : mTargetSmartPtr(aSmartPtr) {}
980 #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
981 ~nsGetterAddRefs() {
982 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),
983 mTargetSmartPtr.get());
985 #endif
987 operator void**() {
988 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
991 operator nsISupports**() { return mTargetSmartPtr.StartAssignment(); }
992 nsISupports*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
994 private:
995 nsCOMPtr<nsISupports>& mTargetSmartPtr;
998 template <class T>
999 inline nsGetterAddRefs<T> getter_AddRefs(nsCOMPtr<T>& aSmartPtr) {
1000 return nsGetterAddRefs<T>(aSmartPtr);
1003 template <class T, class DestinationType>
1004 inline nsresult CallQueryInterface(
1005 T* aSource, nsGetterAddRefs<DestinationType> aDestination) {
1006 return CallQueryInterface(aSource,
1007 static_cast<DestinationType**>(aDestination));
1010 // Comparing two |nsCOMPtr|s
1012 template <class T, class U>
1013 inline bool operator==(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs) {
1014 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
1017 template <class T, class U>
1018 inline bool operator!=(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs) {
1019 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
1022 // Comparing an |nsCOMPtr| to a raw pointer
1024 template <class T, class U>
1025 inline bool operator==(const nsCOMPtr<T>& aLhs, const U* aRhs) {
1026 return static_cast<const T*>(aLhs.get()) == aRhs;
1029 template <class T, class U>
1030 inline bool operator==(const U* aLhs, const nsCOMPtr<T>& aRhs) {
1031 return aLhs == static_cast<const T*>(aRhs.get());
1034 template <class T, class U>
1035 inline bool operator!=(const nsCOMPtr<T>& aLhs, const U* aRhs) {
1036 return static_cast<const T*>(aLhs.get()) != aRhs;
1039 template <class T, class U>
1040 inline bool operator!=(const U* aLhs, const nsCOMPtr<T>& aRhs) {
1041 return aLhs != static_cast<const T*>(aRhs.get());
1044 template <class T, class U>
1045 inline bool operator==(const nsCOMPtr<T>& aLhs, U* aRhs) {
1046 return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
1049 template <class T, class U>
1050 inline bool operator==(U* aLhs, const nsCOMPtr<T>& aRhs) {
1051 return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
1054 template <class T, class U>
1055 inline bool operator!=(const nsCOMPtr<T>& aLhs, U* aRhs) {
1056 return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
1059 template <class T, class U>
1060 inline bool operator!=(U* aLhs, const nsCOMPtr<T>& aRhs) {
1061 return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
1064 // Comparing an |nsCOMPtr| to |nullptr|
1066 template <class T>
1067 inline bool operator==(const nsCOMPtr<T>& aLhs, decltype(nullptr)) {
1068 return aLhs.get() == nullptr;
1071 template <class T>
1072 inline bool operator==(decltype(nullptr), const nsCOMPtr<T>& aRhs) {
1073 return nullptr == aRhs.get();
1076 template <class T>
1077 inline bool operator!=(const nsCOMPtr<T>& aLhs, decltype(nullptr)) {
1078 return aLhs.get() != nullptr;
1081 template <class T>
1082 inline bool operator!=(decltype(nullptr), const nsCOMPtr<T>& aRhs) {
1083 return nullptr != aRhs.get();
1086 // Comparing any two [XP]COM objects for identity
1088 inline bool SameCOMIdentity(nsISupports* aLhs, nsISupports* aRhs) {
1089 return nsCOMPtr<nsISupports>(do_QueryInterface(aLhs)) ==
1090 nsCOMPtr<nsISupports>(do_QueryInterface(aRhs));
1093 template <class SourceType, class DestinationType>
1094 inline nsresult CallQueryInterface(nsCOMPtr<SourceType>& aSourcePtr,
1095 DestinationType** aDestPtr) {
1096 return CallQueryInterface(aSourcePtr.get(), aDestPtr);
1099 template <class T>
1100 RefPtr<T>::RefPtr(const nsQueryReferent& aQueryReferent) {
1101 void* newRawPtr;
1102 if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1103 newRawPtr = nullptr;
1105 mRawPtr = static_cast<T*>(newRawPtr);
1108 template <class T>
1109 RefPtr<T>::RefPtr(const nsCOMPtr_helper& aHelper) {
1110 void* newRawPtr;
1111 if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1112 newRawPtr = nullptr;
1114 mRawPtr = static_cast<T*>(newRawPtr);
1117 template <class T>
1118 RefPtr<T>& RefPtr<T>::operator=(const nsQueryReferent& aQueryReferent) {
1119 void* newRawPtr;
1120 if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1121 newRawPtr = nullptr;
1123 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1124 return *this;
1127 template <class T>
1128 RefPtr<T>& RefPtr<T>::operator=(const nsCOMPtr_helper& aHelper) {
1129 void* newRawPtr;
1130 if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1131 newRawPtr = nullptr;
1133 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1134 return *this;
1137 template <class T>
1138 inline already_AddRefed<T> do_AddRef(const nsCOMPtr<T>& aObj) {
1139 nsCOMPtr<T> ref(aObj);
1140 return ref.forget();
1143 // MOZ_DBG support
1145 template <class T>
1146 std::ostream& operator<<(std::ostream& aOut, const nsCOMPtr<T>& aObj) {
1147 return mozilla::DebugValue(aOut, aObj.get());
1150 // ToRefPtr allows to move an nsCOMPtr<T> into a RefPtr<T>. Be mindful when
1151 // using this, because usually RefPtr<T> should only be used with concrete T and
1152 // nsCOMPtr<T> should only be used with XPCOM interface T.
1153 template <class T>
1154 RefPtr<T> ToRefPtr(nsCOMPtr<T>&& aObj) {
1155 return aObj.forget();
1158 // Integration with ResultExtensions.h
1159 template <typename R>
1160 auto ResultRefAsParam(nsCOMPtr<R>& aResult) {
1161 return getter_AddRefs(aResult);
1164 namespace mozilla::detail {
1165 template <typename T>
1166 struct outparam_as_pointer;
1168 template <typename T>
1169 struct outparam_as_pointer<nsGetterAddRefs<T>> {
1170 using type = T**;
1172 } // namespace mozilla::detail
1174 #endif // !defined(nsCOMPtr_h___)