summaryrefslogtreecommitdiffhomepage
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/carc_api.md43
-rw-r--r--docs/cbox_api.md58
-rw-r--r--docs/ccommon_api.md141
-rw-r--r--docs/cdeq_api.md85
-rw-r--r--docs/clist_api.md82
-rw-r--r--docs/cmap_api.md26
-rw-r--r--docs/cpque_api.md34
-rw-r--r--docs/cqueue_api.md40
-rw-r--r--docs/crandom_api.md3
-rw-r--r--docs/cregex_api.md40
-rw-r--r--docs/cset_api.md9
-rw-r--r--docs/csmap_api.md20
-rw-r--r--docs/cspan_api.md78
-rw-r--r--docs/csset_api.md8
-rw-r--r--docs/cstack_api.md42
-rw-r--r--docs/cstr_api.md7
-rw-r--r--docs/csview_api.md34
-rw-r--r--docs/cvec_api.md84
18 files changed, 455 insertions, 379 deletions
diff --git a/docs/carc_api.md b/docs/carc_api.md
index 48b64ff0..8b7b67a1 100644
--- a/docs/carc_api.md
+++ b/docs/carc_api.md
@@ -6,14 +6,14 @@ deallocated when the last remaining **carc** owning the object is destroyed with
The object is destroyed using *carc_X_drop()*. A **carc** may also own no objects, in which
case it is called empty. The *carc_X_cmp()*, *carc_X_drop()* methods are defined based on
-the `i_cmp` and `i_valdrop` macros specified. Use *carc_X_clone(p)* when sharing ownership of
+the `i_cmp` and `i_keydrop` macros specified. Use *carc_X_clone(p)* when sharing ownership of
the pointed-to object.
All **carc** functions can be called by multiple threads on different instances of **carc** without
additional synchronization even if these instances are copies and share ownership of the same object.
**carc** uses thread-safe atomic reference counting, through the *carc_X_clone()* and *carc_X_drop()* methods.
-When declaring a container with shared pointers, define `i_valboxed` with the carc type, see example.
+When declaring a container with shared pointers, define `i_keyboxed` with the carc type, see example.
See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr) for a functional reference, or Rust [std::sync::Arc](https://doc.rust-lang.org/std/sync/struct.Arc.html) / [std::rc::Rc](https://doc.rust-lang.org/std/rc/struct.Rc.html).
@@ -21,14 +21,14 @@ See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory
```c
#define i_type // full typename of the carc
-#define i_val // value: REQUIRED
+#define i_key // element type: REQUIRED
-#define i_valraw // convertion "raw" type - defaults to i_val
-#define i_valto // convertion func i_val* => i_valraw: REQUIRED IF i_valraw defined.
-#define i_valfrom // convertion func i_valraw => i_val
+#define i_keyraw // convertion "raw" type - defaults to i_key
+#define i_keyto // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined.
+#define i_keyfrom // convertion func i_keyraw => i_key
#define i_opt c_no_atomic // Non-atomic reference counting, like Rust Rc.
-#define i_tag // alternative typename: carc_{i_tag}. i_tag defaults to i_val
+#define i_tag // alternative typename: carc_{i_tag}. i_tag defaults to i_key
#include <stc/carc.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
@@ -36,9 +36,9 @@ See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory
## Methods
```c
carc_X carc_X_init(); // empty shared pointer
-carc_X carc_X_from(i_valraw raw); // create an carc from raw type (available if i_valraw defined by user).
-carc_X carc_X_from_ptr(i_val* p); // create an carc from raw pointer. Takes ownership of p.
-carc_X carc_X_make(i_val val); // create an carc from constructed val object. Faster than from_ptr().
+carc_X carc_X_from(i_keyraw raw); // create an carc from raw type (available if i_keyraw defined by user).
+carc_X carc_X_from_ptr(i_key* p); // create an carc from raw pointer. Takes ownership of p.
+carc_X carc_X_make(i_key key); // create an carc from constructed key object. Faster than from_ptr().
carc_X carc_X_clone(carc_X other); // return other with increased use count
carc_X carc_X_move(carc_X* self); // transfer ownership to receiver; self becomes NULL
@@ -49,7 +49,7 @@ void carc_X_drop(carc_X* self); // destruct (decr
long carc_X_use_count(const carc_X* self);
void carc_X_reset(carc_X* self);
-void carc_X_reset_to(carc_X* self, i_val* p); // assign new carc from ptr. Takes ownership of p.
+void carc_X_reset_to(carc_X* self, i_key* p); // assign new carc from ptr. Takes ownership of p.
uint64_t carc_X_hash(const carc_X* x); // hash value
int carc_X_cmp(const carc_X* x, const carc_X* y); // compares pointer addresses if no `i_cmp` is specified.
@@ -58,19 +58,19 @@ bool carc_X_eq(const carc_X* x, const carc_X* y); // carc_X_cmp() =
// functions on pointed to objects.
-uint64_t carc_X_value_hash(const i_val* x);
-int carc_X_value_cmp(const i_val* x, const i_val* y);
-bool carc_X_value_eq(const i_val* x, const i_val* y);
+uint64_t carc_X_value_hash(const i_key* x);
+int carc_X_value_cmp(const i_key* x, const i_key* y);
+bool carc_X_value_eq(const i_key* x, const i_key* y);
```
## Types and constants
| Type name | Type definition | Used to represent... |
|:------------------|:--------------------------------------------------|:-----------------------|
-| `carc_NULL` | `{NULL, NULL}` | Init nullptr const |
+| `carc_null` | `{0}` | Init nullptr const |
| `carc_X` | `struct { carc_X_value* get; long* use_count; }` | The carc type |
-| `carc_X_value` | `i_val` | The carc element type |
-| `carc_X_raw` | `i_valraw` | Convertion type |
+| `carc_X_value` | `i_key` | The carc element type |
+| `carc_X_raw` | `i_keyraw` | Convertion type |
## Example
@@ -78,6 +78,7 @@ bool carc_X_value_eq(const i_val* x, const i_val* y);
// Create two stacks with carcs to maps.
// Demonstrate sharing and cloning of maps.
// Show elements dropped.
+#define i_implement
#include <stc/cstr.h>
#define i_type Map
@@ -88,15 +89,15 @@ bool carc_X_value_eq(const i_val* x, const i_val* y);
#include <stc/csmap.h>
#define i_type Arc // (atomic) ref. counted pointer
-#define i_val Map
-#define i_valdrop(p) (printf("drop Arc:\n"), Map_drop(p))
+#define i_key Map
+#define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p))
#include <stc/carc.h>
#define i_type Stack
-#define i_valboxed Arc // Note: use i_valboxed for carc or cbox value types
+#define i_keyboxed Arc // Note: use i_keyboxed for carc or cbox value types
#include <stc/cstack.h>
-int main()
+int main(void)
{
Stack s1 = {0}, s2 = {0};
Map *map;
diff --git a/docs/cbox_api.md b/docs/cbox_api.md
index ca4d90da..b6c76d2f 100644
--- a/docs/cbox_api.md
+++ b/docs/cbox_api.md
@@ -2,11 +2,11 @@
**cbox** is a smart pointer to a heap allocated value of type X. A **cbox** can
be empty. The *cbox_X_cmp()*, *cbox_X_drop()* methods are defined based on the `i_cmp`
-and `i_valdrop` macros specified. Use *cbox_X_clone(p)* to make a deep copy, which uses the
-`i_valclone` macro if defined.
+and `i_keydrop` macros specified. Use *cbox_X_clone(p)* to make a deep copy, which uses the
+`i_keyclone` macro if defined.
-When declaring a container of **cbox** values, define `i_valboxed` with the
-cbox type instead of defining `i_val`. This will auto-set `i_valdrop`, `i_valclone`, and `i_cmp` using
+When declaring a container of **cbox** values, define `i_keyboxed` with the
+cbox type instead of defining `i_key`. This will auto-set `i_keydrop`, `i_keyclone`, and `i_cmp` using
functions defined by the specified **cbox**.
See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr) for a functional reference, or Rust [std::boxed::Box](https://doc.rust-lang.org/std/boxed/struct.Box.html)
@@ -15,29 +15,29 @@ See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory
```c
#define i_type // full typename of the cbox
-#define i_val // value: REQUIRED
-#define i_cmp // three-way compare two i_val* : REQUIRED IF i_val is a non-integral type
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED if i_valdrop is defined, unless 'i_opt c_no_clone' is defined.
+#define i_key // element type: REQUIRED
+#define i_cmp // three-way compare two i_key* : REQUIRED IF i_key is a non-integral type
+#define i_keydrop // destroy element func - defaults to empty destruct
+#define i_keyclone // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined.
-#define i_valraw // convertion type (lookup): default to {i_val}
-#define i_valto // convertion func i_val* => i_valraw: REQUIRED IF i_valraw defined.
-#define i_valfrom // from-raw func.
+#define i_keyraw // convertion type (lookup): default to {i_key}
+#define i_keyto // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined.
+#define i_keyfrom // from-raw func.
-#define i_valclass // alt. to i_val: REQUIRES that {i_val}_clone, {i_val}_drop, {i_valraw}_cmp exist.
-#define i_tag // alternative typename: cbox_{i_tag}. i_tag defaults to i_val
+#define i_keyclass // alt. to i_key: REQUIRES that {i_key}_clone, {i_key}_drop, {i_keyraw}_cmp exist.
+#define i_tag // alternative typename: cbox_{i_tag}. i_tag defaults to i_key
#include <stc/cbox.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
-Define `i_opt` with `c_no_cmp` if comparison between i_val's is not needed/available. Will then
+Define `i_opt` with `c_no_cmp` if comparison between i_key's is not needed/available. Will then
compare the pointer addresses when used. Additionally, `c_no_clone` or `i_is_fwd` may be defined.
## Methods
```c
cbox_X cbox_X_init(); // return an empty cbox
-cbox_X cbox_X_from(i_valraw raw); // create a cbox from raw type. Avail if i_valraw user defined.
-cbox_X cbox_X_from_ptr(i_val* ptr); // create a cbox from a pointer. Takes ownership of ptr.
-cbox_X cbox_X_make(i_val val); // create a cbox from unowned val object.
+cbox_X cbox_X_from(i_keyraw raw); // create a cbox from raw type. Avail if i_keyraw user defined.
+cbox_X cbox_X_from_ptr(i_key* ptr); // create a cbox from a pointer. Takes ownership of ptr.
+cbox_X cbox_X_make(i_key val); // create a cbox from unowned val object.
cbox_X cbox_X_clone(cbox_X other); // return deep copied clone
cbox_X cbox_X_move(cbox_X* self); // transfer ownership to receiving cbox returned. self becomes NULL.
@@ -46,7 +46,7 @@ void cbox_X_assign(cbox_X* self, cbox_X* moved); // transfer owners
void cbox_X_drop(cbox_X* self); // destruct the contained object and free its heap memory.
void cbox_X_reset(cbox_X* self);
-void cbox_X_reset_to(cbox_X* self, i_val* p); // assign new cbox from ptr. Takes ownership of p.
+void cbox_X_reset_to(cbox_X* self, i_key* p); // assign new cbox from ptr. Takes ownership of p.
uint64_t cbox_X_hash(const cbox_X* x); // hash value
int cbox_X_cmp(const cbox_X* x, const cbox_X* y); // compares pointer addresses if no `i_cmp` is specified.
@@ -55,18 +55,18 @@ bool cbox_X_eq(const cbox_X* x, const cbox_X* y); // cbox_X_cmp() ==
// functions on pointed to objects.
-uint64_t cbox_X_value_hash(const i_val* x);
-int cbox_X_value_cmp(const i_val* x, const i_val* y);
-bool cbox_X_value_eq(const i_val* x, const i_val* y);
+uint64_t cbox_X_value_hash(const i_key* x);
+int cbox_X_value_cmp(const i_key* x, const i_key* y);
+bool cbox_X_value_eq(const i_key* x, const i_key* y);
```
## Types and constants
| Type name | Type definition | Used to represent... |
|:-------------------|:--------------------------------|:------------------------|
-| `cbox_NULL` | `{NULL}` | Init nullptr const |
+| `cbox_null` | `{0}` | Init nullptr const |
| `cbox_X` | `struct { cbox_X_value* get; }` | The cbox type |
-| `cbox_X_value` | `i_val` | The cbox element type |
+| `cbox_X_value` | `i_key` | The cbox element type |
## Example
@@ -77,9 +77,9 @@ void int_drop(int* x) {
}
#define i_type IBox
-#define i_val int
-#define i_valdrop int_drop // optional func, just to display elements destroyed
-#define i_valclone(x) x // must specified when i_valdrop is defined.
+#define i_key int
+#define i_keydrop int_drop // optional func, just to display elements destroyed
+#define i_keyclone(x) x // must specified when i_keydrop is defined.
#include <stc/cbox.h>
#define i_type ISet
@@ -87,12 +87,12 @@ void int_drop(int* x) {
#include <stc/csset.h> // ISet : std::set<std::unique_ptr<int>>
#define i_type IVec
-#define i_valboxed IBox // NB: use i_valboxed instead of i_val
+#define i_keyboxed IBox // NB: use i_keyboxed instead of i_key
#include <stc/cvec.h> // IVec : std::vector<std::unique_ptr<int>>
-int main()
+int main(void)
{
- IVec vec = c_make(Vec, {2021, 2012, 2022, 2015});
+ IVec vec = c_init(Vec, {2021, 2012, 2022, 2015});
ISet set = {0};
c_defer(
IVec_drop(&vec),
diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md
index 7a3c3196..e053f743 100644
--- a/docs/ccommon_api.md
+++ b/docs/ccommon_api.md
@@ -18,7 +18,7 @@
#define i_tag ii
#include <stc/csmap.h>
...
-csmap_ii map = c_make(csmap_ii, { {23,1}, {3,2}, {7,3}, {5,4}, {12,5} });
+csmap_ii map = c_init(csmap_ii, { {23,1}, {3,2}, {7,3}, {5,4}, {12,5} });
c_foreach (i, csmap_ii, map)
printf(" %d", i.ref->first);
@@ -40,7 +40,7 @@ c_forpair (id, count, csmap_ii, map)
```
### 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.
+Iterate compound literal array elements. Additional to `i.ref`, you can access `i.size` and `i.index` for the input list/element.
```c
// apply multiple push_backs
c_forlist (i, int, {1, 2, 3})
@@ -82,7 +82,6 @@ c_forrange (i, 30, 0, -5) printf(" %lld", i);
### 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
@@ -100,7 +99,8 @@ c_forfilter (i, crange, r1, isPrime(*i.ref))
// 2. The first 11 primes:
printf("2");
-c_forfilter (i, crange, crange_obj(3, INT64_MAX, 2),
+crange range = crange_make(3, INT64_MAX, 2);
+c_forfilter (i, crange, range,
isPrime(*i.ref) &&
c_flt_take(10)
){
@@ -137,7 +137,7 @@ bool isPrime(long long i) {
return true;
}
-int main() {
+int main(void) {
// 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, ...
@@ -158,11 +158,11 @@ Note that `c_flt_take()` and `c_flt_takewhile()` breaks the loop on false.
---
## Generic algorithms
-### c_make, c_drop
+### c_init, c_drop
Make any container from an initializer list:
```c
-#define i_val_str // owned cstr string value type
+#define i_key_str // owned cstr string value type
#include <stc/cset.h>
#define i_key int
@@ -170,11 +170,10 @@ Make any container from an initializer list:
#include <stc/cmap.h>
...
// 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);
+cset_str myset = c_init(cset_str, {"This", "is", "the", "story"});
int x = 7, y = 8;
-cmap_int mymap = c_make(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} });
+cmap_int mymap = c_init(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} });
```
Drop multiple containers of the same type:
```c
@@ -204,22 +203,40 @@ if (it.ref) cmap_str_erase_at(&map, it);
c_erase_if(i, csmap_str, map, cstr_contains(i.ref, "hello"));
```
-### csort - two times faster qsort
+### sort_n_ - two times faster qsort
-When very fast array sorting is required, **csort** is about twice as fast as *qsort()*, and often simpler to use.
+The **sort_n**, **sort_ij** algorithm 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
-#define i_val int
-#include <stc/algo/csort.h>
+#define i_key int
+#include <stc/algo/sort.h>
+#include <stdio.h>
-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));
+int main(void) {
+ int nums[] = {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4};
+ intarray_sort_n(nums, c_arraylen(nums));
+ c_forrange (i, c_arraylen(arr)) printf(" %d", arr[i]);
}
```
+Containers with random access may also be sorted. Even sorting cdeq/cqueue (with ring buffer) is
+possible and very fast. Note that `i_more` must be defined to retain specified template parameters for use by sort:
+```c
+#define i_type MyDeq
+#define i_key int
+#define i_more
+#include <stc/cdeq.h> // deque
+#include <stc/algo/sort.h>
+#include <stdio.h>
+int main(void) {
+ MyDeq deq = c_init(MyDeq, {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4});
+ MyDeq_sort_n(&deq, MyDeq_size(&deq));
+ c_foreach (i, MyDeq, deq) printf(" %d", *i.ref);
+ MyDeq_drop(&deq);
+}
+```
### c_new, c_delete
@@ -256,7 +273,7 @@ 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`
+**crawstr** - Non-owned `const char*` "class" element type: `#define i_keyclass crawstr`
```c
typedef const char* crawstr;
int crawstr_cmp(const crawstr* x, const crawstr* y);
@@ -295,6 +312,7 @@ 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>
+#include <stdio.h>
struct triples {
int n; // input: max number of triples to be generated.
@@ -302,21 +320,23 @@ struct triples {
int cco_state; // required member
};
-bool triples_next(struct triples* i) { // coroutine
- cco_begin(i);
+int triples(struct triples* i) { // coroutine
+ cco_routine(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_yield();
+ if (--i->n == 0)
+ cco_return;
}
}
}
}
- cco_final: // required label
+ cco_cleanup:
puts("done");
- cco_end(false);
+ }
+ return 0;
}
int gcd(int a, int b) { // greatest common denominator
@@ -328,12 +348,12 @@ int gcd(int a, int b) { // greatest common denominator
return a;
}
-int main()
+int main(void)
{
struct triples t = {.n=INT32_MAX};
int n = 0;
- while (triples_next(&t)) {
+ while (triples(&t)) {
// Skip triples with GCD(a,b) > 1
if (gcd(t.a, t.b) > 1)
continue;
@@ -347,25 +367,54 @@ int main()
}
```
### 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.
+To resume the coroutine from where it was suspended with *cco_yield()*: call the coroutine again.
+
+**Note**: *cco_yield()* / *cco_await()* may not be called inside a `switch` statement from a
+cco_routine scope; Use `if-else-if` constructs instead.
| | 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) |
+| | Function / 'keywords': | |
+|`cco_result` | Enum `CCO_DONE=0`, `CCO_YIELD`, `CCO_AWAIT` | Recommended return values in coroutines |
+| | Function / 'keywords': | |
+| | `cco_cleanup:` | Label for cleanup position in coroutine |
+| `bool` | `cco_done(co)` | Is coroutine done? |
+| | `cco_routine(co) { }` | The coroutine scope |
+| | `cco_yield();` | Yield/suspend execution (return CCO_YIELD)|
+| | `cco_yield_v();` | Yield/suspend execution (return void) |
+| | `cco_yield_v(ret);` | Yield/suspend execution (return ret) |
+| | `cco_yield_final();` | Yield final time, enables cleanup-state |
+| | `cco_yield_final(ret);` | Yield a final value (e.g. CCO_ERROR) |
+| | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)|
+| | `cco_await_v(condition);` | Suspend until condition is true (return void) |
+| | `cco_await_v(condition, ret);` | Suspend until condition is true (return ret)|
+| | `cco_await_on(cocall);` | Await on sub-coroutine to finish (return its ret) |
+| | `cco_return;` | Return from coroutine (inside cco_routine) |
+| | `cco_closure(Closure, ...);` | Define a coroutine closure struct (optional) |
+| | Semaphores: | |
+| | `cco_sem` | Semaphore type |
+| `cco_sem` | `cco_sem_from(long value)` | Create semaphore |
+| | `cco_sem_set(sem, long value)` | Set semaphore value |
+| | `cco_sem_await(sem)` | Await for the semaphore count > 0 |
+| | `cco_sem_await(sem, ret)` | Await with ret on the semaphore |
+| | `cco_sem_release(sem)` | Signal the semaphore (count += 1) |
+| | Timers: | |
+| | `cco_timer` | Timer type |
+| | `cco_timer_await(tm, double sec)` | Await secs for timer to expire (usec prec.)|
+| | `cco_timer_await(tm, double sec, ret)`| Await secs for timer with ret value |
+| | `cco_timer_start(tm, double sec)` | Start timer for secs duration |
+| | `cco_timer_restart(tm)` | Restart timer with same duration |
+| `bool` | `cco_timer_expired(tm)` | Return true if timer is expired |
+| `double` | `cco_timer_elapsed(tm)` | Return seconds elapsed |
+| `double` | `cco_timer_remaining(tm)` | Return seconds remaining |
+| | From caller side: | |
+| `void` | `cco_stop(co)` | Next call of coroutine finalizes |
+| `void` | `cco_reset(co)` | Reset state to initial (for reuse) |
+| `void` | `cco_block_on(cocall) { }` | Run blocking until cocall is finished |
+| `void` | `cco_block_on(cocall, int *result) { }`| Run blocking until cocall is finished |
+| | Time functions: | |
+| `double` | `cco_time(void)` | Return secs with usec prec. since Epoch |
+| | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) |
---
## RAII scope macros
@@ -384,7 +433,10 @@ The **checkauto** utility described below, ensures that the `c_auto*` macros are
| `continue` | Exit a defer-block without resource leak |
```c
+#include <stc/algo/raii.h> // or <stc/calgo.h>
+...
// `c_defer` executes the expression(s) when leaving scope.
+// Note: does not require inclusion of "raii.h".
cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world");
c_defer (cstr_drop(&s1), cstr_drop(&s2))
{
@@ -431,9 +483,10 @@ return ok;
**Example 2**: Load each line of a text file into a vector of strings:
```c
#include <errno.h>
+#define i_implement
#include <stc/cstr.h>
-#define i_val_str
+#define i_key_str
#include <stc/cvec.h>
// receiver should check errno variable
@@ -447,7 +500,7 @@ cvec_str readFile(const char* name)
return vec;
}
-int main()
+int main(void)
{
c_with (cvec_str vec = readFile(__FILE__), cvec_str_drop(&vec))
c_foreach (i, cvec_str, vec)
diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md
index fc11fe66..c6de6cd6 100644
--- a/docs/cdeq_api.md
+++ b/docs/cdeq_api.md
@@ -1,7 +1,9 @@
# STC [cdeq](../include/stc/cdeq.h): Double Ended Queue
![Deque](pics/deque.jpg)
-A **cdeq** is an indexed sequence container that allows fast insertion and deletion at both its beginning and its end. Note that this container is implemented similar to a vector, but has the same performance profile for both *push_back()* and *push_front()* as *cdeq_X_push_back()*. Iterators may be invalidated after push-operations.
+A **cdeq** is an indexed sequence container that allows fast insertion and deletion at both
+its beginning and its end, but has also fast random access to elements. The container is
+implemented as a circular dynamic buffer. Iterators may be invalidated after push-operations.
See the c++ class [std::deque](https://en.cppreference.com/w/cpp/container/deque) for a functional description.
@@ -9,16 +11,16 @@ See the c++ class [std::deque](https://en.cppreference.com/w/cpp/container/deque
```c
#define i_type // full typename of the container
-#define i_val // value: REQUIRED
-#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop defined
+#define i_key // value: REQUIRED
+#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
+#define i_keydrop // destroy value func - defaults to empty destruct
+#define i_keyclone // REQUIRED IF i_keydrop defined
-#define i_valraw // convertion "raw" type - defaults to i_val
-#define i_valfrom // convertion func i_valraw => i_val
-#define i_valto // convertion func i_val* => i_valraw
+#define i_keyraw // convertion "raw" type - defaults to i_key
+#define i_keyfrom // convertion func i_keyraw => i_key
+#define i_keyto // convertion func i_key* => i_keyraw
-#define i_tag // alternative typename: cdeq_{i_tag}. i_tag defaults to i_val
+#define i_tag // alternative typename: cdeq_{i_tag}. i_tag defaults to i_key
#include <stc/cdeq.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
@@ -32,81 +34,74 @@ cdeq_X cdeq_X_clone(cdeq_X deq);
void cdeq_X_clear(cdeq_X* self);
void cdeq_X_copy(cdeq_X* self, const cdeq_X* other);
-cdeq_X_iter cdeq_X_copy_range(cdeq_X* self, i_val* pos, const i_val* p1, const i_val* p2);
bool cdeq_X_reserve(cdeq_X* self, intptr_t cap);
void cdeq_X_shrink_to_fit(cdeq_X* self);
-void cdeq_X_drop(cdeq_X* self); // destructor
+void cdeq_X_drop(cdeq_X* self); // destructor
bool cdeq_X_empty(const cdeq_X* self);
intptr_t cdeq_X_size(const cdeq_X* self);
intptr_t cdeq_X_capacity(const cdeq_X* self);
const cdeq_X_value* cdeq_X_at(const cdeq_X* self, intptr_t idx);
-const cdeq_X_value* cdeq_X_get(const cdeq_X* self, i_valraw raw); // return NULL if not found
-cdeq_X_value* cdeq_X_get_mut(cdeq_X* self, i_valraw raw); // mutable get
-cdeq_X_iter cdeq_X_find(const cdeq_X* self, i_valraw raw);
-cdeq_X_iter cdeq_X_find_in(cdeq_X_iter i1, cdeq_X_iter i2, i_valraw raw); // return cvec_X_end() if not found
+cdeq_X_value* cdeq_X_at_mut(cdeq_X* self, intptr_t idx);
+const cdeq_X_value* cdeq_X_get(const cdeq_X* self, i_keyraw raw); // return NULL if not found
+cdeq_X_value* cdeq_X_get_mut(cdeq_X* self, i_keyraw raw); // mutable get
+cdeq_X_iter cdeq_X_find(const cdeq_X* self, i_keyraw raw);
+cdeq_X_iter cdeq_X_find_in(cdeq_X_iter i1, cdeq_X_iter i2, i_keyraw raw); // return cvec_X_end() if not found
cdeq_X_value* cdeq_X_front(const cdeq_X* self);
cdeq_X_value* cdeq_X_back(const cdeq_X* self);
-cdeq_X_value* cdeq_X_push_front(cdeq_X* self, i_val value);
-cdeq_X_value* cdeq_X_emplace_front(cdeq_X* self, i_valraw raw);
+cdeq_X_value* cdeq_X_push_front(cdeq_X* self, i_key value);
+cdeq_X_value* cdeq_X_emplace_front(cdeq_X* self, i_keyraw raw);
void cdeq_X_pop_front(cdeq_X* self);
-cdeq_X_value* cdeq_X_push_back(cdeq_X* self, i_val value);
-cdeq_X_value* cdeq_X_push(cdeq_X* self, i_val value); // alias for push_back()
-cdeq_X_value* cdeq_X_emplace_back(cdeq_X* self, i_valraw raw);
-cdeq_X_value* cdeq_X_emplace(cdeq_X* self, i_valraw raw); // alias for emplace_back()
+cdeq_X_value* cdeq_X_push_back(cdeq_X* self, i_key value);
+cdeq_X_value* cdeq_X_push(cdeq_X* self, i_key value); // alias for push_back()
+cdeq_X_value* cdeq_X_emplace_back(cdeq_X* self, i_keyraw raw);
+cdeq_X_value* cdeq_X_emplace(cdeq_X* self, i_keyraw raw); // alias for emplace_back()
void cdeq_X_pop_back(cdeq_X* self);
-cdeq_X_iter cdeq_X_insert(cdeq_X* self, intptr_t idx, i_val value); // move value
-cdeq_X_iter cdeq_X_insert_n(cdeq_X* self, intptr_t idx, const i_val[] arr, intptr_t n); // move arr values
-cdeq_X_iter cdeq_X_insert_at(cdeq_X* self, cdeq_X_iter it, i_val value); // move value
-cdeq_X_iter cdeq_X_insert_range(cdeq_X* self, i_val* pos,
- const i_val* p1, const i_val* p2);
+cdeq_X_iter cdeq_X_insert_n(cdeq_X* self, intptr_t idx, const i_key[] arr, intptr_t n); // move values
+cdeq_X_iter cdeq_X_insert_at(cdeq_X* self, cdeq_X_iter it, i_key value); // move value
+cdeq_X_iter cdeq_X_insert_uninit(cdeq_X* self, intptr_t idx, intptr_t n); // uninitialized data
+ // copy values:
+cdeq_X_iter cdeq_X_emplace_n(cdeq_X* self, intptr_t idx, const i_keyraw[] arr, intptr_t n);
+cdeq_X_iter cdeq_X_emplace_at(cdeq_X* self, cdeq_X_iter it, i_keyraw raw);
-cdeq_X_iter cdeq_X_emplace_n(cdeq_X* self, intptr_t idx, const i_valraw[] arr, intptr_t n); // clone values
-cdeq_X_iter cdeq_X_emplace_at(cdeq_X* self, cdeq_X_iter it, i_valraw raw);
-cdeq_X_iter cdeq_X_emplace_range(cdeq_X* self, i_val* pos,
- const i_valraw* p1, const i_valraw* p2);
-
-cdeq_X_iter cdeq_X_erase_n(cdeq_X* self, intptr_t idx, intptr_t n);
+void cdeq_X_erase_n(cdeq_X* self, intptr_t idx, intptr_t n);
cdeq_X_iter cdeq_X_erase_at(cdeq_X* self, cdeq_X_iter it);
cdeq_X_iter cdeq_X_erase_range(cdeq_X* self, cdeq_X_iter it1, cdeq_X_iter it2);
-cdeq_X_iter cdeq_X_erase_range_p(cdeq_X* self, i_val* p1, i_val* p2);
-
-void cdeq_X_sort(cdeq_X* self);
-void cdeq_X_sort_range(cdeq_X_iter i1, cdeq_X_iter i2,
- int(*cmp)(const i_val*, const i_val*));
cdeq_X_iter cdeq_X_begin(const cdeq_X* self);
cdeq_X_iter cdeq_X_end(const cdeq_X* self);
void cdeq_X_next(cdeq_X_iter* it);
-cdeq_X_iter cdeq_X_advance(cdeq_X_iter it, size_t n);
+cdeq_X_iter cdeq_X_advance(cdeq_X_iter it, intptr_t n);
-cdeq_X_raw cdeq_X_value_toraw(cdeq_X_value* pval);
+bool cdeq_X_eq(const cdeq_X* c1, const cdeq_X* c2); // require i_eq/i_cmp/i_less.
cdeq_X_value cdeq_X_value_clone(cdeq_X_value val);
+cdeq_X_raw cdeq_X_value_toraw(const cdeq_X_value* pval);
+void cdeq_X_value_drop(cdeq_X_value* pval);
```
## Types
| Type name | Type definition | Used to represent... |
|:-------------------|:------------------------------------|:-----------------------|
-| `cdeq_X` | `struct { cdeq_X_value* data; }` | The cdeq type |
-| `cdeq_X_value` | `i_val` | The cdeq value type |
-| `cdeq_X_raw` | `i_valraw` | The raw value type |
-| `cdeq_X_iter` | `struct { cdeq_X_value* ref; }` | The iterator type |
+| `cdeq_X` | `struct { cdeq_X_value* data; }` | The cdeq type |
+| `cdeq_X_value` | `i_key` | The cdeq value type |
+| `cdeq_X_raw` | `i_keyraw` | The raw value type |
+| `cdeq_X_iter` | `struct { cdeq_X_value* ref; }` | The iterator type |
## Examples
```c
-#define i_val int
+#define i_key int
#define i_tag i
#include <stc/cdeq.h>
#include <stdio.h>
-int main() {
+int main(void) {
cdeq_i q = cdeq_i_init();
cdeq_i_push_front(&q, 10);
c_foreach (i, cdeq_i, q)
diff --git a/docs/clist_api.md b/docs/clist_api.md
index a1dbe105..3d785789 100644
--- a/docs/clist_api.md
+++ b/docs/clist_api.md
@@ -22,16 +22,16 @@ See the c++ class [std::list](https://en.cppreference.com/w/cpp/container/list)
## Header file and declaration
```c
-#define i_type // container type name (default: clist_{i_val})
-#define i_val // value: REQUIRED
-#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop defined
-
-#define i_valraw // convertion "raw" type (default: {i_val})
-#define i_valto // convertion func i_val* => i_valraw
-#define i_valfrom // convertion func i_valraw => i_val
-#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_val
+#define i_type // container type name (default: clist_{i_key})
+#define i_key // value: REQUIRED
+#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
+#define i_keydrop // destroy value func - defaults to empty destruct
+#define i_keyclone // REQUIRED IF i_keydrop defined
+
+#define i_keyraw // convertion "raw" type (default: {i_key})
+#define i_keyto // convertion func i_key* => i_keyraw
+#define i_keyfrom // convertion func i_keyraw => i_key
+#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_key
#include <stc/clist.h>
```
@@ -53,50 +53,53 @@ intptr_t clist_X_count(const clist_X* list);
clist_X_value* clist_X_back(const clist_X* self);
clist_X_value* clist_X_front(const clist_X* self);
-void clist_X_push_back(clist_X* self, i_val value); // note: no pop_back()
-void clist_X_push_front(clist_X* self, i_val value);
-void clist_X_push(clist_X* self, i_val value); // alias for push_back()
+void clist_X_push_back(clist_X* self, i_key value); // note: no pop_back()
+void clist_X_push_front(clist_X* self, i_key value);
+void clist_X_push(clist_X* self, i_key value); // alias for push_back()
-void clist_X_emplace_back(clist_X* self, i_valraw raw);
-void clist_X_emplace_front(clist_X* self, i_valraw raw);
-void clist_X_emplace(clist_X* self, i_valraw raw); // alias for emplace_back()
+void clist_X_emplace_back(clist_X* self, i_keyraw raw);
+void clist_X_emplace_front(clist_X* self, i_keyraw raw);
+void clist_X_emplace(clist_X* self, i_keyraw raw); // alias for emplace_back()
-clist_X_iter clist_X_insert_at(clist_X* self, clist_X_iter it, i_val value); // return iter to new elem
-clist_X_iter clist_X_emplace_at(clist_X* self, clist_X_iter it, i_valraw raw);
+clist_X_iter clist_X_insert_at(clist_X* self, clist_X_iter it, i_key value); // return iter to new elem
+clist_X_iter clist_X_emplace_at(clist_X* self, clist_X_iter it, i_keyraw raw);
void clist_X_pop_front(clist_X* self);
clist_X_iter clist_X_erase_at(clist_X* self, clist_X_iter it); // return iter after it
clist_X_iter clist_X_erase_range(clist_X* self, clist_X_iter it1, clist_X_iter it2);
-intptr_t clist_X_remove(clist_X* self, i_valraw raw); // removes all matches
+intptr_t clist_X_remove(clist_X* self, i_keyraw raw); // removes all matches
clist_X clist_X_split_off(clist_X* self, clist_X_iter i1, clist_X_iter i2); // split off [i1, i2)
clist_X_iter clist_X_splice(clist_X* self, clist_X_iter it, clist_X* other); // return updated valid it
clist_X_iter clist_X_splice_range(clist_X* self, clist_X_iter it, // return updated valid it
clist_X* other, clist_X_iter it1, clist_X_iter it2);
-clist_X_iter clist_X_find(const clist_X* self, i_valraw raw);
-clist_X_iter clist_X_find_in(clist_X_iter it1, clist_X_iter it2, i_valraw raw);
-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);
+clist_X_iter clist_X_find(const clist_X* self, i_keyraw raw);
+clist_X_iter clist_X_find_in(clist_X_iter it1, clist_X_iter it2, i_keyraw raw);
+const i_key* clist_X_get(const clist_X* self, i_keyraw raw);
+i_key* clist_X_get_mut(clist_X* self, i_keyraw raw);
void clist_X_reverse(clist_X* self);
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
+clist_X_node* clist_X_get_node(clist_X_value* val); // get enclosing node
clist_X_value* clist_X_push_back_node(clist_X* self, clist_X_node* node);
clist_X_value* clist_X_insert_after_node(clist_X* self, clist_X_node* ref, clist_X_node* node);
-clist_X_node* clist_X_unlink_after_node(clist_X* self, clist_X_node* ref); // return the unlinked node
+clist_X_node* clist_X_unlink_after_node(clist_X* self, clist_X_node* ref); // return unlinked node
+clist_X_node* clist_X_unlink_front_node(clist_X* self); // return unlinked node
void clist_X_erase_after_node(clist_X* self, clist_X_node* node);
clist_X_iter clist_X_begin(const clist_X* self);
clist_X_iter clist_X_end(const clist_X* self);
void clist_X_next(clist_X_iter* it);
-clist_X_iter clist_X_advance(clist_X_iter it, size_t n); // return n elements ahead.
+clist_X_iter clist_X_advance(clist_X_iter it, size_t n); // return n elements ahead.
-clist_X_raw clist_X_value_toraw(clist_X_value* pval);
+bool clist_X_eq(const clist_X* c1, const clist_X* c2); // equality test
clist_X_value clist_X_value_clone(clist_X_value val);
+clist_X_raw clist_X_value_toraw(const clist_X_value* pval);
+void clist_X_value_drop(clist_X_value* pval);
```
## Types
@@ -105,8 +108,8 @@ clist_X_value clist_X_value_clone(clist_X_value val);
|:--------------------|:------------------------------------|:-----------------------------------------|
| `clist_X` | `struct { clist_X_node* last; }` | The clist type |
| `clist_X_node` | `struct { clist_X_node* next; clist_X_value value; }` | The clist node type |
-| `clist_X_value` | `i_val` | The clist element type |
-| `clist_X_raw` | `i_valraw` | clist raw value type |
+| `clist_X_value` | `i_key` | The clist element type |
+| `clist_X_raw` | `i_keyraw` | clist raw value type |
| `clist_X_iter` | `struct { clist_value *ref; ... }` | clist iterator |
## Example
@@ -114,14 +117,13 @@ clist_X_value clist_X_value_clone(clist_X_value val);
Interleave *push_front()* / *push_back()* then *sort()*:
```c
#define i_type DList
-#define i_val double
-#define i_extern // link with sort() fn.
+#define i_key double
#include <stc/clist.h>
#include <stdio.h>
-int main() {
- DList list = c_make(DList, {10., 20., 30., 40., 50., 60., 70., 80., 90.});
+int main(void) {
+ DList list = c_init(DList, {10., 20., 30., 40., 50., 60., 70., 80., 90.});
c_forrange (i, 1, 10) {
if (i & 1) DList_push_front(&list, (double) i);
@@ -152,14 +154,14 @@ Use of *erase_at()* and *erase_range()*:
```c
// erasing from clist
#define i_tag i
-#define i_val int
+#define i_key int
#include <stc/clist.h>
#include <stdio.h>
-int main ()
+int main(void)
{
- clist_i L = c_make(clist_i, {10, 20, 30, 40, 50});
+ clist_i L = c_init(clist_i, {10, 20, 30, 40, 50});
// 10 20 30 40 50
clist_i_iter it = clist_i_begin(&L); // ^
clist_i_next(&it);
@@ -187,14 +189,14 @@ mylist contains: 10 30
Splice `[30, 40]` from *L2* into *L1* before `3`:
```c
#define i_tag i
-#define i_val int
+#define i_key int
#include <stc/clist.h>
#include <stdio.h>
-int main() {
- clist_i L1 = c_make(clist_i, {1, 2, 3, 4, 5});
- clist_i L2 = c_make(clist_i, {10, 20, 30, 40, 50});
+int main(void) {
+ clist_i L1 = c_init(clist_i, {1, 2, 3, 4, 5});
+ clist_i L2 = c_init(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);
diff --git a/docs/cmap_api.md b/docs/cmap_api.md
index d2a94ee8..eca350b4 100644
--- a/docs/cmap_api.md
+++ b/docs/cmap_api.md
@@ -9,8 +9,8 @@ hashing (aka open addressing) with linear probing, and without leaving tombstone
***Iterator invalidation***: References and iterators are invalidated after erase. No iterators are invalidated after insert,
unless the hash-table need to be extended. The hash table size can be reserved prior to inserts if the total max size is known.
-The order of elements is preserved after erase and insert. This makes it possible to erase individual elements while iterating
-through the container by using the returned iterator from *erase_at()*, which references the next element.
+The order of elements may not be preserved after erase. It is still possible to erase elements when iterating through
+the container by setting the iterator to the value returned from *erase_at()*, which references the next element. Note that a small number of elements may be visited twice when doing this, but all elements will be visited.
See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/container/unordered_map) for a functional description.
@@ -36,7 +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_ssize // internal; default int32_t. If defined, table expand 2x (else 1.5x)
+#define i_expandby // default 1. If 2, 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.
@@ -114,16 +114,17 @@ bool c_memcmp_eq(const i_keyraw* a, const i_keyraw* b); // !
## Examples
```c
+#define i_implement
#include <stc/cstr.h>
#define i_key_str
#define i_val_str
#include <stc/cmap.h>
-int main()
+int main(void)
{
// Create an unordered_map of three strings (that map to strings)
- cmap_str umap = c_make(cmap_str, {
+ cmap_str umap = c_init(cmap_str, {
{"RED", "#FF0000"},
{"GREEN", "#00FF00"},
{"BLUE", "#0000FF"}
@@ -157,13 +158,14 @@ The HEX of color BLACK is:[#000000]
### Example 2
This example uses a cmap with cstr as mapped value.
```c
+#define i_implement
#include <stc/cstr.h>
#define i_type IDMap
#define i_key int
#define i_val_str
#include <stc/cmap.h>
-int main()
+int main(void)
{
uint32_t col = 0xcc7744ff;
@@ -206,7 +208,7 @@ typedef struct { int x, y, z; } Vec3i;
#define i_tag vi
#include <stc/cmap.h>
-int main()
+int main(void)
{
// Define map with defered destruct
cmap_vi vecs = {0};
@@ -241,7 +243,7 @@ typedef struct { int x, y, z; } Vec3i;
#define i_tag iv
#include <stc/cmap.h>
-int main()
+int main(void)
{
cmap_iv vecs = {0}
@@ -267,6 +269,7 @@ Output:
### Example 5: Advanced
Key type is struct.
```c
+#define i_implement
#include <stc/cstr.h>
typedef struct {
@@ -274,7 +277,7 @@ typedef struct {
cstr country;
} Viking;
-#define Viking_init() ((Viking){cstr_NULL, cstr_NULL})
+#define Viking_init() ((Viking){cstr_null, cstr_null})
static inline int Viking_cmp(const Viking* a, const Viking* b) {
int c = cstr_cmp(&a->name, &b->name);
@@ -301,7 +304,7 @@ static inline void Viking_drop(Viking* vk) {
#define i_val int
#include <stc/cmap.h>
-int main()
+int main(void)
{
// Use a HashMap to store the vikings' health points.
Vikings vikings = {0};
@@ -335,6 +338,7 @@ In example 5 we needed to construct a lookup key which allocated strings, and th
In this example we use rawtype feature to make it even simpler to use. Note that we must use the emplace() methods
to add "raw" type entries (otherwise compile error):
```c
+#define i_implement
#include <stc/cstr.h>
typedef struct Viking {
@@ -376,7 +380,7 @@ static inline RViking Viking_toraw(const Viking* vp) {
#define i_val int
#include <stc/cmap.h>
-int main()
+int main(void)
{
Vikings vikings = {0};
diff --git a/docs/cpque_api.md b/docs/cpque_api.md
index 962ee162..5b63dfd1 100644
--- a/docs/cpque_api.md
+++ b/docs/cpque_api.md
@@ -8,17 +8,17 @@ See the c++ class [std::priority_queue](https://en.cppreference.com/w/cpp/contai
## Header file and declaration
```c
-#define i_type // define type name of the container (default cpque_{i_val})
-#define i_val // value: REQUIRED
-#define i_less // compare two i_val* : REQUIRED IF i_val/i_valraw is a non-integral type
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop defined
+#define i_type // define type name of the container (default cpque_{i_key})
+#define i_key // value: REQUIRED
+#define i_less // compare two i_key* : REQUIRED IF i_key/i_keyraw is a non-integral type
+#define i_keydrop // destroy value func - defaults to empty destruct
+#define i_keyclone // REQUIRED IF i_keydrop defined
-#define i_valraw // convertion type
-#define i_valfrom // convertion func i_valraw => i_val
-#define i_valto // convertion func i_val* => i_valraw.
+#define i_keyraw // convertion type
+#define i_keyfrom // convertion func i_keyraw => i_key
+#define i_keyto // convertion func i_key* => i_keyraw.
-#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_val
+#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_key
#include <stc/cpque.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
@@ -28,7 +28,7 @@ See the c++ class [std::priority_queue](https://en.cppreference.com/w/cpp/contai
```c
cpque_X cpque_X_init(void); // create empty pri-queue.
cpque_X cpque_X_with_capacity(intptr_t cap);
-cpque_X cpque_X_with_size(intptr_t size, i_val null);
+cpque_X cpque_X_with_size(intptr_t size, i_key null);
cpque_X cpque_X_clone(cpque_X pq);
void cpque_X_clear(cpque_X* self);
@@ -39,16 +39,16 @@ void cpque_X_drop(cpque_X* self); // destructor
intptr_t cpque_X_size(const cpque_X* self);
bool cpque_X_empty(const cpque_X* self);
-i_val* cpque_X_top(const cpque_X* self);
+i_key* cpque_X_top(const cpque_X* self);
void cpque_X_make_heap(cpque_X* self); // heapify the vector.
-void cpque_X_push(cpque_X* self, i_val value);
-void cpque_X_emplace(cpque_X* self, i_valraw raw); // converts from raw
+void cpque_X_push(cpque_X* self, i_key value);
+void cpque_X_emplace(cpque_X* self, i_keyraw raw); // converts from raw
void cpque_X_pop(cpque_X* self);
void cpque_X_erase_at(cpque_X* self, intptr_t idx);
-i_val cpque_X_value_clone(i_val value);
+i_key cpque_X_value_clone(i_key value);
```
## Types
@@ -56,19 +56,19 @@ i_val cpque_X_value_clone(i_val value);
| Type name | Type definition | Used to represent... |
|:-------------------|:--------------------------------------|:------------------------|
| `cpque_X` | `struct {cpque_X_value* data; ...}` | The cpque type |
-| `cpque_X_value` | `i_val` | The cpque element type |
+| `cpque_X_value` | `i_key` | The cpque element type |
## Example
```c
#include <stc/crand.h>
#include <stdio.h>
-#define i_val int64_t
+#define i_key int64_t
#define i_cmp -c_default_cmp // min-heap
#define i_tag i
#include <stc/cpque.h>
-int main()
+int main(void)
{
intptr_t N = 10000000;
crand_t rng = crand_init(1234);
diff --git a/docs/cqueue_api.md b/docs/cqueue_api.md
index 9ea4b148..b324e5fc 100644
--- a/docs/cqueue_api.md
+++ b/docs/cqueue_api.md
@@ -7,16 +7,16 @@ See the c++ class [std::queue](https://en.cppreference.com/w/cpp/container/queue
## Header file and declaration
```c
-#define i_type // container type name (default: cset_{i_key})
-#define i_val // value: REQUIRED
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop defined
+#define i_type // container type name (default: cqueue_{i_key})
+#define i_key // value: REQUIRED
+#define i_keydrop // destroy value func - defaults to empty destruct
+#define i_keyclone // REQUIRED IF i_keydrop defined
-#define i_valraw // convertion "raw" type - defaults to i_val
-#define i_valfrom // convertion func i_valraw => i_val
-#define i_valto // convertion func i_val* => i_valraw
+#define i_keyraw // convertion "raw" type - defaults to i_key
+#define i_keyfrom // convertion func i_keyraw => i_key
+#define i_keyto // convertion func i_key* => i_keyraw
-#define i_tag // alternative typename: cqueue_{i_tag}. i_tag defaults to i_val
+#define i_tag // alternative typename: cqueue_{i_tag}. i_tag defaults to i_key
#include <stc/cqueue.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
@@ -26,27 +26,35 @@ See the c++ class [std::queue](https://en.cppreference.com/w/cpp/container/queue
```c
cqueue_X cqueue_X_init(void);
+cqueue_X cqueue_X_with_capacity(intptr_t size);
cqueue_X cqueue_X_clone(cqueue_X q);
void cqueue_X_clear(cqueue_X* self);
void cqueue_X_copy(cqueue_X* self, const cqueue_X* other);
+bool cqueue_X_reserve(cqueue_X* self, intptr_t cap);
+void cqueue_X_shrink_to_fit(cqueue_X* self);
void cqueue_X_drop(cqueue_X* self); // destructor
intptr_t cqueue_X_size(const cqueue_X* self);
+intptr_t cqueue_X_capacity(const cqueue_X* self);
bool cqueue_X_empty(const cqueue_X* self);
+
cqueue_X_value* cqueue_X_front(const cqueue_X* self);
cqueue_X_value* cqueue_X_back(const cqueue_X* self);
-cqueue_X_value* cqueue_X_push(cqueue_X* self, i_val value);
-cqueue_X_value* cqueue_X_emplace(cqueue_X* self, i_valraw raw);
-
+cqueue_X_value* cqueue_X_push(cqueue_X* self, i_key value);
+cqueue_X_value* cqueue_X_emplace(cqueue_X* self, i_keyraw raw);
void cqueue_X_pop(cqueue_X* self);
cqueue_X_iter cqueue_X_begin(const cqueue_X* self);
cqueue_X_iter cqueue_X_end(const cqueue_X* self);
void cqueue_X_next(cqueue_X_iter* it);
+cqueue_X_iter cqueue_X_advance(cqueue_X_iter it, intptr_t n);
-i_val cqueue_X_value_clone(i_val value);
+bool cqueue_X_eq(const cqueue_X* c1, const cqueue_X* c2); // require i_eq/i_cmp/i_less.
+i_key cqueue_X_value_clone(i_key value);
+cqueue_X_raw cqueue_X_value_toraw(const cqueue_X_value* pval);
+void cqueue_X_value_drop(cqueue_X_value* pval);
```
## Types
@@ -54,19 +62,19 @@ i_val cqueue_X_value_clone(i_val value);
| Type name | Type definition | Used to represent... |
|:--------------------|:---------------------|:-------------------------|
| `cqueue_X` | `cdeq_X` | The cqueue type |
-| `cqueue_X_value` | `i_val` | The cqueue element type |
-| `cqueue_X_raw` | `i_valraw` | cqueue raw value type |
+| `cqueue_X_value` | `i_key` | The cqueue element type |
+| `cqueue_X_raw` | `i_keyraw` | cqueue raw value type |
| `cqueue_X_iter` | `cdeq_X_iter` | cqueue iterator |
## Examples
```c
-#define i_val int
+#define i_key int
#define i_tag i
#include <stc/cqueue.h>
#include <stdio.h>
-int main() {
+int main(void) {
cqueue_i Q = cqueue_i_init();
// push() and pop() a few.
diff --git a/docs/crandom_api.md b/docs/crandom_api.md
index 7281b2d7..22a4f4dd 100644
--- a/docs/crandom_api.md
+++ b/docs/crandom_api.md
@@ -67,6 +67,7 @@ double crand_norm(crand_t* rng, crand_norm_t* dist);
```c
#include <time.h>
#include <stc/crand.h>
+#define i_implement
#include <stc/cstr.h>
// Declare int -> int sorted map. Uses typetag 'i' for ints.
@@ -75,7 +76,7 @@ double crand_norm(crand_t* rng, crand_norm_t* dist);
#define i_tag i
#include <stc/csmap.h>
-int main()
+int main(void)
{
enum {N = 10000000};
const double Mean = -12.0, StdDev = 6.0, Scale = 74;
diff --git a/docs/cregex_api.md b/docs/cregex_api.md
index 9a15a869..52476e09 100644
--- a/docs/cregex_api.md
+++ b/docs/cregex_api.md
@@ -12,16 +12,16 @@ 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
+ CREG_DOTALL = 1<<0, // dot matches newline too: can be set/overridden by (?s) and (?-s) in RE
+ CREG_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
+ CREG_FULLMATCH = 1<<2, // like start-, end-of-line anchors were in pattern: "^ ... $"
+ CREG_NEXT = 1<<3, // use end of previous match[0] as start of input
+ CREG_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
+ CREG_STRIP = 1<<5, // only keep the replaced matches, strip the rest
};
cregex cregex_init(void);
@@ -29,7 +29,7 @@ cregex cregex_from(const char* pattern, int cflags = CREG_DEFAULT);
// return CREG_OK, or negative error code on failure
int cregex_compile(cregex *self, const char* pattern, int cflags = CREG_DEFAULT);
- // num. of capture groups in regex. 0 if RE is invalid. First group is the full match
+ // num. of capture groups in regex, excluding the 0th group which is the full match
int cregex_captures(const cregex* self);
// return CREG_OK, CREG_NOMATCH, or CREG_MATCHERROR
@@ -44,15 +44,15 @@ bool cregex_is_match(const cregex* re, const char* input);
// Replace all matches in input
cstr cregex_replace(const cregex* re, const char* input, const char* replace, int count = INT_MAX);
- // Replace count matches in input string-view. Optionally transform replacement with mfun.
+ // Replace count matches in input string-view. Optionally transform replacement.
cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count = INT_MAX);
cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count,
- bool(*mfun)(int capgrp, csview match, cstr* mstr), int rflags);
+ bool(*transform)(int group, csview match, cstr* result), int rflags);
// All-in-one replacement (compile + find/replace + drop)
cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count = INT_MAX);
cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count,
- bool(*mfun)(int capgrp, csview match, cstr* mstr), int rflags);
+ bool(*transform)(int group, csview match, cstr* result), int rflags);
// destroy
void cregex_drop(cregex* self);
```
@@ -99,10 +99,10 @@ If an error occurs ```cregex_compile``` returns a negative error code stored in
[ [Run this code](https://godbolt.org/z/z434TMKfo) ]
```c
-#define i_extern // include external cstr, utf8, cregex functions implementation.
+#define i_import // include dependent cstr, utf8 and cregex function definitions.
#include <stc/cregex.h>
-int main() {
+int main(void) {
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";
@@ -138,20 +138,20 @@ In order to use a callback function in the replace call, see `examples/regex_rep
To iterate multiple matches in an input string, you may use
```c
csview match[5] = {0};
-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]));
+while (cregex_find(&re, input, match, CREG_NEXT) == CREG_OK)
+ for (int k = 1; i <= cregex_captures(&re); ++k)
+ printf("submatch %d: %.*s\n", k, c_SV(match[k]));
```
There is also a for-loop macro to simplify it:
```c
c_formatch (it, &re, input)
- c_forrange (k, cregex_captures(&re))
- printf("submatch %lld: %.*s\n", k, c_SV(it.match[k]));
+ for (int k = 1; i <= cregex_captures(&re); ++k)
+ printf("submatch %d: %.*s\n", k, c_SV(it.match[k]));
```
## Using cregex in a project
-The easiest is to `#define i_extern` before `#include <stc/cregex.h>`. Make sure to do that in one translation unit only.
+The easiest is to `#define i_import` before `#include <stc/cregex.h>`. Make sure to do that in one translation unit only.
For reference, **cregex** uses the following files:
- `stc/cregex.h`, `stc/utf8.h`, `stc/csview.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h`
@@ -181,8 +181,8 @@ For reference, **cregex** uses the following files:
| \B | Not UTF8 word boundary | * |
| \Q | Start literal input mode | * |
| \E | End literal input mode | * |
-| (?i) (?-i) | Ignore case on/off (override CREG_C_ICASE) | * |
-| (?s) (?-s) | Dot matches newline on/off (override CREG_C_DOTALL) | * |
+| (?i) (?-i) | Ignore case on/off (override CREG_ICASE) | * |
+| (?s) (?-s) | Dot matches newline on/off (override CREG_DOTALL) | * |
| \n \t \r | Match UTF8 newline, tab, carriage return | |
| \d \s \w | Match UTF8 digit, whitespace, alphanumeric character | |
| \D \S \W | Do not match the groups described above | |
diff --git a/docs/cset_api.md b/docs/cset_api.md
index 026d7462..e894ad4f 100644
--- a/docs/cset_api.md
+++ b/docs/cset_api.md
@@ -18,8 +18,8 @@ A **cset** is an associative container that contains a set of unique objects of
#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_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val
-#define i_ssize // default int32_t. If defined, table expand 2x (else 1.5x)
+#define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_key
+#define i_expandby // default 1. If 2, table expand 2x (else 1.5x)
#include <stc/cset.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
@@ -77,16 +77,17 @@ cset_X_value cset_X_value_clone(cset_X_value val);
## Example
```c
+#define i_implement
#include <stc/cstr.h>
#define i_type Strset
#define i_key_str
#include <stc/cset.h>
-int main ()
+int main(void)
{
Strset first, second={0}, third={0}, fourth={0}, fifth;
- first = c_make(Strset, {"red", "green", "blue"});
+ first = c_init(Strset, {"red", "green", "blue"});
fifth = Strset_clone(second);
c_forlist (i, const char*, {"orange", "pink", "yellow"})
diff --git a/docs/csmap_api.md b/docs/csmap_api.md
index 93faa4f9..099d7dfc 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_ssize // internal size rep. defaults to int32_t
#include <stc/csmap.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
@@ -84,7 +83,8 @@ void csmap_X_next(csmap_X_iter* iter);
csmap_X_iter csmap_X_advance(csmap_X_iter it, intptr_t n);
csmap_X_value csmap_X_value_clone(csmap_X_value val);
-csmap_X_raw csmap_X_value_toraw(csmap_X_value* pval);
+csmap_X_raw csmap_X_value_toraw(const csmap_X_value* pval);
+void csmap_X_value_drop(csmap_X_value* pval);
```
## Types
@@ -102,16 +102,16 @@ csmap_X_raw csmap_X_value_toraw(csmap_X_value* pval);
## Examples
```c
+#define i_implement
#include <stc/cstr.h>
-
#define i_key_str // special macro for i_key = cstr, i_tag = str
#define i_val_str // ditto
#include <stc/csmap.h>
-int main()
+int main(void)
{
// Create a sorted map of three strings (maps to string)
- csmap_str colors = c_make(csmap_str, {
+ csmap_str colors = c_init(csmap_str, {
{"RED", "#FF0000"},
{"GREEN", "#00FF00"},
{"BLUE", "#0000FF"}
@@ -150,6 +150,7 @@ Translate a
[ [Run this code](https://godbolt.org/z/9d1PP77Pa) ]
```c
+#define i_implement
#include <stc/cstr.h>
#define i_type strmap
#define i_key_str
@@ -165,7 +166,7 @@ static void print_result(strmap_result result) {
print_node(result.ref);
}
-int main()
+int main(void)
{
strmap m = {0};
@@ -182,6 +183,7 @@ int main()
### Example 3
This example uses a csmap with cstr as mapped value.
```c
+#define i_implement
#include <stc/cstr.h>
#define i_type IDSMap
@@ -189,10 +191,10 @@ This example uses a csmap with cstr as mapped value.
#define i_val_str
#include <stc/csmap.h>
-int main()
+int main(void)
{
uint32_t col = 0xcc7744ff;
- IDSMap idnames = c_make(IDSMap, { {100, "Red"}, {110, "Blue"} });
+ IDSMap idnames = c_init(IDSMap, { {100, "Red"}, {110, "Blue"} });
// Assign/overwrite an existing mapped value with a const char*
IDSMap_emplace_or_assign(&idnames, 110, "White");
@@ -235,7 +237,7 @@ static int Vec3i_cmp(const Vec3i* a, const Vec3i* b) {
#include <stc/csmap.h>
#include <stdio.h>
-int main()
+int main(void)
{
csmap_vi vmap = {0};
diff --git a/docs/cspan_api.md b/docs/cspan_api.md
index 10565b0f..09821450 100644
--- a/docs/cspan_api.md
+++ b/docs/cspan_api.md
@@ -22,15 +22,14 @@ using_cspan4(S, ValueType); // define span types S, S2, S3, S4 with
## Methods
All functions are type-safe. Note that the span argument itself is generally not side-effect safe,
-i.e., it may be expanded multiple times. However, all integer arguments are safe, e.g.
+i.e., it may be expanded multiple times. However, all index arguments are safe, e.g.
`cspan_at(&ms3, i++, j++, k++)` is allowed. If the number of arguments does not match the span rank,
a compile error is issued. Runtime bounds checks are enabled by default (define `STC_NDEBUG` or `NDEBUG` to disable).
```c
-SpanType cspan_make(T SpanType, {v1, v2, ...}); // make a 1-d cspan from values
+SpanType cspan_init(T SpanType, {v1, v2, ...}); // make a 1-d cspan from values
SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from compatible STC container
SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from C array
-SpanTypeN cspan_md(ValueType* data, intptr_t xdim, ...); // make a multi-dimensional cspan
-
+
intptr_t cspan_size(const SpanTypeN* self); // return number of elements
intptr_t cspan_rank(const SpanTypeN* self); // dimensions; compile time constant
intptr_t cspan_index(const SpanTypeN* self, intptr_t x, ..); // index of element
@@ -39,32 +38,38 @@ ValueType* cspan_at(const SpanTypeN* self, intptr_t x, ...); // #args mus
ValueType* cspan_front(const SpanTypeN* self);
ValueType* cspan_back(const SpanTypeN* self);
- // general index slicing to create a subspan.
- // {i} reduces rank. {i,c_END} slice to end. {c_ALL} use the full extent.
-SpanTypeR cspan_slice(T SpanTypeR, const SpanTypeN* self, {x0,x1}, {y0,y1}.., {N0,N1});
-
- // create a subspan of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL});
-SpanType cspan_submd2(const SpanType2* self, intptr_t x); // return a 1d subspan from a 2d span.
-SpanTypeN cspan_submd3(const SpanType3* self, intptr_t x, ...); // return a 1d or 2d subspan from a 3d span.
-SpanTypeN cspan_submd4(const SpanType4* self, intptr_t x, ...); // number of args determines rank of output span.
-
- // create a subspan of same rank. Like e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL});
-SpanType cspan_subspan(const SpanType* self, intptr_t offset, intptr_t count);
-SpanType2 cspan_subspan2(const SpanType2 self, intptr_t offset, intptr_t count);
-SpanType3 cspan_subspan3(const SpanType3 self, intptr_t offset, intptr_t count);
-
SpanTypeN_iter SpanType_begin(const SpanTypeN* self);
SpanTypeN_iter SpanType_end(const SpanTypeN* self);
void SpanType_next(SpanTypeN_iter* it);
-```
-## Types
-| Type name | Type definition | Used to represent... |
+SpanTypeN cspan_md(ValueType* data, d1, d2, ...); // make a multi-dim cspan, row-major order.
+SpanTypeN cspan_md_order(char order, ValueType* data, d1, d2, ...); // order='C': row-major, 'F': column-major (FORTRAN).
+
+ // transpose a md span (inverse axes). no changes to the underlying array.
+void cspan_transpose(const SpanTypeN* self);
+bool cspan_is_order_F(const SpanTypeN* self);
+
+ // create a subspan of input span rank. Like e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL});
+SpanType cspan_subspan(const SpanType* span, intptr_t offset, intptr_t count);
+SpanType2 cspan_subspan2(const SpanType2* span, intptr_t offset, intptr_t count);
+SpanType3 cspan_subspan3(const SpanType3* span, intptr_t offset, intptr_t count);
+
+ // create a sub md span of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL});
+OutSpan1 cspan_submd2(const SpanType2* parent, intptr_t x); // return a 1d subspan from a 2d span.
+OutSpanN cspan_submd3(const SpanType3* parent, intptr_t x, ...); // return a 1d or 2d subspan from a 3d span.
+OutSpanN cspan_submd4(const SpanType4* parent, intptr_t x, ...); // number of args decides rank of output span.
+
+ // general slicing of an md span.
+ // {i}: reduce rank. {i,c_END}: slice to end. {c_ALL}: use full extent.
+OutSpanN cspan_slice(TYPE OutSpanN, const SpanTypeN* parent, {x0,x1}, {y0,y1}.., {N0,N1});
+```
+## TypesPd
+| Type name | Type definition / usage | Used to represent... |
|:------------------|:----------------------------------------------------|:---------------------|
| SpanTypeN | `struct { ValueType *data; uint32_t shape[N]; .. }` | SpanType with rank N |
| SpanTypeN`_value` | `ValueType` | The ValueType |
-| `c_ALL` | | Full extent |
-| `c_END` | | End of extent |
+| `c_ALL` | Use with `cspan_slice()`. | Full extent |
+| `c_END` | " | End of extent |
## Example 1
@@ -96,10 +101,10 @@ if __name__ == '__main__':
#include <stc/cspan.h>
using_cspan3(myspan, int); // define myspan, myspan2, myspan3.
-int main() {
+int main(void) {
int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24};
- myspan3 ms3 = cspan_md(arr, 2, 3, 4);
+ myspan3 ms3 = cspan_md(arr, 2, 3, 4); // C-order, i.e. row-major.
myspan3 ss3 = cspan_slice(myspan3, &ms3, {c_ALL}, {1,3}, {2,c_END});
myspan2 ss2 = cspan_submd3(&ss3, 1);
@@ -118,7 +123,7 @@ int main() {
#include <mdspan>
#include <tuple>
-int main() {
+int main(void) {
int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24};
std::mdspan ms3(arr, 2, 3, 4);
@@ -136,15 +141,16 @@ int main() {
## Example 2
Slicing cspan without and with reducing the rank:
```c
-#include <c11/print.h>
+#define i_implement
+#include <c11/fmt.h>
#include <stc/cspan.h>
using_cspan3(Span, int); // Shorthand to define Span, Span2, and Span3
-int main()
+int main(void)
{
- // c_make() can create any STC container/span from an initializer list:
- Span span = c_make(Span, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ // c_init() can create any STC container/span from an initializer list:
+ Span span = c_init(Span, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24});
// create a 3d cspan:
Span3 span3 = cspan_md(span.data, 2, 4, 3);
@@ -154,7 +160,7 @@ int main()
puts("\niterate span2 flat:");
c_foreach (i, Span2, span2)
- print(" {}", *i.ref);
+ fmt_print(" {}", *i.ref);
puts("");
// slice without reducing rank:
@@ -164,8 +170,8 @@ int main()
c_forrange (i, ss3.shape[0]) {
c_forrange (j, ss3.shape[1]) {
c_forrange (k, ss3.shape[2])
- print(" {:2}", *cspan_at(&ss3, i, j, k));
- print(" |");
+ fmt_print(" {:2}", *cspan_at(&ss3, i, j, k));
+ fmt_print(" |");
}
}
// slice and reduce rank:
@@ -174,13 +180,13 @@ int main()
puts("\niterate ss2 by dimensions:");
c_forrange (i, ss2.shape[0]) {
c_forrange (j, ss2.shape[1])
- print(" {:2}", *cspan_at(&ss2, i, j));
- print(" |");
+ fmt_print(" {:2}", *cspan_at(&ss2, i, j));
+ fmt_print(" |");
}
puts("\niterate ss2 flat:");
c_foreach (i, Span2, ss2)
- print(" {:2}", *i.ref);
+ fmt_print(" {:2}", *i.ref);
puts("");
}
```
diff --git a/docs/csset_api.md b/docs/csset_api.md
index e83ab857..aef3af3c 100644
--- a/docs/csset_api.md
+++ b/docs/csset_api.md
@@ -18,8 +18,7 @@ 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_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_val
-#define i_ssize // defaults to int32_t
+#define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_key
#include <stc/csset.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
@@ -77,17 +76,18 @@ csset_X_value csset_X_value_clone(csset_X_value val);
## Example
```c
+#define i_implement
#include <stc/cstr.h>
#define i_type SSet
#define i_key_str
#include <stc/csset.h>
-int main ()
+int main(void)
{
SSet second={0}, third={0}, fourth={0}, fifth={0};
- second = c_make(SSet, {"red", "green", "blue"});
+ second = c_init(SSet, {"red", "green", "blue"});
c_forlist (i, const char*, {"orange", "pink", "yellow"})
SSet_emplace(&third, *i.ref);
diff --git a/docs/cstack_api.md b/docs/cstack_api.md
index b1371f4e..e799b152 100644
--- a/docs/cstack_api.md
+++ b/docs/cstack_api.md
@@ -9,15 +9,15 @@ See the c++ class [std::stack](https://en.cppreference.com/w/cpp/container/stack
```c
#define i_type // full typename of the container
-#define i_val // value: REQUIRED
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop defined
+#define i_key // value: REQUIRED
+#define i_keydrop // destroy value func - defaults to empty destruct
+#define i_keyclone // REQUIRED IF i_keydrop defined
-#define i_valraw // convertion "raw" type - defaults to i_val
-#define i_valfrom // convertion func i_valraw => i_val
-#define i_valto // convertion func i_val* => i_valraw
+#define i_keyraw // convertion "raw" type - defaults to i_key
+#define i_keyfrom // convertion func i_keyraw => i_key
+#define i_keyto // convertion func i_key* => i_keyraw
-#define i_tag // alternative typename: cstack_{i_tag}. i_tag defaults to i_val
+#define i_tag // alternative typename: cstack_{i_tag}. i_tag defaults to i_key
#include <stc/cstack.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
@@ -27,13 +27,13 @@ See the c++ class [std::stack](https://en.cppreference.com/w/cpp/container/stack
```c
cstack_X cstack_X_init(void);
cstack_X cstack_X_with_capacity(intptr_t cap);
-cstack_X cstack_X_with_size(intptr_t size, i_val fill);
+cstack_X cstack_X_with_size(intptr_t size, i_key fill);
cstack_X cstack_X_clone(cstack_X st);
void cstack_X_clear(cstack_X* self);
bool cstack_X_reserve(cstack_X* self, intptr_t n);
void cstack_X_shrink_to_fit(cstack_X* self);
-i_val* cstack_X_append_uninit(cstack_X* self, intptr_t n);
+i_key* cstack_X_append_uninit(cstack_X* self, intptr_t n);
void cstack_X_copy(cstack_X* self, const cstack_X* other);
void cstack_X_drop(cstack_X* self); // destructor
@@ -41,12 +41,12 @@ intptr_t cstack_X_size(const cstack_X* self);
intptr_t cstack_X_capacity(const cstack_X* self);
bool cstack_X_empty(const cstack_X* self);
-i_val* cstack_X_top(const cstack_X* self);
-const i_val* cstack_X_at(const cstack_X* self, intptr_t idx);
-i_val* cstack_X_at_mut(cstack_X* self, intptr_t idx);
+i_key* cstack_X_top(const cstack_X* self);
+const i_key* cstack_X_at(const cstack_X* self, intptr_t idx);
+i_key* cstack_X_at_mut(cstack_X* self, intptr_t idx);
-i_val* cstack_X_push(cstack_X* self, i_val value);
-i_val* cstack_X_emplace(cstack_X* self, i_valraw raw);
+i_key* cstack_X_push(cstack_X* self, i_key value);
+i_key* cstack_X_emplace(cstack_X* self, i_keyraw raw);
void cstack_X_pop(cstack_X* self);
@@ -54,8 +54,10 @@ cstack_X_iter cstack_X_begin(const cstack_X* self);
cstack_X_iter cstack_X_end(const cstack_X* self);
void cstack_X_next(cstack_X_iter* it);
-i_valraw cstack_X_value_toraw(cvec_X_value* pval);
-i_val cstack_X_value_clone(i_val value);
+bool cstack_X_eq(const cstack_X* c1, const cstack_X* c2); // require i_eq/i_cmp/i_less.
+i_key cstack_X_value_clone(i_key value);
+i_keyraw cstack_X_value_toraw(const cvec_X_value* pval);
+void cstack_X_value_drop(cvec_X_value* pval);
```
## Types
@@ -63,19 +65,19 @@ i_val cstack_X_value_clone(i_val value);
| Type name | Type definition | Used to represent... |
|:--------------------|:-------------------------------------|:----------------------------|
| `cstack_X` | `struct { cstack_value *data; ... }` | The cstack type |
-| `cstack_X_value` | `i_val` | The cstack element type |
-| `cstack_X_raw` | `i_valraw` | cstack raw value type |
+| `cstack_X_value` | `i_key` | The cstack element type |
+| `cstack_X_raw` | `i_keyraw` | cstack raw value type |
| `cstack_X_iter` | `struct { cstack_value *ref; }` | cstack iterator |
## Example
```c
#define i_type IStack
-#define i_val int
+#define i_key int
#include <stc/cstack.h>
#include <stdio.h>
-int main() {
+int main(void) {
IStack stk = IStack_init();
for (int i=0; i < 100; ++i)
diff --git a/docs/cstr_api.md b/docs/cstr_api.md
index 64ad002c..dae5669f 100644
--- a/docs/cstr_api.md
+++ b/docs/cstr_api.md
@@ -18,7 +18,7 @@ All cstr definitions and prototypes are available by including a single header f
## Methods
```c
-cstr cstr_init(void); // constructor; same as cstr_NULL.
+cstr cstr_init(void); // constructor; same as cstr_null.
cstr cstr_lit(const char literal_only[]); // cstr from literal; no strlen() call.
cstr cstr_from(const char* str); // constructor using strlen()
cstr cstr_from_n(const char* str, intptr_t n); // constructor with n first bytes of str
@@ -153,13 +153,14 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt
| Name | Value |
|:------------------|:------------------|
| `c_NPOS` | `INTPTR_MAX` |
-| `cstr_NULL` | cstr null value |
+| `cstr_null` | empty cstr value |
## Example
```c
+#define i_implement
#include <stc/cstr.h>
-int main() {
+int main(void) {
cstr s0, s1, full_path;
c_defer(
cstr_drop(&s0),
diff --git a/docs/csview_api.md b/docs/csview_api.md
index ec3bf121..79a5c07b 100644
--- a/docs/csview_api.md
+++ b/docs/csview_api.md
@@ -20,8 +20,9 @@ description.
All csview definitions and prototypes are available by including a single header file.
```c
-#include <stc/cstr.h> // optional, include cstr+csview functionality
-#include <stc/csview.h>
+#define i_implement
+#include <stc/cstr.h>
+#include <stc/csview.h> // after cstr.h: include extra cstr-csview functions
```
## Methods
@@ -111,28 +112,29 @@ uint64_t csview_hash(const csview* x);
| Name | Value | Usage |
|:---------------|:---------------------|:---------------------------------------------|
-| `csview_NULL` | same as `c_sv("")` | `sview = csview_NULL;` |
+| `csview_null` | same as `c_sv("")` | `sview = csview_null;` |
| `c_SV(sv)` | printf argument | `printf("sv: %.*s\n", c_SV(sv));` |
## Example
```c
+#define i_implement
#include <stc/cstr.h>
#include <stc/csview.h>
-int main ()
+int main(void)
{
cstr str1 = cstr_lit("We think in generalities, but we live in details.");
- // (quoting Alfred N. Whitehead)
+ // (quoting Alfred N. Whitehead)
- csview sv1 = cstr_substr(&str1, 3, 5); // "think"
- intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1
- csview sv2 = cstr_substr(&str1, pos, 4); // get "live"
- csview sv3 = cstr_slice(&str1, -8, -1); // get "details"
+ csview sv1 = cstr_substr_ex(&str1, 3, 5); // "think"
+ intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1
+ csview sv2 = cstr_substr_ex(&str1, pos, 4); // get "live"
+ csview sv3 = cstr_slice_ex(&str1, -8, -1); // get "details"
printf("%.*s %.*s %.*s\n",
c_SV(sv1), c_SV(sv2), c_SV(sv3));
cstr s1 = cstr_lit("Apples are red");
- cstr s2 = cstr_from_sv(cstr_substr(&s1, -3, 3)); // "red"
- cstr s3 = cstr_from_sv(cstr_substr(&s1, 0, 6)); // "Apples"
+ cstr s2 = cstr_from_sv(cstr_substr_ex(&s1, -3, 3)); // "red"
+ cstr s3 = cstr_from_sv(cstr_substr_ex(&s1, 0, 6)); // "Apples"
printf("%s %s\n", cstr_str(&s2), cstr_str(&s3));
c_drop(cstr, &str1, &s1, &s2, &s3);
@@ -146,10 +148,10 @@ red Apples
### Example 2: UTF8 handling
```c
+#define i_import // include dependent cstr, utf8 and cregex function definitions.
#include <stc/cstr.h>
-#include <stc/csview.h>
-int main()
+int main(void)
{
cstr s1 = cstr_lit("hell😀 w😀rld");
@@ -181,9 +183,9 @@ void print_split(csview input, const char* sep)
printf("[%.*s]\n", c_SV(i.token));
puts("");
}
-
+#define i_implement
#include <stc/cstr.h>
-#define i_val_str
+#define i_key_str
#include <stc/cstack.h>
cstack_str string_split(csview input, const char* sep)
@@ -196,7 +198,7 @@ cstack_str string_split(csview input, const char* sep)
return out;
}
-int main()
+int main(void)
{
print_split(c_sv("//This is a//double-slash//separated//string"), "//");
print_split(c_sv("This has no matching separator"), "xx");
diff --git a/docs/cvec_api.md b/docs/cvec_api.md
index 5879bc1f..d38ef23f 100644
--- a/docs/cvec_api.md
+++ b/docs/cvec_api.md
@@ -13,16 +13,16 @@ See the c++ class [std::vector](https://en.cppreference.com/w/cpp/container/vect
```c
#define i_type // full typename of the container
-#define i_val // value: REQUIRED
-#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop defined
+#define i_key // value: REQUIRED
+#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
+#define i_keydrop // destroy value func - defaults to empty destruct
+#define i_keyclone // REQUIRED IF i_keydrop defined
-#define i_valraw // convertion "raw" type - defaults to i_val
-#define i_valfrom // convertion func i_valraw => i_val
-#define i_valto // convertion func i_val* => i_valraw
+#define i_keyraw // convertion "raw" type - defaults to i_key
+#define i_keyfrom // convertion func i_keyraw => i_key
+#define i_keyto // convertion func i_key* => i_keyraw
-#define i_tag // alternative typename: cvec_{i_tag}. i_tag defaults to i_val
+#define i_tag // alternative typename: cvec_{i_tag}. i_tag defaults to i_key
#include <stc/cvec.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
@@ -31,16 +31,15 @@ See the c++ class [std::vector](https://en.cppreference.com/w/cpp/container/vect
```c
cvec_X cvec_X_init(void);
-cvec_X cvec_X_with_size(intptr_t size, i_val null);
+cvec_X cvec_X_with_size(intptr_t size, i_key null);
cvec_X cvec_X_with_capacity(intptr_t size);
cvec_X cvec_X_clone(cvec_X vec);
void cvec_X_clear(cvec_X* self);
void cvec_X_copy(cvec_X* self, const cvec_X* other);
-cvec_X_iter cvec_X_copy_range(cvec_X* self, i_val* pos, const i_val* p1, const i_val* p2);
+cvec_X_iter cvec_X_copy_n(cvec_X* self, intptr_t idx, const i_key* arr, intptr_t n);
bool cvec_X_reserve(cvec_X* self, intptr_t cap);
-bool cvec_X_resize(cvec_X* self, intptr_t size, i_val null);
-cvec_X_iter cvec_X_insert_uninit(cvec_X* self, i_val* pos, intptr_t n); // return pos iter
+bool cvec_X_resize(cvec_X* self, intptr_t size, i_key null);
void cvec_X_shrink_to_fit(cvec_X* self);
void cvec_X_drop(cvec_X* self); // destructor
@@ -49,55 +48,52 @@ intptr_t cvec_X_size(const cvec_X* self);
intptr_t cvec_X_capacity(const cvec_X* self);
const cvec_X_value* cvec_X_at(const cvec_X* self, intptr_t idx);
-const cvec_X_value* cvec_X_get(const cvec_X* self, i_valraw raw); // return NULL if not found
-cvec_X_value* cvec_X_at_mut(cvec_X* self, intptr_t idx);
-cvec_X_value* cvec_X_get_mut(cvec_X* self, i_valraw raw); // find mutable value, return value ptr
-cvec_X_iter cvec_X_find(const cvec_X* self, i_valraw raw);
-cvec_X_iter cvec_X_find_in(cvec_X_iter i1, cvec_X_iter i2, i_valraw raw); // return cvec_X_end() if not found
+const cvec_X_value* cvec_X_get(const cvec_X* self, i_keyraw raw); // return NULL if not found
+cvec_X_value* cvec_X_at_mut(cvec_X* self, intptr_t idx); // return mutable at idx
+cvec_X_value* cvec_X_get_mut(cvec_X* self, i_keyraw raw); // find mutable value
+cvec_X_iter cvec_X_find(const cvec_X* self, i_keyraw raw);
+cvec_X_iter cvec_X_find_in(cvec_X_iter i1, cvec_X_iter i2, i_keyraw raw); // return cvec_X_end() if not found
// On sorted vectors:
-cvec_X_iter cvec_X_binary_search(const cvec_X* self, i_valraw raw); // at elem == raw, else end
-cvec_X_iter cvec_X_lower_bound(const cvec_X* self, i_valraw raw); // at first elem >= raw, else end
+cvec_X_iter cvec_X_binary_search(const cvec_X* self, i_keyraw raw); // at elem == raw, else end
+cvec_X_iter cvec_X_lower_bound(const cvec_X* self, i_keyraw raw); // at first elem >= raw, else end
cvec_X_iter cvec_X_binary_search_in(cvec_X_iter i1, cvec_X_iter i2,
- i_valraw raw, cvec_X_iter* lower_bound);
+ i_keyraw raw, cvec_X_iter* lower_bound);
cvec_X_value* cvec_X_front(const cvec_X* self);
cvec_X_value* cvec_X_back(const cvec_X* self);
-cvec_X_value* cvec_X_push(cvec_X* self, i_val value);
-cvec_X_value* cvec_X_emplace(cvec_X* self, i_valraw raw);
-cvec_X_value* cvec_X_push_back(cvec_X* self, i_val value); // alias for push
-cvec_X_value* cvec_X_emplace_back(cvec_X* self, i_valraw raw); // alias for emplace
+cvec_X_value* cvec_X_push(cvec_X* self, i_key value);
+cvec_X_value* cvec_X_emplace(cvec_X* self, i_keyraw raw);
+cvec_X_value* cvec_X_push_back(cvec_X* self, i_key value); // alias for push
+cvec_X_value* cvec_X_emplace_back(cvec_X* self, i_keyraw raw); // alias for emplace
void cvec_X_pop(cvec_X* self);
void cvec_X_pop_back(cvec_X* self); // alias for pop
-cvec_X_iter cvec_X_insert(cvec_X* self, intptr_t idx, i_val value); // move value
-cvec_X_iter cvec_X_insert_n(cvec_X* self, intptr_t idx, const i_val[] arr, intptr_t n); // move n values
-cvec_X_iter cvec_X_insert_at(cvec_X* self, cvec_X_iter it, i_val value); // move value
-cvec_X_iter cvec_X_insert_range(cvec_X* self, i_val* pos,
- const i_val* p1, const i_val* p2);
+cvec_X_iter cvec_X_insert_n(cvec_X* self, intptr_t idx, const i_key arr[], intptr_t n); // move values
+cvec_X_iter cvec_X_insert_at(cvec_X* self, cvec_X_iter it, i_key value); // move value
+cvec_X_iter cvec_X_insert_uninit(cvec_X* self, intptr_t idx, intptr_t n); // return iter at idx
-cvec_X_iter cvec_X_emplace_n(cvec_X* self, intptr_t idx, const i_valraw[] arr, intptr_t n); // clone values
-cvec_X_iter cvec_X_emplace_at(cvec_X* self, cvec_X_iter it, i_valraw raw);
-cvec_X_iter cvec_X_emplace_range(cvec_X* self, i_val* pos,
- const i_valraw* p1, const i_valraw* p2);
+cvec_X_iter cvec_X_emplace_n(cvec_X* self, intptr_t idx, const i_keyraw raw[], intptr_t n);
+cvec_X_iter cvec_X_emplace_at(cvec_X* self, cvec_X_iter it, i_keyraw raw);
cvec_X_iter cvec_X_erase_n(cvec_X* self, intptr_t idx, intptr_t n);
cvec_X_iter cvec_X_erase_at(cvec_X* self, cvec_X_iter it);
cvec_X_iter cvec_X_erase_range(cvec_X* self, cvec_X_iter it1, cvec_X_iter it2);
-cvec_X_iter cvec_X_erase_range_p(cvec_X* self, i_val* p1, i_val* p2);
void cvec_X_sort(cvec_X* self);
void cvec_X_sort_range(cvec_X_iter i1, cvec_X_iter i2,
- int(*cmp)(const i_val*, const i_val*));
+ int(*cmp)(const i_key*, const i_key*));
cvec_X_iter cvec_X_begin(const cvec_X* self);
cvec_X_iter cvec_X_end(const cvec_X* self);
void cvec_X_next(cvec_X_iter* iter);
cvec_X_iter cvec_X_advance(cvec_X_iter it, size_t n);
-cvec_X_raw cvec_X_value_toraw(cvec_X_value* pval);
+bool cvec_X_eq(const cvec_X* c1, const cvec_X* c2); // equality comp.
cvec_X_value cvec_X_value_clone(cvec_X_value val);
+cvec_X_raw cvec_X_value_toraw(const cvec_X_value* pval);
+cvec_X_raw cvec_X_value_drop(cvec_X_value* pval);
```
## Types
@@ -105,18 +101,18 @@ cvec_X_value cvec_X_value_clone(cvec_X_value val);
| Type name | Type definition | Used to represent... |
|:-------------------|:----------------------------------|:-----------------------|
| `cvec_X` | `struct { cvec_X_value* data; }` | The cvec type |
-| `cvec_X_value` | `i_val` | The cvec value type |
-| `cvec_X_raw` | `i_valraw` | The raw value type |
+| `cvec_X_value` | `i_key` | The cvec value type |
+| `cvec_X_raw` | `i_keyraw` | The raw value type |
| `cvec_X_iter` | `struct { cvec_X_value* ref; }` | The iterator type |
## Examples
```c
-#define i_val int
+#define i_key int
#include <stc/cvec.h>
#include <stdio.h>
-int main()
+int main(void)
{
// Create a vector containing integers
cvec_int vec = {0};
@@ -151,12 +147,13 @@ sorted: 5 7 8 13 16 25
```
### Example 2
```c
+#define i_implement
#include <stc/cstr.h>
-#define i_val_str
+#define i_key_str
#include <stc/cvec.h>
-int main() {
+int main(void) {
cvec_str names = cvec_str_init();
cvec_str_emplace(&names, "Mary");
@@ -187,6 +184,7 @@ item: 2 elements so far
Container with elements of structs:
```c
+#define i_implement
#include <stc/cstr.h>
typedef struct {
@@ -208,7 +206,7 @@ User User_clone(User user) {
// Declare a managed, clonable vector of users.
#define i_type UVec
-#define i_valclass User // User is a "class" as it has _cmp, _clone and _drop functions.
+#define i_keyclass User // User is a "class" as it has _cmp, _clone and _drop functions.
#include <stc/cvec.h>
int main(void) {