summaryrefslogtreecommitdiffstats
path: root/chromium/base/task/promise
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-01-23 17:21:03 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-01-23 16:25:15 +0000
commitc551f43206405019121bd2b2c93714319a0a3300 (patch)
tree1f48c30631c421fd4bbb3c36da20183c8a2ed7d7 /chromium/base/task/promise
parent7961cea6d1041e3e454dae6a1da660b453efd238 (diff)
BASELINE: Update Chromium to 79.0.3945.139
Change-Id: I336b7182fab9bca80b709682489c07db112eaca5 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/base/task/promise')
-rw-r--r--chromium/base/task/promise/abstract_promise.cc67
-rw-r--r--chromium/base/task/promise/abstract_promise.h208
-rw-r--r--chromium/base/task/promise/abstract_promise_unittest.cc13
-rw-r--r--chromium/base/task/promise/dependent_list.h2
-rw-r--r--chromium/base/task/promise/finally_executor.h12
-rw-r--r--chromium/base/task/promise/helpers.cc50
-rw-r--r--chromium/base/task/promise/helpers.h146
-rw-r--r--chromium/base/task/promise/helpers_unittest.cc17
-rw-r--r--chromium/base/task/promise/no_op_promise_executor.cc13
-rw-r--r--chromium/base/task/promise/no_op_promise_executor.h8
-rw-r--r--chromium/base/task/promise/post_task_executor.h12
-rw-r--r--chromium/base/task/promise/post_task_executor_unittest.cc22
-rw-r--r--chromium/base/task/promise/promise.h335
-rw-r--r--chromium/base/task/promise/promise_unittest.cc88
-rw-r--r--chromium/base/task/promise/promise_value.h6
-rw-r--r--chromium/base/task/promise/then_and_catch_executor.cc18
-rw-r--r--chromium/base/task/promise/then_and_catch_executor.h87
17 files changed, 781 insertions, 323 deletions
diff --git a/chromium/base/task/promise/abstract_promise.cc b/chromium/base/task/promise/abstract_promise.cc
index f48ba8517e2..315cfd30bfc 100644
--- a/chromium/base/task/promise/abstract_promise.cc
+++ b/chromium/base/task/promise/abstract_promise.cc
@@ -8,6 +8,7 @@
#include "base/lazy_instance.h"
#include "base/sequenced_task_runner.h"
#include "base/task/promise/dependent_list.h"
+#include "base/task/promise/post_task_executor.h"
#include "base/threading/sequenced_task_runner_handle.h"
namespace base {
@@ -65,6 +66,10 @@ AbstractPromise::~AbstractPromise() {
OnCanceled();
}
+void AbstractPromise::EmplaceResolvedVoid() {
+ emplace(Resolved<void>());
+}
+
bool AbstractPromise::IsCanceled() const {
if (dependents_.IsCanceled())
return true;
@@ -290,7 +295,7 @@ AbstractPromise* AbstractPromise::GetCurriedPromise() {
const PromiseExecutor* AbstractPromise::GetExecutor() const {
if (!value_.ContainsPromiseExecutor())
return nullptr;
- return value_.Get<internal::PromiseExecutor>();
+ return value_.Get<PromiseExecutor>();
}
PromiseExecutor::PrerequisitePolicy AbstractPromise::GetPrerequisitePolicy() {
@@ -509,7 +514,7 @@ void AbstractPromise::OnRejectMakeDependantsUseCurriedPrerequisite(
void AbstractPromise::DispatchPromise() {
if (task_runner_) {
- task_runner_->PostPromiseInternal(this, TimeDelta());
+ task_runner_->PostPromiseInternal(WrappedPromise(this), TimeDelta());
} else {
Execute();
}
@@ -670,14 +675,66 @@ void AbstractPromise::AdjacencyList::Clear() {
prerequisite_list_.clear();
} else {
// If there's multiple prerequisites we can't do that because the
- // DependentList::Nodes may still be in use by some of them. Instead we
- // release our prerequisite references and rely on refcounting to release
- // the owning AbstractPromise.
+ // DependentList::Nodes may still be in use by some of them.
+ // Instead we release our prerequisite references and rely on refcounting to
+ // release the owning AbstractPromise.
for (DependentList::Node& node : prerequisite_list_) {
node.ClearPrerequisite();
}
}
}
+BasePromise::BasePromise() = default;
+
+BasePromise::BasePromise(
+ scoped_refptr<internal::AbstractPromise> abstract_promise)
+ : abstract_promise_(std::move(abstract_promise)) {}
+
+BasePromise::BasePromise(const BasePromise& other) = default;
+BasePromise::BasePromise(BasePromise&& other) = default;
+
+BasePromise& BasePromise::operator=(const BasePromise& other) = default;
+BasePromise& BasePromise::operator=(BasePromise&& other) = default;
+
+BasePromise::~BasePromise() = default;
+
} // namespace internal
+
+WrappedPromise::WrappedPromise() = default;
+
+WrappedPromise::WrappedPromise(scoped_refptr<internal::AbstractPromise> promise)
+ : promise_(std::move(promise)) {}
+
+WrappedPromise::WrappedPromise(internal::PassedPromise&& passed_promise)
+ : promise_(passed_promise.Release(), subtle::kAdoptRefTag) {
+ DCHECK(promise_);
+}
+
+WrappedPromise::WrappedPromise(const Location& from_here, OnceClosure task)
+ : WrappedPromise(internal::AbstractPromise::CreateNoPrerequisitePromise(
+ from_here,
+ RejectPolicy::kMustCatchRejection,
+ internal::DependentList::ConstructUnresolved(),
+ internal::PromiseExecutor::Data(
+ base::in_place_type_t<internal::PostTaskExecutor<void>>(),
+ std::move(task)))) {}
+
+WrappedPromise::WrappedPromise(const WrappedPromise& other) = default;
+WrappedPromise::WrappedPromise(WrappedPromise&& other) = default;
+
+WrappedPromise& WrappedPromise::operator=(const WrappedPromise& other) =
+ default;
+WrappedPromise& WrappedPromise::operator=(WrappedPromise&& other) = default;
+
+WrappedPromise::~WrappedPromise() = default;
+
+void WrappedPromise::Execute() {
+ DCHECK(promise_);
+ promise_->Execute();
+}
+
+void WrappedPromise::Clear() {
+ promise_ = nullptr;
+}
+
} // namespace base
diff --git a/chromium/base/task/promise/abstract_promise.h b/chromium/base/task/promise/abstract_promise.h
index 9f67c688bd4..c16132c187c 100644
--- a/chromium/base/task/promise/abstract_promise.h
+++ b/chromium/base/task/promise/abstract_promise.h
@@ -23,6 +23,9 @@ class TaskRunner;
template <typename ResolveType, typename RejectType>
class ManualPromiseResolver;
+template <typename ResolveType, typename RejectType>
+class Promise;
+
// AbstractPromise Memory Management.
//
// Consider a chain of promises: P1, P2 & P3
@@ -265,13 +268,71 @@ enum class RejectPolicy {
kCatchNotRequired,
};
+class WrappedPromise;
+
namespace internal {
template <typename T, typename... Args>
class PromiseCallbackHelper;
-class PromiseHolder;
+class AbstractPromise;
class AbstractPromiseTest;
+class BasePromise;
+
+// A binary size optimization to reduce the overhead of passing a scoped_refptr
+// to Promise<> returned by PostTask. There are many thousands of PostTasks so
+// even a single extra instruction (such as the scoped_refptr move constructor
+// clearing the pointer) adds up. This is why we're not constructing a Promise<>
+// with a scoped_refptr.
+//
+// The constructor calls AddRef, it's up to the owner of this object to either
+// call Clear (which calls Release) or AbstractPromise in order to pass
+// ownership onto a WrappedPromise.
+class BASE_EXPORT PassedPromise {
+ public:
+ explicit inline PassedPromise(const scoped_refptr<AbstractPromise>& promise);
+
+ PassedPromise() : promise_(nullptr) {}
+
+ PassedPromise(const PassedPromise&) = delete;
+ PassedPromise& operator=(const PassedPromise&) = delete;
+
+#if DCHECK_IS_ON()
+ PassedPromise(PassedPromise&& other) noexcept : promise_(other.promise_) {
+ DCHECK(promise_);
+ other.promise_ = nullptr;
+ }
+
+ PassedPromise& operator=(PassedPromise&& other) noexcept {
+ DCHECK(!promise_);
+ promise_ = other.promise_;
+ DCHECK(promise_);
+ other.promise_ = nullptr;
+ return *this;
+ }
+
+ ~PassedPromise() {
+ DCHECK(!promise_) << "The PassedPromise must be Cleared or passed onto a "
+ "Wrapped Promise";
+ }
+#else
+ PassedPromise(PassedPromise&&) noexcept = default;
+ PassedPromise& operator=(PassedPromise&&) noexcept = default;
+#endif
+
+ AbstractPromise* Release() {
+ AbstractPromise* promise = promise_;
+#if DCHECK_IS_ON()
+ promise_ = nullptr;
+#endif
+ return promise;
+ }
+
+ AbstractPromise* get() const { return promise_; }
+
+ private:
+ AbstractPromise* promise_;
+};
// Internal promise representation, maintains a graph of dependencies and posts
// promises as they become ready. In debug builds various sanity checks are
@@ -308,12 +369,11 @@ class BASE_EXPORT AbstractPromise
RejectPolicy reject_policy,
ConstructType tag,
PromiseExecutor::Data&& executor_data) noexcept {
- scoped_refptr<AbstractPromise> promise =
- subtle::AdoptRefIfNeeded(new internal::AbstractPromise(
- nullptr, from_here, nullptr, reject_policy,
- tag, std::move(executor_data)),
- AbstractPromise::kRefCountPreference);
- return promise;
+ return subtle::AdoptRefIfNeeded(
+ new internal::AbstractPromise(nullptr, from_here, nullptr,
+ reject_policy, tag,
+ std::move(executor_data)),
+ AbstractPromise::kRefCountPreference);
}
AbstractPromise(const AbstractPromise&) = delete;
@@ -347,7 +407,9 @@ class BASE_EXPORT AbstractPromise
public:
PromiseValue& value() { return value_; }
+#if DCHECK_IS_ON()
~ValueHandle() { value_.reset(); }
+#endif
private:
friend class AbstractPromise;
@@ -357,6 +419,8 @@ class BASE_EXPORT AbstractPromise
PromiseValue& value_;
};
+ // Used for promise results that require move semantics. E.g. a promise chain
+ // involving a std::unique_ptr<>.
ValueHandle TakeValue() { return ValueHandle(value_); }
// Returns nullptr if there isn't a curried promise.
@@ -380,6 +444,10 @@ class BASE_EXPORT AbstractPromise
"Use scoped_refptr<AbstractPromise> instead");
}
+ // An out-of line emplace(Resolved<void>()); Useful for reducing binary
+ // bloat in executor templates.
+ void EmplaceResolvedVoid();
+
// This is separate from AbstractPromise to reduce the memory footprint of
// regular PostTask without promise chains.
class BASE_EXPORT AdjacencyList {
@@ -457,9 +525,14 @@ class BASE_EXPORT AbstractPromise
void IgnoreUncaughtCatchForTesting();
- private:
- friend class AbstractPromiseTest;
+ // Signals that this promise was cancelled. If executor hasn't run yet, this
+ // will prevent it from running and cancels any dependent promises unless they
+ // have PrerequisitePolicy::kAny, in which case they will only be canceled if
+ // all of their prerequisites are canceled. If OnCanceled() or OnResolved() or
+ // OnRejected() has already run, this does nothing.
+ void OnCanceled();
+ private:
friend base::RefCountedThreadSafe<AbstractPromise>;
friend class AbstractPromiseTest;
@@ -470,8 +543,6 @@ class BASE_EXPORT AbstractPromise
template <typename T, typename... Args>
friend class PromiseCallbackHelper;
- friend class PromiseHolder;
-
template <typename ConstructType>
AbstractPromise(const scoped_refptr<TaskRunner>& task_runner,
const Location& from_here,
@@ -520,13 +591,6 @@ class BASE_EXPORT AbstractPromise
// have been canceled, in which case null is returned.
AbstractPromise* FindCurriedAncestor();
- // Signals that this promise was cancelled. If executor hasn't run yet, this
- // will prevent it from running and cancels any dependent promises unless they
- // have PrerequisitePolicy::kAny, in which case they will only be canceled if
- // all of their prerequisites are canceled. If OnCanceled() or OnResolved() or
- // OnRejected() has already run, this does nothing.
- void OnCanceled();
-
// Signals that |value_| now contains a resolve value. Dependent promises may
// scheduled for execution.
void OnResolved();
@@ -714,7 +778,115 @@ class BASE_EXPORT AbstractPromise
std::unique_ptr<AdjacencyList> prerequisites_;
};
+PassedPromise::PassedPromise(const scoped_refptr<AbstractPromise>& promise)
+ : promise_(promise.get()) {
+ promise_->AddRef();
+}
+
+// Non-templatized base class of the Promise<> template. This is a binary size
+// optimization, letting us use an out of line destructor in the template
+// instead of the more complex scoped_refptr<> destructor.
+class BASE_EXPORT BasePromise {
+ public:
+ BasePromise();
+
+ BasePromise(const BasePromise& other);
+ BasePromise(BasePromise&& other) noexcept;
+
+ BasePromise& operator=(const BasePromise& other);
+ BasePromise& operator=(BasePromise&& other) noexcept;
+
+ // We want an out of line destructor to reduce binary size.
+ ~BasePromise();
+
+ // Returns true if the promise is not null.
+ operator bool() const { return abstract_promise_.get(); }
+
+ protected:
+ struct InlineConstructor {};
+
+ explicit BasePromise(
+ scoped_refptr<internal::AbstractPromise> abstract_promise);
+
+ // We want this to be inlined to reduce binary size for the Promise<>
+ // constructor. Its a template to bypass ChromiumStyle plugin which otherwise
+ // insists this is out of line.
+ template <typename T>
+ explicit BasePromise(internal::PassedPromise&& passed_promise,
+ T InlineConstructor)
+ : abstract_promise_(passed_promise.Release(), subtle::kAdoptRefTag) {}
+
+ scoped_refptr<internal::AbstractPromise> abstract_promise_;
+};
+
} // namespace internal
+
+// Wrapper around scoped_refptr<base::internal::AbstractPromise> which is
+// intended for use by TaskRunner implementations.
+class BASE_EXPORT WrappedPromise {
+ public:
+ WrappedPromise();
+
+ explicit WrappedPromise(scoped_refptr<internal::AbstractPromise> promise);
+
+ WrappedPromise(const WrappedPromise& other);
+ WrappedPromise(WrappedPromise&& other) noexcept;
+
+ WrappedPromise& operator=(const WrappedPromise& other);
+ WrappedPromise& operator=(WrappedPromise&& other) noexcept;
+
+ explicit WrappedPromise(internal::PassedPromise&& passed_promise);
+
+ // Constructs a promise to run |task|.
+ WrappedPromise(const Location& from_here, OnceClosure task);
+
+ // If the WrappedPromise hasn't been executed, cleared or taken by
+ // TakeForTesting, it will be canceled to prevent memory leaks of dependent
+ // tasks that will never run.
+ ~WrappedPromise();
+
+ // Returns true if the promise is not null.
+ operator bool() const { return promise_.get(); }
+
+ bool IsCanceled() const {
+ DCHECK(promise_);
+ return promise_->IsCanceled();
+ }
+
+ void OnCanceled() {
+ DCHECK(promise_);
+ promise_->OnCanceled();
+ }
+
+ // Can only be called once, clears |promise_| after execution.
+ void Execute();
+
+ // Clears |promise_|.
+ void Clear();
+
+ const Location& from_here() const {
+ DCHECK(promise_);
+ return promise_->from_here();
+ }
+
+ scoped_refptr<internal::AbstractPromise>& GetForTesting() { return promise_; }
+
+ scoped_refptr<internal::AbstractPromise> TakeForTesting() {
+ return std::move(promise_);
+ }
+
+ private:
+ template <typename ResolveType, typename RejectType>
+ friend class Promise;
+
+ template <typename T, typename... Args>
+ friend class internal::PromiseCallbackHelper;
+
+ friend class Promises;
+
+ scoped_refptr<internal::AbstractPromise> promise_;
+};
+
} // namespace base
#endif // BASE_TASK_PROMISE_ABSTRACT_PROMISE_H_
diff --git a/chromium/base/task/promise/abstract_promise_unittest.cc b/chromium/base/task/promise/abstract_promise_unittest.cc
index ea8d31fd898..5cbe4498d54 100644
--- a/chromium/base/task/promise/abstract_promise_unittest.cc
+++ b/chromium/base/task/promise/abstract_promise_unittest.cc
@@ -238,10 +238,13 @@ class AbstractPromiseTest : public testing::Test {
#endif
std::move(settings.callback));
- return AbstractPromise::Create(
- settings.task_runner, settings.from_here,
- std::move(settings.prerequisites), settings.reject_policy,
- DependentList::ConstructUnresolved(), std::move(executor_data));
+ return WrappedPromise(AbstractPromise::Create(
+ settings.task_runner, settings.from_here,
+ std::move(settings.prerequisites),
+ settings.reject_policy,
+ DependentList::ConstructUnresolved(),
+ std::move(executor_data)))
+ .TakeForTesting();
}
PromiseSettings settings;
@@ -293,7 +296,7 @@ class AbstractPromiseTest : public testing::Test {
PromiseSettingsBuilder AllPromise(
Location from_here,
- std::vector<internal::DependentList::Node> prerequisite_list) {
+ std::vector<DependentList::Node> prerequisite_list) {
PromiseSettingsBuilder builder(
from_here, std::make_unique<AbstractPromise::AdjacencyList>(
std::move(prerequisite_list)));
diff --git a/chromium/base/task/promise/dependent_list.h b/chromium/base/task/promise/dependent_list.h
index 020bdbfc77f..3245c1cb48f 100644
--- a/chromium/base/task/promise/dependent_list.h
+++ b/chromium/base/task/promise/dependent_list.h
@@ -59,7 +59,7 @@ class BASE_EXPORT DependentList {
// Align Node on an 8-byte boundary to ensure the first 3 bits are 0 and can
// be used to store additional state (see static_asserts below).
- class BASE_EXPORT alignas(8) Node {
+ class BASE_EXPORT ALIGNAS(8) Node {
public:
Node();
explicit Node(Node&& other) noexcept;
diff --git a/chromium/base/task/promise/finally_executor.h b/chromium/base/task/promise/finally_executor.h
index 7dc1c798a5c..a80f81c5ee9 100644
--- a/chromium/base/task/promise/finally_executor.h
+++ b/chromium/base/task/promise/finally_executor.h
@@ -43,9 +43,15 @@ class FinallyExecutor {
void Execute(AbstractPromise* promise) {
AbstractPromise* prerequisite = promise->GetOnlyPrerequisite();
- CallbackT* resolve_executor = static_cast<CallbackT*>(&common_.callback_);
- RunHelper<CallbackT, void, ResolveStorage, RejectStorage>::Run(
- std::move(*resolve_executor), prerequisite, promise);
+ // Internally RunHelper uses const RepeatingCallback<>& to avoid the
+ // binary size overhead of moving a scoped_refptr<> about. We respect
+ // the onceness of the callback and RunHelper will overwrite the callback
+ // with the result.
+ using RepeatingCB = typename ToRepeatingCallback<CallbackT>::value;
+ RepeatingCB* resolve_executor =
+ static_cast<RepeatingCB*>(&common_.callback_);
+ RunHelper<RepeatingCB, void, ResolveStorage, RejectStorage>::Run(
+ *resolve_executor, prerequisite, promise);
}
#if DCHECK_IS_ON()
diff --git a/chromium/base/task/promise/helpers.cc b/chromium/base/task/promise/helpers.cc
index 8a68a123956..f100cac0c29 100644
--- a/chromium/base/task/promise/helpers.cc
+++ b/chromium/base/task/promise/helpers.cc
@@ -11,32 +11,11 @@
namespace base {
namespace internal {
-PromiseHolder::PromiseHolder(scoped_refptr<AbstractPromise> promise)
- : promise_(std::move(promise)) {}
-
-PromiseHolder::~PromiseHolder() {
- // Detect if the promise was not executed and if so cancel to ensure memory
- // is released.
- if (promise_)
- promise_->OnCanceled();
-}
-
-PromiseHolder::PromiseHolder(PromiseHolder&& other)
- : promise_(std::move(other.promise_)) {}
-
-scoped_refptr<AbstractPromise> PromiseHolder::Unwrap() const {
- return std::move(promise_);
-}
-
-scoped_refptr<TaskRunner> GetCurrentSequence() {
- return SequencedTaskRunnerHandle::Get();
-}
-
DoNothing ToCallbackBase(DoNothing task) {
return task;
}
-scoped_refptr<AbstractPromise> ConstructAbstractPromiseWithSinglePrerequisite(
+PassedPromise ConstructAbstractPromiseWithSinglePrerequisite(
const scoped_refptr<TaskRunner>& task_runner,
const Location& from_here,
AbstractPromise* prerequisite,
@@ -46,26 +25,35 @@ scoped_refptr<AbstractPromise> ConstructAbstractPromiseWithSinglePrerequisite(
if (!prerequisite) {
// Ensure the destructor for |executor_data| runs.
PromiseExecutor dummy_executor(std::move(executor_data));
- return nullptr;
+ return PassedPromise();
}
- return AbstractPromise::Create(
+ return PassedPromise(AbstractPromise::Create(
task_runner, from_here,
std::make_unique<AbstractPromise::AdjacencyList>(prerequisite),
RejectPolicy::kMustCatchRejection,
- internal::DependentList::ConstructUnresolved(), std::move(executor_data));
+ internal::DependentList::ConstructUnresolved(),
+ std::move(executor_data)));
}
-scoped_refptr<AbstractPromise> ConstructManualPromiseResolverPromise(
+PassedPromise ConstructHereAbstractPromiseWithSinglePrerequisite(
const Location& from_here,
- RejectPolicy reject_policy,
- bool can_resolve,
- bool can_reject) {
- return AbstractPromise::CreateNoPrerequisitePromise(
+ AbstractPromise* prerequisite,
+ internal::PromiseExecutor::Data&& executor_data) noexcept {
+ return ConstructAbstractPromiseWithSinglePrerequisite(
+ SequencedTaskRunnerHandle::Get(), from_here, prerequisite,
+ std::move(executor_data));
+}
+
+PassedPromise ConstructManualPromiseResolverPromise(const Location& from_here,
+ RejectPolicy reject_policy,
+ bool can_resolve,
+ bool can_reject) {
+ return PassedPromise(AbstractPromise::CreateNoPrerequisitePromise(
from_here, reject_policy, internal::DependentList::ConstructUnresolved(),
internal::PromiseExecutor::Data(
in_place_type_t<internal::NoOpPromiseExecutor>(), can_resolve,
- can_reject));
+ can_reject)));
}
} // namespace internal
diff --git a/chromium/base/task/promise/helpers.h b/chromium/base/task/promise/helpers.h
index 29cb49011ab..87d9ff64bec 100644
--- a/chromium/base/task/promise/helpers.h
+++ b/chromium/base/task/promise/helpers.h
@@ -19,11 +19,6 @@ class DoNothing;
namespace internal {
-// A wrapper around SequencedTaskRunnerHandle::Get(). This file is included by
-// base/task_runner.h which means we can't include anything that depends on
-// that!
-scoped_refptr<TaskRunner> BASE_EXPORT GetCurrentSequence();
-
template <typename T>
using ToNonVoidT = std::conditional_t<std::is_void<T>::value, Void, T>;
@@ -412,9 +407,26 @@ class ArgMoveSemanticsHelper {
}
};
+// Helper for converting a callback to its repeating variant.
+template <typename Cb>
+struct ToRepeatingCallback;
+
+template <typename Cb>
+struct ToRepeatingCallback<OnceCallback<Cb>> {
+ using value = RepeatingCallback<Cb>;
+};
+
+template <typename Cb>
+struct ToRepeatingCallback<RepeatingCallback<Cb>> {
+ using value = RepeatingCallback<Cb>;
+};
+
// Helper for running a promise callback and storing the result if any.
//
-// Callback = signature of the callback to execute,
+// Callback = signature of the callback to execute. Note we use repeating
+// callbacks to avoid the binary size overhead of a once callback which will
+// generate a destructor which is redundant because we overwrite the executor
+// with the promise result which also triggers the destructor.
// ArgStorageType = type of the callback parameter (or void if none)
// ResolveStorage = type to use for resolve, usually Resolved<T>.
// RejectStorage = type to use for reject, usually Rejected<T>.
@@ -431,18 +443,18 @@ template <typename CbResult,
typename ArgStorageType,
typename ResolveStorage,
typename RejectStorage>
-struct RunHelper<OnceCallback<CbResult(CbArg)>,
+struct RunHelper<RepeatingCallback<CbResult(CbArg)>,
ArgStorageType,
ResolveStorage,
RejectStorage> {
- using Callback = OnceCallback<CbResult(CbArg)>;
+ using Callback = RepeatingCallback<CbResult(CbArg)>;
- static void Run(Callback&& executor,
+ static void Run(const Callback& executor,
AbstractPromise* arg,
AbstractPromise* result) {
EmplaceHelper<ResolveStorage, RejectStorage>::Emplace(
- result, std::move(executor).Run(
- ArgMoveSemanticsHelper<CbArg, ArgStorageType>::Get(arg)));
+ result,
+ executor.Run(ArgMoveSemanticsHelper<CbArg, ArgStorageType>::Get(arg)));
}
};
@@ -451,19 +463,18 @@ template <typename CbArg,
typename ArgStorageType,
typename ResolveStorage,
typename RejectStorage>
-struct RunHelper<OnceCallback<void(CbArg)>,
+struct RunHelper<RepeatingCallback<void(CbArg)>,
ArgStorageType,
ResolveStorage,
RejectStorage> {
- using Callback = OnceCallback<void(CbArg)>;
+ using Callback = RepeatingCallback<void(CbArg)>;
- static void Run(Callback&& executor,
+ static void Run(const Callback& executor,
AbstractPromise* arg,
AbstractPromise* result) {
static_assert(std::is_void<typename ResolveStorage::Type>::value, "");
- std::move(executor).Run(
- ArgMoveSemanticsHelper<CbArg, ArgStorageType>::Get(arg));
- result->emplace(Resolved<void>());
+ executor.Run(ArgMoveSemanticsHelper<CbArg, ArgStorageType>::Get(arg));
+ result->EmplaceResolvedVoid();
}
};
@@ -472,17 +483,17 @@ template <typename CbResult,
typename ArgStorageType,
typename ResolveStorage,
typename RejectStorage>
-struct RunHelper<OnceCallback<CbResult()>,
+struct RunHelper<RepeatingCallback<CbResult()>,
ArgStorageType,
ResolveStorage,
RejectStorage> {
- using Callback = OnceCallback<CbResult()>;
+ using Callback = RepeatingCallback<CbResult()>;
- static void Run(Callback&& executor,
+ static void Run(const Callback& executor,
AbstractPromise* arg,
AbstractPromise* result) {
- EmplaceHelper<ResolveStorage, RejectStorage>::Emplace(
- result, std::move(executor).Run());
+ EmplaceHelper<ResolveStorage, RejectStorage>::Emplace(result,
+ executor.Run());
}
};
@@ -490,16 +501,16 @@ struct RunHelper<OnceCallback<CbResult()>,
template <typename ArgStorageType,
typename ResolveStorage,
typename RejectStorage>
-struct RunHelper<OnceCallback<void()>,
+struct RunHelper<RepeatingCallback<void()>,
ArgStorageType,
ResolveStorage,
RejectStorage> {
- static void Run(OnceCallback<void()>&& executor,
+ static void Run(const RepeatingCallback<void()>& executor,
AbstractPromise* arg,
AbstractPromise* result) {
static_assert(std::is_void<typename ResolveStorage::Type>::value, "");
- std::move(executor).Run();
- result->emplace(Resolved<void>());
+ executor.Run();
+ result->EmplaceResolvedVoid();
}
};
@@ -538,79 +549,51 @@ template <typename CbResult,
typename... CbArgs,
typename ResolveStorage,
typename RejectStorage>
-struct RunHelper<OnceCallback<CbResult(CbArgs...)>,
+struct RunHelper<RepeatingCallback<CbResult(CbArgs...)>,
Resolved<std::tuple<CbArgs...>>,
ResolveStorage,
RejectStorage> {
- using Callback = OnceCallback<CbResult(CbArgs...)>;
+ using Callback = RepeatingCallback<CbResult(CbArgs...)>;
using StorageType = Resolved<std::tuple<CbArgs...>>;
using IndexSequence = std::index_sequence_for<CbArgs...>;
- static void Run(Callback&& executor,
+ static void Run(const Callback& executor,
AbstractPromise* arg,
AbstractPromise* result) {
AbstractPromise::ValueHandle value = arg->TakeValue();
std::tuple<CbArgs...>& tuple = value.value().Get<StorageType>()->value;
- RunInternal(std::move(executor), tuple, result,
+ RunInternal(executor, tuple, result,
std::integral_constant<bool, std::is_void<CbResult>::value>(),
IndexSequence{});
}
private:
template <typename Callback, size_t... Indices>
- static void RunInternal(Callback&& executor,
+ static void RunInternal(const Callback& executor,
std::tuple<CbArgs...>& tuple,
AbstractPromise* result,
std::false_type void_result,
std::index_sequence<Indices...>) {
- EmplaceHelper<ResolveStorage, RejectStorage>::Emplace(
- std::move(executor).Run(
- TupleArgMoveSemanticsHelper<Callback, std::tuple<CbArgs...>,
- Indices>::Get(tuple)...));
+ EmplaceHelper<ResolveStorage, RejectStorage>::Emplace(executor.Run(
+ TupleArgMoveSemanticsHelper<Callback, std::tuple<CbArgs...>,
+ Indices>::Get(tuple)...));
}
template <typename Callback, size_t... Indices>
- static void RunInternal(Callback&& executor,
+ static void RunInternal(const Callback& executor,
std::tuple<CbArgs...>& tuple,
AbstractPromise* result,
std::true_type void_result,
std::index_sequence<Indices...>) {
- std::move(executor).Run(
- TupleArgMoveSemanticsHelper<Callback, std::tuple<CbArgs...>,
- Indices>::Get(tuple)...);
- result->emplace(Resolved<void>());
+ executor.Run(TupleArgMoveSemanticsHelper<Callback, std::tuple<CbArgs...>,
+ Indices>::Get(tuple)...);
+ result->EmplaceResolvedVoid();
}
};
-// For use with base::Bind*. Cancels the promise if the callback was not run by
-// the time the callback is deleted.
-class BASE_EXPORT PromiseHolder {
- public:
- explicit PromiseHolder(scoped_refptr<internal::AbstractPromise> promise);
-
- ~PromiseHolder();
-
- PromiseHolder(PromiseHolder&& other);
-
- scoped_refptr<internal::AbstractPromise> Unwrap() const;
-
- private:
- mutable scoped_refptr<internal::AbstractPromise> promise_;
-};
-
-} // namespace internal
-
-template <>
-struct BindUnwrapTraits<internal::PromiseHolder> {
- static scoped_refptr<internal::AbstractPromise> Unwrap(
- const internal::PromiseHolder& o) {
- return o.Unwrap();
- }
-};
-
-namespace internal {
-
-// Used by ManualPromiseResolver<> to generate callbacks.
+// Used by ManualPromiseResolver<> to generate callbacks. Note the use of
+// WrappedPromise, this is necessary because we want to cancel the promise (to
+// release memory) if the callback gets deleted without having being run.
template <typename T, typename... Args>
class PromiseCallbackHelper {
public:
@@ -624,7 +607,7 @@ class PromiseCallbackHelper {
std::forward<Args>(args)...);
promise->OnResolved();
},
- PromiseHolder(promise));
+ promise);
}
static RepeatingCallback GetRepeatingResolveCallback(
@@ -635,7 +618,7 @@ class PromiseCallbackHelper {
std::forward<Args>(args)...);
promise->OnResolved();
},
- PromiseHolder(promise));
+ promise);
}
static Callback GetRejectCallback(scoped_refptr<AbstractPromise>& promise) {
@@ -645,7 +628,7 @@ class PromiseCallbackHelper {
std::forward<Args>(args)...);
promise->OnRejected();
},
- PromiseHolder(promise));
+ promise);
}
static RepeatingCallback GetRepeatingRejectCallback(
@@ -656,7 +639,7 @@ class PromiseCallbackHelper {
std::forward<Args>(args)...);
promise->OnRejected();
},
- PromiseHolder(promise));
+ promise);
}
};
@@ -679,8 +662,7 @@ struct IsValidPromiseArg<PromiseType&, CallbackArgType> {
// rejection storage type.
template <typename RejectT>
struct AllPromiseRejectHelper {
- static void Reject(AbstractPromise* result,
- const scoped_refptr<AbstractPromise>& prerequisite) {
+ static void Reject(AbstractPromise* result, AbstractPromise* prerequisite) {
result->emplace(scoped_refptr<AbstractPromise>(prerequisite));
}
};
@@ -709,14 +691,20 @@ CallbackBase&& ToCallbackBase(const CallbackT&& task) {
// Helps reduce template bloat by moving AbstractPromise construction out of
// line.
-scoped_refptr<AbstractPromise> BASE_EXPORT
-ConstructAbstractPromiseWithSinglePrerequisite(
+PassedPromise BASE_EXPORT ConstructAbstractPromiseWithSinglePrerequisite(
const scoped_refptr<TaskRunner>& task_runner,
const Location& from_here,
AbstractPromise* prerequsite,
- internal::PromiseExecutor::Data&& executor_data) noexcept;
+ PromiseExecutor::Data&& executor_data) noexcept;
+
+// Like ConstructAbstractPromiseWithSinglePrerequisite except tasks are posted
+// onto SequencedTaskRunnerHandle::Get().
+PassedPromise BASE_EXPORT ConstructHereAbstractPromiseWithSinglePrerequisite(
+ const Location& from_here,
+ AbstractPromise* prerequsite,
+ PromiseExecutor::Data&& executor_data) noexcept;
-scoped_refptr<AbstractPromise> BASE_EXPORT
+PassedPromise BASE_EXPORT
ConstructManualPromiseResolverPromise(const Location& from_here,
RejectPolicy reject_policy,
bool can_resolve,
diff --git a/chromium/base/task/promise/helpers_unittest.cc b/chromium/base/task/promise/helpers_unittest.cc
index afdc9e7079e..f13fb5c8c7a 100644
--- a/chromium/base/task/promise/helpers_unittest.cc
+++ b/chromium/base/task/promise/helpers_unittest.cc
@@ -187,8 +187,9 @@ TEST(EmplaceHelper, EmplacePromiseResult) {
TEST(EmplaceHelper, EmplacePromise) {
scoped_refptr<AbstractPromise> promise =
DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- scoped_refptr<AbstractPromise> curried = DoNothingPromiseBuilder(FROM_HERE);
+ PassedPromise curried = NoOpPromiseExecutor::Create(
+ FROM_HERE, false, false, RejectPolicy::kCatchNotRequired);
EmplaceHelper<Resolved<int>, Rejected<NoReject>>::Emplace(
promise.get(), Promise<int>(std::move(curried)));
@@ -243,8 +244,8 @@ TEST(RunHelper, CallbackVoidArgumentIntResult) {
scoped_refptr<AbstractPromise> result =
DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- RunHelper<OnceCallback<int()>, Resolved<void>, Resolved<int>,
- Rejected<std::string>>::Run(BindOnce([]() { return 123; }),
+ RunHelper<RepeatingCallback<int()>, Resolved<void>, Resolved<int>,
+ Rejected<std::string>>::Run(BindRepeating([]() { return 123; }),
arg.get(), result.get());
EXPECT_EQ(result->value().template Get<Resolved<int>>()->value, 123);
@@ -255,8 +256,8 @@ TEST(RunHelper, CallbackVoidArgumentVoidResult) {
scoped_refptr<AbstractPromise> result =
DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
- RunHelper<OnceCallback<void()>, Resolved<void>, Resolved<void>,
- Rejected<std::string>>::Run(BindOnce([]() {}), arg.get(),
+ RunHelper<RepeatingCallback<void()>, Resolved<void>, Resolved<void>,
+ Rejected<std::string>>::Run(BindRepeating([]() {}), arg.get(),
result.get());
EXPECT_TRUE(result->value().ContainsResolved());
@@ -268,8 +269,8 @@ TEST(RunHelper, CallbackIntArgumentIntResult) {
DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
arg->emplace(Resolved<int>(123));
- RunHelper<OnceCallback<int(int)>, Resolved<int>, Resolved<int>,
- Rejected<std::string>>::Run(BindOnce([](int value) {
+ RunHelper<RepeatingCallback<int(int)>, Resolved<int>, Resolved<int>,
+ Rejected<std::string>>::Run(BindRepeating([](int value) {
return value + 1;
}),
arg.get(), result.get());
@@ -284,7 +285,7 @@ TEST(RunHelper, CallbackIntArgumentArgumentVoidResult) {
arg->emplace(Resolved<int>(123));
int value;
- RunHelper<OnceCallback<void(int)>, Resolved<int>, Resolved<void>,
+ RunHelper<RepeatingCallback<void(int)>, Resolved<int>, Resolved<void>,
Rejected<std::string>>::Run(BindLambdaForTesting([&](int arg) {
value = arg;
}),
diff --git a/chromium/base/task/promise/no_op_promise_executor.cc b/chromium/base/task/promise/no_op_promise_executor.cc
index 74a5bcc57c8..e168ed91007 100644
--- a/chromium/base/task/promise/no_op_promise_executor.cc
+++ b/chromium/base/task/promise/no_op_promise_executor.cc
@@ -45,15 +45,14 @@ bool NoOpPromiseExecutor::CanReject() const {
void NoOpPromiseExecutor::Execute(AbstractPromise* promise) {}
// static
-scoped_refptr<internal::AbstractPromise> NoOpPromiseExecutor::Create(
- Location from_here,
- bool can_resolve,
- bool can_reject,
- RejectPolicy reject_policy) {
- return AbstractPromise::CreateNoPrerequisitePromise(
+PassedPromise NoOpPromiseExecutor::Create(Location from_here,
+ bool can_resolve,
+ bool can_reject,
+ RejectPolicy reject_policy) {
+ return PassedPromise(AbstractPromise::CreateNoPrerequisitePromise(
from_here, reject_policy, DependentList::ConstructUnresolved(),
PromiseExecutor::Data(in_place_type_t<NoOpPromiseExecutor>(), can_resolve,
- can_reject));
+ can_reject)));
}
} // namespace internal
diff --git a/chromium/base/task/promise/no_op_promise_executor.h b/chromium/base/task/promise/no_op_promise_executor.h
index 005ee8c0130..13f8ef0891b 100644
--- a/chromium/base/task/promise/no_op_promise_executor.h
+++ b/chromium/base/task/promise/no_op_promise_executor.h
@@ -21,10 +21,10 @@ class BASE_EXPORT NoOpPromiseExecutor {
static constexpr PromiseExecutor::PrerequisitePolicy kPrerequisitePolicy =
PromiseExecutor::PrerequisitePolicy::kNever;
- static scoped_refptr<AbstractPromise> Create(Location from_here,
- bool can_resolve,
- bool can_reject,
- RejectPolicy reject_policy);
+ static PassedPromise Create(Location from_here,
+ bool can_resolve,
+ bool can_reject,
+ RejectPolicy reject_policy);
PromiseExecutor::PrerequisitePolicy GetPrerequisitePolicy() const;
bool IsCancelled() const;
diff --git a/chromium/base/task/promise/post_task_executor.h b/chromium/base/task/promise/post_task_executor.h
index c018113de63..e3882ba1712 100644
--- a/chromium/base/task/promise/post_task_executor.h
+++ b/chromium/base/task/promise/post_task_executor.h
@@ -52,10 +52,14 @@ class PostTaskExecutor {
static_assert(sizeof(CallbackBase) == sizeof(OnceCallback<ReturnType()>),
"We assume it's possible to cast from CallbackBase to "
"OnceCallback<ReturnType()>");
- OnceCallback<ReturnType()>* task =
- static_cast<OnceCallback<ReturnType()>*>(&task_);
- internal::RunHelper<OnceCallback<ReturnType()>, void, ResolveStorage,
- RejectStorage>::Run(std::move(*task), nullptr, promise);
+ // Internally RunHelper uses const RepeatingCallback<>& to avoid the
+ // binary size overhead of moving a scoped_refptr<> about. We respect
+ // the onceness of the callback and RunHelper will overwrite the callback
+ // with the result.
+ RepeatingCallback<ReturnType()>* task =
+ static_cast<RepeatingCallback<ReturnType()>*>(&task_);
+ internal::RunHelper<RepeatingCallback<ReturnType()>, void, ResolveStorage,
+ RejectStorage>::Run(*task, nullptr, promise);
}
private:
diff --git a/chromium/base/task/promise/post_task_executor_unittest.cc b/chromium/base/task/promise/post_task_executor_unittest.cc
index 8e86aaefad4..1d3fc57e4d0 100644
--- a/chromium/base/task/promise/post_task_executor_unittest.cc
+++ b/chromium/base/task/promise/post_task_executor_unittest.cc
@@ -16,9 +16,8 @@ namespace internal {
class PostTaskExecutorTest : public testing::Test {
public:
template <typename CallbackT>
- scoped_refptr<internal::AbstractPromise> CreatePostTaskPromise(
- const Location& from_here,
- CallbackT&& task) {
+ WrappedPromise CreatePostTaskPromise(const Location& from_here,
+ CallbackT&& task) {
// Extract properties from |task| callback.
using CallbackTraits = CallbackTraits<std::decay_t<CallbackT>>;
@@ -27,20 +26,20 @@ class PostTaskExecutorTest : public testing::Test {
internal::PostTaskExecutor<typename CallbackTraits::ReturnType>>(),
internal::ToCallbackBase(std::move(task)));
- return AbstractPromise::CreateNoPrerequisitePromise(
+ return WrappedPromise(AbstractPromise::CreateNoPrerequisitePromise(
from_here, RejectPolicy::kMustCatchRejection,
internal::DependentList::ConstructUnresolved(),
- std::move(executor_data));
+ std::move(executor_data)));
}
};
TEST_F(PostTaskExecutorTest, OnceClosure) {
bool run = false;
- scoped_refptr<AbstractPromise> p = CreatePostTaskPromise(
+ WrappedPromise p = CreatePostTaskPromise(
FROM_HERE, BindOnce([](bool* run) { *run = true; }, &run));
- p->Execute();
+ p.Execute();
EXPECT_TRUE(run);
}
@@ -48,20 +47,19 @@ TEST_F(PostTaskExecutorTest, OnceClosure) {
TEST_F(PostTaskExecutorTest, RepeatingClosure) {
bool run = false;
- scoped_refptr<AbstractPromise> p = CreatePostTaskPromise(
+ WrappedPromise p = CreatePostTaskPromise(
FROM_HERE, BindRepeating([](bool* run) { *run = true; }, &run));
- p->Execute();
+ p.Execute();
EXPECT_TRUE(run);
}
TEST_F(PostTaskExecutorTest, DoNothing) {
// Check it compiles and the executor doesn't crash when run.
- scoped_refptr<AbstractPromise> p =
- CreatePostTaskPromise(FROM_HERE, DoNothing());
+ WrappedPromise p = CreatePostTaskPromise(FROM_HERE, DoNothing());
- p->Execute();
+ p.Execute();
}
} // namespace internal
diff --git a/chromium/base/task/promise/promise.h b/chromium/base/task/promise/promise.h
index 4f2275ea183..467f74cb8e4 100644
--- a/chromium/base/task/promise/promise.h
+++ b/chromium/base/task/promise/promise.h
@@ -30,12 +30,12 @@ BASE_EXPORT scoped_refptr<TaskRunner> CreateTaskRunner(
// callback will be posted immediately, otherwise it has to wait.
//
// Promise<> is copyable, moveable and thread safe. Under the hood
-// internal::AbstractPromise is refcounted so retaining multiple Promises<> will
+// AbstractPromise is refcounted so retaining multiple Promises<> will
// prevent that part of the promise graph from being released.
template <typename ResolveType, typename RejectType = NoReject>
-class Promise {
+class Promise : public internal::BasePromise {
public:
- Promise() : abstract_promise_(nullptr) {}
+ Promise() = default;
static_assert(
!std::is_reference<ResolveType>::value ||
@@ -49,16 +49,17 @@ class Promise {
explicit Promise(
scoped_refptr<internal::AbstractPromise> abstract_promise) noexcept
- : abstract_promise_(std::move(abstract_promise)) {}
+ : BasePromise(std::move(abstract_promise)) {}
- ~Promise() = default;
+ // Every PostTask calls this constructor so we need to be careful to avoid
+ // unnecessary binary bloat.
+ explicit Promise(internal::PassedPromise passed_promise) noexcept
+ : BasePromise(std::move(passed_promise),
+ BasePromise::InlineConstructor()) {}
- operator bool() const { return !!abstract_promise_; }
+ ~Promise() = default;
- bool IsCancelledForTesting() const {
- DCHECK(abstract_promise_);
- return abstract_promise_->IsCanceled();
- }
+ bool IsCancelledForTesting() const { return abstract_promise_->IsCanceled(); }
// Waits until the promise has settled and if resolved it returns the resolved
// value.
@@ -75,8 +76,10 @@ class Promise {
}
DCHECK(abstract_promise_->IsResolved())
<< "Can't take resolved value, promise wasn't resolved.";
- return std::move(
- abstract_promise_->TakeValue().value().Get<Resolved<T>>()->value);
+ return std::move(abstract_promise_->TakeValue()
+ .value()
+ .template Get<Resolved<T>>()
+ ->value);
}
// Waits until the promise has settled and if rejected it returns the rejected
@@ -95,8 +98,10 @@ class Promise {
abstract_promise_->IgnoreUncaughtCatchForTesting();
DCHECK(abstract_promise_->IsRejected())
<< "Can't take rejected value, promise wasn't rejected.";
- return std::move(
- abstract_promise_->TakeValue().value().Get<Rejected<T>>()->value);
+ return std::move(abstract_promise_->TakeValue()
+ .value()
+ .template Get<Rejected<T>>()
+ ->value);
}
bool IsResolvedForTesting() const {
@@ -122,22 +127,22 @@ class Promise {
//
// |task_runner| is const-ref to avoid bloat due the destructor (which posts a
// task).
- template <typename RejectCb>
+ template <typename CatchCb>
auto CatchOn(const scoped_refptr<TaskRunner>& task_runner,
const Location& from_here,
- RejectCb on_reject) noexcept {
+ CatchCb on_reject) noexcept {
DCHECK(!on_reject.is_null());
// Extract properties from the |on_reject| callback.
- using RejectCallbackTraits = internal::CallbackTraits<RejectCb>;
- using RejectCallbackArgT = typename RejectCallbackTraits::ArgType;
+ using CatchCallbackTraits = internal::CallbackTraits<CatchCb>;
+ using CatchCallbackArgT = typename CatchCallbackTraits::ArgType;
// Compute the resolve and reject types of the returned Promise.
using ReturnedPromiseTraits =
internal::PromiseCombiner<ResolveType,
NoReject, // We've caught the reject case.
- typename RejectCallbackTraits::ResolveType,
- typename RejectCallbackTraits::RejectType>;
+ typename CatchCallbackTraits::ResolveType,
+ typename CatchCallbackTraits::RejectType>;
using ReturnedPromiseResolveT = typename ReturnedPromiseTraits::ResolveType;
using ReturnedPromiseRejectT = typename ReturnedPromiseTraits::RejectType;
@@ -148,13 +153,13 @@ class Promise {
static_assert(ReturnedPromiseTraits::valid,
"Ambiguous promise resolve type");
static_assert(
- internal::IsValidPromiseArg<RejectType, RejectCallbackArgT>::value ||
- std::is_void<RejectCallbackArgT>::value,
+ internal::IsValidPromiseArg<RejectType, CatchCallbackArgT>::value ||
+ std::is_void<CatchCallbackArgT>::value,
"|on_reject| callback must accept Promise::RejectType or void.");
static_assert(
- !std::is_reference<RejectCallbackArgT>::value ||
- std::is_const<std::remove_reference_t<RejectCallbackArgT>>::value,
+ !std::is_reference<CatchCallbackArgT>::value ||
+ std::is_const<std::remove_reference_t<CatchCallbackArgT>>::value,
"Google C++ Style: References in function parameters must be const.");
return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
@@ -163,7 +168,7 @@ class Promise {
internal::PromiseExecutor::Data(
in_place_type_t<internal::ThenAndCatchExecutor<
OnceClosure, // Never called.
- OnceCallback<typename RejectCallbackTraits::SignatureType>,
+ OnceCallback<typename CatchCallbackTraits::SignatureType>,
internal::NoCallback, RejectType,
Resolved<ReturnedPromiseResolveT>,
Rejected<ReturnedPromiseRejectT>>>(),
@@ -171,18 +176,59 @@ class Promise {
internal::ToCallbackBase(std::move(on_reject)))));
}
- template <typename RejectCb>
+ template <typename CatchCb>
auto CatchOn(const TaskTraits& traits,
const Location& from_here,
- RejectCb&& on_reject) noexcept {
+ CatchCb&& on_reject) noexcept {
return CatchOn(CreateTaskRunner(traits), from_here,
- std::forward<RejectCb>(on_reject));
+ std::forward<CatchCb>(on_reject));
}
- template <typename RejectCb>
- auto CatchHere(const Location& from_here, RejectCb&& on_reject) noexcept {
- return CatchOn(internal::GetCurrentSequence(), from_here,
- std::forward<RejectCb>(on_reject));
+ template <typename CatchCb>
+ auto CatchHere(const Location& from_here, CatchCb&& on_reject) noexcept {
+ DCHECK(!on_reject.is_null());
+
+ // Extract properties from the |on_reject| callback.
+ using CatchCallbackTraits = internal::CallbackTraits<CatchCb>;
+ using CatchCallbackArgT = typename CatchCallbackTraits::ArgType;
+
+ // Compute the resolve and reject types of the returned Promise.
+ using ReturnedPromiseTraits =
+ internal::PromiseCombiner<ResolveType,
+ NoReject, // We've caught the reject case.
+ typename CatchCallbackTraits::ResolveType,
+ typename CatchCallbackTraits::RejectType>;
+ using ReturnedPromiseResolveT = typename ReturnedPromiseTraits::ResolveType;
+ using ReturnedPromiseRejectT = typename ReturnedPromiseTraits::RejectType;
+
+ static_assert(!std::is_same<NoReject, RejectType>::value,
+ "Can't catch a NoReject promise.");
+
+ // Check we wouldn't need to return Promise<Variant<...>, ...>
+ static_assert(ReturnedPromiseTraits::valid,
+ "Ambiguous promise resolve type");
+ static_assert(
+ internal::IsValidPromiseArg<RejectType, CatchCallbackArgT>::value ||
+ std::is_void<CatchCallbackArgT>::value,
+ "|on_reject| callback must accept Promise::RejectType or void.");
+
+ static_assert(
+ !std::is_reference<CatchCallbackArgT>::value ||
+ std::is_const<std::remove_reference_t<CatchCallbackArgT>>::value,
+ "Google C++ Style: References in function parameters must be const.");
+
+ return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
+ ConstructHereAbstractPromiseWithSinglePrerequisite(
+ from_here, abstract_promise_.get(),
+ internal::PromiseExecutor::Data(
+ in_place_type_t<internal::ThenAndCatchExecutor<
+ OnceClosure, // Never called.
+ OnceCallback<typename CatchCallbackTraits::SignatureType>,
+ internal::NoCallback, RejectType,
+ Resolved<ReturnedPromiseResolveT>,
+ Rejected<ReturnedPromiseRejectT>>>(),
+ OnceClosure(),
+ internal::ToCallbackBase(std::move(on_reject)))));
}
// A task to execute |on_resolve| is posted on |task_runner| as soon as this
@@ -198,23 +244,22 @@ class Promise {
//
// |task_runner| is const-ref to avoid bloat due the destructor (which posts a
// task).
- template <typename ResolveCb>
+ template <typename ThenCb>
auto ThenOn(const scoped_refptr<TaskRunner>& task_runner,
const Location& from_here,
- ResolveCb on_resolve) noexcept {
+ ThenCb on_resolve) noexcept {
DCHECK(!on_resolve.is_null());
// Extract properties from the |on_resolve| callback.
- using ResolveCallbackTraits =
- internal::CallbackTraits<std::decay_t<ResolveCb>>;
- using ResolveCallbackArgT = typename ResolveCallbackTraits::ArgType;
+ using ThenCallbackTraits = internal::CallbackTraits<std::decay_t<ThenCb>>;
+ using ThenCallbackArgT = typename ThenCallbackTraits::ArgType;
// Compute the resolve and reject types of the returned Promise.
using ReturnedPromiseTraits =
internal::PromiseCombiner<NoResolve, // We've caught the resolve case.
RejectType,
- typename ResolveCallbackTraits::ResolveType,
- typename ResolveCallbackTraits::RejectType>;
+ typename ThenCallbackTraits::ResolveType,
+ typename ThenCallbackTraits::RejectType>;
using ReturnedPromiseResolveT = typename ReturnedPromiseTraits::ResolveType;
using ReturnedPromiseRejectT = typename ReturnedPromiseTraits::RejectType;
@@ -223,13 +268,13 @@ class Promise {
"Ambiguous promise reject type");
static_assert(
- internal::IsValidPromiseArg<ResolveType, ResolveCallbackArgT>::value ||
- std::is_void<ResolveCallbackArgT>::value,
+ internal::IsValidPromiseArg<ResolveType, ThenCallbackArgT>::value ||
+ std::is_void<ThenCallbackArgT>::value,
"|on_resolve| callback must accept Promise::ResolveType or void.");
static_assert(
- !std::is_reference<ResolveCallbackArgT>::value ||
- std::is_const<std::remove_reference_t<ResolveCallbackArgT>>::value,
+ !std::is_reference<ThenCallbackArgT>::value ||
+ std::is_const<std::remove_reference_t<ThenCallbackArgT>>::value,
"Google C++ Style: References in function parameters must be const.");
return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
@@ -237,7 +282,7 @@ class Promise {
task_runner, from_here, abstract_promise_.get(),
internal::PromiseExecutor::Data(
in_place_type_t<internal::ThenAndCatchExecutor<
- OnceCallback<typename ResolveCallbackTraits::SignatureType>,
+ OnceCallback<typename ThenCallbackTraits::SignatureType>,
OnceClosure, ResolveType, internal::NoCallback,
Resolved<ReturnedPromiseResolveT>,
Rejected<ReturnedPromiseRejectT>>>(),
@@ -245,18 +290,56 @@ class Promise {
OnceClosure())));
}
- template <typename ResolveCb>
+ template <typename ThenCb>
auto ThenOn(const TaskTraits& traits,
const Location& from_here,
- ResolveCb&& on_resolve) noexcept {
+ ThenCb&& on_resolve) noexcept {
return ThenOn(CreateTaskRunner(traits), from_here,
- std::forward<ResolveCb>(on_resolve));
+ std::forward<ThenCb>(on_resolve));
}
- template <typename ResolveCb>
- auto ThenHere(const Location& from_here, ResolveCb&& on_resolve) noexcept {
- return ThenOn(internal::GetCurrentSequence(), from_here,
- std::forward<ResolveCb>(on_resolve));
+ template <typename ThenCb>
+ auto ThenHere(const Location& from_here, ThenCb&& on_resolve) noexcept {
+ DCHECK(!on_resolve.is_null());
+
+ // Extract properties from the |on_resolve| callback.
+ using ThenCallbackTraits = internal::CallbackTraits<std::decay_t<ThenCb>>;
+ using ThenCallbackArgT = typename ThenCallbackTraits::ArgType;
+
+ // Compute the resolve and reject types of the returned Promise.
+ using ReturnedPromiseTraits =
+ internal::PromiseCombiner<NoResolve, // We've caught the resolve case.
+ RejectType,
+ typename ThenCallbackTraits::ResolveType,
+ typename ThenCallbackTraits::RejectType>;
+ using ReturnedPromiseResolveT = typename ReturnedPromiseTraits::ResolveType;
+ using ReturnedPromiseRejectT = typename ReturnedPromiseTraits::RejectType;
+
+ // Check we wouldn't need to return Promise<..., Variant<...>>
+ static_assert(ReturnedPromiseTraits::valid,
+ "Ambiguous promise reject type");
+
+ static_assert(
+ internal::IsValidPromiseArg<ResolveType, ThenCallbackArgT>::value ||
+ std::is_void<ThenCallbackArgT>::value,
+ "|on_resolve| callback must accept Promise::ResolveType or void.");
+
+ static_assert(
+ !std::is_reference<ThenCallbackArgT>::value ||
+ std::is_const<std::remove_reference_t<ThenCallbackArgT>>::value,
+ "Google C++ Style: References in function parameters must be const.");
+
+ return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
+ ConstructHereAbstractPromiseWithSinglePrerequisite(
+ from_here, abstract_promise_.get(),
+ internal::PromiseExecutor::Data(
+ in_place_type_t<internal::ThenAndCatchExecutor<
+ OnceCallback<typename ThenCallbackTraits::SignatureType>,
+ OnceClosure, ResolveType, internal::NoCallback,
+ Resolved<ReturnedPromiseResolveT>,
+ Rejected<ReturnedPromiseRejectT>>>(),
+ internal::ToCallbackBase(std::move(on_resolve)),
+ OnceClosure())));
}
// A task to execute |on_reject| is posted on |task_runner| as soon as this
@@ -279,26 +362,26 @@ class Promise {
//
// |task_runner| is const-ref to avoid bloat due the destructor (which posts a
// task).
- template <typename ResolveCb, typename RejectCb>
+ template <typename ThenCb, typename CatchCb>
auto ThenOn(const scoped_refptr<TaskRunner>& task_runner,
const Location& from_here,
- ResolveCb on_resolve,
- RejectCb on_reject) noexcept {
+ ThenCb on_resolve,
+ CatchCb on_reject) noexcept {
DCHECK(!on_resolve.is_null());
DCHECK(!on_reject.is_null());
// Extract properties from the |on_resolve| and |on_reject| callbacks.
- using ResolveCallbackTraits = internal::CallbackTraits<ResolveCb>;
- using RejectCallbackTraits = internal::CallbackTraits<RejectCb>;
- using ResolveCallbackArgT = typename ResolveCallbackTraits::ArgType;
- using RejectCallbackArgT = typename RejectCallbackTraits::ArgType;
+ using ThenCallbackTraits = internal::CallbackTraits<ThenCb>;
+ using CatchCallbackTraits = internal::CallbackTraits<CatchCb>;
+ using ThenCallbackArgT = typename ThenCallbackTraits::ArgType;
+ using CatchCallbackArgT = typename CatchCallbackTraits::ArgType;
// Compute the resolve and reject types of the returned Promise.
using ReturnedPromiseTraits =
- internal::PromiseCombiner<typename ResolveCallbackTraits::ResolveType,
- typename ResolveCallbackTraits::RejectType,
- typename RejectCallbackTraits::ResolveType,
- typename RejectCallbackTraits::RejectType>;
+ internal::PromiseCombiner<typename ThenCallbackTraits::ResolveType,
+ typename ThenCallbackTraits::RejectType,
+ typename CatchCallbackTraits::ResolveType,
+ typename CatchCallbackTraits::RejectType>;
using ReturnedPromiseResolveT = typename ReturnedPromiseTraits::ResolveType;
using ReturnedPromiseRejectT = typename ReturnedPromiseTraits::RejectType;
@@ -310,23 +393,23 @@ class Promise {
"compatible types.");
static_assert(
- internal::IsValidPromiseArg<ResolveType, ResolveCallbackArgT>::value ||
- std::is_void<ResolveCallbackArgT>::value,
+ internal::IsValidPromiseArg<ResolveType, ThenCallbackArgT>::value ||
+ std::is_void<ThenCallbackArgT>::value,
"|on_resolve| callback must accept Promise::ResolveType or void.");
static_assert(
- internal::IsValidPromiseArg<RejectType, RejectCallbackArgT>::value ||
- std::is_void<RejectCallbackArgT>::value,
+ internal::IsValidPromiseArg<RejectType, CatchCallbackArgT>::value ||
+ std::is_void<CatchCallbackArgT>::value,
"|on_reject| callback must accept Promise::RejectType or void.");
static_assert(
- !std::is_reference<ResolveCallbackArgT>::value ||
- std::is_const<std::remove_reference_t<ResolveCallbackArgT>>::value,
+ !std::is_reference<ThenCallbackArgT>::value ||
+ std::is_const<std::remove_reference_t<ThenCallbackArgT>>::value,
"Google C++ Style: References in function parameters must be const.");
static_assert(
- !std::is_reference<RejectCallbackArgT>::value ||
- std::is_const<std::remove_reference_t<RejectCallbackArgT>>::value,
+ !std::is_reference<CatchCallbackArgT>::value ||
+ std::is_const<std::remove_reference_t<CatchCallbackArgT>>::value,
"Google C++ Style: References in function parameters must be const.");
return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
@@ -334,31 +417,84 @@ class Promise {
task_runner, from_here, abstract_promise_.get(),
internal::PromiseExecutor::Data(
in_place_type_t<internal::ThenAndCatchExecutor<
- OnceCallback<typename ResolveCallbackTraits::SignatureType>,
- OnceCallback<typename RejectCallbackTraits::SignatureType>,
+ OnceCallback<typename ThenCallbackTraits::SignatureType>,
+ OnceCallback<typename CatchCallbackTraits::SignatureType>,
ResolveType, RejectType, Resolved<ReturnedPromiseResolveT>,
Rejected<ReturnedPromiseRejectT>>>(),
internal::ToCallbackBase(std::move(on_resolve)),
internal::ToCallbackBase(std::move(on_reject)))));
}
- template <typename ResolveCb, typename RejectCb>
+ template <typename ThenCb, typename CatchCb>
auto ThenOn(const TaskTraits& traits,
const Location& from_here,
- ResolveCb on_resolve,
- RejectCb on_reject) noexcept {
+ ThenCb on_resolve,
+ CatchCb on_reject) noexcept {
return ThenOn(CreateTaskRunner(traits), from_here,
- std::forward<ResolveCb>(on_resolve),
- std::forward<RejectCb>(on_reject));
+ std::forward<ThenCb>(on_resolve),
+ std::forward<CatchCb>(on_reject));
}
- template <typename ResolveCb, typename RejectCb>
+ template <typename ThenCb, typename CatchCb>
auto ThenHere(const Location& from_here,
- ResolveCb on_resolve,
- RejectCb on_reject) noexcept {
- return ThenOn(internal::GetCurrentSequence(), from_here,
- std::forward<ResolveCb>(on_resolve),
- std::forward<RejectCb>(on_reject));
+ ThenCb on_resolve,
+ CatchCb on_reject) noexcept {
+ DCHECK(!on_resolve.is_null());
+ DCHECK(!on_reject.is_null());
+
+ // Extract properties from the |on_resolve| and |on_reject| callbacks.
+ using ThenCallbackTraits = internal::CallbackTraits<ThenCb>;
+ using CatchCallbackTraits = internal::CallbackTraits<CatchCb>;
+ using ThenCallbackArgT = typename ThenCallbackTraits::ArgType;
+ using CatchCallbackArgT = typename CatchCallbackTraits::ArgType;
+
+ // Compute the resolve and reject types of the returned Promise.
+ using ReturnedPromiseTraits =
+ internal::PromiseCombiner<typename ThenCallbackTraits::ResolveType,
+ typename ThenCallbackTraits::RejectType,
+ typename CatchCallbackTraits::ResolveType,
+ typename CatchCallbackTraits::RejectType>;
+ using ReturnedPromiseResolveT = typename ReturnedPromiseTraits::ResolveType;
+ using ReturnedPromiseRejectT = typename ReturnedPromiseTraits::RejectType;
+
+ static_assert(!std::is_same<NoReject, RejectType>::value,
+ "Can't catch a NoReject promise.");
+
+ static_assert(ReturnedPromiseTraits::valid,
+ "|on_resolve| callback and |on_resolve| callback must return "
+ "compatible types.");
+
+ static_assert(
+ internal::IsValidPromiseArg<ResolveType, ThenCallbackArgT>::value ||
+ std::is_void<ThenCallbackArgT>::value,
+ "|on_resolve| callback must accept Promise::ResolveType or void.");
+
+ static_assert(
+ internal::IsValidPromiseArg<RejectType, CatchCallbackArgT>::value ||
+ std::is_void<CatchCallbackArgT>::value,
+ "|on_reject| callback must accept Promise::RejectType or void.");
+
+ static_assert(
+ !std::is_reference<ThenCallbackArgT>::value ||
+ std::is_const<std::remove_reference_t<ThenCallbackArgT>>::value,
+ "Google C++ Style: References in function parameters must be const.");
+
+ static_assert(
+ !std::is_reference<CatchCallbackArgT>::value ||
+ std::is_const<std::remove_reference_t<CatchCallbackArgT>>::value,
+ "Google C++ Style: References in function parameters must be const.");
+
+ return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
+ ConstructHereAbstractPromiseWithSinglePrerequisite(
+ from_here, abstract_promise_.get(),
+ internal::PromiseExecutor::Data(
+ in_place_type_t<internal::ThenAndCatchExecutor<
+ OnceCallback<typename ThenCallbackTraits::SignatureType>,
+ OnceCallback<typename CatchCallbackTraits::SignatureType>,
+ ResolveType, RejectType, Resolved<ReturnedPromiseResolveT>,
+ Rejected<ReturnedPromiseRejectT>>>(),
+ internal::ToCallbackBase(std::move(on_resolve)),
+ internal::ToCallbackBase(std::move(on_reject)))));
}
// A task to execute |finally_callback| on |task_runner| is posted after the
@@ -405,8 +541,24 @@ class Promise {
template <typename FinallyCb>
auto FinallyHere(const Location& from_here,
FinallyCb finally_callback) noexcept {
- return FinallyOn(internal::GetCurrentSequence(), from_here,
- std::move(finally_callback));
+ // Extract properties from |finally_callback| callback.
+ using CallbackTraits = internal::CallbackTraits<FinallyCb>;
+ using ReturnedPromiseResolveT = typename CallbackTraits::ResolveType;
+ using ReturnedPromiseRejectT = typename CallbackTraits::RejectType;
+
+ using CallbackArgT = typename CallbackTraits::ArgType;
+ static_assert(std::is_void<CallbackArgT>::value,
+ "|finally_callback| callback must have no arguments");
+
+ return Promise<ReturnedPromiseResolveT, ReturnedPromiseRejectT>(
+ ConstructHereAbstractPromiseWithSinglePrerequisite(
+ from_here, abstract_promise_.get(),
+ internal::PromiseExecutor::Data(
+ in_place_type_t<internal::FinallyExecutor<
+ OnceCallback<typename CallbackTraits::ReturnType()>,
+ Resolved<ReturnedPromiseResolveT>,
+ Rejected<ReturnedPromiseRejectT>>>(),
+ internal::ToCallbackBase(std::move(finally_callback)))));
}
template <typename... Args>
@@ -442,8 +594,6 @@ class Promise {
nullptr, from_here, nullptr, RejectPolicy::kMustCatchRejection,
internal::DependentList::ConstructResolved(),
std::move(executor_data)));
- promise->emplace(in_place_type_t<Rejected<RejectType>>(),
- std::forward<Args>(args)...);
return Promise<ResolveType, RejectType>(std::move(promise));
}
@@ -454,6 +604,11 @@ class Promise {
abstract_promise_->IgnoreUncaughtCatchForTesting();
}
+ const scoped_refptr<internal::AbstractPromise>& GetScopedRefptrForTesting()
+ const {
+ return abstract_promise_;
+ }
+
private:
template <typename A, typename B>
friend class Promise;
@@ -471,8 +626,6 @@ class Promise {
template <typename A, typename B>
friend class ManualPromiseResolver;
-
- scoped_refptr<internal::AbstractPromise> abstract_promise_;
};
// Used for manually resolving and rejecting a Promise. This is for
@@ -624,8 +777,8 @@ class Promises {
std::vector<internal::DependentList::Node> prerequisite_list(
sizeof...(promises));
int i = 0;
- for (auto&& p : {promises.abstract_promise_...}) {
- prerequisite_list[i++].SetPrerequisite(p.get());
+ for (auto&& p : {promises.abstract_promise_.get()...}) {
+ prerequisite_list[i++].SetPrerequisite(p);
}
internal::PromiseExecutor::Data executor_data(
diff --git a/chromium/base/task/promise/promise_unittest.cc b/chromium/base/task/promise/promise_unittest.cc
index bb3dda41cb3..d81adacb1a0 100644
--- a/chromium/base/task/promise/promise_unittest.cc
+++ b/chromium/base/task/promise/promise_unittest.cc
@@ -106,6 +106,86 @@ TEST(PromiseMemoryLeakTest, TargetTaskRunnerClearsTasks) {
EXPECT_TRUE(delete_reply_flag);
}
+TEST(PromiseMemoryLeakTest, GetResolveCallbackNeverRun) {
+ test::TaskEnvironment task_environment_;
+ OnceCallback<void(int)> cb;
+ MockObject mock_object;
+ bool delete_task_flag = false;
+
+ {
+ ManualPromiseResolver<int> p(FROM_HERE);
+ cb = p.GetResolveCallback();
+
+ p.promise().ThenHere(
+ FROM_HERE, BindOnce(&MockObject::Task, Unretained(&mock_object),
+ MakeRefCounted<ObjectToDelete>(&delete_task_flag)));
+ }
+
+ EXPECT_FALSE(delete_task_flag);
+ cb = OnceCallback<void(int)>();
+ EXPECT_TRUE(delete_task_flag);
+}
+
+TEST(PromiseMemoryLeakTest, GetRepeatingResolveCallbackNeverRun) {
+ test::TaskEnvironment task_environment_;
+ RepeatingCallback<void(int)> cb;
+ MockObject mock_object;
+ bool delete_task_flag = false;
+
+ {
+ ManualPromiseResolver<int> p(FROM_HERE);
+ cb = p.GetRepeatingResolveCallback();
+
+ p.promise().ThenHere(
+ FROM_HERE, BindOnce(&MockObject::Task, Unretained(&mock_object),
+ MakeRefCounted<ObjectToDelete>(&delete_task_flag)));
+ }
+
+ EXPECT_FALSE(delete_task_flag);
+ cb = RepeatingCallback<void(int)>();
+ EXPECT_TRUE(delete_task_flag);
+}
+
+TEST(PromiseMemoryLeakTest, GetRejectCallbackNeverRun) {
+ test::TaskEnvironment task_environment_;
+ OnceCallback<void(int)> cb;
+ MockObject mock_object;
+ bool delete_task_flag = false;
+
+ {
+ ManualPromiseResolver<void, int> p(FROM_HERE);
+ cb = p.GetRejectCallback();
+
+ p.promise().CatchHere(
+ FROM_HERE, BindOnce(&MockObject::Task, Unretained(&mock_object),
+ MakeRefCounted<ObjectToDelete>(&delete_task_flag)));
+ }
+
+ EXPECT_FALSE(delete_task_flag);
+ cb = OnceCallback<void(int)>();
+ EXPECT_TRUE(delete_task_flag);
+}
+
+TEST(PromiseMemoryLeakTest, GetRepeatingRejectCallbackNeverRun) {
+ test::TaskEnvironment task_environment_;
+ RepeatingCallback<void(int)> cb;
+ MockObject mock_object;
+ bool delete_task_flag = false;
+
+ {
+ ManualPromiseResolver<void, int> p(FROM_HERE);
+ cb = p.GetRepeatingRejectCallback();
+
+ p.promise().CatchHere(
+ FROM_HERE, BindOnce(&MockObject::Task, Unretained(&mock_object),
+ MakeRefCounted<ObjectToDelete>(&delete_task_flag)));
+ }
+
+ EXPECT_FALSE(delete_task_flag);
+ cb = RepeatingCallback<void(int)>();
+ EXPECT_TRUE(delete_task_flag);
+}
+
TEST_F(PromiseTest, GetResolveCallbackThen) {
ManualPromiseResolver<int> p(FROM_HERE);
p.GetResolveCallback().Run(123);
@@ -1602,13 +1682,17 @@ TEST_F(PromiseTest, MoveOnlyTypeMultipleCatchesNotAllowed) {
auto p = Promise<void, std::unique_ptr<int>>::CreateRejected(
FROM_HERE, std::make_unique<int>(123));
- p.CatchHere(FROM_HERE,
- BindOnce([](std::unique_ptr<int> i) { EXPECT_EQ(123, *i); }));
+ auto r = p.CatchHere(
+ FROM_HERE, BindOnce([](std::unique_ptr<int> i) { EXPECT_EQ(123, *i); }));
EXPECT_DCHECK_DEATH({
p.CatchHere(FROM_HERE,
BindOnce([](std::unique_ptr<int> i) { EXPECT_EQ(123, *i); }));
});
+
+ // TODO(alexclarke): Temporary, remove when SequenceManager handles promises
+ // natively.
+ r.GetScopedRefptrForTesting()->OnCanceled();
#endif
}
diff --git a/chromium/base/task/promise/promise_value.h b/chromium/base/task/promise/promise_value.h
index 32ec758716d..3b1cfc43464 100644
--- a/chromium/base/task/promise/promise_value.h
+++ b/chromium/base/task/promise/promise_value.h
@@ -40,9 +40,6 @@ struct Resolved {
"Can't have Resolved<NoResolve>");
}
- Resolved(const Resolved& other) = default;
- Resolved(Resolved&& other) = default;
-
// Conversion constructor accepts any arguments except Resolved<T>.
template <
typename... Args,
@@ -75,9 +72,6 @@ struct Rejected {
"Can't have Rejected<NoReject>");
}
- Rejected(const Rejected& other) = default;
- Rejected(Rejected&& other) = default;
-
// Conversion constructor accepts any arguments except Rejected<T>.
template <
typename... Args,
diff --git a/chromium/base/task/promise/then_and_catch_executor.cc b/chromium/base/task/promise/then_and_catch_executor.cc
index 5f7f8f09ad0..5eb38e99b78 100644
--- a/chromium/base/task/promise/then_and_catch_executor.cc
+++ b/chromium/base/task/promise/then_and_catch_executor.cc
@@ -8,14 +8,14 @@ namespace base {
namespace internal {
bool ThenAndCatchExecutorCommon::IsCancelled() const {
- if (!resolve_callback_.is_null()) {
+ if (!then_callback_.is_null()) {
// If there is both a resolve and a reject executor they must be canceled
// at the same time.
- DCHECK(reject_callback_.is_null() ||
- reject_callback_.IsCancelled() == resolve_callback_.IsCancelled());
- return resolve_callback_.IsCancelled();
+ DCHECK(catch_callback_.is_null() ||
+ catch_callback_.IsCancelled() == then_callback_.IsCancelled());
+ return then_callback_.IsCancelled();
}
- return reject_callback_.IsCancelled();
+ return catch_callback_.IsCancelled();
}
void ThenAndCatchExecutorCommon::Execute(AbstractPromise* promise,
@@ -23,16 +23,16 @@ void ThenAndCatchExecutorCommon::Execute(AbstractPromise* promise,
ExecuteCallback execute_catch) {
AbstractPromise* prerequisite = promise->GetOnlyPrerequisite();
if (prerequisite->IsResolved()) {
- if (ProcessNullCallback(resolve_callback_, prerequisite, promise))
+ if (ProcessNullCallback(then_callback_, prerequisite, promise))
return;
- execute_then(prerequisite, promise, &resolve_callback_);
+ execute_then(prerequisite, promise, &then_callback_);
} else {
DCHECK(prerequisite->IsRejected());
- if (ProcessNullCallback(reject_callback_, prerequisite, promise))
+ if (ProcessNullCallback(catch_callback_, prerequisite, promise))
return;
- execute_catch(prerequisite, promise, &reject_callback_);
+ execute_catch(prerequisite, promise, &catch_callback_);
}
}
diff --git a/chromium/base/task/promise/then_and_catch_executor.h b/chromium/base/task/promise/then_and_catch_executor.h
index 56d30ba2a11..7668fc1fbcb 100644
--- a/chromium/base/task/promise/then_and_catch_executor.h
+++ b/chromium/base/task/promise/then_and_catch_executor.h
@@ -17,11 +17,11 @@ namespace internal {
// Exists to reduce template bloat.
class BASE_EXPORT ThenAndCatchExecutorCommon {
public:
- ThenAndCatchExecutorCommon(internal::CallbackBase&& resolve_executor,
- internal::CallbackBase&& reject_executor) noexcept
- : resolve_callback_(std::move(resolve_executor)),
- reject_callback_(std::move(reject_executor)) {
- DCHECK(!resolve_callback_.is_null() || !reject_callback_.is_null());
+ ThenAndCatchExecutorCommon(internal::CallbackBase&& then_callback,
+ internal::CallbackBase&& catch_callback) noexcept
+ : then_callback_(std::move(then_callback)),
+ catch_callback_(std::move(catch_callback)) {
+ DCHECK(!then_callback_.is_null() || !catch_callback_.is_null());
}
~ThenAndCatchExecutorCommon() = default;
@@ -44,24 +44,23 @@ class BASE_EXPORT ThenAndCatchExecutorCommon {
AbstractPromise* arg,
AbstractPromise* result);
- CallbackBase resolve_callback_;
- CallbackBase reject_callback_;
+ CallbackBase then_callback_;
+ CallbackBase catch_callback_;
};
// Tag signals no callback which is used to eliminate dead code.
struct NoCallback {};
-template <typename ResolveOnceCallback,
- typename RejectOnceCallback,
+template <typename ThenOnceCallback,
+ typename CatchOnceCallback,
typename ArgResolve,
typename ArgReject,
typename ResolveStorage,
typename RejectStorage>
class ThenAndCatchExecutor {
public:
- using ResolveReturnT =
- typename CallbackTraits<ResolveOnceCallback>::ReturnType;
- using RejectReturnT = typename CallbackTraits<RejectOnceCallback>::ReturnType;
+ using ThenReturnT = typename CallbackTraits<ThenOnceCallback>::ReturnType;
+ using CatchReturnT = typename CallbackTraits<CatchOnceCallback>::ReturnType;
using PrerequisiteCouldResolve =
std::integral_constant<bool,
!std::is_same<ArgResolve, NoCallback>::value>;
@@ -69,8 +68,8 @@ class ThenAndCatchExecutor {
std::integral_constant<bool, !std::is_same<ArgReject, NoCallback>::value>;
ThenAndCatchExecutor(CallbackBase&& resolve_callback,
- CallbackBase&& reject_callback) noexcept
- : common_(std::move(resolve_callback), std::move(reject_callback)) {}
+ CallbackBase&& catch_callback) noexcept
+ : common_(std::move(resolve_callback), std::move(catch_callback)) {}
bool IsCancelled() const { return common_.IsCancelled(); }
@@ -85,29 +84,29 @@ class ThenAndCatchExecutor {
#if DCHECK_IS_ON()
PromiseExecutor::ArgumentPassingType ResolveArgumentPassingType() const {
- return common_.resolve_callback_.is_null()
+ return common_.then_callback_.is_null()
? PromiseExecutor::ArgumentPassingType::kNoCallback
- : CallbackTraits<ResolveOnceCallback>::argument_passing_type;
+ : CallbackTraits<ThenOnceCallback>::argument_passing_type;
}
PromiseExecutor::ArgumentPassingType RejectArgumentPassingType() const {
- return common_.reject_callback_.is_null()
+ return common_.catch_callback_.is_null()
? PromiseExecutor::ArgumentPassingType::kNoCallback
- : CallbackTraits<RejectOnceCallback>::argument_passing_type;
+ : CallbackTraits<CatchOnceCallback>::argument_passing_type;
}
bool CanResolve() const {
- return (!common_.resolve_callback_.is_null() &&
- PromiseCallbackTraits<ResolveReturnT>::could_resolve) ||
- (!common_.reject_callback_.is_null() &&
- PromiseCallbackTraits<RejectReturnT>::could_resolve);
+ return (!common_.then_callback_.is_null() &&
+ PromiseCallbackTraits<ThenReturnT>::could_resolve) ||
+ (!common_.catch_callback_.is_null() &&
+ PromiseCallbackTraits<CatchReturnT>::could_resolve);
}
bool CanReject() const {
- return (!common_.resolve_callback_.is_null() &&
- PromiseCallbackTraits<ResolveReturnT>::could_reject) ||
- (!common_.reject_callback_.is_null() &&
- PromiseCallbackTraits<RejectReturnT>::could_reject);
+ return (!common_.then_callback_.is_null() &&
+ PromiseCallbackTraits<ThenReturnT>::could_reject) ||
+ (!common_.catch_callback_.is_null() &&
+ PromiseCallbackTraits<CatchReturnT>::could_reject);
}
#endif
@@ -121,8 +120,8 @@ class ThenAndCatchExecutor {
static void ExecuteCatch(AbstractPromise* prerequisite,
AbstractPromise* promise,
- CallbackBase* reject_callback) {
- ExecuteCatchInternal(prerequisite, promise, reject_callback,
+ CallbackBase* catch_callback) {
+ ExecuteCatchInternal(prerequisite, promise, catch_callback,
PrerequisiteCouldReject());
}
@@ -130,10 +129,16 @@ class ThenAndCatchExecutor {
AbstractPromise* promise,
CallbackBase* resolve_callback,
std::true_type can_resolve) {
- RunHelper<ResolveOnceCallback, Resolved<ArgResolve>, ResolveStorage,
- RejectStorage>::
- Run(std::move(*static_cast<ResolveOnceCallback*>(resolve_callback)),
- prerequisite, promise);
+ // Internally RunHelper uses const RepeatingCallback<>& to avoid the
+ // binary size overhead of moving a scoped_refptr<> about. We respect
+ // the onceness of the callback and RunHelper will overwrite the callback
+ // with the result.
+ using RepeatingThenCB =
+ typename ToRepeatingCallback<ThenOnceCallback>::value;
+ RunHelper<
+ RepeatingThenCB, Resolved<ArgResolve>, ResolveStorage,
+ RejectStorage>::Run(*static_cast<RepeatingThenCB*>(resolve_callback),
+ prerequisite, promise);
}
static void ExecuteThenInternal(AbstractPromise* prerequisite,
@@ -145,17 +150,23 @@ class ThenAndCatchExecutor {
static void ExecuteCatchInternal(AbstractPromise* prerequisite,
AbstractPromise* promise,
- CallbackBase* reject_callback,
+ CallbackBase* catch_callback,
std::true_type can_reject) {
- RunHelper<RejectOnceCallback, Rejected<ArgReject>, ResolveStorage,
- RejectStorage>::
- Run(std::move(*static_cast<RejectOnceCallback*>(reject_callback)),
- prerequisite, promise);
+ // Internally RunHelper uses const RepeatingCallback<>& to avoid the
+ // binary size overhead of moving a scoped_refptr<> about. We respect
+ // the onceness of the callback and RunHelper will overwrite the callback
+ // with the result.
+ using RepeatingCatchCB =
+ typename ToRepeatingCallback<CatchOnceCallback>::value;
+ RunHelper<
+ RepeatingCatchCB, Rejected<ArgReject>, ResolveStorage,
+ RejectStorage>::Run(*static_cast<RepeatingCatchCB*>(catch_callback),
+ prerequisite, promise);
}
static void ExecuteCatchInternal(AbstractPromise* prerequisite,
AbstractPromise* promise,
- CallbackBase* reject_callback,
+ CallbackBase* catch_callback,
std::false_type can_reject) {
// |prerequisite| can't reject so don't generate dead code.
}