diff options
author | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-21 19:23:44 +0000 |
---|---|---|
committer | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-21 19:23:44 +0000 |
commit | 7296f2763bd40e560466f09836c7208c42d90f94 (patch) | |
tree | 142a03c36f75f42738206355a029707ad88cdffc /base/bind_internal.h.pump | |
parent | 1fbbf963079bc977ea041b7e50ddf4666f6fec38 (diff) | |
download | chromium_src-7296f2763bd40e560466f09836c7208c42d90f94.zip chromium_src-7296f2763bd40e560466f09836c7208c42d90f94.tar.gz chromium_src-7296f2763bd40e560466f09836c7208c42d90f94.tar.bz2 |
Callback API Change: Reimplement Bind(); support IgnoreResult, full currying, and use less types.
The main API change IgnoreResult() and fully currying. See unittest for what the new API looks like. The rest of the changes are done to support that.
Previously, IgnoreReturn could not be used with WeakPtr<> Bind()s as it was applied after the fact to the Callback object. Now, IgnoreResult() wraps the function like Unretained().
As an incidental benefit, the new implementation gave us fully currying for free.
Also, the new implementation scales better when supporting higher arities of functions. The new type growth is:
(n^2 + 20n) / 2
as opposed to
(3n^2 + 17n) / 2
where n == arity.
For n = 6 and n=10, the new implementation has 81 and 155 templates respectively.
The old implementation had 105 and 235 templates respectively.
BUG=35233,98919,98542
TEST=existing unittests
Review URL: http://codereview.chromium.org/8483003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110975 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/bind_internal.h.pump')
-rw-r--r-- | base/bind_internal.h.pump | 631 |
1 files changed, 365 insertions, 266 deletions
diff --git a/base/bind_internal.h.pump b/base/bind_internal.h.pump index 429e13f..1192974 100644 --- a/base/bind_internal.h.pump +++ b/base/bind_internal.h.pump @@ -5,7 +5,14 @@ $$ $$ http://code.google.com/p/googletest/wiki/PumpManual $$ +// TODO(ajwong): If you create an fully unbound method, is there a way to +// enforce the first argument must be refcounted? Or do we just say +// "oh well"? +// +// Do we want to allow creating a fully unbound method?? + $var MAX_ARITY = 6 +$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 @@ -29,371 +36,463 @@ $var MAX_ARITY = 6 namespace base { namespace internal { -// The method by which a function is invoked is determined by 3 different -// dimensions: +// 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. +// RunType -- A function type (as opposed to function _pointer_ type) for +// a Run() function. Usually just a convenience typedef. +// (Bound)ArgsType -- A function type that is being (ab)used to store the +// types of set of arguments. The "return" type is always +// void here. We use this hack so that we do not need +// a new type name for each arity of type. (eg., +// BindState1, BindState2). This makes forward +// declarations and friending much much easier. // -// 1) The type of function (normal or method). -// 2) The arity of the function. -// 3) The number of bound parameters. +// Types: +// RunnableAdapter<> -- Wraps the various "function" pointer types into an +// object that adheres to the Runnable interface. +// There are |3*ARITY| RunnableAdapter types. +// 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. +// There are |ARITY| ForceVoidReturn types. +// FunctorTraits<> -- Type traits used determine the correct RunType and +// RunnableType for a Functor. This is where function +// signature adapters are applied. +// There are |ARITY| ForceVoidReturn types. +// MakeRunnable<> -- Takes a Functor and returns an object in the Runnable +// 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. +// There are |k*ARITY| InvokeHelper types. +// 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. + + +// RunnableAdapter<> // -// The templates below handle the determination of each of these dimensions. -// In brief: -// -// FunctionTraits<> -- Provides a normalied signature, and other traits. -// InvokerN<> -- Provides a DoInvoke() function that actually executes -// a calback. -// InvokerStorageN<> -- Provides storage for the bound parameters, and -// typedefs to the above. -// IsWeakMethod<> -- Determines if we are binding a method to a WeakPtr<>. -// -// More details about the design of each class is included in a comment closer -// to their defition. - - -// IsWeakMethod determines if we are binding a method to a WeakPtr<> for an -// object. It is used to select an InvokerN that will no-op itself in the -// event the WeakPtr<> for the target object is invalidated. -template <bool IsMethod, typename T> -struct IsWeakMethod : public false_type {}; - -template <typename T> -struct IsWeakMethod<true, WeakPtr<T> > : public true_type {}; - -// FunctionTraits<> +// 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. // -// The FunctionTraits<> template determines the type of function, and also -// creates a NormalizedType used to select the InvokerN classes. It turns out -// that syntactically, you only really have 2 variations when invoking a -// funciton pointer: normal, and method. One is invoked func_ptr(arg1). The -// other is invoked (*obj_->method_ptr(arg1)). +// 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(). // -// However, in the type system, there are many more distinctions. In standard -// C++, there's all variations of const, and volatile on the function pointer. -// In Windows, there are additional calling conventions (eg., __stdcall, -// __fastcall, etc.). FunctionTraits<> handles categorizing each of these into -// a normalized signature. +// This class also exposes a RunType typedef that is the function type of the +// Run() function. // -// Having a NormalizedSignature signature, reduces the combinatoric -// complexity of defintions for the InvokerN<> later. Even though there are -// only 2 syntactic variations on invoking a function, without normalizing the -// signature, there would need to be one specialization of InvokerN for each -// unique (function_type, bound_arg, unbound_args) tuple in order to match all -// function signatures. -// -// By normalizing the function signature, we reduce function_type to exactly 2. +// 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 Sig> -struct FunctionTraits; +template <typename Functor> +class RunnableAdapter; -$range ARITY 0..MAX_ARITY $for ARITY [[ $range ARG 1..ARITY // Function: Arity $(ARITY). template <typename R[[]] -$if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]> -struct FunctionTraits<R(*)($for ARG , [[X$(ARG)]])> { - typedef R (*NormalizedSig)($for ARG , [[X$(ARG)]]); - typedef false_type IsMethod; - - typedef R Return; - -$if ARITY > 0 [[ - - // Target type for each bound parameter. +$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]> +class RunnableAdapter<R(*)($for ARG , [[A$(ARG)]])> { + public: + typedef R (RunType)($for ARG , [[A$(ARG)]]); -$for ARG [[ - typedef X$(ARG) B$(ARG); + explicit RunnableAdapter(R(*function)($for ARG , [[A$(ARG)]])) + : function_(function) { + } -]] $$ for ARG -]] $$ if ARITY > 0 + R Run($for ARG , [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) { + return function_($for ARG , [[a$(ARG)]]); + } + private: + R (*function_)($for ARG , [[A$(ARG)]]); }; // Method: Arity $(ARITY). template <typename R, typename T[[]] -$if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]> -struct FunctionTraits<R(T::*)($for ARG , [[X$(ARG)]])> { - typedef R (T::*NormalizedSig)($for ARG , [[X$(ARG)]]); +$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]> +class RunnableAdapter<R(T::*)($for ARG , [[A$(ARG)]])> { + public: + typedef R (RunType)(T*[[]] +$if ARITY > 0[[, ]] $for ARG , [[A$(ARG)]]); typedef true_type IsMethod; - typedef R Return; - - // Target type for each bound parameter. - typedef T B1; - -$for ARG [[ - typedef X$(ARG) B$(ARG + 1); + explicit RunnableAdapter(R(T::*method)($for ARG , [[A$(ARG)]])) + : method_(method) { + } -]] $$ for ARG + R Run(T* object[[]] +$if ARITY > 0[[, ]] $for ARG, [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) { + return (object->*method_)($for ARG , [[a$(ARG)]]); + } + private: + R (T::*method_)($for ARG , [[A$(ARG)]]); }; // Const Method: Arity $(ARITY). template <typename R, typename T[[]] -$if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]> -struct FunctionTraits<R(T::*)($for ARG , [[X$(ARG)]]) const> { - typedef R (T::*NormalizedSig)($for ARG , [[X$(ARG)]]); +$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]> +class RunnableAdapter<R(T::*)($for ARG , [[A$(ARG)]]) const> { + public: + typedef R (RunType)(const T*[[]] +$if ARITY > 0[[, ]] $for ARG , [[A$(ARG)]]); typedef true_type IsMethod; - typedef R Return; + explicit RunnableAdapter(R(T::*method)($for ARG , [[A$(ARG)]]) const) + : method_(method) { + } + + R Run(const T* object[[]] +$if ARITY > 0[[, ]] $for ARG, [[typename CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) { + return (object->*method_)($for ARG , [[a$(ARG)]]); + } + + private: + R (T::*method_)($for ARG , [[A$(ARG)]]) const; +}; + +]] $$ for ARITY + - // Target type for each bound parameter. - typedef T B1; +// FunctionTraits<> +// +// Breaks a function signature apart into typedefs for easier introspection. +template <typename Sig> +struct FunctionTraits; +$for ARITY [[ +$range ARG 1..ARITY + +template <typename R[[]] +$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]> +struct FunctionTraits<R($for ARG , [[A$(ARG)]])> { + typedef R ReturnType; $for ARG [[ - typedef X$(ARG) B$(ARG + 1); -]] $$ for ARG + typedef A$(ARG) A$(ARG)Type; +]] }; -]] $$for ARITY +]] -// InvokerN<> -// -// The InvokerN templates contain a static DoInvoke() function that is the key -// to implementing type erasure in the Callback() classes. -// -// DoInvoke() is a static function with a fixed signature that is independent -// of StorageType; its first argument is a pointer to the non-templated common -// baseclass of StorageType. This lets us store pointer to DoInvoke() in a -// function pointer that has knowledge of the specific StorageType, and thus -// no knowledge of the bound function and bound parameter types. + +// ForceVoidReturn<> // -// As long as we ensure that DoInvoke() is only used with pointers there were -// upcasted from the correct StorageType, we can be sure that execution is -// safe. +// Set of templates that support forcing the function return type to void. +template <typename Sig> +struct ForceVoidReturn; + +$for ARITY [[ +$range ARG 1..ARITY + +template <typename R[[]] +$if ARITY > 0[[, ]] $for ARG , [[typename A$(ARG)]]> +struct ForceVoidReturn<R($for ARG , [[A$(ARG)]])> { + typedef void(RunType)($for ARG , [[A$(ARG)]]); +}; + +]] $$ for ARITY + + +// FunctorTraits<> // -// The InvokerN templates are the only point that knows the number of bound -// and unbound arguments. This is intentional because it allows the other -// templates classes in the system to only have as many specializations as -// the max arity of function we wish to support. +// See description at top of file. +template <typename T> +struct FunctorTraits { + typedef RunnableAdapter<T> RunnableType; + typedef typename RunnableType::RunType RunType; +}; -$range BOUND 0..MAX_ARITY -$for BOUND [[ +template <typename T> +struct FunctorTraits<IgnoreResultHelper<T> > { + typedef typename FunctorTraits<T>::RunnableType RunnableType; + typedef typename ForceVoidReturn< + typename RunnableType::RunType>::RunType RunType; +}; -template <bool IsWeak, typename StorageType, typename NormalizedSig> -struct Invoker$(BOUND); +template <typename T> +struct FunctorTraits<Callback<T> > { + typedef Callback<T> RunnableType; + typedef typename Callback<T>::RunType RunType; +}; -$range ARITY 0..MAX_ARITY -$for ARITY [[ -$var UNBOUND = ARITY - BOUND -$if UNBOUND >= 0 [[ +// MakeRunnable<> +// +// Converts a passed in functor to a RunnableType using type inference. -$$ Variables for function traits generation. -$range ARG 1..ARITY -$range BOUND_ARG 1..BOUND -$range UNBOUND_ARG (ARITY - UNBOUND + 1)..ARITY +template <typename T> +typename FunctorTraits<T>::RunnableType MakeRunnable(const T& t) { + return RunnableAdapter<T>(t); +} -$$ Variables for method traits generation. We are always short one arity since -$$ the first bound parameter is the object. -$var M_ARITY = ARITY - 1 -$range M_ARG 1..M_ARITY -$range M_BOUND_ARG 2..BOUND -$range M_UNBOUND_ARG (M_ARITY - UNBOUND + 1)..M_ARITY +template <typename T> +typename FunctorTraits<T>::RunnableType +MakeRunnable(const IgnoreResultHelper<T>& t) { + return MakeRunnable(t.functor_); +} -// Function: Arity $(ARITY) -> $(UNBOUND). -template <typename StorageType, typename R[[]] -$if ARITY > 0 [[,]][[]] -$for ARG , [[typename X$(ARG)]]> -struct Invoker$(BOUND)<false, StorageType, R(*)($for ARG , [[X$(ARG)]])> { - typedef R(*DoInvokeType)( - internal::InvokerStorageBase*[[]] -$if UNBOUND != 0 [[, ]] -$for UNBOUND_ARG , [[typename internal::ParamTraits<X$(UNBOUND_ARG)>::ForwardType]]); +template <typename T> +const typename FunctorTraits<Callback<T> >::RunnableType& +MakeRunnable(const Callback<T>& t) { + return t; +} - static R DoInvoke(InvokerStorageBase* base[[]] -$if UNBOUND != 0 [[, ]][[]] -$for UNBOUND_ARG , [[typename internal::ParamTraits<X$(UNBOUND_ARG)>::ForwardType x$(UNBOUND_ARG)]]) { - StorageType* invoker = static_cast<StorageType*>(base); - return invoker->f_($for BOUND_ARG , [[Unwrap(invoker->p$(BOUND_ARG)_)]][[]] -$$ Add comma if there are both boudn and unbound args. -$if UNBOUND > 0 [[$if BOUND > 0 [[, ]]]][[]] -$for UNBOUND_ARG , [[x$(UNBOUND_ARG)]]); + +// InvokeHelper<> +// +// There are 3 logical InvokeHelper<> specializations: normal, void-return, +// 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. +template <bool IsWeakCall, typename ReturnType, typename Runnable, + typename ArgsType> +struct InvokeHelper; + +$for ARITY [[ +$range ARG 1..ARITY + +template <typename ReturnType, typename Runnable[[]] +$if ARITY > 0 [[,]] $for ARG , [[typename A$(ARG)]]> +struct InvokeHelper<false, ReturnType, Runnable, + void($for ARG , [[A$(ARG)]])> { + static ReturnType MakeItSo(Runnable runnable[[]] +$if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) { + return runnable.Run($for ARG , [[a$(ARG)]]); } }; -$if BOUND > 0 [[ - -// Method: Arity $(M_ARITY) -> $(UNBOUND). -template <typename StorageType, typename R, typename T[[]] -$if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]> -struct Invoker$(BOUND)<false, StorageType, R(T::*)($for M_ARG , [[X$(M_ARG)]])> { - typedef R(*DoInvokeType)( - internal::InvokerStorageBase*[[]] -$if UNBOUND != 0 [[, ]] -$for M_UNBOUND_ARG , [[typename internal::ParamTraits<X$(M_UNBOUND_ARG)>::ForwardType]]); - - static R DoInvoke(InvokerStorageBase* base[[]] -$if UNBOUND > 0 [[, ]][[]] -$for M_UNBOUND_ARG , [[typename internal::ParamTraits<X$(M_UNBOUND_ARG)>::ForwardType x$(M_UNBOUND_ARG)]]) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)([[]] -$for M_BOUND_ARG , [[Unwrap(invoker->p$(M_BOUND_ARG)_)]][[]] -$if UNBOUND > 0 [[$if BOUND > 1 [[, ]]]][[]] -$for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]); +template <typename Runnable[[]] +$if ARITY > 0 [[,]] $for ARG , [[typename A$(ARG)]]> +struct InvokeHelper<false, void, Runnable, + void($for ARG , [[A$(ARG)]])> { + static void MakeItSo(Runnable runnable[[]] +$if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) { + runnable.Run($for ARG , [[a$(ARG)]]); } }; -// WeakPtr Method: Arity $(M_ARITY) -> $(UNBOUND). -template <typename StorageType, typename T[[]] -$if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]> -struct Invoker$(BOUND)<true, StorageType, void(T::*)($for M_ARG , [[X$(M_ARG)]])> { - typedef void(*DoInvokeType)( - internal::InvokerStorageBase*[[]] -$if UNBOUND != 0 [[, ]] -$for M_UNBOUND_ARG , [[typename internal::ParamTraits<X$(M_UNBOUND_ARG)>::ForwardType]]); - - static void DoInvoke(InvokerStorageBase* base[[]] -$if UNBOUND > 0 [[, ]][[]] -$for M_UNBOUND_ARG , [[typename internal::ParamTraits<X$(M_UNBOUND_ARG)>::ForwardType x$(M_UNBOUND_ARG)]]) { - StorageType* invoker = static_cast<StorageType*>(base); - typename StorageType::P1Traits::StorageType& weak_ptr = invoker->p1_; - if (!weak_ptr.get()) { +$if ARITY > 0 [[ + +template <typename Runnable[[]], $for ARG , [[typename A$(ARG)]]> +struct InvokeHelper<true, void, Runnable, + void($for ARG , [[A$(ARG)]])> { + static void MakeItSo(Runnable runnable[[]] +$if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) { + if (!a1.get()) { return; } - (weak_ptr->*invoker->f_)([[]] -$for M_BOUND_ARG , [[Unwrap(invoker->p$(M_BOUND_ARG)_)]][[]] -$if UNBOUND > 0 [[$if BOUND > 1 [[, ]]]][[]] -$for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]); + + runnable.Run($for ARG , [[a$(ARG)]]); } }; -]] $$ if BOUND +]] -]] $$ if UNBOUND -]] $$ for ARITY -]] $$ for BOUND +]] $$ for ARITY -// BindMoreFuncN<> -// -// This set of functions help in fully binding the free parameters in a -// Callback<>. -$for BOUND [[ -$range BOUND_ARG 1..BOUND -$if BOUND != 0 [[ +#if !defined(_MSC_VER) -template <typename Sig, $for BOUND_ARG , [[typename P$(BOUND_ARG)]]> -void BindMoreFunc$(BOUND)(const base::Callback<Sig>& callback, [[]] -$for BOUND_ARG , [[const P$(BOUND_ARG)& p$(BOUND_ARG)]]) { - callback.Run($for BOUND_ARG , [[p$(BOUND_ARG)]]); -} +template <typename ReturnType, typename Runnable, typename ArgsType> +struct InvokeHelper<true, ReturnType, Runnable, ArgsType> { + // WeakCalls are only supported for functions with a void return type. + // Otherwise, the function result would be undefined if the the WeakPtr<> + // is invalidated. + COMPILE_ASSERT(is_void<ReturnType>::value, + weak_ptrs_can_only_bind_to_methods_without_return_values); +}; -]] $$ if BOUND -]] $$ for BOUND +#endif -// InvokerStorageN<> -// -// These are the actual storage classes for the Invokers. -// -// Though these types are "classes", they are being used as structs with -// all member variable public. We cannot make it a struct because it inherits -// from a class which causes a compiler warning. We cannot add a "Run()" method -// that forwards the unbound arguments because that would require we unwrap the -// Sig type like in InvokerN above to know the return type, and the arity -// of Run(). +// Invoker<> // -// An alternate solution would be to merge InvokerN and InvokerStorageN, -// but the generated code seemed harder to read. +// See description at the top of the file. +template <int NumBound, typename Storage, typename RunType> +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 -template <typename Sig[[]] -$if BOUND > 0 [[, ]] -$for BOUND_ARG , [[typename P$(BOUND_ARG)]]> -class InvokerStorage$(BOUND) : public InvokerStorageBase { - public: - typedef InvokerStorage$(BOUND) StorageType; - typedef FunctionTraits<Sig> TargetTraits; - typedef typename TargetTraits::IsMethod IsMethod; - typedef Sig Signature; +// Arity $(ARITY) -> $(UNBOUND). +template <typename StorageType, typename R[[]] +$if ARITY > 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<X$(UNBOUND_ARG)>::ForwardType]]); -$for BOUND_ARG [[ - typedef ParamTraits<P$(BOUND_ARG)> P$(BOUND_ARG)Traits; + typedef R(UnboundRunType)($for UNBOUND_ARG , [[X$(UNBOUND_ARG)]]); + static R Run(BindStateBase* base[[]] +$if UNBOUND != 0 [[, ]][[]] +$for UNBOUND_ARG , [[ +typename CallbackParamTraits<X$(UNBOUND_ARG)>::ForwardType x$(UNBOUND_ARG) +]][[]] +) { + StorageType* storage = static_cast<StorageType*>(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; ]] -$if BOUND == 0 [[ - typedef Invoker$(BOUND)<false, StorageType, - typename TargetTraits::NormalizedSig> Invoker; -]] $else [[ - typedef Invoker$(BOUND)<IsWeakMethod<IsMethod::value, P1>::value, StorageType, - typename TargetTraits::NormalizedSig> Invoker; - COMPILE_ASSERT(!(IsWeakMethod<IsMethod::value, P1>::value) || - is_void<typename TargetTraits::Return>::value, - weak_ptrs_can_only_bind_to_methods_without_return_values); + +$for BOUND_ARG +[[ + + typename Bound$(BOUND_ARG)UnwrapTraits::ForwardType x$(BOUND_ARG) = + Bound$(BOUND_ARG)UnwrapTraits::Unwrap(storage->p$(BOUND_ARG)_); ]] + return InvokeHelper<StorageType::IsWeakCall::value, R, + typename StorageType::RunnableType, + void( +$for BOUND_ARG , [[ +typename Bound$(BOUND_ARG)UnwrapTraits::ForwardType +]] -$for BOUND_ARG [[ -$if BOUND_ARG == 1 [[ +$if UNBOUND > 0 [[$if BOUND > 0 [[, ]]]][[]] - // For methods, we need to be careful for parameter 1. We skip the - // scoped_refptr check because the binder itself takes care of this. We also - // disallow binding of an array as the method's target object. - COMPILE_ASSERT(IsMethod::value || - internal::NeedsScopedRefptrButGetsRawPtr< - typename ParamTraits<P$(BOUND_ARG)>::StorageType>::value == 0, - p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!IsMethod::value || !is_array<P$(BOUND_ARG)>::value, - first_bound_argument_to_method_cannot_be_array); -]] $else [[ +$for UNBOUND_ARG , [[ +typename CallbackParamTraits<X$(UNBOUND_ARG)>::ForwardType x$(UNBOUND_ARG) +]] +)> + ::MakeItSo(storage->runnable_ +$if ARITY > 0[[, ]] $for ARG , [[x$(ARG)]]); + } +}; + +]] $$ for BOUND +]] $$ for ARITY - COMPILE_ASSERT(internal::NeedsScopedRefptrButGetsRawPtr< - typename ParamTraits<P$(BOUND_ARG)>::StorageType>::value == 0, - p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr); -]] $$ $if BOUND_ARG -]] $$ $for BOUND_ARG +// 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. +// RunType is type of the Run() function that the Invoker<> should use. +// Normally, this is the same as the RunType of the Runnable, but it can +// be different if an adapter like IgnoreResult() has been used. +// +// BoundArgsType contains the storage type for all the bound arguments by +// (ab)using a function type. +template <typename Runnable, typename RunType, typename BoundArgsType> +struct BindState; -$if BOUND > 0 [[ +$for ARITY [[ +$range ARG 1..ARITY - // Do not allow binding a non-const reference parameter. Non-const reference - // parameters are disallowed by the Google style guide. Also, binding a - // non-const reference parameter can make for subtle bugs because the - // invoked function will receive a reference to the stored copy of the - // argument and not the original. - COMPILE_ASSERT( - !($for BOUND_ARG || [[ is_non_const_reference<typename TargetTraits::B$(BOUND_ARG)>::value ]]), - do_not_bind_functions_with_nonconst_ref); +template <typename Runnable, typename RunType[[]] +$if ARITY > 0[[, ]] $for ARG , [[typename P$(ARG)]]> +struct BindState<Runnable, RunType, void($for ARG , [[P$(ARG)]])> : public BindStateBase { + typedef Runnable RunnableType; +$if ARITY > 0 [[ + typedef IsWeakMethod<HasIsMethodTag<Runnable>::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<P$(ARG)> Bound$(ARG)UnwrapTraits; + +]] $$ for ARG + + +]] $$ if ARITY > 0 - InvokerStorage$(BOUND)(Sig f -$if BOUND > 0 [[, ]] -$for BOUND_ARG , [[const P$(BOUND_ARG)& p$(BOUND_ARG)]]) - : f_(f)[[]] -$if BOUND == 0 [[ +$$ 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 [[ { ]] $else [[ -, $for BOUND_ARG , [[p$(BOUND_ARG)_(static_cast<typename ParamTraits<P$(BOUND_ARG)>::StorageType>(p$(BOUND_ARG)))]] { - MaybeRefcount<IsMethod, P1>::AddRef(p1_); +, $for ARG , [[ + + p$(ARG)_(p$(ARG)) +]] { + MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::AddRef(p1_); ]] } - virtual ~InvokerStorage$(BOUND)() { -$if BOUND > 0 [[ - - MaybeRefcount<IsMethod, P1>::Release(p1_); - + virtual ~BindState() { +$if ARITY > 0 [[ + MaybeRefcount<HasIsMethodTag<Runnable>::value, P1>::Release(p1_); ]] } - Sig f_; + RunnableType runnable_; -$for BOUND_ARG [[ - typename ParamTraits<P$(BOUND_ARG)>::StorageType p$(BOUND_ARG)_; +$for ARG [[ + P$(ARG) p$(ARG)_; ]] }; -]] $$ for BOUND +]] $$ for ARITY } // namespace internal } // namespace base |