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/. */
6
7 #ifndef nsCOMPtr_h___
8 #define nsCOMPtr_h___
9
10 /*
11 * Having problems?
12 *
13 * See the User Manual at:
14 * http://www.mozilla.org/projects/xpcom/nsCOMPtr.html
15 *
16 *
17 * nsCOMPtr
18 * better than a raw pointer
19 * for owning objects
20 * -- scc
21 */
22
23 #include "mozilla/AlreadyAddRefed.h"
24 #include "mozilla/Assertions.h"
25 #include "mozilla/Attributes.h"
26 #include "mozilla/Move.h"
27 #include "mozilla/TypeTraits.h"
28
29 #include "nsDebug.h" // for |NS_ASSERTION|
30 #include "nsISupportsUtils.h" // for |nsresult|, |NS_ADDREF|, |NS_GET_TEMPLATE_IID| et al
31 #include "mozilla/RefPtr.h"
32
33 #include "nsCycleCollectionNoteChild.h"
34
35
36 /*
37 * WARNING: This file defines several macros for internal use only. These
38 * macros begin with the prefix |NSCAP_|. Do not use these macros in your own
39 * code. They are for internal use only for cross-platform compatibility, and
40 * are subject to change without notice.
41 */
42
43
44 #ifdef _MSC_VER
45 // Under VC++, we win by inlining StartAssignment.
46 #define NSCAP_FEATURE_INLINE_STARTASSIGNMENT
47
48 // Also under VC++, at the highest warning level, we are overwhelmed with
49 // warnings about (unused) inline functions being removed. This is to be
50 // expected with templates, so we disable the warning.
51 #pragma warning( disable: 4514 )
52 #endif
53
54 #define NSCAP_FEATURE_USE_BASE
55
56 #ifdef DEBUG
57 #define NSCAP_FEATURE_TEST_DONTQUERY_CASES
58 #undef NSCAP_FEATURE_USE_BASE
59 #endif
60
61 #ifdef __GNUC__
62 // Our use of nsCOMPtr_base::mRawPtr violates the C++ standard's aliasing
63 // rules. Mark it with the may_alias attribute so that gcc 3.3 and higher
64 // don't reorder instructions based on aliasing assumptions for
65 // this variable. Fortunately, gcc versions < 3.3 do not do any
66 // optimizations that break nsCOMPtr.
67
68 #define NS_MAY_ALIAS_PTR(t) t* __attribute__((__may_alias__))
69 #else
70 #define NS_MAY_ALIAS_PTR(t) t*
71 #endif
72
73 #if defined(NSCAP_DISABLE_DEBUG_PTR_TYPES)
74 #define NSCAP_FEATURE_USE_BASE
75 #endif
76
77 /*
78 * The following three macros (NSCAP_ADDREF, NSCAP_RELEASE, and
79 * NSCAP_LOG_ASSIGNMENT) allow external clients the ability to add logging or
80 * other interesting debug facilities. In fact, if you want |nsCOMPtr| to
81 * participate in the standard logging facility, you provide
82 * (e.g., in "nsISupportsImpl.h") suitable definitions
83 *
84 * #define NSCAP_ADDREF(this, ptr) NS_ADDREF(ptr)
85 * #define NSCAP_RELEASE(this, ptr) NS_RELEASE(ptr)
86 */
87
88 #ifndef NSCAP_ADDREF
89 #define NSCAP_ADDREF(this, ptr) (ptr)->AddRef()
90 #endif
91
92 #ifndef NSCAP_RELEASE
93 #define NSCAP_RELEASE(this, ptr) (ptr)->Release()
94 #endif
95
96 // Clients can define |NSCAP_LOG_ASSIGNMENT| to perform logging.
97 #ifdef NSCAP_LOG_ASSIGNMENT
98 // Remember that |NSCAP_LOG_ASSIGNMENT| was defined by some client so that we
99 // know to instantiate |~nsGetterAddRefs| in turn to note the external
100 // assignment into the |nsCOMPtr|.
101 #define NSCAP_LOG_EXTERNAL_ASSIGNMENT
102 #else
103 // ...otherwise, just strip it out of the code
104 #define NSCAP_LOG_ASSIGNMENT(this, ptr)
105 #endif
106
107 #ifndef NSCAP_LOG_RELEASE
108 #define NSCAP_LOG_RELEASE(this, ptr)
109 #endif
110
111 namespace mozilla {
112 template<class T> class OwningNonNull;
113 } // namespace mozilla
114
115 template<class T>
116 inline already_AddRefed<T>
dont_AddRef(T * aRawPtr)117 dont_AddRef(T* aRawPtr)
118 {
119 return already_AddRefed<T>(aRawPtr);
120 }
121
122 template<class T>
123 inline already_AddRefed<T>&&
dont_AddRef(already_AddRefed<T> && aAlreadyAddRefedPtr)124 dont_AddRef(already_AddRefed<T>&& aAlreadyAddRefedPtr)
125 {
126 return mozilla::Move(aAlreadyAddRefedPtr);
127 }
128
129
130 /*
131 * An nsCOMPtr_helper transforms commonly called getters into typesafe forms
132 * that are more convenient to call, and more efficient to use with |nsCOMPtr|s.
133 * Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc.
134 *
135 * Here are the rules for a helper:
136 * - it implements |operator()| to produce an interface pointer
137 * - (except for its name) |operator()| is a valid [XP]COM `getter'
138 * - the interface pointer that it returns is already |AddRef()|ed (as from
139 * any good getter)
140 * - it matches the type requested with the supplied |nsIID| argument
141 * - its constructor provides an optional |nsresult*| that |operator()| can
142 * fill in with an error when it is executed
143 *
144 * See |class nsGetInterface| for an example.
145 */
146 class MOZ_STACK_CLASS nsCOMPtr_helper
147 {
148 public:
149 virtual nsresult NS_FASTCALL operator()(const nsIID&, void**) const = 0;
150 };
151
152 /*
153 * nsQueryInterface could have been implemented as an nsCOMPtr_helper to avoid
154 * adding specialized machinery in nsCOMPtr, but do_QueryInterface is called
155 * often enough that the codesize savings are big enough to warrant the
156 * specialcasing.
157 */
158 class MOZ_STACK_CLASS nsQueryInterface final
159 {
160 public:
161 explicit
nsQueryInterface(nsISupports * aRawPtr)162 nsQueryInterface(nsISupports* aRawPtr) : mRawPtr(aRawPtr) {}
163
164 nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
165
166 private:
167 nsISupports* MOZ_OWNING_REF mRawPtr;
168 };
169
170 class nsQueryInterfaceWithError final
171 {
172 public:
nsQueryInterfaceWithError(nsISupports * aRawPtr,nsresult * aError)173 nsQueryInterfaceWithError(nsISupports* aRawPtr, nsresult* aError)
174 : mRawPtr(aRawPtr)
175 , mErrorPtr(aError)
176 {
177 }
178
179 nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
180
181 private:
182 nsISupports* MOZ_OWNING_REF mRawPtr;
183 nsresult* mErrorPtr;
184 };
185
186 inline nsQueryInterface
do_QueryInterface(nsISupports * aRawPtr)187 do_QueryInterface(nsISupports* aRawPtr)
188 {
189 return nsQueryInterface(aRawPtr);
190 }
191
192 inline nsQueryInterfaceWithError
do_QueryInterface(nsISupports * aRawPtr,nsresult * aError)193 do_QueryInterface(nsISupports* aRawPtr, nsresult* aError)
194 {
195 return nsQueryInterfaceWithError(aRawPtr, aError);
196 }
197
198 template<class T>
199 inline void
do_QueryInterface(already_AddRefed<T> &)200 do_QueryInterface(already_AddRefed<T>&)
201 {
202 // This signature exists solely to _stop_ you from doing the bad thing.
203 // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
204 // someone else is an automatic leak. See bug 8221.
205 }
206
207 template<class T>
208 inline void
do_QueryInterface(already_AddRefed<T> &,nsresult *)209 do_QueryInterface(already_AddRefed<T>&, nsresult*)
210 {
211 // This signature exists solely to _stop_ you from doing the bad thing.
212 // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
213 // someone else is an automatic leak. See bug 8221.
214 }
215
216
217 ////////////////////////////////////////////////////////////////////////////
218 // Using servicemanager with COMPtrs
219 class nsGetServiceByCID final
220 {
221 public:
nsGetServiceByCID(const nsCID & aCID)222 explicit nsGetServiceByCID(const nsCID& aCID) : mCID(aCID) {}
223
224 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
225
226 private:
227 const nsCID& mCID;
228 };
229
230 class nsGetServiceByCIDWithError final
231 {
232 public:
nsGetServiceByCIDWithError(const nsCID & aCID,nsresult * aErrorPtr)233 nsGetServiceByCIDWithError(const nsCID& aCID, nsresult* aErrorPtr)
234 : mCID(aCID)
235 , mErrorPtr(aErrorPtr)
236 {
237 }
238
239 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
240
241 private:
242 const nsCID& mCID;
243 nsresult* mErrorPtr;
244 };
245
246 class nsGetServiceByContractID final
247 {
248 public:
nsGetServiceByContractID(const char * aContractID)249 explicit nsGetServiceByContractID(const char* aContractID)
250 : mContractID(aContractID)
251 {
252 }
253
254 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
255
256 private:
257 const char* mContractID;
258 };
259
260 class nsGetServiceByContractIDWithError final
261 {
262 public:
nsGetServiceByContractIDWithError(const char * aContractID,nsresult * aErrorPtr)263 nsGetServiceByContractIDWithError(const char* aContractID, nsresult* aErrorPtr)
264 : mContractID(aContractID)
265 , mErrorPtr(aErrorPtr)
266 {
267 }
268
269 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
270
271 private:
272 const char* mContractID;
273 nsresult* mErrorPtr;
274 };
275
276 /**
277 * Factors implementation for all template versions of nsCOMPtr.
278 *
279 * Here's the way people normally do things like this:
280 *
281 * template<class T> class Foo { ... };
282 * template<> class Foo<void*> { ... };
283 * template<class T> class Foo<T*> : private Foo<void*> { ... };
284 */
285 class nsCOMPtr_base
286 {
287 public:
mRawPtr(aRawPtr)288 explicit nsCOMPtr_base(nsISupports* aRawPtr = nullptr) : mRawPtr(aRawPtr) {}
289
~nsCOMPtr_base()290 NS_CONSTRUCTOR_FASTCALL ~nsCOMPtr_base()
291 {
292 NSCAP_LOG_RELEASE(this, mRawPtr);
293 if (mRawPtr) {
294 NSCAP_RELEASE(this, mRawPtr);
295 }
296 }
297
298 void NS_FASTCALL
299 assign_with_AddRef(nsISupports*);
300 void NS_FASTCALL
301 assign_from_qi(const nsQueryInterface, const nsIID&);
302 void NS_FASTCALL
303 assign_from_qi_with_error(const nsQueryInterfaceWithError&, const nsIID&);
304 void NS_FASTCALL
305 assign_from_gs_cid(const nsGetServiceByCID, const nsIID&);
306 void NS_FASTCALL
307 assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError&, const nsIID&);
308 void NS_FASTCALL
309 assign_from_gs_contractid(const nsGetServiceByContractID, const nsIID&);
310 void NS_FASTCALL
311 assign_from_gs_contractid_with_error(const nsGetServiceByContractIDWithError&,
312 const nsIID&);
313 void NS_FASTCALL
314 assign_from_helper(const nsCOMPtr_helper&, const nsIID&);
315 void** NS_FASTCALL
316 begin_assignment();
317
318 protected:
NS_MAY_ALIAS_PTR(nsISupports)319 NS_MAY_ALIAS_PTR(nsISupports) MOZ_OWNING_REF mRawPtr;
320
321 void assign_assuming_AddRef(nsISupports* aNewPtr)
322 {
323 // |AddRef()|ing the new value (before entering this function) before
324 // |Release()|ing the old lets us safely ignore the self-assignment case.
325 // We must, however, be careful only to |Release()| _after_ doing the
326 // assignment, in case the |Release()| leads to our _own_ destruction,
327 // which would, in turn, cause an incorrect second |Release()| of our old
328 // pointer. Thank <waterson@netscape.com> for discovering this.
329 nsISupports* oldPtr = mRawPtr;
330 mRawPtr = aNewPtr;
331 NSCAP_LOG_ASSIGNMENT(this, aNewPtr);
332 NSCAP_LOG_RELEASE(this, oldPtr);
333 if (oldPtr) {
334 NSCAP_RELEASE(this, oldPtr);
335 }
336 }
337 };
338
339 // template<class T> class nsGetterAddRefs;
340
341 // Helper for assert_validity method
342 template<class T>
343 char (&TestForIID(decltype(&NS_GET_TEMPLATE_IID(T))))[2];
344 template<class T>
345 char TestForIID(...);
346
347 template<class T>
348 class nsCOMPtr final
349 #ifdef NSCAP_FEATURE_USE_BASE
350 : private nsCOMPtr_base
351 #endif
352 {
353
354 #ifdef NSCAP_FEATURE_USE_BASE
355 #define NSCAP_CTOR_BASE(x) nsCOMPtr_base(x)
356 #else
357 #define NSCAP_CTOR_BASE(x) mRawPtr(x)
358
359 private:
360 void assign_with_AddRef(nsISupports*);
361 void assign_from_qi(const nsQueryInterface, const nsIID&);
362 void assign_from_qi_with_error(const nsQueryInterfaceWithError&, const nsIID&);
363 void assign_from_gs_cid(const nsGetServiceByCID, const nsIID&);
364 void assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError&,
365 const nsIID&);
366 void assign_from_gs_contractid(const nsGetServiceByContractID, const nsIID&);
367 void assign_from_gs_contractid_with_error(
368 const nsGetServiceByContractIDWithError&, const nsIID&);
369 void assign_from_helper(const nsCOMPtr_helper&, const nsIID&);
370 void** begin_assignment();
371
372 void assign_assuming_AddRef(T* aNewPtr)
373 {
374 T* oldPtr = mRawPtr;
375 mRawPtr = aNewPtr;
376 NSCAP_LOG_ASSIGNMENT(this, aNewPtr);
377 NSCAP_LOG_RELEASE(this, oldPtr);
378 if (oldPtr) {
379 NSCAP_RELEASE(this, oldPtr);
380 }
381 }
382
383 private:
384 T* MOZ_OWNING_REF mRawPtr;
385 #endif
386
assert_validity()387 void assert_validity()
388 {
389 static_assert(1 < sizeof(TestForIID<T>(nullptr)), "nsCOMPtr only works "
390 "for types with IIDs. Either use RefPtr; add an IID to "
391 "your type with NS_DECLARE_STATIC_IID_ACCESSOR/"
392 "NS_DEFINE_STATIC_IID_ACCESSOR; or make the nsCOMPtr point "
393 "to a base class with an IID.");
394 }
395
396 public:
397 typedef T element_type;
398
399 #ifndef NSCAP_FEATURE_USE_BASE
~nsCOMPtr()400 ~nsCOMPtr()
401 {
402 NSCAP_LOG_RELEASE(this, mRawPtr);
403 if (mRawPtr) {
404 NSCAP_RELEASE(this, mRawPtr);
405 }
406 }
407 #endif
408
409 #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
Assert_NoQueryNeeded()410 void Assert_NoQueryNeeded()
411 {
412 if (mRawPtr) {
413 nsCOMPtr<T> query_result(do_QueryInterface(mRawPtr));
414 NS_ASSERTION(query_result.get() == mRawPtr, "QueryInterface needed");
415 }
416 }
417
418 #define NSCAP_ASSERT_NO_QUERY_NEEDED() Assert_NoQueryNeeded();
419 #else
420 #define NSCAP_ASSERT_NO_QUERY_NEEDED()
421 #endif
422
423
424 // Constructors
425
nsCOMPtr()426 nsCOMPtr()
427 : NSCAP_CTOR_BASE(nullptr)
428 {
429 assert_validity();
430 NSCAP_LOG_ASSIGNMENT(this, nullptr);
431 }
432
nsCOMPtr(decltype (nullptr))433 MOZ_IMPLICIT nsCOMPtr(decltype(nullptr))
434 : NSCAP_CTOR_BASE(nullptr)
435 {
436 assert_validity();
437 NSCAP_LOG_ASSIGNMENT(this, nullptr);
438 }
439
nsCOMPtr(const nsCOMPtr<T> & aSmartPtr)440 nsCOMPtr(const nsCOMPtr<T>& aSmartPtr)
441 : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr)
442 {
443 assert_validity();
444 if (mRawPtr) {
445 NSCAP_ADDREF(this, mRawPtr);
446 }
447 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr);
448 }
449
nsCOMPtr(nsCOMPtr<T> && aSmartPtr)450 nsCOMPtr(nsCOMPtr<T>&& aSmartPtr)
451 : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr)
452 {
453 assert_validity();
454 aSmartPtr.mRawPtr = nullptr;
455 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
456 NSCAP_ASSERT_NO_QUERY_NEEDED();
457 }
458
nsCOMPtr(T * aRawPtr)459 MOZ_IMPLICIT nsCOMPtr(T* aRawPtr)
460 : NSCAP_CTOR_BASE(aRawPtr)
461 {
462 assert_validity();
463 if (mRawPtr) {
464 NSCAP_ADDREF(this, mRawPtr);
465 }
466 NSCAP_LOG_ASSIGNMENT(this, aRawPtr);
467 NSCAP_ASSERT_NO_QUERY_NEEDED();
468 }
469
nsCOMPtr(already_AddRefed<T> & aSmartPtr)470 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T>& aSmartPtr)
471 : NSCAP_CTOR_BASE(aSmartPtr.take())
472 {
473 assert_validity();
474 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
475 NSCAP_ASSERT_NO_QUERY_NEEDED();
476 }
477
478 // Construct from |otherComPtr.forget()|.
nsCOMPtr(already_AddRefed<T> && aSmartPtr)479 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T>&& aSmartPtr)
480 : NSCAP_CTOR_BASE(aSmartPtr.take())
481 {
482 assert_validity();
483 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
484 NSCAP_ASSERT_NO_QUERY_NEEDED();
485 }
486
487 // Construct from |already_AddRefed|.
488 template<typename U>
nsCOMPtr(already_AddRefed<U> & aSmartPtr)489 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<U>& aSmartPtr)
490 : NSCAP_CTOR_BASE(static_cast<T*>(aSmartPtr.take()))
491 {
492 assert_validity();
493 // But make sure that U actually inherits from T.
494 static_assert(mozilla::IsBaseOf<T, U>::value,
495 "U is not a subclass of T");
496 NSCAP_LOG_ASSIGNMENT(this, static_cast<T*>(mRawPtr));
497 NSCAP_ASSERT_NO_QUERY_NEEDED();
498 }
499
500 // Construct from |otherComPtr.forget()|.
501 template<typename U>
nsCOMPtr(already_AddRefed<U> && aSmartPtr)502 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<U>&& aSmartPtr)
503 : NSCAP_CTOR_BASE(static_cast<T*>(aSmartPtr.take()))
504 {
505 assert_validity();
506 // But make sure that U actually inherits from T.
507 static_assert(mozilla::IsBaseOf<T, U>::value,
508 "U is not a subclass of T");
509 NSCAP_LOG_ASSIGNMENT(this, static_cast<T*>(mRawPtr));
510 NSCAP_ASSERT_NO_QUERY_NEEDED();
511 }
512
513 // Construct from |do_QueryInterface(expr)|.
nsCOMPtr(const nsQueryInterface aQI)514 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterface aQI)
515 : NSCAP_CTOR_BASE(nullptr)
516 {
517 assert_validity();
518 NSCAP_LOG_ASSIGNMENT(this, nullptr);
519 assign_from_qi(aQI, NS_GET_TEMPLATE_IID(T));
520 }
521
522 // Construct from |do_QueryInterface(expr, &rv)|.
nsCOMPtr(const nsQueryInterfaceWithError & aQI)523 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceWithError& aQI)
524 : NSCAP_CTOR_BASE(nullptr)
525 {
526 assert_validity();
527 NSCAP_LOG_ASSIGNMENT(this, nullptr);
528 assign_from_qi_with_error(aQI, NS_GET_TEMPLATE_IID(T));
529 }
530
531 // Construct from |do_GetService(cid_expr)|.
nsCOMPtr(const nsGetServiceByCID aGS)532 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCID aGS)
533 : NSCAP_CTOR_BASE(nullptr)
534 {
535 assert_validity();
536 NSCAP_LOG_ASSIGNMENT(this, nullptr);
537 assign_from_gs_cid(aGS, NS_GET_TEMPLATE_IID(T));
538 }
539
540 // Construct from |do_GetService(cid_expr, &rv)|.
nsCOMPtr(const nsGetServiceByCIDWithError & aGS)541 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCIDWithError& aGS)
542 : NSCAP_CTOR_BASE(nullptr)
543 {
544 assert_validity();
545 NSCAP_LOG_ASSIGNMENT(this, nullptr);
546 assign_from_gs_cid_with_error(aGS, NS_GET_TEMPLATE_IID(T));
547 }
548
549 // Construct from |do_GetService(contractid_expr)|.
nsCOMPtr(const nsGetServiceByContractID aGS)550 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractID aGS)
551 : NSCAP_CTOR_BASE(nullptr)
552 {
553 assert_validity();
554 NSCAP_LOG_ASSIGNMENT(this, nullptr);
555 assign_from_gs_contractid(aGS, NS_GET_TEMPLATE_IID(T));
556 }
557
558 // Construct from |do_GetService(contractid_expr, &rv)|.
nsCOMPtr(const nsGetServiceByContractIDWithError & aGS)559 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
560 : NSCAP_CTOR_BASE(nullptr)
561 {
562 assert_validity();
563 NSCAP_LOG_ASSIGNMENT(this, nullptr);
564 assign_from_gs_contractid_with_error(aGS, NS_GET_TEMPLATE_IID(T));
565 }
566
567 // And finally, anything else we might need to construct from can exploit the
568 // nsCOMPtr_helper facility.
nsCOMPtr(const nsCOMPtr_helper & aHelper)569 MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper)
570 : NSCAP_CTOR_BASE(nullptr)
571 {
572 assert_validity();
573 NSCAP_LOG_ASSIGNMENT(this, nullptr);
574 assign_from_helper(aHelper, NS_GET_TEMPLATE_IID(T));
575 NSCAP_ASSERT_NO_QUERY_NEEDED();
576 }
577
578 // Defined in OwningNonNull.h
579 template<class U>
580 MOZ_IMPLICIT nsCOMPtr(const mozilla::OwningNonNull<U>& aOther);
581
582
583 // Assignment operators
584
585 nsCOMPtr<T>& operator=(const nsCOMPtr<T>& aRhs)
586 {
587 assign_with_AddRef(aRhs.mRawPtr);
588 return *this;
589 }
590
591 nsCOMPtr<T>& operator=(T* aRhs)
592 {
593 assign_with_AddRef(aRhs);
594 NSCAP_ASSERT_NO_QUERY_NEEDED();
595 return *this;
596 }
597
decltype(nullptr)598 nsCOMPtr<T>& operator=(decltype(nullptr))
599 {
600 assign_assuming_AddRef(nullptr);
601 return *this;
602 }
603
604 // Assign from |already_AddRefed|.
605 template<typename U>
606 nsCOMPtr<T>& operator=(already_AddRefed<U>& aRhs)
607 {
608 // Make sure that U actually inherits from T
609 static_assert(mozilla::IsBaseOf<T, U>::value,
610 "U is not a subclass of T");
611 assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
612 NSCAP_ASSERT_NO_QUERY_NEEDED();
613 return *this;
614 }
615
616 // Assign from |otherComPtr.forget()|.
617 template<typename U>
618 nsCOMPtr<T>& operator=(already_AddRefed<U>&& aRhs)
619 {
620 // Make sure that U actually inherits from T
621 static_assert(mozilla::IsBaseOf<T, U>::value,
622 "U is not a subclass of T");
623 assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
624 NSCAP_ASSERT_NO_QUERY_NEEDED();
625 return *this;
626 }
627
628 // Assign from |do_QueryInterface(expr)|.
629 nsCOMPtr<T>& operator=(const nsQueryInterface aRhs)
630 {
631 assign_from_qi(aRhs, NS_GET_TEMPLATE_IID(T));
632 return *this;
633 }
634
635 // Assign from |do_QueryInterface(expr, &rv)|.
636 nsCOMPtr<T>& operator=(const nsQueryInterfaceWithError& aRhs)
637 {
638 assign_from_qi_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
639 return *this;
640 }
641
642 // Assign from |do_GetService(cid_expr)|.
643 nsCOMPtr<T>& operator=(const nsGetServiceByCID aRhs)
644 {
645 assign_from_gs_cid(aRhs, NS_GET_TEMPLATE_IID(T));
646 return *this;
647 }
648
649 // Assign from |do_GetService(cid_expr, &rv)|.
650 nsCOMPtr<T>& operator=(const nsGetServiceByCIDWithError& aRhs)
651 {
652 assign_from_gs_cid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
653 return *this;
654 }
655
656 // Assign from |do_GetService(contractid_expr)|.
657 nsCOMPtr<T>& operator=(const nsGetServiceByContractID aRhs)
658 {
659 assign_from_gs_contractid(aRhs, NS_GET_TEMPLATE_IID(T));
660 return *this;
661 }
662
663 // Assign from |do_GetService(contractid_expr, &rv)|.
664 nsCOMPtr<T>& operator=(const nsGetServiceByContractIDWithError& aRhs)
665 {
666 assign_from_gs_contractid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
667 return *this;
668 }
669
670 // And finally, anything else we might need to assign from can exploit the
671 // nsCOMPtr_helper facility.
672 nsCOMPtr<T>& operator=(const nsCOMPtr_helper& aRhs)
673 {
674 assign_from_helper(aRhs, NS_GET_TEMPLATE_IID(T));
675 NSCAP_ASSERT_NO_QUERY_NEEDED();
676 return *this;
677 }
678
679 // Defined in OwningNonNull.h
680 template<class U>
681 nsCOMPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
682
683 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
swap(nsCOMPtr<T> & aRhs)684 void swap(nsCOMPtr<T>& aRhs)
685 {
686 #ifdef NSCAP_FEATURE_USE_BASE
687 nsISupports* temp = aRhs.mRawPtr;
688 #else
689 T* temp = aRhs.mRawPtr;
690 #endif
691 NSCAP_LOG_ASSIGNMENT(&aRhs, mRawPtr);
692 NSCAP_LOG_ASSIGNMENT(this, temp);
693 NSCAP_LOG_RELEASE(this, mRawPtr);
694 NSCAP_LOG_RELEASE(&aRhs, temp);
695 aRhs.mRawPtr = mRawPtr;
696 mRawPtr = temp;
697 // |aRhs| maintains the same invariants, so we don't need to |NSCAP_ASSERT_NO_QUERY_NEEDED|
698 }
699
700 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
swap(T * & aRhs)701 void swap(T*& aRhs)
702 {
703 #ifdef NSCAP_FEATURE_USE_BASE
704 nsISupports* temp = aRhs;
705 #else
706 T* temp = aRhs;
707 #endif
708 NSCAP_LOG_ASSIGNMENT(this, temp);
709 NSCAP_LOG_RELEASE(this, mRawPtr);
710 aRhs = reinterpret_cast<T*>(mRawPtr);
711 mRawPtr = temp;
712 NSCAP_ASSERT_NO_QUERY_NEEDED();
713 }
714
715
716 // Other pointer operators
717
718 // Return the value of mRawPtr and null out mRawPtr. Useful for
719 // already_AddRefed return values.
forget()720 already_AddRefed<T> forget()
721 {
722 T* temp = nullptr;
723 swap(temp);
724 return already_AddRefed<T>(temp);
725 }
726
727 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
728 // Useful to avoid unnecessary AddRef/Release pairs with "out" parameters
729 // where aRhs bay be a T** or an I** where I is a base class of T.
730 template<typename I>
forget(I ** aRhs)731 void forget(I** aRhs)
732 {
733 NS_ASSERTION(aRhs, "Null pointer passed to forget!");
734 NSCAP_LOG_RELEASE(this, mRawPtr);
735 *aRhs = get();
736 mRawPtr = nullptr;
737 }
738
739 // Prefer the implicit conversion provided automatically by
740 // |operator T*() const|. Use |get()| to resolve ambiguity or to get a
741 // castable pointer.
get()742 T* get() const { return reinterpret_cast<T*>(mRawPtr); }
743
744 // Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
745 // used in a context where a raw pointer is expected. It is this operator
746 // that makes an nsCOMPtr substitutable for a raw pointer.
747 //
748 // Prefer the implicit use of this operator to calling |get()|, except where
749 // necessary to resolve ambiguity.
750 operator T*() const
751 #ifdef MOZ_HAVE_REF_QUALIFIERS
752 &
753 #endif
754 { return get(); }
755
756 #ifdef MOZ_HAVE_REF_QUALIFIERS
757 // Don't allow implicit conversion of temporary nsCOMPtr to raw pointer,
758 // because the refcount might be one and the pointer will immediately become
759 // invalid.
760 operator T*() const && = delete;
761
762 // Needed to avoid the deleted operator above
763 explicit operator bool() const { return !!mRawPtr; }
764 #endif
765
766 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
767 {
768 MOZ_ASSERT(mRawPtr != nullptr,
769 "You can't dereference a NULL nsCOMPtr with operator->().");
770 return get();
771 }
772
773 // These are not intended to be used by clients. See |address_of| below.
get_address()774 nsCOMPtr<T>* get_address() { return this; }
get_address()775 const nsCOMPtr<T>* get_address() const { return this; }
776
777 public:
778 T& operator*() const
779 {
780 MOZ_ASSERT(mRawPtr != nullptr,
781 "You can't dereference a NULL nsCOMPtr with operator*().");
782 return *get();
783 }
784
StartAssignment()785 T** StartAssignment()
786 {
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
793 }
794 };
795
796
797 /*
798 * Specializing nsCOMPtr for nsISupports allows us to use nsCOMPtr<nsISupports>
799 * the same way people use nsISupports* and void*, i.e., as a `catch-all'
800 * pointing to any valid [XP]COM interface. Otherwise, an nsCOMPtr<nsISupports>
801 * would only be able to point to the single [XP]COM-correct nsISupports
802 * instance within an object; extra querying ensues. Clients need to be able to
803 * pass around arbitrary interface pointers, without hassles, through
804 * intermediary code that doesn't know the exact type.
805 */
806 template<>
807 class nsCOMPtr<nsISupports>
808 : private nsCOMPtr_base
809 {
810 public:
811 typedef nsISupports element_type;
812
813 // Constructors
814
nsCOMPtr()815 nsCOMPtr()
816 : nsCOMPtr_base(nullptr)
817 {
818 NSCAP_LOG_ASSIGNMENT(this, nullptr);
819 }
820
nsCOMPtr(decltype (nullptr))821 MOZ_IMPLICIT nsCOMPtr(decltype(nullptr))
822 : nsCOMPtr_base(nullptr)
823 {
824 NSCAP_LOG_ASSIGNMENT(this, nullptr);
825 }
826
nsCOMPtr(const nsCOMPtr<nsISupports> & aSmartPtr)827 nsCOMPtr(const nsCOMPtr<nsISupports>& aSmartPtr)
828 : nsCOMPtr_base(aSmartPtr.mRawPtr)
829 {
830 if (mRawPtr) {
831 NSCAP_ADDREF(this, mRawPtr);
832 }
833 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr);
834 }
835
nsCOMPtr(nsISupports * aRawPtr)836 MOZ_IMPLICIT nsCOMPtr(nsISupports* aRawPtr)
837 : nsCOMPtr_base(aRawPtr)
838 {
839 if (mRawPtr) {
840 NSCAP_ADDREF(this, mRawPtr);
841 }
842 NSCAP_LOG_ASSIGNMENT(this, aRawPtr);
843 }
844
845 // Construct from |already_AddRefed|.
nsCOMPtr(already_AddRefed<nsISupports> & aSmartPtr)846 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<nsISupports>& aSmartPtr)
847 : nsCOMPtr_base(aSmartPtr.take())
848 {
849 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
850 }
851
852 // Construct from |otherComPtr.forget()|.
nsCOMPtr(already_AddRefed<nsISupports> && aSmartPtr)853 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<nsISupports>&& aSmartPtr)
854 : nsCOMPtr_base(aSmartPtr.take())
855 {
856 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
857 }
858
859 // Construct from |do_QueryInterface(expr)|.
nsCOMPtr(const nsQueryInterface aQI)860 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterface aQI)
861 : nsCOMPtr_base(nullptr)
862 {
863 NSCAP_LOG_ASSIGNMENT(this, nullptr);
864 assign_from_qi(aQI, NS_GET_IID(nsISupports));
865 }
866
867 // Construct from |do_QueryInterface(expr, &rv)|.
nsCOMPtr(const nsQueryInterfaceWithError & aQI)868 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceWithError& aQI)
869 : nsCOMPtr_base(nullptr)
870 {
871 NSCAP_LOG_ASSIGNMENT(this, nullptr);
872 assign_from_qi_with_error(aQI, NS_GET_IID(nsISupports));
873 }
874
875 // Construct from |do_GetService(cid_expr)|.
nsCOMPtr(const nsGetServiceByCID aGS)876 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCID aGS)
877 : nsCOMPtr_base(nullptr)
878 {
879 NSCAP_LOG_ASSIGNMENT(this, nullptr);
880 assign_from_gs_cid(aGS, NS_GET_IID(nsISupports));
881 }
882
883 // Construct from |do_GetService(cid_expr, &rv)|.
nsCOMPtr(const nsGetServiceByCIDWithError & aGS)884 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCIDWithError& aGS)
885 : nsCOMPtr_base(nullptr)
886 {
887 NSCAP_LOG_ASSIGNMENT(this, nullptr);
888 assign_from_gs_cid_with_error(aGS, NS_GET_IID(nsISupports));
889 }
890
891 // Construct from |do_GetService(contractid_expr)|.
nsCOMPtr(const nsGetServiceByContractID aGS)892 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractID aGS)
893 : nsCOMPtr_base(nullptr)
894 {
895 NSCAP_LOG_ASSIGNMENT(this, nullptr);
896 assign_from_gs_contractid(aGS, NS_GET_IID(nsISupports));
897 }
898
899 // Construct from |do_GetService(contractid_expr, &rv)|.
nsCOMPtr(const nsGetServiceByContractIDWithError & aGS)900 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
901 : nsCOMPtr_base(nullptr)
902 {
903 NSCAP_LOG_ASSIGNMENT(this, nullptr);
904 assign_from_gs_contractid_with_error(aGS, NS_GET_IID(nsISupports));
905 }
906
907 // And finally, anything else we might need to construct from can exploit
908 // the |nsCOMPtr_helper| facility
nsCOMPtr(const nsCOMPtr_helper & aHelper)909 MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper)
910 : nsCOMPtr_base(nullptr)
911 {
912 NSCAP_LOG_ASSIGNMENT(this, nullptr);
913 assign_from_helper(aHelper, NS_GET_IID(nsISupports));
914 }
915
916
917 // Assignment operators
918
919 nsCOMPtr<nsISupports>& operator=(const nsCOMPtr<nsISupports>& aRhs)
920 {
921 assign_with_AddRef(aRhs.mRawPtr);
922 return *this;
923 }
924
925 nsCOMPtr<nsISupports>& operator=(nsISupports* aRhs)
926 {
927 assign_with_AddRef(aRhs);
928 return *this;
929 }
930
decltype(nullptr)931 nsCOMPtr<nsISupports>& operator=(decltype(nullptr))
932 {
933 assign_assuming_AddRef(nullptr);
934 return *this;
935 }
936
937 // Assign from |already_AddRefed|.
938 nsCOMPtr<nsISupports>& operator=(already_AddRefed<nsISupports>& aRhs)
939 {
940 assign_assuming_AddRef(aRhs.take());
941 return *this;
942 }
943
944 // Assign from |otherComPtr.forget()|.
945 nsCOMPtr<nsISupports>& operator=(already_AddRefed<nsISupports>&& aRhs)
946 {
947 assign_assuming_AddRef(aRhs.take());
948 return *this;
949 }
950
951 // Assign from |do_QueryInterface(expr)|.
952 nsCOMPtr<nsISupports>& operator=(const nsQueryInterface aRhs)
953 {
954 assign_from_qi(aRhs, NS_GET_IID(nsISupports));
955 return *this;
956 }
957
958 // Assign from |do_QueryInterface(expr, &rv)|.
959 nsCOMPtr<nsISupports>& operator=(const nsQueryInterfaceWithError& aRhs)
960 {
961 assign_from_qi_with_error(aRhs, NS_GET_IID(nsISupports));
962 return *this;
963 }
964
965 // Assign from |do_GetService(cid_expr)|.
966 nsCOMPtr<nsISupports>& operator=(const nsGetServiceByCID aRhs)
967 {
968 assign_from_gs_cid(aRhs, NS_GET_IID(nsISupports));
969 return *this;
970 }
971
972 // Assign from |do_GetService(cid_expr, &rv)|.
973 nsCOMPtr<nsISupports>& operator=(const nsGetServiceByCIDWithError& aRhs)
974 {
975 assign_from_gs_cid_with_error(aRhs, NS_GET_IID(nsISupports));
976 return *this;
977 }
978
979 // Assign from |do_GetService(contractid_expr)|.
980 nsCOMPtr<nsISupports>& operator=(const nsGetServiceByContractID aRhs)
981 {
982 assign_from_gs_contractid(aRhs, NS_GET_IID(nsISupports));
983 return *this;
984 }
985
986 // Assign from |do_GetService(contractid_expr, &rv)|.
987 nsCOMPtr<nsISupports>& operator=(const nsGetServiceByContractIDWithError& aRhs)
988 {
989 assign_from_gs_contractid_with_error(aRhs, NS_GET_IID(nsISupports));
990 return *this;
991 }
992
993 // And finally, anything else we might need to assign from can exploit the
994 // nsCOMPtr_helper facility
995 nsCOMPtr<nsISupports>& operator=(const nsCOMPtr_helper& aRhs)
996 {
997 assign_from_helper(aRhs, NS_GET_IID(nsISupports));
998 return *this;
999 }
1000
1001 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
swap(nsCOMPtr<nsISupports> & aRhs)1002 void swap(nsCOMPtr<nsISupports>& aRhs)
1003 {
1004 nsISupports* temp = aRhs.mRawPtr;
1005 NSCAP_LOG_ASSIGNMENT(&aRhs, mRawPtr);
1006 NSCAP_LOG_ASSIGNMENT(this, temp);
1007 NSCAP_LOG_RELEASE(this, mRawPtr);
1008 NSCAP_LOG_RELEASE(&aRhs, temp);
1009 aRhs.mRawPtr = mRawPtr;
1010 mRawPtr = temp;
1011 }
1012
1013 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
swap(nsISupports * & aRhs)1014 void swap(nsISupports*& aRhs)
1015 {
1016 nsISupports* temp = aRhs;
1017 NSCAP_LOG_ASSIGNMENT(this, temp);
1018 NSCAP_LOG_RELEASE(this, mRawPtr);
1019 aRhs = mRawPtr;
1020 mRawPtr = temp;
1021 }
1022
1023 // Return the value of mRawPtr and null out mRawPtr. Useful for
1024 // already_AddRefed return values.
forget()1025 already_AddRefed<nsISupports> forget()
1026 {
1027 nsISupports* temp = nullptr;
1028 swap(temp);
1029 return already_AddRefed<nsISupports>(temp);
1030 }
1031
1032 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
1033 // Useful to avoid unnecessary AddRef/Release pairs with "out"
1034 // parameters.
forget(nsISupports ** aRhs)1035 void forget(nsISupports** aRhs)
1036 {
1037 NS_ASSERTION(aRhs, "Null pointer passed to forget!");
1038 *aRhs = nullptr;
1039 swap(*aRhs);
1040 }
1041
1042 // Other pointer operators
1043
1044 // Prefer the implicit conversion provided automatically by
1045 // |operator nsISupports*() const|. Use |get()| to resolve ambiguity or to
1046 // get a castable pointer.
get()1047 nsISupports* get() const { return reinterpret_cast<nsISupports*>(mRawPtr); }
1048
1049 // Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
1050 // used in a context where a raw pointer is expected. It is this operator
1051 // that makes an nsCOMPtr substitutable for a raw pointer.
1052 //
1053 // Prefer the implicit use of this operator to calling |get()|, except where
1054 // necessary to resolve ambiguity/
1055 operator nsISupports* () const { return get(); }
1056
1057 nsISupports* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
1058 {
1059 MOZ_ASSERT(mRawPtr != nullptr,
1060 "You can't dereference a NULL nsCOMPtr with operator->().");
1061 return get();
1062 }
1063
1064 // These are not intended to be used by clients. See |address_of| below.
get_address()1065 nsCOMPtr<nsISupports>* get_address() { return this; }
get_address()1066 const nsCOMPtr<nsISupports>* get_address() const { return this; }
1067
1068 public:
1069
1070 nsISupports& operator*() const
1071 {
1072 MOZ_ASSERT(mRawPtr != nullptr,
1073 "You can't dereference a NULL nsCOMPtr with operator*().");
1074 return *get();
1075 }
1076
StartAssignment()1077 nsISupports** StartAssignment()
1078 {
1079 #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
1080 return reinterpret_cast<nsISupports**>(begin_assignment());
1081 #else
1082 assign_assuming_AddRef(nullptr);
1083 return reinterpret_cast<nsISupports**>(&mRawPtr);
1084 #endif
1085 }
1086 };
1087
1088 template<typename T>
1089 inline void
ImplCycleCollectionUnlink(nsCOMPtr<T> & aField)1090 ImplCycleCollectionUnlink(nsCOMPtr<T>& aField)
1091 {
1092 aField = nullptr;
1093 }
1094
1095 template<typename T>
1096 inline void
1097 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
1098 nsCOMPtr<T>& aField,
1099 const char* aName,
1100 uint32_t aFlags = 0)
1101 {
1102 CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
1103 }
1104
1105 #ifndef NSCAP_FEATURE_USE_BASE
1106 template<class T>
1107 void
assign_with_AddRef(nsISupports * aRawPtr)1108 nsCOMPtr<T>::assign_with_AddRef(nsISupports* aRawPtr)
1109 {
1110 if (aRawPtr) {
1111 NSCAP_ADDREF(this, aRawPtr);
1112 }
1113 assign_assuming_AddRef(reinterpret_cast<T*>(aRawPtr));
1114 }
1115
1116 template<class T>
1117 void
assign_from_qi(const nsQueryInterface aQI,const nsIID & aIID)1118 nsCOMPtr<T>::assign_from_qi(const nsQueryInterface aQI, const nsIID& aIID)
1119 {
1120 void* newRawPtr;
1121 if (NS_FAILED(aQI(aIID, &newRawPtr))) {
1122 newRawPtr = nullptr;
1123 }
1124 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1125 }
1126
1127 template<class T>
1128 void
assign_from_qi_with_error(const nsQueryInterfaceWithError & aQI,const nsIID & aIID)1129 nsCOMPtr<T>::assign_from_qi_with_error(const nsQueryInterfaceWithError& aQI,
1130 const nsIID& aIID)
1131 {
1132 void* newRawPtr;
1133 if (NS_FAILED(aQI(aIID, &newRawPtr))) {
1134 newRawPtr = nullptr;
1135 }
1136 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1137 }
1138
1139 template<class T>
1140 void
assign_from_gs_cid(const nsGetServiceByCID aGS,const nsIID & aIID)1141 nsCOMPtr<T>::assign_from_gs_cid(const nsGetServiceByCID aGS, const nsIID& aIID)
1142 {
1143 void* newRawPtr;
1144 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1145 newRawPtr = nullptr;
1146 }
1147 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1148 }
1149
1150 template<class T>
1151 void
assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError & aGS,const nsIID & aIID)1152 nsCOMPtr<T>::assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError& aGS,
1153 const nsIID& aIID)
1154 {
1155 void* newRawPtr;
1156 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1157 newRawPtr = nullptr;
1158 }
1159 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1160 }
1161
1162 template<class T>
1163 void
assign_from_gs_contractid(const nsGetServiceByContractID aGS,const nsIID & aIID)1164 nsCOMPtr<T>::assign_from_gs_contractid(const nsGetServiceByContractID aGS,
1165 const nsIID& aIID)
1166 {
1167 void* newRawPtr;
1168 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1169 newRawPtr = nullptr;
1170 }
1171 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1172 }
1173
1174 template<class T>
1175 void
assign_from_gs_contractid_with_error(const nsGetServiceByContractIDWithError & aGS,const nsIID & aIID)1176 nsCOMPtr<T>::assign_from_gs_contractid_with_error(
1177 const nsGetServiceByContractIDWithError& aGS, const nsIID& aIID)
1178 {
1179 void* newRawPtr;
1180 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1181 newRawPtr = nullptr;
1182 }
1183 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1184 }
1185
1186 template<class T>
1187 void
assign_from_helper(const nsCOMPtr_helper & helper,const nsIID & aIID)1188 nsCOMPtr<T>::assign_from_helper(const nsCOMPtr_helper& helper, const nsIID& aIID)
1189 {
1190 void* newRawPtr;
1191 if (NS_FAILED(helper(aIID, &newRawPtr))) {
1192 newRawPtr = nullptr;
1193 }
1194 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1195 }
1196
1197 template<class T>
1198 void**
begin_assignment()1199 nsCOMPtr<T>::begin_assignment()
1200 {
1201 assign_assuming_AddRef(nullptr);
1202 union
1203 {
1204 T** mT;
1205 void** mVoid;
1206 } result;
1207 result.mT = &mRawPtr;
1208 return result.mVoid;
1209 }
1210 #endif
1211
1212 template<class T>
1213 inline nsCOMPtr<T>*
address_of(nsCOMPtr<T> & aPtr)1214 address_of(nsCOMPtr<T>& aPtr)
1215 {
1216 return aPtr.get_address();
1217 }
1218
1219 template<class T>
1220 inline const nsCOMPtr<T>*
address_of(const nsCOMPtr<T> & aPtr)1221 address_of(const nsCOMPtr<T>& aPtr)
1222 {
1223 return aPtr.get_address();
1224 }
1225
1226 /**
1227 * This class is designed to be used for anonymous temporary objects in the
1228 * argument list of calls that return COM interface pointers, e.g.,
1229 *
1230 * nsCOMPtr<IFoo> fooP;
1231 * ...->QueryInterface(iid, getter_AddRefs(fooP))
1232 *
1233 * DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
1234 *
1235 * When initialized with a |nsCOMPtr|, as in the example above, it returns
1236 * a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call
1237 * (|QueryInterface| in this case) can fill in.
1238 *
1239 * This type should be a nested class inside |nsCOMPtr<T>|.
1240 */
1241 template<class T>
1242 class nsGetterAddRefs
1243 {
1244 public:
nsGetterAddRefs(nsCOMPtr<T> & aSmartPtr)1245 explicit nsGetterAddRefs(nsCOMPtr<T>& aSmartPtr)
1246 : mTargetSmartPtr(aSmartPtr)
1247 {
1248 }
1249
1250 #if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT)
~nsGetterAddRefs()1251 ~nsGetterAddRefs()
1252 {
1253 #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
1254 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),
1255 mTargetSmartPtr.get());
1256 #endif
1257
1258 #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
1259 mTargetSmartPtr.Assert_NoQueryNeeded();
1260 #endif
1261 }
1262 #endif
1263
1264 operator void**()
1265 {
1266 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
1267 }
1268
1269 operator T**() { return mTargetSmartPtr.StartAssignment(); }
1270 T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
1271
1272 private:
1273 nsCOMPtr<T>& mTargetSmartPtr;
1274 };
1275
1276
1277 template<>
1278 class nsGetterAddRefs<nsISupports>
1279 {
1280 public:
nsGetterAddRefs(nsCOMPtr<nsISupports> & aSmartPtr)1281 explicit nsGetterAddRefs(nsCOMPtr<nsISupports>& aSmartPtr)
1282 : mTargetSmartPtr(aSmartPtr)
1283 {
1284 }
1285
1286 #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
~nsGetterAddRefs()1287 ~nsGetterAddRefs()
1288 {
1289 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),
1290 mTargetSmartPtr.get());
1291 }
1292 #endif
1293
1294 operator void**()
1295 {
1296 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
1297 }
1298
1299 operator nsISupports**() { return mTargetSmartPtr.StartAssignment(); }
1300 nsISupports*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
1301
1302 private:
1303 nsCOMPtr<nsISupports>& mTargetSmartPtr;
1304 };
1305
1306 template<class T>
1307 inline nsGetterAddRefs<T>
getter_AddRefs(nsCOMPtr<T> & aSmartPtr)1308 getter_AddRefs(nsCOMPtr<T>& aSmartPtr)
1309 {
1310 return nsGetterAddRefs<T>(aSmartPtr);
1311 }
1312
1313 template<class T, class DestinationType>
1314 inline nsresult
CallQueryInterface(T * aSource,nsGetterAddRefs<DestinationType> aDestination)1315 CallQueryInterface(T* aSource, nsGetterAddRefs<DestinationType> aDestination)
1316 {
1317 return CallQueryInterface(aSource,
1318 static_cast<DestinationType**>(aDestination));
1319 }
1320
1321
1322 // Comparing two |nsCOMPtr|s
1323
1324 template<class T, class U>
1325 inline bool
1326 operator==(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs)
1327 {
1328 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
1329 }
1330
1331
1332 template<class T, class U>
1333 inline bool
1334 operator!=(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs)
1335 {
1336 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
1337 }
1338
1339
1340 // Comparing an |nsCOMPtr| to a raw pointer
1341
1342 template<class T, class U>
1343 inline bool
1344 operator==(const nsCOMPtr<T>& aLhs, const U* aRhs)
1345 {
1346 return static_cast<const T*>(aLhs.get()) == aRhs;
1347 }
1348
1349 template<class T, class U>
1350 inline bool
1351 operator==(const U* aLhs, const nsCOMPtr<T>& aRhs)
1352 {
1353 return aLhs == static_cast<const T*>(aRhs.get());
1354 }
1355
1356 template<class T, class U>
1357 inline bool
1358 operator!=(const nsCOMPtr<T>& aLhs, const U* aRhs)
1359 {
1360 return static_cast<const T*>(aLhs.get()) != aRhs;
1361 }
1362
1363 template<class T, class U>
1364 inline bool
1365 operator!=(const U* aLhs, const nsCOMPtr<T>& aRhs)
1366 {
1367 return aLhs != static_cast<const T*>(aRhs.get());
1368 }
1369
1370 template<class T, class U>
1371 inline bool
1372 operator==(const nsCOMPtr<T>& aLhs, U* aRhs)
1373 {
1374 return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
1375 }
1376
1377 template<class T, class U>
1378 inline bool
1379 operator==(U* aLhs, const nsCOMPtr<T>& aRhs)
1380 {
1381 return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
1382 }
1383
1384 template<class T, class U>
1385 inline bool
1386 operator!=(const nsCOMPtr<T>& aLhs, U* aRhs)
1387 {
1388 return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
1389 }
1390
1391 template<class T, class U>
1392 inline bool
1393 operator!=(U* aLhs, const nsCOMPtr<T>& aRhs)
1394 {
1395 return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
1396 }
1397
1398
1399
1400 // Comparing an |nsCOMPtr| to |nullptr|
1401
1402 template<class T>
1403 inline bool
1404 operator==(const nsCOMPtr<T>& aLhs, decltype(nullptr))
1405 {
1406 return aLhs.get() == nullptr;
1407 }
1408
1409 template<class T>
1410 inline bool
1411 operator==(decltype(nullptr), const nsCOMPtr<T>& aRhs)
1412 {
1413 return nullptr == aRhs.get();
1414 }
1415
1416 template<class T>
1417 inline bool
1418 operator!=(const nsCOMPtr<T>& aLhs, decltype(nullptr))
1419 {
1420 return aLhs.get() != nullptr;
1421 }
1422
1423 template<class T>
1424 inline bool
1425 operator!=(decltype(nullptr), const nsCOMPtr<T>& aRhs)
1426 {
1427 return nullptr != aRhs.get();
1428 }
1429
1430
1431 // Comparing any two [XP]COM objects for identity
1432
1433 inline bool
SameCOMIdentity(nsISupports * aLhs,nsISupports * aRhs)1434 SameCOMIdentity(nsISupports* aLhs, nsISupports* aRhs)
1435 {
1436 return nsCOMPtr<nsISupports>(do_QueryInterface(aLhs)) ==
1437 nsCOMPtr<nsISupports>(do_QueryInterface(aRhs));
1438 }
1439
1440
1441
1442 template<class SourceType, class DestinationType>
1443 inline nsresult
CallQueryInterface(nsCOMPtr<SourceType> & aSourcePtr,DestinationType ** aDestPtr)1444 CallQueryInterface(nsCOMPtr<SourceType>& aSourcePtr, DestinationType** aDestPtr)
1445 {
1446 return CallQueryInterface(aSourcePtr.get(), aDestPtr);
1447 }
1448
1449 template <class T>
RefPtr(const nsCOMPtr_helper & aHelper)1450 RefPtr<T>::RefPtr(const nsCOMPtr_helper& aHelper)
1451 {
1452 void* newRawPtr;
1453 if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1454 newRawPtr = nullptr;
1455 }
1456 mRawPtr = static_cast<T*>(newRawPtr);
1457 }
1458
1459 template <class T>
1460 RefPtr<T>&
1461 RefPtr<T>::operator=(const nsCOMPtr_helper& aHelper)
1462 {
1463 void* newRawPtr;
1464 if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1465 newRawPtr = nullptr;
1466 }
1467 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1468 return *this;
1469 }
1470
1471
1472 #endif // !defined(nsCOMPtr_h___)
1473