Advertisement
Guest User

Untitled

a guest
Aug 22nd, 2017
159
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.83 KB | None | 0 0
  1. #include <cassert>
  2. #include <cstdio>
  3. #include <condition_variable>
  4. #include <exception>
  5. #include <mutex>
  6. #include <experimental/coroutine>
  7.  
  8. // From https://channel9.msdn.com/events/CPP/CppCon-2016/CppCon-2016-Gor-Nishanov-C-Coroutines-Under-the-covers
  9. template <class T>
  10. struct task {
  11. enum Which { eNone, eValue };
  12. struct promise_type {
  13. Which which{eNone};
  14. alignas(T) char buffer[sizeof(T)];
  15. std::exception_ptr eptr;
  16. std::experimental::coroutine_handle<> waiter;
  17.  
  18. task get_return_object() { return task{this}; }
  19. std::experimental::suspend_always initial_suspend() { return {}; }
  20. auto final_suspend() {
  21. struct Awaiter {
  22. promise_type* me;
  23. bool await_ready() { return false; }
  24. void await_suspend(std::experimental::coroutine_handle<>) {
  25. assert(me->waiter);
  26. me->waiter.resume();
  27. }
  28. void await_resume() {}
  29. };
  30. return Awaiter{this};
  31. }
  32. template <class U>
  33. void return_value(U&& value) {
  34. assert(which == eNone);
  35. ::new((void*)buffer) T(std::forward<U>(value));
  36. which = eValue;
  37. }
  38. void unhandled_exception() {
  39. assert(which == eNone);
  40. eptr = std::current_exception();
  41. }
  42. promise_type() {
  43. std::printf("promise_type %p\n", (void*)this);
  44. }
  45. promise_type(promise_type const&) = delete;
  46. ~promise_type() {
  47. std::printf("~promise_type %p\n", (void*)this);
  48. if (which == eValue) {
  49. static_cast<T*>((void*)buffer)->~T();
  50. }
  51. }
  52. };
  53. bool await_ready() { return coro.done(); }
  54. void await_suspend(std::experimental::coroutine_handle<> waiter) {
  55. coro.promise().waiter = waiter;
  56. coro.resume();
  57. }
  58. T await_resume() {
  59. auto& promise = coro.promise();
  60. if (promise.eptr) {
  61. assert(promise.which == eNone);
  62. std::rethrow_exception(coro.promise().eptr);
  63. }
  64. assert(promise.which == eValue);
  65. return *static_cast<T*>((void*)promise.buffer);
  66. }
  67. ~task() {
  68. if (coro) {
  69. coro.destroy();
  70. }
  71. }
  72. task(task&& that) noexcept
  73. : coro(std::exchange(that.coro, nullptr))
  74. {}
  75. private:
  76. task() = delete;
  77. task(task const&) = delete;
  78. explicit task(promise_type* p)
  79. : coro(std::experimental::coroutine_handle<promise_type>::from_promise(*p))
  80. {}
  81. std::experimental::coroutine_handle<promise_type> coro;
  82. };
  83.  
  84. task<int> some_fun() {
  85. co_return 42;
  86. }
  87. task<int> some_fun2() {
  88. int i = co_await some_fun();
  89. std::printf("in some_fun2, got %d\n", i);
  90. co_return i + 1;
  91. }
  92.  
  93. template <typename T>
  94. T sync_await(task<T>&& t) {
  95. struct looper {
  96. struct promise_type {
  97. std::mutex m;
  98. std::condition_variable c;
  99. bool done{false};
  100. std::experimental::suspend_never initial_suspend() { return {}; }
  101. std::experimental::suspend_always final_suspend() {
  102. { std::lock_guard<std::mutex> g(m); done = true; }
  103. c.notify_all();
  104. return {};
  105. }
  106. looper get_return_object() { return looper{*this}; }
  107. void return_void() {}
  108. void unhandled_exception() {}
  109. };
  110. promise_type* promise;
  111. explicit looper(promise_type& p) : promise(&p) {}
  112. looper(looper const&) = delete;
  113. looper(looper &&that) : promise(std::exchange(that.promise, nullptr)) {}
  114. ~looper() {
  115. // Needed because final_suspend returns suspend_always:
  116. if (promise) {
  117. std::experimental::coroutine_handle<promise_type>::
  118. from_promise(*promise).destroy();
  119. }
  120. }
  121. void loop() {
  122. std::unique_lock<std::mutex> lock(promise->m);
  123. promise->c.wait(lock, [this] { return promise->done; });
  124. }
  125. };
  126.  
  127. [&]() -> looper {
  128. (void)co_await t;
  129. }().loop();
  130. return t.await_resume();
  131. }
  132.  
  133. int main() {
  134. auto i = some_fun2();
  135. int j = sync_await(std::move(i));
  136. std::printf("%d\n", j);
  137. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement