forked from mozilla/gecko-dev
-
Notifications
You must be signed in to change notification settings - Fork 1
/
RefPtr.h
210 lines (178 loc) · 5.16 KB
/
RefPtr.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Helpers for defining and using refcounted objects. */
#ifndef mozilla_RefPtr_h
#define mozilla_RefPtr_h
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/Assertions.h"
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
#include "mozilla/RefCounted.h"
#include "mozilla/RefCountType.h"
#include "mozilla/nsRefPtr.h"
#include "mozilla/TypeTraits.h"
#if defined(MOZILLA_INTERNAL_API)
#include "nsXPCOM.h"
#endif
#if defined(MOZILLA_INTERNAL_API) && \
!defined(MOZILLA_XPCOMRT_API) && \
(defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
#define MOZ_REFCOUNTED_LEAK_CHECKING
#endif
namespace mozilla {
template<typename T> class OutParamRef;
template<typename T> OutParamRef<T> getter_AddRefs(RefPtr<T>&);
/**
* RefPtr points to a refcounted thing that has AddRef and Release
* methods to increase/decrease the refcount, respectively. After a
* RefPtr<T> is assigned a T*, the T* can be used through the RefPtr
* as if it were a T*.
*
* A RefPtr can forget its underlying T*, which results in the T*
* being wrapped in a temporary object until the T* is either
* re-adopted from or released by the temporary.
*/
template<typename T>
class RefPtr
{
// To allow them to use unref()
friend class OutParamRef<T>;
struct DontRef {};
public:
RefPtr() : mPtr(0) {}
RefPtr(const RefPtr& aOther) : mPtr(ref(aOther.mPtr)) {}
MOZ_IMPLICIT RefPtr(already_AddRefed<T>& aOther) : mPtr(aOther.take()) {}
MOZ_IMPLICIT RefPtr(already_AddRefed<T>&& aOther) : mPtr(aOther.take()) {}
MOZ_IMPLICIT RefPtr(T* aVal) : mPtr(ref(aVal)) {}
template<typename U>
MOZ_IMPLICIT RefPtr(const RefPtr<U>& aOther) : mPtr(ref(aOther.get())) {}
~RefPtr() { unref(mPtr); }
RefPtr& operator=(const RefPtr& aOther)
{
assign(ref(aOther.mPtr));
return *this;
}
RefPtr& operator=(already_AddRefed<T>& aOther)
{
assign(aOther.take());
return *this;
}
RefPtr& operator=(already_AddRefed<T>&& aOther)
{
assign(aOther.take());
return *this;
}
RefPtr& operator=(T* aVal)
{
assign(ref(aVal));
return *this;
}
template<typename U>
RefPtr& operator=(const RefPtr<U>& aOther)
{
assign(ref(aOther.get()));
return *this;
}
already_AddRefed<T> forget()
{
T* tmp = mPtr;
mPtr = nullptr;
return already_AddRefed<T>(tmp);
}
T* get() const { return mPtr; }
operator T*() const
#ifdef MOZ_HAVE_REF_QUALIFIERS
&
#endif
{ return mPtr; }
T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return mPtr; }
T& operator*() const { return *mPtr; }
#ifdef MOZ_HAVE_REF_QUALIFIERS
// Don't allow implicit conversion of temporary RefPtr to raw pointer, because
// the refcount might be one and the pointer will immediately become invalid.
operator T*() const && = delete;
// Needed to avoid the deleted operator above
explicit operator bool() const { return !!mPtr; }
#endif
private:
void assign(T* aVal)
{
T* tmp = mPtr;
mPtr = aVal;
unref(tmp);
}
T* MOZ_OWNING_REF mPtr;
static MOZ_ALWAYS_INLINE T* ref(T* aVal)
{
if (aVal) {
aVal->AddRef();
}
return aVal;
}
static MOZ_ALWAYS_INLINE void unref(T* aVal)
{
if (aVal) {
aVal->Release();
}
}
};
/**
* OutParamRef is a wrapper that tracks a refcounted pointer passed as
* an outparam argument to a function. OutParamRef implements COM T**
* outparam semantics: this requires the callee to AddRef() the T*
* returned through the T** outparam on behalf of the caller. This
* means the caller (through OutParamRef) must Release() the old
* object contained in the tracked RefPtr. It's OK if the callee
* returns the same T* passed to it through the T** outparam, as long
* as the callee obeys the COM discipline.
*
* Prefer returning already_AddRefed<T> from functions over creating T**
* outparams and passing OutParamRef<T> to T**. Prefer RefPtr<T>*
* outparams over T** outparams.
*/
template<typename T>
class OutParamRef
{
friend OutParamRef getter_AddRefs<T>(RefPtr<T>&);
public:
~OutParamRef()
{
RefPtr<T>::unref(mRefPtr.mPtr);
mRefPtr.mPtr = mTmp;
}
operator T**() { return &mTmp; }
private:
explicit OutParamRef(RefPtr<T>& p) : mRefPtr(p), mTmp(p.get()) {}
RefPtr<T>& mRefPtr;
T* mTmp;
OutParamRef() = delete;
OutParamRef& operator=(const OutParamRef&) = delete;
};
/**
* getter_AddRefs cooperates with OutParamRef to implement COM outparam semantics.
*/
template<typename T>
OutParamRef<T>
getter_AddRefs(RefPtr<T>& aPtr)
{
return OutParamRef<T>(aPtr);
}
} // namespace mozilla
// Declared in nsRefPtr.h
template<class T> template<class U>
nsRefPtr<T>::nsRefPtr(mozilla::RefPtr<U>&& aOther)
: nsRefPtr(aOther.forget())
{
}
template<class T> template<class U>
nsRefPtr<T>&
nsRefPtr<T>::operator=(mozilla::RefPtr<U>&& aOther)
{
assign_assuming_AddRef(aOther.forget().take());
return *this;
}
#endif /* mozilla_RefPtr_h */