LeviLamina
Loading...
Searching...
No Matches
Generator.h
1#pragma once
2
3#include <concepts>
4#include <coroutine>
5#include <cstddef>
6#include <exception>
7#include <iterator>
8#include <type_traits>
9
10namespace ll::coro {
11
12template <class T>
13struct Generator {
14 using value = std::remove_cvref_t<T>;
15 using reference = T&&;
16 using yielded = reference;
17
18
19 struct promise_type {
20 std::add_pointer_t<yielded> ptr;
21 std::exception_ptr exception;
22
23 Generator get_return_object() noexcept { return Generator{*this}; }
24
25 std::suspend_always initial_suspend() noexcept { return {}; }
26
27 std::suspend_always final_suspend() noexcept { return {}; }
28
29 void unhandled_exception() noexcept { exception = std::current_exception(); }
30
31 void rethrow() {
32 if (exception) {
33 std::rethrow_exception(exception);
34 }
35 }
36 std::suspend_always yield_value(yielded val) noexcept {
37 ptr = std::addressof(val);
38 return {};
39 }
40 auto yield_value(std::remove_reference_t<yielded> const& lval)
41 requires std::is_rvalue_reference_v<yielded>
42 && std::constructible_from<std::remove_cvref_t<yielded>, std::remove_reference_t<yielded> const&>
43 {
44 struct YieldCopied {
45 std::remove_cvref_t<yielded> storage;
46 constexpr YieldCopied(std::remove_reference_t<yielded> const& v) : storage(v) {}
47 constexpr bool await_ready() const noexcept { return false; }
48 constexpr void await_suspend(std::coroutine_handle<promise_type> h) noexcept {
49 h.promise().ptr = std::addressof(storage);
50 }
51 constexpr void await_resume() const noexcept {}
52 };
53 return YieldCopied{lval};
54 }
55 void return_void() noexcept {}
56
57 template <class U>
58 U&& await_transform(U&&) = delete;
59 };
60
61 struct iterator {
62 using iterator_category = std::input_iterator_tag;
63 using difference_type = ptrdiff_t;
64 using value_type = Generator::value;
65 using reference = Generator::reference;
66 using pointer = std::add_pointer_t<yielded>;
67
68 std::coroutine_handle<promise_type> handle = nullptr;
69
70 iterator() = default;
71 explicit iterator(std::coroutine_handle<promise_type> handle) noexcept : handle(handle) {}
72
73 iterator& operator++() {
74 handle.resume();
75 if (handle.done()) {
76 std::exchange(handle, nullptr).promise().rethrow();
77 }
78
79 return *this;
80 }
81
82 void operator++(int) { ++*this; }
83
84 [[nodiscard]] bool operator==(iterator const& other) const noexcept { return handle == other.handle; }
85
86 [[nodiscard]] reference operator*() const noexcept { return static_cast<reference>(*handle.promise().ptr); }
87
88 [[nodiscard]] pointer operator->() const noexcept { return handle.promise().ptr; }
89 };
90 [[nodiscard]] iterator begin() {
91 if (handle) {
92 handle.resume();
93 if (handle.done()) {
94 handle.promise().rethrow();
95 return {};
96 }
97 }
98 return iterator{handle};
99 }
100
101 [[nodiscard]] iterator end() noexcept { return {}; }
102
103 constexpr Generator(Generator&& other) noexcept : handle(std::exchange(other.handle, nullptr)) {}
104
105 constexpr ~Generator() {
106 if (handle) {
107 handle.destroy();
108 }
109 }
110 constexpr Generator() = default;
111
112 Generator& operator=(Generator&& other) noexcept {
113 std::swap(other.handle, handle);
114 return *this;
115 }
116
117private:
118 constexpr explicit Generator(promise_type& promise) noexcept
119 : handle(std::coroutine_handle<promise_type>::from_promise(promise)) {}
120
121 std::coroutine_handle<promise_type> handle = nullptr;
122};
123} // namespace ll::coro
Definition Generator.h:61
Definition Generator.h:19
Definition Generator.h:13