LeechCraft 0.6.70-18808-g3467692359
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
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 std::coroutine_handle<> OuterTask_;
69
70 explicit TaskAwaiter (Handle_t subtask)
71 : Subtask_ { subtask }
72 {
73 if (Subtask_)
74 Subtask_.promise ().IncRef ();
75 }
76
77 TaskAwaiter (TaskAwaiter&& other) noexcept
78 : Subtask_ { std::exchange (other.Subtask_, {}) }
79 , OuterTask_ { std::exchange (other.OuterTask_, {}) }
80 {
81 }
82
83 TaskAwaiter (const TaskAwaiter&) = delete;
86
88 {
89 if (Subtask_ && OuterTask_)
90 {
91 auto& promise = Subtask_.promise ();
92 std::lock_guard guard { promise };
93 promise.RemoveAwaiter (OuterTask_);
94 }
95
96 if (Subtask_)
97 Subtask_.promise ().DecRef ();
98 }
99
100 bool await_ready () const noexcept
101 {
102 const auto& promise = Subtask_.promise ();
103 std::lock_guard guard { promise };
104 return CheckTaskFinishedUnlocked (promise);
105 }
106
107 bool await_suspend (std::coroutine_handle<> handle)
108 {
109 auto& promise = Subtask_.promise ();
110 std::lock_guard guard { promise };
111 if (CheckTaskFinishedUnlocked (promise))
112 return false;
113
114 OuterTask_ = handle;
115 promise.AddAwaiter (handle);
116 return true;
117 }
118
120 {
121 auto& promise = Subtask_.promise ();
122 std::lock_guard guard { promise };
123 if (promise.Exception_)
124 try
125 {
126 std::rethrow_exception (promise.Exception_);
127 }
128 catch (const EitherFailureAbort&)
129 {
130 }
131
132 if constexpr (!Promise::IsVoid)
133 return Promise::ResumeValue (*promise.Ret_);
134 }
135 private:
136 bool CheckTaskFinishedUnlocked (const Promise& promise) const
137 {
138 if (promise.Exception_)
139 return true;
140
141 if constexpr (Promise::IsVoid)
142 return promise.Done_;
143 else
144 return static_cast<bool> (promise.Ret_);
145 }
146 };
147 }
148
149 template<typename R, template<typename> typename... Extensions>
150 class Task
151 {
152 public:
153 struct promise_type;
154 private:
155 using Handle_t = std::coroutine_handle<promise_type>;
156 Handle_t Handle_;
157 public:
160 , Extensions<promise_type>...
161 , detail::DefaultAwaiterHandler<Extensions<promise_type>...>
162 , detail::DefaultLockingHandler<Extensions<promise_type>...>
163 , detail::DefaultResumeValueHandler<Extensions<promise_type>...>
164 {
165 auto GetAddress () { return Handle_t::from_promise (*this).address (); }
166
168 {
169 return Task { Handle_t::from_promise (*this) };
170 }
171
172 std::suspend_never initial_suspend () const noexcept { return {}; }
173
174 auto final_suspend () noexcept { return detail::FinalSuspender<promise_type> { *this }; }
175
177 {
178 this->Exception_ = std::current_exception ();
179 }
180
181 void IncRef ()
182 {
183 this->Refs_.fetch_add (1);
184 }
185
186 void DecRef ()
187 {
188 if (this->Refs_.fetch_sub (1) == 1)
189 Handle_t::from_promise (*this).destroy ();
190 }
191 };
192
193 using ResultType_t = R;
194
195 template<typename RR>
196 using ReplaceResult_t = Task<RR, Extensions...>;
197
198 template<template<typename> typename F>
199 using ApplyResult_t = Task<F<R>, Extensions...>;
200
201 explicit Task (const std::coroutine_handle<promise_type>& handle)
202 : Handle_ { handle }
203 {
204 if (handle)
205 handle.promise ().IncRef ();
206 }
207
208 ~Task () noexcept
209 {
210 if (Handle_)
211 Handle_.promise ().DecRef ();
212 }
213
214 Task (const Task& other)
215 : Handle_ { other.Handle_ }
216 {
217 if (Handle_)
218 Handle_.promise ().IncRef ();
219 }
220
221 Task& operator= (const Task& other)
222 {
223 Task task { other };
224 *this = std::move (task);
225 return *this;
226 }
227
228 Task (Task&& other) noexcept
229 {
230 std::swap (Handle_, other.Handle_);
231 }
232
233 Task& operator= (Task&& other) noexcept
234 {
235 std::swap (Handle_, other.Handle_);
236 return *this;
237 }
238
239 auto operator co_await () const noexcept
240 {
241 return detail::TaskAwaiter<promise_type> { Handle_ };
242 }
243 };
244
245 namespace detail
246 {
247 template<typename R, template<typename> typename... Extensions>
249 {
250 using Promise = typename Task<R, Extensions...>::promise_type;
251 Promise *Promise_ = nullptr;
252
253 bool await_ready () const noexcept { return false; }
254
255 bool await_suspend (std::coroutine_handle<Promise> handle) noexcept
256 {
257 Promise_ = &handle.promise ();
258 return false;
259 }
260
261 decltype (auto) await_resume () const noexcept
262 {
263 return *Promise_;
264 }
265 };
266 }
267}
Task & operator=(const Task &other)
Definition task.h:221
Task(Task &&other) noexcept
Definition task.h:228
~Task() noexcept
Definition task.h:208
Task< F< T >, SharedTaskExtension... > ApplyResult_t
Definition task.h:199
Task< RR, SharedTaskExtension... > ReplaceResult_t
Definition task.h:196
Task(const Task &other)
Definition task.h:214
Task(const std::coroutine_handle< promise_type > &handle)
Definition task.h:201
std::suspend_never initial_suspend() const noexcept
Definition task.h:172
auto final_suspend() noexcept
Definition task.h:174
bool await_ready() const noexcept
Definition task.h:253
decltype(auto) await_resume() const noexcept
Definition task.h:261
bool await_suspend(std::coroutine_handle< Promise > handle) noexcept
Definition task.h:255
typename Task< R, Extensions... >::promise_type Promise
Definition task.h:250
std::exception_ptr Exception_
Definition task.h:26
std::atomic< size_t > Refs_
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:100
TaskAwaiter(Handle_t subtask)
Definition task.h:70
std::coroutine_handle< Promise > Handle_t
Definition task.h:65
TaskAwaiter & operator=(const TaskAwaiter &)=delete
TaskAwaiter(TaskAwaiter &&other) noexcept
Definition task.h:77
bool await_suspend(std::coroutine_handle<> handle)
Definition task.h:107
TaskAwaiter(const TaskAwaiter &)=delete
std::coroutine_handle OuterTask_
Definition task.h:68