summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-15 01:27:38 +0000
committerajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-15 01:27:38 +0000
commitb38d3578e53d0a7f441c6858334a2d9f08e5c024 (patch)
tree917a1d893c40fd10408e172b1a66cba692a0fedc /base
parentc41fe6697e38057138cbe33332d9882e0d7d9b4b (diff)
downloadchromium_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.gyp2
-rw-r--r--base/base.gypi5
-rw-r--r--base/bind.h99
-rw-r--r--base/bind.h.pump71
-rw-r--r--base/bind_helpers.h287
-rw-r--r--base/bind_internal.h1670
-rw-r--r--base/bind_internal.h.pump237
-rw-r--r--base/bind_unittest.cc597
-rw-r--r--base/callback.h640
-rw-r--r--base/callback.h.pump291
-rw-r--r--base/callback_helpers.h55
-rw-r--r--base/callback_old.h254
-rw-r--r--base/template_util.h43
-rw-r--r--base/template_util_unittest.cc66
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