Commit a089acfe authored by Jeremy Roman's avatar Jeremy Roman Committed by Commit Bot

Teach CrossThreadBind* how to use CrossThread*Function as a functor.

This allows "currying" of WTF cross-thread functions to be done using
CrossThreadBindOnce and CrossThreadBindRepeating (but not with base::Bind).

This is a reasonably common pattern to do with base callbacks and is
a reasonable thing to want from WTF's wrappers.

Bug: 992422
Change-Id: I9d3311e0362ef25657c31ce952becdfb7d0bc81a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1750043
Auto-Submit: Jeremy Roman <jbroman@chromium.org>
Commit-Queue: Kentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#686262}
parent ab8c7d69
......@@ -292,6 +292,7 @@ jumbo_source_set("wtf_unittests_sources") {
"allocator/partitions_test.cc",
"ascii_ctype_test.cc",
"assertions_test.cc",
"cross_thread_functional_test.cc",
"decimal_test.cc",
"deque_test.cc",
"doubly_linked_list_test.cc",
......
......@@ -33,30 +33,65 @@ namespace WTF {
// Bind(&Func1, 42, str);
// Bind(&Func1, 42, str.IsolatedCopy());
namespace internal {
// Deduction of the signature to avoid complicated calls to MakeUnboundRunType.
template <typename Signature>
auto MakeCrossThreadFunction(base::RepeatingCallback<Signature> callback) {
return CrossThreadFunction<Signature>(std::move(callback));
}
template <typename Signature>
auto MakeCrossThreadOnceFunction(base::OnceCallback<Signature> callback) {
return CrossThreadOnceFunction<Signature>(std::move(callback));
}
// Insertion of coercion for specific types; transparent forwarding otherwise.
template <typename T>
decltype(auto) CoerceFunctorForCrossThreadBind(T&& functor) {
return std::forward<T>(functor);
}
template <typename Signature>
base::RepeatingCallback<Signature> CoerceFunctorForCrossThreadBind(
CrossThreadFunction<Signature>&& functor) {
return ConvertToBaseCallback(std::move(functor));
}
template <typename Signature>
base::OnceCallback<Signature> CoerceFunctorForCrossThreadBind(
CrossThreadOnceFunction<Signature>&& functor) {
return ConvertToBaseOnceCallback(std::move(functor));
}
} // namespace internal
template <typename FunctionType, typename... Ps>
CrossThreadFunction<base::MakeUnboundRunType<FunctionType, Ps...>>
CrossThreadBindRepeating(FunctionType&& function, Ps&&... parameters) {
auto CrossThreadBindRepeating(FunctionType&& function, Ps&&... parameters) {
static_assert(
internal::CheckGCedTypeRestrictions<std::index_sequence_for<Ps...>,
std::decay_t<Ps>...>::ok,
"A bound argument uses a bad pattern.");
using UnboundRunType = base::MakeUnboundRunType<FunctionType, Ps...>;
return CrossThreadFunction<UnboundRunType>(
base::Bind(function, CrossThreadCopier<std::decay_t<Ps>>::Copy(
std::forward<Ps>(parameters))...));
return internal::MakeCrossThreadFunction(
base::Bind(internal::CoerceFunctorForCrossThreadBind(
std::forward<FunctionType>(function)),
CrossThreadCopier<std::decay_t<Ps>>::Copy(
std::forward<Ps>(parameters))...));
}
template <typename FunctionType, typename... Ps>
CrossThreadOnceFunction<base::MakeUnboundRunType<FunctionType, Ps...>>
CrossThreadBindOnce(FunctionType&& function, Ps&&... parameters) {
auto CrossThreadBindOnce(FunctionType&& function, Ps&&... parameters) {
static_assert(
internal::CheckGCedTypeRestrictions<std::index_sequence_for<Ps...>,
std::decay_t<Ps>...>::ok,
"A bound argument uses a bad pattern.");
using UnboundRunType = base::MakeUnboundRunType<FunctionType, Ps...>;
return CrossThreadOnceFunction<UnboundRunType>(base::BindOnce(
std::move(function), CrossThreadCopier<std::decay_t<Ps>>::Copy(
std::forward<Ps>(parameters))...));
return internal::MakeCrossThreadOnceFunction(
base::BindOnce(internal::CoerceFunctorForCrossThreadBind(
std::forward<FunctionType>(function)),
CrossThreadCopier<std::decay_t<Ps>>::Copy(
std::forward<Ps>(parameters))...));
}
} // namespace WTF
......
// 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.
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include <utility>
#include "testing/gtest/include/gtest/gtest.h"
namespace WTF {
namespace {
// Tests that "currying" CrossThreadFunction and CrossThreadOnceFunction works,
// as it does with the base counterparts.
struct SomeFunctor;
static_assert(std::is_same<decltype(internal::CoerceFunctorForCrossThreadBind(
std::declval<SomeFunctor&>())),
SomeFunctor&>(),
"functor coercion should not affect Functor lvalue ref type");
static_assert(std::is_same<decltype(internal::CoerceFunctorForCrossThreadBind(
std::declval<SomeFunctor>())),
SomeFunctor&&>(),
"functor coercion should not affect Functor rvalue ref type");
TEST(CrossThreadFunctionalTest, CrossThreadBindRepeating_CrossThreadFunction) {
auto adder = CrossThreadBindRepeating([](int x, int y) { return x + y; });
auto five_adder = CrossThreadBindRepeating(std::move(adder), 5);
EXPECT_EQ(five_adder.Run(7), 12);
}
TEST(CrossThreadFunctionalTest, CrossThreadBindOnce_CrossThreadOnceFunction) {
auto adder = CrossThreadBindOnce([](int x, int y) { return x + y; });
auto five_adder = CrossThreadBindOnce(std::move(adder), 5);
EXPECT_EQ(std::move(five_adder).Run(7), 12);
}
TEST(CrossThreadFunctionalTest, CrossThreadBindOnce_CrossThreadFunction) {
auto adder = CrossThreadBindRepeating([](int x, int y) { return x + y; });
auto five_adder = CrossThreadBindOnce(std::move(adder), 5);
EXPECT_EQ(std::move(five_adder).Run(7), 12);
}
} // namespace
} // namespace WTF
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment