I try get understating how exactly new coroutines work in C++20 but aside for very trivial examples I can't make it work.
My goal is to create deep nested functions that allow that most inner one could break and return control to most outer code and after some condition it give control back to this inner function.
This is effective setjmp and longjmp.
I botch some code using some examples find in net:
#include <iostream>
#include <coroutine>
#include <optional>
template <typename T>
struct task
{
struct task_promise;
using promise_type = task_promise;
using handle_type = std::coroutine_handle<promise_type>;
mutable handle_type m_handle;
task(handle_type handle)
: m_handle(handle)
{
}
task(task&& other) noexcept
: m_handle(other.m_handle)
{
other.m_handle = nullptr;
}
bool await_ready()
{
return m_handle.done();
}
bool await_suspend(std::coroutine_handle<> handle)
{
if (!m_handle.done()) {
m_handle.resume();
}
return !m_handle.done();
}
auto await_resume()
{
return result();
}
T result() const
{
if (!m_handle.done())
m_handle.resume();
return *m_handle.promise().m_value;
}
//manualy wait for finish
bool one_step()
{
if (!m_handle.done())
m_handle.resume();
return !m_handle.done();
}
~task()
{
if (m_handle)
m_handle.destroy();
}
struct task_promise
{
std::optional<T> m_value {};
auto value()
{
return m_value;
}
auto initial_suspend()
{
return std::suspend_always{};
}
auto final_suspend()
{
return std::suspend_always{};
}
auto return_value(T t)
{
m_value = t;
return std::suspend_always{};
}
task<T> get_return_object()
{
return {handle_type::from_promise(*this)};
}
void unhandled_exception()
{
std::terminate();
}
void rethrow_if_unhandled_exception()
{
}
};
};
static task<int> suspend_one()
{
std::cout<< "suspend_one in\n";
co_await std::suspend_always();
std::cout<< "suspend_one return\n";
co_return 1;
}
static task<int> suspend_two()
{
std::cout<< "suspend_two -> suspend_one #1\n";
auto a = co_await suspend_one();
std::cout<< "suspend_two -> suspend_one #2\n";
auto b = co_await suspend_one();
std::cout<< "suspend_two return\n";
co_return a + b;
}
static task<int> suspend_five()
{
std::cout<< "suspend_five -> suspend_two #1\n";
auto a = co_await suspend_two();
std::cout<< "suspend_five -> suspend_one #2\n";
auto b = co_await suspend_one();
std::cout<< "suspend_five -> suspend_two #3\n";
auto c = co_await suspend_two();
std::cout<< "suspend_five return\n";
co_return a + b + c;
}
static task<int> run()
{
std::cout<< "run -> suspend_two #1\n";
auto a = co_await suspend_two();
std::cout<< "run -> suspend_one #2\n";
auto b = co_await suspend_one();
std::cout<< "run -> suspend_five #3\n";
auto c = co_await suspend_five();
std::cout<< "run -> suspend_one #4\n";
auto d = co_await suspend_one();
std::cout<< "run -> suspend_two #5\n";
auto e = co_await suspend_two();
std::cout<< "run return\n";
co_return a + b + c + d + e;
}
int main()
{
std::cout<< "main in\n";
auto r = run();
std::cout<< "main -> while\n";
while (r.one_step()){ std::cout<< "<<<< while loop\n"; }
std::cout<< "main return\n";
return r.result();
}
https://gcc.godbolt.org/z/JULJCi
Function run work as expected but I have problem with e.g. suspend_five where it never reach line
std::cout<< "suspend_five -> suspend_two #3\n";
Probably my version of task is completely broken but I have no idea where find this error or how it should look.
Or simply thing I want achieve is not supported by C++20? co_yeld could be candidate for work around because it look more possible to nest them manually (for (auto z : f()) co_yeld z;) but goal of this question is to understand internal mechanic of C++20 functionality that solving some existing problem.
cppcorobut this will miss my point because it would be still black magic for me, and I could not know how its work and how it implement it my self