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 https://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_StaticLocalPtr_h
8 #define mozilla_StaticLocalPtr_h
10 #include "mozilla/AlreadyAddRefed.h"
11 #include "mozilla/Assertions.h"
12 #include "mozilla/Attributes.h"
13 #include "mozilla/RefPtr.h"
18 * StaticLocalAutoPtr and StaticLocalRefPtr are like UniquePtr and RefPtr,
19 * except they are suitable for use as "magic static" local variables -- that
20 * is, they are able to take advantage of C++11's guarantee of thread safety
21 * during initialization by atomically constructing both the smart pointer
22 * itself as well as the object being pointed to.
24 * A static local instance of StaticLocal{Auto,Ref}Ptr does not cause the
25 * compiler to emit any atexit calls. In order to accomplish this,
26 * StaticLocal{Auto,Ref}Ptr must have a trivial destructor. As a consequence,
27 * it does not delete/release its raw pointer upon destruction.
29 * The clang plugin, run as part of our "static analysis" builds, makes it a
30 * compile-time error to use StaticLocal{Auto,Ref}Ptr as anything except a
31 * static local variable.
33 * StaticLocal{Auto,Ref}Ptr have a limited interface as compared to
34 * ns{Auto,Ref}Ptr; this is intentional, since their range of acceptable uses is
39 class MOZ_STATIC_LOCAL_CLASS StaticLocalAutoPtr final
{
41 explicit StaticLocalAutoPtr(T
* aRawPtr
) : mRawPtr(aRawPtr
) {}
43 StaticLocalAutoPtr(StaticLocalAutoPtr
<T
>&& aOther
) : mRawPtr(aOther
.mRawPtr
) {
44 aOther
.mRawPtr
= nullptr;
47 StaticLocalAutoPtr
<T
>& operator=(T
* aRhs
) {
52 T
* get() const { return mRawPtr
; }
54 operator T
*() const { return get(); }
56 T
* operator->() const {
61 T
& operator*() const { return *get(); }
70 StaticLocalAutoPtr(const StaticLocalAutoPtr
<T
>& aOther
) = delete;
72 // We do not allow assignment as the intention of this class is to only
73 // assign to mRawPtr during construction.
74 StaticLocalAutoPtr
& operator=(const StaticLocalAutoPtr
<T
>& aOther
) = delete;
75 StaticLocalAutoPtr
& operator=(StaticLocalAutoPtr
<T
>&&) = delete;
77 void Assign(T
* aNewPtr
) {
78 MOZ_ASSERT(!aNewPtr
|| mRawPtr
!= aNewPtr
);
88 class MOZ_STATIC_LOCAL_CLASS StaticLocalRefPtr final
{
90 explicit StaticLocalRefPtr(T
* aRawPtr
) : mRawPtr(nullptr) {
91 AssignWithAddref(aRawPtr
);
94 explicit StaticLocalRefPtr(already_AddRefed
<T
>& aPtr
) : mRawPtr(nullptr) {
95 AssignAssumingAddRef(aPtr
.take());
98 explicit StaticLocalRefPtr(already_AddRefed
<T
>&& aPtr
) : mRawPtr(nullptr) {
99 AssignAssumingAddRef(aPtr
.take());
102 StaticLocalRefPtr(const StaticLocalRefPtr
<T
>& aPtr
)
103 : StaticLocalRefPtr(aPtr
.mRawPtr
) {}
105 StaticLocalRefPtr(StaticLocalRefPtr
<T
>&& aPtr
) : mRawPtr(aPtr
.mRawPtr
) {
106 aPtr
.mRawPtr
= nullptr;
109 StaticLocalRefPtr
<T
>& operator=(T
* aRhs
) {
110 AssignWithAddref(aRhs
);
114 already_AddRefed
<T
> forget() {
117 return already_AddRefed
<T
>(temp
);
120 T
* get() const { return mRawPtr
; }
122 operator T
*() const { return get(); }
124 T
* operator->() const {
129 T
& operator*() const { return *get(); }
132 // We do not allow assignment as the intention of this class is to only
133 // assign to mRawPtr during construction.
134 StaticLocalRefPtr
<T
>& operator=(const StaticLocalRefPtr
<T
>& aRhs
) = delete;
135 StaticLocalRefPtr
<T
>& operator=(StaticLocalRefPtr
<T
>&& aRhs
) = delete;
137 void AssignWithAddref(T
* aNewPtr
) {
141 AssignAssumingAddRef(aNewPtr
);
144 void AssignAssumingAddRef(T
* aNewPtr
) {
152 T
* MOZ_OWNING_REF mRawPtr
;
155 namespace StaticLocalPtr_internal
{
157 } // namespace StaticLocalPtr_internal
159 #define REFLEXIVE_EQUALITY_OPERATORS(type1, type2, eq_fn, ...) \
160 template <__VA_ARGS__> \
161 inline bool operator==(type1 lhs, type2 rhs) { \
165 template <__VA_ARGS__> \
166 inline bool operator==(type2 lhs, type1 rhs) { \
170 template <__VA_ARGS__> \
171 inline bool operator!=(type1 lhs, type2 rhs) { \
172 return !(lhs == rhs); \
175 template <__VA_ARGS__> \
176 inline bool operator!=(type2 lhs, type1 rhs) { \
177 return !(lhs == rhs); \
180 // StaticLocalAutoPtr (in)equality operators
182 template <class T
, class U
>
183 inline bool operator==(const StaticLocalAutoPtr
<T
>& aLhs
,
184 const StaticLocalAutoPtr
<U
>& aRhs
) {
185 return aLhs
.get() == aRhs
.get();
188 template <class T
, class U
>
189 inline bool operator!=(const StaticLocalAutoPtr
<T
>& aLhs
,
190 const StaticLocalAutoPtr
<U
>& aRhs
) {
191 return !(aLhs
== aRhs
);
194 REFLEXIVE_EQUALITY_OPERATORS(const StaticLocalAutoPtr
<T
>&, const U
*,
195 lhs
.get() == rhs
, class T
, class U
)
197 REFLEXIVE_EQUALITY_OPERATORS(const StaticLocalAutoPtr
<T
>&, U
*, lhs
.get() == rhs
,
200 // Let us compare StaticLocalAutoPtr to 0.
201 REFLEXIVE_EQUALITY_OPERATORS(const StaticLocalAutoPtr
<T
>&,
202 StaticLocalPtr_internal::Zero
*,
203 lhs
.get() == nullptr, class T
)
205 // StaticLocalRefPtr (in)equality operators
207 template <class T
, class U
>
208 inline bool operator==(const StaticLocalRefPtr
<T
>& aLhs
,
209 const StaticLocalRefPtr
<U
>& aRhs
) {
210 return aLhs
.get() == aRhs
.get();
213 template <class T
, class U
>
214 inline bool operator!=(const StaticLocalRefPtr
<T
>& aLhs
,
215 const StaticLocalRefPtr
<U
>& aRhs
) {
216 return !(aLhs
== aRhs
);
219 REFLEXIVE_EQUALITY_OPERATORS(const StaticLocalRefPtr
<T
>&, const U
*,
220 lhs
.get() == rhs
, class T
, class U
)
222 REFLEXIVE_EQUALITY_OPERATORS(const StaticLocalRefPtr
<T
>&, U
*, lhs
.get() == rhs
,
225 // Let us compare StaticLocalRefPtr to 0.
226 REFLEXIVE_EQUALITY_OPERATORS(const StaticLocalRefPtr
<T
>&,
227 StaticLocalPtr_internal::Zero
*,
228 lhs
.get() == nullptr, class T
)
230 #undef REFLEXIVE_EQUALITY_OPERATORS
232 } // namespace mozilla
234 // Declared in mozilla/RefPtr.h
237 RefPtr
<T
>::RefPtr(const mozilla::StaticLocalRefPtr
<U
>& aOther
)
238 : RefPtr(aOther
.get()) {}
242 RefPtr
<T
>& RefPtr
<T
>::operator=(const mozilla::StaticLocalRefPtr
<U
>& aOther
) {
243 return operator=(aOther
.get());
247 inline already_AddRefed
<T
> do_AddRef(
248 const mozilla::StaticLocalRefPtr
<T
>& aObj
) {
253 #endif // mozilla_StaticLocalPtr_h