Chromium Code Reviews| Index: third_party/WebKit/Source/wtf/MakeCancellable.h |
| diff --git a/third_party/WebKit/Source/wtf/MakeCancellable.h b/third_party/WebKit/Source/wtf/MakeCancellable.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..38a00100d3ed7324249983602de7808232d7b4e3 |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/wtf/MakeCancellable.h |
| @@ -0,0 +1,156 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#ifndef WTF_MakeCancellable_h |
| +#define WTF_MakeCancellable_h |
| + |
| +#include "base/logging.h" |
| +#include "wtf/Functional.h" |
| +#include "wtf/RefCounted.h" |
| +#include "wtf/WTFExport.h" |
| +#include <memory> |
| + |
| +namespace WTF { |
| + |
| +class WTF_EXPORT FunctionCanceller : public RefCounted<FunctionCanceller> { |
| +public: |
| + virtual void cancel() = 0; |
| + |
| +protected: |
| + FunctionCanceller(); |
| + virtual ~FunctionCanceller(); |
| + friend RefCounted<FunctionCanceller>; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(FunctionCanceller); |
| +}; |
| + |
| +// ScopedFunctionCanceller holds a FunctionCanceller and cancels the target |
| +// 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
|
| +// Example: |
| +// void Foo() {} |
| +// |
| +// std::unique_ptr<Closure> f = bind(&Foo); |
| +// RefPtr<FunctionCanceller> canceller; |
| +// 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
|
| +// |
| +// { |
| +// ScopedFunctionCanceller scopedCanceller(canceller); |
| +// // Scope out of |scopedCanceller| cancels Foo invocation. |
| +// // (*g)(); will be no-op. |
| +// } |
| +// |
| +// ScopedFunctionCanceller scopedCanceller(canceller); |
| +// |
| +// // Manual cancellation is also available. This cancels the invocation |
| +// // of Foo too. |
| +// scopedCanceller.cancel(); |
| +// |
| +// // detach() unassociates the FunctionCanceller instance without cancelling |
| +// // it. After detach() call, the destructor nor cancel() no longer cancels |
| +// // the invocation of Foo. |
| +// scopedCanceller.detach(); |
| +// |
| +class WTF_EXPORT ScopedFunctionCanceller { |
|
haraken
2016/07/29 14:02:52
Can this be DISALLOW_ALLOCATION?
tzik
2016/07/29 16:49:13
Done.
|
| +public: |
| + ScopedFunctionCanceller(); |
| + explicit ScopedFunctionCanceller(PassRefPtr<FunctionCanceller>); |
| + |
| + ScopedFunctionCanceller(ScopedFunctionCanceller&&); |
| + ScopedFunctionCanceller& operator=(ScopedFunctionCanceller&&); |
| + ScopedFunctionCanceller(const ScopedFunctionCanceller&) = delete; |
| + ScopedFunctionCanceller& operator=(const ScopedFunctionCanceller&) = delete; |
| + |
| + ~ScopedFunctionCanceller(); |
| + void detach(); |
| + void cancel(); |
| + |
| +private: |
| + RefPtr<FunctionCanceller> m_canceller; |
| +}; |
| + |
| +namespace internal { |
| + |
| +template <typename... Params> |
| +class FunctionCancellerImpl final : public FunctionCanceller { |
| +public: |
| + FunctionCancellerImpl(std::unique_ptr<Function<void(Params...)>> function) |
| + : m_function(std::move(function)) |
| + { |
| + DCHECK(m_function); |
| + } |
| + |
| + void runUnlessCancelled(const ScopedFunctionCanceller&, Params... params) |
| + { |
| + if (m_function) |
| + (*m_function)(std::forward<Params>(params)...); |
| + } |
| + |
| + void cancel() override |
| + { |
| + m_function = nullptr; |
| + } |
| + |
| +private: |
| + ~FunctionCancellerImpl() override = default; |
| + |
| + std::unique_ptr<WTF::Function<void(Params...)>> m_function; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(FunctionCancellerImpl); |
| +}; |
| + |
| +} // namespace internal |
| + |
| +// makeCancellable wraps a WTF::Function to make cancellable function. |
| +// This function returns a tuple of a WTF::Function, and a FunctionCanceller. |
| +// An invocation of the resulting function is relayed to the original function |
| +// if the FunctionCanceller::cancel() is not called. |
| +// |
| +// Example: |
| +// void foo() {} |
| +// std::unique_ptr<Function<void()>> function = WTF::bind(&foo); |
| +// |
| +// std::unique_ptr<Function<void()>> wrappedFunction; |
| +// RefPtr<FunctionCanceller> canceller; |
| +// std::tie(wrappedFunction, canceller) = makeCancellable(std::move(function)); |
| +// |
| +// (*wrappedFunction)(); // Not cancelled. foo() is called. |
| +// canceller->cancel(); |
| +// (*wrappedFunction)(); // Cancelled. foo() is not called. |
| +// |
| +template <typename... Params> |
| +std::tuple<std::unique_ptr<Function<void(Params...)>>, PassRefPtr<FunctionCanceller>> |
| +makeCancellable(std::unique_ptr<Function<void(Params...)>> function) |
| +{ |
| + using Canceller = internal::FunctionCancellerImpl<Params...>; |
| + RefPtr<Canceller> canceller = adoptRef(new Canceller(std::move(function))); |
| + |
| + // Keep a ScopedFunctionCanceller instance in |wrappedFunction| below, so |
| + // that the destruction of |wrappedFunction| implies the destruction of |
| + // |function|. This is needed to avoid a circular strong reference among a |
| + // bound parameter, Function, and FunctionCanceller. |
| + // |
| + // E.g.: |
| + // struct Foo : GarbageCollectedFinalized<Foo> { |
| + // RefPtr<FunctionCanceller> m_canceller; |
| + // void bar(); |
| + // }; |
| + // |
| + // Foo* foo = new Foo; |
| + // std::unique_ptr<Closure> g; |
| + // std::tie(g, foo->m_canceller) = |
| + // makeCancellable(bind(&Foo::bar, wrapPersistent(foo))); |
| + // |
| + // // Destruction of the resulting Function implies the destruction of |
| + // // the original function via ScopedFunctionCanceller below, that |
| + // // resolves a circular strong reference: |
| + // // foo -> m_canceller -> m_function -> foo |
| + // g = nullptr; |
| + std::unique_ptr<Function<void(Params...)>> wrappedFunction = |
| + bind(&Canceller::runUnlessCancelled, canceller, ScopedFunctionCanceller(canceller)); |
| + return std::make_tuple(std::move(wrappedFunction), canceller.release()); |
| +} |
| + |
| +} // namespace WTF |
| + |
| +#endif // WTF_MakeCancellable_h |