Skip to content

Commit

Permalink
Proof of principle of generator 'send' functionality
Browse files Browse the repository at this point in the history
- not production ready
- 'int' type currently hardcoded
- input_value is currently 'public'; not sure if that's desired
- copy_awaiter does not yet have support for 'send'

- credits for this approach go to 'Nicol Bolas'
https://stackoverflow.com/questions/64083104/making-python-generator-via-c20-coroutines
  • Loading branch information
Niek Bouman committed Nov 16, 2024
1 parent e201340 commit 9fef713
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 5 deletions.
24 changes: 19 additions & 5 deletions include/seastar/coroutine/generator.hh
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ protected:
// pointer to the denoted object in the promise as long as the result of
// dereferencing this pointer is convertible to the Ref type.
std::add_pointer_t<Yielded> _value = nullptr;

public:
int input_value;
protected:
std::exception_ptr _exception;
std::coroutine_handle<> _consumer;
Expand Down Expand Up @@ -107,11 +108,14 @@ protected:
class yield_awaiter final {
generator_promise_base* _promise;
std::coroutine_handle<> _consumer;
int& _ret;

public:
yield_awaiter(generator_promise_base* promise,
std::coroutine_handle<> consumer) noexcept
std::coroutine_handle<> consumer, int& ret) noexcept
: _promise{promise}
, _consumer{consumer}
, _ret{ret}
{}
bool await_ready() const noexcept {
return false;
Expand All @@ -127,7 +131,7 @@ protected:
}
return _consumer;
}
void await_resume() noexcept {}
int& await_resume() noexcept { return _ret; }
};

class copy_awaiter {
Expand Down Expand Up @@ -177,7 +181,7 @@ public:

yield_awaiter final_suspend() noexcept {
_value = nullptr;
return yield_awaiter{this, this->_consumer};
return yield_awaiter{this, this->_consumer, this->input_value};
}

void unhandled_exception() noexcept {
Expand All @@ -186,7 +190,7 @@ public:

yield_awaiter yield_value(Yielded value) noexcept {
this->_value = std::addressof(value);
return yield_awaiter{this, this->_consumer};
return yield_awaiter{this, this->_consumer, this->input_value};
}

copy_awaiter yield_value(const std::remove_reference_t<Yielded>& value)
Expand Down Expand Up @@ -418,6 +422,16 @@ public:
[[nodiscard]] std::default_sentinel_t end() const noexcept {
return {};
}

void send(value_type const& input)
{
_coro.promise().input_value = input;
}

void send(value_type&& input)
{
_coro.promise().input_value = std::move(input);
}
};

template <typename Ref, typename Value>
Expand Down
21 changes: 21 additions & 0 deletions tests/unit/generator_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -382,3 +382,24 @@ SEASTAR_TEST_CASE(test_batch_generator_convertible) {
BOOST_REQUIRE_EQUAL(*n, expected_n++);
}
}

coroutine::experimental::generator<int>
bidirectional_generator() {
int num = 0;
for (;;) {
num = co_yield num+1;
}
}

SEASTAR_TEST_CASE(test_generator_input) {

auto numbers = bidirectional_generator();
auto n = co_await numbers.begin();

std::cout << *n << ' '; // will print 1

numbers.send(42);
co_await ++n;

std::cout << *n << ' '; // will print 43
}

0 comments on commit 9fef713

Please sign in to comment.