diff options
author | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-15 01:27:38 +0000 |
---|---|---|
committer | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-15 01:27:38 +0000 |
commit | b38d3578e53d0a7f441c6858334a2d9f08e5c024 (patch) | |
tree | 917a1d893c40fd10408e172b1a66cba692a0fedc /base | |
parent | c41fe6697e38057138cbe33332d9882e0d7d9b4b (diff) | |
download | chromium_src-b38d3578e53d0a7f441c6858334a2d9f08e5c024.zip chromium_src-b38d3578e53d0a7f441c6858334a2d9f08e5c024.tar.gz chromium_src-b38d3578e53d0a7f441c6858334a2d9f08e5c024.tar.bz2 |
Unified callback system based on tr1::function/tr1::bind and Google's internal callback code.
This callback system allows for creation of functors for normal functions, methods, and const methods. It is a superset of the functionality of NewRunnableMethod, NewRunnableFunction, NewCallback, and CreateFunctor.
We support partial binding of function arguments, and also specification of refcounting semantics by wrapping a target object in a wrapper object.
BUG=35223
TEST=none
Review URL: http://codereview.chromium.org/6109007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@74904 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/base.gyp | 2 | ||||
-rw-r--r-- | base/base.gypi | 5 | ||||
-rw-r--r-- | base/bind.h | 99 | ||||
-rw-r--r-- | base/bind.h.pump | 71 | ||||
-rw-r--r-- | base/bind_helpers.h | 287 | ||||
-rw-r--r-- | base/bind_internal.h | 1670 | ||||
-rw-r--r-- | base/bind_internal.h.pump | 237 | ||||
-rw-r--r-- | base/bind_unittest.cc | 597 | ||||
-rw-r--r-- | base/callback.h | 640 | ||||
-rw-r--r-- | base/callback.h.pump | 291 | ||||
-rw-r--r-- | base/callback_helpers.h | 55 | ||||
-rw-r--r-- | base/callback_old.h | 254 | ||||
-rw-r--r-- | base/template_util.h | 43 | ||||
-rw-r--r-- | base/template_util_unittest.cc | 66 |
14 files changed, 4103 insertions, 214 deletions
diff --git a/base/base.gyp b/base/base.gyp index c407ce9..868569e 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -65,6 +65,7 @@ 'at_exit_unittest.cc', 'atomicops_unittest.cc', 'base64_unittest.cc', + 'bind_unittest.cc', 'bits_unittest.cc', 'callback_unittest.cc', 'command_line_unittest.cc', @@ -142,6 +143,7 @@ 'sys_string_conversions_unittest.cc', 'task_queue_unittest.cc', 'task_unittest.cc', + 'template_util_unittest.cc', 'threading/non_thread_safe_unittest.cc', 'threading/platform_thread_unittest.cc', 'threading/simple_thread_unittest.cc', diff --git a/base/base.gypi b/base/base.gypi index 385794e..7a5da2e 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -36,9 +36,14 @@ 'base_switches.cc', 'base_switches.h', 'basictypes.h', + 'bind.h', + 'bind_helpers.h', + 'bind_internal.h', 'bits.h', 'bzip2_error_handler.cc', 'callback.h', + 'callback_helpers.h', + 'callback_old.h', 'command_line.cc', 'command_line.h', 'compiler_specific.h', diff --git a/base/bind.h b/base/bind.h new file mode 100644 index 0000000..c23af2e --- /dev/null +++ b/base/bind.h @@ -0,0 +1,99 @@ +// This file was GENERATED by command: +// pump.py bind.h.pump +// DO NOT EDIT BY HAND!!! + + +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_BIND_H_ +#define BASE_BIND_H_ +#pragma once + +#include "base/bind_internal.h" +#include "base/callback_helpers.h" + +// See base/callback.h for how to use these functions. +// +// IMPLEMENTATION NOTE +// Though Bind()'s result is meant to be stored in a Callback<> type, it +// cannot actually return the exact type without requiring a large amount +// of extra template specializations. The problem is that in order to +// discern the correct specialization of Callback<>, Bind would need to +// unwrap the function signature to determine the signature's arity, and +// whether or not it is a method. +// +// Each unique combination of (arity, function_type, num_prebound) where +// function_type is one of {function, method, const_method} would require +// one specialization. We eventually have to do a similar number of +// specializations anyways in the implementation (see the FunctionTraitsN, +// classes). However, it is avoidable in Bind if we return the result +// via an indirection like we do below. + +namespace base { + +template <typename Sig> +internal::InvokerStorageHolder<internal::InvokerStorage0<Sig> > +Bind(Sig f) { + return internal::MakeInvokerStorageHolder( + new internal::InvokerStorage0<Sig>(f)); +} + +template <typename Sig, typename P1> +internal::InvokerStorageHolder<internal::InvokerStorage1<Sig,P1> > +Bind(Sig f, const P1& p1) { + return internal::MakeInvokerStorageHolder( + new internal::InvokerStorage1<Sig, P1>( + f, p1)); +} + +template <typename Sig, typename P1, typename P2> +internal::InvokerStorageHolder<internal::InvokerStorage2<Sig,P1, P2> > +Bind(Sig f, const P1& p1, const P2& p2) { + return internal::MakeInvokerStorageHolder( + new internal::InvokerStorage2<Sig, P1, P2>( + f, p1, p2)); +} + +template <typename Sig, typename P1, typename P2, typename P3> +internal::InvokerStorageHolder<internal::InvokerStorage3<Sig,P1, P2, P3> > +Bind(Sig f, const P1& p1, const P2& p2, const P3& p3) { + return internal::MakeInvokerStorageHolder( + new internal::InvokerStorage3<Sig, P1, P2, P3>( + f, p1, p2, p3)); +} + +template <typename Sig, typename P1, typename P2, typename P3, typename P4> +internal::InvokerStorageHolder<internal::InvokerStorage4<Sig,P1, P2, P3, P4> > +Bind(Sig f, const P1& p1, const P2& p2, const P3& p3, const P4& p4) { + return internal::MakeInvokerStorageHolder( + new internal::InvokerStorage4<Sig, P1, P2, P3, P4>( + f, p1, p2, p3, p4)); +} + +template <typename Sig, typename P1, typename P2, typename P3, typename P4, + typename P5> +internal::InvokerStorageHolder<internal::InvokerStorage5<Sig,P1, P2, P3, P4, + P5> > +Bind(Sig f, const P1& p1, const P2& p2, const P3& p3, const P4& p4, + const P5& p5) { + return internal::MakeInvokerStorageHolder( + new internal::InvokerStorage5<Sig, P1, P2, P3, P4, P5>( + f, p1, p2, p3, p4, p5)); +} + +template <typename Sig, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6> +internal::InvokerStorageHolder<internal::InvokerStorage6<Sig,P1, P2, P3, P4, + P5, P6> > +Bind(Sig f, const P1& p1, const P2& p2, const P3& p3, const P4& p4, + const P5& p5, const P6& p6) { + return internal::MakeInvokerStorageHolder( + new internal::InvokerStorage6<Sig, P1, P2, P3, P4, P5, P6>( + f, p1, p2, p3, p4, p5, p6)); +} + +} // namespace base + +#endif // BASE_BIND_H_ diff --git a/base/bind.h.pump b/base/bind.h.pump new file mode 100644 index 0000000..fc7f246 --- /dev/null +++ b/base/bind.h.pump @@ -0,0 +1,71 @@ +$$ This is a pump file for generating file templates. Pump is a python +$$ script that is part of the Google Test suite of utilities. Description +$$ can be found here: +$$ +$$ http://code.google.com/p/googletest/wiki/PumpManual +$$ + +$var MAX_ARITY = 6 + +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_BIND_H_ +#define BASE_BIND_H_ +#pragma once + +#include "base/bind_internal.h" +#include "base/callback_helpers.h" + +// See base/callback.h for how to use these functions. +// +// IMPLEMENTATION NOTE +// Though Bind()'s result is meant to be stored in a Callback<> type, it +// cannot actually return the exact type without requiring a large amount +// of extra template specializations. The problem is that in order to +// discern the correct specialization of Callback<>, Bind would need to +// unwrap the function signature to determine the signature's arity, and +// whether or not it is a method. +// +// Each unique combination of (arity, function_type, num_prebound) where +// function_type is one of {function, method, const_method} would require +// one specialization. We eventually have to do a similar number of +// specializations anyways in the implementation (see the FunctionTraitsN, +// classes). However, it is avoidable in Bind if we return the result +// via an indirection like we do below. + +namespace base { + +$range BOUND 0..MAX_ARITY +$for BOUND [[ +$range BOUND_ARG 1..BOUND + +$if BOUND == 0 [[ + +template <typename Sig> +internal::InvokerStorageHolder<internal::InvokerStorage0<Sig> > +Bind(Sig f) { + return internal::MakeInvokerStorageHolder( + new internal::InvokerStorage0<Sig>(f)); +} + +]] $else [[ + +template <typename Sig, $for BOUND_ARG , [[typename P$(BOUND_ARG)]]> +internal::InvokerStorageHolder<internal::InvokerStorage$(BOUND)<Sig, +$for BOUND_ARG , [[P$(BOUND_ARG)]]> > +Bind(Sig f, $for BOUND_ARG , [[const P$(BOUND_ARG)& p$(BOUND_ARG)]]) { + return internal::MakeInvokerStorageHolder( + new internal::InvokerStorage$(BOUND)<Sig, [[]] +$for BOUND_ARG , [[P$(BOUND_ARG)]]>( + f, $for BOUND_ARG , [[p$(BOUND_ARG)]])); +} + +]] + +]] $$ for BOUND + +} // namespace base + +#endif // BASE_BIND_H_ diff --git a/base/bind_helpers.h b/base/bind_helpers.h new file mode 100644 index 0000000..c1ca3d7 --- /dev/null +++ b/base/bind_helpers.h @@ -0,0 +1,287 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This defines a set of argument wrappers and related factory methods that +// can be used specify the refcounting and reference semantics of arguments +// that are bound by the Bind() function in base/bind.h. +// +// The public functions are base::Unretained() and base::ConstRef(). +// Unretained() allows Bind() to bind a non-refcounted class. +// ConstRef() allows binding a constant reference to an argument rather +// than a copy. +// +// +// EXAMPLE OF Unretained(): +// +// class Foo { +// public: +// void func() { cout << "Foo:f" << endl; +// }; +// +// // In some function somewhere. +// Foo foo; +// Callback<void(void)> foo_callback = +// Bind(&Foo::func, Unretained(&foo)); +// foo_callback.Run(); // Prints "Foo:f". +// +// Without the Unretained() wrapper on |&foo|, the above call would fail +// to compile because Foo does not support the AddRef() and Release() methods. +// +// +// EXAMPLE OF ConstRef(); +// void foo(int arg) { cout << arg << endl } +// +// int n = 1; +// Callback<void(void)> no_ref = Bind(&foo, n); +// Callback<void(void)> has_ref = Bind(&foo, ConstRef(n)); +// +// no_ref.Run(); // Prints "1" +// has_ref.Run(); // Prints "1" +// +// n = 2; +// no_ref.Run(); // Prints "1" +// has_ref.Run(); // Prints "2" +// +// Note that because ConstRef() takes a reference on |n|, |n| must outlive all +// its bound callbacks. +// + +#ifndef BASE_BIND_HELPERS_H_ +#define BASE_BIND_HELPERS_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/template_util.h" + +namespace base { +namespace internal { + +// Use the Substitution Failure Is Not An Error (SFINAE) trick to inspect T +// for the existence of AddRef() and Release() functions of the correct +// signature. +// +// http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error +// http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence +// http://stackoverflow.com/questions/4358584/sfinae-approach-comparison +// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions +// +// The last link in particular show the method used below. +// +// For SFINAE to work with inherited methods, we need to pull some extra tricks +// with multiple inheritance. In the more standard formulation, the overloads +// of Check would be: +// +// template <typename C> +// Yes NotTheCheckWeWant(Helper<&C::TargetFunc>*); +// +// template <typename C> +// No NotTheCheckWeWant(...); +// +// static const bool value = sizeof(NotTheCheckWeWant<T>(0)) == sizeof(Yes); +// +// The problem here is that template resolution will not match +// C::TargetFunc if TargetFunc does not exist directly in C. That is, if +// TargetFunc in inherited from an ancestor, &C::TargetFunc will not match, +// |value| will be false. This formulation only checks for whether or +// not TargetFunc exist directly in the class being introspected. +// +// To get around this, we play a dirty trick with multiple inheritance. +// First, We create a class BaseMixin that declares each function that we +// want to probe for. Then we create a class Base that inherits from both T +// (the class we wish to probe) and BaseMixin. Note that the function +// signature in BaseMixin does not need to match the signature of the function +// we are probing for; thus it's easiest to just use void(void). +// +// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an +// ambiguous resolution between BaseMixin and T. This lets us write the +// following: +// +// template <typename C> +// No GoodCheck(Helper<&C::TargetFunc>*); +// +// template <typename C> +// Yes GoodCheck(...); +// +// static const bool value = sizeof(GoodCheck<Base>(0)) == sizeof(Yes); +// +// Notice here that the variadic version of GoodCheck() returns Yes here +// instead of No like the previous one. Also notice that we calculate |value| +// by specializing GoodCheck() on Base instead of T. +// +// We've reversed the roles of the variadic, and Helper overloads. +// GoodCheck(Helper<&C::TargetFunc>*), when C = Base, fails to be a valid +// substitution if T::TargetFunc exists. Thus GoodCheck<Base>(0) will resolve +// to the variadic version if T has TargetFunc. If T::TargetFunc does not +// exist, then &C::TargetFunc is not ambiguous, and the overload resolution +// will prefer GoodCheck(Helper<&C::TargetFunc>*). +// +// This method of SFINAE will correctly probe for inherited names, but it cannot +// typecheck those names. It's still a good enough sanity check though. +// +// Works on gcc-4.2, gcc-4.4, and Visual Studio 2008. +// +// TODO(ajwong): Move to ref_counted.h or template_util.h when we've vetted +// this works well. +template <typename T> +class SupportsAddRefAndRelease { + typedef char Yes[1]; + typedef char No[2]; + + struct BaseMixin { + void AddRef(); + void Release(); + }; + + struct Base : public T, public BaseMixin { + }; + + template <void(BaseMixin::*)(void)> struct Helper {}; + + template <typename C> + static No& Check(Helper<&C::AddRef>*, Helper<&C::Release>*); + + template <typename > + static Yes& Check(...); + + public: + static const bool value = sizeof(Check<Base>(0,0)) == sizeof(Yes); +}; + + +// Helpers to assert that arguments of a recounted type are bound with a +// scoped_refptr. +template <bool IsClasstype, typename T> +struct UnsafeBindtoRefCountedArgHelper : false_type { +}; + +template <typename T> +struct UnsafeBindtoRefCountedArgHelper<true, T> + : integral_constant<bool, SupportsAddRefAndRelease<T>::value> { +}; + +template <typename T> +struct UnsafeBindtoRefCountedArg + : UnsafeBindtoRefCountedArgHelper<is_class<T>::value, T> { +}; + + +template <typename T> +class UnretainedWrapper { + public: + explicit UnretainedWrapper(T* o) : obj_(o) {} + T* get() { return obj_; } + private: + T* obj_; +}; + +template <typename T> +class ConstRefWrapper { + public: + explicit ConstRefWrapper(const T& o) : ptr_(&o) {} + const T& get() { return *ptr_; } + private: + const T* ptr_; +}; + + +// Unwrap the stored parameters for the wrappers above. +template <typename T> +T Unwrap(T o) { return o; } + +template <typename T> +T* Unwrap(UnretainedWrapper<T> unretained) { return unretained.get(); } + +template <typename T> +const T& Unwrap(ConstRefWrapper<T> const_ref) { + return const_ref.get(); +} + + +// Utility for handling different refcounting semantics in the Bind() +// function. +template <typename ref, typename T> +struct MaybeRefcount; + +template <typename T> +struct MaybeRefcount<base::false_type, T> { + static void AddRef(const T&) {} + static void Release(const T&) {} +}; + +template <typename T, size_t n> +struct MaybeRefcount<base::false_type, T[n]> { + static void AddRef(const T*) {} + static void Release(const T*) {} +}; + +template <typename T> +struct MaybeRefcount<base::true_type, UnretainedWrapper<T> > { + static void AddRef(const UnretainedWrapper<T>&) {} + static void Release(const UnretainedWrapper<T>&) {} +}; + +template <typename T> +struct MaybeRefcount<base::true_type, T*> { + static void AddRef(T* o) { o->AddRef(); } + static void Release(T* o) { o->Release(); } +}; + +template <typename T> +struct MaybeRefcount<base::true_type, const T*> { + static void AddRef(const T* o) { o->AddRef(); } + static void Release(const T* o) { o->Release(); } +}; + + +// This is a typetraits object that's used to convert an argument type into a +// type suitable for storage. In particular, it strips off references, and +// converts arrays to pointers. +// +// This array type becomes an issue because we are passing bound parameters by +// const reference. In this case, we end up passing an actual array type in the +// initializer list which C++ does not allow. This will break passing of +// C-string literals. +template <typename T> +struct BindType { + typedef T StorageType; +}; + +// This should almost be impossible to trigger unless someone manually +// specifies type of the bind parameters. However, in case they do, +// this will guard against us accidentally storing a reference parameter. +template <typename T> +struct BindType<T&> { + typedef T StorageType; +}; + +// Note that for array types, we implicitly add a const in the conversion. This +// means that it is not possible to bind array arguments to functions that take +// a non-const pointer. Trying to specialize the template based on a "const +// T[n]" does not seem to match correctly, so we are stuck with this +// restriction. +template <typename T, size_t n> +struct BindType<T[n]> { + typedef const T* StorageType; +}; + +template <typename T> +struct BindType<T[]> { + typedef const T* StorageType; +}; + +} // namespace internal + +template <typename T> +inline internal::UnretainedWrapper<T> Unretained(T* o) { + return internal::UnretainedWrapper<T>(o); +} + +template <typename T> +inline internal::ConstRefWrapper<T> ConstRef(const T& o) { + return internal::ConstRefWrapper<T>(o); +} + +} // namespace base + +#endif // BASE_BIND_HELPERS_H_ diff --git a/base/bind_internal.h b/base/bind_internal.h new file mode 100644 index 0000000..62f2050 --- /dev/null +++ b/base/bind_internal.h @@ -0,0 +1,1670 @@ +// This file was GENERATED by command: +// pump.py bind_internal.h.pump +// DO NOT EDIT BY HAND!!! + + +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_BIND_INTERNAL_H_ +#define BASE_BIND_INTERNAL_H_ +#pragma once + +#include "base/bind_helpers.h" +#include "base/callback_helpers.h" +#include "base/template_util.h" + +namespace base { +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 +// 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 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. +// +// 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. + +template <typename StorageType, typename Sig> +struct FunctionTraits0; + +// Function: Arity 0 -> 0. +template <typename StorageType, typename R> +struct FunctionTraits0<StorageType, R(*)()> { + typedef base::false_type IsMethod; + + static R DoInvoke(InvokerStorageBase* base) { + StorageType* invoker = static_cast<StorageType*>(base); + return invoker->f_(); + } +}; + +// Function: Arity 1 -> 1. +template <typename StorageType, typename R,typename X1> +struct FunctionTraits0<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); + } +}; + +// Function: Arity 2 -> 2. +template <typename StorageType, typename R,typename X1, typename X2> +struct FunctionTraits0<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); + } +}; + +// Function: Arity 3 -> 3. +template <typename StorageType, typename R,typename X1, typename X2, + typename X3> +struct FunctionTraits0<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); + return invoker->f_(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)> { + 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::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); + return invoker->f_(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)> { + 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::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); + return invoker->f_(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)> { + 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 || + 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); + return invoker->f_(x1, x2, x3, x4, x5, x6); + } +}; + +template <typename StorageType, typename Sig> +struct FunctionTraits1; + +// Function: Arity 1 -> 0. +template <typename StorageType, typename R,typename X1> +struct FunctionTraits1<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_)); + } +}; + +// Method: Arity 0 -> 0. +template <typename StorageType, typename R, typename T> +struct FunctionTraits1<StorageType, R(T::*)()> { + typedef base::true_type IsMethod; + + 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)> { + 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); + } +}; + +// Method: Arity 1 -> 1. +template <typename StorageType, typename R, typename T, typename X1> +struct FunctionTraits1<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)> { + 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); + } +}; + +// Method: Arity 2 -> 2. +template <typename StorageType, typename R, typename T, typename X1, + typename X2> +struct FunctionTraits1<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)> { + 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::false_type IsMethod; + + static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3, + const X4& x4) { + StorageType* invoker = static_cast<StorageType*>(base); + return invoker->f_(Unwrap(invoker->p1_), 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)> { + 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); + } +}; + +// 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)> { + 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::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); + return invoker->f_(Unwrap(invoker->p1_), 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)> { + 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); + } +}; + +// 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)> { + 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 || + 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); + return invoker->f_(Unwrap(invoker->p1_), 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)> { + 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); + } +}; + +// 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; + +// Function: Arity 2 -> 0. +template <typename StorageType, typename R,typename X1, typename X2> +struct FunctionTraits2<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_)); + } +}; + +// Method: Arity 1 -> 0. +template <typename StorageType, typename R, typename T, typename X1> +struct FunctionTraits2<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)> { + 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); + } +}; + +// Method: Arity 2 -> 1. +template <typename StorageType, typename R, typename T, typename X1, + typename X2> +struct FunctionTraits2<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)> { + 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::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); + } +}; + +// 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)> { + 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)> { + 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::false_type IsMethod; + + static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4, + const X5& x5) { + StorageType* invoker = static_cast<StorageType*>(base); + return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), 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)> { + 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); + } +}; + +// 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)> { + 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 || + 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); + return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), 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)> { + 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); + } +}; + +// 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; + +// Function: Arity 3 -> 0. +template <typename StorageType, typename R,typename X1, typename X2, + typename X3> +struct FunctionTraits3<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_), + Unwrap(invoker->p3_)); + } +}; + +// Method: Arity 2 -> 0. +template <typename StorageType, typename R, typename T, typename X1, + typename X2> +struct FunctionTraits3<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_), + Unwrap(invoker->p3_)); + } +}; + +// 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)> { + 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::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_), + Unwrap(invoker->p3_), 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)> { + 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); + } +}; + +// 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)> { + 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::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_), + Unwrap(invoker->p3_), 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)> { + 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); + } +}; + +// 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)> { + 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 || + 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); + return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), + Unwrap(invoker->p3_), 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)> { + 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); + } +}; + +// 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; + +// 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)> { + 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::false_type IsMethod; + + static R DoInvoke(InvokerStorageBase* base) { + StorageType* invoker = static_cast<StorageType*>(base); + return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), + Unwrap(invoker->p3_), Unwrap(invoker->p4_)); + } +}; + +// 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)> { + 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_)); + } +}; + +// 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)> { + 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::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_), + Unwrap(invoker->p3_), Unwrap(invoker->p4_), 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)> { + 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); + } +}; + +// 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)> { + 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 || + 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_), + Unwrap(invoker->p3_), Unwrap(invoker->p4_), 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)> { + 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); + } +}; + +// 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; + +// 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)> { + 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::false_type IsMethod; + + static R DoInvoke(InvokerStorageBase* base) { + StorageType* invoker = static_cast<StorageType*>(base); + return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), + Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_)); + } +}; + +// 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)> { + 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_)); + } +}; + +// 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)> { + 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 || + 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_), + Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_), 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)> { + 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); + } +}; + +// 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; + +// 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)> { + 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 || + 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_), + Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_), + Unwrap(invoker->p6_)); + } +}; + +// 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)> { + 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_)); + } +}; + +// 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. +// +// 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 +// of Run(). +// +// An alternate solution would be to merge FunctionTraitsN 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; + + + + InvokerStorage0(Sig f) + : f_(f) { + } + + virtual ~InvokerStorage0() { } + + Sig f_; +}; + +template <typename Sig, typename P1> +class InvokerStorage1 : public InvokerStorageBase { + public: + typedef InvokerStorage1 StorageType; + typedef FunctionTraits1<StorageType, Sig> FunctionTraits; + typedef typename FunctionTraits::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. + COMPILE_ASSERT(IsMethod::value || + !internal::UnsafeBindtoRefCountedArg<P1>::value, + p1_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!IsMethod::value || !is_array<P1>::value, + first_bound_argument_to_method_cannot_be_array); + + + InvokerStorage1(Sig f, const P1& p1) + : f_(f), p1_(static_cast<typename BindType<P1>::StorageType>(p1)) { + MaybeRefcount<IsMethod, P1>::AddRef(p1_); + } + + virtual ~InvokerStorage1() { + MaybeRefcount<IsMethod, P1>::Release(p1_); + } + + Sig f_; + typename BindType<P1>::StorageType p1_; +}; + +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; + + // For methods, we need to be careful for parameter 1. We skip the + // scoped_refptr check because the binder itself takes care of this. We also + // disallow binding of an array as the method's target object. + COMPILE_ASSERT(IsMethod::value || + !internal::UnsafeBindtoRefCountedArg<P1>::value, + p1_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!IsMethod::value || !is_array<P1>::value, + first_bound_argument_to_method_cannot_be_array); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P2>::value, + p2_is_refcounted_type_and_needs_scoped_refptr); + + + InvokerStorage2(Sig f, const P1& p1, const P2& p2) + : f_(f), p1_(static_cast<typename BindType<P1>::StorageType>(p1)), + p2_(static_cast<typename BindType<P2>::StorageType>(p2)) { + MaybeRefcount<IsMethod, P1>::AddRef(p1_); + } + + virtual ~InvokerStorage2() { + MaybeRefcount<IsMethod, P1>::Release(p1_); + } + + Sig f_; + typename BindType<P1>::StorageType p1_; + typename BindType<P2>::StorageType p2_; +}; + +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; + + // For methods, we need to be careful for parameter 1. We skip the + // scoped_refptr check because the binder itself takes care of this. We also + // disallow binding of an array as the method's target object. + COMPILE_ASSERT(IsMethod::value || + !internal::UnsafeBindtoRefCountedArg<P1>::value, + p1_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!IsMethod::value || !is_array<P1>::value, + first_bound_argument_to_method_cannot_be_array); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P2>::value, + p2_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P3>::value, + p3_is_refcounted_type_and_needs_scoped_refptr); + + + InvokerStorage3(Sig f, const P1& p1, const P2& p2, const P3& p3) + : f_(f), p1_(static_cast<typename BindType<P1>::StorageType>(p1)), + p2_(static_cast<typename BindType<P2>::StorageType>(p2)), + p3_(static_cast<typename BindType<P3>::StorageType>(p3)) { + MaybeRefcount<IsMethod, P1>::AddRef(p1_); + } + + virtual ~InvokerStorage3() { + MaybeRefcount<IsMethod, P1>::Release(p1_); + } + + Sig f_; + typename BindType<P1>::StorageType p1_; + typename BindType<P2>::StorageType p2_; + typename BindType<P3>::StorageType p3_; +}; + +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; + + // For methods, we need to be careful for parameter 1. We skip the + // scoped_refptr check because the binder itself takes care of this. We also + // disallow binding of an array as the method's target object. + COMPILE_ASSERT(IsMethod::value || + !internal::UnsafeBindtoRefCountedArg<P1>::value, + p1_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!IsMethod::value || !is_array<P1>::value, + first_bound_argument_to_method_cannot_be_array); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P2>::value, + p2_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P3>::value, + p3_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P4>::value, + p4_is_refcounted_type_and_needs_scoped_refptr); + + + InvokerStorage4(Sig f, const P1& p1, const P2& p2, const P3& p3, const P4& p4) + : f_(f), p1_(static_cast<typename BindType<P1>::StorageType>(p1)), + p2_(static_cast<typename BindType<P2>::StorageType>(p2)), + p3_(static_cast<typename BindType<P3>::StorageType>(p3)), + p4_(static_cast<typename BindType<P4>::StorageType>(p4)) { + MaybeRefcount<IsMethod, P1>::AddRef(p1_); + } + + virtual ~InvokerStorage4() { + MaybeRefcount<IsMethod, P1>::Release(p1_); + } + + Sig f_; + typename BindType<P1>::StorageType p1_; + typename BindType<P2>::StorageType p2_; + typename BindType<P3>::StorageType p3_; + typename BindType<P4>::StorageType p4_; +}; + +template <typename Sig, typename P1, typename P2, typename P3, typename P4, + typename P5> +class InvokerStorage5 : public InvokerStorageBase { + public: + typedef InvokerStorage5 StorageType; + typedef FunctionTraits5<StorageType, Sig> FunctionTraits; + typedef typename FunctionTraits::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. + COMPILE_ASSERT(IsMethod::value || + !internal::UnsafeBindtoRefCountedArg<P1>::value, + p1_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!IsMethod::value || !is_array<P1>::value, + first_bound_argument_to_method_cannot_be_array); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P2>::value, + p2_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P3>::value, + p3_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P4>::value, + p4_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P5>::value, + p5_is_refcounted_type_and_needs_scoped_refptr); + + + InvokerStorage5(Sig f, const P1& p1, const P2& p2, const P3& p3, + const P4& p4, const P5& p5) + : f_(f), p1_(static_cast<typename BindType<P1>::StorageType>(p1)), + p2_(static_cast<typename BindType<P2>::StorageType>(p2)), + p3_(static_cast<typename BindType<P3>::StorageType>(p3)), + p4_(static_cast<typename BindType<P4>::StorageType>(p4)), + p5_(static_cast<typename BindType<P5>::StorageType>(p5)) { + MaybeRefcount<IsMethod, P1>::AddRef(p1_); + } + + virtual ~InvokerStorage5() { + MaybeRefcount<IsMethod, P1>::Release(p1_); + } + + Sig f_; + typename BindType<P1>::StorageType p1_; + typename BindType<P2>::StorageType p2_; + typename BindType<P3>::StorageType p3_; + typename BindType<P4>::StorageType p4_; + typename BindType<P5>::StorageType p5_; +}; + +template <typename Sig, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6> +class InvokerStorage6 : public InvokerStorageBase { + public: + typedef InvokerStorage6 StorageType; + typedef FunctionTraits6<StorageType, Sig> FunctionTraits; + typedef typename FunctionTraits::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. + COMPILE_ASSERT(IsMethod::value || + !internal::UnsafeBindtoRefCountedArg<P1>::value, + p1_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!IsMethod::value || !is_array<P1>::value, + first_bound_argument_to_method_cannot_be_array); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P2>::value, + p2_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P3>::value, + p3_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P4>::value, + p4_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P5>::value, + p5_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P6>::value, + p6_is_refcounted_type_and_needs_scoped_refptr); + + + InvokerStorage6(Sig f, const P1& p1, const P2& p2, const P3& p3, + const P4& p4, const P5& p5, const P6& p6) + : f_(f), p1_(static_cast<typename BindType<P1>::StorageType>(p1)), + p2_(static_cast<typename BindType<P2>::StorageType>(p2)), + p3_(static_cast<typename BindType<P3>::StorageType>(p3)), + p4_(static_cast<typename BindType<P4>::StorageType>(p4)), + p5_(static_cast<typename BindType<P5>::StorageType>(p5)), + p6_(static_cast<typename BindType<P6>::StorageType>(p6)) { + MaybeRefcount<IsMethod, P1>::AddRef(p1_); + } + + virtual ~InvokerStorage6() { + MaybeRefcount<IsMethod, P1>::Release(p1_); + } + + Sig f_; + typename BindType<P1>::StorageType p1_; + typename BindType<P2>::StorageType p2_; + typename BindType<P3>::StorageType p3_; + typename BindType<P4>::StorageType p4_; + typename BindType<P5>::StorageType p5_; + typename BindType<P6>::StorageType p6_; +}; + +} // namespace internal +} // namespace base + +#endif // BASE_BIND_INTERNAL_H_ diff --git a/base/bind_internal.h.pump b/base/bind_internal.h.pump new file mode 100644 index 0000000..132b0db --- /dev/null +++ b/base/bind_internal.h.pump @@ -0,0 +1,237 @@ +$$ This is a pump file for generating file templates. Pump is a python +$$ script that is part of the Google Test suite of utilities. Description +$$ can be found here: +$$ +$$ http://code.google.com/p/googletest/wiki/PumpManual +$$ + +$var MAX_ARITY = 6 + +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_BIND_INTERNAL_H_ +#define BASE_BIND_INTERNAL_H_ +#pragma once + +#include "base/bind_helpers.h" +#include "base/callback_helpers.h" +#include "base/template_util.h" + +namespace base { +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 +// 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 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. +// +// 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. + +$range BOUND 0..MAX_ARITY +$for BOUND [[ + +template <typename StorageType, typename Sig> +struct FunctionTraits$(BOUND); + +$range ARITY 0..MAX_ARITY +$for ARITY [[ + +$var UNBOUND = ARITY - BOUND +$if UNBOUND >= 0 [[ + +$$ Variables for function traits generation. +$range ARG 1..ARITY +$range BOUND_ARG 1..BOUND +$range UNBOUND_ARG (ARITY - UNBOUND + 1)..ARITY + +$$ Variables for method traits generation. We are always short one arity since +$$ the first bound parameter is the object. +$var M_ARITY = ARITY - 1 +$range M_ARG 1..M_ARITY +$range M_BOUND_ARG 2..BOUND +$range M_UNBOUND_ARG (M_ARITY - UNBOUND + 1)..M_ARITY + +// Function: Arity $(ARITY) -> $(UNBOUND). +template <typename StorageType, typename R[[]] +$if ARITY > 0 [[,]][[]] +$for ARG , [[typename X$(ARG)]]> +struct FunctionTraits$(BOUND)<StorageType, R(*)($for ARG , [[X$(ARG)]])> { +$if ARITY > 0 [[ + + COMPILE_ASSERT( + !($for ARG || [[ is_non_const_reference<X$(ARG)>::value ]]), + do_not_bind_functions_with_nonconst_ref); + +]] + + typedef base::false_type IsMethod; + + static R DoInvoke(InvokerStorageBase* base[[]] +$if UNBOUND != 0 [[, ]][[]] +$for UNBOUND_ARG , [[const X$(UNBOUND_ARG)& x$(UNBOUND_ARG)]]) { + StorageType* invoker = static_cast<StorageType*>(base); + return invoker->f_($for BOUND_ARG , [[Unwrap(invoker->p$(BOUND_ARG)_)]][[]] +$$ Add comma if there are both boudn and unbound args. +$if UNBOUND > 0 [[$if BOUND > 0 [[, ]]]][[]] +$for UNBOUND_ARG , [[x$(UNBOUND_ARG)]]); + } +}; + +$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)]])> { +$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)]]); + } +}; + +// 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 +]] $$ for ARITY +]] $$ for BOUND + + +// 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 +// of Run(). +// +// An alternate solution would be to merge FunctionTraitsN and InvokerStorageN, +// but the generated code seemed harder to read. + +$for BOUND [[ +$range BOUND_ARG 1..BOUND + +template <typename Sig[[]] +$if BOUND > 0 [[, ]] +$for BOUND_ARG , [[typename P$(BOUND_ARG)]]> +class InvokerStorage$(BOUND) : public InvokerStorageBase { + public: + typedef InvokerStorage$(BOUND) StorageType; + typedef FunctionTraits$(BOUND)<StorageType, Sig> FunctionTraits; + typedef typename FunctionTraits::IsMethod IsMethod; + +$for BOUND_ARG [[ +$if BOUND_ARG == 1 [[ + + // For methods, we need to be careful for parameter 1. We skip the + // scoped_refptr check because the binder itself takes care of this. We also + // disallow binding of an array as the method's target object. + COMPILE_ASSERT(IsMethod::value || + !internal::UnsafeBindtoRefCountedArg<P$(BOUND_ARG)>::value, + p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr); + COMPILE_ASSERT(!IsMethod::value || !is_array<P$(BOUND_ARG)>::value, + first_bound_argument_to_method_cannot_be_array); +]] $else [[ + + COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P$(BOUND_ARG)>::value, + p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr); +]] $$ $if BOUND_ARG +]] $$ $for BOUND_ARG + + + + InvokerStorage$(BOUND)(Sig f +$if BOUND > 0 [[, ]] +$for BOUND_ARG , [[const P$(BOUND_ARG)& p$(BOUND_ARG)]]) + : f_(f)[[]] +$if BOUND == 0 [[ + { + +]] $else [[ +, $for BOUND_ARG , [[p$(BOUND_ARG)_(static_cast<typename BindType<P$(BOUND_ARG)>::StorageType>(p$(BOUND_ARG)))]] { + MaybeRefcount<IsMethod, P1>::AddRef(p1_); + +]] + } + + virtual ~InvokerStorage$(BOUND)() { +$if BOUND > 0 [[ + + MaybeRefcount<IsMethod, P1>::Release(p1_); + +]] + } + + Sig f_; + +$for BOUND_ARG [[ + typename BindType<P$(BOUND_ARG)>::StorageType p$(BOUND_ARG)_; + +]] +}; + +]] $$ for BOUND + +} // namespace internal +} // namespace base + +#endif // BASE_BIND_INTERNAL_H_ diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc new file mode 100644 index 0000000..47d971a --- /dev/null +++ b/base/bind_unittest.cc @@ -0,0 +1,597 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/bind.h" + +#if defined(BASE_CALLBACK_H_) +// We explicitly do not want to include callback.h so people are not tempted +// to use bind.h in a headerfile for getting the Callback types. +#error "base/bind.h should avoid pulling in callback.h by default." +#endif + +#include "base/callback.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::Mock; +using ::testing::Return; +using ::testing::StrictMock; + +namespace base { +namespace { + +class NoRef { + public: + NoRef() {} + + MOCK_METHOD0(VoidMethod0, void(void)); + MOCK_CONST_METHOD0(VoidConstMethod0, void(void)); + + MOCK_METHOD0(IntMethod0, int(void)); + MOCK_CONST_METHOD0(IntConstMethod0, int(void)); + + private: + // Particularly important in this test to ensure no copies are made. + DISALLOW_COPY_AND_ASSIGN(NoRef); +}; + +class HasRef : public NoRef { + public: + HasRef() {} + + MOCK_CONST_METHOD0(AddRef, void(void)); + MOCK_CONST_METHOD0(Release, bool(void)); + + private: + // Particularly important in this test to ensure no copies are made. + DISALLOW_COPY_AND_ASSIGN(HasRef); +}; + +static const int kParentValue = 1; +static const int kChildValue = 2; + +class Parent { + public: + void AddRef(void) const {} + void Release(void) const {} + virtual void VirtualSet() { value = kParentValue; } + void NonVirtualSet() { value = kParentValue; } + int value; +}; + +class Child : public Parent { + public: + virtual void VirtualSet() { value = kChildValue; } + void NonVirtualSet() { value = kChildValue; } +}; + +class NoRefParent { + public: + virtual void VirtualSet() { value = kParentValue; } + void NonVirtualSet() { value = kParentValue; } + int value; +}; + +class NoRefChild : public NoRefParent { + virtual void VirtualSet() { value = kChildValue; } + void NonVirtualSet() { value = kChildValue; } +}; + +// Used for probing the number of copies that occur if a type must be coerced +// during argument forwarding in the Run() methods. +struct DerivedCopyCounter { + DerivedCopyCounter(int* copies, int* assigns) + : copies_(copies), assigns_(assigns) { + } + int* copies_; + int* assigns_; +}; + +// Used for probing the number of copies in an argument. +class CopyCounter { + public: + CopyCounter(int* copies, int* assigns) + : copies_(copies), assigns_(assigns) { + } + + CopyCounter(const CopyCounter& other) + : copies_(other.copies_), + assigns_(other.assigns_) { + (*copies_)++; + } + + // Probing for copies from coerscion. + CopyCounter(const DerivedCopyCounter& other) + : copies_(other.copies_), + assigns_(other.assigns_) { + (*copies_)++; + } + + const CopyCounter& operator=(const CopyCounter& rhs) { + copies_ = rhs.copies_; + assigns_ = rhs.assigns_; + + if (assigns_) { + (*assigns_)++; + } + + return *this; + } + + int copies() const { + return *copies_; + } + + int assigns() const { + return *assigns_; + } + + private: + int* copies_; + int* assigns_; +}; + +// Some test functions that we can Bind to. +template <typename T> +T PolymorphicIdentity(T t) { + return t; +} + +template <typename T> +void VoidPolymorphic1(T t) { +} + +int Identity(int n) { + return n; +} + +int ArrayGet(const int array[], int n) { + return array[n]; +} + +int Sum(int a, int b, int c, int d, int e, int f) { + return a + b + c + d + e + f; +} + +const char* CStringIdentity(const char* s) { + return s; +} + +int GetCopies(const CopyCounter& counter) { + return counter.copies(); +} + +int UnwrapNoRefParent(NoRefParent p) { + return p.value; +} + +int UnwrapNoRefParentPtr(NoRefParent* p) { + return p->value; +} + +int UnwrapNoRefParentConstRef(const NoRefParent& p) { + return p.value; +} + +// Only useful in no-compile tests. +int UnwrapNoRefParentRef(Parent& p) { + return p.value; +} + +class BindTest : public ::testing::Test { + public: + BindTest() { + const_has_ref_ptr_ = &has_ref_; + const_no_ref_ptr_ = &no_ref_; + static_func_mock_ptr = &static_func_mock_; + } + + virtual ~BindTest() { + } + + static void VoidFunc0(void) { + static_func_mock_ptr->VoidMethod0(); + } + + static int IntFunc0(void) { return static_func_mock_ptr->IntMethod0(); } + + protected: + StrictMock<NoRef> no_ref_; + StrictMock<HasRef> has_ref_; + const HasRef* const_has_ref_ptr_; + const NoRef* const_no_ref_ptr_; + StrictMock<NoRef> static_func_mock_; + + // Used by the static functions to perform expectations. + static StrictMock<NoRef>* static_func_mock_ptr; + + private: + DISALLOW_COPY_AND_ASSIGN(BindTest); +}; + +StrictMock<NoRef>* BindTest::static_func_mock_ptr; + +// Ensure we can create unbound callbacks. We need this to be able to store +// them in class members that can be initialized later. +TEST_F(BindTest, DefaultConstruction) { + Callback<void(void)> c0; + Callback<void(int)> c1; + Callback<void(int,int)> c2; + Callback<void(int,int,int)> c3; + Callback<void(int,int,int,int)> c4; + Callback<void(int,int,int,int,int)> c5; + Callback<void(int,int,int,int,int,int)> c6; +} + +// Sanity check that we can instantiate a callback for each arity. +TEST_F(BindTest, ArityTest) { + Callback<int(void)> c0 = Bind(&Sum, 32, 16, 8, 4, 2, 1); + EXPECT_EQ(63, c0.Run()); + + Callback<int(int)> c1 = Bind(&Sum, 32, 16, 8, 4, 2); + EXPECT_EQ(75, c1.Run(13)); + + Callback<int(int,int)> c2 = Bind(&Sum, 32, 16, 8, 4); + EXPECT_EQ(85, c2.Run(13, 12)); + + Callback<int(int,int,int)> c3 = Bind(&Sum, 32, 16, 8); + EXPECT_EQ(92, c3.Run(13, 12, 11)); + + Callback<int(int,int,int,int)> c4 = Bind(&Sum, 32, 16); + EXPECT_EQ(94, c4.Run(13, 12, 11, 10)); + + Callback<int(int,int,int,int,int)> c5 = Bind(&Sum, 32); + EXPECT_EQ(87, c5.Run(13, 12, 11, 10, 9)); + + Callback<int(int,int,int,int,int,int)> c6 = Bind(&Sum); + EXPECT_EQ(69, c6.Run(13, 12, 11, 10, 9, 14)); +} + +// Function type support. +// - Normal function. +// - Method bound to non-const object. +// - Const method bound to non-const object. +// - Const method bound to const object. +// - Derived classes can be used with pointers to non-virtual base functions. +// - Derived classes can be used with pointers to virtual base functions (and +// preserve virtual dispatch). +TEST_F(BindTest, FunctionTypeSupport) { + EXPECT_CALL(static_func_mock_, VoidMethod0()); + EXPECT_CALL(has_ref_, AddRef()).Times(3); + EXPECT_CALL(has_ref_, Release()).Times(3); + EXPECT_CALL(has_ref_, VoidMethod0()); + EXPECT_CALL(has_ref_, VoidConstMethod0()).Times(2); + + Closure normal_cb = Bind(&VoidFunc0); + Closure method_cb = Bind(&HasRef::VoidMethod0, &has_ref_); + Closure const_method_nonconst_obj_cb = Bind(&HasRef::VoidConstMethod0, + &has_ref_); + Closure const_method_const_obj_cb = Bind(&HasRef::VoidConstMethod0, + const_has_ref_ptr_); + normal_cb.Run(); + method_cb.Run(); + const_method_nonconst_obj_cb.Run(); + const_method_const_obj_cb.Run(); + + Child child; + child.value = 0; + Closure virtual_set_cb = Bind(&Parent::VirtualSet, &child); + virtual_set_cb.Run(); + EXPECT_EQ(kChildValue, child.value); + + child.value = 0; + Closure non_virtual_set_cb = Bind(&Parent::NonVirtualSet, &child); + non_virtual_set_cb.Run(); + EXPECT_EQ(kParentValue, child.value); +} + +// Return value support. +// - Function with return value. +// - Method with return value. +// - Const method with return value. +TEST_F(BindTest, ReturnValues) { + EXPECT_CALL(static_func_mock_, IntMethod0()).WillOnce(Return(1337)); + EXPECT_CALL(has_ref_, AddRef()).Times(3); + EXPECT_CALL(has_ref_, Release()).Times(3); + EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(31337)); + EXPECT_CALL(has_ref_, IntConstMethod0()) + .WillOnce(Return(41337)) + .WillOnce(Return(51337)); + + Callback<int(void)> normal_cb = Bind(&IntFunc0); + Callback<int(void)> method_cb = Bind(&HasRef::IntMethod0, &has_ref_); + Callback<int(void)> const_method_nonconst_obj_cb = + Bind(&HasRef::IntConstMethod0, &has_ref_); + Callback<int(void)> const_method_const_obj_cb = + Bind(&HasRef::IntConstMethod0, const_has_ref_ptr_); + EXPECT_EQ(1337, normal_cb.Run()); + EXPECT_EQ(31337, method_cb.Run()); + EXPECT_EQ(41337, const_method_nonconst_obj_cb.Run()); + EXPECT_EQ(51337, const_method_const_obj_cb.Run()); +} + +// Argument binding tests. +// - Argument binding to primitive. +// - Argument binding to primitive pointer. +// - Argument binding to a literal integer. +// - Argument binding to a literal string. +// - Argument binding with template function. +// - Argument binding to an object. +// - Argument gets type converted. +// - Pointer argument gets converted. +// - Const Reference forces conversion. +TEST_F(BindTest, ArgumentBinding) { + int n = 2; + + Callback<int(void)> bind_primitive_cb = Bind(&Identity, n); + EXPECT_EQ(n, bind_primitive_cb.Run()); + + Callback<int*(void)> bind_primitive_pointer_cb = + Bind(&PolymorphicIdentity<int*>, &n); + EXPECT_EQ(&n, bind_primitive_pointer_cb.Run()); + + Callback<int(void)> bind_int_literal_cb = Bind(&Identity, 3); + EXPECT_EQ(3, bind_int_literal_cb.Run()); + + Callback<const char*(void)> bind_string_literal_cb = + Bind(&CStringIdentity, "hi"); + EXPECT_STREQ("hi", bind_string_literal_cb.Run()); + + Callback<int(void)> bind_template_function_cb = + Bind(&PolymorphicIdentity<int>, 4); + EXPECT_EQ(4, bind_template_function_cb.Run()); + + NoRefParent p; + p.value = 5; + Callback<int(void)> bind_object_cb = Bind(&UnwrapNoRefParent, p); + EXPECT_EQ(5, bind_object_cb.Run()); + + NoRefChild c; + c.value = 6; + Callback<int(void)> bind_promotes_cb = Bind(&UnwrapNoRefParent, c); + EXPECT_EQ(6, bind_promotes_cb.Run()); + + c.value = 7; + Callback<int(void)> bind_pointer_promotes_cb = + Bind(&UnwrapNoRefParentPtr, &c); + EXPECT_EQ(7, bind_pointer_promotes_cb.Run()); + + c.value = 8; + Callback<int(void)> bind_const_reference_promotes_cb = + Bind(&UnwrapNoRefParentConstRef, c); + EXPECT_EQ(8, bind_const_reference_promotes_cb.Run()); +} + +// Functions that take reference parameters. +// - Forced reference parameter type still stores a copy. +// - Forced const reference parameter type still stores a copy. +TEST_F(BindTest, ReferenceArgumentBinding) { + int n = 1; + int& ref_n = n; + const int& const_ref_n = n; + + Callback<int(void)> ref_copies_cb = Bind(&Identity, ref_n); + EXPECT_EQ(n, ref_copies_cb.Run()); + n++; + EXPECT_EQ(n - 1, ref_copies_cb.Run()); + + Callback<int(void)> const_ref_copies_cb = Bind(&Identity, const_ref_n); + EXPECT_EQ(n, const_ref_copies_cb.Run()); + n++; + EXPECT_EQ(n - 1, const_ref_copies_cb.Run()); +} + +// Check that we can pass in arrays and have them be stored as a pointer. +// - Array of values stores a pointer. +// - Array of const values stores a pointer. +TEST_F(BindTest, ArrayArgumentBinding) { + int array[4] = {1, 1, 1, 1}; + const int (*const_array_ptr)[4] = &array; + + Callback<int(void)> array_cb = Bind(&ArrayGet, array, 1); + EXPECT_EQ(1, array_cb.Run()); + + Callback<int(void)> const_array_cb = Bind(&ArrayGet, *const_array_ptr, 1); + EXPECT_EQ(1, const_array_cb.Run()); + + array[1] = 3; + EXPECT_EQ(3, array_cb.Run()); + EXPECT_EQ(3, const_array_cb.Run()); +} + +// Verify SupportsAddRefAndRelease correctly introspects the class type for +// AddRef() and Release(). +TEST_F(BindTest, SupportsAddRefAndRelease) { + EXPECT_TRUE(internal::SupportsAddRefAndRelease<HasRef>::value); + EXPECT_FALSE(internal::SupportsAddRefAndRelease<NoRef>::value); + + // StrictMock<T> is a derived class of T. So, we use StrictMock<HasRef> and + // StrictMock<NoRef> to test that SupportsAddRefAndRelease works over + // inheritance. + EXPECT_TRUE(internal::SupportsAddRefAndRelease<StrictMock<HasRef> >::value); + EXPECT_FALSE(internal::SupportsAddRefAndRelease<StrictMock<NoRef> >::value); +} + +// Unretained() wrapper support. +// - Method bound to Unretained() non-object. +// - Const method bound to Unretained() non-const object. +// - Const method bound to Unretained() const object. +TEST_F(BindTest, Unretained) { + EXPECT_CALL(no_ref_, VoidMethod0()); + EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2); + + Callback<void(void)> method_cb = + Bind(&NoRef::VoidMethod0, Unretained(&no_ref_)); + method_cb.Run(); + + Callback<void(void)> const_method_cb = + Bind(&NoRef::VoidConstMethod0, Unretained(&no_ref_)); + const_method_cb.Run(); + + Callback<void(void)> const_method_const_ptr_cb = + Bind(&NoRef::VoidConstMethod0, Unretained(const_no_ref_ptr_)); + const_method_const_ptr_cb.Run(); +} + +// ConstRef() wrapper support. +// - Binding w/o ConstRef takes a copy. +// - Binding a ConstRef takes a reference. +// - Binding ConstRef to a function ConstRef does not copy on invoke. +TEST_F(BindTest, ConstRef) { + int n = 1; + + Callback<int(void)> copy_cb = Bind(&Identity, n); + Callback<int(void)> const_ref_cb = Bind(&Identity, ConstRef(n)); + EXPECT_EQ(n, copy_cb.Run()); + EXPECT_EQ(n, const_ref_cb.Run()); + n++; + EXPECT_EQ(n - 1, copy_cb.Run()); + EXPECT_EQ(n, const_ref_cb.Run()); + + int copies = 0; + int assigns = 0; + CopyCounter counter(&copies, &assigns); + Callback<int(void)> all_const_ref_cb = + Bind(&GetCopies, ConstRef(counter)); + EXPECT_EQ(0, all_const_ref_cb.Run()); + EXPECT_EQ(0, copies); + EXPECT_EQ(0, assigns); +} + +// Argument Copy-constructor usage for non-reference parameters. +// - Bound arguments are only copied once. +// - Forwarded arguments are only copied once. +// - Forwarded arguments with coerscions are only copied twice (once for the +// coerscion, and one for the final dispatch). +TEST_F(BindTest, ArgumentCopies) { + int copies = 0; + int assigns = 0; + + CopyCounter counter(&copies, &assigns); + + Callback<void(void)> copy_cb = + Bind(&VoidPolymorphic1<CopyCounter>, counter); + EXPECT_GE(1, copies); + EXPECT_EQ(0, assigns); + + copies = 0; + assigns = 0; + Callback<void(CopyCounter)> forward_cb = + Bind(&VoidPolymorphic1<CopyCounter>); + forward_cb.Run(counter); + EXPECT_GE(1, copies); + EXPECT_EQ(0, assigns); + + copies = 0; + assigns = 0; + DerivedCopyCounter dervied(&copies, &assigns); + Callback<void(CopyCounter)> coerce_cb = + Bind(&VoidPolymorphic1<CopyCounter>); + coerce_cb.Run(dervied); + EXPECT_GE(2, copies); + EXPECT_EQ(0, assigns); +} + +// Callback construction and assignment tests. +// - Construction from an InvokerStorageHolder should not cause ref/deref. +// - Assignment from other callback should only cause one ref +// +// TODO(ajwong): Is there actually a way to test this? + +// No-compile tests. These should not compile. If they do, we are allowing +// error-prone, or incorrect behavior in the callback system. Uncomment the +// tests to check. +TEST_F(BindTest, NoCompile) { + // - Method bound to const-object. + // + // Only const methods should be allowed to work with const objects. + // + // Callback<void(void)> method_to_const_cb = + // Bind(&HasRef::VoidMethod0, const_has_ref_ptr_); + // method_to_const_cb.Run(); + + // - Method bound to non-refcounted object. + // - Const Method bound to non-refcounted object. + // + // We require refcounts unless you have Unretained(). + // + // Callback<void(void)> no_ref_cb = + // Bind(&NoRef::VoidMethod0, &no_ref_); + // no_ref_cb.Run(); + // Callback<void(void)> no_ref_const_cb = + // Bind(&NoRef::VoidConstMethod0, &no_ref_); + // no_ref_const_cb.Run(); + + // - Unretained() used with a refcounted object. + // + // If the object supports refcounts, unretaining it in the callback is a + // memory management contract break. + // Callback<void(void)> unretained_cb = + // Bind(&HasRef::VoidConstMethod0, Unretained(&has_ref_)); + // unretained_cb.Run(); + + // - Const argument used with non-const pointer parameter of same type. + // - Const argument used with non-const pointer parameter of super type. + // + // This is just a const-correctness check. + // + // const Parent* const_parent_ptr; + // const Child* const_child_ptr; + // Callback<Parent*(void)> pointer_same_cb = + // Bind(&PolymorphicIdentity<Parent*>, const_parent_ptr); + // pointer_same_cb.Run(); + // Callback<Parent*(void)> pointer_super_cb = + // Bind(&PolymorphicIdentity<Parent*>, const_child_ptr); + // pointer_super_cb.Run(); + + // - Construction of Callback<A> from Callback<B> if A is supertype of B. + // Specific example: Callback<void(void)> a; Callback<int(void)> b; a = b; + // + // While this is technically safe, most people aren't used to it when coding + // C++ so if this is happening, it is almost certainly an error. + // + // Callback<int(void)> cb_a0 = Bind(&Identity, 1); + // Callback<void(void)> cb_b0 = cb_a0; + + // - Assignment of Callback<A> from Callback<B> if A is supertype of B. + // See explanation above. + // + // Callback<int(void)> cb_a1 = Bind(&Identity, 1); + // Callback<void(void)> cb_b1; + // cb_a1 = cb_b1; + + // - Functions with reference parameters, unsupported. + // + // First, non-const reference parameters are disallowed by the Google + // style guide. Seconds, since we are doing argument forwarding it becomes + // very tricky to avoid copies, maintain const correctness, and not + // accidentally have the function be modifying a temporary, or a copy. + // + // NoRefParent p; + // Callback<int(Parent&)> ref_arg_cb = Bind(&UnwrapNoRefParentRef); + // ref_arg_cb.Run(p); + // Callback<int(void)> ref_cb = Bind(&UnwrapNoRefParentRef, p); + // ref_cb.Run(); + + // - A method should not be bindable with an array of objects. + // + // This is likely not wanted behavior. We specifically check for it though + // because it is possible, depending on how you implement prebinding, to + // implicitly convert an array type to a pointer type. + // + // HasRef p[10]; + // Callback<void(void)> method_bound_to_array_cb = + // Bind(&HasRef::VoidConstMethod0, p); + // method_bound_to_array_cb.Run(); + + // - Refcounted types should not be bound as a raw pointer. + // HasRef for_raw_ptr; + // Callback<void(void)> ref_count_as_raw_ptr = + // Bind(&VoidPolymorphic1<HasRef*>, &for_raw_ptr); + // ASSERT_EQ(&for_raw_ptr, ref_count_as_raw_ptr.Run()); + +} + +} // namespace +} // namespace base diff --git a/base/callback.h b/base/callback.h index e5ea771..05a7182 100644 --- a/base/callback.h +++ b/base/callback.h @@ -1,4 +1,9 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// This file was GENERATED by command: +// pump.py callback.h.pump +// DO NOT EDIT BY HAND!!! + + +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,249 +11,472 @@ #define BASE_CALLBACK_H_ #pragma once -#include "base/tuple.h" -#include "base/raw_scoped_refptr_mismatch_checker.h" - -// Callback -------------------------------------------------------------------- -// -// A Callback is like a Task but with unbound parameters. It is basically an -// object-oriented function pointer. -// -// Callbacks are designed to work with Tuples. A set of helper functions and -// classes is provided to hide the Tuple details from the consumer. Client -// code will generally work with the CallbackRunner base class, which merely -// provides a Run method and is returned by the New* functions. This allows -// users to not care which type of class implements the callback, only that it -// has a certain number and type of arguments. -// -// The implementation of this is done by CallbackImpl, which inherits -// CallbackStorage to store the data. This allows the storage of the data -// (requiring the class type T) to be hidden from users, who will want to call -// this regardless of the implementor's type T. -// -// Note that callbacks currently have no facility for cancelling or abandoning -// them. We currently handle this at a higher level for cases where this is -// necessary. The pointer in a callback must remain valid until the callback -// is made. -// -// Like Task, the callback executor is responsible for deleting the callback -// pointer once the callback has executed. -// -// Example client usage: -// void Object::DoStuff(int, string); -// Callback2<int, string>::Type* callback = -// NewCallback(obj, &Object::DoStuff); -// callback->Run(5, string("hello")); -// delete callback; -// or, equivalently, using tuples directly: -// CallbackRunner<Tuple2<int, string> >* callback = -// NewCallback(obj, &Object::DoStuff); -// callback->RunWithParams(MakeTuple(5, string("hello"))); -// -// There is also a 0-args version that returns a value. Example: -// int Object::GetNextInt(); -// CallbackWithReturnValue<int>::Type* callback = -// NewCallbackWithReturnValue(obj, &Object::GetNextInt); -// int next_int = callback->Run(); -// delete callback; - -// Base for all Callbacks that handles storage of the pointers. -template <class T, typename Method> -class CallbackStorage { - public: - CallbackStorage(T* obj, Method meth) : obj_(obj), meth_(meth) { - } - - protected: - T* obj_; - Method meth_; -}; +#include "base/callback_helpers.h" +#include "base/callback_old.h" -// Interface that is exposed to the consumer, that does the actual calling -// of the method. -template <typename Params> -class CallbackRunner { +// New, super-duper, unified Callback system. This will eventually replace +// NewRunnableMethod, NewRunnableFunction, CreateFunctor, and CreateCallback +// systems currently in the Chromium code base. +// +// WHAT IS THIS: +// +// The templated Callback class is a generalized function object. Together +// with the Bind() function in bind.h, they provide a type-safe method for +// performing currying of arguments, and creating a "closure." +// +// In programing languages, a closure is a first-class function where all its +// parameters have been bound (usually via currying). Closures are well +// suited for representing, and passing around a unit of delayed execution. +// They are used in Chromium code to schedule tasks on different MessageLoops. +// +// +// MEMORY MANAGEMENT AND PASSING +// +// The Callback objects themselves should be passed by const-reference, and +// stored by copy. They internally store their state via a refcounted class +// and thus do not need to be deleted. +// +// The reason to pass via a const-reference is to avoid unnecessary +// AddRef/Release pairs to the internal state. +// +// +// EXAMPLE USAGE: +// +// /* Binding a normal function. */ +// int Return5() { return 5; } +// base::Callback<int(int)> func_cb = base::Bind(&Return5); +// LOG(INFO) << func_cb.Run(5); // Prints 5. +// +// void PrintHi() { LOG(INFO) << "hi."; } +// base::Closure void_func_cb = base::Bind(&PrintHi); +// LOG(INFO) << void_func_cb.Run(); // Prints: hi. +// +// /* Binding a class method. */ +// class Ref : public RefCountedThreadSafe<Ref> { +// public: +// int Foo() { return 3; } +// void PrintBye() { LOG(INFO) << "bye."; } +// }; +// scoped_refptr<Ref> ref = new Ref(); +// base::Callback<int(void)> ref_cb = base::Bind(&Ref::Foo, ref.get()); +// LOG(INFO) << ref_cb.Run(); // Prints out 3. +// +// base::Closure void_ref_cb = base::Bind(&Ref::PrintBye, ref.get()); +// void_ref_cb.Run(); // Prints: bye. +// +// /* Binding a class method in a non-refcounted class. +// * +// * WARNING: You must be sure the referee outlives the callback! +// * This is particularly important if you post a closure to a +// * MessageLoop because then it becomes hard to know what the +// * lifetime of the referee needs to be. +// */ +// class NoRef { +// public: +// int Foo() { return 4; } +// void PrintWhy() { LOG(INFO) << "why???"; } +// }; +// NoRef no_ref; +// base::Callback<int(void)> base::no_ref_cb = +// base::Bind(&NoRef::Foo, base::Unretained(&no_ref)); +// LOG(INFO) << ref_cb.Run(); // Prints out 4. +// +// base::Closure void_no_ref_cb = +// base::Bind(&NoRef::PrintWhy, base::Unretained(no_ref)); +// void_no_ref_cb.Run(); // Prints: why??? +// +// /* Binding a reference. */ +// int Identity(int n) { return n; } +// int value = 1; +// base::Callback<int(void)> bound_copy_cb = base::Bind(&Identity, value); +// base::Callback<int(void)> bound_ref_cb = +// base::Bind(&Identity, base::ConstRef(value)); +// LOG(INFO) << bound_copy_cb.Run(); // Prints 1. +// LOG(INFO) << bound_ref_cb.Run(); // Prints 1. +// value = 2; +// LOG(INFO) << bound_copy_cb.Run(); // Prints 1. +// LOG(INFO) << bound_ref_cb.Run(); // Prints 2. +// +// +// WHERE IS THIS DESIGN FROM: +// +// The design Callback and Bind is heavily influenced by C++'s +// tr1::function/tr1::bind, and by the "Google Callback" system used inside +// Google. +// +// +// HOW THE IMPLEMENTATION WORKS: +// +// There are three main components to the system: +// 1) The Callback classes. +// 2) The Bind() functions. +// 3) The arguments wrappers (eg., Unretained() and ConstRef()). +// +// The Callback classes represent a generic function pointer. Internally, +// it stores a refcounted piece of state that represents the target function +// and all its bound parameters. Each Callback specialization has a templated +// constructor that takes an InvokerStorageHolder<> object. In the context of +// the constructor, the static type of this InvokerStorageHolder<> object +// uniquely identifies the function it is representing, all its bound +// parameters, and a DoInvoke() that is capable of invoking the target. +// +// Callback's constructor is takes the InvokerStorageHolder<> that has the +// full static type and erases the target function type, and the bound +// parameters. It does this by storing a pointer to the specific DoInvoke() +// function, and upcasting the state of InvokerStorageHolder<> to a +// InvokerStorageBase. This is safe as long as this InvokerStorageBase pointer +// is only used with the stored DoInvoke() pointer. +// +// To create InvokerStorageHolder<> objects, we use the Bind() functions. +// These functions, along with a set of internal templates, are reponsible for +// +// - Unwrapping the function signature into return type, and parameters +// - Determining the number of parameters that are bound +// - Creating the storage for the bound parameters +// - Performing compile-time asserts to avoid error-prone behavior +// - Returning an InvokerStorageHolder<> with an DoInvoke() that has an arity +// matching the number of unbound parameters, and knows the correct +// refcounting semantics for the target object if we are binding a class +// method. +// +// The Bind functions do the above using type-inference, and template +// specializations. +// +// By default Bind() will store copies of all bound parameters, and attempt +// to refcount a target object if the function being bound is a class method. +// +// To change this behavior, we introduce a set of argument wrappers +// (eg. Unretained(), and ConstRef()). These are simple container templates +// that are passed by value, and wrap a pointer to argument. See the +// file-level comment in base/bind_helpers.h for more info. +// +// These types are passed to the Unwrap() functions, and the MaybeRefcount() +// functions respectively to modify the behavior of Bind(). The Unwrap() +// and MaybeRefcount() functions change behavior by doing partial +// specialization based on whether or not a parameter is a wrapper type. +// +// ConstRef() is similar to tr1::cref. Unretained() is specific to Chromium. +// +// +// WHY NOT TR1 FUNCTION/BIND? +// +// Direct use of tr1::function and tr1::bind was considered, but ultimately +// rejected because of the number of copy constructors invocations involved +// in the binding of arguments during construction, and the forwarding of +// arguments during invocation. These copies will no longer be an issue in +// C++0x because C++0x will support rvalue reference allowing for the compiler +// to avoid these copies. However, waiting for C++0x is not an option. +// +// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the +// tr1::bind call itself will invoke a non-trivial copy constructor three times +// for each bound parameter. Also, each when passing a tr1::function, each +// bound argument will be copied again. +// +// In addition to the copies taken at binding and invocation, copying a +// tr1::function causes a copy to be made of all the bound parameters and +// state. +// +// Furthermore, in Chromium, it is desirable for the Callback to take a +// reference on a target object when representing a class method call. This +// is not supported by tr1. +// +// Lastly, tr1::function and tr1::bind has a more general and flexible API. +// This includes things like argument reordering by use of +// tr1::bind::placeholder, support for non-const reference parameters, and some +// limited amount of subtyping of the tr1::function object (eg., +// tr1::function<int(int)> is convertible to tr1::function<void(int)>). +// +// These are not features that are required in Chromium. Some of them, such as +// allowing for reference parameters, and subtyping of functions, may actually +// because a source of errors. Removing support for these features actually +// allows for a simpler implementation, and a terser Currying API. +// +// +// WHY NOT GOOGLE CALLBACKS? +// +// The Google callback system also does not support refcounting. Furthermore, +// its implementation has a number of strange edge cases with respect to type +// conversion of its arguments. In particular, the argument's constness must +// at times match exactly the function signature, or the type-inference might +// break. Given the above, writing a custom solution was easier. +// +// +// MISSING FUNCTIONALITY +// - Invoking the return of Bind. Bind(&foo).Run() does not work; +// - Binding arrays to functions that take a non-const pointer. +// Example: +// void Foo(const char* ptr); +// void Bar(char* ptr); +// Bind(&Foo, "test"); +// Bind(&Bar, "test"); // This fails because ptr is not const. + +namespace base { + +// First, we forward declare the Callback class template. This informs the +// compiler that the template only has 1 type parameter which is the function +// signature that the Callback is representing. +// +// After this, create template specializations for 0-6 parameters. Note that +// even though the template typelist grows, the specialization still +// only has one type: the function signature. +template <typename Sig> +class Callback; + +template <typename R> +class Callback<R(void)> { public: - typedef Params TupleType; - - virtual ~CallbackRunner() {} - virtual void RunWithParams(const Params& params) = 0; - - // Convenience functions so callers don't have to deal with Tuples. - inline void Run() { - RunWithParams(Tuple0()); + typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*); + + Callback() : polymorphic_invoke_(NULL) { } + + // We pass InvokerStorageHolder by const ref to avoid incurring an + // unnecessary AddRef/Unref pair even though we will modify the object. + // We cannot use a normal reference because the compiler will warn + // since this is often used on a return value, which is a temporary. + // + // Note that this constructor CANNOT be explicit, and that Bind() CANNOT + // return the exact Callback<> type. See base/bind.h for details. + template <typename T> + Callback(const internal::InvokerStorageHolder<T>& invoker_holder) + : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) { + invoker_storage_.swap(invoker_holder.invoker_storage_); } - template <typename Arg1> - inline void Run(const Arg1& a) { - RunWithParams(Params(a)); + R Run(void) const { + return polymorphic_invoke_(invoker_storage_.get()); } - template <typename Arg1, typename Arg2> - inline void Run(const Arg1& a, const Arg2& b) { - RunWithParams(Params(a, b)); - } + private: + scoped_refptr<internal::InvokerStorageBase> invoker_storage_; + PolymorphicInvoke polymorphic_invoke_; +}; - template <typename Arg1, typename Arg2, typename Arg3> - inline void Run(const Arg1& a, const Arg2& b, const Arg3& c) { - RunWithParams(Params(a, b, c)); +template <typename R, typename A1> +class Callback<R(A1)> { + public: + typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&); + + Callback() : polymorphic_invoke_(NULL) { } + + // We pass InvokerStorageHolder by const ref to avoid incurring an + // unnecessary AddRef/Unref pair even though we will modify the object. + // We cannot use a normal reference because the compiler will warn + // since this is often used on a return value, which is a temporary. + // + // Note that this constructor CANNOT be explicit, and that Bind() CANNOT + // return the exact Callback<> type. See base/bind.h for details. + template <typename T> + Callback(const internal::InvokerStorageHolder<T>& invoker_holder) + : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) { + invoker_storage_.swap(invoker_holder.invoker_storage_); } - template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> - inline void Run(const Arg1& a, const Arg2& b, const Arg3& c, const Arg4& d) { - RunWithParams(Params(a, b, c, d)); + R Run(const A1& a1) const { + return polymorphic_invoke_(invoker_storage_.get(), a1); } - template <typename Arg1, typename Arg2, typename Arg3, - typename Arg4, typename Arg5> - inline void Run(const Arg1& a, const Arg2& b, const Arg3& c, - const Arg4& d, const Arg5& e) { - RunWithParams(Params(a, b, c, d, e)); - } + private: + scoped_refptr<internal::InvokerStorageBase> invoker_storage_; + PolymorphicInvoke polymorphic_invoke_; }; -template <class T, typename Method, typename Params> -class CallbackImpl : public CallbackStorage<T, Method>, - public CallbackRunner<Params> { +template <typename R, typename A1, typename A2> +class Callback<R(A1, A2)> { public: - CallbackImpl(T* obj, Method meth) : CallbackStorage<T, Method>(obj, meth) { + typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&, + const A2&); + + Callback() : polymorphic_invoke_(NULL) { } + + // We pass InvokerStorageHolder by const ref to avoid incurring an + // unnecessary AddRef/Unref pair even though we will modify the object. + // We cannot use a normal reference because the compiler will warn + // since this is often used on a return value, which is a temporary. + // + // Note that this constructor CANNOT be explicit, and that Bind() CANNOT + // return the exact Callback<> type. See base/bind.h for details. + template <typename T> + Callback(const internal::InvokerStorageHolder<T>& invoker_holder) + : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) { + invoker_storage_.swap(invoker_holder.invoker_storage_); } - virtual void RunWithParams(const Params& params) { - // use "this->" to force C++ to look inside our templatized base class; see - // Effective C++, 3rd Ed, item 43, p210 for details. - DispatchToMethod(this->obj_, this->meth_, params); + + R Run(const A1& a1, + const A2& a2) const { + return polymorphic_invoke_(invoker_storage_.get(), a1, + a2); } -}; -// 0-arg implementation -struct Callback0 { - typedef CallbackRunner<Tuple0> Type; + private: + scoped_refptr<internal::InvokerStorageBase> invoker_storage_; + PolymorphicInvoke polymorphic_invoke_; }; -template <class T> -typename Callback0::Type* NewCallback(T* object, void (T::*method)()) { - return new CallbackImpl<T, void (T::*)(), Tuple0 >(object, method); -} - -// 1-arg implementation -template <typename Arg1> -struct Callback1 { - typedef CallbackRunner<Tuple1<Arg1> > Type; -}; +template <typename R, typename A1, typename A2, typename A3> +class Callback<R(A1, A2, A3)> { + public: + typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&, + const A2&, + const A3&); + + Callback() : polymorphic_invoke_(NULL) { } + + // We pass InvokerStorageHolder by const ref to avoid incurring an + // unnecessary AddRef/Unref pair even though we will modify the object. + // We cannot use a normal reference because the compiler will warn + // since this is often used on a return value, which is a temporary. + // + // Note that this constructor CANNOT be explicit, and that Bind() CANNOT + // return the exact Callback<> type. See base/bind.h for details. + template <typename T> + Callback(const internal::InvokerStorageHolder<T>& invoker_holder) + : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) { + invoker_storage_.swap(invoker_holder.invoker_storage_); + } -template <class T, typename Arg1> -typename Callback1<Arg1>::Type* NewCallback(T* object, - void (T::*method)(Arg1)) { - return new CallbackImpl<T, void (T::*)(Arg1), Tuple1<Arg1> >(object, method); -} + R Run(const A1& a1, + const A2& a2, + const A3& a3) const { + return polymorphic_invoke_(invoker_storage_.get(), a1, + a2, + a3); + } -// 2-arg implementation -template <typename Arg1, typename Arg2> -struct Callback2 { - typedef CallbackRunner<Tuple2<Arg1, Arg2> > Type; + private: + scoped_refptr<internal::InvokerStorageBase> invoker_storage_; + PolymorphicInvoke polymorphic_invoke_; }; -template <class T, typename Arg1, typename Arg2> -typename Callback2<Arg1, Arg2>::Type* NewCallback( - T* object, - void (T::*method)(Arg1, Arg2)) { - return new CallbackImpl<T, void (T::*)(Arg1, Arg2), - Tuple2<Arg1, Arg2> >(object, method); -} - -// 3-arg implementation -template <typename Arg1, typename Arg2, typename Arg3> -struct Callback3 { - typedef CallbackRunner<Tuple3<Arg1, Arg2, Arg3> > Type; -}; +template <typename R, typename A1, typename A2, typename A3, typename A4> +class Callback<R(A1, A2, A3, A4)> { + public: + typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&, + const A2&, + const A3&, + const A4&); + + Callback() : polymorphic_invoke_(NULL) { } + + // We pass InvokerStorageHolder by const ref to avoid incurring an + // unnecessary AddRef/Unref pair even though we will modify the object. + // We cannot use a normal reference because the compiler will warn + // since this is often used on a return value, which is a temporary. + // + // Note that this constructor CANNOT be explicit, and that Bind() CANNOT + // return the exact Callback<> type. See base/bind.h for details. + template <typename T> + Callback(const internal::InvokerStorageHolder<T>& invoker_holder) + : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) { + invoker_storage_.swap(invoker_holder.invoker_storage_); + } -template <class T, typename Arg1, typename Arg2, typename Arg3> -typename Callback3<Arg1, Arg2, Arg3>::Type* NewCallback( - T* object, - void (T::*method)(Arg1, Arg2, Arg3)) { - return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3), - Tuple3<Arg1, Arg2, Arg3> >(object, method); -} - -// 4-arg implementation -template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> -struct Callback4 { - typedef CallbackRunner<Tuple4<Arg1, Arg2, Arg3, Arg4> > Type; -}; + R Run(const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4) const { + return polymorphic_invoke_(invoker_storage_.get(), a1, + a2, + a3, + a4); + } -template <class T, typename Arg1, typename Arg2, typename Arg3, typename Arg4> -typename Callback4<Arg1, Arg2, Arg3, Arg4>::Type* NewCallback( - T* object, - void (T::*method)(Arg1, Arg2, Arg3, Arg4)) { - return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3, Arg4), - Tuple4<Arg1, Arg2, Arg3, Arg4> >(object, method); -} - -// 5-arg implementation -template <typename Arg1, typename Arg2, typename Arg3, - typename Arg4, typename Arg5> -struct Callback5 { - typedef CallbackRunner<Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> > Type; + private: + scoped_refptr<internal::InvokerStorageBase> invoker_storage_; + PolymorphicInvoke polymorphic_invoke_; }; -template <class T, typename Arg1, typename Arg2, - typename Arg3, typename Arg4, typename Arg5> -typename Callback5<Arg1, Arg2, Arg3, Arg4, Arg5>::Type* NewCallback( - T* object, - void (T::*method)(Arg1, Arg2, Arg3, Arg4, Arg5)) { - return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3, Arg4, Arg5), - Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> >(object, method); -} - -// An UnboundMethod is a wrapper for a method where the actual object is -// provided at Run dispatch time. -template <class T, class Method, class Params> -class UnboundMethod { +template <typename R, typename A1, typename A2, typename A3, typename A4, + typename A5> +class Callback<R(A1, A2, A3, A4, A5)> { public: - UnboundMethod(Method m, const Params& p) : m_(m), p_(p) { - COMPILE_ASSERT( - (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value), - badunboundmethodparams); + typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&, + const A2&, + const A3&, + const A4&, + const A5&); + + Callback() : polymorphic_invoke_(NULL) { } + + // We pass InvokerStorageHolder by const ref to avoid incurring an + // unnecessary AddRef/Unref pair even though we will modify the object. + // We cannot use a normal reference because the compiler will warn + // since this is often used on a return value, which is a temporary. + // + // Note that this constructor CANNOT be explicit, and that Bind() CANNOT + // return the exact Callback<> type. See base/bind.h for details. + template <typename T> + Callback(const internal::InvokerStorageHolder<T>& invoker_holder) + : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) { + invoker_storage_.swap(invoker_holder.invoker_storage_); } - void Run(T* obj) const { - DispatchToMethod(obj, m_, p_); + + R Run(const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5) const { + return polymorphic_invoke_(invoker_storage_.get(), a1, + a2, + a3, + a4, + a5); } - private: - Method m_; - Params p_; -}; -// Return value implementation with no args. -template <typename ReturnValue> -struct CallbackWithReturnValue { - class Type { - public: - virtual ~Type() {} - virtual ReturnValue Run() = 0; - }; + private: + scoped_refptr<internal::InvokerStorageBase> invoker_storage_; + PolymorphicInvoke polymorphic_invoke_; }; -template <class T, typename Method, typename ReturnValue> -class CallbackWithReturnValueImpl - : public CallbackStorage<T, Method>, - public CallbackWithReturnValue<ReturnValue>::Type { +template <typename R, typename A1, typename A2, typename A3, typename A4, + typename A5, typename A6> +class Callback<R(A1, A2, A3, A4, A5, A6)> { public: - CallbackWithReturnValueImpl(T* obj, Method meth) - : CallbackStorage<T, Method>(obj, meth) {} + typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&, + const A2&, + const A3&, + const A4&, + const A5&, + const A6&); + + Callback() : polymorphic_invoke_(NULL) { } + + // We pass InvokerStorageHolder by const ref to avoid incurring an + // unnecessary AddRef/Unref pair even though we will modify the object. + // We cannot use a normal reference because the compiler will warn + // since this is often used on a return value, which is a temporary. + // + // Note that this constructor CANNOT be explicit, and that Bind() CANNOT + // return the exact Callback<> type. See base/bind.h for details. + template <typename T> + Callback(const internal::InvokerStorageHolder<T>& invoker_holder) + : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) { + invoker_storage_.swap(invoker_holder.invoker_storage_); + } - virtual ReturnValue Run() { - return (this->obj_->*(this->meth_))(); + R Run(const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5, + const A6& a6) const { + return polymorphic_invoke_(invoker_storage_.get(), a1, + a2, + a3, + a4, + a5, + a6); } - protected: - virtual ~CallbackWithReturnValueImpl() {} + private: + scoped_refptr<internal::InvokerStorageBase> invoker_storage_; + PolymorphicInvoke polymorphic_invoke_; }; -template <class T, typename ReturnValue> -typename CallbackWithReturnValue<ReturnValue>::Type* -NewCallbackWithReturnValue(T* object, ReturnValue (T::*method)()) { - return new CallbackWithReturnValueImpl<T, ReturnValue (T::*)(), ReturnValue>( - object, method); -} + +// Syntactic sugar to make Callbacks<void(void)> easier to declare since it +// will be used in a lot of APIs with delayed execution. +typedef Callback<void(void)> Closure; + +} // namespace base #endif // BASE_CALLBACK_H diff --git a/base/callback.h.pump b/base/callback.h.pump new file mode 100644 index 0000000..9fc4b0b --- /dev/null +++ b/base/callback.h.pump @@ -0,0 +1,291 @@ +$$ This is a pump file for generating file templates. Pump is a python +$$ script that is part of the Google Test suite of utilities. Description +$$ can be found here: +$$ +$$ http://code.google.com/p/googletest/wiki/PumpManual +$$ + +$var MAX_ARITY = 6 + +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_CALLBACK_H_ +#define BASE_CALLBACK_H_ +#pragma once + +#include "base/callback_helpers.h" +#include "base/callback_old.h" + +// New, super-duper, unified Callback system. This will eventually replace +// NewRunnableMethod, NewRunnableFunction, CreateFunctor, and CreateCallback +// systems currently in the Chromium code base. +// +// WHAT IS THIS: +// +// The templated Callback class is a generalized function object. Together +// with the Bind() function in bind.h, they provide a type-safe method for +// performing currying of arguments, and creating a "closure." +// +// In programing languages, a closure is a first-class function where all its +// parameters have been bound (usually via currying). Closures are well +// suited for representing, and passing around a unit of delayed execution. +// They are used in Chromium code to schedule tasks on different MessageLoops. +// +// +// MEMORY MANAGEMENT AND PASSING +// +// The Callback objects themselves should be passed by const-reference, and +// stored by copy. They internally store their state via a refcounted class +// and thus do not need to be deleted. +// +// The reason to pass via a const-reference is to avoid unnecessary +// AddRef/Release pairs to the internal state. +// +// +// EXAMPLE USAGE: +// +// /* Binding a normal function. */ +// int Return5() { return 5; } +// base::Callback<int(int)> func_cb = base::Bind(&Return5); +// LOG(INFO) << func_cb.Run(5); // Prints 5. +// +// void PrintHi() { LOG(INFO) << "hi."; } +// base::Closure void_func_cb = base::Bind(&PrintHi); +// LOG(INFO) << void_func_cb.Run(); // Prints: hi. +// +// /* Binding a class method. */ +// class Ref : public RefCountedThreadSafe<Ref> { +// public: +// int Foo() { return 3; } +// void PrintBye() { LOG(INFO) << "bye."; } +// }; +// scoped_refptr<Ref> ref = new Ref(); +// base::Callback<int(void)> ref_cb = base::Bind(&Ref::Foo, ref.get()); +// LOG(INFO) << ref_cb.Run(); // Prints out 3. +// +// base::Closure void_ref_cb = base::Bind(&Ref::PrintBye, ref.get()); +// void_ref_cb.Run(); // Prints: bye. +// +// /* Binding a class method in a non-refcounted class. +// * +// * WARNING: You must be sure the referee outlives the callback! +// * This is particularly important if you post a closure to a +// * MessageLoop because then it becomes hard to know what the +// * lifetime of the referee needs to be. +// */ +// class NoRef { +// public: +// int Foo() { return 4; } +// void PrintWhy() { LOG(INFO) << "why???"; } +// }; +// NoRef no_ref; +// base::Callback<int(void)> base::no_ref_cb = +// base::Bind(&NoRef::Foo, base::Unretained(&no_ref)); +// LOG(INFO) << ref_cb.Run(); // Prints out 4. +// +// base::Closure void_no_ref_cb = +// base::Bind(&NoRef::PrintWhy, base::Unretained(no_ref)); +// void_no_ref_cb.Run(); // Prints: why??? +// +// /* Binding a reference. */ +// int Identity(int n) { return n; } +// int value = 1; +// base::Callback<int(void)> bound_copy_cb = base::Bind(&Identity, value); +// base::Callback<int(void)> bound_ref_cb = +// base::Bind(&Identity, base::ConstRef(value)); +// LOG(INFO) << bound_copy_cb.Run(); // Prints 1. +// LOG(INFO) << bound_ref_cb.Run(); // Prints 1. +// value = 2; +// LOG(INFO) << bound_copy_cb.Run(); // Prints 1. +// LOG(INFO) << bound_ref_cb.Run(); // Prints 2. +// +// +// WHERE IS THIS DESIGN FROM: +// +// The design Callback and Bind is heavily influenced by C++'s +// tr1::function/tr1::bind, and by the "Google Callback" system used inside +// Google. +// +// +// HOW THE IMPLEMENTATION WORKS: +// +// There are three main components to the system: +// 1) The Callback classes. +// 2) The Bind() functions. +// 3) The arguments wrappers (eg., Unretained() and ConstRef()). +// +// The Callback classes represent a generic function pointer. Internally, +// it stores a refcounted piece of state that represents the target function +// and all its bound parameters. Each Callback specialization has a templated +// constructor that takes an InvokerStorageHolder<> object. In the context of +// the constructor, the static type of this InvokerStorageHolder<> object +// uniquely identifies the function it is representing, all its bound +// parameters, and a DoInvoke() that is capable of invoking the target. +// +// Callback's constructor is takes the InvokerStorageHolder<> that has the +// full static type and erases the target function type, and the bound +// parameters. It does this by storing a pointer to the specific DoInvoke() +// function, and upcasting the state of InvokerStorageHolder<> to a +// InvokerStorageBase. This is safe as long as this InvokerStorageBase pointer +// is only used with the stored DoInvoke() pointer. +// +// To create InvokerStorageHolder<> objects, we use the Bind() functions. +// These functions, along with a set of internal templates, are reponsible for +// +// - Unwrapping the function signature into return type, and parameters +// - Determining the number of parameters that are bound +// - Creating the storage for the bound parameters +// - Performing compile-time asserts to avoid error-prone behavior +// - Returning an InvokerStorageHolder<> with an DoInvoke() that has an arity +// matching the number of unbound parameters, and knows the correct +// refcounting semantics for the target object if we are binding a class +// method. +// +// The Bind functions do the above using type-inference, and template +// specializations. +// +// By default Bind() will store copies of all bound parameters, and attempt +// to refcount a target object if the function being bound is a class method. +// +// To change this behavior, we introduce a set of argument wrappers +// (eg. Unretained(), and ConstRef()). These are simple container templates +// that are passed by value, and wrap a pointer to argument. See the +// file-level comment in base/bind_helpers.h for more info. +// +// These types are passed to the Unwrap() functions, and the MaybeRefcount() +// functions respectively to modify the behavior of Bind(). The Unwrap() +// and MaybeRefcount() functions change behavior by doing partial +// specialization based on whether or not a parameter is a wrapper type. +// +// ConstRef() is similar to tr1::cref. Unretained() is specific to Chromium. +// +// +// WHY NOT TR1 FUNCTION/BIND? +// +// Direct use of tr1::function and tr1::bind was considered, but ultimately +// rejected because of the number of copy constructors invocations involved +// in the binding of arguments during construction, and the forwarding of +// arguments during invocation. These copies will no longer be an issue in +// C++0x because C++0x will support rvalue reference allowing for the compiler +// to avoid these copies. However, waiting for C++0x is not an option. +// +// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the +// tr1::bind call itself will invoke a non-trivial copy constructor three times +// for each bound parameter. Also, each when passing a tr1::function, each +// bound argument will be copied again. +// +// In addition to the copies taken at binding and invocation, copying a +// tr1::function causes a copy to be made of all the bound parameters and +// state. +// +// Furthermore, in Chromium, it is desirable for the Callback to take a +// reference on a target object when representing a class method call. This +// is not supported by tr1. +// +// Lastly, tr1::function and tr1::bind has a more general and flexible API. +// This includes things like argument reordering by use of +// tr1::bind::placeholder, support for non-const reference parameters, and some +// limited amount of subtyping of the tr1::function object (eg., +// tr1::function<int(int)> is convertible to tr1::function<void(int)>). +// +// These are not features that are required in Chromium. Some of them, such as +// allowing for reference parameters, and subtyping of functions, may actually +// because a source of errors. Removing support for these features actually +// allows for a simpler implementation, and a terser Currying API. +// +// +// WHY NOT GOOGLE CALLBACKS? +// +// The Google callback system also does not support refcounting. Furthermore, +// its implementation has a number of strange edge cases with respect to type +// conversion of its arguments. In particular, the argument's constness must +// at times match exactly the function signature, or the type-inference might +// break. Given the above, writing a custom solution was easier. +// +// +// MISSING FUNCTIONALITY +// - Invoking the return of Bind. Bind(&foo).Run() does not work; +// - Binding arrays to functions that take a non-const pointer. +// Example: +// void Foo(const char* ptr); +// void Bar(char* ptr); +// Bind(&Foo, "test"); +// Bind(&Bar, "test"); // This fails because ptr is not const. + +namespace base { + +// First, we forward declare the Callback class template. This informs the +// compiler that the template only has 1 type parameter which is the function +// signature that the Callback is representing. +// +// After this, create template specializations for 0-$(MAX_ARITY) parameters. Note that +// even though the template typelist grows, the specialization still +// only has one type: the function signature. +template <typename Sig> +class Callback; + + +$range ARITY 0..MAX_ARITY +$for ARITY [[ +$range ARG 1..ARITY + +$if ARITY == 0 [[ +template <typename R> +class Callback<R(void)> { +]] $else [[ +template <typename R, $for ARG , [[typename A$(ARG)]]> +class Callback<R($for ARG , [[A$(ARG)]])> { +]] + + public: + typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*[[]] +$if ARITY != 0 [[, ]] +$for ARG , + [[const A$(ARG)&]]); + + Callback() : polymorphic_invoke_(NULL) { } + + // We pass InvokerStorageHolder by const ref to avoid incurring an + // unnecessary AddRef/Unref pair even though we will modify the object. + // We cannot use a normal reference because the compiler will warn + // since this is often used on a return value, which is a temporary. + // + // Note that this constructor CANNOT be explicit, and that Bind() CANNOT + // return the exact Callback<> type. See base/bind.h for details. + template <typename T> + Callback(const internal::InvokerStorageHolder<T>& invoker_holder) + : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) { + invoker_storage_.swap(invoker_holder.invoker_storage_); + } + + +$if ARITY == 0 [[ + R Run(void) const { +]] $else [[ + R Run($for ARG , + [[const A$(ARG)& a$(ARG)]]) const { +]] + + return polymorphic_invoke_(invoker_storage_.get()[[]] +$if ARITY != 0 [[, ]] +$for ARG , + [[a$(ARG)]]); + } + + private: + scoped_refptr<internal::InvokerStorageBase> invoker_storage_; + PolymorphicInvoke polymorphic_invoke_; +}; + + +]] $$ for ARITY + +// Syntactic sugar to make Callbacks<void(void)> easier to declare since it +// will be used in a lot of APIs with delayed execution. +typedef Callback<void(void)> Closure; + +} // namespace base + +#endif // BASE_CALLBACK_H diff --git a/base/callback_helpers.h b/base/callback_helpers.h new file mode 100644 index 0000000..86b0df1 --- /dev/null +++ b/base/callback_helpers.h @@ -0,0 +1,55 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains utility functions and classes that help the +// implementation, and management of the Callback objects. + +#ifndef BASE_CALLBACK_HELPERS_H_ +#define BASE_CALLBACK_HELPERS_H_ +#pragma once + +#include "base/ref_counted.h" + +namespace base { +namespace internal { + +// InvokerStorageBase is used to provide an opaque handle that the Callback +// class can use to represent a function object with bound arguments. It +// behaves as an existential type that is used by a corresponding +// DoInvoke function to perform the function execution. This allows +// us to shield the Callback class from the types of the bound argument via +// "type erasure." +class InvokerStorageBase : public RefCountedThreadSafe<InvokerStorageBase> { + protected: + friend class RefCountedThreadSafe<InvokerStorageBase>; + virtual ~InvokerStorageBase() {} +}; + +// This structure exists purely to pass the returned |invoker_storage_| from +// Bind() to Callback while avoiding an extra AddRef/Release() pair. +// +// To do this, the constructor of Callback<> must take a const-ref. The +// reference must be to a const object otherwise the compiler will emit a +// warning about taking a reference to a temporary. +// +// Unfortunately, this means that the internal |invoker_storage_| field must +// be made mutable. +template <typename T> +struct InvokerStorageHolder { + explicit InvokerStorageHolder(T* invoker_storage) + : invoker_storage_(invoker_storage) { + } + + mutable scoped_refptr<InvokerStorageBase> invoker_storage_; +}; + +template <typename T> +InvokerStorageHolder<T> MakeInvokerStorageHolder(T* o) { + return InvokerStorageHolder<T>(o); +} + +} // namespace internal +} // namespace base + +#endif // BASE_CALLBACK_HELPERS_H_ diff --git a/base/callback_old.h b/base/callback_old.h new file mode 100644 index 0000000..ab3927d --- /dev/null +++ b/base/callback_old.h @@ -0,0 +1,254 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_CALLBACK_OLD_H_ +#define BASE_CALLBACK_OLD_H_ +#pragma once + +#include "base/tuple.h" +#include "base/raw_scoped_refptr_mismatch_checker.h" + +// Callback -------------------------------------------------------------------- +// +// A Callback is like a Task but with unbound parameters. It is basically an +// object-oriented function pointer. +// +// Callbacks are designed to work with Tuples. A set of helper functions and +// classes is provided to hide the Tuple details from the consumer. Client +// code will generally work with the CallbackRunner base class, which merely +// provides a Run method and is returned by the New* functions. This allows +// users to not care which type of class implements the callback, only that it +// has a certain number and type of arguments. +// +// The implementation of this is done by CallbackImpl, which inherits +// CallbackStorage to store the data. This allows the storage of the data +// (requiring the class type T) to be hidden from users, who will want to call +// this regardless of the implementor's type T. +// +// Note that callbacks currently have no facility for cancelling or abandoning +// them. We currently handle this at a higher level for cases where this is +// necessary. The pointer in a callback must remain valid until the callback +// is made. +// +// Like Task, the callback executor is responsible for deleting the callback +// pointer once the callback has executed. +// +// Example client usage: +// void Object::DoStuff(int, string); +// Callback2<int, string>::Type* callback = +// NewCallback(obj, &Object::DoStuff); +// callback->Run(5, string("hello")); +// delete callback; +// or, equivalently, using tuples directly: +// CallbackRunner<Tuple2<int, string> >* callback = +// NewCallback(obj, &Object::DoStuff); +// callback->RunWithParams(MakeTuple(5, string("hello"))); +// +// There is also a 0-args version that returns a value. Example: +// int Object::GetNextInt(); +// CallbackWithReturnValue<int>::Type* callback = +// NewCallbackWithReturnValue(obj, &Object::GetNextInt); +// int next_int = callback->Run(); +// delete callback; + +// Base for all Callbacks that handles storage of the pointers. +template <class T, typename Method> +class CallbackStorage { + public: + CallbackStorage(T* obj, Method meth) : obj_(obj), meth_(meth) { + } + + protected: + T* obj_; + Method meth_; +}; + +// Interface that is exposed to the consumer, that does the actual calling +// of the method. +template <typename Params> +class CallbackRunner { + public: + typedef Params TupleType; + + virtual ~CallbackRunner() {} + virtual void RunWithParams(const Params& params) = 0; + + // Convenience functions so callers don't have to deal with Tuples. + inline void Run() { + RunWithParams(Tuple0()); + } + + template <typename Arg1> + inline void Run(const Arg1& a) { + RunWithParams(Params(a)); + } + + template <typename Arg1, typename Arg2> + inline void Run(const Arg1& a, const Arg2& b) { + RunWithParams(Params(a, b)); + } + + template <typename Arg1, typename Arg2, typename Arg3> + inline void Run(const Arg1& a, const Arg2& b, const Arg3& c) { + RunWithParams(Params(a, b, c)); + } + + template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> + inline void Run(const Arg1& a, const Arg2& b, const Arg3& c, const Arg4& d) { + RunWithParams(Params(a, b, c, d)); + } + + template <typename Arg1, typename Arg2, typename Arg3, + typename Arg4, typename Arg5> + inline void Run(const Arg1& a, const Arg2& b, const Arg3& c, + const Arg4& d, const Arg5& e) { + RunWithParams(Params(a, b, c, d, e)); + } +}; + +template <class T, typename Method, typename Params> +class CallbackImpl : public CallbackStorage<T, Method>, + public CallbackRunner<Params> { + public: + CallbackImpl(T* obj, Method meth) : CallbackStorage<T, Method>(obj, meth) { + } + virtual void RunWithParams(const Params& params) { + // use "this->" to force C++ to look inside our templatized base class; see + // Effective C++, 3rd Ed, item 43, p210 for details. + DispatchToMethod(this->obj_, this->meth_, params); + } +}; + +// 0-arg implementation +struct Callback0 { + typedef CallbackRunner<Tuple0> Type; +}; + +template <class T> +typename Callback0::Type* NewCallback(T* object, void (T::*method)()) { + return new CallbackImpl<T, void (T::*)(), Tuple0 >(object, method); +} + +// 1-arg implementation +template <typename Arg1> +struct Callback1 { + typedef CallbackRunner<Tuple1<Arg1> > Type; +}; + +template <class T, typename Arg1> +typename Callback1<Arg1>::Type* NewCallback(T* object, + void (T::*method)(Arg1)) { + return new CallbackImpl<T, void (T::*)(Arg1), Tuple1<Arg1> >(object, method); +} + +// 2-arg implementation +template <typename Arg1, typename Arg2> +struct Callback2 { + typedef CallbackRunner<Tuple2<Arg1, Arg2> > Type; +}; + +template <class T, typename Arg1, typename Arg2> +typename Callback2<Arg1, Arg2>::Type* NewCallback( + T* object, + void (T::*method)(Arg1, Arg2)) { + return new CallbackImpl<T, void (T::*)(Arg1, Arg2), + Tuple2<Arg1, Arg2> >(object, method); +} + +// 3-arg implementation +template <typename Arg1, typename Arg2, typename Arg3> +struct Callback3 { + typedef CallbackRunner<Tuple3<Arg1, Arg2, Arg3> > Type; +}; + +template <class T, typename Arg1, typename Arg2, typename Arg3> +typename Callback3<Arg1, Arg2, Arg3>::Type* NewCallback( + T* object, + void (T::*method)(Arg1, Arg2, Arg3)) { + return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3), + Tuple3<Arg1, Arg2, Arg3> >(object, method); +} + +// 4-arg implementation +template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> +struct Callback4 { + typedef CallbackRunner<Tuple4<Arg1, Arg2, Arg3, Arg4> > Type; +}; + +template <class T, typename Arg1, typename Arg2, typename Arg3, typename Arg4> +typename Callback4<Arg1, Arg2, Arg3, Arg4>::Type* NewCallback( + T* object, + void (T::*method)(Arg1, Arg2, Arg3, Arg4)) { + return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3, Arg4), + Tuple4<Arg1, Arg2, Arg3, Arg4> >(object, method); +} + +// 5-arg implementation +template <typename Arg1, typename Arg2, typename Arg3, + typename Arg4, typename Arg5> +struct Callback5 { + typedef CallbackRunner<Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> > Type; +}; + +template <class T, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> +typename Callback5<Arg1, Arg2, Arg3, Arg4, Arg5>::Type* NewCallback( + T* object, + void (T::*method)(Arg1, Arg2, Arg3, Arg4, Arg5)) { + return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3, Arg4, Arg5), + Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> >(object, method); +} + +// An UnboundMethod is a wrapper for a method where the actual object is +// provided at Run dispatch time. +template <class T, class Method, class Params> +class UnboundMethod { + public: + UnboundMethod(Method m, const Params& p) : m_(m), p_(p) { + COMPILE_ASSERT( + (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value), + badunboundmethodparams); + } + void Run(T* obj) const { + DispatchToMethod(obj, m_, p_); + } + private: + Method m_; + Params p_; +}; + +// Return value implementation with no args. +template <typename ReturnValue> +struct CallbackWithReturnValue { + class Type { + public: + virtual ~Type() {} + virtual ReturnValue Run() = 0; + }; +}; + +template <class T, typename Method, typename ReturnValue> +class CallbackWithReturnValueImpl + : public CallbackStorage<T, Method>, + public CallbackWithReturnValue<ReturnValue>::Type { + public: + CallbackWithReturnValueImpl(T* obj, Method meth) + : CallbackStorage<T, Method>(obj, meth) {} + + virtual ReturnValue Run() { + return (this->obj_->*(this->meth_))(); + } + + protected: + virtual ~CallbackWithReturnValueImpl() {} +}; + +template <class T, typename ReturnValue> +typename CallbackWithReturnValue<ReturnValue>::Type* +NewCallbackWithReturnValue(T* object, ReturnValue (T::*method)()) { + return new CallbackWithReturnValueImpl<T, ReturnValue (T::*)(), ReturnValue>( + object, method); +} + +#endif // BASE_CALLBACK_OLD_H_ diff --git a/base/template_util.h b/base/template_util.h index 27bdb73..0408fc6 100644 --- a/base/template_util.h +++ b/base/template_util.h @@ -6,6 +6,8 @@ #define BASE_TEMPLATE_UTIL_H_ #pragma once +#include <cstddef> // For size_t. + #include "build/build_config.h" namespace base { @@ -27,14 +29,22 @@ typedef integral_constant<bool, false> false_type; template <class T> struct is_pointer : false_type {}; template <class T> struct is_pointer<T*> : true_type {}; +template<class> struct is_array : public false_type {}; +template<class T, size_t n> struct is_array<T[n]> : public true_type {}; +template<class T> struct is_array<T[]> : public true_type {}; + +template <class T> struct is_non_const_reference : false_type {}; +template <class T> struct is_non_const_reference<T&> : true_type {}; +template <class T> struct is_non_const_reference<const T&> : false_type {}; + namespace internal { -// Types small_ and big_ are guaranteed such that sizeof(small_) < -// sizeof(big_) -typedef char small_; +// Types YesType and NoType are guaranteed such that sizeof(YesType) < +// sizeof(NoType). +typedef char YesType; -struct big_ { - small_ dummy[2]; +struct NoType { + YesType dummy[2]; }; #if !defined(OS_WIN) @@ -50,13 +60,23 @@ struct big_ { template <typename From, typename To> struct ConvertHelper { - static small_ Test(To); - static big_ Test(...); + static YesType Test(To); + static NoType Test(...); static From Create(); }; #endif // !defined(OS_WIN) +// Used to determine if a type is a struct/union/class. Inspired by Boost's +// is_class type_trait implementation. +struct IsClassHelper { + template <typename C> + static YesType Test(void(C::*)(void)); + + template <typename C> + static NoType Test(...); +}; + } // namespace internal #if !defined(OS_WIN) @@ -67,11 +87,18 @@ struct is_convertible : integral_constant<bool, sizeof(internal::ConvertHelper<From, To>::Test( internal::ConvertHelper<From, To>::Create())) - == sizeof(internal::small_)> { + == sizeof(internal::YesType)> { }; #endif // !defined(OS_WIN) +template <typename T> +struct is_class + : integral_constant<bool, + sizeof(internal::IsClassHelper::Test<T>(0)) == + sizeof(internal::YesType)> { +}; + } // namespace base #endif // BASE_TEMPLATE_UTIL_H_ diff --git a/base/template_util_unittest.cc b/base/template_util_unittest.cc new file mode 100644 index 0000000..020872a --- /dev/null +++ b/base/template_util_unittest.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/template_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace base { +namespace { + +struct AStruct {}; +class AClass {}; +enum AnEnum {}; + +class Parent {}; +class Child : public Parent {}; + +TEST(TemplateUtilTest, IsPointer) { + EXPECT_FALSE(is_pointer<int>::value); + EXPECT_FALSE(is_pointer<int&>::value); + EXPECT_TRUE(is_pointer<int*>::value); + EXPECT_TRUE(is_pointer<const int*>::value); +} + +TEST(TemplateUtilTest, IsArray) { + EXPECT_FALSE(is_array<int>::value); + EXPECT_FALSE(is_array<int*>::value); + EXPECT_FALSE(is_array<int(*)[3]>::value); + EXPECT_TRUE(is_array<int[]>::value); + EXPECT_TRUE(is_array<const int[]>::value); + EXPECT_TRUE(is_array<int[3]>::value); +} + +TEST(TemplateUtilTest, IsNonConstReference) { + EXPECT_FALSE(is_non_const_reference<int>::value); + EXPECT_FALSE(is_non_const_reference<const int&>::value); + EXPECT_TRUE(is_non_const_reference<int&>::value); +} + +#if !defined(OS_WIN) +// TODO(ajwong): Why is is_convertible disabled on windows? +TEST(TemplateUtilTest, IsConvertible) { + // Extra parents needed to make EXPECT_*'s parsing happy. Otherwise, + // it sees the equivalent of + // + // EXPECT_TRUE( (is_convertible < Child), (Parent > ::value)); + // + // Silly C++. + EXPECT_TRUE( (is_convertible<Child, Parent>::value) ); + EXPECT_FALSE( (is_convertible<Parent, Child>::value) ); +} +#endif // !defined(OS_WIN) + +TEST(TemplateUtilTest, IsClass) { + EXPECT_EQ(true, is_class<AStruct>::value); + EXPECT_EQ(true, is_class<AClass>::value); + + EXPECT_EQ(false, is_class<AnEnum>::value); + EXPECT_EQ(false, is_class<int>::value); + EXPECT_EQ(false, is_class<char*>::value); + EXPECT_EQ(false, is_class<int&>::value); + EXPECT_EQ(false, is_class<char[3]>::value); +} + +} // namespace +} // namespace base |