blob: eb2a924f33718bfea694acc86bbdc429717a449c [file] [log] [blame]
// Copyright 2019 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 BASE_TASK_PROMISE_ALL_CONTAINER_EXECUTOR_H_
#define BASE_TASK_PROMISE_ALL_CONTAINER_EXECUTOR_H_
#include <tuple>
#include "base/task/promise/abstract_promise.h"
#include "base/task/promise/helpers.h"
#include "base/task/promise/no_op_promise_executor.h"
namespace base {
namespace internal {
// For Promises::All(std::vector<Promise<T>& promises)
template <typename ResolveType, typename RejectType>
class AllContainerPromiseExecutor {
public:
bool IsCancelled() const { return false; }
static constexpr PromiseExecutor::PrerequisitePolicy kPrerequisitePolicy =
PromiseExecutor::PrerequisitePolicy::kAll;
struct VoidResolveType {};
struct NonVoidResolveType {};
using ResolveTypeTag = std::conditional_t<std::is_void<ResolveType>::value,
VoidResolveType,
NonVoidResolveType>;
void Execute(AbstractPromise* promise) {
// All is rejected if any prerequisites are rejected.
AbstractPromise* first_settled = promise->GetFirstSettledPrerequisite();
if (first_settled && first_settled->IsRejected()) {
AllPromiseRejectHelper<Rejected<RejectType>>::Reject(promise,
first_settled);
return;
}
ResolveInternal(promise, ResolveTypeTag());
}
#if DCHECK_IS_ON()
PromiseExecutor::ArgumentPassingType ResolveArgumentPassingType() const {
return UseMoveSemantics<ResolveType>::argument_passing_type;
}
PromiseExecutor::ArgumentPassingType RejectArgumentPassingType() const {
return UseMoveSemantics<RejectType>::argument_passing_type;
}
bool CanResolve() const {
return !std::is_same<ResolveType, NoResolve>::value;
}
bool CanReject() const { return !std::is_same<RejectType, NoReject>::value; }
#endif
private:
// For containers of Promise<void> there is no point resolving with
// std::vector<Void>.
void ResolveInternal(AbstractPromise* promise, VoidResolveType) {
promise->emplace(Resolved<void>());
}
void ResolveInternal(AbstractPromise* promise, NonVoidResolveType) {
using NonVoidResolveType = ToNonVoidT<ResolveType>;
Resolved<std::vector<NonVoidResolveType>> result;
const std::vector<DependentList::Node>* prerequisite_list =
promise->prerequisite_list();
DCHECK(prerequisite_list);
result.value.reserve(prerequisite_list->size());
for (const auto& node : *prerequisite_list) {
DCHECK(node.prerequisite()->IsResolved());
result.value.push_back(
ArgMoveSemanticsHelper<
NonVoidResolveType,
Resolved<NonVoidResolveType>>::Get(node.prerequisite()));
}
promise->emplace(std::move(result));
}
};
template <typename Container, typename ContainerT>
struct AllContainerHelper;
template <typename Container, typename ResolveType, typename RejectType>
struct AllContainerHelper<Container, Promise<ResolveType, RejectType>> {
using PromiseResolve = std::vector<ToNonVoidT<ResolveType>>;
// As an optimization we don't return std::vector<ResolveType> for void
// ResolveType.
using PromiseType = std::conditional_t<std::is_void<ResolveType>::value,
Promise<void, RejectType>,
Promise<PromiseResolve, RejectType>>;
static PromiseType All(const Location& from_here, const Container& promises) {
size_t i = 0;
std::vector<DependentList::Node> prerequisite_list(promises.size());
// TODO(alexclarke): Move construction of this list and AbstractPromise out
// of line to reduce template bloat.
for (auto& promise : promises) {
prerequisite_list[i++].SetPrerequisite(promise.abstract_promise_.get());
}
internal::PromiseExecutor::Data executor_data(
(in_place_type_t<
AllContainerPromiseExecutor<ResolveType, RejectType>>()));
return PromiseType(AbstractPromise::Create(
nullptr, from_here,
std::make_unique<AbstractPromise::AdjacencyList>(
std::move(prerequisite_list)),
RejectPolicy::kMustCatchRejection, DependentList::ConstructUnresolved(),
std::move(executor_data)));
}
};
// TODO(alexclarke): Maybe specalize to support containers of variants.
// E.g. Promises::All(std::vector<Variant<Promise<T>...>>& promises)
} // namespace internal
} // namespace base
#endif // BASE_TASK_PROMISE_ALL_CONTAINER_EXECUTOR_H_