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 mozilla_RefPtr_h
8
#define mozilla_RefPtr_h
9
10
#include "mozilla/AlreadyAddRefed.h"
11
#include "mozilla/Assertions.h"
12
#include "mozilla/Attributes.h"
13
#include "mozilla/DbgMacro.h"
14
15
/*****************************************************************************/
16
17
// template <class T> class RefPtrGetterAddRefs;
18
19
class nsQueryReferent;
20
class nsCOMPtr_helper;
21
class nsISupports;
22
23
namespace mozilla {
24
template <class T>
25
class OwningNonNull;
26
template <class T>
27
class StaticLocalRefPtr;
28
template <class T>
29
class StaticRefPtr;
30
#if defined(XP_WIN)
31
namespace mscom {
32
class AgileReference;
33
} // namespace mscom
34
#endif // defined(XP_WIN)
35
36
// Traditionally, RefPtr supports automatic refcounting of any pointer type
37
// with AddRef() and Release() methods that follow the traditional semantics.
38
//
39
// This traits class can be specialized to operate on other pointer types. For
40
// example, we specialize this trait for opaque FFI types that represent
41
// refcounted objects in Rust.
42
//
43
// Given the use of ConstRemovingRefPtrTraits below, U should not be a const-
44
// qualified type.
45
template <class U>
46
struct RefPtrTraits {
47
static void AddRef(U* aPtr) { aPtr->AddRef(); }
48
static void Release(U* aPtr) { aPtr->Release(); }
49
};
50
51
} // namespace mozilla
52
53
template <class T>
54
class MOZ_IS_REFPTR RefPtr {
55
private:
56
void assign_with_AddRef(T* aRawPtr) {
57
if (aRawPtr) {
58
ConstRemovingRefPtrTraits<T>::AddRef(aRawPtr);
59
}
60
assign_assuming_AddRef(aRawPtr);
61
}
62
63
void assign_assuming_AddRef(T* aNewPtr) {
64
T* oldPtr = mRawPtr;
65
mRawPtr = aNewPtr;
66
if (oldPtr) {
67
ConstRemovingRefPtrTraits<T>::Release(oldPtr);
68
}
69
}
70
71
private:
72
T* MOZ_OWNING_REF mRawPtr;
73
74
public:
75
typedef T element_type;
76
77
~RefPtr() {
78
if (mRawPtr) {
79
ConstRemovingRefPtrTraits<T>::Release(mRawPtr);
80
}
81
}
82
83
// Constructors
84
85
RefPtr()
86
: mRawPtr(nullptr)
87
// default constructor
88
{}
89
90
RefPtr(const RefPtr<T>& aSmartPtr)
91
: mRawPtr(aSmartPtr.mRawPtr)
92
// copy-constructor
93
{
94
if (mRawPtr) {
95
ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
96
}
97
}
98
99
RefPtr(RefPtr<T>&& aRefPtr) : mRawPtr(aRefPtr.mRawPtr) {
100
aRefPtr.mRawPtr = nullptr;
101
}
102
103
// construct from a raw pointer (of the right type)
104
105
MOZ_IMPLICIT RefPtr(T* aRawPtr) : mRawPtr(aRawPtr) {
106
if (mRawPtr) {
107
ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
108
}
109
}
110
111
MOZ_IMPLICIT RefPtr(decltype(nullptr)) : mRawPtr(nullptr) {}
112
113
template <typename I>
114
MOZ_IMPLICIT RefPtr(already_AddRefed<I>& aSmartPtr)
115
: mRawPtr(aSmartPtr.take())
116
// construct from |already_AddRefed|
117
{}
118
119
template <typename I>
120
MOZ_IMPLICIT RefPtr(already_AddRefed<I>&& aSmartPtr)
121
: mRawPtr(aSmartPtr.take())
122
// construct from |otherRefPtr.forget()|
123
{}
124
125
template <typename I>
126
MOZ_IMPLICIT RefPtr(const RefPtr<I>& aSmartPtr)
127
: mRawPtr(aSmartPtr.get())
128
// copy-construct from a smart pointer with a related pointer type
129
{
130
if (mRawPtr) {
131
ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
132
}
133
}
134
135
template <typename I>
136
MOZ_IMPLICIT RefPtr(RefPtr<I>&& aSmartPtr)
137
: mRawPtr(aSmartPtr.forget().take())
138
// construct from |Move(RefPtr<SomeSubclassOfT>)|.
139
{}
140
141
MOZ_IMPLICIT RefPtr(const nsQueryReferent& aHelper);
142
MOZ_IMPLICIT RefPtr(const nsCOMPtr_helper& aHelper);
143
#if defined(XP_WIN)
144
MOZ_IMPLICIT RefPtr(const mozilla::mscom::AgileReference& aAgileRef);
145
#endif // defined(XP_WIN)
146
147
// Defined in OwningNonNull.h
148
template <class U>
149
MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull<U>& aOther);
150
151
// Defined in StaticLocalPtr.h
152
template <class U>
153
MOZ_IMPLICIT RefPtr(const mozilla::StaticLocalRefPtr<U>& aOther);
154
155
// Defined in StaticPtr.h
156
template <class U>
157
MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr<U>& aOther);
158
159
// Assignment operators
160
161
RefPtr<T>& operator=(decltype(nullptr)) {
162
assign_assuming_AddRef(nullptr);
163
return *this;
164
}
165
166
RefPtr<T>& operator=(const RefPtr<T>& aRhs)
167
// copy assignment operator
168
{
169
assign_with_AddRef(aRhs.mRawPtr);
170
return *this;
171
}
172
173
template <typename I>
174
RefPtr<T>& operator=(const RefPtr<I>& aRhs)
175
// assign from an RefPtr of a related pointer type
176
{
177
assign_with_AddRef(aRhs.get());
178
return *this;
179
}
180
181
RefPtr<T>& operator=(T* aRhs)
182
// assign from a raw pointer (of the right type)
183
{
184
assign_with_AddRef(aRhs);
185
return *this;
186
}
187
188
template <typename I>
189
RefPtr<T>& operator=(already_AddRefed<I>& aRhs)
190
// assign from |already_AddRefed|
191
{
192
assign_assuming_AddRef(aRhs.take());
193
return *this;
194
}
195
196
template <typename I>
197
RefPtr<T>& operator=(already_AddRefed<I>&& aRhs)
198
// assign from |otherRefPtr.forget()|
199
{
200
assign_assuming_AddRef(aRhs.take());
201
return *this;
202
}
203
204
RefPtr<T>& operator=(const nsQueryReferent& aQueryReferent);
205
RefPtr<T>& operator=(const nsCOMPtr_helper& aHelper);
206
#if defined(XP_WIN)
207
RefPtr<T>& operator=(const mozilla::mscom::AgileReference& aAgileRef);
208
#endif // defined(XP_WIN)
209
210
RefPtr<T>& operator=(RefPtr<T>&& aRefPtr) {
211
assign_assuming_AddRef(aRefPtr.forget().take());
212
return *this;
213
}
214
215
// Defined in OwningNonNull.h
216
template <class U>
217
RefPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
218
219
// Defined in StaticLocalPtr.h
220
template <class U>
221
RefPtr<T>& operator=(const mozilla::StaticLocalRefPtr<U>& aOther);
222
223
// Defined in StaticPtr.h
224
template <class U>
225
RefPtr<T>& operator=(const mozilla::StaticRefPtr<U>& aOther);
226
227
// Other pointer operators
228
229
void swap(RefPtr<T>& aRhs)
230
// ...exchange ownership with |aRhs|; can save a pair of refcount operations
231
{
232
T* temp = aRhs.mRawPtr;
233
aRhs.mRawPtr = mRawPtr;
234
mRawPtr = temp;
235
}
236
237
void swap(T*& aRhs)
238
// ...exchange ownership with |aRhs|; can save a pair of refcount operations
239
{
240
T* temp = aRhs;
241
aRhs = mRawPtr;
242
mRawPtr = temp;
243
}
244
245
already_AddRefed<T> MOZ_MAY_CALL_AFTER_MUST_RETURN forget()
246
// return the value of mRawPtr and null out mRawPtr. Useful for
247
// already_AddRefed return values.
248
{
249
T* temp = nullptr;
250
swap(temp);
251
return already_AddRefed<T>(temp);
252
}
253
254
template <typename I>
255
void forget(I** aRhs)
256
// Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
257
// Useful to avoid unnecessary AddRef/Release pairs with "out"
258
// parameters where aRhs bay be a T** or an I** where I is a base class
259
// of T.
260
{
261
MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
262
*aRhs = mRawPtr;
263
mRawPtr = nullptr;
264
}
265
266
void forget(nsISupports** aRhs) {
267
MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
268
*aRhs = ToSupports(mRawPtr);
269
mRawPtr = nullptr;
270
}
271
272
T* get() const
273
/*
274
Prefer the implicit conversion provided automatically by |operator T*()
275
const|. Use |get()| to resolve ambiguity or to get a castable pointer.
276
*/
277
{
278
return const_cast<T*>(mRawPtr);
279
}
280
281
operator T*() const&
282
/*
283
...makes an |RefPtr| act like its underlying raw pointer type whenever it
284
is used in a context where a raw pointer is expected. It is this operator
285
that makes an |RefPtr| substitutable for a raw pointer.
286
287
Prefer the implicit use of this operator to calling |get()|, except where
288
necessary to resolve ambiguity.
289
*/
290
{
291
return get();
292
}
293
294
// Don't allow implicit conversion of temporary RefPtr to raw pointer,
295
// because the refcount might be one and the pointer will immediately become
296
// invalid.
297
operator T*() const&& = delete;
298
299
// These are needed to avoid the deleted operator above. XXX Why is operator!
300
// needed separately? Shouldn't the compiler prefer using the non-deleted
301
// operator bool instead of the deleted operator T*?
302
explicit operator bool() const { return !!mRawPtr; }
303
bool operator!() const { return !mRawPtr; }
304
305
T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
306
MOZ_ASSERT(mRawPtr != nullptr,
307
"You can't dereference a NULL RefPtr with operator->().");
308
return get();
309
}
310
311
template <typename R, typename... Args>
312
class Proxy {
313
typedef R (T::*member_function)(Args...);
314
T* mRawPtr;
315
member_function mFunction;
316
317
public:
318
Proxy(T* aRawPtr, member_function aFunction)
319
: mRawPtr(aRawPtr), mFunction(aFunction) {}
320
template <typename... ActualArgs>
321
R operator()(ActualArgs&&... aArgs) {
322
return ((*mRawPtr).*mFunction)(std::forward<ActualArgs>(aArgs)...);
323
}
324
};
325
326
template <typename R, typename... Args>
327
Proxy<R, Args...> operator->*(R (T::*aFptr)(Args...)) const {
328
MOZ_ASSERT(mRawPtr != nullptr,
329
"You can't dereference a NULL RefPtr with operator->*().");
330
return Proxy<R, Args...>(get(), aFptr);
331
}
332
333
RefPtr<T>* get_address()
334
// This is not intended to be used by clients. See |address_of|
335
// below.
336
{
337
return this;
338
}
339
340
const RefPtr<T>* get_address() const
341
// This is not intended to be used by clients. See |address_of|
342
// below.
343
{
344
return this;
345
}
346
347
public:
348
T& operator*() const {
349
MOZ_ASSERT(mRawPtr != nullptr,
350
"You can't dereference a NULL RefPtr with operator*().");
351
return *get();
352
}
353
354
T** StartAssignment() {
355
assign_assuming_AddRef(nullptr);
356
return reinterpret_cast<T**>(&mRawPtr);
357
}
358
359
private:
360
// This helper class makes |RefPtr<const T>| possible by casting away
361
// the constness from the pointer when calling AddRef() and Release().
362
//
363
// This is necessary because AddRef() and Release() implementations can't
364
// generally expected to be const themselves (without heavy use of |mutable|
365
// and |const_cast| in their own implementations).
366
//
367
// This should be sound because while |RefPtr<const T>| provides a
368
// const view of an object, the object itself should not be const (it
369
// would have to be allocated as |new const T| or similar to be const).
370
template <class U>
371
struct ConstRemovingRefPtrTraits {
372
static void AddRef(U* aPtr) { mozilla::RefPtrTraits<U>::AddRef(aPtr); }
373
static void Release(U* aPtr) { mozilla::RefPtrTraits<U>::Release(aPtr); }
374
};
375
template <class U>
376
struct ConstRemovingRefPtrTraits<const U> {
377
static void AddRef(const U* aPtr) {
378
mozilla::RefPtrTraits<U>::AddRef(const_cast<U*>(aPtr));
379
}
380
static void Release(const U* aPtr) {
381
mozilla::RefPtrTraits<U>::Release(const_cast<U*>(aPtr));
382
}
383
};
384
};
385
386
class nsCycleCollectionTraversalCallback;
387
template <typename T>
388
void CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback,
389
T* aChild, const char* aName, uint32_t aFlags);
390
391
template <typename T>
392
inline void ImplCycleCollectionUnlink(RefPtr<T>& aField) {
393
aField = nullptr;
394
}
395
396
template <typename T>
397
inline void ImplCycleCollectionTraverse(
398
nsCycleCollectionTraversalCallback& aCallback, RefPtr<T>& aField,
399
const char* aName, uint32_t aFlags = 0) {
400
CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
401
}
402
403
template <class T>
404
inline RefPtr<T>* address_of(RefPtr<T>& aPtr) {
405
return aPtr.get_address();
406
}
407
408
template <class T>
409
inline const RefPtr<T>* address_of(const RefPtr<T>& aPtr) {
410
return aPtr.get_address();
411
}
412
413
template <class T>
414
class RefPtrGetterAddRefs
415
/*
416
...
417
418
This class is designed to be used for anonymous temporary objects in the
419
argument list of calls that return COM interface pointers, e.g.,
420
421
RefPtr<IFoo> fooP;
422
...->GetAddRefedPointer(getter_AddRefs(fooP))
423
424
DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
425
426
When initialized with a |RefPtr|, as in the example above, it returns
427
a |void**|, a |T**|, or an |nsISupports**| as needed, that the
428
outer call (|GetAddRefedPointer| in this case) can fill in.
429
430
This type should be a nested class inside |RefPtr<T>|.
431
*/
432
{
433
public:
434
explicit RefPtrGetterAddRefs(RefPtr<T>& aSmartPtr)
435
: mTargetSmartPtr(aSmartPtr) {
436
// nothing else to do
437
}
438
439
operator void**() {
440
return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
441
}
442
443
operator T**() { return mTargetSmartPtr.StartAssignment(); }
444
445
T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
446
447
private:
448
RefPtr<T>& mTargetSmartPtr;
449
};
450
451
template <class T>
452
inline RefPtrGetterAddRefs<T> getter_AddRefs(RefPtr<T>& aSmartPtr)
453
/*
454
Used around a |RefPtr| when
455
...makes the class |RefPtrGetterAddRefs<T>| invisible.
456
*/
457
{
458
return RefPtrGetterAddRefs<T>(aSmartPtr);
459
}
460
461
// Comparing two |RefPtr|s
462
463
template <class T, class U>
464
inline bool operator==(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) {
465
return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
466
}
467
468
template <class T, class U>
469
inline bool operator!=(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) {
470
return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
471
}
472
473
// Comparing an |RefPtr| to a raw pointer
474
475
template <class T, class U>
476
inline bool operator==(const RefPtr<T>& aLhs, const U* aRhs) {
477
return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs);
478
}
479
480
template <class T, class U>
481
inline bool operator==(const U* aLhs, const RefPtr<T>& aRhs) {
482
return static_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
483
}
484
485
template <class T, class U>
486
inline bool operator!=(const RefPtr<T>& aLhs, const U* aRhs) {
487
return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs);
488
}
489
490
template <class T, class U>
491
inline bool operator!=(const U* aLhs, const RefPtr<T>& aRhs) {
492
return static_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
493
}
494
495
template <class T, class U>
496
inline bool operator==(const RefPtr<T>& aLhs, U* aRhs) {
497
return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
498
}
499
500
template <class T, class U>
501
inline bool operator==(U* aLhs, const RefPtr<T>& aRhs) {
502
return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
503
}
504
505
template <class T, class U>
506
inline bool operator!=(const RefPtr<T>& aLhs, U* aRhs) {
507
return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
508
}
509
510
template <class T, class U>
511
inline bool operator!=(U* aLhs, const RefPtr<T>& aRhs) {
512
return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
513
}
514
515
// Comparing an |RefPtr| to |nullptr|
516
517
template <class T>
518
inline bool operator==(const RefPtr<T>& aLhs, decltype(nullptr)) {
519
return aLhs.get() == nullptr;
520
}
521
522
template <class T>
523
inline bool operator==(decltype(nullptr), const RefPtr<T>& aRhs) {
524
return nullptr == aRhs.get();
525
}
526
527
template <class T>
528
inline bool operator!=(const RefPtr<T>& aLhs, decltype(nullptr)) {
529
return aLhs.get() != nullptr;
530
}
531
532
template <class T>
533
inline bool operator!=(decltype(nullptr), const RefPtr<T>& aRhs) {
534
return nullptr != aRhs.get();
535
}
536
537
// MOZ_DBG support
538
539
template <class T>
540
std::ostream& operator<<(std::ostream& aOut, const RefPtr<T>& aObj) {
541
return mozilla::DebugValue(aOut, aObj.get());
542
}
543
544
/*****************************************************************************/
545
546
template <class T>
547
inline already_AddRefed<T> do_AddRef(T* aObj) {
548
RefPtr<T> ref(aObj);
549
return ref.forget();
550
}
551
552
template <class T>
553
inline already_AddRefed<T> do_AddRef(const RefPtr<T>& aObj) {
554
RefPtr<T> ref(aObj);
555
return ref.forget();
556
}
557
558
namespace mozilla {
559
560
/**
561
* Helper function to be able to conveniently write things like:
562
*
563
* already_AddRefed<T>
564
* f(...)
565
* {
566
* return MakeAndAddRef<T>(...);
567
* }
568
*/
569
template <typename T, typename... Args>
570
already_AddRefed<T> MakeAndAddRef(Args&&... aArgs) {
571
RefPtr<T> p(new T(std::forward<Args>(aArgs)...));
572
return p.forget();
573
}
574
575
/**
576
* Helper function to be able to conveniently write things like:
577
*
578
* auto runnable =
579
* MakeRefPtr<ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>>(
580
* mOnSuccess, mOnFailure, *error, mWindowID);
581
*/
582
template <typename T, typename... Args>
583
RefPtr<T> MakeRefPtr(Args&&... aArgs) {
584
RefPtr<T> p(new T(std::forward<Args>(aArgs)...));
585
return p;
586
}
587
588
} // namespace mozilla
589
590
#endif /* mozilla_RefPtr_h */