Bug 1910362 - Create new Nimbus helper r=aaronmt,ohorvath
[gecko.git] / xpcom / base / OwningNonNull.h
blob24c22f8f60707be42fb2d87efda0395998bb8dc0
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
12 #include "nsCOMPtr.h"
13 #include "nsCycleCollectionNoteChild.h"
15 namespace mozilla {
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
22 // RefPtr<T> instead.
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&
27 // implicitly
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
31 // member function
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
37 // builds.
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
50 // proliferate.
51 template <class T>
52 class MOZ_IS_SMARTPTR_TO_REFCOUNTED OwningNonNull {
53 public:
54 using element_type = T;
56 OwningNonNull() = default;
58 MOZ_IMPLICIT OwningNonNull(T& aValue) { init(&aValue); }
60 template <class U>
61 MOZ_IMPLICIT OwningNonNull(already_AddRefed<U>&& aValue) {
62 init(aValue);
65 template <class U>
66 MOZ_IMPLICIT OwningNonNull(RefPtr<U>&& aValue) {
67 init(std::move(aValue));
70 template <class U>
71 MOZ_IMPLICIT OwningNonNull(const OwningNonNull<U>& aValue) {
72 init(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) {
88 init(aValue);
89 return *this;
92 OwningNonNull<T>& operator=(T& aValue) {
93 init(&aValue);
94 return *this;
97 template <class U>
98 OwningNonNull<T>& operator=(already_AddRefed<U>&& aValue) {
99 init(aValue);
100 return *this;
103 template <class U>
104 OwningNonNull<T>& operator=(RefPtr<U>&& aValue) {
105 init(std::move(aValue));
106 return *this;
109 template <class U>
110 OwningNonNull<T>& operator=(const OwningNonNull<U>& aValue) {
111 init(aValue);
112 return *this;
115 // Don't allow assigning nullptr, it makes no sense
116 void operator=(decltype(nullptr)) = delete;
118 T& ref() const {
119 MOZ_ASSERT(mInited);
120 MOZ_ASSERT(mPtr, "OwningNonNull<T> was set to null");
121 return *mPtr;
124 // Make us work with smart pointer helpers that expect a get().
125 T* get() const {
126 MOZ_ASSERT(mInited);
127 MOZ_ASSERT(mPtr, "OwningNonNull<T> was set to null");
128 return mPtr;
131 template <typename U>
132 void swap(U& aOther) {
133 mPtr.swap(aOther);
134 #ifdef DEBUG
135 mInited = mPtr;
136 #endif
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?");
144 return mPtr;
147 private:
148 void unlinkForCC() {
149 #ifdef DEBUG
150 mInited = false;
151 #endif
152 mPtr = nullptr;
155 // Allow ImplCycleCollectionUnlink to call unlinkForCC().
156 template <typename U>
157 friend void ImplCycleCollectionUnlink(OwningNonNull<U>& aField);
159 protected:
160 template <typename U>
161 void init(U&& aValue) {
162 mPtr = std::move(aValue);
163 MOZ_ASSERT(mPtr);
164 #ifdef DEBUG
165 mInited = true;
166 #endif
169 RefPtr<T> mPtr;
170 #ifdef DEBUG
171 bool mInited = false;
172 #endif
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
190 template <class T>
191 template <class U>
192 nsCOMPtr<T>::nsCOMPtr(const mozilla::OwningNonNull<U>& aOther)
193 : nsCOMPtr(aOther.get()) {}
195 template <class T>
196 template <class U>
197 nsCOMPtr<T>& nsCOMPtr<T>::operator=(const mozilla::OwningNonNull<U>& aOther) {
198 return operator=(aOther.get());
201 // Declared in mozilla/RefPtr.h
202 template <class T>
203 template <class U>
204 RefPtr<T>::RefPtr(const mozilla::OwningNonNull<U>& aOther)
205 : RefPtr(aOther.get()) {}
207 template <class T>
208 template <class U>
209 RefPtr<T>& RefPtr<T>::operator=(const mozilla::OwningNonNull<U>& aOther) {
210 return operator=(aOther.get());
213 #endif // mozilla_OwningNonNull_h