1 | // Copyright 2013 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | // This file provides weak pointers and weak pointer factories that work like |
6 | // Chromium's |base::WeakPtr<T>| and |base::WeakPtrFactory<T>|. |
7 | |
8 | #ifndef FLUTTER_FML_MEMORY_WEAK_PTR_H_ |
9 | #define FLUTTER_FML_MEMORY_WEAK_PTR_H_ |
10 | |
11 | #include <utility> |
12 | |
13 | #include "flutter/fml/logging.h" |
14 | #include "flutter/fml/memory/ref_counted.h" |
15 | #include "flutter/fml/memory/task_runner_checker.h" |
16 | #include "flutter/fml/memory/thread_checker.h" |
17 | #include "flutter/fml/memory/weak_ptr_internal.h" |
18 | |
19 | namespace fml { |
20 | |
21 | struct DebugThreadChecker { |
22 | FML_DECLARE_THREAD_CHECKER(checker); |
23 | }; |
24 | |
25 | struct DebugTaskRunnerChecker { |
26 | FML_DECLARE_TASK_RUNNER_CHECKER(checker); |
27 | }; |
28 | |
29 | // Forward declaration, so |WeakPtr<T>| can friend it. |
30 | template <typename T> |
31 | class WeakPtrFactory; |
32 | |
33 | // Class for "weak pointers" that can be invalidated. Valid weak pointers |
34 | // can only originate from a |WeakPtrFactory| (see below), though weak |
35 | // pointers are copyable and movable. |
36 | // |
37 | // Weak pointers are not in general thread-safe. They may only be *used* on |
38 | // a single thread, namely the same thread as the "originating" |
39 | // |WeakPtrFactory| (which can invalidate the weak pointers that it |
40 | // generates). |
41 | // |
42 | // However, weak pointers may be passed to other threads, reset on other |
43 | // threads, or destroyed on other threads. They may also be reassigned on |
44 | // other threads (in which case they should then only be used on the thread |
45 | // corresponding to the new "originating" |WeakPtrFactory|). |
46 | template <typename T> |
47 | class WeakPtr { |
48 | public: |
49 | WeakPtr() : ptr_(nullptr) {} |
50 | |
51 | // Copy constructor. |
52 | explicit WeakPtr(const WeakPtr<T>& r) = default; |
53 | |
54 | template <typename U> |
55 | WeakPtr(const WeakPtr<U>& r) |
56 | : ptr_(static_cast<T*>(r.ptr_)), flag_(r.flag_), checker_(r.checker_) {} |
57 | |
58 | // Move constructor. |
59 | WeakPtr(WeakPtr<T>&& r) = default; |
60 | |
61 | template <typename U> |
62 | WeakPtr(WeakPtr<U>&& r) |
63 | : ptr_(static_cast<T*>(r.ptr_)), |
64 | flag_(std::move(r.flag_)), |
65 | checker_(r.checker_) {} |
66 | |
67 | virtual ~WeakPtr() = default; |
68 | |
69 | // The following methods are thread-friendly, in the sense that they may be |
70 | // called subject to additional synchronization. |
71 | |
72 | // Copy assignment. |
73 | WeakPtr<T>& operator=(const WeakPtr<T>& r) = default; |
74 | |
75 | // Move assignment. |
76 | WeakPtr<T>& operator=(WeakPtr<T>&& r) = default; |
77 | |
78 | void reset() { flag_ = nullptr; } |
79 | |
80 | // The following methods should only be called on the same thread as the |
81 | // "originating" |WeakPtrFactory|. |
82 | |
83 | explicit operator bool() const { |
84 | CheckThreadSafety(); |
85 | return flag_ && flag_->is_valid(); |
86 | } |
87 | |
88 | T* get() const { |
89 | CheckThreadSafety(); |
90 | return *this ? ptr_ : nullptr; |
91 | } |
92 | |
93 | // TODO(gw280): Remove all remaining usages of getUnsafe(). |
94 | // No new usages of getUnsafe() are allowed. |
95 | // |
96 | // https://github.com/flutter/flutter/issues/42949 |
97 | T* getUnsafe() const { |
98 | // This is an unsafe method to get access to the raw pointer. |
99 | // We still check the flag_ to determine if the pointer is valid |
100 | // but callees should note that this WeakPtr could have been |
101 | // invalidated on another thread. |
102 | return flag_ && flag_->is_valid() ? ptr_ : nullptr; |
103 | } |
104 | |
105 | T& operator*() const { |
106 | CheckThreadSafety(); |
107 | FML_DCHECK(*this); |
108 | return *get(); |
109 | } |
110 | |
111 | T* operator->() const { |
112 | CheckThreadSafety(); |
113 | FML_DCHECK(*this); |
114 | return get(); |
115 | } |
116 | |
117 | protected: |
118 | explicit WeakPtr(T* ptr, fml::RefPtr<fml::internal::WeakPtrFlag>&& flag) |
119 | : ptr_(ptr), flag_(std::move(flag)) {} |
120 | |
121 | virtual void CheckThreadSafety() const { |
122 | FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); |
123 | } |
124 | |
125 | private: |
126 | template <typename U> |
127 | friend class WeakPtr; |
128 | |
129 | friend class WeakPtrFactory<T>; |
130 | |
131 | explicit WeakPtr(T* ptr, |
132 | fml::RefPtr<fml::internal::WeakPtrFlag>&& flag, |
133 | DebugThreadChecker checker) |
134 | : ptr_(ptr), flag_(std::move(flag)), checker_(checker) {} |
135 | T* ptr_; |
136 | fml::RefPtr<fml::internal::WeakPtrFlag> flag_; |
137 | DebugThreadChecker checker_; |
138 | |
139 | // Copy/move construction/assignment supported. |
140 | }; |
141 | |
142 | // Forward declaration, so |TaskRunnerAffineWeakPtr<T>| can friend it. |
143 | template <typename T> |
144 | class TaskRunnerAffineWeakPtrFactory; |
145 | |
146 | // A weak pointer that can be used in different threads as long as |
147 | // the threads are belong to the same |TaskRunner|. |
148 | // |
149 | // It is still not in general thread safe as |WeakPtr|. |
150 | template <typename T> |
151 | class TaskRunnerAffineWeakPtr : public WeakPtr<T> { |
152 | public: |
153 | TaskRunnerAffineWeakPtr() : WeakPtr<T>() {} |
154 | |
155 | TaskRunnerAffineWeakPtr(const TaskRunnerAffineWeakPtr<T>& r) = default; |
156 | |
157 | template <typename U> |
158 | TaskRunnerAffineWeakPtr(const TaskRunnerAffineWeakPtr<U>& r) |
159 | : WeakPtr<T>(r), checker_(r.checker_) {} |
160 | |
161 | TaskRunnerAffineWeakPtr(TaskRunnerAffineWeakPtr<T>&& r) = default; |
162 | |
163 | template <typename U> |
164 | TaskRunnerAffineWeakPtr(TaskRunnerAffineWeakPtr<U>&& r) |
165 | : WeakPtr<T>(r), checker_(r.checker_) {} |
166 | |
167 | ~TaskRunnerAffineWeakPtr() = default; |
168 | |
169 | TaskRunnerAffineWeakPtr<T>& operator=(const TaskRunnerAffineWeakPtr<T>& r) = |
170 | default; |
171 | |
172 | TaskRunnerAffineWeakPtr<T>& operator=(TaskRunnerAffineWeakPtr<T>&& r) = |
173 | default; |
174 | |
175 | protected: |
176 | void CheckThreadSafety() const override { |
177 | FML_DCHECK_TASK_RUNNER_IS_CURRENT(checker_.checker); |
178 | } |
179 | |
180 | private: |
181 | template <typename U> |
182 | friend class TaskRunnerAffineWeakPtr; |
183 | friend class TaskRunnerAffineWeakPtrFactory<T>; |
184 | |
185 | explicit TaskRunnerAffineWeakPtr( |
186 | T* ptr, |
187 | fml::RefPtr<fml::internal::WeakPtrFlag>&& flag, |
188 | DebugTaskRunnerChecker checker) |
189 | : WeakPtr<T>(ptr, std::move(flag)), checker_(checker) {} |
190 | |
191 | DebugTaskRunnerChecker checker_; |
192 | }; |
193 | |
194 | // Class that produces (valid) |WeakPtr<T>|s. Typically, this is used as a |
195 | // member variable of |T| (preferably the last one -- see below), and |T|'s |
196 | // methods control how weak pointers to it are vended. This class is not |
197 | // thread-safe, and should only be created, destroyed and used on a single |
198 | // thread. |
199 | // |
200 | // Example: |
201 | // |
202 | // class Controller { |
203 | // public: |
204 | // Controller() : ..., weak_factory_(this) {} |
205 | // ... |
206 | // |
207 | // void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); } |
208 | // void WorkComplete(const Result& result) { ... } |
209 | // |
210 | // private: |
211 | // ... |
212 | // |
213 | // // Member variables should appear before the |WeakPtrFactory|, to ensure |
214 | // // that any |WeakPtr|s to |Controller| are invalidated before its member |
215 | // // variables' destructors are executed. |
216 | // WeakPtrFactory<Controller> weak_factory_; |
217 | // }; |
218 | // |
219 | // class Worker { |
220 | // public: |
221 | // static void StartNew(const WeakPtr<Controller>& controller) { |
222 | // Worker* worker = new Worker(controller); |
223 | // // Kick off asynchronous processing.... |
224 | // } |
225 | // |
226 | // private: |
227 | // Worker(const WeakPtr<Controller>& controller) : controller_(controller) {} |
228 | // |
229 | // void DidCompleteAsynchronousProcessing(const Result& result) { |
230 | // if (controller_) |
231 | // controller_->WorkComplete(result); |
232 | // } |
233 | // |
234 | // WeakPtr<Controller> controller_; |
235 | // }; |
236 | template <typename T> |
237 | class WeakPtrFactory { |
238 | public: |
239 | explicit WeakPtrFactory(T* ptr) |
240 | : ptr_(ptr), flag_(fml::MakeRefCounted<fml::internal::WeakPtrFlag>()) { |
241 | FML_DCHECK(ptr_); |
242 | } |
243 | |
244 | ~WeakPtrFactory() { |
245 | CheckThreadSafety(); |
246 | flag_->Invalidate(); |
247 | } |
248 | |
249 | // Gets a new weak pointer, which will be valid until either |
250 | // |InvalidateWeakPtrs()| is called or this object is destroyed. |
251 | WeakPtr<T> GetWeakPtr() const { |
252 | return WeakPtr<T>(ptr_, flag_.Clone(), checker_); |
253 | } |
254 | |
255 | private: |
256 | // Note: See weak_ptr_internal.h for an explanation of why we store the |
257 | // pointer here, instead of in the "flag". |
258 | T* const ptr_; |
259 | fml::RefPtr<fml::internal::WeakPtrFlag> flag_; |
260 | |
261 | void CheckThreadSafety() const { |
262 | FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); |
263 | } |
264 | |
265 | DebugThreadChecker checker_; |
266 | |
267 | FML_DISALLOW_COPY_AND_ASSIGN(WeakPtrFactory); |
268 | }; |
269 | |
270 | // A type of |WeakPtrFactory| that produces |TaskRunnerAffineWeakPtr| instead of |
271 | // |WeakPtr|. |
272 | template <typename T> |
273 | class TaskRunnerAffineWeakPtrFactory { |
274 | public: |
275 | explicit TaskRunnerAffineWeakPtrFactory(T* ptr) |
276 | : ptr_(ptr), flag_(fml::MakeRefCounted<fml::internal::WeakPtrFlag>()) { |
277 | FML_DCHECK(ptr_); |
278 | } |
279 | |
280 | ~TaskRunnerAffineWeakPtrFactory() { |
281 | CheckThreadSafety(); |
282 | flag_->Invalidate(); |
283 | } |
284 | |
285 | // Gets a new weak pointer, which will be valid until either |
286 | // |InvalidateWeakPtrs()| is called or this object is destroyed. |
287 | TaskRunnerAffineWeakPtr<T> GetWeakPtr() const { |
288 | return TaskRunnerAffineWeakPtr<T>(ptr_, flag_.Clone(), checker_); |
289 | } |
290 | |
291 | private: |
292 | // Note: See weak_ptr_internal.h for an explanation of why we store the |
293 | // pointer here, instead of in the "flag". |
294 | T* const ptr_; |
295 | fml::RefPtr<fml::internal::WeakPtrFlag> flag_; |
296 | |
297 | void CheckThreadSafety() const { |
298 | FML_DCHECK_TASK_RUNNER_IS_CURRENT(checker_.checker); |
299 | } |
300 | |
301 | DebugTaskRunnerChecker checker_; |
302 | |
303 | FML_DISALLOW_COPY_AND_ASSIGN(TaskRunnerAffineWeakPtrFactory); |
304 | }; |
305 | |
306 | } // namespace fml |
307 | |
308 | #endif // FLUTTER_FML_MEMORY_WEAK_PTR_H_ |
309 | |