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
19namespace fml {
20
21struct DebugThreadChecker {
22 FML_DECLARE_THREAD_CHECKER(checker);
23};
24
25struct DebugTaskRunnerChecker {
26 FML_DECLARE_TASK_RUNNER_CHECKER(checker);
27};
28
29// Forward declaration, so |WeakPtr<T>| can friend it.
30template <typename T>
31class 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|).
46template <typename T>
47class 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.
143template <typename T>
144class 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|.
150template <typename T>
151class 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// };
236template <typename T>
237class 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|.
272template <typename T>
273class 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