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/. */
7 #ifndef mozilla_StaticPtr_h
8 #define mozilla_StaticPtr_h
10 #include "mozilla/AlreadyAddRefed.h"
11 #include "mozilla/Assertions.h"
12 #include "mozilla/Attributes.h"
13 #include "mozilla/RefPtr.h"
18 * StaticAutoPtr and StaticRefPtr are like UniquePtr and RefPtr, except they
19 * are suitable for use as global variables.
21 * In particular, a global instance of Static{Auto,Ref}Ptr doesn't cause the
22 * compiler to emit a static initializer.
24 * Since the compiler guarantees that all global variables are initialized to
25 * 0, the default constexpr constructors will result in no actual code being
26 * generated. Since we rely on this, the clang plugin, run as part of our
27 * "static analysis" builds, makes it a compile-time error to use
28 * Static{Auto,Ref}Ptr as anything except a global variable.
30 * Static{Auto,Ref}Ptr have a limited interface as compared to ns{Auto,Ref}Ptr;
31 * this is intentional, since their range of acceptable uses is smaller.
35 class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS StaticAutoPtr
{
37 constexpr StaticAutoPtr() = default;
38 StaticAutoPtr(const StaticAutoPtr
&) = delete;
40 StaticAutoPtr
<T
>& operator=(T
* aRhs
) {
45 T
* get() const { return mRawPtr
; }
47 operator T
*() const { return get(); }
49 T
* operator->() const {
54 T
& operator*() const { return *get(); }
63 void Assign(T
* aNewPtr
) {
64 MOZ_ASSERT(!aNewPtr
|| mRawPtr
!= aNewPtr
);
74 class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS StaticRefPtr
{
76 constexpr StaticRefPtr() = default;
77 StaticRefPtr(const StaticRefPtr
&) = delete;
79 StaticRefPtr
<T
>& operator=(T
* aRhs
) {
80 AssignWithAddref(aRhs
);
84 StaticRefPtr
<T
>& operator=(const StaticRefPtr
<T
>& aRhs
) {
85 return (this = aRhs
.mRawPtr
);
88 StaticRefPtr
<T
>& operator=(already_AddRefed
<T
>& aRhs
) {
89 AssignAssumingAddRef(aRhs
.take());
94 StaticRefPtr
<T
>& operator=(RefPtr
<U
>&& aRhs
) {
95 AssignAssumingAddRef(aRhs
.forget().take());
99 StaticRefPtr
<T
>& operator=(already_AddRefed
<T
>&& aRhs
) {
100 AssignAssumingAddRef(aRhs
.take());
104 already_AddRefed
<T
> forget() {
107 return already_AddRefed
<T
>(temp
);
110 T
* get() const { return mRawPtr
; }
112 operator T
*() const { return get(); }
114 T
* operator->() const {
119 T
& operator*() const { return *get(); }
122 void AssignWithAddref(T
* aNewPtr
) {
124 RefPtrTraits
<T
>::AddRef(aNewPtr
);
126 AssignAssumingAddRef(aNewPtr
);
129 void AssignAssumingAddRef(T
* aNewPtr
) {
133 RefPtrTraits
<T
>::Release(oldPtr
);
137 T
* MOZ_OWNING_REF mRawPtr
= nullptr;
140 namespace StaticPtr_internal
{
142 } // namespace StaticPtr_internal
144 #define REFLEXIVE_EQUALITY_OPERATORS(type1, type2, eq_fn, ...) \
145 template <__VA_ARGS__> \
146 inline bool operator==(type1 lhs, type2 rhs) { \
150 template <__VA_ARGS__> \
151 inline bool operator==(type2 lhs, type1 rhs) { \
155 template <__VA_ARGS__> \
156 inline bool operator!=(type1 lhs, type2 rhs) { \
157 return !(lhs == rhs); \
160 template <__VA_ARGS__> \
161 inline bool operator!=(type2 lhs, type1 rhs) { \
162 return !(lhs == rhs); \
165 // StaticAutoPtr (in)equality operators
167 template <class T
, class U
>
168 inline bool operator==(const StaticAutoPtr
<T
>& aLhs
,
169 const StaticAutoPtr
<U
>& aRhs
) {
170 return aLhs
.get() == aRhs
.get();
173 template <class T
, class U
>
174 inline bool operator!=(const StaticAutoPtr
<T
>& aLhs
,
175 const StaticAutoPtr
<U
>& aRhs
) {
176 return !(aLhs
== aRhs
);
179 REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr
<T
>&, const U
*,
180 lhs
.get() == rhs
, class T
, class U
)
182 REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr
<T
>&, U
*, lhs
.get() == rhs
,
185 // Let us compare StaticAutoPtr to 0.
186 REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr
<T
>&, StaticPtr_internal::Zero
*,
187 lhs
.get() == nullptr, class T
)
189 // StaticRefPtr (in)equality operators
191 template <class T
, class U
>
192 inline bool operator==(const StaticRefPtr
<T
>& aLhs
,
193 const StaticRefPtr
<U
>& aRhs
) {
194 return aLhs
.get() == aRhs
.get();
197 template <class T
, class U
>
198 inline bool operator!=(const StaticRefPtr
<T
>& aLhs
,
199 const StaticRefPtr
<U
>& aRhs
) {
200 return !(aLhs
== aRhs
);
203 REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr
<T
>&, const U
*, lhs
.get() == rhs
,
206 REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr
<T
>&, U
*, lhs
.get() == rhs
,
209 // Let us compare StaticRefPtr to 0.
210 REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr
<T
>&, StaticPtr_internal::Zero
*,
211 lhs
.get() == nullptr, class T
)
213 #undef REFLEXIVE_EQUALITY_OPERATORS
215 } // namespace mozilla
217 // Declared in mozilla/RefPtr.h
220 RefPtr
<T
>::RefPtr(const mozilla::StaticRefPtr
<U
>& aOther
)
221 : RefPtr(aOther
.get()) {}
225 RefPtr
<T
>& RefPtr
<T
>::operator=(const mozilla::StaticRefPtr
<U
>& aOther
) {
226 return operator=(aOther
.get());
230 inline already_AddRefed
<T
> do_AddRef(const mozilla::StaticRefPtr
<T
>& aObj
) {