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.md493
-rw-r--r--docs/clist_api.md23
-rw-r--r--docs/cmap_api.md195
-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/cset_api.md52
-rw-r--r--docs/csmap_api.md110
-rw-r--r--docs/cspan_api.md19
-rw-r--r--docs/csset_api.md50
-rw-r--r--docs/cstr_api.md7
-rw-r--r--docs/csview_api.md28
-rw-r--r--docs/cvec_api.md46
15 files changed, 652 insertions, 568 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 64daad42..90191e40 100644
--- a/docs/ccommon_api.md
+++ b/docs/ccommon_api.md
@@ -2,106 +2,17 @@
The following macros are recommended to use, and they safe/have no side-effects.
-## 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.
-
-| 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
+---
+## Ranged for-loops
-### c_foreach, c_foreach_r, c_forpair
+### c_foreach, c_foreach_rv, c_forpair
-| Usage | Description |
-|:-----------------------------------------|:----------------------------------------|
-| `c_foreach (it, ctype, container)` | Iteratate all elements |
-| `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) |
-| `c_foreach_r (it, ctype, container)` | Iteratate in reverse (cstack,cvec,cdeq) |
-| `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
@@ -130,6 +41,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.
@@ -151,46 +81,55 @@ 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_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_count(it)` | Increment current and return value |
-| `c_flt_last(it)` | Get value of last count/skip/take |
+| 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 |
```c
// Example:
-#include <stc/algo/crange.h>
-#include <stc/algo/filter.h>
+#include <stc/calgo.h>
#include <stdio.h>
bool isPrime(long long i) {
@@ -199,58 +138,32 @@ bool isPrime(long long i) {
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
-
-// 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_drop
-- *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
@@ -259,26 +172,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;
@@ -297,39 +205,238 @@ 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
+### 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
+#include <stc/cstr.h>
+
+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
+Memory allocator wrappers that uses signed sizes.
+
+### c_arraylen
+Return number of elements in an array. array must not be a pointer!
+```c
+int array[] = {1, 2, 3, 4};
+intptr_t n = c_arraylen(array);
+```
+
+### c_swap, c_const_cast
```c
// Safe macro for swapping internals of two objects of same type:
c_swap(cmap_int, &map1, &map2);
-// Drop multiple containers of same type:
-c_drop(cvec_i, &vec1, &vec2, &vec3);
+// 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!
```
-### General predefined template parameter functions
-```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
+### 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
+```
-### c_malloc, c_calloc, c_realloc, c_free: customizable allocators
-Memory allocator wrappers that uses signed sizes.
+---
+## 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:
+```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_suspended(ctx)` | Is coroutine in suspended state? |
+| `bool` | `cco_alive(ctx)` | Is coroutine still alive? |
+| `void` | `cco_begin(ctx)` | Begin coroutine block |
+| `rettype` | `cco_end(retval)` | End coroutine block with return value |
+| `rettype` | `cco_end()` | End coroutine block with (void) |
+| `rettype` | `cco_yield(retval)` | Return a value and suspend execution |
+| `rettype` | `cco_yield(corocall2, ctx2, retval)` | Yield from another coroutine and return val |
+| `rettype` | `cco_yield(corocall2, ctx2)` | Yield from another coroutine (void) |
+| | 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_arraylen
-Return number of elements in an array. array must not be a pointer!
```c
-int array[] = {1, 2, 3, 4};
-intptr_t n = c_arraylen(array);
+// `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** 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 be6949ec..a1dbe105 100644
--- a/docs/clist_api.md
+++ b/docs/clist_api.md
@@ -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..8749bd09 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.
@@ -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/cset_api.md b/docs/cset_api.md
index 287f7636..db9fb802 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>
```
@@ -80,37 +78,35 @@ cset_X_value cset_X_value_clone(cset_X_value val);
## 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..0eff8c26 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>
```
@@ -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:
@@ -149,32 +147,29 @@ 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:
@@ -205,16 +200,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:
@@ -238,17 +234,17 @@ typedef struct { int x, y, z; } Vec3i;
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);
- }
+ csmap_iv imap = {0};
+
+ csmap_iv_insert(&imap, 1, (Vec3i){100, 0, 0});
+ csmap_iv_insert(&imap, 2, (Vec3i){0, 100, 0});
+ csmap_iv_insert(&imap, 3, (Vec3i){0, 0, 100});
+ csmap_iv_insert(&imap, 4, (Vec3i){100, 100, 100});
+
+ c_forpair (n, v, csmap_iv, imap)
+ printf("%d: { %3d, %3d, %3d }\n", *_.n, _.v->x, _.v->y, _.v->z);
+
+ csmap_iv_drop(&imap);
}
```
Output:
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..1869327c 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>
@@ -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});