Create a CallWrapper interface, for making closure-like callbacks.  This is similar to RunnableMethod, but does not derive / involve a Task.  This is more convenient than Callback, because the interfaces do not need to know what the underlying template arguments are, everything is dealt with as a CallWrapper*.

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@1151 0039d316-1c4b-4281-b951-d872f2087c98


CrOS-Libchrome-Original-Commit: 8e4e18052ac86ebc929048f0f6b2aeb750620320
diff --git a/base/SConscript b/base/SConscript
index b6214e3..a7fc566 100644
--- a/base/SConscript
+++ b/base/SConscript
@@ -244,6 +244,7 @@
 # cross-platform live below.
 test_files = [
     'at_exit_unittest.cc',
+    'call_wrapper_unittest.cc',
     'command_line_unittest.cc',
     'json_reader_unittest.cc',
     'json_writer_unittest.cc',
diff --git a/base/build/base.vcproj b/base/build/base.vcproj
index 8648217..b78f41c 100644
--- a/base/build/base.vcproj
+++ b/base/build/base.vcproj
@@ -206,6 +206,10 @@
 			>
 		</File>
 		<File
+			RelativePath="..\call_wrapper.h"
+			>
+		</File>
+		<File
 			RelativePath="..\clipboard.h"
 			>
 		</File>
diff --git a/base/build/base_unittests.vcproj b/base/build/base_unittests.vcproj
index fa32036..2c7908a 100644
--- a/base/build/base_unittests.vcproj
+++ b/base/build/base_unittests.vcproj
@@ -168,6 +168,10 @@
 				>
 			</File>
 			<File
+				RelativePath="..\call_wrapper_unittest.cc"
+				>
+			</File>
+			<File
 				RelativePath="..\clipboard_unittest.cc"
 				>
 			</File>
diff --git a/base/call_wrapper.h b/base/call_wrapper.h
new file mode 100644
index 0000000..c968f76
--- /dev/null
+++ b/base/call_wrapper.h
@@ -0,0 +1,234 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef BASE_CALL_WRAPPER_H_
+#define BASE_CALL_WRAPPER_H_
+
+// WARNING: This is currently in competition with Task related callbacks, see
+//          task.h, you should maybe be using those interfaces instead.
+//
+// A function / method call invocation wrapper.  This creates a "closure" of
+// sorts, storing a function pointer (or method pointer), along with a possible
+// list of arguments.  The objects have a single method Run(), which will call
+// the function / method with the arguments unpacked.  Memory is automatically
+// managed, a Wrapper is only good for 1 Run(), and will delete itself after.
+//
+// All wrappers should be constructed through the two factory methods:
+//   CallWrapper* NewFunctionCallWrapper(funcptr, ...);
+//   CallWrapper* NewMethodCallWrapper(obj, &Klass::Method, ...);
+//
+// The arguments are copied by value, and kept within the CallWrapper object.
+// The parameters should be simple types, or pointers to more complex types.
+// The copied parameters will be automatically destroyed, but any pointers,
+// or other objects that need to be managed should be managed by the callback.
+// If your Run method does custom cleanup, and Run is never called, this could
+// of course leak that manually managed memory.
+//
+// Some example usage:
+//   CallWrapper* wrapper = NewFunctionCallWrapper(&my_func);
+//   wrapper->Run();  // my_func(); delete wrapper;
+//   // wrapper is no longer valid.
+//
+//   CallWrapper* wrapper = NewFunctionCallWrapper(&my_func, 10);
+//   wrapper->Run();  // my_func(10); delete wrapper;
+//   // wrapper is no longer valid.
+//
+//   MyObject obj;
+//   CallWrapper* wrapper = NewMethodCallWrapper(&obj, &MyObject::Foo, 1, 2);
+//   wrapper->Run();  // obj->Foo(1, 2); delete wrapper;
+//   // wrapper is no longer valid.
+
+#include "base/tuple.h"
+
+class CallWrapper {
+ public:
+  virtual ~CallWrapper() { }
+  virtual void Run() = 0;
+ protected:
+  CallWrapper() { }
+};
+
+// Wraps a function / static method call.
+template <typename FuncType, typename TupleType>
+class FunctionCallWrapper : public CallWrapper {
+ public:
+  FunctionCallWrapper(FuncType func, TupleType params)
+      : func_(func), params_(params) { }
+  virtual void Run() {
+    DispatchToFunction(func_, params_);
+    delete this;
+  }
+ private:
+  FuncType func_;
+  // We copy from the const& constructor argument to our own copy here.
+  TupleType params_;
+};
+
+// Wraps a method invocation on an object.
+template <typename ObjType, typename MethType, typename TupleType>
+class MethodCallWrapper : public CallWrapper {
+ public:
+  MethodCallWrapper(ObjType* obj, MethType meth, TupleType params)
+      : obj_(obj), meth_(meth), params_(params) { }
+  virtual void Run() {
+    DispatchToMethod(obj_, meth_, params_);
+    delete this;
+  }
+ private:
+  ObjType* obj_;
+  MethType meth_;
+  // We copy from the const& constructor argument to our own copy here.
+  TupleType params_;
+};
+
+// Factory functions, conveniently creating a Tuple for 0-5 arguments.
+template <typename FuncType>
+inline CallWrapper* NewFunctionCallWrapper(FuncType func) {
+  typedef Tuple0 TupleType;
+  return new FunctionCallWrapper<FuncType, TupleType>(
+      func, MakeTuple());
+}
+
+template <typename FuncType, typename Arg0Type>
+inline CallWrapper* NewFunctionCallWrapper(FuncType func,
+                                           const Arg0Type& arg0) {
+  typedef Tuple1<Arg0Type> TupleType;
+  return new FunctionCallWrapper<FuncType, TupleType>(
+      func, MakeTuple(arg0));
+}
+
+template <typename FuncType, typename Arg0Type, typename Arg1Type>
+inline CallWrapper* NewFunctionCallWrapper(FuncType func,
+                                           const Arg0Type& arg0,
+                                           const Arg1Type& arg1) {
+  typedef Tuple2<Arg0Type, Arg1Type> TupleType;
+  return new FunctionCallWrapper<FuncType, TupleType>(
+      func, MakeTuple(arg0, arg1));
+}
+
+template <typename FuncType, typename Arg0Type, typename Arg1Type,
+          typename Arg2Type>
+inline CallWrapper* NewFunctionCallWrapper(FuncType func,
+                                           const Arg0Type& arg0,
+                                           const Arg1Type& arg1,
+                                           const Arg2Type& arg2) {
+  typedef Tuple3<Arg0Type, Arg1Type, Arg2Type> TupleType;
+  return new FunctionCallWrapper<FuncType, TupleType>(
+      func, MakeTuple(arg0, arg1, arg2));
+}
+
+template <typename FuncType, typename Arg0Type, typename Arg1Type,
+          typename Arg2Type, typename Arg3Type>
+inline CallWrapper* NewFunctionCallWrapper(FuncType func,
+                                           const Arg0Type& arg0,
+                                           const Arg1Type& arg1,
+                                           const Arg2Type& arg2,
+                                           const Arg3Type& arg3) {
+  typedef Tuple4<Arg0Type, Arg1Type, Arg2Type, Arg3Type> TupleType;
+  return new FunctionCallWrapper<FuncType, TupleType>(
+      func, MakeTuple(arg0, arg1, arg2, arg3));
+}
+
+template <typename FuncType, typename Arg0Type, typename Arg1Type,
+          typename Arg2Type, typename Arg3Type, typename Arg4Type>
+inline CallWrapper* NewFunctionCallWrapper(FuncType func,
+                                           const Arg0Type& arg0,
+                                           const Arg1Type& arg1,
+                                           const Arg2Type& arg2,
+                                           const Arg3Type& arg3,
+                                           const Arg4Type& arg4) {
+  typedef Tuple5<Arg0Type, Arg1Type, Arg2Type, Arg3Type, Arg4Type> TupleType;
+  return new FunctionCallWrapper<FuncType, TupleType>(
+      func, MakeTuple(arg0, arg1, arg2, arg3, arg4));
+}
+
+
+template <typename ObjType, typename MethType>
+inline CallWrapper* NewMethodCallWrapper(ObjType* obj, MethType meth) {
+  typedef Tuple0 TupleType;
+  return new MethodCallWrapper<ObjType, MethType, TupleType>(
+      obj, meth, MakeTuple());
+}
+
+template <typename ObjType, typename MethType, typename Arg0Type>
+inline CallWrapper* NewMethodCallWrapper(ObjType* obj, MethType meth,
+                                         const Arg0Type& arg0) {
+  typedef Tuple1<Arg0Type> TupleType;
+  return new MethodCallWrapper<ObjType, MethType, TupleType>(
+      obj, meth, MakeTuple(arg0));
+}
+
+template <typename ObjType, typename MethType, typename Arg0Type,
+          typename Arg1Type>
+inline CallWrapper* NewMethodCallWrapper(ObjType* obj, MethType meth,
+                                         const Arg0Type& arg0,
+                                         const Arg1Type& arg1) {
+  typedef Tuple2<Arg0Type, Arg1Type> TupleType;
+  return new MethodCallWrapper<ObjType, MethType, TupleType>(
+      obj, meth, MakeTuple(arg0, arg1));
+}
+
+template <typename ObjType, typename MethType, typename Arg0Type,
+          typename Arg1Type, typename Arg2Type>
+inline CallWrapper* NewMethodCallWrapper(ObjType* obj, MethType meth,
+                                         const Arg0Type& arg0,
+                                         const Arg1Type& arg1,
+                                         const Arg2Type& arg2) {
+  typedef Tuple3<Arg0Type, Arg1Type, Arg2Type> TupleType;
+  return new MethodCallWrapper<ObjType, MethType, TupleType>(
+      obj, meth, MakeTuple(arg0, arg1, arg2));
+}
+
+template <typename ObjType, typename MethType, typename Arg0Type,
+          typename Arg1Type, typename Arg2Type, typename Arg3Type>
+inline CallWrapper* NewMethodCallWrapper(ObjType* obj, MethType meth,
+                                         const Arg0Type& arg0,
+                                         const Arg1Type& arg1,
+                                         const Arg2Type& arg2,
+                                         const Arg3Type& arg3) {
+  typedef Tuple4<Arg0Type, Arg1Type, Arg2Type, Arg3Type> TupleType;
+  return new MethodCallWrapper<ObjType, MethType, TupleType>(
+      obj, meth, MakeTuple(arg0, arg1, arg2, arg3));
+}
+
+template <typename ObjType, typename MethType, typename Arg0Type,
+          typename Arg1Type, typename Arg2Type, typename Arg3Type,
+          typename Arg4Type>
+inline CallWrapper* NewMethodCallWrapper(ObjType* obj, MethType meth,
+                                         const Arg0Type& arg0,
+                                         const Arg1Type& arg1,
+                                         const Arg2Type& arg2,
+                                         const Arg3Type& arg3,
+                                         const Arg4Type& arg4) {
+  typedef Tuple5<Arg0Type, Arg1Type, Arg2Type, Arg3Type, Arg4Type> TupleType;
+  return new MethodCallWrapper<ObjType, MethType, TupleType>(
+      obj, meth, MakeTuple(arg0, arg1, arg2, arg3, arg4));
+}
+
+#endif  // BASE_CALL_WRAPPER_H_
diff --git a/base/call_wrapper_unittest.cc b/base/call_wrapper_unittest.cc
new file mode 100644
index 0000000..60dedc5
--- /dev/null
+++ b/base/call_wrapper_unittest.cc
@@ -0,0 +1,171 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/call_wrapper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+int global_int = 0;
+void set_global_int_5() {
+  global_int = 5;
+}
+void set_global_int(int x) {
+  global_int = x;
+}
+void set_int(int* p, int x) {
+  *p = x;
+}
+void set_int_add2(int* p, int x, int y) {
+  *p = x + y;
+}
+void set_int_add3(int* p, int x, int y, int z) {
+  *p = x + y + z;
+}
+void set_int_add4(int* p, int x, int y, int z, int w) {
+  *p = x + y + z + w;
+}
+
+}  // namespace
+
+TEST(CallWrapperTest, FunctionCall) {
+  // Function call with 0 arguments.
+  {
+    EXPECT_EQ(0, global_int);
+    CallWrapper* wrapper = NewFunctionCallWrapper(set_global_int_5);
+
+    EXPECT_EQ(0, global_int);
+    wrapper->Run();
+    EXPECT_EQ(5, global_int);
+  }
+  // Function call with 1 argument.
+  {
+    EXPECT_EQ(5, global_int);
+    CallWrapper* wrapper = NewFunctionCallWrapper(set_global_int, 0);
+
+    EXPECT_EQ(5, global_int);
+    wrapper->Run();
+    EXPECT_EQ(0, global_int);
+  }
+  // Function call with 2 arguments.
+  {
+    int stack_int = 4;
+    CallWrapper* wrapper;
+
+    wrapper = NewFunctionCallWrapper(set_int, &global_int, 8);
+    EXPECT_EQ(4, stack_int);
+    EXPECT_EQ(0, global_int);
+    wrapper->Run();
+    EXPECT_EQ(4, stack_int);
+    EXPECT_EQ(8, global_int);
+
+    wrapper = NewFunctionCallWrapper(set_int, &stack_int, 8);
+    EXPECT_EQ(4, stack_int);
+    EXPECT_EQ(8, global_int);
+    wrapper->Run();
+    EXPECT_EQ(8, stack_int);
+    EXPECT_EQ(8, global_int);
+  }
+  // Function call with 3-5 arguments.
+  {
+    int stack_int = 12;
+    CallWrapper* wrapper;
+
+    wrapper = NewFunctionCallWrapper(set_int_add2, &stack_int, 1, 6);
+    EXPECT_EQ(12, stack_int);
+    wrapper->Run();
+    EXPECT_EQ(7, stack_int);
+
+    wrapper = NewFunctionCallWrapper(set_int_add3, &stack_int, 1, 6, 2);
+    EXPECT_EQ(7, stack_int);
+    wrapper->Run();
+    EXPECT_EQ(9, stack_int);
+
+    wrapper = NewFunctionCallWrapper(set_int_add4, &stack_int, 1, 6, 2, 3);
+    EXPECT_EQ(9, stack_int);
+    wrapper->Run();
+    EXPECT_EQ(12, stack_int);
+  }
+}
+
+namespace {
+
+class Incrementer {
+ public:
+  Incrementer(int* ptr) : ptr_(ptr) { }
+  void IncrementBy(int x) { *ptr_ += x; }
+  void Increment() { IncrementBy(1); }
+  void SetIntAdd2(int x, int y) { *ptr_ = x + y; }
+  void SetIntAdd3(int x, int y, int z) { *ptr_ = x + y + z; }
+  void SetIntAdd4(int x, int y, int z, int w) { *ptr_ = x + y + z + w; }
+ private:
+  int* ptr_;
+};
+
+}  // namespace
+
+TEST(CallWrapperTest, MethodCall) {
+  // Method call with 0 and 1 arguments.
+  {
+    int stack_int = 0;
+    Incrementer incr(&stack_int);
+    CallWrapper* wrapper;
+
+    wrapper = NewMethodCallWrapper(&incr, &Incrementer::Increment);
+    EXPECT_EQ(0, stack_int);
+    wrapper->Run();
+    EXPECT_EQ(1, stack_int);
+
+    wrapper = NewMethodCallWrapper(&incr, &Incrementer::IncrementBy, 10);
+    EXPECT_EQ(1, stack_int);
+    wrapper->Run();
+    EXPECT_EQ(11, stack_int);
+  }
+  // Method call with 2-5 arguments.
+  {
+    int stack_int = 0;
+    Incrementer incr(&stack_int);
+    CallWrapper* wrapper;
+
+    wrapper = NewMethodCallWrapper(&incr, &Incrementer::SetIntAdd2, 1, 5);
+    EXPECT_EQ(0, stack_int);
+    wrapper->Run();
+    EXPECT_EQ(6, stack_int);
+
+    wrapper = NewMethodCallWrapper(&incr, &Incrementer::SetIntAdd3, 1, 5, 7);
+    EXPECT_EQ(6, stack_int);
+    wrapper->Run();
+    EXPECT_EQ(13, stack_int);
+
+    wrapper = NewMethodCallWrapper(&incr, &Incrementer::SetIntAdd4, 1, 5, 7, 2);
+    EXPECT_EQ(13, stack_int);
+    wrapper->Run();
+    EXPECT_EQ(15, stack_int);
+  }
+}