SW Task Event Loop Framework v1.0.0
High-performance C++ asynchronous event loop framework with timer management and promise-based programming
Loading...
Searching...
No Matches
Task.h
Go to the documentation of this file.
1
9 #pragma once
10
11 #include <coroutine>
12 #include <exception>
13 #include <memory>
14 #include <optional>
15 #include <vector>
16 #include <mutex>
17 #include <atomic>
18 #include <utility>
19
20 namespace swt {
21
22 // Forward declaration
23 template<typename T>
24 class Task;
25
44 template<typename T>
46 public:
47 using Handle = std::coroutine_handle<TaskPromise<T>>;
48
54
59 std::suspend_always initial_suspend() noexcept {
60 return {};
61 }
62
67 auto final_suspend() noexcept {
68 struct FinalAwaiter {
69 TaskPromise* promise;
70
71 bool await_ready() noexcept { return false; }
72
78 std::coroutine_handle<> await_suspend(std::coroutine_handle<TaskPromise<T>> h) noexcept {
79 std::lock_guard<std::mutex> lock(promise->mContinuationMutex);
80
81 // Resume all waiting continuations
82 for (auto& continuation : promise->mContinuations) {
83 continuation.resume();
84 }
85 promise->mContinuations.clear();
86
87 return std::noop_coroutine();
88 }
89
90 void await_resume() noexcept {}
91 };
92
93 return FinalAwaiter{this};
94 }
95
100 void return_value(T value) {
101 mResult = std::move(value);
102 mResultReady.store(true, std::memory_order_release);
103 }
104
109 mException = std::current_exception();
110 mResultReady.store(true, std::memory_order_release);
111 }
112
120 if (mException) {
121 std::rethrow_exception(mException);
122 }
123 if (mResult.has_value()) {
124 return mResult.value(); // Don't move, might be called multiple times
125 }
126 throw std::runtime_error("Task not completed");
127 }
128
133 bool isReady() const noexcept {
134 return mResultReady.load(std::memory_order_acquire);
135 }
136
144 void addContinuation(std::coroutine_handle<> continuation) {
145 std::lock_guard<std::mutex> lock(mContinuationMutex);
146
147 // If already completed, resume immediately
148 if (mResultReady.load(std::memory_order_acquire)) {
149 continuation.resume();
150 } else {
151 mContinuations.push_back(continuation);
152 }
153 }
154
155 private:
156 std::optional<T> mResult;
157 std::exception_ptr mException;
158 std::atomic<bool> mResultReady{false};
159
160 std::mutex mContinuationMutex;
161 std::vector<std::coroutine_handle<>> mContinuations;
162 };
163
171 template<>
172 class TaskPromise<void> {
173 public:
174 using Handle = std::coroutine_handle<TaskPromise<void>>;
175
181
186 std::suspend_always initial_suspend() noexcept {
187 return {};
188 }
189
194 auto final_suspend() noexcept {
195 struct FinalAwaiter {
196 TaskPromise* promise;
197
198 bool await_ready() noexcept { return false; }
199
200 std::coroutine_handle<> await_suspend(std::coroutine_handle<TaskPromise<void>> h) noexcept {
201 std::lock_guard<std::mutex> lock(promise->mContinuationMutex);
202
203 for (auto& continuation : promise->mContinuations) {
204 continuation.resume();
205 }
206 promise->mContinuations.clear();
207
208 return std::noop_coroutine();
209 }
210
211 void await_resume() noexcept {}
212 };
213
214 return FinalAwaiter{this};
215 }
216
220 void return_void() {
221 mResultReady.store(true, std::memory_order_release);
222 }
223
228 mException = std::current_exception();
229 mResultReady.store(true, std::memory_order_release);
230 }
231
236 void getResult() {
237 if (mException) {
238 std::rethrow_exception(mException);
239 }
240 }
241
246 bool isReady() const noexcept {
247 return mResultReady.load(std::memory_order_acquire);
248 }
249
254 void addContinuation(std::coroutine_handle<> continuation) {
255 std::lock_guard<std::mutex> lock(mContinuationMutex);
256
257 if (mResultReady.load(std::memory_order_acquire)) {
258 continuation.resume();
259 } else {
260 mContinuations.push_back(continuation);
261 }
262 }
263
264 private:
265 std::exception_ptr mException;
266 std::atomic<bool> mResultReady{false};
267 std::mutex mContinuationMutex;
268 std::vector<std::coroutine_handle<>> mContinuations;
269 };
270
302 template<typename T>
303 class Task {
304 public:
306 using Handle = typename promise_type::Handle;
307
312 explicit Task(Handle handle) : mHandle(handle) {}
313
318 if (mHandle) {
319 mHandle.destroy();
320 }
321 }
322
323 // Move-only semantics
324 Task(const Task&) = delete;
325 Task& operator=(const Task&) = delete;
326
331 Task(Task&& other) noexcept : mHandle(std::exchange(other.mHandle, {})) {}
332
338 Task& operator=(Task&& other) noexcept {
339 if (this != &other) {
340 if (mHandle) {
341 mHandle.destroy();
342 }
343 mHandle = std::exchange(other.mHandle, {});
344 }
345 return *this;
346 }
347
354 void start() {
355 if (mHandle && !mHandle.done()) {
356 mHandle.resume();
357 }
358 }
359
364 bool done() const noexcept {
365 return mHandle && mHandle.done();
366 }
367
376 auto getResult() -> T requires (!std::is_void_v<T>) {
377 if (!mHandle) {
378 throw std::runtime_error("Invalid task handle");
379 }
380
381 if (!mHandle.promise().isReady()) {
382 throw std::runtime_error("Task not completed - use co_await or check done() first");
383 }
384
385 return mHandle.promise().getResult();
386 }
387
393 void getResult() requires std::is_void_v<T> {
394 if (!mHandle) {
395 throw std::runtime_error("Invalid task handle");
396 }
397
398 if (!mHandle.promise().isReady()) {
399 throw std::runtime_error("Task not completed - use co_await or check done() first");
400 }
401
402 mHandle.promise().getResult();
403 }
404
409 bool await_ready() const noexcept {
410 return done();
411 }
412
420 void await_suspend(std::coroutine_handle<> waiter) noexcept {
421 if (!mHandle) {
422 // Invalid handle, resume immediately
423 waiter.resume();
424 return;
425 }
426
427 // Add waiter as continuation
428 mHandle.promise().addContinuation(waiter);
429
430 // Start this task if not already started
431 if (!mHandle.done()) {
432 mHandle.resume();
433 }
434 }
435
441 auto await_resume() -> T requires (!std::is_void_v<T>) {
442 return getResult();
443 }
444
449 void await_resume() requires std::is_void_v<T> {
450 getResult();
451 }
452
457 bool isReady() const noexcept {
458 return mHandle && mHandle.promise().isReady();
459 }
460
461 private:
462 Handle mHandle;
463 };
464
465 // Implementations for get_return_object
466 template<typename T>
468 return Task<T>{Handle::from_promise(*this)};
469 }
470
472 return Task<void>{Handle::from_promise(*this)};
473 }
474
475 } // namespace swt
std::suspend_always initial_suspend() noexcept
Initial suspend behavior - always suspend to allow manual start.
Definition Task.h:186
void unhandled_exception()
Handle unhandled exceptions in the coroutine.
Definition Task.h:227
bool isReady() const noexcept
Check if the task has completed.
Definition Task.h:246
void addContinuation(std::coroutine_handle<> continuation)
Add a continuation to be resumed when task completes.
Definition Task.h:254
void getResult()
Check for exceptions (void tasks have no return value)
Definition Task.h:236
auto final_suspend() noexcept
Final suspend behavior with continuation chaining.
Definition Task.h:194
std::coroutine_handle< TaskPromise< void > > Handle
Definition Task.h:174
void return_void()
Handle void return from coroutine.
Definition Task.h:220
Promise type for coroutine-based Task implementation.
Definition Task.h:45
auto final_suspend() noexcept
Final suspend behavior with continuation chaining.
Definition Task.h:67
T getResult()
Get the stored result value.
Definition Task.h:119
void unhandled_exception()
Handle unhandled exceptions in the coroutine.
Definition Task.h:108
void addContinuation(std::coroutine_handle<> continuation)
Add a continuation to be resumed when task completes.
Definition Task.h:144
bool isReady() const noexcept
Check if the task has completed.
Definition Task.h:133
std::suspend_always initial_suspend() noexcept
Initial suspend behavior - always suspend to allow manual start.
Definition Task.h:59
void return_value(T value)
Store the coroutine return value.
Definition Task.h:100
Task< T > get_return_object()
Create the Task object for this promise.
Definition Task.h:467
std::coroutine_handle< TaskPromise< T > > Handle
Definition Task.h:47
RAII wrapper for coroutines with proper continuation chaining.
Definition Task.h:303
Task(Task &&other) noexcept
Move constructor.
Definition Task.h:331
auto getResult() -> T
Get the result value (non-blocking)
Definition Task.h:376
Task(Handle handle)
Construct task with coroutine handle.
Definition Task.h:312
Task & operator=(const Task &)=delete
void await_resume()
Complete co_await for void tasks.
Definition Task.h:449
void getResult()
Get the result for void tasks (non-blocking)
Definition Task.h:393
~Task()
Destructor - automatically destroys coroutine handle.
Definition Task.h:317
Task(const Task &)=delete
bool await_ready() const noexcept
Check if task is ready (awaitable interface)
Definition Task.h:409
bool isReady() const noexcept
Check if task is ready without blocking.
Definition Task.h:457
bool done() const noexcept
Check if the task has completed.
Definition Task.h:364
typename promise_type::Handle Handle
Definition Task.h:306
Task & operator=(Task &&other) noexcept
Move assignment operator.
Definition Task.h:338
auto await_resume() -> T
Get result when co_await completes (non-void version)
Definition Task.h:441
void await_suspend(std::coroutine_handle<> waiter) noexcept
Suspend awaiting coroutine until this task completes.
Definition Task.h:420
void start()
Start the coroutine execution.
Definition Task.h:354
Software Timer namespace containing all timer-related classes.
Definition Awaitable.h:21