diff options
author | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-19 00:52:15 +0000 |
---|---|---|
committer | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-19 00:52:15 +0000 |
commit | 4346ef91c5d16fd98da3dad5356b0f994f225ce6 (patch) | |
tree | 2f0d0bcdb836a1f0d052ae901b9bfc69a44ed6b1 /base | |
parent | c034941e26f9e62e7f5c9b58cd7a3f52bac1b1db (diff) | |
download | chromium_src-4346ef91c5d16fd98da3dad5356b0f994f225ce6.zip chromium_src-4346ef91c5d16fd98da3dad5356b0f994f225ce6.tar.gz chromium_src-4346ef91c5d16fd98da3dad5356b0f994f225ce6.tar.bz2 |
Callbacks: Replumb the type-inference.
In preparation for attempting to support __stdcall, __fastcall, etc., break
apart the templates so that instead of having one set of InvokerNs per type
of function pointer, only have one per syntactic method of invocation.
This lets the number of template specializations scale better. Previously,
for each type of function pointer, we needed sum(1...arity) InvokerN
specializations. There were 3 types (function, method, const method).
The Windows calling conventions would have added another 2.
in this method, we have 2 sets of InvokerN templates, and 1 set of
FunctionTraits templates for each type. We only need (arity) number of
FunctionTraits templates, so this is a net win. For our 6-arity system,
it should go from
5 types * (1+2+3+4+5+6) InvokerNs = 105 specializations
to
5 types * 6 FunctionTraits + 2 calling_syntaxes * (1+2+3+4+5+6) InvokerNs = 72 specializations
This puts a bit more work on the compiler, but...hey, better it than the reader of the code.
BUG=35223
TEST=none
Review URL: http://codereview.chromium.org/6538045
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75482 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/bind_internal.h | 879 | ||||
-rw-r--r-- | base/bind_internal.h.pump | 148 | ||||
-rw-r--r-- | base/callback.h | 15 | ||||
-rw-r--r-- | base/callback.h.pump | 3 | ||||
-rw-r--r-- | base/callback_unittest.cc | 6 |
5 files changed, 407 insertions, 644 deletions
diff --git a/base/bind_internal.h b/base/bind_internal.h index dd8afde..fe3764b 100644 --- a/base/bind_internal.h +++ b/base/bind_internal.h @@ -21,35 +21,229 @@ namespace internal { // The method by which a function is invoked is determined by 3 different // dimensions: // -// 1) The type of function (normal, method, const-method) -// 2) The arity of the function +// 1) The type of function (normal or method). +// 2) The arity of the function. // 3) The number of bound parameters. // -// The FunctionTraitsN classes unwrap the function signature type to -// specialize based on the first two dimensions. The N in FunctionTraitsN -// specifies the 3rd dimension. We could have specified the unbound parameters -// via template parameters, but this method looked cleaner. +// The templates below handle the determination of each of these dimensions. +// In brief: // -// The FunctionTraitsN contains 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. +// 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. +// +// More details about the design of each class is included in a comment closer +// to their defition. + +// FunctionTraits<> +// +// 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)). +// +// 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. +// +// 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. + +template <typename Sig> +struct FunctionTraits; + +// Function: Arity 0. +template <typename R> +struct FunctionTraits<R(*)()> { + typedef R (*NormalizedSig)(); + typedef base::false_type IsMethod; +}; + +// Method: Arity 0. +template <typename R, typename T> +struct FunctionTraits<R(T::*)()> { + typedef R (T::*NormalizedSig)(); + typedef base::true_type IsMethod; +}; + +// Const Method: Arity 0. +template <typename R, typename T> +struct FunctionTraits<R(T::*)() const> { + typedef R (T::*NormalizedSig)(); + typedef base::true_type IsMethod; +}; + +// Function: Arity 1. +template <typename R, typename X1> +struct FunctionTraits<R(*)(X1)> { + typedef R (*NormalizedSig)(X1); + typedef base::false_type IsMethod; +}; + +// Method: Arity 1. +template <typename R, typename T, typename X1> +struct FunctionTraits<R(T::*)(X1)> { + typedef R (T::*NormalizedSig)(X1); + typedef base::true_type IsMethod; +}; + +// Const Method: Arity 1. +template <typename R, typename T, typename X1> +struct FunctionTraits<R(T::*)(X1) const> { + typedef R (T::*NormalizedSig)(X1); + typedef base::true_type IsMethod; +}; + +// Function: Arity 2. +template <typename R, typename X1, typename X2> +struct FunctionTraits<R(*)(X1, X2)> { + typedef R (*NormalizedSig)(X1, X2); + typedef base::false_type IsMethod; +}; + +// Method: Arity 2. +template <typename R, typename T, typename X1, typename X2> +struct FunctionTraits<R(T::*)(X1, X2)> { + typedef R (T::*NormalizedSig)(X1, X2); + typedef base::true_type IsMethod; +}; + +// Const Method: Arity 2. +template <typename R, typename T, typename X1, typename X2> +struct FunctionTraits<R(T::*)(X1, X2) const> { + typedef R (T::*NormalizedSig)(X1, X2); + typedef base::true_type IsMethod; +}; + +// Function: Arity 3. +template <typename R, typename X1, typename X2, typename X3> +struct FunctionTraits<R(*)(X1, X2, X3)> { + typedef R (*NormalizedSig)(X1, X2, X3); + typedef base::false_type IsMethod; +}; + +// Method: Arity 3. +template <typename R, typename T, typename X1, typename X2, typename X3> +struct FunctionTraits<R(T::*)(X1, X2, X3)> { + typedef R (T::*NormalizedSig)(X1, X2, X3); + typedef base::true_type IsMethod; +}; + +// Const Method: Arity 3. +template <typename R, typename T, typename X1, typename X2, typename X3> +struct FunctionTraits<R(T::*)(X1, X2, X3) const> { + typedef R (T::*NormalizedSig)(X1, X2, X3); + typedef base::true_type IsMethod; +}; + +// Function: Arity 4. +template <typename R, typename X1, typename X2, typename X3, typename X4> +struct FunctionTraits<R(*)(X1, X2, X3, X4)> { + typedef R (*NormalizedSig)(X1, X2, X3, X4); + typedef base::false_type IsMethod; +}; + +// Method: Arity 4. +template <typename R, typename T, typename X1, typename X2, typename X3, + typename X4> +struct FunctionTraits<R(T::*)(X1, X2, X3, X4)> { + typedef R (T::*NormalizedSig)(X1, X2, X3, X4); + typedef base::true_type IsMethod; +}; + +// Const Method: Arity 4. +template <typename R, typename T, typename X1, typename X2, typename X3, + typename X4> +struct FunctionTraits<R(T::*)(X1, X2, X3, X4) const> { + typedef R (T::*NormalizedSig)(X1, X2, X3, X4); + typedef base::true_type IsMethod; +}; + +// Function: Arity 5. +template <typename R, typename X1, typename X2, typename X3, typename X4, + typename X5> +struct FunctionTraits<R(*)(X1, X2, X3, X4, X5)> { + typedef R (*NormalizedSig)(X1, X2, X3, X4, X5); + typedef base::false_type IsMethod; +}; + +// Method: Arity 5. +template <typename R, typename T, typename X1, typename X2, typename X3, + typename X4, typename X5> +struct FunctionTraits<R(T::*)(X1, X2, X3, X4, X5)> { + typedef R (T::*NormalizedSig)(X1, X2, X3, X4, X5); + typedef base::true_type IsMethod; +}; + +// Const Method: Arity 5. +template <typename R, typename T, typename X1, typename X2, typename X3, + typename X4, typename X5> +struct FunctionTraits<R(T::*)(X1, X2, X3, X4, X5) const> { + typedef R (T::*NormalizedSig)(X1, X2, X3, X4, X5); + typedef base::true_type IsMethod; +}; + +// Function: Arity 6. +template <typename R, typename X1, typename X2, typename X3, typename X4, + typename X5, typename X6> +struct FunctionTraits<R(*)(X1, X2, X3, X4, X5, X6)> { + typedef R (*NormalizedSig)(X1, X2, X3, X4, X5, X6); + typedef base::false_type IsMethod; +}; + +// Method: Arity 6. +template <typename R, typename T, typename X1, typename X2, typename X3, + typename X4, typename X5, typename X6> +struct FunctionTraits<R(T::*)(X1, X2, X3, X4, X5, X6)> { + typedef R (T::*NormalizedSig)(X1, X2, X3, X4, X5, X6); + typedef base::true_type IsMethod; +}; + +// Const Method: Arity 6. +template <typename R, typename T, typename X1, typename X2, typename X3, + typename X4, typename X5, typename X6> +struct FunctionTraits<R(T::*)(X1, X2, X3, X4, X5, X6) const> { + typedef R (T::*NormalizedSig)(X1, X2, X3, X4, X5, X6); + typedef base::true_type IsMethod; +}; + +// 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. // // 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. +// +// 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. -template <typename StorageType, typename Sig> -struct FunctionTraits0; +template <typename StorageType, typename NormalizedSig> +struct Invoker0; // Function: Arity 0 -> 0. template <typename StorageType, typename R> -struct FunctionTraits0<StorageType, R(*)()> { - typedef base::false_type IsMethod; - +struct Invoker0<StorageType, R(*)()> { static R DoInvoke(InvokerStorageBase* base) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(); @@ -58,13 +252,11 @@ struct FunctionTraits0<StorageType, R(*)()> { // Function: Arity 1 -> 1. template <typename StorageType, typename R,typename X1> -struct FunctionTraits0<StorageType, R(*)(X1)> { +struct Invoker0<StorageType, R(*)(X1)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X1& x1) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(x1); @@ -73,14 +265,12 @@ struct FunctionTraits0<StorageType, R(*)(X1)> { // Function: Arity 2 -> 2. template <typename StorageType, typename R,typename X1, typename X2> -struct FunctionTraits0<StorageType, R(*)(X1, X2)> { +struct Invoker0<StorageType, R(*)(X1, X2)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(x1, x2); @@ -90,15 +280,13 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2)> { // Function: Arity 3 -> 3. template <typename StorageType, typename R,typename X1, typename X2, typename X3> -struct FunctionTraits0<StorageType, R(*)(X1, X2, X3)> { +struct Invoker0<StorageType, R(*)(X1, X2, X3)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || is_non_const_reference<X3>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2, const X3& x3) { StorageType* invoker = static_cast<StorageType*>(base); @@ -109,7 +297,7 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2, X3)> { // Function: Arity 4 -> 4. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4> -struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4)> { +struct Invoker0<StorageType, R(*)(X1, X2, X3, X4)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -117,8 +305,6 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4)> { is_non_const_reference<X4>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2, const X3& x3, const X4& x4) { StorageType* invoker = static_cast<StorageType*>(base); @@ -129,7 +315,7 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4)> { // Function: Arity 5 -> 5. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4, X5)> { +struct Invoker0<StorageType, R(*)(X1, X2, X3, X4, X5)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -138,8 +324,6 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4, X5)> { is_non_const_reference<X5>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2, const X3& x3, const X4& x4, const X5& x5) { StorageType* invoker = static_cast<StorageType*>(base); @@ -150,7 +334,7 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4, X5)> { // Function: Arity 6 -> 6. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4, typename X5, typename X6> -struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { +struct Invoker0<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -160,8 +344,6 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { is_non_const_reference<X6>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2, const X3& x3, const X4& x4, const X5& x5, const X6& x6) { StorageType* invoker = static_cast<StorageType*>(base); @@ -169,18 +351,16 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { } }; -template <typename StorageType, typename Sig> -struct FunctionTraits1; +template <typename StorageType, typename NormalizedSig> +struct Invoker1; // Function: Arity 1 -> 0. template <typename StorageType, typename R,typename X1> -struct FunctionTraits1<StorageType, R(*)(X1)> { +struct Invoker1<StorageType, R(*)(X1)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_)); @@ -189,36 +369,21 @@ struct FunctionTraits1<StorageType, R(*)(X1)> { // Method: Arity 0 -> 0. template <typename StorageType, typename R, typename T> -struct FunctionTraits1<StorageType, R(T::*)()> { - typedef base::true_type IsMethod; - +struct Invoker1<StorageType, R(T::*)()> { static R DoInvoke(InvokerStorageBase* base) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(); } }; -// Const Method: Arity 0 -> 0. -template <typename StorageType, typename R, typename T> -struct FunctionTraits1<StorageType, R(T::*)() const> { - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base ) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(); - } -}; - // Function: Arity 2 -> 1. template <typename StorageType, typename R,typename X1, typename X2> -struct FunctionTraits1<StorageType, R(*)(X1, X2)> { +struct Invoker1<StorageType, R(*)(X1, X2)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X2& x2) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_), x2); @@ -227,46 +392,27 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2)> { // Method: Arity 1 -> 1. template <typename StorageType, typename R, typename T, typename X1> -struct FunctionTraits1<StorageType, R(T::*)(X1)> { +struct Invoker1<StorageType, R(T::*)(X1)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X1& x1) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(x1); } }; -// Const Method: Arity 1 -> 1. -template <typename StorageType, typename R, typename T, typename X1> -struct FunctionTraits1<StorageType, R(T::*)(X1) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X1& x1) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(x1); - } -}; - // Function: Arity 3 -> 2. template <typename StorageType, typename R,typename X1, typename X2, typename X3> -struct FunctionTraits1<StorageType, R(*)(X1, X2, X3)> { +struct Invoker1<StorageType, R(*)(X1, X2, X3)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || is_non_const_reference<X3>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_), x2, x3); @@ -276,41 +422,22 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2, X3)> { // Method: Arity 2 -> 2. template <typename StorageType, typename R, typename T, typename X1, typename X2> -struct FunctionTraits1<StorageType, R(T::*)(X1, X2)> { +struct Invoker1<StorageType, R(T::*)(X1, X2)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2); } }; -// Const Method: Arity 2 -> 2. -template <typename StorageType, typename R, typename T, typename X1, - typename X2> -struct FunctionTraits1<StorageType, R(T::*)(X1, X2) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2); - } -}; - // Function: Arity 4 -> 3. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4> -struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4)> { +struct Invoker1<StorageType, R(*)(X1, X2, X3, X4)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -318,8 +445,6 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4)> { is_non_const_reference<X4>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3, const X4& x4) { StorageType* invoker = static_cast<StorageType*>(base); @@ -330,15 +455,13 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4)> { // Method: Arity 3 -> 3. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3> -struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3)> { +struct Invoker1<StorageType, R(T::*)(X1, X2, X3)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || is_non_const_reference<X3>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2, const X3& x3) { StorageType* invoker = static_cast<StorageType*>(base); @@ -346,28 +469,10 @@ struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3)> { } }; -// Const Method: Arity 3 -> 3. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3> -struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2, - const X3& x3) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2, x3); - } -}; - // Function: Arity 5 -> 4. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4, X5)> { +struct Invoker1<StorageType, R(*)(X1, X2, X3, X4, X5)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -376,8 +481,6 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4, X5)> { is_non_const_reference<X5>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3, const X4& x4, const X5& x5) { StorageType* invoker = static_cast<StorageType*>(base); @@ -388,7 +491,7 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4, X5)> { // Method: Arity 4 -> 4. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3, typename X4> -struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4)> { +struct Invoker1<StorageType, R(T::*)(X1, X2, X3, X4)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -396,8 +499,6 @@ struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4)> { is_non_const_reference<X4>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2, const X3& x3, const X4& x4) { StorageType* invoker = static_cast<StorageType*>(base); @@ -405,29 +506,10 @@ struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4)> { } }; -// Const Method: Arity 4 -> 4. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3, typename X4> -struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value || - is_non_const_reference<X4>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2, - const X3& x3, const X4& x4) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2, x3, x4); - } -}; - // Function: Arity 6 -> 5. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4, typename X5, typename X6> -struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { +struct Invoker1<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -437,8 +519,6 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { is_non_const_reference<X6>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3, const X4& x4, const X5& x5, const X6& x6) { StorageType* invoker = static_cast<StorageType*>(base); @@ -449,7 +529,7 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { // Method: Arity 5 -> 5. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { +struct Invoker1<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -458,8 +538,6 @@ struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { is_non_const_reference<X5>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2, const X3& x3, const X4& x4, const X5& x5) { StorageType* invoker = static_cast<StorageType*>(base); @@ -467,39 +545,17 @@ struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { } }; -// Const Method: Arity 5 -> 5. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value || - is_non_const_reference<X4>::value || - is_non_const_reference<X5>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2, - const X3& x3, const X4& x4, const X5& x5) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2, x3, x4, x5); - } -}; - -template <typename StorageType, typename Sig> -struct FunctionTraits2; +template <typename StorageType, typename NormalizedSig> +struct Invoker2; // Function: Arity 2 -> 0. template <typename StorageType, typename R,typename X1, typename X2> -struct FunctionTraits2<StorageType, R(*)(X1, X2)> { +struct Invoker2<StorageType, R(*)(X1, X2)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_)); @@ -508,46 +564,27 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2)> { // Method: Arity 1 -> 0. template <typename StorageType, typename R, typename T, typename X1> -struct FunctionTraits2<StorageType, R(T::*)(X1)> { +struct Invoker2<StorageType, R(T::*)(X1)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_)); } }; -// Const Method: Arity 1 -> 0. -template <typename StorageType, typename R, typename T, typename X1> -struct FunctionTraits2<StorageType, R(T::*)(X1) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base ) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_)); - } -}; - // Function: Arity 3 -> 1. template <typename StorageType, typename R,typename X1, typename X2, typename X3> -struct FunctionTraits2<StorageType, R(*)(X1, X2, X3)> { +struct Invoker2<StorageType, R(*)(X1, X2, X3)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || is_non_const_reference<X3>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X3& x3) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), x3); @@ -557,41 +594,22 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2, X3)> { // Method: Arity 2 -> 1. template <typename StorageType, typename R, typename T, typename X1, typename X2> -struct FunctionTraits2<StorageType, R(T::*)(X1, X2)> { +struct Invoker2<StorageType, R(T::*)(X1, X2)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X2& x2) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2); } }; -// Const Method: Arity 2 -> 1. -template <typename StorageType, typename R, typename T, typename X1, - typename X2> -struct FunctionTraits2<StorageType, R(T::*)(X1, X2) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X2& x2) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2); - } -}; - // Function: Arity 4 -> 2. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4> -struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4)> { +struct Invoker2<StorageType, R(*)(X1, X2, X3, X4)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -599,8 +617,6 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4)> { is_non_const_reference<X4>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), x3, x4); @@ -610,42 +626,23 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4)> { // Method: Arity 3 -> 2. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3> -struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3)> { +struct Invoker2<StorageType, R(T::*)(X1, X2, X3)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || is_non_const_reference<X3>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2, x3); } }; -// Const Method: Arity 3 -> 2. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3> -struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2, x3); - } -}; - // Function: Arity 5 -> 3. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4, X5)> { +struct Invoker2<StorageType, R(*)(X1, X2, X3, X4, X5)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -654,8 +651,6 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4, X5)> { is_non_const_reference<X5>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4, const X5& x5) { StorageType* invoker = static_cast<StorageType*>(base); @@ -666,7 +661,7 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4, X5)> { // Method: Arity 4 -> 3. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3, typename X4> -struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4)> { +struct Invoker2<StorageType, R(T::*)(X1, X2, X3, X4)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -674,8 +669,6 @@ struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4)> { is_non_const_reference<X4>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3, const X4& x4) { StorageType* invoker = static_cast<StorageType*>(base); @@ -684,30 +677,10 @@ struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4)> { } }; -// Const Method: Arity 4 -> 3. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3, typename X4> -struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value || - is_non_const_reference<X4>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3, - const X4& x4) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2, x3, - x4); - } -}; - // Function: Arity 6 -> 4. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4, typename X5, typename X6> -struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { +struct Invoker2<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -717,8 +690,6 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { is_non_const_reference<X6>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4, const X5& x5, const X6& x6) { StorageType* invoker = static_cast<StorageType*>(base); @@ -730,7 +701,7 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { // Method: Arity 5 -> 4. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { +struct Invoker2<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -739,8 +710,6 @@ struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { is_non_const_reference<X5>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3, const X4& x4, const X5& x5) { StorageType* invoker = static_cast<StorageType*>(base); @@ -749,42 +718,19 @@ struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { } }; -// Const Method: Arity 5 -> 4. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value || - is_non_const_reference<X4>::value || - is_non_const_reference<X5>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3, - const X4& x4, const X5& x5) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2, x3, - x4, x5); - } -}; - -template <typename StorageType, typename Sig> -struct FunctionTraits3; +template <typename StorageType, typename NormalizedSig> +struct Invoker3; // Function: Arity 3 -> 0. template <typename StorageType, typename R,typename X1, typename X2, typename X3> -struct FunctionTraits3<StorageType, R(*)(X1, X2, X3)> { +struct Invoker3<StorageType, R(*)(X1, X2, X3)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || is_non_const_reference<X3>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), @@ -795,14 +741,12 @@ struct FunctionTraits3<StorageType, R(*)(X1, X2, X3)> { // Method: Arity 2 -> 0. template <typename StorageType, typename R, typename T, typename X1, typename X2> -struct FunctionTraits3<StorageType, R(T::*)(X1, X2)> { +struct Invoker3<StorageType, R(T::*)(X1, X2)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), @@ -810,28 +754,10 @@ struct FunctionTraits3<StorageType, R(T::*)(X1, X2)> { } }; -// Const Method: Arity 2 -> 0. -template <typename StorageType, typename R, typename T, typename X1, - typename X2> -struct FunctionTraits3<StorageType, R(T::*)(X1, X2) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base ) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), - Unwrap(invoker->p3_)); - } -}; - // Function: Arity 4 -> 1. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4> -struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4)> { +struct Invoker3<StorageType, R(*)(X1, X2, X3, X4)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -839,8 +765,6 @@ struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4)> { is_non_const_reference<X4>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X4& x4) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), @@ -851,15 +775,13 @@ struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4)> { // Method: Arity 3 -> 1. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3> -struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3)> { +struct Invoker3<StorageType, R(T::*)(X1, X2, X3)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || is_non_const_reference<X3>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X3& x3) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), @@ -867,28 +789,10 @@ struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3)> { } }; -// Const Method: Arity 3 -> 1. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3> -struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X3& x3) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), - Unwrap(invoker->p3_), x3); - } -}; - // Function: Arity 5 -> 2. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4, X5)> { +struct Invoker3<StorageType, R(*)(X1, X2, X3, X4, X5)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -897,8 +801,6 @@ struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4, X5)> { is_non_const_reference<X5>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X4& x4, const X5& x5) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), @@ -909,7 +811,7 @@ struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4, X5)> { // Method: Arity 4 -> 2. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3, typename X4> -struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4)> { +struct Invoker3<StorageType, R(T::*)(X1, X2, X3, X4)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -917,8 +819,6 @@ struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4)> { is_non_const_reference<X4>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), @@ -926,29 +826,10 @@ struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4)> { } }; -// Const Method: Arity 4 -> 2. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3, typename X4> -struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value || - is_non_const_reference<X4>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), - Unwrap(invoker->p3_), x3, x4); - } -}; - // Function: Arity 6 -> 3. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4, typename X5, typename X6> -struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { +struct Invoker3<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -958,8 +839,6 @@ struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { is_non_const_reference<X6>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X4& x4, const X5& x5, const X6& x6) { StorageType* invoker = static_cast<StorageType*>(base); @@ -971,7 +850,7 @@ struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { // Method: Arity 5 -> 3. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { +struct Invoker3<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -980,8 +859,6 @@ struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { is_non_const_reference<X5>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4, const X5& x5) { StorageType* invoker = static_cast<StorageType*>(base); @@ -990,34 +867,13 @@ struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { } }; -// Const Method: Arity 5 -> 3. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value || - is_non_const_reference<X4>::value || - is_non_const_reference<X5>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4, - const X5& x5) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), - Unwrap(invoker->p3_), x3, x4, x5); - } -}; - -template <typename StorageType, typename Sig> -struct FunctionTraits4; +template <typename StorageType, typename NormalizedSig> +struct Invoker4; // Function: Arity 4 -> 0. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4> -struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4)> { +struct Invoker4<StorageType, R(*)(X1, X2, X3, X4)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -1025,8 +881,6 @@ struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4)> { is_non_const_reference<X4>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), @@ -1037,15 +891,13 @@ struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4)> { // Method: Arity 3 -> 0. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3> -struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3)> { +struct Invoker4<StorageType, R(T::*)(X1, X2, X3)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || is_non_const_reference<X3>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), @@ -1053,28 +905,10 @@ struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3)> { } }; -// Const Method: Arity 3 -> 0. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3> -struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base ) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), - Unwrap(invoker->p3_), Unwrap(invoker->p4_)); - } -}; - // Function: Arity 5 -> 1. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4, X5)> { +struct Invoker4<StorageType, R(*)(X1, X2, X3, X4, X5)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -1083,8 +917,6 @@ struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4, X5)> { is_non_const_reference<X5>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X5& x5) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), @@ -1095,7 +927,7 @@ struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4, X5)> { // Method: Arity 4 -> 1. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3, typename X4> -struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4)> { +struct Invoker4<StorageType, R(T::*)(X1, X2, X3, X4)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -1103,8 +935,6 @@ struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4)> { is_non_const_reference<X4>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X4& x4) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), @@ -1112,29 +942,10 @@ struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4)> { } }; -// Const Method: Arity 4 -> 1. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3, typename X4> -struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value || - is_non_const_reference<X4>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X4& x4) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), - Unwrap(invoker->p3_), Unwrap(invoker->p4_), x4); - } -}; - // Function: Arity 6 -> 2. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4, typename X5, typename X6> -struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { +struct Invoker4<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -1144,8 +955,6 @@ struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { is_non_const_reference<X6>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X5& x5, const X6& x6) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), @@ -1156,7 +965,7 @@ struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { // Method: Arity 5 -> 2. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { +struct Invoker4<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -1165,8 +974,6 @@ struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { is_non_const_reference<X5>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X4& x4, const X5& x5) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), @@ -1174,33 +981,13 @@ struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { } }; -// Const Method: Arity 5 -> 2. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value || - is_non_const_reference<X4>::value || - is_non_const_reference<X5>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X4& x4, const X5& x5) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), - Unwrap(invoker->p3_), Unwrap(invoker->p4_), x4, x5); - } -}; - -template <typename StorageType, typename Sig> -struct FunctionTraits5; +template <typename StorageType, typename NormalizedSig> +struct Invoker5; // Function: Arity 5 -> 0. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits5<StorageType, R(*)(X1, X2, X3, X4, X5)> { +struct Invoker5<StorageType, R(*)(X1, X2, X3, X4, X5)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -1209,8 +996,6 @@ struct FunctionTraits5<StorageType, R(*)(X1, X2, X3, X4, X5)> { is_non_const_reference<X5>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), @@ -1221,7 +1006,7 @@ struct FunctionTraits5<StorageType, R(*)(X1, X2, X3, X4, X5)> { // Method: Arity 4 -> 0. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3, typename X4> -struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4)> { +struct Invoker5<StorageType, R(T::*)(X1, X2, X3, X4)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -1229,8 +1014,6 @@ struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4)> { is_non_const_reference<X4>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), @@ -1238,29 +1021,10 @@ struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4)> { } }; -// Const Method: Arity 4 -> 0. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3, typename X4> -struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value || - is_non_const_reference<X4>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base ) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), - Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_)); - } -}; - // Function: Arity 6 -> 1. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4, typename X5, typename X6> -struct FunctionTraits5<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { +struct Invoker5<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -1270,8 +1034,6 @@ struct FunctionTraits5<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { is_non_const_reference<X6>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X6& x6) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), @@ -1282,7 +1044,7 @@ struct FunctionTraits5<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { // Method: Arity 5 -> 1. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { +struct Invoker5<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -1291,8 +1053,6 @@ struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { is_non_const_reference<X5>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base, const X5& x5) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), @@ -1300,33 +1060,13 @@ struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { } }; -// Const Method: Arity 5 -> 1. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value || - is_non_const_reference<X4>::value || - is_non_const_reference<X5>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base, const X5& x5) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), - Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_), x5); - } -}; - -template <typename StorageType, typename Sig> -struct FunctionTraits6; +template <typename StorageType, typename NormalizedSig> +struct Invoker6; // Function: Arity 6 -> 0. template <typename StorageType, typename R,typename X1, typename X2, typename X3, typename X4, typename X5, typename X6> -struct FunctionTraits6<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { +struct Invoker6<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -1336,8 +1076,6 @@ struct FunctionTraits6<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { is_non_const_reference<X6>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base) { StorageType* invoker = static_cast<StorageType*>(base); return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), @@ -1349,7 +1087,7 @@ struct FunctionTraits6<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> { // Method: Arity 5 -> 0. template <typename StorageType, typename R, typename T, typename X1, typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits6<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { +struct Invoker6<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { COMPILE_ASSERT( !( is_non_const_reference<X1>::value || is_non_const_reference<X2>::value || @@ -1358,8 +1096,6 @@ struct FunctionTraits6<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { is_non_const_reference<X5>::value ), do_not_bind_functions_with_nonconst_ref); - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base) { StorageType* invoker = static_cast<StorageType*>(base); return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), @@ -1368,47 +1104,28 @@ struct FunctionTraits6<StorageType, R(T::*)(X1, X2, X3, X4, X5)> { } }; -// Const Method: Arity 5 -> 0. -template <typename StorageType, typename R, typename T, typename X1, - typename X2, typename X3, typename X4, typename X5> -struct FunctionTraits6<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> { - COMPILE_ASSERT( - !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value - || is_non_const_reference<X3>::value || - is_non_const_reference<X4>::value || - is_non_const_reference<X5>::value ), - do_not_bind_functions_with_nonconst_ref); - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base ) { - StorageType* invoker = static_cast<StorageType*>(base); - return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), - Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_), - Unwrap(invoker->p6_)); - } -}; - -// These are the actual storage classes for the invokers. +// 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 FunctionTraitsN above to know the return type, and the arity +// Sig type like in InvokerN above to know the return type, and the arity // of Run(). // -// An alternate solution would be to merge FunctionTraitsN and InvokerStorageN, +// An alternate solution would be to merge InvokerN and InvokerStorageN, // but the generated code seemed harder to read. template <typename Sig> class InvokerStorage0 : public InvokerStorageBase { public: typedef InvokerStorage0 StorageType; - typedef FunctionTraits0<StorageType, Sig> FunctionTraits; - typedef typename FunctionTraits::IsMethod IsMethod; - + typedef FunctionTraits<Sig> TargetTraits; + typedef Invoker0<StorageType, typename TargetTraits::NormalizedSig> Invoker; + typedef typename TargetTraits::IsMethod IsMethod; InvokerStorage0(Sig f) @@ -1424,9 +1141,9 @@ template <typename Sig, typename P1> class InvokerStorage1 : public InvokerStorageBase { public: typedef InvokerStorage1 StorageType; - typedef FunctionTraits1<StorageType, Sig> FunctionTraits; - typedef typename FunctionTraits::IsMethod IsMethod; - + typedef FunctionTraits<Sig> TargetTraits; + typedef Invoker1<StorageType, typename TargetTraits::NormalizedSig> Invoker; + typedef typename TargetTraits::IsMethod IsMethod; // 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. @@ -1454,9 +1171,9 @@ template <typename Sig, typename P1, typename P2> class InvokerStorage2 : public InvokerStorageBase { public: typedef InvokerStorage2 StorageType; - typedef FunctionTraits2<StorageType, Sig> FunctionTraits; - typedef typename FunctionTraits::IsMethod IsMethod; - + typedef FunctionTraits<Sig> TargetTraits; + typedef Invoker2<StorageType, typename TargetTraits::NormalizedSig> Invoker; + typedef typename TargetTraits::IsMethod IsMethod; // 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. @@ -1488,9 +1205,9 @@ template <typename Sig, typename P1, typename P2, typename P3> class InvokerStorage3 : public InvokerStorageBase { public: typedef InvokerStorage3 StorageType; - typedef FunctionTraits3<StorageType, Sig> FunctionTraits; - typedef typename FunctionTraits::IsMethod IsMethod; - + typedef FunctionTraits<Sig> TargetTraits; + typedef Invoker3<StorageType, typename TargetTraits::NormalizedSig> Invoker; + typedef typename TargetTraits::IsMethod IsMethod; // 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. @@ -1526,9 +1243,9 @@ template <typename Sig, typename P1, typename P2, typename P3, typename P4> class InvokerStorage4 : public InvokerStorageBase { public: typedef InvokerStorage4 StorageType; - typedef FunctionTraits4<StorageType, Sig> FunctionTraits; - typedef typename FunctionTraits::IsMethod IsMethod; - + typedef FunctionTraits<Sig> TargetTraits; + typedef Invoker4<StorageType, typename TargetTraits::NormalizedSig> Invoker; + typedef typename TargetTraits::IsMethod IsMethod; // 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. @@ -1569,9 +1286,9 @@ template <typename Sig, typename P1, typename P2, typename P3, typename P4, class InvokerStorage5 : public InvokerStorageBase { public: typedef InvokerStorage5 StorageType; - typedef FunctionTraits5<StorageType, Sig> FunctionTraits; - typedef typename FunctionTraits::IsMethod IsMethod; - + typedef FunctionTraits<Sig> TargetTraits; + typedef Invoker5<StorageType, typename TargetTraits::NormalizedSig> Invoker; + typedef typename TargetTraits::IsMethod IsMethod; // 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. @@ -1617,9 +1334,9 @@ template <typename Sig, typename P1, typename P2, typename P3, typename P4, class InvokerStorage6 : public InvokerStorageBase { public: typedef InvokerStorage6 StorageType; - typedef FunctionTraits6<StorageType, Sig> FunctionTraits; - typedef typename FunctionTraits::IsMethod IsMethod; - + typedef FunctionTraits<Sig> TargetTraits; + typedef Invoker6<StorageType, typename TargetTraits::NormalizedSig> Invoker; + typedef typename TargetTraits::IsMethod IsMethod; // 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. diff --git a/base/bind_internal.h.pump b/base/bind_internal.h.pump index 6fd95fe..b1ba2d7 100644 --- a/base/bind_internal.h.pump +++ b/base/bind_internal.h.pump @@ -25,32 +25,103 @@ namespace internal { // The method by which a function is invoked is determined by 3 different // dimensions: // -// 1) The type of function (normal, method, const-method) -// 2) The arity of the function +// 1) The type of function (normal or method). +// 2) The arity of the function. // 3) The number of bound parameters. // -// The FunctionTraitsN classes unwrap the function signature type to -// specialize based on the first two dimensions. The N in FunctionTraitsN -// specifies the 3rd dimension. We could have specified the unbound parameters -// via template parameters, but this method looked cleaner. +// The templates below handle the determination of each of these dimensions. +// In brief: // -// The FunctionTraitsN contains 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. +// 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. +// +// More details about the design of each class is included in a comment closer +// to their defition. + +// FunctionTraits<> +// +// 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)). +// +// 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. +// +// 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. + +template <typename Sig> +struct FunctionTraits; + +$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 base::false_type IsMethod; +}; + +// 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)]]); + typedef base::true_type IsMethod; +}; + +// 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)]]); + typedef base::true_type IsMethod; +}; + +]] $$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. // // 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. +// +// 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. $range BOUND 0..MAX_ARITY $for BOUND [[ -template <typename StorageType, typename Sig> -struct FunctionTraits$(BOUND); +template <typename StorageType, typename NormalizedSig> +struct Invoker$(BOUND); $range ARITY 0..MAX_ARITY $for ARITY [[ @@ -74,7 +145,7 @@ $range M_UNBOUND_ARG (M_ARITY - UNBOUND + 1)..M_ARITY template <typename StorageType, typename R[[]] $if ARITY > 0 [[,]][[]] $for ARG , [[typename X$(ARG)]]> -struct FunctionTraits$(BOUND)<StorageType, R(*)($for ARG , [[X$(ARG)]])> { +struct Invoker$(BOUND)<StorageType, R(*)($for ARG , [[X$(ARG)]])> { $if ARITY > 0 [[ COMPILE_ASSERT( @@ -83,8 +154,6 @@ $if ARITY > 0 [[ ]] - typedef base::false_type IsMethod; - static R DoInvoke(InvokerStorageBase* base[[]] $if UNBOUND != 0 [[, ]][[]] $for UNBOUND_ARG , [[const X$(UNBOUND_ARG)& x$(UNBOUND_ARG)]]) { @@ -101,7 +170,7 @@ $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 FunctionTraits$(BOUND)<StorageType, R(T::*)($for M_ARG , [[X$(M_ARG)]])> { +struct Invoker$(BOUND)<StorageType, R(T::*)($for M_ARG , [[X$(M_ARG)]])> { $if M_ARITY > 0 [[ COMPILE_ASSERT( @@ -110,8 +179,6 @@ $if M_ARITY > 0 [[ ]] - typedef base::true_type IsMethod; - static R DoInvoke(InvokerStorageBase* base[[]] $if UNBOUND > 0 [[, ]][[]] $for M_UNBOUND_ARG , [[const X$(M_UNBOUND_ARG)& x$(M_UNBOUND_ARG)]]) { @@ -123,31 +190,6 @@ $for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]); } }; -// Const Method: Arity $(M_ARITY) -> $(UNBOUND). -template <typename StorageType, typename R, typename T[[]] -$if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]> -struct FunctionTraits$(BOUND)<StorageType, R(T::*)($for M_ARG , [[X$(M_ARG)]]) const> { -$if M_ARITY > 0 [[ - - COMPILE_ASSERT( - !($for M_ARG || [[is_non_const_reference<X$(M_ARG)>::value ]]), - do_not_bind_functions_with_nonconst_ref); - -]] - - typedef base::true_type IsMethod; - - static R DoInvoke(InvokerStorageBase* base[[]] -$if UNBOUND > 0 [[, ]] -[[]] $for M_UNBOUND_ARG , [[const X$(M_UNBOUND_ARG)& 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)]]); - } -}; - ]] $$ if BOUND ]] $$ if UNBOUND @@ -155,16 +197,18 @@ $for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]); ]] $$ for BOUND -// These are the actual storage classes for the invokers. +// 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 FunctionTraitsN above to know the return type, and the arity +// Sig type like in InvokerN above to know the return type, and the arity // of Run(). // -// An alternate solution would be to merge FunctionTraitsN and InvokerStorageN, +// An alternate solution would be to merge InvokerN and InvokerStorageN, // but the generated code seemed harder to read. $for BOUND [[ @@ -176,9 +220,9 @@ $for BOUND_ARG , [[typename P$(BOUND_ARG)]]> class InvokerStorage$(BOUND) : public InvokerStorageBase { public: typedef InvokerStorage$(BOUND) StorageType; - typedef FunctionTraits$(BOUND)<StorageType, Sig> FunctionTraits; - typedef typename FunctionTraits::IsMethod IsMethod; - + typedef FunctionTraits<Sig> TargetTraits; + typedef Invoker$(BOUND)<StorageType, typename TargetTraits::NormalizedSig> Invoker; + typedef typename TargetTraits::IsMethod IsMethod; $for BOUND_ARG [[ $if BOUND_ARG == 1 [[ diff --git a/base/callback.h b/base/callback.h index 9c76aa5..bcc3dfd 100644 --- a/base/callback.h +++ b/base/callback.h @@ -221,6 +221,7 @@ namespace base { // only has one type: the function signature. template <typename Sig> class Callback; + template <typename R> class Callback<R(void)> : public internal::CallbackBase { public: @@ -238,7 +239,7 @@ class Callback<R(void)> : public internal::CallbackBase { template <typename T> Callback(const internal::InvokerStorageHolder<T>& invoker_holder) : CallbackBase( - reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke), + reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke), &invoker_holder.invoker_storage_) { } @@ -267,7 +268,7 @@ class Callback<R(A1)> : public internal::CallbackBase { template <typename T> Callback(const internal::InvokerStorageHolder<T>& invoker_holder) : CallbackBase( - reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke), + reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke), &invoker_holder.invoker_storage_) { } @@ -297,7 +298,7 @@ class Callback<R(A1, A2)> : public internal::CallbackBase { template <typename T> Callback(const internal::InvokerStorageHolder<T>& invoker_holder) : CallbackBase( - reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke), + reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke), &invoker_holder.invoker_storage_) { } @@ -330,7 +331,7 @@ class Callback<R(A1, A2, A3)> : public internal::CallbackBase { template <typename T> Callback(const internal::InvokerStorageHolder<T>& invoker_holder) : CallbackBase( - reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke), + reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke), &invoker_holder.invoker_storage_) { } @@ -366,7 +367,7 @@ class Callback<R(A1, A2, A3, A4)> : public internal::CallbackBase { template <typename T> Callback(const internal::InvokerStorageHolder<T>& invoker_holder) : CallbackBase( - reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke), + reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke), &invoker_holder.invoker_storage_) { } @@ -406,7 +407,7 @@ class Callback<R(A1, A2, A3, A4, A5)> : public internal::CallbackBase { template <typename T> Callback(const internal::InvokerStorageHolder<T>& invoker_holder) : CallbackBase( - reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke), + reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke), &invoker_holder.invoker_storage_) { } @@ -449,7 +450,7 @@ class Callback<R(A1, A2, A3, A4, A5, A6)> : public internal::CallbackBase { template <typename T> Callback(const internal::InvokerStorageHolder<T>& invoker_holder) : CallbackBase( - reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke), + reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke), &invoker_holder.invoker_storage_) { } diff --git a/base/callback.h.pump b/base/callback.h.pump index 2efe0c5..34b0eb0 100644 --- a/base/callback.h.pump +++ b/base/callback.h.pump @@ -226,6 +226,7 @@ namespace base { template <typename Sig> class Callback; + $range ARITY 0..MAX_ARITY $for ARITY [[ $range ARG 1..ARITY @@ -256,7 +257,7 @@ $for ARG , template <typename T> Callback(const internal::InvokerStorageHolder<T>& invoker_holder) : CallbackBase( - reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke), + reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke), &invoker_holder.invoker_storage_) { } diff --git a/base/callback_unittest.cc b/base/callback_unittest.cc index e41b399..f327412 100644 --- a/base/callback_unittest.cc +++ b/base/callback_unittest.cc @@ -21,7 +21,7 @@ class HelperObject { int next_number_; }; -struct FakeTraits { +struct FakeInvoker { static void DoInvoke(internal::InvokerStorageBase*) { } }; @@ -30,12 +30,12 @@ struct FakeTraits { // comparators and emptiness APIs. class FakeInvokerStorage1 : public internal::InvokerStorageBase { public: - typedef FakeTraits FunctionTraits; + typedef FakeInvoker Invoker; }; class FakeInvokerStorage2 : public internal::InvokerStorageBase { public: - typedef FakeTraits FunctionTraits; + typedef FakeInvoker Invoker; }; TEST(CallbackOld, OneArg) { |