Async++ unknown
Async (co_await/co_return) code for C++
Loading...
Searching...
No Matches
task.h
1#pragma once
2#include <asyncpp/detail/promise_allocator_base.h>
4#include <cassert>
5#include <exception>
6#include <variant>
7
8namespace asyncpp {
9 template<class T, ByteAllocator Allocator>
10 class task;
11
12 namespace detail {
13 template<class TVal, ByteAllocator Allocator, class TPromise>
14 class task_promise_base : public promise_allocator_base<Allocator> {
15 public:
16 task_promise_base() noexcept = default;
17 ~task_promise_base() = default;
18 task_promise_base(const task_promise_base&) = delete;
19 task_promise_base(task_promise_base&&) = delete;
20 task_promise_base& operator=(const task_promise_base&) = delete;
21 task_promise_base& operator=(task_promise_base&&) = delete;
22
23 coroutine_handle<TPromise> get_return_object() noexcept {
24 return coroutine_handle<TPromise>::from_promise(*static_cast<TPromise*>(this));
25 }
26
27 suspend_always initial_suspend() { return {}; }
28 auto final_suspend() noexcept {
29 struct awaiter {
30 constexpr bool await_ready() noexcept { return false; }
31 auto await_suspend(coroutine_handle<TPromise> hndl) noexcept {
32 assert(hndl);
33 assert(hndl.promise().m_continuation);
34 return hndl.promise().m_continuation;
35 }
36 constexpr void await_resume() noexcept {}
37 };
38 return awaiter{};
39 }
40
41 void unhandled_exception() noexcept {
42 m_value.template emplace<std::exception_ptr>(std::current_exception());
43 }
44
45 TVal rethrow_if_exception() {
46 if (std::holds_alternative<std::exception_ptr>(m_value))
47 std::rethrow_exception(std::get<std::exception_ptr>(m_value));
48 return std::get<TVal>(std::move(this->m_value));
49 }
50
51 coroutine_handle<> m_continuation{};
52 std::variant<std::monostate, TVal, std::exception_ptr> m_value{};
53 };
54
55 template<class T, ByteAllocator Allocator>
56 class task_promise : public task_promise_base<T, Allocator, task_promise<T, Allocator>> {
57 public:
58 template<class U>
59 void return_value(U&& value)
60 requires(std::is_convertible_v<U, T>)
61 {
62 this->m_value.template emplace<T>(std::forward<U>(value));
63 }
64 template<class U>
65 void return_value(U const& value)
66 requires(!std::is_reference_v<U>)
67 {
68 this->m_value.template emplace<T>(value);
69 }
70 T get() { return this->rethrow_if_exception(); }
71 };
72
73 struct returned {};
74 template<ByteAllocator Allocator>
75 class task_promise<void, Allocator>
76 : public task_promise_base<returned, Allocator, task_promise<void, Allocator>> {
77 public:
78 void return_void() { this->m_value.template emplace<returned>(); }
79 void get() { this->rethrow_if_exception(); }
80 };
81 } // namespace detail
82
87 template<class T = void, ByteAllocator Allocator = default_allocator_type>
88 class [[nodiscard]] task {
89 public:
91 using promise_type = detail::task_promise<T, Allocator>;
93 using handle_t = coroutine_handle<promise_type>;
94
96 //NOLINTNEXTLINE(google-explicit-constructor)
97 task(handle_t hndl) noexcept : m_coro(hndl) {
98 assert(this->m_coro);
99 assert(!this->m_coro.done());
100 }
101
103 explicit task(std::nullptr_t) noexcept : m_coro{} {}
104
106 task(task&& other) noexcept : m_coro{std::exchange(other.m_coro, {})} {}
108 task& operator=(task&& other) noexcept {
109 m_coro = std::exchange(other.m_coro, m_coro);
110 return *this;
111 }
112 task(const task&) = delete;
113 task& operator=(const task&) = delete;
114
117 if (m_coro) m_coro.destroy();
118 m_coro = nullptr;
119 }
120
122 explicit operator bool() const noexcept { return m_coro != nullptr; }
124 bool operator!() const noexcept { return m_coro == nullptr; }
125
127 auto operator co_await() noexcept {
128 struct awaiter {
129 constexpr explicit awaiter(handle_t coro) : m_coro(coro) {}
130 constexpr bool await_ready() noexcept { return false; }
131 auto await_suspend(coroutine_handle<void> hndl) noexcept {
132 assert(this->m_coro);
133 assert(hndl);
134 m_coro.promise().m_continuation = hndl;
135 return m_coro;
136 }
137 T await_resume() {
138 assert(this->m_coro);
139 return this->m_coro.promise().get();
140 }
141
142 private:
143 handle_t m_coro;
144 };
145 assert(this->m_coro);
146 return awaiter{m_coro};
147 }
148
149 private:
150 handle_t m_coro;
151 };
152} // namespace asyncpp
Generic task type.
Definition task.h:88
~task()
Destructor.
Definition task.h:116
task(std::nullptr_t) noexcept
Construct from nullptr. The resulting task is invalid.
Definition task.h:103
task(task &&other) noexcept
Move constructor.
Definition task.h:106
detail::task_promise< T, Allocator > promise_type
Promise type.
Definition task.h:91
coroutine_handle< promise_type > handle_t
Handle type.
Definition task.h:93
bool operator!() const noexcept
Check if the task does not hold a valid coroutine.
Definition task.h:124
task & operator=(task &&other) noexcept
Move assignment.
Definition task.h:108
task(handle_t hndl) noexcept
Construct from handle.
Definition task.h:97
Provides a consistent import interface for coroutine, experimental/coroutine or a best effort fallbac...