From 399eb8d0e1de2839d826a9e0cf123d90d00b0018 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 1 May 2023 23:11:45 +0200 Subject: Replaced cco_yield(corocall, ctx, retval) with cco_await(cond) and cco_await_while(cond). --- misc/examples/coroutines.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'misc/examples/coroutines.c') diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index b11b8532..af9fef81 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -78,29 +78,27 @@ struct combined { int cco_state; }; + bool combined(struct combined* C) { cco_begin(C); - cco_yield(prime(&C->prm), &C->prm, true); - cco_yield(fibonacci(&C->fib), &C->fib, true); + cco_await(prime(&C->prm) == false); + cco_await(fibonacci(&C->fib) == false); // Reuse the C->prm context and extend the count: C->prm.count = 8; C->prm.result += 2; cco_reset(&C->prm); - cco_yield(prime(&C->prm), &C->prm, true); + cco_await(prime(&C->prm) == false); cco_final: puts("final comb"); cco_end(false); } -int main(void) { +int main(void) +{ struct combined comb = {.prm={.count=8}, .fib={14}}; - if (true) - while (combined(&comb)) - printf("Prime(%d)=%lld, Fib(%d)=%lld\n", - comb.prm.idx, (long long)comb.prm.result, - comb.fib.idx, (long long)comb.fib.result); - else - while (prime(&comb.prm)) - printf("Prime(%d)=%lld\n", - comb.prm.idx, (long long)comb.prm.result); + + while (combined(&comb)) + printf("Prime(%d)=%lld, Fib(%d)=%lld\n", + comb.prm.idx, (long long)comb.prm.result, + comb.fib.idx, (long long)comb.fib.result); } -- cgit v1.2.3 From 2adea8b3b06ebe1b2152870862100f7e7985cfdf Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 2 May 2023 07:20:29 +0200 Subject: Improved coroutine.h, added new coro examples. --- docs/ccommon_api.md | 28 +++++++++------- include/stc/algo/coroutine.h | 49 ++++++++++++++++++++++------ misc/examples/cointerleave.c | 60 ++++++++++++++++++++++++++++++++++ misc/examples/coread.c | 14 ++++---- misc/examples/coroutines.c | 20 ++++++------ misc/examples/scheduler.c | 76 ++++++++++++++++++++++++++++++++++++++++++++ misc/examples/triples.c | 8 ++--- 7 files changed, 212 insertions(+), 43 deletions(-) create mode 100644 misc/examples/cointerleave.c create mode 100644 misc/examples/scheduler.c (limited to 'misc/examples/coroutines.c') diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 549eff4e..27df13ce 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -302,13 +302,13 @@ struct triples { int cco_state; // required member }; -bool triples_next(struct triples* i) { // coroutine +bool triples(struct triples* i) { // coroutine 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) { - cco_yield(true); + cco_yield(false); if (--i->n == 0) cco_return; } } @@ -316,7 +316,7 @@ bool triples_next(struct triples* i) { // coroutine } cco_final: // required label puts("done"); - cco_end(false); + cco_end(true); } int gcd(int a, int b) { // greatest common denominator @@ -333,7 +333,7 @@ int main() struct triples t = {.n=INT32_MAX}; int n = 0; - while (triples_next(&t)) { + while (!triples(&t)) { // Skip triples with GCD(a,b) > 1 if (gcd(t.a, t.b) > 1) continue; @@ -353,20 +353,24 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| | | `cco_final:` | Obligatory label in coroutine | -| | `cco_return;` | Early return from the coroutine | +| | `cco_return` | Early return from the coroutine (no arg) | | `bool` | `cco_alive(ctx)` | Is coroutine in initial or suspended state? | | `bool` | `cco_done(ctx)` | Is coroutine not alive? | | `bool` | `cco_suspended(ctx)` | Is coroutine in suspended state? | -| `void` | `cco_begin(ctx)` | Begin coroutine block | -| `rettype` | `cco_end(retval)` | End coroutine block and return retval | -| `void` | `cco_end()` | End coroutine block (return void) | -| `rettype` | `cco_yield(retval)` | Suspend execution and return retval | -| `void` | `cco_yield()` | Suspend execution (return void) | -| `rettype` | `cco_await_while(cond, retval)` | If cond, suspend execution and return retval | -| `bool` | `cco_await(cond)` | If not cond, suspend execution and return true | +| | `cco_begin(ctx)` | Begin coroutine block | +| | `cco_end(retval)` | End coroutine block and return retval | +| | `cco_end()` | End coroutine block (return void) | +| | `cco_yield(retval)` | Suspend execution and return retval | +| | `cco_yield()` | Suspend execution (return void) | +| | `cco_await(promise)` | Suspend and return false until promise is true | +| | `cco_await_while(cond, retval)` | Suspend and return retval while cond is true | | | From caller side: | | | `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | | `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) | +| | Semaphores: | | +| | `cco_semaphore` | Semaphore type | +| | `cco_await_sem(sem)` | Await for the semaphore count > 0 | +| | `cco_signal_sem(sem)` | Signal the semaphore by increasing count| --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 6c1d7d28..4b7bee5f 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -26,38 +26,38 @@ #include #include -struct iterate { +struct coroutine { int max_x, max_y; int x, y; int cco_state; // required member }; -bool iterate(struct iterate* I) { +bool coroutine(struct coroutine* I) { cco_begin(I); for (I->x = 0; I->x < I->max_x; I->x++) for (I->y = 0; I->y < I->max_y; I->y++) - cco_yield(true); + cco_yield(false); cco_final: - puts("final"); - cco_end(false); + puts("final"); + cco_end(true); } int main(void) { - struct iterate it = {.max_x=3, .max_y=3}; + struct coroutine it = {.max_x=3, .max_y=3}; int n = 0; - while (iterate(&it)) + while (!coroutine(&it)) { printf("%d %d\n", it.x, it.y); // example of early stop: - if (++n == 20) cco_stop(&it); // signal to stop at next + if (++n == 7) cco_stop(&it); // signal to stop at next } return 0; } */ #include -enum { +enum cco_states { cco_state_final = -1, cco_state_done = -2, }; @@ -89,7 +89,7 @@ enum { case __LINE__: if (cond) return retval; \ } while (0) -#define cco_await(cond) cco_await_while(!(cond), true) +#define cco_await(promise) cco_await_while(!(promise), false) #define cco_final \ case cco_state_final: \ @@ -110,4 +110,33 @@ enum { if (*_state == cco_state_done) *_state = 0; \ } while (0) + +typedef struct { + int count; +} cco_semaphore; + +/** + * Wait for a semaphore + * + * This macro carries out the "wait" operation on the semaphore. The + * wait operation causes the "thread" to block while the counter is + * zero. When the counter reaches a value larger than zero, the + * protothread will continue. + */ +#define cco_await_sem(sem) \ + do { \ + cco_await((sem)->count > 0); \ + --(sem)->count; \ + } while (0) + +/** + * Signal a semaphore + * + * This macro carries out the "signal" operation on the semaphore. The + * signal operation increments the counter inside the semaphore, which + * eventually will cause waiting "threads" to continue executing. + */ +#define cco_signal_sem(sem) ++(sem)->count +#define cco_reset_sem(sem, value) ((sem)->count = value) + #endif diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c new file mode 100644 index 00000000..64473d96 --- /dev/null +++ b/misc/examples/cointerleave.c @@ -0,0 +1,60 @@ +// https://www.youtube.com/watch?v=8sEe-4tig_A +#include +#include +#define i_type IVec +#define i_val int +#include + +struct GenValue { + IVec *v; + IVec_iter it; + int cco_state; +}; + +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); +} + +struct Generator { + struct GenValue x, y; + int cco_state; + int value; +}; + +bool interleaved(struct Generator* g) +{ + cco_begin(g); + while (cco_alive(&g->x) || cco_alive(&g->y)) + { + g->value = next_value(&g->x); + if (cco_alive(&g->x)) cco_yield(false); + + g->value = next_value(&g->y); + if (cco_alive(&g->y)) cco_yield(false); + } + cco_final: + cco_end(true); +} + +void Use(void) +{ + IVec a = c_make(IVec, {2, 4, 6, 8, 10, 11}); + IVec b = c_make(IVec, {3, 5, 7, 9}); + + struct Generator g = {{&a}, {&b}}; + + while (!interleaved(&g)) + printf("%d\n", g.value); + + c_drop(IVec, &a, &b); +} + +int main() +{ + Use(); +} diff --git a/misc/examples/coread.c b/misc/examples/coread.c index 0a7f4816..d5385a87 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -4,36 +4,36 @@ // Read file line by line using coroutines: -struct file_nextline { +struct file_read { const char* filename; int cco_state; FILE* fp; cstr line; }; -bool file_nextline(struct file_nextline* U) +bool file_read(struct file_read* U) { cco_begin(U) U->fp = fopen(U->filename, "r"); U->line = cstr_init(); while (cstr_getline(&U->line, U->fp)) - cco_yield(true); + cco_yield(false); cco_final: // this label is required. printf("finish\n"); cstr_drop(&U->line); fclose(U->fp); - cco_end(false); + cco_end(true); } int main(void) { - struct file_nextline it = {__FILE__}; + struct file_read g = {__FILE__}; int n = 0; - while (file_nextline(&it)) + while (!file_read(&g)) { - printf("%3d %s\n", ++n, cstr_str(&it.line)); + printf("%3d %s\n", ++n, cstr_str(&g.line)); //if (n == 10) cco_stop(&it); } } diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index af9fef81..3fddf913 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -23,7 +23,7 @@ bool prime(struct prime* U) { if (U->result == 2) { if (U->count-- == 0) cco_return; ++U->idx; - cco_yield(true); + cco_yield(false); } U->result += !(U->result & 1); for (U->pos = U->result; U->count > 0; U->pos += 2) { @@ -31,12 +31,12 @@ bool prime(struct prime* U) { --U->count; ++U->idx; U->result = U->pos; - cco_yield(true); + cco_yield(false); } } cco_final: printf("final prm\n"); - cco_end(false); + cco_end(true); } @@ -63,11 +63,11 @@ bool fibonacci(struct fibonacci* F) { F->result = F->b; F->b = sum; } - cco_yield(true); + cco_yield(false); } cco_final: printf("final fib\n"); - cco_end(false); + cco_end(true); } // Combine @@ -81,23 +81,23 @@ struct combined { bool combined(struct combined* C) { cco_begin(C); - cco_await(prime(&C->prm) == false); - cco_await(fibonacci(&C->fib) == false); + cco_await(prime(&C->prm)); + cco_await(fibonacci(&C->fib)); // Reuse the C->prm context and extend the count: C->prm.count = 8; C->prm.result += 2; cco_reset(&C->prm); - cco_await(prime(&C->prm) == false); + cco_await(prime(&C->prm)); cco_final: puts("final comb"); - cco_end(false); + cco_end(true); } int main(void) { struct combined comb = {.prm={.count=8}, .fib={14}}; - while (combined(&comb)) + while (!combined(&comb)) printf("Prime(%d)=%lld, Fib(%d)=%lld\n", comb.prm.idx, (long long)comb.prm.result, comb.fib.idx, (long long)comb.fib.result); diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c new file mode 100644 index 00000000..1809f2ec --- /dev/null +++ b/misc/examples/scheduler.c @@ -0,0 +1,76 @@ +// https://www.youtube.com/watch?v=8sEe-4tig_A +#include +#include + +struct Scheduler; +struct Task { + bool (*resume)(struct Task*); + struct Scheduler* sched; + int cco_state; +}; + +#define i_type Scheduler +#define i_val struct Task +#define i_no_cmp +#include + +static bool schedule(Scheduler* sched) +{ + struct Task task = *Scheduler_front(sched); + Scheduler_pop_front(sched); + + if (cco_alive(&task)) + task.resume(&task); + + return !Scheduler_empty(sched); +} + +static bool resume_task(const struct Task* task) +{ + Scheduler_push_back(task->sched, *task); + return false; +} + + +static bool taskA(struct Task* task) +{ + cco_begin(task); + puts("Hello, from task A"); + cco_yield(resume_task(task)); + puts("A is back doing work"); + cco_yield(resume_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); +} + +static bool taskB(struct Task* task) +{ + cco_begin(task); + puts("Hello, from task B"); + cco_yield(resume_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); +} + +void Use(void) +{ + Scheduler scheduler = c_make(Scheduler, { + {taskA, &scheduler}, + {taskB, &scheduler}, + }); + + while (schedule(&scheduler)) {} + + Scheduler_drop(&scheduler); +} + +int main() +{ + Use(); +} diff --git a/misc/examples/triples.c b/misc/examples/triples.c index 520bf012..2e0211c3 100644 --- a/misc/examples/triples.c +++ b/misc/examples/triples.c @@ -23,13 +23,13 @@ struct triples { int cco_state; }; -bool triples_next(struct triples* I) { +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) { - cco_yield(true); + cco_yield(false); if (--I->n == 0) cco_return; } } @@ -37,7 +37,7 @@ bool triples_next(struct triples* I) { } cco_final: puts("done"); - cco_end(false); + cco_end(true); } int gcd(int a, int b) { @@ -58,7 +58,7 @@ int main() struct triples t = {INT32_MAX}; int n = 0; - while (triples_next(&t)) { + while (!triples_coro(&t)) { if (gcd(t.a, t.b) > 1) continue; if (t.c < 100) -- cgit v1.2.3 From ab7a91c501fb3b7054e836a931754caae578c5f2 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 2 May 2023 13:09:16 +0200 Subject: Removed cco_alive(), was same as !cco_done() --- docs/ccommon_api.md | 3 +-- include/stc/algo/coroutine.h | 1 - misc/examples/cointerleave.c | 6 +++--- misc/examples/coroutines.c | 46 ++++++++++++++++++++++---------------------- misc/examples/scheduler.c | 2 +- 5 files changed, 28 insertions(+), 30 deletions(-) (limited to 'misc/examples/coroutines.c') diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 27df13ce..407ddac4 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -354,9 +354,8 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c |:----------|:-------------------------------------|:----------------------------------------| | | `cco_final:` | Obligatory label in coroutine | | | `cco_return` | Early return from the coroutine (no arg) | -| `bool` | `cco_alive(ctx)` | Is coroutine in initial or suspended state? | -| `bool` | `cco_done(ctx)` | Is coroutine not alive? | | `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 (return void) | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 4b7bee5f..f6769162 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -63,7 +63,6 @@ enum cco_states { }; #define cco_suspended(ctx) ((ctx)->cco_state > 0) -#define cco_alive(ctx) ((ctx)->cco_state != cco_state_done) #define cco_done(ctx) ((ctx)->cco_state == cco_state_done) #define cco_begin(ctx) \ diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 64473d96..9ef7d561 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -29,13 +29,13 @@ struct Generator { bool interleaved(struct Generator* g) { cco_begin(g); - while (cco_alive(&g->x) || cco_alive(&g->y)) + while (!cco_done(&g->x) || !cco_done(&g->y)) { g->value = next_value(&g->x); - if (cco_alive(&g->x)) cco_yield(false); + if (!cco_done(&g->x)) cco_yield(false); g->value = next_value(&g->y); - if (cco_alive(&g->y)) cco_yield(false); + if (!cco_done(&g->y)) cco_yield(false); } cco_final: cco_end(true); diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index 3fddf913..bbe85874 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -17,20 +17,20 @@ struct prime { int cco_state; }; -bool prime(struct prime* U) { - cco_begin(U); - if (U->result < 2) U->result = 2; - if (U->result == 2) { - if (U->count-- == 0) cco_return; - ++U->idx; +bool prime(struct prime* g) { + cco_begin(g); + if (g->result < 2) g->result = 2; + if (g->result == 2) { + if (g->count-- == 0) cco_return; + ++g->idx; cco_yield(false); } - U->result += !(U->result & 1); - for (U->pos = U->result; U->count > 0; U->pos += 2) { - if (is_prime(U->pos)) { - --U->count; - ++U->idx; - U->result = U->pos; + g->result += !(g->result & 1); + for (g->pos = g->result; g->count > 0; g->pos += 2) { + if (is_prime(g->pos)) { + --g->count; + ++g->idx; + g->result = g->pos; cco_yield(false); } } @@ -48,20 +48,20 @@ struct fibonacci { int cco_state; }; -bool fibonacci(struct fibonacci* F) { - assert(F->count < 94); +bool fibonacci(struct fibonacci* g) { + assert(g->count < 94); - cco_begin(F); - F->idx = 0; - F->result = 0; - F->b = 1; + cco_begin(g); + g->idx = 0; + g->result = 0; + g->b = 1; for (;;) { - if (F->count-- == 0) + if (g->count-- == 0) cco_return; - if (++F->idx > 1) { - int64_t sum = F->result + F->b; // NB! locals only lasts until next cco_yield! - F->result = F->b; - F->b = sum; + if (++g->idx > 1) { + int64_t sum = g->result + g->b; // NB! locals only lasts until next cco_yield! + g->result = g->b; + g->b = sum; } cco_yield(false); } diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index 1809f2ec..db9c2716 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -19,7 +19,7 @@ static bool schedule(Scheduler* sched) struct Task task = *Scheduler_front(sched); Scheduler_pop_front(sched); - if (cco_alive(&task)) + if (!cco_done(&task)) task.resume(&task); return !Scheduler_empty(sched); -- cgit v1.2.3 From e4efe2f9cc87e70e981ee75ec5c4d6db4cb60c49 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 2 May 2023 23:11:20 +0200 Subject: Changed cco_with_..() API again, final. --- docs/ccommon_api.md | 16 ++++++++-------- include/stc/algo/coroutine.h | 29 +++++++++++++---------------- misc/examples/cointerleave.c | 13 +++++++------ misc/examples/coroutines.c | 26 ++++++++++++++------------ 4 files changed, 42 insertions(+), 42 deletions(-) (limited to 'misc/examples/coroutines.c') diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index f4a2c349..7014def8 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -358,18 +358,18 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | `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 (return void) | +| | `cco_end()` | End coroutine block | | | `cco_yield(retval)` | Suspend execution and return retval | -| | `cco_yield()` | Suspend execution (return void) | -| | `cco_await(promise)` | Suspend and return false until promise is true | -| | `cco_await_void(promise)` | Suspend until promise is true (return void) | -| | `cco_await_while(cond, retval)` | Suspend and return retval while cond is true | +| | `cco_yield()` | Suspend execution | +| | `cco_await(promise)` | Suspend until promise is true | +| | `cco_await_with(promise, retval)` | Suspend with retval until promise is true | | | Semaphores: | | -| | `cco_semaphore` | Semaphore type | -| | `cco_await_sem(sem)` | Await for the semaphore count > 0 | +| | `cco_semaphore` | Semaphore type | +| | `cco_await_sem(sem)` | Await for the semaphore count > 0 | +| | `cco_await_sem_with(sem, retval)` | Await with retval for the semaphore | | | `cco_signal_sem(sem)` | Signal the semaphore by increasing count| | | From caller side: | | -| `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | +| `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | | `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) | --- diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 5cadbc6a..ae9e4464 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -82,15 +82,13 @@ enum cco_states { case __LINE__:; \ } while (0) -#define cco_await_while(cond, retval) \ +#define cco_await(promise) cco_await_with(promise, ) +#define cco_await_with(promise, retval) \ do { \ *_state = __LINE__; \ - case __LINE__: if (cond) return retval; \ + case __LINE__: if (!(promise)) return retval; \ } while (0) -#define cco_await(promise) cco_await_while(!(promise), false) -#define cco_await_void(promise) cco_await_while(!(promise), ) - #define cco_final \ case cco_state_final: \ _cco_final_ @@ -118,22 +116,21 @@ typedef struct { /** * Wait for a semaphore * - * This macro carries out the "wait" operation on the semaphore. The - * wait operation causes the "thread" to block while the counter is - * zero. When the counter reaches a value larger than zero, the - * "thread" will continue. + * This macro carries out the "wait" operation on the semaphore, + * and causes the "thread" to block while the counter is zero. */ -#define cco_await_sem(sem) \ - do { \ - cco_await((sem)->count > 0); \ - --(sem)->count; \ - } while (0) +#define cco_await_sem(sem) cco_await_sem_with(sem, ) +#define cco_await_sem_with(sem, retval) \ + do { \ + cco_await_with((sem)->count > 0, retval); \ + --(sem)->count; \ + } while (0) /** * Signal a semaphore * - * This macro carries out the "signal" operation on the semaphore. The - * signal operation increments the counter inside the semaphore, which + * This macro carries out the "signal" operation on the semaphore, + * and increments the counter inside the semaphore, which * eventually will cause waiting "threads" to continue executing. */ #define cco_signal_sem(sem) ++(sem)->count diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 9ef7d561..5bdbd257 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -26,19 +26,19 @@ struct Generator { int value; }; -bool interleaved(struct Generator* g) +void interleaved(struct Generator* g) { cco_begin(g); while (!cco_done(&g->x) || !cco_done(&g->y)) { g->value = next_value(&g->x); - if (!cco_done(&g->x)) cco_yield(false); + if (!cco_done(&g->x)) cco_yield(); g->value = next_value(&g->y); - if (!cco_done(&g->y)) cco_yield(false); + if (!cco_done(&g->y)) cco_yield(); } cco_final: - cco_end(true); + cco_end(); } void Use(void) @@ -48,9 +48,10 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - while (!interleaved(&g)) - printf("%d\n", g.value); + while (interleaved(&g), !cco_done(&g)) + printf("%d ", g.value); + puts(""); c_drop(IVec, &a, &b); } diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index bbe85874..00cedd84 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -4,16 +4,17 @@ // Demonstrate to call another coroutine from a coroutine: // First create prime generator, then call fibonacci sequence: +typedef long long llong; bool is_prime(int64_t i) { - for (int64_t j=2; j*j <= i; ++j) + for (llong j=2; j*j <= i; ++j) if (i % j == 0) return false; return true; } struct prime { int count, idx; - int64_t result, pos; + llong result, pos; int cco_state; }; @@ -44,7 +45,7 @@ bool prime(struct prime* g) { struct fibonacci { int count, idx; - int64_t result, b; + llong result, b; int cco_state; }; @@ -59,7 +60,7 @@ bool fibonacci(struct fibonacci* g) { if (g->count-- == 0) cco_return; if (++g->idx > 1) { - int64_t sum = g->result + g->b; // NB! locals only lasts until next cco_yield! + llong sum = g->result + g->b; // NB! locals lasts only until next cco_yield/cco_await! g->result = g->b; g->b = sum; } @@ -81,13 +82,13 @@ struct combined { bool combined(struct combined* C) { cco_begin(C); - cco_await(prime(&C->prm)); - cco_await(fibonacci(&C->fib)); + cco_await_with(prime(&C->prm), false); + cco_await_with(fibonacci(&C->fib), false); // Reuse the C->prm context and extend the count: - C->prm.count = 8; C->prm.result += 2; + C->prm.count = 8, C->prm.result += 2; cco_reset(&C->prm); - cco_await(prime(&C->prm)); + cco_await_with(prime(&C->prm), false); cco_final: puts("final comb"); cco_end(true); @@ -95,10 +96,11 @@ bool combined(struct combined* C) { int main(void) { - struct combined comb = {.prm={.count=8}, .fib={14}}; + struct combined c = {.prm={.count=8}, .fib={14}}; - while (!combined(&comb)) + while (!combined(&c)) { printf("Prime(%d)=%lld, Fib(%d)=%lld\n", - comb.prm.idx, (long long)comb.prm.result, - comb.fib.idx, (long long)comb.fib.result); + c.prm.idx, c.prm.result, + c.fib.idx, c.fib.result); + } } -- cgit v1.2.3 From 6b23e35287f26dad63abd755c5f365b443e025a3 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 3 May 2023 16:45:37 +0200 Subject: Reverted from cco_await_with(promise, ret) to cco_await(promise, ret). --- include/stc/algo/coroutine.h | 15 +++++++++------ misc/examples/coread.c | 14 +++++++------- misc/examples/coroutines.c | 26 ++++++++++++++------------ 3 files changed, 30 insertions(+), 25 deletions(-) (limited to 'misc/examples/coroutines.c') diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index ae9e4464..89dd27f0 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -57,11 +57,12 @@ int main(void) { */ #include -enum cco_states { +enum { cco_state_final = -1, cco_state_done = -2, }; +#define cco_initial(ctx) ((ctx)->cco_state == 0) #define cco_suspended(ctx) ((ctx)->cco_state > 0) #define cco_done(ctx) ((ctx)->cco_state == cco_state_done) @@ -82,8 +83,9 @@ enum cco_states { case __LINE__:; \ } while (0) -#define cco_await(promise) cco_await_with(promise, ) -#define cco_await_with(promise, retval) \ +#define cco_await(...) c_MACRO_OVERLOAD(cco_await, __VA_ARGS__) +#define cco_await_1(promise) cco_await_2(promise, ) +#define cco_await_2(promise, retval) \ do { \ *_state = __LINE__; \ case __LINE__: if (!(promise)) return retval; \ @@ -119,10 +121,11 @@ typedef struct { * This macro carries out the "wait" operation on the semaphore, * and causes the "thread" to block while the counter is zero. */ -#define cco_await_sem(sem) cco_await_sem_with(sem, ) -#define cco_await_sem_with(sem, retval) \ +#define cco_await_sem(...) c_MACRO_OVERLOAD(cco_await_sem, __VA_ARGS__) +#define cco_await_sem_1(sem) cco_await_sem_2(sem, ) +#define cco_await_sem_2(sem, retval) \ do { \ - cco_await_with((sem)->count > 0, retval); \ + cco_await_2((sem)->count > 0, retval); \ --(sem)->count; \ } while (0) diff --git a/misc/examples/coread.c b/misc/examples/coread.c index d5385a87..38447c44 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -11,19 +11,19 @@ struct file_read { cstr line; }; -bool file_read(struct file_read* U) +bool file_read(struct file_read* g) { - cco_begin(U) - U->fp = fopen(U->filename, "r"); - U->line = cstr_init(); + cco_begin(g) + g->fp = fopen(g->filename, "r"); + g->line = cstr_init(); - while (cstr_getline(&U->line, U->fp)) + while (cstr_getline(&g->line, g->fp)) cco_yield(false); cco_final: // this label is required. printf("finish\n"); - cstr_drop(&U->line); - fclose(U->fp); + cstr_drop(&g->line); + fclose(g->fp); cco_end(true); } diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index 00cedd84..a5db3291 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -36,7 +36,7 @@ bool prime(struct prime* g) { } } cco_final: - printf("final prm\n"); + printf("final prm\n"); cco_end(true); } @@ -60,14 +60,15 @@ bool fibonacci(struct fibonacci* g) { if (g->count-- == 0) cco_return; if (++g->idx > 1) { - llong sum = g->result + g->b; // NB! locals lasts only until next cco_yield/cco_await! + // NB! locals lasts only until next cco_yield/cco_await! + llong sum = g->result + g->b; g->result = g->b; g->b = sum; } cco_yield(false); } cco_final: - printf("final fib\n"); + printf("final fib\n"); cco_end(true); } @@ -80,17 +81,18 @@ struct combined { }; -bool combined(struct combined* C) { - cco_begin(C); - cco_await_with(prime(&C->prm), false); - cco_await_with(fibonacci(&C->fib), false); +bool combined(struct combined* g) { + cco_begin(g); + cco_await(prime(&g->prm), false); + cco_await(fibonacci(&g->fib), false); - // Reuse the C->prm context and extend the count: - C->prm.count = 8, C->prm.result += 2; - cco_reset(&C->prm); - cco_await_with(prime(&C->prm), false); + // Reuse the g->prm context and extend the count: + g->prm.count = 8, g->prm.result += 2; + cco_reset(&g->prm); + cco_await(prime(&g->prm), false); - cco_final: puts("final comb"); + cco_final: + puts("final combined"); cco_end(true); } -- cgit v1.2.3 From b03148caa1d6fc660e6e7c5986dd6fd38779bedc Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 4 May 2023 11:51:56 +0200 Subject: Updates in coroutines.h: No longer *required* with cco_final:, but only when no cleanup is needed. --- docs/ccommon_api.md | 8 ++++---- include/stc/algo/coroutine.h | 14 ++++++-------- misc/examples/cointerleave.c | 8 ++++---- misc/examples/coread.c | 8 ++++---- misc/examples/coroutines.c | 6 +++--- misc/examples/generator.c | 32 +++++++++++++++--------------- misc/examples/scheduler.c | 2 -- misc/examples/triples.c | 46 +++++++++++++++++++++++--------------------- 8 files changed, 61 insertions(+), 63 deletions(-) (limited to 'misc/examples/coroutines.c') 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 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 #include +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}; -- cgit v1.2.3 From b909bee0e400fa12908bc3d9bca447ea2a71864b Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 8 May 2023 11:14:03 +0200 Subject: More coroutine updates. --- docs/ccommon_api.md | 7 ++++-- include/stc/algo/coroutine.h | 53 ++++++++++++++++++++++++++------------------ misc/examples/coroutines.c | 12 +++++----- 3 files changed, 42 insertions(+), 30 deletions(-) (limited to 'misc/examples/coroutines.c') diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index c20043f8..daf21e56 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -314,7 +314,7 @@ bool triples(struct triples* i) { // coroutine } } } - cco_final: // required for cleanup + cco_final: // tear down puts("done"); cco_end(true); } @@ -363,6 +363,8 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_yield(retval)` | Suspend execution and return retval | | | `cco_await(promise)` | Suspend until promise is true | | | `cco_await(promise, retval)` | Suspend with retval until promise is true | +| | `cco_call(ctx, corocall)` | Call coro async, suspend while not done | +| | `cco_call(ctx, corocall, retval)` | Call coro async, return retval on suspend | | | Semaphores: | | | | `csem` | Semaphore type | | | `cco_await_sem(sem)` | Await for the semaphore count > 0 | @@ -373,13 +375,14 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `ctimer` | Timer type | | | `cco_await_timer(tm)` | Await for timer to expire | | | `cco_await_timer(tm, retval)` | Await with retval for timer to expire | -| | `ctimer_start(tm, long msecs)` | Start timer for milliseconds | +| | `ctimer_start(tm, long msecs)` | Start timer msecs milliseconds | | | `ctimer_restart(tm)` | Restart timer with same duration | | `bool` | `ctimer_expired(tm)` | Return true if timer is expired | | `long` | `ctimer_remaining(tm)` | Return milliseconds remaining | | | From caller side: | | | `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` | | `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) | +| `void` | `cco_run_blocked(ctx, corocall) { }` | Call coro blocked until done | --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 80b96bbd..942abc5a 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -62,12 +62,12 @@ enum { cco_state_done = -2, }; -#define cco_initial(ctx) ((ctx)->cco_state == 0) -#define cco_suspended(ctx) ((ctx)->cco_state > 0) -#define cco_done(ctx) ((ctx)->cco_state == cco_state_done) +#define cco_initial(co) ((co)->cco_state == 0) +#define cco_suspended(co) ((co)->cco_state > 0) +#define cco_done(co) ((co)->cco_state == cco_state_done) -#define cco_begin(ctx) \ - int *_state = &(ctx)->cco_state; \ +#define cco_begin(co) \ + int *_state = &(co)->cco_state; \ goto _begin; _begin: switch (*_state) { \ case 0: @@ -90,21 +90,30 @@ enum { case __LINE__: if (!(promise)) return retval; \ } while (0) +#define cco_call(...) c_MACRO_OVERLOAD(cco_call, __VA_ARGS__) +#define cco_call_2(co, call) cco_call_3(co, call, ) +#define cco_call_3(co, call, retval) cco_await_2((call, cco_done(co)), retval) + +#define cco_run_blocked(co, call) while (call, !cco_done(co)) + #define cco_final \ case cco_state_final #define cco_return \ do { *_state = cco_state_final; goto _begin; } while (0) -#define cco_stop(ctx) \ +#define cco_return_v(value) \ + return (*_state = cco_state_final, value) + +#define cco_stop(co) \ do { \ - int* _state = &(ctx)->cco_state; \ + int* _state = &(co)->cco_state; \ if (*_state > 0) *_state = cco_state_final; \ } while (0) -#define cco_reset(ctx) \ +#define cco_reset(co) \ do { \ - int* _state = &(ctx)->cco_state; \ + int* _state = &(co)->cco_state; \ if (*_state == cco_state_done) *_state = 0; \ } while (0) @@ -151,28 +160,28 @@ typedef struct { } ctimer; #define cco_await_timer(...) c_MACRO_OVERLOAD(cco_await_timer, __VA_ARGS__) -#define cco_await_timer_2(t, msecs) cco_await_timer_3(t, msecs, ) -#define cco_await_timer_3(t, msecs, ret) \ +#define cco_await_timer_2(tm, msecs) cco_await_timer_3(tm, msecs, ) +#define cco_await_timer_3(tm, msecs, ret) \ do { \ - ctimer_start(t, msecs); \ - cco_await_2(ctimer_expired(t), ret); \ + ctimer_start(tm, msecs); \ + cco_await_2(ctimer_expired(tm), ret); \ } while (0) -static inline void ctimer_start(ctimer* t, long msecs) { - t->interval = msecs*(CLOCKS_PER_SEC/1000); - t->start = clock(); +static inline void ctimer_start(ctimer* tm, long msecs) { + tm->interval = msecs*(CLOCKS_PER_SEC/1000); + tm->start = clock(); } -static inline void ctimer_restart(ctimer* t) { - t->start = clock(); +static inline void ctimer_restart(ctimer* tm) { + tm->start = clock(); } -static inline bool ctimer_expired(ctimer* t) { - return clock() - t->start >= t->interval; +static inline bool ctimer_expired(ctimer* tm) { + return clock() - tm->start >= tm->interval; } -static inline long ctimer_remaining(ctimer* t) { - return (long)((double)(t->start + t->interval - clock())*(1000.0/CLOCKS_PER_SEC)); +static inline long ctimer_remaining(ctimer* tm) { + return (long)((double)(tm->start + tm->interval - clock())*(1000.0/CLOCKS_PER_SEC)); } #endif diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index 9071fee0..7f255dda 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -81,26 +81,26 @@ struct combined { }; -bool combined(struct combined* g) { +void combined(struct combined* g) { cco_begin(g); - cco_await(prime(&g->prm), false); - cco_await(fibonacci(&g->fib), false); + cco_await(prime(&g->prm)); + cco_await(fibonacci(&g->fib)); // Reuse the g->prm context and extend the count: g->prm.count = 8, g->prm.result += 2; cco_reset(&g->prm); - cco_await(prime(&g->prm), false); + cco_await(prime(&g->prm)); cco_final: puts("final combined"); - cco_end(true); + cco_end(); } int main(void) { struct combined c = {.prm={.count=8}, .fib={14}}; - while (!combined(&c)) { + cco_run_blocked(&c, combined(&c)) { printf("Prime(%d)=%lld, Fib(%d)=%lld\n", c.prm.idx, c.prm.result, c.fib.idx, c.fib.result); -- cgit v1.2.3 From 99d94309f31f082b505180d2cb7c1c6c2215e9f0 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Tue, 9 May 2023 04:40:24 +0200 Subject: reverted cco_await_done => cco_await_at. --- docs/ccommon_api.md | 10 +++++----- include/stc/algo/coroutine.h | 8 ++++---- include/stc/cpque.h | 5 +++-- misc/examples/cointerleave.c | 2 +- misc/examples/coread.c | 11 +++++------ misc/examples/coroutines.c | 2 +- misc/examples/scheduler.c | 12 ++++++------ 7 files changed, 25 insertions(+), 25 deletions(-) (limited to 'misc/examples/coroutines.c') diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 512aeb80..93ad2bb7 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -361,12 +361,12 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_end(ret)` | End coroutine block and return ret | | | `cco_yield()` | Yield/suspend execution | | | `cco_yield(ret)` | Yield/suspend execution and return ret | -| | `cco_yield_at(co, call)` | Yield next in co call, if not done | -| | `cco_yield_at(co, call, ret)` | Yield next in co call with ret | +| | `cco_yield_at(co, call)` | Yield at co call if it is suspended | +| | `cco_yield_at(co, call, ret)` | Yield at co call with ret if suspended | | | `cco_await(promise)` | Await/suspend until promise is true | | | `cco_await(promise, ret)` | Await/suspend with ret value | -| | `cco_await_done(co, call)` | Await for co call to finish | -| | `cco_await_done(co, call, ret)` | Await for co call to finish with ret | +| | `cco_await_at(co, call)` | Await for co call to finish | +| | `cco_await_at(co, call, ret)` | Await for co call to finish with ret | | | Semaphores: | | | | `csem` | Semaphore type | | | `cco_await_sem(sem)` | Await for the semaphore count > 0 | @@ -384,7 +384,7 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | From caller side: | | | `void` | `cco_stop(co)` | Next call of coroutine returns `cco_end()` | | `void` | `cco_reset(co)` | Reset state to initial (for reuse) | -| `void` | `cco_run_blocked(co, corocall) { }` | Call coro blocked until done | +| `void` | `cco_run(co, corocall) { }` | Run blocking until coro is done | --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 979e05bb..2ea7122b 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -95,11 +95,11 @@ enum { case __LINE__: if (!(promise)) return ret; \ } while (0) -#define cco_await_done(...) c_MACRO_OVERLOAD(cco_await_done, __VA_ARGS__) -#define cco_await_done_2(co, call) cco_await_done_3(co, call, ) -#define cco_await_done_3(co, call, ret) cco_await_2((call, cco_done(co)), ret) +#define cco_await_at(...) c_MACRO_OVERLOAD(cco_await_at, __VA_ARGS__) +#define cco_await_at_2(co, call) cco_await_at_3(co, call, ) +#define cco_await_at_3(co, call, ret) cco_await_2((call, cco_done(co)), ret) -#define cco_run_blocked(co, call) while (call, !cco_done(co)) +#define cco_run(co, call) while (call, !cco_done(co)) #define cco_final \ case cco_state_final diff --git a/include/stc/cpque.h b/include/stc/cpque.h index c76621cd..85002c67 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -36,7 +36,7 @@ typedef i_keyraw _cx_raw; STC_API void _cx_memb(_make_heap)(_cx_self* self); STC_API void _cx_memb(_erase_at)(_cx_self* self, intptr_t idx); -STC_API void _cx_memb(_push)(_cx_self* self, _cx_value value); +STC_API _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value value); STC_INLINE _cx_self _cx_memb(_init)(void) { return c_LITERAL(_cx_self){NULL}; } @@ -144,7 +144,7 @@ _cx_memb(_erase_at)(_cx_self* self, const intptr_t idx) { _cx_memb(_sift_down_)(self, idx + 1, n); } -STC_DEF void +STC_DEF _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value value) { if (self->_len == self->_cap) _cx_memb(_reserve)(self, self->_len*3/2 + 4); @@ -153,6 +153,7 @@ _cx_memb(_push)(_cx_self* self, _cx_value value) { for (; c > 1 && (i_less((&arr[c/2]), (&value))); c /= 2) arr[c] = arr[c/2]; arr[c] = value; + return arr + c; } #endif diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 0854a741..d725989f 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -43,7 +43,7 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - cco_run_blocked(&g, interleaved(&g)) { + cco_run(&g, interleaved(&g)) { printf("%d ", g.value); } puts(""); diff --git a/misc/examples/coread.c b/misc/examples/coread.c index 0073191b..e60fb31c 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -11,29 +11,28 @@ struct file_read { cstr line; }; -bool file_read(struct file_read* g) +void file_read(struct file_read* g) { cco_begin(g) g->fp = fopen(g->filename, "r"); g->line = cstr_init(); - while (cstr_getline(&g->line, g->fp)) - cco_yield(false); + cco_await(!cstr_getline(&g->line, g->fp)); cco_final: printf("finish\n"); cstr_drop(&g->line); fclose(g->fp); - cco_end(true); + cco_end(); } int main(void) { struct file_read g = {__FILE__}; int n = 0; - while (!file_read(&g)) + cco_run(&g, file_read(&g)) { printf("%3d %s\n", ++n, cstr_str(&g.line)); - //if (n == 10) cco_stop(&it); + //if (n == 10) cco_stop(&g); } } diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index 7f255dda..a7136993 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -100,7 +100,7 @@ int main(void) { struct combined c = {.prm={.count=8}, .fib={14}}; - cco_run_blocked(&c, combined(&c)) { + cco_run(&c, combined(&c)) { printf("Prime(%d)=%lld, Fib(%d)=%lld\n", c.prm.idx, c.prm.result, c.fib.idx, c.fib.result); diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index 04107d5e..bad5201b 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -25,7 +25,7 @@ static bool schedule(Scheduler* sched) return !Scheduler_empty(sched); } -static bool resume_task(const struct Task* task) +static bool push_task(const struct Task* task) { Scheduler_push_back(task->sched, *task); return false; @@ -36,11 +36,11 @@ static bool taskA(struct Task* task) { cco_begin(task); puts("Hello, from task A"); - cco_yield(resume_task(task)); + cco_yield(push_task(task)); puts("A is back doing work"); - cco_yield(resume_task(task)); + cco_yield(push_task(task)); puts("A is back doing more work"); - cco_yield(resume_task(task)); + cco_yield(push_task(task)); puts("A is back doing even more work"); cco_end(true); } @@ -49,9 +49,9 @@ static bool taskB(struct Task* task) { cco_begin(task); puts("Hello, from task B"); - cco_yield(resume_task(task)); + cco_yield(push_task(task)); puts("B is back doing work"); - cco_yield(resume_task(task)); + cco_yield(push_task(task)); puts("B is back doing more work"); cco_end(true); } -- cgit v1.2.3 From 276b8110033aa275f58ce60d096f220ca050738c Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 24 May 2023 16:21:22 +0200 Subject: coroutine.h: - Renamed Liigo's coroutine macro cco(x) => cco_routine(x). - Removed cco_begin(x), cco_end() macros. Replaced by cco_routine(x). - Replaced csleep_ms() with csleep_us(), using select() which is portable. - Updated all coroutine examples. --- docs/ccommon_api.md | 11 +++++----- include/stc/algo/coroutine.h | 49 +++++++++++++++----------------------------- misc/examples/cointerleave.c | 11 +++++----- misc/examples/coread.c | 3 ++- misc/examples/coroutines.c | 14 +++++++------ misc/examples/generator.c | 21 ++++++++++--------- misc/examples/scheduler.c | 10 +++++---- misc/examples/triples.c | 5 +++-- 8 files changed, 58 insertions(+), 66 deletions(-) (limited to 'misc/examples/coroutines.c') diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 5f6c82ed..beaad7e9 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -321,7 +321,7 @@ struct triples { }; bool triples(struct triples* i) { // coroutine - cco_begin(i); + cco_routine(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) { @@ -332,9 +332,10 @@ bool triples(struct triples* i) { // coroutine } } } - cco_final: // tear down + cco_final: puts("done"); - cco_end(true); + } + return true; } int gcd(int a, int b) { // greatest common denominator @@ -374,9 +375,7 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_return` | Early return from the coroutine (no arg) | | `bool` | `cco_suspended(co)` | Is coroutine in suspended state? | | `bool` | `cco_done(co)` | Is coroutine done? | -| | `cco_begin(co)` | Begin coroutine block | -| | `cco_end()` | End coroutine block | -| | `cco_end(ret)` | End coroutine block and return ret | +| | `cco_routine(co) { ... }` | The coroutine closure | | | `cco_yield()` | Yield/suspend execution | | | `cco_yield(ret)` | Yield/suspend execution and return ret | | | `cco_yield_coro(co, call)` | Yield at co call if it is suspended | diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 78dc80c6..ebfed613 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -26,31 +26,32 @@ #include #include -struct coroutine { +struct iterpair { int max_x, max_y; int x, y; int cco_state; // required member }; -bool coroutine(struct coroutine* I) { - cco_begin(I); +bool iterpair(struct iterpair* I) { + cco_routine(I) { for (I->x = 0; I->x < I->max_x; I->x++) for (I->y = 0; I->y < I->max_y; I->y++) cco_yield(false); - cco_final: // required if there is cleanup code + cco_final: // required if there is cleanup code puts("final"); - cco_end(true); + } + return true; // finished } int main(void) { - struct coroutine it = {.max_x=3, .max_y=3}; + struct iterpair it = {.max_x=3, .max_y=3}; int n = 0; - while (!coroutine(&it)) + while (!iterpair(&it)) { printf("%d %d\n", it.x, it.y); // example of early stop: - if (++n == 7) cco_stop(&it); // signal to stop at next + if (++n == 7) cco_stop(&it); // signal to stop/finalize in next } return 0; } @@ -66,19 +67,9 @@ enum { #define cco_suspended(co) ((co)->cco_state > 0) #define cco_done(co) ((co)->cco_state == cco_state_done) -#define cco_begin(co) \ - int *_state = &(co)->cco_state; \ - goto _begin; _begin: switch (*_state) { \ - case 0: - -#define cco_end(ret) \ - } \ - *_state = cco_state_done; \ - return ret - -#define cco(co) \ +#define cco_routine(co) \ for (int *_state = &(co)->cco_state, _once=1; _once; *_state = cco_state_done, _once=0) \ - _begin: switch (*_state) case 0: + _begin: switch (*_state) case 0: // thanks, @liigo! #define cco_yield(ret) \ do { \ @@ -96,7 +87,7 @@ enum { #define cco_await_2(promise, ret) \ do { \ *_state = __LINE__; \ - case __LINE__: if (!(promise)) return ret; \ + case __LINE__: if (!(promise)) {return ret; goto _begin;} \ } while (0) #define cco_await_coro(...) c_MACRO_OVERLOAD(cco_await_coro, __VA_ARGS__) @@ -150,18 +141,12 @@ typedef struct { */ #include +#include -#ifdef _WIN32 - static inline void csleep_ms(long msecs) { - extern void Sleep(unsigned long); - Sleep((unsigned long)msecs); - } -#elif _POSIX_C_SOURCE >= 199309L - static inline void csleep_ms(long msecs) { - struct timespec ts = {msecs/1000, 1000000*(msecs % 1000)}; - nanosleep(&ts, NULL); - } -#endif +static inline void csleep_us(int64_t usec) { + struct timeval tv = {.tv_sec=(int)(usec/1000000), .tv_usec=usec % 1000000}; + select(0, NULL, NULL, NULL, &tv); +} typedef struct { clock_t start; diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index e11b2bf3..42bf1d32 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -1,6 +1,6 @@ // https://www.youtube.com/watch?v=8sEe-4tig_A -#include #include +#include #define i_type IVec #define i_val int #include @@ -13,10 +13,11 @@ struct GenValue { static int get_value(struct GenValue* g) { - cco_begin(g); + cco_routine(g) { for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it)) cco_yield(*g->it.ref); - cco_end(0); + } + return -1; } struct Generator { @@ -27,13 +28,13 @@ struct Generator { void interleaved(struct Generator* g) { - cco_begin(g); + cco_routine(g) { while (!(cco_done(&g->x) & cco_done(&g->y))) { cco_yield_coro(&g->x, g->value = get_value(&g->x)); cco_yield_coro(&g->y, g->value = get_value(&g->y)); } - cco_end(); + } } void Use(void) diff --git a/misc/examples/coread.c b/misc/examples/coread.c index 1976231f..ef6cd6ee 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -1,3 +1,4 @@ +#define i_static #include #include #include @@ -13,7 +14,7 @@ struct file_read { void file_read(struct file_read* g) { - cco(g) { + cco_routine(g) { g->fp = fopen(g->filename, "r"); g->line = cstr_init(); diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index a7136993..040b8472 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -19,7 +19,7 @@ struct prime { }; bool prime(struct prime* g) { - cco_begin(g); + cco_routine(g) { if (g->result < 2) g->result = 2; if (g->result == 2) { if (g->count-- == 0) cco_return; @@ -37,7 +37,8 @@ bool prime(struct prime* g) { } cco_final: printf("final prm\n"); - cco_end(true); + } + return true; } @@ -52,7 +53,7 @@ struct fibonacci { bool fibonacci(struct fibonacci* g) { assert(g->count < 94); - cco_begin(g); + cco_routine(g) { g->idx = 0; g->result = 0; g->b = 1; @@ -69,7 +70,8 @@ bool fibonacci(struct fibonacci* g) { } cco_final: printf("final fib\n"); - cco_end(true); + } + return true; } // Combine @@ -82,7 +84,7 @@ struct combined { void combined(struct combined* g) { - cco_begin(g); + cco_routine(g) { cco_await(prime(&g->prm)); cco_await(fibonacci(&g->fib)); @@ -93,7 +95,7 @@ void combined(struct combined* g) { cco_final: puts("final combined"); - cco_end(); + } } int main(void) diff --git a/misc/examples/generator.c b/misc/examples/generator.c index 41dffafb..6b4b8407 100644 --- a/misc/examples/generator.c +++ b/misc/examples/generator.c @@ -15,13 +15,14 @@ typedef struct { } Triple_iter; void Triple_next(Triple_iter* it) { - Triple_value* t = it->ref; - cco_begin(it); - 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 (it->count++ == t->size) + Triple_value* g = it->ref; + cco_routine(it) + { + for (g->c = 5; g->size; ++g->c) { + for (g->a = 1; g->a < g->c; ++g->a) { + for (g->b = g->a; g->b < g->c; ++g->b) { + if (g->a*g->a + g->b*g->b == g->c*g->c) { + if (it->count++ == g->size) cco_return; cco_yield(); } @@ -30,11 +31,11 @@ void Triple_next(Triple_iter* it) { } cco_final: it->ref = NULL; - cco_end(); + } } -Triple_iter Triple_begin(Triple* t) { - Triple_iter it = {.ref=t}; +Triple_iter Triple_begin(Triple* g) { + Triple_iter it = {.ref=g}; Triple_next(&it); return it; } diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index 14c85f56..ea1414c7 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -34,7 +34,7 @@ static bool push_task(const struct Task* task) static bool taskA(struct Task* task) { - cco_begin(task); + cco_routine(task) { puts("Hello, from task A"); cco_yield(push_task(task)); puts("A is back doing work"); @@ -42,18 +42,20 @@ static bool taskA(struct Task* task) puts("A is back doing more work"); cco_yield(push_task(task)); puts("A is back doing even more work"); - cco_end(true); + } + return true; } static bool taskB(struct Task* task) { - cco_begin(task); + cco_routine(task) { puts("Hello, from task B"); cco_yield(push_task(task)); puts("B is back doing work"); cco_yield(push_task(task)); puts("B is back doing more work"); - cco_end(true); + } + return true; } void Use(void) diff --git a/misc/examples/triples.c b/misc/examples/triples.c index 183b7389..06142916 100644 --- a/misc/examples/triples.c +++ b/misc/examples/triples.c @@ -33,7 +33,7 @@ struct triples { }; bool triples_coro(struct triples* t) { - cco_begin(t); + cco_routine(t) { t->count = 0; for (t->c = 5; t->size; ++t->c) { for (t->a = 1; t->a < t->c; ++t->a) { @@ -48,7 +48,8 @@ bool triples_coro(struct triples* t) { } cco_final: puts("done"); - cco_end(true); + } + return true; } int main() -- cgit v1.2.3 From c51bdc8d8aeac63c0af955f81593ef0be326a7e0 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 13 Jun 2023 18:24:52 +0200 Subject: Missed an update --- misc/examples/coroutines.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'misc/examples/coroutines.c') diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index 040b8472..1e900fa1 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -102,7 +102,7 @@ int main(void) { struct combined c = {.prm={.count=8}, .fib={14}}; - cco_run(&c, combined(&c)) { + cco_block_on(&c, combined) { printf("Prime(%d)=%lld, Fib(%d)=%lld\n", c.prm.idx, c.prm.result, c.fib.idx, c.fib.result); -- cgit v1.2.3 From e25dec033773ab713a7593a923e2c83745be0b9a Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sun, 2 Jul 2023 22:01:46 +0200 Subject: Update in coroutine API. cco_yield, cco_await, cco_await_on, cco_block_on has changed. cco_final: renamed => cco_cleanup: Reverted i_retain template param back to => i_more. --- docs/ccommon_api.md | 62 +++++++++++------- include/stc/algo/coroutine.h | 120 ++++++++++++++++++++-------------- include/stc/algo/sort.h | 2 +- include/stc/cdeq.h | 6 +- include/stc/priv/template2.h | 4 +- misc/benchmarks/various/csort_bench.c | 2 +- misc/examples/cointerleave.c | 11 ++-- misc/examples/coread.c | 7 +- misc/examples/coroutines.c | 54 +++++++-------- misc/examples/dining_philosophers.c | 16 +++-- misc/examples/generator.c | 5 +- misc/examples/scheduler.c | 34 +++++----- misc/examples/triples.c | 10 +-- 13 files changed, 189 insertions(+), 144 deletions(-) (limited to 'misc/examples/coroutines.c') diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index c9c65156..b30bdda6 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -222,11 +222,11 @@ int main() { } ``` Containers with random access may also be sorted. Even sorting cdeq/cqueue (with ring buffer) is -possible and very fast. Note that `i_retain` must be defined to retain specified template parameters for use by sort: +possible and very fast. Note that `i_more` must be defined to retain specified template parameters for use by sort: ```c #define i_type MyDeq #define i_val int -#define i_retain +#define i_more #include // deque #include #include @@ -313,6 +313,7 @@ the gcd() function. It also ensures that it stops when the diagonal size >= 100: [ [Run this code](https://godbolt.org/z/coqqrfbd5) ] ```c #include +#include struct triples { int n; // input: max number of triples to be generated. @@ -320,22 +321,23 @@ struct triples { int cco_state; // required member }; -bool triples(struct triples* i) { // coroutine +int triples(struct triples* i) { // coroutine cco_routine(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) { - cco_yield(false); - if (--i->n == 0) cco_return; + cco_yield(); + if (--i->n == 0) + cco_return; } } } } - cco_final: + cco_cleanup: puts("done"); } - return true; + return 0; } int gcd(int a, int b) { // greatest common denominator @@ -352,7 +354,7 @@ int main() struct triples t = {.n=INT32_MAX}; int n = 0; - while (!triples(&t)) { + while (triples(&t)) { // Skip triples with GCD(a,b) > 1 if (gcd(t.a, t.b) > 1) continue; @@ -366,28 +368,36 @@ int main() } ``` ### Coroutine API -**Note**: *cco_yield()* may not be called inside a `switch` statement. Use `if-else-if` constructs instead. -To resume the coroutine from where it was suspended with *cco_yield()*, simply call the coroutine again. +To resume the coroutine from where it was suspended with *cco_yield()*: call the coroutine again. + +**Note**: *cco_yield()* / *cco_await()* may not be called inside a `switch` statement; either use +`if-else-if` constructs, or `cco_switch / cco_case / cco_default` for switch-emulation instead. | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| -| | `cco_final:` | Label for cleanup in coroutine | +| | Function / 'keywords': | | +|`cco_result` | Enum `CCO_DONE=0`, `CCO_YIELD`, `CCO_AWAIT` | Recommended return values in coroutines | +| | Function / 'keywords': | | +| | `cco_cleanup:` | Label for cleanup position in coroutine | | `bool` | `cco_done(co)` | Is coroutine done? | -| | `cco_routine(co) { ... }` | The coroutine closure | -| | `cco_yield()` | Yield/suspend execution | -| | `cco_yield(ret)` | Yield/suspend execution and return ret | -| | `cco_await(promise)` | Await/suspend until promise is true | -| | `cco_await(promise, ret)` | Await/suspend with ret value | -| | `cco_return` | Replaces return. Jump to cco_final: if exist| -| | `cco_return_v(val)` | Yield final value, enter final-state | -| | `cco_closure(Ret, Closure, ...)` | Define coroutine closure struct. | -| `void` | `cco_await_on(closure) { }` | Await on closure to finish | -| `void` | `cco_await_on(co, func) { }` | Await on func(co) to finish | +| | `cco_routine(co) { }` | The coroutine scope | +| | `cco_yield();` | Yield/suspend execution (return CCO_YIELD)| +| | `cco_yield_v();` | Yield/suspend execution (return void) | +| | `cco_yield_v(ret);` | Yield/suspend execution (return ret) | +| | `cco_yield_final();` | Yield final time, enables cleanup-state | +| | `cco_yield_final(val);` | Yield a final value (e.g. CCO_ERROR) | +| | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)| +| | `cco_await_v(condition);` | Suspend until condition is true (return void) | +| | `cco_await_v(condition, ret);` | Suspend until condition is true (return ret)| +| | `cco_await_on(cocall);` | Await on sub-coroutine to finish | +| | `cco_return;` | Return from coroutine (inside cco_routine) | +| | `cco_closure(Closure, ...);` | Define a coroutine closure struct (optional) | | | Semaphores: | | | | `cco_sem` | Semaphore type | +| `cco_sem` | `cco_sem_from(long value)` | Create semaphore | +| | `cco_sem_set(sem, long value)` | Set semaphore value | | | `cco_sem_await(sem)` | Await for the semaphore count > 0 | | | `cco_sem_await(sem, ret)` | Await with ret on the semaphore | -| `cco_sem` | `cco_sem_init(long value)` | Set semaphore value | | | `cco_sem_release(sem)` | Signal the semaphore (count += 1) | | | Timers: | | | | `cco_timer` | Timer type | @@ -401,11 +411,15 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | From caller side: | | | `void` | `cco_stop(co)` | Next call of coroutine finalizes | | `void` | `cco_reset(co)` | Reset state to initial (for reuse) | -| `void` | `cco_block_on(closure) { }` | Run blocking until closure is finished | -| `void` | `cco_block_on(co, func) { }` | Run blocking until func is finished | +| `void` | `cco_block_on(cocall) { }` | Run blocking until cocall is finished | +| `void` | `cco_block_on(cocall, int *result) { }`| Run blocking until cocall is finished | | | Time functions: | | | `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | | | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | +| | Emulate switch: | | +| | `cco_switch(x) { }` | Like switch syntax | +| | `cco_case(val) { }` | Braces are required. Fall-through if no break; | +| | `cco_default { }` | Default action | --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index e20fd8ad..198b0439 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -32,22 +32,22 @@ struct iterpair { int cco_state; // required member }; -bool iterpair(struct iterpair* I) { +int iterpair(struct iterpair* I) { cco_routine(I) { for (I->x = 0; I->x < I->max_x; I->x++) for (I->y = 0; I->y < I->max_y; I->y++) - cco_yield(false); + cco_yield(); - cco_final: // required if there is cleanup code + cco_cleanup: // required if there is cleanup code puts("final"); } - return true; // finished + return 0; // CCO_DONE } int main(void) { struct iterpair it = {.max_x=3, .max_y=3}; int n = 0; - while (!iterpair(&it)) + while (iterpair(&it)) { printf("%d %d\n", it.x, it.y); // example of early stop: @@ -59,12 +59,19 @@ int main(void) { #include "../ccommon.h" enum { - cco_state_final = -1, - cco_state_done = -2, + CCO_STATE_CLEANUP = -1, + CCO_STATE_DONE = -2, }; +typedef enum { + CCO_DONE = 0, + CCO_YIELD = 1, + CCO_AWAIT = 2, + CCO_ERROR = -1, +} cco_result; #define cco_initial(co) ((co)->cco_state == 0) -#define cco_done(co) ((co)->cco_state == cco_state_done) +#define cco_suspended(co) ((co)->cco_state > 0) +#define cco_done(co) ((co)->cco_state == CCO_STATE_DONE) /* Emulate switch in coro: always use { } after cco_case(val) and cco_default. */ #define cco_switch(x) for (long long _sw = (long long)(x), _b=0; !_b; _b=1) @@ -72,83 +79,97 @@ enum { #define cco_default #define cco_routine(co) \ - for (int *_state = &(co)->cco_state; *_state != cco_state_done; *_state = cco_state_done) \ + for (int *_state = &(co)->cco_state; *_state != CCO_STATE_DONE; *_state = CCO_STATE_DONE) \ _resume: switch (*_state) case 0: // thanks, @liigo! -#define cco_yield(ret) \ +#define cco_yield() cco_yield_v(CCO_YIELD) +#define cco_yield_v(ret) \ do { \ *_state = __LINE__; return ret; goto _resume; \ case __LINE__:; \ } while (0) -#define cco_await(...) c_MACRO_OVERLOAD(cco_await, __VA_ARGS__) -#define cco_await_1(promise) cco_await_2(promise, ) -#define cco_await_2(promise, ret) \ +#define cco_await(promise) cco_await_v_2(promise, CCO_AWAIT) +#define cco_await_v(...) c_MACRO_OVERLOAD(cco_await_v, __VA_ARGS__) +#define cco_await_v_1(promise) cco_await_v_2(promise, ) +#define cco_await_v_2(promise, ret) \ do { \ *_state = __LINE__; \ case __LINE__: if (!(promise)) {return ret; goto _resume;} \ } while (0) -#define cco_closure(Ret, Closure, ...) \ - struct Closure { \ - Ret (*cco_fn)(struct Closure*); \ - int cco_state; \ - __VA_ARGS__ \ - } - -typedef struct cco_base { - void (*cco_fn)(struct cco_base*); - int cco_state; -} cco_base; - -#define cco_base_cast(closure) \ - ((cco_base *)(closure) + 0*sizeof((cco_resume(closure), (int*)0 == &(closure)->cco_state))) - -#define cco_resume(closure) (closure)->cco_fn(closure) -#define cco_await_on(...) c_MACRO_OVERLOAD(cco_await_on, __VA_ARGS__) -#define cco_await_on_1(closure) cco_await_2((cco_resume(closure), cco_done(closure)), ) -#define cco_await_on_2(co, func) cco_await_2((func(co), cco_done(co)), ) +/* cco_await_on(): assumes coroutine returns a cco_result value (int) */ +#define cco_await_on(corocall) \ + do { \ + *_state = __LINE__; \ + case __LINE__: { int _r = corocall; if (_r != CCO_DONE) {return _r; goto _resume;} } \ + } while (0) +/* cco_block_on(): assumes coroutine returns a cco_result value (int) */ #define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__) -#define cco_block_on_1(closure) while (cco_resume(closure), !cco_done(closure)) -#define cco_block_on_2(co, func) while (func(co), !cco_done(co)) +#define cco_block_on_1(corocall) while (corocall != CCO_DONE) +#define cco_block_on_2(corocall, res) while ((*(res) = (corocall)) != CCO_DONE) -#define cco_final \ - *_state = cco_state_final; case cco_state_final +#define cco_cleanup \ + *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP #define cco_return \ do { \ - *_state = *_state >= 0 ? cco_state_final : cco_state_done; \ + *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ goto _resume; \ } while (0) -#define cco_return_v(value) \ +#define cco_yield_final() cco_yield_final_v(CCO_YIELD) +#define cco_yield_final_v(value) \ do { \ - *_state = *_state >= 0 ? cco_state_final : cco_state_done; \ + *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ return value; \ } while (0) #define cco_stop(co) \ do { \ int* _s = &(co)->cco_state; \ - if (*_s > 0) *_s = cco_state_final; \ - else if (*_s == 0) *_s = cco_state_done; \ + if (*_s > 0) *_s = CCO_STATE_CLEANUP; \ + else if (*_s == 0) *_s = CCO_STATE_DONE; \ } while (0) #define cco_reset(co) \ (void)((co)->cco_state = 0) +/* + * Closure (optional) + */ + +#define cco_closure(Name, ...) \ + struct Name { \ + int (*cco_fn)(struct Name*); \ + int cco_state; \ + __VA_ARGS__ \ + } + +typedef struct cco_base { + int (*cco_fn)(struct cco_base*); + int cco_state; +} cco_base; + +#define cco_resume(closure) \ + (closure)->cco_fn(closure) + +#define cco_cast(closure) \ + ((cco_base *)(closure) + 0*sizeof((cco_resume(closure), (int*)0 == &(closure)->cco_state))) + /* * Semaphore */ typedef struct { intptr_t count; } cco_sem; -#define cco_sem_await(...) c_MACRO_OVERLOAD(cco_sem_await, __VA_ARGS__) -#define cco_sem_await_1(sem) cco_sem_await_2(sem, ) -#define cco_sem_await_2(sem, ret) \ +#define cco_sem_await(sem) cco_sem_await_v_2(sem, CCO_AWAIT) +#define cco_sem_await_v(...) c_MACRO_OVERLOAD(cco_sem_await_v, __VA_ARGS__) +#define cco_sem_await_v_1(sem) cco_sem_await_v_2(sem, ) +#define cco_sem_await_v_2(sem, ret) \ do { \ - cco_await_2((sem)->count > 0, ret); \ + cco_await_v_2((sem)->count > 0, ret); \ --(sem)->count; \ } while (0) @@ -197,12 +218,13 @@ typedef struct { intptr_t count; } cco_sem; typedef struct { double interval, start; } cco_timer; -#define cco_timer_await(...) c_MACRO_OVERLOAD(cco_timer_await, __VA_ARGS__) -#define cco_timer_await_2(tm, sec) cco_timer_await_3(tm, sec, ) -#define cco_timer_await_3(tm, sec, ret) \ +#define cco_timer_await(tm, sec) cco_timer_await_v_3(tm, sec, CCO_AWAIT) +#define cco_timer_await_v(...) c_MACRO_OVERLOAD(cco_timer_await_v, __VA_ARGS__) +#define cco_timer_await_v_2(tm, sec) cco_timer_await_v_3(tm, sec, ) +#define cco_timer_await_v_3(tm, sec, ret) \ do { \ cco_timer_start(tm, sec); \ - cco_await_2(cco_timer_expired(tm), ret); \ + cco_await_v_2(cco_timer_expired(tm), ret); \ } while (0) static inline void cco_timer_start(cco_timer* tm, double sec) { diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h index 002e6499..8365ccc5 100644 --- a/include/stc/algo/sort.h +++ b/include/stc/algo/sort.h @@ -44,7 +44,7 @@ int main() { // ex2: #define i_val int #define i_type IDeq -#define i_retain // retain input template params to be reused by sort.h +#define i_more // retain input template params to be reused by sort.h #include #include diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 2db040f1..bac40f90 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -23,11 +23,11 @@ #define _i_prefix cdeq_ #define _pop _pop_front #define _pull _pull_front -#ifdef i_retain +#ifdef i_more #include "cqueue.h" - #define i_retain + #define i_more #else - #define i_retain + #define i_more #include "cqueue.h" #endif #undef _pop diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h index bd8bc5fc..def5d01e 100644 --- a/include/stc/priv/template2.h +++ b/include/stc/priv/template2.h @@ -20,8 +20,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifdef i_retain -#undef i_retain +#ifdef i_more +#undef i_more #else #undef i_type #undef i_tag diff --git a/misc/benchmarks/various/csort_bench.c b/misc/benchmarks/various/csort_bench.c index 93034dde..d434693f 100644 --- a/misc/benchmarks/various/csort_bench.c +++ b/misc/benchmarks/various/csort_bench.c @@ -8,7 +8,7 @@ #define NDEBUG #define i_type Ints #define i_val int -#define i_retain +#define i_more #include #include diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c index 1ba7b861..61562a5f 100644 --- a/misc/examples/cointerleave.c +++ b/misc/examples/cointerleave.c @@ -15,7 +15,7 @@ static int get_value(struct GenValue* g) { cco_routine(g) { for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it)) - cco_yield(*g->it.ref); + cco_yield_v(*g->it.ref); } return -1; } @@ -26,10 +26,10 @@ struct Generator { int value; }; -void interleaved(struct Generator* g) +cco_result interleaved(struct Generator* g) { cco_routine(g) { - do { + while (!(cco_done(&g->x) & cco_done(&g->y))) { g->value = get_value(&g->x); if (!cco_done(&g->x)) cco_yield(); @@ -37,8 +37,9 @@ void interleaved(struct Generator* g) g->value = get_value(&g->y); if (!cco_done(&g->y)) cco_yield(); - } while (!(cco_done(&g->x) & cco_done(&g->y))); + } } + return CCO_DONE; } void Use(void) @@ -48,7 +49,7 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - cco_block_on(&g, interleaved) { + cco_block_on(interleaved(&g)) { printf("%d ", g.value); } puts(""); diff --git a/misc/examples/coread.c b/misc/examples/coread.c index 622228c0..a13f6be5 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -12,7 +12,7 @@ struct file_read { cstr line; }; -void file_read(struct file_read* g) +int file_read(struct file_read* g) { cco_routine(g) { g->fp = fopen(g->filename, "r"); @@ -21,18 +21,19 @@ void file_read(struct file_read* g) cco_await(!cstr_getline(&g->line, g->fp)); - cco_final: + cco_cleanup: printf("finish\n"); cstr_drop(&g->line); if (g->fp) fclose(g->fp); } + return 0; } int main(void) { struct file_read g = {__FILE__}; int n = 0; - cco_block_on(&g, file_read) + cco_block_on(file_read(&g)) { printf("%3d %s\n", ++n, cstr_str(&g.line)); //if (n == 10) cco_stop(&g); diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c index 1e900fa1..b8dfaa13 100644 --- a/misc/examples/coroutines.c +++ b/misc/examples/coroutines.c @@ -4,27 +4,26 @@ // Demonstrate to call another coroutine from a coroutine: // First create prime generator, then call fibonacci sequence: -typedef long long llong; -bool is_prime(int64_t i) { - for (llong j=2; j*j <= i; ++j) +bool is_prime(long long i) { + for (long long j=2; j*j <= i; ++j) if (i % j == 0) return false; return true; } struct prime { int count, idx; - llong result, pos; + long long result, pos; int cco_state; }; -bool prime(struct prime* g) { +int prime(struct prime* g) { cco_routine(g) { if (g->result < 2) g->result = 2; if (g->result == 2) { if (g->count-- == 0) cco_return; ++g->idx; - cco_yield(false); + cco_yield(); } g->result += !(g->result & 1); for (g->pos = g->result; g->count > 0; g->pos += 2) { @@ -32,13 +31,13 @@ bool prime(struct prime* g) { --g->count; ++g->idx; g->result = g->pos; - cco_yield(false); + cco_yield(); } } - cco_final: + cco_cleanup: printf("final prm\n"); } - return true; + return 0; } @@ -46,13 +45,14 @@ bool prime(struct prime* g) { struct fibonacci { int count, idx; - llong result, b; + long long result, b; int cco_state; }; -bool fibonacci(struct fibonacci* g) { +int fibonacci(struct fibonacci* g) { assert(g->count < 94); + long long sum; cco_routine(g) { g->idx = 0; g->result = 0; @@ -61,17 +61,17 @@ bool fibonacci(struct fibonacci* g) { if (g->count-- == 0) cco_return; if (++g->idx > 1) { - // NB! locals lasts only until next cco_yield/cco_await! - llong sum = g->result + g->b; + // NB! locals lasts only until next yield/await! + sum = g->result + g->b; g->result = g->b; g->b = sum; } - cco_yield(false); + cco_yield(); } - cco_final: + cco_cleanup: printf("final fib\n"); } - return true; + return 0; } // Combine @@ -82,29 +82,31 @@ struct combined { int cco_state; }; - -void combined(struct combined* g) { +int combined(struct combined* g) { cco_routine(g) { - cco_await(prime(&g->prm)); - cco_await(fibonacci(&g->fib)); + cco_await_on(prime(&g->prm)); + cco_await_on(fibonacci(&g->fib)); // Reuse the g->prm context and extend the count: g->prm.count = 8, g->prm.result += 2; cco_reset(&g->prm); - cco_await(prime(&g->prm)); + cco_await_on(prime(&g->prm)); - cco_final: + cco_cleanup: puts("final combined"); } + return 0; } int main(void) { struct combined c = {.prm={.count=8}, .fib={14}}; + int res; - cco_block_on(&c, combined) { - printf("Prime(%d)=%lld, Fib(%d)=%lld\n", - c.prm.idx, c.prm.result, - c.fib.idx, c.fib.result); + cco_block_on(combined(&c), &res) { + if (res == CCO_YIELD) + printf("Prime(%d)=%lld, Fib(%d)=%lld\n", + c.prm.idx, c.prm.result, + c.fib.idx, c.fib.result); } } diff --git a/misc/examples/dining_philosophers.c b/misc/examples/dining_philosophers.c index e13eb055..61fe67fb 100644 --- a/misc/examples/dining_philosophers.c +++ b/misc/examples/dining_philosophers.c @@ -27,7 +27,7 @@ struct Dining { // Philosopher coroutine -void philosopher(struct Philosopher* p) +int philosopher(struct Philosopher* p) { double duration; cco_routine(p) { @@ -48,14 +48,15 @@ void philosopher(struct Philosopher* p) cco_sem_release(p->right_fork); } - cco_final: + cco_cleanup: printf("Philosopher %d finished\n", p->id); } + return 0; } // Dining coroutine -void dining(struct Dining* d) +int dining(struct Dining* d) { cco_routine(d) { for (int i = 0; i < num_forks; ++i) @@ -68,20 +69,21 @@ void dining(struct Dining* d) } while (1) { - // per-"frame" logic update of all philosophers states + // per-"frame" logic resume each philosopher for (int i = 0; i < num_philosophers; ++i) { philosopher(&d->ph[i]); } cco_yield(); // suspend, return control back to main } - cco_final: + cco_cleanup: for (int i = 0; i < num_philosophers; ++i) { cco_stop(&d->ph[i]); philosopher(&d->ph[i]); } puts("Dining finished"); } + return 0; } int main() @@ -89,13 +91,13 @@ int main() struct Dining dine; cco_reset(&dine); int n=0; - cco_timer tm = cco_timer_from(10.0); // seconds + cco_timer tm = cco_timer_from(15.0); // seconds csrand((uint64_t)time(NULL)); while (!cco_done(&dine)) { if (cco_timer_expired(&tm)) cco_stop(&dine); - dining(&dine); + dining(&dine); // resume cco_sleep(0.001); ++n; } diff --git a/misc/examples/generator.c b/misc/examples/generator.c index 6b4b8407..3ff7a645 100644 --- a/misc/examples/generator.c +++ b/misc/examples/generator.c @@ -14,7 +14,7 @@ typedef struct { int cco_state; } Triple_iter; -void Triple_next(Triple_iter* it) { +int Triple_next(Triple_iter* it) { Triple_value* g = it->ref; cco_routine(it) { @@ -29,9 +29,10 @@ void Triple_next(Triple_iter* it) { } } } - cco_final: + cco_cleanup: it->ref = NULL; } + return 0; } Triple_iter Triple_begin(Triple* g) { diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c index 04f7ba4a..c1168850 100644 --- a/misc/examples/scheduler.c +++ b/misc/examples/scheduler.c @@ -2,9 +2,11 @@ #include #include -cco_closure(bool, Task, +struct Task { + int (*fn)(struct Task*); + int cco_state; struct Scheduler* sched; -); +}; #define i_type Scheduler #define i_val struct Task @@ -16,49 +18,49 @@ static bool schedule(Scheduler* sched) Scheduler_pop(sched); if (!cco_done(&task)) - cco_resume(&task); + task.fn(&task); return !Scheduler_empty(sched); } -static bool push_task(const struct Task* task) +static int push_task(const struct Task* task) { Scheduler_push(task->sched, *task); - return false; + return CCO_YIELD; } -static bool taskA(struct Task* task) +static int taskA(struct Task* task) { cco_routine(task) { puts("Hello, from task A"); - cco_yield(push_task(task)); + cco_yield_v(push_task(task)); puts("A is back doing work"); - cco_yield(push_task(task)); + cco_yield_v(push_task(task)); puts("A is back doing more work"); - cco_yield(push_task(task)); + cco_yield_v(push_task(task)); puts("A is back doing even more work"); } - return true; + return 0; } -static bool taskB(struct Task* task) +static int taskB(struct Task* task) { cco_routine(task) { puts("Hello, from task B"); - cco_yield(push_task(task)); + cco_yield_v(push_task(task)); puts("B is back doing work"); - cco_yield(push_task(task)); + cco_yield_v(push_task(task)); puts("B is back doing more work"); } - return true; + return 0; } void Use(void) { Scheduler scheduler = c_init(Scheduler, { - {.cco_fn=taskA, .sched=&scheduler}, - {.cco_fn=taskB, .sched=&scheduler}, + {.fn=taskA, .sched=&scheduler}, + {.fn=taskB, .sched=&scheduler}, }); while (schedule(&scheduler)) {} diff --git a/misc/examples/triples.c b/misc/examples/triples.c index 17e3d40b..a8ca6b47 100644 --- a/misc/examples/triples.c +++ b/misc/examples/triples.c @@ -32,7 +32,7 @@ struct triples { int cco_state; }; -void triples_coro(struct triples* t) { +int triples_coro(struct triples* t) { cco_routine(t) { t->count = 0; for (t->c = 5; t->size; ++t->c) { @@ -46,9 +46,10 @@ void triples_coro(struct triples* t) { } } } - cco_final: + cco_cleanup: puts("done"); } + return 0; } int main() @@ -57,11 +58,10 @@ int main() triples_vanilla(5); puts("\nCoroutine triples:"); - struct triples t = {INT32_MAX}; + struct triples t = {.size=INT32_MAX}; int n = 0; - while (!cco_done(&t)) { - triples_coro(&t); + while (triples_coro(&t)) { if (gcd(t.a, t.b) > 1) continue; if (t.c < 100) -- cgit v1.2.3 From 900295256d825fc323149cd223c49787f32a3696 Mon Sep 17 00:00:00 2001 From: tylov Date: Thu, 20 Jul 2023 15:09:10 +0200 Subject: Moved examples to sub-directories. Added cotask1.c cotask2.c examples. --- misc/examples/algorithms/forfilter.c | 149 +++++++++++++++++ misc/examples/algorithms/forloops.c | 69 ++++++++ misc/examples/algorithms/random.c | 45 ++++++ misc/examples/algorithms/shape.c | 158 ++++++++++++++++++ misc/examples/algorithms/shape.cpp | 122 ++++++++++++++ misc/examples/arc_containers.c | 81 ---------- misc/examples/arc_demo.c | 62 -------- misc/examples/arcvec_erase.c | 50 ------ misc/examples/astar.c | 174 -------------------- misc/examples/birthday.c | 68 -------- misc/examples/bits.c | 66 -------- misc/examples/bits2.c | 41 ----- misc/examples/bitsets/bits.c | 66 ++++++++ misc/examples/bitsets/bits2.c | 41 +++++ misc/examples/bitsets/prime.c | 56 +++++++ misc/examples/books.c | 62 -------- misc/examples/box.c | 69 -------- misc/examples/box2.c | 82 ---------- misc/examples/cointerleave.c | 62 -------- misc/examples/complex.c | 49 ------ misc/examples/convert.c | 57 ------- misc/examples/coread.c | 41 ----- misc/examples/coroutines.c | 112 ------------- misc/examples/coroutines/cointerleave.c | 62 ++++++++ misc/examples/coroutines/coread.c | 41 +++++ misc/examples/coroutines/coroutines.c | 112 +++++++++++++ misc/examples/coroutines/cotasks1.c | 100 ++++++++++++ misc/examples/coroutines/cotasks2.c | 103 ++++++++++++ misc/examples/coroutines/dining_philosophers.c | 105 ++++++++++++ misc/examples/coroutines/generator.c | 55 +++++++ misc/examples/coroutines/scheduler.c | 74 +++++++++ misc/examples/coroutines/triples.c | 72 +++++++++ misc/examples/csmap_erase.c | 82 ---------- misc/examples/csmap_find.c | 73 --------- misc/examples/csmap_insert.c | 108 ------------- misc/examples/csset_erase.c | 41 ----- misc/examples/cstr_match.c | 26 --- misc/examples/demos.c | 194 ----------------------- misc/examples/dining_philosophers.c | 105 ------------ misc/examples/forfilter.c | 149 ----------------- misc/examples/forloops.c | 69 -------- misc/examples/functor.c | 57 ------- misc/examples/gauss2.c | 45 ------ misc/examples/generator.c | 55 ------- misc/examples/hashmap.c | 50 ------ misc/examples/hashmaps/birthday.c | 68 ++++++++ misc/examples/hashmaps/books.c | 62 ++++++++ misc/examples/hashmaps/hashmap.c | 50 ++++++ misc/examples/hashmaps/new_map.c | 75 +++++++++ misc/examples/hashmaps/phonebook.c | 72 +++++++++ misc/examples/hashmaps/unordered_set.c | 45 ++++++ misc/examples/hashmaps/vikings.c | 59 +++++++ misc/examples/inits.c | 108 ------------- misc/examples/intrusive.c | 33 ---- misc/examples/linkedlists/intrusive.c | 33 ++++ misc/examples/linkedlists/list.c | 64 ++++++++ misc/examples/linkedlists/list_erase.c | 30 ++++ misc/examples/linkedlists/list_splice.c | 38 +++++ misc/examples/linkedlists/new_list.c | 70 ++++++++ misc/examples/list.c | 64 -------- misc/examples/list_erase.c | 30 ---- misc/examples/list_splice.c | 38 ----- misc/examples/lower_bound.c | 66 -------- misc/examples/make.sh | 18 ++- misc/examples/mapmap.c | 64 -------- misc/examples/mixed/astar.c | 174 ++++++++++++++++++++ misc/examples/mixed/complex.c | 49 ++++++ misc/examples/mixed/convert.c | 57 +++++++ misc/examples/mixed/demos.c | 194 +++++++++++++++++++++++ misc/examples/mixed/inits.c | 108 +++++++++++++ misc/examples/mixed/read.c | 27 ++++ misc/examples/mmap.c | 65 -------- misc/examples/multidim.c | 67 -------- misc/examples/multimap.c | 102 ------------ misc/examples/music_arc.c | 67 -------- misc/examples/new_list.c | 70 -------- misc/examples/new_map.c | 75 --------- misc/examples/new_pque.c | 22 --- misc/examples/new_queue.c | 47 ------ misc/examples/new_smap.c | 67 -------- misc/examples/new_sptr.c | 75 --------- misc/examples/new_vec.c | 43 ----- misc/examples/person_arc.c | 77 --------- misc/examples/phonebook.c | 72 --------- misc/examples/prime.c | 56 ------- misc/examples/printspan.c | 52 ------ misc/examples/priority.c | 37 ----- misc/examples/priorityqueues/functor.c | 57 +++++++ misc/examples/priorityqueues/new_pque.c | 22 +++ misc/examples/priorityqueues/priority.c | 37 +++++ misc/examples/queue.c | 32 ---- misc/examples/queues/new_queue.c | 47 ++++++ misc/examples/queues/queue.c | 32 ++++ misc/examples/random.c | 45 ------ misc/examples/rawptr_elements.c | 59 ------- misc/examples/read.c | 27 ---- misc/examples/regex1.c | 32 ---- misc/examples/regex2.c | 34 ---- misc/examples/regex_match.c | 37 ----- misc/examples/regex_replace.c | 57 ------- misc/examples/regularexpressions/regex1.c | 32 ++++ misc/examples/regularexpressions/regex2.c | 34 ++++ misc/examples/regularexpressions/regex_match.c | 37 +++++ misc/examples/regularexpressions/regex_replace.c | 57 +++++++ misc/examples/replace.c | 36 ----- misc/examples/scheduler.c | 74 --------- misc/examples/shape.c | 158 ------------------ misc/examples/shape.cpp | 122 -------------- misc/examples/sidebyside.cpp | 57 ------- misc/examples/smartpointers/arc_containers.c | 81 ++++++++++ misc/examples/smartpointers/arc_demo.c | 62 ++++++++ misc/examples/smartpointers/arcvec_erase.c | 50 ++++++ misc/examples/smartpointers/box.c | 69 ++++++++ misc/examples/smartpointers/box2.c | 82 ++++++++++ misc/examples/smartpointers/music_arc.c | 67 ++++++++ misc/examples/smartpointers/new_sptr.c | 75 +++++++++ misc/examples/smartpointers/person_arc.c | 77 +++++++++ misc/examples/smartpointers/rawptr_elements.c | 59 +++++++ misc/examples/sorted_map.c | 67 -------- misc/examples/sortedmaps/csmap_erase.c | 82 ++++++++++ misc/examples/sortedmaps/csmap_find.c | 73 +++++++++ misc/examples/sortedmaps/csmap_insert.c | 108 +++++++++++++ misc/examples/sortedmaps/csset_erase.c | 41 +++++ misc/examples/sortedmaps/gauss2.c | 45 ++++++ misc/examples/sortedmaps/listmap.c | 65 ++++++++ misc/examples/sortedmaps/mapmap.c | 64 ++++++++ misc/examples/sortedmaps/multimap.c | 102 ++++++++++++ misc/examples/sortedmaps/new_smap.c | 67 ++++++++ misc/examples/sortedmaps/sorted_map.c | 67 ++++++++ misc/examples/spans/multidim.c | 67 ++++++++ misc/examples/spans/printspan.c | 52 ++++++ misc/examples/splitstr.c | 21 --- misc/examples/sso_map.c | 19 --- misc/examples/sso_substr.c | 21 --- misc/examples/stack.c | 32 ---- misc/examples/strings/cstr_match.c | 26 +++ misc/examples/strings/replace.c | 36 +++++ misc/examples/strings/splitstr.c | 21 +++ misc/examples/strings/sso_map.c | 19 +++ misc/examples/strings/sso_substr.c | 21 +++ misc/examples/strings/sview_split.c | 20 +++ misc/examples/strings/utf8replace_c.c | 25 +++ misc/examples/strings/utf8replace_rs.rs | 22 +++ misc/examples/sview_split.c | 20 --- misc/examples/triples.c | 72 --------- misc/examples/unordered_set.c | 45 ------ misc/examples/utf8replace_c.c | 25 --- misc/examples/utf8replace_rs.rs | 22 --- misc/examples/vectors/lower_bound.c | 66 ++++++++ misc/examples/vectors/new_vec.c | 43 +++++ misc/examples/vectors/stack.c | 32 ++++ misc/examples/vikings.c | 59 ------- 152 files changed, 4856 insertions(+), 4708 deletions(-) create mode 100644 misc/examples/algorithms/forfilter.c create mode 100644 misc/examples/algorithms/forloops.c create mode 100644 misc/examples/algorithms/random.c create mode 100644 misc/examples/algorithms/shape.c create mode 100644 misc/examples/algorithms/shape.cpp delete mode 100644 misc/examples/arc_containers.c delete mode 100644 misc/examples/arc_demo.c delete mode 100644 misc/examples/arcvec_erase.c delete mode 100644 misc/examples/astar.c delete mode 100644 misc/examples/birthday.c delete mode 100644 misc/examples/bits.c delete mode 100644 misc/examples/bits2.c create mode 100644 misc/examples/bitsets/bits.c create mode 100644 misc/examples/bitsets/bits2.c create mode 100644 misc/examples/bitsets/prime.c delete mode 100644 misc/examples/books.c delete mode 100644 misc/examples/box.c delete mode 100644 misc/examples/box2.c delete mode 100644 misc/examples/cointerleave.c delete mode 100644 misc/examples/complex.c delete mode 100644 misc/examples/convert.c delete mode 100644 misc/examples/coread.c delete mode 100644 misc/examples/coroutines.c create mode 100644 misc/examples/coroutines/cointerleave.c create mode 100644 misc/examples/coroutines/coread.c create mode 100644 misc/examples/coroutines/coroutines.c create mode 100644 misc/examples/coroutines/cotasks1.c create mode 100644 misc/examples/coroutines/cotasks2.c create mode 100644 misc/examples/coroutines/dining_philosophers.c create mode 100644 misc/examples/coroutines/generator.c create mode 100644 misc/examples/coroutines/scheduler.c create mode 100644 misc/examples/coroutines/triples.c delete mode 100644 misc/examples/csmap_erase.c delete mode 100644 misc/examples/csmap_find.c delete mode 100644 misc/examples/csmap_insert.c delete mode 100644 misc/examples/csset_erase.c delete mode 100644 misc/examples/cstr_match.c delete mode 100644 misc/examples/demos.c delete mode 100644 misc/examples/dining_philosophers.c delete mode 100644 misc/examples/forfilter.c delete mode 100644 misc/examples/forloops.c delete mode 100644 misc/examples/functor.c delete mode 100644 misc/examples/gauss2.c delete mode 100644 misc/examples/generator.c delete mode 100644 misc/examples/hashmap.c create mode 100644 misc/examples/hashmaps/birthday.c create mode 100644 misc/examples/hashmaps/books.c create mode 100644 misc/examples/hashmaps/hashmap.c create mode 100644 misc/examples/hashmaps/new_map.c create mode 100644 misc/examples/hashmaps/phonebook.c create mode 100644 misc/examples/hashmaps/unordered_set.c create mode 100644 misc/examples/hashmaps/vikings.c delete mode 100644 misc/examples/inits.c delete mode 100644 misc/examples/intrusive.c create mode 100644 misc/examples/linkedlists/intrusive.c create mode 100644 misc/examples/linkedlists/list.c create mode 100644 misc/examples/linkedlists/list_erase.c create mode 100644 misc/examples/linkedlists/list_splice.c create mode 100644 misc/examples/linkedlists/new_list.c delete mode 100644 misc/examples/list.c delete mode 100644 misc/examples/list_erase.c delete mode 100644 misc/examples/list_splice.c delete mode 100644 misc/examples/lower_bound.c delete mode 100644 misc/examples/mapmap.c create mode 100644 misc/examples/mixed/astar.c create mode 100644 misc/examples/mixed/complex.c create mode 100644 misc/examples/mixed/convert.c create mode 100644 misc/examples/mixed/demos.c create mode 100644 misc/examples/mixed/inits.c create mode 100644 misc/examples/mixed/read.c delete mode 100644 misc/examples/mmap.c delete mode 100644 misc/examples/multidim.c delete mode 100644 misc/examples/multimap.c delete mode 100644 misc/examples/music_arc.c delete mode 100644 misc/examples/new_list.c delete mode 100644 misc/examples/new_map.c delete mode 100644 misc/examples/new_pque.c delete mode 100644 misc/examples/new_queue.c delete mode 100644 misc/examples/new_smap.c delete mode 100644 misc/examples/new_sptr.c delete mode 100644 misc/examples/new_vec.c delete mode 100644 misc/examples/person_arc.c delete mode 100644 misc/examples/phonebook.c delete mode 100644 misc/examples/prime.c delete mode 100644 misc/examples/printspan.c delete mode 100644 misc/examples/priority.c create mode 100644 misc/examples/priorityqueues/functor.c create mode 100644 misc/examples/priorityqueues/new_pque.c create mode 100644 misc/examples/priorityqueues/priority.c delete mode 100644 misc/examples/queue.c create mode 100644 misc/examples/queues/new_queue.c create mode 100644 misc/examples/queues/queue.c delete mode 100644 misc/examples/random.c delete mode 100644 misc/examples/rawptr_elements.c delete mode 100644 misc/examples/read.c delete mode 100644 misc/examples/regex1.c delete mode 100644 misc/examples/regex2.c delete mode 100644 misc/examples/regex_match.c delete mode 100644 misc/examples/regex_replace.c create mode 100644 misc/examples/regularexpressions/regex1.c create mode 100644 misc/examples/regularexpressions/regex2.c create mode 100644 misc/examples/regularexpressions/regex_match.c create mode 100644 misc/examples/regularexpressions/regex_replace.c delete mode 100644 misc/examples/replace.c delete mode 100644 misc/examples/scheduler.c delete mode 100644 misc/examples/shape.c delete mode 100644 misc/examples/shape.cpp delete mode 100644 misc/examples/sidebyside.cpp create mode 100644 misc/examples/smartpointers/arc_containers.c create mode 100644 misc/examples/smartpointers/arc_demo.c create mode 100644 misc/examples/smartpointers/arcvec_erase.c create mode 100644 misc/examples/smartpointers/box.c create mode 100644 misc/examples/smartpointers/box2.c create mode 100644 misc/examples/smartpointers/music_arc.c create mode 100644 misc/examples/smartpointers/new_sptr.c create mode 100644 misc/examples/smartpointers/person_arc.c create mode 100644 misc/examples/smartpointers/rawptr_elements.c delete mode 100644 misc/examples/sorted_map.c create mode 100644 misc/examples/sortedmaps/csmap_erase.c create mode 100644 misc/examples/sortedmaps/csmap_find.c create mode 100644 misc/examples/sortedmaps/csmap_insert.c create mode 100644 misc/examples/sortedmaps/csset_erase.c create mode 100644 misc/examples/sortedmaps/gauss2.c create mode 100644 misc/examples/sortedmaps/listmap.c create mode 100644 misc/examples/sortedmaps/mapmap.c create mode 100644 misc/examples/sortedmaps/multimap.c create mode 100644 misc/examples/sortedmaps/new_smap.c create mode 100644 misc/examples/sortedmaps/sorted_map.c create mode 100644 misc/examples/spans/multidim.c create mode 100644 misc/examples/spans/printspan.c delete mode 100644 misc/examples/splitstr.c delete mode 100644 misc/examples/sso_map.c delete mode 100644 misc/examples/sso_substr.c delete mode 100644 misc/examples/stack.c create mode 100644 misc/examples/strings/cstr_match.c create mode 100644 misc/examples/strings/replace.c create mode 100644 misc/examples/strings/splitstr.c create mode 100644 misc/examples/strings/sso_map.c create mode 100644 misc/examples/strings/sso_substr.c create mode 100644 misc/examples/strings/sview_split.c create mode 100644 misc/examples/strings/utf8replace_c.c create mode 100644 misc/examples/strings/utf8replace_rs.rs delete mode 100644 misc/examples/sview_split.c delete mode 100644 misc/examples/triples.c delete mode 100644 misc/examples/unordered_set.c delete mode 100644 misc/examples/utf8replace_c.c delete mode 100644 misc/examples/utf8replace_rs.rs create mode 100644 misc/examples/vectors/lower_bound.c create mode 100644 misc/examples/vectors/new_vec.c create mode 100644 misc/examples/vectors/stack.c delete mode 100644 misc/examples/vikings.c (limited to 'misc/examples/coroutines.c') diff --git a/misc/examples/algorithms/forfilter.c b/misc/examples/algorithms/forfilter.c new file mode 100644 index 00000000..f3c008b3 --- /dev/null +++ b/misc/examples/algorithms/forfilter.c @@ -0,0 +1,149 @@ +#include +#define i_import +#include +#define i_implement +#include +#include +#include + +#define i_type IVec +#define i_key int +#include + +// filters and transforms: +#define flt_skipValue(i, x) (*i.ref != (x)) +#define flt_isEven(i) ((*i.ref & 1) == 0) +#define flt_isOdd(i) (*i.ref & 1) +#define flt_square(i) (*i.ref * *i.ref) + +void demo1(void) +{ + IVec vec = c_init(IVec, {0, 1, 2, 3, 4, 5, 80, 6, 7, 80, 8, 9, 80, + 10, 11, 12, 13, 14, 15, 80, 16, 17}); + + c_forfilter (i, IVec, vec, flt_skipValue(i, 80)) + printf(" %d", *i.ref); + puts(""); + + int sum = 0; + c_forfilter (i, IVec, vec, + c_flt_skipwhile(i, *i.ref != 80) && + c_flt_skip(i, 1) && + flt_isEven(i) && + flt_skipValue(i, 80) && + c_flt_take(i, 5) // short-circuit + ){ + sum += flt_square(i); + } + + printf("\n sum: %d\n", sum); + IVec_drop(&vec); +} + + +/* Rust: +fn main() { + let vector = (1..) // Infinite range of integers + .skip_while(|x| *x != 11) // Skip initial numbers unequal 11 + .filter(|x| x % 2 != 0) // Collect odd numbers + .take(5) // Only take five numbers + .map(|x| x * x) // Square each number + .collect::>(); // Return as a new Vec + println!("{:?}", vector); // Print result +} +*/ +void demo2(void) +{ + IVec vector = {0}; + crange r = crange_make(INT64_MAX); + c_forfilter (x, crange, r, + c_flt_skipwhile(x, *x.ref != 11) && + (*x.ref % 2) != 0 && + c_flt_take(x, 5) + ){ + IVec_push(&vector, (int)(*x.ref * *x.ref)); + } + c_foreach (x, IVec, vector) printf(" %d", *x.ref); + + puts(""); + IVec_drop(&vector); +} + +/* Rust: +fn main() { + let sentence = "This is a sentence in Rust."; + let words: Vec<&str> = sentence + .split_whitespace() + .collect(); + let words_containing_i: Vec<&str> = words + .into_iter() + .filter(|word| word.contains("i")) + .collect(); + println!("{:?}", words_containing_i); +} +*/ +#define i_type SVec +#define i_keyclass csview +#include + +void demo3(void) +{ + const char* sentence = "This is a sentence in C99."; + SVec words = {0}; + c_fortoken (w, sentence, " ") // split words + SVec_push(&words, *w.ref); + + SVec words_containing_i = {0}; + c_forfilter (w, SVec, words, + csview_contains(*w.ref, "i")) + SVec_push(&words_containing_i, *w.ref); + + c_foreach (w, SVec, words_containing_i) + printf(" %.*s", c_SV(*w.ref)); + + puts(""); + c_drop(SVec, &words, &words_containing_i); +} + +void demo4(void) +{ + // Keep only uppercase letters and convert them to lowercase: + csview s = c_sv("ab123cReAghNGnΩoEp"); // Ω = multi-byte + cstr out = {0}; + + c_forfilter (i, csview, s, utf8_isupper(utf8_peek(i.ref))) { + char chr[4]; + utf8_encode(chr, utf8_tolower(utf8_peek(i.ref))); + cstr_push(&out, chr); + } + + printf(" %s\n", cstr_str(&out)); + cstr_drop(&out); +} + +void demo5(void) +{ + #define flt_even(i) ((*i.ref & 1) == 0) + #define flt_mid_decade(i) ((*i.ref % 10) != 0) + crange R = crange_make(1963, INT32_MAX); + + c_forfilter (i, crange, R, + c_flt_skip(i,15) && + c_flt_skipwhile(i, flt_mid_decade(i)) && + c_flt_skip(i,30) && + flt_even(i) && + c_flt_take(i,5) + ){ + printf(" %lld", *i.ref); + } + puts(""); +} + +int main(void) +{ + puts("demo1"); demo1(); + puts("demo2"); demo2(); + puts("demo3"); demo3(); + puts("demo4"); demo4(); + puts("demo5"); demo5(); +} diff --git a/misc/examples/algorithms/forloops.c b/misc/examples/algorithms/forloops.c new file mode 100644 index 00000000..72d745f8 --- /dev/null +++ b/misc/examples/algorithms/forloops.c @@ -0,0 +1,69 @@ +#include +#include + +#define i_type IVec +#define i_key int +#include + +#define i_type IMap +#define i_key int +#define i_val int +#include + + +int main(void) +{ + puts("c_forrange:"); + c_forrange (30) printf(" xx"); + puts(""); + + c_forrange (i, 30) printf(" %lld", i); + puts(""); + + c_forrange (i, 30, 60) printf(" %lld", i); + puts(""); + + c_forrange (i, 30, 90, 2) printf(" %lld", i); + + puts("\n\nc_forlist:"); + c_forlist (i, int, {12, 23, 453, 65, 676}) + printf(" %d", *i.ref); + puts(""); + + c_forlist (i, const char*, {"12", "23", "453", "65", "676"}) + printf(" %s", *i.ref); + puts(""); + + IVec vec = c_init(IVec, {12, 23, 453, 65, 113, 215, 676, 34, 67, 20, 27, 66, 189, 45, 280, 199}); + IMap map = c_init(IMap, {{12, 23}, {453, 65}, {676, 123}, {34, 67}}); + + puts("\n\nc_foreach:"); + c_foreach (i, IVec, vec) + printf(" %d", *i.ref); + + puts("\n\nc_foreach_r: reverse"); + c_foreach_rv (i, IVec, vec) + printf(" %d", *i.ref); + + puts("\n\nc_foreach in map:"); + c_foreach (i, IMap, map) + printf(" (%d %d)", i.ref->first, i.ref->second); + + puts("\n\nc_forpair:"); + c_forpair (key, val, IMap, map) + printf(" (%d %d)", *_.key, *_.val); + + #define isOdd(i) (*i.ref & 1) + + puts("\n\nc_forfilter:"); + c_forfilter (i, IVec, vec, + isOdd(i) && + c_flt_skip(i, 4) && + c_flt_take(i, 4) + ){ + printf(" %d", *i.ref); + } + + IVec_drop(&vec); + IMap_drop(&map); +} diff --git a/misc/examples/algorithms/random.c b/misc/examples/algorithms/random.c new file mode 100644 index 00000000..b7c0f277 --- /dev/null +++ b/misc/examples/algorithms/random.c @@ -0,0 +1,45 @@ +#include +#include +#include + +int main(void) +{ + const int N = 1000000000; + const uint64_t seed = (uint64_t)time(NULL), range = 1000000; + crand_t rng = crand_init(seed); + + int64_t sum; + clock_t diff, before; + + printf("Compare speed of full and unbiased ranged random numbers...\n"); + sum = 0; + before = clock(); + c_forrange (N) { + sum += (uint32_t)crand_u64(&rng); + } + diff = clock() - before; + printf("full range\t\t: %f secs, %d, avg: %f\n", + (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); + + crand_unif_t dist1 = crand_unif_init(0, range); + rng = crand_init(seed); + sum = 0; + before = clock(); + c_forrange (N) { + sum += crand_unif(&rng, &dist1); // unbiased + } + diff = clock() - before; + printf("unbiased 0-%" PRIu64 "\t: %f secs, %d, avg: %f\n", + range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); + + sum = 0; + rng = crand_init(seed); + before = clock(); + c_forrange (N) { + sum += (int64_t)(crand_u64(&rng) % (range + 1)); // biased + } + diff = clock() - before; + printf("biased 0-%" PRIu64 " \t: %f secs, %d, avg: %f\n", + range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); + +} diff --git a/misc/examples/algorithms/shape.c b/misc/examples/algorithms/shape.c new file mode 100644 index 00000000..bd4bdd5a --- /dev/null +++ b/misc/examples/algorithms/shape.c @@ -0,0 +1,158 @@ +// Demo of typesafe polymorphism in C99, using STC. + +#include +#include +#include + +#define DYN_CAST(T, s) \ + (&T##_api == (s)->api ? (T*)(s) : (T*)0) + +// Shape definition +// ============================================================ + +typedef struct { + float x, y; +} Point; + +typedef struct Shape Shape; + +struct ShapeAPI { + void (*drop)(Shape*); + void (*draw)(const Shape*); +}; + +struct Shape { + struct ShapeAPI* api; + uint32_t color; + uint16_t style; + uint8_t thickness; + uint8_t hardness; +}; + +void Shape_drop(Shape* shape) +{ + printf("shape destructed\n"); +} + +void Shape_delete(Shape* shape) +{ + if (shape) { + shape->api->drop(shape); + c_free(shape); + } +} + +// Triangle implementation +// ============================================================ + +typedef struct { + Shape shape; + Point p[3]; +} Triangle; + +extern struct ShapeAPI Triangle_api; + + +Triangle Triangle_from(Point a, Point b, Point c) { + Triangle t = {{&Triangle_api}, {a, b, c}}; + return t; +} + +static void Triangle_draw(const Shape* shape) +{ + const Triangle* self = DYN_CAST(Triangle, shape); + printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n", + (double)self->p[0].x, (double)self->p[0].y, + (double)self->p[1].x, (double)self->p[1].y, + (double)self->p[2].x, (double)self->p[2].y); +} + +struct ShapeAPI Triangle_api = { + .drop = Shape_drop, + .draw = Triangle_draw, +}; + +// Polygon implementation +// ============================================================ + +#define i_type PointVec +#define i_key Point +#include + +typedef struct { + Shape shape; + PointVec points; +} Polygon; + +extern struct ShapeAPI Polygon_api; + + +Polygon Polygon_init(void) { + Polygon p = {{&Polygon_api}, {0}}; + return p; +} + +void Polygon_addPoint(Polygon* self, Point p) +{ + PointVec_push(&self->points, p); +} + +static void Polygon_drop(Shape* shape) +{ + Polygon* self = DYN_CAST(Polygon, shape); + printf("poly destructed\n"); + PointVec_drop(&self->points); +} + +static void Polygon_draw(const Shape* shape) +{ + const Polygon* self = DYN_CAST(Polygon, shape); + printf("Polygon :"); + c_foreach (i, PointVec, self->points) + printf(" (%g,%g)", (double)i.ref->x, (double)i.ref->y); + puts(""); +} + +struct ShapeAPI Polygon_api = { + .drop = Polygon_drop, + .draw = Polygon_draw, +}; + +// Test +// ============================================================ + +#define i_type Shapes +#define i_key Shape* +#define i_keydrop(x) Shape_delete(*x) +#define i_no_clone +#include + +void testShape(const Shape* shape) +{ + shape->api->draw(shape); +} + + +int main(void) +{ + Shapes shapes = {0}; + + Triangle* tri1 = c_new(Triangle, Triangle_from(c_LITERAL(Point){5, 7}, c_LITERAL(Point){12, 7}, c_LITERAL(Point){12, 20})); + Polygon* pol1 = c_new(Polygon, Polygon_init()); + Polygon* pol2 = c_new(Polygon, Polygon_init()); + + c_forlist (i, Point, {{50, 72}, {123, 73}, {127, 201}, {828, 333}}) + Polygon_addPoint(pol1, *i.ref); + + c_forlist (i, Point, {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}) + Polygon_addPoint(pol2, *i.ref); + + Shapes_push(&shapes, &tri1->shape); + Shapes_push(&shapes, &pol1->shape); + Shapes_push(&shapes, &pol2->shape); + + c_foreach (i, Shapes, shapes) + testShape(*i.ref); + + Shapes_drop(&shapes); +} diff --git a/misc/examples/algorithms/shape.cpp b/misc/examples/algorithms/shape.cpp new file mode 100644 index 00000000..ea1f53d2 --- /dev/null +++ b/misc/examples/algorithms/shape.cpp @@ -0,0 +1,122 @@ +// Demo of polymorphism in C++ + +#include +#include +#include + +// Shape definition +// ============================================================ + +struct Point { + float x, y; +}; + +std::ostream& operator<<(std::ostream& os, const Point& p) { + os << " (" << p.x << "," << p.y << ")"; + return os; +} + +struct Shape { + virtual ~Shape(); + virtual void draw() const = 0; + + uint32_t color; + uint16_t style; + uint8_t thickness; + uint8_t hardness; +}; + +Shape::~Shape() +{ + std::cout << "base destructed" << std::endl; +} + +// Triangle implementation +// ============================================================ + +struct Triangle : public Shape +{ + Triangle(Point a, Point b, Point c); + void draw() const override; + + private: Point p[3]; +}; + + +Triangle::Triangle(Point a, Point b, Point c) + : p{a, b, c} {} + +void Triangle::draw() const +{ + std::cout << "Triangle :" + << p[0] << p[1] << p[2] + << std::endl; +} + + +// Polygon implementation +// ============================================================ + + +struct Polygon : public Shape +{ + ~Polygon(); + void draw() const override; + void addPoint(const Point& p); + + private: std::vector points; +}; + + +void Polygon::addPoint(const Point& p) +{ + points.push_back(p); +} + +Polygon::~Polygon() +{ + std::cout << "poly destructed" << std::endl; +} + +void Polygon::draw() const +{ + std::cout << "Polygon :"; + for (auto& p : points) + std::cout << p ; + std::cout << std::endl; +} + + +// Test +// ============================================================ + +void testShape(const Shape* shape) +{ + shape->draw(); +} + +#include + +int main(void) +{ + std::vector> shapes; + + auto tri1 = std::make_unique(Point{5, 7}, Point{12, 7}, Point{12, 20}); + auto pol1 = std::make_unique(); + auto pol2 = std::make_unique(); + + for (auto& p: std::array + {{{50, 72}, {123, 73}, {127, 201}, {828, 333}}}) + pol1->addPoint(p); + + for (auto& p: std::array + {{{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}}) + pol2->addPoint(p); + + shapes.push_back(std::move(tri1)); + shapes.push_back(std::move(pol1)); + shapes.push_back(std::move(pol2)); + + for (auto& shape: shapes) + testShape(shape.get()); +} diff --git a/misc/examples/arc_containers.c b/misc/examples/arc_containers.c deleted file mode 100644 index 2fb04c56..00000000 --- a/misc/examples/arc_containers.c +++ /dev/null @@ -1,81 +0,0 @@ -// Create a stack and a list of shared pointers to maps, -// and demonstrate sharing and cloning of maps. -#define i_implement -#include -#include -#define i_type Map -#define i_key_str // strings -#define i_val int -#define i_keydrop(p) (printf("drop name: %s\n", cstr_str(p)), cstr_drop(p)) -#include - -#define i_type Arc // (atomic) ref. counted type -#define i_key Map -#define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p)) -// no need for atomic ref. count in single thread: -#define i_opt c_no_atomic -#include - -#define i_type Stack -#define i_keyboxed Arc // define i_keyboxed for carc/cbox value (not i_key) -#include - -#define i_type List -#define i_keyboxed Arc // as above -#include - -int main(void) -{ - Stack stack = {0}; - List list = {0}; - c_defer( - Stack_drop(&stack), - List_drop(&list) - ){ - // POPULATE stack with shared pointers to Maps: - Map *map; - map = Stack_push(&stack, Arc_from(Map_init()))->get; - Map_emplace(map, "Joey", 1990); - Map_emplace(map, "Mary", 1995); - Map_emplace(map, "Joanna", 1992); - - map = Stack_push(&stack, Arc_from(Map_init()))->get; - Map_emplace(map, "Rosanna", 2001); - Map_emplace(map, "Brad", 1999); - Map_emplace(map, "Jack", 1980); - - // POPULATE list: - map = List_push_back(&list, Arc_from(Map_init()))->get; - Map_emplace(map, "Steve", 1979); - Map_emplace(map, "Rick", 1974); - Map_emplace(map, "Tracy", 2003); - - // Share two Maps from the stack with the list using emplace (clone the carc): - List_push_back(&list, Arc_clone(stack.data[0])); - List_push_back(&list, Arc_clone(stack.data[1])); - - // Clone (deep copy) a Map from the stack to the list - // List will contain two shared and two unshared maps. - map = List_push_back(&list, Arc_from(Map_clone(*stack.data[1].get)))->get; - - // Add one more element to the cloned map: - Map_emplace_or_assign(map, "CLONED", 2021); - - // Add one more element to the shared map: - Map_emplace_or_assign(stack.data[1].get, "SHARED", 2021); - - puts("STACKS"); - c_foreach (i, Stack, stack) { - c_forpair (name, year, Map, *i.ref->get) - printf(" %s:%d", cstr_str(_.name), *_.year); - puts(""); - } - - puts("LIST"); - c_foreach (i, List, list) { - c_forpair (name, year, Map, *i.ref->get) - printf(" %s:%d", cstr_str(_.name), *_.year); - puts(""); - } - } -} diff --git a/misc/examples/arc_demo.c b/misc/examples/arc_demo.c deleted file mode 100644 index 929a48a1..00000000 --- a/misc/examples/arc_demo.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include - -void int_drop(int* x) { - printf("drop: %d\n", *x); -} - -// carc implements its own clone method using reference counting, -// so 'i_keyclone' is not required to be defined (ignored). - -#define i_type Arc // set type name to be defined (instead of 'carc_int') -#define i_key int -#define i_keydrop int_drop // optional, just to display the elements destroyed -#define i_cmp_native // use int comparison (x < y, x == y). -#include // Arc - -#define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements -#include // csset_Arc (like: std::set>) - -#define i_keyboxed Arc // note: as above. -#include // cvec_Arc (like: std::vector>) - -int main(void) -{ - const int years[] = {2021, 2012, 2022, 2015}; - - cvec_Arc vec = {0}; - c_forrange (i, c_arraylen(years)) { - cvec_Arc_emplace(&vec, years[i]); - // cvec_Arc_push(&vec, Arc_from(years[i])); // alt. - } - - cvec_Arc_sort(&vec); - - printf("vec:"); - c_foreach (i, cvec_Arc, vec) - printf(" %d", *i.ref->get); - puts(""); - - // add odd numbers from vec to set - csset_Arc set = {0}; - c_foreach (i, cvec_Arc, vec) - if (*i.ref->get & 1) - csset_Arc_insert(&set, Arc_clone(*i.ref)); // copy shared pointer => increments counter. - - // erase the two last elements in vec - cvec_Arc_pop_back(&vec); - cvec_Arc_pop_back(&vec); - - printf("vec:"); - c_foreach (i, cvec_Arc, vec) printf(" %d", *i.ref->get); - - printf("\nset:"); - c_foreach (i, csset_Arc, set) printf(" %d", *i.ref->get); - - Arc p = Arc_clone(vec.data[0]); - printf("\n%d is now owned by %ld objects\n", *p.get, *p.use_count); - - Arc_drop(&p); - cvec_Arc_drop(&vec); - csset_Arc_drop(&set); -} diff --git a/misc/examples/arcvec_erase.c b/misc/examples/arcvec_erase.c deleted file mode 100644 index ba54c1c7..00000000 --- a/misc/examples/arcvec_erase.c +++ /dev/null @@ -1,50 +0,0 @@ -#include - -void show_drop(int* x) { printf("drop: %d\n", *x); } - -#define i_type Arc -#define i_key int -#define i_keydrop show_drop -#define i_cmp_native // enable sort/search for int type -#include // Shared pointer to int - -#define i_type Vec -#define i_keyboxed Arc -#include // Vec: cvec - - -int main(void) -{ - Vec vec = c_init(Vec, {2012, 1990, 2012, 2019, 2015}); - - // clone the second 2012 and push it back. - // note: cloning make sure that vec.data[2] has ref count 2. - Vec_push(&vec, Arc_clone(vec.data[2])); - - printf("vec before erase :"); - c_foreach (i, Vec, vec) - printf(" %d", *i.ref->get); - - printf("\nerase vec.data[2]; or first matching value depending on compare.\n"); - Vec_iter it; - it = Vec_find(&vec, *vec.data[2].get); - if (it.ref) - Vec_erase_at(&vec, it); - - int year = 2015; - it = Vec_find(&vec, year); // Ok as tmp only. - if (it.ref) - Vec_erase_at(&vec, it); - - printf("vec after erase :"); - c_foreach (i, Vec, vec) - printf(" %d", *i.ref->get); - - Vec_sort(&vec); - printf("\nvec after sort :"); - c_foreach (i, Vec, vec) - printf(" %d", *i.ref->get); - - puts("\nDone"); - Vec_drop(&vec); -} diff --git a/misc/examples/astar.c b/misc/examples/astar.c deleted file mode 100644 index 590b7952..00000000 --- a/misc/examples/astar.c +++ /dev/null @@ -1,174 +0,0 @@ -// -// -- An A* pathfinder inspired by the excellent tutorial at Red Blob Games -- -// -// This is a reimplementation of the CTL example to STC: -// https://github.com/glouw/ctl/blob/master/examples/astar.c -// https://www.redblobgames.com/pathfinding/a-star/introduction.html -#define i_implement -#include -#include - -typedef struct -{ - int x; - int y; - int priorty; - int width; -} -point; - -point -point_init(int x, int y, int width) -{ - return c_LITERAL(point){ x, y, 0, width }; -} - -int -point_cmp_priority(const point* a, const point* b) -{ - return c_default_cmp(&a->priorty, &b->priorty); -} - -int -point_equal(const point* a, const point* b) -{ - return a->x == b->x && a->y == b->y; -} - -point -point_from(const cstr* maze, const char* c, int width) -{ - int index = (int)cstr_find(maze, c); - return point_init(index % width, index / width, width); -} - -int -point_index(const point* p) -{ - return p->x + p->width * p->y; -} - -int -point_key_cmp(const point* a, const point* b) -{ - int i = point_index(a); - int j = point_index(b); - return (i == j) ? 0 : (i < j) ? -1 : 1; -} - -#define i_key point -#define i_cmp point_cmp_priority -#include - -#define i_key point -#define i_opt c_no_cmp -#include - -#define i_key point -#define i_val int -#define i_cmp point_key_cmp -#define i_tag pcost -#include - -#define i_key point -#define i_val point -#define i_cmp point_key_cmp -#define i_tag pstep -#include - -cdeq_point -astar(cstr* maze, int width) -{ - cdeq_point ret_path = {0}; - - cpque_point front = {0}; - csmap_pstep from = {0}; - csmap_pcost costs = {0}; - c_defer( - cpque_point_drop(&front), - csmap_pstep_drop(&from), - csmap_pcost_drop(&costs) - ){ - point start = point_from(maze, "@", width); - point goal = point_from(maze, "!", width); - csmap_pcost_insert(&costs, start, 0); - cpque_point_push(&front, start); - while (!cpque_point_empty(&front)) - { - point current = *cpque_point_top(&front); - cpque_point_pop(&front); - if (point_equal(¤t, &goal)) - break; - point deltas[] = { - { -1, +1, 0, width }, { 0, +1, 0, width }, { 1, +1, 0, width }, - { -1, 0, 0, width }, /* ~ ~ ~ ~ ~ ~ ~ */ { 1, 0, 0, width }, - { -1, -1, 0, width }, { 0, -1, 0, width }, { 1, -1, 0, width }, - }; - for (size_t i = 0; i < c_arraylen(deltas); i++) - { - point delta = deltas[i]; - point next = point_init(current.x + delta.x, current.y + delta.y, width); - int new_cost = *csmap_pcost_at(&costs, current); - if (cstr_str(maze)[point_index(&next)] != '#') - { - const csmap_pcost_value *cost = csmap_pcost_get(&costs, next); - if (cost == NULL || new_cost < cost->second) - { - csmap_pcost_insert(&costs, next, new_cost); - next.priorty = new_cost + abs(goal.x - next.x) + abs(goal.y - next.y); - cpque_point_push(&front, next); - csmap_pstep_insert(&from, next, current); - } - } - } - } - point current = goal; - while (!point_equal(¤t, &start)) - { - cdeq_point_push_front(&ret_path, current); - current = *csmap_pstep_at(&from, current); - } - cdeq_point_push_front(&ret_path, start); - } - return ret_path; -} - -int -main(void) -{ - cstr maze = cstr_lit( - "#########################################################################\n" - "# # # # # # #\n" - "# # ######### # ##### ######### ##### ##### ##### # ! #\n" - "# # # # # # # # # #\n" - "######### # ######### ######### ##### # # # ######### #\n" - "# # # # # # # # # # #\n" - "# # ############# # # ######### ##### # ######### # #\n" - "# # # # # # # # # #\n" - "# ############# ##### ##### # ##### ######### # ##### #\n" - "# # # # # # # # # #\n" - "# ##### ##### # ##### # ######### # # # #############\n" - "# # # # # # # # # # # #\n" - "############# # # # ######### # ##### # ##### ##### #\n" - "# # # # # # # # # #\n" - "# ##### # ######### ##### # ##### ##### ############# #\n" - "# # # # # # # # # #\n" - "# # ######### # ##### ######### # # ############# # #\n" - "# # # # # # # # # # #\n" - "# ######### # # # ##### ######### ######### # #########\n" - "# # # # # # # # # #\n" - "# @ # ##### ##### ##### ######### ##### # ######### # #\n" - "# # # # # # #\n" - "#########################################################################\n" - ); - int width = (int)cstr_find(&maze, "\n") + 1; - cdeq_point ret_path = astar(&maze, width); - - c_foreach (it, cdeq_point, ret_path) - cstr_data(&maze)[point_index(it.ref)] = 'x'; - - printf("%s", cstr_str(&maze)); - - cdeq_point_drop(&ret_path); - cstr_drop(&maze); -} diff --git a/misc/examples/birthday.c b/misc/examples/birthday.c deleted file mode 100644 index 4742cb45..00000000 --- a/misc/examples/birthday.c +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include -#include -#include - -#define i_tag ic -#define i_key uint64_t -#define i_val int -#include - -static uint64_t seed = 12345; - -static void test_repeats(void) -{ - enum {BITS = 46, BITS_TEST = BITS/2 + 2}; - static const uint64_t N = 1ull << BITS_TEST; - static const uint64_t mask = (1ull << BITS) - 1; - - printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST); - crand_t rng = crand_init(seed); - - cmap_ic m = cmap_ic_with_capacity(N); - c_forrange (i, N) { - uint64_t k = crand_u64(&rng) & mask; - int v = cmap_ic_insert(&m, k, 0).ref->second += 1; - if (v > 1) printf("repeated value %" PRIu64 " (%d) at 2^%d\n", - k, v, (int)log2((double)i)); - } - cmap_ic_drop(&m); -} - -#define i_key uint32_t -#define i_val uint64_t -#define i_tag x -#include - -void test_distribution(void) -{ - enum {BITS = 26}; - printf("distribution test: 2^%d values\n", BITS); - crand_t rng = crand_init(seed); - const size_t N = 1ull << BITS ; - - cmap_x map = {0}; - c_forrange (N) { - uint64_t k = crand_u64(&rng); - cmap_x_insert(&map, k & 0xf, 0).ref->second += 1; - } - - uint64_t sum = 0; - c_foreach (i, cmap_x, map) sum += i.ref->second; - sum /= (uint64_t)map.size; - - c_foreach (i, cmap_x, map) { - printf("%4" PRIu32 ": %" PRIu64 " - %" PRIu64 ": %11.8f\n", - i.ref->first, i.ref->second, sum, - (1.0 - (double)i.ref->second / (double)sum)); - } - - cmap_x_drop(&map); -} - -int main(void) -{ - seed = (uint64_t)time(NULL); - test_distribution(); - test_repeats(); -} diff --git a/misc/examples/bits.c b/misc/examples/bits.c deleted file mode 100644 index e0a11346..00000000 --- a/misc/examples/bits.c +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include - -int main(void) -{ - cbits set = cbits_with_size(23, true); - cbits s2; - c_defer( - cbits_drop(&set), - cbits_drop(&s2) - ){ - printf("count %lld, %lld\n", cbits_count(&set), cbits_size(&set)); - cbits s1 = cbits_from("1110100110111"); - char buf[256]; - cbits_to_str(&s1, buf, 0, 255); - printf("buf: %s: %lld\n", buf, cbits_count(&s1)); - cbits_drop(&s1); - - cbits_reset(&set, 9); - cbits_resize(&set, 43, false); - printf(" str: %s\n", cbits_to_str(&set, buf, 0, 255)); - - printf("%4lld: ", cbits_size(&set)); - c_forrange (i, cbits_size(&set)) - printf("%d", cbits_test(&set, i)); - puts(""); - - cbits_set(&set, 28); - cbits_resize(&set, 77, true); - cbits_resize(&set, 93, false); - cbits_resize(&set, 102, true); - cbits_set_value(&set, 99, false); - printf("%4lld: ", cbits_size(&set)); - c_forrange (i, cbits_size(&set)) - printf("%d", cbits_test(&set, i)); - - puts("\nIterate:"); - printf("%4lld: ", cbits_size(&set)); - c_forrange (i, cbits_size(&set)) - printf("%d", cbits_test(&set, i)); - puts(""); - - // Make a clone - s2 = cbits_clone(set); - cbits_flip_all(&s2); - cbits_set(&s2, 16); - cbits_set(&s2, 17); - cbits_set(&s2, 18); - printf(" new: "); - c_forrange (i, cbits_size(&s2)) - printf("%d", cbits_test(&s2, i)); - puts(""); - - printf(" xor: "); - cbits_xor(&set, &s2); - c_forrange (i, cbits_size(&set)) - printf("%d", cbits_test(&set, i)); - puts(""); - - cbits_set_all(&set, false); - printf("%4lld: ", cbits_size(&set)); - c_forrange (i, cbits_size(&set)) - printf("%d", cbits_test(&set, i)); - puts(""); - } -} diff --git a/misc/examples/bits2.c b/misc/examples/bits2.c deleted file mode 100644 index de2f16f4..00000000 --- a/misc/examples/bits2.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -// Example of static sized (stack allocated) bitsets - -#define i_type Bits -#define i_capacity 80 // enable fixed bitset on the stack -#include - -int main(void) -{ - Bits s1 = Bits_from("1110100110111"); - - printf("size %lld\n", Bits_size(&s1)); - char buf[256]; - Bits_to_str(&s1, buf, 0, 256); - printf("buf: %s: count=%lld\n", buf, Bits_count(&s1)); - - Bits_reset(&s1, 8); - printf(" s1: %s\n", Bits_to_str(&s1, buf, 0, 256)); - - Bits s2 = Bits_clone(s1); - - Bits_flip_all(&s2); - Bits_reset(&s2, 66); - Bits_reset(&s2, 67); - printf(" s2: "); - c_forrange (i, Bits_size(&s2)) - printf("%d", Bits_test(&s2, i)); - puts(""); - - printf("xor: "); - Bits_xor(&s1, &s2); - c_forrange (i, Bits_size(&s1)) - printf("%d", Bits_test(&s1, i)); - puts(""); - - printf("all: "); - Bits_set_pattern(&s1, 0x3333333333333333); - c_forrange (i, Bits_size(&s1)) - printf("%d", Bits_test(&s1, i)); - puts(""); -} diff --git a/misc/examples/bitsets/bits.c b/misc/examples/bitsets/bits.c new file mode 100644 index 00000000..e0a11346 --- /dev/null +++ b/misc/examples/bitsets/bits.c @@ -0,0 +1,66 @@ +#include +#include + +int main(void) +{ + cbits set = cbits_with_size(23, true); + cbits s2; + c_defer( + cbits_drop(&set), + cbits_drop(&s2) + ){ + printf("count %lld, %lld\n", cbits_count(&set), cbits_size(&set)); + cbits s1 = cbits_from("1110100110111"); + char buf[256]; + cbits_to_str(&s1, buf, 0, 255); + printf("buf: %s: %lld\n", buf, cbits_count(&s1)); + cbits_drop(&s1); + + cbits_reset(&set, 9); + cbits_resize(&set, 43, false); + printf(" str: %s\n", cbits_to_str(&set, buf, 0, 255)); + + printf("%4lld: ", cbits_size(&set)); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + puts(""); + + cbits_set(&set, 28); + cbits_resize(&set, 77, true); + cbits_resize(&set, 93, false); + cbits_resize(&set, 102, true); + cbits_set_value(&set, 99, false); + printf("%4lld: ", cbits_size(&set)); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + + puts("\nIterate:"); + printf("%4lld: ", cbits_size(&set)); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + puts(""); + + // Make a clone + s2 = cbits_clone(set); + cbits_flip_all(&s2); + cbits_set(&s2, 16); + cbits_set(&s2, 17); + cbits_set(&s2, 18); + printf(" new: "); + c_forrange (i, cbits_size(&s2)) + printf("%d", cbits_test(&s2, i)); + puts(""); + + printf(" xor: "); + cbits_xor(&set, &s2); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + puts(""); + + cbits_set_all(&set, false); + printf("%4lld: ", cbits_size(&set)); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + puts(""); + } +} diff --git a/misc/examples/bitsets/bits2.c b/misc/examples/bitsets/bits2.c new file mode 100644 index 00000000..de2f16f4 --- /dev/null +++ b/misc/examples/bitsets/bits2.c @@ -0,0 +1,41 @@ +#include +// Example of static sized (stack allocated) bitsets + +#define i_type Bits +#define i_capacity 80 // enable fixed bitset on the stack +#include + +int main(void) +{ + Bits s1 = Bits_from("1110100110111"); + + printf("size %lld\n", Bits_size(&s1)); + char buf[256]; + Bits_to_str(&s1, buf, 0, 256); + printf("buf: %s: count=%lld\n", buf, Bits_count(&s1)); + + Bits_reset(&s1, 8); + printf(" s1: %s\n", Bits_to_str(&s1, buf, 0, 256)); + + Bits s2 = Bits_clone(s1); + + Bits_flip_all(&s2); + Bits_reset(&s2, 66); + Bits_reset(&s2, 67); + printf(" s2: "); + c_forrange (i, Bits_size(&s2)) + printf("%d", Bits_test(&s2, i)); + puts(""); + + printf("xor: "); + Bits_xor(&s1, &s2); + c_forrange (i, Bits_size(&s1)) + printf("%d", Bits_test(&s1, i)); + puts(""); + + printf("all: "); + Bits_set_pattern(&s1, 0x3333333333333333); + c_forrange (i, Bits_size(&s1)) + printf("%d", Bits_test(&s1, i)); + puts(""); +} diff --git a/misc/examples/bitsets/prime.c b/misc/examples/bitsets/prime.c new file mode 100644 index 00000000..cb3b095a --- /dev/null +++ b/misc/examples/bitsets/prime.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include + + +cbits sieveOfEratosthenes(int64_t n) +{ + cbits bits = cbits_with_size(n/2 + 1, true); + int64_t q = (int64_t)sqrt((double) n) + 1; + for (int64_t i = 3; i < q; i += 2) { + int64_t j = i; + for (; j < n; j += 2) { + if (cbits_test(&bits, j>>1)) { + i = j; + break; + } + } + for (int64_t j = i*i; j < n; j += i*2) + cbits_reset(&bits, j>>1); + } + return bits; +} + +int main(void) +{ + int n = 1000000000; + printf("Computing prime numbers up to %d\n", n); + + clock_t t = clock(); + cbits primes = sieveOfEratosthenes(n + 1); + int np = (int)cbits_count(&primes); + t = clock() - t; + + puts("Show all the primes in the range [2, 1000):"); + printf("2"); + c_forrange (i, 3, 1000, 2) + if (cbits_test(&primes, i>>1)) printf(" %lld", i); + puts("\n"); + + puts("Show the last 50 primes using a temporary crange generator:"); + crange range = crange_make(n - 1, 0, -2); + + c_forfilter (i, crange, range, + cbits_test(&primes, *i.ref/2) && + c_flt_take(i, 50) + ){ + printf("%lld ", *i.ref); + if (c_flt_getcount(i) % 10 == 0) puts(""); + } + printf("Number of primes: %d, time: %.2f\n\n", np, (double)t/CLOCKS_PER_SEC); + + cbits_drop(&primes); +} diff --git a/misc/examples/books.c b/misc/examples/books.c deleted file mode 100644 index 1fd57f27..00000000 --- a/misc/examples/books.c +++ /dev/null @@ -1,62 +0,0 @@ -// https://doc.rust-lang.org/std/collections/struct.HashMap.html -#define i_implement -#include -#define i_key_str -#define i_val_str -#include - -// Type inference lets us omit an explicit type signature (which -// would be `HashMap` in this example). -int main(void) -{ - cmap_str book_reviews = {0}; - - // Review some books. - cmap_str_emplace(&book_reviews, - "Adventures of Huckleberry Finn", - "My favorite book." - ); - cmap_str_emplace(&book_reviews, - "Grimms' Fairy Tales", - "Masterpiece." - ); - cmap_str_emplace(&book_reviews, - "Pride and Prejudice", - "Very enjoyable" - ); - cmap_str_insert(&book_reviews, - cstr_lit("The Adventures of Sherlock Holmes"), - cstr_lit("Eye lyked it alot.") - ); - - // Check for a specific one. - // When collections store owned values (String), they can still be - // queried using references (&str). - if (cmap_str_contains(&book_reviews, "Les Misérables")) { - printf("We've got %" c_ZI " reviews, but Les Misérables ain't one.", - cmap_str_size(&book_reviews)); - } - - // oops, this review has a lot of spelling mistakes, let's delete it. - cmap_str_erase(&book_reviews, "The Adventures of Sherlock Holmes"); - - // Look up the values associated with some keys. - const char* to_find[] = {"Pride and Prejudice", "Alice's Adventure in Wonderland"}; - c_forrange (i, c_arraylen(to_find)) { - const cmap_str_value* b = cmap_str_get(&book_reviews, to_find[i]); - if (b) - printf("%s: %s\n", cstr_str(&b->first), cstr_str(&b->second)); - else - printf("%s is unreviewed.\n", to_find[i]); - } - - // Look up the value for a key (will panic if the key is not found). - printf("Review for Jane: %s\n", cstr_str(cmap_str_at(&book_reviews, "Pride and Prejudice"))); - - // Iterate over everything. - c_forpair (book, review, cmap_str, book_reviews) { - printf("%s: \"%s\"\n", cstr_str(_.book), cstr_str(_.review)); - } - - cmap_str_drop(&book_reviews); -} diff --git a/misc/examples/box.c b/misc/examples/box.c deleted file mode 100644 index 94d126c0..00000000 --- a/misc/examples/box.c +++ /dev/null @@ -1,69 +0,0 @@ -/* cbox: heap allocated boxed type */ -#define i_implement -#include - -typedef struct { cstr name, last; } Person; - -Person Person_make(const char* name, const char* last) { - return c_LITERAL(Person){.name = cstr_from(name), .last = cstr_from(last)}; -} - -uint64_t Person_hash(const Person* a) { - return cstr_hash(&a->name) ^ cstr_hash(&a->last); -} - -int Person_cmp(const Person* a, const Person* b) { - int c = cstr_cmp(&a->name, &b->name); - return c ? c : cstr_cmp(&a->last, &b->last); -} - -Person Person_clone(Person p) { - p.name = cstr_clone(p.name); - p.last = cstr_clone(p.last); - return p; -} - -void Person_drop(Person* p) { - printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); - c_drop(cstr, &p->name, &p->last); -} - -#define i_type PBox -#define i_keyclass Person // "class" binds _cmp, _clone, _drop functions. -#include - -#define i_type Persons -#define i_keyboxed PBox // "arcbox" informs that PBox is a smart pointer. -#include - -int main(void) -{ - Persons vec = {0}; - PBox p = PBox_from(Person_make("Laura", "Palmer")); - PBox q = PBox_clone(p); - cstr_assign(&q.get->name, "Leland"); - - printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last)); - printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last)); - - Persons_emplace(&vec, Person_make("Dale", "Cooper")); - Persons_emplace(&vec, Person_make("Audrey", "Home")); - - // NB! Clone/share p and q in the Persons container. - Persons_push(&vec, PBox_clone(p)); - Persons_push(&vec, PBox_clone(q)); - - c_foreach (i, Persons, vec) - printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last)); - puts(""); - - // Look-up Audrey! Create a temporary Person for lookup. - Person a = Person_make("Audrey", "Home"); - const PBox *v = Persons_get(&vec, a); // lookup - if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last)); - - Person_drop(&a); - PBox_drop(&p); - PBox_drop(&q); - Persons_drop(&vec); -} diff --git a/misc/examples/box2.c b/misc/examples/box2.c deleted file mode 100644 index eaab1c47..00000000 --- a/misc/examples/box2.c +++ /dev/null @@ -1,82 +0,0 @@ -// example: https://doc.rust-lang.org/rust-by-example/std/box.html -#include - -typedef struct { - double x; - double y; -} Point; - -// A Rectangle can be specified by where its top left and bottom right -// corners are in space -typedef struct { - Point top_left; - Point bottom_right; -} Rectangle; - -#define i_key Point -#include // cbox_Point - -#define i_key Rectangle -#include // cbox_Rectangle - -// Box in box: -#define i_type BoxBoxPoint -#define i_keyboxed cbox_Point // NB: use i_keyboxed when value is a cbox or carc! -#define i_no_cmp -#include // BoxBoxPoint - -Point origin(void) { - return c_LITERAL(Point){ .x=1.0, .y=2.0 }; -} - -cbox_Point boxed_origin(void) { - // Allocate this point on the heap, and return a pointer to it - return cbox_Point_make(c_LITERAL(Point){ .x=1.0, .y=2.0 }); -} - - -int main(void) { - // Stack allocated variables - Point point = origin(); - Rectangle rectangle = { - .top_left = origin(), - .bottom_right = { .x=3.0, .y=-4.0 } - }; - - // Heap allocated rectangle - cbox_Rectangle boxed_rectangle = cbox_Rectangle_make(c_LITERAL(Rectangle){ - .top_left = origin(), - .bottom_right = { .x=3.0, .y=-4.0 } - }); - // The output of functions can be boxed - cbox_Point boxed_point = cbox_Point_make(origin()); - - // Can use from(raw) and toraw instead: - BoxBoxPoint box_in_a_box = BoxBoxPoint_from(origin()); - - c_defer( - BoxBoxPoint_drop(&box_in_a_box), - cbox_Point_drop(&boxed_point), - cbox_Rectangle_drop(&boxed_rectangle) - ){ - printf("box_in_a_box: x = %g\n", BoxBoxPoint_toraw(&box_in_a_box).x); - - printf("Point occupies %d bytes on the stack\n", - (int)sizeof(point)); - printf("Rectangle occupies %d bytes on the stack\n", - (int)sizeof(rectangle)); - - // box size == pointer size - printf("Boxed point occupies %d bytes on the stack\n", - (int)sizeof(boxed_point)); - printf("Boxed rectangle occupies %d bytes on the stack\n", - (int)sizeof(boxed_rectangle)); - printf("Boxed box occupies %d bytes on the stack\n", - (int)sizeof(box_in_a_box)); - - // Copy the data contained in `boxed_point` into `unboxed_point` - Point unboxed_point = *boxed_point.get; - printf("Unboxed point occupies %d bytes on the stack\n", - (int)sizeof(unboxed_point)); - } -} diff --git a/misc/examples/cointerleave.c b/misc/examples/cointerleave.c deleted file mode 100644 index 599ceaab..00000000 --- a/misc/examples/cointerleave.c +++ /dev/null @@ -1,62 +0,0 @@ -// https://www.youtube.com/watch?v=8sEe-4tig_A -#include -#include -#define i_type IVec -#define i_key int -#include - -struct GenValue { - IVec *v; - IVec_iter it; - int cco_state; -}; - -static int get_value(struct GenValue* g) -{ - cco_routine(g) { - for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it)) - cco_yield_v(*g->it.ref); - } - return -1; -} - -struct Generator { - struct GenValue x, y; - int cco_state; - int value; -}; - -cco_result interleaved(struct Generator* g) -{ - cco_routine(g) { - while (!(cco_done(&g->x) & cco_done(&g->y))) { - g->value = get_value(&g->x); - if (!cco_done(&g->x)) - cco_yield(); - - g->value = get_value(&g->y); - if (!cco_done(&g->y)) - cco_yield(); - } - } - return CCO_DONE; -} - -void Use(void) -{ - IVec a = c_init(IVec, {2, 4, 6, 8, 10, 11}); - IVec b = c_init(IVec, {3, 5, 7, 9}); - - struct Generator g = {{&a}, {&b}}; - - cco_block_on(interleaved(&g)) { - printf("%d ", g.value); - } - puts(""); - c_drop(IVec, &a, &b); -} - -int main(void) -{ - Use(); -} diff --git a/misc/examples/complex.c b/misc/examples/complex.c deleted file mode 100644 index 4eb1574b..00000000 --- a/misc/examples/complex.c +++ /dev/null @@ -1,49 +0,0 @@ - -// Define similar c++ data types: -// -// using FloatStack = std::stack; -// using StackList = std::stack; -// using ListMap = std::unordered_map>; -// using MapMap = std::unordered_map; -#define i_implement -#include - -#define i_type FloatStack -#define i_key float -#include - -#define i_type StackList -#define i_keyclass FloatStack // "class" picks up _clone, _drop, _cmp -#define i_opt c_no_cmp // exclude FloatStack_cmp(): not defined -#include - -#define i_type ListMap -#define i_key int -#define i_valclass StackList // "class" picks up _clone, _drop -#include - -#define i_type MapMap -#define i_key_str -#define i_valclass ListMap -#include - - -int main(void) -{ - MapMap mmap = {0}; - - // Put in some data in the structures - ListMap* lmap = &MapMap_emplace(&mmap, "first", ListMap_init()).ref->second; - StackList* list = &ListMap_insert(lmap, 42, StackList_init()).ref->second; - FloatStack* stack = StackList_push_back(list, FloatStack_with_size(10, 0)); - stack->data[3] = 3.1415927f; - printf("stack size: %" c_ZI "\n", FloatStack_size(stack)); - - // Access the data entry - const ListMap* lmap_p = MapMap_at(&mmap, "first"); - const StackList* list_p = ListMap_at(lmap_p, 42); - const FloatStack* stack_p = StackList_back(list_p); - printf("value is: %f\n", (double)*FloatStack_at(stack_p, 3)); // pi - - MapMap_drop(&mmap); -} diff --git a/misc/examples/convert.c b/misc/examples/convert.c deleted file mode 100644 index fa64560e..00000000 --- a/misc/examples/convert.c +++ /dev/null @@ -1,57 +0,0 @@ -#define i_implement -#include - -#define i_key_str -#define i_val_str -#include - -#define i_key_str -#include - -#define i_key_str -#include - -int main(void) -{ - cmap_str map, mclone; - cvec_str keys = {0}, values = {0}; - clist_str list = {0}; - - c_defer( - cmap_str_drop(&map), - cmap_str_drop(&mclone), - cvec_str_drop(&keys), - cvec_str_drop(&values), - clist_str_drop(&list) - ){ - map = c_init(cmap_str, { - {"green", "#00ff00"}, - {"blue", "#0000ff"}, - {"yellow", "#ffff00"}, - }); - - puts("MAP:"); - c_foreach (i, cmap_str, map) - printf(" %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); - - puts("\nCLONE MAP:"); - mclone = cmap_str_clone(map); - c_foreach (i, cmap_str, mclone) - printf(" %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); - - puts("\nCOPY MAP TO VECS:"); - c_foreach (i, cmap_str, mclone) { - cvec_str_emplace_back(&keys, cstr_str(&i.ref->first)); - cvec_str_emplace_back(&values, cstr_str(&i.ref->second)); - } - c_forrange (i, cvec_str_size(&keys)) - printf(" %s: %s\n", cstr_str(keys.data + i), cstr_str(values.data + i)); - - puts("\nCOPY VEC TO LIST:"); - c_foreach (i, cvec_str, keys) - clist_str_emplace_back(&list, cstr_str(i.ref)); - - c_foreach (i, clist_str, list) - printf(" %s\n", cstr_str(i.ref)); - } -} diff --git a/misc/examples/coread.c b/misc/examples/coread.c deleted file mode 100644 index a13f6be5..00000000 --- a/misc/examples/coread.c +++ /dev/null @@ -1,41 +0,0 @@ -#define i_implement -#include -#include -#include - -// Read file line by line using coroutines: - -struct file_read { - const char* filename; - int cco_state; - FILE* fp; - cstr line; -}; - -int file_read(struct file_read* g) -{ - cco_routine(g) { - g->fp = fopen(g->filename, "r"); - if (!g->fp) cco_return; - g->line = cstr_init(); - - cco_await(!cstr_getline(&g->line, g->fp)); - - cco_cleanup: - printf("finish\n"); - cstr_drop(&g->line); - if (g->fp) fclose(g->fp); - } - return 0; -} - -int main(void) -{ - struct file_read g = {__FILE__}; - int n = 0; - cco_block_on(file_read(&g)) - { - printf("%3d %s\n", ++n, cstr_str(&g.line)); - //if (n == 10) cco_stop(&g); - } -} diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c deleted file mode 100644 index b8dfaa13..00000000 --- a/misc/examples/coroutines.c +++ /dev/null @@ -1,112 +0,0 @@ -#include -#include -#include - -// Demonstrate to call another coroutine from a coroutine: -// First create prime generator, then call fibonacci sequence: - -bool is_prime(long long i) { - for (long long j=2; j*j <= i; ++j) - if (i % j == 0) return false; - return true; -} - -struct prime { - int count, idx; - long long result, pos; - int cco_state; -}; - -int prime(struct prime* g) { - cco_routine(g) { - if (g->result < 2) g->result = 2; - if (g->result == 2) { - if (g->count-- == 0) cco_return; - ++g->idx; - cco_yield(); - } - g->result += !(g->result & 1); - for (g->pos = g->result; g->count > 0; g->pos += 2) { - if (is_prime(g->pos)) { - --g->count; - ++g->idx; - g->result = g->pos; - cco_yield(); - } - } - cco_cleanup: - printf("final prm\n"); - } - return 0; -} - - -// Use coroutine to create a fibonacci sequence generator: - -struct fibonacci { - int count, idx; - long long result, b; - int cco_state; -}; - -int fibonacci(struct fibonacci* g) { - assert(g->count < 94); - - long long sum; - cco_routine(g) { - g->idx = 0; - g->result = 0; - g->b = 1; - for (;;) { - if (g->count-- == 0) - cco_return; - if (++g->idx > 1) { - // NB! locals lasts only until next yield/await! - sum = g->result + g->b; - g->result = g->b; - g->b = sum; - } - cco_yield(); - } - cco_cleanup: - printf("final fib\n"); - } - return 0; -} - -// Combine - -struct combined { - struct prime prm; - struct fibonacci fib; - int cco_state; -}; - -int combined(struct combined* g) { - cco_routine(g) { - cco_await_on(prime(&g->prm)); - cco_await_on(fibonacci(&g->fib)); - - // Reuse the g->prm context and extend the count: - g->prm.count = 8, g->prm.result += 2; - cco_reset(&g->prm); - cco_await_on(prime(&g->prm)); - - cco_cleanup: - puts("final combined"); - } - return 0; -} - -int main(void) -{ - struct combined c = {.prm={.count=8}, .fib={14}}; - int res; - - cco_block_on(combined(&c), &res) { - if (res == CCO_YIELD) - printf("Prime(%d)=%lld, Fib(%d)=%lld\n", - c.prm.idx, c.prm.result, - c.fib.idx, c.fib.result); - } -} diff --git a/misc/examples/coroutines/cointerleave.c b/misc/examples/coroutines/cointerleave.c new file mode 100644 index 00000000..599ceaab --- /dev/null +++ b/misc/examples/coroutines/cointerleave.c @@ -0,0 +1,62 @@ +// https://www.youtube.com/watch?v=8sEe-4tig_A +#include +#include +#define i_type IVec +#define i_key int +#include + +struct GenValue { + IVec *v; + IVec_iter it; + int cco_state; +}; + +static int get_value(struct GenValue* g) +{ + cco_routine(g) { + for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it)) + cco_yield_v(*g->it.ref); + } + return -1; +} + +struct Generator { + struct GenValue x, y; + int cco_state; + int value; +}; + +cco_result interleaved(struct Generator* g) +{ + cco_routine(g) { + while (!(cco_done(&g->x) & cco_done(&g->y))) { + g->value = get_value(&g->x); + if (!cco_done(&g->x)) + cco_yield(); + + g->value = get_value(&g->y); + if (!cco_done(&g->y)) + cco_yield(); + } + } + return CCO_DONE; +} + +void Use(void) +{ + IVec a = c_init(IVec, {2, 4, 6, 8, 10, 11}); + IVec b = c_init(IVec, {3, 5, 7, 9}); + + struct Generator g = {{&a}, {&b}}; + + cco_block_on(interleaved(&g)) { + printf("%d ", g.value); + } + puts(""); + c_drop(IVec, &a, &b); +} + +int main(void) +{ + Use(); +} diff --git a/misc/examples/coroutines/coread.c b/misc/examples/coroutines/coread.c new file mode 100644 index 00000000..a13f6be5 --- /dev/null +++ b/misc/examples/coroutines/coread.c @@ -0,0 +1,41 @@ +#define i_implement +#include +#include +#include + +// Read file line by line using coroutines: + +struct file_read { + const char* filename; + int cco_state; + FILE* fp; + cstr line; +}; + +int file_read(struct file_read* g) +{ + cco_routine(g) { + g->fp = fopen(g->filename, "r"); + if (!g->fp) cco_return; + g->line = cstr_init(); + + cco_await(!cstr_getline(&g->line, g->fp)); + + cco_cleanup: + printf("finish\n"); + cstr_drop(&g->line); + if (g->fp) fclose(g->fp); + } + return 0; +} + +int main(void) +{ + struct file_read g = {__FILE__}; + int n = 0; + cco_block_on(file_read(&g)) + { + printf("%3d %s\n", ++n, cstr_str(&g.line)); + //if (n == 10) cco_stop(&g); + } +} diff --git a/misc/examples/coroutines/coroutines.c b/misc/examples/coroutines/coroutines.c new file mode 100644 index 00000000..b8dfaa13 --- /dev/null +++ b/misc/examples/coroutines/coroutines.c @@ -0,0 +1,112 @@ +#include +#include +#include + +// Demonstrate to call another coroutine from a coroutine: +// First create prime generator, then call fibonacci sequence: + +bool is_prime(long long i) { + for (long long j=2; j*j <= i; ++j) + if (i % j == 0) return false; + return true; +} + +struct prime { + int count, idx; + long long result, pos; + int cco_state; +}; + +int prime(struct prime* g) { + cco_routine(g) { + if (g->result < 2) g->result = 2; + if (g->result == 2) { + if (g->count-- == 0) cco_return; + ++g->idx; + cco_yield(); + } + g->result += !(g->result & 1); + for (g->pos = g->result; g->count > 0; g->pos += 2) { + if (is_prime(g->pos)) { + --g->count; + ++g->idx; + g->result = g->pos; + cco_yield(); + } + } + cco_cleanup: + printf("final prm\n"); + } + return 0; +} + + +// Use coroutine to create a fibonacci sequence generator: + +struct fibonacci { + int count, idx; + long long result, b; + int cco_state; +}; + +int fibonacci(struct fibonacci* g) { + assert(g->count < 94); + + long long sum; + cco_routine(g) { + g->idx = 0; + g->result = 0; + g->b = 1; + for (;;) { + if (g->count-- == 0) + cco_return; + if (++g->idx > 1) { + // NB! locals lasts only until next yield/await! + sum = g->result + g->b; + g->result = g->b; + g->b = sum; + } + cco_yield(); + } + cco_cleanup: + printf("final fib\n"); + } + return 0; +} + +// Combine + +struct combined { + struct prime prm; + struct fibonacci fib; + int cco_state; +}; + +int combined(struct combined* g) { + cco_routine(g) { + cco_await_on(prime(&g->prm)); + cco_await_on(fibonacci(&g->fib)); + + // Reuse the g->prm context and extend the count: + g->prm.count = 8, g->prm.result += 2; + cco_reset(&g->prm); + cco_await_on(prime(&g->prm)); + + cco_cleanup: + puts("final combined"); + } + return 0; +} + +int main(void) +{ + struct combined c = {.prm={.count=8}, .fib={14}}; + int res; + + cco_block_on(combined(&c), &res) { + if (res == CCO_YIELD) + printf("Prime(%d)=%lld, Fib(%d)=%lld\n", + c.prm.idx, c.prm.result, + c.fib.idx, c.fib.result); + } +} diff --git a/misc/examples/coroutines/cotasks1.c b/misc/examples/coroutines/cotasks1.c new file mode 100644 index 00000000..c87582f1 --- /dev/null +++ b/misc/examples/coroutines/cotasks1.c @@ -0,0 +1,100 @@ +// https://mariusbancila.ro/blog/2020/06/22/a-cpp20-coroutine-example/ + +#include +#include +#define i_static +#include +#include + +struct next_value { + int val; + int cco_state; + cco_timer tm; +}; + +int next_value(struct next_value* co) +{ + cco_routine (co) { + while (true) { + cco_timer_await(&co->tm, 1 + rand() % 2); + co->val = rand(); + cco_yield(); + } + } + return 0; +} + +void print_time() +{ + time_t now = time(NULL); + char mbstr[64]; + strftime(mbstr, sizeof(mbstr), "[%H:%M:%S]", localtime(&now)); + printf("%s ", mbstr); +} + +// PRODUCER + +struct produce_items { + struct next_value next; + cstr str; + int cco_state; +}; + +int produce_items(struct produce_items* p) +{ + cco_routine (p) { + p->str = cstr_null; + while (true) + { + cco_await(next_value(&p->next) != CCO_AWAIT); + cstr_printf(&p->str, "item %d", p->next.val); + print_time(); + printf("produced %s\n", cstr_str(&p->str)); + cco_yield(); + } + cco_cleanup: + cstr_drop(&p->str); + puts("done produce"); + } + return 0; +} + +// CONSUMER + +struct consume_items { + int n, i; + int cco_state; +}; + +int consume_items(struct consume_items* c, struct produce_items* p) +{ + cco_routine (c) { + for (c->i = 1; c->i <= c->n; ++c->i) + { + printf("consume #%d\n", c->i); + cco_await(produce_items(p) != CCO_AWAIT); + print_time(); + printf("consumed %s\n", cstr_str(&p->str)); + } + cco_cleanup: + puts("done consume"); + } + return 0; +} + +int main(void) +{ + struct produce_items produce = {0}; + struct consume_items consume = {.n=5}; + int count = 0; + + cco_block_on(consume_items(&consume, &produce)) + { + ++count; + //cco_sleep(0.001); + //if (consume.i == 3) cco_stop(&consume); + } + cco_stop(&produce); + produce_items(&produce); + printf("count: %d\n", count); +} \ No newline at end of file diff --git a/misc/examples/coroutines/cotasks2.c b/misc/examples/coroutines/cotasks2.c new file mode 100644 index 00000000..293583bc --- /dev/null +++ b/misc/examples/coroutines/cotasks2.c @@ -0,0 +1,103 @@ +// https://mariusbancila.ro/blog/2020/06/22/a-cpp20-coroutine-example/ + +#include +#include +#define i_static +#include +#include + +cco_task_struct (next_value, + int val; + cco_timer tm; +); + +int next_value(struct next_value* co, cco_runtime* rt) +{ + cco_routine (co) { + while (true) { + cco_timer_await(&co->tm, 1 + rand() % 2); + co->val = rand(); + cco_yield(); + } + } + return 0; +} + +void print_time() +{ + time_t now = time(NULL); + char mbstr[64]; + strftime(mbstr, sizeof(mbstr), "[%H:%M:%S]", localtime(&now)); + printf("%s ", mbstr); +} + +// PRODUCER + +cco_task_struct (produce_items, + struct next_value next; + cstr str; +); + +int produce_items(struct produce_items* p, cco_runtime* rt) +{ + cco_routine (p) { + p->str = cstr_null; + while (true) + { + // await for next CCO_YIELD in next_value() + cco_await_task(&p->next, rt, CCO_YIELD); + cstr_printf(&p->str, "item %d", p->next.val); + print_time(); + printf("produced %s\n", cstr_str(&p->str)); + cco_yield(); + } + cco_cleanup: + cstr_drop(&p->str); + puts("done produce"); + } + return 0; +} + +// CONSUMER + +cco_task_struct (consume_items, + int n, i; + struct produce_items produce; +); + +int consume_items(struct consume_items* c, cco_runtime* rt) +{ + cco_routine (c) { + for (c->i = 1; c->i <= c->n; ++c->i) + { + printf("consume #%d\n", c->i); + cco_await_task(&c->produce, rt, CCO_YIELD); + print_time(); + printf("consumed %s\n", cstr_str(&c->produce.str)); + } + cco_cleanup: + cco_stop(&c->produce); + cco_resume(&c->produce, rt); + puts("done consume"); + } + return 0; +} + +int main(void) +{ + struct consume_items consume = { + .n=5, + .cco_fn=consume_items, + .produce={.cco_fn=produce_items, .next={.cco_fn=next_value}}, + }; + int count = 0; + + cco_block_task(&consume) + { + ++count; + //cco_sleep(0.001); + //if (consume.i == 3) + // cco_stop(&consume); + } + printf("count: %d\n", count); +} \ No newline at end of file diff --git a/misc/examples/coroutines/dining_philosophers.c b/misc/examples/coroutines/dining_philosophers.c new file mode 100644 index 00000000..a5063a42 --- /dev/null +++ b/misc/examples/coroutines/dining_philosophers.c @@ -0,0 +1,105 @@ +// https://en.wikipedia.org/wiki/Dining_philosophers_problem +#include +#include +#include +#include + +// Define the number of philosophers and forks +enum { + num_philosophers = 5, + num_forks = num_philosophers, +}; + +struct Philosopher { + int id; + cco_timer tm; + cco_sem* left_fork; + cco_sem* right_fork; + int cco_state; // required +}; + +struct Dining { + // Define semaphores for the forks + cco_sem forks[num_forks]; + struct Philosopher ph[num_philosophers]; + int cco_state; // required +}; + + +// Philosopher coroutine +int philosopher(struct Philosopher* p) +{ + double duration; + cco_routine(p) { + while (1) { + duration = 1.0 + crandf()*2.0; + printf("Philosopher %d is thinking for %.0f minutes...\n", p->id, duration*10); + cco_timer_await(&p->tm, duration); + + printf("Philosopher %d is hungry...\n", p->id); + cco_sem_await(p->left_fork); + cco_sem_await(p->right_fork); + + duration = 0.5 + crandf(); + printf("Philosopher %d is eating for %.0f minutes...\n", p->id, duration*10); + cco_timer_await(&p->tm, duration); + + cco_sem_release(p->left_fork); + cco_sem_release(p->right_fork); + } + + cco_cleanup: + printf("Philosopher %d finished\n", p->id); + } + return 0; +} + + +// Dining coroutine +int dining(struct Dining* d) +{ + cco_routine(d) { + for (int i = 0; i < num_forks; ++i) + cco_sem_set(&d->forks[i], 1); // all forks available + for (int i = 0; i < num_philosophers; ++i) { + cco_reset(&d->ph[i]); + d->ph[i].id = i + 1; + d->ph[i].left_fork = &d->forks[i]; + d->ph[i].right_fork = &d->forks[(i + 1) % num_forks]; + } + + while (1) { + // per-"frame" logic resume each philosopher + for (int i = 0; i < num_philosophers; ++i) { + philosopher(&d->ph[i]); + } + cco_yield(); // suspend, return control back to main + } + + cco_cleanup: + for (int i = 0; i < num_philosophers; ++i) { + cco_stop(&d->ph[i]); + philosopher(&d->ph[i]); + } + puts("Dining finished"); + } + return 0; +} + +int main(void) +{ + struct Dining dine; + cco_reset(&dine); + int n=0; + cco_timer tm = cco_timer_from(15.0); // seconds + csrand((uint64_t)time(NULL)); + + while (!cco_done(&dine)) { + if (cco_timer_expired(&tm)) + cco_stop(&dine); + dining(&dine); // resume + cco_sleep(0.001); + ++n; + } + printf("n=%d\n", n); +} diff --git a/misc/examples/coroutines/generator.c b/misc/examples/coroutines/generator.c new file mode 100644 index 00000000..a15f9ba5 --- /dev/null +++ b/misc/examples/coroutines/generator.c @@ -0,0 +1,55 @@ +// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ + +#include +#include + +typedef struct { + int size; + int a, b, c; +} Triple, Triple_value; + +typedef struct { + Triple_value* ref; + int count; + int cco_state; +} Triple_iter; + +int Triple_next(Triple_iter* it) { + Triple_value* g = it->ref; + cco_routine(it) + { + for (g->c = 5; g->size; ++g->c) { + for (g->a = 1; g->a < g->c; ++g->a) { + for (g->b = g->a; g->b < g->c; ++g->b) { + if (g->a*g->a + g->b*g->b == g->c*g->c) { + if (it->count++ == g->size) + cco_return; + cco_yield(); + } + } + } + } + cco_cleanup: + it->ref = NULL; + } + return 0; +} + +Triple_iter Triple_begin(Triple* g) { + Triple_iter it = {.ref=g}; + Triple_next(&it); + return it; +} + + +int main(void) +{ + puts("Pythagorean triples with c < 100:"); + Triple triple = {.size=30}; // max number of triples + c_foreach (i, Triple, triple) { + if (i.ref->c < 100) + 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/coroutines/scheduler.c b/misc/examples/coroutines/scheduler.c new file mode 100644 index 00000000..38defd0f --- /dev/null +++ b/misc/examples/coroutines/scheduler.c @@ -0,0 +1,74 @@ +// https://www.youtube.com/watch?v=8sEe-4tig_A +#include +#include + +struct Task { + int (*fn)(struct Task*); + int cco_state; + struct Scheduler* sched; +}; + +#define i_type Scheduler +#define i_key struct Task +#include + +static bool schedule(Scheduler* sched) +{ + struct Task task = *Scheduler_front(sched); + Scheduler_pop(sched); + + if (!cco_done(&task)) + task.fn(&task); + + return !Scheduler_empty(sched); +} + +static int push_task(const struct Task* task) +{ + Scheduler_push(task->sched, *task); + return CCO_YIELD; +} + + +static int taskA(struct Task* task) +{ + cco_routine(task) { + puts("Hello, from task A"); + cco_yield_v(push_task(task)); + puts("A is back doing work"); + cco_yield_v(push_task(task)); + puts("A is back doing more work"); + cco_yield_v(push_task(task)); + puts("A is back doing even more work"); + } + return 0; +} + +static int taskB(struct Task* task) +{ + cco_routine(task) { + puts("Hello, from task B"); + cco_yield_v(push_task(task)); + puts("B is back doing work"); + cco_yield_v(push_task(task)); + puts("B is back doing more work"); + } + return 0; +} + +void Use(void) +{ + Scheduler scheduler = c_init(Scheduler, { + {.fn=taskA, .sched=&scheduler}, + {.fn=taskB, .sched=&scheduler}, + }); + + while (schedule(&scheduler)) {} + + Scheduler_drop(&scheduler); +} + +int main(void) +{ + Use(); +} diff --git a/misc/examples/coroutines/triples.c b/misc/examples/coroutines/triples.c new file mode 100644 index 00000000..9f2fcc1e --- /dev/null +++ b/misc/examples/coroutines/triples.c @@ -0,0 +1,72 @@ +// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ + +#include +#include + +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, 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 && gcd(a, b) == 1) { + printf("%d: {%d, %d, %d}\n", ++i, a, b, c); + if (--n == 0) goto done; + } + } + } + } + done:; +} + +struct triples { + int size, count; + int a, b, c; + int cco_state; +}; + +int triples_coro(struct triples* t) { + cco_routine(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(); + } + } + } + } + cco_cleanup: + puts("done"); + } + return 0; +} + +int main(void) +{ + puts("Vanilla triples:"); + triples_vanilla(5); + + puts("\nCoroutine triples:"); + struct triples t = {.size=INT32_MAX}; + int n = 0; + + while (triples_coro(&t)) { + if (gcd(t.a, t.b) > 1) + continue; + if (t.c < 100) + printf("%d: {%d, %d, %d}\n", ++n, t.a, t.b, t.c); + else + cco_stop(&t); + } +} diff --git a/misc/examples/csmap_erase.c b/misc/examples/csmap_erase.c deleted file mode 100644 index 8d4eeae3..00000000 --- a/misc/examples/csmap_erase.c +++ /dev/null @@ -1,82 +0,0 @@ -// map_erase.c -// From C++ example: https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-16 -#define i_implement -#include -#include - -#define i_key int -#define i_val_str -#define i_type mymap -#include - -void printmap(mymap m) -{ - c_foreach (elem, mymap, m) - printf(" [%d, %s]", elem.ref->first, cstr_str(&elem.ref->second)); - printf("\nsize() == %" c_ZI "\n\n", mymap_size(&m)); -} - -int main(void) -{ - mymap m1 = {0}; - - // Fill in some data to test with, one at a time - mymap_insert(&m1, 1, cstr_lit("A")); - mymap_insert(&m1, 2, cstr_lit("B")); - mymap_insert(&m1, 3, cstr_lit("C")); - mymap_insert(&m1, 4, cstr_lit("D")); - mymap_insert(&m1, 5, cstr_lit("E")); - - puts("Starting data of map m1 is:"); - printmap(m1); - // The 1st member function removes an element at a given position - mymap_erase_at(&m1, mymap_advance(mymap_begin(&m1), 1)); - puts("After the 2nd element is deleted, the map m1 is:"); - printmap(m1); - - // Fill in some data to test with - mymap m2 = c_init(mymap, { - {10, "Bob"}, - {11, "Rob"}, - {12, "Robert"}, - {13, "Bert"}, - {14, "Bobby"}, - }); - - puts("Starting data of map m2 is:"); - printmap(m2); - mymap_iter it1 = mymap_advance(mymap_begin(&m2), 1); - mymap_iter it2 = mymap_find(&m2, mymap_back(&m2)->first); - - puts("to remove:"); - c_foreach (i, mymap, it1, it2) - printf(" [%d, %s]", i.ref->first, cstr_str(&i.ref->second)); - puts(""); - // The 2nd member function removes elements - // in the range [First, Last) - mymap_erase_range(&m2, it1, it2); - puts("After the middle elements are deleted, the map m2 is:"); - printmap(m2); - - mymap m3 = {0}; - - // Fill in some data to test with, one at a time, using emplace - mymap_emplace(&m3, 1, "red"); - mymap_emplace(&m3, 2, "yellow"); - mymap_emplace(&m3, 3, "blue"); - mymap_emplace(&m3, 4, "green"); - mymap_emplace(&m3, 5, "orange"); - mymap_emplace(&m3, 6, "purple"); - mymap_emplace(&m3, 7, "pink"); - - puts("Starting data of map m3 is:"); - printmap(m3); - // The 3rd member function removes elements with a given Key - int count = mymap_erase(&m3, 2); - // The 3rd member function also returns the number of elements removed - printf("The number of elements removed from m3 is: %d\n", count); - puts("After the element with a key of 2 is deleted, the map m3 is:"); - printmap(m3); - - c_drop(mymap, &m1, &m2, &m3); -} diff --git a/misc/examples/csmap_find.c b/misc/examples/csmap_find.c deleted file mode 100644 index c392338d..00000000 --- a/misc/examples/csmap_find.c +++ /dev/null @@ -1,73 +0,0 @@ -// This implements the c++ std::map::find example at: -// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-17 -#define i_implement -#include - -#define i_key int -#define i_val_str -#define i_tag istr -#include - -#define i_key csmap_istr_raw -#define i_tag istr -#include - -void print_elem(csmap_istr_raw p) { - printf("(%d, %s) ", p.first, p.second); -} - -#define using_print_collection(CX) \ - void print_collection_##CX(const CX* t) { \ - printf("%" c_ZI " elements: ", CX##_size(t)); \ - \ - c_foreach (p, CX, *t) { \ - print_elem(CX##_value_toraw(p.ref)); \ - } \ - puts(""); \ - } - -using_print_collection(csmap_istr) -using_print_collection(cvec_istr) - -void findit(csmap_istr c, csmap_istr_key val) -{ - printf("Trying find() on value %d\n", val); - csmap_istr_iter result = csmap_istr_find(&c, val); // prefer contains() or get() - if (result.ref) { - printf("Element found: "); print_elem(csmap_istr_value_toraw(result.ref)); puts(""); - } else { - puts("Element not found."); - } -} - -int main(void) -{ - csmap_istr m1 = c_init(csmap_istr, {{40, "Zr"}, {45, "Rh"}}); - cvec_istr v = {0}; - - puts("The starting map m1 is (key, value):"); - print_collection_csmap_istr(&m1); - - typedef cvec_istr_value pair; - cvec_istr_push(&v, c_LITERAL(pair){43, "Tc"}); - cvec_istr_push(&v, c_LITERAL(pair){41, "Nb"}); - cvec_istr_push(&v, c_LITERAL(pair){46, "Pd"}); - cvec_istr_push(&v, c_LITERAL(pair){42, "Mo"}); - cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"}); - cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"}); // attempt a duplicate - - puts("Inserting the following vector data into m1:"); - print_collection_cvec_istr(&v); - - c_foreach (i, cvec_istr, cvec_istr_begin(&v), cvec_istr_end(&v)) - csmap_istr_emplace(&m1, i.ref->first, i.ref->second); - - puts("The modified map m1 is (key, value):"); - print_collection_csmap_istr(&m1); - puts(""); - findit(m1, 45); - findit(m1, 6); - - csmap_istr_drop(&m1); - cvec_istr_drop(&v); -} diff --git a/misc/examples/csmap_insert.c b/misc/examples/csmap_insert.c deleted file mode 100644 index c9f02891..00000000 --- a/misc/examples/csmap_insert.c +++ /dev/null @@ -1,108 +0,0 @@ -// This implements the std::map insert c++ example at: -// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-19 -#define i_key int -#define i_val int -#define i_tag ii // Map of int => int -#include - -#define i_implement -#include -#define i_key int -#define i_val_str -#define i_tag istr // Map of int => cstr -#include - -#define i_key csmap_ii_raw -#define i_opt c_no_cmp -#define i_tag ii -#include - -void print_ii(csmap_ii map) { - c_foreach (e, csmap_ii, map) - printf("(%d, %d) ", e.ref->first, e.ref->second); - puts(""); -} - -void print_istr(csmap_istr map) { - c_foreach (e, csmap_istr, map) - printf("(%d, %s) ", e.ref->first, cstr_str(&e.ref->second)); - puts(""); -} - -int main(void) -{ - // insert single values - csmap_ii m1 = {0}; - csmap_ii_insert(&m1, 1, 10); - csmap_ii_push(&m1, c_LITERAL(csmap_ii_value){2, 20}); - - puts("The original key and mapped values of m1 are:"); - print_ii(m1); - - // intentionally attempt a duplicate, single element - csmap_ii_result ret = csmap_ii_insert(&m1, 1, 111); - if (!ret.inserted) { - csmap_ii_value pr = *ret.ref; - puts("Insert failed, element with key value 1 already exists."); - printf(" The existing element is (%d, %d)\n", pr.first, pr.second); - } - else { - puts("The modified key and mapped values of m1 are:"); - print_ii(m1); - } - puts(""); - - csmap_ii_insert(&m1, 3, 30); - puts("The modified key and mapped values of m1 are:"); - print_ii(m1); - puts(""); - - // The templatized version inserting a jumbled range - csmap_ii m2 = {0}; - cvec_ii v = {0}; - typedef cvec_ii_value ipair; - cvec_ii_push(&v, c_LITERAL(ipair){43, 294}); - cvec_ii_push(&v, c_LITERAL(ipair){41, 262}); - cvec_ii_push(&v, c_LITERAL(ipair){45, 330}); - cvec_ii_push(&v, c_LITERAL(ipair){42, 277}); - cvec_ii_push(&v, c_LITERAL(ipair){44, 311}); - - puts("Inserting the following vector data into m2:"); - c_foreach (e, cvec_ii, v) - printf("(%d, %d) ", e.ref->first, e.ref->second); - puts(""); - - c_foreach (e, cvec_ii, v) - csmap_ii_insert_or_assign(&m2, e.ref->first, e.ref->second); - - puts("The modified key and mapped values of m2 are:"); - c_foreach (e, csmap_ii, m2) - printf("(%d, %d) ", e.ref->first, e.ref->second); - puts("\n"); - - // The templatized versions move-constructing elements - csmap_istr m3 = {0}; - csmap_istr_value ip1 = {475, cstr_lit("blue")}, ip2 = {510, cstr_lit("green")}; - - // single element - csmap_istr_insert(&m3, ip1.first, cstr_move(&ip1.second)); - puts("After the first move insertion, m3 contains:"); - print_istr(m3); - - // single element - csmap_istr_insert(&m3, ip2.first, cstr_move(&ip2.second)); - puts("After the second move insertion, m3 contains:"); - print_istr(m3); - puts(""); - - csmap_ii m4 = {0}; - // Insert the elements from an initializer_list - m4 = c_init(csmap_ii, {{4, 44}, {2, 22}, {3, 33}, {1, 11}, {5, 55}}); - puts("After initializer_list insertion, m4 contains:"); - print_ii(m4); - puts(""); - - cvec_ii_drop(&v); - csmap_istr_drop(&m3); - c_drop(csmap_ii, &m1, &m2, &m4); -} diff --git a/misc/examples/csset_erase.c b/misc/examples/csset_erase.c deleted file mode 100644 index 9c7f5e1a..00000000 --- a/misc/examples/csset_erase.c +++ /dev/null @@ -1,41 +0,0 @@ -#include - -#define i_key int -#include - -int main(void) -{ - csset_int set = c_init(csset_int, {30, 20, 80, 40, 60, 90, 10, 70, 50}); - - c_foreach (k, csset_int, set) - printf(" %d", *k.ref); - puts(""); - - int val = 64; - csset_int_iter it; - printf("Show values >= %d:\n", val); - it = csset_int_lower_bound(&set, val); - - c_foreach (k, csset_int, it, csset_int_end(&set)) - printf(" %d", *k.ref); - puts(""); - - printf("Erase values >= %d:\n", val); - while (it.ref) - it = csset_int_erase_at(&set, it); - - c_foreach (k, csset_int, set) - printf(" %d", *k.ref); - puts(""); - - val = 40; - printf("Erase values < %d:\n", val); - it = csset_int_lower_bound(&set, val); - csset_int_erase_range(&set, csset_int_begin(&set), it); - - c_foreach (k, csset_int, set) - printf(" %d", *k.ref); - puts(""); - - csset_int_drop(&set); -} diff --git a/misc/examples/cstr_match.c b/misc/examples/cstr_match.c deleted file mode 100644 index be03e981..00000000 --- a/misc/examples/cstr_match.c +++ /dev/null @@ -1,26 +0,0 @@ -#define i_implement -#include -#include -#include - -int main(void) -{ - cstr ss = cstr_lit("The quick brown fox jumps over the lazy dog.JPG"); - - intptr_t pos = cstr_find_at(&ss, 0, "brown"); - printf("%" c_ZI " [%s]\n", pos, pos == c_NPOS ? "" : cstr_str(&ss) + pos); - printf("equals: %d\n", cstr_equals(&ss, "The quick brown fox jumps over the lazy dog.JPG")); - printf("contains: %d\n", cstr_contains(&ss, "umps ove")); - printf("starts_with: %d\n", cstr_starts_with(&ss, "The quick brown")); - printf("ends_with: %d\n", cstr_ends_with(&ss, ".jpg")); - printf("ends_with: %d\n", cstr_ends_with(&ss, ".JPG")); - - cstr s1 = cstr_lit("hell😀 w😀rl🐨"); - csview ch1 = cstr_u8_chr(&s1, 7); - csview ch2 = cstr_u8_chr(&s1, 10); - printf("%s\nsize: %" c_ZI ", %" c_ZI "\n", cstr_str(&s1), cstr_u8_size(&s1), cstr_size(&s1)); - printf("ch1: %.*s\n", c_SV(ch1)); - printf("ch2: %.*s\n", c_SV(ch2)); - - c_drop(cstr, &ss, &s1); -} diff --git a/misc/examples/demos.c b/misc/examples/demos.c deleted file mode 100644 index 1a604d9f..00000000 --- a/misc/examples/demos.c +++ /dev/null @@ -1,194 +0,0 @@ -#define i_implement -#include - -void stringdemo1(void) -{ - cstr cs = cstr_lit("one-nine-three-seven-five"); - printf("%s.\n", cstr_str(&cs)); - - cstr_insert(&cs, 3, "-two"); - printf("%s.\n", cstr_str(&cs)); - - cstr_erase(&cs, 7, 5); // -nine - printf("%s.\n", cstr_str(&cs)); - - cstr_replace(&cs, "seven", "four", 1); - printf("%s.\n", cstr_str(&cs)); - - cstr_take(&cs, cstr_from_fmt("%s *** %s", cstr_str(&cs), cstr_str(&cs))); - printf("%s.\n", cstr_str(&cs)); - - printf("find \"four\": %s\n", cstr_str(&cs) + cstr_find(&cs, "four")); - - // reassign: - cstr_assign(&cs, "one two three four five six seven"); - cstr_append(&cs, " eight"); - printf("append: %s\n", cstr_str(&cs)); - - cstr_drop(&cs); -} - -#define i_key int64_t -#define i_tag ix -#include - -void vectordemo1(void) -{ - cvec_ix bignums = cvec_ix_with_capacity(100); - cvec_ix_reserve(&bignums, 100); - for (int i = 10; i <= 100; i += 10) - cvec_ix_push(&bignums, i * i); - - printf("erase - %d: %" PRIu64 "\n", 3, bignums.data[3]); - cvec_ix_erase_n(&bignums, 3, 1); // erase index 3 - - cvec_ix_pop(&bignums); // erase the last - cvec_ix_erase_n(&bignums, 0, 1); // erase the first - - for (int i = 0; i < cvec_ix_size(&bignums); ++i) { - printf("%d: %" PRIu64 "\n", i, bignums.data[i]); - } - - cvec_ix_drop(&bignums); -} - -#define i_key_str -#include - -void vectordemo2(void) -{ - cvec_str names = {0}; - cvec_str_emplace_back(&names, "Mary"); - cvec_str_emplace_back(&names, "Joe"); - cvec_str_emplace_back(&names, "Chris"); - cstr_assign(&names.data[1], "Jane"); // replace Joe - printf("names[1]: %s\n", cstr_str(&names.data[1])); - - cvec_str_sort(&names); // Sort the array - - c_foreach (i, cvec_str, names) - printf("sorted: %s\n", cstr_str(i.ref)); - - cvec_str_drop(&names); -} - -#define i_key int -#define i_tag ix -#define i_cmp_native -#include - -void listdemo1(void) -{ - clist_ix nums = {0}, nums2 = {0}; - for (int i = 0; i < 10; ++i) - clist_ix_push_back(&nums, i); - for (int i = 100; i < 110; ++i) - clist_ix_push_back(&nums2, i); - - /* splice nums2 to front of nums */ - clist_ix_splice(&nums, clist_ix_begin(&nums), &nums2); - c_foreach (i, clist_ix, nums) - printf("spliced: %d\n", *i.ref); - puts(""); - - *clist_ix_find(&nums, 104).ref += 50; - clist_ix_remove(&nums, 103); - clist_ix_iter it = clist_ix_begin(&nums); - clist_ix_erase_range(&nums, clist_ix_advance(it, 5), clist_ix_advance(it, 15)); - clist_ix_pop_front(&nums); - clist_ix_push_back(&nums, -99); - clist_ix_sort(&nums); - - c_foreach (i, clist_ix, nums) - printf("sorted: %d\n", *i.ref); - - c_drop(clist_ix, &nums, &nums2); -} - -#define i_key int -#define i_tag i -#include - -void setdemo1(void) -{ - cset_i nums = {0}; - cset_i_insert(&nums, 8); - cset_i_insert(&nums, 11); - - c_foreach (i, cset_i, nums) - printf("set: %d\n", *i.ref); - cset_i_drop(&nums); -} - -#define i_key int -#define i_val int -#define i_tag ii -#include - -void mapdemo1(void) -{ - cmap_ii nums = {0}; - cmap_ii_insert(&nums, 8, 64); - cmap_ii_insert(&nums, 11, 121); - printf("val 8: %d\n", *cmap_ii_at(&nums, 8)); - cmap_ii_drop(&nums); -} - -#define i_key_str -#define i_val int -#define i_tag si -#include - -void mapdemo2(void) -{ - cmap_si nums = {0}; - cmap_si_emplace_or_assign(&nums, "Hello", 64); - cmap_si_emplace_or_assign(&nums, "Groovy", 121); - cmap_si_emplace_or_assign(&nums, "Groovy", 200); // overwrite previous - - // iterate the map: - for (cmap_si_iter i = cmap_si_begin(&nums); i.ref; cmap_si_next(&i)) - printf("long: %s: %d\n", cstr_str(&i.ref->first), i.ref->second); - - // or rather use the short form: - c_foreach (i, cmap_si, nums) - printf("short: %s: %d\n", cstr_str(&i.ref->first), i.ref->second); - - cmap_si_drop(&nums); -} - -#define i_key_str -#define i_val_str -#include - -void mapdemo3(void) -{ - cmap_str table = {0}; - cmap_str_emplace(&table, "Map", "test"); - cmap_str_emplace(&table, "Make", "my"); - cmap_str_emplace(&table, "Sunny", "day"); - cmap_str_iter it = cmap_str_find(&table, "Make"); - c_foreach (i, cmap_str, table) - printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); - printf("size %" c_ZI ": remove: Make: %s\n", cmap_str_size(&table), cstr_str(&it.ref->second)); - //cmap_str_erase(&table, "Make"); - cmap_str_erase_at(&table, it); - - printf("size %" c_ZI "\n", cmap_str_size(&table)); - c_foreach (i, cmap_str, table) - printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); - - cmap_str_drop(&table); // frees key and value cstrs, and hash table. -} - -int main(void) -{ - printf("\nSTRINGDEMO1\n"); stringdemo1(); - printf("\nVECTORDEMO1\n"); vectordemo1(); - printf("\nVECTORDEMO2\n"); vectordemo2(); - printf("\nLISTDEMO1\n"); listdemo1(); - printf("\nSETDEMO1\n"); setdemo1(); - printf("\nMAPDEMO1\n"); mapdemo1(); - printf("\nMAPDEMO2\n"); mapdemo2(); - printf("\nMAPDEMO3\n"); mapdemo3(); -} diff --git a/misc/examples/dining_philosophers.c b/misc/examples/dining_philosophers.c deleted file mode 100644 index a5063a42..00000000 --- a/misc/examples/dining_philosophers.c +++ /dev/null @@ -1,105 +0,0 @@ -// https://en.wikipedia.org/wiki/Dining_philosophers_problem -#include -#include -#include -#include - -// Define the number of philosophers and forks -enum { - num_philosophers = 5, - num_forks = num_philosophers, -}; - -struct Philosopher { - int id; - cco_timer tm; - cco_sem* left_fork; - cco_sem* right_fork; - int cco_state; // required -}; - -struct Dining { - // Define semaphores for the forks - cco_sem forks[num_forks]; - struct Philosopher ph[num_philosophers]; - int cco_state; // required -}; - - -// Philosopher coroutine -int philosopher(struct Philosopher* p) -{ - double duration; - cco_routine(p) { - while (1) { - duration = 1.0 + crandf()*2.0; - printf("Philosopher %d is thinking for %.0f minutes...\n", p->id, duration*10); - cco_timer_await(&p->tm, duration); - - printf("Philosopher %d is hungry...\n", p->id); - cco_sem_await(p->left_fork); - cco_sem_await(p->right_fork); - - duration = 0.5 + crandf(); - printf("Philosopher %d is eating for %.0f minutes...\n", p->id, duration*10); - cco_timer_await(&p->tm, duration); - - cco_sem_release(p->left_fork); - cco_sem_release(p->right_fork); - } - - cco_cleanup: - printf("Philosopher %d finished\n", p->id); - } - return 0; -} - - -// Dining coroutine -int dining(struct Dining* d) -{ - cco_routine(d) { - for (int i = 0; i < num_forks; ++i) - cco_sem_set(&d->forks[i], 1); // all forks available - for (int i = 0; i < num_philosophers; ++i) { - cco_reset(&d->ph[i]); - d->ph[i].id = i + 1; - d->ph[i].left_fork = &d->forks[i]; - d->ph[i].right_fork = &d->forks[(i + 1) % num_forks]; - } - - while (1) { - // per-"frame" logic resume each philosopher - for (int i = 0; i < num_philosophers; ++i) { - philosopher(&d->ph[i]); - } - cco_yield(); // suspend, return control back to main - } - - cco_cleanup: - for (int i = 0; i < num_philosophers; ++i) { - cco_stop(&d->ph[i]); - philosopher(&d->ph[i]); - } - puts("Dining finished"); - } - return 0; -} - -int main(void) -{ - struct Dining dine; - cco_reset(&dine); - int n=0; - cco_timer tm = cco_timer_from(15.0); // seconds - csrand((uint64_t)time(NULL)); - - while (!cco_done(&dine)) { - if (cco_timer_expired(&tm)) - cco_stop(&dine); - dining(&dine); // resume - cco_sleep(0.001); - ++n; - } - printf("n=%d\n", n); -} diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c deleted file mode 100644 index f3c008b3..00000000 --- a/misc/examples/forfilter.c +++ /dev/null @@ -1,149 +0,0 @@ -#include -#define i_import -#include -#define i_implement -#include -#include -#include - -#define i_type IVec -#define i_key int -#include - -// filters and transforms: -#define flt_skipValue(i, x) (*i.ref != (x)) -#define flt_isEven(i) ((*i.ref & 1) == 0) -#define flt_isOdd(i) (*i.ref & 1) -#define flt_square(i) (*i.ref * *i.ref) - -void demo1(void) -{ - IVec vec = c_init(IVec, {0, 1, 2, 3, 4, 5, 80, 6, 7, 80, 8, 9, 80, - 10, 11, 12, 13, 14, 15, 80, 16, 17}); - - c_forfilter (i, IVec, vec, flt_skipValue(i, 80)) - printf(" %d", *i.ref); - puts(""); - - int sum = 0; - c_forfilter (i, IVec, vec, - c_flt_skipwhile(i, *i.ref != 80) && - c_flt_skip(i, 1) && - flt_isEven(i) && - flt_skipValue(i, 80) && - c_flt_take(i, 5) // short-circuit - ){ - sum += flt_square(i); - } - - printf("\n sum: %d\n", sum); - IVec_drop(&vec); -} - - -/* Rust: -fn main() { - let vector = (1..) // Infinite range of integers - .skip_while(|x| *x != 11) // Skip initial numbers unequal 11 - .filter(|x| x % 2 != 0) // Collect odd numbers - .take(5) // Only take five numbers - .map(|x| x * x) // Square each number - .collect::>(); // Return as a new Vec - println!("{:?}", vector); // Print result -} -*/ -void demo2(void) -{ - IVec vector = {0}; - crange r = crange_make(INT64_MAX); - c_forfilter (x, crange, r, - c_flt_skipwhile(x, *x.ref != 11) && - (*x.ref % 2) != 0 && - c_flt_take(x, 5) - ){ - IVec_push(&vector, (int)(*x.ref * *x.ref)); - } - c_foreach (x, IVec, vector) printf(" %d", *x.ref); - - puts(""); - IVec_drop(&vector); -} - -/* Rust: -fn main() { - let sentence = "This is a sentence in Rust."; - let words: Vec<&str> = sentence - .split_whitespace() - .collect(); - let words_containing_i: Vec<&str> = words - .into_iter() - .filter(|word| word.contains("i")) - .collect(); - println!("{:?}", words_containing_i); -} -*/ -#define i_type SVec -#define i_keyclass csview -#include - -void demo3(void) -{ - const char* sentence = "This is a sentence in C99."; - SVec words = {0}; - c_fortoken (w, sentence, " ") // split words - SVec_push(&words, *w.ref); - - SVec words_containing_i = {0}; - c_forfilter (w, SVec, words, - csview_contains(*w.ref, "i")) - SVec_push(&words_containing_i, *w.ref); - - c_foreach (w, SVec, words_containing_i) - printf(" %.*s", c_SV(*w.ref)); - - puts(""); - c_drop(SVec, &words, &words_containing_i); -} - -void demo4(void) -{ - // Keep only uppercase letters and convert them to lowercase: - csview s = c_sv("ab123cReAghNGnΩoEp"); // Ω = multi-byte - cstr out = {0}; - - c_forfilter (i, csview, s, utf8_isupper(utf8_peek(i.ref))) { - char chr[4]; - utf8_encode(chr, utf8_tolower(utf8_peek(i.ref))); - cstr_push(&out, chr); - } - - printf(" %s\n", cstr_str(&out)); - cstr_drop(&out); -} - -void demo5(void) -{ - #define flt_even(i) ((*i.ref & 1) == 0) - #define flt_mid_decade(i) ((*i.ref % 10) != 0) - crange R = crange_make(1963, INT32_MAX); - - c_forfilter (i, crange, R, - c_flt_skip(i,15) && - c_flt_skipwhile(i, flt_mid_decade(i)) && - c_flt_skip(i,30) && - flt_even(i) && - c_flt_take(i,5) - ){ - printf(" %lld", *i.ref); - } - puts(""); -} - -int main(void) -{ - puts("demo1"); demo1(); - puts("demo2"); demo2(); - puts("demo3"); demo3(); - puts("demo4"); demo4(); - puts("demo5"); demo5(); -} diff --git a/misc/examples/forloops.c b/misc/examples/forloops.c deleted file mode 100644 index 47cced8f..00000000 --- a/misc/examples/forloops.c +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include - -#define i_type IVec -#define i_key int -#include - -#define i_type IMap -#define i_key int -#define i_val int -#include - - -int main(void) -{ - puts("c_forrange:"); - c_forrange (30) printf(" xx"); - puts(""); - - c_forrange (i, 30) printf(" %lld", i); - puts(""); - - c_forrange (i, 30, 60) printf(" %lld", i); - puts(""); - - c_forrange (i, 30, 90, 2) printf(" %lld", i); - - puts("\n\nc_forlist:"); - c_forlist (i, int, {12, 23, 453, 65, 676}) - printf(" %d", *i.ref); - puts(""); - - c_forlist (i, const char*, {"12", "23", "453", "65", "676"}) - printf(" %s", *i.ref); - puts(""); - - IVec vec = c_init(IVec, {12, 23, 453, 65, 113, 215, 676, 34, 67, 20, 27, 66, 189, 45, 280, 199}); - IMap map = c_init(IMap, {{12, 23}, {453, 65}, {676, 123}, {34, 67}}); - - puts("\n\nc_foreach:"); - c_foreach (i, IVec, vec) - printf(" %d", *i.ref); - - puts("\n\nc_foreach_r: reverse"); - c_foreach_rv (i, IVec, vec) - printf(" %d", *i.ref); - - puts("\n\nc_foreach in map:"); - c_foreach (i, IMap, map) - printf(" (%d %d)", i.ref->first, i.ref->second); - - puts("\n\nc_forpair:"); - c_forpair (key, val, IMap, map) - printf(" (%d %d)", *_.key, *_.val); - - #define isOdd(i) (*i.ref & 1) - - puts("\n\nc_forfilter:"); - c_forfilter (i, IVec, vec, - isOdd(i) && - c_flt_skip(i, 4) && - c_flt_take(i, 4) - ){ - printf(" %d", *i.ref); - } - - IVec_drop(&vec); - IMap_drop(&map); -} diff --git a/misc/examples/functor.c b/misc/examples/functor.c deleted file mode 100644 index e3bde1dd..00000000 --- a/misc/examples/functor.c +++ /dev/null @@ -1,57 +0,0 @@ -// Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue -// Example of per-instance less-function on a single priority queue type -// - -#include - -#define i_type IPQue -#define i_base cpque -#define i_key int -#define i_extend bool(*less)(const int*, const int*); -#define i_less(x, y) c_extend()->less(x, y) -// Note: i_less: c_extend() accessible for cpque types -// i_cmp: c_extend() accessible for csmap and csset types -// i_hash/i_eq: c_extend() accessible for cmap and cset types -#include - -void print_queue(const char* name, IPQue_ext q) { - // NB: make a clone because there is no way to traverse - // priority queue's content without erasing the queue. - IPQue_ext copy = {q.less, IPQue_clone(q.get)}; - - for (printf("%s: \t", name); !IPQue_empty(©.get); IPQue_pop(©.get)) - printf("%d ", *IPQue_top(©.get)); - puts(""); - - IPQue_drop(©.get); -} - -static bool int_less(const int* x, const int* y) { return *x < *y; } -static bool int_greater(const int* x, const int* y) { return *x > *y; } -static bool int_lambda(const int* x, const int* y) { return (*x ^ 1) < (*y ^ 1); } - -int main(void) -{ - const int data[] = {1,8,5,6,3,4,0,9,7,2}, n = c_arraylen(data); - printf("data: \t"); - c_forrange (i, n) printf("%d ", data[i]); - puts(""); - - - // Max priority queue - IPQue_ext q1 = {.less=int_less}; - IPQue_put_n(&q1.get, data, n); - print_queue("q1", q1); - - // Min priority queue - IPQue_ext minq1 = {.less=int_greater}; - IPQue_put_n(&minq1.get, data, n); - print_queue("minq1", minq1); - - // Using lambda to compare elements. - IPQue_ext q5 = {.less=int_lambda}; - IPQue_put_n(&q5.get, data, n); - print_queue("q5", q5); - - c_drop(IPQue, &q1.get, &minq1.get, &q5.get); -} diff --git a/misc/examples/gauss2.c b/misc/examples/gauss2.c deleted file mode 100644 index 1ab8ade5..00000000 --- a/misc/examples/gauss2.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include - -#define i_implement -#include -#include - -// Declare int -> int sorted map. -#define i_key int -#define i_val int -#include - -int main(void) -{ - enum {N = 5000000}; - uint64_t seed = (uint64_t)time(NULL); - crand_t rng = crand_init(seed); - const double Mean = round(crand_f64(&rng)*98.0 - 49.0), StdDev = crand_f64(&rng)*10.0 + 1.0, Scale = 74.0; - - printf("Demo of gaussian / normal distribution of %d random samples\n", N); - printf("Mean %f, StdDev %f\n", Mean, StdDev); - - // Setup random engine with normal distribution. - crand_norm_t dist = crand_norm_init(Mean, StdDev); - - // Create and init histogram map with defered destruct - csmap_int hist = {0}; - cstr bar = {0}; - - c_forrange (N) { - int index = (int)round(crand_norm(&rng, &dist)); - csmap_int_insert(&hist, index, 0).ref->second += 1; - } - - // Print the gaussian bar chart - c_forpair (index, count, csmap_int, hist) { - int n = (int)round((double)*_.count * StdDev * Scale * 2.5 / (double)N); - if (n > 0) { - cstr_resize(&bar, n, '*'); - printf("%4d %s\n", *_.index, cstr_str(&bar)); - } - } - cstr_drop(&bar); - csmap_int_drop(&hist); -} diff --git a/misc/examples/generator.c b/misc/examples/generator.c deleted file mode 100644 index a15f9ba5..00000000 --- a/misc/examples/generator.c +++ /dev/null @@ -1,55 +0,0 @@ -// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ - -#include -#include - -typedef struct { - int size; - int a, b, c; -} Triple, Triple_value; - -typedef struct { - Triple_value* ref; - int count; - int cco_state; -} Triple_iter; - -int Triple_next(Triple_iter* it) { - Triple_value* g = it->ref; - cco_routine(it) - { - for (g->c = 5; g->size; ++g->c) { - for (g->a = 1; g->a < g->c; ++g->a) { - for (g->b = g->a; g->b < g->c; ++g->b) { - if (g->a*g->a + g->b*g->b == g->c*g->c) { - if (it->count++ == g->size) - cco_return; - cco_yield(); - } - } - } - } - cco_cleanup: - it->ref = NULL; - } - return 0; -} - -Triple_iter Triple_begin(Triple* g) { - Triple_iter it = {.ref=g}; - Triple_next(&it); - return it; -} - - -int main(void) -{ - puts("Pythagorean triples with c < 100:"); - Triple triple = {.size=30}; // max number of triples - c_foreach (i, Triple, triple) { - if (i.ref->c < 100) - 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/hashmap.c b/misc/examples/hashmap.c deleted file mode 100644 index cf11b7f7..00000000 --- a/misc/examples/hashmap.c +++ /dev/null @@ -1,50 +0,0 @@ -// https://doc.rust-lang.org/rust-by-example/std/hash.html -#define i_implement -#include -#define i_key_str -#define i_val_str -#include -#include - -const char* call(const char* number) { - if (!strcmp(number, "798-1364")) - return "We're sorry, the call cannot be completed as dialed." - " Please hang up and try again."; - else if (!strcmp(number, "645-7689")) - return "Hello, this is Mr. Awesome's Pizza. My name is Fred." - " What can I get for you today?"; - else - return "Hi! Who is this again?"; -} - -int main(void) { - cmap_str contacts = {0}; - - cmap_str_emplace(&contacts, "Daniel", "798-1364"); - cmap_str_emplace(&contacts, "Ashley", "645-7689"); - cmap_str_emplace(&contacts, "Katie", "435-8291"); - cmap_str_emplace(&contacts, "Robert", "956-1745"); - - const cmap_str_value* v; - if ((v = cmap_str_get(&contacts, "Daniel"))) - printf("Calling Daniel: %s\n", call(cstr_str(&v->second))); - else - printf("Don't have Daniel's number."); - - cmap_str_emplace_or_assign(&contacts, "Daniel", "164-6743"); - - if ((v = cmap_str_get(&contacts, "Ashley"))) - printf("Calling Ashley: %s\n", call(cstr_str(&v->second))); - else - printf("Don't have Ashley's number."); - - cmap_str_erase(&contacts, "Ashley"); - - puts(""); - c_forpair (contact, number, cmap_str, contacts) { - printf("Calling %s: %s\n", cstr_str(_.contact), call(cstr_str(_.number))); - } - puts(""); - - cmap_str_drop(&contacts); -} diff --git a/misc/examples/hashmaps/birthday.c b/misc/examples/hashmaps/birthday.c new file mode 100644 index 00000000..4742cb45 --- /dev/null +++ b/misc/examples/hashmaps/birthday.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include + +#define i_tag ic +#define i_key uint64_t +#define i_val int +#include + +static uint64_t seed = 12345; + +static void test_repeats(void) +{ + enum {BITS = 46, BITS_TEST = BITS/2 + 2}; + static const uint64_t N = 1ull << BITS_TEST; + static const uint64_t mask = (1ull << BITS) - 1; + + printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST); + crand_t rng = crand_init(seed); + + cmap_ic m = cmap_ic_with_capacity(N); + c_forrange (i, N) { + uint64_t k = crand_u64(&rng) & mask; + int v = cmap_ic_insert(&m, k, 0).ref->second += 1; + if (v > 1) printf("repeated value %" PRIu64 " (%d) at 2^%d\n", + k, v, (int)log2((double)i)); + } + cmap_ic_drop(&m); +} + +#define i_key uint32_t +#define i_val uint64_t +#define i_tag x +#include + +void test_distribution(void) +{ + enum {BITS = 26}; + printf("distribution test: 2^%d values\n", BITS); + crand_t rng = crand_init(seed); + const size_t N = 1ull << BITS ; + + cmap_x map = {0}; + c_forrange (N) { + uint64_t k = crand_u64(&rng); + cmap_x_insert(&map, k & 0xf, 0).ref->second += 1; + } + + uint64_t sum = 0; + c_foreach (i, cmap_x, map) sum += i.ref->second; + sum /= (uint64_t)map.size; + + c_foreach (i, cmap_x, map) { + printf("%4" PRIu32 ": %" PRIu64 " - %" PRIu64 ": %11.8f\n", + i.ref->first, i.ref->second, sum, + (1.0 - (double)i.ref->second / (double)sum)); + } + + cmap_x_drop(&map); +} + +int main(void) +{ + seed = (uint64_t)time(NULL); + test_distribution(); + test_repeats(); +} diff --git a/misc/examples/hashmaps/books.c b/misc/examples/hashmaps/books.c new file mode 100644 index 00000000..1fd57f27 --- /dev/null +++ b/misc/examples/hashmaps/books.c @@ -0,0 +1,62 @@ +// https://doc.rust-lang.org/std/collections/struct.HashMap.html +#define i_implement +#include +#define i_key_str +#define i_val_str +#include + +// Type inference lets us omit an explicit type signature (which +// would be `HashMap` in this example). +int main(void) +{ + cmap_str book_reviews = {0}; + + // Review some books. + cmap_str_emplace(&book_reviews, + "Adventures of Huckleberry Finn", + "My favorite book." + ); + cmap_str_emplace(&book_reviews, + "Grimms' Fairy Tales", + "Masterpiece." + ); + cmap_str_emplace(&book_reviews, + "Pride and Prejudice", + "Very enjoyable" + ); + cmap_str_insert(&book_reviews, + cstr_lit("The Adventures of Sherlock Holmes"), + cstr_lit("Eye lyked it alot.") + ); + + // Check for a specific one. + // When collections store owned values (String), they can still be + // queried using references (&str). + if (cmap_str_contains(&book_reviews, "Les Misérables")) { + printf("We've got %" c_ZI " reviews, but Les Misérables ain't one.", + cmap_str_size(&book_reviews)); + } + + // oops, this review has a lot of spelling mistakes, let's delete it. + cmap_str_erase(&book_reviews, "The Adventures of Sherlock Holmes"); + + // Look up the values associated with some keys. + const char* to_find[] = {"Pride and Prejudice", "Alice's Adventure in Wonderland"}; + c_forrange (i, c_arraylen(to_find)) { + const cmap_str_value* b = cmap_str_get(&book_reviews, to_find[i]); + if (b) + printf("%s: %s\n", cstr_str(&b->first), cstr_str(&b->second)); + else + printf("%s is unreviewed.\n", to_find[i]); + } + + // Look up the value for a key (will panic if the key is not found). + printf("Review for Jane: %s\n", cstr_str(cmap_str_at(&book_reviews, "Pride and Prejudice"))); + + // Iterate over everything. + c_forpair (book, review, cmap_str, book_reviews) { + printf("%s: \"%s\"\n", cstr_str(_.book), cstr_str(_.review)); + } + + cmap_str_drop(&book_reviews); +} diff --git a/misc/examples/hashmaps/hashmap.c b/misc/examples/hashmaps/hashmap.c new file mode 100644 index 00000000..cf11b7f7 --- /dev/null +++ b/misc/examples/hashmaps/hashmap.c @@ -0,0 +1,50 @@ +// https://doc.rust-lang.org/rust-by-example/std/hash.html +#define i_implement +#include +#define i_key_str +#define i_val_str +#include +#include + +const char* call(const char* number) { + if (!strcmp(number, "798-1364")) + return "We're sorry, the call cannot be completed as dialed." + " Please hang up and try again."; + else if (!strcmp(number, "645-7689")) + return "Hello, this is Mr. Awesome's Pizza. My name is Fred." + " What can I get for you today?"; + else + return "Hi! Who is this again?"; +} + +int main(void) { + cmap_str contacts = {0}; + + cmap_str_emplace(&contacts, "Daniel", "798-1364"); + cmap_str_emplace(&contacts, "Ashley", "645-7689"); + cmap_str_emplace(&contacts, "Katie", "435-8291"); + cmap_str_emplace(&contacts, "Robert", "956-1745"); + + const cmap_str_value* v; + if ((v = cmap_str_get(&contacts, "Daniel"))) + printf("Calling Daniel: %s\n", call(cstr_str(&v->second))); + else + printf("Don't have Daniel's number."); + + cmap_str_emplace_or_assign(&contacts, "Daniel", "164-6743"); + + if ((v = cmap_str_get(&contacts, "Ashley"))) + printf("Calling Ashley: %s\n", call(cstr_str(&v->second))); + else + printf("Don't have Ashley's number."); + + cmap_str_erase(&contacts, "Ashley"); + + puts(""); + c_forpair (contact, number, cmap_str, contacts) { + printf("Calling %s: %s\n", cstr_str(_.contact), call(cstr_str(_.number))); + } + puts(""); + + cmap_str_drop(&contacts); +} diff --git a/misc/examples/hashmaps/new_map.c b/misc/examples/hashmaps/new_map.c new file mode 100644 index 00000000..de990040 --- /dev/null +++ b/misc/examples/hashmaps/new_map.c @@ -0,0 +1,75 @@ +#define i_implement +#include +#include + +forward_cmap(cmap_pnt, struct Point, int); + +typedef struct MyStruct { + cmap_pnt pntmap; + cstr name; +} MyStruct; + +// int => int map +#define i_key int +#define i_val int +#include + +// Point => int map +typedef struct Point { int x, y; } Point; + +int point_cmp(const Point* a, const Point* b) { + int c = a->x - b->x; + return c ? c : a->y - b->y; +} + +// Point => int map +#define i_key Point +#define i_val int +#define i_cmp point_cmp +#define i_hash c_default_hash +#define i_is_forward +#define i_tag pnt +#include + +// cstr => cstr map +#define i_key_str +#define i_val_str +#include + +// string set +#define i_key_str +#include + + +int main(void) +{ + cmap_pnt pmap = c_init(cmap_pnt, {{{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}}); + + c_foreach (i, cmap_pnt, pmap) + printf(" (%d, %d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second); + puts(""); + + cmap_str smap = c_init(cmap_str, { + {"Hello, friend", "long time no see"}, + {"So long", "see you around"}, + }); + + cset_str sset = c_init(cset_str, { + "Hello, friend", + "Nice to see you again", + "So long", + }); + + cmap_int map = {0}; + cmap_int_insert(&map, 123, 321); + cmap_int_insert(&map, 456, 654); + cmap_int_insert(&map, 789, 987); + + c_foreach (i, cset_str, sset) + printf(" %s\n", cstr_str(i.ref)); + + cmap_int_drop(&map); + cset_str_drop(&sset); + cmap_str_drop(&smap); + cmap_pnt_drop(&pmap); +} diff --git a/misc/examples/hashmaps/phonebook.c b/misc/examples/hashmaps/phonebook.c new file mode 100644 index 00000000..faf7566e --- /dev/null +++ b/misc/examples/hashmaps/phonebook.c @@ -0,0 +1,72 @@ +// The MIT License (MIT) +// Copyright (c) 2018 Maksim Andrianov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +// Program to emulates the phone book. +#define i_implement +#include + +#define i_key_str +#define i_val_str +#include + +#define i_key_str +#include + +void print_phone_book(cmap_str phone_book) +{ + c_foreach (i, cmap_str, phone_book) + printf("%s\t- %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); +} + +int main(int argc, char **argv) +{ + cmap_str phone_book = c_init(cmap_str, { + {"Lilia Friedman", "(892) 670-4739"}, + {"Tariq Beltran", "(489) 600-7575"}, + {"Laiba Juarez", "(303) 885-5692"}, + {"Elliott Mooney", "(945) 616-4482"}, + }); + + printf("Phone book:\n"); + print_phone_book(phone_book); + + cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1880"); + cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1990"); + + printf("\nPhone book after adding Zak Byers:\n"); + print_phone_book(phone_book); + + if (cmap_str_contains(&phone_book, "Tariq Beltran")) + printf("\nTariq Beltran is in phone book\n"); + + cmap_str_erase(&phone_book, "Tariq Beltran"); + cmap_str_erase(&phone_book, "Elliott Mooney"); + + printf("\nPhone book after erasing Tariq and Elliott:\n"); + print_phone_book(phone_book); + + cmap_str_emplace_or_assign(&phone_book, "Zak Byers", "(555) 396-188"); + + printf("\nPhone book after update phone of Zak Byers:\n"); + print_phone_book(phone_book); + + cmap_str_drop(&phone_book); +} diff --git a/misc/examples/hashmaps/unordered_set.c b/misc/examples/hashmaps/unordered_set.c new file mode 100644 index 00000000..dd899d78 --- /dev/null +++ b/misc/examples/hashmaps/unordered_set.c @@ -0,0 +1,45 @@ +// https://iq.opengenus.org/containers-cpp-stl/ +// C program to demonstrate various function of stc cset +#define i_implement +#include +#define i_key_str +#include + +int main(void) +{ + // declaring set for storing string data-type + cset_str stringSet = {0}; + c_defer( + cset_str_drop(&stringSet) + ){ + // inserting various string, same string will be stored + // once in set + cset_str_emplace(&stringSet, "code"); + cset_str_emplace(&stringSet, "in"); + cset_str_emplace(&stringSet, "C"); + cset_str_emplace(&stringSet, "is"); + cset_str_emplace(&stringSet, "fast"); + + const char* key = "slow"; + + // find returns end iterator if key is not found, + // else it returns iterator to that key + + if (cset_str_find(&stringSet, key).ref == NULL) + printf("\"%s\" not found\n", key); + else + printf("Found \"%s\"\n", key); + + key = "C"; + if (!cset_str_contains(&stringSet, key)) + printf("\"%s\" not found\n", key); + else + printf("Found \"%s\"\n", key); + + // now iterating over whole set and printing its + // content + printf("All elements :\n"); + c_foreach (itr, cset_str, stringSet) + printf("%s\n", cstr_str(itr.ref)); + } +} diff --git a/misc/examples/hashmaps/vikings.c b/misc/examples/hashmaps/vikings.c new file mode 100644 index 00000000..d6125854 --- /dev/null +++ b/misc/examples/hashmaps/vikings.c @@ -0,0 +1,59 @@ +#define i_implement +#include + +typedef struct Viking { + cstr name; + cstr country; +} Viking; + +void Viking_drop(Viking* vk) { + cstr_drop(&vk->name); + cstr_drop(&vk->country); +} + +// Define Viking lookup struct with hash, cmp, and convertion functions between Viking and RViking structs: + +typedef struct RViking { + const char* name; + const char* country; +} RViking; + +static inline int RViking_cmp(const RViking* rx, const RViking* ry) { + int c = strcmp(rx->name, ry->name); + return c ? c : strcmp(rx->country, ry->country); +} + +static inline Viking Viking_from(RViking raw) { // note: parameter is by value + return c_LITERAL(Viking){cstr_from(raw.name), cstr_from(raw.country)}; +} + +static inline RViking Viking_toraw(const Viking* vp) { + return c_LITERAL(RViking){cstr_str(&vp->name), cstr_str(&vp->country)}; +} + +// With this in place, we define the Viking => int hash map type: +#define i_type Vikings +#define i_keyclass Viking // key type +#define i_rawclass RViking // lookup type +#define i_keyfrom Viking_from +#define i_opt c_no_clone +#define i_hash(rp) cstrhash(rp->name) ^ cstrhash(rp->country) +#define i_val int // mapped type +#include + +int main(void) +{ + Vikings vikings = {0}; + Vikings_emplace(&vikings, c_LITERAL(RViking){"Einar", "Norway"}, 20); + Vikings_emplace(&vikings, c_LITERAL(RViking){"Olaf", "Denmark"}, 24); + Vikings_emplace(&vikings, c_LITERAL(RViking){"Harald", "Iceland"}, 12); + Vikings_emplace(&vikings, c_LITERAL(RViking){"Björn", "Sweden"}, 10); + + Vikings_value* v = Vikings_get_mut(&vikings, c_LITERAL(RViking){"Einar", "Norway"}); + v->second += 3; // add 3 hp points to Einar + + c_forpair (vk, hp, Vikings, vikings) { + printf("%s of %s has %d hp\n", cstr_str(&_.vk->name), cstr_str(&_.vk->country), *_.hp); + } + Vikings_drop(&vikings); +} diff --git a/misc/examples/inits.c b/misc/examples/inits.c deleted file mode 100644 index 53a49f1f..00000000 --- a/misc/examples/inits.c +++ /dev/null @@ -1,108 +0,0 @@ -#define i_implement -#include - -#define i_key int -#define i_val_str -#define i_tag id // Map of int => cstr -#include - -#define i_key_str -#define i_val int -#define i_tag cnt // Map of cstr => int -#include - -typedef struct {int x, y;} ipair_t; -inline static int ipair_cmp(const ipair_t* a, const ipair_t* b) { - int c = c_default_cmp(&a->x, &b->x); - return c ? c : c_default_cmp(&a->y, &b->y); -} - - -#define i_key ipair_t -#define i_cmp ipair_cmp -#define i_tag ip -#include - -#define i_key ipair_t -#define i_cmp ipair_cmp -#define i_tag ip -#include - -#define i_key float -#define i_tag f -#include - -int main(void) -{ - // CVEC FLOAT / PRIORITY QUEUE - - cpque_f floats = {0}; - const float nums[] = {4.0f, 2.0f, 5.0f, 3.0f, 1.0f}; - - // PRIORITY QUEUE - c_forrange (i, c_arraylen(nums)) - cpque_f_push(&floats, nums[i]); - - puts("\npop and show high priorites first:"); - while (! cpque_f_empty(&floats)) { - printf("%.1f ", (double)*cpque_f_top(&floats)); - cpque_f_pop(&floats); - } - puts("\n"); - cpque_f_drop(&floats); - - // CMAP ID - - int year = 2020; - cmap_id idnames = {0}; - cmap_id_emplace(&idnames, 100, "Hello"); - cmap_id_insert(&idnames, 110, cstr_lit("World")); - cmap_id_insert(&idnames, 120, cstr_from_fmt("Howdy, -%d-", year)); - - c_foreach (i, cmap_id, idnames) - printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second)); - puts(""); - cmap_id_drop(&idnames); - - // CMAP CNT - - cmap_cnt countries = c_init(cmap_cnt, { - {"Norway", 100}, - {"Denmark", 50}, - {"Iceland", 10}, - {"Belgium", 10}, - {"Italy", 10}, - {"Germany", 10}, - {"Spain", 10}, - {"France", 10}, - }); - cmap_cnt_emplace(&countries, "Greenland", 0).ref->second += 20; - cmap_cnt_emplace(&countries, "Sweden", 0).ref->second += 20; - cmap_cnt_emplace(&countries, "Norway", 0).ref->second += 20; - cmap_cnt_emplace(&countries, "Finland", 0).ref->second += 20; - - c_forpair (country, health, cmap_cnt, countries) - printf("%s: %d\n", cstr_str(_.country), *_.health); - puts(""); - cmap_cnt_drop(&countries); - - // CVEC PAIR - - cvec_ip pairs1 = c_init(cvec_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); - cvec_ip_sort(&pairs1); - - c_foreach (i, cvec_ip, pairs1) - printf("(%d %d) ", i.ref->x, i.ref->y); - puts(""); - cvec_ip_drop(&pairs1); - - // CLIST PAIR - - clist_ip pairs2 = c_init(clist_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); - clist_ip_sort(&pairs2); - - c_foreach (i, clist_ip, pairs2) - printf("(%d %d) ", i.ref->x, i.ref->y); - puts(""); - clist_ip_drop(&pairs2); -} diff --git a/misc/examples/intrusive.c b/misc/examples/intrusive.c deleted file mode 100644 index c22ed260..00000000 --- a/misc/examples/intrusive.c +++ /dev/null @@ -1,33 +0,0 @@ -// Example of clist using the node API. - -#include - -#define i_type List -#define i_key int -#define i_cmp_native -#include - -void printList(List list) { - printf("list:"); - c_foreach (i, List, list) - printf(" %d", *i.ref); - puts(""); -} - -int main(void) { - List list = {0}; - c_forlist (i, int, {6, 9, 3, 1, 7, 4, 5, 2, 8}) - List_push_back_node(&list, c_new(List_node, {0, *i.ref})); - - printList(list); - - puts("Sort list"); - List_sort(&list); - printList(list); - - puts("Remove nodes from list"); - while (!List_empty(&list)) - c_free(List_unlink_after_node(&list, list.last)); - - printList(list); -} diff --git a/misc/examples/linkedlists/intrusive.c b/misc/examples/linkedlists/intrusive.c new file mode 100644 index 00000000..c22ed260 --- /dev/null +++ b/misc/examples/linkedlists/intrusive.c @@ -0,0 +1,33 @@ +// Example of clist using the node API. + +#include + +#define i_type List +#define i_key int +#define i_cmp_native +#include + +void printList(List list) { + printf("list:"); + c_foreach (i, List, list) + printf(" %d", *i.ref); + puts(""); +} + +int main(void) { + List list = {0}; + c_forlist (i, int, {6, 9, 3, 1, 7, 4, 5, 2, 8}) + List_push_back_node(&list, c_new(List_node, {0, *i.ref})); + + printList(list); + + puts("Sort list"); + List_sort(&list); + printList(list); + + puts("Remove nodes from list"); + while (!List_empty(&list)) + c_free(List_unlink_after_node(&list, list.last)); + + printList(list); +} diff --git a/misc/examples/linkedlists/list.c b/misc/examples/linkedlists/list.c new file mode 100644 index 00000000..ad8bebb8 --- /dev/null +++ b/misc/examples/linkedlists/list.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include + +#define i_type DList +#define i_key double +#define i_cmp_native +#include + +int main(void) { + const int n = 3000000; + DList list = {0}; + + crand_t rng = crand_init(1234567); + int m = 0; + c_forrange (n) + DList_push_back(&list, crand_f64(&rng)*n + 100), ++m; + + double sum = 0.0; + printf("sumarize %d:\n", m); + c_foreach (i, DList, list) + sum += *i.ref; + printf("sum %f\n\n", sum); + + c_forfilter (i, DList, list, c_flt_take(i, 10)) + printf("%8d: %10f\n", c_flt_getcount(i), *i.ref); + + puts("sort"); + DList_sort(&list); // qsort O(n*log n) + puts("sorted"); + + c_forfilter (i, DList, list, c_flt_take(i, 10)) + printf("%8d: %10f\n", c_flt_getcount(i), *i.ref); + puts(""); + + DList_drop(&list); + list = c_init(DList, {10, 20, 30, 40, 30, 50}); + + const double* v = DList_get(&list, 30); + printf("found: %f\n", *v); + + c_foreach (i, DList, list) + printf(" %g", *i.ref); + puts(""); + + DList_remove(&list, 30); + DList_insert_at(&list, DList_begin(&list), 5); // same as push_front() + DList_push_back(&list, 500); + DList_push_front(&list, 1964); + + printf("Full: "); + c_foreach (i, DList, list) + printf(" %g", *i.ref); + + printf("\nSubs: "); + DList_iter it = DList_begin(&list); + + c_foreach (i, DList, DList_advance(it, 4), DList_end(&list)) + printf(" %g", *i.ref); + puts(""); + + DList_drop(&list); +} diff --git a/misc/examples/linkedlists/list_erase.c b/misc/examples/linkedlists/list_erase.c new file mode 100644 index 00000000..211c5a5d --- /dev/null +++ b/misc/examples/linkedlists/list_erase.c @@ -0,0 +1,30 @@ +// erasing from clist +#include + +#define i_type IList +#define i_key int +#include + +int main(void) +{ + IList L = c_init(IList, {10, 20, 30, 40, 50}); + + c_foreach (x, IList, L) + printf("%d ", *x.ref); + puts(""); + // 10 20 30 40 50 + IList_iter it = IList_begin(&L); // ^ + IList_next(&it); + it = IList_erase_at(&L, it); // 10 30 40 50 + // ^ + IList_iter end = IList_end(&L); // + IList_next(&it); + it = IList_erase_range(&L, it, end); // 10 30 + // ^ + printf("list contains:"); + c_foreach (x, IList, L) + printf(" %d", *x.ref); + puts(""); + + IList_drop(&L); +} diff --git a/misc/examples/linkedlists/list_splice.c b/misc/examples/linkedlists/list_splice.c new file mode 100644 index 00000000..f1fd6e1f --- /dev/null +++ b/misc/examples/linkedlists/list_splice.c @@ -0,0 +1,38 @@ +#include + +#define i_key int +#define i_tag i +#include + +void print_ilist(const char* s, clist_i list) +{ + printf("%s", s); + c_foreach (i, clist_i, list) { + printf(" %d", *i.ref); + } + puts(""); +} + +int main(void) +{ + clist_i list1 = c_init(clist_i, {1, 2, 3, 4, 5}); + clist_i list2 = c_init(clist_i, {10, 20, 30, 40, 50}); + + print_ilist("list1:", list1); + print_ilist("list2:", list2); + + clist_i_iter it = clist_i_advance(clist_i_begin(&list1), 2); + it = clist_i_splice(&list1, it, &list2); + + puts("After splice"); + print_ilist("list1:", list1); + print_ilist("list2:", list2); + + clist_i_splice_range(&list2, clist_i_begin(&list2), &list1, it, clist_i_end(&list1)); + + puts("After splice_range"); + print_ilist("list1:", list1); + print_ilist("list2:", list2); + + c_drop(clist_i, &list1, &list2); +} diff --git a/misc/examples/linkedlists/new_list.c b/misc/examples/linkedlists/new_list.c new file mode 100644 index 00000000..2112bf1f --- /dev/null +++ b/misc/examples/linkedlists/new_list.c @@ -0,0 +1,70 @@ +#include +#include + +forward_clist(clist_i32, int); +forward_clist(clist_pnt, struct Point); + +typedef struct { + clist_i32 intlist; + clist_pnt pntlist; +} MyStruct; + +#define i_key int +#define i_tag i32 +#define i_is_forward +#include + +typedef struct Point { int x, y; } Point; +int point_cmp(const Point* a, const Point* b) { + int c = a->x - b->x; + return c ? c : a->y - b->y; +} + +#define i_key Point +#define i_cmp point_cmp +#define i_is_forward +#define i_tag pnt +#include + +#define i_key float +#define i_cmp_native // use < and == operators for comparison +#include + +void MyStruct_drop(MyStruct* s); +#define i_type MyList +#define i_key MyStruct +#define i_keydrop MyStruct_drop // define drop function +#define i_no_clone // must explicitely exclude or define cloning support because of drop. +#include + +void MyStruct_drop(MyStruct* s) { + clist_i32_drop(&s->intlist); + clist_pnt_drop(&s->pntlist); +} + + +int main(void) +{ + MyStruct my = {0}; + clist_i32_push_back(&my.intlist, 123); + clist_pnt_push_back(&my.pntlist, c_LITERAL(Point){123, 456}); + MyStruct_drop(&my); + + clist_pnt plist = c_init(clist_pnt, {{42, 14}, {32, 94}, {62, 81}}); + clist_pnt_sort(&plist); + + c_foreach (i, clist_pnt, plist) + printf(" (%d %d)", i.ref->x, i.ref->y); + puts(""); + clist_pnt_drop(&plist); + + + clist_float flist = c_init(clist_float, {123.3f, 321.2f, -32.2f, 78.2f}); + clist_float_sort(&flist); + + c_foreach (i, clist_float, flist) + printf(" %g", (double)*i.ref); + + puts(""); + clist_float_drop(&flist); +} diff --git a/misc/examples/list.c b/misc/examples/list.c deleted file mode 100644 index ad8bebb8..00000000 --- a/misc/examples/list.c +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include -#include - -#define i_type DList -#define i_key double -#define i_cmp_native -#include - -int main(void) { - const int n = 3000000; - DList list = {0}; - - crand_t rng = crand_init(1234567); - int m = 0; - c_forrange (n) - DList_push_back(&list, crand_f64(&rng)*n + 100), ++m; - - double sum = 0.0; - printf("sumarize %d:\n", m); - c_foreach (i, DList, list) - sum += *i.ref; - printf("sum %f\n\n", sum); - - c_forfilter (i, DList, list, c_flt_take(i, 10)) - printf("%8d: %10f\n", c_flt_getcount(i), *i.ref); - - puts("sort"); - DList_sort(&list); // qsort O(n*log n) - puts("sorted"); - - c_forfilter (i, DList, list, c_flt_take(i, 10)) - printf("%8d: %10f\n", c_flt_getcount(i), *i.ref); - puts(""); - - DList_drop(&list); - list = c_init(DList, {10, 20, 30, 40, 30, 50}); - - const double* v = DList_get(&list, 30); - printf("found: %f\n", *v); - - c_foreach (i, DList, list) - printf(" %g", *i.ref); - puts(""); - - DList_remove(&list, 30); - DList_insert_at(&list, DList_begin(&list), 5); // same as push_front() - DList_push_back(&list, 500); - DList_push_front(&list, 1964); - - printf("Full: "); - c_foreach (i, DList, list) - printf(" %g", *i.ref); - - printf("\nSubs: "); - DList_iter it = DList_begin(&list); - - c_foreach (i, DList, DList_advance(it, 4), DList_end(&list)) - printf(" %g", *i.ref); - puts(""); - - DList_drop(&list); -} diff --git a/misc/examples/list_erase.c b/misc/examples/list_erase.c deleted file mode 100644 index 211c5a5d..00000000 --- a/misc/examples/list_erase.c +++ /dev/null @@ -1,30 +0,0 @@ -// erasing from clist -#include - -#define i_type IList -#define i_key int -#include - -int main(void) -{ - IList L = c_init(IList, {10, 20, 30, 40, 50}); - - c_foreach (x, IList, L) - printf("%d ", *x.ref); - puts(""); - // 10 20 30 40 50 - IList_iter it = IList_begin(&L); // ^ - IList_next(&it); - it = IList_erase_at(&L, it); // 10 30 40 50 - // ^ - IList_iter end = IList_end(&L); // - IList_next(&it); - it = IList_erase_range(&L, it, end); // 10 30 - // ^ - printf("list contains:"); - c_foreach (x, IList, L) - printf(" %d", *x.ref); - puts(""); - - IList_drop(&L); -} diff --git a/misc/examples/list_splice.c b/misc/examples/list_splice.c deleted file mode 100644 index f1fd6e1f..00000000 --- a/misc/examples/list_splice.c +++ /dev/null @@ -1,38 +0,0 @@ -#include - -#define i_key int -#define i_tag i -#include - -void print_ilist(const char* s, clist_i list) -{ - printf("%s", s); - c_foreach (i, clist_i, list) { - printf(" %d", *i.ref); - } - puts(""); -} - -int main(void) -{ - clist_i list1 = c_init(clist_i, {1, 2, 3, 4, 5}); - clist_i list2 = c_init(clist_i, {10, 20, 30, 40, 50}); - - print_ilist("list1:", list1); - print_ilist("list2:", list2); - - clist_i_iter it = clist_i_advance(clist_i_begin(&list1), 2); - it = clist_i_splice(&list1, it, &list2); - - puts("After splice"); - print_ilist("list1:", list1); - print_ilist("list2:", list2); - - clist_i_splice_range(&list2, clist_i_begin(&list2), &list1, it, clist_i_end(&list1)); - - puts("After splice_range"); - print_ilist("list1:", list1); - print_ilist("list2:", list2); - - c_drop(clist_i, &list1, &list2); -} diff --git a/misc/examples/lower_bound.c b/misc/examples/lower_bound.c deleted file mode 100644 index bea828f2..00000000 --- a/misc/examples/lower_bound.c +++ /dev/null @@ -1,66 +0,0 @@ -#include - -#define i_key int -#define i_cmp_native -#include - -#define i_key int -#include - -int main(void) -{ - // TEST SORTED VECTOR - { - int key, *res; - cvec_int vec = c_init(cvec_int, {40, 600, 1, 7000, 2, 500, 30}); - - cvec_int_sort(&vec); - - key = 100; - res = cvec_int_lower_bound(&vec, key).ref; - if (res) - printf("Sorted Vec %d: lower bound: %d\n", key, *res); // 500 - - key = 10; - cvec_int_iter it1 = cvec_int_lower_bound(&vec, key); - if (it1.ref) - printf("Sorted Vec %3d: lower_bound: %d\n", key, *it1.ref); // 30 - - key = 600; - cvec_int_iter it2 = cvec_int_binary_search(&vec, key); - if (it2.ref) - printf("Sorted Vec %d: bin. search: %d\n", key, *it2.ref); // 600 - - c_foreach (i, cvec_int, it1, it2) - printf(" %d\n", *i.ref); - - puts(""); - cvec_int_drop(&vec); - } - - // TEST SORTED SET - { - int key, *res; - csset_int set = c_init(csset_int, {40, 600, 1, 7000, 2, 500, 30}); - - key = 100; - res = csset_int_lower_bound(&set, key).ref; - if (res) - printf("Sorted Set %d: lower bound: %d\n", key, *res); // 500 - - key = 10; - csset_int_iter it1 = csset_int_lower_bound(&set, key); - if (it1.ref) - printf("Sorted Set %3d: lower bound: %d\n", key, *it1.ref); // 30 - - key = 600; - csset_int_iter it2 = csset_int_find(&set, key); - if (it2.ref) - printf("Sorted Set %d: find : %d\n", key, *it2.ref); // 600 - - c_foreach (i, csset_int, it1, it2) - printf(" %d\n", *i.ref); - - csset_int_drop(&set); - } -} diff --git a/misc/examples/make.sh b/misc/examples/make.sh index cf224950..7135ffdf 100755 --- a/misc/examples/make.sh +++ b/misc/examples/make.sh @@ -37,18 +37,20 @@ else fi if [ $run = 0 ] ; then - for i in *.c ; do - echo $comp -I../../include $i $clibs $oflag$(basename $i .c).exe - $comp -I../../include $i $clibs $oflag$(basename $i .c).exe + for i in */*.c ; do + #out=$(basename $i .c).exe + out=$(dirname $i)/$(basename $i .c).exe + echo $comp -I../../include $i $clibs $oflag$out + $comp -I../../include $i $clibs $oflag$out done else - for i in *.c ; do + for i in */*.c ; do echo $comp -I../../include $i $clibs $comp -I../../include $i $clibs - if [ -f $(basename -s .c $i).exe ]; then ./$(basename -s .c $i).exe; fi - if [ -f ./a.exe ]; then ./a.exe; fi - if [ -f ./a.out ]; then ./a.out; fi + #out=$(basename $i .c).exe + out=$(dirname $i)/$(basename $i .c).exe + if [ -f $out ]; then ./$out; fi done fi -rm -f a.out *.o *.obj # *.exe +#rm -f a.out *.o *.obj # *.exe diff --git a/misc/examples/mapmap.c b/misc/examples/mapmap.c deleted file mode 100644 index d3065659..00000000 --- a/misc/examples/mapmap.c +++ /dev/null @@ -1,64 +0,0 @@ -// create a structure like: std::map>: -#define i_implement -#include - -// People: std::map -#define i_type People -#define i_key_str // name -#define i_val_str // email -#define i_keydrop(p) (printf("kdrop: %s\n", cstr_str(p)), cstr_drop(p)) // override -#include - -// Departments: std::map -#define i_type Departments -#define i_key_str // dep. name -#define i_valclass People -#include - - -void add(Departments* deps, const char* name, const char* email, const char* dep) -{ - People *people = &Departments_emplace(deps, dep, People_init()).ref->second; - People_emplace_or_assign(people, name, email); -} - -int contains(Departments* map, const char* name) -{ - int count = 0; - c_foreach (i, Departments, *map) - if (People_contains(&i.ref->second, name)) - ++count; - return count; -} - -int main(void) -{ - Departments map = {0}; - - add(&map, "Anna Kendro", "Anna@myplace.com", "Support"); - add(&map, "Terry Dane", "Terry@myplace.com", "Development"); - add(&map, "Kik Winston", "Kik@myplace.com", "Finance"); - add(&map, "Nancy Drew", "Nancy@live.com", "Development"); - add(&map, "Nick Denton", "Nick@myplace.com", "Finance"); - add(&map, "Stan Whiteword", "Stan@myplace.com", "Marketing"); - add(&map, "Serena Bath", "Serena@myplace.com", "Support"); - add(&map, "Patrick Dust", "Patrick@myplace.com", "Finance"); - add(&map, "Red Winger", "Red@gmail.com", "Marketing"); - add(&map, "Nick Denton", "Nick@yahoo.com", "Support"); - add(&map, "Colin Turth", "Colin@myplace.com", "Support"); - add(&map, "Dennis Kay", "Dennis@mail.com", "Marketing"); - add(&map, "Anne Dickens", "Anne@myplace.com", "Development"); - - c_foreach (i, Departments, map) - c_forpair (name, email, People, i.ref->second) - printf("%s: %s - %s\n", cstr_str(&i.ref->first), cstr_str(_.name), cstr_str(_.email)); - puts(""); - - printf("found Nick Denton: %d\n", contains(&map, "Nick Denton")); - printf("found Patrick Dust: %d\n", contains(&map, "Patrick Dust")); - printf("found Dennis Kay: %d\n", contains(&map, "Dennis Kay")); - printf("found Serena Bath: %d\n", contains(&map, "Serena Bath")); - puts("Done"); - - Departments_drop(&map); -} diff --git a/misc/examples/mixed/astar.c b/misc/examples/mixed/astar.c new file mode 100644 index 00000000..590b7952 --- /dev/null +++ b/misc/examples/mixed/astar.c @@ -0,0 +1,174 @@ +// +// -- An A* pathfinder inspired by the excellent tutorial at Red Blob Games -- +// +// This is a reimplementation of the CTL example to STC: +// https://github.com/glouw/ctl/blob/master/examples/astar.c +// https://www.redblobgames.com/pathfinding/a-star/introduction.html +#define i_implement +#include +#include + +typedef struct +{ + int x; + int y; + int priorty; + int width; +} +point; + +point +point_init(int x, int y, int width) +{ + return c_LITERAL(point){ x, y, 0, width }; +} + +int +point_cmp_priority(const point* a, const point* b) +{ + return c_default_cmp(&a->priorty, &b->priorty); +} + +int +point_equal(const point* a, const point* b) +{ + return a->x == b->x && a->y == b->y; +} + +point +point_from(const cstr* maze, const char* c, int width) +{ + int index = (int)cstr_find(maze, c); + return point_init(index % width, index / width, width); +} + +int +point_index(const point* p) +{ + return p->x + p->width * p->y; +} + +int +point_key_cmp(const point* a, const point* b) +{ + int i = point_index(a); + int j = point_index(b); + return (i == j) ? 0 : (i < j) ? -1 : 1; +} + +#define i_key point +#define i_cmp point_cmp_priority +#include + +#define i_key point +#define i_opt c_no_cmp +#include + +#define i_key point +#define i_val int +#define i_cmp point_key_cmp +#define i_tag pcost +#include + +#define i_key point +#define i_val point +#define i_cmp point_key_cmp +#define i_tag pstep +#include + +cdeq_point +astar(cstr* maze, int width) +{ + cdeq_point ret_path = {0}; + + cpque_point front = {0}; + csmap_pstep from = {0}; + csmap_pcost costs = {0}; + c_defer( + cpque_point_drop(&front), + csmap_pstep_drop(&from), + csmap_pcost_drop(&costs) + ){ + point start = point_from(maze, "@", width); + point goal = point_from(maze, "!", width); + csmap_pcost_insert(&costs, start, 0); + cpque_point_push(&front, start); + while (!cpque_point_empty(&front)) + { + point current = *cpque_point_top(&front); + cpque_point_pop(&front); + if (point_equal(¤t, &goal)) + break; + point deltas[] = { + { -1, +1, 0, width }, { 0, +1, 0, width }, { 1, +1, 0, width }, + { -1, 0, 0, width }, /* ~ ~ ~ ~ ~ ~ ~ */ { 1, 0, 0, width }, + { -1, -1, 0, width }, { 0, -1, 0, width }, { 1, -1, 0, width }, + }; + for (size_t i = 0; i < c_arraylen(deltas); i++) + { + point delta = deltas[i]; + point next = point_init(current.x + delta.x, current.y + delta.y, width); + int new_cost = *csmap_pcost_at(&costs, current); + if (cstr_str(maze)[point_index(&next)] != '#') + { + const csmap_pcost_value *cost = csmap_pcost_get(&costs, next); + if (cost == NULL || new_cost < cost->second) + { + csmap_pcost_insert(&costs, next, new_cost); + next.priorty = new_cost + abs(goal.x - next.x) + abs(goal.y - next.y); + cpque_point_push(&front, next); + csmap_pstep_insert(&from, next, current); + } + } + } + } + point current = goal; + while (!point_equal(¤t, &start)) + { + cdeq_point_push_front(&ret_path, current); + current = *csmap_pstep_at(&from, current); + } + cdeq_point_push_front(&ret_path, start); + } + return ret_path; +} + +int +main(void) +{ + cstr maze = cstr_lit( + "#########################################################################\n" + "# # # # # # #\n" + "# # ######### # ##### ######### ##### ##### ##### # ! #\n" + "# # # # # # # # # #\n" + "######### # ######### ######### ##### # # # ######### #\n" + "# # # # # # # # # # #\n" + "# # ############# # # ######### ##### # ######### # #\n" + "# # # # # # # # # #\n" + "# ############# ##### ##### # ##### ######### # ##### #\n" + "# # # # # # # # # #\n" + "# ##### ##### # ##### # ######### # # # #############\n" + "# # # # # # # # # # # #\n" + "############# # # # ######### # ##### # ##### ##### #\n" + "# # # # # # # # # #\n" + "# ##### # ######### ##### # ##### ##### ############# #\n" + "# # # # # # # # # #\n" + "# # ######### # ##### ######### # # ############# # #\n" + "# # # # # # # # # # #\n" + "# ######### # # # ##### ######### ######### # #########\n" + "# # # # # # # # # #\n" + "# @ # ##### ##### ##### ######### ##### # ######### # #\n" + "# # # # # # #\n" + "#########################################################################\n" + ); + int width = (int)cstr_find(&maze, "\n") + 1; + cdeq_point ret_path = astar(&maze, width); + + c_foreach (it, cdeq_point, ret_path) + cstr_data(&maze)[point_index(it.ref)] = 'x'; + + printf("%s", cstr_str(&maze)); + + cdeq_point_drop(&ret_path); + cstr_drop(&maze); +} diff --git a/misc/examples/mixed/complex.c b/misc/examples/mixed/complex.c new file mode 100644 index 00000000..4eb1574b --- /dev/null +++ b/misc/examples/mixed/complex.c @@ -0,0 +1,49 @@ + +// Define similar c++ data types: +// +// using FloatStack = std::stack; +// using StackList = std::stack; +// using ListMap = std::unordered_map>; +// using MapMap = std::unordered_map; +#define i_implement +#include + +#define i_type FloatStack +#define i_key float +#include + +#define i_type StackList +#define i_keyclass FloatStack // "class" picks up _clone, _drop, _cmp +#define i_opt c_no_cmp // exclude FloatStack_cmp(): not defined +#include + +#define i_type ListMap +#define i_key int +#define i_valclass StackList // "class" picks up _clone, _drop +#include + +#define i_type MapMap +#define i_key_str +#define i_valclass ListMap +#include + + +int main(void) +{ + MapMap mmap = {0}; + + // Put in some data in the structures + ListMap* lmap = &MapMap_emplace(&mmap, "first", ListMap_init()).ref->second; + StackList* list = &ListMap_insert(lmap, 42, StackList_init()).ref->second; + FloatStack* stack = StackList_push_back(list, FloatStack_with_size(10, 0)); + stack->data[3] = 3.1415927f; + printf("stack size: %" c_ZI "\n", FloatStack_size(stack)); + + // Access the data entry + const ListMap* lmap_p = MapMap_at(&mmap, "first"); + const StackList* list_p = ListMap_at(lmap_p, 42); + const FloatStack* stack_p = StackList_back(list_p); + printf("value is: %f\n", (double)*FloatStack_at(stack_p, 3)); // pi + + MapMap_drop(&mmap); +} diff --git a/misc/examples/mixed/convert.c b/misc/examples/mixed/convert.c new file mode 100644 index 00000000..fa64560e --- /dev/null +++ b/misc/examples/mixed/convert.c @@ -0,0 +1,57 @@ +#define i_implement +#include + +#define i_key_str +#define i_val_str +#include + +#define i_key_str +#include + +#define i_key_str +#include + +int main(void) +{ + cmap_str map, mclone; + cvec_str keys = {0}, values = {0}; + clist_str list = {0}; + + c_defer( + cmap_str_drop(&map), + cmap_str_drop(&mclone), + cvec_str_drop(&keys), + cvec_str_drop(&values), + clist_str_drop(&list) + ){ + map = c_init(cmap_str, { + {"green", "#00ff00"}, + {"blue", "#0000ff"}, + {"yellow", "#ffff00"}, + }); + + puts("MAP:"); + c_foreach (i, cmap_str, map) + printf(" %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); + + puts("\nCLONE MAP:"); + mclone = cmap_str_clone(map); + c_foreach (i, cmap_str, mclone) + printf(" %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); + + puts("\nCOPY MAP TO VECS:"); + c_foreach (i, cmap_str, mclone) { + cvec_str_emplace_back(&keys, cstr_str(&i.ref->first)); + cvec_str_emplace_back(&values, cstr_str(&i.ref->second)); + } + c_forrange (i, cvec_str_size(&keys)) + printf(" %s: %s\n", cstr_str(keys.data + i), cstr_str(values.data + i)); + + puts("\nCOPY VEC TO LIST:"); + c_foreach (i, cvec_str, keys) + clist_str_emplace_back(&list, cstr_str(i.ref)); + + c_foreach (i, clist_str, list) + printf(" %s\n", cstr_str(i.ref)); + } +} diff --git a/misc/examples/mixed/demos.c b/misc/examples/mixed/demos.c new file mode 100644 index 00000000..1a604d9f --- /dev/null +++ b/misc/examples/mixed/demos.c @@ -0,0 +1,194 @@ +#define i_implement +#include + +void stringdemo1(void) +{ + cstr cs = cstr_lit("one-nine-three-seven-five"); + printf("%s.\n", cstr_str(&cs)); + + cstr_insert(&cs, 3, "-two"); + printf("%s.\n", cstr_str(&cs)); + + cstr_erase(&cs, 7, 5); // -nine + printf("%s.\n", cstr_str(&cs)); + + cstr_replace(&cs, "seven", "four", 1); + printf("%s.\n", cstr_str(&cs)); + + cstr_take(&cs, cstr_from_fmt("%s *** %s", cstr_str(&cs), cstr_str(&cs))); + printf("%s.\n", cstr_str(&cs)); + + printf("find \"four\": %s\n", cstr_str(&cs) + cstr_find(&cs, "four")); + + // reassign: + cstr_assign(&cs, "one two three four five six seven"); + cstr_append(&cs, " eight"); + printf("append: %s\n", cstr_str(&cs)); + + cstr_drop(&cs); +} + +#define i_key int64_t +#define i_tag ix +#include + +void vectordemo1(void) +{ + cvec_ix bignums = cvec_ix_with_capacity(100); + cvec_ix_reserve(&bignums, 100); + for (int i = 10; i <= 100; i += 10) + cvec_ix_push(&bignums, i * i); + + printf("erase - %d: %" PRIu64 "\n", 3, bignums.data[3]); + cvec_ix_erase_n(&bignums, 3, 1); // erase index 3 + + cvec_ix_pop(&bignums); // erase the last + cvec_ix_erase_n(&bignums, 0, 1); // erase the first + + for (int i = 0; i < cvec_ix_size(&bignums); ++i) { + printf("%d: %" PRIu64 "\n", i, bignums.data[i]); + } + + cvec_ix_drop(&bignums); +} + +#define i_key_str +#include + +void vectordemo2(void) +{ + cvec_str names = {0}; + cvec_str_emplace_back(&names, "Mary"); + cvec_str_emplace_back(&names, "Joe"); + cvec_str_emplace_back(&names, "Chris"); + cstr_assign(&names.data[1], "Jane"); // replace Joe + printf("names[1]: %s\n", cstr_str(&names.data[1])); + + cvec_str_sort(&names); // Sort the array + + c_foreach (i, cvec_str, names) + printf("sorted: %s\n", cstr_str(i.ref)); + + cvec_str_drop(&names); +} + +#define i_key int +#define i_tag ix +#define i_cmp_native +#include + +void listdemo1(void) +{ + clist_ix nums = {0}, nums2 = {0}; + for (int i = 0; i < 10; ++i) + clist_ix_push_back(&nums, i); + for (int i = 100; i < 110; ++i) + clist_ix_push_back(&nums2, i); + + /* splice nums2 to front of nums */ + clist_ix_splice(&nums, clist_ix_begin(&nums), &nums2); + c_foreach (i, clist_ix, nums) + printf("spliced: %d\n", *i.ref); + puts(""); + + *clist_ix_find(&nums, 104).ref += 50; + clist_ix_remove(&nums, 103); + clist_ix_iter it = clist_ix_begin(&nums); + clist_ix_erase_range(&nums, clist_ix_advance(it, 5), clist_ix_advance(it, 15)); + clist_ix_pop_front(&nums); + clist_ix_push_back(&nums, -99); + clist_ix_sort(&nums); + + c_foreach (i, clist_ix, nums) + printf("sorted: %d\n", *i.ref); + + c_drop(clist_ix, &nums, &nums2); +} + +#define i_key int +#define i_tag i +#include + +void setdemo1(void) +{ + cset_i nums = {0}; + cset_i_insert(&nums, 8); + cset_i_insert(&nums, 11); + + c_foreach (i, cset_i, nums) + printf("set: %d\n", *i.ref); + cset_i_drop(&nums); +} + +#define i_key int +#define i_val int +#define i_tag ii +#include + +void mapdemo1(void) +{ + cmap_ii nums = {0}; + cmap_ii_insert(&nums, 8, 64); + cmap_ii_insert(&nums, 11, 121); + printf("val 8: %d\n", *cmap_ii_at(&nums, 8)); + cmap_ii_drop(&nums); +} + +#define i_key_str +#define i_val int +#define i_tag si +#include + +void mapdemo2(void) +{ + cmap_si nums = {0}; + cmap_si_emplace_or_assign(&nums, "Hello", 64); + cmap_si_emplace_or_assign(&nums, "Groovy", 121); + cmap_si_emplace_or_assign(&nums, "Groovy", 200); // overwrite previous + + // iterate the map: + for (cmap_si_iter i = cmap_si_begin(&nums); i.ref; cmap_si_next(&i)) + printf("long: %s: %d\n", cstr_str(&i.ref->first), i.ref->second); + + // or rather use the short form: + c_foreach (i, cmap_si, nums) + printf("short: %s: %d\n", cstr_str(&i.ref->first), i.ref->second); + + cmap_si_drop(&nums); +} + +#define i_key_str +#define i_val_str +#include + +void mapdemo3(void) +{ + cmap_str table = {0}; + cmap_str_emplace(&table, "Map", "test"); + cmap_str_emplace(&table, "Make", "my"); + cmap_str_emplace(&table, "Sunny", "day"); + cmap_str_iter it = cmap_str_find(&table, "Make"); + c_foreach (i, cmap_str, table) + printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); + printf("size %" c_ZI ": remove: Make: %s\n", cmap_str_size(&table), cstr_str(&it.ref->second)); + //cmap_str_erase(&table, "Make"); + cmap_str_erase_at(&table, it); + + printf("size %" c_ZI "\n", cmap_str_size(&table)); + c_foreach (i, cmap_str, table) + printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); + + cmap_str_drop(&table); // frees key and value cstrs, and hash table. +} + +int main(void) +{ + printf("\nSTRINGDEMO1\n"); stringdemo1(); + printf("\nVECTORDEMO1\n"); vectordemo1(); + printf("\nVECTORDEMO2\n"); vectordemo2(); + printf("\nLISTDEMO1\n"); listdemo1(); + printf("\nSETDEMO1\n"); setdemo1(); + printf("\nMAPDEMO1\n"); mapdemo1(); + printf("\nMAPDEMO2\n"); mapdemo2(); + printf("\nMAPDEMO3\n"); mapdemo3(); +} diff --git a/misc/examples/mixed/inits.c b/misc/examples/mixed/inits.c new file mode 100644 index 00000000..53a49f1f --- /dev/null +++ b/misc/examples/mixed/inits.c @@ -0,0 +1,108 @@ +#define i_implement +#include + +#define i_key int +#define i_val_str +#define i_tag id // Map of int => cstr +#include + +#define i_key_str +#define i_val int +#define i_tag cnt // Map of cstr => int +#include + +typedef struct {int x, y;} ipair_t; +inline static int ipair_cmp(const ipair_t* a, const ipair_t* b) { + int c = c_default_cmp(&a->x, &b->x); + return c ? c : c_default_cmp(&a->y, &b->y); +} + + +#define i_key ipair_t +#define i_cmp ipair_cmp +#define i_tag ip +#include + +#define i_key ipair_t +#define i_cmp ipair_cmp +#define i_tag ip +#include + +#define i_key float +#define i_tag f +#include + +int main(void) +{ + // CVEC FLOAT / PRIORITY QUEUE + + cpque_f floats = {0}; + const float nums[] = {4.0f, 2.0f, 5.0f, 3.0f, 1.0f}; + + // PRIORITY QUEUE + c_forrange (i, c_arraylen(nums)) + cpque_f_push(&floats, nums[i]); + + puts("\npop and show high priorites first:"); + while (! cpque_f_empty(&floats)) { + printf("%.1f ", (double)*cpque_f_top(&floats)); + cpque_f_pop(&floats); + } + puts("\n"); + cpque_f_drop(&floats); + + // CMAP ID + + int year = 2020; + cmap_id idnames = {0}; + cmap_id_emplace(&idnames, 100, "Hello"); + cmap_id_insert(&idnames, 110, cstr_lit("World")); + cmap_id_insert(&idnames, 120, cstr_from_fmt("Howdy, -%d-", year)); + + c_foreach (i, cmap_id, idnames) + printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second)); + puts(""); + cmap_id_drop(&idnames); + + // CMAP CNT + + cmap_cnt countries = c_init(cmap_cnt, { + {"Norway", 100}, + {"Denmark", 50}, + {"Iceland", 10}, + {"Belgium", 10}, + {"Italy", 10}, + {"Germany", 10}, + {"Spain", 10}, + {"France", 10}, + }); + cmap_cnt_emplace(&countries, "Greenland", 0).ref->second += 20; + cmap_cnt_emplace(&countries, "Sweden", 0).ref->second += 20; + cmap_cnt_emplace(&countries, "Norway", 0).ref->second += 20; + cmap_cnt_emplace(&countries, "Finland", 0).ref->second += 20; + + c_forpair (country, health, cmap_cnt, countries) + printf("%s: %d\n", cstr_str(_.country), *_.health); + puts(""); + cmap_cnt_drop(&countries); + + // CVEC PAIR + + cvec_ip pairs1 = c_init(cvec_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); + cvec_ip_sort(&pairs1); + + c_foreach (i, cvec_ip, pairs1) + printf("(%d %d) ", i.ref->x, i.ref->y); + puts(""); + cvec_ip_drop(&pairs1); + + // CLIST PAIR + + clist_ip pairs2 = c_init(clist_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); + clist_ip_sort(&pairs2); + + c_foreach (i, clist_ip, pairs2) + printf("(%d %d) ", i.ref->x, i.ref->y); + puts(""); + clist_ip_drop(&pairs2); +} diff --git a/misc/examples/mixed/read.c b/misc/examples/mixed/read.c new file mode 100644 index 00000000..de04fd31 --- /dev/null +++ b/misc/examples/mixed/read.c @@ -0,0 +1,27 @@ +#define i_implement +#include +#include +#define i_key_str +#include +#include + +cvec_str read_file(const char* name) +{ + cvec_str vec = {0}; + c_with (FILE* f = fopen(name, "r"), fclose(f)) + c_with (cstr line = {0}, cstr_drop(&line)) + while (cstr_getline(&line, f)) + cvec_str_push(&vec, cstr_clone(line)); + return vec; +} + +int main(void) +{ + int n = 0; + c_with (cvec_str vec = read_file(__FILE__), cvec_str_drop(&vec)) + c_foreach (i, cvec_str, vec) + printf("%5d: %s\n", ++n, cstr_str(i.ref)); + + if (errno) + printf("error: read_file(" __FILE__ "). errno: %d\n", errno); +} diff --git a/misc/examples/mmap.c b/misc/examples/mmap.c deleted file mode 100644 index 04a605a7..00000000 --- a/misc/examples/mmap.c +++ /dev/null @@ -1,65 +0,0 @@ -// This implements the multimap c++ example found at: -// https://en.cppreference.com/w/cpp/container/multimap/insert - -// Multimap entries -#define i_implement -#include -#define i_key_str -#include - -// Map of int => clist_str. -#define i_type Multimap -#define i_key int -#define i_valclass clist_str // set i_val = clist_str, bind clist_str_clone and clist_str_drop -#define i_cmp -c_default_cmp // like std::greater -#include - -void print(const char* lbl, const Multimap mmap) -{ - printf("%s ", lbl); - c_foreach (e, Multimap, mmap) { - c_foreach (s, clist_str, e.ref->second) - printf("{%d,%s} ", e.ref->first, cstr_str(s.ref)); - } - puts(""); -} - -void insert(Multimap* mmap, int key, const char* str) -{ - clist_str *list = &Multimap_insert(mmap, key, clist_str_init()).ref->second; - clist_str_emplace_back(list, str); -} - -int main(void) -{ - Multimap mmap = {0}; - - // list-initialize - typedef struct {int a; const char* b;} pair; - c_forlist (i, pair, {{2, "foo"}, {2, "bar"}, {3, "baz"}, {1, "abc"}, {5, "def"}}) - insert(&mmap, i.ref->a, i.ref->b); - print("#1", mmap); - - // insert using value_type - insert(&mmap, 5, "pqr"); - print("#2", mmap); - - // insert using make_pair - insert(&mmap, 6, "uvw"); - print("#3", mmap); - - insert(&mmap, 7, "xyz"); - print("#4", mmap); - - // insert using initialization_list - c_forlist (i, pair, {{5, "one"}, {5, "two"}}) - insert(&mmap, i.ref->a, i.ref->b); - print("#5", mmap); - - // FOLLOWING NOT IN ORIGINAL EXAMPLE: - // erase all entries with key 5 - Multimap_erase(&mmap, 5); - print("+5", mmap); - - Multimap_drop(&mmap); -} diff --git a/misc/examples/multidim.c b/misc/examples/multidim.c deleted file mode 100644 index 798a1126..00000000 --- a/misc/examples/multidim.c +++ /dev/null @@ -1,67 +0,0 @@ -// Example based on https://en.cppreference.com/w/cpp/container/mdspan -#define i_val int -#include -#include -#include - -using_cspan3(ispan, int); - -int main(void) -{ - cstack_int v = c_init(cstack_int, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}); - - // View data as contiguous memory representing 24 ints - ispan ms1 = cspan_from(&v); - - // View the same data as a 3D array 2 x 3 x 4 - ispan3 ms3 = cspan_md(v.data, 2, 3, 4); - - puts("ms3:"); - for (int i=0; i != ms3.shape[0]; i++) { - for (int j=0; j != ms3.shape[1]; j++) { - for (int k=0; k != ms3.shape[2]; k++) { - printf(" %2d", *cspan_at(&ms3, i, j, k)); - } - puts(""); - } - puts(""); - } - puts("ss3 = ms3[:, 1:3, 1:3]"); - ispan3 ss3 = ms3; - ss3 = cspan_slice(ispan3, &ms3, {c_ALL}, {1,3}, {1,3}); - - for (int i=0; i != ss3.shape[0]; i++) { - for (int j=0; j != ss3.shape[1]; j++) { - for (int k=0; k != ss3.shape[2]; k++) { - printf(" %2d", *cspan_at(&ss3, i, j, k)); - } - puts(""); - } - puts(""); - } - - puts("Iterate ss3 flat:"); - c_foreach (i, ispan3, ss3) - printf(" %d", *i.ref); - puts(""); - - ispan2 ms2 = cspan_submd3(&ms3, 0); - - // write data using 2D view - for (int i=0; i != ms2.shape[0]; i++) - for (int j=0; j != ms2.shape[1]; j++) - *cspan_at(&ms2, i, j) = i*1000 + j; - - puts("\nview data as 1D view:"); - for (int i=0; i != cspan_size(&ms1); i++) - printf(" %d", *cspan_at(&ms1, i)); - puts(""); - - puts("iterate subspan ms3[1]:"); - ispan2 sub = cspan_submd3(&ms3, 1); - c_foreach (i, ispan2, sub) - printf(" %d", *i.ref); - puts(""); - - cstack_int_drop(&v); -} diff --git a/misc/examples/multimap.c b/misc/examples/multimap.c deleted file mode 100644 index 1068a5dc..00000000 --- a/misc/examples/multimap.c +++ /dev/null @@ -1,102 +0,0 @@ -#define i_implement -#include - -// Olympics multimap example - -struct OlympicsData { int year; const char *city, *country, *date; } ol_data[] = { - {2026, "Milan and Cortina d'Ampezzo", "Italy", "February 6-22"}, - {2022, "Beijing", "China", "February 4-20"}, - {2018, "PyeongChang", "South Korea", "February 9-25"}, - {2014, "Sochi", "Russia", "February 7-23"}, - {2010, "Vancouver", "Canada", "February 12-28"}, - {2006, "Torino", "Italy", "February 10-26"}, - {2002, "Salt Lake City", "United States", "February 8-24"}, - {1998, "Nagano", "Japan", "February 7-22"}, - {1994, "Lillehammer", "Norway", "February 12-27"}, - {1992, "Albertville", "France", "February 8-23"}, - {1988, "Calgary", "Canada", "February 13-28"}, - {1984, "Sarajevo", "Yugoslavia", "February 8-19"}, - {1980, "Lake Placid", "United States", "February 13-24"}, - {1976, "Innsbruck", "Austria", "February 4-15"}, - {1972, "Sapporo", "Japan", "February 3-13"}, - {1968, "Grenoble", "France", "February 6-18"}, - {1964, "Innsbruck", "Austria", "January 29-February 9"}, - {1960, "Squaw Valley", "United States", "February 18-28"}, - {1956, "Cortina d'Ampezzo", "Italy", "January 26 - February 5"}, - {1952, "Oslo", "Norway", "February 14 - 25"}, - {1948, "St. Moritz", "Switzerland", "January 30 - February 8"}, - {1944, "canceled", "canceled", "canceled"}, - {1940, "canceled", "canceled", "canceled"}, - {1936, "Garmisch-Partenkirchen", "Germany", "February 6 - 16"}, - {1932, "Lake Placid", "United States", "February 4 - 15"}, - {1928, "St. Moritz", "Switzerland", "February 11 - 19"}, - {1924, "Chamonix", "France", "January 25 - February 5"}, -}; - -typedef struct { int year; cstr city, date; } OlympicLoc; - -int OlympicLoc_cmp(const OlympicLoc* a, const OlympicLoc* b); -OlympicLoc OlympicLoc_clone(OlympicLoc loc); -void OlympicLoc_drop(OlympicLoc* self); - -// Create a clist, can be sorted by year. -#define i_keyclass OlympicLoc // binds _cmp, _clone and _drop. -#define i_tag OL -#include - -// Create a csmap where key is country name -#define i_key_str // binds cstr_equ, cstr_hash, cstr_clone, ++ -#define i_valclass clist_OL // binds clist_OL_clone, clist_OL_drop -#define i_tag OL -#include - -int OlympicLoc_cmp(const OlympicLoc* a, const OlympicLoc* b) { - return a->year - b->year; -} - -OlympicLoc OlympicLoc_clone(OlympicLoc loc) { - loc.city = cstr_clone(loc.city); - loc.date = cstr_clone(loc.date); - return loc; -} - -void OlympicLoc_drop(OlympicLoc* self) { - cstr_drop(&self->city); - cstr_drop(&self->date); -} - - -int main(void) -{ - // Define the multimap with destructor defered to when block is completed. - csmap_OL multimap = {0}; - const clist_OL empty = clist_OL_init(); - - for (size_t i = 0; i < c_arraylen(ol_data); ++i) - { - struct OlympicsData* d = &ol_data[i]; - OlympicLoc loc = {.year = d->year, - .city = cstr_from(d->city), - .date = cstr_from(d->date)}; - // Insert an empty list for each new country, and append the entry to the list. - // If country already exist in map, its list is returned from the insert function. - clist_OL* list = &csmap_OL_emplace(&multimap, d->country, empty).ref->second; - clist_OL_push_back(list, loc); - } - - // Sort locations by year for each country. - c_foreach (country, csmap_OL, multimap) - clist_OL_sort(&country.ref->second); - - // Print the multimap: - c_foreach (country, csmap_OL, multimap) - { - // Loop the locations for a country sorted by year - c_foreach (loc, clist_OL, country.ref->second) - printf("%s: %d, %s, %s\n", cstr_str(&country.ref->first), - loc.ref->year, - cstr_str(&loc.ref->city), - cstr_str(&loc.ref->date)); - } - csmap_OL_drop(&multimap); -} diff --git a/misc/examples/music_arc.c b/misc/examples/music_arc.c deleted file mode 100644 index 16111b0b..00000000 --- a/misc/examples/music_arc.c +++ /dev/null @@ -1,67 +0,0 @@ -// shared_ptr-examples.cpp -// based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160 -#define i_implement -#include - -typedef struct -{ - cstr artist; - cstr title; -} Song; - -int Song_cmp(const Song* x, const Song* y) - { return cstr_cmp(&x->title, &y->title); } - -Song Song_make(const char* artist, const char* title) - { return c_LITERAL(Song){cstr_from(artist), cstr_from(title)}; } - -void Song_drop(Song* s) { - printf("drop: %s\n", cstr_str(&s->title)); - c_drop(cstr, &s->artist, &s->title); -} - -// Define the shared pointer: -#define i_type SongArc -#define i_keyclass Song -#define i_no_hash // no hash fn for Song, fallback hash pointer to Song. -#include - -// ... and a vector of them -#define i_type SongVec -#define i_keyboxed SongArc // use i_keyboxed on carc / cbox (instead of i_key) -#include - -void example3(void) -{ - SongVec vec1 = c_init(SongVec, { - Song_make("Bob Dylan", "The Times They Are A Changing"), - Song_make("Aretha Franklin", "Bridge Over Troubled Water"), - Song_make("Thalia", "Entre El Mar y Una Estrella") - }); - - SongVec vec2 = {0}; - // Share all entries in vec with vec2, except Bob Dylan. - c_foreach (s, SongVec, vec1) - if (!cstr_equals(&s.ref->get->artist, "Bob Dylan")) - SongVec_push(&vec2, SongArc_clone(*s.ref)); - - // Add a few more to vec2. We can use emplace when creating new entries - // Emplace calls SongArc_from() on the argument to create the Arc: - SongVec_emplace(&vec2, Song_make("Michael Jackson", "Billie Jean")); - SongVec_emplace(&vec2, Song_make("Rihanna", "Stay")); - - // We now have two vectors with some shared, some unique entries. - c_forlist (i, SongVec, {vec1, vec2}) { - puts("VEC:"); - c_foreach (s, SongVec, *i.ref) - printf(" %s - %s, REFS: %ld\n", cstr_str(&s.ref->get->artist), - cstr_str(&s.ref->get->title), - *s.ref->use_count); - } - c_drop(SongVec, &vec1, &vec2); -} - -int main(void) -{ - example3(); -} diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c deleted file mode 100644 index 2112bf1f..00000000 --- a/misc/examples/new_list.c +++ /dev/null @@ -1,70 +0,0 @@ -#include -#include - -forward_clist(clist_i32, int); -forward_clist(clist_pnt, struct Point); - -typedef struct { - clist_i32 intlist; - clist_pnt pntlist; -} MyStruct; - -#define i_key int -#define i_tag i32 -#define i_is_forward -#include - -typedef struct Point { int x, y; } Point; -int point_cmp(const Point* a, const Point* b) { - int c = a->x - b->x; - return c ? c : a->y - b->y; -} - -#define i_key Point -#define i_cmp point_cmp -#define i_is_forward -#define i_tag pnt -#include - -#define i_key float -#define i_cmp_native // use < and == operators for comparison -#include - -void MyStruct_drop(MyStruct* s); -#define i_type MyList -#define i_key MyStruct -#define i_keydrop MyStruct_drop // define drop function -#define i_no_clone // must explicitely exclude or define cloning support because of drop. -#include - -void MyStruct_drop(MyStruct* s) { - clist_i32_drop(&s->intlist); - clist_pnt_drop(&s->pntlist); -} - - -int main(void) -{ - MyStruct my = {0}; - clist_i32_push_back(&my.intlist, 123); - clist_pnt_push_back(&my.pntlist, c_LITERAL(Point){123, 456}); - MyStruct_drop(&my); - - clist_pnt plist = c_init(clist_pnt, {{42, 14}, {32, 94}, {62, 81}}); - clist_pnt_sort(&plist); - - c_foreach (i, clist_pnt, plist) - printf(" (%d %d)", i.ref->x, i.ref->y); - puts(""); - clist_pnt_drop(&plist); - - - clist_float flist = c_init(clist_float, {123.3f, 321.2f, -32.2f, 78.2f}); - clist_float_sort(&flist); - - c_foreach (i, clist_float, flist) - printf(" %g", (double)*i.ref); - - puts(""); - clist_float_drop(&flist); -} diff --git a/misc/examples/new_map.c b/misc/examples/new_map.c deleted file mode 100644 index de990040..00000000 --- a/misc/examples/new_map.c +++ /dev/null @@ -1,75 +0,0 @@ -#define i_implement -#include -#include - -forward_cmap(cmap_pnt, struct Point, int); - -typedef struct MyStruct { - cmap_pnt pntmap; - cstr name; -} MyStruct; - -// int => int map -#define i_key int -#define i_val int -#include - -// Point => int map -typedef struct Point { int x, y; } Point; - -int point_cmp(const Point* a, const Point* b) { - int c = a->x - b->x; - return c ? c : a->y - b->y; -} - -// Point => int map -#define i_key Point -#define i_val int -#define i_cmp point_cmp -#define i_hash c_default_hash -#define i_is_forward -#define i_tag pnt -#include - -// cstr => cstr map -#define i_key_str -#define i_val_str -#include - -// string set -#define i_key_str -#include - - -int main(void) -{ - cmap_pnt pmap = c_init(cmap_pnt, {{{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}}); - - c_foreach (i, cmap_pnt, pmap) - printf(" (%d, %d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second); - puts(""); - - cmap_str smap = c_init(cmap_str, { - {"Hello, friend", "long time no see"}, - {"So long", "see you around"}, - }); - - cset_str sset = c_init(cset_str, { - "Hello, friend", - "Nice to see you again", - "So long", - }); - - cmap_int map = {0}; - cmap_int_insert(&map, 123, 321); - cmap_int_insert(&map, 456, 654); - cmap_int_insert(&map, 789, 987); - - c_foreach (i, cset_str, sset) - printf(" %s\n", cstr_str(i.ref)); - - cmap_int_drop(&map); - cset_str_drop(&sset); - cmap_str_drop(&smap); - cmap_pnt_drop(&pmap); -} diff --git a/misc/examples/new_pque.c b/misc/examples/new_pque.c deleted file mode 100644 index 16823bb6..00000000 --- a/misc/examples/new_pque.c +++ /dev/null @@ -1,22 +0,0 @@ -#include - -typedef struct Point { int x, y; } Point; - -#define i_type PointQ -#define i_key Point -#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) -#include - - -int main(void) -{ - PointQ pque = c_init(PointQ, {{23, 80}, {12, 32}, {54, 74}, {12, 62}}); - // print - for (; !PointQ_empty(&pque); PointQ_pop(&pque)) - { - const Point *v = PointQ_top(&pque); - printf(" (%d,%d)", v->x, v->y); - } - puts(""); - PointQ_drop(&pque); -} diff --git a/misc/examples/new_queue.c b/misc/examples/new_queue.c deleted file mode 100644 index f3592df6..00000000 --- a/misc/examples/new_queue.c +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -#include -#include - -forward_cqueue(cqueue_pnt, struct Point); - -typedef struct Point { int x, y; } Point; -int point_cmp(const Point* a, const Point* b) { - int c = c_default_cmp(&a->x, &b->x); - return c ? c : c_default_cmp(&a->y, &b->y); -} -#define i_key Point -#define i_cmp point_cmp -#define i_is_forward -#define i_tag pnt -#include - -#define i_type IQ -#define i_key int -#include - -int main(void) { - int n = 50000000; - crand_t rng = crand_init((uint64_t)time(NULL)); - crand_unif_t dist = crand_unif_init(0, n); - - IQ Q = {0}; - - // Push 50'000'000 random numbers onto the queue. - c_forrange (n) - IQ_push(&Q, (int)crand_unif(&rng, &dist)); - - // Push or pop on the queue 50 million times - printf("befor: size %" c_ZI ", capacity %" c_ZI "\n", IQ_size(&Q), IQ_capacity(&Q)); - - c_forrange (n) { - int r = (int)crand_unif(&rng, &dist); - if (r & 3) - IQ_push(&Q, r); - else - IQ_pop(&Q); - } - - printf("after: size %" c_ZI ", capacity %" c_ZI "\n", IQ_size(&Q), IQ_capacity(&Q)); - IQ_drop(&Q); -} diff --git a/misc/examples/new_smap.c b/misc/examples/new_smap.c deleted file mode 100644 index ee946c9a..00000000 --- a/misc/examples/new_smap.c +++ /dev/null @@ -1,67 +0,0 @@ -#define i_implement -#include -#include - -forward_csmap(PMap, struct Point, int); - -// Use forward declared PMap in struct -typedef struct { - PMap pntmap; - cstr name; -} MyStruct; - -// Point => int map -typedef struct Point { int x, y; } Point; -int point_cmp(const Point* a, const Point* b) { - int c = a->x - b->x; - return c ? c : a->y - b->y; -} - -#define i_type PMap -#define i_key Point -#define i_val int -#define i_cmp point_cmp -#define i_is_forward -#include - -// cstr => cstr map -#define i_type SMap -#define i_key_str -#define i_val_str -#include - -// cstr set -#define i_type SSet -#define i_key_str -#include - - -int main(void) -{ - PMap pmap = c_init(PMap, { - {{42, 14}, 1}, - {{32, 94}, 2}, - {{62, 81}, 3}, - }); - SMap smap = c_init(SMap, { - {"Hello, friend", "this is the mapped value"}, - {"The brown fox", "jumped"}, - {"This is the time", "for all good things"}, - }); - SSet sset = {0}; - - c_forpair (p, i, PMap, pmap) - printf(" (%d,%d: %d)", _.p->x, _.p->y, *_.i); - puts(""); - - c_forpair (i, j, SMap, smap) - printf(" (%s: %s)\n", cstr_str(_.i), cstr_str(_.j)); - - SSet_emplace(&sset, "Hello, friend"); - SSet_emplace(&sset, "Goodbye, foe"); - printf("Found? %s\n", SSet_contains(&sset, "Hello, friend") ? "true" : "false"); - - PMap_drop(&pmap); - SMap_drop(&smap); - SSet_drop(&sset); -} diff --git a/misc/examples/new_sptr.c b/misc/examples/new_sptr.c deleted file mode 100644 index 3c6fa16c..00000000 --- a/misc/examples/new_sptr.c +++ /dev/null @@ -1,75 +0,0 @@ -#define i_implement -#include - -typedef struct { cstr name, last; } Person; -Person Person_make(const char* name, const char* last); -Person Person_clone(Person p); -void Person_drop(Person* p); -int Person_cmp(const Person* a, const Person* b); -uint64_t Person_hash(const Person* p); - -#define i_type PersonArc -#define i_keyclass Person // "class" assume _clone, _drop, _cmp, _hash is defined. -#include - -#define i_type IPtr -#define i_key int -#define i_keydrop(x) printf("drop: %d\n", *x) -#define i_cmp_native -#include - -#define i_type IPStack -#define i_keyboxed IPtr -#include - -#define i_type PASet -#define i_keyboxed PersonArc -#include - - -Person Person_make(const char* name, const char* last) { - Person p = {.name = cstr_from(name), .last = cstr_from(last)}; - return p; -} - -int Person_cmp(const Person* a, const Person* b) { - return cstr_cmp(&a->name, &b->name); -} - -uint64_t Person_hash(const Person* p) { - return cstr_hash(&p->name); -} - -Person Person_clone(Person p) { - p.name = cstr_clone(p.name), p.last = cstr_clone(p.last); - return p; -} - -void Person_drop(Person* p) { - printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); - c_drop(cstr, &p->name, &p->last); -} - - -int main(void) { - puts("Ex1"); - PersonArc p = PersonArc_from(Person_make("John", "Smiths")); - PersonArc q = PersonArc_clone(p); // share - PersonArc r = PersonArc_clone(p); - PersonArc s = PersonArc_from(Person_clone(*p.get)); // deep copy - printf("%s %s: refs %ld\n", cstr_str(&p.get->name), cstr_str(&p.get->last), *p.use_count); - c_drop(PersonArc, &p, &q, &r, &s); - - puts("Ex2"); - IPStack vec = {0}; - IPStack_push(&vec, IPtr_from(10)); - IPStack_push(&vec, IPtr_from(20)); - IPStack_emplace(&vec, 30); // same as IPStack_push(&vec, IPtr_from(30)); - IPStack_push(&vec, IPtr_clone(*IPStack_back(&vec))); - IPStack_push(&vec, IPtr_clone(*IPStack_front(&vec))); - - c_foreach (i, IPStack, vec) - printf(" (%d: refs %ld)", *i.ref->get, *i.ref->use_count); - puts(""); - IPStack_drop(&vec); -} diff --git a/misc/examples/new_vec.c b/misc/examples/new_vec.c deleted file mode 100644 index 88efd55a..00000000 --- a/misc/examples/new_vec.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include - -forward_cvec(cvec_i32, int); -forward_cvec(cvec_pnt, struct Point); - -typedef struct MyStruct { - cvec_i32 intvec; - cvec_pnt pntvec; -} MyStruct; - -#define i_key int -#define i_tag i32 -#define i_is_forward -#include - -typedef struct Point { int x, y; } Point; - -#define i_key Point -#define i_tag pnt -#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) -#define i_eq(a, b) a->x == b->x && a->y == b->y -#define i_is_forward -#include - -int main(void) -{ - MyStruct my = {0}; - - cvec_pnt_push(&my.pntvec, c_LITERAL(Point){42, 14}); - cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 94}); - cvec_pnt_push(&my.pntvec, c_LITERAL(Point){62, 81}); - cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 91}); - - cvec_pnt_sort(&my.pntvec); - - c_foreach (i, cvec_pnt, my.pntvec) - printf(" (%d %d)", i.ref->x, i.ref->y); - puts(""); - - cvec_i32_drop(&my.intvec); - cvec_pnt_drop(&my.pntvec); -} diff --git a/misc/examples/person_arc.c b/misc/examples/person_arc.c deleted file mode 100644 index 38c883a7..00000000 --- a/misc/examples/person_arc.c +++ /dev/null @@ -1,77 +0,0 @@ -/* cbox: heap allocated boxed type */ -#define i_implement -#include - -typedef struct { cstr name, last; } Person; - -Person Person_make(const char* name, const char* last) { - Person p = {.name = cstr_from(name), .last = cstr_from(last)}; - return p; -} - -int Person_cmp(const Person* a, const Person* b) { - int c = cstr_cmp(&a->name, &b->name); - return c ? c : cstr_cmp(&a->last, &b->last); -} - -uint64_t Person_hash(const Person* a) { - return cstr_hash(&a->name) ^ cstr_hash(&a->last); -} - -Person Person_clone(Person p) { - p.name = cstr_clone(p.name); - p.last = cstr_clone(p.last); - return p; -} - -void Person_drop(Person* p) { - printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); - c_drop(cstr, &p->name, &p->last); -} - -#define i_type PSPtr -#define i_keyclass Person // ensure Person_drop -#define i_cmp Person_cmp // specify object cmp, instead of ptr cmp for arc. -#include - -#define i_type Persons -#define i_keyboxed PSPtr // binds PSPtr_cmp, PSPtr_drop... -#include - - -int main(void) -{ - PSPtr p = PSPtr_from(Person_make("Laura", "Palmer")); - PSPtr q = PSPtr_from(Person_clone(*p.get)); // deep copy - Persons vec = {0}; - - c_defer( - PSPtr_drop(&p), - PSPtr_drop(&q), - Persons_drop(&vec) - ){ - cstr_assign(&q.get->name, "Leland"); - - printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last)); - printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last)); - - // Use Persons_emplace to implicitly call PSPtr_make on the argument. - // No need to do: Persons_push(&vec, PSPtr_make(Person_make("Audrey", "Home"))); - Persons_emplace(&vec, Person_make("Audrey", "Home")); - Persons_emplace(&vec, Person_make("Dale", "Cooper")); - - // Clone/share p and q to the vector - c_forlist (i, PSPtr, {p, q}) - Persons_push(&vec, PSPtr_clone(*i.ref)); - - c_foreach (i, Persons, vec) - printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last)); - puts(""); - - // Look-up Audrey! - Person a = Person_make("Audrey", "Home"); - const PSPtr *v = Persons_get(&vec, a); - if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last)); - Person_drop(&a); - } -} diff --git a/misc/examples/phonebook.c b/misc/examples/phonebook.c deleted file mode 100644 index faf7566e..00000000 --- a/misc/examples/phonebook.c +++ /dev/null @@ -1,72 +0,0 @@ -// The MIT License (MIT) -// Copyright (c) 2018 Maksim Andrianov -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -// Program to emulates the phone book. -#define i_implement -#include - -#define i_key_str -#define i_val_str -#include - -#define i_key_str -#include - -void print_phone_book(cmap_str phone_book) -{ - c_foreach (i, cmap_str, phone_book) - printf("%s\t- %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); -} - -int main(int argc, char **argv) -{ - cmap_str phone_book = c_init(cmap_str, { - {"Lilia Friedman", "(892) 670-4739"}, - {"Tariq Beltran", "(489) 600-7575"}, - {"Laiba Juarez", "(303) 885-5692"}, - {"Elliott Mooney", "(945) 616-4482"}, - }); - - printf("Phone book:\n"); - print_phone_book(phone_book); - - cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1880"); - cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1990"); - - printf("\nPhone book after adding Zak Byers:\n"); - print_phone_book(phone_book); - - if (cmap_str_contains(&phone_book, "Tariq Beltran")) - printf("\nTariq Beltran is in phone book\n"); - - cmap_str_erase(&phone_book, "Tariq Beltran"); - cmap_str_erase(&phone_book, "Elliott Mooney"); - - printf("\nPhone book after erasing Tariq and Elliott:\n"); - print_phone_book(phone_book); - - cmap_str_emplace_or_assign(&phone_book, "Zak Byers", "(555) 396-188"); - - printf("\nPhone book after update phone of Zak Byers:\n"); - print_phone_book(phone_book); - - cmap_str_drop(&phone_book); -} diff --git a/misc/examples/prime.c b/misc/examples/prime.c deleted file mode 100644 index cb3b095a..00000000 --- a/misc/examples/prime.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include -#include -#include -#include - - -cbits sieveOfEratosthenes(int64_t n) -{ - cbits bits = cbits_with_size(n/2 + 1, true); - int64_t q = (int64_t)sqrt((double) n) + 1; - for (int64_t i = 3; i < q; i += 2) { - int64_t j = i; - for (; j < n; j += 2) { - if (cbits_test(&bits, j>>1)) { - i = j; - break; - } - } - for (int64_t j = i*i; j < n; j += i*2) - cbits_reset(&bits, j>>1); - } - return bits; -} - -int main(void) -{ - int n = 1000000000; - printf("Computing prime numbers up to %d\n", n); - - clock_t t = clock(); - cbits primes = sieveOfEratosthenes(n + 1); - int np = (int)cbits_count(&primes); - t = clock() - t; - - puts("Show all the primes in the range [2, 1000):"); - printf("2"); - c_forrange (i, 3, 1000, 2) - if (cbits_test(&primes, i>>1)) printf(" %lld", i); - puts("\n"); - - puts("Show the last 50 primes using a temporary crange generator:"); - crange range = crange_make(n - 1, 0, -2); - - c_forfilter (i, crange, range, - cbits_test(&primes, *i.ref/2) && - c_flt_take(i, 50) - ){ - printf("%lld ", *i.ref); - if (c_flt_getcount(i) % 10 == 0) puts(""); - } - printf("Number of primes: %d, time: %.2f\n\n", np, (double)t/CLOCKS_PER_SEC); - - cbits_drop(&primes); -} diff --git a/misc/examples/printspan.c b/misc/examples/printspan.c deleted file mode 100644 index cd3c5f4f..00000000 --- a/misc/examples/printspan.c +++ /dev/null @@ -1,52 +0,0 @@ -// printspan.c - -#include -#define i_implement -#include -#define i_key int -#include -#define i_key int -#include -#define i_key_str -#include - -#include -using_cspan(intspan, int, 1); - -void printMe(intspan container) { - printf("%d:", (int)cspan_size(&container)); - c_foreach (e, intspan, container) - printf(" %d", *e.ref); - puts(""); -} - -int main(void) -{ - intspan sp1 = cspan_init(intspan, {1, 2}); - printMe( sp1 ); - - printMe( c_init(intspan, {1, 2, 3}) ); - - int arr[] = {1, 2, 3, 4, 5, 6}; - intspan sp2 = cspan_from_array(arr); - printMe( c_LITERAL(intspan)cspan_subspan(&sp2, 1, 4) ); - - cvec_int vec = c_init(cvec_int, {1, 2, 3, 4, 5}); - printMe( c_LITERAL(intspan)cspan_from(&vec) ); - - printMe( sp2 ); - - cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7}); - printMe( c_LITERAL(intspan)cspan_from(&stk) ); - - csset_str set = c_init(csset_str, {"5", "7", "4", "3", "8", "2", "1", "9", "6"}); - printf("%d:", (int)csset_str_size(&set)); - c_foreach (e, csset_str, set) - printf(" %s", cstr_str(e.ref)); - puts(""); - - // cleanup - cvec_int_drop(&vec); - cstack_int_drop(&stk); - csset_str_drop(&set); -} diff --git a/misc/examples/priority.c b/misc/examples/priority.c deleted file mode 100644 index bf2e188a..00000000 --- a/misc/examples/priority.c +++ /dev/null @@ -1,37 +0,0 @@ - -#include -#include -#include - -#define i_key int64_t -#define i_cmp -c_default_cmp // min-heap (increasing values) -#define i_tag i -#include - -int main(void) { - intptr_t N = 10000000; - crand_t rng = crand_init((uint64_t)time(NULL)); - crand_unif_t dist = crand_unif_init(0, N * 10); - - cpque_i heap = {0}; - - // Push ten million random numbers to priority queue - printf("Push %" c_ZI " numbers\n", N); - c_forrange (N) - cpque_i_push(&heap, crand_unif(&rng, &dist)); - - // push some negative numbers too. - c_forlist (i, int, {-231, -32, -873, -4, -343}) - cpque_i_push(&heap, *i.ref); - - c_forrange (N) - cpque_i_push(&heap, crand_unif(&rng, &dist)); - - puts("Extract the hundred smallest."); - c_forrange (100) { - printf("%" PRId64 " ", *cpque_i_top(&heap)); - cpque_i_pop(&heap); - } - - cpque_i_drop(&heap); -} diff --git a/misc/examples/priorityqueues/functor.c b/misc/examples/priorityqueues/functor.c new file mode 100644 index 00000000..e3bde1dd --- /dev/null +++ b/misc/examples/priorityqueues/functor.c @@ -0,0 +1,57 @@ +// Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue +// Example of per-instance less-function on a single priority queue type +// + +#include + +#define i_type IPQue +#define i_base cpque +#define i_key int +#define i_extend bool(*less)(const int*, const int*); +#define i_less(x, y) c_extend()->less(x, y) +// Note: i_less: c_extend() accessible for cpque types +// i_cmp: c_extend() accessible for csmap and csset types +// i_hash/i_eq: c_extend() accessible for cmap and cset types +#include + +void print_queue(const char* name, IPQue_ext q) { + // NB: make a clone because there is no way to traverse + // priority queue's content without erasing the queue. + IPQue_ext copy = {q.less, IPQue_clone(q.get)}; + + for (printf("%s: \t", name); !IPQue_empty(©.get); IPQue_pop(©.get)) + printf("%d ", *IPQue_top(©.get)); + puts(""); + + IPQue_drop(©.get); +} + +static bool int_less(const int* x, const int* y) { return *x < *y; } +static bool int_greater(const int* x, const int* y) { return *x > *y; } +static bool int_lambda(const int* x, const int* y) { return (*x ^ 1) < (*y ^ 1); } + +int main(void) +{ + const int data[] = {1,8,5,6,3,4,0,9,7,2}, n = c_arraylen(data); + printf("data: \t"); + c_forrange (i, n) printf("%d ", data[i]); + puts(""); + + + // Max priority queue + IPQue_ext q1 = {.less=int_less}; + IPQue_put_n(&q1.get, data, n); + print_queue("q1", q1); + + // Min priority queue + IPQue_ext minq1 = {.less=int_greater}; + IPQue_put_n(&minq1.get, data, n); + print_queue("minq1", minq1); + + // Using lambda to compare elements. + IPQue_ext q5 = {.less=int_lambda}; + IPQue_put_n(&q5.get, data, n); + print_queue("q5", q5); + + c_drop(IPQue, &q1.get, &minq1.get, &q5.get); +} diff --git a/misc/examples/priorityqueues/new_pque.c b/misc/examples/priorityqueues/new_pque.c new file mode 100644 index 00000000..16823bb6 --- /dev/null +++ b/misc/examples/priorityqueues/new_pque.c @@ -0,0 +1,22 @@ +#include + +typedef struct Point { int x, y; } Point; + +#define i_type PointQ +#define i_key Point +#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) +#include + + +int main(void) +{ + PointQ pque = c_init(PointQ, {{23, 80}, {12, 32}, {54, 74}, {12, 62}}); + // print + for (; !PointQ_empty(&pque); PointQ_pop(&pque)) + { + const Point *v = PointQ_top(&pque); + printf(" (%d,%d)", v->x, v->y); + } + puts(""); + PointQ_drop(&pque); +} diff --git a/misc/examples/priorityqueues/priority.c b/misc/examples/priorityqueues/priority.c new file mode 100644 index 00000000..bf2e188a --- /dev/null +++ b/misc/examples/priorityqueues/priority.c @@ -0,0 +1,37 @@ + +#include +#include +#include + +#define i_key int64_t +#define i_cmp -c_default_cmp // min-heap (increasing values) +#define i_tag i +#include + +int main(void) { + intptr_t N = 10000000; + crand_t rng = crand_init((uint64_t)time(NULL)); + crand_unif_t dist = crand_unif_init(0, N * 10); + + cpque_i heap = {0}; + + // Push ten million random numbers to priority queue + printf("Push %" c_ZI " numbers\n", N); + c_forrange (N) + cpque_i_push(&heap, crand_unif(&rng, &dist)); + + // push some negative numbers too. + c_forlist (i, int, {-231, -32, -873, -4, -343}) + cpque_i_push(&heap, *i.ref); + + c_forrange (N) + cpque_i_push(&heap, crand_unif(&rng, &dist)); + + puts("Extract the hundred smallest."); + c_forrange (100) { + printf("%" PRId64 " ", *cpque_i_top(&heap)); + cpque_i_pop(&heap); + } + + cpque_i_drop(&heap); +} diff --git a/misc/examples/queue.c b/misc/examples/queue.c deleted file mode 100644 index 56b5beb9..00000000 --- a/misc/examples/queue.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -#define i_key int -#define i_tag i -#include - -int main(void) { - int n = 100000000; - crand_unif_t dist; - crand_t rng = crand_init(1234); - dist = crand_unif_init(0, n); - - cqueue_i queue = {0}; - - // Push ten million random numbers onto the queue. - c_forrange (n) - cqueue_i_push(&queue, (int)crand_unif(&rng, &dist)); - - // Push or pop on the queue ten million times - printf("%d\n", n); - c_forrange (n) { // forrange uses initial n only. - int r = (int)crand_unif(&rng, &dist); - if (r & 1) - ++n, cqueue_i_push(&queue, r); - else - --n, cqueue_i_pop(&queue); - } - printf("%d, %" c_ZI "\n", n, cqueue_i_size(&queue)); - - cqueue_i_drop(&queue); -} diff --git a/misc/examples/queues/new_queue.c b/misc/examples/queues/new_queue.c new file mode 100644 index 00000000..f3592df6 --- /dev/null +++ b/misc/examples/queues/new_queue.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +forward_cqueue(cqueue_pnt, struct Point); + +typedef struct Point { int x, y; } Point; +int point_cmp(const Point* a, const Point* b) { + int c = c_default_cmp(&a->x, &b->x); + return c ? c : c_default_cmp(&a->y, &b->y); +} +#define i_key Point +#define i_cmp point_cmp +#define i_is_forward +#define i_tag pnt +#include + +#define i_type IQ +#define i_key int +#include + +int main(void) { + int n = 50000000; + crand_t rng = crand_init((uint64_t)time(NULL)); + crand_unif_t dist = crand_unif_init(0, n); + + IQ Q = {0}; + + // Push 50'000'000 random numbers onto the queue. + c_forrange (n) + IQ_push(&Q, (int)crand_unif(&rng, &dist)); + + // Push or pop on the queue 50 million times + printf("befor: size %" c_ZI ", capacity %" c_ZI "\n", IQ_size(&Q), IQ_capacity(&Q)); + + c_forrange (n) { + int r = (int)crand_unif(&rng, &dist); + if (r & 3) + IQ_push(&Q, r); + else + IQ_pop(&Q); + } + + printf("after: size %" c_ZI ", capacity %" c_ZI "\n", IQ_size(&Q), IQ_capacity(&Q)); + IQ_drop(&Q); +} diff --git a/misc/examples/queues/queue.c b/misc/examples/queues/queue.c new file mode 100644 index 00000000..56b5beb9 --- /dev/null +++ b/misc/examples/queues/queue.c @@ -0,0 +1,32 @@ +#include +#include + +#define i_key int +#define i_tag i +#include + +int main(void) { + int n = 100000000; + crand_unif_t dist; + crand_t rng = crand_init(1234); + dist = crand_unif_init(0, n); + + cqueue_i queue = {0}; + + // Push ten million random numbers onto the queue. + c_forrange (n) + cqueue_i_push(&queue, (int)crand_unif(&rng, &dist)); + + // Push or pop on the queue ten million times + printf("%d\n", n); + c_forrange (n) { // forrange uses initial n only. + int r = (int)crand_unif(&rng, &dist); + if (r & 1) + ++n, cqueue_i_push(&queue, r); + else + --n, cqueue_i_pop(&queue); + } + printf("%d, %" c_ZI "\n", n, cqueue_i_size(&queue)); + + cqueue_i_drop(&queue); +} diff --git a/misc/examples/random.c b/misc/examples/random.c deleted file mode 100644 index b7c0f277..00000000 --- a/misc/examples/random.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include - -int main(void) -{ - const int N = 1000000000; - const uint64_t seed = (uint64_t)time(NULL), range = 1000000; - crand_t rng = crand_init(seed); - - int64_t sum; - clock_t diff, before; - - printf("Compare speed of full and unbiased ranged random numbers...\n"); - sum = 0; - before = clock(); - c_forrange (N) { - sum += (uint32_t)crand_u64(&rng); - } - diff = clock() - before; - printf("full range\t\t: %f secs, %d, avg: %f\n", - (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); - - crand_unif_t dist1 = crand_unif_init(0, range); - rng = crand_init(seed); - sum = 0; - before = clock(); - c_forrange (N) { - sum += crand_unif(&rng, &dist1); // unbiased - } - diff = clock() - before; - printf("unbiased 0-%" PRIu64 "\t: %f secs, %d, avg: %f\n", - range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); - - sum = 0; - rng = crand_init(seed); - before = clock(); - c_forrange (N) { - sum += (int64_t)(crand_u64(&rng) % (range + 1)); // biased - } - diff = clock() - before; - printf("biased 0-%" PRIu64 " \t: %f secs, %d, avg: %f\n", - range, (double)diff/CLOCKS_PER_SEC, N, (double)sum/N); - -} diff --git a/misc/examples/rawptr_elements.c b/misc/examples/rawptr_elements.c deleted file mode 100644 index 694ce12e..00000000 --- a/misc/examples/rawptr_elements.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#define i_implement -#include - -// Create cmap of cstr => long* -#define i_type SIPtrMap -#define i_key_str -#define i_val long* -#define i_valraw long -#define i_valfrom(raw) c_new(long, raw) -#define i_valto(x) **x -#define i_valclone(x) c_new(long, *x) -#define i_valdrop(x) c_free(*x) -#include - -// Alternatively, using cbox: -#define i_type IBox -#define i_key long -#include // unique_ptr alike. - -// cmap of cstr => IBox -#define i_type SIBoxMap -#define i_key_str -#define i_valboxed IBox // i_valboxed: use properties from IBox automatically -#include - -int main(void) -{ - // These have the same behaviour, except IBox has a get member: - SIPtrMap map1 = {0}; - SIBoxMap map2 = {0}; - - printf("\nMap cstr => long*:\n"); - SIPtrMap_insert(&map1, cstr_from("Test1"), c_new(long, 1)); - SIPtrMap_insert(&map1, cstr_from("Test2"), c_new(long, 2)); - - // Emplace implicitly creates cstr from const char* and an owned long* from long! - SIPtrMap_emplace(&map1, "Test3", 3); - SIPtrMap_emplace(&map1, "Test4", 4); - - c_forpair (name, number, SIPtrMap, map1) - printf("%s: %ld\n", cstr_str(_.name), **_.number); - - puts("\nMap cstr => IBox:"); - SIBoxMap_insert(&map2, cstr_from("Test1"), IBox_make(1)); - SIBoxMap_insert(&map2, cstr_from("Test2"), IBox_make(2)); - - // Emplace implicitly creates cstr from const char* and IBox from long! - SIBoxMap_emplace(&map2, "Test3", 3); - SIBoxMap_emplace(&map2, "Test4", 4); - - c_forpair (name, number, SIBoxMap, map2) - printf("%s: %ld\n", cstr_str(_.name), *_.number->get); - puts(""); - - SIPtrMap_drop(&map1); - SIBoxMap_drop(&map2); -} diff --git a/misc/examples/read.c b/misc/examples/read.c deleted file mode 100644 index b12f7409..00000000 --- a/misc/examples/read.c +++ /dev/null @@ -1,27 +0,0 @@ -#define i_implement -#include -#include -#define i_key_str -#include -#include - -cvec_str read_file(const char* name) -{ - cvec_str vec = cvec_str_init(); - c_with (FILE* f = fopen(name, "r"), fclose(f)) - c_with (cstr line = cstr_null, cstr_drop(&line)) - while (cstr_getline(&line, f)) - cvec_str_push(&vec, cstr_clone(line)); - return vec; -} - -int main(void) -{ - int n = 0; - c_with (cvec_str vec = read_file(__FILE__), cvec_str_drop(&vec)) - c_foreach (i, cvec_str, vec) - printf("%5d: %s\n", ++n, cstr_str(i.ref)); - - if (errno) - printf("error: read_file(" __FILE__ "). errno: %d\n", errno); -} diff --git a/misc/examples/regex1.c b/misc/examples/regex1.c deleted file mode 100644 index d8032358..00000000 --- a/misc/examples/regex1.c +++ /dev/null @@ -1,32 +0,0 @@ -#define i_import -#include - -int main(int argc, char* argv[]) -{ - if (argc <= 1) { - printf("Usage: regex1 -i\n"); - return 0; - } - cstr input = {0}; - cregex float_expr = {0}; - - int res = cregex_compile(&float_expr, "^[+-]?[0-9]+((\\.[0-9]*)?|\\.[0-9]+)$"); - // Until "q" is given, ask for another number - if (res > 0) while (true) - { - printf("Enter a double precision number (q for quit): "); - cstr_getline(&input, stdin); - - // Exit when the user inputs q - if (cstr_equals(&input, "q")) - break; - - if (cregex_is_match(&float_expr, cstr_str(&input))) - printf("Input is a float\n"); - else - printf("Invalid input : Not a float\n"); - } - - cstr_drop(&input); - cregex_drop(&float_expr); -} diff --git a/misc/examples/regex2.c b/misc/examples/regex2.c deleted file mode 100644 index a798b1a1..00000000 --- a/misc/examples/regex2.c +++ /dev/null @@ -1,34 +0,0 @@ -#define i_import -#include - -int main(void) -{ - struct { const char *pattern, *input; } s[] = { - {"(\\d\\d\\d\\d)[-_](1[0-2]|0[1-9])[-_](3[01]|[12][0-9]|0[1-9])", - "date: 2024-02-29 leapyear day, christmas eve is on 2022-12-24." - }, - {"(https?://|ftp://|www\\.)([0-9A-Za-z@:%_+~#=-]+\\.)+([a-z][a-z][a-z]?)(/[/0-9A-Za-z\\.@:%_+~#=\\?&-]*)?", - "https://en.cppreference.com/w/cpp/regex/regex_search" - }, - {"!((abc|123)+)!", "!123abcabc!"}, - {"(\\p{Alpha}+ )+(\\p{Nd}+)", "Großpackung süßigkeiten 199"}, - {"\\p{Han}+", "This is Han: 王明:那是杂志吗?"}, - }; - - cregex re = {0}; - c_forrange (i, c_arraylen(s)) - { - int res = cregex_compile(&re, s[i].pattern); - if (res < 0) { - printf("error in regex pattern: %d\n", res); - continue; - } - printf("\ninput: %s\n", s[i].input); - - c_formatch (j, &re, s[i].input) { - c_forrange (k, cregex_captures(&re) + 1) - printf(" submatch %lld: %.*s\n", k, c_SV(j.match[k])); - } - } - cregex_drop(&re); -} diff --git a/misc/examples/regex_match.c b/misc/examples/regex_match.c deleted file mode 100644 index 11426d2d..00000000 --- a/misc/examples/regex_match.c +++ /dev/null @@ -1,37 +0,0 @@ -#define i_import -#include -#define i_implement -#include - -#define i_key float -#include - -int main(void) -{ - // Lets find the first sequence of digits in a string - const char *str = "Hello numeric world, there are 24 hours in a day, 3600 seconds in an hour." - " Around 365.25 days a year, and 52 weeks in a year." - " Boltzmann const: 1.38064852E-23, is very small." - " Bohrradius is 5.29177210903e-11, and Avogadros number is 6.02214076e23."; - cregex re = {0}; - cstack_float vec = {0}; - - const char* pattern = "[+-]?([0-9]*\\.)?\\d+([Ee][+-]?\\d+)?"; - int res = cregex_compile(&re, pattern); - printf("%d: %s\n", res, pattern); - - // extract and convert all numbers in str to floats - c_formatch (i, &re, str) - cstack_float_push(&vec, (float)atof(i.match[0].str)); - - c_foreach (i, cstack_float, vec) - printf(" %g\n", (double)*i.ref); - - // extracts the numbers only to a comma separated string. - cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_STRIP); - printf("\n%s\n", cstr_str(&nums)); - - cstr_drop(&nums); - cregex_drop(&re); - cstack_float_drop(&vec); -} diff --git a/misc/examples/regex_replace.c b/misc/examples/regex_replace.c deleted file mode 100644 index f1ea2711..00000000 --- a/misc/examples/regex_replace.c +++ /dev/null @@ -1,57 +0,0 @@ -#define i_import -#include -#include - -bool add_10_years(int i, csview match, cstr* out) { - if (i == 1) { // group 1 matches year - int year; - sscanf(match.str, "%4d", &year); // scan 4 chars only - cstr_printf(out, "%04d", year + 10); - return true; - } - return false; -} - -int main(void) -{ - const char* pattern = "\\b(\\d\\d\\d\\d)-(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])\\b"; - const char* input = "start date: 2015-12-31, end date: 2022-02-28"; - cstr str = {0}; - cregex re = {0}; - - c_defer( - cregex_drop(&re), - cstr_drop(&str) - ){ - printf("INPUT: %s\n", input); - - /* replace with a fixed string, extended all-in-one call: */ - cstr_take(&str, cregex_replace_pattern(pattern, input, "YYYY-MM-DD")); - printf("fixed: %s\n", cstr_str(&str)); - - /* US date format, and add 10 years to dates: */ - cstr_take(&str, cregex_replace_pattern(pattern, input, "$1/$3/$2", 0, add_10_years, CREG_DEFAULT)); - printf("us+10: %s\n", cstr_str(&str)); - - /* Wrap first date inside []: */ - cstr_take(&str, cregex_replace_pattern(pattern, input, "[$0]")); - printf("brack: %s\n", cstr_str(&str)); - - /* Shows how to compile RE separately */ - re = cregex_from(pattern); - if (cregex_captures(&re) == 0) - continue; /* break c_defer */ - - /* European date format. */ - cstr_take(&str, cregex_replace(&re, input, "$3.$2.$1")); - printf("euros: %s\n", cstr_str(&str)); - - /* Strip out everything but the matches */ - cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); - printf("strip: %s\n", cstr_str(&str)); - - /* Wrap all words in ${} */ - cstr_take(&str, cregex_replace_pattern("[a-z]+", "52 apples and 31 mangoes", "$${$0}")); - printf("curly: %s\n", cstr_str(&str)); - } -} diff --git a/misc/examples/regularexpressions/regex1.c b/misc/examples/regularexpressions/regex1.c new file mode 100644 index 00000000..d8032358 --- /dev/null +++ b/misc/examples/regularexpressions/regex1.c @@ -0,0 +1,32 @@ +#define i_import +#include + +int main(int argc, char* argv[]) +{ + if (argc <= 1) { + printf("Usage: regex1 -i\n"); + return 0; + } + cstr input = {0}; + cregex float_expr = {0}; + + int res = cregex_compile(&float_expr, "^[+-]?[0-9]+((\\.[0-9]*)?|\\.[0-9]+)$"); + // Until "q" is given, ask for another number + if (res > 0) while (true) + { + printf("Enter a double precision number (q for quit): "); + cstr_getline(&input, stdin); + + // Exit when the user inputs q + if (cstr_equals(&input, "q")) + break; + + if (cregex_is_match(&float_expr, cstr_str(&input))) + printf("Input is a float\n"); + else + printf("Invalid input : Not a float\n"); + } + + cstr_drop(&input); + cregex_drop(&float_expr); +} diff --git a/misc/examples/regularexpressions/regex2.c b/misc/examples/regularexpressions/regex2.c new file mode 100644 index 00000000..a798b1a1 --- /dev/null +++ b/misc/examples/regularexpressions/regex2.c @@ -0,0 +1,34 @@ +#define i_import +#include + +int main(void) +{ + struct { const char *pattern, *input; } s[] = { + {"(\\d\\d\\d\\d)[-_](1[0-2]|0[1-9])[-_](3[01]|[12][0-9]|0[1-9])", + "date: 2024-02-29 leapyear day, christmas eve is on 2022-12-24." + }, + {"(https?://|ftp://|www\\.)([0-9A-Za-z@:%_+~#=-]+\\.)+([a-z][a-z][a-z]?)(/[/0-9A-Za-z\\.@:%_+~#=\\?&-]*)?", + "https://en.cppreference.com/w/cpp/regex/regex_search" + }, + {"!((abc|123)+)!", "!123abcabc!"}, + {"(\\p{Alpha}+ )+(\\p{Nd}+)", "Großpackung süßigkeiten 199"}, + {"\\p{Han}+", "This is Han: 王明:那是杂志吗?"}, + }; + + cregex re = {0}; + c_forrange (i, c_arraylen(s)) + { + int res = cregex_compile(&re, s[i].pattern); + if (res < 0) { + printf("error in regex pattern: %d\n", res); + continue; + } + printf("\ninput: %s\n", s[i].input); + + c_formatch (j, &re, s[i].input) { + c_forrange (k, cregex_captures(&re) + 1) + printf(" submatch %lld: %.*s\n", k, c_SV(j.match[k])); + } + } + cregex_drop(&re); +} diff --git a/misc/examples/regularexpressions/regex_match.c b/misc/examples/regularexpressions/regex_match.c new file mode 100644 index 00000000..11426d2d --- /dev/null +++ b/misc/examples/regularexpressions/regex_match.c @@ -0,0 +1,37 @@ +#define i_import +#include +#define i_implement +#include + +#define i_key float +#include + +int main(void) +{ + // Lets find the first sequence of digits in a string + const char *str = "Hello numeric world, there are 24 hours in a day, 3600 seconds in an hour." + " Around 365.25 days a year, and 52 weeks in a year." + " Boltzmann const: 1.38064852E-23, is very small." + " Bohrradius is 5.29177210903e-11, and Avogadros number is 6.02214076e23."; + cregex re = {0}; + cstack_float vec = {0}; + + const char* pattern = "[+-]?([0-9]*\\.)?\\d+([Ee][+-]?\\d+)?"; + int res = cregex_compile(&re, pattern); + printf("%d: %s\n", res, pattern); + + // extract and convert all numbers in str to floats + c_formatch (i, &re, str) + cstack_float_push(&vec, (float)atof(i.match[0].str)); + + c_foreach (i, cstack_float, vec) + printf(" %g\n", (double)*i.ref); + + // extracts the numbers only to a comma separated string. + cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_STRIP); + printf("\n%s\n", cstr_str(&nums)); + + cstr_drop(&nums); + cregex_drop(&re); + cstack_float_drop(&vec); +} diff --git a/misc/examples/regularexpressions/regex_replace.c b/misc/examples/regularexpressions/regex_replace.c new file mode 100644 index 00000000..f1ea2711 --- /dev/null +++ b/misc/examples/regularexpressions/regex_replace.c @@ -0,0 +1,57 @@ +#define i_import +#include +#include + +bool add_10_years(int i, csview match, cstr* out) { + if (i == 1) { // group 1 matches year + int year; + sscanf(match.str, "%4d", &year); // scan 4 chars only + cstr_printf(out, "%04d", year + 10); + return true; + } + return false; +} + +int main(void) +{ + const char* pattern = "\\b(\\d\\d\\d\\d)-(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])\\b"; + const char* input = "start date: 2015-12-31, end date: 2022-02-28"; + cstr str = {0}; + cregex re = {0}; + + c_defer( + cregex_drop(&re), + cstr_drop(&str) + ){ + printf("INPUT: %s\n", input); + + /* replace with a fixed string, extended all-in-one call: */ + cstr_take(&str, cregex_replace_pattern(pattern, input, "YYYY-MM-DD")); + printf("fixed: %s\n", cstr_str(&str)); + + /* US date format, and add 10 years to dates: */ + cstr_take(&str, cregex_replace_pattern(pattern, input, "$1/$3/$2", 0, add_10_years, CREG_DEFAULT)); + printf("us+10: %s\n", cstr_str(&str)); + + /* Wrap first date inside []: */ + cstr_take(&str, cregex_replace_pattern(pattern, input, "[$0]")); + printf("brack: %s\n", cstr_str(&str)); + + /* Shows how to compile RE separately */ + re = cregex_from(pattern); + if (cregex_captures(&re) == 0) + continue; /* break c_defer */ + + /* European date format. */ + cstr_take(&str, cregex_replace(&re, input, "$3.$2.$1")); + printf("euros: %s\n", cstr_str(&str)); + + /* Strip out everything but the matches */ + cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP)); + printf("strip: %s\n", cstr_str(&str)); + + /* Wrap all words in ${} */ + cstr_take(&str, cregex_replace_pattern("[a-z]+", "52 apples and 31 mangoes", "$${$0}")); + printf("curly: %s\n", cstr_str(&str)); + } +} diff --git a/misc/examples/replace.c b/misc/examples/replace.c deleted file mode 100644 index 59a56bf7..00000000 --- a/misc/examples/replace.c +++ /dev/null @@ -1,36 +0,0 @@ -#define i_implement -#include - -int main(void) -{ - const char *base = "this is a test string."; - const char *s2 = "n example"; - const char *s3 = "sample phrase"; - - // replace signatures used in the same order as described above: - - // Ustring positions: 0123456789*123456789*12345 - cstr s = cstr_from(base); // "this is a test string." - cstr m = cstr_clone(s); - - cstr_append(&m, cstr_str(&m)); - cstr_append(&m, cstr_str(&m)); - printf("%s\n", cstr_str(&m)); - - cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) - printf("(1) %s\n", cstr_str(&s)); - - cstr_replace_at_sv(&s, 19, 6, c_sv(s3+7, 6)); // "this is an example phrase." (2) - printf("(2) %s\n", cstr_str(&s)); - - cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3) - printf("(3) %s\n", cstr_str(&s)); - - cstr_replace_at_sv(&s, 8, 6, c_sv("a shorty", 7)); // "this is a short phrase." (4) - printf("(4) %s\n", cstr_str(&s)); - - cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) - printf("(5) %s\n", cstr_str(&s)); - - c_drop(cstr, &s, &m); -} diff --git a/misc/examples/scheduler.c b/misc/examples/scheduler.c deleted file mode 100644 index 38defd0f..00000000 --- a/misc/examples/scheduler.c +++ /dev/null @@ -1,74 +0,0 @@ -// https://www.youtube.com/watch?v=8sEe-4tig_A -#include -#include - -struct Task { - int (*fn)(struct Task*); - int cco_state; - struct Scheduler* sched; -}; - -#define i_type Scheduler -#define i_key struct Task -#include - -static bool schedule(Scheduler* sched) -{ - struct Task task = *Scheduler_front(sched); - Scheduler_pop(sched); - - if (!cco_done(&task)) - task.fn(&task); - - return !Scheduler_empty(sched); -} - -static int push_task(const struct Task* task) -{ - Scheduler_push(task->sched, *task); - return CCO_YIELD; -} - - -static int taskA(struct Task* task) -{ - cco_routine(task) { - puts("Hello, from task A"); - cco_yield_v(push_task(task)); - puts("A is back doing work"); - cco_yield_v(push_task(task)); - puts("A is back doing more work"); - cco_yield_v(push_task(task)); - puts("A is back doing even more work"); - } - return 0; -} - -static int taskB(struct Task* task) -{ - cco_routine(task) { - puts("Hello, from task B"); - cco_yield_v(push_task(task)); - puts("B is back doing work"); - cco_yield_v(push_task(task)); - puts("B is back doing more work"); - } - return 0; -} - -void Use(void) -{ - Scheduler scheduler = c_init(Scheduler, { - {.fn=taskA, .sched=&scheduler}, - {.fn=taskB, .sched=&scheduler}, - }); - - while (schedule(&scheduler)) {} - - Scheduler_drop(&scheduler); -} - -int main(void) -{ - Use(); -} diff --git a/misc/examples/shape.c b/misc/examples/shape.c deleted file mode 100644 index bd4bdd5a..00000000 --- a/misc/examples/shape.c +++ /dev/null @@ -1,158 +0,0 @@ -// Demo of typesafe polymorphism in C99, using STC. - -#include -#include -#include - -#define DYN_CAST(T, s) \ - (&T##_api == (s)->api ? (T*)(s) : (T*)0) - -// Shape definition -// ============================================================ - -typedef struct { - float x, y; -} Point; - -typedef struct Shape Shape; - -struct ShapeAPI { - void (*drop)(Shape*); - void (*draw)(const Shape*); -}; - -struct Shape { - struct ShapeAPI* api; - uint32_t color; - uint16_t style; - uint8_t thickness; - uint8_t hardness; -}; - -void Shape_drop(Shape* shape) -{ - printf("shape destructed\n"); -} - -void Shape_delete(Shape* shape) -{ - if (shape) { - shape->api->drop(shape); - c_free(shape); - } -} - -// Triangle implementation -// ============================================================ - -typedef struct { - Shape shape; - Point p[3]; -} Triangle; - -extern struct ShapeAPI Triangle_api; - - -Triangle Triangle_from(Point a, Point b, Point c) { - Triangle t = {{&Triangle_api}, {a, b, c}}; - return t; -} - -static void Triangle_draw(const Shape* shape) -{ - const Triangle* self = DYN_CAST(Triangle, shape); - printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n", - (double)self->p[0].x, (double)self->p[0].y, - (double)self->p[1].x, (double)self->p[1].y, - (double)self->p[2].x, (double)self->p[2].y); -} - -struct ShapeAPI Triangle_api = { - .drop = Shape_drop, - .draw = Triangle_draw, -}; - -// Polygon implementation -// ============================================================ - -#define i_type PointVec -#define i_key Point -#include - -typedef struct { - Shape shape; - PointVec points; -} Polygon; - -extern struct ShapeAPI Polygon_api; - - -Polygon Polygon_init(void) { - Polygon p = {{&Polygon_api}, {0}}; - return p; -} - -void Polygon_addPoint(Polygon* self, Point p) -{ - PointVec_push(&self->points, p); -} - -static void Polygon_drop(Shape* shape) -{ - Polygon* self = DYN_CAST(Polygon, shape); - printf("poly destructed\n"); - PointVec_drop(&self->points); -} - -static void Polygon_draw(const Shape* shape) -{ - const Polygon* self = DYN_CAST(Polygon, shape); - printf("Polygon :"); - c_foreach (i, PointVec, self->points) - printf(" (%g,%g)", (double)i.ref->x, (double)i.ref->y); - puts(""); -} - -struct ShapeAPI Polygon_api = { - .drop = Polygon_drop, - .draw = Polygon_draw, -}; - -// Test -// ============================================================ - -#define i_type Shapes -#define i_key Shape* -#define i_keydrop(x) Shape_delete(*x) -#define i_no_clone -#include - -void testShape(const Shape* shape) -{ - shape->api->draw(shape); -} - - -int main(void) -{ - Shapes shapes = {0}; - - Triangle* tri1 = c_new(Triangle, Triangle_from(c_LITERAL(Point){5, 7}, c_LITERAL(Point){12, 7}, c_LITERAL(Point){12, 20})); - Polygon* pol1 = c_new(Polygon, Polygon_init()); - Polygon* pol2 = c_new(Polygon, Polygon_init()); - - c_forlist (i, Point, {{50, 72}, {123, 73}, {127, 201}, {828, 333}}) - Polygon_addPoint(pol1, *i.ref); - - c_forlist (i, Point, {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}) - Polygon_addPoint(pol2, *i.ref); - - Shapes_push(&shapes, &tri1->shape); - Shapes_push(&shapes, &pol1->shape); - Shapes_push(&shapes, &pol2->shape); - - c_foreach (i, Shapes, shapes) - testShape(*i.ref); - - Shapes_drop(&shapes); -} diff --git a/misc/examples/shape.cpp b/misc/examples/shape.cpp deleted file mode 100644 index ea1f53d2..00000000 --- a/misc/examples/shape.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// Demo of polymorphism in C++ - -#include -#include -#include - -// Shape definition -// ============================================================ - -struct Point { - float x, y; -}; - -std::ostream& operator<<(std::ostream& os, const Point& p) { - os << " (" << p.x << "," << p.y << ")"; - return os; -} - -struct Shape { - virtual ~Shape(); - virtual void draw() const = 0; - - uint32_t color; - uint16_t style; - uint8_t thickness; - uint8_t hardness; -}; - -Shape::~Shape() -{ - std::cout << "base destructed" << std::endl; -} - -// Triangle implementation -// ============================================================ - -struct Triangle : public Shape -{ - Triangle(Point a, Point b, Point c); - void draw() const override; - - private: Point p[3]; -}; - - -Triangle::Triangle(Point a, Point b, Point c) - : p{a, b, c} {} - -void Triangle::draw() const -{ - std::cout << "Triangle :" - << p[0] << p[1] << p[2] - << std::endl; -} - - -// Polygon implementation -// ============================================================ - - -struct Polygon : public Shape -{ - ~Polygon(); - void draw() const override; - void addPoint(const Point& p); - - private: std::vector points; -}; - - -void Polygon::addPoint(const Point& p) -{ - points.push_back(p); -} - -Polygon::~Polygon() -{ - std::cout << "poly destructed" << std::endl; -} - -void Polygon::draw() const -{ - std::cout << "Polygon :"; - for (auto& p : points) - std::cout << p ; - std::cout << std::endl; -} - - -// Test -// ============================================================ - -void testShape(const Shape* shape) -{ - shape->draw(); -} - -#include - -int main(void) -{ - std::vector> shapes; - - auto tri1 = std::make_unique(Point{5, 7}, Point{12, 7}, Point{12, 20}); - auto pol1 = std::make_unique(); - auto pol2 = std::make_unique(); - - for (auto& p: std::array - {{{50, 72}, {123, 73}, {127, 201}, {828, 333}}}) - pol1->addPoint(p); - - for (auto& p: std::array - {{{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}}) - pol2->addPoint(p); - - shapes.push_back(std::move(tri1)); - shapes.push_back(std::move(pol1)); - shapes.push_back(std::move(pol2)); - - for (auto& shape: shapes) - testShape(shape.get()); -} diff --git a/misc/examples/sidebyside.cpp b/misc/examples/sidebyside.cpp deleted file mode 100644 index 9414b691..00000000 --- a/misc/examples/sidebyside.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include -#include -#include - -#define i_type IIMap -#define i_key int -#define i_val int -#include - -#define i_type SIMap -#define i_key_str -#define i_val int -#include - -int main(void) { - { - std::map hist; - hist.emplace(12, 100).first->second += 1; - hist.emplace(13, 100).first->second += 1; - hist.emplace(12, 100).first->second += 1; - - for (auto i: hist) - std::cout << i.first << ", " << i.second << std::endl; - std::cout << std::endl; - } - { - IIMap hist = {0}; - IIMap_insert(&hist, 12, 100).ref->second += 1; - IIMap_insert(&hist, 13, 100).ref->second += 1; - IIMap_insert(&hist, 12, 100).ref->second += 1; - - c_foreach (i, IIMap, hist) - printf("%d, %d\n", i.ref->first, i.ref->second); - puts(""); - IIMap_drop(&hist); - } - // =================================================== - { - std::map food = - {{"burger", 5}, {"pizza", 12}, {"steak", 15}}; - - for (auto i: food) - std::cout << i.first << ", " << i.second << std::endl; - std::cout << std::endl; - } - { - SIMap food = {0}; - c_forlist (i, SIMap_raw, {{"burger", 5}, {"pizza", 12}, {"steak", 15}}) - SIMap_emplace(&food, i.ref->first, i.ref->second); - - c_foreach (i, SIMap, food) - printf("%s, %d\n", cstr_str(&i.ref->first), i.ref->second); - puts(""); - SIMap_drop(&food); - } -} diff --git a/misc/examples/smartpointers/arc_containers.c b/misc/examples/smartpointers/arc_containers.c new file mode 100644 index 00000000..2fb04c56 --- /dev/null +++ b/misc/examples/smartpointers/arc_containers.c @@ -0,0 +1,81 @@ +// Create a stack and a list of shared pointers to maps, +// and demonstrate sharing and cloning of maps. +#define i_implement +#include +#include +#define i_type Map +#define i_key_str // strings +#define i_val int +#define i_keydrop(p) (printf("drop name: %s\n", cstr_str(p)), cstr_drop(p)) +#include + +#define i_type Arc // (atomic) ref. counted type +#define i_key Map +#define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p)) +// no need for atomic ref. count in single thread: +#define i_opt c_no_atomic +#include + +#define i_type Stack +#define i_keyboxed Arc // define i_keyboxed for carc/cbox value (not i_key) +#include + +#define i_type List +#define i_keyboxed Arc // as above +#include + +int main(void) +{ + Stack stack = {0}; + List list = {0}; + c_defer( + Stack_drop(&stack), + List_drop(&list) + ){ + // POPULATE stack with shared pointers to Maps: + Map *map; + map = Stack_push(&stack, Arc_from(Map_init()))->get; + Map_emplace(map, "Joey", 1990); + Map_emplace(map, "Mary", 1995); + Map_emplace(map, "Joanna", 1992); + + map = Stack_push(&stack, Arc_from(Map_init()))->get; + Map_emplace(map, "Rosanna", 2001); + Map_emplace(map, "Brad", 1999); + Map_emplace(map, "Jack", 1980); + + // POPULATE list: + map = List_push_back(&list, Arc_from(Map_init()))->get; + Map_emplace(map, "Steve", 1979); + Map_emplace(map, "Rick", 1974); + Map_emplace(map, "Tracy", 2003); + + // Share two Maps from the stack with the list using emplace (clone the carc): + List_push_back(&list, Arc_clone(stack.data[0])); + List_push_back(&list, Arc_clone(stack.data[1])); + + // Clone (deep copy) a Map from the stack to the list + // List will contain two shared and two unshared maps. + map = List_push_back(&list, Arc_from(Map_clone(*stack.data[1].get)))->get; + + // Add one more element to the cloned map: + Map_emplace_or_assign(map, "CLONED", 2021); + + // Add one more element to the shared map: + Map_emplace_or_assign(stack.data[1].get, "SHARED", 2021); + + puts("STACKS"); + c_foreach (i, Stack, stack) { + c_forpair (name, year, Map, *i.ref->get) + printf(" %s:%d", cstr_str(_.name), *_.year); + puts(""); + } + + puts("LIST"); + c_foreach (i, List, list) { + c_forpair (name, year, Map, *i.ref->get) + printf(" %s:%d", cstr_str(_.name), *_.year); + puts(""); + } + } +} diff --git a/misc/examples/smartpointers/arc_demo.c b/misc/examples/smartpointers/arc_demo.c new file mode 100644 index 00000000..929a48a1 --- /dev/null +++ b/misc/examples/smartpointers/arc_demo.c @@ -0,0 +1,62 @@ +#include +#include + +void int_drop(int* x) { + printf("drop: %d\n", *x); +} + +// carc implements its own clone method using reference counting, +// so 'i_keyclone' is not required to be defined (ignored). + +#define i_type Arc // set type name to be defined (instead of 'carc_int') +#define i_key int +#define i_keydrop int_drop // optional, just to display the elements destroyed +#define i_cmp_native // use int comparison (x < y, x == y). +#include // Arc + +#define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements +#include // csset_Arc (like: std::set>) + +#define i_keyboxed Arc // note: as above. +#include // cvec_Arc (like: std::vector>) + +int main(void) +{ + const int years[] = {2021, 2012, 2022, 2015}; + + cvec_Arc vec = {0}; + c_forrange (i, c_arraylen(years)) { + cvec_Arc_emplace(&vec, years[i]); + // cvec_Arc_push(&vec, Arc_from(years[i])); // alt. + } + + cvec_Arc_sort(&vec); + + printf("vec:"); + c_foreach (i, cvec_Arc, vec) + printf(" %d", *i.ref->get); + puts(""); + + // add odd numbers from vec to set + csset_Arc set = {0}; + c_foreach (i, cvec_Arc, vec) + if (*i.ref->get & 1) + csset_Arc_insert(&set, Arc_clone(*i.ref)); // copy shared pointer => increments counter. + + // erase the two last elements in vec + cvec_Arc_pop_back(&vec); + cvec_Arc_pop_back(&vec); + + printf("vec:"); + c_foreach (i, cvec_Arc, vec) printf(" %d", *i.ref->get); + + printf("\nset:"); + c_foreach (i, csset_Arc, set) printf(" %d", *i.ref->get); + + Arc p = Arc_clone(vec.data[0]); + printf("\n%d is now owned by %ld objects\n", *p.get, *p.use_count); + + Arc_drop(&p); + cvec_Arc_drop(&vec); + csset_Arc_drop(&set); +} diff --git a/misc/examples/smartpointers/arcvec_erase.c b/misc/examples/smartpointers/arcvec_erase.c new file mode 100644 index 00000000..ba54c1c7 --- /dev/null +++ b/misc/examples/smartpointers/arcvec_erase.c @@ -0,0 +1,50 @@ +#include + +void show_drop(int* x) { printf("drop: %d\n", *x); } + +#define i_type Arc +#define i_key int +#define i_keydrop show_drop +#define i_cmp_native // enable sort/search for int type +#include // Shared pointer to int + +#define i_type Vec +#define i_keyboxed Arc +#include // Vec: cvec + + +int main(void) +{ + Vec vec = c_init(Vec, {2012, 1990, 2012, 2019, 2015}); + + // clone the second 2012 and push it back. + // note: cloning make sure that vec.data[2] has ref count 2. + Vec_push(&vec, Arc_clone(vec.data[2])); + + printf("vec before erase :"); + c_foreach (i, Vec, vec) + printf(" %d", *i.ref->get); + + printf("\nerase vec.data[2]; or first matching value depending on compare.\n"); + Vec_iter it; + it = Vec_find(&vec, *vec.data[2].get); + if (it.ref) + Vec_erase_at(&vec, it); + + int year = 2015; + it = Vec_find(&vec, year); // Ok as tmp only. + if (it.ref) + Vec_erase_at(&vec, it); + + printf("vec after erase :"); + c_foreach (i, Vec, vec) + printf(" %d", *i.ref->get); + + Vec_sort(&vec); + printf("\nvec after sort :"); + c_foreach (i, Vec, vec) + printf(" %d", *i.ref->get); + + puts("\nDone"); + Vec_drop(&vec); +} diff --git a/misc/examples/smartpointers/box.c b/misc/examples/smartpointers/box.c new file mode 100644 index 00000000..94d126c0 --- /dev/null +++ b/misc/examples/smartpointers/box.c @@ -0,0 +1,69 @@ +/* cbox: heap allocated boxed type */ +#define i_implement +#include + +typedef struct { cstr name, last; } Person; + +Person Person_make(const char* name, const char* last) { + return c_LITERAL(Person){.name = cstr_from(name), .last = cstr_from(last)}; +} + +uint64_t Person_hash(const Person* a) { + return cstr_hash(&a->name) ^ cstr_hash(&a->last); +} + +int Person_cmp(const Person* a, const Person* b) { + int c = cstr_cmp(&a->name, &b->name); + return c ? c : cstr_cmp(&a->last, &b->last); +} + +Person Person_clone(Person p) { + p.name = cstr_clone(p.name); + p.last = cstr_clone(p.last); + return p; +} + +void Person_drop(Person* p) { + printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); + c_drop(cstr, &p->name, &p->last); +} + +#define i_type PBox +#define i_keyclass Person // "class" binds _cmp, _clone, _drop functions. +#include + +#define i_type Persons +#define i_keyboxed PBox // "arcbox" informs that PBox is a smart pointer. +#include + +int main(void) +{ + Persons vec = {0}; + PBox p = PBox_from(Person_make("Laura", "Palmer")); + PBox q = PBox_clone(p); + cstr_assign(&q.get->name, "Leland"); + + printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last)); + printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last)); + + Persons_emplace(&vec, Person_make("Dale", "Cooper")); + Persons_emplace(&vec, Person_make("Audrey", "Home")); + + // NB! Clone/share p and q in the Persons container. + Persons_push(&vec, PBox_clone(p)); + Persons_push(&vec, PBox_clone(q)); + + c_foreach (i, Persons, vec) + printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last)); + puts(""); + + // Look-up Audrey! Create a temporary Person for lookup. + Person a = Person_make("Audrey", "Home"); + const PBox *v = Persons_get(&vec, a); // lookup + if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last)); + + Person_drop(&a); + PBox_drop(&p); + PBox_drop(&q); + Persons_drop(&vec); +} diff --git a/misc/examples/smartpointers/box2.c b/misc/examples/smartpointers/box2.c new file mode 100644 index 00000000..eaab1c47 --- /dev/null +++ b/misc/examples/smartpointers/box2.c @@ -0,0 +1,82 @@ +// example: https://doc.rust-lang.org/rust-by-example/std/box.html +#include + +typedef struct { + double x; + double y; +} Point; + +// A Rectangle can be specified by where its top left and bottom right +// corners are in space +typedef struct { + Point top_left; + Point bottom_right; +} Rectangle; + +#define i_key Point +#include // cbox_Point + +#define i_key Rectangle +#include // cbox_Rectangle + +// Box in box: +#define i_type BoxBoxPoint +#define i_keyboxed cbox_Point // NB: use i_keyboxed when value is a cbox or carc! +#define i_no_cmp +#include // BoxBoxPoint + +Point origin(void) { + return c_LITERAL(Point){ .x=1.0, .y=2.0 }; +} + +cbox_Point boxed_origin(void) { + // Allocate this point on the heap, and return a pointer to it + return cbox_Point_make(c_LITERAL(Point){ .x=1.0, .y=2.0 }); +} + + +int main(void) { + // Stack allocated variables + Point point = origin(); + Rectangle rectangle = { + .top_left = origin(), + .bottom_right = { .x=3.0, .y=-4.0 } + }; + + // Heap allocated rectangle + cbox_Rectangle boxed_rectangle = cbox_Rectangle_make(c_LITERAL(Rectangle){ + .top_left = origin(), + .bottom_right = { .x=3.0, .y=-4.0 } + }); + // The output of functions can be boxed + cbox_Point boxed_point = cbox_Point_make(origin()); + + // Can use from(raw) and toraw instead: + BoxBoxPoint box_in_a_box = BoxBoxPoint_from(origin()); + + c_defer( + BoxBoxPoint_drop(&box_in_a_box), + cbox_Point_drop(&boxed_point), + cbox_Rectangle_drop(&boxed_rectangle) + ){ + printf("box_in_a_box: x = %g\n", BoxBoxPoint_toraw(&box_in_a_box).x); + + printf("Point occupies %d bytes on the stack\n", + (int)sizeof(point)); + printf("Rectangle occupies %d bytes on the stack\n", + (int)sizeof(rectangle)); + + // box size == pointer size + printf("Boxed point occupies %d bytes on the stack\n", + (int)sizeof(boxed_point)); + printf("Boxed rectangle occupies %d bytes on the stack\n", + (int)sizeof(boxed_rectangle)); + printf("Boxed box occupies %d bytes on the stack\n", + (int)sizeof(box_in_a_box)); + + // Copy the data contained in `boxed_point` into `unboxed_point` + Point unboxed_point = *boxed_point.get; + printf("Unboxed point occupies %d bytes on the stack\n", + (int)sizeof(unboxed_point)); + } +} diff --git a/misc/examples/smartpointers/music_arc.c b/misc/examples/smartpointers/music_arc.c new file mode 100644 index 00000000..16111b0b --- /dev/null +++ b/misc/examples/smartpointers/music_arc.c @@ -0,0 +1,67 @@ +// shared_ptr-examples.cpp +// based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160 +#define i_implement +#include + +typedef struct +{ + cstr artist; + cstr title; +} Song; + +int Song_cmp(const Song* x, const Song* y) + { return cstr_cmp(&x->title, &y->title); } + +Song Song_make(const char* artist, const char* title) + { return c_LITERAL(Song){cstr_from(artist), cstr_from(title)}; } + +void Song_drop(Song* s) { + printf("drop: %s\n", cstr_str(&s->title)); + c_drop(cstr, &s->artist, &s->title); +} + +// Define the shared pointer: +#define i_type SongArc +#define i_keyclass Song +#define i_no_hash // no hash fn for Song, fallback hash pointer to Song. +#include + +// ... and a vector of them +#define i_type SongVec +#define i_keyboxed SongArc // use i_keyboxed on carc / cbox (instead of i_key) +#include + +void example3(void) +{ + SongVec vec1 = c_init(SongVec, { + Song_make("Bob Dylan", "The Times They Are A Changing"), + Song_make("Aretha Franklin", "Bridge Over Troubled Water"), + Song_make("Thalia", "Entre El Mar y Una Estrella") + }); + + SongVec vec2 = {0}; + // Share all entries in vec with vec2, except Bob Dylan. + c_foreach (s, SongVec, vec1) + if (!cstr_equals(&s.ref->get->artist, "Bob Dylan")) + SongVec_push(&vec2, SongArc_clone(*s.ref)); + + // Add a few more to vec2. We can use emplace when creating new entries + // Emplace calls SongArc_from() on the argument to create the Arc: + SongVec_emplace(&vec2, Song_make("Michael Jackson", "Billie Jean")); + SongVec_emplace(&vec2, Song_make("Rihanna", "Stay")); + + // We now have two vectors with some shared, some unique entries. + c_forlist (i, SongVec, {vec1, vec2}) { + puts("VEC:"); + c_foreach (s, SongVec, *i.ref) + printf(" %s - %s, REFS: %ld\n", cstr_str(&s.ref->get->artist), + cstr_str(&s.ref->get->title), + *s.ref->use_count); + } + c_drop(SongVec, &vec1, &vec2); +} + +int main(void) +{ + example3(); +} diff --git a/misc/examples/smartpointers/new_sptr.c b/misc/examples/smartpointers/new_sptr.c new file mode 100644 index 00000000..3c6fa16c --- /dev/null +++ b/misc/examples/smartpointers/new_sptr.c @@ -0,0 +1,75 @@ +#define i_implement +#include + +typedef struct { cstr name, last; } Person; +Person Person_make(const char* name, const char* last); +Person Person_clone(Person p); +void Person_drop(Person* p); +int Person_cmp(const Person* a, const Person* b); +uint64_t Person_hash(const Person* p); + +#define i_type PersonArc +#define i_keyclass Person // "class" assume _clone, _drop, _cmp, _hash is defined. +#include + +#define i_type IPtr +#define i_key int +#define i_keydrop(x) printf("drop: %d\n", *x) +#define i_cmp_native +#include + +#define i_type IPStack +#define i_keyboxed IPtr +#include + +#define i_type PASet +#define i_keyboxed PersonArc +#include + + +Person Person_make(const char* name, const char* last) { + Person p = {.name = cstr_from(name), .last = cstr_from(last)}; + return p; +} + +int Person_cmp(const Person* a, const Person* b) { + return cstr_cmp(&a->name, &b->name); +} + +uint64_t Person_hash(const Person* p) { + return cstr_hash(&p->name); +} + +Person Person_clone(Person p) { + p.name = cstr_clone(p.name), p.last = cstr_clone(p.last); + return p; +} + +void Person_drop(Person* p) { + printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); + c_drop(cstr, &p->name, &p->last); +} + + +int main(void) { + puts("Ex1"); + PersonArc p = PersonArc_from(Person_make("John", "Smiths")); + PersonArc q = PersonArc_clone(p); // share + PersonArc r = PersonArc_clone(p); + PersonArc s = PersonArc_from(Person_clone(*p.get)); // deep copy + printf("%s %s: refs %ld\n", cstr_str(&p.get->name), cstr_str(&p.get->last), *p.use_count); + c_drop(PersonArc, &p, &q, &r, &s); + + puts("Ex2"); + IPStack vec = {0}; + IPStack_push(&vec, IPtr_from(10)); + IPStack_push(&vec, IPtr_from(20)); + IPStack_emplace(&vec, 30); // same as IPStack_push(&vec, IPtr_from(30)); + IPStack_push(&vec, IPtr_clone(*IPStack_back(&vec))); + IPStack_push(&vec, IPtr_clone(*IPStack_front(&vec))); + + c_foreach (i, IPStack, vec) + printf(" (%d: refs %ld)", *i.ref->get, *i.ref->use_count); + puts(""); + IPStack_drop(&vec); +} diff --git a/misc/examples/smartpointers/person_arc.c b/misc/examples/smartpointers/person_arc.c new file mode 100644 index 00000000..38c883a7 --- /dev/null +++ b/misc/examples/smartpointers/person_arc.c @@ -0,0 +1,77 @@ +/* cbox: heap allocated boxed type */ +#define i_implement +#include + +typedef struct { cstr name, last; } Person; + +Person Person_make(const char* name, const char* last) { + Person p = {.name = cstr_from(name), .last = cstr_from(last)}; + return p; +} + +int Person_cmp(const Person* a, const Person* b) { + int c = cstr_cmp(&a->name, &b->name); + return c ? c : cstr_cmp(&a->last, &b->last); +} + +uint64_t Person_hash(const Person* a) { + return cstr_hash(&a->name) ^ cstr_hash(&a->last); +} + +Person Person_clone(Person p) { + p.name = cstr_clone(p.name); + p.last = cstr_clone(p.last); + return p; +} + +void Person_drop(Person* p) { + printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); + c_drop(cstr, &p->name, &p->last); +} + +#define i_type PSPtr +#define i_keyclass Person // ensure Person_drop +#define i_cmp Person_cmp // specify object cmp, instead of ptr cmp for arc. +#include + +#define i_type Persons +#define i_keyboxed PSPtr // binds PSPtr_cmp, PSPtr_drop... +#include + + +int main(void) +{ + PSPtr p = PSPtr_from(Person_make("Laura", "Palmer")); + PSPtr q = PSPtr_from(Person_clone(*p.get)); // deep copy + Persons vec = {0}; + + c_defer( + PSPtr_drop(&p), + PSPtr_drop(&q), + Persons_drop(&vec) + ){ + cstr_assign(&q.get->name, "Leland"); + + printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last)); + printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last)); + + // Use Persons_emplace to implicitly call PSPtr_make on the argument. + // No need to do: Persons_push(&vec, PSPtr_make(Person_make("Audrey", "Home"))); + Persons_emplace(&vec, Person_make("Audrey", "Home")); + Persons_emplace(&vec, Person_make("Dale", "Cooper")); + + // Clone/share p and q to the vector + c_forlist (i, PSPtr, {p, q}) + Persons_push(&vec, PSPtr_clone(*i.ref)); + + c_foreach (i, Persons, vec) + printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last)); + puts(""); + + // Look-up Audrey! + Person a = Person_make("Audrey", "Home"); + const PSPtr *v = Persons_get(&vec, a); + if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last)); + Person_drop(&a); + } +} diff --git a/misc/examples/smartpointers/rawptr_elements.c b/misc/examples/smartpointers/rawptr_elements.c new file mode 100644 index 00000000..694ce12e --- /dev/null +++ b/misc/examples/smartpointers/rawptr_elements.c @@ -0,0 +1,59 @@ +#include +#include +#define i_implement +#include + +// Create cmap of cstr => long* +#define i_type SIPtrMap +#define i_key_str +#define i_val long* +#define i_valraw long +#define i_valfrom(raw) c_new(long, raw) +#define i_valto(x) **x +#define i_valclone(x) c_new(long, *x) +#define i_valdrop(x) c_free(*x) +#include + +// Alternatively, using cbox: +#define i_type IBox +#define i_key long +#include // unique_ptr alike. + +// cmap of cstr => IBox +#define i_type SIBoxMap +#define i_key_str +#define i_valboxed IBox // i_valboxed: use properties from IBox automatically +#include + +int main(void) +{ + // These have the same behaviour, except IBox has a get member: + SIPtrMap map1 = {0}; + SIBoxMap map2 = {0}; + + printf("\nMap cstr => long*:\n"); + SIPtrMap_insert(&map1, cstr_from("Test1"), c_new(long, 1)); + SIPtrMap_insert(&map1, cstr_from("Test2"), c_new(long, 2)); + + // Emplace implicitly creates cstr from const char* and an owned long* from long! + SIPtrMap_emplace(&map1, "Test3", 3); + SIPtrMap_emplace(&map1, "Test4", 4); + + c_forpair (name, number, SIPtrMap, map1) + printf("%s: %ld\n", cstr_str(_.name), **_.number); + + puts("\nMap cstr => IBox:"); + SIBoxMap_insert(&map2, cstr_from("Test1"), IBox_make(1)); + SIBoxMap_insert(&map2, cstr_from("Test2"), IBox_make(2)); + + // Emplace implicitly creates cstr from const char* and IBox from long! + SIBoxMap_emplace(&map2, "Test3", 3); + SIBoxMap_emplace(&map2, "Test4", 4); + + c_forpair (name, number, SIBoxMap, map2) + printf("%s: %ld\n", cstr_str(_.name), *_.number->get); + puts(""); + + SIPtrMap_drop(&map1); + SIBoxMap_drop(&map2); +} diff --git a/misc/examples/sorted_map.c b/misc/examples/sorted_map.c deleted file mode 100644 index 89381554..00000000 --- a/misc/examples/sorted_map.c +++ /dev/null @@ -1,67 +0,0 @@ -// https://iq.opengenus.org/containers-cpp-stl/ - -#include -#define i_key int -#define i_val int -#include - -int main(void) -{ - - // empty map containers - csmap_int gquiz1 = {0}, gquiz2 = {0}; - c_defer( - csmap_int_drop(&gquiz1), - csmap_int_drop(&gquiz2) - ){ - // insert elements in random order - csmap_int_insert(&gquiz1, 2, 30); - csmap_int_insert(&gquiz1, 4, 20); - csmap_int_insert(&gquiz1, 7, 10); - csmap_int_insert(&gquiz1, 5, 50); - csmap_int_insert(&gquiz1, 3, 60); - csmap_int_insert(&gquiz1, 1, 40); - csmap_int_insert(&gquiz1, 6, 50); - - // printing map gquiz1 - printf("\nThe map gquiz1 is :\n\tKEY\tELEMENT\n"); - c_foreach (itr, csmap_int, gquiz1) - printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); - printf("\n"); - - // assigning the elements from gquiz1 to gquiz2 - c_foreach (i, csmap_int, gquiz1) - csmap_int_insert(&gquiz2, i.ref->first, i.ref->second); - - // print all elements of the map gquiz2 - printf("\nThe map gquiz2 is :\n\tKEY\tELEMENT\n"); - c_foreach (itr, csmap_int, gquiz2) - printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); - printf("\n"); - - // remove all elements up to element with key=3 in gquiz2 - printf("\ngquiz2 after removal of elements less than key=3 :\n"); - printf("\tKEY\tELEMENT\n"); - csmap_int_erase_range(&gquiz2, csmap_int_begin(&gquiz2), - csmap_int_find(&gquiz2, 3)); - c_foreach (itr, csmap_int, gquiz2) - printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); - printf("\n"); - - // remove all elements with key = 4 - int num = csmap_int_erase(&gquiz2, 4); - printf("\ngquiz2.erase(4) : %d removed\n", num); - printf("\tKEY\tELEMENT\n"); - c_foreach (itr, csmap_int, gquiz2) - printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); - printf("\n"); - - // lower bound and upper bound for map gquiz1 key = 5 - printf("gquiz1.lower_bound(5) : "); - printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5).ref->first); - printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5).ref->second); - printf("gquiz1.upper_bound(5) : "); - printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5+1).ref->first); - printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5+1).ref->second); - } -} diff --git a/misc/examples/sortedmaps/csmap_erase.c b/misc/examples/sortedmaps/csmap_erase.c new file mode 100644 index 00000000..8d4eeae3 --- /dev/null +++ b/misc/examples/sortedmaps/csmap_erase.c @@ -0,0 +1,82 @@ +// map_erase.c +// From C++ example: https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-16 +#define i_implement +#include +#include + +#define i_key int +#define i_val_str +#define i_type mymap +#include + +void printmap(mymap m) +{ + c_foreach (elem, mymap, m) + printf(" [%d, %s]", elem.ref->first, cstr_str(&elem.ref->second)); + printf("\nsize() == %" c_ZI "\n\n", mymap_size(&m)); +} + +int main(void) +{ + mymap m1 = {0}; + + // Fill in some data to test with, one at a time + mymap_insert(&m1, 1, cstr_lit("A")); + mymap_insert(&m1, 2, cstr_lit("B")); + mymap_insert(&m1, 3, cstr_lit("C")); + mymap_insert(&m1, 4, cstr_lit("D")); + mymap_insert(&m1, 5, cstr_lit("E")); + + puts("Starting data of map m1 is:"); + printmap(m1); + // The 1st member function removes an element at a given position + mymap_erase_at(&m1, mymap_advance(mymap_begin(&m1), 1)); + puts("After the 2nd element is deleted, the map m1 is:"); + printmap(m1); + + // Fill in some data to test with + mymap m2 = c_init(mymap, { + {10, "Bob"}, + {11, "Rob"}, + {12, "Robert"}, + {13, "Bert"}, + {14, "Bobby"}, + }); + + puts("Starting data of map m2 is:"); + printmap(m2); + mymap_iter it1 = mymap_advance(mymap_begin(&m2), 1); + mymap_iter it2 = mymap_find(&m2, mymap_back(&m2)->first); + + puts("to remove:"); + c_foreach (i, mymap, it1, it2) + printf(" [%d, %s]", i.ref->first, cstr_str(&i.ref->second)); + puts(""); + // The 2nd member function removes elements + // in the range [First, Last) + mymap_erase_range(&m2, it1, it2); + puts("After the middle elements are deleted, the map m2 is:"); + printmap(m2); + + mymap m3 = {0}; + + // Fill in some data to test with, one at a time, using emplace + mymap_emplace(&m3, 1, "red"); + mymap_emplace(&m3, 2, "yellow"); + mymap_emplace(&m3, 3, "blue"); + mymap_emplace(&m3, 4, "green"); + mymap_emplace(&m3, 5, "orange"); + mymap_emplace(&m3, 6, "purple"); + mymap_emplace(&m3, 7, "pink"); + + puts("Starting data of map m3 is:"); + printmap(m3); + // The 3rd member function removes elements with a given Key + int count = mymap_erase(&m3, 2); + // The 3rd member function also returns the number of elements removed + printf("The number of elements removed from m3 is: %d\n", count); + puts("After the element with a key of 2 is deleted, the map m3 is:"); + printmap(m3); + + c_drop(mymap, &m1, &m2, &m3); +} diff --git a/misc/examples/sortedmaps/csmap_find.c b/misc/examples/sortedmaps/csmap_find.c new file mode 100644 index 00000000..c392338d --- /dev/null +++ b/misc/examples/sortedmaps/csmap_find.c @@ -0,0 +1,73 @@ +// This implements the c++ std::map::find example at: +// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-17 +#define i_implement +#include + +#define i_key int +#define i_val_str +#define i_tag istr +#include + +#define i_key csmap_istr_raw +#define i_tag istr +#include + +void print_elem(csmap_istr_raw p) { + printf("(%d, %s) ", p.first, p.second); +} + +#define using_print_collection(CX) \ + void print_collection_##CX(const CX* t) { \ + printf("%" c_ZI " elements: ", CX##_size(t)); \ + \ + c_foreach (p, CX, *t) { \ + print_elem(CX##_value_toraw(p.ref)); \ + } \ + puts(""); \ + } + +using_print_collection(csmap_istr) +using_print_collection(cvec_istr) + +void findit(csmap_istr c, csmap_istr_key val) +{ + printf("Trying find() on value %d\n", val); + csmap_istr_iter result = csmap_istr_find(&c, val); // prefer contains() or get() + if (result.ref) { + printf("Element found: "); print_elem(csmap_istr_value_toraw(result.ref)); puts(""); + } else { + puts("Element not found."); + } +} + +int main(void) +{ + csmap_istr m1 = c_init(csmap_istr, {{40, "Zr"}, {45, "Rh"}}); + cvec_istr v = {0}; + + puts("The starting map m1 is (key, value):"); + print_collection_csmap_istr(&m1); + + typedef cvec_istr_value pair; + cvec_istr_push(&v, c_LITERAL(pair){43, "Tc"}); + cvec_istr_push(&v, c_LITERAL(pair){41, "Nb"}); + cvec_istr_push(&v, c_LITERAL(pair){46, "Pd"}); + cvec_istr_push(&v, c_LITERAL(pair){42, "Mo"}); + cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"}); + cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"}); // attempt a duplicate + + puts("Inserting the following vector data into m1:"); + print_collection_cvec_istr(&v); + + c_foreach (i, cvec_istr, cvec_istr_begin(&v), cvec_istr_end(&v)) + csmap_istr_emplace(&m1, i.ref->first, i.ref->second); + + puts("The modified map m1 is (key, value):"); + print_collection_csmap_istr(&m1); + puts(""); + findit(m1, 45); + findit(m1, 6); + + csmap_istr_drop(&m1); + cvec_istr_drop(&v); +} diff --git a/misc/examples/sortedmaps/csmap_insert.c b/misc/examples/sortedmaps/csmap_insert.c new file mode 100644 index 00000000..c9f02891 --- /dev/null +++ b/misc/examples/sortedmaps/csmap_insert.c @@ -0,0 +1,108 @@ +// This implements the std::map insert c++ example at: +// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-19 +#define i_key int +#define i_val int +#define i_tag ii // Map of int => int +#include + +#define i_implement +#include +#define i_key int +#define i_val_str +#define i_tag istr // Map of int => cstr +#include + +#define i_key csmap_ii_raw +#define i_opt c_no_cmp +#define i_tag ii +#include + +void print_ii(csmap_ii map) { + c_foreach (e, csmap_ii, map) + printf("(%d, %d) ", e.ref->first, e.ref->second); + puts(""); +} + +void print_istr(csmap_istr map) { + c_foreach (e, csmap_istr, map) + printf("(%d, %s) ", e.ref->first, cstr_str(&e.ref->second)); + puts(""); +} + +int main(void) +{ + // insert single values + csmap_ii m1 = {0}; + csmap_ii_insert(&m1, 1, 10); + csmap_ii_push(&m1, c_LITERAL(csmap_ii_value){2, 20}); + + puts("The original key and mapped values of m1 are:"); + print_ii(m1); + + // intentionally attempt a duplicate, single element + csmap_ii_result ret = csmap_ii_insert(&m1, 1, 111); + if (!ret.inserted) { + csmap_ii_value pr = *ret.ref; + puts("Insert failed, element with key value 1 already exists."); + printf(" The existing element is (%d, %d)\n", pr.first, pr.second); + } + else { + puts("The modified key and mapped values of m1 are:"); + print_ii(m1); + } + puts(""); + + csmap_ii_insert(&m1, 3, 30); + puts("The modified key and mapped values of m1 are:"); + print_ii(m1); + puts(""); + + // The templatized version inserting a jumbled range + csmap_ii m2 = {0}; + cvec_ii v = {0}; + typedef cvec_ii_value ipair; + cvec_ii_push(&v, c_LITERAL(ipair){43, 294}); + cvec_ii_push(&v, c_LITERAL(ipair){41, 262}); + cvec_ii_push(&v, c_LITERAL(ipair){45, 330}); + cvec_ii_push(&v, c_LITERAL(ipair){42, 277}); + cvec_ii_push(&v, c_LITERAL(ipair){44, 311}); + + puts("Inserting the following vector data into m2:"); + c_foreach (e, cvec_ii, v) + printf("(%d, %d) ", e.ref->first, e.ref->second); + puts(""); + + c_foreach (e, cvec_ii, v) + csmap_ii_insert_or_assign(&m2, e.ref->first, e.ref->second); + + puts("The modified key and mapped values of m2 are:"); + c_foreach (e, csmap_ii, m2) + printf("(%d, %d) ", e.ref->first, e.ref->second); + puts("\n"); + + // The templatized versions move-constructing elements + csmap_istr m3 = {0}; + csmap_istr_value ip1 = {475, cstr_lit("blue")}, ip2 = {510, cstr_lit("green")}; + + // single element + csmap_istr_insert(&m3, ip1.first, cstr_move(&ip1.second)); + puts("After the first move insertion, m3 contains:"); + print_istr(m3); + + // single element + csmap_istr_insert(&m3, ip2.first, cstr_move(&ip2.second)); + puts("After the second move insertion, m3 contains:"); + print_istr(m3); + puts(""); + + csmap_ii m4 = {0}; + // Insert the elements from an initializer_list + m4 = c_init(csmap_ii, {{4, 44}, {2, 22}, {3, 33}, {1, 11}, {5, 55}}); + puts("After initializer_list insertion, m4 contains:"); + print_ii(m4); + puts(""); + + cvec_ii_drop(&v); + csmap_istr_drop(&m3); + c_drop(csmap_ii, &m1, &m2, &m4); +} diff --git a/misc/examples/sortedmaps/csset_erase.c b/misc/examples/sortedmaps/csset_erase.c new file mode 100644 index 00000000..9c7f5e1a --- /dev/null +++ b/misc/examples/sortedmaps/csset_erase.c @@ -0,0 +1,41 @@ +#include + +#define i_key int +#include + +int main(void) +{ + csset_int set = c_init(csset_int, {30, 20, 80, 40, 60, 90, 10, 70, 50}); + + c_foreach (k, csset_int, set) + printf(" %d", *k.ref); + puts(""); + + int val = 64; + csset_int_iter it; + printf("Show values >= %d:\n", val); + it = csset_int_lower_bound(&set, val); + + c_foreach (k, csset_int, it, csset_int_end(&set)) + printf(" %d", *k.ref); + puts(""); + + printf("Erase values >= %d:\n", val); + while (it.ref) + it = csset_int_erase_at(&set, it); + + c_foreach (k, csset_int, set) + printf(" %d", *k.ref); + puts(""); + + val = 40; + printf("Erase values < %d:\n", val); + it = csset_int_lower_bound(&set, val); + csset_int_erase_range(&set, csset_int_begin(&set), it); + + c_foreach (k, csset_int, set) + printf(" %d", *k.ref); + puts(""); + + csset_int_drop(&set); +} diff --git a/misc/examples/sortedmaps/gauss2.c b/misc/examples/sortedmaps/gauss2.c new file mode 100644 index 00000000..1ab8ade5 --- /dev/null +++ b/misc/examples/sortedmaps/gauss2.c @@ -0,0 +1,45 @@ +#include +#include + +#define i_implement +#include +#include + +// Declare int -> int sorted map. +#define i_key int +#define i_val int +#include + +int main(void) +{ + enum {N = 5000000}; + uint64_t seed = (uint64_t)time(NULL); + crand_t rng = crand_init(seed); + const double Mean = round(crand_f64(&rng)*98.0 - 49.0), StdDev = crand_f64(&rng)*10.0 + 1.0, Scale = 74.0; + + printf("Demo of gaussian / normal distribution of %d random samples\n", N); + printf("Mean %f, StdDev %f\n", Mean, StdDev); + + // Setup random engine with normal distribution. + crand_norm_t dist = crand_norm_init(Mean, StdDev); + + // Create and init histogram map with defered destruct + csmap_int hist = {0}; + cstr bar = {0}; + + c_forrange (N) { + int index = (int)round(crand_norm(&rng, &dist)); + csmap_int_insert(&hist, index, 0).ref->second += 1; + } + + // Print the gaussian bar chart + c_forpair (index, count, csmap_int, hist) { + int n = (int)round((double)*_.count * StdDev * Scale * 2.5 / (double)N); + if (n > 0) { + cstr_resize(&bar, n, '*'); + printf("%4d %s\n", *_.index, cstr_str(&bar)); + } + } + cstr_drop(&bar); + csmap_int_drop(&hist); +} diff --git a/misc/examples/sortedmaps/listmap.c b/misc/examples/sortedmaps/listmap.c new file mode 100644 index 00000000..04a605a7 --- /dev/null +++ b/misc/examples/sortedmaps/listmap.c @@ -0,0 +1,65 @@ +// This implements the multimap c++ example found at: +// https://en.cppreference.com/w/cpp/container/multimap/insert + +// Multimap entries +#define i_implement +#include +#define i_key_str +#include + +// Map of int => clist_str. +#define i_type Multimap +#define i_key int +#define i_valclass clist_str // set i_val = clist_str, bind clist_str_clone and clist_str_drop +#define i_cmp -c_default_cmp // like std::greater +#include + +void print(const char* lbl, const Multimap mmap) +{ + printf("%s ", lbl); + c_foreach (e, Multimap, mmap) { + c_foreach (s, clist_str, e.ref->second) + printf("{%d,%s} ", e.ref->first, cstr_str(s.ref)); + } + puts(""); +} + +void insert(Multimap* mmap, int key, const char* str) +{ + clist_str *list = &Multimap_insert(mmap, key, clist_str_init()).ref->second; + clist_str_emplace_back(list, str); +} + +int main(void) +{ + Multimap mmap = {0}; + + // list-initialize + typedef struct {int a; const char* b;} pair; + c_forlist (i, pair, {{2, "foo"}, {2, "bar"}, {3, "baz"}, {1, "abc"}, {5, "def"}}) + insert(&mmap, i.ref->a, i.ref->b); + print("#1", mmap); + + // insert using value_type + insert(&mmap, 5, "pqr"); + print("#2", mmap); + + // insert using make_pair + insert(&mmap, 6, "uvw"); + print("#3", mmap); + + insert(&mmap, 7, "xyz"); + print("#4", mmap); + + // insert using initialization_list + c_forlist (i, pair, {{5, "one"}, {5, "two"}}) + insert(&mmap, i.ref->a, i.ref->b); + print("#5", mmap); + + // FOLLOWING NOT IN ORIGINAL EXAMPLE: + // erase all entries with key 5 + Multimap_erase(&mmap, 5); + print("+5", mmap); + + Multimap_drop(&mmap); +} diff --git a/misc/examples/sortedmaps/mapmap.c b/misc/examples/sortedmaps/mapmap.c new file mode 100644 index 00000000..d3065659 --- /dev/null +++ b/misc/examples/sortedmaps/mapmap.c @@ -0,0 +1,64 @@ +// create a structure like: std::map>: +#define i_implement +#include + +// People: std::map +#define i_type People +#define i_key_str // name +#define i_val_str // email +#define i_keydrop(p) (printf("kdrop: %s\n", cstr_str(p)), cstr_drop(p)) // override +#include + +// Departments: std::map +#define i_type Departments +#define i_key_str // dep. name +#define i_valclass People +#include + + +void add(Departments* deps, const char* name, const char* email, const char* dep) +{ + People *people = &Departments_emplace(deps, dep, People_init()).ref->second; + People_emplace_or_assign(people, name, email); +} + +int contains(Departments* map, const char* name) +{ + int count = 0; + c_foreach (i, Departments, *map) + if (People_contains(&i.ref->second, name)) + ++count; + return count; +} + +int main(void) +{ + Departments map = {0}; + + add(&map, "Anna Kendro", "Anna@myplace.com", "Support"); + add(&map, "Terry Dane", "Terry@myplace.com", "Development"); + add(&map, "Kik Winston", "Kik@myplace.com", "Finance"); + add(&map, "Nancy Drew", "Nancy@live.com", "Development"); + add(&map, "Nick Denton", "Nick@myplace.com", "Finance"); + add(&map, "Stan Whiteword", "Stan@myplace.com", "Marketing"); + add(&map, "Serena Bath", "Serena@myplace.com", "Support"); + add(&map, "Patrick Dust", "Patrick@myplace.com", "Finance"); + add(&map, "Red Winger", "Red@gmail.com", "Marketing"); + add(&map, "Nick Denton", "Nick@yahoo.com", "Support"); + add(&map, "Colin Turth", "Colin@myplace.com", "Support"); + add(&map, "Dennis Kay", "Dennis@mail.com", "Marketing"); + add(&map, "Anne Dickens", "Anne@myplace.com", "Development"); + + c_foreach (i, Departments, map) + c_forpair (name, email, People, i.ref->second) + printf("%s: %s - %s\n", cstr_str(&i.ref->first), cstr_str(_.name), cstr_str(_.email)); + puts(""); + + printf("found Nick Denton: %d\n", contains(&map, "Nick Denton")); + printf("found Patrick Dust: %d\n", contains(&map, "Patrick Dust")); + printf("found Dennis Kay: %d\n", contains(&map, "Dennis Kay")); + printf("found Serena Bath: %d\n", contains(&map, "Serena Bath")); + puts("Done"); + + Departments_drop(&map); +} diff --git a/misc/examples/sortedmaps/multimap.c b/misc/examples/sortedmaps/multimap.c new file mode 100644 index 00000000..1068a5dc --- /dev/null +++ b/misc/examples/sortedmaps/multimap.c @@ -0,0 +1,102 @@ +#define i_implement +#include + +// Olympics multimap example + +struct OlympicsData { int year; const char *city, *country, *date; } ol_data[] = { + {2026, "Milan and Cortina d'Ampezzo", "Italy", "February 6-22"}, + {2022, "Beijing", "China", "February 4-20"}, + {2018, "PyeongChang", "South Korea", "February 9-25"}, + {2014, "Sochi", "Russia", "February 7-23"}, + {2010, "Vancouver", "Canada", "February 12-28"}, + {2006, "Torino", "Italy", "February 10-26"}, + {2002, "Salt Lake City", "United States", "February 8-24"}, + {1998, "Nagano", "Japan", "February 7-22"}, + {1994, "Lillehammer", "Norway", "February 12-27"}, + {1992, "Albertville", "France", "February 8-23"}, + {1988, "Calgary", "Canada", "February 13-28"}, + {1984, "Sarajevo", "Yugoslavia", "February 8-19"}, + {1980, "Lake Placid", "United States", "February 13-24"}, + {1976, "Innsbruck", "Austria", "February 4-15"}, + {1972, "Sapporo", "Japan", "February 3-13"}, + {1968, "Grenoble", "France", "February 6-18"}, + {1964, "Innsbruck", "Austria", "January 29-February 9"}, + {1960, "Squaw Valley", "United States", "February 18-28"}, + {1956, "Cortina d'Ampezzo", "Italy", "January 26 - February 5"}, + {1952, "Oslo", "Norway", "February 14 - 25"}, + {1948, "St. Moritz", "Switzerland", "January 30 - February 8"}, + {1944, "canceled", "canceled", "canceled"}, + {1940, "canceled", "canceled", "canceled"}, + {1936, "Garmisch-Partenkirchen", "Germany", "February 6 - 16"}, + {1932, "Lake Placid", "United States", "February 4 - 15"}, + {1928, "St. Moritz", "Switzerland", "February 11 - 19"}, + {1924, "Chamonix", "France", "January 25 - February 5"}, +}; + +typedef struct { int year; cstr city, date; } OlympicLoc; + +int OlympicLoc_cmp(const OlympicLoc* a, const OlympicLoc* b); +OlympicLoc OlympicLoc_clone(OlympicLoc loc); +void OlympicLoc_drop(OlympicLoc* self); + +// Create a clist, can be sorted by year. +#define i_keyclass OlympicLoc // binds _cmp, _clone and _drop. +#define i_tag OL +#include + +// Create a csmap where key is country name +#define i_key_str // binds cstr_equ, cstr_hash, cstr_clone, ++ +#define i_valclass clist_OL // binds clist_OL_clone, clist_OL_drop +#define i_tag OL +#include + +int OlympicLoc_cmp(const OlympicLoc* a, const OlympicLoc* b) { + return a->year - b->year; +} + +OlympicLoc OlympicLoc_clone(OlympicLoc loc) { + loc.city = cstr_clone(loc.city); + loc.date = cstr_clone(loc.date); + return loc; +} + +void OlympicLoc_drop(OlympicLoc* self) { + cstr_drop(&self->city); + cstr_drop(&self->date); +} + + +int main(void) +{ + // Define the multimap with destructor defered to when block is completed. + csmap_OL multimap = {0}; + const clist_OL empty = clist_OL_init(); + + for (size_t i = 0; i < c_arraylen(ol_data); ++i) + { + struct OlympicsData* d = &ol_data[i]; + OlympicLoc loc = {.year = d->year, + .city = cstr_from(d->city), + .date = cstr_from(d->date)}; + // Insert an empty list for each new country, and append the entry to the list. + // If country already exist in map, its list is returned from the insert function. + clist_OL* list = &csmap_OL_emplace(&multimap, d->country, empty).ref->second; + clist_OL_push_back(list, loc); + } + + // Sort locations by year for each country. + c_foreach (country, csmap_OL, multimap) + clist_OL_sort(&country.ref->second); + + // Print the multimap: + c_foreach (country, csmap_OL, multimap) + { + // Loop the locations for a country sorted by year + c_foreach (loc, clist_OL, country.ref->second) + printf("%s: %d, %s, %s\n", cstr_str(&country.ref->first), + loc.ref->year, + cstr_str(&loc.ref->city), + cstr_str(&loc.ref->date)); + } + csmap_OL_drop(&multimap); +} diff --git a/misc/examples/sortedmaps/new_smap.c b/misc/examples/sortedmaps/new_smap.c new file mode 100644 index 00000000..ee946c9a --- /dev/null +++ b/misc/examples/sortedmaps/new_smap.c @@ -0,0 +1,67 @@ +#define i_implement +#include +#include + +forward_csmap(PMap, struct Point, int); + +// Use forward declared PMap in struct +typedef struct { + PMap pntmap; + cstr name; +} MyStruct; + +// Point => int map +typedef struct Point { int x, y; } Point; +int point_cmp(const Point* a, const Point* b) { + int c = a->x - b->x; + return c ? c : a->y - b->y; +} + +#define i_type PMap +#define i_key Point +#define i_val int +#define i_cmp point_cmp +#define i_is_forward +#include + +// cstr => cstr map +#define i_type SMap +#define i_key_str +#define i_val_str +#include + +// cstr set +#define i_type SSet +#define i_key_str +#include + + +int main(void) +{ + PMap pmap = c_init(PMap, { + {{42, 14}, 1}, + {{32, 94}, 2}, + {{62, 81}, 3}, + }); + SMap smap = c_init(SMap, { + {"Hello, friend", "this is the mapped value"}, + {"The brown fox", "jumped"}, + {"This is the time", "for all good things"}, + }); + SSet sset = {0}; + + c_forpair (p, i, PMap, pmap) + printf(" (%d,%d: %d)", _.p->x, _.p->y, *_.i); + puts(""); + + c_forpair (i, j, SMap, smap) + printf(" (%s: %s)\n", cstr_str(_.i), cstr_str(_.j)); + + SSet_emplace(&sset, "Hello, friend"); + SSet_emplace(&sset, "Goodbye, foe"); + printf("Found? %s\n", SSet_contains(&sset, "Hello, friend") ? "true" : "false"); + + PMap_drop(&pmap); + SMap_drop(&smap); + SSet_drop(&sset); +} diff --git a/misc/examples/sortedmaps/sorted_map.c b/misc/examples/sortedmaps/sorted_map.c new file mode 100644 index 00000000..89381554 --- /dev/null +++ b/misc/examples/sortedmaps/sorted_map.c @@ -0,0 +1,67 @@ +// https://iq.opengenus.org/containers-cpp-stl/ + +#include +#define i_key int +#define i_val int +#include + +int main(void) +{ + + // empty map containers + csmap_int gquiz1 = {0}, gquiz2 = {0}; + c_defer( + csmap_int_drop(&gquiz1), + csmap_int_drop(&gquiz2) + ){ + // insert elements in random order + csmap_int_insert(&gquiz1, 2, 30); + csmap_int_insert(&gquiz1, 4, 20); + csmap_int_insert(&gquiz1, 7, 10); + csmap_int_insert(&gquiz1, 5, 50); + csmap_int_insert(&gquiz1, 3, 60); + csmap_int_insert(&gquiz1, 1, 40); + csmap_int_insert(&gquiz1, 6, 50); + + // printing map gquiz1 + printf("\nThe map gquiz1 is :\n\tKEY\tELEMENT\n"); + c_foreach (itr, csmap_int, gquiz1) + printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); + printf("\n"); + + // assigning the elements from gquiz1 to gquiz2 + c_foreach (i, csmap_int, gquiz1) + csmap_int_insert(&gquiz2, i.ref->first, i.ref->second); + + // print all elements of the map gquiz2 + printf("\nThe map gquiz2 is :\n\tKEY\tELEMENT\n"); + c_foreach (itr, csmap_int, gquiz2) + printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); + printf("\n"); + + // remove all elements up to element with key=3 in gquiz2 + printf("\ngquiz2 after removal of elements less than key=3 :\n"); + printf("\tKEY\tELEMENT\n"); + csmap_int_erase_range(&gquiz2, csmap_int_begin(&gquiz2), + csmap_int_find(&gquiz2, 3)); + c_foreach (itr, csmap_int, gquiz2) + printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); + printf("\n"); + + // remove all elements with key = 4 + int num = csmap_int_erase(&gquiz2, 4); + printf("\ngquiz2.erase(4) : %d removed\n", num); + printf("\tKEY\tELEMENT\n"); + c_foreach (itr, csmap_int, gquiz2) + printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); + printf("\n"); + + // lower bound and upper bound for map gquiz1 key = 5 + printf("gquiz1.lower_bound(5) : "); + printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5).ref->first); + printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5).ref->second); + printf("gquiz1.upper_bound(5) : "); + printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5+1).ref->first); + printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5+1).ref->second); + } +} diff --git a/misc/examples/spans/multidim.c b/misc/examples/spans/multidim.c new file mode 100644 index 00000000..798a1126 --- /dev/null +++ b/misc/examples/spans/multidim.c @@ -0,0 +1,67 @@ +// Example based on https://en.cppreference.com/w/cpp/container/mdspan +#define i_val int +#include +#include +#include + +using_cspan3(ispan, int); + +int main(void) +{ + cstack_int v = c_init(cstack_int, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}); + + // View data as contiguous memory representing 24 ints + ispan ms1 = cspan_from(&v); + + // View the same data as a 3D array 2 x 3 x 4 + ispan3 ms3 = cspan_md(v.data, 2, 3, 4); + + puts("ms3:"); + for (int i=0; i != ms3.shape[0]; i++) { + for (int j=0; j != ms3.shape[1]; j++) { + for (int k=0; k != ms3.shape[2]; k++) { + printf(" %2d", *cspan_at(&ms3, i, j, k)); + } + puts(""); + } + puts(""); + } + puts("ss3 = ms3[:, 1:3, 1:3]"); + ispan3 ss3 = ms3; + ss3 = cspan_slice(ispan3, &ms3, {c_ALL}, {1,3}, {1,3}); + + for (int i=0; i != ss3.shape[0]; i++) { + for (int j=0; j != ss3.shape[1]; j++) { + for (int k=0; k != ss3.shape[2]; k++) { + printf(" %2d", *cspan_at(&ss3, i, j, k)); + } + puts(""); + } + puts(""); + } + + puts("Iterate ss3 flat:"); + c_foreach (i, ispan3, ss3) + printf(" %d", *i.ref); + puts(""); + + ispan2 ms2 = cspan_submd3(&ms3, 0); + + // write data using 2D view + for (int i=0; i != ms2.shape[0]; i++) + for (int j=0; j != ms2.shape[1]; j++) + *cspan_at(&ms2, i, j) = i*1000 + j; + + puts("\nview data as 1D view:"); + for (int i=0; i != cspan_size(&ms1); i++) + printf(" %d", *cspan_at(&ms1, i)); + puts(""); + + puts("iterate subspan ms3[1]:"); + ispan2 sub = cspan_submd3(&ms3, 1); + c_foreach (i, ispan2, sub) + printf(" %d", *i.ref); + puts(""); + + cstack_int_drop(&v); +} diff --git a/misc/examples/spans/printspan.c b/misc/examples/spans/printspan.c new file mode 100644 index 00000000..cd3c5f4f --- /dev/null +++ b/misc/examples/spans/printspan.c @@ -0,0 +1,52 @@ +// printspan.c + +#include +#define i_implement +#include +#define i_key int +#include +#define i_key int +#include +#define i_key_str +#include + +#include +using_cspan(intspan, int, 1); + +void printMe(intspan container) { + printf("%d:", (int)cspan_size(&container)); + c_foreach (e, intspan, container) + printf(" %d", *e.ref); + puts(""); +} + +int main(void) +{ + intspan sp1 = cspan_init(intspan, {1, 2}); + printMe( sp1 ); + + printMe( c_init(intspan, {1, 2, 3}) ); + + int arr[] = {1, 2, 3, 4, 5, 6}; + intspan sp2 = cspan_from_array(arr); + printMe( c_LITERAL(intspan)cspan_subspan(&sp2, 1, 4) ); + + cvec_int vec = c_init(cvec_int, {1, 2, 3, 4, 5}); + printMe( c_LITERAL(intspan)cspan_from(&vec) ); + + printMe( sp2 ); + + cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7}); + printMe( c_LITERAL(intspan)cspan_from(&stk) ); + + csset_str set = c_init(csset_str, {"5", "7", "4", "3", "8", "2", "1", "9", "6"}); + printf("%d:", (int)csset_str_size(&set)); + c_foreach (e, csset_str, set) + printf(" %s", cstr_str(e.ref)); + puts(""); + + // cleanup + cvec_int_drop(&vec); + cstack_int_drop(&stk); + csset_str_drop(&set); +} diff --git a/misc/examples/splitstr.c b/misc/examples/splitstr.c deleted file mode 100644 index ef7ed174..00000000 --- a/misc/examples/splitstr.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#define i_import // cstr + utf8 functions -#include -#define i_implement -#include - -int main(void) -{ - puts("Split with c_fortoken (csview):"); - - c_fortoken (i, "Hello World C99!", " ") - printf("'%.*s'\n", c_SV(i.token)); - - puts("\nSplit with c_formatch (regex):"); - - cregex re = cregex_from("[^ ]+"); - c_formatch (i, &re, " Hello World C99! ") - printf("'%.*s'\n", c_SV(i.match[0])); - - cregex_drop(&re); -} diff --git a/misc/examples/sso_map.c b/misc/examples/sso_map.c deleted file mode 100644 index 4f84b651..00000000 --- a/misc/examples/sso_map.c +++ /dev/null @@ -1,19 +0,0 @@ -#define i_implement -#include -#define i_key_str -#define i_val_str -#include - -int main(void) -{ - cmap_str m = {0}; - cmap_str_emplace(&m, "Test short", "This is a short string"); - cmap_str_emplace(&m, "Test long ", "This is a longer string"); - - c_forpair (k, v, cmap_str, m) - printf("%s: '%s' Len=%" c_ZI ", Is long: %s\n", - cstr_str(_.k), cstr_str(_.v), cstr_size(_.v), - cstr_is_long(_.v) ? "true" : "false"); - - cmap_str_drop(&m); -} diff --git a/misc/examples/sso_substr.c b/misc/examples/sso_substr.c deleted file mode 100644 index 687658df..00000000 --- a/misc/examples/sso_substr.c +++ /dev/null @@ -1,21 +0,0 @@ -#define i_implement -#include -#define i_implement -#include - -int main(void) -{ - cstr str = cstr_lit("We think in generalities, but we live in details."); - csview sv1 = cstr_substr_ex(&str, 3, 5); // "think" - intptr_t pos = cstr_find(&str, "live"); // position of "live" - csview sv2 = cstr_substr_ex(&str, pos, 4); // "live" - csview sv3 = cstr_slice_ex(&str, -8, -1); // "details" - printf("%.*s, %.*s, %.*s\n", c_SV(sv1), c_SV(sv2), c_SV(sv3)); - - cstr_assign(&str, "apples are green or red"); - cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red" - cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples" - printf("%s %s: %d, %d\n", cstr_str(&s2), cstr_str(&s3), - cstr_is_long(&str), cstr_is_long(&s2)); - c_drop (cstr, &str, &s2, &s3); -} diff --git a/misc/examples/stack.c b/misc/examples/stack.c deleted file mode 100644 index 6297fb6f..00000000 --- a/misc/examples/stack.c +++ /dev/null @@ -1,32 +0,0 @@ - -#include - -#define i_tag i -#define i_capacity 100 -#define i_key int -#include - -#define i_tag c -#define i_key char -#include - -int main(void) { - cstack_i stack = {0}; - cstack_c chars = {0}; - - c_forrange (i, 101) - cstack_i_push(&stack, (int)(i*i)); - - printf("%d\n", *cstack_i_top(&stack)); - - c_forrange (i, 90) - cstack_i_pop(&stack); - - c_foreach (i, cstack_i, stack) - printf(" %d", *i.ref); - puts(""); - printf("top: %d\n", *cstack_i_top(&stack)); - - cstack_i_drop(&stack); - cstack_c_drop(&chars); -} diff --git a/misc/examples/strings/cstr_match.c b/misc/examples/strings/cstr_match.c new file mode 100644 index 00000000..be03e981 --- /dev/null +++ b/misc/examples/strings/cstr_match.c @@ -0,0 +1,26 @@ +#define i_implement +#include +#include +#include + +int main(void) +{ + cstr ss = cstr_lit("The quick brown fox jumps over the lazy dog.JPG"); + + intptr_t pos = cstr_find_at(&ss, 0, "brown"); + printf("%" c_ZI " [%s]\n", pos, pos == c_NPOS ? "" : cstr_str(&ss) + pos); + printf("equals: %d\n", cstr_equals(&ss, "The quick brown fox jumps over the lazy dog.JPG")); + printf("contains: %d\n", cstr_contains(&ss, "umps ove")); + printf("starts_with: %d\n", cstr_starts_with(&ss, "The quick brown")); + printf("ends_with: %d\n", cstr_ends_with(&ss, ".jpg")); + printf("ends_with: %d\n", cstr_ends_with(&ss, ".JPG")); + + cstr s1 = cstr_lit("hell😀 w😀rl🐨"); + csview ch1 = cstr_u8_chr(&s1, 7); + csview ch2 = cstr_u8_chr(&s1, 10); + printf("%s\nsize: %" c_ZI ", %" c_ZI "\n", cstr_str(&s1), cstr_u8_size(&s1), cstr_size(&s1)); + printf("ch1: %.*s\n", c_SV(ch1)); + printf("ch2: %.*s\n", c_SV(ch2)); + + c_drop(cstr, &ss, &s1); +} diff --git a/misc/examples/strings/replace.c b/misc/examples/strings/replace.c new file mode 100644 index 00000000..59a56bf7 --- /dev/null +++ b/misc/examples/strings/replace.c @@ -0,0 +1,36 @@ +#define i_implement +#include + +int main(void) +{ + const char *base = "this is a test string."; + const char *s2 = "n example"; + const char *s3 = "sample phrase"; + + // replace signatures used in the same order as described above: + + // Ustring positions: 0123456789*123456789*12345 + cstr s = cstr_from(base); // "this is a test string." + cstr m = cstr_clone(s); + + cstr_append(&m, cstr_str(&m)); + cstr_append(&m, cstr_str(&m)); + printf("%s\n", cstr_str(&m)); + + cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) + printf("(1) %s\n", cstr_str(&s)); + + cstr_replace_at_sv(&s, 19, 6, c_sv(s3+7, 6)); // "this is an example phrase." (2) + printf("(2) %s\n", cstr_str(&s)); + + cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3) + printf("(3) %s\n", cstr_str(&s)); + + cstr_replace_at_sv(&s, 8, 6, c_sv("a shorty", 7)); // "this is a short phrase." (4) + printf("(4) %s\n", cstr_str(&s)); + + cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) + printf("(5) %s\n", cstr_str(&s)); + + c_drop(cstr, &s, &m); +} diff --git a/misc/examples/strings/splitstr.c b/misc/examples/strings/splitstr.c new file mode 100644 index 00000000..ef7ed174 --- /dev/null +++ b/misc/examples/strings/splitstr.c @@ -0,0 +1,21 @@ +#include +#define i_import // cstr + utf8 functions +#include +#define i_implement +#include + +int main(void) +{ + puts("Split with c_fortoken (csview):"); + + c_fortoken (i, "Hello World C99!", " ") + printf("'%.*s'\n", c_SV(i.token)); + + puts("\nSplit with c_formatch (regex):"); + + cregex re = cregex_from("[^ ]+"); + c_formatch (i, &re, " Hello World C99! ") + printf("'%.*s'\n", c_SV(i.match[0])); + + cregex_drop(&re); +} diff --git a/misc/examples/strings/sso_map.c b/misc/examples/strings/sso_map.c new file mode 100644 index 00000000..4f84b651 --- /dev/null +++ b/misc/examples/strings/sso_map.c @@ -0,0 +1,19 @@ +#define i_implement +#include +#define i_key_str +#define i_val_str +#include + +int main(void) +{ + cmap_str m = {0}; + cmap_str_emplace(&m, "Test short", "This is a short string"); + cmap_str_emplace(&m, "Test long ", "This is a longer string"); + + c_forpair (k, v, cmap_str, m) + printf("%s: '%s' Len=%" c_ZI ", Is long: %s\n", + cstr_str(_.k), cstr_str(_.v), cstr_size(_.v), + cstr_is_long(_.v) ? "true" : "false"); + + cmap_str_drop(&m); +} diff --git a/misc/examples/strings/sso_substr.c b/misc/examples/strings/sso_substr.c new file mode 100644 index 00000000..687658df --- /dev/null +++ b/misc/examples/strings/sso_substr.c @@ -0,0 +1,21 @@ +#define i_implement +#include +#define i_implement +#include + +int main(void) +{ + cstr str = cstr_lit("We think in generalities, but we live in details."); + csview sv1 = cstr_substr_ex(&str, 3, 5); // "think" + intptr_t pos = cstr_find(&str, "live"); // position of "live" + csview sv2 = cstr_substr_ex(&str, pos, 4); // "live" + csview sv3 = cstr_slice_ex(&str, -8, -1); // "details" + printf("%.*s, %.*s, %.*s\n", c_SV(sv1), c_SV(sv2), c_SV(sv3)); + + cstr_assign(&str, "apples are green or red"); + cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red" + cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples" + printf("%s %s: %d, %d\n", cstr_str(&s2), cstr_str(&s3), + cstr_is_long(&str), cstr_is_long(&s2)); + c_drop (cstr, &str, &s2, &s3); +} diff --git a/misc/examples/strings/sview_split.c b/misc/examples/strings/sview_split.c new file mode 100644 index 00000000..ac275da0 --- /dev/null +++ b/misc/examples/strings/sview_split.c @@ -0,0 +1,20 @@ +#define i_implement +#include +#define i_implement +#include + +int main(void) +{ + // No memory allocations or string length calculations! + const csview date = c_sv("2021/03/12"); + intptr_t pos = 0; + const csview year = csview_token(date, "/", &pos); + const csview month = csview_token(date, "/", &pos); + const csview day = csview_token(date, "/", &pos); + + printf("%.*s, %.*s, %.*s\n", c_SV(year), c_SV(month), c_SV(day)); + + cstr y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day); + printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d)); + c_drop(cstr, &y, &m, &d); +} diff --git a/misc/examples/strings/utf8replace_c.c b/misc/examples/strings/utf8replace_c.c new file mode 100644 index 00000000..1d54486f --- /dev/null +++ b/misc/examples/strings/utf8replace_c.c @@ -0,0 +1,25 @@ +#define i_implement +#include + +int main(void) +{ + cstr hello = cstr_lit("hell😀 w😀rld"); + printf("%s\n", cstr_str(&hello)); + + /* replace second smiley at utf8 codepoint pos 7 */ + cstr_u8_replace_at(&hello, + cstr_u8_to_pos(&hello, 7), + 1, + c_sv("🐨") + ); + printf("%s\n", cstr_str(&hello)); + + c_foreach (c, cstr, hello) + printf("%.*s,", c_SV(c.u8.chr)); + + cstr str = cstr_lit("scooby, dooby doo"); + cstr_replace(&str, "oo", "00"); + printf("\n%s\n", cstr_str(&str)); + + c_drop(cstr, &hello, &str); +} diff --git a/misc/examples/strings/utf8replace_rs.rs b/misc/examples/strings/utf8replace_rs.rs new file mode 100644 index 00000000..8b163b4e --- /dev/null +++ b/misc/examples/strings/utf8replace_rs.rs @@ -0,0 +1,22 @@ +pub fn main() { + let mut hello = String::from("hell😀 w😀rld"); + println!("{}", hello); + + /* replace second smiley at utf8 codepoint pos 7 */ + hello.replace_range( + hello + .char_indices() + .nth(7) + .map(|(pos, ch)| (pos..pos + ch.len_utf8())) + .unwrap(), + "🐨", + ); + println!("{}", hello); + + for c in hello.chars() { + print!("{},", c); + } + + let str = "If you find the time, you will find the winner"; + println!("\n{}", str.replace("find", "match")); +} diff --git a/misc/examples/sview_split.c b/misc/examples/sview_split.c deleted file mode 100644 index ac275da0..00000000 --- a/misc/examples/sview_split.c +++ /dev/null @@ -1,20 +0,0 @@ -#define i_implement -#include -#define i_implement -#include - -int main(void) -{ - // No memory allocations or string length calculations! - const csview date = c_sv("2021/03/12"); - intptr_t pos = 0; - const csview year = csview_token(date, "/", &pos); - const csview month = csview_token(date, "/", &pos); - const csview day = csview_token(date, "/", &pos); - - printf("%.*s, %.*s, %.*s\n", c_SV(year), c_SV(month), c_SV(day)); - - cstr y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day); - printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d)); - c_drop(cstr, &y, &m, &d); -} diff --git a/misc/examples/triples.c b/misc/examples/triples.c deleted file mode 100644 index 9f2fcc1e..00000000 --- a/misc/examples/triples.c +++ /dev/null @@ -1,72 +0,0 @@ -// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/ - -#include -#include - -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, 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 && gcd(a, b) == 1) { - printf("%d: {%d, %d, %d}\n", ++i, a, b, c); - if (--n == 0) goto done; - } - } - } - } - done:; -} - -struct triples { - int size, count; - int a, b, c; - int cco_state; -}; - -int triples_coro(struct triples* t) { - cco_routine(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(); - } - } - } - } - cco_cleanup: - puts("done"); - } - return 0; -} - -int main(void) -{ - puts("Vanilla triples:"); - triples_vanilla(5); - - puts("\nCoroutine triples:"); - struct triples t = {.size=INT32_MAX}; - int n = 0; - - while (triples_coro(&t)) { - if (gcd(t.a, t.b) > 1) - continue; - if (t.c < 100) - printf("%d: {%d, %d, %d}\n", ++n, t.a, t.b, t.c); - else - cco_stop(&t); - } -} diff --git a/misc/examples/unordered_set.c b/misc/examples/unordered_set.c deleted file mode 100644 index dd899d78..00000000 --- a/misc/examples/unordered_set.c +++ /dev/null @@ -1,45 +0,0 @@ -// https://iq.opengenus.org/containers-cpp-stl/ -// C program to demonstrate various function of stc cset -#define i_implement -#include -#define i_key_str -#include - -int main(void) -{ - // declaring set for storing string data-type - cset_str stringSet = {0}; - c_defer( - cset_str_drop(&stringSet) - ){ - // inserting various string, same string will be stored - // once in set - cset_str_emplace(&stringSet, "code"); - cset_str_emplace(&stringSet, "in"); - cset_str_emplace(&stringSet, "C"); - cset_str_emplace(&stringSet, "is"); - cset_str_emplace(&stringSet, "fast"); - - const char* key = "slow"; - - // find returns end iterator if key is not found, - // else it returns iterator to that key - - if (cset_str_find(&stringSet, key).ref == NULL) - printf("\"%s\" not found\n", key); - else - printf("Found \"%s\"\n", key); - - key = "C"; - if (!cset_str_contains(&stringSet, key)) - printf("\"%s\" not found\n", key); - else - printf("Found \"%s\"\n", key); - - // now iterating over whole set and printing its - // content - printf("All elements :\n"); - c_foreach (itr, cset_str, stringSet) - printf("%s\n", cstr_str(itr.ref)); - } -} diff --git a/misc/examples/utf8replace_c.c b/misc/examples/utf8replace_c.c deleted file mode 100644 index 1d54486f..00000000 --- a/misc/examples/utf8replace_c.c +++ /dev/null @@ -1,25 +0,0 @@ -#define i_implement -#include - -int main(void) -{ - cstr hello = cstr_lit("hell😀 w😀rld"); - printf("%s\n", cstr_str(&hello)); - - /* replace second smiley at utf8 codepoint pos 7 */ - cstr_u8_replace_at(&hello, - cstr_u8_to_pos(&hello, 7), - 1, - c_sv("🐨") - ); - printf("%s\n", cstr_str(&hello)); - - c_foreach (c, cstr, hello) - printf("%.*s,", c_SV(c.u8.chr)); - - cstr str = cstr_lit("scooby, dooby doo"); - cstr_replace(&str, "oo", "00"); - printf("\n%s\n", cstr_str(&str)); - - c_drop(cstr, &hello, &str); -} diff --git a/misc/examples/utf8replace_rs.rs b/misc/examples/utf8replace_rs.rs deleted file mode 100644 index 8b163b4e..00000000 --- a/misc/examples/utf8replace_rs.rs +++ /dev/null @@ -1,22 +0,0 @@ -pub fn main() { - let mut hello = String::from("hell😀 w😀rld"); - println!("{}", hello); - - /* replace second smiley at utf8 codepoint pos 7 */ - hello.replace_range( - hello - .char_indices() - .nth(7) - .map(|(pos, ch)| (pos..pos + ch.len_utf8())) - .unwrap(), - "🐨", - ); - println!("{}", hello); - - for c in hello.chars() { - print!("{},", c); - } - - let str = "If you find the time, you will find the winner"; - println!("\n{}", str.replace("find", "match")); -} diff --git a/misc/examples/vectors/lower_bound.c b/misc/examples/vectors/lower_bound.c new file mode 100644 index 00000000..bea828f2 --- /dev/null +++ b/misc/examples/vectors/lower_bound.c @@ -0,0 +1,66 @@ +#include + +#define i_key int +#define i_cmp_native +#include + +#define i_key int +#include + +int main(void) +{ + // TEST SORTED VECTOR + { + int key, *res; + cvec_int vec = c_init(cvec_int, {40, 600, 1, 7000, 2, 500, 30}); + + cvec_int_sort(&vec); + + key = 100; + res = cvec_int_lower_bound(&vec, key).ref; + if (res) + printf("Sorted Vec %d: lower bound: %d\n", key, *res); // 500 + + key = 10; + cvec_int_iter it1 = cvec_int_lower_bound(&vec, key); + if (it1.ref) + printf("Sorted Vec %3d: lower_bound: %d\n", key, *it1.ref); // 30 + + key = 600; + cvec_int_iter it2 = cvec_int_binary_search(&vec, key); + if (it2.ref) + printf("Sorted Vec %d: bin. search: %d\n", key, *it2.ref); // 600 + + c_foreach (i, cvec_int, it1, it2) + printf(" %d\n", *i.ref); + + puts(""); + cvec_int_drop(&vec); + } + + // TEST SORTED SET + { + int key, *res; + csset_int set = c_init(csset_int, {40, 600, 1, 7000, 2, 500, 30}); + + key = 100; + res = csset_int_lower_bound(&set, key).ref; + if (res) + printf("Sorted Set %d: lower bound: %d\n", key, *res); // 500 + + key = 10; + csset_int_iter it1 = csset_int_lower_bound(&set, key); + if (it1.ref) + printf("Sorted Set %3d: lower bound: %d\n", key, *it1.ref); // 30 + + key = 600; + csset_int_iter it2 = csset_int_find(&set, key); + if (it2.ref) + printf("Sorted Set %d: find : %d\n", key, *it2.ref); // 600 + + c_foreach (i, csset_int, it1, it2) + printf(" %d\n", *i.ref); + + csset_int_drop(&set); + } +} diff --git a/misc/examples/vectors/new_vec.c b/misc/examples/vectors/new_vec.c new file mode 100644 index 00000000..88efd55a --- /dev/null +++ b/misc/examples/vectors/new_vec.c @@ -0,0 +1,43 @@ +#include +#include + +forward_cvec(cvec_i32, int); +forward_cvec(cvec_pnt, struct Point); + +typedef struct MyStruct { + cvec_i32 intvec; + cvec_pnt pntvec; +} MyStruct; + +#define i_key int +#define i_tag i32 +#define i_is_forward +#include + +typedef struct Point { int x, y; } Point; + +#define i_key Point +#define i_tag pnt +#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) +#define i_eq(a, b) a->x == b->x && a->y == b->y +#define i_is_forward +#include + +int main(void) +{ + MyStruct my = {0}; + + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){42, 14}); + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 94}); + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){62, 81}); + cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 91}); + + cvec_pnt_sort(&my.pntvec); + + c_foreach (i, cvec_pnt, my.pntvec) + printf(" (%d %d)", i.ref->x, i.ref->y); + puts(""); + + cvec_i32_drop(&my.intvec); + cvec_pnt_drop(&my.pntvec); +} diff --git a/misc/examples/vectors/stack.c b/misc/examples/vectors/stack.c new file mode 100644 index 00000000..6297fb6f --- /dev/null +++ b/misc/examples/vectors/stack.c @@ -0,0 +1,32 @@ + +#include + +#define i_tag i +#define i_capacity 100 +#define i_key int +#include + +#define i_tag c +#define i_key char +#include + +int main(void) { + cstack_i stack = {0}; + cstack_c chars = {0}; + + c_forrange (i, 101) + cstack_i_push(&stack, (int)(i*i)); + + printf("%d\n", *cstack_i_top(&stack)); + + c_forrange (i, 90) + cstack_i_pop(&stack); + + c_foreach (i, cstack_i, stack) + printf(" %d", *i.ref); + puts(""); + printf("top: %d\n", *cstack_i_top(&stack)); + + cstack_i_drop(&stack); + cstack_c_drop(&chars); +} diff --git a/misc/examples/vikings.c b/misc/examples/vikings.c deleted file mode 100644 index d6125854..00000000 --- a/misc/examples/vikings.c +++ /dev/null @@ -1,59 +0,0 @@ -#define i_implement -#include - -typedef struct Viking { - cstr name; - cstr country; -} Viking; - -void Viking_drop(Viking* vk) { - cstr_drop(&vk->name); - cstr_drop(&vk->country); -} - -// Define Viking lookup struct with hash, cmp, and convertion functions between Viking and RViking structs: - -typedef struct RViking { - const char* name; - const char* country; -} RViking; - -static inline int RViking_cmp(const RViking* rx, const RViking* ry) { - int c = strcmp(rx->name, ry->name); - return c ? c : strcmp(rx->country, ry->country); -} - -static inline Viking Viking_from(RViking raw) { // note: parameter is by value - return c_LITERAL(Viking){cstr_from(raw.name), cstr_from(raw.country)}; -} - -static inline RViking Viking_toraw(const Viking* vp) { - return c_LITERAL(RViking){cstr_str(&vp->name), cstr_str(&vp->country)}; -} - -// With this in place, we define the Viking => int hash map type: -#define i_type Vikings -#define i_keyclass Viking // key type -#define i_rawclass RViking // lookup type -#define i_keyfrom Viking_from -#define i_opt c_no_clone -#define i_hash(rp) cstrhash(rp->name) ^ cstrhash(rp->country) -#define i_val int // mapped type -#include - -int main(void) -{ - Vikings vikings = {0}; - Vikings_emplace(&vikings, c_LITERAL(RViking){"Einar", "Norway"}, 20); - Vikings_emplace(&vikings, c_LITERAL(RViking){"Olaf", "Denmark"}, 24); - Vikings_emplace(&vikings, c_LITERAL(RViking){"Harald", "Iceland"}, 12); - Vikings_emplace(&vikings, c_LITERAL(RViking){"Björn", "Sweden"}, 10); - - Vikings_value* v = Vikings_get_mut(&vikings, c_LITERAL(RViking){"Einar", "Norway"}); - v->second += 3; // add 3 hp points to Einar - - c_forpair (vk, hp, Vikings, vikings) { - printf("%s of %s has %d hp\n", cstr_str(&_.vk->name), cstr_str(&_.vk->country), *_.hp); - } - Vikings_drop(&vikings); -} -- cgit v1.2.3