# Coroutine Examples

## Semi-Coroutine

A semi-coroutine asymmetrically reactivates the coroutine that previously activated it.

### Fibonacci

Output successive Fibonacci numbers on each call to routine next.

```#include <fstream>
#include <coroutine>
coroutine Fibonacci { int fn; };       // used for communication
void ?{}( Fibonacci & fib ) with( fib ) { fn = 0; }
void main( Fibonacci & fib ) with( fib ) {
int fn1, fn2;                             // retained between resumes
fn = 0;  fn1 = fn;                      // 1st case
suspend();                              // restart last resume
fn = 1;  fn2 = fn1;  fn1 = fn;     // 2nd case
suspend();                              // restart last resume
for ( ;; ) {
fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn; // general case
suspend();                        // restart last resume
}
}
int next( Fibonacci & fib ) with( fib ) {
resume( fib );                         // restart last suspend
return fn;
}
int main() {
Fibonacci f1, f2;
for ( int i = 1; i <= 10; i += 1 ) {
sout | next( f1 ) | next( f2 ) | endl;
}
}
```

### Format

Input successive characters on each call to routine prt and reformat the characters into 4 character per block and 5 blocks in a group per line.

```#include <fstream>
#include <coroutine>
coroutine Format {
char ch;                                  // used for communication
int g, b;                                   // global because used in destructor
};
void ?{}( Format & fmt ) { resume( fmt ); }  // prime (start) coroutine
void ^?{}( Format & fmt ) with( fmt ) { if ( g != 0 || b != 0 ) sout | endl; }
void main( Format & fmt ) with( fmt ) {
for ( ;; ) {                                 // for as many characters
for ( g = 0; g < 5; g += 1 ) { // groups of 5 blocks
for ( b = 0; b < 4; b += 1 ) { // blocks of 4 characters
suspend();
sout | ch;              // print character
}
sout | "  ";                   // print block separator
}
sout | endl;                       // print group separator
}
}
void prt( Format & fmt, char ch ) {
fmt.ch = ch;
resume( fmt );
}
int main() {
Format fmt;                            // format characters into blocks of 4 and groups of 5 blocks per line
char ch;
Eof: for ( ;; ) {                         // read until end of file
sin | ch;                            // read one character
if ( eof( sin ) ) break Eof;      // eof ?
prt( fmt, ch );                    // push character for formatting
}
}
```

## Full Coroutine

A full-coroutine symmetrically activates another coroutine, which directly or indirectly reactivates the original coroutine (activation cycle).

### Ping Pong

Resume-resume cycle between coroutines ping and pong, no communication.

```#include <fstream>
#include <coroutine>
coroutine PingPong {
const char * name;
unsigned int N;
PingPong * part;
};
void ?{}( PingPong & this, const char * name, unsigned int N, PingPong & part ) {
this.name = name;
this.N = N;
this.part = &part;
}
void ?{}( PingPong & this, const char * name, unsigned int N ) {
this{ name, N, *(PingPong *)0 };
}
void cycle( PingPong & pingpong ) {
resume( pingpong );
}
void partner( PingPong & this, PingPong & part ) {
this.part = &part;
resume( this );
}
void main( PingPong & pingpong ) { // ping's starter ::main, pong's starter ping
for ( unsigned int i = 0; i < pingpong.N; i += 1 ) {
sout | pingpong.name | endl;
cycle( *pingpong.part );
}
}
int main() {
enum { N = 20 };
PingPong ping = { "ping", N }, pong = { "pong", N, ping };
partner( ping, pong );
}
```

### Producer / Consumer

Resume-resume cycle between coroutines prod and cons, bi-directional communication.

```#include <fstream>
#include <coroutine>
#include <stdlib>                          // random
coroutine Cons;                           // forward
int delivery( Cons & cons, int p1, int p2 );
void stop( Cons & cons );

coroutine Prod {
Cons * c;
int N, money, receipt;
};
void main( Prod & prod ) with( prod ) {  // starter ::main
// 1st resume starts here
for ( int i = 0; i < N; i += 1 ) {
int p1 = random( 100 );
int p2 = random( 100 );
sout | p1 | " " | p2 | endl;
int status = delivery( *c, p1, p2 );
sout | " \$" | money | endl;
sout | status | endl;
receipt += 1;
}
stop( *c );
sout | "prod stops" | endl;
}
int payment( Prod & prod, int money ) {
prod.money = money;
resume( prod );                     // main 1st time, then
return prod.receipt;               // prod in delivery
}
void start( Prod & prod, int N, Cons &c ) {
prod.N = N;
prod.c = &c;
prod.receipt = 0;
resume( prod );                     // activate main
}

coroutine Cons {
Prod * p;
int p1, p2, status;
bool done;
};
void ?{}( Cons & cons, Prod & p ) {
cons.p = &p;
cons.status = 0;
cons.done = false;
}
void ^?{}( Cons & cons ) {}
void main( Cons & cons ) with( cons ) {  // starter prod
// 1st resume starts here
int money = 1, receipt;
for ( ; ! done; ) {
sout | p1 | " " | p2 | endl;
sout | " \$" | money | endl;
status += 1;
receipt = payment( *p, money );
sout | " #" | receipt | endl;
money += 1;
}
sout | "cons stops" | endl;
}
int delivery( Cons & cons, int p1, int p2 ) {
cons.p1 = p1;
cons.p2 = p2;
resume( cons );                      // main 1st time, then
return cons.status;                 // cons in payment
}
void stop( Cons & cons ) {
cons.done = true;
resume( cons );                      // activate payment
}
int main() {
Prod prod;
Cons cons = { prod };
random_seed( getpid() );
start( prod, 5, cons );
}
```