Skip to content

Commit

Permalink
[generator] improve iterator interface when yielding non-copyable
Browse files Browse the repository at this point in the history
  • Loading branch information
iboB committed Sep 24, 2024
1 parent d850cd0 commit 998ae90
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 3 deletions.
10 changes: 7 additions & 3 deletions include/itlib/generator.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// itlib-generator v1.02
// itlib-generator v1.03
//
// Simple coroutine generator class for C++20 and later
//
Expand Down Expand Up @@ -28,6 +28,8 @@
//
// VERSION HISTORY
//
// 1.03 (2024-09-24) Improve iterator-like interface when yielding
// non-copyable values
// 1.02 (2024-07-18) Store exception to work around clang's ridiculous
// and overly complicated handling of coroutines
// 1.01 (2024-07-18) Add missing header for newer, more stringent compilers
Expand Down Expand Up @@ -105,8 +107,8 @@ class generator_value <T&> {
template <typename T>
class generator {
public:
// return const ref in case we're generating values, otherwise keep the ref type
using value_ret_t = std::conditional_t<std::is_reference_v<T>, T, const T&>;
// return ref in case we're generating values, otherwise keep the ref type
using value_ret_t = std::conditional_t<std::is_reference_v<T>, T, T&>;

struct promise_type {
generator_value<T> m_val;
Expand Down Expand Up @@ -190,6 +192,8 @@ class generator {
using value_type = std::decay_t<T>;
using reference = value_ret_t;

using difference_type = std::ptrdiff_t; // pointless here, but required for iterator traits and concepts

pseudo_iterator() noexcept = default;
explicit pseudo_iterator(handle_t handle) noexcept : m_handle(handle) {}

Expand Down
28 changes: 28 additions & 0 deletions test/t-generator-20.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
#include <doctest/util/lifetime_counter.hpp>

#include <stdexcept>
#include <iterator>
#include <vector>
#include <string>
#include <span>

itlib::generator<int> range(int begin, int end) {
Expand Down Expand Up @@ -145,3 +147,29 @@ TEST_CASE("lifetime") {
CHECK(ls.m_ctr == 6);
}
}

struct non_copyable {
non_copyable(std::string v) : value(std::move(v)) {}
non_copyable(const non_copyable&) = delete;
non_copyable& operator=(const non_copyable&) = delete;
non_copyable(non_copyable&&) noexcept = default;
non_copyable& operator=(non_copyable&&) noexcept = default;
std::string value;
};

itlib::generator<non_copyable> non_copyable_range(int begin, int end) {
for (int i = begin; i < end; ++i) {
co_yield non_copyable(std::to_string(i));
}
}

TEST_CASE("yield non copyable") {
auto gen = non_copyable_range(10, 15);
std::vector<std::string> values;
int i = 10;
for (auto mi = std::make_move_iterator(gen.begin()); mi.base() != gen.end(); ++mi) {
auto elem = *mi;
CHECK(elem.value == std::to_string(i));
++i;
}
}

0 comments on commit 998ae90

Please sign in to comment.