Skip to content

Commit

Permalink
Add coroutine example with an awaitable that resumes in current thread
Browse files Browse the repository at this point in the history
  • Loading branch information
BewareMyPower committed Mar 11, 2024
1 parent 7cdaed3 commit c70659f
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ _builds/

# YouCompleteMe
.ycm_extra_conf.py

# clangd
compile_flags.txt
10 changes: 10 additions & 0 deletions coroutines/noncopyable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

class noncopyable {
public:
noncopyable() = default;
noncopyable(const noncopyable&) = delete;
noncopyable& operator=(const noncopyable&) = delete;
noncopyable(noncopyable&&) noexcept = default;
noncopyable& operator=(noncopyable&&) noexcept = default;
};
56 changes: 56 additions & 0 deletions coroutines/resume_immediately_awaitable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#pragma once

#include <concepts>
#include <coroutine>

#include "noncopyable.h"

template <typename T>
requires std::default_initializable<T>&& std::movable<T> class Promise
: public noncopyable {
public:
auto get_return_object();
auto initial_suspend() const noexcept { return std::suspend_always{}; }
auto return_value(T&& value) { value_ = std::move(value); }
auto final_suspend() const noexcept { return std::suspend_always{}; }
auto unhandled_exception() const noexcept {}

decltype(auto) release() noexcept { return std::move(value_); }
const auto& value() const noexcept { return value_; }

private:
T value_;
};

// An awaitable that resumes immediately in current thread
template <typename T>
requires std::default_initializable<T>&& std::movable<T> class Awaitable
: public noncopyable {
using Handle = std::coroutine_handle<Promise<T>>;

public:
using promise_type = Promise<T>;
Awaitable(Promise<T>& promise) : handle_(Handle::from_promise(promise)) {}
~Awaitable() { handle_.destroy(); }

decltype(auto) operator()() const {
handle_.resume();
return handle_.promise().value();
}

constexpr auto await_ready() const noexcept { return false; }
auto await_suspend(std::coroutine_handle<> caller) const {
handle_.resume();
return caller;
}
decltype(auto) await_resume() noexcept { return handle_.promise().release(); }

private:
Handle handle_;
};

template <typename T>
requires std::default_initializable<T>&& std::movable<T> inline auto
Promise<T>::get_return_object() {
return Awaitable<T>{*this};
}
24 changes: 24 additions & 0 deletions coroutines/resume_immediately_awaitable_demo.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include <iostream>
#include <memory>

#include "resume_immediately_awaitable.h"

Awaitable<int> f(int x) { co_return x + 1; }
Awaitable<int> g(int x) { co_return(co_await f(x)) + 2; }

Awaitable<std::unique_ptr<int>> ptr_f(int x) {
co_return std::make_unique<int>(x + 1);
}

Awaitable<std::unique_ptr<int>> ptr_g(int x) {
auto ptr = std::move(co_await ptr_f(x));
*ptr += 2;
co_return std::move(ptr);
}

int main() {
auto coro_int = g(100);
std::cout << coro_int() << std::endl;
auto coro_ptr = ptr_g(100);
std::cout << *coro_ptr() << std::endl;
}

0 comments on commit c70659f

Please sign in to comment.