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 mozilla::Runnable
13   {
14     private:
15       T* mPtr;
16     public:
nsHtml5RefPtrReleaser(T * aPtr)17       explicit nsHtml5RefPtrReleaser(T* aPtr)
18           : mPtr(aPtr)
19         {}
Run()20       NS_IMETHOD Run() override
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
assign_with_AddRef(T * rawPtr)39       assign_with_AddRef( T* rawPtr )
40         {
41           if ( rawPtr )
42             rawPtr->AddRef();
43           assign_assuming_AddRef(rawPtr);
44         }
45 
46       void**
begin_assignment()47       begin_assignment()
48         {
49           assign_assuming_AddRef(0);
50           return reinterpret_cast<void**>(&mRawPtr);
51         }
52 
53       void
assign_assuming_AddRef(T * newPtr)54       assign_assuming_AddRef( T* newPtr )
55         {
56           T* oldPtr = mRawPtr;
57           mRawPtr = newPtr;
58           if ( oldPtr )
59             release(oldPtr);
60         }
61 
62       void
release(T * aPtr)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 
~nsHtml5RefPtr()78      ~nsHtml5RefPtr()
79         {
80           if ( mRawPtr )
81             release(mRawPtr);
82         }
83 
84         // Constructors
85 
nsHtml5RefPtr()86       nsHtml5RefPtr()
87             : mRawPtr(0)
88           // default constructor
89         {
90         }
91 
nsHtml5RefPtr(const nsHtml5RefPtr<T> & aSmartPtr)92       nsHtml5RefPtr( const nsHtml5RefPtr<T>& aSmartPtr )
93             : mRawPtr(aSmartPtr.mRawPtr)
94           // copy-constructor
95         {
96           if ( mRawPtr )
97             mRawPtr->AddRef();
98         }
99 
nsHtml5RefPtr(T * aRawPtr)100       explicit 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 
nsHtml5RefPtr(const already_AddRefed<T> & aSmartPtr)108       explicit 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
swap(nsHtml5RefPtr<T> & rhs)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
swap(T * & rhs)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>
forget()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
forget(I ** rhs)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*
get()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 MOZ_NO_ADDREF_RELEASE_ON_RETURN
208         {
209           NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsHtml5RefPtr with operator->().");
210           return get();
211         }
212 
213       nsHtml5RefPtr<T>*
get_address()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>*
get_address()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**
StartAssignment()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>*
address_of(nsHtml5RefPtr<T> & aPtr)252 address_of( nsHtml5RefPtr<T>& aPtr )
253   {
254     return aPtr.get_address();
255   }
256 
257 template <class T>
258 inline
259 const nsHtml5RefPtr<T>*
address_of(const nsHtml5RefPtr<T> & aPtr)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
nsHtml5RefPtrGetterAddRefs(nsHtml5RefPtr<T> & aSmartPtr)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>
getter_AddRefs(nsHtml5RefPtr<T> & aSmartPtr)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 template <class T, class U>
382 inline
383 bool
384 operator==( const nsHtml5RefPtr<T>& lhs, U* rhs )
385   {
386     return static_cast<const T*>(lhs.get()) == const_cast<const U*>(rhs);
387   }
388 
389 template <class T, class U>
390 inline
391 bool
392 operator==( U* lhs, const nsHtml5RefPtr<T>& rhs )
393   {
394     return const_cast<const U*>(lhs) == static_cast<const T*>(rhs.get());
395   }
396 
397 template <class T, class U>
398 inline
399 bool
400 operator!=( const nsHtml5RefPtr<T>& lhs, U* rhs )
401   {
402     return static_cast<const T*>(lhs.get()) != const_cast<const U*>(rhs);
403   }
404 
405 template <class T, class U>
406 inline
407 bool
408 operator!=( U* lhs, const nsHtml5RefPtr<T>& rhs )
409   {
410     return const_cast<const U*>(lhs) != static_cast<const T*>(rhs.get());
411   }
412 
413 
414 
415   // Comparing an |nsHtml5RefPtr| to |0|
416 
417 template <class T>
418 inline
419 bool
420 operator==( const nsHtml5RefPtr<T>& lhs, decltype(nullptr) )
421   {
422     return lhs.get() == nullptr;
423   }
424 
425 template <class T>
426 inline
427 bool
428 operator==( decltype(nullptr), const nsHtml5RefPtr<T>& rhs )
429   {
430     return nullptr == rhs.get();
431   }
432 
433 template <class T>
434 inline
435 bool
436 operator!=( const nsHtml5RefPtr<T>& lhs, decltype(nullptr) )
437   {
438     return lhs.get() != nullptr;
439   }
440 
441 template <class T>
442 inline
443 bool
444 operator!=( decltype(nullptr), const nsHtml5RefPtr<T>& rhs )
445   {
446     return nullptr != rhs.get();
447   }
448 
449 #endif // !defined(nsHtml5RefPtr_h)
450