diff --git a/coro.hpp b/coro.hpp new file mode 100644 index 0000000..c06eb2c --- /dev/null +++ b/coro.hpp @@ -0,0 +1,104 @@ +#pragma once +#include +#include +#include +#include + +using namespace std; + +enum TaskStates { + STARTED, AWAIT, YIELD, + EXCEPTION, RETURN, + RETURN_VOID, DEAD +}; + +template +struct Task { + struct promise_type; + + using handle_type = std::coroutine_handle; + + struct promise_type { + T value_; + std::exception_ptr exception_; + TaskStates state_{STARTED}; + + Task get_return_object() { + return Task(handle_type::from_promise(*this)); + } + + std::suspend_always initial_suspend() { + state_ = AWAIT; + return {}; + } + + std::suspend_always final_suspend() noexcept { + return {}; + } + + void unhandled_exception() { + state_ = EXCEPTION; + exception_ = std::current_exception(); + } + + template From> // C++20 concept + void return_value(From &&from) { + state_ = RETURN; + value_ = std::forward(from); + } + + template From> // C++20 concept + std::suspend_always yield_value(From &&from) { + state_ = YIELD; + value_ = std::forward(from); + return {}; + } + + void return_void() { + state_ = RETURN_VOID; + } + }; + + handle_type h_; + + Task() { + } + + Task(handle_type h) : h_(h) { + } + + Task(const Task &t) : h_(t.h_) { + } + + void destroy() { + // this should make it safe to clal repeatedly + if(h_.promise().state_ != DEAD) { + h_.destroy(); + h_.promise().state_ = DEAD; + } + } + + T operator()() { + assert(!h_.done()); + call(); + return std::move(h_.promise().value_); + } + + bool done() { + return h_.done(); + } + + TaskStates state() { + return h_.promise().state_; + } + + private: + + void call() { + h_(); + + if (h_.promise().exception_) { + std::rethrow_exception(h_.promise().exception_); + } + } +}; diff --git a/corotest.cpp b/corotest.cpp index f1c294a..fb8ea7b 100644 --- a/corotest.cpp +++ b/corotest.cpp @@ -1,94 +1,11 @@ -#include +#include "coro.hpp" #include -#include -#include #include -#include -#include - -using namespace std; -using namespace std::chrono; - -template -struct Task { - struct promise_type; - - using handle_type = std::coroutine_handle; - - struct promise_type { - T value_; - std::exception_ptr exception_; - - Task get_return_object() { - return Task(handle_type::from_promise(*this)); - } - - std::suspend_always initial_suspend() { - return {}; - } - - std::suspend_always final_suspend() noexcept { - return {}; - } - - void unhandled_exception() { - exception_ = std::current_exception(); - } - - template From> // C++20 concept - void return_value(From &&from) { - value_ = std::forward(from); - } - - template From> // C++20 concept - std::suspend_always yield_value(From &&from) { - value_ = std::forward(from); - return {}; - } - - void return_void() {} - }; - - handle_type h_; - - Task() { - } - - Task(handle_type h) : h_(h) { - } - - Task(const Task &t) : h_(t.h_) { - } - - void destroy() { - h_.destroy(); - } - - T operator()() { - assert(!h_.done()); - call(); - return std::move(h_.promise().value_); - } - - bool done() { - return h_.done(); - } - - private: - - void call() { - h_(); - - if (h_.promise().exception_) - std::rethrow_exception(h_.promise().exception_); - } -}; - -#define pass() co_await std::suspend_always{} +#include Task task_test() { - pass(); + co_await std::suspend_always{}; for (unsigned i = 0; i < 3; ++i) co_yield i; @@ -113,12 +30,21 @@ int main() Task &t = tasks[i]; if(t.done()) { + // remove it from the tasks + // this cause crash I think? t.destroy(); done_count++; } else { auto res = t(); - cout << "T# " << i << " result " - << res << endl; + + if(t.state() == AWAIT) { + cout << "AWAIT! " << t.state() << endl; + } else if(t.state() != YIELD) { + cout << "NOT YIELD: " << t.state() << endl; + } else { + cout << "T# " << i << " result " + << res << " STATE " << t.state() << endl; + } } } } diff --git a/meson.build b/meson.build index 790ae5e..ae63084 100644 --- a/meson.build +++ b/meson.build @@ -46,7 +46,9 @@ executable('jsontest', 'jsontest.cpp', executable('threadtest', 'threadtest.cpp', dependencies: dependencies) -executable('corotest', 'corotest.cpp', +executable('corotest', [ + 'corotest.cpp' + ], dependencies: dependencies, cpp_args: '-fcoroutines')