| /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
| * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| /* Weak pointer functionality, implemented as a mixin for use with any class. */ |
| |
| /** |
| * SupportsWeakPtr lets you have a pointer to an object 'Foo' without affecting |
| * its lifetime. It works by creating a single shared reference counted object |
| * (WeakReference) that each WeakPtr will access 'Foo' through. This lets 'Foo' |
| * clear the pointer in the WeakReference without having to know about all of |
| * the WeakPtrs to it and allows the WeakReference to live beyond the lifetime |
| * of 'Foo'. |
| * |
| * AtomicSupportsWeakPtr can be used for a variant with an atomically updated |
| * reference counter. |
| * |
| * The overhead of WeakPtr is that accesses to 'Foo' becomes an additional |
| * dereference, and an additional heap allocated pointer sized object shared |
| * between all of the WeakPtrs. |
| * |
| * Example of usage: |
| * |
| * // To have a class C support weak pointers, inherit from SupportsWeakPtr<C>. |
| * class C : public SupportsWeakPtr<C> |
| * { |
| * public: |
| * int num; |
| * void act(); |
| * }; |
| * |
| * C* ptr = new C(); |
| * |
| * // Get weak pointers to ptr. The first time asWeakPtr is called |
| * // a reference counted WeakReference object is created that |
| * // can live beyond the lifetime of 'ptr'. The WeakReference |
| * // object will be notified of 'ptr's destruction. |
| * WeakPtr<C> weak = ptr->asWeakPtr(); |
| * WeakPtr<C> other = ptr->asWeakPtr(); |
| * |
| * // Test a weak pointer for validity before using it. |
| * if (weak) { |
| * weak->num = 17; |
| * weak->act(); |
| * } |
| * |
| * // Destroying the underlying object clears weak pointers to it. |
| * delete ptr; |
| * |
| * MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it."); |
| * MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it."); |
| * |
| * WeakPtr is typesafe and may be used with any class. It is not required that |
| * the class be reference-counted or allocated in any particular way. |
| * |
| * The API was loosely inspired by Chromium's weak_ptr.h: |
| * http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h |
| */ |
| |
| #ifndef mozilla_WeakPtr_h_ |
| #define mozilla_WeakPtr_h_ |
| |
| #include "mozilla/Assertions.h" |
| #include "mozilla/Atomics.h" |
| #include "mozilla/NullPtr.h" |
| #include "mozilla/RefPtr.h" |
| #include "mozilla/TypeTraits.h" |
| |
| namespace mozilla { |
| |
| template <typename T, class WeakReference> class WeakPtrBase; |
| template <typename T, class WeakReference> class SupportsWeakPtrBase; |
| |
| namespace detail { |
| |
| // This can live beyond the lifetime of the class derived from SupportsWeakPtrBase. |
| template<class T, RefCountAtomicity Atomicity> |
| class WeakReference : public RefCounted<WeakReference<T, Atomicity>, Atomicity> |
| { |
| public: |
| explicit WeakReference(T* p) : ptr(p) {} |
| T* get() const { |
| return ptr; |
| } |
| |
| private: |
| friend class WeakPtrBase<T, WeakReference>; |
| friend class SupportsWeakPtrBase<T, WeakReference>; |
| void detach() { |
| ptr = nullptr; |
| } |
| T* ptr; |
| }; |
| |
| } // namespace detail |
| |
| template <typename T, class WeakReference> |
| class SupportsWeakPtrBase |
| { |
| public: |
| WeakPtrBase<T, WeakReference> asWeakPtr() { |
| if (!weakRef) |
| weakRef = new WeakReference(static_cast<T*>(this)); |
| return WeakPtrBase<T, WeakReference>(weakRef); |
| } |
| |
| protected: |
| ~SupportsWeakPtrBase() { |
| MOZ_STATIC_ASSERT((IsBaseOf<SupportsWeakPtrBase<T, WeakReference>, T>::value), |
| "T must derive from SupportsWeakPtrBase<T, WeakReference>"); |
| if (weakRef) |
| weakRef->detach(); |
| } |
| |
| private: |
| friend class WeakPtrBase<T, WeakReference>; |
| |
| RefPtr<WeakReference> weakRef; |
| }; |
| |
| template <typename T> |
| class SupportsWeakPtr |
| : public SupportsWeakPtrBase<T, detail::WeakReference<T, detail::NonAtomicRefCount> > |
| { |
| }; |
| |
| template <typename T> |
| class AtomicSupportsWeakPtr |
| : public SupportsWeakPtrBase<T, detail::WeakReference<T, detail::AtomicRefCount> > |
| { |
| }; |
| |
| namespace detail { |
| |
| template <typename T> |
| struct WeakReferenceCount |
| { |
| static const RefCountAtomicity atomicity = |
| IsBaseOf<AtomicSupportsWeakPtr<T>, T>::value |
| ? AtomicRefCount |
| : NonAtomicRefCount; |
| }; |
| |
| } |
| |
| template <typename T, class WeakReference> |
| class WeakPtrBase |
| { |
| public: |
| WeakPtrBase(const WeakPtrBase<T, WeakReference>& o) : ref(o.ref) {} |
| // Ensure that ref is dereferenceable in the uninitialized state |
| WeakPtrBase() : ref(new WeakReference(nullptr)) {} |
| |
| operator T*() const { |
| return ref->get(); |
| } |
| T& operator*() const { |
| return *ref->get(); |
| } |
| |
| T* operator->() const { |
| return ref->get(); |
| } |
| |
| T* get() const { |
| return ref->get(); |
| } |
| |
| private: |
| friend class SupportsWeakPtrBase<T, WeakReference>; |
| |
| explicit WeakPtrBase(const RefPtr<WeakReference> &o) : ref(o) {} |
| |
| RefPtr<WeakReference> ref; |
| }; |
| |
| template <typename T> |
| class WeakPtr : public WeakPtrBase<T, detail::WeakReference<T, detail::WeakReferenceCount<T>::atomicity> > |
| { |
| typedef WeakPtrBase<T, detail::WeakReference<T, detail::WeakReferenceCount<T>::atomicity> > Base; |
| public: |
| WeakPtr(const WeakPtr<T>& o) : Base(o) {} |
| WeakPtr(const Base& o) : Base(o) {} |
| WeakPtr() {} |
| }; |
| |
| } // namespace mozilla |
| |
| #endif /* ifdef mozilla_WeakPtr_h_ */ |