summaryrefslogtreecommitdiffhomepage
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/algorithm_api.md (renamed from docs/ccommon_api.md)194
-rw-r--r--docs/carc_api.md57
-rw-r--r--docs/cbox_api.md69
-rw-r--r--docs/cdeq_api.md94
-rw-r--r--docs/clist_api.md83
-rw-r--r--docs/cmap_api.md84
-rw-r--r--docs/coroutine_api.md292
-rw-r--r--docs/cpque_api.md38
-rw-r--r--docs/cqueue_api.md41
-rw-r--r--docs/crandom_api.md60
-rw-r--r--docs/crawstr_api.md101
-rw-r--r--docs/cregex_api.md40
-rw-r--r--docs/cset_api.md31
-rw-r--r--docs/csmap_api.md59
-rw-r--r--docs/cspan_api.md295
-rw-r--r--docs/csset_api.md28
-rw-r--r--docs/cstack_api.md47
-rw-r--r--docs/cstr_api.md38
-rw-r--r--docs/csview_api.md166
-rw-r--r--docs/cvec_api.md96
-rw-r--r--docs/pics/Figure_1.pngbin0 -> 60722 bytes
-rw-r--r--docs/pics/coroutine.jpgbin0 -> 81539 bytes
22 files changed, 1159 insertions, 754 deletions
diff --git a/docs/ccommon_api.md b/docs/algorithm_api.md
index 7a3c3196..63bced22 100644
--- a/docs/ccommon_api.md
+++ b/docs/algorithm_api.md
@@ -1,15 +1,17 @@
# STC Algorithms
----
+"No raw loops" - Sean Parent
## Ranged for-loops
-### c_foreach, c_foreach_rv, c_forpair
+### c_foreach, c_forpair
+```c
+#include <stc/ccommon.h>
+```
| 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
@@ -18,7 +20,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 +42,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})
@@ -54,9 +56,9 @@ c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} })
c_forlist (i, const char*, {"Hello", "crazy", "world"})
cstack_str_emplace(&stk, *i.ref);
```
-
---
-## Range algorithms
+
+## Integer range loops
### c_forrange
Abstraction for iterating sequence of integers. Like python's **for** *i* **in** *range()* loop.
@@ -79,20 +81,19 @@ c_forrange (i, 30, 0, -5) printf(" %lld", i);
// 30 25 20 15 10 5
```
-### crange
+### crange: Integer range generator object
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
+crange crange_init(stop); // will generate 0, 1, ..., stop-1
+crange crange_init(start, stop); // will generate start, start+1, ... stop-1
+crange crange_init(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);
+crange r1 = crange_init(3, 32, 2);
printf("2"); // first prime
c_forfilter (i, crange, r1, isPrime(*i.ref))
printf(" %lld", *i.ref);
@@ -100,7 +101,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_init(3, INT64_MAX, 2);
+c_forfilter (i, crange, range,
isPrime(*i.ref) &&
c_flt_take(10)
){
@@ -110,12 +112,12 @@ c_forfilter (i, crange, crange_obj(3, INT64_MAX, 2),
```
### c_forfilter
-Iterate a container/range with chained range filtering.
+Iterate a container or a crange with chained `&&` 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 |
+| `c_forfilter_it (it, ctype, startit, filter)` | Filter from startit iterator position |
| Built-in filter | Description |
|:----------------------------------|:-------------------------------------------|
@@ -126,9 +128,9 @@ Iterate a container/range with chained range filtering.
| `c_flt_counter(it)` | Increment current and return count |
| `c_flt_getcount(it)` | Number of items passed skip*/take*/counter |
-[ [Run this example](https://godbolt.org/z/n9aYrYPv8) ]
+[ [Run this example](https://godbolt.org/z/exqYEK6qa) ]
```c
-#include <stc/calgo.h>
+#include <stc/algorithm.h>
#include <stdio.h>
bool isPrime(long long i) {
@@ -137,10 +139,10 @@ 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, ...
+ crange R = crange_init(1001, INT64_MAX, 2); // 1001, 1003, ...
c_forfilter (i, crange, R,
isPrime(*i.ref) &&
@@ -158,11 +160,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 +172,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 +205,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};
+ ints_sort_n(nums, c_arraylen(nums)); // note: function name derived from i_key
+ 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,12 +275,13 @@ 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`
+**ccharptr** - Non-owning `const char*` "class" element type: `#define i_keyclass ccharptr`
```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);
+typedef const char* ccharptr;
+int ccharptr_cmp(const ccharptr* x, const ccharptr* y);
+uint64_t ccharptr_hash(const ccharptr* x);
+ccharptr ccharptr_clone(ccharptr sp);
+void ccharptr_drop(ccharptr* x);
```
Default implementations
```c
@@ -273,100 +293,6 @@ Type c_default_clone(Type val); // return val
Type c_default_toraw(const Type* p); // return *p
void c_default_drop(Type* p); // does nothing
```
-
----
-## Coroutines
-This is a much improved implementation of
-[Simon Tatham's coroutines](https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html),
-which utilizes the *Duff's device* trick. Tatham's implementation is not typesafe,
-and it always allocates the coroutine's internal state dynamically. But crucially,
-it does not let the coroutine do self-cleanup on early finish - i.e. it
-only frees the initial dynamically allocated memory.
-
-In this implementation, a coroutine may have any signature, but it should
-take a struct pointer as parameter, which must contain the member `int cco_state;`
-The struct should normally store all the *local* variables to be used in the
-coroutine. It can also store input and output data if desired.
-
-The coroutine example below generates Pythagorian triples, but the calling loop
-skips the triples which are upscaled version of smaller ones, by checking
-the gcd() function. It also ensures that it stops when the diagonal size >= 100:
-
-[ [Run this code](https://godbolt.org/z/coqqrfbd5) ]
-```c
-#include <stc/calgo.h>
-
-struct triples {
- int n; // input: max number of triples to be generated.
- int a, b, c;
- int cco_state; // required member
-};
-
-bool triples_next(struct triples* i) { // coroutine
- cco_begin(i);
- for (i->c = 5; i->n; ++i->c) {
- for (i->a = 1; i->a < i->c; ++i->a) {
- for (i->b = i->a + 1; i->b < i->c; ++i->b) {
- if ((int64_t)i->a*i->a + (int64_t)i->b*i->b == (int64_t)i->c*i->c) {
- cco_yield(true);
- if (--i->n == 0) cco_return;
- }
- }
- }
- }
- cco_final: // required label
- puts("done");
- cco_end(false);
-}
-
-int gcd(int a, int b) { // greatest common denominator
- while (b) {
- int t = a % b;
- a = b;
- b = t;
- }
- return a;
-}
-
-int main()
-{
- struct triples t = {.n=INT32_MAX};
- int n = 0;
-
- while (triples_next(&t)) {
- // Skip triples with GCD(a,b) > 1
- if (gcd(t.a, t.b) > 1)
- continue;
-
- // Stop when c >= 100
- if (t.c < 100)
- printf("%d: [%d, %d, %d]\n", ++n, t.a, t.b, t.c);
- else
- cco_stop(&t); // cleanup in next coroutine call/resume
- }
-}
-```
-### Coroutine API
-**Note**: *cco_yield()* may not be called inside a `switch` statement. Use `if-else-if` constructs instead.
-To resume the coroutine from where it was suspended with *cco_yield()*, simply call the coroutine again.
-
-| | Function / operator | Description |
-|:----------|:-------------------------------------|:----------------------------------------|
-| | `cco_final:` | Obligatory label in coroutine |
-| | `cco_return;` | Early return from the coroutine |
-| `bool` | `cco_alive(ctx)` | Is coroutine in initial or suspended state? |
-| `bool` | `cco_suspended(ctx)` | Is coroutine in suspended state? |
-| `void` | `cco_begin(ctx)` | Begin coroutine block |
-| `rettype` | `cco_end(retval)` | End coroutine block with return value |
-| `void` | `cco_end()` | End coroutine block |
-| `rettype` | `cco_yield(retval)` | Suspend execution and return a value |
-| `void` | `cco_yield()` | Suspend execution |
-| `rettype` | `cco_yield(corocall2, ctx2, retval)` | Yield from another coroutine and return val |
-| `void` | `cco_yield(corocall2, ctx2)` | Yield from another coroutine |
-| | From the caller side: | |
-| `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` |
-| `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) |
-
---
## RAII scope macros
General ***defer*** mechanics for resource acquisition. These macros allows you to specify the
@@ -385,6 +311,7 @@ The **checkauto** utility described below, ensures that the `c_auto*` macros are
```c
// `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 +358,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 +375,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/carc_api.md b/docs/carc_api.md
index 48b64ff0..3e394378 100644
--- a/docs/carc_api.md
+++ b/docs/carc_api.md
@@ -6,29 +6,35 @@ 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).
## Header file and declaration
```c
-#define i_type // full typename of the carc
-#define i_val // value: 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_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_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // carc container type name
+#define i_cmp <f> // three-way compareison. REQUIRED IF i_key is a non-integral type
+ // Note that containers of carcs will "inherit" i_cmp
+ // when using carc in containers with i_valboxed MyArc - ie. the i_type.
+#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type.
+#define i_keydrop <f> // destroy element func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined.
+
+#define i_keyraw <t> // convertion type (lookup): default to {i_key}
+#define i_keyto <f> // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined.
+#define i_keyfrom <f> // from-raw func.
+
+#define i_opt c_no_atomic // Non-atomic reference counting, like Rust Rc.
+#define i_tag <s> // 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 +42,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 +55,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 +64,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 +84,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 +95,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..7d25aed8 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)
@@ -14,30 +14,35 @@ See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory
## Header file and declaration
```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_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_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_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // cbox container type name
+#define i_cmp <f> // three-way compareison. REQUIRED IF i_key is a non-integral type
+ // Note that containers of carcs will "inherit" i_cmp
+ // when using carc in containers with i_valboxed MyArc - ie. the i_type.
+#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type.
+#define i_keydrop <f> // destroy element func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED if i_keydrop is defined, unless 'i_opt c_no_clone' is defined.
+
+#define i_keyraw <t> // convertion type (lookup): default to {i_key}
+#define i_keyto <f> // convertion func i_key* => i_keyraw: REQUIRED IF i_keyraw defined.
+#define i_keyfrom <f> // from-raw func.
+
+#define i_tag <s> // alternative typename: cbox_{i_tag}. i_tag defaults to i_key
+#define i_keyclass <t> // Use instead of i_key when functions {i_key}_clone,
+ // {i_key}_drop and {i_keyraw}_cmp exist.
+#define i_keyboxed <t> // Use instead of i_key when key is a carc- or a cbox-type.
#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
+Unless `c_use_cmp` is defined, 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 +51,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 +60,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 +82,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 +92,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/cdeq_api.md b/docs/cdeq_api.md
index fc11fe66..3ce58e78 100644
--- a/docs/cdeq_api.md
+++ b/docs/cdeq_api.md
@@ -1,24 +1,27 @@
# 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.
## Header file and declaration
```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_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_tag // alternative typename: cdeq_{i_tag}. i_tag defaults to i_val
+#define i_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // cdeq container type name
+#define i_cmp <f> // three-way compare of two i_keyraw*.
+#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type.
+#define i_keydrop <f> // destroy value func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_keydrop is defined
+
+#define i_keyraw <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_keyto <f> // convertion func i_key* => i_keyraw
+
+#define i_tag <s> // 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 +35,76 @@ 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_pull_front(cdeq_X* self); // move out front element
-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_value cdeq_X_pull_back(cdeq_X* self); // move out last element
-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..a24d813b 100644
--- a/docs/clist_api.md
+++ b/docs/clist_api.md
@@ -22,16 +22,17 @@ 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_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // clist container type name
+#define i_cmp <f> // three-way compare two i_keyraw*
+#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type.
+#define i_keydrop <f> // destroy value func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_keydrop defined
+
+#define i_keyraw <t> // convertion "raw" type (default: {i_key})
+#define i_keyto <f> // convertion func i_key* => i_keyraw
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_tag <s> // alternative typename: cpque_{i_tag}. i_tag defaults to i_key
#include <stc/clist.h>
```
@@ -53,50 +54,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 +109,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 +118,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 +155,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 +190,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..8e29efe1 100644
--- a/docs/cmap_api.md
+++ b/docs/cmap_api.md
@@ -9,34 +9,33 @@ 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.
## Header file and declaration
```c
-#define i_type // container type name (default: cmap_{i_key})
-#define i_key // hash key: REQUIRED
-#define i_val // map value: REQUIRED
-#define i_hash // hash func i_keyraw*: REQUIRED IF i_keyraw is non-pod type
-#define i_eq // equality comparison two i_keyraw*: REQUIRED IF i_keyraw is a
- // non-integral type. Three-way i_cmp may alternatively be specified.
-#define i_keydrop // destroy key func - defaults to empty destruct
-#define i_keyclone // REQUIRED IF i_keydrop defined
-#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_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop 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_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_key <t> // key type: REQUIRED.
+#define i_val <t> // mapped value type: REQUIRED.
+#define i_type <t> // container type name (default: cmap_{i_key})
+#define i_hash <f> // hash func i_keyraw*: REQUIRED IF i_keyraw is non-pod type
+#define i_eq <f> // equality comparison two i_keyraw*: REQUIRED IF i_keyraw is a
+ // non-integral type. Three-way i_cmp may alternatively be specified.
+#define i_keydrop <f> // destroy key func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_keydrop defined
+#define i_keyraw <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_keyto <f> // convertion func i_key* => i_keyraw
+
+#define i_valdrop <f> // destroy value func - defaults to empty destruct
+#define i_valclone <f> // REQUIRED IF i_valdrop defined
+#define i_valraw <t> // convertion "raw" type - defaults to i_val
+#define i_valfrom <f> // convertion func i_valraw => i_val
+#define i_valto <f> // convertion func i_val* => i_valraw
+
+#define i_tag <s> // alternative typename: cmap_{i_tag}. i_tag defaults to i_val
#include <stc/cmap.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
@@ -72,7 +71,8 @@ cmap_X_result cmap_X_insert_or_assign(cmap_X* self, i_key key, i_val map
cmap_X_result cmap_X_push(cmap_X* self, cmap_X_value entry); // similar to insert
cmap_X_result cmap_X_emplace(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // no change if rkey in map
-cmap_X_result cmap_X_emplace_or_assign(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update
+cmap_X_result cmap_X_emplace_or_assign(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update mapped
+cmap_X_result cmap_X_emplace_key(cmap_X* self, i_keyraw rkey); // see example 1.
int cmap_X_erase(cmap_X* self, i_keyraw rkey); // return 0 or 1
cmap_X_iter cmap_X_erase_at(cmap_X* self, cmap_X_iter it); // return iter after it
@@ -86,13 +86,14 @@ cmap_X_iter cmap_X_advance(cmap_X_iter it, cmap_X_ssize n);
cmap_X_value cmap_X_value_clone(cmap_X_value val);
cmap_X_raw cmap_X_value_toraw(cmap_X_value* pval);
```
-Helpers:
+Free helper functions:
```c
-uint64_t c_default_hash(const X *obj); // macro, calls cfasthash(obj, sizeof *obj)
-uint64_t cstrhash(const char *str); // string hash funcion, uses strlen()
-uint64_t cfasthash(const void *data, intptr_t len); // base hash function
+uint64_t stc_hash(const void *data, intptr_t len); // base hash function
+uint64_t stc_strhash(const char *str); // string hash funcion, uses strlen()
+uint64_t stc_nextpow2(intptr_t i); // get next power of 2 >= i
-// equalto template parameter functions:
+// hash/equal template default functions:
+uint64_t c_default_hash(const X *obj); // macro, calls stc_hash(obj, sizeof *obj)
bool c_default_eq(const i_keyraw* a, const i_keyraw* b); // *a == *b
bool c_memcmp_eq(const i_keyraw* a, const i_keyraw* b); // !memcmp(a, b, sizeof *a)
```
@@ -114,16 +115,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"}
@@ -138,6 +140,11 @@ int main()
cmap_str_emplace(&umap, "BLACK", "#000000");
cmap_str_emplace(&umap, "WHITE", "#FFFFFF");
+ // Insert only if "CYAN" is not in the map: create mapped value when needed only.
+ cmap_str_result res = cmap_str_emplace_key(&umap, "CYAN");
+ if (res.inserted)
+ res.ref->second = cstr_from("#00FFFF"); // must assign second if key was inserted.
+
// 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")));
@@ -157,13 +164,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 +214,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 +249,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 +275,7 @@ Output:
### Example 5: Advanced
Key type is struct.
```c
+#define i_implement
#include <stc/cstr.h>
typedef struct {
@@ -274,7 +283,7 @@ typedef struct {
cstr country;
} Viking;
-#define Viking_init() ((Viking){cstr_NULL, cstr_NULL})
+#define Viking_init() ((Viking){.name={0}, .country={0}})
static inline int Viking_cmp(const Viking* a, const Viking* b) {
int c = cstr_cmp(&a->name, &b->name);
@@ -301,7 +310,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 +344,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 {
@@ -372,11 +382,11 @@ static inline RViking Viking_toraw(const Viking* vp) {
#define i_keyraw RViking
#define i_keyfrom Viking_from
#define i_opt c_no_clone // disable map cloning
-#define i_hash(rp) (cstrhash(rp->name) ^ cstrhash(rp->country))
+#define i_hash(rp) (stc_strhash(rp->name) ^ stc_strhash(rp->country))
#define i_val int
#include <stc/cmap.h>
-int main()
+int main(void)
{
Vikings vikings = {0};
diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md
new file mode 100644
index 00000000..b917e0a1
--- /dev/null
+++ b/docs/coroutine_api.md
@@ -0,0 +1,292 @@
+# STC [coroutine](../include/stc/coroutine.h): Coroutines
+![Coroutine](pics/coroutine.jpg)
+
+An implementation of stackless coroutines, which are lightweight threads, providing a blocking
+context cheaply using little memory per coroutine.
+
+Coroutines are used to accomplish a non-preempted form of concurrency known as cooperative multitasking and, therefore, do not incur context switching when yielding to another thread. Within a coroutine, **yield** and **await** is accomplished by utilizing Duff's device within a thread's function and an external variable used in within the switch statement. This allows jumping (resuming) from a yield upon another function call. In order to block threads, these yields may be guarded by a conditional so that successive calls to the same function will yield unless the guard conditional is true.
+
+Because these coroutines are stackless, local variables within the coroutine where usage crosses `cco_yield` or `cco_await` must be stored in a struct which is passed as pointer to the coroutine. This has the advantages that they become very lightweight and therefore useful on severely memory constrained systems like small microcontrollers where other solutions are impractical or less desirable.
+
+### Coroutine API
+
+NB! ***cco_yield\*()*** / ***cco_await\*()*** may not be called from within a `switch` statement in a
+`cco_routine` scope; Use `if-else-if` constructs instead.
+
+| | Function / operator | Description |
+|:----------|:-------------------------------------|:----------------------------------------|
+|`cco_result` | `CCO_DONE`, `CCO_AWAIT`, `CCO_YIELD` | Default set of return values from coroutines |
+| | `cco_final:` | 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(ret);` | Yield/suspend execution (return ret) |
+| | `cco_yield_final();` | Yield final suspend, enter cleanup-state |
+| | `cco_yield_final(ret);` | Yield a final value |
+| | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)|
+| | `cco_await_call(cocall);` | Await for subcoro to finish (returns its ret value) |
+| | `cco_await_call(cocall, retbit);` | Await for subcoro's return to be in (retbit \| CCO_DONE) |
+| | `cco_return;` | Return from coroutine (inside cco_routine) |
+| | Task objects: | |
+| | `cco_task_struct(Name, ...);` | Define a coroutine task struct |
+| | `cco_await_task(task, cco_runtime* rt);`| Await for task to finish |
+| | `cco_await_task(task, rt, retbit);` | Await for task's return to be in (retbit \| CCO_DONE) |
+|`cco_result`| `cco_resume_task(task, rt);` | Resume suspended task |
+| | Semaphores: | |
+| | `cco_sem` | Semaphore type |
+| | `cco_await_sem(sem)` | Await for the semaphore count > 0 |
+| `cco_sem` | `cco_sem_from(long value)` | Create semaphore |
+| | `cco_sem_set(sem, long value)` | Set semaphore value |
+
+| | `cco_sem_release(sem)` | Signal the semaphore (count += 1) |
+| | Timers: | |
+| | `cco_timer` | Timer type |
+| | `cco_await_timer(tm, double sec)` | Await secs for timer to expire (usec prec.)|
+| | `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_blocking_call(cocall) {}` | Run blocking until cocall is finished |
+| | `cco_blocking_task(task) {}` | Run blocking until task is finished |
+| | `cco_blocking_task(task, rt, STACKSZ) {}`| Run blocking until task 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.) |
+
+
+## Implementation and examples
+
+This small implementation of coroutines is inspired by
+[Simon Tatham's coroutines](https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html) and
+[Adam Dunkel's photothreads](https://dunkels.com/adam/pt), but provides big improvements regarding
+ergonomics, features, and type-safety. Crucially, it also allows coroutines to self-cleanup when
+cancelled (not resumed until they are done).
+
+A coroutine function may have almost any signature, but the implementation adds support for
+coroutines which returns an int, indicating CCO_DONE, CCO_AWAIT, or CCO_YIELD. It should also
+take a struct pointer as parameter which must contains the member `int cco_state`. The struct should
+normally store all *local* variables to be used within the coroutine, along with *input* and *output* data
+for the coroutine.
+
+Note that this implementation is not limited to support a certain set of coroutine types,
+like generators. It can even operate like stackfull coroutines, i.e. you can efficiently
+yield or await from a (deeply) nested coroutine call using cco_task objects described later.
+
+The first example is a generator of Pythagorian triples, and stops when diagonal size > max_c.
+
+[ [Run this code](https://godbolt.org/z/d5zW3f9Gv) ]
+```c
+#include <stc/coroutine.h>
+#include <stdio.h>
+#include <stdio.h>
+// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/
+
+struct triples {
+ int max_c; // input: max c.
+ int a, b, c; // output
+ int cco_state; // required member
+};
+
+int triples(struct triples* i) {
+ cco_routine(i) { // the coroutine scope!
+ for (i->c = 5;; ++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)
+ {
+ if (i->c > i->max_c)
+ cco_return; // "jump" to cco_final if defined, else exit scope.
+ cco_yield();
+ }
+ }
+ }
+ }
+ cco_final:
+ puts("done");
+ }
+ return 0; // CCO_DONE
+}
+
+int main(void) {
+ struct triples co = {.max_c = 25};
+ int n = 0;
+
+ cco_blocking_call(triples(&co)) {
+ printf("%d: [%d, %d, %d]\n", ++n, co.a, co.b, co.c);
+ }
+}
+```
+The next variant skips the triples which are upscaled version of smaller ones by checking
+the gcd() function. Note that the gcd1_triples struct contains the triples struct so that
+both functions have separate call frames:
+
+[ [Run this code](https://godbolt.org/z/a7da9M8P5) ]
+```c
+int gcd(int a, int b) { // greatest common denominator
+ while (b) {
+ int t = a % b;
+ a = b;
+ b = t;
+ }
+ return a;
+}
+
+struct gcd1_triples {
+ int max_n, max_c, count; // input: max_n, max_c limit #triples to be generated.
+ struct triples tri; // triples call frame
+ int cco_state;
+};
+
+int gcd1_triples(struct gcd1_triples* i)
+{
+ cco_routine(i) {
+ cco_reset(&i->tri);
+ i->tri.max_c = i->max_c;
+
+ while (triples(&i->tri) != CCO_DONE) {
+ // Skip triples with GCD(a,b) > 1
+ if (gcd(i->tri.a, i->tri.b) > 1)
+ continue;
+
+ // Done when count > max_n
+ if (++i->count > i->max_n)
+ cco_return;
+ else
+ cco_yield();
+ }
+ cco_final:
+ cco_stop(&i->tri); // to cleanup state if still active
+ triples(&i->tri); // do cleanup (or no-op if done)
+ }
+ return 0;
+}
+
+int main(void) {
+ struct gcd1_triples co = {.max_n = 100, .max_c = 100};
+ int n = 0;
+
+ cco_blocking_call(gcd1_triples(&co)) {
+ printf("%d: [%d, %d, %d]\n", ++n, co.tri.a, co.tri.b, co.tri.c);
+ }
+}
+```
+When using ***cco_blocking_call()***, the coroutine is continuously resumed after each yield suspension.
+However, this means that it first calls ***gcd1_triples()***, which immediately jumps to after the `cco_yield`
+-statement and calls ***triples()***, which again jumps and resumes after its `cco_yield`-statement. This
+is efficient only when yielding or awaiting from the top- or second-level call like here, but naturally not
+when couroutine calls are more deeply nested or recursive.
+
+The STC coroutine implementation therefore also contains task-objects (`cco_task`), which are base-coroutine
+objects/enclosures. These can be executed using ***cco_blocking_task()*** instead of ***cco_blocking_call()***.
+Inner coroutine calls are done by ***cco_await_task()***, where you may await for a certain return value, normally CCO_YIELD or just CCO_DONE. It uses a stack of pointers of task-enclosures to call the current
+inner-level function directly. The task-objects have the added benefit that coroutines can be managed
+by a scheduler, which is useful when dealing with large numbers of coroutines (like in many games and
+simulations).
+
+Note that these two modes may be mixed, and that for short-lived coroutines (only a few suspends),
+it is often beneficial to call the sub-coroutine directly rather than via ***cco_await_task()***
+(which pushes the task on top of the runtime stack and yields - then executed on next resume).
+
+The following example uses task-objects with 3-levels deep coroutine calls. It emulates an async generator
+by awaiting a few seconds before producing a number, using a timer.
+```c
+// https://mariusbancila.ro/blog/2020/06/22/a-cpp20-coroutine-example/
+#include <time.h>
+#include <stdio.h>
+#define i_static
+#include <stc/cstr.h>
+#include <stc/coroutine.h>
+
+cco_task_struct (next_value,
+ int val;
+ cco_timer tm;
+);
+
+int next_value(struct next_value* co, cco_runtime* rt)
+{
+ cco_routine (co) {
+ while (true) {
+ cco_await_timer(&co->tm, 1 + rand() % 2); // suspend with CCO_AWAIT
+ co->val = rand();
+ cco_yield(); // suspend with CCO_YIELD
+ }
+ }
+ return 0;
+}
+
+void print_time()
+{
+ time_t now = time(NULL);
+ char mbstr[64];
+ strftime(mbstr, sizeof(mbstr), "[%H:%M:%S]", localtime(&now));
+ printf("%s ", mbstr);
+}
+
+// PRODUCER
+cco_task_struct (produce_items,
+ struct next_value next;
+ cstr text;
+);
+
+int produce_items(struct produce_items* p, cco_runtime* rt)
+{
+ cco_routine (p) {
+ p->text = cstr_init();
+ p->next.cco_func = next_value;
+ while (true)
+ {
+ // await for CCO_YIELD (or CCO_DONE)
+ cco_await_task(&p->next, rt, CCO_YIELD);
+ cstr_printf(&p->text, "item %d", p->next.val);
+ print_time();
+ printf("produced %s\n", cstr_str(&p->text));
+ cco_yield();
+ }
+ cco_final:
+ cstr_drop(&p->text);
+ puts("done produce");
+ }
+ return 0;
+}
+
+// CONSUMER
+cco_task_struct (consume_items,
+ int n, i;
+ struct produce_items produce;
+);
+
+int consume_items(struct consume_items* c, cco_runtime* rt)
+{
+ cco_routine (c) {
+ c->produce.cco_func = produce_items;
+
+ for (c->i = 1; c->i <= c->n; ++c->i)
+ {
+ printf("consume #%d\n", c->i);
+ cco_await_task(&c->produce, rt, CCO_YIELD);
+ print_time();
+ printf("consumed %s\n", cstr_str(&c->produce.text));
+ }
+ cco_final:
+ cco_stop(&c->produce);
+ cco_resume_task(&c->produce, rt);
+ puts("done consume");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct consume_items consume = {
+ .n = 5,
+ .cco_func = consume_items,
+ };
+ cco_blocking_task(&consume);
+}
+```
diff --git a/docs/cpque_api.md b/docs/cpque_api.md
index 962ee162..247424b4 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_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // cpque container type name
+#define i_less <f> // compare two i_key* : REQUIRED IF i_key/i_keyraw is a non-integral type
+#define i_keydrop <f> // destroy value func - defaults to empty destruct
+#define i_keyclone <f> // 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 <t> // convertion type
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_keyto <f> // convertion func i_key* => i_keyraw.
-#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_val
+#define i_tag <s> // 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,30 +56,30 @@ 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);
- crand_unif_t dist = crand_unif_init(0, N * 10);
+ crand_uniform_t dist = crand_uniform_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));
+ cpque_i_push(&heap, crand_uniform(&rng, &dist));
// Add some negative ones.
int nums[] = {-231, -32, -873, -4, -343};
diff --git a/docs/cqueue_api.md b/docs/cqueue_api.md
index 9ea4b148..ba4411b7 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_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // cqueue container type name
+#define i_keydrop <f> // destroy value func - defaults to empty destruct
+#define i_keyclone <f> // 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 <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_keyto <f> // convertion func i_key* => i_keyraw
-#define i_tag // alternative typename: cqueue_{i_tag}. i_tag defaults to i_val
+#define i_tag <s> // 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,36 @@ 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_value cqueue_X_pull(cqueue_X* self); // move out last element
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 +63,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..c6491243 100644
--- a/docs/crandom_api.md
+++ b/docs/crandom_api.md
@@ -1,35 +1,30 @@
# 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
+This features a *64-bit PRNG* named **crand64**, and can generate bounded uniform and normal
distributed random numbers.
See [random](https://en.cppreference.com/w/cpp/header/random) for similar c++ functionality.
## Description
-**stc64** is a novel, extremely fast PRNG by Tyge Løvset, suited for parallel usage. It features
-Weyl-sequences as part of its state. It is inspired on *sfc64*, but has a different output function
-and state size.
+**crand64** is a very fast PRNG, suited for parallel usage. It is based on *sfc64*, but has a
+different output function and state size. It features a Weyl-sequence as part of its state.
-**sfc64** is the fastest among *pcg*, *xoshiro`**`*, and *lehmer*. It is equally fast as *sfc64* on
-most platforms. *wyrand* is faster on platforms with fast 128-bit multiplication, and has 2^64 period
-length (https://github.com/lemire/SwiftWyhash/issues/10). However, *wyrand* is not suited for massive
-parallel usage due to its limited total minimal period length.
+**crand64** is faster or equally fast as *wyrand*, *xoshiro\*\**, *sfc64*, and *romu_trio*
+with both **clang 16.0** and **gcc 13.1** from the [prng_bench.c](../misc/benchmarks/various/prng_bench.cpp)
+on windows 11, Ryzen 7 5700X. (clang does not optimize *xoshiro\*\** and *sfc64* as well as gcc does).
-**stc64** does not require multiplication or 128-bit integer operations. It has 320 bit state,
-but updates only 256 bit per generated number.
+**crand64** has no jump *function*, but each odd number Weyl-increment (state[4]) starts a new
+unique 2^64 *minimum* length period, i.e. virtually unlimitied number of unique threads.
+In contrast, *wyrand* and *sfc64* have only a (total) minimum period of 2^64 (*romu_trio* has
+no guarantees), and may therefore not be suited for massive parallel usage (for purists).
-There is no *jump function*, but each odd number Weyl-increment (state[4]) starts a new
-unique 2^64 *minimum* length period. For a single thread, a minimum period of 2^127 is generated
-when the Weyl-increment is incremented by 2 every 2^64 output.
+**crand64** does not require multiplication or 128-bit integer operations. It has 320 bit state,
+where 64-bits are constant per instance.
-**stc64** passes *PractRand* (tested up to 8TB output), Vigna's Hamming weight test, and simple
-correlation tests, i.e. *n* interleaved streams with only one-bit differences in initial state.
-Also 32-bit and 16-bit versions passes PractRand up to their size limits.
-
-For more, see the PRNG shootout by Vigna: http://prng.di.unimi.it and a debate between the authors of
-xoshiro and pcg (Vigna/O'Neill) PRNGs: https://www.pcg-random.org/posts/on-vignas-pcg-critique.html
+**crand64** passes *PractRand* (tested up to 8TB output), Vigna's Hamming weight test, and simple
+correlation tests. The 16- and 32-bit variants also passes PractRand up to their size limits.
## Header file
@@ -41,32 +36,33 @@ All crand definitions and prototypes are available by including a single header
## Methods
```c
-void csrand(uint64_t seed); // seed global stc64 prng
+void csrand(uint64_t seed); // seed global crand64 prng
uint64_t crand(void); // global crand_u64(rng)
double crandf(void); // global crand_f64(rng)
-crand_t crand_init(uint64_t seed); // stc64_init(s) is deprecated
+crand_t crand_init(uint64_t seed);
uint64_t crand_u64(crand_t* rng); // range [0, 2^64 - 1]
double crand_f64(crand_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]
+crand_uniform_t crand_uniform_init(int64_t low, int64_t high); // uniform-distribution range
+int64_t crand_uniform(crand_t* rng, crand_uniform_t* dist);
-crand_norm_t crand_norm_init(double mean, double stddev); // normal-distribution
-double crand_norm(crand_t* rng, crand_norm_t* dist);
+crand_normal_t crand_normal_init(double mean, double stddev); // normal-gauss distribution
+double crand_normal(crand_t* rng, crand_normal_t* dist);
```
## Types
| Name | Type definition | Used to represent... |
|:-------------------|:------------------------------------------|:-----------------------------|
| `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 |
+| `crand_uniform_t` | `struct {int64_t lower; uint64_t range;}` | Integer uniform distribution |
+| `crand_normal_t` | `struct {double mean, stddev;}` | Normal distribution type |
## Example
```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 +71,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;
@@ -85,17 +81,17 @@ int main()
// Setup random engine with normal distribution.
uint64_t seed = time(NULL);
crand_t rng = crand_init(seed);
- crand_norm_t dist = crand_norm_init(Mean, StdDev);
+ crand_normal_t dist = crand_normal_init(Mean, StdDev);
// Create histogram map
- csmap_i mhist = csmap_i_init();
+ csmap_i mhist = {0};
c_forrange (N) {
- int index = (int)round(crand_norm(&rng, &dist));
+ int index = (int)round(crand_normal(&rng, &dist));
csmap_i_emplace(&mhist, index, 0).ref->second += 1;
}
// Print the gaussian bar chart
- cstr bar = cstr_init();
+ cstr bar = {0};
c_foreach (i, csmap_i, mhist) {
int n = (int)(i.ref->second * StdDev * Scale * 2.5 / N);
if (n > 0) {
diff --git a/docs/crawstr_api.md b/docs/crawstr_api.md
new file mode 100644
index 00000000..b63e532f
--- /dev/null
+++ b/docs/crawstr_api.md
@@ -0,0 +1,101 @@
+# STC [crawstr](../include/stc/crawstr.h): Null-terminated UTF8 String View
+![String](pics/string.jpg)
+
+The type **crawstr** is a ***null-terminated*** string view and refers to a constant contiguous sequence of
+char-elements with the first element of the sequence at position zero. The implementation holds two
+members: a pointer to constant char and a size. See [csview](csview_api.md) for a ***non null-terminated***
+string view/span type.
+
+Because **crawstr** is null-terminated, it can be an efficient replacent for `const char*`. It never
+allocates memory, and therefore need not be destructed. Its lifetime is limited by the source string
+storage. It keeps the length of the string, i.e. no need to call *strlen()* for various operations.
+
+## Header file
+
+All crawstr definitions and prototypes are available by including a single header file.
+
+```c
+#include <stc/crawstr.h>
+```
+## Methods
+
+```c
+crawstr crawstr_from(const char* str); // construct from const char*
+crawstr c_rs(const char literal_only[]); // construct from literal, no strlen()
+
+intptr_t crawstr_size(crawstr rs);
+bool crawstr_empty(crawstr rs); // check if size == 0
+void crawstr_clear(crawstr* self);
+csview crawstr_sv(crawstr rs); // convert to csview type
+
+bool crawstr_equals(crawstr rs, const char* str);
+intptr_t crawstr_find(crawstr rs, const char* str);
+bool crawstr_contains(crawstr rs, const char* str);
+bool crawstr_starts_with(crawstr rs, const char* str);
+bool crawstr_ends_with(crawstr rs, const char* str);
+
+crawstr_iter crawstr_begin(const crawstr* self);
+crawstr_iter crawstr_end(const crawstr* self);
+void crawstr_next(crawstr_iter* it); // utf8 codepoint step, not byte!
+crawstr_iter crawstr_advance(crawstr_iter it, intptr_t n);
+```
+
+#### Helper methods for usage in containers
+```c
+int crawstr_cmp(const crawstr* x, const crawstr* y);
+int crawstr_icmp(const crawstr* x, const crawstr* y); // depends on src/utf8code.c:
+bool crawstr_eq(const crawstr* x, const crawstr* y);
+uint64_t crawstr_hash(const crawstr* x);
+```
+
+#### UTF8 methods
+```c
+ // from utf8.h
+intptr_t utf8_size(const char *s);
+intptr_t utf8_size_n(const char *s, intptr_t nbytes); // number of UTF8 codepoints within n bytes
+const char* utf8_at(const char *s, intptr_t index); // from UTF8 index to char* position
+intptr_t utf8_pos(const char* s, intptr_t index); // from UTF8 index to byte index position
+unsigned utf8_chr_size(const char* s); // UTF8 character size: 1-4
+ // implemented in src/utf8code.c:
+bool utf8_valid(const char* s);
+bool utf8_valid_n(const char* s, intptr_t nbytes);
+uint32_t utf8_decode(utf8_decode_t *d, uint8_t byte); // decode next byte to utf8, return state.
+unsigned utf8_encode(char *out, uint32_t codepoint); // encode unicode cp into out buffer
+uint32_t utf8_peek(const char* s); // codepoint value of character at s
+uint32_t utf8_peek_off(const char* s, int offset); // codepoint value at utf8 pos (may be negative)
+```
+
+## Types
+
+| Type name | Type definition | Used to represent... |
+|:----------------|:---------------------------------------------|:-------------------------|
+| `crawstr` | `struct { const char *str; intptr_t size; }` | The string view type |
+| `crawstr_value` | `const char` | The element type |
+| `crawstr_iter` | `union { crawstr_value *ref; csview chr; }` | UTF8 iterator |
+
+## Example: UTF8 iteration and case conversion
+```c
+#define i_import
+#include <stc/cstr.h>
+#include <stc/crawstr.h>
+
+int main(void)
+{
+ crawstr rs = c_rs("Liberté, égalité, fraternité.");
+ printf("%s\n", rs.str);
+
+ c_foreach (i, crawstr, rs)
+ printf("%.*s ", c_SV(i.chr));
+ puts("");
+
+ cstr str = cstr_toupper_sv(crawstr_sv(rs));
+ printf("%s\n", cstr_str(&str));
+ cstr_drop(&str);
+}
+```
+Output:
+```
+Liberté, égalité, fraternité.
+L i b e r t é , é g a l i t é , f r a t e r n i t é .
+LIBERTÉ, ÉGALITÉ, FRATERNITÉ.
+```
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..928d63a8 100644
--- a/docs/cset_api.md
+++ b/docs/cset_api.md
@@ -7,19 +7,19 @@ A **cset** is an associative container that contains a set of unique objects of
## Header file and declaration
```c
-#define i_type // container type name (default: cset_{i_key})
-#define i_key // hash key: REQUIRED.
-#define i_hash // hash func: REQUIRED IF i_keyraw is a non-pod type.
-#define i_eq // equality comparison two i_keyraw*: !i_cmp is used if not defined.
-#define i_keydrop // destroy key func - defaults to empty destruct
-#define i_keyclone // REQUIRED IF i_keydrop defined
-
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#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_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // container type name
+#define i_hash <f> // hash func i_keyraw*: REQUIRED IF i_keyraw is non-pod type
+#define i_eq <f> // equality comparison two i_keyraw*: REQUIRED IF i_keyraw is a
+ // non-integral type. Three-way i_cmp may alternatively be specified.
+#define i_keydrop <f> // destroy key func: defaults to empty destruct
+#define i_keyclone <f> // clone func: REQUIRED IF i_keydrop defined
+
+#define i_keyraw <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key - defaults to plain copy
+#define i_keyto <f> // convertion func i_key* => i_keyraw - defaults to plain copy
+
+#define i_tag <s> // alternative typename: cmap_{i_tag}. i_tag defaults to i_key
#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..d739283b 100644
--- a/docs/csmap_api.md
+++ b/docs/csmap_api.md
@@ -15,25 +15,24 @@ See the c++ class [std::map](https://en.cppreference.com/w/cpp/container/map) fo
## Header file and declaration
```c
-#define i_type // container type name (default: cmap_{i_key})
-#define i_key // key: REQUIRED
-#define i_val // value: REQUIRED
-#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
-
-#define i_keydrop // destroy key func - defaults to empty destruct
-#define i_keyclone // REQUIRED IF i_valdrop defined
-#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_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop 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_tag // alternative typename: csmap_{i_tag}. i_tag defaults to i_val
-#define i_ssize // internal size rep. defaults to int32_t
+#define i_key <t> // key type: REQUIRED.
+#define i_val <t> // mapped value type: REQUIRED.
+#define i_type <t> // container type name (default: cmap_{i_key})
+#define i_cmp <f> // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
+
+#define i_keydrop <f> // destroy key func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_valdrop defined
+#define i_keyraw <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_keyto <f> // convertion func i_key* => i_keyraw
+
+#define i_valdrop <f> // destroy value func - defaults to empty destruct
+#define i_valclone <f> // REQUIRED IF i_valdrop defined
+#define i_valraw <t> // convertion "raw" type - defaults to i_val
+#define i_valfrom <f> // convertion func i_valraw => i_val
+#define i_valto <f> // convertion func i_val* => i_valraw
+
+#define i_tag <s> // alternative typename: csmap_{i_tag}. i_tag defaults to i_val
#include <stc/csmap.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
@@ -73,6 +72,7 @@ csmap_X_result csmap_X_push(csmap_X* self, csmap_X_value entry);
csmap_X_result csmap_X_emplace(csmap_X* self, i_keyraw rkey, i_valraw rmapped); // no change if rkey in map
csmap_X_result csmap_X_emplace_or_assign(csmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update rmapped
+csmap_X_result csmap_X_emplace_key(csmap_X* self, i_keyraw rkey); // if key not in map, mapped is left unassigned
int csmap_X_erase(csmap_X* self, i_keyraw rkey);
csmap_X_iter csmap_X_erase_at(csmap_X* self, csmap_X_iter it); // returns iter after it
@@ -84,7 +84,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 +103,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"}
@@ -148,8 +149,9 @@ Translate a
[C++ example using *insert* and *emplace*](https://en.cppreference.com/w/cpp/container/map/try_emplace)
to STC:
-[ [Run this code](https://godbolt.org/z/9d1PP77Pa) ]
+[ [Run this code](https://godbolt.org/z/b46W5Ezrb) ]
```c
+#define i_implement
#include <stc/cstr.h>
#define i_type strmap
#define i_key_str
@@ -165,7 +167,7 @@ static void print_result(strmap_result result) {
print_node(result.ref);
}
-int main()
+int main(void)
{
strmap m = {0};
@@ -182,6 +184,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 +192,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 +238,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..4875e021 100644
--- a/docs/cspan_api.md
+++ b/docs/cspan_api.md
@@ -1,9 +1,14 @@
# STC [cspan](../include/stc/cspan.h): Multi-dimensional Array View
![Array](pics/array.jpg)
-The **cspan** is templated non-owning *single* and *multi-dimensional* view of an array. It has similarities
-with Python's numpy array slicing and C++ [std::span](https://en.cppreference.com/w/cpp/container/span) /
-[std::mdspan](https://en.cppreference.com/w/cpp/container/mdspan), and others.
+The **cspan** types are templated non-owning *single* and *multi-dimensional* views of an array.
+It supports both row-major and column-major layout efficiently, in a addition to slicing
+capabilities similar to [python's numpy arrays](https://numpy.org/doc/stable/user/basics.indexing.html).
+Note that each dimension is currently limited to int32_t sizes and 8 dimensions (can be extended).
+
+See also C++
+[std::span](https://en.cppreference.com/w/cpp/container/span) /
+[std::mdspan](https://en.cppreference.com/w/cpp/container/mdspan) for similar functionality.
## Header file and declaration
**cspan** types are defined by the *using_cspan()* macro after the header is included.
@@ -21,182 +26,226 @@ 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.
-`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).
+All functions are type-safe. NOTE: the span argument itself is generally **not** side-effect safe -
+it may be expanded multiple times. However, all index arguments are safe, e.g.
+`cspan_at(&ms3, i++, j++, k++)` is safe, but `cspan_at(&spans[n++], i, j)` is an error! 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_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
+SpanType cspan_init(TYPE SpanType, {v1, v2, ...}); // make a 1-d cspan from values
+SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from a cvec, cstack, cpque (heap)
+SpanType cspan_from_n(ValueType* ptr, int32_t n); // make a 1-d cspan from a pointer and length
+SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from a C array
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
-
-ValueType* cspan_at(const SpanTypeN* self, intptr_t x, ...); // #args must match input span rank
+intptr_t cspan_index(const SpanTypeN* self, int32_t x, ..); // offset index at i, j, ..
+
+ValueType* cspan_at(const SpanTypeN* self, int32_t x, ...); // num args is compile-time checked
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);
+
+ // make a multi-dim cspan
+SpanTypeN cspan_md(ValueType* data, int32_t d1, int32_t d2, ...); // row-major layout
+SpanTypeN cspan_md_layout(cspan_layout layout, ValueType* data, int32_t d1, d2, ...);
+
+ // transpose a md span. Inverses layout and axes only.
+void cspan_transpose(const SpanTypeN* self);
+cspan_layout cspan_get_layout(const SpanTypeN* self);
+bool cspan_is_rowmajor(const SpanTypeN* self);
+bool cspan_is_colmajor(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, int32_t offset, int32_t count);
+SpanType2 cspan_subspan2(const SpanType2* span, int32_t offset, int32_t count);
+SpanType3 cspan_subspan3(const SpanType3* span, int32_t offset, int32_t count);
+
+ // create a sub md span of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL});
+OutSpan cspan_submd2(const SpanType2* parent, int32_t x); // return a 1d subspan from a 2d span.
+OutSpanN cspan_submd3(const SpanType3* parent, int32_t x, ...); // return a 1d or 2d subspan from a 3d span.
+OutSpanN cspan_submd4(const SpanType4* parent, int32_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 SpanTypeM* parent, {x0,x1}, {y0,y1}.., {N0,N1});
```
## Types
-
-| Type name | Type definition | Used to represent... |
+| 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 |
-
+| SpanTypeN_value | `ValueType` | The ValueType |
+| SpanTypeN | `struct { ValueType *data; int32_t shape[N]; .. }` | SpanType with rank N |
+| `cspan_tupleN` | `struct { intptr_t d[N]; }` | Strides for each rank |
+| `cspan_layout` | `enum { c_ROWMAJOR, c_COLMAJOR }` | Multi-dim layout |
+| `c_ALL` | `cspan_slice(&md, {1,3}, {c_ALL})` | Full extent |
+| `c_END` | `cspan_slice(&md, {1,c_END}, {2,c_END})` | End of extent |
+
## Example 1
-Dimension slicing in python, C, and C++:
+[ [Run this code](https://godbolt.org/z/Tv9d1T3TM) ]
+```c
+#include <stdio.h>
+#define i_key int
+#include <stc/cvec.h>
+
+#define i_key int
+#include <stc/cstack.h>
+
+#include <stc/cspan.h>
+using_cspan(intspan, int);
+
+void printMe(intspan container) {
+ printf("%d:", (int)cspan_size(&container));
+ c_foreach (e, intspan, container)
+ printf(" %d", *e.ref);
+ puts("");
+}
+
+int main(void)
+{
+ printMe( c_init(intspan, {1, 2, 3, 4}) );
+
+ int arr[] = {1, 2, 3, 4, 5};
+ printMe( (intspan)cspan_from_array(arr) );
+
+ cvec_int vec = c_init(cvec_int, {1, 2, 3, 4, 5, 6});
+ printMe( (intspan)cspan_from(&vec) );
+
+ cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7});
+ printMe( (intspan)cspan_from(&stk) );
+
+ intspan spn = c_init(intspan, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
+ printMe( (intspan)cspan_subspan(&spn, 2, 8) );
+
+ // cleanup
+ cvec_int_drop(&vec);
+ cstack_int_drop(&stk);
+}
+```
+
+## Example 2
+
+Multi-dimension slicing (first in python):
```py
import numpy as np
+def print_span(s2):
+ for i in range(s2.shape[0]):
+ for j in range(s2.shape[1]):
+ print(" {}".format(s2[i, j]), end='')
+ print('')
+ print('')
+
if __name__ == '__main__':
ms3 = np.array((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24), int)
- ms3 = np.reshape(ms3, (2, 3, 4))
- ss3 = ms3[:, 1:3, 2:]
- ss2 = ss3[1]
-
- for i in range(ss2.shape[0]):
- for j in range(ss2.shape[1]):
- print(" {}".format(ss2[i, j]), end='')
- print('')
+ ms3 = np.reshape(ms3, (2, 3, 4), order='C')
+ ss3 = ms3[:, 0:3, 2:]
+ a = ss3[1]
+ b = np.transpose(a)
- for i in ss2.flat:
- print(" {}".format(i), end='')
+ print_span(ms3[1])
+ print_span(a)
+ print_span(b)
-# 19 20 23 24
-# 19 20 23 24
+ for i in a.flat: print(" {}".format(i), end='')
+ print('')
+ for i in b.flat: print(" {}".format(i), end='')
+'''
+ 13 14 15 16
+ 17 18 19 20
+ 21 22 23 24
+
+ 15 16
+ 19 20
+ 23 24
+
+ 15 19 23
+ 16 20 24
+
+ 15 16 19 20 23 24
+ 15 19 23 16 20 24
+'''
```
-... can be written in C using cspan:
+... in C with STC cspan:
+
+[ [Run this code](https://godbolt.org/z/e3PeWe7e9) ]
```c
#include <stdio.h>
#include <stc/cspan.h>
-using_cspan3(myspan, int); // define myspan, myspan2, myspan3.
-
-int main() {
- 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 ss3 = cspan_slice(myspan3, &ms3, {c_ALL}, {1,3}, {2,c_END});
- myspan2 ss2 = cspan_submd3(&ss3, 1);
+using_cspan3(myspan, int); // define myspan, myspan2, myspan3.
- c_forrange (i, ss2.shape[0])
- c_forrange (j, ss2.shape[1])
- printf(" %d", *cspan_at(&ss2, i, j));
+void print_span(myspan2 ms) {
+ for (int i=0; i < ms.shape[0]; ++i) {
+ for (int j=0; j < ms.shape[1]; ++j)
+ printf(" %2d", *cspan_at(&ms, i, j));
+ puts("");
+ }
puts("");
-
- c_foreach (i, myspan2, ss2)
- printf(" %d", *i.ref);
}
-```
-... and (almost) in C++23:
-```c++
-#include <print>
-#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);
- auto ss3 = std::submdspan(ms3, std::full_extent, std::tuple{1,3}, std::tuple{2,4});
- auto ss2 = std::submdspan(ss3, 1, std::full_extent, std::full_extent);
+ myspan3 ms3 = cspan_md(arr, 2, 3, 4); // row-major layout
+ myspan3 ss3 = cspan_slice(myspan3, &ms3, {c_ALL}, {0,3}, {2,c_END});
+ myspan2 a = cspan_submd3(&ss3, 1);
+ myspan2 b = a;
+ cspan_transpose(&b);
- for (std::size_t i = 0; i < ss2.extent(0); ++i)
- for (std::size_t j = 0; j < ss2.extent(1); ++j)
- std::print(" {}", ss2[i, j]);
- std::println();
+ print_span((myspan2)cspan_submd3(&ms3, 1));
+ print_span(a);
+ print_span(b);
- // std::mdspan can't be iterated joined/flat!
+ c_foreach (i, myspan2, a) printf(" %d", *i.ref);
+ puts("");
+ c_foreach (i, myspan2, b) printf(" %d", *i.ref);
}
```
-## Example 2
+
+## Example 3
Slicing cspan without and with reducing the rank:
+
+[ [Run this code](https://godbolt.org/z/jjzcvPPxW) ]
```c
-#include <c11/print.h>
+#include <stdio.h>
#include <stc/cspan.h>
+#define i_key int
+#include <stc/cvec.h>
+#define i_key int
+#include <stc/cstack.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,
+ 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);
- // reduce rank: (i.e. span3[1])
- Span2 span2 = cspan_submd3(&span3, 1);
-
- puts("\niterate span2 flat:");
- c_foreach (i, Span2, span2)
- print(" {}", *i.ref);
- puts("");
-
// slice without reducing rank:
Span3 ss3 = cspan_slice(Span3, &span3, {c_ALL}, {3,4}, {c_ALL});
- puts("\niterate ss3 by dimensions:");
- 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(" |");
+ for (int i=0; i < ss3.shape[0]; ++i) {
+ for (int j=0; j < ss3.shape[1]; ++j) {
+ for (int k=0; k < ss3.shape[2]; ++k)
+ printf(" %2d", *cspan_at(&ss3, i, j, k));
+ puts("");
}
+ 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])
- print(" {:2}", *cspan_at(&ss2, i, j));
- print(" |");
+ for (int i=0; i < ss2.shape[0]; ++i) {
+ for (int j=0; j < ss2.shape[1]; ++j)
+ printf(" %2d", *cspan_at(&ss2, i, j));
+ puts("");
}
-
- puts("\niterate ss2 flat:");
- c_foreach (i, Span2, ss2)
- print(" {:2}", *i.ref);
- puts("");
}
```
-Output:
-```
-iterate span2 flat:
- 13 14 15 16 17 18 19 20 21 22 23 24
-
-iterate ss3 by dimensions:
- 10 11 12 |
- 22 23 24 |
-
-iterate ss2 by dimensions:
- 10 | 11 | 12 |
- 22 | 23 | 24 |
-
-iterate ss2 flat:
- 10 11 12 22 23 24
-```
diff --git a/docs/csset_api.md b/docs/csset_api.md
index e83ab857..21e38f61 100644
--- a/docs/csset_api.md
+++ b/docs/csset_api.md
@@ -8,18 +8,17 @@ See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) fo
## Header file and declaration
```c
-#define i_type // full typename of the container
-#define i_key // key: REQUIRED
-#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
-#define i_keydrop // destroy key func - defaults to empty destruct
-#define i_keyclone // REQUIRED IF i_keydrop defined
-
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#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_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // container type name
+#define i_cmp <f> // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
+#define i_keydrop <f> // destroy key func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_keydrop defined
+
+#define i_keyraw <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key - defaults to plain copy
+#define i_keyto <f> // convertion func i_key* => i_keyraw - defaults to plain copy
+
+#define i_tag <s> // 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..da0bc954 100644
--- a/docs/cstack_api.md
+++ b/docs/cstack_api.md
@@ -8,16 +8,16 @@ See the c++ class [std::stack](https://en.cppreference.com/w/cpp/container/stack
## Header file and declaration
```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 <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_type <t> // container type name
+#define i_keydrop <f> // destroy value func - defaults to empty destruct
+#define i_keyclone <f> // 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 <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_keyto <f> // convertion func i_key* => i_keyraw
-#define i_tag // alternative typename: cstack_{i_tag}. i_tag defaults to i_val
+#define i_tag <s> // 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,21 +41,24 @@ 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);
+void cstack_X_pop(cstack_X* self); // destroy last element
+cstack_X_value cstack_X_pull(cstack_X* self); // move out last element
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 +66,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..29dfe464 100644
--- a/docs/cstr_api.md
+++ b/docs/cstr_api.md
@@ -1,11 +1,17 @@
# STC [cstr](../include/stc/cstr.h): String
![String](pics/string.jpg)
-A **cstr** object represent sequences of characters. It supports an interface similar to that of a standard container of bytes, but adding features specifically designed to operate with strings of single-byte characters, terminated by the null character.
+A **cstr** object represent sequences of characters. It supports an interface similar
+to that of a standard container of bytes, but adding features specifically designed to
+operate with strings of single-byte characters, terminated by the null character.
-**cstr** has basic support for *UTF8* encoded strings, and has a set of compact and efficient functions for handling case-foldings and comparisons of UTF strings.
+**cstr** has basic support for *UTF8* encoded strings, and has a set of compact and
+efficient functions for handling case-conversion, iteration and indexing into UTF8
+codepoints.
-**cstr** uses short strings optimization (sso), which eliminates heap memory allocation for string capacity less than 24 bytes. `sizeof(cstr)` is also 24. In comparison, c++ `sizeof(std::string)` is typically 32, but sso capacity is only 15 bytes.
+**cstr** uses short strings optimization (sso), which eliminates heap memory allocation
+for string capacity up to 22 bytes. `sizeof(cstr)` is 24. In comparison, C++
+`sizeof(std::string)` is typically 32, but sso capacity is only 15 bytes.
## Header file
@@ -18,11 +24,12 @@ 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; empty string
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
cstr cstr_from_sv(csview sv); // construct cstr from csview
+cstr cstr_from_rs(crawstr rs); // construct cstr from crawstr
cstr cstr_with_capacity(intptr_t cap);
cstr cstr_with_size(intptr_t len, char fill); // repeat fill len times
cstr cstr_from_fmt(const char* fmt, ...); // printf() formatting
@@ -32,10 +39,11 @@ cstr* cstr_take(cstr* self, cstr s); // take owne
cstr cstr_move(cstr* self); // move string to caller, leave self empty
void cstr_drop(cstr* self); // destructor
-const char* cstr_str(const cstr* self); // cast to const char*
-char* cstr_data(cstr* self); // cast to mutable char*
-csview cstr_sv(const cstr* self); // cast to string view
-cstr_buf cstr_buffer(cstr* self); // cast to mutable buffer (with capacity)
+const char* cstr_str(const cstr* self); // to const char*
+csview cstr_sv(const cstr* self); // to csview
+crawstr cstr_rs(const cstr* self); // to crawstr
+char* cstr_data(cstr* self); // to mutable char*
+cstr_buf cstr_buffer(cstr* self); // to mutable buffer (with capacity)
intptr_t cstr_size(const cstr* self);
intptr_t cstr_capacity(const cstr* self);
@@ -132,11 +140,11 @@ Note that all methods with arguments `(..., const char* str, intptr_t n)`, `n` m
#### Helper methods:
```c
-int cstr_cmp(const cstr* s1, const cstr* s2);
-bool cstr_eq(const cstr* s1, const cstr* s2);
-bool cstr_hash(const cstr* self);
+int cstr_cmp(const cstr* s1, const cstr* s2);
+bool cstr_eq(const cstr* s1, const cstr* s2);
+uint64_t cstr_hash(const cstr* self);
-char* cstrnstrn(const char* str, const char* search, intptr_t slen, intptr_t nlen);
+char* stc_strnstrn(const char* str, intptr_t slen, const char* needle, intptr_t nlen);
```
## Types
@@ -145,7 +153,7 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt
|:----------------|:---------------------------------------------|:---------------------|
| `cstr` | `struct { ... }` | The string type |
| `cstr_value` | `char` | String element type |
-| `csview` | `struct { const char *str; intptr_t size; }` | String view type |
+| `cstr_iter` | `union { cstr_value *ref; csview chr; }` | String iterator |
| `cstr_buf` | `struct { char *data; intptr_t size, cap; }` | String buffer type |
## Constants and macros
@@ -153,13 +161,13 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt
| Name | Value |
|:------------------|:------------------|
| `c_NPOS` | `INTPTR_MAX` |
-| `cstr_NULL` | cstr null 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..76a803a8 100644
--- a/docs/csview_api.md
+++ b/docs/csview_api.md
@@ -1,87 +1,79 @@
-# STC [csview](../include/stc/csview.h): String View
+# STC [csview](../include/stc/csview.h): Sub-string View
![String](pics/string.jpg)
-The type **csview** is a string view and can refer to a constant contiguous sequence of char-elements with the first
-element of the sequence at position zero. The implementation holds two members: a pointer to constant char and a size.
+The type **csview** is a non-null terminated string view and can refer to a constant contiguous
+sequence of char-elements with the first element of the sequence at position zero. The implementation
+holds two members: a pointer to constant char and a size.
-**csview** is an efficient replacent for `const char*`. It never allocates memory, and therefore need not be destructed.
-Its lifetime is limited by the source string storage. It keeps the length of the string, and does not call *strlen()*
-when passing it around. It is faster when using`csview` as convertion type (raw) than `const char*` in associative
-containers with cstr keys.
+Because **csview** is non-null terminated, it cannot be a replacent view for `const char*` -
+see [crawstr](crawstr_api.md) for that. **csview** never allocates memory, and therefore need not be
+destructed. Its lifetime is limited by the source string storage. It keeps the length of the string,
+and does not need to call *strlen()* to acquire the length.
-Note: a **csview** may ***not be null-terminated***, and must therefore be printed like:
-`printf("%.*s", csview_ARG(sv))`.
+- **csview** iterators works on UTF8 codepoints - like **cstr** and **crawstr** (see Example 2).
+- Because it is null-terminated, it must be printed the following way:
+```c
+printf("%.*s", c_SV(sstr));
+```
-See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional
-description.
+See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view)
+for a functional description.
## Header file
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
```c
-csview c_sv(const char literal_only[]); // construct from literal, no strlen()
-csview c_sv(const char* str, intptr_t n); // construct from str and length n
-csview csview_lit(const char literal_only[]); // alias for c_sv(lit)
-csview csview_from(const char* str); // construct from const char*
-csview csview_from_n(const char* str, intptr_t n); // alias for c_sv(str, n)
-
-intptr_t csview_size(csview sv);
-bool csview_empty(csview sv);
-void csview_clear(csview* self);
-
-bool csview_equals(csview sv, csview sv2);
-intptr_t csview_find(csview sv, const char* str);
-intptr_t csview_find_sv(csview sv, csview find);
-bool csview_contains(csview sv, const char* str);
-bool csview_starts_with(csview sv, const char* str);
-bool csview_ends_with(csview sv, const char* str);
-
-csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); // negative pos count from end
-csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); // negative p1, p2 count from end
-csview csview_token(csview sv, const char* sep, intptr_t* start); // *start > sv.size after last token
+csview c_sv(const char literal_only[]); // construct from literal, no strlen()
+csview c_sv(const char* str, intptr_t n); // construct from str and length n
+csview csview_from(const char* str); // construct from const char*
+csview csview_from_n(const char* str, intptr_t n); // alias for c_sv(str, n)
+
+intptr_t csview_size(csview sv);
+bool csview_empty(csview sv);
+void csview_clear(csview* self);
+
+bool csview_equals(csview sv, const char* str);
+intptr_t csview_equals_sv(csview sv, csview find);
+intptr_t csview_find(csview sv, const char* str);
+intptr_t csview_find_sv(csview sv, csview find);
+bool csview_contains(csview sv, const char* str);
+bool csview_starts_with(csview sv, const char* str);
+bool csview_ends_with(csview sv, const char* str);
+csview csview_substr(csview sv, intptr_t pos, intptr_t n);
+csview csview_slice(csview sv, intptr_t pos1, intptr_t pos2);
+
+csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); // negative pos count from end
+csview csview_slice_ex(csview sv, intptr_t pos1, intptr_t pos2); // negative pos1, pos2 count from end
+csview csview_token(csview sv, const char* sep, intptr_t* start); // *start > sv.size after last token
```
#### UTF8 methods
```c
-intptr_t csview_u8_size(csview sv);
-csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len);
-bool csview_valid_utf8(csview sv); // requires linking with src/utf8code.c
-
-csview_iter csview_begin(const csview* self);
-csview_iter csview_end(const csview* self);
-void csview_next(csview_iter* it); // utf8 codepoint step, not byte!
-csview_iter csview_advance(csview_iter it, intptr_t n);
-
- // from utf8.h
-intptr_t utf8_size(const char *s);
-intptr_t utf8_size_n(const char *s, intptr_t nbytes); // number of UTF8 codepoints within n bytes
-const char* utf8_at(const char *s, intptr_t index); // from UTF8 index to char* position
-intptr_t utf8_pos(const char* s, intptr_t index); // from UTF8 index to byte index position
-unsigned utf8_chr_size(const char* s); // UTF8 character size: 1-4
- // implemented in src/utf8code.c:
-bool utf8_valid(const char* s);
-bool utf8_valid_n(const char* s, intptr_t nbytes);
-uint32_t utf8_decode(utf8_decode_t *d, uint8_t byte); // decode next byte to utf8, return state.
-unsigned utf8_encode(char *out, uint32_t codepoint); // encode unicode cp into out buffer
-uint32_t utf8_peek(const char* s); // codepoint value of character at s
-uint32_t utf8_peek_off(const char* s, int offset); // codepoint value at utf8 pos (may be negative)
-```
-
-#### Extended cstr methods
-```c
-csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n);
-csview cstr_substr_ex(const cstr* s, intptr_t pos, intptr_t n); // negative pos count from end
-csview cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len);
+intptr_t csview_u8_size(csview sv);
+csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len);
+bool csview_valid_utf8(csview sv); // requires linking with src/utf8code.c
+
+csview_iter csview_begin(const csview* self);
+csview_iter csview_end(const csview* self);
+void csview_next(csview_iter* it); // utf8 codepoint step, not byte!
+csview_iter csview_advance(csview_iter it, intptr_t n);
+```
-csview cstr_slice(const cstr* self, intptr_t p1, intptr_t p2);
-csview cstr_slice_ex(const cstr* s, intptr_t p, intptr_t q); // negative p or q count from end
+#### cstr methods returning csview
+```c
+csview cstr_slice(const cstr* self, intptr_t pos1, intptr_t pos2);
+csview cstr_slice_ex(const cstr* self, intptr_t pos1, intptr_t pos2); // see csview_slice_ex()
+csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n);
+csview cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n); // see csview_substr_ex()
+csview cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len);
```
#### Iterate tokens with *c_fortoken*, *c_fortoken_sv*
@@ -93,46 +85,46 @@ c_fortoken (i, "hello, one, two, three", ", ")
#### Helper methods
```c
-int csview_cmp(const csview* x, const csview* y);
-int csview_icmp(const csview* x, const csview* y);
-bool csview_eq(const csview* x, const csview* y);
-uint64_t csview_hash(const csview* x);
+int csview_cmp(const csview* x, const csview* y);
+int csview_icmp(const csview* x, const csview* y);
+bool csview_eq(const csview* x, const csview* y);
+uint64_t csview_hash(const csview* x);
```
## Types
| Type name | Type definition | Used to represent... |
|:----------------|:-------------------------------------------|:-------------------------|
-| `csview` | `struct { const char *str; intptr_t size; }` | The string view type |
-| `csview_value` | `char` | The string element type |
-| `csview_iter` | `struct { csview_value *ref; }` | UTF8 iterator |
+| `csview` | `struct { const char *buf; intptr_t size; }` | The string view type |
+| `csview_value` | `const char` | The string element type |
+| `csview_iter` | `union { csview_value *ref; csview chr; }` | UTF8 iterator |
## Constants and macros
| Name | Value | Usage |
|:---------------|:---------------------|:---------------------------------------------|
-| `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.");
+ cstr str1 = cstr_from("We think in generalities, but we live in details.");
// (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 ss1 = cstr_substr_ex(&str1, 3, 5); // "think"
+ intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1
+ csview ss2 = cstr_substr_ex(&str1, pos, 4); // get "live"
+ csview ss3 = cstr_slice_ex(&str1, -8, -1); // get "details"
printf("%.*s %.*s %.*s\n",
- c_SV(sv1), c_SV(sv2), c_SV(sv3));
+ c_SV(ss1), c_SV(ss2), c_SV(ss3));
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 +138,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");
@@ -157,7 +149,7 @@ int main()
printf("%s\n", cstr_str(&s1));
c_foreach (i, cstr, s1)
- printf("%.*s,", c_SV(i.u8.chr));
+ printf("%.*s,", c_SV(i.chr));
cstr_drop(&s1);
}
@@ -181,9 +173,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 +188,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..8997ed51 100644
--- a/docs/cvec_api.md
+++ b/docs/cvec_api.md
@@ -12,17 +12,18 @@ See the c++ class [std::vector](https://en.cppreference.com/w/cpp/container/vect
## Header file and declaration
```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_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_tag // alternative typename: cvec_{i_tag}. i_tag defaults to i_val
+#define i_type <t> // container type name
+#define i_key <t> // element type: REQUIRED. Note: i_val* may be specified instead of i_key*.
+#define i_cmp <f> // three-way compare two i_keyraw*
+#define i_use_cmp // define instead of i_cmp only when i_key is an integral/native-type.
+#define i_keydrop <f> // destroy value func - defaults to empty destruct
+#define i_keyclone <f> // REQUIRED IF i_keydrop defined
+
+#define i_keyraw <t> // convertion "raw" type - defaults to i_key
+#define i_keyfrom <f> // convertion func i_keyraw => i_key
+#define i_keyto <f> // convertion func i_key* => i_keyraw
+
+#define i_tag <s> // 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 +32,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 +49,53 @@ 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(cvec_X* self); // destroy last element
void cvec_X_pop_back(cvec_X* self); // alias for pop
+cvec_X_value cvec_X_pull(cvec_X* self); // move out last element
-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 +103,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 +149,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 +186,7 @@ item: 2 elements so far
Container with elements of structs:
```c
+#define i_implement
#include <stc/cstr.h>
typedef struct {
@@ -208,7 +208,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) {
@@ -224,4 +224,4 @@ int main(void) {
c_drop(UVec, &vec, &vec2); // cleanup
}
-``` \ No newline at end of file
+```
diff --git a/docs/pics/Figure_1.png b/docs/pics/Figure_1.png
new file mode 100644
index 00000000..46a1478f
--- /dev/null
+++ b/docs/pics/Figure_1.png
Binary files differ
diff --git a/docs/pics/coroutine.jpg b/docs/pics/coroutine.jpg
new file mode 100644
index 00000000..e5fceab3
--- /dev/null
+++ b/docs/pics/coroutine.jpg
Binary files differ