Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * vim: set ts=2 sw=2 et tw=78:
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 : {
50 : friend class ::nsPresArena;
51 :
52 : public:
53 4 : ArenaRefPtr()
54 4 : {
55 4 : AssertValidType();
56 4 : }
57 :
58 : template<typename I>
59 : MOZ_IMPLICIT ArenaRefPtr(already_AddRefed<I>& aRhs)
60 : {
61 : AssertValidType();
62 : assign(aRhs);
63 : }
64 :
65 : template<typename I>
66 : MOZ_IMPLICIT ArenaRefPtr(already_AddRefed<I>&& aRhs)
67 : {
68 : AssertValidType();
69 : assign(aRhs);
70 : }
71 :
72 : MOZ_IMPLICIT ArenaRefPtr(T* aRhs)
73 : {
74 : AssertValidType();
75 : assign(aRhs);
76 : }
77 :
78 : template<typename I>
79 : ArenaRefPtr<T>& operator=(already_AddRefed<I>& aRhs)
80 : {
81 : assign(aRhs);
82 : return *this;
83 : }
84 :
85 : template<typename I>
86 : ArenaRefPtr<T>& operator=(already_AddRefed<I>&& aRhs)
87 : {
88 : assign(aRhs);
89 : return *this;
90 : }
91 :
92 12 : ArenaRefPtr<T>& operator=(T* aRhs)
93 : {
94 12 : assign(aRhs);
95 12 : return *this;
96 : }
97 :
98 0 : ~ArenaRefPtr() { assign(nullptr); }
99 :
100 4 : operator T*() const & { return get(); }
101 : operator T*() const && = delete;
102 4 : explicit operator bool() const { return !!mPtr; }
103 12 : bool operator!() const { return !mPtr; }
104 4 : T* operator->() const { return mPtr.operator->(); }
105 : T& operator*() const { return *get(); }
106 :
107 4 : T* get() const { return mPtr; }
108 :
109 : private:
110 : void AssertValidType();
111 :
112 : /**
113 : * Clears the pointer to the arena-allocated object but skips the usual
114 : * step of deregistering the ArenaRefPtr from the nsPresArena. This
115 : * method is called by nsPresArena when clearing all registered ArenaRefPtrs
116 : * so that it can deregister them all at once, avoiding hash table churn.
117 : */
118 0 : void ClearWithoutDeregistering()
119 : {
120 0 : mPtr = nullptr;
121 0 : }
122 :
123 : template<typename I>
124 : void assign(already_AddRefed<I>& aSmartPtr)
125 : {
126 : RefPtr<T> newPtr(aSmartPtr);
127 : assignFrom(newPtr);
128 : }
129 :
130 : template<typename I>
131 : void assign(already_AddRefed<I>&& aSmartPtr)
132 : {
133 : RefPtr<T> newPtr(aSmartPtr);
134 : assignFrom(newPtr);
135 : }
136 :
137 12 : void assign(T* aPtr) { assignFrom(aPtr); }
138 :
139 : template<typename I>
140 12 : void assignFrom(I& aPtr)
141 : {
142 12 : if (aPtr == mPtr) {
143 4 : return;
144 : }
145 8 : bool sameArena = mPtr && aPtr && mPtr->Arena() == aPtr->Arena();
146 8 : if (mPtr && !sameArena) {
147 4 : MOZ_ASSERT(mPtr->Arena());
148 4 : mPtr->Arena()->DeregisterArenaRefPtr(this);
149 : }
150 8 : mPtr = Move(aPtr);
151 8 : if (mPtr && !sameArena) {
152 4 : MOZ_ASSERT(mPtr->Arena());
153 4 : mPtr->Arena()->RegisterArenaRefPtr(this);
154 : }
155 : }
156 :
157 : RefPtr<T> mPtr;
158 : };
159 :
160 : } // namespace mozilla
161 :
162 : #endif // mozilla_ArenaRefPtr_h
|