summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-18 04:05:14 +0000
committerajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-18 04:05:14 +0000
commit15fcb6590c658858007a61dd24055dcefd0b699d (patch)
tree817040b4ccd84a59dcd778696ff328016083d95b
parent3d049916edeb079db28283fb230b89def0721547 (diff)
downloadchromium_src-15fcb6590c658858007a61dd24055dcefd0b699d.zip
chromium_src-15fcb6590c658858007a61dd24055dcefd0b699d.tar.gz
chromium_src-15fcb6590c658858007a61dd24055dcefd0b699d.tar.bz2
Emptiness, Reset, and Comparison API for Callbacks.
Since Callback<> is essentially a smartpointer, some introspective APIs are required for sensible usage. BUG=35223 TEST=new unittests Review URL: http://codereview.chromium.org/6507029 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75360 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/bind_unittest.cc12
-rw-r--r--base/callback.h202
-rw-r--r--base/callback.h.pump70
-rw-r--r--base/callback_unittest.cc96
4 files changed, 268 insertions, 112 deletions
diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc
index 47d971a..77eb98a 100644
--- a/base/bind_unittest.cc
+++ b/base/bind_unittest.cc
@@ -212,18 +212,6 @@ class BindTest : public ::testing::Test {
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);
diff --git a/base/callback.h b/base/callback.h
index 05a7182..9e43afb 100644
--- a/base/callback.h
+++ b/base/callback.h
@@ -212,6 +212,49 @@
namespace base {
+namespace internal {
+
+// Holds the methods that don't require specialization to reduce template bloat.
+class CallbackBase {
+ public:
+ // Returns true if Callback is null (doesn't refer to anything).
+ bool is_null() const {
+ return invoker_storage_.get() == NULL;
+ }
+
+ // Returns the Callback into an uninitalized state.
+ void Reset() {
+ invoker_storage_ = NULL;
+ polymorphic_invoke_ = NULL;
+ }
+
+ bool Equals(const CallbackBase& other) const {
+ return invoker_storage_.get() == other.invoker_storage_.get() &&
+ polymorphic_invoke_ == other.polymorphic_invoke_;
+ }
+
+ protected:
+ // In C++, it is safe to cast function pointers to function pointers of
+ // another type. It is not okay to use void*. We create a InvokeFuncStorage
+ // that that can store our function pointer, and then cast it back to
+ // the original type on usage.
+ typedef void(*InvokeFuncStorage)(void);
+
+ CallbackBase(InvokeFuncStorage polymorphic_invoke,
+ scoped_refptr<InvokerStorageBase>* invoker_storage)
+ : polymorphic_invoke_(polymorphic_invoke) {
+ if (invoker_storage) {
+ invoker_storage_.swap(*invoker_storage);
+ }
+ }
+
+ scoped_refptr<InvokerStorageBase> invoker_storage_;
+ InvokeFuncStorage polymorphic_invoke_;
+};
+
+} // namespace internal
+
+
// 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.
@@ -221,13 +264,12 @@ namespace base {
// only has one type: the function signature.
template <typename Sig>
class Callback;
-
template <typename R>
-class Callback<R(void)> {
+class Callback<R(void)> : public internal::CallbackBase {
public:
typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -238,25 +280,25 @@ class Callback<R(void)> {
// 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_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
- R Run(void) const {
- return polymorphic_invoke_(invoker_storage_.get());
- }
+ R Run() const {
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
+ return f(invoker_storage_.get());
+ }
};
template <typename R, typename A1>
-class Callback<R(A1)> {
+class Callback<R(A1)> : public internal::CallbackBase {
public:
typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -267,26 +309,26 @@ class Callback<R(A1)> {
// 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_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
R Run(const A1& a1) const {
- return polymorphic_invoke_(invoker_storage_.get(), a1);
- }
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
+ return f(invoker_storage_.get(), a1);
+ }
};
template <typename R, typename A1, typename A2>
-class Callback<R(A1, A2)> {
+class Callback<R(A1, A2)> : public internal::CallbackBase {
public:
typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
const A2&);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -297,29 +339,29 @@ class Callback<R(A1, A2)> {
// 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_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
R Run(const A1& a1,
const A2& a2) const {
- return polymorphic_invoke_(invoker_storage_.get(), a1,
- a2);
- }
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
+ return f(invoker_storage_.get(), a1,
+ a2);
+ }
};
template <typename R, typename A1, typename A2, typename A3>
-class Callback<R(A1, A2, A3)> {
+class Callback<R(A1, A2, A3)> : public internal::CallbackBase {
public:
typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
const A2&,
const A3&);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -330,32 +372,32 @@ class Callback<R(A1, A2, A3)> {
// 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_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
R Run(const A1& a1,
const A2& a2,
const A3& a3) const {
- return polymorphic_invoke_(invoker_storage_.get(), a1,
- a2,
- a3);
- }
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
+ return f(invoker_storage_.get(), a1,
+ a2,
+ a3);
+ }
};
template <typename R, typename A1, typename A2, typename A3, typename A4>
-class Callback<R(A1, A2, A3, A4)> {
+class Callback<R(A1, A2, A3, A4)> : public internal::CallbackBase {
public:
typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
const A2&,
const A3&,
const A4&);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -366,28 +408,28 @@ class Callback<R(A1, A2, A3, A4)> {
// 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_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
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);
- }
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
+ return f(invoker_storage_.get(), a1,
+ a2,
+ a3,
+ a4);
+ }
};
template <typename R, typename A1, typename A2, typename A3, typename A4,
typename A5>
-class Callback<R(A1, A2, A3, A4, A5)> {
+class Callback<R(A1, A2, A3, A4, A5)> : public internal::CallbackBase {
public:
typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
const A2&,
@@ -395,7 +437,7 @@ class Callback<R(A1, A2, A3, A4, A5)> {
const A4&,
const A5&);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -406,8 +448,9 @@ class Callback<R(A1, A2, A3, A4, A5)> {
// 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_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
R Run(const A1& a1,
@@ -415,21 +458,20 @@ class Callback<R(A1, A2, A3, A4, A5)> {
const A3& a3,
const A4& a4,
const A5& a5) const {
- return polymorphic_invoke_(invoker_storage_.get(), a1,
- a2,
- a3,
- a4,
- a5);
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+ return f(invoker_storage_.get(), a1,
+ a2,
+ a3,
+ a4,
+ a5);
}
-
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
};
template <typename R, typename A1, typename A2, typename A3, typename A4,
typename A5, typename A6>
-class Callback<R(A1, A2, A3, A4, A5, A6)> {
+class Callback<R(A1, A2, A3, A4, A5, A6)> : public internal::CallbackBase {
public:
typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
const A2&,
@@ -438,7 +480,7 @@ class Callback<R(A1, A2, A3, A4, A5, A6)> {
const A5&,
const A6&);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -449,8 +491,9 @@ class Callback<R(A1, A2, A3, A4, A5, A6)> {
// 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_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
R Run(const A1& a1,
@@ -459,17 +502,16 @@ class Callback<R(A1, A2, A3, A4, A5, A6)> {
const A4& a4,
const A5& a5,
const A6& a6) const {
- return polymorphic_invoke_(invoker_storage_.get(), a1,
- a2,
- a3,
- a4,
- a5,
- a6);
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+ return f(invoker_storage_.get(), a1,
+ a2,
+ a3,
+ a4,
+ a5,
+ a6);
}
-
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
};
diff --git a/base/callback.h.pump b/base/callback.h.pump
index 9fc4b0b..19b7987 100644
--- a/base/callback.h.pump
+++ b/base/callback.h.pump
@@ -216,6 +216,49 @@ $var MAX_ARITY = 6
namespace base {
+namespace internal {
+
+// Holds the methods that don't require specialization to reduce template bloat.
+class CallbackBase {
+ public:
+ // Returns true if Callback is null (doesn't refer to anything).
+ bool is_null() const {
+ return invoker_storage_.get() == NULL;
+ }
+
+ // Returns the Callback into an uninitalized state.
+ void Reset() {
+ invoker_storage_ = NULL;
+ polymorphic_invoke_ = NULL;
+ }
+
+ bool Equals(const CallbackBase& other) const {
+ return invoker_storage_.get() == other.invoker_storage_.get() &&
+ polymorphic_invoke_ == other.polymorphic_invoke_;
+ }
+
+ protected:
+ // In C++, it is safe to cast function pointers to function pointers of
+ // another type. It is not okay to use void*. We create a InvokeFuncStorage
+ // that that can store our function pointer, and then cast it back to
+ // the original type on usage.
+ typedef void(*InvokeFuncStorage)(void);
+
+ CallbackBase(InvokeFuncStorage polymorphic_invoke,
+ scoped_refptr<InvokerStorageBase>* invoker_storage)
+ : polymorphic_invoke_(polymorphic_invoke) {
+ if (invoker_storage) {
+ invoker_storage_.swap(*invoker_storage);
+ }
+ }
+
+ scoped_refptr<InvokerStorageBase> invoker_storage_;
+ InvokeFuncStorage polymorphic_invoke_;
+};
+
+} // namespace internal
+
+
// 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.
@@ -226,17 +269,16 @@ namespace base {
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)> {
+class Callback<R(void)> : public internal::CallbackBase {
]] $else [[
template <typename R, $for ARG , [[typename A$(ARG)]]>
-class Callback<R($for ARG , [[A$(ARG)]])> {
+class Callback<R($for ARG , [[A$(ARG)]])> : public internal::CallbackBase {
]]
public:
@@ -245,7 +287,7 @@ $if ARITY != 0 [[, ]]
$for ARG ,
[[const A$(ARG)&]]);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -256,27 +298,21 @@ $for ARG ,
// 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_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::FunctionTraits::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
-
-$if ARITY == 0 [[
- R Run(void) const {
-]] $else [[
R Run($for ARG ,
[[const A$(ARG)& a$(ARG)]]) const {
-]]
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
- return polymorphic_invoke_(invoker_storage_.get()[[]]
+ return f(invoker_storage_.get()[[]]
$if ARITY != 0 [[, ]]
$for ARG ,
- [[a$(ARG)]]);
+ [[a$(ARG)]]);
}
-
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
};
diff --git a/base/callback_unittest.cc b/base/callback_unittest.cc
index bc15927..bf2b606 100644
--- a/base/callback_unittest.cc
+++ b/base/callback_unittest.cc
@@ -3,10 +3,12 @@
// found in the LICENSE file.
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace base {
namespace {
class HelperObject {
@@ -19,9 +21,24 @@ class HelperObject {
int next_number_;
};
-} // namespace
+struct FakeTraits {
+ static void DoInvoke(internal::InvokerStorageBase*) {
+ }
+};
+
+// White-box testpoints to inject into a Callback<> object for checking
+// comparators and emptiness APIs.
+class FakeInvokerStorage1 : public internal::InvokerStorageBase {
+ public:
+ typedef FakeTraits FunctionTraits;
+};
+
+class FakeInvokerStorage2 : public internal::InvokerStorageBase {
+ public:
+ typedef FakeTraits FunctionTraits;
+};
-TEST(Callback, OneArg) {
+TEST(CallbackOld, OneArg) {
HelperObject obj;
scoped_ptr<Callback1<int*>::Type> callback(
NewCallback(&obj, &HelperObject::GetNextNumberArg));
@@ -31,10 +48,83 @@ TEST(Callback, OneArg) {
EXPECT_EQ(number, 1);
}
-TEST(Callback, ReturnValue) {
+TEST(CallbackOld, ReturnValue) {
HelperObject obj;
scoped_ptr<CallbackWithReturnValue<int>::Type> callback(
NewCallbackWithReturnValue(&obj, &HelperObject::GetNextNumber));
EXPECT_EQ(callback->Run(), 1);
}
+
+class CallbackTest : public ::testing::Test {
+ public:
+ CallbackTest()
+ : callback_a_(MakeInvokerStorageHolder(new FakeInvokerStorage1())),
+ callback_b_(MakeInvokerStorageHolder(new FakeInvokerStorage2())) {
+ }
+
+ virtual ~CallbackTest() {
+ }
+
+ protected:
+ Callback<void(void)> callback_a_;
+ const Callback<void(void)> callback_b_; // Ensure APIs work with const.
+ Callback<void(void)> null_callback_;
+};
+
+// 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(CallbackTest, 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;
+
+ EXPECT_TRUE(c0.is_null());
+ EXPECT_TRUE(c1.is_null());
+ EXPECT_TRUE(c2.is_null());
+ EXPECT_TRUE(c3.is_null());
+ EXPECT_TRUE(c4.is_null());
+ EXPECT_TRUE(c5.is_null());
+ EXPECT_TRUE(c6.is_null());
+}
+
+TEST_F(CallbackTest, IsNull) {
+ EXPECT_TRUE(null_callback_.is_null());
+ EXPECT_FALSE(callback_a_.is_null());
+ EXPECT_FALSE(callback_b_.is_null());
+}
+
+TEST_F(CallbackTest, Equals) {
+ EXPECT_TRUE(callback_a_.Equals(callback_a_));
+ EXPECT_FALSE(callback_a_.Equals(callback_b_));
+ EXPECT_FALSE(callback_b_.Equals(callback_a_));
+
+ // We should compare based on instance, not type.
+ Callback<void(void)> callback_c(
+ MakeInvokerStorageHolder(new FakeInvokerStorage1()));
+ Callback<void(void)> callback_a2 = callback_a_;
+ EXPECT_TRUE(callback_a_.Equals(callback_a2));
+ EXPECT_FALSE(callback_a_.Equals(callback_c));
+
+ // Empty, however, is always equal to empty.
+ Callback<void(void)> empty2;
+ EXPECT_TRUE(null_callback_.Equals(empty2));
+}
+
+TEST_F(CallbackTest, Reset) {
+ // Resetting should bring us back to empty.
+ ASSERT_FALSE(callback_a_.is_null());
+ ASSERT_FALSE(callback_a_.Equals(null_callback_));
+
+ callback_a_.Reset();
+
+ EXPECT_TRUE(callback_a_.is_null());
+ EXPECT_TRUE(callback_a_.Equals(null_callback_));
+}
+
+} // namespace
+} // namespace base