Skip to content

Commit

Permalink
Allow Bind() to take a Callback<> and bind all its free parameters.
Browse files Browse the repository at this point in the history
Basically, turns base::Callback<void(...)> to base::Closure.

It turns out there are a number of use caess where an API takes a callback, and then wants to invoke the Callback on another thread. This piece of syntactic sugar removes the need for custom helper functions.

This isn't quite full currying, however it is much simpler to implement.  

BUG=87287
TEST=none


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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@103446 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
ajwong@chromium.org committed Sep 30, 2011
1 parent f3f0da4 commit cea20fe
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 0 deletions.
46 changes: 46 additions & 0 deletions base/bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// DO NOT EDIT BY HAND!!!



// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
Expand Down Expand Up @@ -94,6 +95,51 @@ Bind(Sig f, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
f, p1, p2, p3, p4, p5, p6));
}

// Specializations to allow binding all the free arguments in a
// pre-existing base::Callback<>. This does not give full support for
// currying, but is significantly simpler and addresses the use case
// where a base::Callback<> needs to be invoked on another context/thread.
template <typename Sig, typename P1>
base::Closure Bind(const base::Callback<Sig>& callback, const P1& p1) {
return base::Bind(&internal::BindMoreFunc1<Sig, P1>, callback, p1);
}

template <typename Sig, typename P1, typename P2>
base::Closure Bind(const base::Callback<Sig>& callback, const P1& p1,
const P2& p2) {
return base::Bind(&internal::BindMoreFunc2<Sig, P1, P2>, callback, p1, p2);
}

template <typename Sig, typename P1, typename P2, typename P3>
base::Closure Bind(const base::Callback<Sig>& callback, const P1& p1,
const P2& p2, const P3& p3) {
return base::Bind(&internal::BindMoreFunc3<Sig, P1, P2, P3>, callback, p1,
p2, p3);
}

template <typename Sig, typename P1, typename P2, typename P3, typename P4>
base::Closure Bind(const base::Callback<Sig>& callback, const P1& p1,
const P2& p2, const P3& p3, const P4& p4) {
return base::Bind(&internal::BindMoreFunc4<Sig, P1, P2, P3, P4>, callback,
p1, p2, p3, p4);
}

template <typename Sig, typename P1, typename P2, typename P3, typename P4,
typename P5>
base::Closure Bind(const base::Callback<Sig>& callback, const P1& p1,
const P2& p2, const P3& p3, const P4& p4, const P5& p5) {
return base::Bind(&internal::BindMoreFunc5<Sig, P1, P2, P3, P4, P5>,
callback, p1, p2, p3, p4, p5);
}

template <typename Sig, typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6>
base::Closure Bind(const base::Callback<Sig>& callback, const P1& p1,
const P2& p2, const P3& p3, const P4& p4, const P5& p5, const P6& p6) {
return base::Bind(&internal::BindMoreFunc6<Sig, P1, P2, P3, P4, P5, P6>,
callback, p1, p2, p3, p4, p5, p6);
}

} // namespace base

#endif // BASE_BIND_H_
20 changes: 20 additions & 0 deletions base/bind.h.pump
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,26 @@ $for BOUND_ARG , [[P$(BOUND_ARG)]]>(
f, $for BOUND_ARG , [[p$(BOUND_ARG)]]));
}

]]
]] $$ for BOUND

// Specializations to allow binding all the free arguments in a
// pre-existing base::Callback<>. This does not give full support for
// currying, but is significantly simpler and addresses the use case
// where a base::Callback<> needs to be invoked on another context/thread.
$for BOUND [[
$range BOUND_ARG 1..BOUND
$if BOUND != 0 [[

template <typename Sig, $for BOUND_ARG , [[typename P$(BOUND_ARG)]]>
base::Closure Bind(const base::Callback<Sig>& callback, [[]]
$for BOUND_ARG , [[const P$(BOUND_ARG)& p$(BOUND_ARG)]]) {
return base::Bind([[]]
&internal::BindMoreFunc$(BOUND)<Sig, $for BOUND_ARG , [[P$(BOUND_ARG)]]>, [[]]
callback, [[]]
$for BOUND_ARG , [[p$(BOUND_ARG)]]);
}

]]

]] $$ for BOUND
Expand Down
41 changes: 41 additions & 0 deletions base/bind_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1721,6 +1721,47 @@ struct Invoker6<true, StorageType, void(T::*)(X1, X2, X3, X4, X5)> {
}
};

// BindMoreFuncN<>
//
// This set of functions help in fully binding the free parameters in a
// Callback<>.
template <typename Sig, typename P1>
void BindMoreFunc1(const base::Callback<Sig>& callback, const P1& p1) {
callback.Run(p1);
}

template <typename Sig, typename P1, typename P2>
void BindMoreFunc2(const base::Callback<Sig>& callback, const P1& p1,
const P2& p2) {
callback.Run(p1, p2);
}

template <typename Sig, typename P1, typename P2, typename P3>
void BindMoreFunc3(const base::Callback<Sig>& callback, const P1& p1,
const P2& p2, const P3& p3) {
callback.Run(p1, p2, p3);
}

template <typename Sig, typename P1, typename P2, typename P3, typename P4>
void BindMoreFunc4(const base::Callback<Sig>& callback, const P1& p1,
const P2& p2, const P3& p3, const P4& p4) {
callback.Run(p1, p2, p3, p4);
}

template <typename Sig, typename P1, typename P2, typename P3, typename P4,
typename P5>
void BindMoreFunc5(const base::Callback<Sig>& callback, const P1& p1,
const P2& p2, const P3& p3, const P4& p4, const P5& p5) {
callback.Run(p1, p2, p3, p4, p5);
}

template <typename Sig, typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6>
void BindMoreFunc6(const base::Callback<Sig>& callback, const P1& p1,
const P2& p2, const P3& p3, const P4& p4, const P5& p5, const P6& p6) {
callback.Run(p1, p2, p3, p4, p5, p6);
}

// InvokerStorageN<>
//
// These are the actual storage classes for the Invokers.
Expand Down
17 changes: 17 additions & 0 deletions base/bind_internal.h.pump
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,23 @@ $for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]);
]] $$ for ARITY
]] $$ for BOUND

// BindMoreFuncN<>
//
// This set of functions help in fully binding the free parameters in a
// Callback<>.
$for BOUND [[
$range BOUND_ARG 1..BOUND
$if BOUND != 0 [[

template <typename Sig, $for BOUND_ARG , [[typename P$(BOUND_ARG)]]>
void BindMoreFunc$(BOUND)(const base::Callback<Sig>& callback, [[]]
$for BOUND_ARG , [[const P$(BOUND_ARG)& p$(BOUND_ARG)]]) {
callback.Run($for BOUND_ARG , [[p$(BOUND_ARG)]]);
}

]] $$ if BOUND
]] $$ for BOUND

// InvokerStorageN<>
//
// These are the actual storage classes for the Invokers.
Expand Down
35 changes: 35 additions & 0 deletions base/bind_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ int Sum(int a, int b, int c, int d, int e, int f) {
return a + b + c + d + e + f;
}

void OutputSum(int* output, int a, int b, int c, int d, int e) {
*output = a + b + c + d + e;
}

const char* CStringIdentity(const char* s) {
return s;
}
Expand Down Expand Up @@ -243,6 +247,37 @@ TEST_F(BindTest, ArityTest) {
EXPECT_EQ(69, c6.Run(13, 12, 11, 10, 9, 14));
}

// Bind should be able to take existing Callbacks and convert to a Closure.
TEST_F(BindTest, CallbackBindMore) {
int output = 0;
Closure c;

Callback<void(int)> c1 = Bind(&OutputSum, &output, 16, 8, 4, 2);
c = Bind(c1, 10);
c.Run();
EXPECT_EQ(40, output);

Callback<void(int,int)> c2 = Bind(&OutputSum, &output, 16, 8, 4);
c = Bind(c2, 10, 9);
c.Run();
EXPECT_EQ(47, output);

Callback<void(int,int,int)> c3 = Bind(&OutputSum, &output, 16, 8);
c = Bind(c3, 10, 9, 8);
c.Run();
EXPECT_EQ(51, output);

Callback<void(int,int,int,int)> c4 = Bind(&OutputSum, &output, 16);
c = Bind(c4, 10, 9, 8, 7);
c.Run();
EXPECT_EQ(50, output);

Callback<void(int,int,int,int,int)> c5 = Bind(&OutputSum, &output);
c = Bind(c5, 10, 9, 8, 7, 6);
c.Run();
EXPECT_EQ(40, output);
}

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

0 comments on commit cea20fe

Please sign in to comment.