|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef nsHtml5RefPtr_h |
|
7 #define nsHtml5RefPtr_h |
|
8 |
|
9 #include "nsThreadUtils.h" |
|
10 |
|
11 template <class T> |
|
12 class nsHtml5RefPtrReleaser : public nsRunnable |
|
13 { |
|
14 private: |
|
15 T* mPtr; |
|
16 public: |
|
17 nsHtml5RefPtrReleaser(T* aPtr) |
|
18 : mPtr(aPtr) |
|
19 {} |
|
20 NS_IMETHODIMP Run() |
|
21 { |
|
22 mPtr->Release(); |
|
23 return NS_OK; |
|
24 } |
|
25 }; |
|
26 |
|
27 // template <class T> class nsHtml5RefPtrGetterAddRefs; |
|
28 |
|
29 /** |
|
30 * Like nsRefPtr except release is proxied to the main thread. Mostly copied |
|
31 * from nsRefPtr. |
|
32 */ |
|
33 template <class T> |
|
34 class nsHtml5RefPtr |
|
35 { |
|
36 private: |
|
37 |
|
38 void |
|
39 assign_with_AddRef( T* rawPtr ) |
|
40 { |
|
41 if ( rawPtr ) |
|
42 rawPtr->AddRef(); |
|
43 assign_assuming_AddRef(rawPtr); |
|
44 } |
|
45 |
|
46 void** |
|
47 begin_assignment() |
|
48 { |
|
49 assign_assuming_AddRef(0); |
|
50 return reinterpret_cast<void**>(&mRawPtr); |
|
51 } |
|
52 |
|
53 void |
|
54 assign_assuming_AddRef( T* newPtr ) |
|
55 { |
|
56 T* oldPtr = mRawPtr; |
|
57 mRawPtr = newPtr; |
|
58 if ( oldPtr ) |
|
59 release(oldPtr); |
|
60 } |
|
61 |
|
62 void |
|
63 release( T* aPtr ) |
|
64 { |
|
65 nsCOMPtr<nsIRunnable> releaser = new nsHtml5RefPtrReleaser<T>(aPtr); |
|
66 if (NS_FAILED(NS_DispatchToMainThread(releaser))) |
|
67 { |
|
68 NS_WARNING("Failed to dispatch releaser event."); |
|
69 } |
|
70 } |
|
71 |
|
72 private: |
|
73 T* mRawPtr; |
|
74 |
|
75 public: |
|
76 typedef T element_type; |
|
77 |
|
78 ~nsHtml5RefPtr() |
|
79 { |
|
80 if ( mRawPtr ) |
|
81 release(mRawPtr); |
|
82 } |
|
83 |
|
84 // Constructors |
|
85 |
|
86 nsHtml5RefPtr() |
|
87 : mRawPtr(0) |
|
88 // default constructor |
|
89 { |
|
90 } |
|
91 |
|
92 nsHtml5RefPtr( const nsHtml5RefPtr<T>& aSmartPtr ) |
|
93 : mRawPtr(aSmartPtr.mRawPtr) |
|
94 // copy-constructor |
|
95 { |
|
96 if ( mRawPtr ) |
|
97 mRawPtr->AddRef(); |
|
98 } |
|
99 |
|
100 nsHtml5RefPtr( T* aRawPtr ) |
|
101 : mRawPtr(aRawPtr) |
|
102 // construct from a raw pointer (of the right type) |
|
103 { |
|
104 if ( mRawPtr ) |
|
105 mRawPtr->AddRef(); |
|
106 } |
|
107 |
|
108 nsHtml5RefPtr( const already_AddRefed<T>& aSmartPtr ) |
|
109 : mRawPtr(aSmartPtr.mRawPtr) |
|
110 // construct from |dont_AddRef(expr)| |
|
111 { |
|
112 } |
|
113 |
|
114 // Assignment operators |
|
115 |
|
116 nsHtml5RefPtr<T>& |
|
117 operator=( const nsHtml5RefPtr<T>& rhs ) |
|
118 // copy assignment operator |
|
119 { |
|
120 assign_with_AddRef(rhs.mRawPtr); |
|
121 return *this; |
|
122 } |
|
123 |
|
124 nsHtml5RefPtr<T>& |
|
125 operator=( T* rhs ) |
|
126 // assign from a raw pointer (of the right type) |
|
127 { |
|
128 assign_with_AddRef(rhs); |
|
129 return *this; |
|
130 } |
|
131 |
|
132 nsHtml5RefPtr<T>& |
|
133 operator=( const already_AddRefed<T>& rhs ) |
|
134 // assign from |dont_AddRef(expr)| |
|
135 { |
|
136 assign_assuming_AddRef(rhs.mRawPtr); |
|
137 return *this; |
|
138 } |
|
139 |
|
140 // Other pointer operators |
|
141 |
|
142 void |
|
143 swap( nsHtml5RefPtr<T>& rhs ) |
|
144 // ...exchange ownership with |rhs|; can save a pair of refcount operations |
|
145 { |
|
146 T* temp = rhs.mRawPtr; |
|
147 rhs.mRawPtr = mRawPtr; |
|
148 mRawPtr = temp; |
|
149 } |
|
150 |
|
151 void |
|
152 swap( T*& rhs ) |
|
153 // ...exchange ownership with |rhs|; can save a pair of refcount operations |
|
154 { |
|
155 T* temp = rhs; |
|
156 rhs = mRawPtr; |
|
157 mRawPtr = temp; |
|
158 } |
|
159 |
|
160 already_AddRefed<T> |
|
161 forget() |
|
162 // return the value of mRawPtr and null out mRawPtr. Useful for |
|
163 // already_AddRefed return values. |
|
164 { |
|
165 T* temp = 0; |
|
166 swap(temp); |
|
167 return temp; |
|
168 } |
|
169 |
|
170 template <typename I> |
|
171 void |
|
172 forget( I** rhs) |
|
173 // Set the target of rhs to the value of mRawPtr and null out mRawPtr. |
|
174 // Useful to avoid unnecessary AddRef/Release pairs with "out" |
|
175 // parameters where rhs bay be a T** or an I** where I is a base class |
|
176 // of T. |
|
177 { |
|
178 NS_ASSERTION(rhs, "Null pointer passed to forget!"); |
|
179 *rhs = mRawPtr; |
|
180 mRawPtr = 0; |
|
181 } |
|
182 |
|
183 T* |
|
184 get() const |
|
185 /* |
|
186 Prefer the implicit conversion provided automatically by |operator T*() const|. |
|
187 Use |get()| to resolve ambiguity or to get a castable pointer. |
|
188 */ |
|
189 { |
|
190 return const_cast<T*>(mRawPtr); |
|
191 } |
|
192 |
|
193 operator T*() const |
|
194 /* |
|
195 ...makes an |nsHtml5RefPtr| act like its underlying raw pointer type whenever it |
|
196 is used in a context where a raw pointer is expected. It is this operator |
|
197 that makes an |nsHtml5RefPtr| substitutable for a raw pointer. |
|
198 |
|
199 Prefer the implicit use of this operator to calling |get()|, except where |
|
200 necessary to resolve ambiguity. |
|
201 */ |
|
202 { |
|
203 return get(); |
|
204 } |
|
205 |
|
206 T* |
|
207 operator->() const |
|
208 { |
|
209 NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsHtml5RefPtr with operator->()."); |
|
210 return get(); |
|
211 } |
|
212 |
|
213 nsHtml5RefPtr<T>* |
|
214 get_address() |
|
215 // This is not intended to be used by clients. See |address_of| |
|
216 // below. |
|
217 { |
|
218 return this; |
|
219 } |
|
220 |
|
221 const nsHtml5RefPtr<T>* |
|
222 get_address() const |
|
223 // This is not intended to be used by clients. See |address_of| |
|
224 // below. |
|
225 { |
|
226 return this; |
|
227 } |
|
228 |
|
229 public: |
|
230 T& |
|
231 operator*() const |
|
232 { |
|
233 NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsHtml5RefPtr with operator*()."); |
|
234 return *get(); |
|
235 } |
|
236 |
|
237 T** |
|
238 StartAssignment() |
|
239 { |
|
240 #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT |
|
241 return reinterpret_cast<T**>(begin_assignment()); |
|
242 #else |
|
243 assign_assuming_AddRef(0); |
|
244 return reinterpret_cast<T**>(&mRawPtr); |
|
245 #endif |
|
246 } |
|
247 }; |
|
248 |
|
249 template <class T> |
|
250 inline |
|
251 nsHtml5RefPtr<T>* |
|
252 address_of( nsHtml5RefPtr<T>& aPtr ) |
|
253 { |
|
254 return aPtr.get_address(); |
|
255 } |
|
256 |
|
257 template <class T> |
|
258 inline |
|
259 const nsHtml5RefPtr<T>* |
|
260 address_of( const nsHtml5RefPtr<T>& aPtr ) |
|
261 { |
|
262 return aPtr.get_address(); |
|
263 } |
|
264 |
|
265 template <class T> |
|
266 class nsHtml5RefPtrGetterAddRefs |
|
267 /* |
|
268 ... |
|
269 |
|
270 This class is designed to be used for anonymous temporary objects in the |
|
271 argument list of calls that return COM interface pointers, e.g., |
|
272 |
|
273 nsHtml5RefPtr<IFoo> fooP; |
|
274 ...->GetAddRefedPointer(getter_AddRefs(fooP)) |
|
275 |
|
276 DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead. |
|
277 |
|
278 When initialized with a |nsHtml5RefPtr|, as in the example above, it returns |
|
279 a |void**|, a |T**|, or an |nsISupports**| as needed, that the |
|
280 outer call (|GetAddRefedPointer| in this case) can fill in. |
|
281 |
|
282 This type should be a nested class inside |nsHtml5RefPtr<T>|. |
|
283 */ |
|
284 { |
|
285 public: |
|
286 explicit |
|
287 nsHtml5RefPtrGetterAddRefs( nsHtml5RefPtr<T>& aSmartPtr ) |
|
288 : mTargetSmartPtr(aSmartPtr) |
|
289 { |
|
290 // nothing else to do |
|
291 } |
|
292 |
|
293 operator void**() |
|
294 { |
|
295 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment()); |
|
296 } |
|
297 |
|
298 operator T**() |
|
299 { |
|
300 return mTargetSmartPtr.StartAssignment(); |
|
301 } |
|
302 |
|
303 T*& |
|
304 operator*() |
|
305 { |
|
306 return *(mTargetSmartPtr.StartAssignment()); |
|
307 } |
|
308 |
|
309 private: |
|
310 nsHtml5RefPtr<T>& mTargetSmartPtr; |
|
311 }; |
|
312 |
|
313 template <class T> |
|
314 inline |
|
315 nsHtml5RefPtrGetterAddRefs<T> |
|
316 getter_AddRefs( nsHtml5RefPtr<T>& aSmartPtr ) |
|
317 /* |
|
318 Used around a |nsHtml5RefPtr| when |
|
319 ...makes the class |nsHtml5RefPtrGetterAddRefs<T>| invisible. |
|
320 */ |
|
321 { |
|
322 return nsHtml5RefPtrGetterAddRefs<T>(aSmartPtr); |
|
323 } |
|
324 |
|
325 |
|
326 |
|
327 // Comparing two |nsHtml5RefPtr|s |
|
328 |
|
329 template <class T, class U> |
|
330 inline |
|
331 bool |
|
332 operator==( const nsHtml5RefPtr<T>& lhs, const nsHtml5RefPtr<U>& rhs ) |
|
333 { |
|
334 return static_cast<const T*>(lhs.get()) == static_cast<const U*>(rhs.get()); |
|
335 } |
|
336 |
|
337 |
|
338 template <class T, class U> |
|
339 inline |
|
340 bool |
|
341 operator!=( const nsHtml5RefPtr<T>& lhs, const nsHtml5RefPtr<U>& rhs ) |
|
342 { |
|
343 return static_cast<const T*>(lhs.get()) != static_cast<const U*>(rhs.get()); |
|
344 } |
|
345 |
|
346 |
|
347 // Comparing an |nsHtml5RefPtr| to a raw pointer |
|
348 |
|
349 template <class T, class U> |
|
350 inline |
|
351 bool |
|
352 operator==( const nsHtml5RefPtr<T>& lhs, const U* rhs ) |
|
353 { |
|
354 return static_cast<const T*>(lhs.get()) == static_cast<const U*>(rhs); |
|
355 } |
|
356 |
|
357 template <class T, class U> |
|
358 inline |
|
359 bool |
|
360 operator==( const U* lhs, const nsHtml5RefPtr<T>& rhs ) |
|
361 { |
|
362 return static_cast<const U*>(lhs) == static_cast<const T*>(rhs.get()); |
|
363 } |
|
364 |
|
365 template <class T, class U> |
|
366 inline |
|
367 bool |
|
368 operator!=( const nsHtml5RefPtr<T>& lhs, const U* rhs ) |
|
369 { |
|
370 return static_cast<const T*>(lhs.get()) != static_cast<const U*>(rhs); |
|
371 } |
|
372 |
|
373 template <class T, class U> |
|
374 inline |
|
375 bool |
|
376 operator!=( const U* lhs, const nsHtml5RefPtr<T>& rhs ) |
|
377 { |
|
378 return static_cast<const U*>(lhs) != static_cast<const T*>(rhs.get()); |
|
379 } |
|
380 |
|
381 // To avoid ambiguities caused by the presence of builtin |operator==|s |
|
382 // creating a situation where one of the |operator==| defined above |
|
383 // has a better conversion for one argument and the builtin has a |
|
384 // better conversion for the other argument, define additional |
|
385 // |operator==| without the |const| on the raw pointer. |
|
386 // See bug 65664 for details. |
|
387 |
|
388 #ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ |
|
389 template <class T, class U> |
|
390 inline |
|
391 bool |
|
392 operator==( const nsHtml5RefPtr<T>& lhs, U* rhs ) |
|
393 { |
|
394 return static_cast<const T*>(lhs.get()) == const_cast<const U*>(rhs); |
|
395 } |
|
396 |
|
397 template <class T, class U> |
|
398 inline |
|
399 bool |
|
400 operator==( U* lhs, const nsHtml5RefPtr<T>& rhs ) |
|
401 { |
|
402 return const_cast<const U*>(lhs) == static_cast<const T*>(rhs.get()); |
|
403 } |
|
404 |
|
405 template <class T, class U> |
|
406 inline |
|
407 bool |
|
408 operator!=( const nsHtml5RefPtr<T>& lhs, U* rhs ) |
|
409 { |
|
410 return static_cast<const T*>(lhs.get()) != const_cast<const U*>(rhs); |
|
411 } |
|
412 |
|
413 template <class T, class U> |
|
414 inline |
|
415 bool |
|
416 operator!=( U* lhs, const nsHtml5RefPtr<T>& rhs ) |
|
417 { |
|
418 return const_cast<const U*>(lhs) != static_cast<const T*>(rhs.get()); |
|
419 } |
|
420 #endif |
|
421 |
|
422 |
|
423 |
|
424 // Comparing an |nsHtml5RefPtr| to |0| |
|
425 |
|
426 template <class T> |
|
427 inline |
|
428 bool |
|
429 operator==( const nsHtml5RefPtr<T>& lhs, NSCAP_Zero* rhs ) |
|
430 // specifically to allow |smartPtr == 0| |
|
431 { |
|
432 return static_cast<const void*>(lhs.get()) == reinterpret_cast<const void*>(rhs); |
|
433 } |
|
434 |
|
435 template <class T> |
|
436 inline |
|
437 bool |
|
438 operator==( NSCAP_Zero* lhs, const nsHtml5RefPtr<T>& rhs ) |
|
439 // specifically to allow |0 == smartPtr| |
|
440 { |
|
441 return reinterpret_cast<const void*>(lhs) == static_cast<const void*>(rhs.get()); |
|
442 } |
|
443 |
|
444 template <class T> |
|
445 inline |
|
446 bool |
|
447 operator!=( const nsHtml5RefPtr<T>& lhs, NSCAP_Zero* rhs ) |
|
448 // specifically to allow |smartPtr != 0| |
|
449 { |
|
450 return static_cast<const void*>(lhs.get()) != reinterpret_cast<const void*>(rhs); |
|
451 } |
|
452 |
|
453 template <class T> |
|
454 inline |
|
455 bool |
|
456 operator!=( NSCAP_Zero* lhs, const nsHtml5RefPtr<T>& rhs ) |
|
457 // specifically to allow |0 != smartPtr| |
|
458 { |
|
459 return reinterpret_cast<const void*>(lhs) != static_cast<const void*>(rhs.get()); |
|
460 } |
|
461 |
|
462 |
|
463 #ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO |
|
464 |
|
465 // We need to explicitly define comparison operators for `int' |
|
466 // because the compiler is lame. |
|
467 |
|
468 template <class T> |
|
469 inline |
|
470 bool |
|
471 operator==( const nsHtml5RefPtr<T>& lhs, int rhs ) |
|
472 // specifically to allow |smartPtr == 0| |
|
473 { |
|
474 return static_cast<const void*>(lhs.get()) == reinterpret_cast<const void*>(rhs); |
|
475 } |
|
476 |
|
477 template <class T> |
|
478 inline |
|
479 bool |
|
480 operator==( int lhs, const nsHtml5RefPtr<T>& rhs ) |
|
481 // specifically to allow |0 == smartPtr| |
|
482 { |
|
483 return reinterpret_cast<const void*>(lhs) == static_cast<const void*>(rhs.get()); |
|
484 } |
|
485 |
|
486 #endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO) |
|
487 |
|
488 #endif // !defined(nsHtml5RefPtr_h) |