• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/thread_checker.h"
16 #include "flutter/fml/memory/weak_ptr_internal.h"
17 
18 namespace fml {
19 
20 struct DebugThreadChecker {
21   FML_DECLARE_THREAD_CHECKER(checker);
22 };
23 
24 // Forward declaration, so |WeakPtr<T>| can friend it.
25 template <typename T>
26 class WeakPtrFactory;
27 
28 // Class for "weak pointers" that can be invalidated. Valid weak pointers can
29 // only originate from a |WeakPtrFactory| (see below), though weak pointers are
30 // copyable and movable.
31 //
32 // Weak pointers are not in general thread-safe. They may only be *used* on a
33 // single thread, namely the same thread as the "originating" |WeakPtrFactory|
34 // (which can invalidate the weak pointers that it generates).
35 //
36 // However, weak pointers may be passed to other threads, reset on other
37 // threads, or destroyed on other threads. They may also be reassigned on other
38 // threads (in which case they should then only be used on the thread
39 // corresponding to the new "originating" |WeakPtrFactory|).
40 template <typename T>
41 class WeakPtr {
42  public:
WeakPtr()43   WeakPtr() : ptr_(nullptr) {}
44 
45   // Copy constructor.
46   WeakPtr(const WeakPtr<T>& r) = default;
47 
48   template <typename U>
WeakPtr(const WeakPtr<U> & r)49   WeakPtr(const WeakPtr<U>& r)
50       : ptr_(static_cast<T*>(r.ptr_)), flag_(r.flag_), checker_(r.checker_) {}
51 
52   // Move constructor.
53   WeakPtr(WeakPtr<T>&& r) = default;
54 
55   template <typename U>
WeakPtr(WeakPtr<U> && r)56   WeakPtr(WeakPtr<U>&& r)
57       : ptr_(static_cast<T*>(r.ptr_)),
58         flag_(std::move(r.flag_)),
59         checker_(r.checker_) {}
60 
61   ~WeakPtr() = default;
62 
63   // The following methods are thread-friendly, in the sense that they may be
64   // called subject to additional synchronization.
65 
66   // Copy assignment.
67   WeakPtr<T>& operator=(const WeakPtr<T>& r) = default;
68 
69   // Move assignment.
70   WeakPtr<T>& operator=(WeakPtr<T>&& r) = default;
71 
reset()72   void reset() { flag_ = nullptr; }
73 
74   // The following methods should only be called on the same thread as the
75   // "originating" |WeakPtrFactory|.
76 
77   explicit operator bool() const {
78     FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker);
79     return flag_ && flag_->is_valid();
80   }
81 
get()82   T* get() const {
83     FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker);
84     return *this ? ptr_ : nullptr;
85   }
86 
87   T& operator*() const {
88     FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker);
89     FML_DCHECK(*this);
90     return *get();
91   }
92 
93   T* operator->() const {
94     FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker);
95     FML_DCHECK(*this);
96     return get();
97   }
98 
99  private:
100   template <typename U>
101   friend class WeakPtr;
102 
103   friend class WeakPtrFactory<T>;
104 
WeakPtr(T * ptr,fml::RefPtr<fml::internal::WeakPtrFlag> && flag,DebugThreadChecker checker)105   explicit WeakPtr(T* ptr,
106                    fml::RefPtr<fml::internal::WeakPtrFlag>&& flag,
107                    DebugThreadChecker checker)
108       : ptr_(ptr), flag_(std::move(flag)), checker_(checker) {}
109 
110   T* ptr_;
111   fml::RefPtr<fml::internal::WeakPtrFlag> flag_;
112   DebugThreadChecker checker_;
113 
114   // Copy/move construction/assignment supported.
115 };
116 
117 // Class that produces (valid) |WeakPtr<T>|s. Typically, this is used as a
118 // member variable of |T| (preferably the last one -- see below), and |T|'s
119 // methods control how weak pointers to it are vended. This class is not
120 // thread-safe, and should only be created, destroyed and used on a single
121 // thread.
122 //
123 // Example:
124 //
125 //  class Controller {
126 //   public:
127 //    Controller() : ..., weak_factory_(this) {}
128 //    ...
129 //
130 //    void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); }
131 //    void WorkComplete(const Result& result) { ... }
132 //
133 //   private:
134 //    ...
135 //
136 //    // Member variables should appear before the |WeakPtrFactory|, to ensure
137 //    // that any |WeakPtr|s to |Controller| are invalidated before its member
138 //    // variables' destructors are executed.
139 //    WeakPtrFactory<Controller> weak_factory_;
140 //  };
141 //
142 //  class Worker {
143 //   public:
144 //    static void StartNew(const WeakPtr<Controller>& controller) {
145 //      Worker* worker = new Worker(controller);
146 //      // Kick off asynchronous processing....
147 //    }
148 //
149 //   private:
150 //    Worker(const WeakPtr<Controller>& controller) : controller_(controller) {}
151 //
152 //    void DidCompleteAsynchronousProcessing(const Result& result) {
153 //      if (controller_)
154 //        controller_->WorkComplete(result);
155 //    }
156 //
157 //    WeakPtr<Controller> controller_;
158 //  };
159 template <typename T>
160 class WeakPtrFactory {
161  public:
WeakPtrFactory(T * ptr)162   explicit WeakPtrFactory(T* ptr)
163       : ptr_(ptr), flag_(fml::MakeRefCounted<fml::internal::WeakPtrFlag>()) {
164     FML_DCHECK(ptr_);
165   }
166 
~WeakPtrFactory()167   ~WeakPtrFactory() {
168     FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker);
169     flag_->Invalidate();
170   }
171 
172   // Gets a new weak pointer, which will be valid until either
173   // |InvalidateWeakPtrs()| is called or this object is destroyed.
GetWeakPtr()174   WeakPtr<T> GetWeakPtr() const {
175     return WeakPtr<T>(ptr_, flag_.Clone(), checker_);
176   }
177 
178  private:
179   // Note: See weak_ptr_internal.h for an explanation of why we store the
180   // pointer here, instead of in the "flag".
181   T* const ptr_;
182   fml::RefPtr<fml::internal::WeakPtrFlag> flag_;
183   DebugThreadChecker checker_;
184 
185   FML_DISALLOW_COPY_AND_ASSIGN(WeakPtrFactory);
186 };
187 
188 }  // namespace fml
189 
190 #endif  // FLUTTER_FML_MEMORY_WEAK_PTR_H_
191