Skip to content

Commit

Permalink
Implement void futures support for co::all.
Browse files Browse the repository at this point in the history
Fixes #14
  • Loading branch information
NatalieWolfe committed Feb 27, 2022
1 parent 596f128 commit 24028ce
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 26 deletions.
42 changes: 39 additions & 3 deletions lw/co/future.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <atomic>
#include <concepts>
#include <coroutine>
#include <exception>
#include <memory>
Expand Down Expand Up @@ -362,17 +363,52 @@ Future<T> make_resolved_future(std::exception_ptr err) {
return promise.get_future();
}

namespace internal {

template <typename T>
struct TupleAwaitResult {
typedef T result_type;
static co::Future<T> await(co::Future<T> future) { return future; }
};

template <>
struct TupleAwaitResult<void> {
typedef std::nullptr_t result_type;
static co::Future<std::nullptr_t> await(co::Future<void> future) {
co_await future;
co_return nullptr;
}
};

}

/**
* Await all the provided futures concurrently.
*
* Any `void` futures will resolve to a `nullptr` in the results tuple.
*
* @return
* A tuple containing all the resolved values from the futures in the order
* they are specified in the arguments.
*/
template <typename... Args>
co::Future<std::tuple<Args...>> all(co::Future<Args>... futures) {
// TODO(#14): Implement this method for `co::Future<void>`.
co_return std::make_tuple((co_await futures)...);
co::Future<
std::tuple<typename internal::TupleAwaitResult<Args>::result_type...>
> all(co::Future<Args>... futures) {
co_return std::make_tuple(
(co_await internal::TupleAwaitResult<Args>::await(std::move(futures)))...
);
}

/**
* Awaits all of the futures concurrently.
*
* This method requires all provided futures to be `void` resolving.
*/
template <std::same_as<co::Future<void>>... Futures>
co::Future<void> all_void(Futures&&... futures) {
(co_await futures, ...);
co_return; // Cover empty parameter pack case.
}

}
70 changes: 47 additions & 23 deletions lw/co/future_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,29 +374,53 @@ TEST(AwaitAll, AllResolve) {
destroy_all_schedulers();
}

// TODO(#14): Implement support for Future<void> in co::all.
// TEST(AwaitAll, AllVoid) {
// int counter = 0;
// auto coro0 = [&]() -> Future<void> {
// co_await next_tick();
// EXPECT_EQ(++counter, 1);
// };
// auto coro1 = [&]() -> Future<void> {
// co_await next_tick();
// EXPECT_EQ(++counter, 2);
// };
// auto coro2 = [&]() -> Future<void> {
// co_await next_tick();
// EXPECT_EQ(++counter, 3);
// };

// Scheduler::this_thread().schedule([&]() -> Task {
// co_await all(coro0(), coro1(), coro2());
// EXPECT_EQ(counter, 3);
// });
// Scheduler::this_thread().run();
// destroy_all_schedulers();
// }
TEST(AwaitAll, AllVoid) {
int counter = 0;
auto coro0 = [&]() -> Future<void> {
co_await next_tick();
EXPECT_EQ(++counter, 1);
};
auto coro1 = [&]() -> Future<void> {
co_await next_tick();
EXPECT_EQ(++counter, 2);
};
auto coro2 = [&]() -> Future<void> {
co_await next_tick();
EXPECT_EQ(++counter, 3);
};

Scheduler::this_thread().schedule([&]() -> Task {
co_await all_void(coro0(), coro1(), coro2());
EXPECT_EQ(counter, 3);
});
Scheduler::this_thread().run();
destroy_all_schedulers();
}

TEST(AwaitAll, MixVoid) {
int counter = 0;
auto coro0 = [&]() -> Future<void> {
co_await next_tick();
EXPECT_EQ(++counter, 1);
};
auto coro1 = [&]() -> Future<int> {
co_await next_tick();
EXPECT_EQ(++counter, 2);
co_return 42;
};
auto coro2 = [&]() -> Future<void> {
co_await next_tick();
EXPECT_EQ(++counter, 3);
};

Scheduler::this_thread().schedule([&]() -> Task {
auto [a, b, c ] = co_await all(coro0(), coro1(), coro2());
EXPECT_EQ(counter, 3);
EXPECT_EQ(b, 42);
});
Scheduler::this_thread().run();
destroy_all_schedulers();
}

TEST(AwaitAll, ResolveOutOfOrder) {
int counter = 0;
Expand Down

0 comments on commit 24028ce

Please sign in to comment.