KDDockWidgets API Documentation 2.0
Loading...
Searching...
No Matches
coroutine.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2021 Daniel Vrátil <dvratil@kde.org>
2//
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include <version>
8#include <utility>
9
10// __cpp_lib_coroutine is not defined if the compiler doesn't support coroutines
11// (__cpp_impl_coroutine), e.g. clang as of 13.0.
12#if defined(__cpp_lib_coroutine)
13#include <coroutine>
14#elif defined(__clang__)
15// Implement our own <coroutine> header in a way that is compatible with the standard.
16// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/n4849.pdf
17
18#include <type_traits> // void_t
19#include <cstddef> // size_t
20
21// Intrinsincs for Clang
22// https://clang.llvm.org/docs/LanguageExtensions.html#c-coroutines-support-builtins
23extern "C" {
24void __builtin_coro_destroy(void *addr);
25void __builtin_coro_resume(void *addr);
26bool __builtin_coro_done(void *addr);
27void* __builtin_coro_promise(void *addr, int alignment, bool from_promise);
28void *__builtin_coro_noop();
29}
30
31// 17.12.1 Header <coroutine> synopsis
32namespace std {
33
34// 17.12.2, coroutine traits
35// (omitted, because we implement them in std::experimental namespace and import them into the std
36// namespace).
37// template<class R, class .. ArgTypes>
38// struct coroutine_traits;
39
40// 17.12.3, coroutine traits
41template<class Promise = void>
42struct coroutine_handle;
43
44// 17.12.3.6, comparison operators
45constexpr bool operator==(coroutine_handle<> x, coroutine_handle<> y) noexcept;
46// constexpr strong_ordering operator<=>(coroutine_handle<> x, coroutine_handle<> y) noexcept;
47
48// 17.12.3.7, hash support
49//template<class T> struct hash;
50//template<class P> struct hash<coroutine_handle<P>>;
51
52// 17.12.4, n-op- coroutines
53struct noop_coroutine_promise;
54
55template<>
56struct coroutine_handle<noop_coroutine_promise>;
57using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
58noop_coroutine_handle noop_coroutine() noexcept;
59
60// 17.12.5, trivial awaitables
61struct suspend_never;
62struct suspend_always;
63
64} // namespace std
65
66
67// Implementation
68namespace std {
69
70// Clang checks for std::experimental::coroutine_traits explicitly, so we must define the types
71// in the experimental namespace.
72namespace experimental {
73
74template<class R, class = void>
75struct __coroutine_traits_base {};
76
77template<class R>
78struct __coroutine_traits_base<R, void_t<typename R::promise_type>> {
79 using promise_type = typename R::promise_type;
80};
81
82
83// 17.12.2, coroutine traits
84
85template<class R, class ... ArgTypes>
86struct coroutine_traits : __coroutine_traits_base<R> {};
87
88
89// Clang requires that std::experimental::coroutine_handle is a class template
90template<typename Promise>
91struct coroutine_handle : public std::coroutine_handle<Promise> {};
92
93} // namespace experimental
94
95// Import std::experimental::coroutine_traits into the std namespace
96template<typename R, typename ... ArgTypes>
97using coroutine_traits = std::experimental::coroutine_traits<R, ArgTypes ...>;
98
99
100// 17.12.3, coroutine handle
101
102template<>
103struct coroutine_handle<void> {
104 // 17.12.3.1, construct/reset
105 constexpr coroutine_handle() noexcept {}
106 constexpr coroutine_handle(nullptr_t) noexcept {}
107 coroutine_handle &operator=(nullptr_t) noexcept {
108 m_ptr = nullptr;
109 return *this;
110 }
111
112 // 17.12.3.2, export/import
113 constexpr void *address() const noexcept {
114 return m_ptr;
115 }
116
117 static constexpr coroutine_handle from_address(void *addr) noexcept {
118 coroutine_handle handle;
119 handle.m_ptr = addr;
120 return handle;
121 }
122
123 // 17.12.3.3, observers
124 constexpr explicit operator bool() const noexcept {
125 return m_ptr != nullptr;
126 }
127 bool done() const {
128 return __builtin_coro_done(m_ptr);
129 }
130
131 // 17.12.3.4, resumption
132 void operator()() const {
133 resume();
134 }
135 void resume() const {
136 __builtin_coro_resume(m_ptr);
137 }
138 void destroy() const {
139 __builtin_coro_destroy(m_ptr);
140 }
141
142protected:
143 void *m_ptr = nullptr;
144};
145
146template<class Promise>
147struct coroutine_handle : public coroutine_handle<> {
148 // 17.12.3.1, construct, reset
149 using coroutine_handle<>::coroutine_handle;
150 static coroutine_handle from_promise(Promise &promise) {
151 coroutine_handle handle;
152 handle.m_ptr = __builtin_coro_promise(&promise, alignof(Promise), /* from-promise=*/ true);
153 return handle;
154 }
155 coroutine_handle &operator=(nullptr_t) noexcept {
156 this->m_ptr = nullptr;
157 return *this;
158 }
159
160 // 17.12.3.2, export/import
161 static constexpr coroutine_handle from_address(void *addr) noexcept {
162 coroutine_handle handle;
163 handle.m_ptr = addr;
164 return handle;
165 }
166
167 //17.12.3.5, promise access
168 Promise &promise() const {
169 return *reinterpret_cast<Promise *>(
170 __builtin_coro_promise(m_ptr, alignof(Promise), /*from-promise=*/false));
171 }
172};
173
174// 17.12.3.6, comparison operators
175constexpr bool operator==(coroutine_handle<> x, coroutine_handle<> y) noexcept {
176 return x.address() == y.address();
177}
178
179//constexpr strong_ordering operator<=>(coroutine_handle<> x, coroutine_handle<> y) noexcept;
180
181// 17.12.4, no-op coroutines
182struct noop_coroutine_promise {};
183
184template<>
185struct coroutine_handle<noop_coroutine_promise>;
186using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
187
188template<>
189struct coroutine_handle<noop_coroutine_promise> : public coroutine_handle<> {
190 // 17.12.4.2.1, observers
191 constexpr explicit operator bool() const noexcept { return true; }
192 constexpr bool done() const noexcept { return false; }
193 constexpr void operator()() const noexcept {}
194 constexpr void resume() const noexcept {}
195 constexpr void destroy() const noexcept {}
196
197 noop_coroutine_promise &promise() const noexcept {
198 return *reinterpret_cast<noop_coroutine_promise *>(
199 __builtin_coro_promise(__builtin_coro_noop(),
200 alignof(noop_coroutine_promise), false));
201 }
202
203private:
204 coroutine_handle() noexcept
205 : coroutine_handle<>(from_address(__builtin_coro_noop())) {}
206
207 friend noop_coroutine_handle noop_coroutine() noexcept;
208};
209
210inline noop_coroutine_handle noop_coroutine() noexcept {
211 return {};
212}
213
214// 17.12.5, trivial awaitables
215
216struct suspend_never {
217 constexpr bool await_ready() const noexcept { return true; }
218 constexpr void await_resume() const noexcept {}
219 constexpr void await_suspend(coroutine_handle<>) const noexcept {}
220};
221
222struct suspend_always {
223 constexpr bool await_ready() const noexcept { return false; }
224 constexpr void await_suspend(coroutine_handle<>) const noexcept {}
225 constexpr void await_resume() const noexcept {}
226};
227
228} // namespace std
229
230#else // defined(__clang__)
231#pragma error "Current compiler does not support coroutines, or is not supported by QCoro."
232#endif // defined(__cpp_lib_coroutine)
233
234// The QCORO_STD macro is no longer needed (with the code above), but keep it for backwards
235// compatibility.
236#ifdef QCORO_NO_DEPRECATED_QCOROSTD
237#define QCORO_STD std
238#else // QCORO_NO_DEPRECATED_QCOROSTD
239#ifdef _MSC_VER
240 #define _QCORO_STRINGIFY2(x) #x
241 #define _QCORO_STRINGIFY(x) _QCORO_STRINGIFY2(x)
242 #define QCORO_STD \
243 __pragma(message(__FILE__ "(" _QCORO_STRINGIFY(__LINE__) ") QCORO_STD macro is deprecated, use regular 'std' namespace instead, or pass /DQCORO_NO_DEPRECATED_QCOROSTD to suppress this warning.")) \
244 std
245#else // GCC, clang
246 #define QCORO_STD \
247 _Pragma("GCC warning \"QCORO_STD macro is deprecated, use regular 'std' namespace instead, or pass -DQCORO_NO_DEPRECATED_QCOROSTD to suppress this warning.\"") \
248 std
249#endif // _MSC_VER
250#endif // QCORO_NO_DEPRECATED_QCOROSTD
251
252// Moc doesn't seem to understand something in the <concepts> header...
253#ifndef Q_MOC_RUN
254
255#include "concepts_p.h"
256
257namespace QCoro {
258
259namespace detail {
260
261
262template<typename T>
263concept has_await_methods = requires(T t) {
264 { t.await_ready() } -> std::same_as<bool>;
265 {t.await_suspend(std::declval<std::coroutine_handle<>>())};
266 {t.await_resume()};
267};
268
269template<typename T>
270concept has_member_operator_coawait = requires(T t) {
271 // TODO: Check that result of co_await() satisfies Awaitable again
272 { t.operator co_await() };
273};
274
275template<typename T>
276concept has_nonmember_operator_coawait = requires(T t) {
277 // TODO: Check that result of the operator satisfied Awaitable again
278#if defined(_MSC_VER) && !defined(__clang__)
279 // FIXME: MSVC is unable to perform ADL lookup for operator co_await and just fails to compile
280 { ::operator co_await(static_cast<T &&>(t)) };
281#else
282 { operator co_await(static_cast<T &&>(t)) };
283#endif
284};
285
286} // namespace detail
287
289
292template<typename T>
296
297} // namespace QCoro
298
299#endif // Q_MOC_RUN
A concept describing the Awaitable type.
Definition coroutine.h:293
Definition utils.h:161

© Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
KDDockWidgets
Advanced Dock Widget Framework for Qt
https://www.kdab.com/development-resources/qt-tools/kddockwidgets/
Generated by doxygen 1.9.8