|
28 | 28 | //
|
29 | 29 | // VERSION HISTORY
|
30 | 30 | //
|
31 |
| -// 1.00 (2024-07-xx) Initial release |
| 31 | +// 1.00 (2024-07-17) Initial release |
32 | 32 | //
|
33 | 33 | //
|
34 | 34 | // DOCUMENTATION
|
|
37 | 37 | // It defines the class generator which allows you to write simple coroutine-
|
38 | 38 | // based generators.
|
39 | 39 | //
|
40 |
| -// Example: |
| 40 | +// The library provides two interfaces for consuming the generated values. |
| 41 | +// |
| 42 | +// The first is a range-for iterator-like interface. Example: |
41 | 43 | //
|
42 | 44 | // itlib::generator<int> range(int begin, int end) {
|
43 | 45 | // for (int i = begin; i < end; ++i) {
|
|
49 | 51 | // std::cout << i << std::endl;
|
50 | 52 | // }
|
51 | 53 | //
|
| 54 | +// The range-for interface would copy the return values if they are not |
| 55 | +// references. Unfortunately this is required to make operator* work as if |
| 56 | +// it's a real iterator (safely called multiple times) |
| 57 | +// |
| 58 | +// In case you want to avoid the copies, prefer using the next() interface: |
| 59 | +// |
| 60 | +// auto r = range(0, 10); |
| 61 | +// while (true) { |
| 62 | +// auto v = r.next(); |
| 63 | +// if (!v) break; |
| 64 | +// // v is std::optional<int>, you can move the value out of it |
| 65 | +// std::cout << *v << std::endl; |
| 66 | +// } |
| 67 | +// |
| 68 | +// Both interfaces support reference generated values. |
| 69 | +// |
52 | 70 | // TESTS
|
53 | 71 | //
|
54 | 72 | // You can find unit tests in the official repo:
|
@@ -121,10 +139,27 @@ class generator {
|
121 | 139 |
|
122 | 140 | using handle_t = std::coroutine_handle<promise_type>;
|
123 | 141 |
|
| 142 | + generator(generator&& other) noexcept : m_handle(std::exchange(other.m_handle, nullptr)) {} |
| 143 | + |
| 144 | + generator& operator=(generator&& other) noexcept { |
| 145 | + if (m_handle) m_handle.destroy(); |
| 146 | + m_handle = std::exchange(other.m_handle, nullptr); |
| 147 | + return *this; |
| 148 | + } |
| 149 | + |
124 | 150 | ~generator() {
|
125 | 151 | if (m_handle) m_handle.destroy();
|
126 | 152 | }
|
127 | 153 |
|
| 154 | + void reset() noexcept { |
| 155 | + if (m_handle) m_handle.destroy(); |
| 156 | + m_handle = nullptr; |
| 157 | + } |
| 158 | + |
| 159 | + explicit operator bool() const noexcept { |
| 160 | + return !!m_handle; |
| 161 | + } |
| 162 | + |
128 | 163 | // next (optional-based) interface
|
129 | 164 |
|
130 | 165 | // NOTE: this won't return true until next() has returned an empty optional at least once
|
|
0 commit comments