Skip to content

Instantly share code, notes, and snippets.

@ArchieAtkinson
Created May 6, 2024 11:09
Coroutine Demo (Taken from Andreas Fertig Talk)
#include <array>
#include <concepts>
#include <coroutine>
#include <cstdlib>
#include <exception>
#include <iostream>
#include <source_location>
#include <string>
#include <utility>
struct Chat
{
struct promise_type
{
std::string _msgOut{};
std::string _msgIn{};
void* operator new(std::size_t sz) {
std::cout << " ---- " << std::source_location::current().function_name() << " : " << sz << "\n";
return malloc(sz);
}
void operator delete(void* p) {
if (p)
free(p);
}
static void unhandled_exception() noexcept
{
std::cout << " ---- " << std::source_location::current().function_name() << "\n";
}
Chat get_return_object()
{
std::cout << " ---- " << std::source_location::current().function_name() << "\n";
return Chat{this};
}
static std::suspend_always initial_suspend() noexcept
{
std::cout << " ---- " << std::source_location::current().function_name() << "\n";
return {};
}
std::suspend_always yield_value(std::string msg) noexcept
{
_msgOut = std::move(msg);
return {};
}
auto await_transform(std::string) noexcept
{
std::cout << " ---- " << std::source_location::current().function_name() << "\n";
struct awaiter
{
promise_type &pt;
static bool await_ready() noexcept
{
std::cout << " ---- " << std::source_location::current().function_name() << "\n";
return true;
}
[[nodiscard]] std::string await_resume() const noexcept
{
std::cout << " ---- " << std::source_location::current().function_name() << "\n";
return std::move(pt._msgIn);
}
static void await_suspend(std::coroutine_handle<> /*unused*/) noexcept
{
std::cout << " ---- " << std::source_location::current().function_name() << "\n";
}
};
return awaiter{*this};
}
void return_value(std::string msg) noexcept
{
std::cout << " ---- " << std::source_location::current().function_name() << "\n";
_msgOut = std::move(msg);
}
static std::suspend_always final_suspend() noexcept
{
std::cout << " ---- " << std::source_location::current().function_name() << "\n";
return {};
}
};
using Handle = std::coroutine_handle<promise_type>;
Handle mCoroHdl{};
explicit Chat(promise_type *p) : mCoroHdl(Handle::from_promise(*p))
{
std::cout << " ---- " << std::source_location::current().function_name() << "\n";
}
Chat(Chat &&rhs) noexcept : mCoroHdl(std::exchange(rhs.mCoroHdl, nullptr))
{
std::cout << " ---- " << std::source_location::current().function_name() << "\n";
}
~Chat()
{
std::cout << " ---- " << std::source_location::current().function_name() << "\n";
if (mCoroHdl)
{
mCoroHdl.destroy();
}
}
[[nodiscard]] std::string listen() const
{
std::cout << " ---- " << std::source_location::current().function_name() << "\n";
if (not mCoroHdl.done())
{
std::cout << " ---- not done\n";
mCoroHdl.resume();
}
return std::move(mCoroHdl.promise()._msgOut);
}
void answer(std::string msg) const
{
std::cout << " ---- " << std::source_location::current().function_name() << "\n";
mCoroHdl.promise()._msgIn = msg;
if (not mCoroHdl.done())
{
mCoroHdl.resume();
}
}
};
Chat Fun()
{
std::cout << " -- Before Hello \n";
co_yield std::string{"Hello\n"};
std::cout << " -- After Hello \n";
std::cout << co_await std::string{};
std::cout << " -- Before Here \n";
co_return std::string{"Here\n"};
}
int main()
{
std::cout << std::source_location::current().function_name() << "\n";
Chat chat = Fun();
std::cout << "After Fun() \n";
std::cout << chat.listen();
std::cout << "After chat.listen() \n";
chat.answer("Where are you?\n");
std::cout << "After chat.answer() \n";
std::cout << chat.listen();
std::cout << "After chat.listen() \n";
std::exit(0);
}
@ArchieAtkinson
Copy link
Author

Output:

int main()
 ---- static void* Chat::promise_type::operator new(std::size_t) : 152
 ---- Chat Chat::promise_type::get_return_object()
 ---- Chat::Chat(Chat::promise_type*)
 ---- static std::__n4861::suspend_always Chat::promise_type::initial_suspend()
After Fun() 
 ---- std::string Chat::listen() const
 ---- not done
 -- Before Hello 
Hello
After chat.listen() 
 ---- void Chat::answer(std::string) const
 -- After Hello 
 ---- auto Chat::promise_type::await_transform(std::string)
 ---- static bool Chat::promise_type::await_transform(std::string)::awaiter::await_ready()
 ---- std::string Chat::promise_type::await_transform(std::string)::awaiter::await_resume() const
Where are you?
 -- Before Here 
 ---- void Chat::promise_type::return_value(std::string)
 ---- static std::__n4861::suspend_always Chat::promise_type::final_suspend()
After chat.answer() 
 ---- std::string Chat::listen() const
Here
After chat.listen()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment