Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Unified Diff: components/scheduler/promises/promise_internal.h

Issue 1401553002: NOT INTENDED FOR LANDING: A promises demo (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Support for rejectatble promises! Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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_
« no previous file with comments | « components/scheduler/promises/promise_executor.cc ('k') | components/scheduler/promises/promise_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698