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> {
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>
class Future : private futures::detail::FutureBase<T> {
private:
......@@ -1008,6 +1015,13 @@ class Timekeeper {
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
#if FOLLY_HAS_COROUTINES
......
......@@ -26,6 +26,7 @@
#include <atomic>
#include <memory>
#include <numeric>
#include <queue>
#include <string>
#include <thread>
#include <type_traits>
......@@ -1176,3 +1177,32 @@ TEST(Future, futureWithinNoValueReferenceWhenTimeOut) {
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) {
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