Remove `Runnable` concept from base/bind_internal.h
`Runnable` concept was useful when bind_internal.h was a huge generated
file. However, it's an unneeded layer these days.
This CL removes `Runnable` from bind_internal.h to simplify its impl.
After this CL, BindState holds the bound Functor directly in its internal
storage.
This CL contains:
* Merge bind_internal_win.h into bind_internal.h
* Move typechecks in Bind() into MakeBindStateType.
* Remove no longer used HasIsMethodTag in bind_helper.h.
* Remove InvokeHelper specialization for IgnoreResult.
* Merge assertion-only InvokeHelper specialization into another
specialization.
* Factor out the type setup in BindState into MakeBindStateType.
BUG=554299
Review-Url: https://codereview.chromium.org/2106773002
Cr-Commit-Position: refs/heads/master@{#403413}
CrOS-Libchrome-Original-Commit: 99de02ba952b0a69291f81c5b8ca14d81cc1f74f
diff --git a/base/bind_internal.h b/base/bind_internal.h
index c7d6c3b..6b692a8 100644
--- a/base/bind_internal.h
+++ b/base/bind_internal.h
@@ -18,10 +18,6 @@
#include "base/tuple.h"
#include "build/build_config.h"
-#if defined(OS_WIN)
-#include "base/bind_internal_win.h"
-#endif
-
namespace base {
namespace internal {
@@ -29,40 +25,26 @@
//
//
// CONCEPTS:
-// Runnable -- A type (really a type class) that has a single Run() method
-// and a RunType typedef that corresponds to the type of Run().
-// A Runnable can declare that it should treated like a method
-// call by including a typedef named IsMethod. The value of
-// this typedef is NOT inspected, only the existence. When a
-// Runnable declares itself a method, Bind() will enforce special
-// refcounting + WeakPtr handling semantics for the first
-// parameter which is expected to be an object.
-// Functor -- A copyable type representing something that should be called.
-// All function pointers, Callback<>, and Runnables are functors
-// even if the invocation syntax differs.
+// Functor -- A movable type representing something that should be called.
+// All function pointers and Callback<> are functors even if the
+// invocation syntax differs.
// RunType -- A function type (as opposed to function _pointer_ type) for
-// a Run() function. Usually just a convenience typedef.
+// a Callback<>::Run(). Usually just a convenience typedef.
// (Bound)Args -- A set of types that stores the arguments.
//
// Types:
-// RunnableAdapter<> -- Wraps the various "function" pointer types into an
-// object that adheres to the Runnable interface.
// ForceVoidReturn<> -- Helper class for translating function signatures to
// equivalent forms with a "void" return type.
-// FunctorTraits<> -- Type traits used determine the correct RunType and
-// RunnableType for a Functor. This is where function
+// FunctorTraits<> -- Type traits used to determine the correct RunType and
+// invocation manner for a Functor. This is where function
// signature adapters are applied.
-// MakeRunnable<> -- Takes a Functor and returns an object in the Runnable
-// type class that represents the underlying Functor.
-// InvokeHelper<> -- Take a Runnable + arguments and actully invokes it.
+// InvokeHelper<> -- Take a Functor + arguments and actully invokes it.
// Handle the differing syntaxes needed for WeakPtr<>
-// support, and for ignoring return values. This is separate
-// from Invoker to avoid creating multiple version of
-// Invoker<>.
-// Invoker<> -- Unwraps the curried parameters and executes the Runnable.
+// support. This is separate from Invoker to avoid creating
+// multiple version of Invoker<>.
+// Invoker<> -- Unwraps the curried parameters and executes the Functor.
// BindState<> -- Stores the curried parameters, and is the main entry point
-// into the Bind() system, doing most of the type resolution.
-// There are ARITY BindState types.
+// into the Bind() system.
// HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw
// pointer to a RefCounted type.
@@ -80,127 +62,6 @@
std::true_type,
HasRefCountedTypeAsRawPtr<Args...>>::type {};
-// BindsArrayToFirstArg selects true_type when |is_method| is true and the first
-// item of |Args| is an array type.
-// Implementation note: This non-specialized case handles !is_method case and
-// zero-arity case only. Other cases should be handled by the specialization
-// below.
-template <bool is_method, typename... Args>
-struct BindsArrayToFirstArg : std::false_type {};
-
-template <typename T, typename... Args>
-struct BindsArrayToFirstArg<true, T, Args...>
- : std::is_array<typename std::remove_reference<T>::type> {};
-
-// HasRefCountedParamAsRawPtr is the same to HasRefCountedTypeAsRawPtr except
-// when |is_method| is true HasRefCountedParamAsRawPtr skips the first argument.
-// Implementation note: This non-specialized case handles !is_method case and
-// zero-arity case only. Other cases should be handled by the specialization
-// below.
-template <bool is_method, typename... Args>
-struct HasRefCountedParamAsRawPtr : HasRefCountedTypeAsRawPtr<Args...> {};
-
-template <typename T, typename... Args>
-struct HasRefCountedParamAsRawPtr<true, T, Args...>
- : HasRefCountedTypeAsRawPtr<Args...> {};
-
-// RunnableAdapter<>
-//
-// The RunnableAdapter<> templates provide a uniform interface for invoking
-// a function pointer, method pointer, or const method pointer. The adapter
-// exposes a Run() method with an appropriate signature. Using this wrapper
-// allows for writing code that supports all three pointer types without
-// undue repetition. Without it, a lot of code would need to be repeated 3
-// times.
-//
-// For method pointers and const method pointers the first argument to Run()
-// is considered to be the received of the method. This is similar to STL's
-// mem_fun().
-//
-// This class also exposes a RunType typedef that is the function type of the
-// Run() function.
-//
-// If and only if the wrapper contains a method or const method pointer, an
-// IsMethod typedef is exposed. The existence of this typedef (NOT the value)
-// marks that the wrapper should be considered a method wrapper.
-
-template <typename Functor>
-class RunnableAdapter;
-
-// Function.
-template <typename R, typename... Args>
-class RunnableAdapter<R(*)(Args...)> {
- public:
- // MSVC 2013 doesn't support Type Alias of function types.
- // Revisit this after we update it to newer version.
- typedef R RunType(Args...);
-
- explicit RunnableAdapter(R(*function)(Args...))
- : function_(function) {
- }
-
- template <typename... RunArgs>
- R Run(RunArgs&&... args) const {
- return function_(std::forward<RunArgs>(args)...);
- }
-
- private:
- R (*function_)(Args...);
-};
-
-// Method.
-template <typename R, typename T, typename... Args>
-class RunnableAdapter<R(T::*)(Args...)> {
- public:
- // MSVC 2013 doesn't support Type Alias of function types.
- // Revisit this after we update it to newer version.
- typedef R RunType(T*, Args...);
- using IsMethod = std::true_type;
-
- explicit RunnableAdapter(R(T::*method)(Args...))
- : method_(method) {
- }
-
- template <typename Receiver, typename... RunArgs>
- R Run(Receiver&& receiver_ptr, RunArgs&&... args) const {
- // Clang skips CV qualifier check on a method pointer invocation when the
- // receiver is a subclass. Store the receiver into a const reference to
- // T to ensure the CV check works.
- // https://llvm.org/bugs/show_bug.cgi?id=27037
- T& receiver = *receiver_ptr;
- return (receiver.*method_)(std::forward<RunArgs>(args)...);
- }
-
- private:
- R (T::*method_)(Args...);
-};
-
-// Const Method.
-template <typename R, typename T, typename... Args>
-class RunnableAdapter<R(T::*)(Args...) const> {
- public:
- using RunType = R(const T*, Args...);
- using IsMethod = std::true_type;
-
- explicit RunnableAdapter(R(T::*method)(Args...) const)
- : method_(method) {
- }
-
- template <typename Receiver, typename... RunArgs>
- R Run(Receiver&& receiver_ptr, RunArgs&&... args) const {
- // Clang skips CV qualifier check on a method pointer invocation when the
- // receiver is a subclass. Store the receiver into a unqualified reference
- // to T to ensure the CV check works.
- // https://llvm.org/bugs/show_bug.cgi?id=27037
- const T& receiver = *receiver_ptr;
- return (receiver.*method_)(std::forward<RunArgs>(args)...);
- }
-
- private:
- R (T::*method_)(Args...) const;
-};
-
-
// ForceVoidReturn<>
//
// Set of templates that support forcing the function return type to void.
@@ -209,110 +70,142 @@
template <typename R, typename... Args>
struct ForceVoidReturn<R(Args...)> {
- // MSVC 2013 doesn't support Type Alias of function types.
- // Revisit this after we update it to newer version.
- typedef void RunType(Args...);
+ using RunType = void(Args...);
};
-
// FunctorTraits<>
//
// See description at top of file.
-template <typename T>
-struct FunctorTraits {
- using RunnableType = RunnableAdapter<T>;
- using RunType = typename RunnableType::RunType;
+template <typename Functor>
+struct FunctorTraits;
+
+// For functions.
+template <typename R, typename... Args>
+struct FunctorTraits<R (*)(Args...)> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+
+ template <typename... RunArgs>
+ static R Invoke(R (*function)(Args...), RunArgs&&... args) {
+ return function(std::forward<RunArgs>(args)...);
+ }
};
+#if defined(OS_WIN) && !defined(ARCH_CPU_X86_64)
+
+// For functions.
+template <typename R, typename... Args>
+struct FunctorTraits<R(__stdcall*)(Args...)> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+
+ template <typename... RunArgs>
+ static R Invoke(R(__stdcall* function)(Args...), RunArgs&&... args) {
+ return function(std::forward<RunArgs>(args)...);
+ }
+};
+
+// For functions.
+template <typename R, typename... Args>
+struct FunctorTraits<R(__fastcall*)(Args...)> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+
+ template <typename... RunArgs>
+ static R Invoke(R(__fastcall* function)(Args...), RunArgs&&... args) {
+ return function(std::forward<RunArgs>(args)...);
+ }
+};
+
+#endif // defined(OS_WIN) && !defined(ARCH_CPU_X86_64)
+
+// For methods.
+template <typename R, typename Receiver, typename... Args>
+struct FunctorTraits<R (Receiver::*)(Args...)> {
+ using RunType = R(Receiver*, Args...);
+ static constexpr bool is_method = true;
+
+ template <typename ReceiverPtr, typename... RunArgs>
+ static R Invoke(R (Receiver::*method)(Args...),
+ ReceiverPtr&& receiver_ptr,
+ RunArgs&&... args) {
+ // Clang skips CV qualifier check on a method pointer invocation when the
+ // receiver is a subclass. Store the receiver into a const reference to
+ // T to ensure the CV check works.
+ // https://llvm.org/bugs/show_bug.cgi?id=27037
+ Receiver& receiver = *receiver_ptr;
+ return (receiver.*method)(std::forward<RunArgs>(args)...);
+ }
+};
+
+// For const methods.
+template <typename R, typename Receiver, typename... Args>
+struct FunctorTraits<R (Receiver::*)(Args...) const> {
+ using RunType = R(const Receiver*, Args...);
+ static constexpr bool is_method = true;
+
+ template <typename ReceiverPtr, typename... RunArgs>
+ static R Invoke(R (Receiver::*method)(Args...) const,
+ ReceiverPtr&& receiver_ptr,
+ RunArgs&&... args) {
+ // Clang skips CV qualifier check on a method pointer invocation when the
+ // receiver is a subclass. Store the receiver into a const reference to
+ // T to ensure the CV check works.
+ // https://llvm.org/bugs/show_bug.cgi?id=27037
+ const Receiver& receiver = *receiver_ptr;
+ return (receiver.*method)(std::forward<RunArgs>(args)...);
+ }
+};
+
+// For IgnoreResults.
template <typename T>
-struct FunctorTraits<IgnoreResultHelper<T>> {
- using RunnableType = typename FunctorTraits<T>::RunnableType;
+struct FunctorTraits<IgnoreResultHelper<T>> : FunctorTraits<T> {
using RunType =
- typename ForceVoidReturn<typename RunnableType::RunType>::RunType;
+ typename ForceVoidReturn<typename FunctorTraits<T>::RunType>::RunType;
+
+ template <typename IgnoreResultType, typename... RunArgs>
+ static void Invoke(IgnoreResultType&& ignore_result_helper,
+ RunArgs&&... args) {
+ FunctorTraits<T>::Invoke(ignore_result_helper.functor_,
+ std::forward<RunArgs>(args)...);
+ }
};
-template <typename T>
-struct FunctorTraits<Callback<T>> {
- using RunnableType = Callback<T> ;
- using RunType = typename Callback<T>::RunType;
+// For Callbacks.
+template <typename R, typename... Args, CopyMode copy_mode>
+struct FunctorTraits<Callback<R(Args...), copy_mode>> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+
+ template <typename CallbackType, typename... RunArgs>
+ static R Invoke(CallbackType&& callback, RunArgs&&... args) {
+ DCHECK(!callback.is_null());
+ return std::forward<CallbackType>(callback).Run(
+ std::forward<RunArgs>(args)...);
+ }
};
-
-// MakeRunnable<>
-//
-// Converts a passed in functor to a RunnableType using type inference.
-
-template <typename T>
-typename FunctorTraits<T>::RunnableType MakeRunnable(const T& t) {
- return RunnableAdapter<T>(t);
-}
-
-template <typename T>
-typename FunctorTraits<T>::RunnableType
-MakeRunnable(const IgnoreResultHelper<T>& t) {
- return MakeRunnable(t.functor_);
-}
-
-template <typename T>
-const typename FunctorTraits<Callback<T>>::RunnableType&
-MakeRunnable(const Callback<T>& t) {
- DCHECK(!t.is_null());
- return t;
-}
-
-
// InvokeHelper<>
//
-// There are 3 logical InvokeHelper<> specializations: normal, void-return,
-// WeakCalls.
+// There are 2 logical InvokeHelper<> specializations: normal, WeakCalls.
//
// The normal type just calls the underlying runnable.
//
-// We need a InvokeHelper to handle void return types in order to support
-// IgnoreResult(). Normally, if the Runnable's RunType had a void return,
-// the template system would just accept "return functor.Run()" ignoring
-// the fact that a void function is being used with return. This piece of
-// sugar breaks though when the Runnable's RunType is not void. Thus, we
-// need a partial specialization to change the syntax to drop the "return"
-// from the invocation call.
-//
-// WeakCalls similarly need special syntax that is applied to the first
-// argument to check if they should no-op themselves.
+// WeakCalls need special syntax that is applied to the first argument to check
+// if they should no-op themselves.
template <bool is_weak_call, typename ReturnType>
struct InvokeHelper;
template <typename ReturnType>
struct InvokeHelper<false, ReturnType> {
- template <typename Runnable, typename... RunArgs>
- static inline ReturnType MakeItSo(Runnable&& runnable, RunArgs&&... args) {
- return std::forward<Runnable>(runnable).Run(std::forward<RunArgs>(args)...);
+ template <typename Functor, typename... RunArgs>
+ static inline ReturnType MakeItSo(Functor&& functor, RunArgs&&... args) {
+ using Traits = FunctorTraits<typename std::decay<Functor>::type>;
+ return Traits::Invoke(std::forward<Functor>(functor),
+ std::forward<RunArgs>(args)...);
}
};
-template <>
-struct InvokeHelper<false, void> {
- template <typename Runnable, typename... RunArgs>
- static inline void MakeItSo(Runnable&& runnable, RunArgs&&... args) {
- std::forward<Runnable>(runnable).Run(std::forward<RunArgs>(args)...);
- }
-};
-
-template <>
-struct InvokeHelper<true, void> {
- template <typename Runnable, typename BoundWeakPtr, typename... RunArgs>
- static void MakeItSo(Runnable&& runnable,
- BoundWeakPtr&& weak_ptr,
- RunArgs&&... args) {
- if (!weak_ptr) {
- return;
- }
- std::forward<Runnable>(runnable).Run(
- std::forward<BoundWeakPtr>(weak_ptr), std::forward<RunArgs>(args)...);
- }
-};
-
-#if !defined(_MSC_VER)
-
template <typename ReturnType>
struct InvokeHelper<true, ReturnType> {
// WeakCalls are only supported for functions with a void return type.
@@ -320,9 +213,19 @@
// is invalidated.
static_assert(std::is_void<ReturnType>::value,
"weak_ptrs can only bind to methods without return values");
-};
-#endif
+ template <typename Functor, typename BoundWeakPtr, typename... RunArgs>
+ static inline void MakeItSo(Functor&& functor,
+ BoundWeakPtr weak_ptr,
+ RunArgs&&... args) {
+ if (!weak_ptr)
+ return;
+ using Traits = FunctorTraits<typename std::decay<Functor>::type>;
+ Traits::Invoke(std::forward<Functor>(functor),
+ std::forward<BoundWeakPtr>(weak_ptr),
+ std::forward<RunArgs>(args)...);
+ }
+};
// Invoker<>
//
@@ -339,19 +242,20 @@
const StorageType* storage = static_cast<StorageType*>(base);
static constexpr size_t num_bound_args =
std::tuple_size<decltype(storage->bound_args_)>::value;
- return RunImpl(storage->runnable_,
+ return RunImpl(storage->functor_,
storage->bound_args_,
MakeIndexSequence<num_bound_args>(),
std::forward<UnboundArgs>(unbound_args)...);
}
- template <typename Runnable, typename BoundArgsTuple, size_t... indices>
- static inline R RunImpl(Runnable&& runnable,
+ private:
+ template <typename Functor, typename BoundArgsTuple, size_t... indices>
+ static inline R RunImpl(Functor&& functor,
BoundArgsTuple&& bound,
IndexSequence<indices...>,
UnboundArgs&&... unbound_args) {
static constexpr bool is_method =
- HasIsMethodTag<typename std::decay<Runnable>::type>::value;
+ FunctorTraits<typename std::decay<Functor>::type>::is_method;
using DecayedArgsTuple = typename std::decay<BoundArgsTuple>::type;
static constexpr bool is_weak_call =
@@ -361,35 +265,17 @@
DecayedArgsTuple>::type...>::value;
return InvokeHelper<is_weak_call, R>::MakeItSo(
- std::forward<Runnable>(runnable),
- Unwrap(std::get<indices>(std::forward<BoundArgsTuple>(bound)))...,
+ std::forward<Functor>(functor),
+ Unwrap(base::get<indices>(std::forward<BoundArgsTuple>(bound)))...,
std::forward<UnboundArgs>(unbound_args)...);
}
};
-// Used to implement MakeArgsStorage.
-template <bool is_method, typename... BoundArgs>
-struct MakeArgsStorageImpl {
- using Type = std::tuple<BoundArgs...>;
-};
-
-template <typename Obj, typename... BoundArgs>
-struct MakeArgsStorageImpl<true, Obj*, BoundArgs...> {
- using Type = std::tuple<scoped_refptr<Obj>, BoundArgs...>;
-};
-
-// Constructs a tuple type to store BoundArgs into BindState.
-// This wraps the first argument into a scoped_refptr if |is_method| is true and
-// the first argument is a raw pointer.
-// Other arguments are adjusted for store and packed into a tuple.
-template <bool is_method, typename... BoundArgs>
-using MakeArgsStorage = typename MakeArgsStorageImpl<
- is_method, typename std::decay<BoundArgs>::type...>::Type;
-
// Used to implement MakeUnboundRunType.
template <typename Functor, typename... BoundArgs>
struct MakeUnboundRunTypeImpl {
- using RunType = typename FunctorTraits<Functor>::RunType;
+ using RunType =
+ typename FunctorTraits<typename std::decay<Functor>::type>::RunType;
using ReturnType = ExtractReturnType<RunType>;
using Args = ExtractArgs<RunType>;
using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), Args>;
@@ -398,28 +284,19 @@
// BindState<>
//
-// This stores all the state passed into Bind() and is also where most
-// of the template resolution magic occurs.
-//
-// Runnable is the functor we are binding arguments to.
-//
-// BoundArgs contains the storage type for all the bound arguments.
-template <typename Runnable, typename... BoundArgs>
-struct BindState final : public BindStateBase {
- private:
- using RunnableType = typename std::decay<Runnable>::type;
-
- static constexpr bool is_method = HasIsMethodTag<RunnableType>::value;
-
- public:
- template <typename... ForwardArgs>
- explicit BindState(RunnableType runnable, ForwardArgs&&... bound_args)
+// This stores all the state passed into Bind().
+template <typename Functor, typename... BoundArgs>
+struct BindState final : BindStateBase {
+ template <typename... ForwardBoundArgs>
+ explicit BindState(Functor functor, ForwardBoundArgs&&... bound_args)
: BindStateBase(&Destroy),
- runnable_(std::move(runnable)),
- bound_args_(std::forward<ForwardArgs>(bound_args)...) {}
+ functor_(std::move(functor)),
+ bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {
+ DCHECK(functor_);
+ }
- RunnableType runnable_;
- MakeArgsStorage<is_method, BoundArgs...> bound_args_;
+ Functor functor_;
+ std::tuple<BoundArgs...> bound_args_;
private:
~BindState() {}
@@ -429,6 +306,50 @@
}
};
+// Used to implement MakeBindStateType.
+template <bool is_method, typename Functor, typename... BoundArgs>
+struct MakeBindStateTypeImpl;
+
+template <typename Functor, typename... BoundArgs>
+struct MakeBindStateTypeImpl<false, Functor, BoundArgs...> {
+ static_assert(!HasRefCountedTypeAsRawPtr<BoundArgs...>::value,
+ "A parameter is a refcounted type and needs scoped_refptr.");
+ using Type = BindState<typename std::decay<Functor>::type,
+ typename std::decay<BoundArgs>::type...>;
+};
+
+template <typename Functor>
+struct MakeBindStateTypeImpl<true, Functor> {
+ using Type = BindState<typename std::decay<Functor>::type>;
+};
+
+template <typename Functor, typename Receiver, typename... BoundArgs>
+struct MakeBindStateTypeImpl<true, Functor, Receiver, BoundArgs...> {
+ static_assert(
+ !std::is_array<typename std::remove_reference<Receiver>::type>::value,
+ "First bound argument to a method cannot be an array.");
+ static_assert(!HasRefCountedTypeAsRawPtr<BoundArgs...>::value,
+ "A parameter is a refcounted type and needs scoped_refptr.");
+
+ private:
+ using DecayedReceiver = typename std::decay<Receiver>::type;
+
+ public:
+ using Type = BindState<
+ typename std::decay<Functor>::type,
+ typename std::conditional<
+ std::is_pointer<DecayedReceiver>::value,
+ scoped_refptr<typename std::remove_pointer<DecayedReceiver>::type>,
+ DecayedReceiver>::type,
+ typename std::decay<BoundArgs>::type...>;
+};
+
+template <typename Functor, typename... BoundArgs>
+using MakeBindStateType = typename MakeBindStateTypeImpl<
+ FunctorTraits<typename std::decay<Functor>::type>::is_method,
+ Functor,
+ BoundArgs...>::Type;
+
} // namespace internal
// Returns a RunType of bound functor.