Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generator<T> coroutine type #5

Closed
lewissbaker opened this issue Apr 16, 2017 · 4 comments
Closed

Add generator<T> coroutine type #5

lewissbaker opened this issue Apr 16, 2017 · 4 comments
Assignees

Comments

@lewissbaker
Copy link
Owner

Add a new type cppcoro::generator<T> that allows you to write a coroutine that yields a sequence of values procedurally from within the coroutine using the co_yield keyword.

eg.

cppcoro::generator<int> range(int n)
{
  for (int i = 0; i < n; ++i) co_yield i;
}

// Outputs: 0 1 2 3 4 5 6 7 8 9
void usage()
{
  for (auto i : range(10))
  {
    std::cout << i << " ";
  }
}
@lewissbaker
Copy link
Owner Author

Some questions for me as to the design:

  • Should generator<T> yield a sequence of T& or const T& or should it return T by value?
  • Should we allow generator<T&>?
    How would this differ from generator<T> above if it yields a sequence of T&?
  • Should we allow generator<T&&>?
    ie. co_yield'ed value must be an r-value reference and iterator dereference is rvalue reference
  • Should we allow co_yield T{} even if generator is yielding a sequence of T& lvalue references?
    Current C++ rules don't allow temporaries to bind to lvalue reference parameters.

There may be a performance advantage in storing a copy of the value in the generator's promise rather than a pointer to the value passed to co_yield, at least for fundamental types and possibly some other simple user-defined types. The elimination of an extra indirection when the consumer dereferences the iterator could be significant in some tight loops.

Need to evaluate the performance impact of this approach on Clang which has more advanced coroutine optimisation than MSVC at the moment.

@lewissbaker
Copy link
Owner Author

Also need to consider custom allocators for the coroutine frame.

I'm not a huge fan of making the allocator template parameter of the generator type (ie. generator<T, ALLOC>) as I feel that this decision should be made by the caller (eg. via parameters) rather than the implementer of the coroutine.

This would also allow callers to pass stateful allocators rather than being limited to stateless allocators.
This may be particularly applicable to recursive_generator class as such functions tend to be recursive and thus not applicable for allocation-elision. So an allocator that allocated space for batches of coroutine frames to allow for efficient allocation/deallocation of recursive coroutine frames could be a good performance improvement.

eg. Something like

template<typename ALLOCATOR>
cppcoro::generator<foo> some_func(std::allocator_arg_t,  ALLOCATOR& alloc, P1 arg1, P2 arg2);

@lewissbaker lewissbaker self-assigned this Jun 4, 2017
@lewissbaker
Copy link
Owner Author

Commit 40c6216 adds initial generator<T> implementation.

Still need to update README with some documentation.

@lewissbaker
Copy link
Owner Author

README has now been updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant