Generator/Exponential: Difference between revisions
Content deleted Content added
→{{header|E}}: Add C using libco. |
→{{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> /* |
#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 |
cothread_t giver; /* this cothread calls yield64() */ |
||
cothread_t taker; /* this |
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 |
* Creates a cothread for the generator. The first call to next64(gen) |
||
* will enter the |
* 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. */ |
|||
⚫ | |||
/* |
/* |
||
Line 96: | Line 109: | ||
} |
} |
||
/* stuff for squares_without_cubes() */ |
|||
⚫ | |||
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 |
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); |
||
⚫ | |||
⚫ | |||
/* Allow other cothread to free this generator. */ |
|||
⚫ | |||
f.old_free = gen->free; |
|||
⚫ | |||
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> |