14template <CQEHandlerLike CQEHandler, PrepFuncLike PrepFunc,
typename... Args>
15auto build_op_sender(PrepFunc &&prep_func, Args &&...args) {
16 return OpSender<std::decay_t<PrepFunc>, CQEHandler>(
17 std::forward<PrepFunc>(prep_func),
18 CQEHandler(std::forward<Args>(args)...));
21template <CQEHandlerLike CQEHandler, PrepFuncLike PrepFunc,
22 typename MultiShotFunc,
typename... Args>
23auto build_multishot_op_sender(PrepFunc &&func, MultiShotFunc &&multishot_func,
24 Args &&...handler_args) {
25 return MultiShotOpSender<std::decay_t<PrepFunc>, CQEHandler,
26 std::decay_t<MultiShotFunc>>(
27 std::forward<PrepFunc>(func),
28 CQEHandler(std::forward<Args>(handler_args)...),
29 std::forward<MultiShotFunc>(multishot_func));
32template <CQEHandlerLike CQEHandler, PrepFuncLike PrepFunc,
typename FreeFunc,
34auto build_zero_copy_op_sender(PrepFunc &&func, FreeFunc &&free_func,
35 Args &&...handler_args) {
36 return ZeroCopyOpSender<std::decay_t<PrepFunc>, CQEHandler,
37 std::decay_t<FreeFunc>>(
38 std::forward<PrepFunc>(func),
39 CQEHandler(std::forward<Args>(handler_args)...),
40 std::forward<FreeFunc>(free_func));
45struct NeverStopToken {
47 template <
typename>
struct callback_type {
48 constexpr explicit callback_type(NeverStopToken,
auto &&) noexcept {}
51 static constexpr bool stop_requested() noexcept {
return false; }
53 static constexpr bool stop_possible() noexcept {
return false; }
55 constexpr bool operator==(NeverStopToken
const &)
const noexcept =
default;
58template <
typename Sender>
class SenderAwaiter {
60 SenderAwaiter(Sender sender)
61 : operation_state_(std::move(sender).connect(Receiver{this})) {}
63 SenderAwaiter(
const SenderAwaiter &) =
delete;
64 SenderAwaiter &operator=(
const SenderAwaiter &) =
delete;
65 SenderAwaiter(SenderAwaiter &&) =
delete;
66 SenderAwaiter &operator=(SenderAwaiter &&) =
delete;
69 bool await_ready() const noexcept {
return false; }
71 template <
typename Promise>
72 bool await_suspend(std::coroutine_handle<Promise> h)
noexcept {
73 operation_state_.start(0);
74 if (handle_ == std::noop_coroutine()) {
83 auto await_resume() noexcept {
return std::move(result_); }
88 template <
typename R>
void operator()(R &&result)
noexcept {
89 self->handle_result_(std::forward<R>(result));
91 NeverStopToken get_stop_token() const noexcept {
return {}; }
94 template <
typename R>
void handle_result_(R &&result) {
95 result_ = std::forward<R>(result);
99 handle_ = std::noop_coroutine();
103 using OperationState = operation_state_t<Sender, Receiver>;
105 std::coroutine_handle<> handle_ =
nullptr;
106 OperationState operation_state_;
107 typename Sender::ReturnType result_;
110template <
typename Sender>
auto as_awaiter(Sender &&sender) {
111 return detail::SenderAwaiter<std::decay_t<Sender>>(
112 std::forward<Sender>(sender));
122template <
unsigned int Flags,
typename Sender>
auto flag(Sender &&sender) {
123 return FlaggedOpSender<Flags, std::decay_t<Sender>>(
124 std::forward<Sender>(sender));
131template <
typename Sender>
auto drain(Sender &&sender) {
149template <
template <
typename... Senders>
typename SenderType,
152 return SenderType<std::decay_t<Senders>...>(
153 std::forward<Senders>(senders)...);
162template <
template <
typename Sender>
typename RangedSenderType,
163 std::ranges::range Range>
165 using SenderType =
typename std::decay_t<Range>::value_type;
166 auto begin = std::make_move_iterator(std::begin(range));
167 auto end = std::make_move_iterator(std::end(range));
168 std::vector<SenderType> senders(begin, end);
169 return RangedSenderType<SenderType>(std::move(senders));
177template <
typename... Senders>
auto when_all(Senders &&...senders) {
186template <std::ranges::range Range>
auto when_all(Range &&range) {
195template <
typename... Senders>
auto when_any(Senders &&...senders) {
196 static_assert(
sizeof...(Senders) > 0,
197 "when_any requires at least one sender");
206template <std::ranges::range Range>
auto when_any(Range &&range) {
215template <
typename... Senders>
auto link(Senders &&...senders) {
224template <std::ranges::range Range>
auto link(Range &&range) {
233template <
typename... Senders>
auto hard_link(Senders &&...senders) {
242template <std::ranges::range Range>
auto hard_link(Range &&range) {
254template <
typename Sender1,
typename Sender2>
256 return when_all(std::move(s1), std::move(s2));
262template <
typename S,
typename... Ss>
264 return WhenAllSender<Ss..., std::decay_t<S>>(std::move(aws),
271template <
typename Sender1,
typename Sender2>
273 return when_any(std::move(s1), std::move(s2));
279template <
typename S,
typename... Ss>
281 return WhenAnySender<Ss..., std::decay_t<S>>(std::move(aws),
288template <
typename Sender1,
typename Sender2>
290 return link(std::move(s1), std::move(s2));
296template <
typename S,
typename... Ss>
298 return LinkSender<Ss..., std::decay_t<S>>(std::move(aws),
Operators for composing operations.
auto operator&&(Sender1 s1, Sender2 s2)
Operator overloads version of condy::when_all.
auto operator>>(Sender1 s1, Sender2 s2)
Operator overloads version of condy::link.
auto operator||(Sender1 s1, Sender2 s2)
Operator overloads version of condy::when_any.
The main namespace for the Condy library.
auto drain(Sender &&sender)
Mark an operation as drain operation.
auto link(Senders &&...senders)
Compose multiple operations into a single operation that executes them in sequence.
auto parallel(Senders &&...senders)
Compose multiple operations into a single sender that executes them in parallel.
auto hard_link(Senders &&...senders)
Compose multiple operations into a single operation that executes them in sequence and continues even...
auto when_any(Senders &&...senders)
Compose multiple operations into a single operation that completes when any of them complete.
auto when_all(Senders &&...senders)
Compose multiple operations into a single operation that completes when all of them complete.
auto flag(Sender &&sender)
Decorates an operation with specific io_uring sqe flags.
auto always_async(Sender &&sender)
Mark an operation to always execute asynchronously.
Sender types for composing asynchronous operations.