LeechCraft 0.6.70-17335-ge406ffdcaf
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 <utility>
13#include <QVector>
14#include "finalsuspender.h"
15#include "taskfwd.h"
16
17namespace LC::Util
18{
19 namespace detail
20 {
21 template<typename R>
23 {
24 using ReturnType_t = R;
25
26 constexpr static bool IsVoid = false;
27
28 std::optional<R> Ret_;
29
30 template<typename U = R>
31 void return_value (U&& val)
32 {
33 Ret_.emplace (std::forward<U> (val));
34 }
35 };
36
37 template<>
38 struct PromiseRet<void>
39 {
40 constexpr static bool IsVoid = true;
41
42 bool Done_ = false;
43
44 void return_void () noexcept
45 {
46 Done_ = true;
47 }
48 };
49
50 struct EitherFailureAbort : std::exception {};
51
52 template<typename Promise>
54 {
55 using Handle_t = std::coroutine_handle<Promise>;
57
58 bool await_ready () const noexcept
59 {
60 const auto& promise = Handle_.promise ();
61 if (promise.Exception_)
62 return true;
63
64 if constexpr (Promise::IsVoid)
65 return promise.Done_;
66 else
67 return static_cast<bool> (promise.Ret_);
68 }
69
70 void await_suspend (std::coroutine_handle<> handle)
71 {
72 Handle_.promise ().WaitingHandles_.push_back (handle);
73 }
74
75 auto await_resume () const
76 {
77 const auto& promise = Handle_.promise ();
78 if (promise.Exception_)
79 try
80 {
81 std::rethrow_exception (promise.Exception_);
82 }
83 catch (EitherFailureAbort)
84 {
85 }
86
87 if constexpr (!Promise::IsVoid)
88 return *promise.Ret_;
89 }
90 };
91 }
92
93 template<typename R, template<typename> typename... Extensions>
94 class Task
95 {
96 public:
97 struct promise_type;
98 private:
99 using Handle_t = std::coroutine_handle<promise_type>;
100 Handle_t Handle_;
101 public:
103 , Extensions<promise_type>...
104 {
105 size_t Refs_ = 1; // TODO make thread-safe
106 QVector<std::coroutine_handle<>> WaitingHandles_ {};
107 std::exception_ptr Exception_ {};
108
109 auto GetAddress () { return Handle_t::from_promise (*this).address (); }
110
112 {
113 return Task { Handle_t::from_promise (*this) };
114 }
115
116 std::suspend_never initial_suspend () const noexcept { return {}; }
117
118 auto final_suspend () noexcept
119 {
120 ([this]
121 {
122 using Base = Extensions<promise_type>;
123 if constexpr (requires (Base t) { t.FinalSuspend (); })
124 Base::FinalSuspend ();
125 } (), ...);
127 }
128
130 {
131 Exception_ = std::current_exception ();
132 }
133
134 void IncRef ()
135 {
136 ++Refs_;
137 }
138
139 void DecRef ()
140 {
141 if (!--Refs_)
142 Handle_t::from_promise (*this).destroy ();
143 }
144 };
145
146 using ResultType_t = R;
147
148 template<typename RR>
149 using ReplaceResult_t = Task<RR, Extensions...>;
150
151 explicit Task (const std::coroutine_handle<promise_type>& handle)
152 : Handle_ { handle }
153 {
154 if (handle)
155 handle.promise ().IncRef ();
156 }
157
158 ~Task () noexcept
159 {
160 if (Handle_)
161 Handle_.promise ().DecRef ();
162 }
163
164 Task (const Task& other)
165 : Handle_ { other.Handle_ }
166 {
167 if (Handle_)
168 Handle_.promise ().IncRef ();
169 }
170
171 Task& operator= (const Task& other)
172 {
173 Task task { other };
174 *this = std::move (task);
175 return *this;
176 }
177
178 Task (Task&& other) noexcept
179 {
180 std::swap (Handle_, other.Handle_);
181 }
182
183 Task& operator= (Task&& other) noexcept
184 {
185 std::swap (Handle_, other.Handle_);
186 return *this;
187 }
188
189 auto operator co_await () const noexcept
190 {
191 return detail::TaskAwaiter<promise_type> { Handle_ };
192 }
193 };
194
195 namespace detail
196 {
197 template<typename R, template<typename> typename... Extensions>
199 {
200 using Promise = typename Task<R, Extensions...>::promise_type;
201 Promise *Promise_ = nullptr;
202
203 bool await_ready () const noexcept { return false; }
204
205 bool await_suspend (std::coroutine_handle<Promise> handle) const noexcept
206 {
207 Promise_ = &handle.promise ();
208 return false;
209 }
210
211 decltype (auto) await_resume () const noexcept
212 {
213 return *Promise_;
214 }
215 };
216 }
217}
Task & operator=(const Task &other)
Definition task.h:171
Task(Task &&other) noexcept
Definition task.h:178
~Task() noexcept
Definition task.h:158
Task< RR, Extensions... > ReplaceResult_t
Definition task.h:149
Task(const Task &other)
Definition task.h:164
Task(const std::coroutine_handle< promise_type > &handle)
Definition task.h:151
std::suspend_never initial_suspend() const noexcept
Definition task.h:116
auto final_suspend() noexcept
Definition task.h:118
QVector< std::coroutine_handle<> > WaitingHandles_
Definition task.h:106
std::exception_ptr Exception_
Definition task.h:107
bool await_ready() const noexcept
Definition task.h:203
decltype(auto) await_resume() const noexcept
Definition task.h:211
bool await_suspend(std::coroutine_handle< Promise > handle) const noexcept
Definition task.h:205
typename Task< R, Extensions... >::promise_type Promise
Definition task.h:200
static constexpr bool IsVoid
Definition task.h:40
std::optional< R > Ret_
Definition task.h:28
static constexpr bool IsVoid
Definition task.h:26
void return_value(U &&val)
Definition task.h:31
bool await_ready() const noexcept
Definition task.h:58
std::coroutine_handle< Promise > Handle_t
Definition task.h:55
void await_suspend(std::coroutine_handle<> handle)
Definition task.h:70
auto await_resume() const
Definition task.h:75