1// <coroutine> -*- C++ -*- 2 3// Copyright (C) 2019-2020 Free Software Foundation, Inc. 4// 5// This file is part of the GNU ISO C++ Library. This library is free 6// software; you can redistribute it and/or modify it under the 7// terms of the GNU General Public License as published by the 8// Free Software Foundation; either version 3, or (at your option) 9// any later version. 10 11// This library is distributed in the hope that it will be useful, 12// but WITHOUT ANY WARRANTY; without even the implied warranty of 13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14// GNU General Public License for more details. 15 16// Under Section 7 of GPL version 3, you are granted additional 17// permissions described in the GCC Runtime Library Exception, version 18// 3.1, as published by the Free Software Foundation. 19 20// You should have received a copy of the GNU General Public License and 21// a copy of the GCC Runtime Library Exception along with this program; 22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23// <http://www.gnu.org/licenses/>. 24 25/** @file include/coroutine 26 * This is a Standard C++ Library header. 27 */ 28 29#ifndef _GLIBCXX_COROUTINE 30#define _GLIBCXX_COROUTINE 1 31 32#pragma GCC system_header 33 34// It is very likely that earlier versions would work, but they are untested. 35#if __cplusplus >= 201402L 36 37#include <bits/c++config.h> 38 39/** 40 * @defgroup coroutines Coroutines 41 * 42 * Components for supporting coroutine implementations. 43 */ 44 45#if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L 46# include <compare> 47# define _COROUTINES_USE_SPACESHIP 1 48#else 49# include <bits/stl_function.h> // for std::less 50# define _COROUTINES_USE_SPACESHIP 0 51#endif 52 53namespace std _GLIBCXX_VISIBILITY (default) 54{ 55_GLIBCXX_BEGIN_NAMESPACE_VERSION 56 57#if __cpp_impl_coroutine 58 59#define __cpp_lib_coroutine 201902L 60 61 inline namespace __n4861 { 62 63 // 17.12.2 coroutine traits 64 /// [coroutine.traits] 65 /// [coroutine.traits.primary] 66 /// If _Result::promise_type is valid and denotes a type then the traits 67 /// have a single publicly accessible member, otherwise they are empty. 68 template <typename _Result, typename = void> 69 struct __coroutine_traits_impl {}; 70 71 template <typename _Result> 72 struct __coroutine_traits_impl<_Result, 73 __void_t<typename _Result::promise_type>> 74 { 75 using promise_type = typename _Result::promise_type; 76 }; 77 78 template <typename _Result, typename...> 79 struct coroutine_traits : __coroutine_traits_impl<_Result> {}; 80 81 // 17.12.3 Class template coroutine_handle 82 /// [coroutine.handle] 83 template <typename _Promise = void> 84 struct coroutine_handle; 85 86 template <> struct 87 coroutine_handle<void> 88 { 89 public: 90 // 17.12.3.1, construct/reset 91 constexpr coroutine_handle() noexcept : _M_fr_ptr(0) {} 92 93 constexpr coroutine_handle(std::nullptr_t __h) noexcept 94 : _M_fr_ptr(__h) 95 {} 96 97 coroutine_handle& operator=(std::nullptr_t) noexcept 98 { 99 _M_fr_ptr = nullptr; 100 return *this; 101 } 102 103 public: 104 // 17.12.3.2, export/import 105 constexpr void* address() const noexcept { return _M_fr_ptr; } 106 107 constexpr static coroutine_handle from_address(void* __a) noexcept 108 { 109 coroutine_handle __self; 110 __self._M_fr_ptr = __a; 111 return __self; 112 } 113 114 public: 115 // 17.12.3.3, observers 116 constexpr explicit operator bool() const noexcept 117 { 118 return bool(_M_fr_ptr); 119 } 120 121 bool done() const noexcept { return __builtin_coro_done(_M_fr_ptr); } 122 123 // 17.12.3.4, resumption 124 void operator()() const { resume(); } 125 126 void resume() const { __builtin_coro_resume(_M_fr_ptr); } 127 128 void destroy() const { __builtin_coro_destroy(_M_fr_ptr); } 129 130 protected: 131 void* _M_fr_ptr; 132 }; 133 134 // 17.12.3.6 Comparison operators 135 /// [coroutine.handle.compare] 136 constexpr bool operator==(coroutine_handle<> __a, 137 coroutine_handle<> __b) noexcept 138 { 139 return __a.address() == __b.address(); 140 } 141 142#if _COROUTINES_USE_SPACESHIP 143 constexpr strong_ordering 144 operator<=>(coroutine_handle<> __a, coroutine_handle<> __b) noexcept 145 { return std::compare_three_way()(__a.address(), __b.address()); } 146#else 147 // These are to enable operation with std=c++14,17. 148 constexpr bool operator!=(coroutine_handle<> __a, 149 coroutine_handle<> __b) noexcept 150 { 151 return !(__a == __b); 152 } 153 154 constexpr bool operator<(coroutine_handle<> __a, 155 coroutine_handle<> __b) noexcept 156 { 157 return less<void*>()(__a.address(), __b.address()); 158 } 159 160 constexpr bool operator>(coroutine_handle<> __a, 161 coroutine_handle<> __b) noexcept 162 { 163 return __b < __a; 164 } 165 166 constexpr bool operator<=(coroutine_handle<> __a, 167 coroutine_handle<> __b) noexcept 168 { 169 return !(__a > __b); 170 } 171 172 constexpr bool operator>=(coroutine_handle<> __a, 173 coroutine_handle<> __b) noexcept 174 { 175 return !(__a < __b); 176 } 177#endif 178 179 template <typename _Promise> 180 struct coroutine_handle : coroutine_handle<> 181 { 182 // 17.12.3.1, construct/reset 183 using coroutine_handle<>::coroutine_handle; 184 185 static coroutine_handle from_promise(_Promise& p) 186 { 187 coroutine_handle __self; 188 __self._M_fr_ptr 189 = __builtin_coro_promise((char*) &p, __alignof(_Promise), true); 190 return __self; 191 } 192 193 coroutine_handle& operator=(std::nullptr_t) noexcept 194 { 195 coroutine_handle<>::operator=(nullptr); 196 return *this; 197 } 198 199 // 17.12.3.2, export/import 200 constexpr static coroutine_handle from_address(void* __a) noexcept 201 { 202 coroutine_handle __self; 203 __self._M_fr_ptr = __a; 204 return __self; 205 } 206 207 // 17.12.3.5, promise accesss 208 _Promise& promise() const 209 { 210 void* __t 211 = __builtin_coro_promise (this->_M_fr_ptr, __alignof(_Promise), false); 212 return *static_cast<_Promise*>(__t); 213 } 214 }; 215 216 /// [coroutine.noop] 217 struct noop_coroutine_promise 218 { 219 }; 220 221 void __dummy_resume_destroy() __attribute__((__weak__)); 222 void __dummy_resume_destroy() {} 223 224 struct __noop_coro_frame 225 { 226 void (*__r)() = __dummy_resume_destroy; 227 void (*__d)() = __dummy_resume_destroy; 228 struct noop_coroutine_promise __p; 229 } __noop_coro_fr __attribute__((__weak__)); 230 231 // 17.12.4.1 Class noop_coroutine_promise 232 /// [coroutine.promise.noop] 233 template <> 234 struct coroutine_handle<noop_coroutine_promise> : public coroutine_handle<> 235 { 236 using _Promise = noop_coroutine_promise; 237 238 public: 239 // 17.12.4.2.1, observers 240 constexpr explicit operator bool() const noexcept { return true; } 241 242 constexpr bool done() const noexcept { return false; } 243 244 // 17.12.4.2.2, resumption 245 void operator()() const noexcept {} 246 247 void resume() const noexcept {} 248 249 void destroy() const noexcept {} 250 251 // 17.12.4.2.3, promise access 252 _Promise& promise() const 253 { 254 return *static_cast<_Promise*>( 255 __builtin_coro_promise(this->_M_fr_ptr, __alignof(_Promise), false)); 256 } 257 258 // 17.12.4.2.4, address 259 private: 260 friend coroutine_handle<noop_coroutine_promise> noop_coroutine() noexcept; 261 262 coroutine_handle() noexcept { this->_M_fr_ptr = (void*) &__noop_coro_fr; } 263 }; 264 265 using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>; 266 267 inline noop_coroutine_handle noop_coroutine() noexcept 268 { 269 return noop_coroutine_handle(); 270 } 271 272 // 17.12.5 Trivial awaitables 273 /// [coroutine.trivial.awaitables] 274 struct suspend_always 275 { 276 constexpr bool await_ready() const noexcept { return false; } 277 278 constexpr void await_suspend(coroutine_handle<>) const noexcept {} 279 280 constexpr void await_resume() const noexcept {} 281 }; 282 283 struct suspend_never 284 { 285 constexpr bool await_ready() const noexcept { return true; } 286 287 constexpr void await_suspend(coroutine_handle<>) const noexcept {} 288 289 constexpr void await_resume() const noexcept {} 290 }; 291 292 } // namespace __n4861 293 294#else 295#error "the coroutine header requires -fcoroutines" 296#endif 297 298 _GLIBCXX_END_NAMESPACE_VERSION 299} // namespace std 300 301#endif // C++14 (we are allowing use from at least this) 302 303#endif // _GLIBCXX_COROUTINE 304