LeechCraft 0.6.70-19214-g121e5318a7
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 "defaulthandlers.h"
17#include "taskfwd.h"
18
19namespace LC::Util
20{
21 namespace detail
22 {
24 {
25 std::atomic<size_t> Refs_ = 1;
26 std::exception_ptr Exception_ {};
27
28 enum class CoroState : std::uint8_t
29 {
31 Suspended,
33 };
35 };
36
37 template<typename R>
39 {
40 using ReturnType_t = R;
41
42 constexpr static bool IsVoid = false;
43
44 std::optional<R> Ret_;
45
46 template<typename U = R>
47 void return_value (this auto&& self, U&& val)
48 {
49 std::lock_guard guard { self };
50 self.Ret_.emplace (std::forward<U> (val));
51 }
52 };
53
54 template<>
55 struct PromiseRet<void> : PromiseBase
56 {
57 constexpr static bool IsVoid = true;
58
59 bool Done_ = false;
60
61 void return_void (this auto&& self) noexcept
62 {
63 std::lock_guard guard { self };
64 self.Done_ = true;
65 }
66 };
67
68 struct EitherFailureAbort final : std::exception {};
69
70 template<typename Promise>
72 {
73 using Handle_t = std::coroutine_handle<Promise>;
75
76 std::coroutine_handle<> OuterTask_;
77
78 explicit TaskAwaiter (Handle_t subtask)
79 : Subtask_ { subtask }
80 {
81 if (Subtask_)
82 Subtask_.promise ().IncRef ();
83 }
84
85 TaskAwaiter (TaskAwaiter&& other) noexcept
86 : Subtask_ { std::exchange (other.Subtask_, {}) }
87 , OuterTask_ { std::exchange (other.OuterTask_, {}) }
88 {
89 }
90
91 TaskAwaiter (const TaskAwaiter&) = delete;
94
96 {
97 if (Subtask_ && OuterTask_)
98 {
99 auto& promise = Subtask_.promise ();
100 std::lock_guard guard { promise };
101 promise.RemoveAwaiter (OuterTask_);
102 }
103
104 if (Subtask_)
105 Subtask_.promise ().DecRef ();
106 }
107
108 bool await_ready () const noexcept
109 {
110 const auto& promise = Subtask_.promise ();
111 std::lock_guard guard { promise };
112 return CheckTaskFinishedUnlocked (promise);
113 }
114
115 bool await_suspend (std::coroutine_handle<> handle)
116 {
117 auto& promise = Subtask_.promise ();
118 std::lock_guard guard { promise };
119 if (CheckTaskFinishedUnlocked (promise))
120 return false;
121
122 OuterTask_ = handle;
123 promise.AddAwaiter (handle);
124 return true;
125 }
126
128 {
129 auto& promise = Subtask_.promise ();
130 std::lock_guard guard { promise };
131 if (promise.Exception_)
132 try
133 {
134 std::rethrow_exception (promise.Exception_);
135 }
136 catch (const EitherFailureAbort&)
137 {
138 }
139
140 if constexpr (!Promise::IsVoid)
141 return Promise::ResumeValue (*promise.Ret_);
142 }
143 private:
144 bool CheckTaskFinishedUnlocked (const Promise& promise) const
145 {
146 if (promise.Exception_)
147 return true;
148
149 if constexpr (Promise::IsVoid)
150 return promise.Done_;
151 else
152 return static_cast<bool> (promise.Ret_);
153 }
154 };
155 }
156
157 template<typename R, template<typename> typename... Extensions>
158 class Task
159 {
160 public:
161 struct promise_type;
162 private:
163 using Handle_t = std::coroutine_handle<promise_type>;
164 Handle_t Handle_;
165 public:
168 , Extensions<promise_type>...
169 , detail::DefaultAwaiterHandler<Extensions<promise_type>...>
170 , detail::DefaultLockingHandler<Extensions<promise_type>...>
171 , detail::DefaultResumeValueHandler<Extensions<promise_type>...>
172 {
173 auto GetAddress () { return Handle_t::from_promise (*this).address (); }
174
176 {
177 return Task { Handle_t::from_promise (*this) };
178 }
179
180 std::suspend_never initial_suspend () const noexcept { return {}; }
181
182 auto final_suspend () noexcept
183 {
186 }
187
189 {
190 this->Exception_ = std::current_exception ();
191 }
192
193 void IncRef ()
194 {
195 this->Refs_.fetch_add (1);
196 }
197
198 void DecRef ()
199 {
200 if (this->Refs_.fetch_sub (1) == 1)
201 Handle_t::from_promise (*this).destroy ();
202 }
203 };
204
205 using ResultType_t = R;
206
207 template<typename RR>
208 using ReplaceResult_t = Task<RR, Extensions...>;
209
210 template<template<typename> typename F>
211 using ApplyResult_t = Task<F<R>, Extensions...>;
212
213 explicit Task (const std::coroutine_handle<promise_type>& handle)
214 : Handle_ { handle }
215 {
216 if (handle)
217 handle.promise ().IncRef ();
218 }
219
220 ~Task () noexcept
221 {
222 if (Handle_)
223 Handle_.promise ().DecRef ();
224 }
225
226 Task (const Task& other)
227 : Handle_ { other.Handle_ }
228 {
229 if (Handle_)
230 Handle_.promise ().IncRef ();
231 }
232
233 Task& operator= (const Task& other)
234 {
235 Task task { other };
236 *this = std::move (task);
237 return *this;
238 }
239
240 Task (Task&& other) noexcept
241 {
242 std::swap (Handle_, other.Handle_);
243 }
244
245 Task& operator= (Task&& other) noexcept
246 {
247 std::swap (Handle_, other.Handle_);
248 return *this;
249 }
250
251 auto operator co_await () const noexcept
252 {
253 return detail::TaskAwaiter<promise_type> { Handle_ };
254 }
255 };
256
257 namespace detail
258 {
259 template<typename R, template<typename> typename... Extensions>
261 {
262 using Promise = typename Task<R, Extensions...>::promise_type;
263 Promise *Promise_ = nullptr;
264
265 bool await_ready () const noexcept { return false; }
266
267 bool await_suspend (std::coroutine_handle<Promise> handle) noexcept
268 {
269 Promise_ = &handle.promise ();
270 return false;
271 }
272
273 decltype (auto) await_resume () const noexcept
274 {
275 return *Promise_;
276 }
277 };
278 }
279}
Task & operator=(const Task &other)
Definition task.h:233
Task(Task &&other) noexcept
Definition task.h:240
~Task() noexcept
Definition task.h:220
Task< F< T >, SharedTaskExtension... > ApplyResult_t
Definition task.h:211
Task< RR, SharedTaskExtension... > ReplaceResult_t
Definition task.h:208
Task(const Task &other)
Definition task.h:226
Task(const std::coroutine_handle< promise_type > &handle)
Definition task.h:213
std::suspend_never initial_suspend() const noexcept
Definition task.h:180
auto final_suspend() noexcept
Definition task.h:182
bool await_ready() const noexcept
Definition task.h:265
decltype(auto) await_resume() const noexcept
Definition task.h:273
bool await_suspend(std::coroutine_handle< Promise > handle) noexcept
Definition task.h:267
typename Task< R, Extensions... >::promise_type Promise
Definition task.h:262
std::exception_ptr Exception_
Definition task.h:26
std::atomic< size_t > Refs_
Definition task.h:25
static constexpr bool IsVoid
Definition task.h:57
void return_void(this auto &&self) noexcept
Definition task.h:61
std::optional< R > Ret_
Definition task.h:44
static constexpr bool IsVoid
Definition task.h:42
void return_value(this auto &&self, U &&val)
Definition task.h:47
bool await_ready() const noexcept
Definition task.h:108
TaskAwaiter(Handle_t subtask)
Definition task.h:78
std::coroutine_handle< Promise > Handle_t
Definition task.h:73
TaskAwaiter & operator=(const TaskAwaiter &)=delete
TaskAwaiter(TaskAwaiter &&other) noexcept
Definition task.h:85
bool await_suspend(std::coroutine_handle<> handle)
Definition task.h:115
TaskAwaiter(const TaskAwaiter &)=delete
std::coroutine_handle OuterTask_
Definition task.h:76