Commit 301a89b5 authored by Michael Park's avatar Michael Park Committed by Facebook Github Bot

Added `SemiFuture::delayed`

Summary:
Added `FutureBase::delayedImplementation`. Kept the existing semantics of
`Future::delayed` and `Future::delayedUnsafe`. `SemiFuture::delayed` uses
the inline executor which means we could execute our trivial lambda on
the `Timekeeper` thread. However we ultimately return a `SemiFuture`,
so we're not necessarily on the hook to execute an arbitrarily complex
continuation.

NOTE: This is still possible if the user explicitly specifies
`.via(inline_executor)`. Perhaps we should consider disallowing, or maybe linting for this.

Reviewed By: yfeldblum

Differential Revision: D8372515

fbshipit-source-id: e660dbf2a2bb084e11c5e57d1badacf09425f939
parent 856466e2
......@@ -875,6 +875,16 @@ SemiFuture<T> SemiFuture<T>::deferError(F&& func) && {
});
}
template <typename T>
SemiFuture<T> SemiFuture<T>::delayed(Duration dur, Timekeeper* tk) && {
return collectAllSemiFuture(*this, futures::sleep(dur, tk))
.toUnsafeFuture()
.then([](std::tuple<Try<T>, Try<Unit>> tup) {
Try<T>& t = std::get<0>(tup);
return makeFuture<T>(std::move(t));
});
}
template <class T>
Future<T> Future<T>::makeEmpty() {
return Future<T>(futures::detail::EmptyConstruct{});
......@@ -1781,12 +1791,7 @@ Future<T> Future<T>::delayed(Duration dur, Timekeeper* tk) && {
template <class T>
Future<T> Future<T>::delayedUnsafe(Duration dur, Timekeeper* tk) {
return collectAllSemiFuture(*this, futures::sleep(dur, tk))
.toUnsafeFuture()
.then([](std::tuple<Try<T>, Try<Unit>> tup) {
Try<T>& t = std::get<0>(tup);
return makeFuture<T>(std::move(t));
});
return std::move(*this).semi().delayed(dur, tk).toUnsafeFuture();
}
namespace futures {
......
......@@ -781,6 +781,19 @@ class SemiFuture : private futures::detail::FutureBase<T> {
: this->withinImplementation(dur, e, tk);
}
/// Delay the completion of this SemiFuture for at least this duration from
/// now. The optional Timekeeper is as with futures::sleep().
///
/// Preconditions:
///
/// - `valid() == true` (else throws FutureInvalid)
///
/// Postconditions:
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
SemiFuture<T> delayed(Duration dur, Timekeeper* tk = nullptr) &&;
/// Return a future that completes inline, as if the future had no executor.
/// Intended for porting legacy code without behavioural change, and for rare
/// cases where this is really the intended behaviour.
......
......@@ -117,6 +117,17 @@ TEST(Timekeeper, futureDelayed) {
EXPECT_GE(dur, one_ms);
}
TEST(Timekeeper, semiFutureDelayed) {
auto t1 = now();
auto dur = makeSemiFuture()
.delayed(one_ms)
.toUnsafeFuture()
.then([=] { return now() - t1; })
.get();
EXPECT_GE(dur, one_ms);
}
TEST(Timekeeper, futureDelayedUnsafe) {
auto t1 = now();
auto dur =
......
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