Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <cassert>
- #include <cstdio>
- #include <condition_variable>
- #include <exception>
- #include <mutex>
- #include <experimental/coroutine>
- // From https://channel9.msdn.com/events/CPP/CppCon-2016/CppCon-2016-Gor-Nishanov-C-Coroutines-Under-the-covers
- template <class T>
- struct task {
- enum Which { eNone, eValue };
- struct promise_type {
- Which which{eNone};
- alignas(T) char buffer[sizeof(T)];
- std::exception_ptr eptr;
- std::experimental::coroutine_handle<> waiter;
- task get_return_object() { return task{this}; }
- std::experimental::suspend_always initial_suspend() { return {}; }
- auto final_suspend() {
- struct Awaiter {
- promise_type* me;
- bool await_ready() { return false; }
- void await_suspend(std::experimental::coroutine_handle<>) {
- assert(me->waiter);
- me->waiter.resume();
- }
- void await_resume() {}
- };
- return Awaiter{this};
- }
- template <class U>
- void return_value(U&& value) {
- assert(which == eNone);
- ::new((void*)buffer) T(std::forward<U>(value));
- which = eValue;
- }
- void unhandled_exception() {
- assert(which == eNone);
- eptr = std::current_exception();
- }
- promise_type() {
- std::printf("promise_type %p\n", (void*)this);
- }
- promise_type(promise_type const&) = delete;
- ~promise_type() {
- std::printf("~promise_type %p\n", (void*)this);
- if (which == eValue) {
- static_cast<T*>((void*)buffer)->~T();
- }
- }
- };
- bool await_ready() { return coro.done(); }
- void await_suspend(std::experimental::coroutine_handle<> waiter) {
- coro.promise().waiter = waiter;
- coro.resume();
- }
- T await_resume() {
- auto& promise = coro.promise();
- if (promise.eptr) {
- assert(promise.which == eNone);
- std::rethrow_exception(coro.promise().eptr);
- }
- assert(promise.which == eValue);
- return *static_cast<T*>((void*)promise.buffer);
- }
- ~task() {
- if (coro) {
- coro.destroy();
- }
- }
- task(task&& that) noexcept
- : coro(std::exchange(that.coro, nullptr))
- {}
- private:
- task() = delete;
- task(task const&) = delete;
- explicit task(promise_type* p)
- : coro(std::experimental::coroutine_handle<promise_type>::from_promise(*p))
- {}
- std::experimental::coroutine_handle<promise_type> coro;
- };
- task<int> some_fun() {
- co_return 42;
- }
- task<int> some_fun2() {
- int i = co_await some_fun();
- std::printf("in some_fun2, got %d\n", i);
- co_return i + 1;
- }
- template <typename T>
- T sync_await(task<T>&& t) {
- struct looper {
- struct promise_type {
- std::mutex m;
- std::condition_variable c;
- bool done{false};
- std::experimental::suspend_never initial_suspend() { return {}; }
- std::experimental::suspend_always final_suspend() {
- { std::lock_guard<std::mutex> g(m); done = true; }
- c.notify_all();
- return {};
- }
- looper get_return_object() { return looper{*this}; }
- void return_void() {}
- void unhandled_exception() {}
- };
- promise_type* promise;
- explicit looper(promise_type& p) : promise(&p) {}
- looper(looper const&) = delete;
- looper(looper &&that) : promise(std::exchange(that.promise, nullptr)) {}
- ~looper() {
- // Needed because final_suspend returns suspend_always:
- if (promise) {
- std::experimental::coroutine_handle<promise_type>::
- from_promise(*promise).destroy();
- }
- }
- void loop() {
- std::unique_lock<std::mutex> lock(promise->m);
- promise->c.wait(lock, [this] { return promise->done; });
- }
- };
- [&]() -> looper {
- (void)co_await t;
- }().loop();
- return t.await_resume();
- }
- int main() {
- auto i = some_fun2();
- int j = sync_await(std::move(i));
- std::printf("%d\n", j);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement