Commit Graph

4 Commits

Author SHA1 Message Date
Lauri Vasama 086dc9fbc9 Remove RecursiveCoroutine operator*
* Add rc_eval to force evaluation.
2025-10-31 17:23:52 +01:00
Pietro Fezzardi b58693b8e8 RecursiveCoroutine: enable direct continuation
Before this commit, the execution logic of RecursiveCoroutine used an
underlying std::stack allocated on the heap to hold all the
coroutine_handles. It also manually managed passing return values from
callees to callers.

This commit drops this unnecessary auxiliary stack.
When a RecursiveCoroutine co_awaits another one, the handle of the
awaiter is injected into the awaitee, so that when the awaitee is done
it can directly execute the remaining part of the awaiter as a
continuation.
2021-05-05 17:48:04 +02:00
Pietro Fezzardi 8ffcd49dd2 RecursiveCoroutine: fix reference arguments
Before this commit, recursive coroutines did not work properly if they
had out arguments with reference type.
The reason is that `rc_run` was inferring the type of its arguments from
the arguments themselves, not from the prototype of the recursive
coroutine.

Hence, code snippets like the following did not work properly, because
`rc_run` was taking x by value, not by reference.

```
RecursiveCoroutine<void> accumulate_on_i(int &i) {
  // ...
}

int f() {
  int x = 0;
  rc_run(accumulate_on_i, x);
  return x;
}
```

This commit fixes the problem. Now the arguments of `rc_run` are
properly forwarded to the recursive coroutine.
2021-02-17 11:37:00 +01:00
Pietro Fezzardi e1b283b0b6 Add RecursiveCoroutine headers and tests
RecursiveCoroutines are a facility intended to be used as-drop in
replacement of recursive functions.

They provide the following features.
- They can be written almost as regular recursive functions,
  with 4 caveats.
  1. A recursive coroutine that returns a type `T`, needs to be declared
     to return a `RecursiveCoroutine<T>`.
  2. Inside the body of a recursive coroutine, when recursively calling
     another recursive coroutine, the recursive call needs to be
     prepended by the new keyword `rc_recur`.
  3. Inside the body of a recursive coroutine, the `return` statement
     needs to be substituted with `rc_return`.
  4. When launching a recursive coroutine `A` from a function that is
     not a recursive coroutine, `A` needs to be called with the provided
     dedicated template wrapper `rc_run`.
     The syntax is the following `rc_run(A, arg0, arg1, ...)`.
     This is necessary to enable swapping off recursive coroutine and
     fall back to regular recursion for debug.
     See below for how to do it.
- Unlike regular recursive functions, they don't use the system stack
  for recursion. They use a custom heap-allocated stack to manage
  recursion. This makes them more robust for implementing recursive
  functions that manipulate user-defined input, because they are much
  less likely to trigger stack overflow.
- They can be turned off compiling with
  `-DDISABLE_RECURSIVE_COROUTINES`, falling back to regular recursion,
  for debug purposes.
- They support both direct and indirect recursion, i.e. a recursive
  coroutine A can recursively call itself, or it can recursively call
  another recursive coroutine B, which in turns recursively calls A.
2020-12-29 16:15:31 +01:00