diff options
Diffstat (limited to 'base')
-rw-r--r-- | base/SConscript | 1 | ||||
-rw-r--r-- | base/build/base.vcproj | 4 | ||||
-rw-r--r-- | base/build/base_unittests.vcproj | 4 | ||||
-rw-r--r-- | base/call_wrapper.h | 234 | ||||
-rw-r--r-- | base/call_wrapper_unittest.cc | 171 |
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); + } +} |