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..e1c58cdd486bf29493aa9ebc1619b78f12b9adbb |
--- /dev/null |
+++ b/third_party/WebKit/Source/wtf/MakeCancellable.h |
@@ -0,0 +1,172 @@ |
+// 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 ScopedFunctionCanceller; |
+ |
+namespace internal { |
+ |
+class WTF_EXPORT FunctionCanceller : public RefCounted<FunctionCanceller> { |
+public: |
+ virtual void cancel() = 0; |
+ virtual bool isActive() const = 0; |
+ |
+protected: |
+ FunctionCanceller(); |
+ virtual ~FunctionCanceller(); |
+ friend RefCounted<FunctionCanceller>; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(FunctionCanceller); |
+}; |
+ |
+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; |
+ } |
+ |
+ bool isActive() const override |
+ { |
+ return !!m_function; |
+ } |
+ |
+private: |
+ ~FunctionCancellerImpl() override = default; |
+ |
+ std::unique_ptr<WTF::Function<void(Params...)>> m_function; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(FunctionCancellerImpl); |
+}; |
+ |
+} // namespace internal |
+ |
+// ScopedFunctionCanceller is a handle associated to a Function, and cancels the |
+// invocation of the Function on the scope out or cancel() call. |
+// Example: |
+// void Foo() {} |
+// |
+// std::unique_ptr<Closure> f = bind(&Foo); |
+// auto result = makeCancellable(std::move(f)); |
+// |
+// { |
+// ScopedFunctionCanceller scopedCanceller = std::move(result.canceller); |
+// // Scope out of |scopedCanceller| cancels Foo invocation. |
+// // (*result.function)(); will be no-op. |
+// } |
+// |
+// ScopedFunctionCanceller scopedCanceller = std::move(result.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 { |
+ DISALLOW_NEW(); |
+public: |
+ ScopedFunctionCanceller(); |
+ explicit ScopedFunctionCanceller(PassRefPtr<internal::FunctionCanceller>); |
+ |
+ ScopedFunctionCanceller(ScopedFunctionCanceller&&); |
+ ScopedFunctionCanceller& operator=(ScopedFunctionCanceller&&); |
+ ScopedFunctionCanceller(const ScopedFunctionCanceller&) = delete; |
+ ScopedFunctionCanceller& operator=(const ScopedFunctionCanceller&) = delete; |
+ |
+ ~ScopedFunctionCanceller(); |
+ void detach(); |
+ void cancel(); |
+ bool isActive() const; |
+ |
+private: |
+ RefPtr<internal::FunctionCanceller> m_canceller; |
+}; |
+ |
+template <typename... Params> |
+struct MakeCancellableResult { |
+ ScopedFunctionCanceller canceller; |
+ std::unique_ptr<Function<void(Params...)>> function; |
+ |
+ MakeCancellableResult(ScopedFunctionCanceller canceller, std::unique_ptr<Function<void(Params...)>> function) |
+ : canceller(std::move(canceller)), function(std::move(function)) { } |
+}; |
+ |
+// makeCancellable wraps a WTF::Function to make the function cancellable. |
+// This function returns a WTF::Function, and a ScopedFunctionCanceller. |
+// An invocation of the resulting function is relayed to the original function |
+// if the resulting ScopedFunctionCanceller is alive and the cancel() is not |
+// called. |
+// The inner Function that is passed to makeCancellable() will be destroyed |
+// when it's cancelled or the outer Function is destroyed. |
+// |
+// Example: |
+// void foo() {} |
+// std::unique_ptr<Function<void()>> function = WTF::bind(&foo); |
+// |
+// auto result = makeCancellable(std::move(function)); |
+// |
+// (*result.function)(); // Not cancelled. foo() is called. |
+// result.canceller.cancel(); |
+// (*result.function)(); // Cancelled. foo() is not called. |
+// |
+template <typename... Params> |
+MakeCancellableResult<Params...> makeCancellable(std::unique_ptr<Function<void(Params...)>> function) |
+{ |
+ using Canceller = internal::FunctionCancellerImpl<Params...>; |
+ RefPtr<Canceller> canceller = adoptRef(new Canceller(std::move(function))); |
+ |
+ // Implementation note: |
+ // 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; |
+ // auto result = 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 |
+ // result.function = nullptr; |
+ auto wrappedFunction = bind(&Canceller::runUnlessCancelled, canceller, ScopedFunctionCanceller(canceller)); |
+ return MakeCancellableResult<Params...>(ScopedFunctionCanceller(canceller.release()), std::move(wrappedFunction)); |
+} |
+ |
+} // namespace WTF |
+ |
+#endif // WTF_MakeCancellable_h |