Commit 48b9743d authored by Lee Howes's avatar Lee Howes Committed by Facebook Github Bot

Add getSemiFuture to folly::Promise

Summary: Also deprecates folly::getFuture function.

Reviewed By: yfeldblum

Differential Revision: D6594299

fbshipit-source-id: 67435f35dca660da049cd8c505ee9a21424c0d2b
parent e951fd70
...@@ -312,6 +312,7 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -312,6 +312,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
void boost_(); void boost_();
private: private:
friend class Promise<T>;
template <class> template <class>
friend class futures::detail::FutureBase; friend class futures::detail::FutureBase;
template <class> template <class>
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <atomic> #include <atomic>
#include <thread> #include <thread>
#include <folly/executors/InlineExecutor.h>
#include <folly/futures/FutureException.h> #include <folly/futures/FutureException.h>
#include <folly/futures/detail/Core.h> #include <folly/futures/detail/Core.h>
...@@ -85,10 +86,17 @@ void Promise<T>::detach() { ...@@ -85,10 +86,17 @@ void Promise<T>::detach() {
} }
template <class T> template <class T>
Future<T> Promise<T>::getFuture() { SemiFuture<T> Promise<T>::getSemiFuture() {
throwIfRetrieved(); throwIfRetrieved();
retrieved_ = true; retrieved_ = true;
return Future<T>(core_); return SemiFuture<T>(core_);
}
template <class T>
Future<T> Promise<T>::getFuture() {
// An InlineExecutor approximates the old behaviour of continuations
// running inine on setting the value of the promise.
return getSemiFuture().via(&InlineExecutor::instance());
} }
template <class T> template <class T>
......
...@@ -53,8 +53,15 @@ class Promise { ...@@ -53,8 +53,15 @@ class Promise {
Promise(Promise<T>&&) noexcept; Promise(Promise<T>&&) noexcept;
Promise& operator=(Promise<T>&&) noexcept; Promise& operator=(Promise<T>&&) noexcept;
/** Return a SemiFuture tied to the shared core state. This can be called only
once, thereafter FutureAlreadyRetrieved exception will be raised. */
SemiFuture<T> getSemiFuture();
/** Return a Future tied to the shared core state. This can be called only /** Return a Future tied to the shared core state. This can be called only
once, thereafter Future already retrieved exception will be raised. */ once, thereafter FutureAlreadyRetrieved exception will be raised.
NOTE: This function is deprecated. Please use getSemiFuture and pass the
appropriate executor to .via on the returned SemiFuture to get a
valid Future where necessary. */
Future<T> getFuture(); Future<T> getFuture();
/** Fulfill the Promise with an exception_wrapper */ /** Fulfill the Promise with an exception_wrapper */
......
...@@ -20,9 +20,9 @@ ...@@ -20,9 +20,9 @@
#include <memory> #include <memory>
using namespace folly; using namespace folly;
using std::unique_ptr;
using std::string; using std::string;
using std::unique_ptr;
typedef FutureException eggs_t; typedef FutureException eggs_t;
static eggs_t eggs("eggs"); static eggs_t eggs("eggs");
...@@ -38,6 +38,12 @@ TEST(Promise, special) { ...@@ -38,6 +38,12 @@ TEST(Promise, special) {
EXPECT_TRUE(std::is_move_assignable<Promise<int>>::value); EXPECT_TRUE(std::is_move_assignable<Promise<int>>::value);
} }
TEST(Promise, getSemiFuture) {
Promise<int> p;
SemiFuture<int> f = p.getSemiFuture();
EXPECT_FALSE(f.isReady());
}
TEST(Promise, getFuture) { TEST(Promise, getFuture) {
Promise<int> p; Promise<int> p;
Future<int> f = p.getFuture(); Future<int> f = p.getFuture();
...@@ -49,6 +55,44 @@ TEST(Promise, setValueUnit) { ...@@ -49,6 +55,44 @@ TEST(Promise, setValueUnit) {
p.setValue(); p.setValue();
} }
TEST(Promise, setValueSemiFuture) {
Promise<int> fund;
auto ffund = fund.getSemiFuture();
fund.setValue(42);
EXPECT_EQ(42, ffund.value());
struct Foo {
string name;
int value;
};
Promise<Foo> pod;
auto fpod = pod.getSemiFuture();
Foo f = {"the answer", 42};
pod.setValue(f);
Foo f2 = fpod.value();
EXPECT_EQ(f.name, f2.name);
EXPECT_EQ(f.value, f2.value);
pod = Promise<Foo>();
fpod = pod.getSemiFuture();
pod.setValue(std::move(f2));
Foo f3 = fpod.value();
EXPECT_EQ(f.name, f3.name);
EXPECT_EQ(f.value, f3.value);
Promise<unique_ptr<int>> mov;
auto fmov = mov.getSemiFuture();
mov.setValue(std::make_unique<int>(42));
unique_ptr<int> ptr = std::move(fmov.value());
EXPECT_EQ(42, *ptr);
Promise<Unit> v;
auto fv = v.getSemiFuture();
v.setValue();
EXPECT_TRUE(fv.isReady());
}
TEST(Promise, setValue) { TEST(Promise, setValue) {
Promise<int> fund; Promise<int> fund;
auto ffund = fund.getFuture(); auto ffund = fund.getFuture();
......
...@@ -171,7 +171,7 @@ TEST(SemiFuture, MakeSemiFutureFromFutureWithValue) { ...@@ -171,7 +171,7 @@ TEST(SemiFuture, MakeSemiFutureFromFutureWithValue) {
TEST(SemiFuture, MakeSemiFutureFromReadyFuture) { TEST(SemiFuture, MakeSemiFutureFromReadyFuture) {
Promise<int> p; Promise<int> p;
auto f = SemiFuture<int>{p.getFuture()}; auto f = p.getSemiFuture();
EXPECT_FALSE(f.isReady()); EXPECT_FALSE(f.isReady());
p.setValue(42); p.setValue(42);
EXPECT_TRUE(f.isReady()); EXPECT_TRUE(f.isReady());
...@@ -179,7 +179,7 @@ TEST(SemiFuture, MakeSemiFutureFromReadyFuture) { ...@@ -179,7 +179,7 @@ TEST(SemiFuture, MakeSemiFutureFromReadyFuture) {
TEST(SemiFuture, MakeSemiFutureFromNotReadyFuture) { TEST(SemiFuture, MakeSemiFutureFromNotReadyFuture) {
Promise<int> p; Promise<int> p;
auto f = SemiFuture<int>{p.getFuture()}; auto f = p.getSemiFuture();
EXPECT_THROW(f.value(), eggs_t); EXPECT_THROW(f.value(), eggs_t);
} }
...@@ -187,7 +187,7 @@ TEST(SemiFuture, MakeFutureFromSemiFuture) { ...@@ -187,7 +187,7 @@ TEST(SemiFuture, MakeFutureFromSemiFuture) {
folly::EventBase e; folly::EventBase e;
Promise<int> p; Promise<int> p;
std::atomic<int> result{0}; std::atomic<int> result{0};
auto f = SemiFuture<int>{p.getFuture()}; auto f = p.getSemiFuture();
auto future = std::move(f).via(&e).then([&](int value) { auto future = std::move(f).via(&e).then([&](int value) {
result = value; result = value;
return value; return value;
...@@ -206,7 +206,7 @@ TEST(SemiFuture, MakeFutureFromSemiFutureLValue) { ...@@ -206,7 +206,7 @@ TEST(SemiFuture, MakeFutureFromSemiFutureLValue) {
folly::EventBase e; folly::EventBase e;
Promise<int> p; Promise<int> p;
std::atomic<int> result{0}; std::atomic<int> result{0};
auto f = SemiFuture<int>{p.getFuture()}; auto f = p.getSemiFuture();
auto future = std::move(f).via(&e).then([&](int value) { auto future = std::move(f).via(&e).then([&](int value) {
result = value; result = value;
return value; return value;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment