struct gen64 {
	cothread_t giver;	
	cothread_t taker;	
	int64_t given;
	void (*free)(struct gen64 *);
	void *garbage;
};


inline void
yield64(struct gen64 *gen, int64_t value)
{
	gen->given = value;
	co_switch(gen->taker);
}


inline int64_t
next64(struct gen64 *gen)
{
	gen->taker = co_active();
	co_switch(gen->giver);
	return gen->given;
}

static void
gen64_free(struct gen64 *gen)
{
	co_delete(gen->giver);
}

struct gen64 *entry64;


inline void
gen64_init(struct gen64 *gen, void (*entry)(void))
{
	if ((gen->giver = co_create(4096, entry)) == NULL) {
		
		fputs(, stderr);
		exit(1);
	}
	gen->free = gen64_free;
	entry64 = gen;
}




void
powers(struct gen64 *gen, int64_t m)
{
	int64_t base, exponent, n, result;

	for (n = 0;; n++) {
		
		base = n;
		exponent = m;
		for (result = 1; exponent != 0; exponent >>= 1) {
			if (exponent & 1) result *= base;
			base *= base;
		}
		yield64(gen, result);
	}
	
}



ENTRY(enter_squares, powers(entry64, 2))
ENTRY(enter_cubes, powers(entry64, 3))

struct swc {
	struct gen64 cubes;
	struct gen64 squares;
	void (*old_free)(struct gen64 *);
};

static void
swc_free(struct gen64 *gen)
{
	struct swc *f = gen->garbage;
	f->cubes.free(&f->cubes);
	f->squares.free(&f->squares);
	f->old_free(gen);
}


void
squares_without_cubes(struct gen64 *gen)
{
	struct swc f;
	int64_t c, s;

	gen64_init(&f.cubes, enter_cubes);
	c = next64(&f.cubes);

	gen64_init(&f.squares, enter_squares);
	s = next64(&f.squares);

	
	f.old_free = gen->free;
	gen->garbage = &f;
	gen->free = swc_free;

	for (;;) {
		while (c < s)
			c = next64(&f.cubes);
		if (c != s)
			yield64(gen, s);
		s = next64(&f.squares);
	}
	
}

ENTRY(enter_squares_without_cubes, squares_without_cubes(entry64))


int
main()
{
	struct gen64 gen;
	int i;

	gen64_init(&gen, enter_squares_without_cubes);

	for (i = 0; i < 20; i++)
		next64(&gen);
	for (i = 0; i < 9; i++)
		printf( PRId64 , next64(&gen));
	printf( PRId64 , next64(&gen));

	gen.free(&gen); 
	return 0;
}