From d167b41554b659b3c0966210b17f6e038eb11648 Mon Sep 17 00:00:00 2001 From: Hans Fugal Date: Thu, 11 Jun 2015 11:51:06 -0700 Subject: [PATCH] folly::via(Executor*, Func) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Summary: ((not yet) more performant) sugar for `via(&x).then(func)` Reviewed By: @​hannesr Differential Revision: D2131246 --- folly/futures/Future-inl.h | 11 ++++++++ folly/futures/helpers.h | 11 ++++++-- folly/futures/test/ViaTest.cpp | 51 +++++++++++++++++++++++++++++++++- 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/folly/futures/Future-inl.h b/folly/futures/Future-inl.h index 0b2a301c..59498af9 100644 --- a/folly/futures/Future-inl.h +++ b/folly/futures/Future-inl.h @@ -435,6 +435,17 @@ inline Future Future::via(Executor* executor, int8_t priority) & { return std::move(f).via(executor, priority); } + +template +auto via(Executor* x, Func func) + -> Future::Inner> +// this would work, if not for Future :-/ +// -> decltype(via(x).then(func)) +{ + // TODO make this actually more performant. :-P #7260175 + return via(x).then(func); +} + template bool Future::isReady() const { throwIfInvalid(); diff --git a/folly/futures/helpers.h b/folly/futures/helpers.h index 5ae28f1f..c099f580 100644 --- a/folly/futures/helpers.h +++ b/folly/futures/helpers.h @@ -56,7 +56,7 @@ namespace futures { return map(c.begin(), c.end(), std::forward(func)); } -} +} // namespace futures /** Make a completed Future by moving in a value. e.g. @@ -124,6 +124,13 @@ inline Future via( Executor* executor, int8_t priority = Executor::MID_PRI); +/// Execute a function via the given executor and return a future. +/// This is semantically equivalent to via(executor).then(func), but +/// easier to read and slightly more efficient. +template +auto via(Executor*, Func func) + -> Future::Inner>; + /** When all the input Futures complete, the returned Future will complete. Errors do not cause early termination; this Future will always succeed after all its Futures have finished (whether successfully or with an @@ -286,4 +293,4 @@ auto unorderedReduce(Collection&& c, T&& initial, F&& func) std::forward(func)); } -} // namespace folly +} // namespace diff --git a/folly/futures/test/ViaTest.cpp b/folly/futures/test/ViaTest.cpp index 72b2e1e8..499d61d4 100644 --- a/folly/futures/test/ViaTest.cpp +++ b/folly/futures/test/ViaTest.cpp @@ -415,7 +415,7 @@ TEST(Via, viaRaces) { t2.join(); } -TEST(Future, callbackRace) { +TEST(Via, callbackRace) { ThreadExecutor x; auto fn = [&x]{ @@ -441,3 +441,52 @@ TEST(Future, callbackRace) { fn().wait(); } + +TEST(ViaFunc, liftsVoid) { + ManualExecutor x; + int count = 0; + Future f = via(&x, [&]{ count++; }); + + EXPECT_EQ(0, count); + x.run(); + EXPECT_EQ(1, count); +} + +TEST(ViaFunc, value) { + ManualExecutor x; + EXPECT_EQ(42, via(&x, []{ return 42; }).getVia(&x)); +} + +TEST(ViaFunc, exception) { + ManualExecutor x; + EXPECT_THROW( + via(&x, []() -> int { throw std::runtime_error("expected"); }) + .getVia(&x), + std::runtime_error); +} + +TEST(ViaFunc, future) { + ManualExecutor x; + EXPECT_EQ(42, via(&x, []{ return makeFuture(42); }) + .getVia(&x)); +} + +TEST(ViaFunc, voidFuture) { + ManualExecutor x; + int count = 0; + via(&x, [&]{ count++; }).getVia(&x); + EXPECT_EQ(1, count); +} + +TEST(ViaFunc, isSticky) { + ManualExecutor x; + int count = 0; + + auto f = via(&x, [&]{ count++; }); + x.run(); + + f.then([&]{ count++; }); + EXPECT_EQ(1, count); + x.run(); + EXPECT_EQ(2, count); +} -- 2.34.1