From 4733fd1c76d97fa6267d789c6c0b2d41749a885c Mon Sep 17 00:00:00 2001 From: Hannes Roth Date: Fri, 7 Mar 2014 08:02:11 -0800 Subject: [PATCH] (Wangle) Support .then(function pointer) syntax Summary: Support `.then(&static_function)`, `.then(&static_member_function)`, `.then(&Class::static_member_function)`, `.then(instance, &Class::member_function)` in Wangle. C++ does not allow `.then(instance, &member_function)`, sadly. This implementation just creates the closure for you and defers to the existing `then` implementations. Test Plan: Added a test. Reviewed By: hans@fb.com FB internal diff: D1204954 --- folly/wangle/Future.h | 66 +++++++++++++++++++++++++++++++- folly/wangle/test/FutureTest.cpp | 44 +++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/folly/wangle/Future.h b/folly/wangle/Future.h index d89f7134..3b13b194 100644 --- a/folly/wangle/Future.h +++ b/folly/wangle/Future.h @@ -100,7 +100,7 @@ class Future { Future&&)>::type> >::type then(F&& func); - /// Variant where func returns a future instead of a T. e.g. + /// Variant where func returns a Future instead of a T. e.g. /// /// Future f2 = f1.then( /// [](Try&&) { return makeFuture("foo"); }); @@ -110,6 +110,70 @@ class Future { Future&&)>::type::value_type> >::type then(F&& func); + /// Variant where func is an ordinary function (static method, method) + /// + /// R doWork(Try&&); + /// + /// Future f2 = f1.then(doWork); + /// + /// or + /// + /// struct Worker { + /// static R doWork(Try&&); } + /// + /// Future f2 = f1.then(&Worker::doWork); + template + typename std::enable_if::value, Future>::type + inline then(R(*func)(Try&&)) { + return then([func](Try&& t) { + return (*func)(std::move(t)); + }); + } + + /// Variant where func returns a Future instead of a R. e.g. + /// + /// struct Worker { + /// Future doWork(Try&&); } + /// + /// Future f2 = f1.then(&Worker::doWork); + template + typename std::enable_if::value, R>::type + inline then(R(*func)(Try&&)) { + return then([func](Try&& t) { + return (*func)(std::move(t)); + }); + } + + /// Variant where func is an member function + /// + /// struct Worker { + /// R doWork(Try&&); } + /// + /// Worker *w; + /// Future f2 = f1.then(w, &Worker::doWork); + template + typename std::enable_if::value, Future>::type + inline then(Caller *instance, R(Caller::*func)(Try&&)) { + return then([instance, func](Try&& t) { + return (instance->*func)(std::move(t)); + }); + } + + /// Variant where func returns a Future instead of a R. e.g. + /// + /// struct Worker { + /// Future doWork(Try&&); } + /// + /// Worker *w; + /// Future f2 = f1.then(w, &Worker::doWork); + template + typename std::enable_if::value, R>::type + inline then(Caller *instance, R(Caller::*func)(Try&&)) { + return then([instance, func](Try&& t) { + return (instance->*func)(std::move(t)); + }); + } + /// Convenience method for ignoring the value and creating a Future. /// Exceptions still propagate. Future then(); diff --git a/folly/wangle/test/FutureTest.cpp b/folly/wangle/test/FutureTest.cpp index e5906058..8afbdc17 100644 --- a/folly/wangle/test/FutureTest.cpp +++ b/folly/wangle/test/FutureTest.cpp @@ -91,6 +91,50 @@ TEST(Future, then) { EXPECT_TRUE(f.isReady()); } +static string doWorkStatic(Try&& t) { + return t.value() + ";static"; +} + +TEST(Future, thenFunction) { + struct Worker { + string doWork(Try&& t) { + return t.value() + ";class"; + } + static string doWorkStatic(Try&& t) { + return t.value() + ";class-static"; + } + } w; + + auto f = makeFuture("start") + .then(doWorkStatic) + .then(Worker::doWorkStatic) + .then(&w, &Worker::doWork); + + EXPECT_EQ(f.value(), "start;static;class-static;class"); +} + +static Future doWorkStaticFuture(Try&& t) { + return makeFuture(t.value() + ";static"); +} + +TEST(Future, thenFunctionFuture) { + struct Worker { + Future doWorkFuture(Try&& t) { + return makeFuture(t.value() + ";class"); + } + static Future doWorkStaticFuture(Try&& t) { + return makeFuture(t.value() + ";class-static"); + } + } w; + + auto f = makeFuture("start") + .then(doWorkStaticFuture) + .then(Worker::doWorkStaticFuture) + .then(&w, &Worker::doWorkFuture); + + EXPECT_EQ(f.value(), "start;static;class-static;class"); +} + TEST(Future, value) { auto f = makeFuture(unique_ptr(new int(42))); auto up = std::move(f.value()); -- 2.34.1