Refactor the API (possibly adding overhead) to fix a corner case
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 25/100
- Issue type
- Refactor
- Clarity
- Mostly clear
- Activity status
- Stale
- Tech stack
- cpp
- Domain
- backend-api-design
Research direction
Start with boost::coroutines2::coroutine's push_type and pull_type APIs, especially begin(), operator(), iterator operations, and the framework-generated counterpart described in the issue. Compare the current and imagined lifecycle tables, then define the empty-range and final-value behavior; the issue names no source files or tests, so locating those entry points is part of the work.
Written by the indexing model from the issue text.
Description
According to the documentation:
- push_type does not enter coroutine-function on construction;
- the first call of push_type::operator() synthesizes a complementary pull_type and passes it as reference to coroutine-function
But what happens if:
push_type coro([](pull_type&){ return; });- the user finds that
bool(coro) == true(or:begin(coro) != end(coro)) so the user would like to performcoro(value_of_T)(or:*begin(coro) = value_of_T)
It seems the value will be lost.
The problem is: you don't know whether an output range is empty unless you push a value to it first.
(Edit: sorry for the mistake, it's the last value that will always be lost if the output range is not infinite.)
#include<boost/coroutine2/all.hpp>
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<utility>
int main()
{
typedef boost::coroutines2::coroutine<std::string> coro_t;
struct FinalEOL {
~FinalEOL() {
std::cout << std::endl;
}
};
const int num = 5, width = 15;
coro_t::push_type writer(
[&](coro_t::pull_type& in) {
//// finish the last line when we leave by whatever means
//FinalEOL eol;
// pull values from upstream, lay them out 'num' to a line
//for (;;) {
// for (int i = 0; i < num; ++i) {
// // when we exhaust the input, stop
// if (!in) return;
// std::cout << std::setw(width) << in.get();
// // now that we've handled this item, advance to next
// in();
// }
// // after 'num' items, line break
// std::cout << std::endl;
//}
});
std::vector<std::string> words{
"peas", "porridge", "hot", "peas",
"porridge", "cold", "peas", "porridge",
"in", "the", "pot", "nine",
"days", "old" };
//std::copy(begin(words), end(words), begin(writer));
// safe version of std::copy that takes care of end(dest)
auto [words_it, writer_it] = std::pair{ begin(words),begin(writer) };
for (; words_it != end(words) && writer_it != end(writer); ++words_it, ++writer_it)
{
*writer_it = *words_it;
}
// print remaining words; the first word is lost
for (; words_it != end(words); ++words_it)
{
std::cout << *words_it << "\t";
}
}
An applicable approach would be to resume the coroutine in begin(coro) like https://github.com/lewissbaker/cppcoro#generatort .
Here is the current API and the imagined API:
current API:
| pull_type | framework-generated push_type for pull_type | push_type | framework-generated pull_type for push_type | |
|---|---|---|---|---|
| constructor | enter coroutine-function | |||
| operator() iterator::operator++() |
resume coroutine-function | suspend coroutine-function | ||
| get() | transfer data | transfer data | ||
| operator() iterator::operator=() |
transfer data, suspend coroutine-function | (first time: transfer data, enter coroutine-function) transfer data, resume coroutine-function |
imagined API:
| pull_type | framework-generated push_type for pull_type | push_type | framework-generated pull_type for push_type | |
|---|---|---|---|---|
| constructor | ||||
| start() begin(coro) |
①enter coroutine-function | ② | ⒈enter coroutine-function | ⒉suspend coroutine-function |
| advance() iterator::operator++() |
⑥⑩resume coroutine-function | ④⑧suspend coroutine-function | ⒋⒏resume coroutine-function | ⒍⒑suspend coroutine-function |
| get() | ⑤⑨transfer data | ⒌⒐transfer data | ||
| set() iterator::operator=() |
③⑦transfer data | ⒊⒎transfer data |
Note that in the column of push_type: if after ⒊transfer data instead of ⒋resume coroutine-function you ⒋abandon the coroutine, then the value_of_T will still be lost. But this time it is the user of API to blame, not the framework.
These are what you can do:
| utility | current API | imagined API |
|---|---|---|
merge pipe and source into sourcevoid(pull_type<T1>,push_type<T2>) + pull_type<T1> -> pull_type<T2> |
trivial for loop | trivial for loop |
merge pipe and source into sourceT2(T1) + pull_type<T1> -> pull_type<T2> |
trivial for loop | trivial for loop |
merge pipe and sink into sinkvoid(pull_type<T1>,push_type<T2>) + push_type<T2> -> push_type<T1> |
trivial for loop | trivial for loop |
merge pipe and sink into sinkT2(T1) + push_type<T2> -> push_type<T1> |
trivial for loop | trivial for loop |
merge source and sink and stops when either one exhaustsstd::pair<source_it_t, sink_it_t> safe_copy(source_begin, source_end, sink_begin, sink_end) |
the first value of source will be lost if sink is an empty range | trivial for loop the user will not lose the first value of source because if sink is an empty range then we have begin(sink) == end(sink) after construction and start()/begin(sink) |
- Dominant language
- C++
- Stars
- 139
- Forks
- 44
- PR merge metrics
- No merged PRs in 30d
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from boostorg/coroutine2
-
Difficulty 2/5 1-3 hours Newbie friendliness 50/100
boostorg/coroutine2#54 ·
-
Difficulty 4/5 3-5 days Newbie friendliness 25/100
boostorg/coroutine2#53 ·
-
Difficulty 4/5 3-5 days Newbie friendliness 20/100
boostorg/coroutine2#49 ·
All issues in boostorg/coroutine2
Similar issues
-
HasBacktrace Priority-Critical
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
azerothcore/azerothcore-wotlk#27921 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
yhirose/cpp-peglib#344 ·
-
bug-unconfirmed
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
shadps4-emu/shadps4-qtlauncher#453 ·
Maintainers usually reply within 2 days