5#ifndef CPPCORO_GENERATOR_HPP_INCLUDED
6#define CPPCORO_GENERATOR_HPP_INCLUDED
8#include "coroutine.hpp"
23 class generator_promise
27 using value_type = std::remove_reference_t<T>;
28 using reference_type = std::conditional_t<std::is_reference_v<T>, T, T&>;
29 using pointer_type = value_type*;
31 generator_promise() =
default;
33 generator<T> get_return_object() noexcept;
35 constexpr cppcoro::suspend_always initial_suspend() const noexcept {
return {}; }
36 constexpr cppcoro::suspend_always final_suspend() const noexcept {
return {}; }
40 std::enable_if_t<!std::is_rvalue_reference<U>::value,
int> = 0>
41 cppcoro::suspend_always yield_value(std::remove_reference_t<T>& value)
noexcept
43 m_value = std::addressof(value);
47 cppcoro::suspend_always yield_value(std::remove_reference_t<T>&& value)
noexcept
49 m_value = std::addressof(value);
53 void unhandled_exception()
55 m_exception = std::current_exception();
62 reference_type value() const noexcept
64 return static_cast<reference_type
>(*m_value);
69 cppcoro::suspend_never await_transform(U&& value) =
delete;
71 void rethrow_if_exception()
75 std::rethrow_exception(m_exception);
81 pointer_type m_value{};
82 std::exception_ptr m_exception{};
86 struct generator_sentinel {};
89 class generator_iterator
91 using coroutine_handle = cppcoro::coroutine_handle<generator_promise<T>>;
95 using iterator_category = std::input_iterator_tag;
97 using difference_type = std::ptrdiff_t;
98 using value_type =
typename generator_promise<T>::value_type;
99 using reference =
typename generator_promise<T>::reference_type;
100 using pointer =
typename generator_promise<T>::pointer_type;
103 generator_iterator() noexcept
104 : m_coroutine(
nullptr)
107 explicit generator_iterator(coroutine_handle coroutine) noexcept
108 : m_coroutine(coroutine)
111 friend bool operator==(
const generator_iterator& it, generator_sentinel)
noexcept
113 return !it.m_coroutine || it.m_coroutine.done();
116 friend bool operator!=(
const generator_iterator& it, generator_sentinel s)
noexcept
121 friend bool operator==(generator_sentinel s,
const generator_iterator& it)
noexcept
126 friend bool operator!=(generator_sentinel s,
const generator_iterator& it)
noexcept
131 generator_iterator& operator++()
133 m_coroutine.resume();
134 if (m_coroutine.done())
136 m_coroutine.promise().rethrow_if_exception();
148 reference operator*() const noexcept
150 return m_coroutine.promise().value();
153 pointer operator->() const noexcept
155 return std::addressof(
operator*());
160 coroutine_handle m_coroutine;
165 class [[nodiscard]] generator
169 using promise_type = detail::generator_promise<T>;
170 using iterator = detail::generator_iterator<T>;
173 : m_coroutine(
nullptr)
176 generator(generator&& other) noexcept
177 : m_coroutine(other.m_coroutine)
179 other.m_coroutine =
nullptr;
182 generator(
const generator& other) =
delete;
188 m_coroutine.destroy();
192 generator& operator=(generator other)
noexcept
202 m_coroutine.resume();
203 if (m_coroutine.done())
205 m_coroutine.promise().rethrow_if_exception();
212 detail::generator_sentinel
end() noexcept
214 return detail::generator_sentinel{};
217 void swap(generator& other)
noexcept
219 std::swap(m_coroutine, other.m_coroutine);
224 friend class detail::generator_promise<T>;
226 explicit generator(cppcoro::coroutine_handle<promise_type> coroutine) noexcept
227 : m_coroutine(coroutine)
230 cppcoro::coroutine_handle<promise_type> m_coroutine;
235 void swap(generator<T>& a, generator<T>& b)
243 generator<T> generator_promise<T>::get_return_object() noexcept
245 using coroutine_handle = cppcoro::coroutine_handle<generator_promise<T>>;
246 return generator<T>{ coroutine_handle::from_promise(*
this) };
250 template<
typename FUNC,
typename T>
251 generator<std::invoke_result_t<FUNC&, typename generator<T>::iterator::reference>> fmap(FUNC func, generator<T> source)
253 for (
auto&& value : source)
255 co_yield std::invoke(func,
static_cast<decltype(value)
>(value));
iterator_impl< false > iterator
Mutable block iterator type.
iterator end()
Get an iterator past the last block.
iterator begin()
Get an iterator to the first block.