Last active
April 20, 2025 08:42
-
-
Save yohhoy/cd567aaf1aeb6ca6ff555d528b348b58 to your computer and use it in GitHub Desktop.
C++26 Sender/Receiver and awaitable Coroutine
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cassert> | |
#include <concepts> | |
#include <coroutine> | |
#include <print> | |
// https://github.com/NVIDIA/stdexec/ | |
#include <stdexec/execution.hpp> | |
namespace ex = stdexec; | |
template<typename T> | |
class Lazy { | |
public: | |
struct promise_type; | |
using value_type = T; | |
using handle_type = std::coroutine_handle<promise_type>; | |
struct promise_type { | |
value_type value_; | |
static auto get_return_object_on_allocation_failure() | |
{ return Lazy{nullptr}; } | |
auto get_return_object() | |
{ return Lazy{handle_type::from_promise(*this)}; } | |
auto initial_suspend() noexcept { return std::suspend_always{}; } | |
auto final_suspend() noexcept { return std::suspend_always{}; } | |
void unhandled_exception() { throw; } | |
void return_value(value_type v) noexcept { value_ = v; } | |
}; | |
private: | |
Lazy(handle_type h) : coro_{h} {} | |
public: | |
Lazy(Lazy&& rhs) | |
: coro_{std::exchange(rhs.coro_, nullptr)} {} | |
Lazy& operator=(Lazy&& rhs) { | |
if (coro_) { std::exchange(coro_, nullptr).destroy(); } | |
std::swap(rhs.coro_, coro_); | |
return *this; | |
} | |
~Lazy() | |
{ if (coro_) { coro_.destroy(); } } | |
value_type get() { | |
assert(coro_); | |
if (!coro_.done()) { | |
coro_.resume(); | |
} | |
return coro_.promise().value_; | |
} | |
auto operator co_await() noexcept { | |
struct awaiter { | |
handle_type h; | |
bool await_ready() const { return h.done(); } | |
bool await_suspend(std::coroutine_handle<>) | |
{ h.resume(); return false; } | |
value_type await_resume() | |
{ return h.promise().value_; } | |
}; | |
return awaiter{coro_}; | |
} | |
private: | |
handle_type coro_; | |
}; | |
Lazy<int> subtask(int n) // child coro | |
{ | |
std::println("subtask {}", n); | |
co_return n * 3; | |
} | |
Lazy<int> task(int n) // parent coro | |
{ | |
std::println("task.1 {}", n); | |
int v = co_await subtask(7); | |
std::println("task.2 {}", v); | |
co_return v * n; | |
} | |
int main() | |
{ | |
std::println("-- Coroutine"); | |
{ | |
try { | |
auto t = task(2); | |
std::println("get"); | |
auto v = t.get(); | |
std::println("value={}", v); | |
} catch (...) { | |
std::println("<exception>"); | |
} | |
} | |
std::println("-- Sender/Receiver"); | |
{ | |
struct DumpReceiver { | |
using receiver_concept = ex::receiver_t; | |
void set_value(int v) && noexcept | |
{ std::println("value={}", v); } | |
void set_error(std::exception_ptr) && noexcept | |
{ std::println("<error>"); } | |
void set_stopped() && noexcept | |
{ std::println("<stopped>"); } | |
}; | |
ex::sender auto sndr = task(2); | |
ex::receiver auto rcvr = DumpReceiver{}; | |
std::println("connect"); | |
ex::operation_state auto op = ex::connect(std::move(sndr), rcvr); | |
std::println("start"); | |
ex::start(op); | |
} | |
} |
Author
yohhoy
commented
Apr 19, 2025
•
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment