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