OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium 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 #ifndef WTF_MakeCancellable_h | |
6 #define WTF_MakeCancellable_h | |
7 | |
8 #include "base/logging.h" | |
9 #include "wtf/Functional.h" | |
10 #include "wtf/RefCounted.h" | |
11 #include "wtf/WTFExport.h" | |
12 #include <memory> | |
13 | |
14 namespace WTF { | |
15 | |
16 class WTF_EXPORT FunctionCanceller : public RefCounted<FunctionCanceller> { | |
17 public: | |
18 virtual void cancel() = 0; | |
19 | |
20 protected: | |
21 FunctionCanceller(); | |
22 virtual ~FunctionCanceller(); | |
23 friend RefCounted<FunctionCanceller>; | |
24 | |
25 DISALLOW_COPY_AND_ASSIGN(FunctionCanceller); | |
26 }; | |
27 | |
28 // ScopedFunctionCanceller holds a FunctionCanceller and cancels the target | |
29 // function on its destruction. | |
haraken
2016/07/29 14:02:52
Are you assuming that normal developers use both F
tzik
2016/07/29 16:49:13
Since all existing implementations of custom cance
haraken
2016/07/29 19:18:39
I'm a bit confused. Then what's the point of split
tzik
2016/07/29 21:10:36
That's to make the auto cancel opt-in per comments
| |
30 // Example: | |
31 // void Foo() {} | |
32 // | |
33 // std::unique_ptr<Closure> f = bind(&Foo); | |
34 // RefPtr<FunctionCanceller> canceller; | |
35 // std::tie(g, canceller) = makeCancellable(std::move(f)); | |
haraken
2016/07/29 14:02:52
Nit: I'd prefer passing the canceller parameter as
tzik
2016/07/29 16:49:13
Updated.
I want to avoid using the output paramet
| |
36 // | |
37 // { | |
38 // ScopedFunctionCanceller scopedCanceller(canceller); | |
39 // // Scope out of |scopedCanceller| cancels Foo invocation. | |
40 // // (*g)(); will be no-op. | |
41 // } | |
42 // | |
43 // ScopedFunctionCanceller scopedCanceller(canceller); | |
44 // | |
45 // // Manual cancellation is also available. This cancels the invocation | |
46 // // of Foo too. | |
47 // scopedCanceller.cancel(); | |
48 // | |
49 // // detach() unassociates the FunctionCanceller instance without cancelling | |
50 // // it. After detach() call, the destructor nor cancel() no longer cancels | |
51 // // the invocation of Foo. | |
52 // scopedCanceller.detach(); | |
53 // | |
54 class WTF_EXPORT ScopedFunctionCanceller { | |
haraken
2016/07/29 14:02:52
Can this be DISALLOW_ALLOCATION?
tzik
2016/07/29 16:49:13
Done.
| |
55 public: | |
56 ScopedFunctionCanceller(); | |
57 explicit ScopedFunctionCanceller(PassRefPtr<FunctionCanceller>); | |
58 | |
59 ScopedFunctionCanceller(ScopedFunctionCanceller&&); | |
60 ScopedFunctionCanceller& operator=(ScopedFunctionCanceller&&); | |
61 ScopedFunctionCanceller(const ScopedFunctionCanceller&) = delete; | |
62 ScopedFunctionCanceller& operator=(const ScopedFunctionCanceller&) = delete; | |
63 | |
64 ~ScopedFunctionCanceller(); | |
65 void detach(); | |
66 void cancel(); | |
67 | |
68 private: | |
69 RefPtr<FunctionCanceller> m_canceller; | |
70 }; | |
71 | |
72 namespace internal { | |
73 | |
74 template <typename... Params> | |
75 class FunctionCancellerImpl final : public FunctionCanceller { | |
76 public: | |
77 FunctionCancellerImpl(std::unique_ptr<Function<void(Params...)>> function) | |
78 : m_function(std::move(function)) | |
79 { | |
80 DCHECK(m_function); | |
81 } | |
82 | |
83 void runUnlessCancelled(const ScopedFunctionCanceller&, Params... params) | |
84 { | |
85 if (m_function) | |
86 (*m_function)(std::forward<Params>(params)...); | |
87 } | |
88 | |
89 void cancel() override | |
90 { | |
91 m_function = nullptr; | |
92 } | |
93 | |
94 private: | |
95 ~FunctionCancellerImpl() override = default; | |
96 | |
97 std::unique_ptr<WTF::Function<void(Params...)>> m_function; | |
98 | |
99 DISALLOW_COPY_AND_ASSIGN(FunctionCancellerImpl); | |
100 }; | |
101 | |
102 } // namespace internal | |
103 | |
104 // makeCancellable wraps a WTF::Function to make cancellable function. | |
105 // This function returns a tuple of a WTF::Function, and a FunctionCanceller. | |
106 // An invocation of the resulting function is relayed to the original function | |
107 // if the FunctionCanceller::cancel() is not called. | |
108 // | |
109 // Example: | |
110 // void foo() {} | |
111 // std::unique_ptr<Function<void()>> function = WTF::bind(&foo); | |
112 // | |
113 // std::unique_ptr<Function<void()>> wrappedFunction; | |
114 // RefPtr<FunctionCanceller> canceller; | |
115 // std::tie(wrappedFunction, canceller) = makeCancellable(std::move(function)) ; | |
116 // | |
117 // (*wrappedFunction)(); // Not cancelled. foo() is called. | |
118 // canceller->cancel(); | |
119 // (*wrappedFunction)(); // Cancelled. foo() is not called. | |
120 // | |
121 template <typename... Params> | |
122 std::tuple<std::unique_ptr<Function<void(Params...)>>, PassRefPtr<FunctionCancel ler>> | |
123 makeCancellable(std::unique_ptr<Function<void(Params...)>> function) | |
124 { | |
125 using Canceller = internal::FunctionCancellerImpl<Params...>; | |
126 RefPtr<Canceller> canceller = adoptRef(new Canceller(std::move(function))); | |
127 | |
128 // Keep a ScopedFunctionCanceller instance in |wrappedFunction| below, so | |
129 // that the destruction of |wrappedFunction| implies the destruction of | |
130 // |function|. This is needed to avoid a circular strong reference among a | |
131 // bound parameter, Function, and FunctionCanceller. | |
132 // | |
133 // E.g.: | |
134 // struct Foo : GarbageCollectedFinalized<Foo> { | |
135 // RefPtr<FunctionCanceller> m_canceller; | |
136 // void bar(); | |
137 // }; | |
138 // | |
139 // Foo* foo = new Foo; | |
140 // std::unique_ptr<Closure> g; | |
141 // std::tie(g, foo->m_canceller) = | |
142 // makeCancellable(bind(&Foo::bar, wrapPersistent(foo))); | |
143 // | |
144 // // Destruction of the resulting Function implies the destruction of | |
145 // // the original function via ScopedFunctionCanceller below, that | |
146 // // resolves a circular strong reference: | |
147 // // foo -> m_canceller -> m_function -> foo | |
148 // g = nullptr; | |
149 std::unique_ptr<Function<void(Params...)>> wrappedFunction = | |
150 bind(&Canceller::runUnlessCancelled, canceller, ScopedFunctionCanceller( canceller)); | |
151 return std::make_tuple(std::move(wrappedFunction), canceller.release()); | |
152 } | |
153 | |
154 } // namespace WTF | |
155 | |
156 #endif // WTF_MakeCancellable_h | |
OLD | NEW |