make value-returning no-argument coroutines iterable

This commit is contained in:
q66 2017-03-06 19:01:17 +01:00
parent 64d92743e4
commit 7ba1f9265b
2 changed files with 25 additions and 15 deletions

View file

@ -4,7 +4,7 @@
using namespace ostd; using namespace ostd;
int main() { int main() {
generator<int> g = [](auto yield) { coroutine<int()> g = [](auto yield) {
yield(5); yield(5);
yield(10); yield(10);
yield(15); yield(15);
@ -13,8 +13,8 @@ int main() {
}; };
writeln("generator test"); writeln("generator test");
for (int i: g) { for (int i: g.iter()) {
writeln("generated: ", i); writefln("generated: %s", i);
} }
} }

View file

@ -181,6 +181,9 @@ inline void swap(coroutine_context &a, coroutine_context &b) {
template<typename T> template<typename T>
struct coroutine; struct coroutine;
template<typename T>
struct coroutine_range;
namespace detail { namespace detail {
/* like reference_wrapper but for any value */ /* like reference_wrapper but for any value */
template<typename T> template<typename T>
@ -345,6 +348,8 @@ namespace detail {
/* yield takes a value but doesn't return any args */ /* yield takes a value but doesn't return any args */
template<typename R> template<typename R>
struct coro_base<R> { struct coro_base<R> {
coroutine_range<R> iter();
protected: protected:
coro_base(void (*callp)(void *), size_t ss): coro_base(void (*callp)(void *), size_t ss):
p_ctx(ss, callp, this) p_ctx(ss, callp, this)
@ -554,29 +559,27 @@ inline void swap(coroutine<R(A...)> &a, coroutine<R(A...)> &b) {
} }
template<typename T> template<typename T>
struct generator: input_range<generator<T>> { struct coroutine_range: input_range<coroutine_range<T>> {
using range_category = input_range_tag; using range_category = input_range_tag;
using value_type = T; using value_type = T;
using reference = T &; using reference = T &;
using size_type = size_t; using size_type = size_t;
using difference_type = stream_off_t; using difference_type = stream_off_t;
generator() = default; coroutine_range() = delete;
coroutine_range(coroutine<T()> &c): p_coro(&c) {
template<typename F>
generator(F &&func, size_t ss = COROUTINE_DEFAULT_STACK_SIZE):
p_ptr(new coroutine<T()>{std::forward<F>(func), ss})
{
pop_front(); pop_front();
} }
coroutine_range(coroutine_range const &r):
p_coro(r.p_coro), p_item(r.p_item) {}
bool empty() const { bool empty() const {
return !p_item; return !p_item;
} }
void pop_front() { void pop_front() {
if (*p_ptr) { if (*p_coro) {
p_item = (*p_ptr)(); p_item = (*p_coro)();
} else { } else {
p_item = std::nullopt; p_item = std::nullopt;
} }
@ -586,14 +589,21 @@ struct generator: input_range<generator<T>> {
return p_item.value(); return p_item.value();
} }
bool equals_front(generator const &g) { bool equals_front(coroutine_range const &g) {
return p_ptr == g.p_ptr; return p_coro == g.p_coro;
} }
private: private:
std::shared_ptr<coroutine<T()>> p_ptr; coroutine<T()> *p_coro;
mutable std::optional<T> p_item; mutable std::optional<T> p_item;
}; };
namespace detail {
template<typename R>
coroutine_range<R> coro_base<R>::iter() {
return coroutine_range<R>{static_cast<coroutine<R()> &>(*this)};
}
}
} /* namespace ostd */ } /* namespace ostd */
#endif #endif