Add getSemiFuture to folly::Promise
authorLee Howes <lwh@fb.com>
Sat, 23 Dec 2017 03:29:14 +0000 (19:29 -0800)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Sat, 23 Dec 2017 03:36:47 +0000 (19:36 -0800)
Summary: Also deprecates folly::getFuture function.

Reviewed By: yfeldblum

Differential Revision: D6594299

fbshipit-source-id: 67435f35dca660da049cd8c505ee9a21424c0d2b

folly/futures/Future.h
folly/futures/Promise-inl.h
folly/futures/Promise.h
folly/futures/test/PromiseTest.cpp
folly/futures/test/SemiFutureTest.cpp

index 5eda2c34b4d9c8d263815bfe3f1ea9b1b269440f..2179623b593db88ac2fa92cbaa55d213182a6bc5 100644 (file)
@@ -312,6 +312,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
   void boost_();
 
  private:
+  friend class Promise<T>;
   template <class>
   friend class futures::detail::FutureBase;
   template <class>
index 5c06d3035a543f40c680aea8cc581c1f3394541f..45e6929a9152a7bc0bf4750cf7583e8da4a684e3 100644 (file)
@@ -19,6 +19,7 @@
 #include <atomic>
 #include <thread>
 
+#include <folly/executors/InlineExecutor.h>
 #include <folly/futures/FutureException.h>
 #include <folly/futures/detail/Core.h>
 
@@ -85,10 +86,17 @@ void Promise<T>::detach() {
 }
 
 template <class T>
-Future<T> Promise<T>::getFuture() {
+SemiFuture<T> Promise<T>::getSemiFuture() {
   throwIfRetrieved();
   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>
index 7bb58d1e8abfaa61c9ff4f9d303848472013fa8d..359651324c19c15b3ce8a5907ed29a720b914543 100644 (file)
@@ -53,8 +53,15 @@ class Promise {
   Promise(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
-    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();
 
   /** Fulfill the Promise with an exception_wrapper */
index 509aa7aa6edbb9524c672e8ad95d3916665e0a06..e5796d19bf0303a46f8f0a494969a84979fcbddb 100644 (file)
@@ -20,9 +20,9 @@
 #include <memory>
 
 using namespace folly;
-using std::unique_ptr;
 using std::string;
 
+using std::unique_ptr;
 typedef FutureException eggs_t;
 static eggs_t eggs("eggs");
 
@@ -38,6 +38,12 @@ TEST(Promise, special) {
   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) {
   Promise<int> p;
   Future<int> f = p.getFuture();
@@ -49,6 +55,44 @@ TEST(Promise, setValueUnit) {
   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) {
   Promise<int> fund;
   auto ffund = fund.getFuture();
index 7b927021e7dce159d36982857e4b0ccf1a53cb97..b5c059daef2e0dcfe65a3779d94d982d6c6b9507 100644 (file)
@@ -171,7 +171,7 @@ TEST(SemiFuture, MakeSemiFutureFromFutureWithValue) {
 
 TEST(SemiFuture, MakeSemiFutureFromReadyFuture) {
   Promise<int> p;
-  auto f = SemiFuture<int>{p.getFuture()};
+  auto f = p.getSemiFuture();
   EXPECT_FALSE(f.isReady());
   p.setValue(42);
   EXPECT_TRUE(f.isReady());
@@ -179,7 +179,7 @@ TEST(SemiFuture, MakeSemiFutureFromReadyFuture) {
 
 TEST(SemiFuture, MakeSemiFutureFromNotReadyFuture) {
   Promise<int> p;
-  auto f = SemiFuture<int>{p.getFuture()};
+  auto f = p.getSemiFuture();
   EXPECT_THROW(f.value(), eggs_t);
 }
 
@@ -187,7 +187,7 @@ TEST(SemiFuture, MakeFutureFromSemiFuture) {
   folly::EventBase e;
   Promise<int> p;
   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) {
     result = value;
     return value;
@@ -206,7 +206,7 @@ TEST(SemiFuture, MakeFutureFromSemiFutureLValue) {
   folly::EventBase e;
   Promise<int> p;
   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) {
     result = value;
     return value;