-
Notifications
You must be signed in to change notification settings - Fork 0
/
generator.hpp
66 lines (53 loc) · 1.85 KB
/
generator.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// Andrew Naplavkov
#ifndef STEP20_GENERATOR_HPP
#define STEP20_GENERATOR_HPP
#include <coroutine>
#include <iterator>
#include <memory>
#include <optional>
namespace step20 {
inline auto co_destroy = [](void* address) {
std::coroutine_handle<>::from_address(address).destroy();
};
/// @see https://en.cppreference.com/w/cpp/header/generator
template <std::movable T>
struct generator : private std::unique_ptr<void, decltype(co_destroy)> {
struct promise_type : std::optional<T> {
std::suspend_never initial_suspend() { return {}; }
void await_transform() = delete;
void return_void() {}
void unhandled_exception() { throw; }
std::suspend_always final_suspend() noexcept { return {}; }
std::suspend_always yield_value(T value)
{
this->emplace(std::move(value));
return {};
}
generator get_return_object()
{
auto result = generator{};
result.reset(handle::from_promise(*this).address());
return result;
}
};
using handle = std::coroutine_handle<promise_type>;
struct iterator : private handle {
using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using reference = const T&;
explicit iterator(handle coro) : handle{coro} {}
reference operator*() const { return *this->promise(); }
bool operator==(std::default_sentinel_t) const { return this->done(); }
void operator++(int) { this->resume(); }
iterator& operator++()
{
this->resume();
return *this;
}
};
auto begin() const { return iterator{handle::from_address(get())}; }
auto end() const { return std::default_sentinel; }
};
} // namespace step20
#endif // STEP20_GENERATOR_HPP