Fix Centurion name.
[0ad.git] / libraries / source / spidermonkey / include-win32-release / mozilla / WeakPtr.h
bloba4e534fc53061a6eb9f3e982f830fb5f4efde9bb
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 /* Weak pointer functionality, implemented as a mixin for use with any class. */
9 /**
10 * SupportsWeakPtr lets you have a pointer to an object 'Foo' without affecting
11 * its lifetime. It works by creating a single shared reference counted object
12 * (WeakReference) that each WeakPtr will access 'Foo' through. This lets 'Foo'
13 * clear the pointer in the WeakReference without having to know about all of
14 * the WeakPtrs to it and allows the WeakReference to live beyond the lifetime
15 * of 'Foo'.
17 * PLEASE NOTE: This weak pointer implementation is not thread-safe.
19 * Note that when deriving from SupportsWeakPtr you should add
20 * MOZ_DECLARE_WEAKREFERENCE_TYPENAME(ClassName) to the public section of your
21 * class, where ClassName is the name of your class.
23 * The overhead of WeakPtr is that accesses to 'Foo' becomes an additional
24 * dereference, and an additional heap allocated pointer sized object shared
25 * between all of the WeakPtrs.
27 * Example of usage:
29 * // To have a class C support weak pointers, inherit from
30 * // SupportsWeakPtr<C>.
31 * class C : public SupportsWeakPtr<C>
32 * {
33 * public:
34 * MOZ_DECLARE_WEAKREFERENCE_TYPENAME(C)
35 * int mNum;
36 * void act();
37 * };
39 * C* ptr = new C();
41 * // Get weak pointers to ptr. The first time a weak pointer
42 * // is obtained, a reference counted WeakReference object is created that
43 * // can live beyond the lifetime of 'ptr'. The WeakReference
44 * // object will be notified of 'ptr's destruction.
45 * WeakPtr<C> weak = ptr;
46 * WeakPtr<C> other = ptr;
48 * // Test a weak pointer for validity before using it.
49 * if (weak) {
50 * weak->mNum = 17;
51 * weak->act();
52 * }
54 * // Destroying the underlying object clears weak pointers to it.
55 * delete ptr;
57 * MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it.");
58 * MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it.");
60 * WeakPtr is typesafe and may be used with any class. It is not required that
61 * the class be reference-counted or allocated in any particular way.
63 * The API was loosely inspired by Chromium's weak_ptr.h:
64 * http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h
67 #ifndef mozilla_WeakPtr_h
68 #define mozilla_WeakPtr_h
70 #include "mozilla/ArrayUtils.h"
71 #include "mozilla/Assertions.h"
72 #include "mozilla/Attributes.h"
73 #include "mozilla/Maybe.h"
74 #include "mozilla/RefCounted.h"
75 #include "mozilla/RefPtr.h"
77 #include <string.h>
78 #include <type_traits>
80 #if defined(MOZILLA_INTERNAL_API)
81 // For thread safety checking.
82 # include "nsISupportsImpl.h"
83 #endif
85 #if defined(MOZILLA_INTERNAL_API) && \
86 defined(MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED)
88 // Weak referencing is not implemeted as thread safe. When a WeakPtr
89 // is created or dereferenced on thread A but the real object is just
90 // being Released() on thread B, there is a possibility of a race
91 // when the proxy object (detail::WeakReference) is notified about
92 // the real object destruction just between when thread A is storing
93 // the object pointer locally and is about to add a reference to it.
95 // Hence, a non-null weak proxy object is considered to have a single
96 // "owning thread". It means that each query for a weak reference,
97 // its dereference, and destruction of the real object must all happen
98 // on a single thread. The following macros implement assertions for
99 // checking these conditions.
101 // We re-use XPCOM's nsAutoOwningThread checks when they are available. This has
102 // the advantage that it works with cooperative thread pools.
104 # define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK \
105 /* Will be none if mPtr = nullptr. */ \
106 Maybe<nsAutoOwningThread> _owningThread;
107 # define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \
108 do { \
109 if (p) { \
110 _owningThread.emplace(); \
112 } while (false)
113 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \
114 do { \
115 if (_owningThread.isSome() && !_owningThread.ref().IsCurrentThread()) { \
116 WeakPtrTraits<T>::AssertSafeToAccessFromNonOwningThread(); \
118 } while (false)
119 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
120 (that)->AssertThreadSafety();
121 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(that) \
122 do { \
123 if (that) { \
124 (that)->AssertThreadSafety(); \
126 } while (false)
128 # define MOZ_WEAKPTR_THREAD_SAFETY_CHECKING 1
130 #else
132 # define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
133 # define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \
134 do { \
135 } while (false)
136 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \
137 do { \
138 } while (false)
139 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
140 do { \
141 } while (false)
142 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(that) \
143 do { \
144 } while (false)
146 #endif
148 namespace mozilla {
150 template <typename T>
151 class WeakPtr;
152 template <typename T>
153 class SupportsWeakPtr;
155 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
156 # define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) \
157 static const char* weakReferenceTypeName() { \
158 return "WeakReference<" #T ">"; \
160 #else
161 # define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T)
162 #endif
164 template <class T>
165 struct WeakPtrTraits {
166 static void AssertSafeToAccessFromNonOwningThread() {
167 MOZ_DIAGNOSTIC_ASSERT(false, "WeakPtr accessed from multiple threads");
171 namespace detail {
173 // This can live beyond the lifetime of the class derived from
174 // SupportsWeakPtr.
175 template <class T>
176 class WeakReference : public ::mozilla::RefCounted<WeakReference<T>> {
177 public:
178 explicit WeakReference(T* p) : mPtr(p) {
179 MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK();
182 T* get() const {
183 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
184 return mPtr;
187 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
188 const char* typeName() const {
189 // The first time this is called mPtr is null, so don't
190 // invoke any methods on mPtr.
191 return T::weakReferenceTypeName();
193 size_t typeSize() const { return sizeof(*this); }
194 #endif
196 #ifdef MOZ_WEAKPTR_THREAD_SAFETY_CHECKING
197 void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); }
198 #endif
200 private:
201 friend class mozilla::SupportsWeakPtr<T>;
203 void detach() {
204 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
205 mPtr = nullptr;
208 T* MOZ_NON_OWNING_REF mPtr;
209 MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
212 } // namespace detail
214 template <typename T>
215 class SupportsWeakPtr {
216 protected:
217 ~SupportsWeakPtr() {
218 static_assert(std::is_base_of<SupportsWeakPtr<T>, T>::value,
219 "T must derive from SupportsWeakPtr<T>");
220 DetachWeakPtr();
223 protected:
224 void DetachWeakPtr() {
225 if (mSelfReferencingWeakPtr) {
226 mSelfReferencingWeakPtr.mRef->detach();
230 private:
231 const WeakPtr<T>& SelfReferencingWeakPtr() {
232 if (!mSelfReferencingWeakPtr) {
233 mSelfReferencingWeakPtr.mRef =
234 new detail::WeakReference<T>(static_cast<T*>(this));
235 } else {
236 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakPtr.mRef);
238 return mSelfReferencingWeakPtr;
241 const WeakPtr<const T>& SelfReferencingWeakPtr() const {
242 const WeakPtr<T>& p =
243 const_cast<SupportsWeakPtr*>(this)->SelfReferencingWeakPtr();
244 return reinterpret_cast<const WeakPtr<const T>&>(p);
247 friend class WeakPtr<T>;
248 friend class WeakPtr<const T>;
250 WeakPtr<T> mSelfReferencingWeakPtr;
253 template <typename T>
254 class WeakPtr {
255 typedef detail::WeakReference<T> WeakReference;
256 using NonConstT = std::remove_const_t<T>;
258 public:
259 WeakPtr& operator=(const WeakPtr& aOther) {
260 // We must make sure the reference we have now is safe to be dereferenced
261 // before we throw it away... (this can be called from a ctor)
262 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef);
263 // ...and make sure the new reference is used on a single thread as well.
264 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(aOther.mRef);
266 mRef = aOther.mRef;
267 return *this;
270 WeakPtr(const WeakPtr& aOther) {
271 // The thread safety check is performed inside of the operator= method.
272 *this = aOther;
275 WeakPtr& operator=(decltype(nullptr)) {
276 // We must make sure the reference we have now is safe to be dereferenced
277 // before we throw it away.
278 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef);
279 if (!mRef || mRef->get()) {
280 // Ensure that mRef is dereferenceable in the uninitialized state.
281 mRef = new WeakReference(nullptr);
283 return *this;
286 WeakPtr& operator=(SupportsWeakPtr<NonConstT> const* aOther) {
287 // We must make sure the reference we have now is safe to be dereferenced
288 // before we throw it away.
289 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef);
290 if (aOther) {
291 *this = aOther->SelfReferencingWeakPtr();
292 } else if (!mRef || mRef->get()) {
293 // Ensure that mRef is dereferenceable in the uninitialized state.
294 mRef = new WeakReference(nullptr);
296 // The thread safety check happens inside SelfReferencingWeakPtr
297 // or is initialized in the WeakReference constructor.
298 return *this;
301 WeakPtr& operator=(SupportsWeakPtr<NonConstT>* aOther) {
302 // We must make sure the reference we have now is safe to be dereferenced
303 // before we throw it away.
304 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef);
305 if (aOther) {
306 *this = aOther->SelfReferencingWeakPtr();
307 } else if (!mRef || mRef->get()) {
308 // Ensure that mRef is dereferenceable in the uninitialized state.
309 mRef = new WeakReference(nullptr);
311 // The thread safety check happens inside SelfReferencingWeakPtr
312 // or is initialized in the WeakReference constructor.
313 return *this;
316 MOZ_IMPLICIT WeakPtr(T* aOther) { *this = aOther; }
318 // Ensure that mRef is dereferenceable in the uninitialized state.
319 WeakPtr() : mRef(new WeakReference(nullptr)) {}
321 operator T*() const { return mRef->get(); }
322 T& operator*() const { return *mRef->get(); }
324 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return mRef->get(); }
326 T* get() const { return mRef->get(); }
328 already_AddRefed<WeakReference> TakeRef() { return mRef.forget(); }
330 ~WeakPtr() {
331 if (mRef) {
332 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef);
336 private:
337 friend class SupportsWeakPtr<T>;
339 explicit WeakPtr(const RefPtr<WeakReference>& aOther) : mRef(aOther) {}
341 RefPtr<WeakReference> mRef;
344 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR tmp->DetachWeakPtr();
346 #define NS_IMPL_CYCLE_COLLECTION_WEAK_PTR(class_, ...) \
347 NS_IMPL_CYCLE_COLLECTION_CLASS(class_) \
348 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(class_) \
349 NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__) \
350 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR \
351 NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
352 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(class_) \
353 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) \
354 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
356 #define NS_IMPL_CYCLE_COLLECTION_WEAK_PTR_INHERITED(class_, super_, ...) \
357 NS_IMPL_CYCLE_COLLECTION_CLASS(class_) \
358 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(class_, super_) \
359 NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__) \
360 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR \
361 NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
362 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(class_, super_) \
363 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) \
364 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
366 } // namespace mozilla
368 #endif /* mozilla_WeakPtr_h */