xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/include/std/coroutine (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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