From 8ce65709225bac5922e6b2b80a912cf9796949b1 Mon Sep 17 00:00:00 2001 From: tzik Date: Thu, 5 Feb 2015 11:11:26 -0800 Subject: [PATCH] Bind: Use Variadic Templates in bind_internal.h * Introduce TypeList as helpers. * Drop bind_internal.h.pump and replace generated codes with Variadic Templates version. BUG=433164 Review URL: https://codereview.chromium.org/743853002 Cr-Commit-Position: refs/heads/master@{#314847} --- base/bind.h | 14 +- base/bind_helpers.h | 139 +++++++++++---- base/{bind_internal.h.pump => bind_internal.h} | 228 +++++++------------------ base/bind_unittest.nc | 2 +- 4 files changed, 180 insertions(+), 203 deletions(-) rename base/{bind_internal.h.pump => bind_internal.h} (72%) diff --git a/base/bind.h b/base/bind.h index 7874656c6091..51be10dd7e65 100644 --- a/base/bind.h +++ b/base/bind.h @@ -52,13 +52,14 @@ base::Callback< typename internal::BindState< typename internal::FunctorTraits::RunnableType, typename internal::FunctorTraits::RunType, - void()>::UnboundRunType> + internal::TypeList<>>::UnboundRunType> Bind(Functor functor) { // Typedefs for how to store and run the functor. typedef typename internal::FunctorTraits::RunnableType RunnableType; typedef typename internal::FunctorTraits::RunType RunType; - typedef internal::BindState BindState; + typedef internal::BindState> BindState; return Callback( new BindState(internal::MakeRunnable(functor))); @@ -69,7 +70,8 @@ base::Callback< typename internal::BindState< typename internal::FunctorTraits::RunnableType, typename internal::FunctorTraits::RunType, - void(typename internal::CallbackParamTraits::StorageType...)> + internal::TypeList< + typename internal::CallbackParamTraits::StorageType...>> ::UnboundRunType> Bind(Functor functor, const Args&... args) { // Typedefs for how to store and run the functor. @@ -101,8 +103,10 @@ Bind(Functor functor, const Args&... args) { !internal::HasRefCountedParamAsRawPtr::value, "a_parameter_is_refcounted_type_and_needs_scoped_refptr"); - typedef internal::BindState::StorageType...)> + typedef internal::BindState< + RunnableType, RunType, + internal::TypeList< + typename internal::CallbackParamTraits::StorageType...>> BindState; return Callback( diff --git a/base/bind_helpers.h b/base/bind_helpers.h index f3efc31953c7..f8e89bd8f01e 100644 --- a/base/bind_helpers.h +++ b/base/bind_helpers.h @@ -435,45 +435,46 @@ struct UnwrapTraits > { // Utility for handling different refcounting semantics in the Bind() // function. -template -struct MaybeRefcount; +template +struct MaybeScopedRefPtr; -template -struct MaybeRefcount { - static void AddRef(const T&) {} - static void Release(const T&) {} +template +struct MaybeScopedRefPtr { + MaybeScopedRefPtr() {} }; -template -struct MaybeRefcount { - static void AddRef(const T*) {} - static void Release(const T*) {} +template +struct MaybeScopedRefPtr { + MaybeScopedRefPtr(const T&, const Rest&...) {} }; -template -struct MaybeRefcount { - static void AddRef(const T&) {} - static void Release(const T&) {} +template +struct MaybeScopedRefPtr { + MaybeScopedRefPtr(const T*, const Rest&...) {} }; -template -struct MaybeRefcount { - static void AddRef(T* o) { o->AddRef(); } - static void Release(T* o) { o->Release(); } +template +struct MaybeScopedRefPtr { + MaybeScopedRefPtr(const T& o, const Rest&...) {} +}; + +template +struct MaybeScopedRefPtr { + MaybeScopedRefPtr(T* o, const Rest&...) : ref_(o) {} + scoped_refptr ref_; }; // No need to additionally AddRef() and Release() since we are storing a // scoped_refptr<> inside the storage object already. -template -struct MaybeRefcount > { - static void AddRef(const scoped_refptr& o) {} - static void Release(const scoped_refptr& o) {} +template +struct MaybeScopedRefPtr, Rest...> { + MaybeScopedRefPtr(const scoped_refptr&, const Rest&...) {} }; -template -struct MaybeRefcount { - static void AddRef(const T* o) { o->AddRef(); } - static void Release(const T* o) { o->Release(); } +template +struct MaybeScopedRefPtr { + MaybeScopedRefPtr(const T* o, const Rest&...) : ref_(o) {} + scoped_refptr ref_; }; // IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a @@ -481,15 +482,89 @@ struct MaybeRefcount { // InvokeHelper that will no-op itself in the event the WeakPtr<> for // the target object is invalidated. // -// P1 should be the type of the object that will be received of the method. -template +// The first argument should be the type of the object that will be received by +// the method. +template struct IsWeakMethod : public false_type {}; -template -struct IsWeakMethod > : public true_type {}; +template +struct IsWeakMethod, Args...> : public true_type {}; -template -struct IsWeakMethod > > : public true_type {}; +template +struct IsWeakMethod>, Args...> + : public true_type {}; + + +// Packs a list of types to hold them in a single type. +template +struct TypeList {}; + +// Used for DropTypeListItem implementation. +template +struct DropTypeListItemImpl; + +// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure. +template +struct DropTypeListItemImpl> + : DropTypeListItemImpl> {}; + +template +struct DropTypeListItemImpl<0, TypeList> { + typedef TypeList Type; +}; + +template <> +struct DropTypeListItemImpl<0, TypeList<>> { + typedef TypeList<> Type; +}; + +// A type-level function that drops |n| list item from given TypeList. +template +using DropTypeListItem = typename DropTypeListItemImpl::Type; + +// Used for ConcatTypeLists implementation. +template +struct ConcatTypeListsImpl; + +template +struct ConcatTypeListsImpl, TypeList> { + typedef TypeList Type; +}; + +// A type-level function that concats two TypeLists. +template +using ConcatTypeLists = typename ConcatTypeListsImpl::Type; + +template +struct NthTypeImpl; + +template +struct NthTypeImpl> + : NthTypeImpl> { +}; + +template +struct NthTypeImpl<0, TypeList> { + typedef T Type; +}; + +// A type-level function that extracts |n|th type from a TypeList. +template +using NthType = typename NthTypeImpl::Type; + +// Used for MakeFunctionType implementation. +template +struct MakeFunctionTypeImpl; + +template +struct MakeFunctionTypeImpl> { + typedef R(Type)(Args...); +}; + +// A type-level function that constructs a function type that has |R| as its +// return type and has TypeLists items as its arguments. +template +using MakeFunctionType = typename MakeFunctionTypeImpl::Type; } // namespace internal diff --git a/base/bind_internal.h.pump b/base/bind_internal.h similarity index 72% rename from base/bind_internal.h.pump rename to base/bind_internal.h index 0ed3ca2eebd9..5fc14592cd3a 100644 --- a/base/bind_internal.h.pump +++ b/base/bind_internal.h @@ -1,14 +1,3 @@ -$$ This is a pump file for generating file templates. Pump is a python -$$ script that is part of the Google Test suite of utilities. Description -$$ can be found here: -$$ -$$ http://code.google.com/p/googletest/wiki/PumpManual -$$ - -$$ See comment for MAX_ARITY in base/bind.h.pump. -$var MAX_ARITY = 7 -$range ARITY 0..MAX_ARITY - // Copyright (c) 2011 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. @@ -21,6 +10,7 @@ $range ARITY 0..MAX_ARITY #include "base/memory/raw_scoped_refptr_mismatch_checker.h" #include "base/memory/weak_ptr.h" #include "base/template_util.h" +#include "base/tuple.h" #include "build/build_config.h" #if defined(OS_WIN) @@ -57,10 +47,6 @@ namespace internal { // Types: // RunnableAdapter<> -- Wraps the various "function" pointer types into an // object that adheres to the Runnable interface. -// FunctionTraits<> -- Type traits that unwrap a function signature into a -// a set of easier to use typedefs. Used mainly for -// compile time asserts. -// There are |ARITY| FunctionTraits types. // ForceVoidReturn<> -- Helper class for translating function signatures to // equivalent forms with a "void" return type. // FunctorTraits<> -- Type traits used determine the correct RunType and @@ -70,12 +56,11 @@ namespace internal { // type class that represents the underlying Functor. // There are |O(1)| MakeRunnable types. // InvokeHelper<> -- Take a Runnable + 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<> -// which grows at O(n^2) with the arity. +// 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. -// There are |(ARITY^2 + ARITY)/2| Invoketypes. // 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. @@ -215,29 +200,6 @@ class RunnableAdapter { R (T::*method_)(Args...) const; }; -// TODO(tzik): Remove FunctionTraits after we finish removing bind.pump. -// FunctionTraits<> -// -// Breaks a function signature apart into typedefs for easier introspection. -template -struct FunctionTraits; - -$for ARITY [[ -$range ARG 1..ARITY - -template 0[[, ]] $for ARG , [[typename A$(ARG)]]> -struct FunctionTraits { - typedef R ReturnType; -$for ARG [[ - - typedef A$(ARG) A$(ARG)Type; -]] - -}; - -]] - // ForceVoidReturn<> // @@ -261,14 +223,14 @@ struct FunctorTraits { }; template -struct FunctorTraits > { +struct FunctorTraits> { typedef typename FunctorTraits::RunnableType RunnableType; typedef typename ForceVoidReturn< typename RunnableType::RunType>::RunType RunType; }; template -struct FunctorTraits > { +struct FunctorTraits> { typedef Callback RunnableType; typedef typename Callback::RunType RunType; }; @@ -290,7 +252,7 @@ MakeRunnable(const IgnoreResultHelper& t) { } template -const typename FunctorTraits >::RunnableType& +const typename FunctorTraits>::RunnableType& MakeRunnable(const Callback& t) { DCHECK(!t.is_null()); return t; @@ -319,22 +281,21 @@ template -struct InvokeHelper { +struct InvokeHelper> { static ReturnType MakeItSo(Runnable runnable, Args... args) { return runnable.Run(CallbackForward(args)...); } }; template -struct InvokeHelper { +struct InvokeHelper> { static void MakeItSo(Runnable runnable, Args... args) { runnable.Run(CallbackForward(args)...); } }; template -struct InvokeHelper { +struct InvokeHelper> { static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, Args... args) { if (!weak_ptr.get()) { return; @@ -359,77 +320,33 @@ struct InvokeHelper { // Invoker<> // // See description at the top of the file. -template +template struct Invoker; -$for ARITY [[ - -$$ Number of bound arguments. -$range BOUND 0..ARITY -$for BOUND [[ - -$var UNBOUND = ARITY - BOUND -$range ARG 1..ARITY -$range BOUND_ARG 1..BOUND -$range UNBOUND_ARG (ARITY - UNBOUND + 1)..ARITY - -// Arity $(ARITY) -> $(UNBOUND). -template 0 [[,]][[]] -$for ARG , [[typename X$(ARG)]]> -struct Invoker<$(BOUND), StorageType, R($for ARG , [[X$(ARG)]])> { - typedef R(RunType)(BindStateBase*[[]] -$if UNBOUND != 0 [[, ]] -$for UNBOUND_ARG , [[typename CallbackParamTraits::ForwardType]]); - - typedef R(UnboundRunType)($for UNBOUND_ARG , [[X$(UNBOUND_ARG)]]); - - static R Run(BindStateBase* base[[]] -$if UNBOUND != 0 [[, ]][[]] -$for UNBOUND_ARG , [[ -typename CallbackParamTraits::ForwardType x$(UNBOUND_ARG) -]][[]] -) { +template +struct Invoker, + StorageType, TypeList, + InvokeHelperType, R(UnboundForwardArgs...)> { + static R Run(BindStateBase* base, + UnboundForwardArgs... unbound_args) { StorageType* storage = static_cast(base); - // Local references to make debugger stepping easier. If in a debugger, // you really want to warp ahead and step through the // InvokeHelper<>::MakeItSo() call below. -$for BOUND_ARG -[[ - - typedef typename StorageType::Bound$(BOUND_ARG)UnwrapTraits Bound$(BOUND_ARG)UnwrapTraits; -]] - - -$for BOUND_ARG -[[ - - typename Bound$(BOUND_ARG)UnwrapTraits::ForwardType x$(BOUND_ARG) = - Bound$(BOUND_ARG)UnwrapTraits::Unwrap(storage->p$(BOUND_ARG)_); -]] - - return InvokeHelper 0 [[$if BOUND > 0 [[, ]]]][[]] - -$for UNBOUND_ARG , [[ -typename CallbackParamTraits::ForwardType x$(UNBOUND_ARG) -]] -)> - ::MakeItSo(storage->runnable_ -$if ARITY > 0[[, ]] $for ARG , [[CallbackForward(x$(ARG))]]); + return InvokeHelperType::MakeItSo( + storage->runnable_, + Unwrappers::Unwrap(get(storage->bound_args_))..., + CallbackForward(unbound_args)...); } }; -]] $$ for BOUND -]] $$ for ARITY - // BindState<> // @@ -443,73 +360,54 @@ $if ARITY > 0[[, ]] $for ARG , [[CallbackForward(x$(ARG))]]); // // BoundArgsType contains the storage type for all the bound arguments by // (ab)using a function type. -template +template struct BindState; -$for ARITY [[ -$range ARG 1..ARITY - -template 0[[, ]] $for ARG , [[typename P$(ARG)]]> -struct BindState : public BindStateBase { - typedef Runnable RunnableType; - -$if ARITY > 0 [[ - typedef IsWeakMethod::value, P1> IsWeakCall; -]] $else [[ - typedef false_type IsWeakCall; -]] - - typedef Invoker<$(ARITY), BindState, RunType> InvokerType; - typedef typename InvokerType::UnboundRunType UnboundRunType; - -$if ARITY > 0 [[ - - // Convenience typedefs for bound argument types. - -$for ARG [[ - typedef UnwrapTraits Bound$(ARG)UnwrapTraits; - -]] $$ for ARG +template +struct BindState> + : public BindStateBase { + private: + using StorageType = BindState>; + using RunnableType = Runnable; + // true_type if Runnable is a method invocation and the first bound argument + // is a WeakPtr. + using IsWeakCall = + IsWeakMethod::value, BoundArgs...>; -]] $$ if ARITY > 0 + using BoundIndices = MakeIndexSequence; + using Unwrappers = TypeList...>; + using UnboundForwardArgs = DropTypeListItem< + sizeof...(BoundArgs), + TypeList::ForwardType...>>; + using UnboundForwardRunType = MakeFunctionType; -$$ The extra [[ ]] is needed to massage spacing. Silly pump.py. -[[ ]]$if ARITY == 0 [[explicit ]]BindState(const Runnable& runnable -$if ARITY > 0 [[, ]] $for ARG , [[const P$(ARG)& p$(ARG)]]) - : runnable_(runnable)[[]] -$if ARITY == 0 [[ - { + using InvokeHelperArgs = ConcatTypeLists< + TypeList::ForwardType...>, + UnboundForwardArgs>; + using InvokeHelperType = + InvokeHelper; -]] $else [[ -, $for ARG , [[ + using UnboundArgs = DropTypeListItem>; - p$(ARG)_(p$(ARG)) -]] { - MaybeRefcount::value, P1>::AddRef(p1_); + public: + using InvokerType = Invoker; + using UnboundRunType = MakeFunctionType; -]] - } + BindState(const Runnable& runnable, const BoundArgs&... bound_args) + : runnable_(runnable), ref_(bound_args...), bound_args_(bound_args...) {} RunnableType runnable_; - -$for ARG [[ - P$(ARG) p$(ARG)_; - -]] + MaybeScopedRefPtr::value, BoundArgs...> ref_; + Tuple bound_args_; private: - ~BindState() override { -$if ARITY > 0 [[ - MaybeRefcount::value, P1>::Release(p1_); -]] - } - + ~BindState() override {} }; -]] $$ for ARITY - } // namespace internal } // namespace base diff --git a/base/bind_unittest.nc b/base/bind_unittest.nc index 33b5f5c858e6..259638673a91 100644 --- a/base/bind_unittest.nc +++ b/base/bind_unittest.nc @@ -190,7 +190,7 @@ void WontCompile() { weak_ptr_with_non_void_return_type.Run(); } -#elif defined(NCTEST_DISALLOW_ASSIGN_DIFFERENT_TYPES) // [r"fatal error: no viable conversion from 'Callback::RunnableType, typename internal::FunctorTraits::RunType, void \(\)>::UnboundRunType>' to 'Callback'"] +#elif defined(NCTEST_DISALLOW_ASSIGN_DIFFERENT_TYPES) // [r"fatal error: no viable conversion from 'Callback::RunnableType, typename internal::FunctorTraits::RunType, internal::TypeList<> >::UnboundRunType>' to 'Callback'"] // Bind result cannot be assigned to Callbacks with a mismatching type. void WontCompile() { -- 2.11.4.GIT