diff options
| -rw-r--r-- | docs/ccommon_api.md | 8 | ||||
| -rw-r--r-- | include/stc/algo/coroutine.h | 14 | ||||
| -rw-r--r-- | misc/examples/cointerleave.c | 8 | ||||
| -rw-r--r-- | misc/examples/coread.c | 8 | ||||
| -rw-r--r-- | misc/examples/coroutines.c | 6 | ||||
| -rw-r--r-- | misc/examples/generator.c | 32 | ||||
| -rw-r--r-- | misc/examples/scheduler.c | 2 | ||||
| -rw-r--r-- | misc/examples/triples.c | 46 |
8 files changed, 61 insertions, 63 deletions
diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 7014def8..2319109b 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -314,7 +314,7 @@ bool triples(struct triples* i) { // coroutine } } } - cco_final: // required label + cco_final: // required for cleanup puts("done"); cco_end(true); } @@ -352,15 +352,15 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| -| | `cco_final:` | Obligatory label in coroutine | +| | `cco_final:` | Label for cleanup in coroutine | | | `cco_return` | Early return from the coroutine (no arg) | | `bool` | `cco_suspended(ctx)` | Is coroutine in suspended state? | | `bool` | `cco_done(ctx)` | Is coroutine done? | | | `cco_begin(ctx)` | Begin coroutine block | -| | `cco_end(retval)` | End coroutine block and return retval | | | `cco_end()` | End coroutine block | -| | `cco_yield(retval)` | Suspend execution and return retval | +| | `cco_end(retval)` | End coroutine block and return retval | | | `cco_yield()` | Suspend execution | +| | `cco_yield(retval)` | Suspend execution and return retval | | | `cco_await(promise)` | Suspend until promise is true | | | `cco_await_with(promise, retval)` | Suspend with retval until promise is true | | | Semaphores: | | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 89dd27f0..c9cb8fc0 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -38,7 +38,7 @@ bool coroutine(struct coroutine* I) { for (I->y = 0; I->y < I->max_y; I->y++) cco_yield(false); - cco_final: + cco_final: // required if there is cleanup code puts("final"); cco_end(true); } @@ -68,13 +68,12 @@ enum { #define cco_begin(ctx) \ int *_state = &(ctx)->cco_state; \ - switch (*_state) { \ + goto _begin; _begin: switch (*_state) { \ case 0: #define cco_end(retval) \ - *_state = cco_state_done; break; \ - case -99: goto _cco_final_; \ } \ + *_state = cco_state_done; \ return retval #define cco_yield(retval) \ @@ -92,11 +91,10 @@ enum { } while (0) #define cco_final \ - case cco_state_final: \ - _cco_final_ + case cco_state_final #define cco_return \ - goto _cco_final_ + do { *_state = cco_state_final; goto _begin; } while (0) #define cco_stop(ctx) \ do { \ @@ -112,7 +110,7 @@ enum { typedef struct { - int count; + intptr_t count; } cco_semaphore; /** diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 5bdbd257..4fe89316 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -16,7 +16,6 @@ static int next_value(struct GenValue* g) cco_begin(g); for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it)) cco_yield(*g->it.ref); - cco_final: cco_end(0); } @@ -37,7 +36,6 @@ void interleaved(struct Generator* g) g->value = next_value(&g->y); if (!cco_done(&g->y)) cco_yield(); } - cco_final: cco_end(); } @@ -48,9 +46,11 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - while (interleaved(&g), !cco_done(&g)) + while (1) { + interleaved(&g); + if (cco_done(&g)) break; printf("%d ", g.value); - + } puts(""); c_drop(IVec, &a, &b); } diff --git a/misc/examples/coread.c b/misc/examples/coread.c index 38447c44..0073191b 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -20,10 +20,10 @@ bool file_read(struct file_read* g) while (cstr_getline(&g->line, g->fp)) cco_yield(false); - cco_final: // this label is required. - printf("finish\n"); - cstr_drop(&g->line); - fclose(g->fp); + cco_final: + printf("finish\n"); + cstr_drop(&g->line); + fclose(g->fp); cco_end(true); } diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index a5db3291..9071fee0 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -35,7 +35,7 @@ bool prime(struct prime* g) { cco_yield(false); } } - cco_final: + cco_final: printf("final prm\n"); cco_end(true); } @@ -67,7 +67,7 @@ bool fibonacci(struct fibonacci* g) { } cco_yield(false); } - cco_final: + cco_final: printf("final fib\n"); cco_end(true); } @@ -91,7 +91,7 @@ bool combined(struct combined* g) { cco_reset(&g->prm); cco_await(prime(&g->prm), false); - cco_final: + cco_final: puts("final combined"); cco_end(true); } diff --git a/misc/examples/generator.c b/misc/examples/generator.c index 2bccc489..41dffafb 100644 --- a/misc/examples/generator.c +++ b/misc/examples/generator.c @@ -4,37 +4,38 @@ #include <stdio.h> typedef struct { - int n; + int size; int a, b, c; -} Triple_value, Triple; +} Triple, Triple_value; typedef struct { Triple_value* ref; + int count; int cco_state; } Triple_iter; -bool Triple_next(Triple_iter* it) { +void Triple_next(Triple_iter* it) { Triple_value* t = it->ref; cco_begin(it); - for (t->c = 1;; ++t->c) { + for (t->c = 5; t->size; ++t->c) { for (t->a = 1; t->a < t->c; ++t->a) { for (t->b = t->a; t->b < t->c; ++t->b) { if (t->a*t->a + t->b*t->b == t->c*t->c) { - if (t->n-- == 0) cco_return; - cco_yield(true); + if (it->count++ == t->size) + cco_return; + cco_yield(); } } } } - cco_final: - it->ref = NULL; - cco_end(false); + cco_final: + it->ref = NULL; + cco_end(); } Triple_iter Triple_begin(Triple* t) { - Triple_iter it = {t}; - if (t->n > 0) Triple_next(&it); - else it.ref = NULL; + Triple_iter it = {.ref=t}; + Triple_next(&it); return it; } @@ -42,11 +43,10 @@ Triple_iter Triple_begin(Triple* t) { int main() { puts("Pythagorean triples with c < 100:"); - Triple t = {INT32_MAX}; - c_foreach (i, Triple, t) - { + Triple triple = {.size=30}; // max number of triples + c_foreach (i, Triple, triple) { if (i.ref->c < 100) - printf("%u: (%d, %d, %d)\n", INT32_MAX - i.ref->n + 1, i.ref->a, i.ref->b, i.ref->c); + printf("%u: (%d, %d, %d)\n", i.count, i.ref->a, i.ref->b, i.ref->c); else cco_stop(&i); } diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index db9c2716..04107d5e 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -42,7 +42,6 @@ static bool taskA(struct Task* task) puts("A is back doing more work"); cco_yield(resume_task(task)); puts("A is back doing even more work"); - cco_final: cco_end(true); } @@ -54,7 +53,6 @@ static bool taskB(struct Task* task) puts("B is back doing work"); cco_yield(resume_task(task)); puts("B is back doing more work"); - cco_final: cco_end(true); } diff --git a/misc/examples/triples.c b/misc/examples/triples.c index 2e0211c3..183b7389 100644 --- a/misc/examples/triples.c +++ b/misc/examples/triples.c @@ -3,12 +3,21 @@ #include <stc/algo/coroutine.h> #include <stdio.h> +int gcd(int a, int b) { + while (b) { + int t = a % b; + a = b; + b = t; + } + return a; +} + void triples_vanilla(int n) { - for (int c = 5; n; ++c) { + for (int c = 5, i = 0; n; ++c) { for (int a = 1; a < c; ++a) { for (int b = a + 1; b < c; ++b) { - if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c) { - printf("{%d, %d, %d}\n", a, b, c); + if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c && gcd(a, b) == 1) { + printf("%d: {%d, %d, %d}\n", ++i, a, b, c); if (--n == 0) goto done; } } @@ -18,41 +27,34 @@ void triples_vanilla(int n) { } struct triples { - int n; + int size, count; int a, b, c; int cco_state; }; -bool triples_coro(struct triples* I) { - cco_begin(I); - for (I->c = 5; I->n; ++I->c) { - for (I->a = 1; I->a < I->c; ++I->a) { - for (I->b = I->a + 1; I->b < I->c; ++I->b) { - if ((int64_t)I->a*I->a + (int64_t)I->b*I->b == (int64_t)I->c*I->c) { +bool triples_coro(struct triples* t) { + cco_begin(t); + t->count = 0; + for (t->c = 5; t->size; ++t->c) { + for (t->a = 1; t->a < t->c; ++t->a) { + for (t->b = t->a + 1; t->b < t->c; ++t->b) { + if ((int64_t)t->a*t->a + (int64_t)t->b*t->b == (int64_t)t->c*t->c) { + if (t->count++ == t->size) + cco_return; cco_yield(false); - if (--I->n == 0) cco_return; } } } } - cco_final: + cco_final: puts("done"); cco_end(true); } -int gcd(int a, int b) { - while (b) { - int t = a % b; - a = b; - b = t; - } - return a; -} - int main() { puts("Vanilla triples:"); - triples_vanilla(6); + triples_vanilla(5); puts("\nCoroutine triples:"); struct triples t = {INT32_MAX}; |
