diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/carc_api.md | 96 | ||||
| -rw-r--r-- | docs/cbox_api.md | 11 | ||||
| -rw-r--r-- | docs/ccommon_api.md | 525 | ||||
| -rw-r--r-- | docs/clist_api.md | 27 | ||||
| -rw-r--r-- | docs/cmap_api.md | 201 | ||||
| -rw-r--r-- | docs/coption_api.md | 2 | ||||
| -rw-r--r-- | docs/cpque_api.md | 43 | ||||
| -rw-r--r-- | docs/crandom_api.md | 45 | ||||
| -rw-r--r-- | docs/cregex_api.md | 43 | ||||
| -rw-r--r-- | docs/cset_api.md | 58 | ||||
| -rw-r--r-- | docs/csmap_api.md | 169 | ||||
| -rw-r--r-- | docs/cspan_api.md | 19 | ||||
| -rw-r--r-- | docs/csset_api.md | 56 | ||||
| -rw-r--r-- | docs/cstr_api.md | 7 | ||||
| -rw-r--r-- | docs/csview_api.md | 28 | ||||
| -rw-r--r-- | docs/cvec_api.md | 46 | ||||
| -rw-r--r-- | docs/pics/containers.jpg | bin | 96093 -> 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  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 Binary files differindex cc56a141..2eddd82b 100644 --- a/docs/pics/containers.jpg +++ b/docs/pics/containers.jpg |
