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_StaticPtr_h
8
#define mozilla_StaticPtr_h
9
10
#include "mozilla/AlreadyAddRefed.h"
11
#include "mozilla/Assertions.h"
12
#include "mozilla/Attributes.h"
13
#include "mozilla/RefPtr.h"
14
15
namespace mozilla {
16
17
/**
18
* StaticAutoPtr and StaticRefPtr are like nsAutoPtr and nsRefPtr, except they
19
* are suitable for use as global variables.
20
*
21
* In particular, a global instance of Static{Auto,Ref}Ptr doesn't cause the
22
* compiler to emit a static initializer (in release builds, anyway).
23
*
24
* In order to accomplish this, Static{Auto,Ref}Ptr must have a trivial
25
* constructor and destructor. As a consequence, it cannot initialize its raw
26
* pointer to 0 on construction, and it cannot delete/release its raw pointer
27
* upon destruction.
28
*
29
* Since the compiler guarantees that all global variables are initialized to
30
* 0, these trivial constructors are safe. Since we rely on this, the clang
31
* plugin, run as part of our "static analysis" builds, makes it a compile-time
32
* error to use Static{Auto,Ref}Ptr as anything except a global variable.
33
*
34
* Static{Auto,Ref}Ptr have a limited interface as compared to ns{Auto,Ref}Ptr;
35
* this is intentional, since their range of acceptable uses is smaller.
36
*/
37
38
template <class T>
39
class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS StaticAutoPtr {
40
public:
41
// In debug builds, check that mRawPtr is initialized for us as we expect
42
// by the compiler. In non-debug builds, don't declare a constructor
43
// so that the compiler can see that the constructor is trivial.
44
#ifdef DEBUG
45
StaticAutoPtr() {
46
# ifdef __GNUC__
47
# pragma GCC diagnostic push
48
# pragma GCC diagnostic ignored "-Wuninitialized"
49
// False positive with gcc. See bug 1430729
50
# endif
51
MOZ_ASSERT(!mRawPtr);
52
# ifdef __GNUC__
53
# pragma GCC diagnostic pop
54
# endif
55
}
56
#endif
57
58
StaticAutoPtr<T>& operator=(T* aRhs) {
59
Assign(aRhs);
60
return *this;
61
}
62
63
T* get() const { return mRawPtr; }
64
65
operator T*() const { return get(); }
66
67
T* operator->() const {
68
MOZ_ASSERT(mRawPtr);
69
return get();
70
}
71
72
T& operator*() const { return *get(); }
73
74
T* forget() {
75
T* temp = mRawPtr;
76
mRawPtr = nullptr;
77
return temp;
78
}
79
80
private:
81
// Disallow copy constructor, but only in debug mode. We only define
82
// a default constructor in debug mode (see above); if we declared
83
// this constructor always, the compiler wouldn't generate a trivial
84
// default constructor for us in non-debug mode.
85
#ifdef DEBUG
86
StaticAutoPtr(StaticAutoPtr<T>& aOther);
87
#endif
88
89
void Assign(T* aNewPtr) {
90
MOZ_ASSERT(!aNewPtr || mRawPtr != aNewPtr);
91
T* oldPtr = mRawPtr;
92
mRawPtr = aNewPtr;
93
delete oldPtr;
94
}
95
96
T* mRawPtr;
97
};
98
99
template <class T>
100
class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS StaticRefPtr {
101
public:
102
// In debug builds, check that mRawPtr is initialized for us as we expect
103
// by the compiler. In non-debug builds, don't declare a constructor
104
// so that the compiler can see that the constructor is trivial.
105
#ifdef DEBUG
106
StaticRefPtr() {
107
# ifdef __GNUC__
108
# pragma GCC diagnostic push
109
# pragma GCC diagnostic ignored "-Wuninitialized"
110
// False positive with gcc. See bug 1430729
111
# endif
112
MOZ_ASSERT(!mRawPtr);
113
# ifdef __GNUC__
114
# pragma GCC diagnostic pop
115
# endif
116
}
117
#endif
118
119
StaticRefPtr<T>& operator=(T* aRhs) {
120
AssignWithAddref(aRhs);
121
return *this;
122
}
123
124
StaticRefPtr<T>& operator=(const StaticRefPtr<T>& aRhs) {
125
return (this = aRhs.mRawPtr);
126
}
127
128
StaticRefPtr<T>& operator=(already_AddRefed<T>& aRhs) {
129
AssignAssumingAddRef(aRhs.take());
130
return *this;
131
}
132
133
StaticRefPtr<T>& operator=(already_AddRefed<T>&& aRhs) {
134
AssignAssumingAddRef(aRhs.take());
135
return *this;
136
}
137
138
already_AddRefed<T> forget() {
139
T* temp = mRawPtr;
140
mRawPtr = nullptr;
141
return already_AddRefed<T>(temp);
142
}
143
144
T* get() const { return mRawPtr; }
145
146
operator T*() const { return get(); }
147
148
T* operator->() const {
149
MOZ_ASSERT(mRawPtr);
150
return get();
151
}
152
153
T& operator*() const { return *get(); }
154
155
private:
156
void AssignWithAddref(T* aNewPtr) {
157
if (aNewPtr) {
158
aNewPtr->AddRef();
159
}
160
AssignAssumingAddRef(aNewPtr);
161
}
162
163
void AssignAssumingAddRef(T* aNewPtr) {
164
T* oldPtr = mRawPtr;
165
mRawPtr = aNewPtr;
166
if (oldPtr) {
167
oldPtr->Release();
168
}
169
}
170
171
T* MOZ_OWNING_REF mRawPtr;
172
};
173
174
namespace StaticPtr_internal {
175
class Zero;
176
} // namespace StaticPtr_internal
177
178
#define REFLEXIVE_EQUALITY_OPERATORS(type1, type2, eq_fn, ...) \
179
template <__VA_ARGS__> \
180
inline bool operator==(type1 lhs, type2 rhs) { \
181
return eq_fn; \
182
} \
183
\
184
template <__VA_ARGS__> \
185
inline bool operator==(type2 lhs, type1 rhs) { \
186
return rhs == lhs; \
187
} \
188
\
189
template <__VA_ARGS__> \
190
inline bool operator!=(type1 lhs, type2 rhs) { \
191
return !(lhs == rhs); \
192
} \
193
\
194
template <__VA_ARGS__> \
195
inline bool operator!=(type2 lhs, type1 rhs) { \
196
return !(lhs == rhs); \
197
}
198
199
// StaticAutoPtr (in)equality operators
200
201
template <class T, class U>
202
inline bool operator==(const StaticAutoPtr<T>& aLhs,
203
const StaticAutoPtr<U>& aRhs) {
204
return aLhs.get() == aRhs.get();
205
}
206
207
template <class T, class U>
208
inline bool operator!=(const StaticAutoPtr<T>& aLhs,
209
const StaticAutoPtr<U>& aRhs) {
210
return !(aLhs == aRhs);
211
}
212
213
REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr<T>&, const U*,
214
lhs.get() == rhs, class T, class U)
215
216
REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr<T>&, U*, lhs.get() == rhs,
217
class T, class U)
218
219
// Let us compare StaticAutoPtr to 0.
220
REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr<T>&, StaticPtr_internal::Zero*,
221
lhs.get() == nullptr, class T)
222
223
// StaticRefPtr (in)equality operators
224
225
template <class T, class U>
226
inline bool operator==(const StaticRefPtr<T>& aLhs,
227
const StaticRefPtr<U>& aRhs) {
228
return aLhs.get() == aRhs.get();
229
}
230
231
template <class T, class U>
232
inline bool operator!=(const StaticRefPtr<T>& aLhs,
233
const StaticRefPtr<U>& aRhs) {
234
return !(aLhs == aRhs);
235
}
236
237
REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr<T>&, const U*, lhs.get() == rhs,
238
class T, class U)
239
240
REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr<T>&, U*, lhs.get() == rhs,
241
class T, class U)
242
243
// Let us compare StaticRefPtr to 0.
244
REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr<T>&, StaticPtr_internal::Zero*,
245
lhs.get() == nullptr, class T)
246
247
#undef REFLEXIVE_EQUALITY_OPERATORS
248
249
} // namespace mozilla
250
251
// Declared in mozilla/RefPtr.h
252
template <class T>
253
template <class U>
254
RefPtr<T>::RefPtr(const mozilla::StaticRefPtr<U>& aOther)
255
: RefPtr(aOther.get()) {}
256
257
template <class T>
258
template <class U>
259
RefPtr<T>& RefPtr<T>::operator=(const mozilla::StaticRefPtr<U>& aOther) {
260
return operator=(aOther.get());
261
}
262
263
template <class T>
264
inline already_AddRefed<T> do_AddRef(const mozilla::StaticRefPtr<T>& aObj) {
265
RefPtr<T> ref(aObj);
266
return ref.forget();
267
}
268
269
#endif