2#include <asyncpp/detail/promise_allocator_base.h>
8 template<
class T, ByteAllocator Allocator = default_allocator_type>
12 template<
class T, ByteAllocator Allocator>
13 class generator_promise :
public promise_allocator_base<Allocator> {
15 using value_type = std::remove_reference_t<T>;
16 using reference_type = std::conditional_t<std::is_reference_v<T>, T, T&>;
17 using pointer_type = std::add_pointer_t<value_type>;
19 generator_promise() noexcept = default;
20 ~generator_promise() = default;
21 generator_promise(const generator_promise&) = delete;
22 generator_promise(generator_promise&&) = delete;
24 coroutine_handle<generator_promise> get_return_object() noexcept {
25 return coroutine_handle<generator_promise>::from_promise(*
this);
27 suspend_always initial_suspend() noexcept {
return {}; }
28 suspend_always final_suspend() noexcept {
return {}; }
30 void return_void() noexcept {}
32 suspend_always yield_value(std::remove_reference_t<T>&& value)
noexcept {
33 m_value = std::addressof(value);
37 template<
class U = T,
typename = std::enable_if_t<!std::is_rvalue_reference_v<U>>>
38 suspend_always yield_value(std::remove_reference_t<T>& value)
noexcept {
39 m_value = std::addressof(value);
43 void unhandled_exception() noexcept { m_exception = std::current_exception(); }
45 pointer_type value() const noexcept {
return m_value; }
47 std::exception_ptr exception() const noexcept {
return m_exception; }
51 suspend_never await_transform(U&& value) =
delete;
55 std::exception_ptr m_exception{
nullptr};
58 struct generator_end {};
60 template<
class T, ByteAllocator Allocator>
61 class generator_iterator {
63 using promise_type = generator_promise<T, Allocator>;
64 using handle_t = coroutine_handle<promise_type>;
65 using iterator_category = std::input_iterator_tag;
66 using difference_type = std::ptrdiff_t;
67 using value_type =
typename promise_type::value_type;
68 using reference =
typename promise_type::reference_type;
69 using pointer =
typename promise_type::pointer_type;
71 constexpr generator_iterator() noexcept : m_coro{
nullptr} {}
72 explicit constexpr generator_iterator(handle_t hdl) noexcept : m_coro{hdl} {}
74 bool operator==(generator_end)
const noexcept {
return !m_coro || m_coro.done(); }
76 generator_iterator& operator++() {
79 auto except = m_coro.promise().exception();
80 if (except) std::rethrow_exception(except);
86 void operator++(
int) { ++(*this); }
88 reference operator*() const noexcept {
return static_cast<reference
>(*m_coro.promise().value()); }
90 pointer operator->() const noexcept {
return m_coro.promise().value(); }
96 template<
typename T, ByteAllocator Allocator>
97 inline bool operator!=(
const generator_iterator<T, Allocator>& iter, generator_end end)
noexcept {
98 return !(iter == end);
101 template<
typename T, ByteAllocator Allocator>
102 inline bool operator==(generator_end end,
const generator_iterator<T, Allocator>& iter)
noexcept {
106 template<
typename T, ByteAllocator Allocator>
107 inline bool operator!=(generator_end end,
const generator_iterator<T, Allocator>& iter)
noexcept {
115 template<
typename T, ByteAllocator Allocator>
121 using iterator = detail::generator_iterator<T, Allocator>;
123 generator() noexcept : m_coro{
nullptr} {}
125 generator(coroutine_handle<promise_type> coro) noexcept : m_coro{coro} {}
126 generator(generator&& other) noexcept : m_coro{std::exchange(other.m_coro, {})} {}
127 generator(
const generator&) =
delete;
128 generator& operator=(generator&& other)
noexcept {
129 m_coro = std::exchange(other.m_coro, m_coro);
132 generator& operator=(
const generator&) =
delete;
134 if (m_coro) m_coro.destroy();
136 [[nodiscard]] iterator begin() {
140 auto except = m_coro.promise().exception();
141 if (except) std::rethrow_exception(except);
144 return iterator{m_coro};
146 [[nodiscard]]
constexpr detail::generator_end end() const noexcept {
return {}; }
149 coroutine_handle<promise_type> m_coro;
158 template<
typename FUNC,
typename T>
159 generator<std::invoke_result_t<FUNC&, typename generator<T>::iterator::reference>> fmap(FUNC func,
160 generator<T> source) {
161 for (
auto&& value : source) {
162 co_yield std::invoke(func,
static_cast<decltype(value)
>(value));
Generator coroutine class.
Definition generator.h:116
detail::generator_promise< T, Allocator > promise_type
The promise type.
Definition generator.h:119
detail::generator_iterator< T, Allocator > iterator
The iterator type.
Definition generator.h:121
Provides a consistent import interface for coroutine, experimental/coroutine or a best effort fallbac...