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