Commit 57b57616 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Introduce makePromiseContract

Summary:
[Folly] Introduce makePromiseContract, for producing a paired promise-and-semi-future or a paired promise-and-future, depending on which overload is invoked.

It is not ideal that a future is gotten from a promise, but only once. Rather, it is ideal that they be created together.

C++17 code may use structured bindings:
```lang=c++
auto [p, f] = makePromiseContract(); // promise with semi-future
auto [p, f] = makePromiseContract(&e); // promise with future, given executor e
```

Reviewed By: LeeHowes

Differential Revision: D7984050

fbshipit-source-id: 52ee5624fde7c48aa0e81243564ad067c6c6919f
parent 4d6d653e
...@@ -521,6 +521,13 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -521,6 +521,13 @@ class SemiFuture : private futures::detail::FutureBase<T> {
static void releaseDeferredExecutor(corePtr core); static void releaseDeferredExecutor(corePtr core);
}; };
template <class T>
std::pair<Promise<T>, SemiFuture<T>> makePromiseContract() {
auto p = Promise<T>();
auto f = p.getSemiFuture();
return std::make_pair(std::move(p), std::move(f));
}
template <class T> template <class T>
class Future : private futures::detail::FutureBase<T> { class Future : private futures::detail::FutureBase<T> {
private: private:
...@@ -1008,6 +1015,13 @@ class Timekeeper { ...@@ -1008,6 +1015,13 @@ class Timekeeper {
Future<Unit> at(std::chrono::time_point<Clock> when); Future<Unit> at(std::chrono::time_point<Clock> when);
}; };
template <class T>
std::pair<Promise<T>, Future<T>> makePromiseContract(Executor* e) {
auto p = Promise<T>();
auto f = p.getSemiFuture().via(e);
return std::make_pair(std::move(p), std::move(f));
}
} // namespace folly } // namespace folly
#if FOLLY_HAS_COROUTINES #if FOLLY_HAS_COROUTINES
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include <numeric> #include <numeric>
#include <queue>
#include <string> #include <string>
#include <thread> #include <thread>
#include <type_traits> #include <type_traits>
...@@ -1176,3 +1177,32 @@ TEST(Future, futureWithinNoValueReferenceWhenTimeOut) { ...@@ -1176,3 +1177,32 @@ TEST(Future, futureWithinNoValueReferenceWhenTimeOut) {
EXPECT_EQ(0, callbackInput.value().use_count()); EXPECT_EQ(0, callbackInput.value().use_count());
}); });
} }
TEST(Future, makePromiseContract) {
class ManualExecutor : public Executor {
private:
std::queue<Func> queue_;
public:
void add(Func f) override {
queue_.push(std::move(f));
}
void drain() {
while (!queue_.empty()) {
auto f = std::move(queue_.front());
queue_.pop();
f();
}
}
};
ManualExecutor e;
auto c = makePromiseContract<int>(&e);
c.second = std::move(c.second).then([](int _) { return _ + 1; });
EXPECT_FALSE(c.second.isReady());
c.first.setValue(3);
EXPECT_FALSE(c.second.isReady());
e.drain();
ASSERT_TRUE(c.second.isReady());
EXPECT_EQ(4, std::move(c.second).get());
}
...@@ -1015,3 +1015,10 @@ TEST(SemiFuture, onError) { ...@@ -1015,3 +1015,10 @@ TEST(SemiFuture, onError) {
EXPECT_FLAG(); EXPECT_FLAG();
} }
} }
TEST(SemiFuture, makePromiseContract) {
auto c = makePromiseContract<int>();
c.first.setValue(3);
c.second = std::move(c.second).deferValue([](int _) { return _ + 1; });
EXPECT_EQ(4, std::move(c.second).get());
}
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