directly iterable generators

master
Daniel Kolesa 2017-03-11 14:16:32 +01:00
parent 058efff580
commit 9c9221822a
3 changed files with 46 additions and 9 deletions

View File

@ -4,14 +4,14 @@
using namespace ostd; using namespace ostd;
int main() { int main() {
generator<int> g = [](auto yield) { auto f = [](auto yield) {
for (int i: range(5, 26, 5)) { for (int i: range(5, 26, 5)) {
yield(i); yield(i);
} }
}; };
writeln("generator test"); writeln("generator test");
for (int i: g.iter()) { for (int i: generator<int>{f}) {
writefln("generated: %s", i); writefln("generated: %s", i);
} }
} }

View File

@ -427,6 +427,10 @@ inline void swap(coroutine<R(A...)> &a, coroutine<R(A...)> &b) {
template<typename T> struct generator_range; template<typename T> struct generator_range;
namespace detail {
template<typename T> struct generator_iterator;
}
template<typename T> template<typename T>
struct generator: detail::coroutine_context { struct generator: detail::coroutine_context {
private: private:
@ -518,6 +522,10 @@ public:
generator_range<T> iter(); generator_range<T> iter();
/* for range for loop; they're the same, operator!= bypasses comparing */
detail::generator_iterator<T> begin();
detail::generator_iterator<T> end();
void swap(generator &other) { void swap(generator &other) {
using std::swap; using std::swap;
swap(p_func, other.p_func); swap(p_func, other.p_func);
@ -565,11 +573,10 @@ struct generator_range: input_range<generator_range<T>> {
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 = ptrdiff_t;
generator_range() = delete; generator_range() = delete;
generator_range(generator<T> &g): p_gen(&g) {} generator_range(generator<T> &g): p_gen(&g) {}
generator_range(generator_range const &r): p_gen(r.p_gen) {}
bool empty() const { bool empty() const {
return p_gen->empty(); return p_gen->empty();
@ -595,6 +602,41 @@ generator_range<T> generator<T>::iter() {
return generator_range<T>{*this}; return generator_range<T>{*this};
} }
namespace detail {
/* deliberately incomplete, only for range for loop */
template<typename T>
struct generator_iterator {
generator_iterator() = delete;
generator_iterator(generator<T> &g): p_gen(&g) {}
bool operator!=(generator_iterator const &) {
return !p_gen->empty();
}
T &operator*() const {
return p_gen->value();
}
generator_iterator &operator++() {
p_gen->resume();
return *this;
}
private:
generator<T> *p_gen;
};
} /* namespace detail */
template<typename T>
detail::generator_iterator<T> generator<T>::begin() {
return detail::generator_iterator<T>{*this};
}
template<typename T>
detail::generator_iterator<T> generator<T>::end() {
return detail::generator_iterator<T>{*this};
}
} /* namespace ostd */ } /* namespace ostd */
#endif #endif

View File

@ -268,11 +268,6 @@ namespace detail {
return get_ref().front(); return get_ref().front();
} }
bool operator!=(range_iterator) const { return !get_ref().empty(); } bool operator!=(range_iterator) const { return !get_ref().empty(); }
void swap(range_iterator &v) {
using std::swap;
swap(get_ref(). v.get_ref());
swap(p_init, v.p_init);
}
private: private:
T &get_ref() { return *reinterpret_cast<T *>(&p_range); } T &get_ref() { return *reinterpret_cast<T *>(&p_range); }
T const &get_ref() const { return *reinterpret_cast<T const *>(&p_range); } T const &get_ref() const { return *reinterpret_cast<T const *>(&p_range); }