diff options
Diffstat (limited to 'layout/base/ArenaRefPtr.h')
-rw-r--r-- | layout/base/ArenaRefPtr.h | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/layout/base/ArenaRefPtr.h b/layout/base/ArenaRefPtr.h new file mode 100644 index 000000000..bc8ecaa70 --- /dev/null +++ b/layout/base/ArenaRefPtr.h @@ -0,0 +1,167 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=2 sw=2 et tw=78: + * 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/. + */ + +/* smart pointer for strong references to nsPresArena-allocated objects + that might be held onto until the arena's destruction */ + +#include "mozilla/Assertions.h" +#include "mozilla/RefPtr.h" + +#ifndef mozilla_ArenaRefPtr_h +#define mozilla_ArenaRefPtr_h + +class nsPresArena; + +namespace mozilla { + +/** + * A class for holding strong references to nsPresArena-allocated + * objects. + * + * Since the arena's lifetime is not related to the refcounts + * of the objects allocated within it, it is possible to have a strong + * reference to an arena-allocated object that lives until the + * destruction of the arena. An ArenaRefPtr acts like a weak reference + * in that it will clear its referent if the arena is about to go away. + * + * T must be a class that has these two methods: + * + * static mozilla::ArenaObjectID ArenaObjectID(); + * U* Arena(); + * + * where U is a class that has these two methods: + * + * void RegisterArenaRefPtr(ArenaRefPtr<T>*); + * void DeregisterArenaRefPtr(ArenaRefPtr<T>*); + * + * Currently, both nsPresArena and nsIPresShell can be used as U. + * + * The ArenaObjectID method must return the mozilla::ArenaObjectID that + * uniquely identifies T, and the Arena method must return the nsPresArena + * (or a proxy for it) in which the object was allocated. + */ +template<typename T> +class ArenaRefPtr +{ + friend class ::nsPresArena; + +public: + ArenaRefPtr() + { + AssertValidType(); + } + + template<typename I> + MOZ_IMPLICIT ArenaRefPtr(already_AddRefed<I>& aRhs) + { + AssertValidType(); + assign(aRhs); + } + + template<typename I> + MOZ_IMPLICIT ArenaRefPtr(already_AddRefed<I>&& aRhs) + { + AssertValidType(); + assign(aRhs); + } + + MOZ_IMPLICIT ArenaRefPtr(T* aRhs) + { + AssertValidType(); + assign(aRhs); + } + + template<typename I> + ArenaRefPtr<T>& operator=(already_AddRefed<I>& aRhs) + { + assign(aRhs); + return *this; + } + + template<typename I> + ArenaRefPtr<T>& operator=(already_AddRefed<I>&& aRhs) + { + assign(aRhs); + return *this; + } + + ArenaRefPtr<T>& operator=(T* aRhs) + { + assign(aRhs); + return *this; + } + + ~ArenaRefPtr() { assign(nullptr); } + +#ifdef MOZ_HAVE_REF_QUALIFIERS + operator T*() const & { return get(); } + operator T*() const && = delete; + explicit operator bool() const { return !!mPtr; } + bool operator!() const { return !mPtr; } +#else + operator T*() const { return get(); } +#endif + + T* operator->() const { return mPtr.operator->(); } + T& operator*() const { return *get(); } + + T* get() const { return mPtr; } + +private: + void AssertValidType(); + + /** + * Clears the pointer to the arena-allocated object but skips the usual + * step of deregistering the ArenaRefPtr from the nsPresArena. This + * method is called by nsPresArena when clearing all registered ArenaRefPtrs + * so that it can deregister them all at once, avoiding hash table churn. + */ + void ClearWithoutDeregistering() + { + mPtr = nullptr; + } + + template<typename I> + void assign(already_AddRefed<I>& aSmartPtr) + { + RefPtr<T> newPtr(aSmartPtr); + assignFrom(newPtr); + } + + template<typename I> + void assign(already_AddRefed<I>&& aSmartPtr) + { + RefPtr<T> newPtr(aSmartPtr); + assignFrom(newPtr); + } + + void assign(T* aPtr) { assignFrom(aPtr); } + + template<typename I> + void assignFrom(I& aPtr) + { + if (aPtr == mPtr) { + return; + } + bool sameArena = mPtr && aPtr && mPtr->Arena() == aPtr->Arena(); + if (mPtr && !sameArena) { + MOZ_ASSERT(mPtr->Arena()); + mPtr->Arena()->DeregisterArenaRefPtr(this); + } + mPtr = Move(aPtr); + if (mPtr && !sameArena) { + MOZ_ASSERT(mPtr->Arena()); + mPtr->Arena()->RegisterArenaRefPtr(this); + } + } + + RefPtr<T> mPtr; +}; + +} // namespace mozilla + +#endif // mozilla_ArenaRefPtr_h |