Line data Source code
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>
117 : dont_AddRef(T* aRawPtr)
118 : {
119 0 : return already_AddRefed<T>(aRawPtr);
120 : }
121 :
122 : template<class T>
123 : inline already_AddRefed<T>&&
124 : dont_AddRef(already_AddRefed<T>&& aAlreadyAddRefedPtr)
125 : {
126 0 : return std::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
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:
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
187 : do_QueryInterface(nsISupports* aRawPtr)
188 : {
189 0 : return nsQueryInterface(aRawPtr);
190 : }
191 :
192 : inline nsQueryInterfaceWithError
193 : do_QueryInterface(nsISupports* aRawPtr, nsresult* aError)
194 : {
195 0 : return nsQueryInterfaceWithError(aRawPtr, aError);
196 : }
197 :
198 : template<class T>
199 : inline void
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
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:
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:
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:
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:
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 : class nsIWeakReference;
277 :
278 : // Weak references
279 : class MOZ_STACK_CLASS nsQueryReferent final
280 : {
281 : public:
282 : nsQueryReferent(nsIWeakReference* aWeakPtr, nsresult* aError)
283 : : mWeakPtr(aWeakPtr)
284 : , mErrorPtr(aError)
285 : {
286 : }
287 :
288 : nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
289 :
290 : private:
291 : nsIWeakReference* MOZ_NON_OWNING_REF mWeakPtr;
292 : nsresult* mErrorPtr;
293 : };
294 :
295 : /**
296 : * Factors implementation for all template versions of nsCOMPtr.
297 : *
298 : * Here's the way people normally do things like this:
299 : *
300 : * template<class T> class Foo { ... };
301 : * template<> class Foo<void*> { ... };
302 : * template<class T> class Foo<T*> : private Foo<void*> { ... };
303 : */
304 : class nsCOMPtr_base
305 : {
306 : public:
307 0 : explicit nsCOMPtr_base(nsISupports* aRawPtr = nullptr) : mRawPtr(aRawPtr) {}
308 :
309 0 : NS_CONSTRUCTOR_FASTCALL ~nsCOMPtr_base()
310 0 : {
311 0 : NSCAP_LOG_RELEASE(this, mRawPtr);
312 0 : if (mRawPtr) {
313 0 : NSCAP_RELEASE(this, mRawPtr);
314 : }
315 0 : }
316 :
317 : void NS_FASTCALL
318 : assign_with_AddRef(nsISupports*);
319 : void NS_FASTCALL
320 : assign_from_qi(const nsQueryInterface, const nsIID&);
321 : void NS_FASTCALL
322 : assign_from_qi_with_error(const nsQueryInterfaceWithError&, const nsIID&);
323 : void NS_FASTCALL
324 : assign_from_gs_cid(const nsGetServiceByCID, const nsIID&);
325 : void NS_FASTCALL
326 : assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError&, const nsIID&);
327 : void NS_FASTCALL
328 : assign_from_gs_contractid(const nsGetServiceByContractID, const nsIID&);
329 : void NS_FASTCALL
330 : assign_from_gs_contractid_with_error(const nsGetServiceByContractIDWithError&,
331 : const nsIID&);
332 : void NS_FASTCALL
333 : assign_from_query_referent(const nsQueryReferent&, const nsIID&);
334 : void NS_FASTCALL
335 : assign_from_helper(const nsCOMPtr_helper&, const nsIID&);
336 : void** NS_FASTCALL
337 : begin_assignment();
338 :
339 : protected:
340 : NS_MAY_ALIAS_PTR(nsISupports) MOZ_OWNING_REF mRawPtr;
341 :
342 0 : void assign_assuming_AddRef(nsISupports* aNewPtr)
343 : {
344 : // |AddRef()|ing the new value (before entering this function) before
345 : // |Release()|ing the old lets us safely ignore the self-assignment case.
346 : // We must, however, be careful only to |Release()| _after_ doing the
347 : // assignment, in case the |Release()| leads to our _own_ destruction,
348 : // which would, in turn, cause an incorrect second |Release()| of our old
349 : // pointer. Thank <waterson@netscape.com> for discovering this.
350 0 : nsISupports* oldPtr = mRawPtr;
351 0 : mRawPtr = aNewPtr;
352 0 : NSCAP_LOG_ASSIGNMENT(this, aNewPtr);
353 0 : NSCAP_LOG_RELEASE(this, oldPtr);
354 0 : if (oldPtr) {
355 0 : NSCAP_RELEASE(this, oldPtr);
356 : }
357 0 : }
358 : };
359 :
360 : // template<class T> class nsGetterAddRefs;
361 :
362 : // Helper for assert_validity method
363 : template<class T>
364 : char (&TestForIID(decltype(&NS_GET_TEMPLATE_IID(T))))[2];
365 : template<class T>
366 : char TestForIID(...);
367 :
368 : template<class T>
369 : class MOZ_IS_REFPTR nsCOMPtr final
370 : #ifdef NSCAP_FEATURE_USE_BASE
371 : : private nsCOMPtr_base
372 : #endif
373 : {
374 :
375 : #ifdef NSCAP_FEATURE_USE_BASE
376 : #define NSCAP_CTOR_BASE(x) nsCOMPtr_base(x)
377 : #else
378 : #define NSCAP_CTOR_BASE(x) mRawPtr(x)
379 :
380 : private:
381 : void assign_with_AddRef(nsISupports*);
382 : void assign_from_qi(const nsQueryInterface, const nsIID&);
383 : void assign_from_qi_with_error(const nsQueryInterfaceWithError&, const nsIID&);
384 : void assign_from_gs_cid(const nsGetServiceByCID, const nsIID&);
385 : void assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError&,
386 : const nsIID&);
387 : void assign_from_gs_contractid(const nsGetServiceByContractID, const nsIID&);
388 : void assign_from_gs_contractid_with_error(
389 : const nsGetServiceByContractIDWithError&, const nsIID&);
390 : void assign_from_query_referent(const nsQueryReferent&, const nsIID&);
391 : void assign_from_helper(const nsCOMPtr_helper&, const nsIID&);
392 : void** begin_assignment();
393 :
394 0 : void assign_assuming_AddRef(T* aNewPtr)
395 : {
396 0 : T* oldPtr = mRawPtr;
397 0 : mRawPtr = aNewPtr;
398 0 : NSCAP_LOG_ASSIGNMENT(this, aNewPtr);
399 0 : NSCAP_LOG_RELEASE(this, oldPtr);
400 0 : if (oldPtr) {
401 0 : NSCAP_RELEASE(this, oldPtr);
402 : }
403 0 : }
404 :
405 : private:
406 : T* MOZ_OWNING_REF mRawPtr;
407 : #endif
408 :
409 : void assert_validity()
410 : {
411 : static_assert(1 < sizeof(TestForIID<T>(nullptr)), "nsCOMPtr only works "
412 : "for types with IIDs. Either use RefPtr; add an IID to "
413 : "your type with NS_DECLARE_STATIC_IID_ACCESSOR/"
414 : "NS_DEFINE_STATIC_IID_ACCESSOR; or make the nsCOMPtr point "
415 : "to a base class with an IID.");
416 : }
417 :
418 : public:
419 : typedef T element_type;
420 :
421 : #ifndef NSCAP_FEATURE_USE_BASE
422 0 : ~nsCOMPtr()
423 : {
424 0 : NSCAP_LOG_RELEASE(this, mRawPtr);
425 0 : if (mRawPtr) {
426 0 : NSCAP_RELEASE(this, mRawPtr);
427 : }
428 0 : }
429 : #endif
430 :
431 : #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
432 0 : void Assert_NoQueryNeeded()
433 : {
434 0 : if (mRawPtr) {
435 0 : nsCOMPtr<T> query_result(do_QueryInterface(mRawPtr));
436 0 : NS_ASSERTION(query_result.get() == mRawPtr, "QueryInterface needed");
437 : }
438 0 : }
439 :
440 : #define NSCAP_ASSERT_NO_QUERY_NEEDED() Assert_NoQueryNeeded();
441 : #else
442 : #define NSCAP_ASSERT_NO_QUERY_NEEDED()
443 : #endif
444 :
445 :
446 : // Constructors
447 :
448 0 : nsCOMPtr()
449 0 : : NSCAP_CTOR_BASE(nullptr)
450 : {
451 0 : assert_validity();
452 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
453 : }
454 :
455 0 : MOZ_IMPLICIT nsCOMPtr(decltype(nullptr))
456 0 : : NSCAP_CTOR_BASE(nullptr)
457 : {
458 0 : assert_validity();
459 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
460 : }
461 :
462 0 : nsCOMPtr(const nsCOMPtr<T>& aSmartPtr)
463 0 : : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr)
464 : {
465 0 : assert_validity();
466 0 : if (mRawPtr) {
467 0 : NSCAP_ADDREF(this, mRawPtr);
468 : }
469 0 : NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr);
470 0 : }
471 :
472 0 : nsCOMPtr(nsCOMPtr<T>&& aSmartPtr)
473 0 : : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr)
474 : {
475 0 : assert_validity();
476 0 : aSmartPtr.mRawPtr = nullptr;
477 0 : NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
478 0 : NSCAP_ASSERT_NO_QUERY_NEEDED();
479 0 : }
480 :
481 0 : MOZ_IMPLICIT nsCOMPtr(T* aRawPtr)
482 0 : : NSCAP_CTOR_BASE(aRawPtr)
483 : {
484 0 : assert_validity();
485 0 : if (mRawPtr) {
486 0 : NSCAP_ADDREF(this, mRawPtr);
487 : }
488 0 : NSCAP_LOG_ASSIGNMENT(this, aRawPtr);
489 0 : NSCAP_ASSERT_NO_QUERY_NEEDED();
490 0 : }
491 :
492 0 : MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T>& aSmartPtr)
493 0 : : NSCAP_CTOR_BASE(aSmartPtr.take())
494 : {
495 0 : assert_validity();
496 0 : NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
497 0 : NSCAP_ASSERT_NO_QUERY_NEEDED();
498 0 : }
499 :
500 : // Construct from |otherComPtr.forget()|.
501 0 : MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T>&& aSmartPtr)
502 0 : : NSCAP_CTOR_BASE(aSmartPtr.take())
503 : {
504 0 : assert_validity();
505 0 : NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
506 0 : NSCAP_ASSERT_NO_QUERY_NEEDED();
507 0 : }
508 :
509 : // Construct from |already_AddRefed|.
510 : template<typename U>
511 0 : MOZ_IMPLICIT nsCOMPtr(already_AddRefed<U>& aSmartPtr)
512 0 : : NSCAP_CTOR_BASE(static_cast<T*>(aSmartPtr.take()))
513 : {
514 0 : assert_validity();
515 : // But make sure that U actually inherits from T.
516 : static_assert(mozilla::IsBaseOf<T, U>::value,
517 : "U is not a subclass of T");
518 0 : NSCAP_LOG_ASSIGNMENT(this, static_cast<T*>(mRawPtr));
519 0 : NSCAP_ASSERT_NO_QUERY_NEEDED();
520 0 : }
521 :
522 : // Construct from |otherComPtr.forget()|.
523 : template<typename U>
524 0 : MOZ_IMPLICIT nsCOMPtr(already_AddRefed<U>&& aSmartPtr)
525 0 : : NSCAP_CTOR_BASE(static_cast<T*>(aSmartPtr.take()))
526 : {
527 0 : assert_validity();
528 : // But make sure that U actually inherits from T.
529 : static_assert(mozilla::IsBaseOf<T, U>::value,
530 : "U is not a subclass of T");
531 0 : NSCAP_LOG_ASSIGNMENT(this, static_cast<T*>(mRawPtr));
532 0 : NSCAP_ASSERT_NO_QUERY_NEEDED();
533 0 : }
534 :
535 : // Construct from |do_QueryInterface(expr)|.
536 0 : MOZ_IMPLICIT nsCOMPtr(const nsQueryInterface aQI)
537 0 : : NSCAP_CTOR_BASE(nullptr)
538 : {
539 0 : assert_validity();
540 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
541 0 : assign_from_qi(aQI, NS_GET_TEMPLATE_IID(T));
542 0 : }
543 :
544 : // Construct from |do_QueryInterface(expr, &rv)|.
545 0 : MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceWithError& aQI)
546 0 : : NSCAP_CTOR_BASE(nullptr)
547 : {
548 0 : assert_validity();
549 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
550 0 : assign_from_qi_with_error(aQI, NS_GET_TEMPLATE_IID(T));
551 0 : }
552 :
553 : // Construct from |do_GetService(cid_expr)|.
554 0 : MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCID aGS)
555 0 : : NSCAP_CTOR_BASE(nullptr)
556 : {
557 0 : assert_validity();
558 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
559 0 : assign_from_gs_cid(aGS, NS_GET_TEMPLATE_IID(T));
560 0 : }
561 :
562 : // Construct from |do_GetService(cid_expr, &rv)|.
563 0 : MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCIDWithError& aGS)
564 0 : : NSCAP_CTOR_BASE(nullptr)
565 : {
566 0 : assert_validity();
567 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
568 0 : assign_from_gs_cid_with_error(aGS, NS_GET_TEMPLATE_IID(T));
569 0 : }
570 :
571 : // Construct from |do_GetService(contractid_expr)|.
572 0 : MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractID aGS)
573 0 : : NSCAP_CTOR_BASE(nullptr)
574 : {
575 0 : assert_validity();
576 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
577 0 : assign_from_gs_contractid(aGS, NS_GET_TEMPLATE_IID(T));
578 0 : }
579 :
580 : // Construct from |do_GetService(contractid_expr, &rv)|.
581 0 : MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
582 0 : : NSCAP_CTOR_BASE(nullptr)
583 : {
584 0 : assert_validity();
585 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
586 0 : assign_from_gs_contractid_with_error(aGS, NS_GET_TEMPLATE_IID(T));
587 0 : }
588 :
589 : // Construct from |do_QueryReferent(ptr)|
590 0 : MOZ_IMPLICIT nsCOMPtr(const nsQueryReferent& aQueryReferent)
591 0 : : NSCAP_CTOR_BASE(nullptr)
592 : {
593 0 : assert_validity();
594 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
595 0 : assign_from_query_referent(aQueryReferent, NS_GET_TEMPLATE_IID(T));
596 0 : }
597 :
598 : // And finally, anything else we might need to construct from can exploit the
599 : // nsCOMPtr_helper facility.
600 0 : MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper)
601 0 : : NSCAP_CTOR_BASE(nullptr)
602 : {
603 0 : assert_validity();
604 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
605 0 : assign_from_helper(aHelper, NS_GET_TEMPLATE_IID(T));
606 0 : NSCAP_ASSERT_NO_QUERY_NEEDED();
607 0 : }
608 :
609 : // Defined in OwningNonNull.h
610 : template<class U>
611 : MOZ_IMPLICIT nsCOMPtr(const mozilla::OwningNonNull<U>& aOther);
612 :
613 :
614 : // Assignment operators
615 :
616 0 : nsCOMPtr<T>& operator=(const nsCOMPtr<T>& aRhs)
617 : {
618 0 : assign_with_AddRef(aRhs.mRawPtr);
619 0 : return *this;
620 : }
621 :
622 0 : nsCOMPtr<T>& operator=(nsCOMPtr<T>&& aRhs)
623 : {
624 0 : assign_assuming_AddRef(aRhs.forget().take());
625 0 : NSCAP_ASSERT_NO_QUERY_NEEDED();
626 0 : return *this;
627 : }
628 :
629 0 : nsCOMPtr<T>& operator=(T* aRhs)
630 : {
631 0 : assign_with_AddRef(aRhs);
632 0 : NSCAP_ASSERT_NO_QUERY_NEEDED();
633 0 : return *this;
634 : }
635 :
636 0 : nsCOMPtr<T>& operator=(decltype(nullptr))
637 : {
638 0 : assign_assuming_AddRef(nullptr);
639 0 : return *this;
640 : }
641 :
642 : // Assign from |already_AddRefed|.
643 : template<typename U>
644 0 : nsCOMPtr<T>& operator=(already_AddRefed<U>& aRhs)
645 : {
646 : // Make sure that U actually inherits from T
647 : static_assert(mozilla::IsBaseOf<T, U>::value,
648 : "U is not a subclass of T");
649 0 : assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
650 0 : NSCAP_ASSERT_NO_QUERY_NEEDED();
651 0 : return *this;
652 : }
653 :
654 : // Assign from |otherComPtr.forget()|.
655 : template<typename U>
656 0 : nsCOMPtr<T>& operator=(already_AddRefed<U>&& aRhs)
657 : {
658 : // Make sure that U actually inherits from T
659 : static_assert(mozilla::IsBaseOf<T, U>::value,
660 : "U is not a subclass of T");
661 0 : assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
662 0 : NSCAP_ASSERT_NO_QUERY_NEEDED();
663 0 : return *this;
664 : }
665 :
666 : // Assign from |do_QueryInterface(expr)|.
667 0 : nsCOMPtr<T>& operator=(const nsQueryInterface aRhs)
668 : {
669 0 : assign_from_qi(aRhs, NS_GET_TEMPLATE_IID(T));
670 0 : return *this;
671 : }
672 :
673 : // Assign from |do_QueryInterface(expr, &rv)|.
674 0 : nsCOMPtr<T>& operator=(const nsQueryInterfaceWithError& aRhs)
675 : {
676 0 : assign_from_qi_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
677 0 : return *this;
678 : }
679 :
680 : // Assign from |do_GetService(cid_expr)|.
681 0 : nsCOMPtr<T>& operator=(const nsGetServiceByCID aRhs)
682 : {
683 0 : assign_from_gs_cid(aRhs, NS_GET_TEMPLATE_IID(T));
684 0 : return *this;
685 : }
686 :
687 : // Assign from |do_GetService(cid_expr, &rv)|.
688 0 : nsCOMPtr<T>& operator=(const nsGetServiceByCIDWithError& aRhs)
689 : {
690 0 : assign_from_gs_cid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
691 0 : return *this;
692 : }
693 :
694 : // Assign from |do_GetService(contractid_expr)|.
695 0 : nsCOMPtr<T>& operator=(const nsGetServiceByContractID aRhs)
696 : {
697 0 : assign_from_gs_contractid(aRhs, NS_GET_TEMPLATE_IID(T));
698 0 : return *this;
699 : }
700 :
701 : // Assign from |do_GetService(contractid_expr, &rv)|.
702 0 : nsCOMPtr<T>& operator=(const nsGetServiceByContractIDWithError& aRhs)
703 : {
704 0 : assign_from_gs_contractid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
705 0 : return *this;
706 : }
707 :
708 : // Assign from |do_QueryReferent(ptr)|.
709 0 : nsCOMPtr<T>& operator=(const nsQueryReferent& aRhs)
710 : {
711 0 : assign_from_query_referent(aRhs, NS_GET_TEMPLATE_IID(T));
712 0 : return *this;
713 : }
714 :
715 : // And finally, anything else we might need to assign from can exploit the
716 : // nsCOMPtr_helper facility.
717 0 : nsCOMPtr<T>& operator=(const nsCOMPtr_helper& aRhs)
718 : {
719 0 : assign_from_helper(aRhs, NS_GET_TEMPLATE_IID(T));
720 0 : NSCAP_ASSERT_NO_QUERY_NEEDED();
721 0 : return *this;
722 : }
723 :
724 : // Defined in OwningNonNull.h
725 : template<class U>
726 : nsCOMPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
727 :
728 : // Exchange ownership with |aRhs|; can save a pair of refcount operations.
729 0 : void swap(nsCOMPtr<T>& aRhs)
730 : {
731 : #ifdef NSCAP_FEATURE_USE_BASE
732 : nsISupports* temp = aRhs.mRawPtr;
733 : #else
734 0 : T* temp = aRhs.mRawPtr;
735 : #endif
736 0 : NSCAP_LOG_ASSIGNMENT(&aRhs, mRawPtr);
737 0 : NSCAP_LOG_ASSIGNMENT(this, temp);
738 0 : NSCAP_LOG_RELEASE(this, mRawPtr);
739 0 : NSCAP_LOG_RELEASE(&aRhs, temp);
740 0 : aRhs.mRawPtr = mRawPtr;
741 0 : mRawPtr = temp;
742 : // |aRhs| maintains the same invariants, so we don't need to |NSCAP_ASSERT_NO_QUERY_NEEDED|
743 0 : }
744 :
745 : // Exchange ownership with |aRhs|; can save a pair of refcount operations.
746 0 : void swap(T*& aRhs)
747 : {
748 : #ifdef NSCAP_FEATURE_USE_BASE
749 : nsISupports* temp = aRhs;
750 : #else
751 0 : T* temp = aRhs;
752 : #endif
753 0 : NSCAP_LOG_ASSIGNMENT(this, temp);
754 0 : NSCAP_LOG_RELEASE(this, mRawPtr);
755 0 : aRhs = reinterpret_cast<T*>(mRawPtr);
756 0 : mRawPtr = temp;
757 0 : NSCAP_ASSERT_NO_QUERY_NEEDED();
758 0 : }
759 :
760 :
761 : // Other pointer operators
762 :
763 : // Return the value of mRawPtr and null out mRawPtr. Useful for
764 : // already_AddRefed return values.
765 0 : already_AddRefed<T> MOZ_MAY_CALL_AFTER_MUST_RETURN forget()
766 : {
767 0 : T* temp = nullptr;
768 0 : swap(temp);
769 0 : return already_AddRefed<T>(temp);
770 : }
771 :
772 : // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
773 : // Useful to avoid unnecessary AddRef/Release pairs with "out" parameters
774 : // where aRhs bay be a T** or an I** where I is a base class of T.
775 : template<typename I>
776 0 : void forget(I** aRhs)
777 : {
778 0 : NS_ASSERTION(aRhs, "Null pointer passed to forget!");
779 0 : NSCAP_LOG_RELEASE(this, mRawPtr);
780 0 : *aRhs = get();
781 0 : mRawPtr = nullptr;
782 0 : }
783 :
784 : // Prefer the implicit conversion provided automatically by
785 : // |operator T*() const|. Use |get()| to resolve ambiguity or to get a
786 : // castable pointer.
787 0 : T* get() const { return reinterpret_cast<T*>(mRawPtr); }
788 :
789 : // Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
790 : // used in a context where a raw pointer is expected. It is this operator
791 : // that makes an nsCOMPtr substitutable for a raw pointer.
792 : //
793 : // Prefer the implicit use of this operator to calling |get()|, except where
794 : // necessary to resolve ambiguity.
795 0 : operator T*() const & { return get(); }
796 :
797 : // Don't allow implicit conversion of temporary nsCOMPtr to raw pointer,
798 : // because the refcount might be one and the pointer will immediately become
799 : // invalid.
800 : operator T*() const && = delete;
801 :
802 : // Needed to avoid the deleted operator above
803 0 : explicit operator bool() const { return !!mRawPtr; }
804 :
805 0 : T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
806 : {
807 0 : MOZ_ASSERT(mRawPtr != nullptr,
808 : "You can't dereference a NULL nsCOMPtr with operator->().");
809 0 : return get();
810 : }
811 :
812 : // These are not intended to be used by clients. See |address_of| below.
813 : nsCOMPtr<T>* get_address() { return this; }
814 : const nsCOMPtr<T>* get_address() const { return this; }
815 :
816 : public:
817 0 : T& operator*() const
818 : {
819 0 : MOZ_ASSERT(mRawPtr != nullptr,
820 : "You can't dereference a NULL nsCOMPtr with operator*().");
821 0 : return *get();
822 : }
823 :
824 : T** StartAssignment()
825 : {
826 : #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
827 0 : return reinterpret_cast<T**>(begin_assignment());
828 : #else
829 : assign_assuming_AddRef(nullptr);
830 : return reinterpret_cast<T**>(&mRawPtr);
831 : #endif
832 : }
833 : };
834 :
835 :
836 : /*
837 : * Specializing nsCOMPtr for nsISupports allows us to use nsCOMPtr<nsISupports>
838 : * the same way people use nsISupports* and void*, i.e., as a `catch-all'
839 : * pointing to any valid [XP]COM interface. Otherwise, an nsCOMPtr<nsISupports>
840 : * would only be able to point to the single [XP]COM-correct nsISupports
841 : * instance within an object; extra querying ensues. Clients need to be able to
842 : * pass around arbitrary interface pointers, without hassles, through
843 : * intermediary code that doesn't know the exact type.
844 : */
845 : template<>
846 0 : class nsCOMPtr<nsISupports>
847 : : private nsCOMPtr_base
848 : {
849 : public:
850 : typedef nsISupports element_type;
851 :
852 : // Constructors
853 :
854 : nsCOMPtr()
855 0 : : nsCOMPtr_base(nullptr)
856 : {
857 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
858 : }
859 :
860 : MOZ_IMPLICIT nsCOMPtr(decltype(nullptr))
861 0 : : nsCOMPtr_base(nullptr)
862 : {
863 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
864 : }
865 :
866 0 : nsCOMPtr(const nsCOMPtr<nsISupports>& aSmartPtr)
867 0 : : nsCOMPtr_base(aSmartPtr.mRawPtr)
868 : {
869 0 : if (mRawPtr) {
870 0 : NSCAP_ADDREF(this, mRawPtr);
871 : }
872 0 : NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr);
873 0 : }
874 :
875 0 : MOZ_IMPLICIT nsCOMPtr(nsISupports* aRawPtr)
876 0 : : nsCOMPtr_base(aRawPtr)
877 : {
878 0 : if (mRawPtr) {
879 0 : NSCAP_ADDREF(this, mRawPtr);
880 : }
881 0 : NSCAP_LOG_ASSIGNMENT(this, aRawPtr);
882 0 : }
883 :
884 : // Construct from |already_AddRefed|.
885 0 : MOZ_IMPLICIT nsCOMPtr(already_AddRefed<nsISupports>& aSmartPtr)
886 0 : : nsCOMPtr_base(aSmartPtr.take())
887 : {
888 0 : NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
889 0 : }
890 :
891 : // Construct from |otherComPtr.forget()|.
892 0 : MOZ_IMPLICIT nsCOMPtr(already_AddRefed<nsISupports>&& aSmartPtr)
893 0 : : nsCOMPtr_base(aSmartPtr.take())
894 : {
895 0 : NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
896 0 : }
897 :
898 : // Construct from |do_QueryInterface(expr)|.
899 0 : MOZ_IMPLICIT nsCOMPtr(const nsQueryInterface aQI)
900 0 : : nsCOMPtr_base(nullptr)
901 : {
902 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
903 0 : assign_from_qi(aQI, NS_GET_IID(nsISupports));
904 0 : }
905 :
906 : // Construct from |do_QueryInterface(expr, &rv)|.
907 0 : MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceWithError& aQI)
908 0 : : nsCOMPtr_base(nullptr)
909 : {
910 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
911 0 : assign_from_qi_with_error(aQI, NS_GET_IID(nsISupports));
912 0 : }
913 :
914 : // Construct from |do_GetService(cid_expr)|.
915 : MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCID aGS)
916 : : nsCOMPtr_base(nullptr)
917 : {
918 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
919 : assign_from_gs_cid(aGS, NS_GET_IID(nsISupports));
920 : }
921 :
922 : // Construct from |do_GetService(cid_expr, &rv)|.
923 : MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCIDWithError& aGS)
924 : : nsCOMPtr_base(nullptr)
925 : {
926 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
927 : assign_from_gs_cid_with_error(aGS, NS_GET_IID(nsISupports));
928 : }
929 :
930 : // Construct from |do_GetService(contractid_expr)|.
931 0 : MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractID aGS)
932 0 : : nsCOMPtr_base(nullptr)
933 : {
934 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
935 0 : assign_from_gs_contractid(aGS, NS_GET_IID(nsISupports));
936 0 : }
937 :
938 : // Construct from |do_GetService(contractid_expr, &rv)|.
939 0 : MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
940 0 : : nsCOMPtr_base(nullptr)
941 : {
942 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
943 0 : assign_from_gs_contractid_with_error(aGS, NS_GET_IID(nsISupports));
944 0 : }
945 :
946 : // Construct from |do_QueryReferent(ptr)|
947 0 : MOZ_IMPLICIT nsCOMPtr(const nsQueryReferent& aQueryReferent)
948 0 : : nsCOMPtr_base(nullptr)
949 : {
950 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
951 0 : assign_from_query_referent(aQueryReferent, NS_GET_TEMPLATE_IID(nsISupports));
952 0 : }
953 :
954 : // And finally, anything else we might need to construct from can exploit
955 : // the |nsCOMPtr_helper| facility
956 0 : MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper)
957 0 : : nsCOMPtr_base(nullptr)
958 : {
959 : NSCAP_LOG_ASSIGNMENT(this, nullptr);
960 0 : assign_from_helper(aHelper, NS_GET_IID(nsISupports));
961 0 : }
962 :
963 :
964 : // Assignment operators
965 :
966 0 : nsCOMPtr<nsISupports>& operator=(const nsCOMPtr<nsISupports>& aRhs)
967 : {
968 0 : assign_with_AddRef(aRhs.mRawPtr);
969 0 : return *this;
970 : }
971 :
972 : nsCOMPtr<nsISupports>& operator=(nsISupports* aRhs)
973 : {
974 0 : assign_with_AddRef(aRhs);
975 : return *this;
976 : }
977 :
978 0 : nsCOMPtr<nsISupports>& operator=(decltype(nullptr))
979 : {
980 0 : assign_assuming_AddRef(nullptr);
981 0 : return *this;
982 : }
983 :
984 : // Assign from |already_AddRefed|.
985 0 : nsCOMPtr<nsISupports>& operator=(already_AddRefed<nsISupports>& aRhs)
986 : {
987 0 : assign_assuming_AddRef(aRhs.take());
988 0 : return *this;
989 : }
990 :
991 : // Assign from |otherComPtr.forget()|.
992 0 : nsCOMPtr<nsISupports>& operator=(already_AddRefed<nsISupports>&& aRhs)
993 : {
994 0 : assign_assuming_AddRef(aRhs.take());
995 0 : return *this;
996 : }
997 :
998 : // Assign from |do_QueryInterface(expr)|.
999 0 : nsCOMPtr<nsISupports>& operator=(const nsQueryInterface aRhs)
1000 : {
1001 0 : assign_from_qi(aRhs, NS_GET_IID(nsISupports));
1002 0 : return *this;
1003 : }
1004 :
1005 : // Assign from |do_QueryInterface(expr, &rv)|.
1006 : nsCOMPtr<nsISupports>& operator=(const nsQueryInterfaceWithError& aRhs)
1007 : {
1008 : assign_from_qi_with_error(aRhs, NS_GET_IID(nsISupports));
1009 : return *this;
1010 : }
1011 :
1012 : // Assign from |do_GetService(cid_expr)|.
1013 : nsCOMPtr<nsISupports>& operator=(const nsGetServiceByCID aRhs)
1014 : {
1015 : assign_from_gs_cid(aRhs, NS_GET_IID(nsISupports));
1016 : return *this;
1017 : }
1018 :
1019 : // Assign from |do_GetService(cid_expr, &rv)|.
1020 : nsCOMPtr<nsISupports>& operator=(const nsGetServiceByCIDWithError& aRhs)
1021 : {
1022 : assign_from_gs_cid_with_error(aRhs, NS_GET_IID(nsISupports));
1023 : return *this;
1024 : }
1025 :
1026 : // Assign from |do_GetService(contractid_expr)|.
1027 : nsCOMPtr<nsISupports>& operator=(const nsGetServiceByContractID aRhs)
1028 : {
1029 : assign_from_gs_contractid(aRhs, NS_GET_IID(nsISupports));
1030 : return *this;
1031 : }
1032 :
1033 : // Assign from |do_GetService(contractid_expr, &rv)|.
1034 0 : nsCOMPtr<nsISupports>& operator=(const nsGetServiceByContractIDWithError& aRhs)
1035 : {
1036 0 : assign_from_gs_contractid_with_error(aRhs, NS_GET_IID(nsISupports));
1037 0 : return *this;
1038 : }
1039 :
1040 : // Assign from |do_QueryReferent(ptr)|.
1041 0 : nsCOMPtr<nsISupports>& operator=(const nsQueryReferent& aRhs)
1042 : {
1043 0 : assign_from_query_referent(aRhs, NS_GET_TEMPLATE_IID(nsISupports));
1044 0 : return *this;
1045 : }
1046 :
1047 : // And finally, anything else we might need to assign from can exploit the
1048 : // nsCOMPtr_helper facility
1049 0 : nsCOMPtr<nsISupports>& operator=(const nsCOMPtr_helper& aRhs)
1050 : {
1051 0 : assign_from_helper(aRhs, NS_GET_IID(nsISupports));
1052 0 : return *this;
1053 : }
1054 :
1055 : // Exchange ownership with |aRhs|; can save a pair of refcount operations.
1056 0 : void swap(nsCOMPtr<nsISupports>& aRhs)
1057 : {
1058 0 : nsISupports* temp = aRhs.mRawPtr;
1059 0 : NSCAP_LOG_ASSIGNMENT(&aRhs, mRawPtr);
1060 0 : NSCAP_LOG_ASSIGNMENT(this, temp);
1061 0 : NSCAP_LOG_RELEASE(this, mRawPtr);
1062 0 : NSCAP_LOG_RELEASE(&aRhs, temp);
1063 0 : aRhs.mRawPtr = mRawPtr;
1064 0 : mRawPtr = temp;
1065 0 : }
1066 :
1067 : // Exchange ownership with |aRhs|; can save a pair of refcount operations.
1068 0 : void swap(nsISupports*& aRhs)
1069 : {
1070 0 : nsISupports* temp = aRhs;
1071 0 : NSCAP_LOG_ASSIGNMENT(this, temp);
1072 0 : NSCAP_LOG_RELEASE(this, mRawPtr);
1073 0 : aRhs = mRawPtr;
1074 0 : mRawPtr = temp;
1075 0 : }
1076 :
1077 : // Return the value of mRawPtr and null out mRawPtr. Useful for
1078 : // already_AddRefed return values.
1079 0 : already_AddRefed<nsISupports> forget()
1080 : {
1081 0 : nsISupports* temp = nullptr;
1082 0 : swap(temp);
1083 0 : return already_AddRefed<nsISupports>(temp);
1084 : }
1085 :
1086 : // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
1087 : // Useful to avoid unnecessary AddRef/Release pairs with "out"
1088 : // parameters.
1089 0 : void forget(nsISupports** aRhs)
1090 : {
1091 0 : NS_ASSERTION(aRhs, "Null pointer passed to forget!");
1092 0 : *aRhs = nullptr;
1093 0 : swap(*aRhs);
1094 0 : }
1095 :
1096 : // Other pointer operators
1097 :
1098 : // Prefer the implicit conversion provided automatically by
1099 : // |operator nsISupports*() const|. Use |get()| to resolve ambiguity or to
1100 : // get a castable pointer.
1101 0 : nsISupports* get() const { return reinterpret_cast<nsISupports*>(mRawPtr); }
1102 :
1103 : // Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
1104 : // used in a context where a raw pointer is expected. It is this operator
1105 : // that makes an nsCOMPtr substitutable for a raw pointer.
1106 : //
1107 : // Prefer the implicit use of this operator to calling |get()|, except where
1108 : // necessary to resolve ambiguity/
1109 0 : operator nsISupports* () const { return get(); }
1110 :
1111 0 : nsISupports* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
1112 : {
1113 0 : MOZ_ASSERT(mRawPtr != nullptr,
1114 : "You can't dereference a NULL nsCOMPtr with operator->().");
1115 0 : return get();
1116 : }
1117 :
1118 : // These are not intended to be used by clients. See |address_of| below.
1119 : nsCOMPtr<nsISupports>* get_address() { return this; }
1120 : const nsCOMPtr<nsISupports>* get_address() const { return this; }
1121 :
1122 : public:
1123 :
1124 : nsISupports& operator*() const
1125 : {
1126 : MOZ_ASSERT(mRawPtr != nullptr,
1127 : "You can't dereference a NULL nsCOMPtr with operator*().");
1128 : return *get();
1129 : }
1130 :
1131 : nsISupports** StartAssignment()
1132 : {
1133 : #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
1134 0 : return reinterpret_cast<nsISupports**>(begin_assignment());
1135 : #else
1136 : assign_assuming_AddRef(nullptr);
1137 : return reinterpret_cast<nsISupports**>(&mRawPtr);
1138 : #endif
1139 : }
1140 : };
1141 :
1142 : template<typename T>
1143 : inline void
1144 : ImplCycleCollectionUnlink(nsCOMPtr<T>& aField)
1145 : {
1146 0 : aField = nullptr;
1147 : }
1148 :
1149 : template<typename T>
1150 : inline void
1151 0 : ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
1152 : nsCOMPtr<T>& aField,
1153 : const char* aName,
1154 : uint32_t aFlags = 0)
1155 : {
1156 0 : CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
1157 0 : }
1158 :
1159 : #ifndef NSCAP_FEATURE_USE_BASE
1160 : template<class T>
1161 : void
1162 0 : nsCOMPtr<T>::assign_with_AddRef(nsISupports* aRawPtr)
1163 : {
1164 0 : if (aRawPtr) {
1165 0 : NSCAP_ADDREF(this, aRawPtr);
1166 : }
1167 0 : assign_assuming_AddRef(reinterpret_cast<T*>(aRawPtr));
1168 0 : }
1169 :
1170 : template<class T>
1171 : void
1172 0 : nsCOMPtr<T>::assign_from_qi(const nsQueryInterface aQI, const nsIID& aIID)
1173 : {
1174 : void* newRawPtr;
1175 0 : if (NS_FAILED(aQI(aIID, &newRawPtr))) {
1176 0 : newRawPtr = nullptr;
1177 : }
1178 0 : assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1179 0 : }
1180 :
1181 : template<class T>
1182 : void
1183 0 : nsCOMPtr<T>::assign_from_qi_with_error(const nsQueryInterfaceWithError& aQI,
1184 : const nsIID& aIID)
1185 : {
1186 : void* newRawPtr;
1187 0 : if (NS_FAILED(aQI(aIID, &newRawPtr))) {
1188 0 : newRawPtr = nullptr;
1189 : }
1190 0 : assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1191 0 : }
1192 :
1193 : template<class T>
1194 : void
1195 0 : nsCOMPtr<T>::assign_from_gs_cid(const nsGetServiceByCID aGS, const nsIID& aIID)
1196 : {
1197 : void* newRawPtr;
1198 0 : if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1199 0 : newRawPtr = nullptr;
1200 : }
1201 0 : assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1202 0 : }
1203 :
1204 : template<class T>
1205 : void
1206 0 : nsCOMPtr<T>::assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError& aGS,
1207 : const nsIID& aIID)
1208 : {
1209 : void* newRawPtr;
1210 0 : if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1211 0 : newRawPtr = nullptr;
1212 : }
1213 0 : assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1214 0 : }
1215 :
1216 : template<class T>
1217 : void
1218 0 : nsCOMPtr<T>::assign_from_gs_contractid(const nsGetServiceByContractID aGS,
1219 : const nsIID& aIID)
1220 : {
1221 : void* newRawPtr;
1222 0 : if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1223 0 : newRawPtr = nullptr;
1224 : }
1225 0 : assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1226 0 : }
1227 :
1228 : template<class T>
1229 : void
1230 0 : nsCOMPtr<T>::assign_from_gs_contractid_with_error(
1231 : const nsGetServiceByContractIDWithError& aGS, const nsIID& aIID)
1232 : {
1233 : void* newRawPtr;
1234 0 : if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1235 0 : newRawPtr = nullptr;
1236 : }
1237 0 : assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1238 0 : }
1239 :
1240 : template<class T>
1241 : void
1242 0 : nsCOMPtr<T>::assign_from_query_referent(
1243 : const nsQueryReferent& aQueryReferent, const nsIID& aIID)
1244 : {
1245 : void* newRawPtr;
1246 0 : if (NS_FAILED(aQueryReferent(aIID, &newRawPtr))) {
1247 0 : newRawPtr = nullptr;
1248 : }
1249 0 : assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1250 0 : }
1251 :
1252 : template<class T>
1253 : void
1254 0 : nsCOMPtr<T>::assign_from_helper(const nsCOMPtr_helper& helper, const nsIID& aIID)
1255 : {
1256 : void* newRawPtr;
1257 0 : if (NS_FAILED(helper(aIID, &newRawPtr))) {
1258 0 : newRawPtr = nullptr;
1259 : }
1260 0 : assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1261 0 : }
1262 :
1263 : template<class T>
1264 : void**
1265 : nsCOMPtr<T>::begin_assignment()
1266 : {
1267 0 : assign_assuming_AddRef(nullptr);
1268 : union
1269 : {
1270 : T** mT;
1271 : void** mVoid;
1272 : } result;
1273 0 : result.mT = &mRawPtr;
1274 : return result.mVoid;
1275 : }
1276 : #endif
1277 :
1278 : template<class T>
1279 : inline nsCOMPtr<T>*
1280 : address_of(nsCOMPtr<T>& aPtr)
1281 : {
1282 0 : return aPtr.get_address();
1283 : }
1284 :
1285 : template<class T>
1286 : inline const nsCOMPtr<T>*
1287 : address_of(const nsCOMPtr<T>& aPtr)
1288 : {
1289 : return aPtr.get_address();
1290 : }
1291 :
1292 : /**
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.,
1295 : *
1296 : * nsCOMPtr<IFoo> fooP;
1297 : * ...->QueryInterface(iid, getter_AddRefs(fooP))
1298 : *
1299 : * DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
1300 : *
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.
1304 : *
1305 : * This type should be a nested class inside |nsCOMPtr<T>|.
1306 : */
1307 : template<class T>
1308 : class nsGetterAddRefs
1309 : {
1310 : public:
1311 : explicit nsGetterAddRefs(nsCOMPtr<T>& aSmartPtr)
1312 0 : : mTargetSmartPtr(aSmartPtr)
1313 : {
1314 : }
1315 :
1316 : #if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT)
1317 0 : ~nsGetterAddRefs()
1318 : {
1319 : #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
1320 0 : NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),
1321 : mTargetSmartPtr.get());
1322 : #endif
1323 :
1324 : #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
1325 0 : mTargetSmartPtr.Assert_NoQueryNeeded();
1326 : #endif
1327 0 : }
1328 : #endif
1329 :
1330 0 : operator void**()
1331 : {
1332 0 : return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
1333 : }
1334 :
1335 0 : operator T**() { return mTargetSmartPtr.StartAssignment(); }
1336 0 : T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
1337 :
1338 : private:
1339 : nsCOMPtr<T>& mTargetSmartPtr;
1340 : };
1341 :
1342 :
1343 : template<>
1344 : class nsGetterAddRefs<nsISupports>
1345 : {
1346 : public:
1347 : explicit nsGetterAddRefs(nsCOMPtr<nsISupports>& aSmartPtr)
1348 0 : : mTargetSmartPtr(aSmartPtr)
1349 : {
1350 : }
1351 :
1352 : #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
1353 0 : ~nsGetterAddRefs()
1354 0 : {
1355 0 : NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),
1356 0 : mTargetSmartPtr.get());
1357 0 : }
1358 : #endif
1359 :
1360 0 : operator void**()
1361 : {
1362 0 : return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
1363 : }
1364 :
1365 0 : operator nsISupports**() { return mTargetSmartPtr.StartAssignment(); }
1366 : nsISupports*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
1367 :
1368 : private:
1369 : nsCOMPtr<nsISupports>& mTargetSmartPtr;
1370 : };
1371 :
1372 : template<class T>
1373 : inline nsGetterAddRefs<T>
1374 : getter_AddRefs(nsCOMPtr<T>& aSmartPtr)
1375 : {
1376 0 : return nsGetterAddRefs<T>(aSmartPtr);
1377 : }
1378 :
1379 : template<class T, class DestinationType>
1380 : inline nsresult
1381 0 : CallQueryInterface(T* aSource, nsGetterAddRefs<DestinationType> aDestination)
1382 : {
1383 0 : return CallQueryInterface(aSource,
1384 0 : static_cast<DestinationType**>(aDestination));
1385 : }
1386 :
1387 :
1388 : // Comparing two |nsCOMPtr|s
1389 :
1390 : template<class T, class U>
1391 : inline bool
1392 : operator==(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs)
1393 : {
1394 0 : return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
1395 : }
1396 :
1397 :
1398 : template<class T, class U>
1399 : inline bool
1400 : operator!=(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs)
1401 : {
1402 0 : return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
1403 : }
1404 :
1405 :
1406 : // Comparing an |nsCOMPtr| to a raw pointer
1407 :
1408 : template<class T, class U>
1409 : inline bool
1410 : operator==(const nsCOMPtr<T>& aLhs, const U* aRhs)
1411 : {
1412 0 : return static_cast<const T*>(aLhs.get()) == aRhs;
1413 : }
1414 :
1415 : template<class T, class U>
1416 : inline bool
1417 : operator==(const U* aLhs, const nsCOMPtr<T>& aRhs)
1418 : {
1419 0 : return aLhs == static_cast<const T*>(aRhs.get());
1420 : }
1421 :
1422 : template<class T, class U>
1423 : inline bool
1424 : operator!=(const nsCOMPtr<T>& aLhs, const U* aRhs)
1425 : {
1426 : return static_cast<const T*>(aLhs.get()) != aRhs;
1427 : }
1428 :
1429 : template<class T, class U>
1430 : inline bool
1431 : operator!=(const U* aLhs, const nsCOMPtr<T>& aRhs)
1432 : {
1433 : return aLhs != static_cast<const T*>(aRhs.get());
1434 : }
1435 :
1436 : template<class T, class U>
1437 : inline bool
1438 : operator==(const nsCOMPtr<T>& aLhs, U* aRhs)
1439 : {
1440 0 : return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
1441 : }
1442 :
1443 : template<class T, class U>
1444 : inline bool
1445 : operator==(U* aLhs, const nsCOMPtr<T>& aRhs)
1446 : {
1447 0 : return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
1448 : }
1449 :
1450 : template<class T, class U>
1451 : inline bool
1452 : operator!=(const nsCOMPtr<T>& aLhs, U* aRhs)
1453 : {
1454 0 : return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
1455 : }
1456 :
1457 : template<class T, class U>
1458 : inline bool
1459 : operator!=(U* aLhs, const nsCOMPtr<T>& aRhs)
1460 : {
1461 0 : return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
1462 : }
1463 :
1464 :
1465 :
1466 : // Comparing an |nsCOMPtr| to |nullptr|
1467 :
1468 : template<class T>
1469 : inline bool
1470 : operator==(const nsCOMPtr<T>& aLhs, decltype(nullptr))
1471 : {
1472 0 : return aLhs.get() == nullptr;
1473 : }
1474 :
1475 : template<class T>
1476 : inline bool
1477 : operator==(decltype(nullptr), const nsCOMPtr<T>& aRhs)
1478 : {
1479 0 : return nullptr == aRhs.get();
1480 : }
1481 :
1482 : template<class T>
1483 : inline bool
1484 : operator!=(const nsCOMPtr<T>& aLhs, decltype(nullptr))
1485 : {
1486 0 : return aLhs.get() != nullptr;
1487 : }
1488 :
1489 : template<class T>
1490 : inline bool
1491 : operator!=(decltype(nullptr), const nsCOMPtr<T>& aRhs)
1492 : {
1493 0 : return nullptr != aRhs.get();
1494 : }
1495 :
1496 :
1497 : // Comparing any two [XP]COM objects for identity
1498 :
1499 : inline bool
1500 0 : SameCOMIdentity(nsISupports* aLhs, nsISupports* aRhs)
1501 : {
1502 0 : return nsCOMPtr<nsISupports>(do_QueryInterface(aLhs)) ==
1503 0 : nsCOMPtr<nsISupports>(do_QueryInterface(aRhs));
1504 : }
1505 :
1506 :
1507 :
1508 : template<class SourceType, class DestinationType>
1509 : inline nsresult
1510 0 : CallQueryInterface(nsCOMPtr<SourceType>& aSourcePtr, DestinationType** aDestPtr)
1511 : {
1512 0 : return CallQueryInterface(aSourcePtr.get(), aDestPtr);
1513 : }
1514 :
1515 : template <class T>
1516 0 : RefPtr<T>::RefPtr(const nsQueryReferent& aQueryReferent)
1517 : {
1518 : void* newRawPtr;
1519 0 : if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1520 0 : newRawPtr = nullptr;
1521 : }
1522 0 : mRawPtr = static_cast<T*>(newRawPtr);
1523 0 : }
1524 :
1525 : template <class T>
1526 0 : RefPtr<T>::RefPtr(const nsCOMPtr_helper& aHelper)
1527 : {
1528 : void* newRawPtr;
1529 0 : if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1530 0 : newRawPtr = nullptr;
1531 : }
1532 0 : mRawPtr = static_cast<T*>(newRawPtr);
1533 0 : }
1534 :
1535 : template <class T>
1536 : RefPtr<T>&
1537 : RefPtr<T>::operator=(const nsQueryReferent& aQueryReferent)
1538 : {
1539 : void* newRawPtr;
1540 : if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1541 : newRawPtr = nullptr;
1542 : }
1543 : assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1544 : return *this;
1545 : }
1546 :
1547 : template <class T>
1548 : RefPtr<T>&
1549 0 : RefPtr<T>::operator=(const nsCOMPtr_helper& aHelper)
1550 : {
1551 : void* newRawPtr;
1552 0 : if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1553 0 : newRawPtr = nullptr;
1554 : }
1555 0 : assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1556 0 : return *this;
1557 : }
1558 :
1559 : template <class T>
1560 : inline already_AddRefed<T>
1561 0 : do_AddRef(const nsCOMPtr<T>& aObj)
1562 : {
1563 0 : nsCOMPtr<T> ref(aObj);
1564 0 : return ref.forget();
1565 : }
1566 :
1567 : #endif // !defined(nsCOMPtr_h___)
|