Skip to content

Commit

Permalink
[base] Remove Code Duplication between base::Bind{Once,Repeating}
Browse files Browse the repository at this point in the history
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/+/1617775
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#666229}
  • Loading branch information
jdoerrie authored and Commit Bot committed Jun 5, 2019
1 parent b77149f commit 8739ded
Showing 1 changed file with 46 additions and 43 deletions.
89 changes: 46 additions & 43 deletions base/bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <functional>
#include <memory>
#include <type_traits>
#include <utility>

#include "base/bind_internal.h"
Expand Down Expand Up @@ -179,26 +180,39 @@ template <bool is_once, bool is_method, typename... Args>
using MakeUnwrappedTypeList =
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 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)).");
template <typename Invoker>
struct InvokeFuncImpl<false, Invoker> {
static constexpr auto Value = &Invoker::Run;
};

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
// target function. This check does not affect the behavior of Bind, but its
// error message should be more readable.
static constexpr bool kIsOnce = IsOnceCallback<CallbackT<void()>>::value;
using Helper = internal::BindTypeHelper<Functor, Args...>;
using FunctorTraits = typename Helper::FunctorTraits;
using BoundArgsList = typename Helper::BoundArgsList;
using UnwrappedArgsList =
internal::MakeUnwrappedTypeList<true, FunctorTraits::is_method,
internal::MakeUnwrappedTypeList<kIsOnce, FunctorTraits::is_method,
Args&&...>;
using BoundParamsList = typename Helper::BoundParamsList;
static_assert(internal::AssertBindArgsValidity<
Expand All @@ -209,20 +223,37 @@ BindOnce(Functor&& functor, Args&&... args) {
using BindState = internal::MakeBindStateType<Functor, Args...>;
using UnboundRunType = MakeUnboundRunType<Functor, Args...>;
using Invoker = internal::Invoker<BindState, UnboundRunType>;
using CallbackType = OnceCallback<UnboundRunType>;
using CallbackType = CallbackT<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::RunOnce;
PolymorphicInvoke invoke_func = InvokeFuncImpl<kIsOnce, Invoker>::Value;

using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage;
return CallbackType(BindState::Create(
reinterpret_cast<InvokeFuncStorage>(invoke_func),
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.
template <typename Functor, typename... Args>
inline RepeatingCallback<MakeUnboundRunType<Functor, Args...>>
Expand All @@ -231,36 +262,8 @@ BindRepeating(Functor&& functor, Args&&... args) {
!internal::IsOnceCallback<std::decay_t<Functor>>(),
"BindRepeating cannot bind OnceCallback. Use BindOnce with std::move().");

// 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
// 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)...));
return internal::BindImpl<RepeatingCallback>(std::forward<Functor>(functor),
std::forward<Args>(args)...);
}

// Unannotated Bind.
Expand Down

0 comments on commit 8739ded

Please sign in to comment.