Skip to content

Commit 83b6672

Browse files
committed
[generator] add boolean interface and tests
1 parent c924cfb commit 83b6672

File tree

2 files changed

+45
-6
lines changed

2 files changed

+45
-6
lines changed

include/itlib/generator.hpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
//
2929
// VERSION HISTORY
3030
//
31-
// 1.00 (2024-07-xx) Initial release
31+
// 1.00 (2024-07-17) Initial release
3232
//
3333
//
3434
// DOCUMENTATION
@@ -37,7 +37,9 @@
3737
// It defines the class generator which allows you to write simple coroutine-
3838
// based generators.
3939
//
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:
4143
//
4244
// itlib::generator<int> range(int begin, int end) {
4345
// for (int i = begin; i < end; ++i) {
@@ -49,6 +51,22 @@
4951
// std::cout << i << std::endl;
5052
// }
5153
//
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+
//
5270
// TESTS
5371
//
5472
// You can find unit tests in the official repo:
@@ -121,10 +139,27 @@ class generator {
121139

122140
using handle_t = std::coroutine_handle<promise_type>;
123141

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+
124150
~generator() {
125151
if (m_handle) m_handle.destroy();
126152
}
127153

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+
128163
// next (optional-based) interface
129164

130165
// NOTE: this won't return true until next() has returned an empty optional at least once

test/t-generator-20.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,14 @@ TEST_CASE("simple") {
5252
);
5353
CHECK(i == 102);
5454

55-
auto tr = range(101, 105);
56-
CHECK_NOTHROW(tr.next());
57-
CHECK_NOTHROW(tr.next());
58-
CHECK_THROWS_WITH_AS(tr.next(), "test exception", std::runtime_error);
55+
r = range(101, 105);
56+
CHECK_NOTHROW(r.next());
57+
CHECK_NOTHROW(r.next());
58+
CHECK_THROWS_WITH_AS(r.next(), "test exception", std::runtime_error);
59+
60+
CHECK(!!r);
61+
r.reset();
62+
CHECK_FALSE(r);
5963
}
6064

6165
template <typename T>

0 commit comments

Comments
 (0)