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/. 6 */ 7 8 /* smart pointer for strong references to nsPresArena-allocated objects 9 that might be held onto until the arena's destruction */ 10 11 #include "mozilla/Assertions.h" 12 #include "mozilla/RefPtr.h" 13 14 #ifndef mozilla_ArenaRefPtr_h 15 #define mozilla_ArenaRefPtr_h 16 17 class nsPresArena; 18 19 namespace mozilla { 20 21 /** 22 * A class for holding strong references to nsPresArena-allocated 23 * objects. 24 * 25 * Since the arena's lifetime is not related to the refcounts 26 * of the objects allocated within it, it is possible to have a strong 27 * reference to an arena-allocated object that lives until the 28 * destruction of the arena. An ArenaRefPtr acts like a weak reference 29 * in that it will clear its referent if the arena is about to go away. 30 * 31 * T must be a class that has these two methods: 32 * 33 * static mozilla::ArenaObjectID ArenaObjectID(); 34 * U* Arena(); 35 * 36 * where U is a class that has these two methods: 37 * 38 * void RegisterArenaRefPtr(ArenaRefPtr<T>*); 39 * void DeregisterArenaRefPtr(ArenaRefPtr<T>*); 40 * 41 * Currently, both nsPresArena and nsIPresShell can be used as U. 42 * 43 * The ArenaObjectID method must return the mozilla::ArenaObjectID that 44 * uniquely identifies T, and the Arena method must return the nsPresArena 45 * (or a proxy for it) in which the object was allocated. 46 */ 47 template <typename T> 48 class ArenaRefPtr { 49 friend class ::nsPresArena; 50 51 public: ArenaRefPtr()52 ArenaRefPtr() { AssertValidType(); } 53 54 template <typename I> ArenaRefPtr(already_AddRefed<I> & aRhs)55 MOZ_IMPLICIT ArenaRefPtr(already_AddRefed<I>& aRhs) { 56 AssertValidType(); 57 assign(aRhs); 58 } 59 60 template <typename I> ArenaRefPtr(already_AddRefed<I> && aRhs)61 MOZ_IMPLICIT ArenaRefPtr(already_AddRefed<I>&& aRhs) { 62 AssertValidType(); 63 assign(aRhs); 64 } 65 ArenaRefPtr(T * aRhs)66 MOZ_IMPLICIT ArenaRefPtr(T* aRhs) { 67 AssertValidType(); 68 assign(aRhs); 69 } 70 71 template <typename I> 72 ArenaRefPtr<T>& operator=(already_AddRefed<I>& aRhs) { 73 assign(aRhs); 74 return *this; 75 } 76 77 template <typename I> 78 ArenaRefPtr<T>& operator=(already_AddRefed<I>&& aRhs) { 79 assign(aRhs); 80 return *this; 81 } 82 83 ArenaRefPtr<T>& operator=(T* aRhs) { 84 assign(aRhs); 85 return *this; 86 } 87 ~ArenaRefPtr()88 ~ArenaRefPtr() { assign(nullptr); } 89 90 operator T*() const & { return get(); } 91 operator T*() const && = delete; 92 explicit operator bool() const { return !!mPtr; } 93 bool operator!() const { return !mPtr; } 94 T* operator->() const { return mPtr.operator->(); } 95 T& operator*() const { return *get(); } 96 get()97 T* get() const { return mPtr; } 98 99 private: 100 void AssertValidType(); 101 102 /** 103 * Clears the pointer to the arena-allocated object but skips the usual 104 * step of deregistering the ArenaRefPtr from the nsPresArena. This 105 * method is called by nsPresArena when clearing all registered ArenaRefPtrs 106 * so that it can deregister them all at once, avoiding hash table churn. 107 */ ClearWithoutDeregistering()108 void ClearWithoutDeregistering() { mPtr = nullptr; } 109 110 template <typename I> assign(already_AddRefed<I> & aSmartPtr)111 void assign(already_AddRefed<I>& aSmartPtr) { 112 RefPtr<T> newPtr(aSmartPtr); 113 assignFrom(newPtr); 114 } 115 116 template <typename I> assign(already_AddRefed<I> && aSmartPtr)117 void assign(already_AddRefed<I>&& aSmartPtr) { 118 RefPtr<T> newPtr(aSmartPtr); 119 assignFrom(newPtr); 120 } 121 assign(T * aPtr)122 void assign(T* aPtr) { assignFrom(aPtr); } 123 124 template <typename I> assignFrom(I & aPtr)125 void assignFrom(I& aPtr) { 126 if (aPtr == mPtr) { 127 return; 128 } 129 bool sameArena = mPtr && aPtr && mPtr->Arena() == aPtr->Arena(); 130 if (mPtr && !sameArena) { 131 MOZ_ASSERT(mPtr->Arena()); 132 mPtr->Arena()->DeregisterArenaRefPtr(this); 133 } 134 mPtr = Move(aPtr); 135 if (mPtr && !sameArena) { 136 MOZ_ASSERT(mPtr->Arena()); 137 mPtr->Arena()->RegisterArenaRefPtr(this); 138 } 139 } 140 141 RefPtr<T> mPtr; 142 }; 143 144 } // namespace mozilla 145 146 #endif // mozilla_ArenaRefPtr_h 147