summaryrefslogtreecommitdiffhomepage
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/carc_api.md96
-rw-r--r--docs/cbox_api.md11
-rw-r--r--docs/ccommon_api.md525
-rw-r--r--docs/clist_api.md27
-rw-r--r--docs/cmap_api.md201
-rw-r--r--docs/coption_api.md2
-rw-r--r--docs/cpque_api.md43
-rw-r--r--docs/crandom_api.md45
-rw-r--r--docs/cregex_api.md43
-rw-r--r--docs/cset_api.md58
-rw-r--r--docs/csmap_api.md169
-rw-r--r--docs/cspan_api.md19
-rw-r--r--docs/csset_api.md56
-rw-r--r--docs/cstr_api.md7
-rw-r--r--docs/csview_api.md28
-rw-r--r--docs/cvec_api.md46
-rw-r--r--docs/pics/containers.jpgbin96093 -> 138703 bytes
17 files changed, 743 insertions, 633 deletions
diff --git a/docs/carc_api.md b/docs/carc_api.md
index cc6c9c32..48b64ff0 100644
--- a/docs/carc_api.md
+++ b/docs/carc_api.md
@@ -98,56 +98,56 @@ bool carc_X_value_eq(const i_val* x, const i_val* y);
int main()
{
- c_auto (Stack, s1, s2) // RAII
- {
- // POPULATE s1 with shared pointers to Map:
- Map *map;
-
- map = Stack_push(&s1, Arc_make(Map_init()))->get; // push empty map to s1.
- c_forlist (i, Map_raw, { {"Joey", 1990}, {"Mary", 1995}, {"Joanna", 1992} }) {
- Map_emplace(map, c_PAIR(i.ref)); // populate it.
- }
-
- map = Stack_push(&s1, Arc_make(Map_init()))->get;
- c_forlist (i, Map_raw, { {"Rosanna", 2001}, {"Brad", 1999}, {"Jack", 1980} }) {
- Map_emplace(map, c_PAIR(i.ref));
- }
-
- // POPULATE s2:
- map = Stack_push(&s2, Arc_make(Map_init()))->get;
- c_forlist (i, Map_raw, { {"Steve", 1979}, {"Rick", 1974}, {"Tracy", 2003} }) {
- Map_emplace(map, c_PAIR(i.ref));
- }
-
- // Share two Maps from s1 with s2 by cloning(=sharing) the carcs:
- Stack_push(&s2, Arc_clone(s1.data[0]));
- Stack_push(&s2, Arc_clone(s1.data[1]));
-
- // Deep-copy (does not share) a Map from s1 to s2.
- // s2 will contain two shared and two unshared maps.
- map = Stack_push(&s2, Arc_from(Map_clone(*s1.data[1].get)))->get;
-
- // Add one more element to the cloned map:
- Map_emplace_or_assign(map, "Cloned", 2022);
-
- // Add one more element to the shared map:
- Map_emplace_or_assign(s1.data[1].get, "Shared", 2022);
-
- puts("S1");
- c_foreach (i, Stack, s1) {
- c_forpair (name, year, Map, *i.ref->get)
- printf(" %s:%d", cstr_str(_.name), *_.year);
- puts("");
- }
-
- puts("S2");
- c_foreach (i, Stack, s2) {
- c_forpair (name, year, Map, *i.ref->get)
- printf(" %s:%d", cstr_str(_.name), *_.year);
- puts("");
- }
+ Stack s1 = {0}, s2 = {0};
+ Map *map;
+
+ // POPULATE s1 with shared pointers to Map:
+ map = Stack_push(&s1, Arc_make(Map_init()))->get; // push empty map to s1.
+ Map_emplace(map, "Joey", 1990);
+ Map_emplace(map, "Mary", 1995);
+ Map_emplace(map, "Joanna", 1992);
+
+ map = Stack_push(&s1, Arc_make(Map_init()))->get;
+ Map_emplace(map, "Rosanna", 2001);
+ Map_emplace(map, "Brad", 1999);
+ Map_emplace(map, "Jack", 1980);
+
+ // POPULATE s2:
+ map = Stack_push(&s2, Arc_make(Map_init()))->get;
+ Map_emplace(map, "Steve", 1979);
+ Map_emplace(map, "Rick", 1974);
+ Map_emplace(map, "Tracy", 2003);
+
+ // Share two Maps from s1 with s2 by cloning(=sharing) the carcs:
+ Stack_push(&s2, Arc_clone(s1.data[0]));
+ Stack_push(&s2, Arc_clone(s1.data[1]));
+
+ // Deep-copy (does not share) a Map from s1 to s2.
+ // s2 will contain two shared and two unshared maps.
+ map = Stack_push(&s2, Arc_from(Map_clone(*s1.data[1].get)))->get;
+
+ // Add one more element to the cloned map:
+ Map_emplace_or_assign(map, "Cloned", 2022);
+
+ // Add one more element to the shared map:
+ Map_emplace_or_assign(s1.data[1].get, "Shared", 2022);
+
+ puts("S1");
+ c_foreach (i, Stack, s1) {
+ c_forpair (name, year, Map, *i.ref->get)
+ printf(" %s:%d", cstr_str(_.name), *_.year);
puts("");
}
+
+ puts("S2");
+ c_foreach (i, Stack, s2) {
+ c_forpair (name, year, Map, *i.ref->get)
+ printf(" %s:%d", cstr_str(_.name), *_.year);
+ puts("");
+ }
+ puts("");
+
+ c_drop(Stack, &s1, &s2);
}
```
Output:
diff --git a/docs/cbox_api.md b/docs/cbox_api.md
index 8b03d004..ca4d90da 100644
--- a/docs/cbox_api.md
+++ b/docs/cbox_api.md
@@ -92,11 +92,12 @@ void int_drop(int* x) {
int main()
{
- c_auto (IVec, vec) // declare and init vec, call drop at scope exit
- c_auto (ISet, set) // similar
- {
- vec = c_make(Vec, {2021, 2012, 2022, 2015});
-
+ IVec vec = c_make(Vec, {2021, 2012, 2022, 2015});
+ ISet set = {0};
+ c_defer(
+ IVec_drop(&vec),
+ ISet_drop(&set)
+ ){
printf("vec:");
c_foreach (i, IVec, vec)
printf(" %d", *i.ref->get);
diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md
index 8dcb2ff3..7a3c3196 100644
--- a/docs/ccommon_api.md
+++ b/docs/ccommon_api.md
@@ -1,106 +1,16 @@
-# STC [ccommon](../include/stc/ccommon.h): Generic algorithms and macros
+# STC Algorithms
-The following macros are recommended to use, and they safe/have no side-effects.
+---
+## Ranged for-loops
-## Scope macros (RAII)
-### c_auto, c_with, c_scope, c_defer
-General ***defer*** mechanics for resource acquisition. These macros allows you to specify the
-freeing of the resources at the point where the acquisition takes place.
-The **checkauto** utility described below, ensures that the `c_auto*` macros are used correctly.
+### c_foreach, c_foreach_rv, c_forpair
-| Usage | Description |
-|:---------------------------------------|:----------------------------------------------------------|
-| `c_with (Type var=init, drop)` | Declare `var`. Defer `drop...` to end of scope |
-| `c_with (Type var=init, pred, drop)` | Adds a predicate in order to exit early if init failed |
-| `c_auto (Type, var1,...,var4)` | `c_with (Type var1=Type_init(), Type_drop(&var1))` ... |
-| `c_scope (init, drop)` | Execute `init` and defer `drop` to end of scope |
-| `c_defer (drop...)` | Defer `drop...` to end of scope |
-| `continue` | Exit a block above without memory leaks |
-
-For multiple variables, use either multiple **c_with** in sequence, or declare variable outside
-scope and use **c_scope**. For convenience, **c_auto** support up to 4 variables.
-```c
-// `c_with` is similar to python `with`: it declares and can drop a variable after going out of scope.
-bool ok = false;
-c_with (uint8_t* buf = malloc(BUF_SIZE), buf != NULL, free(buf))
-c_with (FILE* fp = fopen(fname, "rb"), fp != NULL, fclose(fp))
-{
- int n = fread(buf, 1, BUF_SIZE, fp);
- if (n <= 0) continue; // auto cleanup! NB do not break or return here.
- ...
- ok = true;
-}
-return ok;
-
-// `c_auto` automatically initialize and destruct up to 4 variables:
-c_auto (cstr, s1, s2)
-{
- cstr_append(&s1, "Hello");
- cstr_append(&s1, " world");
-
- cstr_append(&s2, "Cool");
- cstr_append(&s2, " stuff");
-
- printf("%s %s\n", cstr_str(&s1), cstr_str(&s2));
-}
-
-// `c_with` is a general variant of `c_auto`:
-c_with (cstr str = cstr_lit("Hello"), cstr_drop(&str))
-{
- cstr_append(&str, " world");
- printf("%s\n", cstr_str(&str));
-}
-
-// `c_scope` is like `c_with` but works with an already declared variable.
-static pthread_mutex_t mut;
-c_scope (pthread_mutex_lock(&mut), pthread_mutex_unlock(&mut))
-{
- /* Do syncronized work. */
-}
-
-// `c_defer` executes the expressions when leaving scope. Prefer c_with or c_scope.
-cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world");
-c_defer (cstr_drop(&s1), cstr_drop(&s2))
-{
- printf("%s %s\n", cstr_str(&s1), cstr_str(&s2));
-}
-```
-**Example**: Load each line of a text file into a vector of strings:
-```c
-#include <errno.h>
-#include <stc/cstr.h>
-
-#define i_val_str
-#include <stc/cvec.h>
-
-// receiver should check errno variable
-cvec_str readFile(const char* name)
-{
- cvec_str vec = cvec_str_init(); // returned
-
- c_with (FILE* fp = fopen(name, "r"), fp != NULL, fclose(fp))
- c_with (cstr line = cstr_NULL, cstr_drop(&line))
- while (cstr_getline(&line, fp))
- cvec_str_emplace_back(&vec, cstr_str(&line));
- return vec;
-}
-
-int main()
-{
- c_with (cvec_str x = readFile(__FILE__), cvec_str_drop(&x))
- c_foreach (i, cvec_str, x)
- printf("%s\n", cstr_str(i.ref));
-}
-```
-## Loop abstraction macros
-
-### c_foreach, c_forpair
-
-| Usage | Description |
-|:-----------------------------------------|:--------------------------------|
-| `c_foreach (it, ctype, container)` | Iteratate all elements |
-| `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) |
-| `c_forpair (key, val, ctype, container)` | Iterate with structured binding |
+| Usage | Description |
+|:-----------------------------------------|:------------------------------------------|
+| `c_foreach (it, ctype, container)` | Iteratate all elements |
+| `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) |
+| `c_foreach_rv (it, ctype, container)` | Iteratate in reverse (cstack, cvec, cdeq) |
+| `c_forpair (key, val, ctype, container)` | Iterate with structured binding |
```c
#define i_key int
@@ -129,6 +39,25 @@ c_forpair (id, count, csmap_ii, map)
// (3 2) (5 4) (7 3) (12 5) (23 1)
```
+### c_forlist
+Iterate compound literal array elements. Additional to `i.ref`, you can access `i.data`, `i.size`, and `i.index` of the input list/element.
+```c
+// apply multiple push_backs
+c_forlist (i, int, {1, 2, 3})
+ cvec_i_push_back(&vec, *i.ref);
+
+// insert in existing map
+c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} })
+ cmap_ii_insert(&map, i.ref->first, i.ref->second);
+
+// string literals pushed to a stack of cstr:
+c_forlist (i, const char*, {"Hello", "crazy", "world"})
+ cstack_str_emplace(&stk, *i.ref);
+```
+
+---
+## Range algorithms
+
### c_forrange
Abstraction for iterating sequence of integers. Like python's **for** *i* **in** *range()* loop.
@@ -150,46 +79,56 @@ c_forrange (i, 30, 0, -5) printf(" %lld", i);
// 30 25 20 15 10 5
```
-### c_forlist
-Iterate compound literal array elements. Additional to `i.ref`, you can access `i.data`, `i.size`, and `i.index` of the input list/element.
+### crange
+A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*:
```c
-// apply multiple push_backs
-c_forlist (i, int, {1, 2, 3})
- cvec_i_push_back(&vec, *i.ref);
-
-// insert in existing map
-c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} })
- cmap_ii_insert(&map, i.ref->first, i.ref->second);
+crange& crange_obj(...) // create a compound literal crange object
+crange crange_make(stop); // will generate 0, 1, ..., stop-1
+crange crange_make(start, stop); // will generate start, start+1, ... stop-1
+crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop
+ // note that step may be negative.
+crange_iter crange_begin(crange* self);
+crange_iter crange_end(crange* self);
+void crange_next(crange_iter* it);
-// string literals pushed to a stack of cstr:
-c_forlist (i, const char*, {"Hello", "crazy", "world"})
- cstack_str_emplace(&stk, *i.ref);
+// 1. All primes less than 32:
+crange r1 = crange_make(3, 32, 2);
+printf("2"); // first prime
+c_forfilter (i, crange, r1, isPrime(*i.ref))
+ printf(" %lld", *i.ref);
+// 2 3 5 7 11 13 17 19 23 29 31
-// reverse the list:
-c_forlist (i, int, {1, 2, 3})
- cvec_i_push_back(&vec, i.data[i.size - 1 - i.index]);
+// 2. The first 11 primes:
+printf("2");
+c_forfilter (i, crange, crange_obj(3, INT64_MAX, 2),
+ isPrime(*i.ref) &&
+ c_flt_take(10)
+){
+ printf(" %lld", *i.ref);
+}
+// 2 3 5 7 11 13 17 19 23 29 31
```
### c_forfilter
-Iterate containers with stop-criteria and chained range filtering.
+Iterate a container/range with chained range filtering.
| Usage | Description |
|:----------------------------------------------------|:---------------------------------------|
| `c_forfilter (it, ctype, container, filter)` | Filter out items in chain with && |
-| `c_forwhile (it, ctype, start, pred)` | Iterate until pred is false |
-
-| Built-in filter | Description |
-|:----------------------------------|:-------------------------------------|
-| `c_flt_skip(it, numItems)` | Skip numItems (inc count) |
-| `c_flt_take(it, numItems)` | Take numItems (inc count) |
-| `c_flt_skipwhile(it, predicate)` | Skip items until predicate is false |
-| `c_flt_takewhile(it, predicate)` | Take items until predicate is false |
-| `c_flt_count(it)` | Increment current and return value |
-| `c_flt_last(it)` | Get value of last count/skip/take |
+| `c_forfilter_it (it, ctype, startit, filter)` | Filter from startit position |
+
+| Built-in filter | Description |
+|:----------------------------------|:-------------------------------------------|
+| `c_flt_skip(it, numItems)` | Skip numItems (inc count) |
+| `c_flt_take(it, numItems)` | Take numItems (inc count) |
+| `c_flt_skipwhile(it, predicate)` | Skip items until predicate is false |
+| `c_flt_takewhile(it, predicate)` | Take items until predicate is false |
+| `c_flt_counter(it)` | Increment current and return count |
+| `c_flt_getcount(it)` | Number of items passed skip*/take*/counter |
+
+[ [Run this example](https://godbolt.org/z/n9aYrYPv8) ]
```c
-// Example:
-#include <stc/algo/crange.h>
-#include <stc/algo/filter.h>
+#include <stc/calgo.h>
#include <stdio.h>
bool isPrime(long long i) {
@@ -197,59 +136,33 @@ bool isPrime(long long i) {
if (i % j == 0) return false;
return true;
}
+
int main() {
- // Get 10 prime numbers starting from 1000.
- // Skip the first 24 primes, then select every 15th prime.
- crange R = crange_make(1001, INT32_MAX, 2);
+ // Get 10 prime numbers starting from 1000. Skip the first 15 primes,
+ // then select every 25th prime (including the initial).
+ crange R = crange_make(1001, INT64_MAX, 2); // 1001, 1003, ...
c_forfilter (i, crange, R,
- isPrime(*i.ref)
- && c_flt_skip(i, 24)
- && c_flt_count(i) % 15 == 1
- && c_flt_take(i, 10))
+ isPrime(*i.ref) &&
+ c_flt_skip(i, 15) &&
+ c_flt_counter(i) % 25 == 1 &&
+ c_flt_take(i, 10)
+ ){
printf(" %lld", *i.ref);
- puts("");
+ }
}
-// out: 1171 1283 1409 1493 1607 1721 1847 1973 2081 2203
+// out: 1097 1289 1481 1637 1861 2039 2243 2417 2657 2803
```
-Note that `c_flt_take()` and `c_flt_takewhile()`breaks the loop on false.
+Note that `c_flt_take()` and `c_flt_takewhile()` breaks the loop on false.
-## Generators
+---
+## Generic algorithms
-### crange
-A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*:
-```c
-crange& crange_obj(...) // create a compound literal crange object
-crange crange_make(stop); // will generate 0, 1, ..., stop-1
-crange crange_make(start, stop); // will generate start, start+1, ... stop-1
-crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop
- // note that step may be negative.
-crange_iter crange_begin(crange* self);
-crange_iter crange_end(crange* self);
-void crange_next(crange_iter* it);
-
-// 1. All primes less than 32:
-crange r1 = crange_make(3, 32, 2);
-printf("2"); // first prime
-c_forfilter (i, crange, r1, isPrime(*i.ref))
- printf(" %lld", *i.ref);
-// 2 3 5 7 11 13 17 19 23 29 31
+### c_make, c_drop
-// 2. The 11 first primes:
-printf("2");
-c_forfilter (i, crange, crange_obj(3, INT64_MAX, 2)
- , isPrime(*i.ref)
- && c_flt_take(10))
- printf(" %lld", *i.ref);
-// 2 3 5 7 11 13 17 19 23 29 31
-```
-## Algorithms
-
-### c_make, c_new, c_delete
-
-- *c_make(C, {...})*: Make any container from an initializer list. Example:
+Make any container from an initializer list:
```c
-#define i_val_str // cstr value type
+#define i_val_str // owned cstr string value type
#include <stc/cset.h>
#define i_key int
@@ -258,26 +171,21 @@ c_forfilter (i, crange, crange_obj(3, INT64_MAX, 2)
...
// Initializes with const char*, internally converted to cstr!
cset_str myset = c_make(cset_str, {"This", "is", "the", "story"});
+cset_str myset2 = c_clone(myset);
int x = 7, y = 8;
cmap_int mymap = c_make(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} });
```
-
-- ***c_new(Type)***: Allocate *and init* a new object on the heap
-- ***c_delete(Type, ptr)***: Drop *and free* an object allocated on the heap
+Drop multiple containers of the same type:
```c
-#include <stc/cstr.h>
-
-cstr *stringptr = c_new(cstr, cstr_from("Hello"));
-printf("%s\n", cstr_str(stringptr));
-c_delete(cstr, stringptr);
+c_drop(cset_str, &myset, &myset2);
```
### c_find_if, c_erase_if, c_eraseremove_if
Find or erase linearily in containers using a predicate
-- For *c_find_if (iter, C, c, pred)*, ***iter*** must be declared outside/prior to call.
-- Use *c_erase_if (iter, C, c, pred)* with **clist**, **cmap**, **cset**, **csmap**, and **csset**.
-- Use *c_eraseremove_if (iter, C, c, pred)* with **cstack**, **cvec**, **cdeq**, and **cqueue**.
+- For `c_find_if(iter, C, c, pred)`, ***iter*** is in/out and must be declared prior to call.
+- Use `c_erase_if(iter, C, c, pred)` with **clist**, **cmap**, **cset**, **csmap**, and **csset**.
+- Use `c_eraseremove_if(iter, C, c, pred)` with **cstack**, **cvec**, **cdeq**, and **cqueue**.
```c
// Search vec for first value > 2:
cvec_i_iter i;
@@ -296,29 +204,36 @@ if (it.ref) cmap_str_erase_at(&map, it);
c_erase_if(i, csmap_str, map, cstr_contains(i.ref, "hello"));
```
-### c_swap, c_drop
+### csort - two times faster qsort
+
+When very fast array sorting is required, **csort** is about twice as fast as *qsort()*, and often simpler to use.
+You may customize `i_tag` and the comparison function `i_cmp` or `i_less`.
+
+There is a [benchmark/test file here](../misc/benchmarks/various/csort_bench.c).
```c
-// Safe macro for swapping internals of two objects of same type:
-c_swap(cmap_int, &map1, &map2);
+#define i_val int
+#include <stc/algo/csort.h>
-// Drop multiple containers of same type:
-c_drop(cvec_i, &vec1, &vec2, &vec3);
+int main() {
+ int array[] = {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4};
+ csort_int(array, c_arraylen(array));
+}
```
-### General predefined template parameter functions
+
+### c_new, c_delete
+
+- `c_new(Type, val)` - Allocate *and init* a new object on the heap
+- `c_delete(Type, ptr)` - Drop *and free* an object allocated on the heap. NULL is OK.
```c
-int c_default_cmp(const Type*, const Type*);
-Type c_default_clone(Type val); // simple copy
-Type c_default_toraw(const Type* val); // dereference val
-void c_default_drop(Type* val); // does nothing
+#include <stc/cstr.h>
-typedef const char* crawstr;
-int crawstr_cmp(const crawstr* x, const crawstr* y);
-bool crawstr_eq(const crawstr* x, const crawstr* y);
-uint64_t crawstr_hash(const crawstr* x);
+cstr *str_p = c_new(cstr, cstr_from("Hello"));
+printf("%s\n", cstr_str(str_p));
+c_delete(cstr, str_p);
```
-### c_malloc, c_calloc, c_realloc, c_free: customizable allocators
+### c_malloc, c_calloc, c_realloc, c_free
Memory allocator wrappers that uses signed sizes.
### c_arraylen
@@ -328,7 +243,219 @@ int array[] = {1, 2, 3, 4};
intptr_t n = c_arraylen(array);
```
-## The **checkauto** utility program (for RAII)
+### c_swap, c_const_cast
+```c
+// Safe macro for swapping internals of two objects of same type:
+c_swap(cmap_int, &map1, &map2);
+
+// Type-safe casting a from const (pointer):
+const char cs[] = "Hello";
+char* s = c_const_cast(char*, cs); // OK
+int* ip = c_const_cast(int*, cs); // issues a warning!
+```
+
+### Predefined template parameter functions
+
+**crawstr** - Non-owned `const char*` "class" element type: `#define i_valclass crawstr`
+```c
+typedef const char* crawstr;
+int crawstr_cmp(const crawstr* x, const crawstr* y);
+bool crawstr_eq(const crawstr* x, const crawstr* y);
+uint64_t crawstr_hash(const crawstr* x);
+```
+Default implementations
+```c
+int c_default_cmp(const Type*, const Type*); // <=>
+bool c_default_less(const Type*, const Type*); // <
+bool c_default_eq(const Type*, const Type*); // ==
+uint64_t c_default_hash(const Type*);
+Type c_default_clone(Type val); // return val
+Type c_default_toraw(const Type* p); // return *p
+void c_default_drop(Type* p); // does nothing
+```
+
+---
+## Coroutines
+This is a much improved implementation of
+[Simon Tatham's coroutines](https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html),
+which utilizes the *Duff's device* trick. Tatham's implementation is not typesafe,
+and it always allocates the coroutine's internal state dynamically. But crucially,
+it does not let the coroutine do self-cleanup on early finish - i.e. it
+only frees the initial dynamically allocated memory.
+
+In this implementation, a coroutine may have any signature, but it should
+take a struct pointer as parameter, which must contain the member `int cco_state;`
+The struct should normally store all the *local* variables to be used in the
+coroutine. It can also store input and output data if desired.
+
+The coroutine example below generates Pythagorian triples, but the calling loop
+skips the triples which are upscaled version of smaller ones, by checking
+the gcd() function. It also ensures that it stops when the diagonal size >= 100:
+
+[ [Run this code](https://godbolt.org/z/coqqrfbd5) ]
+```c
+#include <stc/calgo.h>
+
+struct triples {
+ int n; // input: max number of triples to be generated.
+ int a, b, c;
+ int cco_state; // required member
+};
+
+bool triples_next(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);
+ if (--i->n == 0) cco_return;
+ }
+ }
+ }
+ }
+ cco_final: // required label
+ puts("done");
+ cco_end(false);
+}
+
+int gcd(int a, int b) { // greatest common denominator
+ while (b) {
+ int t = a % b;
+ a = b;
+ b = t;
+ }
+ return a;
+}
+
+int main()
+{
+ struct triples t = {.n=INT32_MAX};
+ int n = 0;
+
+ while (triples_next(&t)) {
+ // Skip triples with GCD(a,b) > 1
+ if (gcd(t.a, t.b) > 1)
+ continue;
+
+ // Stop when c >= 100
+ if (t.c < 100)
+ printf("%d: [%d, %d, %d]\n", ++n, t.a, t.b, t.c);
+ else
+ cco_stop(&t); // cleanup in next coroutine call/resume
+ }
+}
+```
+### 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.
+
+| | Function / operator | Description |
+|:----------|:-------------------------------------|:----------------------------------------|
+| | `cco_final:` | Obligatory label in coroutine |
+| | `cco_return;` | Early return from the coroutine |
+| `bool` | `cco_alive(ctx)` | Is coroutine in initial or suspended state? |
+| `bool` | `cco_suspended(ctx)` | Is coroutine in suspended state? |
+| `void` | `cco_begin(ctx)` | Begin coroutine block |
+| `rettype` | `cco_end(retval)` | End coroutine block with return value |
+| `void` | `cco_end()` | End coroutine block |
+| `rettype` | `cco_yield(retval)` | Suspend execution and return a value |
+| `void` | `cco_yield()` | Suspend execution |
+| `rettype` | `cco_yield(corocall2, ctx2, retval)` | Yield from another coroutine and return val |
+| `void` | `cco_yield(corocall2, ctx2)` | Yield from another coroutine |
+| | From the caller side: | |
+| `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` |
+| `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) |
+
+---
+## RAII scope macros
+General ***defer*** mechanics for resource acquisition. These macros allows you to specify the
+freeing of the resources at the point where the acquisition takes place.
+The **checkauto** utility described below, ensures that the `c_auto*` macros are used correctly.
+
+| Usage | Description |
+|:---------------------------------------|:----------------------------------------------------------|
+| `c_defer (drop...)` | Defer `drop...` to end of scope |
+| `c_scope (init, drop)` | Execute `init` and defer `drop` to end of scope |
+| `c_scope (init, pred, drop)` | Adds a predicate in order to exit early if init failed |
+| `c_with (Type var=init, drop)` | Declare `var`. Defer `drop...` to end of scope |
+| `c_with (Type var=init, pred, drop)` | Adds a predicate in order to exit early if init failed |
+| `c_auto (Type, var1,...,var4)` | `c_with (Type var1=Type_init(), Type_drop(&var1))` ... |
+| `continue` | Exit a defer-block without resource leak |
+
+```c
+// `c_defer` executes the expression(s) when leaving scope.
+cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world");
+c_defer (cstr_drop(&s1), cstr_drop(&s2))
+{
+ printf("%s %s\n", cstr_str(&s1), cstr_str(&s2));
+}
+
+// `c_scope` syntactically "binds" initialization and defer.
+static pthread_mutex_t mut;
+c_scope (pthread_mutex_lock(&mut), pthread_mutex_unlock(&mut))
+{
+ /* Do syncronized work. */
+}
+
+// `c_with` is similar to python `with`: declare a variable and defer the drop call.
+c_with (cstr str = cstr_lit("Hello"), cstr_drop(&str))
+{
+ cstr_append(&str, " world");
+ printf("%s\n", cstr_str(&str));
+}
+
+// `c_auto` automatically initialize and drops up to 4 variables:
+c_auto (cstr, s1, s2)
+{
+ cstr_append(&s1, "Hello");
+ cstr_append(&s1, " world");
+ cstr_append(&s2, "Cool");
+ cstr_append(&s2, " stuff");
+ printf("%s %s\n", cstr_str(&s1), cstr_str(&s2));
+}
+```
+**Example 1**: Use multiple **c_with** in sequence:
+```c
+bool ok = false;
+c_with (uint8_t* buf = malloc(BUF_SIZE), buf != NULL, free(buf))
+c_with (FILE* fp = fopen(fname, "rb"), fp != NULL, fclose(fp))
+{
+ int n = fread(buf, 1, BUF_SIZE, fp);
+ if (n <= 0) continue; // auto cleanup! NB do not break or return here.
+ ...
+ ok = true;
+}
+return ok;
+```
+**Example 2**: Load each line of a text file into a vector of strings:
+```c
+#include <errno.h>
+#include <stc/cstr.h>
+
+#define i_val_str
+#include <stc/cvec.h>
+
+// receiver should check errno variable
+cvec_str readFile(const char* name)
+{
+ cvec_str vec = {0}; // returned
+ c_with (FILE* fp = fopen(name, "r"), fp != NULL, fclose(fp))
+ c_with (cstr line = {0}, cstr_drop(&line))
+ while (cstr_getline(&line, fp))
+ cvec_str_emplace(&vec, cstr_str(&line));
+ return vec;
+}
+
+int main()
+{
+ c_with (cvec_str vec = readFile(__FILE__), cvec_str_drop(&vec))
+ c_foreach (i, cvec_str, vec)
+ printf("| %s\n", cstr_str(i.ref));
+}
+```
+
+### The **checkauto** utility program (for RAII)
The **checkauto** program will check the source code for any misuses of the `c_auto*` macros which
may lead to resource leakages. The `c_auto*`- macros are implemented as one-time executed **for-loops**,
so any `return` or `break` appearing within such a block will lead to resource leaks, as it will disable
diff --git a/docs/clist_api.md b/docs/clist_api.md
index 929931af..a1dbe105 100644
--- a/docs/clist_api.md
+++ b/docs/clist_api.md
@@ -80,8 +80,8 @@ const i_val* clist_X_get(const clist_X* self, i_valraw raw);
i_val* clist_X_get_mut(clist_X* self, i_valraw raw);
void clist_X_reverse(clist_X* self);
-void clist_X_sort(clist_X* self); // needs i_extern defined
-void clist_X_sort_with(clist_X* self, int(*cmp)(const clist_X_node*, const clist_X_node*));
+void clist_X_sort(clist_X* self);
+void clist_X_sort_with(clist_X* self, int(*cmp)(const clist_X_value*, const clist_X_value*));
// Node API
clist_X_node* clist_X_get_node(clist_X_value* val); // get the enclosing node
@@ -193,21 +193,20 @@ Splice `[30, 40]` from *L2* into *L1* before `3`:
#include <stdio.h>
int main() {
- c_auto (clist_i, L1, L2)
- {
- L1 = c_make(clist_i, {1, 2, 3, 4, 5});
- L2 = c_make(clist_i, {10, 20, 30, 40, 50});
+ clist_i L1 = c_make(clist_i, {1, 2, 3, 4, 5});
+ clist_i L2 = c_make(clist_i, {10, 20, 30, 40, 50});
- clist_i_iter i = clist_i_advance(clist_i_begin(&L1), 2);
- clist_i_iter j1 = clist_i_advance(clist_i_begin(&L2), 2), j2 = clist_i_advance(j1, 2);
+ clist_i_iter i = clist_i_advance(clist_i_begin(&L1), 2);
+ clist_i_iter j1 = clist_i_advance(clist_i_begin(&L2), 2), j2 = clist_i_advance(j1, 2);
- clist_i_splice_range(&L1, i, &L2, j1, j2);
+ clist_i_splice_range(&L1, i, &L2, j1, j2);
- c_foreach (i, clist_i, L1)
- printf(" %d", *i.ref); puts("");
- c_foreach (i, clist_i, L2)
- printf(" %d", *i.ref); puts("");
- }
+ c_foreach (i, clist_i, L1)
+ printf(" %d", *i.ref); puts("");
+ c_foreach (i, clist_i, L2)
+ printf(" %d", *i.ref); puts("");
+
+ c_drop(clist_i, &L1, &L2);
}
```
Output:
diff --git a/docs/cmap_api.md b/docs/cmap_api.md
index bf3dddcc..d2a94ee8 100644
--- a/docs/cmap_api.md
+++ b/docs/cmap_api.md
@@ -36,9 +36,7 @@ See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/contain
#define i_valto // convertion func i_val* => i_valraw
#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val
-#define i_hash_functor // advanced, see examples/functor.c for similar usage.
-#define i_eq_functor // advanced, see examples/functor.c for similar usage.
-#define i_ssize // internal; default int32_t. If defined, table expand 2x (else 1.5x)
+#define i_ssize // internal; default int32_t. If defined, table expand 2x (else 1.5x)
#include <stc/cmap.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
@@ -104,12 +102,12 @@ bool c_memcmp_eq(const i_keyraw* a, const i_keyraw* b); // !
| Type name | Type definition | Used to represent... |
|:-------------------|:------------------------------------------------|:------------------------------|
| `cmap_X` | `struct { ... }` | The cmap type |
-| `cmap_X_rawkey` | `i_keyraw` | The raw key type |
-| `cmap_X_rawmapped` | `i_valraw` | The raw mapped type |
-| `cmap_X_raw` | `struct { i_keyraw first; i_valraw second; }` | i_keyraw + i_valraw type |
| `cmap_X_key` | `i_key` | The key type |
| `cmap_X_mapped` | `i_val` | The mapped type |
| `cmap_X_value` | `struct { const i_key first; i_val second; }` | The value: key is immutable |
+| `cmap_X_keyraw` | `i_keyraw` | The raw key type |
+| `cmap_X_rmapped` | `i_valraw` | The raw mapped type |
+| `cmap_X_raw` | `struct { i_keyraw first; i_valraw second; }` | i_keyraw + i_valraw type |
| `cmap_X_result` | `struct { cmap_X_value *ref; bool inserted; }` | Result of insert/emplace |
| `cmap_X_iter` | `struct { cmap_X_value *ref; ... }` | Iterator type |
@@ -125,27 +123,26 @@ bool c_memcmp_eq(const i_keyraw* a, const i_keyraw* b); // !
int main()
{
// Create an unordered_map of three strings (that map to strings)
- c_auto (cmap_str, u)
- {
- u = c_make(cmap_str, {
- {"RED", "#FF0000"},
- {"GREEN", "#00FF00"},
- {"BLUE", "#0000FF"}
- });
-
- // Iterate and print keys and values of unordered map
- c_foreach (n, cmap_str, u) {
- printf("Key:[%s] Value:[%s]\n", cstr_str(&n.ref->first), cstr_str(&n.ref->second));
- }
-
- // Add two new entries to the unordered map
- cmap_str_emplace(&u, "BLACK", "#000000");
- cmap_str_emplace(&u, "WHITE", "#FFFFFF");
-
- // Output values by key
- printf("The HEX of color RED is:[%s]\n", cstr_str(cmap_str_at(&u, "RED")));
- printf("The HEX of color BLACK is:[%s]\n", cstr_str(cmap_str_at(&u, "BLACK")));
+ cmap_str umap = c_make(cmap_str, {
+ {"RED", "#FF0000"},
+ {"GREEN", "#00FF00"},
+ {"BLUE", "#0000FF"}
+ });
+
+ // Iterate and print keys and values of unordered map
+ c_foreach (n, cmap_str, umap) {
+ printf("Key:[%s] Value:[%s]\n", cstr_str(&n.ref->first), cstr_str(&n.ref->second));
}
+
+ // Add two new entries to the unordered map
+ cmap_str_emplace(&umap, "BLACK", "#000000");
+ cmap_str_emplace(&umap, "WHITE", "#FFFFFF");
+
+ // Output values by key
+ printf("The HEX of color RED is:[%s]\n", cstr_str(cmap_str_at(&umap, "RED")));
+ printf("The HEX of color BLACK is:[%s]\n", cstr_str(cmap_str_at(&umap, "BLACK")));
+
+ cmap_str_drop(&umap);
}
```
Output:
@@ -161,33 +158,33 @@ The HEX of color BLACK is:[#000000]
This example uses a cmap with cstr as mapped value.
```c
#include <stc/cstr.h>
-
+#define i_type IDMap
#define i_key int
#define i_val_str
-#define i_tag id
#include <stc/cmap.h>
int main()
{
uint32_t col = 0xcc7744ff;
- c_auto (cmap_id, idnames)
- {
- c_forlist (i, cmap_id_raw, { {100, "Red"}, {110, "Blue"} })
- cmap_id_emplace(&idnames, c_PAIR(i.ref));
-
- // replace existing mapped value:
- cmap_id_emplace_or_assign(&idnames, 110, "White");
-
- // insert a new constructed mapped string into map:
- cmap_id_insert_or_assign(&idnames, 120, cstr_from_fmt("#%08x", col));
-
- // emplace/insert does nothing if key already exist:
- cmap_id_emplace(&idnames, 100, "Green");
-
- c_foreach (i, cmap_id, idnames)
- printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second));
- }
+ IDMap idnames = {0};
+
+ c_forlist (i, IDMap_raw, { {100, "Red"}, {110, "Blue"} })
+ IDMap_emplace(&idnames, i.ref->first, i.ref->second);
+
+ // replace existing mapped value:
+ IDMap_emplace_or_assign(&idnames, 110, "White");
+
+ // insert a new constructed mapped string into map:
+ IDMap_insert_or_assign(&idnames, 120, cstr_from_fmt("#%08x", col));
+
+ // emplace/insert does nothing if key already exist:
+ IDMap_emplace(&idnames, 100, "Green");
+
+ c_foreach (i, IDMap, idnames)
+ printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second));
+
+ IDMap_drop(&idnames);
}
```
Output:
@@ -212,16 +209,17 @@ typedef struct { int x, y, z; } Vec3i;
int main()
{
// Define map with defered destruct
- c_with (cmap_vi vecs = cmap_vi_init(), cmap_vi_drop(&vecs))
- {
- cmap_vi_insert(&vecs, (Vec3i){100, 0, 0}, 1);
- cmap_vi_insert(&vecs, (Vec3i){ 0, 100, 0}, 2);
- cmap_vi_insert(&vecs, (Vec3i){ 0, 0, 100}, 3);
- cmap_vi_insert(&vecs, (Vec3i){100, 100, 100}, 4);
-
- c_forpair (v3, num, cmap_vi, vecs)
- printf("{ %3d, %3d, %3d }: %d\n", _.v3->x, _.v3->y, _.v3->z, *_.num);
- }
+ cmap_vi vecs = {0};
+
+ cmap_vi_insert(&vecs, (Vec3i){100, 0, 0}, 1);
+ cmap_vi_insert(&vecs, (Vec3i){ 0, 100, 0}, 2);
+ cmap_vi_insert(&vecs, (Vec3i){ 0, 0, 100}, 3);
+ cmap_vi_insert(&vecs, (Vec3i){100, 100, 100}, 4);
+
+ c_forpair (v3, num, cmap_vi, vecs)
+ printf("{ %3d, %3d, %3d }: %d\n", _.v3->x, _.v3->y, _.v3->z, *_.num);
+
+ cmap_vi_drop(&vecs);
}
```
Output:
@@ -245,16 +243,17 @@ typedef struct { int x, y, z; } Vec3i;
int main()
{
- c_auto (cmap_iv, vecs) // shorthand for c_with with _init(), _drop().
- {
- cmap_iv_insert(&vecs, 1, (Vec3i){100, 0, 0});
- cmap_iv_insert(&vecs, 2, (Vec3i){ 0, 100, 0});
- cmap_iv_insert(&vecs, 3, (Vec3i){ 0, 0, 100});
- cmap_iv_insert(&vecs, 4, (Vec3i){100, 100, 100});
-
- c_forpair (num, v3, cmap_iv, vecs)
- printf("%d: { %3d, %3d, %3d }\n", *_.num, _.v3->x, _.v3->y, _.v3->z);
- }
+ cmap_iv vecs = {0}
+
+ cmap_iv_insert(&vecs, 1, (Vec3i){100, 0, 0});
+ cmap_iv_insert(&vecs, 2, (Vec3i){ 0, 100, 0});
+ cmap_iv_insert(&vecs, 3, (Vec3i){ 0, 0, 100});
+ cmap_iv_insert(&vecs, 4, (Vec3i){100, 100, 100});
+
+ c_forpair (num, v3, cmap_iv, vecs)
+ printf("%d: { %3d, %3d, %3d }\n", *_.num, _.v3->x, _.v3->y, _.v3->z);
+
+ cmap_iv_drop(&vecs);
}
```
Output:
@@ -300,35 +299,27 @@ static inline void Viking_drop(Viking* vk) {
#define i_type Vikings
#define i_keyclass Viking
#define i_val int
-/*
- i_keyclass implies these defines, unless they are already defined:
- #define i_cmp Viking_cmp
- #define i_hash Viking_hash
- #define i_keyclone Viking_clone
- #define i_keydrop Viking_drop
-*/
#include <stc/cmap.h>
int main()
{
// Use a HashMap to store the vikings' health points.
- c_auto (Vikings, vikings) // uses Vikings_init(), Vikings_drop()
- {
- Vikings_insert(&vikings, (Viking){cstr_lit("Einar"), cstr_lit("Norway")}, 25);
- Vikings_insert(&vikings, (Viking){cstr_lit("Olaf"), cstr_lit("Denmark")}, 24);
- Vikings_insert(&vikings, (Viking){cstr_lit("Harald"), cstr_lit("Iceland")}, 12);
- Vikings_insert(&vikings, (Viking){cstr_lit("Einar"), cstr_lit("Denmark")}, 21);
-
- c_auto (Viking, lookup) {
- lookup = (Viking){cstr_lit("Einar"), cstr_lit("Norway")};
- printf("Lookup: Einar of Norway has %d hp\n\n", *Vikings_at(&vikings, lookup));
- }
-
- // Print the status of the vikings.
- c_forpair (vik, hp, Vikings, vikings) {
- printf("%s of %s has %d hp\n", cstr_str(&_.vik->name), cstr_str(&_.vik->country), *_.hp);
- }
+ Vikings vikings = {0};
+
+ Vikings_insert(&vikings, (Viking){cstr_lit("Einar"), cstr_lit("Norway")}, 25);
+ Vikings_insert(&vikings, (Viking){cstr_lit("Olaf"), cstr_lit("Denmark")}, 24);
+ Vikings_insert(&vikings, (Viking){cstr_lit("Harald"), cstr_lit("Iceland")}, 12);
+ Vikings_insert(&vikings, (Viking){cstr_lit("Einar"), cstr_lit("Denmark")}, 21);
+
+ Viking lookup = (Viking){cstr_lit("Einar"), cstr_lit("Norway")};
+ printf("Lookup: Einar of Norway has %d hp\n\n", *Vikings_at(&vikings, lookup));
+ Viking_drop(&lookup);
+
+ // Print the status of the vikings.
+ c_forpair (vik, hp, Vikings, vikings) {
+ printf("%s of %s has %d hp\n", cstr_str(&_.vik->name), cstr_str(&_.vik->country), *_.hp);
}
+ Vikings_drop(&vikings);
}
```
Output:
@@ -384,30 +375,22 @@ static inline RViking Viking_toraw(const Viking* vp) {
#define i_hash(rp) (cstrhash(rp->name) ^ cstrhash(rp->country))
#define i_val int
#include <stc/cmap.h>
-/*
- i_keyclass implies these defines, unless they are already defined:
- #define i_cmp RViking_cmp
- //#define i_hash RViking_hash // already defined above.
- //#define i_keyclone Viking_clone // not used because c_no_clone
- #define i_keyto Viking_toraw // because i_keyraw type is defined
- #define i_keydrop Viking_drop
-*/
int main()
{
- c_auto (Vikings, vikings)
- {
- Vikings_emplace(&vikings, (RViking){"Einar", "Norway"}, 20);
- Vikings_emplace(&vikings, (RViking){"Olaf", "Denmark"}, 24);
- Vikings_emplace(&vikings, (RViking){"Harald", "Iceland"}, 12);
- Vikings_emplace(&vikings, (RViking){"Björn", "Sweden"}, 10);
-
- Vikings_value *v = Vikings_get_mut(&vikings, (RViking){"Einar", "Norway"});
- if (v) 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 vikings = {0};
+
+ Vikings_emplace(&vikings, (RViking){"Einar", "Norway"}, 20);
+ Vikings_emplace(&vikings, (RViking){"Olaf", "Denmark"}, 24);
+ Vikings_emplace(&vikings, (RViking){"Harald", "Iceland"}, 12);
+ Vikings_emplace(&vikings, (RViking){"Björn", "Sweden"}, 10);
+
+ Vikings_value *v = Vikings_get_mut(&vikings, (RViking){"Einar", "Norway"});
+ if (v) 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/docs/coption_api.md b/docs/coption_api.md
index be0d0978..1e85ac2a 100644
--- a/docs/coption_api.md
+++ b/docs/coption_api.md
@@ -66,6 +66,4 @@ int main(int argc, char *argv[]) {
printf(" %s", argv[i]);
putchar('\n');
}
- return 0;
-}
```
diff --git a/docs/cpque_api.md b/docs/cpque_api.md
index 991623d7..962ee162 100644
--- a/docs/cpque_api.md
+++ b/docs/cpque_api.md
@@ -18,7 +18,6 @@ See the c++ class [std::priority_queue](https://en.cppreference.com/w/cpp/contai
#define i_valfrom // convertion func i_valraw => i_val
#define i_valto // convertion func i_val* => i_valraw.
-#define i_less_functor // takes self as first argument. See examples/functor.c for usage.
#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_val
#include <stc/cpque.h>
```
@@ -61,7 +60,7 @@ i_val cpque_X_value_clone(i_val value);
## Example
```c
-#include <stc/crandom.h>
+#include <stc/crand.h>
#include <stdio.h>
#define i_val int64_t
@@ -72,27 +71,27 @@ i_val cpque_X_value_clone(i_val value);
int main()
{
intptr_t N = 10000000;
- stc64_t rng = stc64_new(1234);
- stc64_uniform_t dist = stc64_uniform_new(0, N * 10);
-
- // Declare heap, with defered drop()
- c_auto (cpque_i, heap)
- {
- // Push ten million random numbers to priority queue.
- c_forrange (N)
- cpque_i_push(&heap, stc64_uniform(&rng, &dist));
-
- // Add some negative ones.
- int nums[] = {-231, -32, -873, -4, -343};
- c_forrange (i, c_ARRAYLEN(nums))
- cpque_i_push(&heap, nums[i]);
-
- // Extract and display the fifty smallest.
- c_forrange (50) {
- printf("%" PRId64 " ", *cpque_i_top(&heap));
- cpque_i_pop(&heap);
- }
+ crand_t rng = crand_init(1234);
+ crand_unif_t dist = crand_unif_init(0, N * 10);
+
+ // Define heap
+ cpque_i heap = {0};
+
+ // Push ten million random numbers to priority queue.
+ c_forrange (N)
+ cpque_i_push(&heap, crand_unif(&rng, &dist));
+
+ // Add some negative ones.
+ int nums[] = {-231, -32, -873, -4, -343};
+ c_forrange (i, c_arraylen(nums))
+ cpque_i_push(&heap, nums[i]);
+
+ // Extract and display the fifty smallest.
+ c_forrange (50) {
+ printf("%" PRId64 " ", *cpque_i_top(&heap));
+ cpque_i_pop(&heap);
}
+ cpque_i_drop(&heap);
}
```
Output:
diff --git a/docs/crandom_api.md b/docs/crandom_api.md
index e69cc539..7281b2d7 100644
--- a/docs/crandom_api.md
+++ b/docs/crandom_api.md
@@ -1,4 +1,4 @@
-# STC [crandom](../include/stc/crandom.h): Pseudo Random Number Generator
+# STC [crand](../include/stc/crand.h): Pseudo Random Number Generator
![Random](pics/random.jpg)
This features a *64-bit PRNG* named **stc64**, and can generate bounded uniform and normal
@@ -33,45 +33,40 @@ xoshiro and pcg (Vigna/O'Neill) PRNGs: https://www.pcg-random.org/posts/on-vigna
## Header file
-All crandom definitions and prototypes are available by including a single header file.
+All crand definitions and prototypes are available by including a single header file.
```c
-#include <stc/crandom.h>
+#include <stc/crand.h>
```
## Methods
```c
-void csrandom(uint64_t seed); // seed global stc64 prng
-uint64_t crandom(void); // global stc64_rand(rng)
-double crandomf(void); // global stc64_randf(rng)
+void csrand(uint64_t seed); // seed global stc64 prng
+uint64_t crand(void); // global crand_u64(rng)
+double crandf(void); // global crand_f64(rng)
-stc64_t stc64_new(uint64_t seed); // stc64_init(s) is deprecated
-stc64_t stc64_with_seq(uint64_t seed, uint64_t seq); // with unique stream
+crand_t crand_init(uint64_t seed); // stc64_init(s) is deprecated
+uint64_t crand_u64(crand_t* rng); // range [0, 2^64 - 1]
+double crand_f64(crand_t* rng); // range [0.0, 1.0)
-uint64_t stc64_rand(stc64_t* rng); // range [0, 2^64 - 1]
-double stc64_randf(stc64_t* rng); // range [0.0, 1.0)
+crand_unif_t crand_unif_init(int64_t low, int64_t high); // uniform-distribution
+int64_t crand_unif(crand_t* rng, crand_unif_t* dist); // range [low, high]
-stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high); // uniform-distribution
-int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* dist); // range [low, high]
-stc64_uniformf_t stc64_uniformf_new(double lowf, double highf);
-double stc64_uniformf(stc64_t* rng, stc64_uniformf_t* dist); // range [lowf, highf)
-
-stc64_normalf_t stc64_normalf_new(double mean, double stddev); // normal-distribution
-double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist);
+crand_norm_t crand_norm_init(double mean, double stddev); // normal-distribution
+double crand_norm(crand_t* rng, crand_norm_t* dist);
```
## Types
| Name | Type definition | Used to represent... |
|:-------------------|:------------------------------------------|:-----------------------------|
-| `stc64_t` | `struct {uint64_t state[4];}` | The PRNG engine type |
-| `stc64_uniform_t` | `struct {int64_t lower; uint64_t range;}` | Integer uniform distribution |
-| `stc64_uniformf_t` | `struct {double lower, range;}` | Real number uniform distr. |
-| `stc64_normalf_t` | `struct {double mean, stddev;}` | Normal distribution type |
+| `crand_t` | `struct {uint64_t state[4];}` | The PRNG engine type |
+| `crand_unif_t` | `struct {int64_t lower; uint64_t range;}` | Integer uniform distribution |
+| `crand_norm_t` | `struct {double mean, stddev;}` | Normal distribution type |
## Example
```c
#include <time.h>
-#include <stc/crandom.h>
+#include <stc/crand.h>
#include <stc/cstr.h>
// Declare int -> int sorted map. Uses typetag 'i' for ints.
@@ -89,13 +84,13 @@ int main()
// Setup random engine with normal distribution.
uint64_t seed = time(NULL);
- stc64_t rng = stc64_new(seed);
- stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev);
+ crand_t rng = crand_init(seed);
+ crand_norm_t dist = crand_norm_init(Mean, StdDev);
// Create histogram map
csmap_i mhist = csmap_i_init();
c_forrange (N) {
- int index = (int) round( stc64_normalf(&rng, &dist) );
+ int index = (int)round(crand_norm(&rng, &dist));
csmap_i_emplace(&mhist, index, 0).ref->second += 1;
}
diff --git a/docs/cregex_api.md b/docs/cregex_api.md
index 64fb6a2b..9a15a869 100644
--- a/docs/cregex_api.md
+++ b/docs/cregex_api.md
@@ -11,15 +11,17 @@ The API is simple and includes powerful string pattern matches and replace funct
```c
enum {
- /* compile-flags */
- CREG_C_DOTALL = 1<<0, /* dot matches newline too: can be set/overridden by (?s) and (?-s) in RE */
- CREG_C_ICASE = 1<<1, /* ignore case mode: can be set/overridden by (?i) and (?-i) in RE */
- /* match-flags */
- CREG_M_FULLMATCH = 1<<2, /* like start-, end-of-line anchors were in pattern: "^ ... $" */
- CREG_M_NEXT = 1<<3, /* use end of previous match[0] as start of input */
- CREG_M_STARTEND = 1<<4, /* use match[0] as start+end of input */
- /* replace-flags */
- CREG_R_STRIP = 1<<5, /* only keep the replaced matches, strip the rest */
+ // compile-flags
+ CREG_C_DOTALL = 1<<0, // dot matches newline too: can be set/overridden by (?s) and (?-s) in RE
+ CREG_C_ICASE = 1<<1, // ignore case mode: can be set/overridden by (?i) and (?-i) in RE
+
+ // match-flags
+ CREG_M_FULLMATCH = 1<<2, // like start-, end-of-line anchors were in pattern: "^ ... $"
+ CREG_M_NEXT = 1<<3, // use end of previous match[0] as start of input
+ CREG_M_STARTEND = 1<<4, // use match[0] as start+end of input
+
+ // replace-flags
+ CREG_R_STRIP = 1<<5, // only keep the replaced matches, strip the rest
};
cregex cregex_init(void);
@@ -80,11 +82,11 @@ void cregex_drop(cregex* self);
### Compiling a regular expression
```c
cregex re1 = cregex_init();
-int result = cregex_compile(&re1, "[0-9]+", CREG_DEFAULT);
+int result = cregex_compile(&re1, "[0-9]+");
if (result < 0) return result;
const char* url = "(https?://|ftp://|www\\.)([0-9A-Za-z@:%_+~#=-]+\\.)+([a-z][a-z][a-z]?)(/[/0-9A-Za-z\\.@:%_+~#=\\?&-]*)?";
-cregex re2 = cregex_from(url, CREG_DEFAULT);
+cregex re2 = cregex_from(url);
if (re2.error != CREG_OK)
return re2.error;
...
@@ -94,27 +96,28 @@ cregex_drop(&re1);
If an error occurs ```cregex_compile``` returns a negative error code stored in re2.error.
### Getting the first match and making text replacements
+
+[ [Run this code](https://godbolt.org/z/z434TMKfo) ]
```c
-#define i_extern // include external utf8 and cregex functions implementation.
+#define i_extern // include external cstr, utf8, cregex functions implementation.
#include <stc/cregex.h>
-#include <stc/cstr.h>
int main() {
- const char* input = "start date is 2023-03-01, and end date is 2025-12-31.";
+ const char* input = "start date is 2023-03-01, end date 2025-12-31.";
const char* pattern = "\\b(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)\\b";
- cregex re = cregex_from(pattern, CREG_DEFAULT);
+ cregex re = cregex_from(pattern);
// Lets find the first date in the string:
csview match[4]; // full-match, year, month, date.
- if (cregex_find(&re, input, match, CREG_DEFAULT) == CREG_OK)
+ if (cregex_find(&re, input, match) == CREG_OK)
printf("Found date: %.*s\n", c_SV(match[0]));
else
printf("Could not find any date\n");
// Lets change all dates into US date format MM/DD/YYYY:
cstr us_input = cregex_replace(&re, input, "$2/$3/$1");
- printf("US input: %s\n", cstr_str(&us_input));
+ printf("%s\n", cstr_str(&us_input));
// Free allocated data
cstr_drop(&us_input);
@@ -123,11 +126,11 @@ int main() {
```
For a single match you may use the all-in-one function:
```c
-if (cregex_find_pattern(pattern, input, match, CREG_DEFAULT))
+if (cregex_find_pattern(pattern, input, match))
printf("Found date: %.*s\n", c_SV(match[0]));
```
-To compile, use: `gcc first_match.c src/cregex.c src/utf8code.c`.
+To use: `gcc first_match.c src/cregex.c src/utf8code.c`.
In order to use a callback function in the replace call, see `examples/regex_replace.c`.
### Iterate through regex matches, *c_formatch*
@@ -139,7 +142,7 @@ while (cregex_find(&re, input, match, CREG_M_NEXT) == CREG_OK)
c_forrange (k, cregex_captures(&re))
printf("submatch %lld: %.*s\n", k, c_SV(match[k]));
```
-There is also a safe macro which simplifies this:
+There is also a for-loop macro to simplify it:
```c
c_formatch (it, &re, input)
c_forrange (k, cregex_captures(&re))
diff --git a/docs/cset_api.md b/docs/cset_api.md
index 287f7636..026d7462 100644
--- a/docs/cset_api.md
+++ b/docs/cset_api.md
@@ -19,8 +19,6 @@ A **cset** is an associative container that contains a set of unique objects of
#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val
-#define i_hash_functor // advanced, see examples/functor.c for similar usage.
-#define i_eq_functor // advanced, see examples/functor.c for similar usage.
#define i_ssize // default int32_t. If defined, table expand 2x (else 1.5x)
#include <stc/cset.h>
```
@@ -70,47 +68,45 @@ cset_X_value cset_X_value_clone(cset_X_value val);
| Type name | Type definition | Used to represent... |
|:-------------------|:-------------------------------------------------|:----------------------------|
| `cset_X` | `struct { ... }` | The cset type |
-| `cset_X_rawkey` | `i_keyraw` | The raw key type |
-| `cset_X_raw` | `i_keyraw` | The raw value type |
| `cset_X_key` | `i_key` | The key type |
-| `cset_X_value` | `i_key` | The value |
+| `cset_X_value` | `i_key` | The key type (alias) |
+| `cset_X_keyraw` | `i_keyraw` | The raw key type |
+| `cset_X_raw` | `i_keyraw` | The raw key type (alias) |
| `cset_X_result` | `struct { cset_X_value* ref; bool inserted; }` | Result of insert/emplace |
| `cset_X_iter` | `struct { cset_X_value *ref; ... }` | Iterator type |
## Example
```c
#include <stc/cstr.h>
-
+#define i_type Strset
#define i_key_str
#include <stc/cset.h>
int main ()
{
- c_auto (cset_str, fifth)
- {
- c_auto (cset_str, first, second)
- c_auto (cset_str, third, fourth)
- {
- second = c_make(cset_str, {"red", "green", "blue"});
-
- c_forlist (i, const char*, {"orange", "pink", "yellow"})
- cset_str_emplace(&third, *i.ref);
-
- cset_str_emplace(&fourth, "potatoes");
- cset_str_emplace(&fourth, "milk");
- cset_str_emplace(&fourth, "flour");
-
- fifth = cset_str_clone(second);
- c_foreach (i, cset_str, third)
- cset_str_emplace(&fifth, cstr_str(i.ref));
-
- c_foreach (i, cset_str, fourth)
- cset_str_emplace(&fifth, cstr_str(i.ref));
- }
- printf("fifth contains:\n\n");
- c_foreach (i, cset_str, fifth)
- printf("%s\n", cstr_str(i.ref));
- }
+ Strset first, second={0}, third={0}, fourth={0}, fifth;
+
+ first = c_make(Strset, {"red", "green", "blue"});
+ fifth = Strset_clone(second);
+
+ c_forlist (i, const char*, {"orange", "pink", "yellow"})
+ Strset_emplace(&third, *i.ref);
+
+ c_foreach (i, Strset, third)
+ Strset_insert(&fifth, cstr_clone(*i.ref));
+
+ Strset_emplace(&fourth, "potatoes");
+ Strset_emplace(&fourth, "milk");
+ Strset_emplace(&fourth, "flour");
+
+ c_foreach (i, Strset, fourth)
+ Strset_emplace(&fifth, cstr_str(i.ref));
+
+ printf("fifth contains:\n\n");
+ c_foreach (i, Strset, fifth)
+ printf("%s\n", cstr_str(i.ref));
+
+ c_drop(Strset, &first, &second, &third, &fourth, &fifth);
}
```
Output:
diff --git a/docs/csmap_api.md b/docs/csmap_api.md
index 8e5780e3..93faa4f9 100644
--- a/docs/csmap_api.md
+++ b/docs/csmap_api.md
@@ -33,7 +33,6 @@ See the c++ class [std::map](https://en.cppreference.com/w/cpp/container/map) fo
#define i_valto // convertion func i_val* => i_valraw
#define i_tag // alternative typename: csmap_{i_tag}. i_tag defaults to i_val
-#define i_cmp_functor // advanced, see examples/functor.c for similar usage.
#define i_ssize // internal size rep. defaults to int32_t
#include <stc/csmap.h>
```
@@ -92,12 +91,12 @@ csmap_X_raw csmap_X_value_toraw(csmap_X_value* pval);
| Type name | Type definition | Used to represent... |
|:--------------------|:--------------------------------------------------|:-----------------------------|
| `csmap_X` | `struct { ... }` | The csmap type |
-| `csmap_X_rawkey` | `i_keyraw` | The raw key type |
-| `csmap_X_rawmapped` | `i_valraw` | The raw mapped type |
-| `csmap_X_raw` | `struct { i_keyraw first; i_valraw second; }` | i_keyraw+i_valraw type |
| `csmap_X_key` | `i_key` | The key type |
| `csmap_X_mapped` | `i_val` | The mapped type |
-| `csmap_X_value` | `struct { const i_key first; i_val second; }` | The value: key is immutable |
+| `csmap_X_value` | `struct { i_key first; i_val second; }` | The value: key is immutable |
+| `csmap_X_keyraw` | `i_keyraw` | The raw key type |
+| `csmap_X_rmapped` | `i_valraw` | The raw mapped type |
+| `csmap_X_raw` | `struct { i_keyraw first; i_valraw second; }` | i_keyraw+i_valraw type |
| `csmap_X_result` | `struct { csmap_X_value *ref; bool inserted; }` | Result of insert/put/emplace |
| `csmap_X_iter` | `struct { csmap_X_value *ref; ... }` | Iterator type |
@@ -112,27 +111,26 @@ csmap_X_raw csmap_X_value_toraw(csmap_X_value* pval);
int main()
{
// Create a sorted map of three strings (maps to string)
- c_auto (csmap_str, colors) // RAII
- {
- colors = c_make(csmap_str, {
- {"RED", "#FF0000"},
- {"GREEN", "#00FF00"},
- {"BLUE", "#0000FF"}
- });
-
- // Iterate and print keys and values of sorted map
- c_foreach (i, csmap_str, colors) {
- printf("Key:[%s] Value:[%s]\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
- }
-
- // Add two new entries to the sorted map
- csmap_str_emplace(&colors, "BLACK", "#000000");
- csmap_str_emplace(&colors, "WHITE", "#FFFFFF");
-
- // Output values by key
- printf("The HEX of color RED is:[%s]\n", cstr_str(csmap_str_at(&colors, "RED")));
- printf("The HEX of color BLACK is:[%s]\n", cstr_str(csmap_str_at(&colors, "BLACK")));
+ csmap_str colors = c_make(csmap_str, {
+ {"RED", "#FF0000"},
+ {"GREEN", "#00FF00"},
+ {"BLUE", "#0000FF"}
+ });
+
+ // Iterate and print keys and values of sorted map
+ c_foreach (i, csmap_str, colors) {
+ printf("Key:[%s] Value:[%s]\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
}
+
+ // Add two new entries to the sorted map
+ csmap_str_emplace(&colors, "BLACK", "#000000");
+ csmap_str_emplace(&colors, "WHITE", "#FFFFFF");
+
+ // Output values by key
+ printf("The HEX of color RED is:[%s]\n", cstr_str(csmap_str_at(&colors, "RED")));
+ printf("The HEX of color BLACK is:[%s]\n", cstr_str(csmap_str_at(&colors, "BLACK")));
+
+ csmap_str_drop(&colors);
}
```
Output:
@@ -144,37 +142,71 @@ The HEX of color RED is:[#FF0000]
The HEX of color BLACK is:[#000000]
```
+
### Example 2
+Translate a
+[C++ example using *insert* and *emplace*](https://en.cppreference.com/w/cpp/container/map/try_emplace)
+ to STC:
+
+[ [Run this code](https://godbolt.org/z/9d1PP77Pa) ]
+```c
+#include <stc/cstr.h>
+#define i_type strmap
+#define i_key_str
+#define i_val_str
+#include <stc/csmap.h>
+
+static void print_node(const strmap_value* node) {
+ printf("[%s] = %s\n", cstr_str(&node->first), cstr_str(&node->second));
+}
+
+static void print_result(strmap_result result) {
+ printf("%s", result.inserted ? "inserted: " : "ignored: ");
+ print_node(result.ref);
+}
+
+int main()
+{
+ strmap m = {0};
+
+ print_result( strmap_emplace(&m, "a", "a") );
+ print_result( strmap_emplace(&m, "b", "abcd") );
+ print_result( strmap_insert(&m, cstr_from("c"), cstr_with_size(10, 'c') ) );
+ print_result( strmap_emplace(&m, "c", "Won't be inserted") );
+
+ c_foreach (p, strmap, m) { print_node(p.ref); }
+ strmap_drop(&m);
+}
+```
+
+### Example 3
This example uses a csmap with cstr as mapped value.
```c
#include <stc/cstr.h>
+#define i_type IDSMap
#define i_key int
#define i_val_str
-#define i_tag id
#include <stc/csmap.h>
int main()
{
uint32_t col = 0xcc7744ff;
- csmap_id idnames = csmap_id_init();
- c_defer (csmap_id_drop(&idnames))
- {
- c_forlist (i, csmap_id_raw, { {100, "Red"}, {110, "Blue"} })
- csmap_id_emplace(&idnames, c_PAIR(i.ref));
+ IDSMap idnames = c_make(IDSMap, { {100, "Red"}, {110, "Blue"} });
- // put replaces existing mapped value:
- csmap_id_emplace_or_assign(&idnames, 110, "White");
+ // Assign/overwrite an existing mapped value with a const char*
+ IDSMap_emplace_or_assign(&idnames, 110, "White");
- // put a constructed mapped value into map:
- csmap_id_insert_or_assign(&idnames, 120, cstr_from_fmt("#%08x", col));
+ // Insert (or assign) a new cstr
+ IDSMap_insert_or_assign(&idnames, 120, cstr_from_fmt("#%08x", col));
- // emplace adds only when key does not exist:
- csmap_id_emplace(&idnames, 100, "Green");
+ // emplace() adds only when key does not already exist:
+ IDSMap_emplace(&idnames, 100, "Green"); // ignored
- c_foreach (i, csmap_id, idnames)
- printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second));
- }
+ c_foreach (i, IDSMap, idnames)
+ printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second));
+
+ IDSMap_drop(&idnames);
}
```
Output:
@@ -184,7 +216,7 @@ Output:
120: #cc7744ff
```
-### Example 3
+### Example 4
Demonstrate csmap with plain-old-data key type Vec3i and int as mapped type: csmap<Vec3i, int>.
```c
typedef struct { int x, y, z; } Vec3i;
@@ -205,16 +237,17 @@ static int Vec3i_cmp(const Vec3i* a, const Vec3i* b) {
int main()
{
- c_auto (csmap_vi, vecs)
- {
- csmap_vi_insert(&vecs, (Vec3i){100, 0, 0}, 1);
- csmap_vi_insert(&vecs, (Vec3i){0, 100, 0}, 2);
- csmap_vi_insert(&vecs, (Vec3i){0, 0, 100}, 3);
- csmap_vi_insert(&vecs, (Vec3i){100, 100, 100}, 4);
-
- c_foreach (i, csmap_vi, vecs)
- printf("{ %3d, %3d, %3d }: %d\n", i.ref->first.x, i.ref->first.y, i.ref->first.z, i.ref->second);
- }
+ csmap_vi vmap = {0};
+
+ csmap_vi_insert(&vmap, (Vec3i){100, 0, 0}, 1);
+ csmap_vi_insert(&vmap, (Vec3i){0, 100, 0}, 2);
+ csmap_vi_insert(&vmap, (Vec3i){0, 0, 100}, 3);
+ csmap_vi_insert(&vmap, (Vec3i){100, 100, 100}, 4);
+
+ c_forpair (v, n, csmap_vi, vmap)
+ printf("{ %3d, %3d, %3d }: %d\n", _.v->x, _.v->y, _.v->z, *_.n);
+
+ csmap_vi_drop(&vmap)
}
```
Output:
@@ -224,37 +257,3 @@ Output:
{ 100, 0, 0 }: 1
{ 100, 100, 100 }: 4
```
-
-### Example 4
-Inverse: demonstrate csmap with mapped POD type Vec3i: csmap<int, Vec3i>:
-```c
-typedef struct { int x, y, z; } Vec3i;
-
-#define i_key int
-#define i_val Vec3i
-#define i_tag iv
-#include <stc/csmap.h>
-#include <stdio.h>
-
-int main()
-{
- // equivalent to: c_auto (csmap_iv, vecs)
- c_with (csmap_iv vecs = csmap_iv_init(), csmap_iv_drop(&vecs))
- {
- csmap_iv_insert(&vecs, 1, (Vec3i){100, 0, 0});
- csmap_iv_insert(&vecs, 2, (Vec3i){0, 100, 0});
- csmap_iv_insert(&vecs, 3, (Vec3i){0, 0, 100});
- csmap_iv_insert(&vecs, 4, (Vec3i){100, 100, 100});
-
- c_foreach (i, csmap_iv, vecs)
- printf("%d: { %3d, %3d, %3d }\n", i.ref->first, i.ref->second.x, i.ref->second.y, i.ref->second.z);
- }
-}
-```
-Output:
-```c
-1: { 100, 0, 0 }
-2: { 0, 100, 0 }
-3: { 0, 0, 100 }
-4: { 100, 100, 100 }
-```
diff --git a/docs/cspan_api.md b/docs/cspan_api.md
index 1e60a526..10565b0f 100644
--- a/docs/cspan_api.md
+++ b/docs/cspan_api.md
@@ -136,7 +136,7 @@ int main() {
## Example 2
Slicing cspan without and with reducing the rank:
```c
-#include <c11/fmt.h>
+#include <c11/print.h>
#include <stc/cspan.h>
using_cspan3(Span, int); // Shorthand to define Span, Span2, and Span3
@@ -154,7 +154,7 @@ int main()
puts("\niterate span2 flat:");
c_foreach (i, Span2, span2)
- fmt_print(" {}", *i.ref);
+ print(" {}", *i.ref);
puts("");
// slice without reducing rank:
@@ -164,26 +164,23 @@ int main()
c_forrange (i, ss3.shape[0]) {
c_forrange (j, ss3.shape[1]) {
c_forrange (k, ss3.shape[2])
- fmt_print(" {:2}", *cspan_at(&ss3, i, j, k));
- fmt_print(" |");
+ print(" {:2}", *cspan_at(&ss3, i, j, k));
+ print(" |");
}
- puts("");
}
// slice and reduce rank:
Span2 ss2 = cspan_slice(Span2, &span3, {c_ALL}, {3}, {c_ALL});
puts("\niterate ss2 by dimensions:");
c_forrange (i, ss2.shape[0]) {
- c_forrange (j, ss2.shape[1]) {
- fmt_print(" {:2}", *cspan_at(&ss2, i, j));
- fmt_print(" |");
- }
- puts("");
+ c_forrange (j, ss2.shape[1])
+ print(" {:2}", *cspan_at(&ss2, i, j));
+ print(" |");
}
puts("\niterate ss2 flat:");
c_foreach (i, Span2, ss2)
- fmt_print(" {:2}", *i.ref);
+ print(" {:2}", *i.ref);
puts("");
}
```
diff --git a/docs/csset_api.md b/docs/csset_api.md
index 80ee1844..e83ab857 100644
--- a/docs/csset_api.md
+++ b/docs/csset_api.md
@@ -18,7 +18,6 @@ See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) fo
#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy
#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
-#define i_cmp_functor // advanced, see examples/functor.c for similar usage.
#define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_val
#define i_ssize // defaults to int32_t
#include <stc/csset.h>
@@ -69,10 +68,10 @@ csset_X_value csset_X_value_clone(csset_X_value val);
| Type name | Type definition | Used to represent... |
|:-------------------|:--------------------------------------------------|:----------------------------|
| `csset_X` | `struct { ... }` | The csset type |
-| `csset_X_rawkey` | `i_keyraw` | The raw key type |
-| `csset_X_raw` | `i_keyraw` | The raw key type |
| `csset_X_key` | `i_key` | The key type |
-| `csset_X_value` | `i_key ` | The value: key is immutable |
+| `csset_X_value` | `i_key` | The key type (alias) |
+| `csset_X_keyraw` | `i_keyraw` | The raw key type |
+| `csset_X_raw` | `i_keyraw` | The raw key type (alias) |
| `csset_X_result` | `struct { csset_X_value* ref; bool inserted; }` | Result of insert/emplace |
| `csset_X_iter` | `struct { csset_X_value *ref; ... }` | Iterator type |
@@ -80,33 +79,38 @@ csset_X_value csset_X_value_clone(csset_X_value val);
```c
#include <stc/cstr.h>
+#define i_type SSet
#define i_key_str
#include <stc/csset.h>
int main ()
{
- c_auto (csset_str, first, second, third)
- c_auto (csset_str, fourth, fifth)
- {
- second = c_make(csset_str, {"red", "green", "blue"});
-
- c_forlist (i, const char*, {"orange", "pink", "yellow"})
- csset_str_emplace(&third, *i.ref);
-
- csset_str_emplace(&fourth, "potatoes");
- csset_str_emplace(&fourth, "milk");
- csset_str_emplace(&fourth, "flour");
-
- fifth = csset_str_clone(second);
- c_foreach (i, csset_str, third)
- csset_str_emplace(&fifth, cstr_str(i.ref));
- c_foreach (i, csset_str, fourth)
- csset_str_emplace(&fifth, cstr_str(i.ref));
-
- printf("fifth contains:\n\n");
- c_foreach (i, csset_str, fifth)
- printf("%s\n", cstr_str(i.ref));
- }
+ SSet second={0}, third={0}, fourth={0}, fifth={0};
+
+ second = c_make(SSet, {"red", "green", "blue"});
+
+ c_forlist (i, const char*, {"orange", "pink", "yellow"})
+ SSet_emplace(&third, *i.ref);
+
+ SSet_emplace(&fourth, "potatoes");
+ SSet_emplace(&fourth, "milk");
+ SSet_emplace(&fourth, "flour");
+
+ // Copy all to fifth:
+
+ fifth = SSet_clone(second);
+
+ c_foreach (i, SSet, third)
+ SSet_emplace(&fifth, cstr_str(i.ref));
+
+ c_foreach (i, SSet, fourth)
+ SSet_emplace(&fifth, cstr_str(i.ref));
+
+ printf("fifth contains:\n\n");
+ c_foreach (i, SSet, fifth)
+ printf("%s\n", cstr_str(i.ref));
+
+ c_drop(SSet, &second, &third, &fourth, &fifth);
}
```
Output:
diff --git a/docs/cstr_api.md b/docs/cstr_api.md
index 64099675..64ad002c 100644
--- a/docs/cstr_api.md
+++ b/docs/cstr_api.md
@@ -160,7 +160,12 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt
#include <stc/cstr.h>
int main() {
- c_auto (cstr, s0, s1, full_path) {
+ cstr s0, s1, full_path;
+ c_defer(
+ cstr_drop(&s0),
+ cstr_drop(&s1),
+ cstr_drop(&full_path)
+ ){
s0 = cstr_lit("Initialization without using strlen().");
printf("%s\nLength: %" c_ZI "\n\n", cstr_str(&s0), cstr_size(&s0));
diff --git a/docs/csview_api.md b/docs/csview_api.md
index 33e61f0e..ec3bf121 100644
--- a/docs/csview_api.md
+++ b/docs/csview_api.md
@@ -151,14 +151,15 @@ red Apples
int main()
{
- c_auto (cstr, s1) {
- s1 = cstr_lit("hell😀 w😀rld");
- cstr_u8_replace_at(&s1, cstr_find(&s1, "😀rld"), 1, c_sv("ø"));
- printf("%s\n", cstr_str(&s1));
-
- c_foreach (i, cstr, s1)
- printf("%.*s,", c_SV(i.u8.chr));
- }
+ cstr s1 = cstr_lit("hell😀 w😀rld");
+
+ cstr_u8_replace_at(&s1, cstr_find(&s1, "😀rld"), 1, c_sv("ø"));
+ printf("%s\n", cstr_str(&s1));
+
+ c_foreach (i, cstr, s1)
+ printf("%.*s,", c_SV(i.u8.chr));
+
+ cstr_drop(&s1);
}
```
Output:
@@ -178,6 +179,7 @@ void print_split(csview input, const char* sep)
{
c_fortoken_sv (i, input, sep)
printf("[%.*s]\n", c_SV(i.token));
+ puts("");
}
#include <stc/cstr.h>
@@ -197,13 +199,15 @@ cstack_str string_split(csview input, const char* sep)
int main()
{
print_split(c_sv("//This is a//double-slash//separated//string"), "//");
- puts("");
print_split(c_sv("This has no matching separator"), "xx");
+
+ cstack_str s = string_split(c_sv("Split,this,,string,now,"), ",");
+
+ c_foreach (i, cstack_str, s)
+ printf("[%s]\n", cstr_str(i.ref));
puts("");
- c_with (cstack_str s = string_split(c_sv("Split,this,,string,now,"), ","), cstack_str_drop(&s))
- c_foreach (i, cstack_str, s)
- printf("[%s]\n", cstr_str(i.ref));
+ cstack_str_drop(&s);
}
```
Output:
diff --git a/docs/cvec_api.md b/docs/cvec_api.md
index 68e08cb2..5879bc1f 100644
--- a/docs/cvec_api.md
+++ b/docs/cvec_api.md
@@ -119,29 +119,29 @@ cvec_X_value cvec_X_value_clone(cvec_X_value val);
int main()
{
// Create a vector containing integers
- c_auto (cvec_int, vec)
- {
- // Add two integers to vector
- cvec_int_push(&vec, 25);
- cvec_int_push(&vec, 13);
-
- // Append a set of numbers
- c_forlist (i, int, {7, 5, 16, 8})
- cvec_int_push(&vec, *i.ref);
-
- printf("initial:");
- c_foreach (k, cvec_int, vec) {
- printf(" %d", *k.ref);
- }
-
- // Sort the vector
- cvec_int_sort(&vec);
-
- printf("\nsorted:");
- c_foreach (k, cvec_int, vec) {
- printf(" %d", *k.ref);
- }
+ cvec_int vec = {0};
+
+ // Add two integers to vector
+ cvec_int_push(&vec, 25);
+ cvec_int_push(&vec, 13);
+
+ // Append a set of numbers
+ c_forlist (i, int, {7, 5, 16, 8})
+ cvec_int_push(&vec, *i.ref);
+
+ printf("initial:");
+ c_foreach (k, cvec_int, vec) {
+ printf(" %d", *k.ref);
+ }
+
+ // Sort the vector
+ cvec_int_sort(&vec);
+
+ printf("\nsorted:");
+ c_foreach (k, cvec_int, vec) {
+ printf(" %d", *k.ref);
}
+ cvec_int_drop(&vec);
}
```
Output:
@@ -212,7 +212,7 @@ User User_clone(User user) {
#include <stc/cvec.h>
int main(void) {
- UVec vec = UVec_init();
+ UVec vec = {0};
UVec_push(&vec, (User){cstr_lit("mary"), 0});
UVec_push(&vec, (User){cstr_lit("joe"), 1});
UVec_push(&vec, (User){cstr_lit("admin"), 2});
diff --git a/docs/pics/containers.jpg b/docs/pics/containers.jpg
index cc56a141..2eddd82b 100644
--- a/docs/pics/containers.jpg
+++ b/docs/pics/containers.jpg
Binary files differ