xpcom/glue/nsCOMPtr.h

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

mercurial