coroutine 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. // -*- C++ -*-
  2. //===----------------------------------------------------------------------===//
  3. //
  4. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  5. // See https://llvm.org/LICENSE.txt for license information.
  6. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #ifndef _LIBCPP_EXPERIMENTAL_COROUTINE
  10. #define _LIBCPP_EXPERIMENTAL_COROUTINE
  11. /**
  12. experimental/coroutine synopsis
  13. // C++next
  14. namespace std {
  15. namespace experimental {
  16. inline namespace coroutines_v1 {
  17. // 18.11.1 coroutine traits
  18. template <typename R, typename... ArgTypes>
  19. class coroutine_traits;
  20. // 18.11.2 coroutine handle
  21. template <typename Promise = void>
  22. class coroutine_handle;
  23. // 18.11.2.7 comparison operators:
  24. bool operator==(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
  25. bool operator!=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
  26. bool operator<(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
  27. bool operator<=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
  28. bool operator>=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
  29. bool operator>(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
  30. // 18.11.3 trivial awaitables
  31. struct suspend_never;
  32. struct suspend_always;
  33. // 18.11.2.8 hash support:
  34. template <class T> struct hash;
  35. template <class P> struct hash<coroutine_handle<P>>;
  36. } // namespace coroutines_v1
  37. } // namespace experimental
  38. } // namespace std
  39. */
  40. #include <__assert>
  41. #include <cstddef>
  42. #include <experimental/__config>
  43. #include <functional>
  44. #include <memory> // for hash<T*>
  45. #include <new>
  46. #include <type_traits>
  47. #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
  48. # pragma GCC system_header
  49. #endif
  50. #ifdef _LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES
  51. # if defined(_LIBCPP_WARNING)
  52. _LIBCPP_WARNING("<experimental/coroutine> cannot be used with this compiler")
  53. # else
  54. # warning <experimental/coroutine> cannot be used with this compiler
  55. # endif
  56. #endif
  57. #ifndef _LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES
  58. _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES
  59. template <class _Tp, class = void>
  60. struct __coroutine_traits_sfinae {};
  61. template <class _Tp>
  62. struct __coroutine_traits_sfinae<
  63. _Tp, typename __void_t<typename _Tp::promise_type>::type>
  64. {
  65. using promise_type = typename _Tp::promise_type;
  66. };
  67. template <typename _Ret, typename... _Args>
  68. struct coroutine_traits
  69. : public __coroutine_traits_sfinae<_Ret>
  70. {
  71. };
  72. template <typename _Promise = void>
  73. class _LIBCPP_TEMPLATE_VIS coroutine_handle;
  74. template <>
  75. class _LIBCPP_TEMPLATE_VIS coroutine_handle<void> {
  76. public:
  77. _LIBCPP_INLINE_VISIBILITY
  78. _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {}
  79. _LIBCPP_INLINE_VISIBILITY
  80. _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {}
  81. _LIBCPP_INLINE_VISIBILITY
  82. coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
  83. __handle_ = nullptr;
  84. return *this;
  85. }
  86. _LIBCPP_INLINE_VISIBILITY
  87. _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; }
  88. _LIBCPP_INLINE_VISIBILITY
  89. _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; }
  90. _LIBCPP_INLINE_VISIBILITY
  91. void operator()() { resume(); }
  92. _LIBCPP_INLINE_VISIBILITY
  93. void resume() {
  94. _LIBCPP_ASSERT(__is_suspended(),
  95. "resume() can only be called on suspended coroutines");
  96. _LIBCPP_ASSERT(!done(),
  97. "resume() has undefined behavior when the coroutine is done");
  98. __builtin_coro_resume(__handle_);
  99. }
  100. _LIBCPP_INLINE_VISIBILITY
  101. void destroy() {
  102. _LIBCPP_ASSERT(__is_suspended(),
  103. "destroy() can only be called on suspended coroutines");
  104. __builtin_coro_destroy(__handle_);
  105. }
  106. _LIBCPP_INLINE_VISIBILITY
  107. bool done() const {
  108. _LIBCPP_ASSERT(__is_suspended(),
  109. "done() can only be called on suspended coroutines");
  110. return __builtin_coro_done(__handle_);
  111. }
  112. public:
  113. _LIBCPP_INLINE_VISIBILITY
  114. static coroutine_handle from_address(void* __addr) _NOEXCEPT {
  115. coroutine_handle __tmp;
  116. __tmp.__handle_ = __addr;
  117. return __tmp;
  118. }
  119. // FIXME: Should from_address(nullptr) be allowed?
  120. _LIBCPP_INLINE_VISIBILITY
  121. static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
  122. return coroutine_handle(nullptr);
  123. }
  124. template <class _Tp, bool _CallIsValid = false>
  125. static coroutine_handle from_address(_Tp*) {
  126. static_assert(_CallIsValid,
  127. "coroutine_handle<void>::from_address cannot be called with "
  128. "non-void pointers");
  129. }
  130. private:
  131. bool __is_suspended() const _NOEXCEPT {
  132. // FIXME actually implement a check for if the coro is suspended.
  133. return __handle_;
  134. }
  135. template <class _PromiseT> friend class coroutine_handle;
  136. void* __handle_;
  137. };
  138. // 18.11.2.7 comparison operators:
  139. inline _LIBCPP_INLINE_VISIBILITY
  140. bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
  141. return __x.address() == __y.address();
  142. }
  143. inline _LIBCPP_INLINE_VISIBILITY
  144. bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
  145. return !(__x == __y);
  146. }
  147. inline _LIBCPP_INLINE_VISIBILITY
  148. bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
  149. return less<void*>()(__x.address(), __y.address());
  150. }
  151. inline _LIBCPP_INLINE_VISIBILITY
  152. bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
  153. return __y < __x;
  154. }
  155. inline _LIBCPP_INLINE_VISIBILITY
  156. bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
  157. return !(__x > __y);
  158. }
  159. inline _LIBCPP_INLINE_VISIBILITY
  160. bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
  161. return !(__x < __y);
  162. }
  163. template <typename _Promise>
  164. class _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> {
  165. using _Base = coroutine_handle<>;
  166. public:
  167. #ifndef _LIBCPP_CXX03_LANG
  168. // 18.11.2.1 construct/reset
  169. using coroutine_handle<>::coroutine_handle;
  170. #else
  171. _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT : _Base() {}
  172. _LIBCPP_INLINE_VISIBILITY coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {}
  173. #endif
  174. _LIBCPP_INLINE_VISIBILITY
  175. coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
  176. _Base::operator=(nullptr);
  177. return *this;
  178. }
  179. _LIBCPP_INLINE_VISIBILITY
  180. _Promise& promise() const {
  181. return *static_cast<_Promise*>(
  182. __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false));
  183. }
  184. public:
  185. _LIBCPP_INLINE_VISIBILITY
  186. static coroutine_handle from_address(void* __addr) _NOEXCEPT {
  187. coroutine_handle __tmp;
  188. __tmp.__handle_ = __addr;
  189. return __tmp;
  190. }
  191. // NOTE: this overload isn't required by the standard but is needed so
  192. // the deleted _Promise* overload doesn't make from_address(nullptr)
  193. // ambiguous.
  194. // FIXME: should from_address work with nullptr?
  195. _LIBCPP_INLINE_VISIBILITY
  196. static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
  197. return coroutine_handle(nullptr);
  198. }
  199. template <class _Tp, bool _CallIsValid = false>
  200. static coroutine_handle from_address(_Tp*) {
  201. static_assert(_CallIsValid,
  202. "coroutine_handle<promise_type>::from_address cannot be called with "
  203. "non-void pointers");
  204. }
  205. template <bool _CallIsValid = false>
  206. static coroutine_handle from_address(_Promise*) {
  207. static_assert(_CallIsValid,
  208. "coroutine_handle<promise_type>::from_address cannot be used with "
  209. "pointers to the coroutine's promise type; use 'from_promise' instead");
  210. }
  211. _LIBCPP_INLINE_VISIBILITY
  212. static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT {
  213. typedef typename remove_cv<_Promise>::type _RawPromise;
  214. coroutine_handle __tmp;
  215. __tmp.__handle_ = __builtin_coro_promise(
  216. _VSTD::addressof(const_cast<_RawPromise&>(__promise)),
  217. _LIBCPP_ALIGNOF(_Promise), true);
  218. return __tmp;
  219. }
  220. };
  221. #if __has_builtin(__builtin_coro_noop)
  222. struct noop_coroutine_promise {};
  223. template <>
  224. class _LIBCPP_TEMPLATE_VIS coroutine_handle<noop_coroutine_promise>
  225. : public coroutine_handle<> {
  226. using _Base = coroutine_handle<>;
  227. using _Promise = noop_coroutine_promise;
  228. public:
  229. _LIBCPP_INLINE_VISIBILITY
  230. _Promise& promise() const {
  231. return *static_cast<_Promise*>(
  232. __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false));
  233. }
  234. _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return true; }
  235. _LIBCPP_CONSTEXPR bool done() const _NOEXCEPT { return false; }
  236. _LIBCPP_CONSTEXPR_AFTER_CXX17 void operator()() const _NOEXCEPT {}
  237. _LIBCPP_CONSTEXPR_AFTER_CXX17 void resume() const _NOEXCEPT {}
  238. _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy() const _NOEXCEPT {}
  239. private:
  240. _LIBCPP_INLINE_VISIBILITY
  241. friend coroutine_handle<noop_coroutine_promise> noop_coroutine() _NOEXCEPT;
  242. _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT {
  243. this->__handle_ = __builtin_coro_noop();
  244. }
  245. };
  246. using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
  247. inline _LIBCPP_INLINE_VISIBILITY
  248. noop_coroutine_handle noop_coroutine() _NOEXCEPT {
  249. return noop_coroutine_handle();
  250. }
  251. #endif // __has_builtin(__builtin_coro_noop)
  252. struct suspend_never {
  253. _LIBCPP_INLINE_VISIBILITY
  254. bool await_ready() const _NOEXCEPT { return true; }
  255. _LIBCPP_INLINE_VISIBILITY
  256. void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
  257. _LIBCPP_INLINE_VISIBILITY
  258. void await_resume() const _NOEXCEPT {}
  259. };
  260. struct suspend_always {
  261. _LIBCPP_INLINE_VISIBILITY
  262. bool await_ready() const _NOEXCEPT { return false; }
  263. _LIBCPP_INLINE_VISIBILITY
  264. void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
  265. _LIBCPP_INLINE_VISIBILITY
  266. void await_resume() const _NOEXCEPT {}
  267. };
  268. _LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES
  269. _LIBCPP_BEGIN_NAMESPACE_STD
  270. template <class _Tp>
  271. struct hash<_VSTD_CORO::coroutine_handle<_Tp> > {
  272. using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>;
  273. _LIBCPP_INLINE_VISIBILITY
  274. size_t operator()(__arg_type const& __v) const _NOEXCEPT
  275. {return hash<void*>()(__v.address());}
  276. };
  277. _LIBCPP_END_NAMESPACE_STD
  278. #endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES)
  279. #endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */