# 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.

3 state
C single instanceC∀ multiple instances
```#include <stdio.h>

int fn1, fn2, state = 1; // global variables
int fib() {
int fn;
switch ( state ) {
case 1:
fn = 0; fn1 = fn; state = 2;
break;
case 2:
fn = 1; fn2 = fn1; fn1 = fn; state = 3;
break;
case 3:
fn = fn1 + fn2; fn2 = fn1; fn1 = fn;
break;
}
return fn;
}
int main() {

for ( int i = 0; i < 10; i += 1 ) {
printf( "%d\n", fib() );
}
}
```
```#include <fstream.hfa>
#include <coroutine.hfa>
coroutine Fibonacci { int fn; };		// used for communication
void main( Fibonacci & fib ) with( fib ) { // called on first resume
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 ( 10 ) {						// print N Fibonacci values
sout | next( f1 ) | next( f2 );
}
}
```
1 state, multiple instances
CC∀
```#include <stdio.h>
typedef struct { int fn1, fn; } Fib;
#define FibCtor { 0, 1 }
int fib( Fib * f ) {

int ret = f->fn1;
f->fn1 = f->fn;
f->fn = f->fn + fn;
return ret;

}

int main() {
Fib f1 = FibCtor, f2 = FibCtor;
for ( int i = 0; i < 10; i += 1 ) {
printf( "%d %d\n", fib( &f1 ), fib( &f2 ) );
}
}
```
```#include <fstream.hfa>
#include <coroutine.hfa>
coroutine Fibonacci { int fn1; };	// used for communication
void main( Fibonacci & fib ) with( fib ) { // called on first resume
int fn;
[fn1, fn] = [0, 1];				// precompute first two states
for () {
suspend;					// restart last resume
[fn1, fn] = [fn, fn1 + fn];	// general case
}
}
int ?()( Fibonacci & fib ) with( fib ) { // function call operator
resume( fib );					// restart last suspend
return fn1;
}
int main() {
Fibonacci f1, f2;
for ( 10 ) {					// print N Fibonacci values
sout | f1() | f2();
}
}
```

### 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.

CC∀
```#include <stdio.h>

struct Format {
char ch;
int g, b;
};
void format( struct Format * fmt ) {
if ( fmt->ch != -1 ) {			// not EOF ?
printf( "%c", fmt->ch );
fmt->b += 1;
if ( fmt->b == 4 ) {		// block ?
printf( "  " );			// separator
fmt->b = 0;
fmt->g += 1;
}
if ( fmt->g == 5 ) {		// group ?
printf( "\n" );			// separator
fmt->g = 0;
}
} else {
if ( fmt->g != 0 || fmt->b != 0 ) printf( "\n" );
}
}
int main() {
struct Format fmt = { 0, 0, 0 };
for () {
scanf( "%c", &fmt.ch );
if ( feof( stdin ) ) break;
format( &fmt );
}
fmt.ch = -1;
format( &fmt );
}
```
```#include <fstream.hfa>
#include <coroutine.hfa>
coroutine Format {
char ch;						// used for communication
int g, b;						// global because used in destructor
};
void main( Format & fmt ) with( fmt ) {
for () {						// for as many characters
for ( g; 5 ) {				// groups of 5 blocks
for ( b; 4 ) {			// blocks of 4 characters
suspend;
sout | ch;			// print character
}
sout | "  ";			// print block separator
}
sout | nl;					// print group separator
}
}
void ?{}( Format & fmt ) { resume( fmt ); } // prime (start) coroutine
void ^?{}( Format & fmt ) with( fmt ) {
if ( g != 0 || b != 0 ) sout | nl;
}
void format( Format & fmt ) {
resume( fmt );
}
int main() {
Format fmt;
eof: for () {					// read until end of file
sin | fmt.ch;				// read one character
if ( eof( sin ) ) break eof;	// eof ?
prt( fmt, ch );				// push character for formatting
}
}
```

### Device Driver

Input successive characters on each call to routine next to parse a simple network protocol and output message text.

```// network protocol:  ... STX ... message ... ESC ETX ... message ... ETX 2-byte CRC ...

#include <fstream.hfa>
#include <coroutine.hfa>

enum Status { CONT, MSG, ESTX, ELNTH, ECRC };
coroutine Driver {
Status status;
char * msg, byte;
};
void ?{}( Driver & d, char * m ) { d.msg = m; }
Status next( Driver & d, char b ) with( d ) {
byte = b; resume( d ); return status;
}
void checkCRC( Driver & d, unsigned int sum ) with( d ) {
suspend;
unsigned short int crc = byte << 8;			// sign extension over written
suspend;
// prevent sign extension for signed char
status = (crc | (unsigned char)byte) == sum ? MSG : ECRC;
}
void main( Driver & d ) with( d ) {
enum { STX = '\002', ESC = '\033', ETX = '\003', MaxMsg = 64 };
msg: for () {											// parse message
status = CONT;
unsigned int lnth = 0, sum = 0;
while ( byte != STX ) suspend;
emsg: for () {
suspend;
choose ( byte ) {							// process byte
case STX:
status = ESTX; suspend; continue msg;
case ETX:
break emsg;
case ESC:
suspend;
}
if ( lnth >= MaxMsg ) {						// buffer full ?
status = ELNTH; suspend; continue msg;
}
msg[lnth++] = byte;
sum += byte;
}
msg[lnth] = '\0';								// terminate string
checkCRC( d, sum );								// refactor CRC check
suspend;
}
}
int main() {
char msg[65], byte;
Driver driver = { msg };
eof: for () {											// read until end of file
sin | byte;										// read one character
if ( eof( sin ) ) break eof;						// eof ?
choose( next( driver, byte ) ) {				// analyse character
case MSG:   sout | "msg:" | msg;
case ESTX:  sout | "STX in message";
case ELNTH: sout | "message too long";
case ECRC:  sout | "CRC failure";
default: ;
}
}
}
```

## 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.hfa>
#include <coroutine.hfa>
coroutine PingPong {
const char * name;
unsigned int N;
PingPong & part;
};
void ?{}( PingPong & this, const char * name, unsigned int N, PingPong & part ) {
this.[name, N] = [name, N];  &this.part = &part;
}
void ?{}( PingPong & this, const char * name, unsigned int N ) {
this{ name, N, *0p };								// call first constructor
}
void cycle( PingPong & pingpong ) {
resume( pingpong );
}
void partner( PingPong & this, PingPong & part ) {
&this.part = &part;
resume( this );
}
void main( PingPong & pingpong ) with(pingpong) {		// ping's starter ::main, pong's starter ping
for ( N ) {											// N ping-pongs
sout | name;
cycle( 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 #include #include // random #include // getpid 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 ( i; N ) { // N pairs of values int p1 = random( 100 ), p2 = random( 100 ); sout | p1 | " " | p2; int status = delivery( c, p1, p2 ); sout | " \$" | money | nl | status; receipt += 1; } stop( c ); sout | "prod stops"; } 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.c = &c; prod.[N, receipt] = [N, 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, done ] = [0, 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 | nl | " \$" | money; status += 1; receipt = payment( p, money ); sout | " #" | receipt; money += 1; } sout | "cons stops"; } int delivery( Cons & cons, int p1, int p2 ) { cons.[p1, p2] = [p1, 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 }; srandom( getpid() ); start( prod, 5, cons ); } ```