C++ Essence Library 0.1.0
A Utility Library for Modern C++ Programming
Loading...
Searching...
No Matches
generator.hpp
1/*
2 * Copyright (c) 2024 The RefValue Project
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#pragma once
24
25#include <coroutine>
26#include <cstddef>
27#include <exception>
28#include <iterator>
29#include <memory>
30#include <new>
31#include <utility>
32
33namespace essence {
34 template <typename T>
35 class generator {
36 public:
37 struct promise_type {
38 const T* value{};
39 std::exception_ptr exception;
40
41 void* operator new(std::size_t size) {
42 return ::operator new(size);
43 }
44
45 void operator delete(void* ptr, std::size_t size) {
46#if __cpp_sized_deallocation >= 201309L
47 ::operator delete(ptr, size);
48#else
49 ::operator delete(ptr);
50#endif
51 }
52
53 generator get_return_object() noexcept {
54 return generator{*this};
55 }
56
57 [[nodiscard]] static std::suspend_always initial_suspend() noexcept {
58 return {};
59 }
60
61 [[nodiscard]] static std::suspend_always final_suspend() noexcept {
62 return {};
63 }
64
65 void unhandled_exception() noexcept {
66 exception = std::current_exception();
67 }
68
69 std::suspend_always yield_value(const T& from) noexcept {
70 value = std::addressof(from);
71
72 return {};
73 }
74
75 static void return_void() noexcept {}
76
77 void rethrow_if_exception() const {
78 if (exception) {
79 std::rethrow_exception(exception);
80 }
81 }
82 };
83
84 class iterator {
85 public:
86 using iterator_category = std::input_iterator_tag;
87 using difference_type = std::ptrdiff_t;
88 using value_type = T;
89 using reference = const T&;
90 using pointer = const T*;
91
92 iterator() = default;
93
94 explicit iterator(std::coroutine_handle<promise_type> handle) noexcept : handle_{handle} {}
95
96 iterator& operator++() {
97 handle_.resume();
98
99 if (handle_.done()) {
100 std::exchange(handle_, {}).promise().rethrow_if_exception();
101 }
102
103 return *this;
104 }
105
106 void operator++(int) {
107 static_cast<void>(operator++());
108 }
109
110 bool operator==(const iterator& right) const noexcept {
111 return handle_ == right.handle_;
112 }
113
114 bool operator!=(const iterator& right) const noexcept {
115 return !(*this == right);
116 }
117
118 reference operator*() const noexcept {
119 return *handle_.promise().value;
120 }
121
122 pointer operator->() const noexcept {
123 return handle_.promise()._Value;
124 }
125
126 private:
127 std::coroutine_handle<promise_type> handle_;
128 };
129
130 explicit generator(promise_type& promise) noexcept
131 : handle_{std::coroutine_handle<promise_type>::from_promise(promise)} {}
132
133 generator(generator&& other) noexcept : handle_{std::exchange(other.handle_, {})} {}
134
135 ~generator() {
136 if (handle_) {
137 handle_.destroy();
138 }
139 }
140
141 generator& operator=(generator&& right) noexcept {
142 handle_ = std::exchange(right.handle_, nullptr);
143
144 return *this;
145 }
146
147 iterator begin() const {
148 if (handle_) {
149 handle_.resume();
150
151 if (handle_.done()) {
152 handle_.promise().rethrow_if_exception();
153
154 return {};
155 }
156 }
157
158 return iterator{handle_};
159 }
160
161 static iterator end() noexcept {
162 return {};
163 }
164
165 private:
166 std::coroutine_handle<promise_type> handle_;
167 };
168} // namespace essence
Definition generator.hpp:84
Definition generator.hpp:35
Definition generator.hpp:37