1// <coroutine> -*- C++ -*- 2 3// Copyright (C) 2019-2022 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 <type_traits> 38#if __cplusplus > 201703L 39# include <compare> 40#endif 41 42#if !defined __cpp_lib_three_way_comparison && _GLIBCXX_HOSTED 43# include <bits/stl_function.h> // for std::less 44#endif 45 46/** 47 * @defgroup coroutines Coroutines 48 * 49 * Components for supporting coroutine implementations. 50 * 51 * @since C++20 (and since C++14 as a libstdc++ extension) 52 */ 53 54namespace std _GLIBCXX_VISIBILITY (default) 55{ 56_GLIBCXX_BEGIN_NAMESPACE_VERSION 57 58#if __cpp_impl_coroutine 59 60#define __cpp_lib_coroutine 201902L 61 62 inline namespace __n4861 { 63 64 // C++20 17.12.2 coroutine traits 65 /// [coroutine.traits] 66 /// [coroutine.traits.primary] 67 /// If _Result::promise_type is valid and denotes a type then the traits 68 /// have a single publicly accessible member, otherwise they are empty. 69 template <typename _Result, typename... _ArgTypes> 70 struct coroutine_traits; 71 72 template <typename _Result, typename = void> 73 struct __coroutine_traits_impl {}; 74 75 template <typename _Result> 76#if __cpp_concepts 77 requires requires { typename _Result::promise_type; } 78 struct __coroutine_traits_impl<_Result, void> 79#else 80 struct __coroutine_traits_impl<_Result, 81 __void_t<typename _Result::promise_type>> 82#endif 83 { 84 using promise_type = typename _Result::promise_type; 85 }; 86 87 template <typename _Result, typename... _ArgTypes> 88 struct coroutine_traits : __coroutine_traits_impl<_Result> {}; 89 90 // C++20 17.12.3 Class template coroutine_handle 91 /// [coroutine.handle] 92 template <typename _Promise = void> 93 struct coroutine_handle; 94 95 template <> struct 96 coroutine_handle<void> 97 { 98 public: 99 // [coroutine.handle.con], construct/reset 100 constexpr coroutine_handle() noexcept : _M_fr_ptr(0) {} 101 102 constexpr coroutine_handle(std::nullptr_t __h) noexcept 103 : _M_fr_ptr(__h) 104 {} 105 106 coroutine_handle& operator=(std::nullptr_t) noexcept 107 { 108 _M_fr_ptr = nullptr; 109 return *this; 110 } 111 112 public: 113 // [coroutine.handle.export.import], export/import 114 constexpr void* address() const noexcept { return _M_fr_ptr; } 115 116 constexpr static coroutine_handle from_address(void* __a) noexcept 117 { 118 coroutine_handle __self; 119 __self._M_fr_ptr = __a; 120 return __self; 121 } 122 123 public: 124 // [coroutine.handle.observers], observers 125 constexpr explicit operator bool() const noexcept 126 { 127 return bool(_M_fr_ptr); 128 } 129 130 bool done() const noexcept { return __builtin_coro_done(_M_fr_ptr); } 131 132 // [coroutine.handle.resumption], resumption 133 void operator()() const { resume(); } 134 135 void resume() const { __builtin_coro_resume(_M_fr_ptr); } 136 137 void destroy() const { __builtin_coro_destroy(_M_fr_ptr); } 138 139 protected: 140 void* _M_fr_ptr; 141 }; 142 143 // [coroutine.handle.compare], comparison operators 144 145 constexpr bool 146 operator==(coroutine_handle<> __a, coroutine_handle<> __b) noexcept 147 { 148 return __a.address() == __b.address(); 149 } 150 151#ifdef __cpp_lib_three_way_comparison 152 constexpr strong_ordering 153 operator<=>(coroutine_handle<> __a, coroutine_handle<> __b) noexcept 154 { 155 return std::compare_three_way()(__a.address(), __b.address()); 156 } 157#else 158 // These are to enable operation with std=c++14,17. 159 constexpr bool 160 operator!=(coroutine_handle<> __a, coroutine_handle<> __b) noexcept 161 { 162 return !(__a == __b); 163 } 164 165 constexpr bool 166 operator<(coroutine_handle<> __a, coroutine_handle<> __b) noexcept 167 { 168#if _GLIBCXX_HOSTED 169 return less<void*>()(__a.address(), __b.address()); 170#else 171 return (__UINTPTR_TYPE__)__a.address() < (__UINTPTR_TYPE__)__b.address(); 172#endif 173 } 174 175 constexpr bool 176 operator>(coroutine_handle<> __a, coroutine_handle<> __b) noexcept 177 { 178 return __b < __a; 179 } 180 181 constexpr bool 182 operator<=(coroutine_handle<> __a, coroutine_handle<> __b) noexcept 183 { 184 return !(__a > __b); 185 } 186 187 constexpr bool 188 operator>=(coroutine_handle<> __a, coroutine_handle<> __b) noexcept 189 { 190 return !(__a < __b); 191 } 192#endif 193 194 template <typename _Promise> 195 struct coroutine_handle 196 { 197 // [coroutine.handle.con], construct/reset 198 199 constexpr coroutine_handle() noexcept { } 200 201 constexpr coroutine_handle(nullptr_t) noexcept { } 202 203 static coroutine_handle 204 from_promise(_Promise& __p) 205 { 206 coroutine_handle __self; 207 __self._M_fr_ptr 208 = __builtin_coro_promise((char*) &__p, __alignof(_Promise), true); 209 return __self; 210 } 211 212 coroutine_handle& operator=(nullptr_t) noexcept 213 { 214 _M_fr_ptr = nullptr; 215 return *this; 216 } 217 218 // [coroutine.handle.export.import], export/import 219 220 constexpr void* address() const noexcept { return _M_fr_ptr; } 221 222 constexpr static coroutine_handle from_address(void* __a) noexcept 223 { 224 coroutine_handle __self; 225 __self._M_fr_ptr = __a; 226 return __self; 227 } 228 229 // [coroutine.handle.conv], conversion 230 constexpr operator coroutine_handle<>() const noexcept 231 { return coroutine_handle<>::from_address(address()); } 232 233 // [coroutine.handle.observers], observers 234 constexpr explicit operator bool() const noexcept 235 { 236 return bool(_M_fr_ptr); 237 } 238 239 bool done() const noexcept { return __builtin_coro_done(_M_fr_ptr); } 240 241 // [coroutine.handle.resumption], resumption 242 void operator()() const { resume(); } 243 244 void resume() const { __builtin_coro_resume(_M_fr_ptr); } 245 246 void destroy() const { __builtin_coro_destroy(_M_fr_ptr); } 247 248 // [coroutine.handle.promise], promise access 249 _Promise& promise() const 250 { 251 void* __t 252 = __builtin_coro_promise (_M_fr_ptr, __alignof(_Promise), false); 253 return *static_cast<_Promise*>(__t); 254 } 255 256 private: 257 void* _M_fr_ptr = nullptr; 258 }; 259 260 /// [coroutine.noop] 261 struct noop_coroutine_promise 262 { 263 }; 264 265 // 17.12.4.1 Class noop_coroutine_promise 266 /// [coroutine.promise.noop] 267 template <> 268 struct coroutine_handle<noop_coroutine_promise> 269 { 270 // _GLIBCXX_RESOLVE_LIB_DEFECTS 271 // 3460. Unimplementable noop_coroutine_handle guarantees 272 // [coroutine.handle.noop.conv], conversion 273 constexpr operator coroutine_handle<>() const noexcept 274 { return coroutine_handle<>::from_address(address()); } 275 276 // [coroutine.handle.noop.observers], observers 277 constexpr explicit operator bool() const noexcept { return true; } 278 279 constexpr bool done() const noexcept { return false; } 280 281 // [coroutine.handle.noop.resumption], resumption 282 void operator()() const noexcept {} 283 284 void resume() const noexcept {} 285 286 void destroy() const noexcept {} 287 288 // [coroutine.handle.noop.promise], promise access 289 noop_coroutine_promise& promise() const noexcept 290 { return _S_fr.__p; } 291 292 // [coroutine.handle.noop.address], address 293 constexpr void* address() const noexcept { return _M_fr_ptr; } 294 295 private: 296 friend coroutine_handle noop_coroutine() noexcept; 297 298 struct __frame 299 { 300 static void __dummy_resume_destroy() { } 301 302 void (*__r)() = __dummy_resume_destroy; 303 void (*__d)() = __dummy_resume_destroy; 304 struct noop_coroutine_promise __p; 305 }; 306 307 static __frame _S_fr; 308 309 explicit coroutine_handle() noexcept = default; 310 311 void* _M_fr_ptr = &_S_fr; 312 }; 313 314 using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>; 315 316 inline noop_coroutine_handle::__frame 317 noop_coroutine_handle::_S_fr{}; 318 319 inline noop_coroutine_handle noop_coroutine() noexcept 320 { 321 return noop_coroutine_handle(); 322 } 323 324 // 17.12.5 Trivial awaitables 325 /// [coroutine.trivial.awaitables] 326 struct suspend_always 327 { 328 constexpr bool await_ready() const noexcept { return false; } 329 330 constexpr void await_suspend(coroutine_handle<>) const noexcept {} 331 332 constexpr void await_resume() const noexcept {} 333 }; 334 335 struct suspend_never 336 { 337 constexpr bool await_ready() const noexcept { return true; } 338 339 constexpr void await_suspend(coroutine_handle<>) const noexcept {} 340 341 constexpr void await_resume() const noexcept {} 342 }; 343 344 } // namespace __n4861 345 346#if _GLIBCXX_HOSTED 347 template<typename _Tp> struct hash; 348 349 template<typename _Promise> 350 struct hash<coroutine_handle<_Promise>> 351 { 352 size_t 353 operator()(const coroutine_handle<_Promise>& __h) const noexcept 354 { 355 return reinterpret_cast<size_t>(__h.address()); 356 } 357 }; 358#endif 359 360#else 361#error "the coroutine header requires -fcoroutines" 362#endif 363 364 _GLIBCXX_END_NAMESPACE_VERSION 365} // namespace std 366 367#endif // C++14 (we are allowing use from at least this) 368 369#endif // _GLIBCXX_COROUTINE 370