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_RefPtr_h
8 : #define mozilla_RefPtr_h
9 :
10 : #include "mozilla/AlreadyAddRefed.h"
11 : #include "mozilla/Assertions.h"
12 : #include "mozilla/Attributes.h"
13 :
14 : /*****************************************************************************/
15 :
16 : // template <class T> class RefPtrGetterAddRefs;
17 :
18 : class nsCOMPtr_helper;
19 :
20 : namespace mozilla {
21 : template<class T> class OwningNonNull;
22 : template<class T> class StaticRefPtr;
23 :
24 : // Traditionally, RefPtr supports automatic refcounting of any pointer type
25 : // with AddRef() and Release() methods that follow the traditional semantics.
26 : //
27 : // This traits class can be specialized to operate on other pointer types. For
28 : // example, we specialize this trait for opaque FFI types that represent
29 : // refcounted objects in Rust.
30 : //
31 : // Given the use of ConstRemovingRefPtrTraits below, U should not be a const-
32 : // qualified type.
33 : template<class U>
34 : struct RefPtrTraits
35 : {
36 297736 : static void AddRef(U* aPtr) {
37 297736 : aPtr->AddRef();
38 297737 : }
39 260968 : static void Release(U* aPtr) {
40 260968 : aPtr->Release();
41 260968 : }
42 : };
43 :
44 : } // namespace mozilla
45 :
46 : template <class T>
47 : class RefPtr
48 : {
49 : private:
50 : void
51 135724 : assign_with_AddRef(T* aRawPtr)
52 : {
53 135724 : if (aRawPtr) {
54 121409 : ConstRemovingRefPtrTraits<T>::AddRef(aRawPtr);
55 : }
56 135724 : assign_assuming_AddRef(aRawPtr);
57 135724 : }
58 :
59 : void
60 250165 : assign_assuming_AddRef(T* aNewPtr)
61 : {
62 250165 : T* oldPtr = mRawPtr;
63 250165 : mRawPtr = aNewPtr;
64 250165 : if (oldPtr) {
65 16685 : ConstRemovingRefPtrTraits<T>::Release(oldPtr);
66 : }
67 250165 : }
68 :
69 : private:
70 : T* MOZ_OWNING_REF mRawPtr;
71 :
72 : public:
73 : typedef T element_type;
74 :
75 534297 : ~RefPtr()
76 : {
77 534297 : if (mRawPtr) {
78 244274 : ConstRemovingRefPtrTraits<T>::Release(mRawPtr);
79 : }
80 534297 : }
81 :
82 : // Constructors
83 :
84 289289 : RefPtr()
85 289289 : : mRawPtr(nullptr)
86 : // default constructor
87 : {
88 289289 : }
89 :
90 19180 : RefPtr(const RefPtr<T>& aSmartPtr)
91 19180 : : mRawPtr(aSmartPtr.mRawPtr)
92 : // copy-constructor
93 : {
94 19180 : if (mRawPtr) {
95 13233 : ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
96 : }
97 19180 : }
98 :
99 3032 : RefPtr(RefPtr<T>&& aRefPtr)
100 3032 : : mRawPtr(aRefPtr.mRawPtr)
101 : {
102 3032 : aRefPtr.mRawPtr = nullptr;
103 3032 : }
104 :
105 : // construct from a raw pointer (of the right type)
106 :
107 186420 : MOZ_IMPLICIT RefPtr(T* aRawPtr)
108 186420 : : mRawPtr(aRawPtr)
109 : {
110 186420 : if (mRawPtr) {
111 162479 : ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
112 : }
113 186420 : }
114 :
115 12748 : MOZ_IMPLICIT RefPtr(decltype(nullptr))
116 12748 : : mRawPtr(nullptr)
117 : {
118 12748 : }
119 :
120 : template <typename I>
121 11887 : MOZ_IMPLICIT RefPtr(already_AddRefed<I>& aSmartPtr)
122 11887 : : mRawPtr(aSmartPtr.take())
123 : // construct from |already_AddRefed|
124 : {
125 11887 : }
126 :
127 : template <typename I>
128 54162 : MOZ_IMPLICIT RefPtr(already_AddRefed<I>&& aSmartPtr)
129 54162 : : mRawPtr(aSmartPtr.take())
130 : // construct from |otherRefPtr.forget()|
131 : {
132 54162 : }
133 :
134 : template <typename I>
135 603 : MOZ_IMPLICIT RefPtr(const RefPtr<I>& aSmartPtr)
136 603 : : mRawPtr(aSmartPtr.get())
137 : // copy-construct from a smart pointer with a related pointer type
138 : {
139 603 : if (mRawPtr) {
140 603 : ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
141 : }
142 603 : }
143 :
144 : template <typename I>
145 2 : MOZ_IMPLICIT RefPtr(RefPtr<I>&& aSmartPtr)
146 2 : : mRawPtr(aSmartPtr.forget().take())
147 : // construct from |Move(RefPtr<SomeSubclassOfT>)|.
148 : {
149 2 : }
150 :
151 : MOZ_IMPLICIT RefPtr(const nsCOMPtr_helper& aHelper);
152 :
153 : // Defined in OwningNonNull.h
154 : template<class U>
155 : MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull<U>& aOther);
156 :
157 : // Defined in StaticPtr.h
158 : template<class U>
159 : MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr<U>& aOther);
160 :
161 : // Assignment operators
162 :
163 : RefPtr<T>&
164 49067 : operator=(decltype(nullptr))
165 : {
166 49067 : assign_assuming_AddRef(nullptr);
167 49067 : return *this;
168 : }
169 :
170 : RefPtr<T>&
171 7094 : operator=(const RefPtr<T>& aRhs)
172 : // copy assignment operator
173 : {
174 7094 : assign_with_AddRef(aRhs.mRawPtr);
175 7094 : return *this;
176 : }
177 :
178 : template <typename I>
179 : RefPtr<T>&
180 1514 : operator=(const RefPtr<I>& aRhs)
181 : // assign from an RefPtr of a related pointer type
182 : {
183 1514 : assign_with_AddRef(aRhs.get());
184 1514 : return *this;
185 : }
186 :
187 : RefPtr<T>&
188 127117 : operator=(T* aRhs)
189 : // assign from a raw pointer (of the right type)
190 : {
191 127117 : assign_with_AddRef(aRhs);
192 127117 : return *this;
193 : }
194 :
195 : template <typename I>
196 : RefPtr<T>&
197 2861 : operator=(already_AddRefed<I>& aRhs)
198 : // assign from |already_AddRefed|
199 : {
200 2861 : assign_assuming_AddRef(aRhs.take());
201 2861 : return *this;
202 : }
203 :
204 : template <typename I>
205 : RefPtr<T>&
206 32093 : operator=(already_AddRefed<I> && aRhs)
207 : // assign from |otherRefPtr.forget()|
208 : {
209 32093 : assign_assuming_AddRef(aRhs.take());
210 32093 : return *this;
211 : }
212 :
213 : RefPtr<T>& operator=(const nsCOMPtr_helper& aHelper);
214 :
215 : RefPtr<T>&
216 117 : operator=(RefPtr<T> && aRefPtr)
217 : {
218 117 : assign_assuming_AddRef(aRefPtr.mRawPtr);
219 117 : aRefPtr.mRawPtr = nullptr;
220 117 : return *this;
221 : }
222 :
223 : // Defined in OwningNonNull.h
224 : template<class U>
225 : RefPtr<T>&
226 : operator=(const mozilla::OwningNonNull<U>& aOther);
227 :
228 : // Defined in StaticPtr.h
229 : template<class U>
230 : RefPtr<T>&
231 : operator=(const mozilla::StaticRefPtr<U>& aOther);
232 :
233 : // Other pointer operators
234 :
235 : void
236 298 : swap(RefPtr<T>& aRhs)
237 : // ...exchange ownership with |aRhs|; can save a pair of refcount operations
238 : {
239 298 : T* temp = aRhs.mRawPtr;
240 298 : aRhs.mRawPtr = mRawPtr;
241 298 : mRawPtr = temp;
242 298 : }
243 :
244 : void
245 107147 : swap(T*& aRhs)
246 : // ...exchange ownership with |aRhs|; can save a pair of refcount operations
247 : {
248 107147 : T* temp = aRhs;
249 107147 : aRhs = mRawPtr;
250 107147 : mRawPtr = temp;
251 107147 : }
252 :
253 : already_AddRefed<T>
254 : MOZ_MAY_CALL_AFTER_MUST_RETURN
255 106625 : forget()
256 : // return the value of mRawPtr and null out mRawPtr. Useful for
257 : // already_AddRefed return values.
258 : {
259 106625 : T* temp = nullptr;
260 106625 : swap(temp);
261 106625 : return already_AddRefed<T>(temp);
262 : }
263 :
264 : template <typename I>
265 : void
266 35207 : forget(I** aRhs)
267 : // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
268 : // Useful to avoid unnecessary AddRef/Release pairs with "out"
269 : // parameters where aRhs bay be a T** or an I** where I is a base class
270 : // of T.
271 : {
272 35207 : MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
273 35207 : *aRhs = mRawPtr;
274 35207 : mRawPtr = nullptr;
275 35207 : }
276 :
277 : T*
278 2272618 : get() const
279 : /*
280 : Prefer the implicit conversion provided automatically by |operator T*() const|.
281 : Use |get()| to resolve ambiguity or to get a castable pointer.
282 : */
283 : {
284 2272618 : return const_cast<T*>(mRawPtr);
285 : }
286 :
287 1006518 : operator T*() const &
288 : /*
289 : ...makes an |RefPtr| act like its underlying raw pointer type whenever it
290 : is used in a context where a raw pointer is expected. It is this operator
291 : that makes an |RefPtr| substitutable for a raw pointer.
292 :
293 : Prefer the implicit use of this operator to calling |get()|, except where
294 : necessary to resolve ambiguity.
295 : */
296 : {
297 1006518 : return get();
298 : }
299 :
300 : // Don't allow implicit conversion of temporary RefPtr to raw pointer,
301 : // because the refcount might be one and the pointer will immediately become
302 : // invalid.
303 : operator T*() const && = delete;
304 :
305 : // These are needed to avoid the deleted operator above. XXX Why is operator!
306 : // needed separately? Shouldn't the compiler prefer using the non-deleted
307 : // operator bool instead of the deleted operator T*?
308 228520 : explicit operator bool() const { return !!mRawPtr; }
309 699073 : bool operator!() const { return !mRawPtr; }
310 :
311 : T*
312 981679 : operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
313 : {
314 981679 : MOZ_ASSERT(mRawPtr != nullptr,
315 : "You can't dereference a NULL RefPtr with operator->().");
316 981679 : return get();
317 : }
318 :
319 : template <typename R, typename... Args>
320 : class Proxy
321 : {
322 : typedef R (T::*member_function)(Args...);
323 : T* mRawPtr;
324 : member_function mFunction;
325 : public:
326 16 : Proxy(T* aRawPtr, member_function aFunction)
327 : : mRawPtr(aRawPtr),
328 16 : mFunction(aFunction)
329 : {
330 16 : }
331 : template<typename... ActualArgs>
332 16 : R operator()(ActualArgs&&... aArgs)
333 : {
334 16 : return ((*mRawPtr).*mFunction)(mozilla::Forward<ActualArgs>(aArgs)...);
335 : }
336 : };
337 :
338 : template <typename R, typename... Args>
339 16 : Proxy<R, Args...> operator->*(R (T::*aFptr)(Args...)) const
340 : {
341 16 : MOZ_ASSERT(mRawPtr != nullptr,
342 : "You can't dereference a NULL RefPtr with operator->*().");
343 16 : return Proxy<R, Args...>(get(), aFptr);
344 : }
345 :
346 : RefPtr<T>*
347 0 : get_address()
348 : // This is not intended to be used by clients. See |address_of|
349 : // below.
350 : {
351 0 : return this;
352 : }
353 :
354 : const RefPtr<T>*
355 : get_address() const
356 : // This is not intended to be used by clients. See |address_of|
357 : // below.
358 : {
359 : return this;
360 : }
361 :
362 : public:
363 : T&
364 3348 : operator*() const
365 : {
366 3348 : MOZ_ASSERT(mRawPtr != nullptr,
367 : "You can't dereference a NULL RefPtr with operator*().");
368 3348 : return *get();
369 : }
370 :
371 : T**
372 30284 : StartAssignment()
373 : {
374 30284 : assign_assuming_AddRef(nullptr);
375 30284 : return reinterpret_cast<T**>(&mRawPtr);
376 : }
377 : private:
378 : // This helper class makes |RefPtr<const T>| possible by casting away
379 : // the constness from the pointer when calling AddRef() and Release().
380 : //
381 : // This is necessary because AddRef() and Release() implementations can't
382 : // generally expected to be const themselves (without heavy use of |mutable|
383 : // and |const_cast| in their own implementations).
384 : //
385 : // This should be sound because while |RefPtr<const T>| provides a
386 : // const view of an object, the object itself should not be const (it
387 : // would have to be allocated as |new const T| or similar to be const).
388 : template<class U>
389 : struct ConstRemovingRefPtrTraits
390 : {
391 297736 : static void AddRef(U* aPtr) {
392 297736 : mozilla::RefPtrTraits<U>::AddRef(aPtr);
393 297737 : }
394 260968 : static void Release(U* aPtr) {
395 260968 : mozilla::RefPtrTraits<U>::Release(aPtr);
396 260968 : }
397 : };
398 : template<class U>
399 : struct ConstRemovingRefPtrTraits<const U>
400 : {
401 0 : static void AddRef(const U* aPtr) {
402 0 : mozilla::RefPtrTraits<U>::AddRef(const_cast<U*>(aPtr));
403 0 : }
404 0 : static void Release(const U* aPtr) {
405 0 : mozilla::RefPtrTraits<U>::Release(const_cast<U*>(aPtr));
406 0 : }
407 : };
408 : };
409 :
410 : class nsCycleCollectionTraversalCallback;
411 : template <typename T>
412 : void
413 : CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback,
414 : T* aChild, const char* aName, uint32_t aFlags);
415 :
416 : template <typename T>
417 : inline void
418 2 : ImplCycleCollectionUnlink(RefPtr<T>& aField)
419 : {
420 2 : aField = nullptr;
421 2 : }
422 :
423 : template <typename T>
424 : inline void
425 919 : ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
426 : RefPtr<T>& aField,
427 : const char* aName,
428 : uint32_t aFlags = 0)
429 : {
430 919 : CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
431 919 : }
432 :
433 : template <class T>
434 : inline RefPtr<T>*
435 0 : address_of(RefPtr<T>& aPtr)
436 : {
437 0 : return aPtr.get_address();
438 : }
439 :
440 : template <class T>
441 : inline const RefPtr<T>*
442 : address_of(const RefPtr<T>& aPtr)
443 : {
444 : return aPtr.get_address();
445 : }
446 :
447 : template <class T>
448 : class RefPtrGetterAddRefs
449 : /*
450 : ...
451 :
452 : This class is designed to be used for anonymous temporary objects in the
453 : argument list of calls that return COM interface pointers, e.g.,
454 :
455 : RefPtr<IFoo> fooP;
456 : ...->GetAddRefedPointer(getter_AddRefs(fooP))
457 :
458 : DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
459 :
460 : When initialized with a |RefPtr|, as in the example above, it returns
461 : a |void**|, a |T**|, or an |nsISupports**| as needed, that the
462 : outer call (|GetAddRefedPointer| in this case) can fill in.
463 :
464 : This type should be a nested class inside |RefPtr<T>|.
465 : */
466 : {
467 : public:
468 : explicit
469 30284 : RefPtrGetterAddRefs(RefPtr<T>& aSmartPtr)
470 30284 : : mTargetSmartPtr(aSmartPtr)
471 : {
472 : // nothing else to do
473 30284 : }
474 :
475 9697 : operator void**()
476 : {
477 9697 : return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
478 : }
479 :
480 20589 : operator T**()
481 : {
482 20589 : return mTargetSmartPtr.StartAssignment();
483 : }
484 :
485 : T*&
486 : operator*()
487 : {
488 : return *(mTargetSmartPtr.StartAssignment());
489 : }
490 :
491 : private:
492 : RefPtr<T>& mTargetSmartPtr;
493 : };
494 :
495 : template <class T>
496 : inline RefPtrGetterAddRefs<T>
497 30286 : getter_AddRefs(RefPtr<T>& aSmartPtr)
498 : /*
499 : Used around a |RefPtr| when
500 : ...makes the class |RefPtrGetterAddRefs<T>| invisible.
501 : */
502 : {
503 30286 : return RefPtrGetterAddRefs<T>(aSmartPtr);
504 : }
505 :
506 :
507 : // Comparing two |RefPtr|s
508 :
509 : template <class T, class U>
510 : inline bool
511 4790 : operator==(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs)
512 : {
513 4790 : return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
514 : }
515 :
516 :
517 : template <class T, class U>
518 : inline bool
519 3956 : operator!=(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs)
520 : {
521 3956 : return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
522 : }
523 :
524 :
525 : // Comparing an |RefPtr| to a raw pointer
526 :
527 : template <class T, class U>
528 : inline bool
529 61 : operator==(const RefPtr<T>& aLhs, const U* aRhs)
530 : {
531 61 : return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs);
532 : }
533 :
534 : template <class T, class U>
535 : inline bool
536 571 : operator==(const U* aLhs, const RefPtr<T>& aRhs)
537 : {
538 571 : return static_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
539 : }
540 :
541 : template <class T, class U>
542 : inline bool
543 : operator!=(const RefPtr<T>& aLhs, const U* aRhs)
544 : {
545 : return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs);
546 : }
547 :
548 : template <class T, class U>
549 : inline bool
550 0 : operator!=(const U* aLhs, const RefPtr<T>& aRhs)
551 : {
552 0 : return static_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
553 : }
554 :
555 : template <class T, class U>
556 : inline bool
557 8387 : operator==(const RefPtr<T>& aLhs, U* aRhs)
558 : {
559 8387 : return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
560 : }
561 :
562 : template <class T, class U>
563 : inline bool
564 3571 : operator==(U* aLhs, const RefPtr<T>& aRhs)
565 : {
566 3571 : return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
567 : }
568 :
569 : template <class T, class U>
570 : inline bool
571 3590 : operator!=(const RefPtr<T>& aLhs, U* aRhs)
572 : {
573 3590 : return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
574 : }
575 :
576 : template <class T, class U>
577 : inline bool
578 25263 : operator!=(U* aLhs, const RefPtr<T>& aRhs)
579 : {
580 25263 : return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
581 : }
582 :
583 : // Comparing an |RefPtr| to |nullptr|
584 :
585 : template <class T>
586 : inline bool
587 184924 : operator==(const RefPtr<T>& aLhs, decltype(nullptr))
588 : {
589 184924 : return aLhs.get() == nullptr;
590 : }
591 :
592 : template <class T>
593 : inline bool
594 2988 : operator==(decltype(nullptr), const RefPtr<T>& aRhs)
595 : {
596 2988 : return nullptr == aRhs.get();
597 : }
598 :
599 : template <class T>
600 : inline bool
601 6671 : operator!=(const RefPtr<T>& aLhs, decltype(nullptr))
602 : {
603 6671 : return aLhs.get() != nullptr;
604 : }
605 :
606 : template <class T>
607 : inline bool
608 28 : operator!=(decltype(nullptr), const RefPtr<T>& aRhs)
609 : {
610 28 : return nullptr != aRhs.get();
611 : }
612 :
613 : /*****************************************************************************/
614 :
615 : template <class T>
616 : inline already_AddRefed<T>
617 3568 : do_AddRef(T* aObj)
618 : {
619 7136 : RefPtr<T> ref(aObj);
620 7136 : return ref.forget();
621 : }
622 :
623 : template <class T>
624 : inline already_AddRefed<T>
625 99 : do_AddRef(const RefPtr<T>& aObj)
626 : {
627 198 : RefPtr<T> ref(aObj);
628 198 : return ref.forget();
629 : }
630 :
631 : namespace mozilla {
632 :
633 : /**
634 : * Helper function to be able to conveniently write things like:
635 : *
636 : * already_AddRefed<T>
637 : * f(...)
638 : * {
639 : * return MakeAndAddRef<T>(...);
640 : * }
641 : */
642 : template<typename T, typename... Args>
643 : already_AddRefed<T>
644 315 : MakeAndAddRef(Args&&... aArgs)
645 : {
646 945 : RefPtr<T> p(new T(Forward<Args>(aArgs)...));
647 630 : return p.forget();
648 : }
649 :
650 : /**
651 : * Helper function to be able to conveniently write things like:
652 : *
653 : * auto runnable = MakeRefPtr<ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>>(
654 : * mOnSuccess, mOnFailure, *error, mWindowID);
655 : */
656 : template<typename T, typename... Args>
657 : RefPtr<T>
658 0 : MakeRefPtr(Args&&... aArgs)
659 : {
660 0 : RefPtr<T> p(new T(Forward<Args>(aArgs)...));
661 0 : return p;
662 : }
663 :
664 : } // namespace mozilla
665 :
666 : #endif /* mozilla_RefPtr_h */
|