16template <CQEHandlerLike CQEHandler, PrepFuncLike PrepFunc,
typename... Args>
17auto build_op_sender(PrepFunc &&prep_func, Args &&...args) {
18 return OpSender<std::decay_t<PrepFunc>, CQEHandler>(
19 std::forward<PrepFunc>(prep_func),
20 CQEHandler(std::forward<Args>(args)...));
23template <CQEHandlerLike CQEHandler, PrepFuncLike PrepFunc,
24 typename MultiShotFunc,
typename... Args>
25auto build_multishot_op_sender(PrepFunc &&func, MultiShotFunc &&multishot_func,
26 Args &&...handler_args) {
27 return MultiShotOpSender<std::decay_t<PrepFunc>, CQEHandler,
28 std::decay_t<MultiShotFunc>>(
29 std::forward<PrepFunc>(func),
30 CQEHandler(std::forward<Args>(handler_args)...),
31 std::forward<MultiShotFunc>(multishot_func));
34template <CQEHandlerLike CQEHandler, PrepFuncLike PrepFunc,
typename FreeFunc,
36auto build_zero_copy_op_sender(PrepFunc &&func, FreeFunc &&free_func,
37 Args &&...handler_args) {
38 return ZeroCopyOpSender<std::decay_t<PrepFunc>, CQEHandler,
39 std::decay_t<FreeFunc>>(
40 std::forward<PrepFunc>(func),
41 CQEHandler(std::forward<Args>(handler_args)...),
42 std::forward<FreeFunc>(free_func));
47struct NeverStopToken {
49 template <
typename>
struct callback_type {
50 constexpr explicit callback_type(NeverStopToken,
auto &&) noexcept {}
53 static constexpr bool stop_requested() noexcept {
return false; }
55 static constexpr bool stop_possible() noexcept {
return false; }
57 constexpr bool operator==(NeverStopToken
const &)
const noexcept =
default;
60template <
typename Sender>
class [[nodiscard]] SenderAwaiter {
62 SenderAwaiter(Sender sender)
63 : operation_state_(std::move(sender).connect_impl(Receiver{this})) {}
65 CONDY_DELETE_COPY_MOVE(SenderAwaiter);
68 bool await_ready() const noexcept {
return false; }
70 template <
typename Promise>
71 bool await_suspend(std::coroutine_handle<Promise> handle)
noexcept {
72 operation_state_.start(0);
73 auto h = std::exchange(handle_, handle);
74 return h == std::noop_coroutine();
77 auto await_resume() noexcept {
return std::move(result_); }
82 template <
typename R>
void operator()(R &&result)
noexcept {
83 self->handle_result_(std::forward<R>(result));
85 NeverStopToken get_stop_token() const noexcept {
return {}; }
88 template <
typename R>
void handle_result_(R &&result)
noexcept {
89 result_ = std::forward<R>(result);
90 auto h = std::exchange(handle_,
nullptr);
94 using OperationState = operation_state_t<Sender, Receiver>;
96 std::coroutine_handle<> handle_ = std::noop_coroutine();
97 OperationState operation_state_;
98 typename Sender::ReturnType result_;
101template <
typename Sender>
auto as_awaiter(Sender &&sender) {
102 return detail::SenderAwaiter<std::decay_t<Sender>>(
103 std::forward<Sender>(sender));
113template <
unsigned int Flags,
typename Sender>
auto flag(Sender &&sender) {
114 return FlaggedOpSender<Flags, std::decay_t<Sender>>(
115 std::forward<Sender>(sender));
122template <
typename Sender>
auto drain(Sender &&sender) {
140template <
template <
typename... Senders>
typename SenderType,
143 return SenderType<std::decay_t<Senders>...>(
144 std::forward<Senders>(senders)...);
153template <
template <
typename Sender>
typename RangedSenderType,
154 std::ranges::range Range>
156 using SenderType =
typename std::remove_cvref_t<Range>::value_type;
157 auto begin = std::make_move_iterator(std::begin(range));
158 auto end = std::make_move_iterator(std::end(range));
159 std::vector<SenderType> senders(begin, end);
160 return RangedSenderType<SenderType>(std::move(senders));
168template <
typename... Senders>
auto when_all(Senders &&...senders) {
177template <std::ranges::range Range>
auto when_all(Range &&range) {
186template <
typename... Senders>
auto when_any(Senders &&...senders) {
187 static_assert(
sizeof...(Senders) > 0,
188 "when_any requires at least one sender");
197template <std::ranges::range Range>
auto when_any(Range &&range) {
198 if (std::ranges::empty(range)) {
199 throw std::invalid_argument(
"when_any requires at least one sender");
209template <
typename... Senders>
auto link(Senders &&...senders) {
218template <std::ranges::range Range>
auto link(Range &&range) {
227template <
typename... Senders>
auto hard_link(Senders &&...senders) {
236template <std::ranges::range Range>
auto hard_link(Range &&range) {
248template <
typename Sender1,
typename Sender2>
250 return when_all(std::move(s1), std::move(s2));
256template <
typename S,
typename... Ss>
258 return WhenAllSender<Ss..., std::decay_t<S>>(std::move(aws),
265template <
typename Sender1,
typename Sender2>
267 return when_any(std::move(s1), std::move(s2));
273template <
typename S,
typename... Ss>
275 return WhenAnySender<Ss..., std::decay_t<S>>(std::move(aws),
282template <
typename Sender1,
typename Sender2>
284 return link(std::move(s1), std::move(s2));
290template <
typename S,
typename... Ss>
292 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.
Internal utility classes and functions used by Condy.