#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
typedef unsigned int uint;
typedef unsigned short word;
typedef unsigned char byte;
#ifdef __GNUC__
#define NOINLINE __attribute__((noinline))
#else
#define NOINLINE __declspec(noinline)
#endif
#include <setjmp.h>
//#include "my_setjmp.h"
enum{
STKPAD=1<<16,
STKSAV=1<<10
};
struct coroutine {
volatile uint state;
volatile char* stkptrH;
volatile char* stkptrL;
jmp_buf PointA, PointB;
char stack[STKSAV];
coroutine() { state=0; }
NOINLINE // necessary for IntelC + my_setjmp.h
void yield( int value ) {
char curtmp; stkptrL=(&curtmp)-16; // -16 is necessary for MSC
if( setjmp(PointB)==0 ) {
state = value;
memcpy( stack, (char*)stkptrL, stkptrH-stkptrL );
longjmp(PointA,1);
}
}
template <typename T>
NOINLINE // necessary for MSC, to avoid allocation of stktmp before setjmp()
void call_do_process() {
char stktmp[STKPAD]; stkptrH = stktmp;
((T*)this)->do_process();
}
template <typename T>
uint call( T& child ) {
if( setjmp(PointA)==0 ) {
if( state ) {
memcpy( (char*)stkptrL, stack, stkptrH-stkptrL );
longjmp(PointB,1);
}
call_do_process<T>();
}
return state;
}
};
struct index : coroutine {
void do_process( void ) {
uint a=1;
while(1) {
yield( a );
a++;
}
}
} F1;
struct fibonacci : coroutine {
void do_process( void ) {
uint a=0,b=1;
while(1) {
yield( b );
b = b + a;
a = b - a;
}
}
} F2;
int main( int argc, char** argv ) {
for( int i=0; i<20; i++ ) {
printf( "%i:%i ", F1.call(F1), F2.call(F2) );
} printf( "\n" );
return 0;
}