Line data Source code
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 : {
41 : public:
42 : // In debug builds, check that mRawPtr is initialized for us as we expect
43 : // by the compiler. In non-debug builds, don't declare a constructor
44 : // so that the compiler can see that the constructor is trivial.
45 : #ifdef DEBUG
46 195 : StaticAutoPtr()
47 : {
48 195 : MOZ_ASSERT(!mRawPtr);
49 195 : }
50 : #endif
51 :
52 68 : StaticAutoPtr<T>& operator=(T* aRhs)
53 : {
54 68 : Assign(aRhs);
55 68 : return *this;
56 : }
57 :
58 21372 : T* get() const { return mRawPtr; }
59 :
60 8461 : operator T*() const { return get(); }
61 :
62 11489 : T* operator->() const
63 : {
64 11489 : MOZ_ASSERT(mRawPtr);
65 11489 : return get();
66 : }
67 :
68 1140 : T& operator*() const { return *get(); }
69 :
70 0 : T* forget()
71 : {
72 0 : T* temp = mRawPtr;
73 0 : mRawPtr = nullptr;
74 0 : return temp;
75 : }
76 :
77 : private:
78 : // Disallow copy constructor, but only in debug mode. We only define
79 : // a default constructor in debug mode (see above); if we declared
80 : // this constructor always, the compiler wouldn't generate a trivial
81 : // default constructor for us in non-debug mode.
82 : #ifdef DEBUG
83 : StaticAutoPtr(StaticAutoPtr<T>& aOther);
84 : #endif
85 :
86 68 : void Assign(T* aNewPtr)
87 : {
88 68 : MOZ_ASSERT(!aNewPtr || mRawPtr != aNewPtr);
89 68 : T* oldPtr = mRawPtr;
90 68 : mRawPtr = aNewPtr;
91 57 : delete oldPtr;
92 68 : }
93 :
94 : T* mRawPtr;
95 : };
96 :
97 : template<class T>
98 : class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS StaticRefPtr
99 : {
100 : public:
101 : // In debug builds, check that mRawPtr is initialized for us as we expect
102 : // by the compiler. In non-debug builds, don't declare a constructor
103 : // so that the compiler can see that the constructor is trivial.
104 : #ifdef DEBUG
105 423 : StaticRefPtr()
106 : {
107 423 : MOZ_ASSERT(!mRawPtr);
108 423 : }
109 : #endif
110 :
111 139 : StaticRefPtr<T>& operator=(T* aRhs)
112 : {
113 139 : AssignWithAddref(aRhs);
114 139 : return *this;
115 : }
116 :
117 : StaticRefPtr<T>& operator=(const StaticRefPtr<T>& aRhs)
118 : {
119 : return (this = aRhs.mRawPtr);
120 : }
121 :
122 : StaticRefPtr<T>& operator=(already_AddRefed<T>& aRhs)
123 : {
124 : AssignAssumingAddRef(aRhs.take());
125 : return *this;
126 : }
127 :
128 9 : StaticRefPtr<T>& operator=(already_AddRefed<T>&& aRhs)
129 : {
130 9 : AssignAssumingAddRef(aRhs.take());
131 9 : return *this;
132 : }
133 :
134 : already_AddRefed<T>
135 2 : forget()
136 : {
137 2 : T* temp = mRawPtr;
138 2 : mRawPtr = nullptr;
139 2 : return already_AddRefed<T>(temp);
140 : }
141 :
142 67836 : T* get() const { return mRawPtr; }
143 :
144 41647 : operator T*() const { return get(); }
145 :
146 23456 : T* operator->() const
147 : {
148 23456 : MOZ_ASSERT(mRawPtr);
149 23456 : return get();
150 : }
151 :
152 9 : T& operator*() const { return *get(); }
153 :
154 : private:
155 139 : void AssignWithAddref(T* aNewPtr)
156 : {
157 139 : if (aNewPtr) {
158 122 : aNewPtr->AddRef();
159 : }
160 139 : AssignAssumingAddRef(aNewPtr);
161 139 : }
162 :
163 148 : void AssignAssumingAddRef(T* aNewPtr)
164 : {
165 148 : T* oldPtr = mRawPtr;
166 148 : mRawPtr = aNewPtr;
167 148 : if (oldPtr) {
168 5 : oldPtr->Release();
169 : }
170 148 : }
171 :
172 : T* MOZ_OWNING_REF mRawPtr;
173 : };
174 :
175 : namespace StaticPtr_internal {
176 : class Zero;
177 : } // namespace StaticPtr_internal
178 :
179 : #define REFLEXIVE_EQUALITY_OPERATORS(type1, type2, eq_fn, ...) \
180 : template<__VA_ARGS__> \
181 : inline bool \
182 : operator==(type1 lhs, type2 rhs) \
183 : { \
184 : return eq_fn; \
185 : } \
186 : \
187 : template<__VA_ARGS__> \
188 : inline bool \
189 : operator==(type2 lhs, type1 rhs) \
190 : { \
191 : return rhs == lhs; \
192 : } \
193 : \
194 : template<__VA_ARGS__> \
195 : inline bool \
196 : operator!=(type1 lhs, type2 rhs) \
197 : { \
198 : return !(lhs == rhs); \
199 : } \
200 : \
201 : template<__VA_ARGS__> \
202 : inline bool \
203 : operator!=(type2 lhs, type1 rhs) \
204 : { \
205 : return !(lhs == rhs); \
206 : }
207 :
208 : // StaticAutoPtr (in)equality operators
209 :
210 : template<class T, class U>
211 : inline bool
212 : operator==(const StaticAutoPtr<T>& aLhs, const StaticAutoPtr<U>& aRhs)
213 : {
214 : return aLhs.get() == aRhs.get();
215 : }
216 :
217 : template<class T, class U>
218 : inline bool
219 : operator!=(const StaticAutoPtr<T>& aLhs, const StaticAutoPtr<U>& aRhs)
220 : {
221 : return !(aLhs == aRhs);
222 : }
223 :
224 : REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr<T>&, const U*,
225 : lhs.get() == rhs, class T, class U)
226 :
227 : REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr<T>&, U*,
228 : lhs.get() == rhs, class T, class U)
229 :
230 : // Let us compare StaticAutoPtr to 0.
231 404 : REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr<T>&, StaticPtr_internal::Zero*,
232 : lhs.get() == nullptr, class T)
233 :
234 : // StaticRefPtr (in)equality operators
235 :
236 : template<class T, class U>
237 : inline bool
238 : operator==(const StaticRefPtr<T>& aLhs, const StaticRefPtr<U>& aRhs)
239 : {
240 : return aLhs.get() == aRhs.get();
241 : }
242 :
243 : template<class T, class U>
244 : inline bool
245 : operator!=(const StaticRefPtr<T>& aLhs, const StaticRefPtr<U>& aRhs)
246 : {
247 : return !(aLhs == aRhs);
248 : }
249 :
250 0 : REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr<T>&, const U*,
251 : lhs.get() == rhs, class T, class U)
252 :
253 37 : REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr<T>&, U*,
254 : lhs.get() == rhs, class T, class U)
255 :
256 : // Let us compare StaticRefPtr to 0.
257 314 : REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr<T>&, StaticPtr_internal::Zero*,
258 : lhs.get() == nullptr, class T)
259 :
260 : #undef REFLEXIVE_EQUALITY_OPERATORS
261 :
262 : } // namespace mozilla
263 :
264 : // Declared in mozilla/RefPtr.h
265 : template<class T> template<class U>
266 372 : RefPtr<T>::RefPtr(const mozilla::StaticRefPtr<U>& aOther)
267 372 : : RefPtr(aOther.get())
268 372 : {}
269 :
270 : template<class T> template<class U>
271 : RefPtr<T>&
272 12 : RefPtr<T>::operator=(const mozilla::StaticRefPtr<U>& aOther)
273 : {
274 12 : return operator=(aOther.get());
275 : }
276 :
277 : #endif
|