Index: components/scheduler/promises/promise_internal.h |
diff --git a/components/scheduler/promises/promise_internal.h b/components/scheduler/promises/promise_internal.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0e0a7bce997564874571ca43b1367db5d2ec97e5 |
--- /dev/null |
+++ b/components/scheduler/promises/promise_internal.h |
@@ -0,0 +1,529 @@ |
+// 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 COMPONENTS_SCHEDULER_PROMISES_PROMISE_INTERNAL_H_ |
+#define COMPONENTS_SCHEDULER_PROMISES_PROMISE_INTERNAL_H_ |
+ |
+#include <set> |
+#include <vector> |
+ |
+#include "base/macros.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/single_thread_task_runner.h" |
+#include "components/scheduler/promises/rejectable.h" |
+ |
+namespace promise { |
+template <typename R> |
+class Promise; |
+ |
+namespace internal { |
+ |
+class PromiseExecutor; |
+class ThreadPoolPromiseExecutor; |
+ |
+template <typename R> |
+class Promise; |
+ |
+class SCHEDULER_EXPORT PromiseBase : public base::RefCounted<PromiseBase> { |
+ public: |
+ enum class PrerequisitePolicy { ALL, ANY, ALWAYS, NEVER }; |
+ |
+ explicit PromiseBase(PrerequisitePolicy prerequisite_policy); |
+ |
+ PromiseBase(std::vector<scoped_refptr<PromiseBase>> prerequisites, |
+ PrerequisitePolicy prerequisite_policy); |
+ |
+ enum class State { |
+ NEW, |
+ PENDING, |
+ PARTIALLY_RESOLVED, |
+ RESOLVED, |
+ REJECTED, |
+ DEPENDENCY_REJECTED, |
+ CANCELLED |
+ }; |
+ |
+ State state() const { return state_; } |
+ |
+ void SetThisAndPrerequisitesAsEager(bool eager); |
+ |
+ void Cancel(); |
+ |
+ std::vector<scoped_refptr<PromiseBase>>& prerequisites() { |
+ return prerequisites_; |
+ } |
+ |
+ std::set<PromiseBase*>& dependants() { return dependants_; } |
+ |
+ bool can_run_now() const { return can_run_now_; } |
+ |
+ bool is_resolved() const { return state() == PromiseBase::State::RESOLVED; } |
+ |
+ protected: |
+ friend class base::RefCounted<PromiseBase>; |
+ friend class PromiseExecutor; |
+ friend class ThreadPoolPromiseExecutor; |
+ |
+ virtual ~PromiseBase(); |
+ |
+ virtual void ExecutorDrivenResolve() = 0; |
+ |
+ void set_state(State state) { state_ = state; } |
+ |
+ void SetThisAndPrerequisitesAsShouldRun(PromiseExecutor* executor, |
+ bool should_run); |
+ |
+ void RegisterDynamicDependancy(scoped_refptr<PromiseBase> dependency); |
+ |
+ bool AllPrerequisitesSatisfied() const; |
+ |
+ void SchedulePromiseForResolve(); |
+ |
+ void MarkAsResolved(); |
+ void MarkAsRejected(); |
+ |
+ std::vector<scoped_refptr<PromiseBase>> prerequisites_; |
+ std::set<PromiseBase*> dependants_; |
+ PromiseExecutor* executor_; |
+ State state_; |
+ PrerequisitePolicy prerequisite_policy_; |
+ bool can_run_now_; |
+ int should_run_refcount_; |
+ int eager_refcount_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(PromiseBase); |
+}; |
+ |
+template <typename R> |
+class SCHEDULER_EXPORT Promise : public PromiseBase { |
+ public: |
+ using ReturnType = R; |
+ |
+ // RStorageType = (R == void) ? bool : R; |
+ // This is useful to avoid the need for partial template specalization. |
+ using RStorageType = |
+ typename std::conditional<std::is_void<R>::value, bool, R>::type; |
+ |
+ explicit Promise(PrerequisitePolicy prerequisite_policy) |
+ : PromiseBase(prerequisite_policy) {} |
+ |
+ Promise(std::vector<scoped_refptr<PromiseBase>> prerequisites, |
+ PrerequisitePolicy prerequisite_policy) |
+ : PromiseBase(std::move(prerequisites), prerequisite_policy) {} |
+ |
+ template <typename RR = R> |
+ enable_if_not_void_t<RR, RR&> GetResolved() { |
+ if (r_promise_) |
+ return r_promise_->GetResolved(); |
+ DCHECK(state() == PromiseBase::State::RESOLVED); |
+ return r_; |
+ } |
+ |
+ template <typename RR = R> |
+ enable_if_not_void_t<RR, void> Resolve(const RR&& r) { |
+ r_ = std::move(r); |
+ PromiseBase::MarkAsResolved(); |
+ } |
+ |
+ template <typename RR = R> |
+ enable_if_not_void_t<RR, void> Resolve(RR&& r) { |
+ r_ = std::move(r); |
+ PromiseBase::MarkAsResolved(); |
+ } |
+ |
+ template <typename RR = R> |
+ enable_if_void_t<RR, void> Resolve() { |
+ PromiseBase::MarkAsResolved(); |
+ } |
+ |
+ void Resolve(::promise::Promise<R> promise) { |
+ r_promise_ = std::move(promise.promise_); |
+ prerequisite_policy_ = PrerequisitePolicy::ALL; |
+ state_ = State::PARTIALLY_RESOLVED; |
+ RegisterDynamicDependancy(r_promise_); |
+ } |
+ |
+ bool is_rejected() const { return false; } |
+ |
+ protected: |
+ void ExecutorDrivenResolve() override { NOTREACHED(); } |
+ |
+ RStorageType r_; |
+ scoped_refptr<Promise<R>> r_promise_; |
+ |
+ virtual ~Promise() {} |
+}; |
+ |
+// Partial template specilazation to provide syntatic sugar for Rejectable |
+// promises. |
+template <typename ResolveT, typename RejectT> |
+class SCHEDULER_EXPORT Promise<Rejectable<ResolveT, RejectT>> |
+ : public PromiseBase { |
+ public: |
+ using ReturnType = Rejectable<ResolveT, RejectT>; |
+ |
+ explicit Promise(PrerequisitePolicy prerequisite_policy) |
+ : PromiseBase(prerequisite_policy) {} |
+ |
+ Promise(std::vector<scoped_refptr<PromiseBase>> prerequisites, |
+ PrerequisitePolicy prerequisite_policy) |
+ : PromiseBase(std::move(prerequisites), prerequisite_policy) {} |
+ |
+ ReturnType& GetResolved() { |
+ if (r_promise_) |
+ return r_promise_->GetResolved(); |
+ return r_; |
+ } |
+ |
+ bool is_rejected() const { |
+ if (r_promise_) |
+ return r_promise_->is_rejected(); |
+ return state() == PromiseBase::State::REJECTED; |
+ } |
+ |
+ template <typename RR = ResolveT> |
+ enable_if_not_void_t<RR, void> Resolve(const RR& r) { |
+ r_.Resolve(r); |
+ PromiseBase::MarkAsResolved(); |
+ } |
+ |
+ template <typename RR = ResolveT> |
+ enable_if_not_void_t<RR, void> Resolve(RR&& r) { |
+ r_.Resolve(std::move(r)); |
+ PromiseBase::MarkAsResolved(); |
+ } |
+ |
+ template <typename RR = ResolveT> |
+ enable_if_void_t<RR, void> Resolve() { |
+ r_.Resolve(); |
+ PromiseBase::MarkAsResolved(); |
+ } |
+ |
+ void Resolve(const ReturnType& r) { |
+ r_ = r; |
+ if (r_.is_resolved()) { |
+ PromiseBase::MarkAsResolved(); |
+ } else { |
+ PromiseBase::MarkAsRejected(); |
+ } |
+ } |
+ |
+ void Resolve(ReturnType&& r) { |
+ r_ = std::move(r); |
+ if (r_.is_resolved()) { |
+ PromiseBase::MarkAsResolved(); |
+ } else { |
+ PromiseBase::MarkAsRejected(); |
+ } |
+ } |
+ |
+ template <typename RR = RejectT> |
+ enable_if_not_void_t<RR, void> Reject(const RR& r) { |
+ r_.Reject(r); |
+ PromiseBase::MarkAsRejected(); |
+ } |
+ |
+ template <typename RR = RejectT> |
+ enable_if_not_void_t<RR, void> Reject(RR&& r) { |
+ r_.Reject(std::move(r)); |
+ PromiseBase::MarkAsRejected(); |
+ } |
+ |
+ template <typename RR = RejectT> |
+ enable_if_void_t<RR, void> Reject() { |
+ r_.Reject(); |
+ PromiseBase::MarkAsRejected(); |
+ } |
+ |
+ void Resolve(::promise::Promise<ReturnType> promise) { |
+ r_promise_ = std::move(promise.promise_); |
+ prerequisite_policy_ = PrerequisitePolicy::ALL; |
+ state_ = State::PARTIALLY_RESOLVED; |
+ RegisterDynamicDependancy(r_promise_); |
+ } |
+ |
+ protected: |
+ void ExecutorDrivenResolve() override { |
+ // This can get called if r_promise_ rejects. |
+ DCHECK(state_ == PromiseBase::State::DEPENDENCY_REJECTED); |
+ } |
+ |
+ ReturnType r_; |
+ scoped_refptr<Promise<ReturnType>> r_promise_; |
+ |
+ virtual ~Promise() {} |
+}; |
+ |
+template <typename R, typename... Args> |
+class FunctionPromise final : public Promise<R> { |
+ public: |
+ FunctionPromise(base::Callback<R(Args...)> cb) |
+ : Promise<R>(PromiseBase::PrerequisitePolicy::ALWAYS), cb_(cb) {} |
+ |
+ private: |
+ ~FunctionPromise() override {} |
+ |
+ void ExecutorDrivenResolve() override { |
+ Promise<R>::Resolve(std::move(cb_.Run())); |
+ } |
+ |
+ base::Callback<R(Args...)> cb_; |
+}; |
+ |
+template <typename... Args> |
+class FunctionPromise<void, Args...> final : public Promise<void> { |
+ public: |
+ FunctionPromise(base::Callback<void(Args...)> cb) |
+ : Promise<void>(PromiseBase::PrerequisitePolicy::ALWAYS), cb_(cb) {} |
+ |
+ private: |
+ ~FunctionPromise() override {} |
+ |
+ void ExecutorDrivenResolve() override { |
+ cb_.Run(); |
+ Promise<void>::Resolve(); |
+ } |
+ |
+ base::Callback<void(Args...)> cb_; |
+}; |
+ |
+// === promise::Race().Then() implementation |
+ |
+template <typename ThenR, typename CallbackR, typename AnyPromise> |
+class SCHEDULER_EXPORT RacePromises final : public Promise<ThenR> { |
+ public: |
+ RacePromises(base::Callback<CallbackR(typename AnyPromise::ReturnType)>&& cb, |
+ std::vector<scoped_refptr<PromiseBase>>&& promises) |
+ : Promise<ThenR>(std::move(promises), |
+ PromiseBase::PrerequisitePolicy::ANY), |
+ cb_(std::move(cb)) {} |
+ |
+ private: |
+ template <typename CB = CallbackR> |
+ enable_if_not_void_t<CB, void> ResolveInternal(PromiseBase* prerequisite) { |
+ Promise<ThenR>::Resolve(std::move(cb_.Run( |
+ std::move(static_cast<AnyPromise*>(prerequisite)->GetResolved())))); |
+ } |
+ |
+ template <typename CB = CallbackR> |
+ enable_if_void_t<CB, void> ResolveInternal(PromiseBase* prerequisite) { |
+ cb_.Run(std::move(static_cast<AnyPromise*>(prerequisite)->GetResolved())); |
+ Promise<ThenR>::Resolve(); |
+ } |
+ |
+ void ExecutorDrivenResolve() override { |
+ for (const scoped_refptr<PromiseBase>& prerequisite : |
+ PromiseBase::prerequisites_) { |
+ if (prerequisite->state() == PromiseBase::State::RESOLVED || |
+ prerequisite->state() == PromiseBase::State::REJECTED) { |
+ ResolveInternal(std::move(prerequisite.get())); |
+ return; |
+ } |
+ } |
+ NOTREACHED(); |
+ } |
+ |
+ ~RacePromises() override {} |
+ |
+ base::Callback<CallbackR(typename AnyPromise::ReturnType)> cb_; |
+}; |
+ |
+template <typename ThenR, typename CallbackR> |
+class SCHEDULER_EXPORT RaceVoidPromises final : public Promise<ThenR> { |
+ public: |
+ RaceVoidPromises(base::Callback<CallbackR()>&& cb, |
+ std::vector<scoped_refptr<PromiseBase>>&& promises) |
+ : Promise<ThenR>(std::move(promises), |
+ PromiseBase::PrerequisitePolicy::ANY), |
+ cb_(std::move(cb)) {} |
+ |
+ private: |
+ template <typename CB = CallbackR> |
+ enable_if_not_void_t<CB, void> ResolveInternal() { |
+ Promise<ThenR>::Resolve(std::move(cb_.Run())); |
+ } |
+ |
+ template <typename CB = CallbackR> |
+ enable_if_void_t<CB, void> ResolveInternal() { |
+ cb_.Run(); |
+ Promise<ThenR>::Resolve(); |
+ } |
+ |
+ void ExecutorDrivenResolve() override { |
+ for (const scoped_refptr<PromiseBase>& prerequisite : |
+ PromiseBase::prerequisites_) { |
+ if (prerequisite->state() == PromiseBase::State::RESOLVED) { |
+ ResolveInternal(); |
+ return; |
+ } |
+ } |
+ NOTREACHED(); |
+ } |
+ |
+ ~RaceVoidPromises() override {} |
+ |
+ base::Callback<CallbackR()> cb_; |
+}; |
+ |
+template <typename R> |
+class SCHEDULER_EXPORT RaceSpec { |
+ public: |
+ template <typename RR> |
+ static PromiseBase* GetPromiseBase(RR r) { |
+ return r.promise(); |
+ } |
+ |
+ template <typename... Promises> |
+ RaceSpec(::promise::Promise<R> r, Promises... promises) |
+ : promises_({r.promise(), GetPromiseBase(promises)...}) {} |
+ |
+ template <typename RR = R, typename ThenR> |
+ enable_if_not_void_t<RR, ::promise::Promise<ThenR>> Then( |
+ base::Callback<ThenR(RR)>&& cb) { |
+ return ::promise::Promise<ThenR>(new RacePromises<ThenR, ThenR, Promise<R>>( |
+ std::move(cb), std::move(promises_))); |
+ } |
+ |
+ template <typename ThenR> |
+ ::promise::Promise<ThenR> Then(base::Callback<ThenR()>&& cb) { |
+ return ::promise::Promise<ThenR>(new RaceVoidPromises<ThenR, ThenR>( |
+ std::move(cb), std::move(promises_))); |
+ } |
+ |
+ template <typename RR = R, typename ThenR> |
+ enable_if_not_void_t<RR, ::promise::Promise<ThenR>> Then( |
+ base::Callback<::promise::Promise<ThenR>(RR)>&& cb) { |
+ return ::promise::Promise<ThenR>( |
+ new RacePromises<ThenR, ::promise::Promise<ThenR>, Promise<RR>>( |
+ std::move(cb), std::move(promises_))); |
+ } |
+ |
+ template <typename ThenR> |
+ ::promise::Promise<ThenR> Then( |
+ base::Callback<::promise::Promise<ThenR>()>&& cb) { |
+ return ::promise::Promise<ThenR>( |
+ new RaceVoidPromises<ThenR, ::promise::Promise<ThenR>>( |
+ std::move(cb), std::move(promises_))); |
+ } |
+ |
+ private: |
+ std::vector<scoped_refptr<PromiseBase>> promises_; |
+}; |
+ |
+// === promise::All().Then() implementation |
+ |
+template <typename ThenR, typename CB, typename... Promises> |
+class SCHEDULER_EXPORT RunAfterAllPromises final : public Promise<ThenR> { |
+ public: |
+ RunAfterAllPromises(base::Callback<CB>&& cb, |
+ std::vector<scoped_refptr<PromiseBase>>&& promises) |
+ : Promise<ThenR>(std::move(promises), |
+ PromiseBase::PrerequisitePolicy::ALL), |
+ cb_(std::move(cb)) {} |
+ |
+ private: |
+ template <size_t... Indices, class... Args> |
+ ThenR forward(indices<Indices...>) { |
+ // The PromiseResolver is evaluated for each index in the Indices parameter |
+ // pack. The trailing '...' is the template magic that makes that work. |
+ return cb_.Run(std::move(PromiseResolver<Indices, Promises...>::GetResolved( |
+ PromiseBase::prerequisites_))...); |
+ } |
+ |
+ template <size_t... Indices, class... Args> |
+ void forward_void(indices<Indices...>) { |
+ // The PromiseResolver is evaluated for each index in the Indices parameter |
+ // pack. The trailing '...' is the template magic that makes that work. |
+ cb_.Run(std::move(PromiseResolver<Indices, Promises...>::GetResolved( |
+ PromiseBase::prerequisites_))...); |
+ } |
+ |
+ template <typename ThenRR = ThenR> |
+ enable_if_not_void_t<ThenRR, void> ResolveInternal() { |
+ using Indices = typename make_indices<sizeof...(Promises)>::type; |
+ Promise<ThenRR>::Resolve(std::move(forward(Indices()))); |
+ } |
+ |
+ template <typename ThenRR = ThenR> |
+ enable_if_void_t<ThenRR, void> ResolveInternal() { |
+ using Indices = typename make_indices<sizeof...(Promises)>::type; |
+ forward_void(Indices()); |
+ Promise<ThenRR>::Resolve(); |
+ } |
+ |
+ void ExecutorDrivenResolve() override { ResolveInternal(); } |
+ |
+ ~RunAfterAllPromises() override {} |
+ |
+ base::Callback<CB> cb_; |
+}; |
+ |
+template <typename ThenR, typename CB, typename... Promises> |
+class SCHEDULER_EXPORT RunAfterAllVoidPromises final : public Promise<ThenR> { |
+ public: |
+ RunAfterAllVoidPromises(base::Callback<CB>&& cb, |
+ std::vector<scoped_refptr<PromiseBase>>&& promises) |
+ : Promise<ThenR>(std::move(promises), |
+ PromiseBase::PrerequisitePolicy::ALL), |
+ cb_(std::move(cb)) {} |
+ |
+ private: |
+ template <typename ThenRR = ThenR> |
+ enable_if_not_void_t<ThenRR, void> ResolveInternal() { |
+ Promise<ThenR>::Resolve(std::move(std::move(cb_.Run()))); |
+ } |
+ |
+ template <typename ThenRR = ThenR> |
+ enable_if_void_t<ThenRR, void> ResolveInternal() { |
+ cb_.Run(); |
+ Promise<ThenR>::Resolve(); |
+ } |
+ |
+ void ExecutorDrivenResolve() override { ResolveInternal(); } |
+ |
+ ~RunAfterAllVoidPromises() override {} |
+ |
+ base::Callback<CB> cb_; |
+}; |
+ |
+template <typename... Promises> |
+class SCHEDULER_EXPORT AllSpec { |
+ public: |
+ template <typename R> |
+ static PromiseBase* GetPromiseBase(R r) { |
+ return r.promise(); |
+ } |
+ |
+ AllSpec(Promises... promises) : promises_({GetPromiseBase(promises)...}) {} |
+ |
+ template <typename ThenR, typename... ThenArgs> |
+ scoped_refptr<Promise<ThenR>> Then(base::Callback<ThenR(ThenArgs...)>&& cb) { |
+ static_assert( |
+ sizeof...(ThenArgs) == sizeof...(Promises), |
+ "Must have the same number of promises and callback arguments"); |
+ static_assert(sizeof...(Promises) > 0, |
+ "Must have at least one promise to wait on"); |
+ return make_scoped_refptr<Promise<ThenR>>( |
+ new RunAfterAllPromises<ThenR, ThenR(ThenArgs...), Promises...>( |
+ std::move(cb), std::move(promises_))); |
+ } |
+ |
+ template <typename ThenR> |
+ scoped_refptr<Promise<ThenR>> Then(base::Callback<ThenR()>&& cb) { |
+ static_assert(sizeof...(Promises) > 0, |
+ "Must have at least one promise to wait on"); |
+ return make_scoped_refptr<Promise<ThenR>>( |
+ new RunAfterAllVoidPromises<ThenR, ThenR(), Promises...>( |
+ std::move(cb), std::move(promises_))); |
+ } |
+ |
+ private: |
+ std::vector<scoped_refptr<PromiseBase>> promises_; |
+}; |
+ |
+} // namespace internal |
+} // namespace promise |
+ |
+#endif // COMPONENTS_SCHEDULER_PROMISES_PROMISE_INTERNAL_H_ |