Source code

Revision control

Other Tools

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