LeechCraft 0.6.70-18450-gabe19ee3b0
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
task.h
Go to the documentation of this file.
1/**********************************************************************
2 * LeechCraft - modular cross-platform feature rich internet client.
3 * Copyright (C) 2006-2014 Georg Rudoy
4 *
5 * Distributed under the Boost Software License, Version 1.0.
6 * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7 **********************************************************************/
8
9#pragma once
10
11#include <coroutine>
12#include <exception>
13#include <mutex>
14#include <utility>
15#include "finalsuspender.h"
16#include "taskfwd.h"
17
18namespace LC::Util
19{
20 namespace detail
21 {
23 {
24 std::atomic<size_t> Refs_ = 1;
25 std::atomic<std::coroutine_handle<>> Continuation_ {};
26 std::exception_ptr Exception_ {};
27 };
28
29 template<typename R>
31 {
32 using ReturnType_t = R;
33
34 constexpr static bool IsVoid = false;
35
36 std::optional<R> Ret_;
37
38 template<typename U = R>
39 void return_value (this auto&& self, U&& val)
40 {
41 std::lock_guard guard { self };
42 self.Ret_.emplace (std::forward<U> (val));
43 }
44 };
45
46 template<>
47 struct PromiseRet<void> : PromiseBase
48 {
49 constexpr static bool IsVoid = true;
50
51 bool Done_ = false;
52
53 void return_void (this auto&& self) noexcept
54 {
55 std::lock_guard guard { self };
56 self.Done_ = true;
57 }
58 };
59
60 struct EitherFailureAbort final : std::exception {};
61
62 template<typename Promise>
64 {
65 using Handle_t = std::coroutine_handle<Promise>;
67
68 explicit TaskAwaiter (Handle_t subtask)
69 : Subtask_ { subtask }
70 {
71 }
72
73 TaskAwaiter (TaskAwaiter&& other) noexcept
74 : Subtask_ { std::exchange (other.Subtask_, {}) }
75 {
76 }
77
78 TaskAwaiter (const TaskAwaiter&) = delete;
81
83 {
84 if (Subtask_)
85 Subtask_.promise ().Continuation_.exchange ({});
86 }
87
88 bool await_ready () const noexcept
89 {
90 const auto& promise = Subtask_.promise ();
91 std::lock_guard guard { promise };
92 return CheckTaskFinishedUnlocked (promise);
93 }
94
95 bool await_suspend (std::coroutine_handle<> handle)
96 {
97 auto& promise = Subtask_.promise ();
98 std::lock_guard guard { promise };
99 if (CheckTaskFinishedUnlocked (promise))
100 return false;
101
102 if (promise.Continuation_.exchange (handle))
103 qFatal () << "subtask has already been awaited on";
104 return true;
105 }
106
108 {
109 const auto& promise = Subtask_.promise ();
110 std::lock_guard guard { promise };
111 if (promise.Exception_)
112 try
113 {
114 std::rethrow_exception (promise.Exception_);
115 }
116 catch (const EitherFailureAbort&)
117 {
118 }
119
120 if constexpr (!Promise::IsVoid)
121 return *promise.Ret_;
122 }
123 private:
124 bool CheckTaskFinishedUnlocked (const Promise& promise) const
125 {
126 if (promise.Exception_)
127 return true;
128
129 if constexpr (Promise::IsVoid)
130 return promise.Done_;
131 else
132 return static_cast<bool> (promise.Ret_);
133 }
134 };
135 }
136
137 template<typename>
139 {
140 mutable std::mutex Mutex_;
141
142 void DoLock () const
143 {
144 Mutex_.lock ();
145 }
146
147 void DoUnlock () const
148 {
149 Mutex_.unlock ();
150 }
151 };
152
153 template<typename R, template<typename> typename... Extensions>
154 class Task
155 {
156 public:
157 struct promise_type;
158 private:
159 using Handle_t = std::coroutine_handle<promise_type>;
160 Handle_t Handle_;
161 public:
163 , Extensions<promise_type>...
164 {
165 void lock () const
166 {
167 if constexpr (requires { this->DoLock (); })
168 this->DoLock ();
169 }
170
171 void unlock () const
172 {
173 if constexpr (requires { this->DoUnlock (); })
174 this->DoUnlock ();
175 }
176
177 auto GetAddress () { return Handle_t::from_promise (*this).address (); }
178
180 {
181 return Task { Handle_t::from_promise (*this) };
182 }
183
184 std::suspend_never initial_suspend () const noexcept { return {}; }
185
186 auto final_suspend () noexcept
187 {
188 ([this]
189 {
190 static_cast<void> (this);
191 using Base = Extensions<promise_type>;
192 if constexpr (requires (Base t) { t.FinalSuspend (); })
193 Base::FinalSuspend ();
194 } (), ...);
196 }
197
199 {
200 this->Exception_ = std::current_exception ();
201 }
202
203 void IncRef ()
204 {
205 this->Refs_.fetch_add (1);
206 }
207
208 void DecRef ()
209 {
210 if (this->Refs_.fetch_sub (1) == 1)
211 Handle_t::from_promise (*this).destroy ();
212 }
213 };
214
215 using ResultType_t = R;
216
217 template<typename RR>
218 using ReplaceResult_t = Task<RR, Extensions...>;
219
220 template<template<typename> typename F>
221 using ApplyResult_t = Task<F<R>, Extensions...>;
222
223 explicit Task (const std::coroutine_handle<promise_type>& handle)
224 : Handle_ { handle }
225 {
226 if (handle)
227 handle.promise ().IncRef ();
228 }
229
230 ~Task () noexcept
231 {
232 if (Handle_)
233 Handle_.promise ().DecRef ();
234 }
235
236 Task (const Task& other)
237 : Handle_ { other.Handle_ }
238 {
239 if (Handle_)
240 Handle_.promise ().IncRef ();
241 }
242
243 Task& operator= (const Task& other)
244 {
245 Task task { other };
246 *this = std::move (task);
247 return *this;
248 }
249
250 Task (Task&& other) noexcept
251 {
252 std::swap (Handle_, other.Handle_);
253 }
254
255 Task& operator= (Task&& other) noexcept
256 {
257 std::swap (Handle_, other.Handle_);
258 return *this;
259 }
260
261 auto operator co_await () const noexcept
262 {
263 return detail::TaskAwaiter<promise_type> { Handle_ };
264 }
265 };
266
267 namespace detail
268 {
269 template<typename R, template<typename> typename... Extensions>
271 {
272 using Promise = typename Task<R, Extensions...>::promise_type;
273 Promise *Promise_ = nullptr;
274
275 bool await_ready () const noexcept { return false; }
276
277 bool await_suspend (std::coroutine_handle<Promise> handle) noexcept
278 {
279 Promise_ = &handle.promise ();
280 return false;
281 }
282
283 decltype (auto) await_resume () const noexcept
284 {
285 return *Promise_;
286 }
287 };
288 }
289}
Task & operator=(const Task &other)
Definition task.h:243
Task(Task &&other) noexcept
Definition task.h:250
~Task() noexcept
Definition task.h:230
Task< F< RR >, Extensions... > ApplyResult_t
Definition task.h:221
Task< RR, Extensions... > ReplaceResult_t
Definition task.h:218
Task(const Task &other)
Definition task.h:236
Task(const std::coroutine_handle< promise_type > &handle)
Definition task.h:223
std::suspend_never initial_suspend() const noexcept
Definition task.h:184
auto final_suspend() noexcept
Definition task.h:186
bool await_ready() const noexcept
Definition task.h:275
decltype(auto) await_resume() const noexcept
Definition task.h:283
bool await_suspend(std::coroutine_handle< Promise > handle) noexcept
Definition task.h:277
typename Task< R, Extensions... >::promise_type Promise
Definition task.h:272
std::exception_ptr Exception_
Definition task.h:26
std::atomic< size_t > Refs_
Definition task.h:24
std::atomic< std::coroutine_handle<> > Continuation_
Definition task.h:25
static constexpr bool IsVoid
Definition task.h:49
void return_void(this auto &&self) noexcept
Definition task.h:53
std::optional< R > Ret_
Definition task.h:36
static constexpr bool IsVoid
Definition task.h:34
void return_value(this auto &&self, U &&val)
Definition task.h:39
bool await_ready() const noexcept
Definition task.h:88
TaskAwaiter(Handle_t subtask)
Definition task.h:68
std::coroutine_handle< Promise > Handle_t
Definition task.h:65
TaskAwaiter & operator=(const TaskAwaiter &)=delete
TaskAwaiter(TaskAwaiter &&other) noexcept
Definition task.h:73
bool await_suspend(std::coroutine_handle<> handle)
Definition task.h:95
TaskAwaiter(const TaskAwaiter &)=delete