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