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 /* A class for non-null strong pointers to reference-counted objects. */
9 #ifndef mozilla_OwningNonNull_h
10 #define mozilla_OwningNonNull_h
13 #include "nsCycleCollectionNoteChild.h"
17 // OwningNonNull<T> is similar to a RefPtr<T>, which is not null after initial
18 // initialization. It has a restricted interface compared to RefPtr, with some
19 // additional operations defined. The main use is in DOM bindings. Use it
20 // outside DOM bindings only if you can ensure it never escapes without being
21 // properly initialized, and you don't need to move it. Otherwise, use a
24 // Compared to a plain RefPtr<T>, in particular
25 // - it is copyable but not movable
26 // - it can be constructed and assigned from T& and is convertible to T&
28 // - it cannot be cleared by the user once initialized, though it can be
29 // re-assigned a new (non-null) value
30 // - it is not convertible to bool, but there is an explicit isInitialized
33 // Beware that there are two cases where an OwningNonNull<T> actually is nullptr
34 // - it was default-constructed and not yet initialized
35 // - it was cleared during CC unlinking.
36 // All attempts to use it in an invalid state will trigger an assertion in debug
39 // The original intent of OwningNonNull<T> was to implement a class with the
40 // same auto-conversion and annotation semantics as mozilla::dom::NonNull<T>
41 // (i.e. never null once you have properly initialized it, auto-converts to T&),
42 // but that holds a strong reference to the object involved. This was designed
43 // for use in DOM bindings and in particular for storing what WebIDL represents
44 // as InterfaceName (as opposed to `InterfaceName?`) in various containers
45 // (dictionaries, sequences). DOM bindings never allow a default-constructed
46 // uninitialized OwningNonNull to escape. RefPtr could have been used for this
47 // use case, just like we could have used T* instead of NonNull<T>, but it
48 // seemed desirable to explicitly annotate the non-null nature of the things
49 // involved to eliminate pointless null-checks, which otherwise tend to
52 class MOZ_IS_SMARTPTR_TO_REFCOUNTED OwningNonNull
{
54 using element_type
= T
;
56 OwningNonNull() = default;
58 MOZ_IMPLICIT
OwningNonNull(T
& aValue
) { init(&aValue
); }
61 MOZ_IMPLICIT
OwningNonNull(already_AddRefed
<U
>&& aValue
) {
66 MOZ_IMPLICIT
OwningNonNull(RefPtr
<U
>&& aValue
) {
67 init(std::move(aValue
));
71 MOZ_IMPLICIT
OwningNonNull(const OwningNonNull
<U
>& aValue
) {
75 // This is no worse than get() in terms of const handling.
76 operator T
&() const { return ref(); }
78 operator T
*() const { return get(); }
80 // Conversion to bool is always true, so delete to catch errors
81 explicit operator bool() const = delete;
83 T
* operator->() const { return get(); }
85 T
& operator*() const { return ref(); }
87 OwningNonNull
<T
>& operator=(T
* aValue
) {
92 OwningNonNull
<T
>& operator=(T
& aValue
) {
98 OwningNonNull
<T
>& operator=(already_AddRefed
<U
>&& aValue
) {
104 OwningNonNull
<T
>& operator=(RefPtr
<U
>&& aValue
) {
105 init(std::move(aValue
));
110 OwningNonNull
<T
>& operator=(const OwningNonNull
<U
>& aValue
) {
115 // Don't allow assigning nullptr, it makes no sense
116 void operator=(decltype(nullptr)) = delete;
120 MOZ_ASSERT(mPtr
, "OwningNonNull<T> was set to null");
124 // Make us work with smart pointer helpers that expect a get().
127 MOZ_ASSERT(mPtr
, "OwningNonNull<T> was set to null");
131 template <typename U
>
132 void swap(U
& aOther
) {
139 // We have some consumers who want to check whether we're inited in non-debug
140 // builds as well. Luckily, we have the invariant that we're inited precisely
141 // when mPtr is non-null.
142 bool isInitialized() const {
143 MOZ_ASSERT(!!mPtr
== mInited
, "mInited out of sync with mPtr?");
155 // Allow ImplCycleCollectionUnlink to call unlinkForCC().
156 template <typename U
>
157 friend void ImplCycleCollectionUnlink(OwningNonNull
<U
>& aField
);
160 template <typename U
>
161 void init(U
&& aValue
) {
162 mPtr
= std::move(aValue
);
171 bool mInited
= false;
175 template <typename T
>
176 inline void ImplCycleCollectionUnlink(OwningNonNull
<T
>& aField
) {
177 aField
.unlinkForCC();
180 template <typename T
>
181 inline void ImplCycleCollectionTraverse(
182 nsCycleCollectionTraversalCallback
& aCallback
, OwningNonNull
<T
>& aField
,
183 const char* aName
, uint32_t aFlags
= 0) {
184 CycleCollectionNoteChild(aCallback
, aField
.get(), aName
, aFlags
);
187 } // namespace mozilla
189 // Declared in nsCOMPtr.h
192 nsCOMPtr
<T
>::nsCOMPtr(const mozilla::OwningNonNull
<U
>& aOther
)
193 : nsCOMPtr(aOther
.get()) {}
197 nsCOMPtr
<T
>& nsCOMPtr
<T
>::operator=(const mozilla::OwningNonNull
<U
>& aOther
) {
198 return operator=(aOther
.get());
201 // Declared in mozilla/RefPtr.h
204 RefPtr
<T
>::RefPtr(const mozilla::OwningNonNull
<U
>& aOther
)
205 : RefPtr(aOther
.get()) {}
209 RefPtr
<T
>& RefPtr
<T
>::operator=(const mozilla::OwningNonNull
<U
>& aOther
) {
210 return operator=(aOther
.get());
213 #endif // mozilla_OwningNonNull_h