2#include <asyncpp/detail/concepts.h>
3#include <asyncpp/detail/promise_allocator_base.h>
11 template<
typename T, ByteAllocator Allocator = default_allocator_type>
12 class async_generator;
16 class async_generator_iterator;
18 class async_generator_yield_operation final {
20 explicit async_generator_yield_operation(coroutine_handle<> consumer) noexcept : m_consumer(consumer) {}
21 [[nodiscard]]
bool await_ready() const noexcept {
return false; }
22 [[nodiscard]] coroutine_handle<> await_suspend([[maybe_unused]] coroutine_handle<> producer)
noexcept {
25 void await_resume() noexcept {}
28 coroutine_handle<> m_consumer;
32 class async_generator_promise_base {
34 async_generator_promise_base() noexcept = default;
35 async_generator_promise_base(const async_generator_promise_base& other) = delete;
36 async_generator_promise_base& operator=(const async_generator_promise_base& other) = delete;
37 [[nodiscard]] suspend_always initial_suspend() const noexcept {
return {}; }
38 [[nodiscard]] async_generator_yield_operation final_suspend() noexcept {
40 return internal_yield_value();
42 void unhandled_exception() noexcept { m_exception = std::current_exception(); }
43 void return_void() noexcept {}
44 [[nodiscard]]
bool finished() const noexcept {
return m_value ==
nullptr; }
45 void rethrow_if_unhandled_exception() {
46 if (m_exception) { std::rethrow_exception(std::move(m_exception)); }
48 [[nodiscard]] T* value() const noexcept {
return m_value; }
51 [[nodiscard]] async_generator_yield_operation internal_yield_value() noexcept {
52 return async_generator_yield_operation{m_consumer};
56 friend class async_generator_yield_operation;
57 template<
typename U, ByteAllocator Allocator>
59 friend class async_generator_iterator<T>;
61 std::exception_ptr m_exception{
nullptr};
62 coroutine_handle<> m_consumer;
68 template<
typename T, ByteAllocator Allocator>
69 class async_generator_promise final :
public async_generator_promise_base<T>,
70 public promise_allocator_base<Allocator> {
71 using value_type = std::remove_reference_t<T>;
74 async_generator_promise() noexcept = default;
75 [[nodiscard]] coroutine_handle<async_generator_promise> get_return_object() noexcept {
76 return coroutine_handle<async_generator_promise>::from_promise(*
this);
78 [[nodiscard]] async_generator_yield_operation yield_value(value_type& value)
noexcept {
79 this->m_value = std::addressof(value);
80 return this->internal_yield_value();
82 [[nodiscard]] async_generator_yield_operation yield_value(value_type&& value)
noexcept {
83 return yield_value(value);
87 template<
typename T, ByteAllocator Allocator>
88 class async_generator_promise<T&&, Allocator> final :
public async_generator_promise_base<T>,
89 public promise_allocator_base<Allocator> {
91 async_generator_promise() noexcept = default;
92 [[nodiscard]] coroutine_handle<async_generator_promise> get_return_object() noexcept {
93 return coroutine_handle<async_generator_promise>::from_promise(*
this);
95 [[nodiscard]] async_generator_yield_operation yield_value(T&& value)
noexcept {
96 this->m_value = std::addressof(value);
97 return this->internal_yield_value();
102 class async_generator_iterator final {
104 using iterator_category = std::input_iterator_tag;
107 using difference_type = std::ptrdiff_t;
108 using value_type = std::remove_reference_t<T>;
109 using reference = std::add_lvalue_reference_t<T>;
110 using pointer = std::add_pointer_t<value_type>;
112 explicit async_generator_iterator(std::nullptr_t)
noexcept {}
113 [[nodiscard]]
auto operator++() noexcept {
114 class increment_op final {
116 explicit increment_op(async_generator_iterator<T>& iterator) noexcept : m_iterator(iterator) {}
117 [[nodiscard]]
bool await_ready() const noexcept {
return false; }
118 [[nodiscard]] coroutine_handle<> await_suspend(coroutine_handle<> consumer)
noexcept {
119 m_iterator.m_promise->m_consumer = consumer;
120 return m_iterator.m_coro;
122 async_generator_iterator<T>& await_resume() {
123 if (m_iterator.m_promise->finished()) {
125 auto promise = m_iterator.m_promise;
126 m_iterator = async_generator_iterator<T>{
nullptr};
127 promise->rethrow_if_unhandled_exception();
134 async_generator_iterator<T>& m_iterator;
136 return increment_op{*
this};
138 [[nodiscard]] reference operator*() const noexcept {
return *
static_cast<T*
>(m_promise->value()); }
139 [[nodiscard]]
bool operator==(
const async_generator_iterator& other)
const noexcept {
140 return m_promise == other.m_promise;
142 [[nodiscard]]
bool operator!=(
const async_generator_iterator& other)
const noexcept {
143 return !(*
this == other);
147 template<
typename U, ByteAllocator Allocator>
150 explicit async_generator_iterator(async_generator_promise_base<T>& promise,
151 coroutine_handle<> coro) noexcept
152 : m_promise(std::addressof(promise)), m_coro{coro} {}
154 async_generator_promise_base<T>* m_promise{};
155 coroutine_handle<> m_coro{};
163 template<
typename T, ByteAllocator Allocator>
166 using promise_type = detail::async_generator_promise<T, Allocator>;
167 using iterator = detail::async_generator_iterator<T>;
171 async_generator(coroutine_handle<promise_type> coro) noexcept : m_coroutine{coro} {}
173 other.m_coroutine =
nullptr;
176 if (m_coroutine) { m_coroutine.destroy(); }
186 [[nodiscard]]
auto begin()
noexcept {
187 class begin_operation final {
188 detail::async_generator_promise_base<T>* m_promise{};
189 coroutine_handle<> m_producer{};
192 explicit begin_operation(std::nullptr_t)
noexcept {}
193 explicit begin_operation(
194 coroutine_handle<detail::async_generator_promise<T, Allocator>> producer) noexcept
195 : m_promise(std::addressof(producer.promise())), m_producer(producer) {}
196 [[nodiscard]]
bool await_ready()
const noexcept {
return this->m_promise ==
nullptr; }
197 [[nodiscard]] coroutine_handle<> await_suspend(coroutine_handle<> consumer)
noexcept {
198 m_promise->m_consumer = consumer;
201 [[nodiscard]] detail::async_generator_iterator<T> await_resume() {
202 if (this->m_promise ==
nullptr)
return detail::async_generator_iterator<T>{
nullptr};
203 if (this->m_promise->finished()) {
205 this->m_promise->rethrow_if_unhandled_exception();
206 return detail::async_generator_iterator<T>{
nullptr};
209 return detail::async_generator_iterator<T>{*this->m_promise, this->m_producer};
212 if (!m_coroutine)
return begin_operation{
nullptr};
213 return begin_operation{m_coroutine};
215 [[nodiscard]] iterator end()
noexcept {
return iterator{
nullptr}; }
218 swap(m_coroutine, other.m_coroutine);
222 coroutine_handle<promise_type> m_coroutine;
225 template<
typename T, ByteAllocator Allocator>
Generator coroutine class supporting co_await.
Definition async_generator.h:164
Provides a consistent import interface for coroutine, experimental/coroutine or a best effort fallbac...