summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/SConscript1
-rw-r--r--base/build/base.vcproj4
-rw-r--r--base/build/base_unittests.vcproj4
-rw-r--r--base/call_wrapper.h234
-rw-r--r--base/call_wrapper_unittest.cc171
5 files changed, 414 insertions, 0 deletions
diff --git a/base/SConscript b/base/SConscript
index b6214e3..a7fc566 100644
--- a/base/SConscript
+++ b/base/SConscript
@@ -244,6 +244,7 @@ if env['PLATFORM'] == 'win32':
# 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);
+ }
+}