diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md index 9c7a15bc..65a2b4ec 100644 --- a/docs/coroutine_api.md +++ b/docs/coroutine_api.md @@ -18,7 +18,7 @@ on the stack), which holds all variables used within their coroutine scopes. Thi that they become extremely lightweight and therefore useful on severely memory constrained systems like microcontrollers with limited resources. - In stackful mode, the coroutine frames are allocated on the heap just before they await another -coroutine. Examples below. +coroutine. See examples. ## Methods and statements @@ -204,27 +204,28 @@ int main(void) { ### Actor models of concurrency in video games and simulations A common usage of coroutines is long-running concurrent tasks, often found in video games. An example of this is the [Dining philosopher's problem](https://en.wikipedia.org/wiki/Dining_philosophers_problem). The following -implementation uses `cco_await*()` and `cco_yield`. It avoids deadlocks because it waits until both forks are -available before aquiring them. It also avoids starvation as the neighbor's hunger increases for each "round". +implementation uses `cco_await` and `cco_yield`. It avoids deadlocks by awaiting for both forks to be +available before aquiring them. It also avoids starvation by increasing both neighbor's hunger when a philosopher +starts eating (because they must be waiting).
The "Dining philosophers" C implementation -[ [Run this code](https://godbolt.org/z/WoaMv6js5) ] +[ [Run this code](https://godbolt.org/z/EK6zs6vbz) ] ```c++ #include #include #include "stc/random.h" #include "stc/coroutine.h" -// Define the number of philosophers + enum {num_philosophers = 5}; -enum {ph_thinking, ph_eating, ph_hungry}; +enum PhState {ph_thinking, ph_hungry, ph_eating}; // Philosopher coroutine struct Philosopher { int id; cco_timer tm; - int state; + enum PhState state; int hunger; struct Philosopher* left; struct Philosopher* right; @@ -272,7 +273,7 @@ int Dining(struct Dining* self) { for (int i = 0; i < num_philosophers; ++i) { cco_reset(&self->philos[i]); self->philos[i].id = i + 1; - self->philos[i].left = &self->philos[i]; + self->philos[i].left = &self->philos[(i - 1 + num_philosophers) % num_philosophers]; self->philos[i].right = &self->philos[(i + 1) % num_philosophers]; } diff --git a/docs/hset_api.md b/docs/hset_api.md index d335030e..65f25e65 100644 --- a/docs/hset_api.md +++ b/docs/hset_api.md @@ -117,17 +117,3 @@ int main(void) c_drop(Strings, &first, &second, &third, &fourth, &fifth); } ``` -Output: -``` -fifth contains: - -red -green -flour -orange -blue -pink -yellow -milk -potatoes -``` diff --git a/docs/smap_api.md b/docs/smap_api.md index 4ce40dc7..e6a44d3e 100644 --- a/docs/smap_api.md +++ b/docs/smap_api.md @@ -117,6 +117,8 @@ void smap_X_value_drop(i_key* pval); | `smap_X_iter` | `struct { smap_X_value *ref; ... }` | Iterator type | ## Examples + +[ [Run this code](https://godbolt.org/z/qs1Gsv5zh) ] ```c++ #include "stc/cstr.h" @@ -149,15 +151,6 @@ int main(void) smap_cstr_drop(&colors); } ``` -Output: -``` -Key:[BLUE] Value:[#0000FF] -Key:[GREEN] Value:[#00FF00] -Key:[RED] Value:[#FF0000] -The HEX of color RED is:[#FF0000] -The HEX of color BLACK is:[#000000] -``` - ### Example 2 Translate a @@ -196,44 +189,44 @@ int main(void) ``` ### Example 3 -This example uses a smap with cstr as mapped value. +This example uses a smap with cstr as mapped value. Note the `i_valpro` usage. + +[ [Run this code](https://godbolt.org/z/M397fG7fM) ] ```c++ #include "stc/cstr.h" -#define i_type IDSMap, int +#define i_type IdMap +#define i_key int #define i_valpro cstr #include "stc/smap.h" int main(void) { uint32_t col = 0xcc7744ff; - IDSMap idnames = c_make(IDSMap, {{100, "Red"}, {110, "Blue"}}); + IdMap idnames = c_make(IdMap, {{100, "Red"}, {110, "Blue"}}); // Assign/overwrite an existing mapped value with a const char* - IDSMap_emplace_or_assign(&idnames, 110, "White"); + IdMap_emplace_or_assign(&idnames, 110, "White"); // Insert (or assign) a new cstr - IDSMap_insert_or_assign(&idnames, 120, cstr_from_fmt("#%08x", col)); + IdMap_insert_or_assign(&idnames, 120, cstr_from_fmt("#%08x", col)); // emplace() adds only when key does not already exist: - IDSMap_emplace(&idnames, 100, "Green"); // ignored + IdMap_emplace(&idnames, 100, "Green"); // ignored - c_foreach (i, IDSMap, idnames) + c_foreach (i, IdMap, idnames) printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second)); - IDSMap_drop(&idnames); + IdMap_drop(&idnames); } ``` -Output: -```c++ -100: Red -110: White -120: #cc7744ff -``` ### Example 4 Demonstrate smap with plain-old-data key type Vec3i and int as mapped type: smap. + +[ [Run this code](https://godbolt.org/z/KE8qEYsvY) ] ```c++ +#include typedef struct { int x, y, z; } Vec3i; static int Vec3i_cmp(const Vec3i* a, const Vec3i* b) { @@ -246,7 +239,6 @@ static int Vec3i_cmp(const Vec3i* a, const Vec3i* b) { #define i_type smap_vi, Vec3i, int #define i_cmp Vec3i_cmp #include "stc/smap.h" -#include int main(void) { @@ -263,10 +255,3 @@ int main(void) smap_vi_drop(&vmap); } ``` -Output: -```c++ -{ 0, 0, 100 }: 3 -{ 0, 100, 0 }: 2 -{ 100, 0, 0 }: 1 -{ 100, 100, 100 }: 4 -``` diff --git a/examples/coroutines/dining_philosophers.c b/examples/coroutines/dining_philosophers.c index 16f64a95..7893f7ea 100644 --- a/examples/coroutines/dining_philosophers.c +++ b/examples/coroutines/dining_philosophers.c @@ -4,15 +4,14 @@ #include "stc/random.h" #include "stc/coroutine.h" -// Define the number of philosophers enum {num_philosophers = 5}; -enum {ph_thinking, ph_hungry, ph_eating}; +enum PhState {ph_thinking, ph_hungry, ph_eating}; // Philosopher coroutine struct Philosopher { int id; cco_timer tm; - int state; + enum PhState state; int hunger; struct Philosopher* left; struct Philosopher* right; @@ -60,7 +59,7 @@ int Dining(struct Dining* self) { for (int i = 0; i < num_philosophers; ++i) { cco_reset(&self->philos[i]); self->philos[i].id = i + 1; - self->philos[i].left = &self->philos[i]; + self->philos[i].left = &self->philos[(i - 1 + num_philosophers) % num_philosophers]; self->philos[i].right = &self->philos[(i + 1) % num_philosophers]; }