Container System 0.1.0
High-performance C++20 type-safe container framework with SIMD-accelerated serialization
Loading...
Searching...
No Matches
task.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
26#pragma once
27
28#include <coroutine>
29#include <exception>
30#include <optional>
31#include <utility>
32#include <type_traits>
33#include <variant>
34#include <atomic>
35
37{
41 template<typename T>
42 class task;
43
44 namespace detail
45 {
50 {
51 std::exception_ptr exception_;
52 std::coroutine_handle<> continuation_;
53 std::atomic<bool> completed_{false};
54
58 [[nodiscard]] std::suspend_never initial_suspend() noexcept
59 {
60 return {};
61 }
62
66 void unhandled_exception() noexcept
67 {
68 exception_ = std::current_exception();
69 }
70
75 {
76 [[nodiscard]] bool await_ready() const noexcept
77 {
78 return false;
79 }
80
81 template<typename Promise>
82 std::coroutine_handle<> await_suspend(
83 std::coroutine_handle<Promise> handle) noexcept
84 {
85 auto& promise = handle.promise();
86 // Read continuation BEFORE marking as complete to avoid
87 // data race with destructor. Once completed_ is true,
88 // the task owner may destroy the coroutine frame.
89 auto continuation = promise.continuation_;
90 // Mark as completed with release semantics to ensure
91 // all prior writes are visible to threads checking done()
92 promise.completed_.store(true, std::memory_order_release);
93 if (continuation)
94 {
95 return continuation;
96 }
97 return std::noop_coroutine();
98 }
99
100 void await_resume() noexcept {}
101 };
102
106 [[nodiscard]] final_awaiter final_suspend() noexcept
107 {
108 return {};
109 }
110 };
111
115 template<typename T>
117 {
118 std::optional<T> result_;
119
123 [[nodiscard]] task<T> get_return_object() noexcept;
124
128 template<typename U>
130 requires std::convertible_to<U, T>
131 {
132 result_.emplace(std::forward<U>(value));
133 }
134
138 [[nodiscard]] T& result() &
139 {
140 if (exception_)
141 {
142 std::rethrow_exception(exception_);
143 }
144 return *result_;
145 }
146
150 [[nodiscard]] T&& result() &&
151 {
152 if (exception_)
153 {
154 std::rethrow_exception(exception_);
155 }
156 return std::move(*result_);
157 }
158 };
159
163 template<>
165 {
169 [[nodiscard]] task<void> get_return_object() noexcept;
170
174 void return_void() noexcept {}
175
179 void result()
180 {
181 if (exception_)
182 {
183 std::rethrow_exception(exception_);
184 }
185 }
186 };
187
188 } // namespace detail
189
207 template<typename T>
208 class task
209 {
210 public:
212 using handle_type = std::coroutine_handle<promise_type>;
213
217 task() noexcept : handle_(nullptr) {}
218
222 explicit task(handle_type handle) noexcept : handle_(handle) {}
223
227 task(task&& other) noexcept : handle_(std::exchange(other.handle_, nullptr)) {}
228
232 task& operator=(task&& other) noexcept
233 {
234 if (this != &other)
235 {
236 if (handle_)
237 {
238 handle_.destroy();
239 }
240 handle_ = std::exchange(other.handle_, nullptr);
241 }
242 return *this;
243 }
244
249 {
250 if (handle_)
251 {
252 handle_.destroy();
253 }
254 }
255
256 // Non-copyable
257 task(const task&) = delete;
258 task& operator=(const task&) = delete;
259
263 [[nodiscard]] bool valid() const noexcept
264 {
265 return handle_ != nullptr;
266 }
267
271 [[nodiscard]] explicit operator bool() const noexcept
272 {
273 return valid();
274 }
275
283 [[nodiscard]] bool done() const noexcept
284 {
285 return handle_ && handle_.promise().completed_.load(std::memory_order_acquire);
286 }
287
293 [[nodiscard]] decltype(auto) get() &
294 {
295 return handle_.promise().result();
296 }
297
301 [[nodiscard]] decltype(auto) get() &&
302 {
303 return std::move(handle_.promise()).result();
304 }
305
309 struct awaiter
310 {
312
316 [[nodiscard]] bool await_ready() const noexcept
317 {
318 return handle_.done();
319 }
320
324 std::coroutine_handle<> await_suspend(
325 std::coroutine_handle<> awaiting) noexcept
326 {
327 handle_.promise().continuation_ = awaiting;
328 return handle_;
329 }
330
334 [[nodiscard]] decltype(auto) await_resume()
335 {
336 return handle_.promise().result();
337 }
338 };
339
343 [[nodiscard]] awaiter operator co_await() noexcept
344 {
345 return awaiter{handle_};
346 }
347
351 void resume() const
352 {
353 if (handle_ && !handle_.done())
354 {
355 handle_.resume();
356 }
357 }
358
359 private:
361 };
362
363 // Implementation of get_return_object for value type
364 template<typename T>
366 {
367 return task<T>{std::coroutine_handle<detail::promise_type<T>>::from_promise(*this)};
368 }
369
370 // Implementation of get_return_object for void type
372 {
373 return task<void>{std::coroutine_handle<detail::promise_type<void>>::from_promise(*this)};
374 }
375
383 template<typename T>
385 {
386 co_return std::forward<T>(value);
387 }
388
395 {
396 co_return;
397 }
398
406 template<typename T>
407 task<T> make_exceptional_task(std::exception_ptr ex)
408 {
409 std::rethrow_exception(ex);
410 // Unreachable, but needed for coroutine
411 co_return T{};
412 }
413
417 template<>
418 inline task<void> make_exceptional_task<void>(std::exception_ptr ex)
419 {
420 std::rethrow_exception(ex);
421 co_return;
422 }
423
424} // namespace kcenon::container::async
Forward declaration of task.
Definition task.h:209
task() noexcept
Default constructor - creates empty task.
Definition task.h:217
task & operator=(task &&other) noexcept
Move assignment operator.
Definition task.h:232
decltype(auto) get() &
Get the result (blocking, for testing)
Definition task.h:293
decltype(auto) get() &&
Get the result (rvalue, blocking, for testing)
Definition task.h:301
task(task &&other) noexcept
Move constructor.
Definition task.h:227
task & operator=(const task &)=delete
bool valid() const noexcept
Check if task is valid (has a coroutine)
Definition task.h:263
std::coroutine_handle< promise_type > handle_type
Definition task.h:212
bool done() const noexcept
Check if the coroutine is done.
Definition task.h:283
void resume() const
Resume the coroutine (for manual execution)
Definition task.h:351
task(handle_type handle) noexcept
Construct from coroutine handle.
Definition task.h:222
task(const task &)=delete
~task()
Destructor - destroys the coroutine if owned.
Definition task.h:248
Enhanced type-safe value with perfect legacy compatibility.
Definition value.h:129
task< T > make_exceptional_task(std::exception_ptr ex)
Create a task that throws an exception.
Definition task.h:407
task< void > make_ready_task()
Create a task that completes immediately with no value.
Definition task.h:394
task< void > make_exceptional_task< void >(std::exception_ptr ex)
Specialization for void.
Definition task.h:418
Final awaiter that resumes the continuation.
Definition task.h:75
std::coroutine_handle await_suspend(std::coroutine_handle< Promise > handle) noexcept
Definition task.h:82
Base promise type with common functionality.
Definition task.h:50
std::suspend_never initial_suspend() noexcept
Never suspend at start - start executing immediately.
Definition task.h:58
void unhandled_exception() noexcept
Handle unhandled exceptions.
Definition task.h:66
final_awaiter final_suspend() noexcept
Suspend at final point to allow result retrieval.
Definition task.h:106
void return_void() noexcept
Handle void return.
Definition task.h:174
Promise type for value-returning tasks.
Definition task.h:117
task< T > get_return_object() noexcept
Get return object (the task)
Definition task.h:365
void return_value(U &&value)
Store the return value.
Definition task.h:129
T & result() &
Get the stored result, rethrowing any exception.
Definition task.h:138
T && result() &&
Get the stored result (rvalue), rethrowing any exception.
Definition task.h:150
bool await_ready() const noexcept
Check if the coroutine is already done.
Definition task.h:316
decltype(auto) await_resume()
Get the result when resumed.
Definition task.h:334
std::coroutine_handle await_suspend(std::coroutine_handle<> awaiting) noexcept
Suspend and set continuation.
Definition task.h:324