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 /* Typed temporary pointers for reference-counted smart pointers. */
8 
9 #ifndef AlreadyAddRefed_h
10 #define AlreadyAddRefed_h
11 
12 #include "mozilla/Assertions.h"
13 #include "mozilla/Attributes.h"
14 #include "mozilla/Move.h"
15 
16 namespace mozilla {
17 
18 struct unused_t;
19 
20 } // namespace mozilla
21 
22 /**
23  * already_AddRefed cooperates with reference counting smart pointers to enable
24  * you to assign in a pointer _without_ |AddRef|ing it.  You might want to use
25  * this as a return type from a function that returns an already |AddRef|ed
26  * pointer.
27  *
28  * TODO Move already_AddRefed to namespace mozilla.  This has not yet been done
29  * because of the sheer number of usages of already_AddRefed.
30  */
31 template<class T>
32 struct MOZ_MUST_USE MOZ_NON_AUTOABLE already_AddRefed
33 {
34   /*
35    * We want to allow returning nullptr from functions returning
36    * already_AddRefed<T>, for simplicity.  But we also don't want to allow
37    * returning raw T*, instead preferring creation of already_AddRefed<T> from
38    * a reference counting smart pointer.
39    *
40    * We address the latter requirement by making the (T*) constructor explicit.
41    * But |return nullptr| won't consider an explicit constructor, so we need
42    * another constructor to handle it.  Plain old (decltype(nullptr)) doesn't
43    * cut it, because if nullptr is emulated as __null (with type int or long),
44    * passing nullptr to an int/long parameter triggers compiler warnings.  We
45    * need a type that no one can pass accidentally; a pointer-to-member-function
46    * (where no such function exists) does the trick nicely.
47    *
48    * That handles the return-value case.  What about for locals, argument types,
49    * and so on?  |already_AddRefed<T>(nullptr)| considers both overloads (and
50    * the (already_AddRefed<T>&&) overload as well!), so there's an ambiguity.
51    * We can target true nullptr using decltype(nullptr), but we can't target
52    * emulated nullptr the same way, because passing __null to an int/long
53    * parameter triggers compiler warnings.  So just give up on this, and provide
54    * this behavior through the default constructor.
55    *
56    * We can revert to simply explicit (T*) and implicit (decltype(nullptr)) when
57    * nullptr no longer needs to be emulated to support the ancient b2g compiler.
58    * (The () overload could also be removed, if desired, if we changed callers.)
59    */
already_AddRefedalready_AddRefed60   already_AddRefed() : mRawPtr(nullptr) {}
61 
62   // The return and argument types here are arbitrarily selected so no
63   // corresponding member function exists.
64   typedef void (already_AddRefed::* MatchNullptr)(double, float);
already_AddRefedalready_AddRefed65   MOZ_IMPLICIT already_AddRefed(MatchNullptr aRawPtr) : mRawPtr(nullptr) {}
66 
already_AddRefedalready_AddRefed67   explicit already_AddRefed(T* aRawPtr) : mRawPtr(aRawPtr) {}
68 
69   // Disallow copy constructor and copy assignment operator: move semantics used instead.
70   already_AddRefed(const already_AddRefed<T>& aOther) = delete;
71   already_AddRefed<T>& operator=(const already_AddRefed<T>& aOther) = delete;
72 
already_AddRefedalready_AddRefed73   already_AddRefed(already_AddRefed<T>&& aOther) : mRawPtr(aOther.take()) {}
74 
75   already_AddRefed<T>& operator=(already_AddRefed<T>&& aOther)
76   {
77     mRawPtr = aOther.take();
78     return *this;
79   }
80 
81   /**
82    * This helper is useful in cases like
83    *
84    *  already_AddRefed<BaseClass>
85    *  Foo()
86    *  {
87    *    RefPtr<SubClass> x = ...;
88    *    return x.forget();
89    *  }
90    *
91    * The autoconversion allows one to omit the idiom
92    *
93    *    RefPtr<BaseClass> y = x.forget();
94    *    return y.forget();
95    *
96    * Note that nsRefPtr is the XPCOM reference counting smart pointer class.
97    */
98   template <typename U>
already_AddRefedalready_AddRefed99   MOZ_IMPLICIT already_AddRefed(already_AddRefed<U>&& aOther) : mRawPtr(aOther.take()) {}
100 
~already_AddRefedalready_AddRefed101   ~already_AddRefed() { MOZ_ASSERT(!mRawPtr); }
102 
103   // Specialize the unused operator<< for already_AddRefed, to allow
104   // nsCOMPtr<nsIFoo> foo;
105   // Unused << foo.forget();
106   // Note that nsCOMPtr is the XPCOM reference counting smart pointer class.
107   friend void operator<<(const mozilla::unused_t& aUnused,
108                          const already_AddRefed<T>& aRhs)
109   {
110     auto mutableAlreadyAddRefed = const_cast<already_AddRefed<T>*>(&aRhs);
111     aUnused << mutableAlreadyAddRefed->take();
112   }
113 
takealready_AddRefed114   MOZ_WARN_UNUSED_RESULT T* take()
115   {
116     T* rawPtr = mRawPtr;
117     mRawPtr = nullptr;
118     return rawPtr;
119   }
120 
121   /**
122    * This helper provides a static_cast replacement for already_AddRefed, so
123    * if you have
124    *
125    *   already_AddRefed<Parent> F();
126    *
127    * you can write
128    *
129    *   already_AddRefed<Child>
130    *   G()
131    *   {
132    *     return F().downcast<Child>();
133    *   }
134    */
135   template<class U>
downcastalready_AddRefed136   already_AddRefed<U> downcast()
137   {
138     U* tmp = static_cast<U*>(mRawPtr);
139     mRawPtr = nullptr;
140     return already_AddRefed<U>(tmp);
141   }
142 
143 private:
144   T* MOZ_OWNING_REF mRawPtr;
145 };
146 
147 #endif // AlreadyAddRefed_h
148