| 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_
|
|
|