Skip to content

Commit

Permalink
Remove BindStateHolder and have Bind() return a Callback<> object dir…
Browse files Browse the repository at this point in the history
…ectly.

This removes some complexity and also fixes a bug where if you call Bind() with the result of Bind(), the resulting Callback would only be valid during the first call.  Ouch.

BUG=none
TEST=new unittests


Review URL: http://codereview.chromium.org/8738001

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@114494 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
ajwong@chromium.org committed Dec 14, 2011
1 parent 30d170b commit e91ac22
Show file tree
Hide file tree
Showing 27 changed files with 342 additions and 281 deletions.
171 changes: 94 additions & 77 deletions base/bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@
namespace base {

template <typename Functor>
internal::BindStateHolder<
internal::BindState<
base::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void()> >
void()>
::UnboundRunType>
Bind(Functor functor) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
Expand All @@ -60,18 +61,20 @@ Bind(Functor functor) {
typedef internal::FunctionTraits<typename RunnableType::RunType>
BoundFunctorTraits;

typedef internal::BindState<RunnableType, RunType, void()> BindState;

return internal::MakeBindStateHolder(
new internal::BindState<RunnableType, RunType, void()>(
internal::MakeRunnable(functor)));

return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor)));
}

template <typename Functor, typename P1>
internal::BindStateHolder<
internal::BindState<
base::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType)> >
void(typename internal::CallbackParamTraits<P1>::StorageType)>
::UnboundRunType>
Bind(Functor functor, const P1& p1) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
Expand Down Expand Up @@ -103,20 +106,22 @@ Bind(Functor functor, const P1& p1) {
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
!is_array<P1>::value,
first_bound_argument_to_method_cannot_be_array);
typedef internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType)> BindState;


return internal::MakeBindStateHolder(
new internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType)>(
internal::MakeRunnable(functor), p1));
return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), p1));
}

template <typename Functor, typename P1, typename P2>
internal::BindStateHolder<
internal::BindState<
base::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType)> >
typename internal::CallbackParamTraits<P2>::StorageType)>
::UnboundRunType>
Bind(Functor functor, const P1& p1, const P2& p2) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
Expand Down Expand Up @@ -151,22 +156,24 @@ Bind(Functor functor, const P1& p1, const P2& p2) {
first_bound_argument_to_method_cannot_be_array);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
p2_is_refcounted_type_and_needs_scoped_refptr);
typedef internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType)> BindState;

return internal::MakeBindStateHolder(
new internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType)>(
internal::MakeRunnable(functor), p1, p2));

return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), p1, p2));
}

template <typename Functor, typename P1, typename P2, typename P3>
internal::BindStateHolder<
internal::BindState<
base::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType)> >
typename internal::CallbackParamTraits<P3>::StorageType)>
::UnboundRunType>
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
Expand Down Expand Up @@ -204,24 +211,26 @@ Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3) {
p2_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
p3_is_refcounted_type_and_needs_scoped_refptr);
typedef internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType)> BindState;


return internal::MakeBindStateHolder(
new internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType)>(
internal::MakeRunnable(functor), p1, p2, p3));
return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), p1, p2, p3));
}

template <typename Functor, typename P1, typename P2, typename P3, typename P4>
internal::BindStateHolder<
internal::BindState<
base::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType)> >
typename internal::CallbackParamTraits<P4>::StorageType)>
::UnboundRunType>
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4) {
// Typedefs for how to store and run the functor.
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
Expand Down Expand Up @@ -262,27 +271,29 @@ Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4) {
p3_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
p4_is_refcounted_type_and_needs_scoped_refptr);
typedef internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType)> BindState;

return internal::MakeBindStateHolder(
new internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType)>(
internal::MakeRunnable(functor), p1, p2, p3, p4));

return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4));
}

template <typename Functor, typename P1, typename P2, typename P3, typename P4,
typename P5>
internal::BindStateHolder<
internal::BindState<
base::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType)> >
typename internal::CallbackParamTraits<P5>::StorageType)>
::UnboundRunType>
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
const P5& p5) {
// Typedefs for how to store and run the functor.
Expand Down Expand Up @@ -327,29 +338,31 @@ Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
p4_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
p5_is_refcounted_type_and_needs_scoped_refptr);
typedef internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType)> BindState;


return internal::MakeBindStateHolder(
new internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType)>(
internal::MakeRunnable(functor), p1, p2, p3, p4, p5));
return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5));
}

template <typename Functor, typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6>
internal::BindStateHolder<
internal::BindState<
base::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType,
typename internal::CallbackParamTraits<P6>::StorageType)> >
typename internal::CallbackParamTraits<P6>::StorageType)>
::UnboundRunType>
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
const P5& p5, const P6& p6) {
// Typedefs for how to store and run the functor.
Expand Down Expand Up @@ -397,22 +410,23 @@ Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
p5_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P6>::value,
p6_is_refcounted_type_and_needs_scoped_refptr);
typedef internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType,
typename internal::CallbackParamTraits<P6>::StorageType)> BindState;

return internal::MakeBindStateHolder(
new internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType,
typename internal::CallbackParamTraits<P6>::StorageType)>(
internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6));

return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6));
}

template <typename Functor, typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6, typename P7>
internal::BindStateHolder<
internal::BindState<
base::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
Expand All @@ -421,7 +435,8 @@ internal::BindStateHolder<
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType,
typename internal::CallbackParamTraits<P6>::StorageType,
typename internal::CallbackParamTraits<P7>::StorageType)> >
typename internal::CallbackParamTraits<P7>::StorageType)>
::UnboundRunType>
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
const P5& p5, const P6& p6, const P7& p7) {
// Typedefs for how to store and run the functor.
Expand Down Expand Up @@ -472,17 +487,19 @@ Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
p6_is_refcounted_type_and_needs_scoped_refptr);
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P7>::value,
p7_is_refcounted_type_and_needs_scoped_refptr);

return internal::MakeBindStateHolder(
new internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType,
typename internal::CallbackParamTraits<P6>::StorageType,
typename internal::CallbackParamTraits<P7>::StorageType)>(
internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6, p7));
typedef internal::BindState<RunnableType, RunType,
void(typename internal::CallbackParamTraits<P1>::StorageType,
typename internal::CallbackParamTraits<P2>::StorageType,
typename internal::CallbackParamTraits<P3>::StorageType,
typename internal::CallbackParamTraits<P4>::StorageType,
typename internal::CallbackParamTraits<P5>::StorageType,
typename internal::CallbackParamTraits<P6>::StorageType,
typename internal::CallbackParamTraits<P7>::StorageType)> BindState;


return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6,
p7));
}

} // namespace base
Expand Down
17 changes: 10 additions & 7 deletions base/bind.h.pump
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,12 @@ $range ARG 1..ARITY

template <typename Functor[[]]
$if ARITY > 0 [[, ]] $for ARG , [[typename P$(ARG)]]>
internal::BindStateHolder<
internal::BindState<
base::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
void($for ARG , [[typename internal::CallbackParamTraits<P$(ARG)>::StorageType]])> >
void($for ARG , [[typename internal::CallbackParamTraits<P$(ARG)>::StorageType]])>
::UnboundRunType>
Bind(Functor functor
$if ARITY > 0 [[, ]] $for ARG , [[const P$(ARG)& p$(ARG)]]) {
// Typedefs for how to store and run the functor.
Expand Down Expand Up @@ -125,11 +126,13 @@ $if ARG == 1 [[

]] $$ $for ARG

typedef internal::BindState<RunnableType, RunType, [[]]
void($for ARG , [[typename internal::CallbackParamTraits<P$(ARG)>::StorageType]])> [[]]
BindState;

return internal::MakeBindStateHolder(
new internal::BindState<RunnableType, RunType, [[]]
void($for ARG , [[typename internal::CallbackParamTraits<P$(ARG)>::StorageType]])>(
internal::MakeRunnable(functor)[[]]

return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor)[[]]
$if ARITY > 0 [[, ]] $for ARG , [[p$(ARG)]]));
}

Expand Down
27 changes: 27 additions & 0 deletions base/bind_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,18 @@ void RefArgSet(int &n) {
n = 2;
}

void PtrArgSet(int *n) {
*n = 2;
}

int FunctionWithWeakFirstParam(WeakPtr<NoRef> o, int n) {
return n;
}

void TakesACallback(const Closure& callback) {
callback.Run();
}

class BindTest : public ::testing::Test {
public:
BindTest() {
Expand Down Expand Up @@ -284,6 +292,25 @@ TEST_F(BindTest, CurryingTest) {
EXPECT_EQ(63, c0.Run());
}

// Test that currying the rvalue result of another Bind() works correctly.
// - rvalue should be usable as argument to Bind().
// - multiple runs of resulting Callback remain valid.
TEST_F(BindTest, CurryingRvalueResultOfBind) {
int n = 0;
Closure cb = base::Bind(&TakesACallback, base::Bind(&PtrArgSet, &n));

// If we implement Bind() such that the return value has auto_ptr-like
// semantics, the second call here will fail because ownership of
// the internal BindState<> would have been transfered to a *temporary*
// constructon of a Callback object on the first call.
cb.Run();
EXPECT_EQ(2, n);

n = 0;
cb.Run();
EXPECT_EQ(2, n);
}

// Function type support.
// - Normal function.
// - Normal function bound with non-refcounted first argument.
Expand Down
Loading

0 comments on commit e91ac22

Please sign in to comment.