task.h 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #ifndef GUL_COROUTINE_TASK_H
  2. #define GUL_COROUTINE_TASK_H
  3. #include <coroutine>
  4. #include <utility>
  5. #include <exception>
  6. namespace gul
  7. {
  8. template<typename T>
  9. struct promise_value
  10. {
  11. T result;
  12. void return_value(T && r )
  13. {
  14. result = std::move(r);
  15. }
  16. };
  17. struct promise_void
  18. {
  19. void return_void()
  20. {
  21. }
  22. };
  23. template<typename T>
  24. struct Task_t
  25. {
  26. struct promise_type : public std::conditional_t< std::is_same_v<void,T>, promise_void, promise_value<T> >
  27. {
  28. bool _done = false;
  29. // must have a default consturctor
  30. promise_type() = default;
  31. // this is the first method to get
  32. // executed when a coroutine is
  33. // called for the first time
  34. // Its job is to construct the return
  35. // object
  36. Task_t<T> get_return_object()
  37. {
  38. //std::cout << "get_return_object()\n";
  39. return Task_t<T>{std::coroutine_handle<promise_type>::from_promise(*this)};
  40. }
  41. // returns an awaiter. can return
  42. // std::suspend_never/always
  43. // This is called just before the corotuine
  44. // starts execution. It specifies in what
  45. // state the coroutine should start in.
  46. // in this case we are not-suspending when
  47. // we first start the coroutine
  48. std::suspend_never initial_suspend() {
  49. _done = false;
  50. //std::cout << "initial suspend\n";
  51. return {};
  52. }
  53. // executes when the coroutine finishes
  54. // executing.
  55. std::suspend_always final_suspend() noexcept {
  56. _done = true;
  57. //std::cout << "final suspend\n";
  58. return {};
  59. }
  60. // if there are any exceptions thrown
  61. // that are not handled, this function
  62. // will be called
  63. void unhandled_exception()
  64. {
  65. std::cout << "Unhandled Exception" << std::endl;
  66. }
  67. };
  68. // a copy constructor that passes in a coroutine handle
  69. // so that we can control the exceution
  70. Task_t(std::coroutine_handle<promise_type> handle_) : handle(handle_)
  71. {
  72. }
  73. ~Task_t()
  74. {
  75. if(handle)
  76. handle.destroy();
  77. }
  78. Task_t(Task_t<T> &&V) : handle(std::exchange(V.handle, nullptr))
  79. {
  80. }
  81. Task_t & operator=(Task_t<T> && V)
  82. {
  83. if(&V != this)
  84. {
  85. handle = std::exchange(V.handle, nullptr);
  86. }
  87. return *this;
  88. }
  89. Task_t(Task_t<T> const &handle_) = delete;
  90. Task_t & operator=(Task_t<T> const & V) = delete;
  91. void resume()
  92. {
  93. try
  94. {
  95. handle.resume();
  96. }
  97. catch (std::exception & e)
  98. {
  99. std::cout << "Exception Thrown: " << e.what() << std::endl;
  100. throw e;
  101. }
  102. }
  103. T operator()()
  104. {
  105. //handle.resume();
  106. return std::move(handle.promise().result);
  107. }
  108. bool done() const
  109. {
  110. return handle.done();
  111. }
  112. std::coroutine_handle<promise_type> handle;
  113. };
  114. template<typename T>
  115. using Task = Task_t<T>;
  116. }
  117. #endif