uvco 0.1
Loading...
Searching...
No Matches
select.h
Go to the documentation of this file.
1// uvco (c) 2023 Lewin Bormann. See LICENSE for specific terms.
2
3#pragma once
4
5#include <cstddef>
6#include <fmt/core.h>
7#include <fmt/ranges.h>
8
9#include "uvco/loop/loop.h"
11
12#include <coroutine>
13#include <tuple>
14#include <utility>
15#include <variant>
16#include <vector>
17
18namespace uvco {
19
23
56template <typename... Ts> class SelectSet {
57public:
58 using Variant = std::variant<Promise<Ts> *...>;
59 using Tuple = std::tuple<Promise<Ts> *...>;
60
61 explicit SelectSet(Promise<Ts> &...promises) : promises_{&promises...} {}
62
64 if (!resumed_) {
65 std::apply(
66 [](auto *...promise) { (promise->core()->resetHandle(), ...); },
67 promises_);
68 }
69 }
70
71 [[nodiscard]] bool await_ready() noexcept {
72 BOOST_ASSERT_MSG(!resumed_, "A select set can only be used once");
73 const bool isReady = std::apply(
74 [](auto *...promise) -> bool { return (promise->ready() || ...); },
75 promises_);
76 resumed_ |= isReady;
77 return isReady;
78 }
79
82 std::coroutine_handle<> await_suspend(std::coroutine_handle<> handle) {
83 std::apply(
84 [handle](auto *...promise) {
85 ((!promise->core()->stale() ? promise->core()->setHandle(handle)
86 : (void)0),
87 ...);
88 },
89 promises_);
90 suspended_ = handle;
91 return Loop::getNext();
92 }
93
101 std::vector<Variant> await_resume() {
102 resumed_ = true;
103 std::vector<Variant> readyPromises;
104 checkPromises(readyPromises);
105 // Prevent the current coroutine from being resumed again, if another
106 // promise in the SelectSet became ready in the meantime.
107 if (suspended_ != nullptr) {
109 suspended_ = nullptr;
110 }
111 return readyPromises;
112 }
113
114private:
115 template <size_t Ix = 0>
116 void checkPromises(std::vector<Variant> &readyPromises) {
117 if constexpr (Ix < sizeof...(Ts)) {
118 using PromisePtr = std::tuple_element_t<Ix, Tuple>;
119 PromisePtr promise = std::get<Ix>(promises_);
120 if (promise->ready()) {
121 readyPromises.emplace_back(std::in_place_index<Ix>, promise);
122 } else {
123 // Reset promises to `init` state and remove the current coroutine's
124 // handle from them so they don't resume us later.
125 promise->core()->resetHandle();
126 }
127 checkPromises<Ix + 1>(readyPromises);
128 }
129 }
130
132 std::coroutine_handle<> suspended_;
133 bool resumed_ = false;
134};
135
137
138} // namespace uvco
static void cancel(std::coroutine_handle<> handle)
Definition loop.cc:104
static std::coroutine_handle getNext()
Definition loop.cc:108
Definition promise.h:49
std::vector< Variant > await_resume()
Definition select.h:101
std::coroutine_handle await_suspend(std::coroutine_handle<> handle)
Definition select.h:82
std::tuple< Promise< Ts > *... > Tuple
Definition select.h:59
SelectSet(Promise< Ts > &...promises)
Definition select.h:61
~SelectSet()
Definition select.h:63
std::coroutine_handle suspended_
Definition select.h:132
Tuple promises_
Definition select.h:131
void checkPromises(std::vector< Variant > &readyPromises)
Definition select.h:116
bool await_ready() noexcept
Definition select.h:71
bool resumed_
Definition select.h:133
std::variant< Promise< Ts > *... > Variant
Definition select.h:58
Definition async_work.cc:18