Skip to content

Commit

Permalink
[generator] add boolean interface and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
iboB committed Jul 17, 2024
1 parent c924cfb commit 83b6672
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 6 deletions.
39 changes: 37 additions & 2 deletions include/itlib/generator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
//
// VERSION HISTORY
//
// 1.00 (2024-07-xx) Initial release
// 1.00 (2024-07-17) Initial release
//
//
// DOCUMENTATION
Expand All @@ -37,7 +37,9 @@
// It defines the class generator which allows you to write simple coroutine-
// based generators.
//
// Example:
// The library provides two interfaces for consuming the generated values.
//
// The first is a range-for iterator-like interface. Example:
//
// itlib::generator<int> range(int begin, int end) {
// for (int i = begin; i < end; ++i) {
Expand All @@ -49,6 +51,22 @@
// std::cout << i << std::endl;
// }
//
// The range-for interface would copy the return values if they are not
// references. Unfortunately this is required to make operator* work as if
// it's a real iterator (safely called multiple times)
//
// In case you want to avoid the copies, prefer using the next() interface:
//
// auto r = range(0, 10);
// while (true) {
// auto v = r.next();
// if (!v) break;
// // v is std::optional<int>, you can move the value out of it
// std::cout << *v << std::endl;
// }
//
// Both interfaces support reference generated values.
//
// TESTS
//
// You can find unit tests in the official repo:
Expand Down Expand Up @@ -121,10 +139,27 @@ class generator {

using handle_t = std::coroutine_handle<promise_type>;

generator(generator&& other) noexcept : m_handle(std::exchange(other.m_handle, nullptr)) {}

generator& operator=(generator&& other) noexcept {
if (m_handle) m_handle.destroy();
m_handle = std::exchange(other.m_handle, nullptr);
return *this;
}

~generator() {
if (m_handle) m_handle.destroy();
}

void reset() noexcept {
if (m_handle) m_handle.destroy();
m_handle = nullptr;
}

explicit operator bool() const noexcept {
return !!m_handle;
}

// next (optional-based) interface

// NOTE: this won't return true until next() has returned an empty optional at least once
Expand Down
12 changes: 8 additions & 4 deletions test/t-generator-20.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,14 @@ TEST_CASE("simple") {
);
CHECK(i == 102);

auto tr = range(101, 105);
CHECK_NOTHROW(tr.next());
CHECK_NOTHROW(tr.next());
CHECK_THROWS_WITH_AS(tr.next(), "test exception", std::runtime_error);
r = range(101, 105);
CHECK_NOTHROW(r.next());
CHECK_NOTHROW(r.next());
CHECK_THROWS_WITH_AS(r.next(), "test exception", std::runtime_error);

CHECK(!!r);
r.reset();
CHECK_FALSE(r);
}

template <typename T>
Expand Down

0 comments on commit 83b6672

Please sign in to comment.