diff options
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) { |