diff --git a/docs/algorithm_api.md b/docs/algorithm_api.md
index 8109aafe..e2bf4239 100644
--- a/docs/algorithm_api.md
+++ b/docs/algorithm_api.md
@@ -1,6 +1,8 @@
# STC Algorithms
-STC contains many generic algorithms and flow control abstactions.
+STC contains many generic algorithms and loop abstactions. Raw loops are one of the most prominent
+sources for errors in C and C++ code. By using the loop abstractions below, your code becomes more
+descriptive and reduces chances of making mistakes. It is often easier to read and write too.
## Ranged for-loops
@@ -19,7 +21,7 @@ STC contains many generic algorithms and flow control abstactions.
| `c_foreach_reverse (it, ctype, container)`| Iteratate elements in reverse: *vec, deque, queue, stack* |
| `c_foreach_reverse (it, ctype, it1, it2)`| Iteratate range [it1, it2) elements in reverse. |
| `c_foreach_n (it, ctype, container, n)`| Iteratate `n` first elements. Index variable is `{it}_index`. |
-| `c_foreach_kv (key, val, ctype, container)` | Iterate with structured binding |
+| `c_foreach_kv (key, val, ctype, container)` | Iterate maps with "structured binding" |
```c
#define i_type IMap, int, int
@@ -79,7 +81,7 @@ c_foritems (i, const char*, {"Hello", "crazy", "world"})
### c_forrange, c_forrange32, c_forrange_t
- `c_forrange`: abstraction for iterating sequence of integers. Like python's **for** *i* **in** *range()* loop. Uses `isize` (*ptrdiff_t*) as control variable.
- `c_forrange32` is like *c_forrange*, but uses `int32` as control variable.
-- `c_forrange_t` is like *c_forrange*, but takes an additional ***type*** as first argument for the control variable.
+- `c_forrange_t` is like *c_forrange*, but takes an additional ***type*** for the control variable as first argument.
| Usage | Python equivalent |
|:-------------------------------------|:-------------------------------------|
@@ -221,16 +223,21 @@ int main(void)
c_func - Function with on-the-fly defined return type
### c_func
-A convenient macro for defining functions with one or multiple return values, e.g. for errors.
+
+A macro for conveniently defining functions with multiple return values. This is for encouraging
+to write functions that returns extra error context when error occurs, or just multiple return values.
+
```c
Vec get_data(void) {
return c_init(Vec, {1, 2, 3, 4, 5, 6});
}
-// same as get_data():
+
+// same as get_data(), but with the c_func macro "syntax".
c_func (get_data1,(void), ->, Vec) {
return c_init(Vec, {1, 2, 3, 4, 5, 6});
}
+// return two Vec types "on-the-fly".
c_func (get_data2,(void), ->, struct {Vec v1, v2;}) {
return (get_data2_result){
.v1=c_init(Vec, {1, 2, 3, 4, 5, 6}),
@@ -238,21 +245,24 @@ c_func (get_data2,(void), ->, struct {Vec v1, v2;}) {
};
}
-c_func (load_data,(const char* fname), ->, struct {Vec out; int err;}) {
+// return a Vec, and an err code which is 0 if OK.
+c_func (load_data,(const char* fname), ->, struct {Vec vec; int err;}) {
FILE* fp = fopen(fname, "rb");
if (fp == 0)
return (load_data_result){.err=1};
- load_data_result vec = {Vec_with_size(1024, '\0')};
- fread(vec.out.data, sizeof(vec.out.data[0]), 1024, fp);
+ load_data_result out = {Vec_with_size(1024, '\0')};
+ fread(out.vec.data, sizeof(out.vec.data[0]), 1024, fp);
fclose(fp);
- return vec;
+ return out;
}
```
c_init, c_push, c_drop - Generic container operations
+These work on any container. *c_init()* may also be used for **cspan** views.
+
### c_init, c_push, c_drop
- **c_init** - construct any container from an initializer list
@@ -268,11 +278,11 @@ c_func (load_data,(const char* fname), ->, struct {Vec out; int err;}) {
#define i_type Map, int, int
#include "stc/hmap.h"
-c_func (split_map,(Map map), ->, struct {Vec keys, vals;}) {
+c_func (split_map,(Map map), ->, struct {Vec keys, values;}) {
split_map_result out = {0};
c_foreach_kv (k, v, Map, map) {
Vec_push(&out.keys, *k);
- Vec_push(&out.vals, *v);
+ Vec_push(&out.values, *v);
}
return out;
}
@@ -294,11 +304,11 @@ int main(void) {
split_map_result res = split_map(map);
- c_foreach (i, Vec, res.vals)
+ c_foreach (i, Vec, res.values)
printf("%d ", *i.ref);
puts("");
- c_drop(Vec, &vec, &res.keys, &res.vals);
+ c_drop(Vec, &vec, &res.keys, &res.values);
c_drop(Map, &map);
}
```
diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h
index e05dc4aa..aaa9bc10 100644
--- a/include/stc/coroutine.h
+++ b/include/stc/coroutine.h
@@ -145,29 +145,41 @@ typedef struct {
/* ============ ADVANCED, OPTIONAL ============= */
/*
- * Iterators (for generators)
- * Gen must be an existing typedef struct, i.e., these must be defined:
- * Gen_iter Gen_begin(Gen* g); // return a coroutine object, advanced to the first yield
- * int Gen_next(Gen_iter* it); // resume the coroutine
+ * Iterators for coroutine generators
+ * A type Gen must be an existing generator typedef struct. Then:
*
- * cco_default_begin(Gen); // implements basic Gen_begin() function
- * ....
+ * typedef Gen Gen_value;
+ * typedef struct {
+ * Gen* ref;
+ * cco_state cco;
+ * ...
+ * } Gen_iter;
+ *
+ * // the generator coroutine, get the next value:
+ * int Gen_next(Gen_iter* it) {
+ * Gen* g = it->ref;
+ * cco_scope (it) {
+ * ...
+ * cco_yield; // suspend exec, gen with value ready
+ * ...
+ * cco_cleanup:
+ * it->ref = NULL; // stops the iteration
+ * }
+ * }
+ *
+ * // create coroutine/iter, advance to the first yield:
+ * Gen_iter Gen_begin(Gen* g) {
+ * Gen_iter it = {.ref = g};
+ * ...
+ * Gen_next(&it);
+ * return it;
+ * }
+ *
+ * ...
* c_foreach (i, Gen, gen)
- printf("%d ", *i.ref);
+ * printf("%d ", *i.ref);
*/
-#define cco_iter_struct(Gen) \
- typedef Gen Gen##_value; \
- typedef struct Gen##_iter Gen##_iter; \
- struct Gen##_iter
-
-#define cco_default_begin(Gen) \
-Gen##_iter Gen##_begin(Gen* g) { \
- Gen##_iter it = {.ref = g}; \
- Gen##_next(&it); \
- return it; \
-} struct Gen##_iter
-
/* Using c_filter with generators:
*/
diff --git a/misc/examples/coroutines/generator.c b/misc/examples/coroutines/generator.c
index eb109f24..f2b7cb93 100644
--- a/misc/examples/coroutines/generator.c
+++ b/misc/examples/coroutines/generator.c
@@ -4,21 +4,22 @@
#include "stc/coroutine.h"
#include "stc/algorithm.h"
+// Create an iterable generator Triple with max_triples items.
+// Requires coroutine Triple_next() and function Triple_begin() to be defined.
+
typedef struct {
int max_triples;
int a, b, c;
-} Triple;
+} Triple, Triple_value;
-// Create an iterable generator on an existing Triple type with count items.
-// Requires coroutine Triple_next() and function Triple_begin() to be defined.
-cco_iter_struct (Triple) {
- Triple_value* ref; // required by iterator
+typedef struct {
+ Triple* ref; // required by iterator
+ cco_state cco; // required by coroutine
int count;
- cco_state cco; // required by coroutine
-};
+} Triple_iter;
int Triple_next(Triple_iter* it) {
- Triple* g = it->ref; // note: before cco_scope
+ Triple* g = it->ref; // get generator before cco_scope starts!
cco_scope(it)
{
for (g->c = 5;; ++g->c) {
@@ -40,14 +41,14 @@ int Triple_next(Triple_iter* it) {
}
Triple_iter Triple_begin(Triple* g) {
- Triple_iter it = {.ref=g};
+ Triple_iter it = {.ref = g};
Triple_next(&it);
return it;
}
int main(void)
{
- Triple triple = {.max_triples=INT32_MAX};
+ Triple triple = {.max_triples = INT32_MAX};
puts("Pythagorean triples.\nGet all triples with c < 40, using c_foreach:");
c_foreach (i, Triple, triple) {
@@ -61,7 +62,8 @@ int main(void)
c_filter(Triple, triple, true
&& (value->c < 40)
&& (cco_flt_take(10), // NB! use cco_flt_take(n) instead of c_flt_take(n)
- // to ensure coroutine/iter cleanup if needed
+ // to ensure coroutine/iter cleanup.
+ // Also applies to cco_flt_takewhile(pred)
printf("%d: (%d, %d, %d)\n", c_flt_getcount(), value->a, value->b, value->c))
);
}