summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/call_wrapper.h45
-rw-r--r--base/call_wrapper_unittest.cc64
-rw-r--r--base/simple_thread.cc4
-rw-r--r--base/simple_thread.h13
-rw-r--r--base/simple_thread_unittest.cc15
5 files changed, 90 insertions, 51 deletions
diff --git a/base/call_wrapper.h b/base/call_wrapper.h
index c968f76..ae9738d0 100644
--- a/base/call_wrapper.h
+++ b/base/call_wrapper.h
@@ -30,42 +30,47 @@
#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.
+// NOTE: If you want a callback that takes at-call-time parameters, you should
+// use Callback (see task.h). CallWrapper only supports creation-time binding.
//
// 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.
+// the function / method with the arguments unpacked. The arguments to the
+// wrapped call are supplied at CallWrapper creation time, and no arguments can
+// be supplied to the Run() method.
//
// 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.
+// The classes memory should be managed like any other dynamically allocated
+// object, and deleted when no longer in use. It is of course wrong to destroy
+// the object while a Run() is in progress, or to call Run() after the object
+// has been destroyed. Arguments are copied by value, and kept within the
+// CallWrapper object. You should only pass-by-value simple parameters, or
+// pointers to more complex types. If your parameters need custom memory
+// management, then you should probably do this at the same point you destroy
+// the CallWrapper. You should be aware of how your CallWrapper is used, and
+// it is valid for Run() to be called 0 or more times.
//
// Some example usage:
// CallWrapper* wrapper = NewFunctionCallWrapper(&my_func);
-// wrapper->Run(); // my_func(); delete wrapper;
-// // wrapper is no longer valid.
+// wrapper->Run(); // my_func();
+// delete wrapper;
//
-// CallWrapper* wrapper = NewFunctionCallWrapper(&my_func, 10);
-// wrapper->Run(); // my_func(10); delete wrapper;
-// // wrapper is no longer valid.
+// scoped_ptr<CallWrapper> wrapper(NewFunctionCallWrapper(&my_func, 10));
+// wrapper->Run(); // my_func(10);
//
// MyObject obj;
-// CallWrapper* wrapper = NewMethodCallWrapper(&obj, &MyObject::Foo, 1, 2);
-// wrapper->Run(); // obj->Foo(1, 2); delete wrapper;
-// // wrapper is no longer valid.
+// scoped_ptr<CallWrapper> wrapper(
+// NewMethodCallWrapper(&obj, &MyObject::Foo, 1, 2));
+// wrapper->Run(); // obj->Foo(1, 2);
#include "base/tuple.h"
+namespace base {
+
class CallWrapper {
public:
virtual ~CallWrapper() { }
@@ -82,7 +87,6 @@ class FunctionCallWrapper : public CallWrapper {
: func_(func), params_(params) { }
virtual void Run() {
DispatchToFunction(func_, params_);
- delete this;
}
private:
FuncType func_;
@@ -98,7 +102,6 @@ class MethodCallWrapper : public CallWrapper {
: obj_(obj), meth_(meth), params_(params) { }
virtual void Run() {
DispatchToMethod(obj_, meth_, params_);
- delete this;
}
private:
ObjType* obj_;
@@ -231,4 +234,6 @@ inline CallWrapper* NewMethodCallWrapper(ObjType* obj, MethType meth,
obj, meth, MakeTuple(arg0, arg1, arg2, arg3, arg4));
}
+} // namespace base
+
#endif // BASE_CALL_WRAPPER_H_
diff --git a/base/call_wrapper_unittest.cc b/base/call_wrapper_unittest.cc
index 45a156a..b1e2518 100644
--- a/base/call_wrapper_unittest.cc
+++ b/base/call_wrapper_unittest.cc
@@ -28,6 +28,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "base/call_wrapper.h"
+#include "base/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -59,34 +60,44 @@ TEST(CallWrapperTest, FunctionCall) {
// Function call with 0 arguments.
{
EXPECT_EQ(0, global_int);
- CallWrapper* wrapper = NewFunctionCallWrapper(SetGlobalInt5);
+ scoped_ptr<base::CallWrapper> wrapper(
+ base::NewFunctionCallWrapper(&SetGlobalInt5));
EXPECT_EQ(0, global_int);
wrapper->Run();
EXPECT_EQ(5, global_int);
+
+ global_int = 0;
+ wrapper->Run();
+ EXPECT_EQ(5, global_int);
}
// Function call with 1 argument.
{
EXPECT_EQ(5, global_int);
- CallWrapper* wrapper = NewFunctionCallWrapper(SetGlobalInt, 0);
+ scoped_ptr<base::CallWrapper> wrapper(
+ base::NewFunctionCallWrapper(&SetGlobalInt, 0));
EXPECT_EQ(5, global_int);
wrapper->Run();
EXPECT_EQ(0, global_int);
+
+ global_int = 5;
+ wrapper->Run();
+ EXPECT_EQ(0, global_int);
}
// Function call with 2 arguments.
{
int stack_int = 4;
- CallWrapper* wrapper;
+ scoped_ptr<base::CallWrapper> wrapper;
- wrapper = NewFunctionCallWrapper(SetInt, &global_int, 8);
+ wrapper.reset(base::NewFunctionCallWrapper(&SetInt, &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(SetInt, &stack_int, 8);
+ wrapper.reset(base::NewFunctionCallWrapper(&SetInt, &stack_int, 8));
EXPECT_EQ(4, stack_int);
EXPECT_EQ(8, global_int);
wrapper->Run();
@@ -96,22 +107,29 @@ TEST(CallWrapperTest, FunctionCall) {
// Function call with 3-5 arguments.
{
int stack_int = 12;
- CallWrapper* wrapper;
+ scoped_ptr<base::CallWrapper> wrapper;
- wrapper = NewFunctionCallWrapper(SetIntAdd2, &stack_int, 1, 6);
+ wrapper.reset(
+ base::NewFunctionCallWrapper(&SetIntAdd2, &stack_int, 1, 6));
EXPECT_EQ(12, stack_int);
wrapper->Run();
EXPECT_EQ(7, stack_int);
- wrapper = NewFunctionCallWrapper(SetIntAdd3, &stack_int, 1, 6, 2);
+ wrapper.reset(
+ base::NewFunctionCallWrapper(&SetIntAdd3, &stack_int, 1, 6, 2));
EXPECT_EQ(7, stack_int);
wrapper->Run();
EXPECT_EQ(9, stack_int);
- wrapper = NewFunctionCallWrapper(SetIntAdd4, &stack_int, 1, 6, 2, 3);
+ wrapper.reset(
+ base::NewFunctionCallWrapper(&SetIntAdd4, &stack_int, 1, 6, 2, 3));
EXPECT_EQ(9, stack_int);
wrapper->Run();
EXPECT_EQ(12, stack_int);
+
+ global_int = 2;
+ wrapper->Run();
+ EXPECT_EQ(12, stack_int);
}
}
@@ -136,37 +154,51 @@ TEST(CallWrapperTest, MethodCall) {
{
int stack_int = 0;
Incrementer incr(&stack_int);
- CallWrapper* wrapper;
+ scoped_ptr<base::CallWrapper> wrapper;
- wrapper = NewMethodCallWrapper(&incr, &Incrementer::Increment);
+ wrapper.reset(
+ base::NewMethodCallWrapper(&incr, &Incrementer::Increment));
EXPECT_EQ(0, stack_int);
wrapper->Run();
EXPECT_EQ(1, stack_int);
- wrapper = NewMethodCallWrapper(&incr, &Incrementer::IncrementBy, 10);
+ wrapper.reset(
+ base::NewMethodCallWrapper(&incr, &Incrementer::IncrementBy, 10));
EXPECT_EQ(1, stack_int);
wrapper->Run();
EXPECT_EQ(11, stack_int);
+ wrapper->Run();
+ EXPECT_EQ(21, stack_int);
+ wrapper->Run();
+ EXPECT_EQ(31, stack_int);
}
// Method call with 2-5 arguments.
{
int stack_int = 0;
Incrementer incr(&stack_int);
- CallWrapper* wrapper;
+ scoped_ptr<base::CallWrapper> wrapper;
- wrapper = NewMethodCallWrapper(&incr, &Incrementer::SetIntAdd2, 1, 5);
+ wrapper.reset(
+ base::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);
+ wrapper.reset(
+ base::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);
+ wrapper.reset(
+ base::NewMethodCallWrapper(&incr,
+ &Incrementer::SetIntAdd4, 1, 5, 7, 2));
EXPECT_EQ(13, stack_int);
wrapper->Run();
EXPECT_EQ(15, stack_int);
+
+ stack_int = 2;
+ wrapper->Run();
+ EXPECT_EQ(15, stack_int);
}
}
diff --git a/base/simple_thread.cc b/base/simple_thread.cc
index 797843d..1d88dada 100644
--- a/base/simple_thread.cc
+++ b/base/simple_thread.cc
@@ -75,8 +75,4 @@ void CallWrapperSimpleThread::Run() {
wrapper_ = NULL;
}
-CallWrapperSimpleThread::~CallWrapperSimpleThread() {
- DCHECK(!wrapper_) << "CallWrapper was never released.";
-}
-
} // namespace base
diff --git a/base/simple_thread.h b/base/simple_thread.h
index fe9a136..44b397d 100644
--- a/base/simple_thread.h
+++ b/base/simple_thread.h
@@ -43,14 +43,15 @@
// NOTE: You *MUST* call Join on the thread to clean up the underlying thread
// resources. You are also responsible for destructing the SimpleThread object.
// It is invalid to destroy a SimpleThread while it is running, or without
-// Start() having been called (and a thread never created).
+// Start() having been called (and a thread never created). The CallWrapper
+// object should live as long as a CallWrapperSimpleThread.
//
// Thread Safety: A SimpleThread is not completely thread safe. It is safe to
// access it from the creating thread or from the newly created thread. This
// implies that the creator thread should be the thread that calls Join.
//
// Example:
-// CallWrapper* wrapper = NewMethodCallWrapper(obj, &Foo::Main);
+// scoped_ptr<CallWrapper> wrapper(NewMethodCallWrapper(obj, &Foo::Main));
// scoped_ptr<SimpleThread> thread(new CallWrapperSimpleThread(wrapper));
// thread->Start();
// // Start will return after the Thread has been successfully started and
@@ -58,7 +59,7 @@
// // until it returns. The CallWrapper will then delete itself.
// thread->Join(); // Wait until the thread has exited. You MUST Join!
// // The SimpleThread object is still valid, however you may not call Join
-// // or Start again. In this example the scoper will destroy the object.
+// // or Start again. In this example the scopers will destroy the objects.
#ifndef BASE_SIMPLE_THREAD_H_
#define BASE_SIMPLE_THREAD_H_
@@ -69,10 +70,10 @@
#include "base/waitable_event.h"
#include "base/platform_thread.h"
-class CallWrapper;
-
namespace base {
+class CallWrapper;
+
// This is the base SimpleThread. You can derive from it and implement the
// virtual Run method, or you can use the CallWrapperSimpleThread interface.
class SimpleThread : public PlatformThread::Delegate {
@@ -151,7 +152,7 @@ class CallWrapperSimpleThread : public SimpleThread {
const std::string& name_prefix)
: SimpleThread(options, name_prefix), wrapper_(wrapper) { }
- virtual ~CallWrapperSimpleThread();
+ virtual ~CallWrapperSimpleThread() { }
virtual void Run();
private:
CallWrapper* wrapper_;
diff --git a/base/simple_thread_unittest.cc b/base/simple_thread_unittest.cc
index c894637..fcdabda 100644
--- a/base/simple_thread_unittest.cc
+++ b/base/simple_thread_unittest.cc
@@ -53,10 +53,11 @@ void SignalEvent(base::WaitableEvent* event) {
TEST(SimpleThreadTest, CreateAndJoin) {
int stack_int = 0;
- CallWrapper* wrapper = NewFunctionCallWrapper(SetInt, &stack_int, 7);
+ scoped_ptr<base::CallWrapper> wrapper(
+ base::NewFunctionCallWrapper(SetInt, &stack_int, 7));
EXPECT_EQ(0, stack_int);
scoped_ptr<base::SimpleThread> thread(
- new base::CallWrapperSimpleThread(wrapper));
+ new base::CallWrapperSimpleThread(wrapper.get()));
EXPECT_FALSE(thread->HasBeenStarted());
EXPECT_FALSE(thread->HasBeenJoined());
EXPECT_EQ(0, stack_int);
@@ -75,8 +76,10 @@ TEST(SimpleThreadTest, WaitForEvent) {
// Create a thread, and wait for it to signal us.
base::WaitableEvent event(true, false);
- scoped_ptr<base::SimpleThread> thread(new base::CallWrapperSimpleThread(
- NewFunctionCallWrapper(SignalEvent, &event)));
+ scoped_ptr<base::CallWrapper> wrapper(
+ base::NewFunctionCallWrapper(SignalEvent, &event));
+ scoped_ptr<base::SimpleThread> thread(
+ new base::CallWrapperSimpleThread(wrapper.get()));
EXPECT_FALSE(event.IsSignaled());
thread->Start();
@@ -89,8 +92,10 @@ TEST(SimpleThreadTest, Named) {
base::WaitableEvent event(true, false);
base::SimpleThread::Options options;
+ scoped_ptr<base::CallWrapper> wrapper(
+ base::NewFunctionCallWrapper(SignalEvent, &event));
scoped_ptr<base::SimpleThread> thread(new base::CallWrapperSimpleThread(
- NewFunctionCallWrapper(SignalEvent, &event), options, "testy"));
+ wrapper.get(), options, "testy"));
EXPECT_EQ(thread->name_prefix(), "testy");
EXPECT_FALSE(event.IsSignaled());