Commit 8739ded9 authored by Jan Wilken Dörrie's avatar Jan Wilken Dörrie Committed by Commit Bot

[base] Remove Code Duplication between base::Bind{Once,Repeating}

This change removes code duplication between base::BindOnce and
base::BindRepeating by introducing a generic base::internal::BindImpl.

Bug: 554299
Change-Id: Ia06233baf973d62b458ed5cb3fbded0da865f83b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1617775Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#666229}
parent b77149f3
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <type_traits>
#include <utility> #include <utility>
#include "base/bind_internal.h" #include "base/bind_internal.h"
...@@ -179,26 +180,39 @@ template <bool is_once, bool is_method, typename... Args> ...@@ -179,26 +180,39 @@ template <bool is_once, bool is_method, typename... Args>
using MakeUnwrappedTypeList = using MakeUnwrappedTypeList =
typename MakeUnwrappedTypeListImpl<is_once, is_method, Args...>::Type; typename MakeUnwrappedTypeListImpl<is_once, is_method, Args...>::Type;
} // namespace internal // Used below in BindImpl to determine whether to use Invoker::Run or
// Invoker::RunOnce.
// Note: Simply using `kIsOnce ? &Invoker::RunOnce : &Invoker::Run` does not
// work, since the compiler needs to check whether both expressions are
// well-formed. Using `Invoker::Run` with a OnceCallback triggers a
// static_assert, which is why the ternary expression does not compile.
// TODO(crbug.com/752720): Remove this indirection once we have `if constexpr`.
template <bool is_once, typename Invoker>
struct InvokeFuncImpl;
template <typename Invoker>
struct InvokeFuncImpl<true, Invoker> {
static constexpr auto Value = &Invoker::RunOnce;
};
// Bind as OnceCallback. template <typename Invoker>
template <typename Functor, typename... Args> struct InvokeFuncImpl<false, Invoker> {
inline OnceCallback<MakeUnboundRunType<Functor, Args...>> static constexpr auto Value = &Invoker::Run;
BindOnce(Functor&& functor, Args&&... args) { };
static_assert(!internal::IsOnceCallback<std::decay_t<Functor>>() ||
(std::is_rvalue_reference<Functor&&>() &&
!std::is_const<std::remove_reference_t<Functor>>()),
"BindOnce requires non-const rvalue for OnceCallback binding."
" I.e.: base::BindOnce(std::move(callback)).");
template <template <typename> class CallbackT,
typename Functor,
typename... Args>
decltype(auto) BindImpl(Functor&& functor, Args&&... args) {
// This block checks if each |args| matches to the corresponding params of the // This block checks if each |args| matches to the corresponding params of the
// target function. This check does not affect the behavior of Bind, but its // target function. This check does not affect the behavior of Bind, but its
// error message should be more readable. // error message should be more readable.
static constexpr bool kIsOnce = IsOnceCallback<CallbackT<void()>>::value;
using Helper = internal::BindTypeHelper<Functor, Args...>; using Helper = internal::BindTypeHelper<Functor, Args...>;
using FunctorTraits = typename Helper::FunctorTraits; using FunctorTraits = typename Helper::FunctorTraits;
using BoundArgsList = typename Helper::BoundArgsList; using BoundArgsList = typename Helper::BoundArgsList;
using UnwrappedArgsList = using UnwrappedArgsList =
internal::MakeUnwrappedTypeList<true, FunctorTraits::is_method, internal::MakeUnwrappedTypeList<kIsOnce, FunctorTraits::is_method,
Args&&...>; Args&&...>;
using BoundParamsList = typename Helper::BoundParamsList; using BoundParamsList = typename Helper::BoundParamsList;
static_assert(internal::AssertBindArgsValidity< static_assert(internal::AssertBindArgsValidity<
...@@ -209,13 +223,13 @@ BindOnce(Functor&& functor, Args&&... args) { ...@@ -209,13 +223,13 @@ BindOnce(Functor&& functor, Args&&... args) {
using BindState = internal::MakeBindStateType<Functor, Args...>; using BindState = internal::MakeBindStateType<Functor, Args...>;
using UnboundRunType = MakeUnboundRunType<Functor, Args...>; using UnboundRunType = MakeUnboundRunType<Functor, Args...>;
using Invoker = internal::Invoker<BindState, UnboundRunType>; using Invoker = internal::Invoker<BindState, UnboundRunType>;
using CallbackType = OnceCallback<UnboundRunType>; using CallbackType = CallbackT<UnboundRunType>;
// Store the invoke func into PolymorphicInvoke before casting it to // Store the invoke func into PolymorphicInvoke before casting it to
// InvokeFuncStorage, so that we can ensure its type matches to // InvokeFuncStorage, so that we can ensure its type matches to
// PolymorphicInvoke, to which CallbackType will cast back. // PolymorphicInvoke, to which CallbackType will cast back.
using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke; using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke;
PolymorphicInvoke invoke_func = &Invoker::RunOnce; PolymorphicInvoke invoke_func = InvokeFuncImpl<kIsOnce, Invoker>::Value;
using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage; using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage;
return CallbackType(BindState::Create( return CallbackType(BindState::Create(
...@@ -223,6 +237,23 @@ BindOnce(Functor&& functor, Args&&... args) { ...@@ -223,6 +237,23 @@ BindOnce(Functor&& functor, Args&&... args) {
std::forward<Functor>(functor), std::forward<Args>(args)...)); std::forward<Functor>(functor), std::forward<Args>(args)...));
} }
} // namespace internal
// Bind as OnceCallback.
template <typename Functor, typename... Args>
inline OnceCallback<MakeUnboundRunType<Functor, Args...>> BindOnce(
Functor&& functor,
Args&&... args) {
static_assert(!internal::IsOnceCallback<std::decay_t<Functor>>() ||
(std::is_rvalue_reference<Functor&&>() &&
!std::is_const<std::remove_reference_t<Functor>>()),
"BindOnce requires non-const rvalue for OnceCallback binding."
" I.e.: base::BindOnce(std::move(callback)).");
return internal::BindImpl<OnceCallback>(std::forward<Functor>(functor),
std::forward<Args>(args)...);
}
// Bind as RepeatingCallback. // Bind as RepeatingCallback.
template <typename Functor, typename... Args> template <typename Functor, typename... Args>
inline RepeatingCallback<MakeUnboundRunType<Functor, Args...>> inline RepeatingCallback<MakeUnboundRunType<Functor, Args...>>
...@@ -231,36 +262,8 @@ BindRepeating(Functor&& functor, Args&&... args) { ...@@ -231,36 +262,8 @@ BindRepeating(Functor&& functor, Args&&... args) {
!internal::IsOnceCallback<std::decay_t<Functor>>(), !internal::IsOnceCallback<std::decay_t<Functor>>(),
"BindRepeating cannot bind OnceCallback. Use BindOnce with std::move()."); "BindRepeating cannot bind OnceCallback. Use BindOnce with std::move().");
// This block checks if each |args| matches to the corresponding params of the return internal::BindImpl<RepeatingCallback>(std::forward<Functor>(functor),
// target function. This check does not affect the behavior of Bind, but its std::forward<Args>(args)...);
// error message should be more readable.
using Helper = internal::BindTypeHelper<Functor, Args...>;
using FunctorTraits = typename Helper::FunctorTraits;
using BoundArgsList = typename Helper::BoundArgsList;
using UnwrappedArgsList =
internal::MakeUnwrappedTypeList<false, FunctorTraits::is_method,
Args&&...>;
using BoundParamsList = typename Helper::BoundParamsList;
static_assert(internal::AssertBindArgsValidity<
std::make_index_sequence<Helper::num_bounds>, BoundArgsList,
UnwrappedArgsList, BoundParamsList>::ok,
"The bound args need to be convertible to the target params.");
using BindState = internal::MakeBindStateType<Functor, Args...>;
using UnboundRunType = MakeUnboundRunType<Functor, Args...>;
using Invoker = internal::Invoker<BindState, UnboundRunType>;
using CallbackType = RepeatingCallback<UnboundRunType>;
// Store the invoke func into PolymorphicInvoke before casting it to
// InvokeFuncStorage, so that we can ensure its type matches to
// PolymorphicInvoke, to which CallbackType will cast back.
using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke;
PolymorphicInvoke invoke_func = &Invoker::Run;
using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage;
return CallbackType(BindState::Create(
reinterpret_cast<InvokeFuncStorage>(invoke_func),
std::forward<Functor>(functor), std::forward<Args>(args)...));
} }
// Unannotated Bind. // Unannotated Bind.
......
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