Generator/Exponential: Difference between revisions

Content deleted Content added
→‎{{libheader|libco}}: Add some ugly code to check for memory allocation, and to free memory. C is being an awful language.
Line 22: Line 22:


<lang c>#include <inttypes.h> /* int64_t, PRId64 */
<lang c>#include <inttypes.h> /* int64_t, PRId64 */
#include <stdlib.h> /* exit() */
#include <stdio.h> /* printf() */
#include <stdio.h> /* printf() */


#include <libco.h> /* co_active(), co_create(), co_switch() */
#include <libco.h> /* co_{active,create,delete,switch}() */




Line 30: Line 31:
/* A generator that yields values of type int64_t. */
/* A generator that yields values of type int64_t. */
struct gen64 {
struct gen64 {
cothread_t giver; /* this coroutine calls yield64() */
cothread_t giver; /* this cothread calls yield64() */
cothread_t taker; /* this coroutine calls next64() */
cothread_t taker; /* this cothread calls next64() */
int64_t given;
int64_t given;
void (*free)(struct gen64 *);
void *garbage;
};
};


Line 50: Line 53:
co_switch(gen->giver);
co_switch(gen->giver);
return gen->given;
return gen->given;
}

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


Line 55: Line 64:


/*
/*
* Creates a coroutine for the generator. The first call to next64(gen)
* Creates a cothread for the generator. The first call to next64(gen)
* will enter the coroutine; the entry function must copy the pointer
* will enter the cothread; the entry function must copy the pointer
* from the global variable struct gen64 *entry64.
* from the global variable struct gen64 *entry64.
*
* Use gen->free(gen) to free the cothread.
*/
*/
inline void
inline void
gen64_init(struct gen64 *gen, void (*entry)(void))
gen64_init(struct gen64 *gen, void (*entry)(void))
{
{
gen->giver = co_create(4096, entry);
if ((gen->giver = co_create(4096, entry)) == NULL) {
/* Perhaps malloc() failed */
fputs("co_create: Cannot create cothread\n", stderr);
exit(1);
}
gen->free = gen64_free;
entry64 = gen;
entry64 = gen;
}
}





/* Defines a static entry function for a coroutine. */
#define ENTRY(name, code) static void name(void) { code; }


/*
/*
Line 96: Line 109:
}
}


/* stuff for squares_without_cubes() */
#define ENTRY(name, code) static void name(void) { code; }
ENTRY(enter_squares, powers(entry64, 2))
ENTRY(enter_squares, powers(entry64, 2))
ENTRY(enter_cubes, powers(entry64, 3))
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);
}


/*
/*
Line 106: Line 136:
squares_without_cubes(struct gen64 *gen)
squares_without_cubes(struct gen64 *gen)
{
{
struct gen64 cubes, squares;
struct swc f;
int64_t c, s;
int64_t c, s;


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

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


/* Allow other cothread to free this generator. */
gen64_init(&squares, enter_squares);
f.old_free = gen->free;
s = next64(&squares);
gen->garbage = &f;
gen->free = swc_free;


for (;;) {
for (;;) {
Line 119: Line 154:
yield64(gen, s);
yield64(gen, s);
while (c <= s)
while (c <= s)
c = next64(&cubes);
c = next64(&f.cubes);
s = next64(&squares);
s = next64(&f.squares);
}
}
/* NOTREACHED */
/* NOTREACHED */
Line 145: Line 180:
printf("%" PRId64 "\n", next64(&gen));
printf("%" PRId64 "\n", next64(&gen));


gen.free(&gen); /* Free memory. */
/*
* This program has no way to free the memory for all three
* coroutines. It can do co_delete(gen.giver) but then there
* would be no way to free the other two coroutines for squares
* and cubes.
*
* Here the program exits, to free the memory for the entire
* program.
*/
return 0;
return 0;
}</lang>
}</lang>