LeechCraft  0.6.70-18450-gabe19ee3b0
Modular cross-platform feature rich live environment.
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 
18 namespace LC::Util
19 {
20  namespace detail
21  {
22  struct PromiseBase
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>
63  struct TaskAwaiter
64  {
65  using Handle_t = std::coroutine_handle<Promise>;
67 
68  explicit TaskAwaiter (Handle_t subtask)
69  : Subtask_ { subtask }
70  {
71  }
72 
74  : Subtask_ { std::exchange (other.Subtask_, {}) }
75  {
76  }
77 
78  TaskAwaiter (const TaskAwaiter&) = delete;
79  TaskAwaiter& operator= (const TaskAwaiter&) = delete;
80  TaskAwaiter& operator= (TaskAwaiter&& other) = 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 
107  auto await_resume ()
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 
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  } (), ...);
195  return detail::FinalSuspender<promise_type> { *this };
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 
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 
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>
270  struct GetPromise
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 }
void return_value(this auto &&self, U &&val)
Definition: task.h:39
std::atomic< std::coroutine_handle<> > Continuation_
Definition: task.h:25
~Task() noexcept
Definition: task.h:230
decltype(auto) await_resume() const noexcept
Definition: task.h:283
void unlock() const
Definition: task.h:171
void swap(FDGuard &g1, FDGuard &g2)
Definition: fdguard.cpp:51
Task(const std::coroutine_handle< promise_type > &handle)
Definition: task.h:223
Task & operator=(const Task &other)
Definition: task.h:243
std::coroutine_handle< Promise > Handle_t
Definition: task.h:65
auto final_suspend() noexcept
Definition: task.h:186
std::optional< R > Ret_
Definition: task.h:36
bool await_suspend(std::coroutine_handle<> handle)
Definition: task.h:95
Task(const Task &other)
Definition: task.h:236
Task(Task &&other) noexcept
Definition: task.h:250
TaskAwaiter(Handle_t subtask)
Definition: task.h:68
TaskAwaiter & operator=(const TaskAwaiter &)=delete
bool await_suspend(std::coroutine_handle< Promise > handle) noexcept
Definition: task.h:277
requires(Tup1Size==Tup2Size) const expr auto ZipWith(Tup1 &&tup1
bool await_ready() const noexcept
Definition: task.h:88
TaskAwaiter(TaskAwaiter &&other) noexcept
Definition: task.h:73
R ResultType_t
Definition: task.h:215
static constexpr bool IsVoid
Definition: task.h:34
auto Tup2 &&tup2 noexcept
Definition: ctstringutils.h:68
bool await_ready() const noexcept
Definition: task.h:275
std::atomic< size_t > Refs_
Definition: task.h:24
std::exception_ptr Exception_
Definition: task.h:26
typename Task< R, Extensions... >::promise_type Promise
Definition: task.h:272
void return_void(this auto &&self) noexcept
Definition: task.h:53
std::suspend_never initial_suspend() const noexcept
Definition: task.h:184