summaryrefslogtreecommitdiffhomepage
path: root/misc/examples
diff options
context:
space:
mode:
authorTyge Lovset <[email protected]>2022-12-20 23:31:51 +0100
committerTyge Lovset <[email protected]>2022-12-20 23:31:51 +0100
commit5f57d597cd27aef55adbcb3b452973b0c6e33667 (patch)
treedfd59c2fd0e36a6ef37912a9d0cc5a65970f1524 /misc/examples
parent1763be8c8cbbc0896477fcf924edd4180d1345a9 (diff)
downloadSTC-modified-5f57d597cd27aef55adbcb3b452973b0c6e33667.tar.gz
STC-modified-5f57d597cd27aef55adbcb3b452973b0c6e33667.zip
Restructured folders: examples, benchmarks, tests into misc folder.
Diffstat (limited to 'misc/examples')
-rw-r--r--misc/examples/README.md4
-rw-r--r--misc/examples/arc_containers.c79
-rw-r--r--misc/examples/arc_demo.c56
-rw-r--r--misc/examples/arcvec_erase.c53
-rw-r--r--misc/examples/astar.c166
-rw-r--r--misc/examples/birthday.c68
-rw-r--r--misc/examples/bits.c61
-rw-r--r--misc/examples/bits2.c41
-rw-r--r--misc/examples/books.c60
-rw-r--r--misc/examples/box.c68
-rw-r--r--misc/examples/box2.c90
-rw-r--r--misc/examples/city.c91
-rw-r--r--misc/examples/complex.c55
-rw-r--r--misc/examples/convert.c50
-rw-r--r--misc/examples/cpque.c72
-rw-r--r--misc/examples/csmap_erase.c84
-rw-r--r--misc/examples/csmap_find.c74
-rw-r--r--misc/examples/csmap_insert.c112
-rw-r--r--misc/examples/csset_erase.c43
-rw-r--r--misc/examples/cstr_match.c23
-rw-r--r--misc/examples/demos.c228
-rw-r--r--misc/examples/forfilter.c144
-rw-r--r--misc/examples/forloops.c81
-rw-r--r--misc/examples/gauss1.c56
-rw-r--r--misc/examples/gauss2.c43
-rw-r--r--misc/examples/hashmap.c48
-rw-r--r--misc/examples/inits.c116
-rw-r--r--misc/examples/intrusive.c52
-rw-r--r--misc/examples/list.c61
-rw-r--r--misc/examples/list_erase.c32
-rw-r--r--misc/examples/list_splice.c43
-rw-r--r--misc/examples/lower_bound.c62
-rwxr-xr-xmisc/examples/make.sh56
-rw-r--r--misc/examples/mapmap.c68
-rw-r--r--misc/examples/mmap.c72
-rw-r--r--misc/examples/multimap.c99
-rw-r--r--misc/examples/music_arc.c68
-rw-r--r--misc/examples/new_arr.c57
-rw-r--r--misc/examples/new_deq.c61
-rw-r--r--misc/examples/new_list.c61
-rw-r--r--misc/examples/new_map.c73
-rw-r--r--misc/examples/new_pque.c55
-rw-r--r--misc/examples/new_queue.c45
-rw-r--r--misc/examples/new_smap.c77
-rw-r--r--misc/examples/new_sptr.c72
-rw-r--r--misc/examples/new_vec.c58
-rw-r--r--misc/examples/person_arc.c74
-rw-r--r--misc/examples/phonebook.c82
-rw-r--r--misc/examples/prime.c51
-rw-r--r--misc/examples/priority.c35
-rw-r--r--misc/examples/queue.c31
-rw-r--r--misc/examples/random.c45
-rw-r--r--misc/examples/rawptr_elements.c55
-rw-r--r--misc/examples/read.c25
-rw-r--r--misc/examples/regex1.c30
-rw-r--r--misc/examples/regex2.c32
-rw-r--r--misc/examples/regex_match.c34
-rw-r--r--misc/examples/regex_replace.c53
-rw-r--r--misc/examples/replace.c34
-rw-r--r--misc/examples/shape.c159
-rw-r--r--misc/examples/shape.cpp122
-rw-r--r--misc/examples/sidebyside.cpp57
-rw-r--r--misc/examples/sorted_map.c64
-rw-r--r--misc/examples/splitstr.c19
-rw-r--r--misc/examples/sso_map.c17
-rw-r--r--misc/examples/sso_substr.c20
-rw-r--r--misc/examples/stack.c30
-rw-r--r--misc/examples/sview_split.c20
-rw-r--r--misc/examples/unordered_set.c42
-rw-r--r--misc/examples/utf8replace_c.c23
-rw-r--r--misc/examples/utf8replace_rs.rs19
-rw-r--r--misc/examples/vikings.c66
-rw-r--r--misc/examples/words.c68
73 files changed, 4545 insertions, 0 deletions
diff --git a/misc/examples/README.md b/misc/examples/README.md
new file mode 100644
index 00000000..4c0aa763
--- /dev/null
+++ b/misc/examples/README.md
@@ -0,0 +1,4 @@
+Examples
+========
+This folder contains various examples of STC container usage.
+
diff --git a/misc/examples/arc_containers.c b/misc/examples/arc_containers.c
new file mode 100644
index 00000000..b577f2c8
--- /dev/null
+++ b/misc/examples/arc_containers.c
@@ -0,0 +1,79 @@
+// Create a stack and a list of shared pointers to maps,
+// and demonstrate sharing and cloning of maps.
+#define i_static
+#include <stc/cstr.h>
+#define i_type Map
+#define i_key_str // strings
+#define i_val int
+#define i_keydrop(p) (printf("drop name: %s\n", cstr_str(p)), cstr_drop(p))
+#include <stc/csmap.h>
+
+#define i_type Arc // (atomic) ref. counted type
+#define i_val Map
+#define i_valdrop(p) (printf("drop Arc:\n"), Map_drop(p))
+// no need for atomic ref. count in single thread:
+#define i_opt c_no_atomic|c_no_lookup
+#include <stc/carc.h>
+
+#define i_type Stack
+#define i_valboxed Arc // define i_valboxed for carc/cbox value (not i_val)
+#define i_opt c_no_cmp
+#include <stc/cvec.h>
+
+#define i_type List
+#define i_valboxed Arc // as above
+#define i_opt c_no_cmp
+#include <stc/clist.h>
+
+int main()
+{
+ c_auto (Stack, stack)
+ c_auto (List, list)
+ {
+ // POPULATE stack with shared pointers to Maps:
+ Map *map;
+ map = Stack_push(&stack, Arc_from(Map_init()))->get;
+ Map_emplace(map, "Joey", 1990);
+ Map_emplace(map, "Mary", 1995);
+ Map_emplace(map, "Joanna", 1992);
+
+ map = Stack_push(&stack, Arc_from(Map_init()))->get;
+ Map_emplace(map, "Rosanna", 2001);
+ Map_emplace(map, "Brad", 1999);
+ Map_emplace(map, "Jack", 1980);
+
+ // POPULATE list:
+ map = List_push_back(&list, Arc_from(Map_init()))->get;
+ Map_emplace(map, "Steve", 1979);
+ Map_emplace(map, "Rick", 1974);
+ Map_emplace(map, "Tracy", 2003);
+
+ // Share two Maps from the stack with the list using emplace (clone the carc):
+ List_push_back(&list, Arc_clone(stack.data[0]));
+ List_push_back(&list, Arc_clone(stack.data[1]));
+
+ // Clone (deep copy) a Map from the stack to the list
+ // List will contain two shared and two unshared maps.
+ map = List_push_back(&list, Arc_from(Map_clone(*stack.data[1].get)))->get;
+
+ // Add one more element to the cloned map:
+ Map_emplace_or_assign(map, "CLONED", 2021);
+
+ // Add one more element to the shared map:
+ Map_emplace_or_assign(stack.data[1].get, "SHARED", 2021);
+
+
+ puts("STACKS");
+ c_foreach (i, Stack, stack) {
+ c_forpair (name, year, Map, *i.ref->get)
+ printf(" %s:%d", cstr_str(_.name), *_.year);
+ puts("");
+ }
+ puts("LIST");
+ c_foreach (i, List, list) {
+ c_forpair (name, year, Map, *i.ref->get)
+ printf(" %s:%d", cstr_str(_.name), *_.year);
+ puts("");
+ }
+ }
+}
diff --git a/misc/examples/arc_demo.c b/misc/examples/arc_demo.c
new file mode 100644
index 00000000..087f90ac
--- /dev/null
+++ b/misc/examples/arc_demo.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <string.h>
+
+void int_drop(int* x) {
+ printf("drop: %d\n", *x);
+}
+
+// carc implements its own clone method using reference counting,
+// so 'i_valclone' is not required to be defined (ignored).
+
+#define i_type Arc // set type name to be defined (instead of 'carc_int')
+#define i_val int
+#define i_valdrop int_drop // optional, just to display the elements destroyed
+#include <stc/carc.h> // Arc
+
+#define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements
+#include <stc/csset.h> // csset_Arc (like: std::set<std::shared_ptr<int>>)
+
+#define i_valboxed Arc // note: as above.
+#include <stc/cvec.h> // cvec_Arc (like: std::vector<std::shared_ptr<int>>)
+
+int main()
+{
+ c_auto (cvec_Arc, vec) // declare and init vec, call cvec_Arc_drop() at scope exit
+ c_auto (csset_Arc, set) // declare and init set, call csset_Arc_drop() at scope exit
+ {
+ const int years[] = {2021, 2012, 2022, 2015};
+ c_forrange (i, c_arraylen(years))
+ cvec_Arc_push(&vec, Arc_from(years[i]));
+
+ printf("vec:");
+ c_foreach (i, cvec_Arc, vec) printf(" %d", *i.ref->get);
+ puts("");
+
+ // add odd numbers from vec to set
+ c_foreach (i, cvec_Arc, vec)
+ if (*i.ref->get & 1)
+ csset_Arc_insert(&set, Arc_clone(*i.ref)); // copy shared pointer => increments counter.
+
+ // erase the two last elements in vec
+ cvec_Arc_pop_back(&vec);
+ cvec_Arc_pop_back(&vec);
+
+ printf("vec:");
+ c_foreach (i, cvec_Arc, vec) printf(" %d", *i.ref->get);
+
+ printf("\nset:");
+ c_foreach (i, csset_Arc, set) printf(" %d", *i.ref->get);
+
+ c_with (Arc p = Arc_clone(vec.data[0]), Arc_drop(&p)) {
+ printf("\n%d is now owned by %ld objects\n", *p.get, *p.use_count);
+ }
+
+ puts("\nDone");
+ }
+}
diff --git a/misc/examples/arcvec_erase.c b/misc/examples/arcvec_erase.c
new file mode 100644
index 00000000..c70d59d9
--- /dev/null
+++ b/misc/examples/arcvec_erase.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+
+void show_drop(int* x) { printf("drop: %d\n", *x); }
+
+#define i_type Arc
+#define i_val int
+#define i_valdrop show_drop
+#define i_cmp c_default_cmp // enable object comparisons (default ptr compare)
+#include <stc/carc.h> // Shared pointer to int
+
+#define i_type Vec
+#define i_valboxed Arc
+#include <stc/cvec.h> // Vec: cvec<Arc>
+
+
+int main()
+{
+ c_auto (Vec, vec)
+ {
+ c_forlist (i, int, {2012, 1990, 2012, 2019, 2015})
+ Vec_emplace(&vec, *i.ref);
+
+ // clone the second 2012 and push it back.
+ // note: cloning make sure that vec.data[2] has ref count 2.
+ Vec_push(&vec, Arc_clone(vec.data[2]));
+
+ printf("vec before erase :");
+ c_foreach (i, Vec, vec)
+ printf(" %d", *i.ref->get);
+
+ printf("\nerase vec.data[2]; or first matching value depending on compare.\n");
+ Vec_iter it;
+ it = Vec_find(&vec, *vec.data[2].get);
+ if (it.ref != Vec_end(&vec).ref)
+ Vec_erase_at(&vec, it);
+
+ int year = 2015;
+ it = Vec_find(&vec, year); // Ok as tmp only.
+ if (it.ref != Vec_end(&vec).ref)
+ Vec_erase_at(&vec, it);
+
+ printf("vec after erase :");
+ c_foreach (i, Vec, vec)
+ printf(" %d", *i.ref->get);
+
+ Vec_sort(&vec);
+ printf("\nvec after sort :");
+ c_foreach (i, Vec, vec)
+ printf(" %d", *i.ref->get);
+
+ puts("\nDone");
+ }
+}
diff --git a/misc/examples/astar.c b/misc/examples/astar.c
new file mode 100644
index 00000000..d4a821f9
--- /dev/null
+++ b/misc/examples/astar.c
@@ -0,0 +1,166 @@
+//
+// -- An A* pathfinder inspired by the excellent tutorial at Red Blob Games --
+//
+// This is a reimplementation of the CTL example to STC:
+// https://github.com/glouw/ctl/blob/master/examples/astar.c
+// https://www.redblobgames.com/pathfinding/a-star/introduction.html
+#include <stc/cstr.h>
+#include <stdio.h>
+
+typedef struct
+{
+ int x;
+ int y;
+ int priorty;
+ int width;
+}
+point;
+
+point
+point_init(int x, int y, int width)
+{
+ return (point) { x, y, 0, width };
+}
+
+int
+point_cmp_priority(const point* a, const point* b)
+{
+ return c_default_cmp(&a->priorty, &b->priorty);
+}
+
+int
+point_equal(const point* a, const point* b)
+{
+ return a->x == b->x && a->y == b->y;
+}
+
+point
+point_from(const cstr* maze, const char* c, int width)
+{
+ int index = cstr_find(maze, c);
+ return point_init(index % width, index / width, width);
+}
+
+int
+point_index(const point* p)
+{
+ return p->x + p->width * p->y;
+}
+
+int
+point_key_cmp(const point* a, const point* b)
+{
+ int i = point_index(a);
+ int j = point_index(b);
+ return (i == j) ? 0 : (i < j) ? -1 : 1;
+}
+
+#define i_val point
+#define i_cmp point_cmp_priority
+#include <stc/cpque.h>
+
+#define i_val point
+#define i_opt c_no_cmp
+#include <stc/cdeq.h>
+
+#define i_key point
+#define i_val int
+#define i_cmp point_key_cmp
+#define i_tag pcost
+#include <stc/csmap.h>
+
+#define i_key point
+#define i_val point
+#define i_cmp point_key_cmp
+#define i_tag pstep
+#include <stc/csmap.h>
+
+cdeq_point
+astar(cstr* maze, int width)
+{
+ cdeq_point path = cdeq_point_init();
+
+ c_auto (cpque_point, front)
+ c_auto (csmap_pstep, from)
+ c_auto (csmap_pcost, costs)
+ {
+ point start = point_from(maze, "@", width);
+ point goal = point_from(maze, "!", width);
+ csmap_pcost_insert(&costs, start, 0);
+ cpque_point_push(&front, start);
+ while (!cpque_point_empty(&front))
+ {
+ point current = *cpque_point_top(&front);
+ cpque_point_pop(&front);
+ if (point_equal(&current, &goal))
+ break;
+ point deltas[] = {
+ { -1, +1, 0, width }, { 0, +1, 0, width }, { 1, +1, 0, width },
+ { -1, 0, 0, width }, /* ~ ~ ~ ~ ~ ~ ~ */ { 1, 0, 0, width },
+ { -1, -1, 0, width }, { 0, -1, 0, width }, { 1, -1, 0, width },
+ };
+ for (size_t i = 0; i < c_arraylen(deltas); i++)
+ {
+ point delta = deltas[i];
+ point next = point_init(current.x + delta.x, current.y + delta.y, width);
+ int new_cost = *csmap_pcost_at(&costs, current);
+ if (cstr_str(maze)[point_index(&next)] != '#')
+ {
+ const csmap_pcost_value *cost = csmap_pcost_get(&costs, next);
+ if (cost == NULL || new_cost < cost->second)
+ {
+ csmap_pcost_insert(&costs, next, new_cost);
+ next.priorty = new_cost + abs(goal.x - next.x) + abs(goal.y - next.y);
+ cpque_point_push(&front, next);
+ csmap_pstep_insert(&from, next, current);
+ }
+ }
+ }
+ }
+ point current = goal;
+ while (!point_equal(&current, &start))
+ {
+ cdeq_point_push_front(&path, current);
+ current = *csmap_pstep_at(&from, current);
+ }
+ cdeq_point_push_front(&path, start);
+ }
+ return path;
+}
+
+int
+main(void)
+{
+ c_with (cstr maze = cstr_lit(
+ "#########################################################################\n"
+ "# # # # # # #\n"
+ "# # ######### # ##### ######### ##### ##### ##### # ! #\n"
+ "# # # # # # # # # #\n"
+ "######### # ######### ######### ##### # # # ######### #\n"
+ "# # # # # # # # # # #\n"
+ "# # ############# # # ######### ##### # ######### # #\n"
+ "# # # # # # # # # #\n"
+ "# ############# ##### ##### # ##### ######### # ##### #\n"
+ "# # # # # # # # # #\n"
+ "# ##### ##### # ##### # ######### # # # #############\n"
+ "# # # # # # # # # # # #\n"
+ "############# # # # ######### # ##### # ##### ##### #\n"
+ "# # # # # # # # # #\n"
+ "# ##### # ######### ##### # ##### ##### ############# #\n"
+ "# # # # # # # # # #\n"
+ "# # ######### # ##### ######### # # ############# # #\n"
+ "# # # # # # # # # # #\n"
+ "# ######### # # # ##### ######### ######### # #########\n"
+ "# # # # # # # # # #\n"
+ "# @ # ##### ##### ##### ######### ##### # ######### # #\n"
+ "# # # # # # #\n"
+ "#########################################################################\n"), cstr_drop(&maze))
+ {
+ int width = cstr_find(&maze, "\n") + 1;
+ c_with (cdeq_point path = astar(&maze, width), cdeq_point_drop(&path))
+ {
+ c_foreach (it, cdeq_point, path) cstr_data(&maze)[point_index(it.ref)] = 'x';
+ printf("%s", cstr_str(&maze));
+ }
+ }
+}
diff --git a/misc/examples/birthday.c b/misc/examples/birthday.c
new file mode 100644
index 00000000..48b8ceaa
--- /dev/null
+++ b/misc/examples/birthday.c
@@ -0,0 +1,68 @@
+#include <math.h>
+#include <stdio.h>
+#include <time.h>
+#include <stc/crandom.h>
+
+#define i_tag ic
+#define i_key uint64_t
+#define i_val uint8_t
+#include <stc/cmap.h>
+
+static uint64_t seed = 12345;
+
+static void test_repeats(void)
+{
+ enum {BITS = 46, BITS_TEST = BITS/2 + 2};
+ const static uint64_t N = 1ull << BITS_TEST;
+ const static uint64_t mask = (1ull << BITS) - 1;
+
+ printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST);
+ stc64_t rng = stc64_new(seed);
+ c_auto (cmap_ic, m)
+ {
+ cmap_ic_reserve(&m, N);
+ c_forrange (i, N) {
+ uint64_t k = stc64_rand(&rng) & mask;
+ int v = cmap_ic_insert(&m, k, 0).ref->second += 1;
+ if (v > 1) printf("repeated value %" PRIu64 " (%d) at 2^%d\n",
+ k, v, (int) log2((double) i));
+ }
+ }
+}
+
+#define i_key uint32_t
+#define i_val uint64_t
+#define i_tag x
+#include <stc/cmap.h>
+
+void test_distribution(void)
+{
+ enum {BITS = 26};
+ printf("distribution test: 2^%d values\n", BITS);
+ stc64_t rng = stc64_new(seed);
+ const size_t N = 1ull << BITS ;
+
+ c_auto (cmap_x, map) {
+ c_forrange (N) {
+ uint64_t k = stc64_rand(&rng);
+ cmap_x_insert(&map, k & 0xf, 0).ref->second += 1;
+ }
+
+ uint64_t sum = 0;
+ c_foreach (i, cmap_x, map) sum += i.ref->second;
+ sum /= map.size;
+
+ c_foreach (i, cmap_x, map) {
+ printf("%4" PRIu32 ": %" PRIu64 " - %" PRIu64 ": %11.8f\n",
+ i.ref->first, i.ref->second, sum,
+ (1 - (double)i.ref->second / sum));
+ }
+ }
+}
+
+int main()
+{
+ seed = time(NULL);
+ test_distribution();
+ test_repeats();
+}
diff --git a/misc/examples/bits.c b/misc/examples/bits.c
new file mode 100644
index 00000000..82fd65ec
--- /dev/null
+++ b/misc/examples/bits.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <stc/cbits.h>
+
+int main()
+{
+ c_with (cbits set = cbits_with_size(23, true), cbits_drop(&set)) {
+ printf("count %" c_ZU ", %" c_ZU "\n", cbits_count(&set), cbits_size(&set));
+ cbits s1 = cbits_from("1110100110111");
+ char buf[256];
+ cbits_to_str(&s1, buf, 0, 255);
+ printf("buf: %s: %" c_ZU "\n", buf, cbits_count(&s1));
+ cbits_drop(&s1);
+
+ cbits_reset(&set, 9);
+ cbits_resize(&set, 43, false);
+ printf(" str: %s\n", cbits_to_str(&set, buf, 0, 255));
+
+ printf("%4" c_ZU ": ", cbits_size(&set));
+ c_forrange (i, cbits_size(&set))
+ printf("%d", cbits_test(&set, i));
+ puts("");
+
+ cbits_set(&set, 28);
+ cbits_resize(&set, 77, true);
+ cbits_resize(&set, 93, false);
+ cbits_resize(&set, 102, true);
+ cbits_set_value(&set, 99, false);
+ printf("%4" c_ZU ": ", cbits_size(&set));
+ c_forrange (i, cbits_size(&set))
+ printf("%d", cbits_test(&set, i));
+
+ puts("\nIterate:");
+ printf("%4" c_ZU ": ", cbits_size(&set));
+ c_forrange (i, cbits_size(&set))
+ printf("%d", cbits_test(&set, i));
+ puts("");
+
+ c_with (cbits s2 = cbits_clone(set), cbits_drop(&s2)) {
+ cbits_flip_all(&s2);
+ cbits_set(&s2, 16);
+ cbits_set(&s2, 17);
+ cbits_set(&s2, 18);
+ printf(" new: ");
+ c_forrange (i, cbits_size(&s2))
+ printf("%d", cbits_test(&s2, i));
+ puts("");
+
+ printf(" xor: ");
+ cbits_xor(&set, &s2);
+ c_forrange (i, cbits_size(&set))
+ printf("%d", cbits_test(&set, i));
+ puts("");
+
+ cbits_set_all(&set, false);
+ printf("%4" c_ZU ": ", cbits_size(&set));
+ c_forrange (i, cbits_size(&set))
+ printf("%d", cbits_test(&set, i));
+ puts("");
+ }
+ }
+}
diff --git a/misc/examples/bits2.c b/misc/examples/bits2.c
new file mode 100644
index 00000000..59e0b337
--- /dev/null
+++ b/misc/examples/bits2.c
@@ -0,0 +1,41 @@
+#include <stdio.h>
+// Example of static sized (stack allocated) bitsets
+
+#define i_type Bits
+#define i_capacity 80 // enable fixed bitset on the stack
+#include <stc/cbits.h>
+
+int main()
+{
+ Bits s1 = Bits_from("1110100110111");
+
+ printf("size %" c_ZU "\n", Bits_size(&s1));
+ char buf[256];
+ Bits_to_str(&s1, buf, 0, 256);
+ printf("buf: %s: count=%" c_ZU "\n", buf, Bits_count(&s1));
+
+ Bits_reset(&s1, 8);
+ printf(" s1: %s\n", Bits_to_str(&s1, buf, 0, 256));
+
+ Bits s2 = Bits_clone(s1);
+
+ Bits_flip_all(&s2);
+ Bits_reset(&s2, 66);
+ Bits_reset(&s2, 67);
+ printf(" s2: ");
+ c_forrange (i, Bits_size(&s2))
+ printf("%d", Bits_test(&s2, i));
+ puts("");
+
+ printf("xor: ");
+ Bits_xor(&s1, &s2);
+ c_forrange (i, Bits_size(&s1))
+ printf("%d", Bits_test(&s1, i));
+ puts("");
+
+ printf("all: ");
+ Bits_set_pattern(&s1, 0x3333333333333333);
+ c_forrange (i, Bits_size(&s1))
+ printf("%d", Bits_test(&s1, i));
+ puts("");
+}
diff --git a/misc/examples/books.c b/misc/examples/books.c
new file mode 100644
index 00000000..b6067d81
--- /dev/null
+++ b/misc/examples/books.c
@@ -0,0 +1,60 @@
+// https://doc.rust-lang.org/std/collections/struct.HashMap.html
+#include <stc/cstr.h>
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
+
+// Type inference lets us omit an explicit type signature (which
+// would be `HashMap<String, String>` in this example).
+int main()
+{
+ c_auto (cmap_str, book_reviews)
+ {
+ // Review some books.
+ cmap_str_emplace(&book_reviews,
+ "Adventures of Huckleberry Finn",
+ "My favorite book."
+ );
+ cmap_str_emplace(&book_reviews,
+ "Grimms' Fairy Tales",
+ "Masterpiece."
+ );
+ cmap_str_emplace(&book_reviews,
+ "Pride and Prejudice",
+ "Very enjoyable"
+ );
+ cmap_str_insert(&book_reviews,
+ cstr_lit("The Adventures of Sherlock Holmes"),
+ cstr_lit("Eye lyked it alot.")
+ );
+
+ // Check for a specific one.
+ // When collections store owned values (String), they can still be
+ // queried using references (&str).
+ if (cmap_str_contains(&book_reviews, "Les Misérables")) {
+ printf("We've got %" c_ZU " reviews, but Les Misérables ain't one.",
+ cmap_str_size(&book_reviews));
+ }
+
+ // oops, this review has a lot of spelling mistakes, let's delete it.
+ cmap_str_erase(&book_reviews, "The Adventures of Sherlock Holmes");
+
+ // Look up the values associated with some keys.
+ const char* to_find[] = {"Pride and Prejudice", "Alice's Adventure in Wonderland"};
+ c_forrange (i, c_arraylen(to_find)) {
+ const cmap_str_value* b = cmap_str_get(&book_reviews, to_find[i]);
+ if (b)
+ printf("%s: %s\n", cstr_str(&b->first), cstr_str(&b->second));
+ else
+ printf("%s is unreviewed.\n", to_find[i]);
+ }
+
+ // Look up the value for a key (will panic if the key is not found).
+ printf("Review for Jane: %s\n", cstr_str(cmap_str_at(&book_reviews, "Pride and Prejudice")));
+
+ // Iterate over everything.
+ c_forpair (book, review, cmap_str, book_reviews) {
+ printf("%s: \"%s\"\n", cstr_str(_.book), cstr_str(_.review));
+ }
+ }
+}
diff --git a/misc/examples/box.c b/misc/examples/box.c
new file mode 100644
index 00000000..da13501f
--- /dev/null
+++ b/misc/examples/box.c
@@ -0,0 +1,68 @@
+/* cbox: heap allocated boxed type */
+#include <stc/cstr.h>
+
+typedef struct { cstr name, last; } Person;
+
+Person Person_make(const char* name, const char* last) {
+ return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+}
+
+uint64_t Person_hash(const Person* a) {
+ return cstr_hash(&a->name) ^ cstr_hash(&a->last);
+}
+
+int Person_cmp(const Person* a, const Person* b) {
+ int c = cstr_cmp(&a->name, &b->name);
+ return c ? c : cstr_cmp(&a->last, &b->last);
+}
+
+Person Person_clone(Person p) {
+ p.name = cstr_clone(p.name);
+ p.last = cstr_clone(p.last);
+ return p;
+}
+
+void Person_drop(Person* p) {
+ printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
+ c_drop(cstr, &p->name, &p->last);
+}
+
+#define i_type PBox
+#define i_valclass Person // "class" binds _cmp, _clone, _drop functions.
+#include <stc/cbox.h>
+
+#define i_type Persons
+#define i_valboxed PBox // "arcbox" informs that PBox is a smart pointer.
+#include <stc/csset.h>
+
+int main()
+{
+ c_auto (Persons, vec)
+ c_auto (PBox, p, q)
+ {
+ p = PBox_from(Person_make("Laura", "Palmer"));
+ q = PBox_clone(p);
+ cstr_assign(&q.get->name, "Leland");
+
+ printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last));
+ printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last));
+
+ Persons_emplace(&vec, Person_make("Dale", "Cooper"));
+ Persons_emplace(&vec, Person_make("Audrey", "Home"));
+
+ // NB! Clone/share p and q in the Persons container.
+ Persons_push(&vec, PBox_clone(p));
+ Persons_push(&vec, PBox_clone(q));
+
+ c_foreach (i, Persons, vec)
+ printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last));
+ puts("");
+
+ // Look-up Audrey! Create a temporary Person for lookup.
+ c_with (Person a = Person_make("Audrey", "Home"), Person_drop(&a)) {
+ const PBox *v = Persons_get(&vec, a); // lookup
+ if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last));
+ }
+ puts("");
+ }
+}
diff --git a/misc/examples/box2.c b/misc/examples/box2.c
new file mode 100644
index 00000000..b9628eeb
--- /dev/null
+++ b/misc/examples/box2.c
@@ -0,0 +1,90 @@
+// https://doc.rust-lang.org/rust-by-example/std/box.html
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stc/ccommon.h>
+
+struct {
+ double x;
+ double y;
+} typedef Point;
+
+// A Rectangle can be specified by where its top left and bottom right
+// corners are in space
+struct {
+ Point top_left;
+ Point bottom_right;
+} typedef Rectangle;
+
+#define i_val Point
+#define i_opt c_no_lookup
+#include <stc/cbox.h> // cbox_Point
+
+#define i_val Rectangle
+#define i_opt c_no_lookup
+#include <stc/cbox.h> // cbox_Rectangle
+
+// Box in box:
+#define i_valboxed cbox_Point // NB: use i_valboxed when value is a cbox or carc!
+ // it will auto define i_valdrop, i_valfrom, and i_cmp.
+#define i_tag BoxPoint
+#define i_opt c_no_lookup
+#include <stc/cbox.h> // cbox_BoxPoint
+
+Point origin(void) {
+ return (Point){ .x=1.0, .y=2.0 };
+}
+
+cbox_Point boxed_origin(void) {
+ // Allocate this point on the heap, and return a pointer to it
+ return cbox_Point_make((Point){ .x=2.0, .y=3.0 });
+}
+
+
+int main(void) {
+ // Stack allocated variables
+ Point point = origin();
+ Rectangle rectangle = (Rectangle){
+ .top_left = origin(),
+ .bottom_right = (Point){ .x=3.0, .y=-4.0 }
+ };
+
+ // Declare auto-deleted box objects
+ c_auto (cbox_Rectangle, boxed_rectangle)
+ c_auto (cbox_Point, boxed_point)
+ c_auto (cbox_BoxPoint, box_in_a_box, boxbox2)
+ {
+ // Heap allocated rectangle
+ boxed_rectangle = cbox_Rectangle_make((Rectangle){
+ .top_left = origin(),
+ .bottom_right = (Point){ .x=3.0, .y=-4.0 }
+ });
+
+ // The output of functions can be boxed
+ boxed_point = cbox_Point_from(origin());
+
+ // Double indirection
+ box_in_a_box = cbox_BoxPoint_make(boxed_origin());
+ boxbox2 = cbox_BoxPoint_from(point); // !!
+ printf("boxbox2: x=%f\n", boxbox2.get->get->x);
+
+ printf("Point occupies %" c_ZU " bytes on the stack\n",
+ sizeof(point));
+ printf("Rectangle occupies %" c_ZU " bytes on the stack\n",
+ sizeof(rectangle));
+
+ // box size == pointer size
+ printf("Boxed point occupies %" c_ZU " bytes on the stack\n",
+ sizeof(boxed_point));
+ printf("Boxed rectangle occupies %" c_ZU " bytes on the stack\n",
+ sizeof(boxed_rectangle));
+ printf("Boxed box occupies %" c_ZU " bytes on the stack\n",
+ sizeof(box_in_a_box));
+
+ // Copy the data contained in `boxed_point` into `unboxed_point`
+ Point unboxed_point = *boxed_point.get;
+ printf("Unboxed point occupies %" c_ZU " bytes on the stack\n",
+ sizeof(unboxed_point));
+ }
+}
diff --git a/misc/examples/city.c b/misc/examples/city.c
new file mode 100644
index 00000000..8557c6cf
--- /dev/null
+++ b/misc/examples/city.c
@@ -0,0 +1,91 @@
+#include <stc/cstr.h>
+
+typedef struct {
+ cstr name;
+ cstr country;
+ float lat, lon;
+ int population;
+} City;
+
+int City_cmp(const City* a, const City* b);
+uint64_t City_hash(const City* a);
+City City_clone(City c);
+void City_drop(City* c);
+
+#define i_type CityArc
+#define i_valclass City
+#include <stc/cbox.h>
+//#include <stc/carc.h> // try instead of cbox.h
+
+#define i_type Cities
+#define i_keyboxed CityArc
+#include <stc/cvec.h>
+
+#define i_type CityMap
+#define i_key int
+#define i_valboxed CityArc
+#include <stc/csmap.h>
+
+
+int City_cmp(const City* a, const City* b) {
+ int c = cstr_cmp(&a->name, &b->name);
+ return c ? c : cstr_cmp(&a->country, &b->country);
+}
+
+uint64_t City_hash(const City* a) {
+ return cstr_hash(&a->name) ^ cstr_hash(&a->country);
+}
+
+City City_clone(City c) {
+ c.name = cstr_clone(c.name);
+ c.country = cstr_clone(c.country);
+ return c;
+}
+
+void City_drop(City* c) {
+ printf("drop %s\n", cstr_str(&c->name));
+ c_drop(cstr, &c->name, &c->country);
+}
+
+
+int main(void)
+{
+ c_auto (Cities, cities, copy)
+ c_auto (CityMap, map)
+ {
+ c_forlist (i, City, {
+ {cstr_lit("New York"), cstr_lit("US"), 4.3f, 23.2f, 9000000},
+ {cstr_lit("Paris"), cstr_lit("France"), 4.3f, 23.2f, 9000000},
+ {cstr_lit("Berlin"), cstr_lit("Germany"), 4.3f, 23.2f, 9000000},
+ {cstr_lit("London"), cstr_lit("UK"), 4.3f, 23.2f, 9000000},
+ }) Cities_emplace(&cities, *i.ref); // NB. creates smart pointers!
+
+ Cities_sort(&cities);
+
+ printf("Vec:\n");
+ c_foreach (c, Cities, cities)
+ printf("city:%s, %d, use:%ld\n", cstr_str(&c.ref->get->name),
+ c.ref->get->population,
+ CityArc_use_count(c.ref));
+ puts("");
+ copy = Cities_clone(cities); // share each element!
+
+ int k = 0, id[] = {8, 4, 3, 9, 2, 5};
+ c_foreach (i, Cities, cities)
+ CityMap_insert(&map, id[k++], CityArc_clone(*i.ref));
+
+ Cities_pop(&cities);
+ Cities_pop(&cities);
+
+ printf("Vec:\n");
+ c_foreach (c, Cities, cities)
+ printf("city:%s, %d, use:%ld\n", cstr_str(&c.ref->get->name),
+ c.ref->get->population,
+ CityArc_use_count(c.ref));
+ printf("\nMap:\n");
+ c_forpair (id, city, CityMap, map)
+ printf("id:%d, city:%s, %d, use:%ld\n", *_.id, cstr_str(&_.city->get->name),
+ _.city->get->population, CityArc_use_count(_.city));
+ puts("");
+ }
+}
diff --git a/misc/examples/complex.c b/misc/examples/complex.c
new file mode 100644
index 00000000..dd2f951a
--- /dev/null
+++ b/misc/examples/complex.c
@@ -0,0 +1,55 @@
+
+// Define similar c++ data types:
+//
+// using FloatStack = std::stack<float>;
+// using StackList = std::stack<FloatStack>;
+// using ListMap = std::unordered_map<int, std::forward_list<StackList>>;
+// using MapMap = std::unordered_map<std::string, ListMap>;
+
+#include <stc/cstr.h>
+
+
+#define i_type FloatStack
+#define i_val float
+#include <stc/cstack.h>
+
+#define i_type StackList
+#define i_valclass FloatStack // "class" picks up _clone, _drop
+#define i_opt c_no_cmp // no FloatStack_cmp()
+#include <stc/clist.h>
+
+#define i_type ListMap
+#define i_key int
+#define i_valclass StackList // "class" picks up _clone, _drop
+#include <stc/cmap.h>
+
+#define i_type MapMap
+#define i_key_str
+#define i_valclass ListMap
+#include <stc/cmap.h>
+
+
+int main()
+{
+ c_auto (MapMap, mmap)
+ {
+ FloatStack stack = FloatStack_with_size(10, 0);
+
+ // Put in some data in the structures
+ stack.data[3] = 3.1415927f;
+ printf("stack size: %" c_ZU "\n", FloatStack_size(&stack));
+
+ StackList list = StackList_init();
+ StackList_push_back(&list, stack);
+
+ ListMap lmap = ListMap_init();
+ ListMap_insert(&lmap, 42, list);
+ MapMap_insert(&mmap, cstr_from("first"), lmap);
+
+ // Access the data entry
+ const ListMap* lmap_p = MapMap_at(&mmap, "first");
+ const StackList* list_p = ListMap_at(lmap_p, 42);
+ const FloatStack* stack_p = StackList_back(list_p);
+ printf("value is: %f\n", *FloatStack_at(stack_p, 3)); // pi
+ }
+}
diff --git a/misc/examples/convert.c b/misc/examples/convert.c
new file mode 100644
index 00000000..18be3c81
--- /dev/null
+++ b/misc/examples/convert.c
@@ -0,0 +1,50 @@
+#include <stc/cstr.h>
+
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
+
+#define i_val_str
+#include <stc/cvec.h>
+
+#define i_val_str
+#define i_extern // define _clist_mergesort() once
+#include <stc/clist.h>
+
+int main()
+{
+ c_auto (cmap_str, map, mclone)
+ c_auto (cvec_str, keys, values)
+ c_auto (clist_str, list)
+ {
+ c_forlist (i, cmap_str_raw, {
+ {"green", "#00ff00"},
+ {"blue", "#0000ff"},
+ {"yellow", "#ffff00"},
+ }) cmap_str_emplace(&map, c_PAIR(i.ref));
+
+ puts("MAP:");
+ c_foreach (i, cmap_str, map)
+ printf(" %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
+
+ puts("\nCLONE MAP:");
+ mclone = cmap_str_clone(map);
+ c_foreach (i, cmap_str, mclone)
+ printf(" %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
+
+ puts("\nCOPY MAP TO VECS:");
+ c_foreach (i, cmap_str, mclone) {
+ cvec_str_emplace_back(&keys, cstr_str(&i.ref->first));
+ cvec_str_emplace_back(&values, cstr_str(&i.ref->second));
+ }
+ c_forrange (i, cvec_str_size(&keys))
+ printf(" %s: %s\n", cstr_str(keys.data + i), cstr_str(values.data + i));
+
+ puts("\nCOPY VEC TO LIST:");
+ c_foreach (i, cvec_str, keys)
+ clist_str_emplace_back(&list, cstr_str(i.ref));
+
+ c_foreach (i, clist_str, list)
+ printf(" %s\n", cstr_str(i.ref));
+ }
+}
diff --git a/misc/examples/cpque.c b/misc/examples/cpque.c
new file mode 100644
index 00000000..7254b0f7
--- /dev/null
+++ b/misc/examples/cpque.c
@@ -0,0 +1,72 @@
+// Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue
+// Example of per-instance less-function on a single priority queue type
+//
+// Note: i_less_functor: available for cpque types
+// i_cmp_functor: available for csmap and csset types
+// i_hash_functor/i_eq_functor: available for cmap and cset types
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stc/forward.h>
+#include <stc/views.h>
+#include <stc/cstr.h>
+
+// predeclare
+forward_cpque(ipque, int);
+
+struct {
+ ipque Q;
+ bool (*less)(const int*, const int*);
+} typedef IPQueue;
+
+#define IPQueue_drop(q) ipque_drop(&(q)->Q)
+
+#define i_type ipque
+#define i_val int
+#define i_opt c_is_forward // needed to avoid re-type-define container type
+#define i_less_functor(self, x, y) c_container_of(self, IPQueue, Q)->less(x, y) // <== This.
+#include <stc/cpque.h>
+
+#define print(name, q, n) do { \
+ printf("%s: \t", name); \
+ c_forrange (i, n) printf("%d ", q[i]); \
+ puts(""); \
+} while(0)
+
+void print_queue(const char* name, IPQueue q) {
+ // NB: make a clone because there is no way to traverse
+ // priority_queue's content without erasing the queue.
+ IPQueue copy = {ipque_clone(q.Q), q.less};
+
+ for (printf("%s: \t", name); !ipque_empty(&copy.Q); ipque_pop(&copy.Q))
+ printf("%d ", *ipque_top(&copy.Q));
+ puts("");
+ ipque_drop(&copy.Q);
+}
+
+static bool int_less(const int* x, const int* y) { return *x < *y; }
+static bool int_greater(const int* x, const int* y) { return *x > *y; }
+static bool int_lambda(const int* x, const int* y) { return (*x ^ 1) < (*y ^ 1); }
+
+int main()
+{
+ const int data[] = {1,8,5,6,3,4,0,9,7,2}, n = c_arraylen(data);
+ print("data", data, n);
+
+ c_autodrop (IPQueue, q1, {ipque_init(), int_less}) // Max priority queue
+ c_autodrop (IPQueue, minq1, {ipque_init(), int_greater}) // Min priority queue
+ c_autodrop (IPQueue, q5, {ipque_init(), int_lambda}) // Using lambda to compare elements.
+ {
+ c_forrange (i, n)
+ ipque_push(&q1.Q, data[i]);
+ print_queue("q1", q1);
+
+ c_forrange (i, n)
+ ipque_push(&minq1.Q, data[i]);
+ print_queue("minq1", minq1);
+
+ c_forrange (i, n)
+ ipque_push(&q5.Q, data[i]);
+ print_queue("q5", q5);
+ }
+}
diff --git a/misc/examples/csmap_erase.c b/misc/examples/csmap_erase.c
new file mode 100644
index 00000000..48d8ceef
--- /dev/null
+++ b/misc/examples/csmap_erase.c
@@ -0,0 +1,84 @@
+// map_erase.c
+// From C++ example: https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-16
+#include <stc/cstr.h>
+#include <stdio.h>
+
+#define i_key int
+#define i_val_str
+#define i_type mymap
+#include <stc/csmap.h>
+
+void printmap(mymap m)
+{
+ c_foreach (elem, mymap, m)
+ printf(" [%d, %s]", elem.ref->first, cstr_str(&elem.ref->second));
+ printf("\nsize() == %" c_ZU "\n\n", mymap_size(&m));
+}
+
+int main()
+{
+ c_auto (mymap, m1)
+ {
+ // Fill in some data to test with, one at a time
+ mymap_insert(&m1, 1, cstr_lit("A"));
+ mymap_insert(&m1, 2, cstr_lit("B"));
+ mymap_insert(&m1, 3, cstr_lit("C"));
+ mymap_insert(&m1, 4, cstr_lit("D"));
+ mymap_insert(&m1, 5, cstr_lit("E"));
+
+ puts("Starting data of map m1 is:");
+ printmap(m1);
+ // The 1st member function removes an element at a given position
+ mymap_erase_at(&m1, mymap_advance(mymap_begin(&m1), 1));
+ puts("After the 2nd element is deleted, the map m1 is:");
+ printmap(m1);
+ }
+
+ c_auto (mymap, m2)
+ {
+ // Fill in some data to test with, one at a time
+ c_forlist (i, mymap_raw, {
+ {10, "Bob"},
+ {11, "Rob"},
+ {12, "Robert"},
+ {13, "Bert"},
+ {14, "Bobby"},
+ }) mymap_emplace(&m2, c_PAIR(i.ref));
+
+ puts("Starting data of map m2 is:");
+ printmap(m2);
+ mymap_iter it1 = mymap_advance(mymap_begin(&m2), 1);
+ mymap_iter it2 = mymap_find(&m2, mymap_back(&m2)->first);
+
+ puts("to remove:");
+ c_foreach (i, mymap, it1, it2)
+ printf(" [%d, %s]", i.ref->first, cstr_str(&i.ref->second));
+ puts("");
+ // The 2nd member function removes elements
+ // in the range [First, Last)
+ mymap_erase_range(&m2, it1, it2);
+ puts("After the middle elements are deleted, the map m2 is:");
+ printmap(m2);
+ }
+
+ c_auto (mymap, m3)
+ {
+ // Fill in some data to test with, one at a time, using emplace
+ mymap_emplace(&m3, 1, "red");
+ mymap_emplace(&m3, 2, "yellow");
+ mymap_emplace(&m3, 3, "blue");
+ mymap_emplace(&m3, 4, "green");
+ mymap_emplace(&m3, 5, "orange");
+ mymap_emplace(&m3, 6, "purple");
+ mymap_emplace(&m3, 7, "pink");
+
+ puts("Starting data of map m3 is:");
+ printmap(m3);
+ // The 3rd member function removes elements with a given Key
+ size_t count = mymap_erase(&m3, 2);
+ // The 3rd member function also returns the number of elements removed
+ printf("The number of elements removed from m3 is: %" c_ZU "\n", count);
+ puts("After the element with a key of 2 is deleted, the map m3 is:");
+ printmap(m3);
+ }
+}
diff --git a/misc/examples/csmap_find.c b/misc/examples/csmap_find.c
new file mode 100644
index 00000000..3c507476
--- /dev/null
+++ b/misc/examples/csmap_find.c
@@ -0,0 +1,74 @@
+// This implements the c++ std::map::find example at:
+// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-17
+#include <stc/cstr.h>
+
+#define i_key int
+#define i_val_str
+#define i_tag istr
+#include <stc/csmap.h>
+
+#define i_val csmap_istr_raw
+#define i_opt c_no_cmp
+#define i_tag istr
+#include <stc/cvec.h>
+
+void print_elem(csmap_istr_raw p) {
+ printf("(%d, %s) ", p.first, p.second);
+}
+
+#define using_print_collection(CX) \
+ void print_collection_##CX(const CX* t) { \
+ printf("%" c_ZU " elements: ", CX##_size(t)); \
+ \
+ c_foreach (p, CX, *t) { \
+ print_elem(CX##_value_toraw(p.ref)); \
+ } \
+ puts(""); \
+ }
+
+using_print_collection(csmap_istr)
+using_print_collection(cvec_istr)
+
+void findit(csmap_istr c, csmap_istr_key val)
+{
+ printf("Trying find() on value %d\n", val);
+ csmap_istr_iter result = csmap_istr_find(&c, val); // prefer contains() or get()
+ if (result.ref != csmap_istr_end(&c).ref) {
+ printf("Element found: "); print_elem(csmap_istr_value_toraw(result.ref)); puts("");
+ } else {
+ puts("Element not found.");
+ }
+}
+
+int main()
+{
+ c_auto (csmap_istr, m1)
+ c_auto (cvec_istr, v)
+ {
+ c_forlist (i, csmap_istr_raw, {{40, "Zr"}, {45, "Rh"}})
+ csmap_istr_emplace(&m1, c_PAIR(i.ref));
+
+ puts("The starting map m1 is (key, value):");
+ print_collection_csmap_istr(&m1);
+
+ typedef cvec_istr_value pair;
+ cvec_istr_push(&v, (pair){43, "Tc"});
+ cvec_istr_push(&v, (pair){41, "Nb"});
+ cvec_istr_push(&v, (pair){46, "Pd"});
+ cvec_istr_push(&v, (pair){42, "Mo"});
+ cvec_istr_push(&v, (pair){44, "Ru"});
+ cvec_istr_push(&v, (pair){44, "Ru"}); // attempt a duplicate
+
+ puts("Inserting the following vector data into m1:");
+ print_collection_cvec_istr(&v);
+
+ c_foreach (i, cvec_istr, cvec_istr_begin(&v), cvec_istr_end(&v))
+ csmap_istr_emplace(&m1, c_PAIR(i.ref));
+
+ puts("The modified map m1 is (key, value):");
+ print_collection_csmap_istr(&m1);
+ puts("");
+ findit(m1, 45);
+ findit(m1, 6);
+ }
+}
diff --git a/misc/examples/csmap_insert.c b/misc/examples/csmap_insert.c
new file mode 100644
index 00000000..8f777fc6
--- /dev/null
+++ b/misc/examples/csmap_insert.c
@@ -0,0 +1,112 @@
+#include <stc/cstr.h>
+
+// This implements the std::map insert c++ example at:
+// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-19
+
+#define i_key int
+#define i_val int
+#define i_tag ii // Map of int => int
+#include <stc/csmap.h>
+
+#define i_key int
+#define i_val_str
+#define i_tag istr // Map of int => cstr
+#include <stc/csmap.h>
+
+#define i_val csmap_ii_raw
+#define i_opt c_no_cmp
+#define i_tag ii
+#include <stc/cvec.h>
+
+void print_ii(csmap_ii map) {
+ c_foreach (e, csmap_ii, map)
+ printf("(%d, %d) ", e.ref->first, e.ref->second);
+ puts("");
+}
+
+void print_istr(csmap_istr map) {
+ c_foreach (e, csmap_istr, map)
+ printf("(%d, %s) ", e.ref->first, cstr_str(&e.ref->second));
+ puts("");
+}
+
+int main()
+{
+ // insert single values
+ c_auto (csmap_ii, m1) {
+ csmap_ii_insert(&m1, 1, 10);
+ csmap_ii_insert(&m1, 2, 20);
+
+ puts("The original key and mapped values of m1 are:");
+ print_ii(m1);
+
+ // intentionally attempt a duplicate, single element
+ csmap_ii_result ret = csmap_ii_insert(&m1, 1, 111);
+ if (!ret.inserted) {
+ csmap_ii_value pr = *ret.ref;
+ puts("Insert failed, element with key value 1 already exists.");
+ printf(" The existing element is (%d, %d)\n", pr.first, pr.second);
+ }
+ else {
+ puts("The modified key and mapped values of m1 are:");
+ print_ii(m1);
+ }
+ puts("");
+
+ csmap_ii_insert(&m1, 3, 30);
+ puts("The modified key and mapped values of m1 are:");
+ print_ii(m1);
+ puts("");
+ }
+
+ // The templatized version inserting a jumbled range
+ c_auto (csmap_ii, m2)
+ c_auto (cvec_ii, v) {
+ typedef cvec_ii_value ipair;
+ cvec_ii_push(&v, (ipair){43, 294});
+ cvec_ii_push(&v, (ipair){41, 262});
+ cvec_ii_push(&v, (ipair){45, 330});
+ cvec_ii_push(&v, (ipair){42, 277});
+ cvec_ii_push(&v, (ipair){44, 311});
+
+ puts("Inserting the following vector data into m2:");
+ c_foreach (e, cvec_ii, v)
+ printf("(%d, %d) ", e.ref->first, e.ref->second);
+ puts("");
+
+ c_foreach (e, cvec_ii, v)
+ csmap_ii_insert_or_assign(&m2, e.ref->first, e.ref->second);
+
+ puts("The modified key and mapped values of m2 are:");
+ c_foreach (e, csmap_ii, m2)
+ printf("(%d, %d) ", e.ref->first, e.ref->second);
+ puts("\n");
+ }
+
+ // The templatized versions move-constructing elements
+ c_auto (csmap_istr, m3) {
+ csmap_istr_value ip1 = {475, cstr_lit("blue")}, ip2 = {510, cstr_lit("green")};
+
+ // single element
+ csmap_istr_insert(&m3, ip1.first, cstr_move(&ip1.second));
+ puts("After the first move insertion, m3 contains:");
+ print_istr(m3);
+
+ // single element
+ csmap_istr_insert(&m3, ip2.first, cstr_move(&ip2.second));
+ puts("After the second move insertion, m3 contains:");
+ print_istr(m3);
+ puts("");
+ }
+
+ c_auto (csmap_ii, m4) {
+ // Insert the elements from an initializer_list
+ c_forlist (i, csmap_ii_raw, {{ 4, 44 }, { 2, 22 }, { 3, 33 },
+ { 1, 11 }, { 5, 55 }})
+ csmap_ii_insert(&m4, c_PAIR(i.ref));
+
+ puts("After initializer_list insertion, m4 contains:");
+ print_ii(m4);
+ puts("");
+ }
+}
diff --git a/misc/examples/csset_erase.c b/misc/examples/csset_erase.c
new file mode 100644
index 00000000..33eb2163
--- /dev/null
+++ b/misc/examples/csset_erase.c
@@ -0,0 +1,43 @@
+#include <stdio.h>
+
+#define i_key int
+#include <stc/csset.h>
+
+int main()
+{
+ c_auto (csset_int, set)
+ {
+ c_forlist (i, int, {30, 20, 80, 40, 60, 90, 10, 70, 50})
+ csset_int_insert(&set, *i.ref);
+
+ c_foreach (k, csset_int, set)
+ printf(" %d", *k.ref);
+ puts("");
+
+ int val = 64;
+ csset_int_iter it;
+ printf("Show values >= %d:\n", val);
+ it = csset_int_lower_bound(&set, val);
+
+ c_foreach (k, csset_int, it, csset_int_end(&set))
+ printf(" %d", *k.ref);
+ puts("");
+
+ printf("Erase values >= %d:\n", val);
+ while (it.ref != csset_int_end(&set).ref)
+ it = csset_int_erase_at(&set, it);
+
+ c_foreach (k, csset_int, set)
+ printf(" %d", *k.ref);
+ puts("");
+
+ val = 40;
+ printf("Erase values < %d:\n", val);
+ it = csset_int_lower_bound(&set, val);
+ csset_int_erase_range(&set, csset_int_begin(&set), it);
+
+ c_foreach (k, csset_int, set)
+ printf(" %d", *k.ref);
+ puts("");
+ }
+}
diff --git a/misc/examples/cstr_match.c b/misc/examples/cstr_match.c
new file mode 100644
index 00000000..286ba505
--- /dev/null
+++ b/misc/examples/cstr_match.c
@@ -0,0 +1,23 @@
+#include <stc/cstr.h>
+#include <stc/csview.h>
+#include <stdio.h>
+
+int main()
+{
+ c_with (cstr ss = cstr_lit("The quick brown fox jumps over the lazy dog.JPG"), cstr_drop(&ss)) {
+ size_t pos = cstr_find_at(&ss, 0, "brown");
+ printf("%" c_ZU " [%s]\n", pos, pos == c_NPOS ? "<NULL>" : cstr_str(&ss) + pos);
+ printf("equals: %d\n", cstr_equals(&ss, "The quick brown fox jumps over the lazy dog.JPG"));
+ printf("contains: %d\n", cstr_contains(&ss, "umps ove"));
+ printf("starts_with: %d\n", cstr_starts_with(&ss, "The quick brown"));
+ printf("ends_with: %d\n", cstr_ends_with(&ss, ".jpg"));
+ printf("ends_with: %d\n", cstr_ends_with(&ss, ".JPG"));
+
+ cstr s1 = cstr_lit("hell😀 w😀rl🐨");
+ csview ch1 = cstr_u8_chr(&s1, 7);
+ csview ch2 = cstr_u8_chr(&s1, 10);
+ printf("%s\nsize: %" c_ZU ", %" c_ZU "\n", cstr_str(&s1), cstr_u8_size(&s1), cstr_size(&s1));
+ printf("ch1: %.*s\n", c_ARGSV(ch1));
+ printf("ch2: %.*s\n", c_ARGSV(ch2));
+ }
+}
diff --git a/misc/examples/demos.c b/misc/examples/demos.c
new file mode 100644
index 00000000..fc3771cb
--- /dev/null
+++ b/misc/examples/demos.c
@@ -0,0 +1,228 @@
+#include <stc/cstr.h>
+
+void stringdemo1()
+{
+ printf("\nSTRINGDEMO1\n");
+ c_with (cstr cs = cstr_lit("one-nine-three-seven-five"), cstr_drop(&cs))
+ {
+ printf("%s.\n", cstr_str(&cs));
+
+ cstr_insert(&cs, 3, "-two");
+ printf("%s.\n", cstr_str(&cs));
+
+ cstr_erase(&cs, 7, 5); // -nine
+ printf("%s.\n", cstr_str(&cs));
+
+ cstr_replace(&cs, "seven", "four", 1);
+ printf("%s.\n", cstr_str(&cs));
+
+ cstr_take(&cs, cstr_from_fmt("%s *** %s", cstr_str(&cs), cstr_str(&cs)));
+ printf("%s.\n", cstr_str(&cs));
+
+ printf("find \"four\": %s\n", cstr_str(&cs) + cstr_find(&cs, "four"));
+
+ // reassign:
+ cstr_assign(&cs, "one two three four five six seven");
+ cstr_append(&cs, " eight");
+ printf("append: %s\n", cstr_str(&cs));
+ }
+}
+
+#define i_val int64_t
+#define i_tag ix
+#include <stc/cvec.h>
+
+void vectordemo1()
+{
+ printf("\nVECTORDEMO1\n");
+ c_with (cvec_ix bignums = cvec_ix_with_capacity(100), cvec_ix_drop(&bignums))
+ {
+ cvec_ix_reserve(&bignums, 100);
+ for (size_t i = 10; i <= 100; i += 10)
+ cvec_ix_push(&bignums, i * i);
+
+ printf("erase - %d: %" PRIu64 "\n", 3, bignums.data[3]);
+ cvec_ix_erase_n(&bignums, 3, 1); // erase index 3
+
+ cvec_ix_pop(&bignums); // erase the last
+ cvec_ix_erase_n(&bignums, 0, 1); // erase the first
+
+ for (size_t i = 0; i < cvec_ix_size(&bignums); ++i) {
+ printf("%" c_ZU ": %" PRIu64 "\n", i, bignums.data[i]);
+ }
+ }
+}
+
+#define i_val_str
+#include <stc/cvec.h>
+
+void vectordemo2()
+{
+ printf("\nVECTORDEMO2\n");
+ c_auto (cvec_str, names) {
+ cvec_str_emplace_back(&names, "Mary");
+ cvec_str_emplace_back(&names, "Joe");
+ cvec_str_emplace_back(&names, "Chris");
+ cstr_assign(&names.data[1], "Jane"); // replace Joe
+ printf("names[1]: %s\n", cstr_str(&names.data[1]));
+
+ cvec_str_sort(&names); // Sort the array
+ c_foreach (i, cvec_str, names)
+ printf("sorted: %s\n", cstr_str(i.ref));
+ }
+}
+
+#define i_val int
+#define i_tag ix
+#define i_extern // define _clist_mergesort() once
+#include <stc/clist.h>
+
+void listdemo1()
+{
+ printf("\nLISTDEMO1\n");
+ c_auto (clist_ix, nums, nums2)
+ {
+ for (int i = 0; i < 10; ++i)
+ clist_ix_push_back(&nums, i);
+ for (int i = 100; i < 110; ++i)
+ clist_ix_push_back(&nums2, i);
+
+ /* splice nums2 to front of nums */
+ clist_ix_splice(&nums, clist_ix_begin(&nums), &nums2);
+ c_foreach (i, clist_ix, nums)
+ printf("spliced: %d\n", *i.ref);
+ puts("");
+
+ *clist_ix_find(&nums, 104).ref += 50;
+ clist_ix_remove(&nums, 103);
+ clist_ix_iter it = clist_ix_begin(&nums);
+ clist_ix_erase_range(&nums, clist_ix_advance(it, 5), clist_ix_advance(it, 15));
+ clist_ix_pop_front(&nums);
+ clist_ix_push_back(&nums, -99);
+ clist_ix_sort(&nums);
+
+ c_foreach (i, clist_ix, nums)
+ printf("sorted: %d\n", *i.ref);
+ }
+}
+
+#define i_key int
+#define i_tag i
+#include <stc/cset.h>
+
+void setdemo1()
+{
+ printf("\nSETDEMO1\n");
+ cset_i nums = cset_i_init();
+ cset_i_insert(&nums, 8);
+ cset_i_insert(&nums, 11);
+
+ c_foreach (i, cset_i, nums)
+ printf("set: %d\n", *i.ref);
+ cset_i_drop(&nums);
+}
+
+#define i_key int
+#define i_val int
+#define i_tag ii
+#include <stc/cmap.h>
+
+void mapdemo1()
+{
+ printf("\nMAPDEMO1\n");
+ cmap_ii nums = cmap_ii_init();
+ cmap_ii_insert(&nums, 8, 64);
+ cmap_ii_insert(&nums, 11, 121);
+ printf("val 8: %d\n", *cmap_ii_at(&nums, 8));
+ cmap_ii_drop(&nums);
+}
+
+#define i_key_str
+#define i_val int
+#define i_tag si
+#include <stc/cmap.h>
+
+void mapdemo2()
+{
+ printf("\nMAPDEMO2\n");
+ c_auto (cmap_si, nums)
+ {
+ cmap_si_emplace_or_assign(&nums, "Hello", 64);
+ cmap_si_emplace_or_assign(&nums, "Groovy", 121);
+ cmap_si_emplace_or_assign(&nums, "Groovy", 200); // overwrite previous
+
+ // iterate the map:
+ for (cmap_si_iter i = cmap_si_begin(&nums); i.ref != cmap_si_end(&nums).ref; cmap_si_next(&i))
+ printf("long: %s: %d\n", cstr_str(&i.ref->first), i.ref->second);
+
+ // or rather use the short form:
+ c_foreach (i, cmap_si, nums)
+ printf("short: %s: %d\n", cstr_str(&i.ref->first), i.ref->second);
+ }
+}
+
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
+
+void mapdemo3()
+{
+ printf("\nMAPDEMO3\n");
+ cmap_str table = cmap_str_init();
+ cmap_str_emplace(&table, "Map", "test");
+ cmap_str_emplace(&table, "Make", "my");
+ cmap_str_emplace(&table, "Sunny", "day");
+ cmap_str_iter it = cmap_str_find(&table, "Make");
+ c_foreach (i, cmap_str, table)
+ printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
+ printf("size %" c_ZU ": remove: Make: %s\n", cmap_str_size(&table), cstr_str(&it.ref->second));
+ //cmap_str_erase(&table, "Make");
+ cmap_str_erase_at(&table, it);
+
+ printf("size %" c_ZU "\n", cmap_str_size(&table));
+ c_foreach (i, cmap_str, table)
+ printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
+ cmap_str_drop(&table); // frees key and value cstrs, and hash table.
+}
+
+#define i_val float
+#define i_tag f
+#include <stc/carr3.h>
+
+void arraydemo1()
+{
+ printf("\nARRAYDEMO1\n");
+ c_with (carr3_f arr3 = carr3_f_with_size(30, 20, 10, 0.0f),
+ carr3_f_drop(&arr3))
+ {
+ arr3.data[5][4][3] = 10.2f;
+ float **arr2 = arr3.data[5];
+ float *arr1 = arr3.data[5][4];
+
+ printf("arr3: %" c_ZU ": (%" c_ZU ", %" c_ZU ", %" c_ZU ") = %" c_ZU "\n", sizeof(arr3),
+ arr3.xdim, arr3.ydim, arr3.zdim, carr3_f_size(&arr3));
+
+ printf("%g\n", arr1[3]); // = 10.2
+ printf("%g\n", arr2[4][3]); // = 10.2
+ printf("%g\n", arr3.data[5][4][3]); // = 10.2
+
+ float x = 0.0;
+ c_foreach (i, carr3_f, arr3)
+ *i.ref = ++x;
+ printf("%g\n", arr3.data[29][19][9]); // = 6000
+ }
+}
+
+
+int main()
+{
+ stringdemo1();
+ vectordemo1();
+ vectordemo2();
+ listdemo1();
+ setdemo1();
+ mapdemo1();
+ mapdemo2();
+ mapdemo3();
+ arraydemo1();
+}
diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c
new file mode 100644
index 00000000..ba4dce7f
--- /dev/null
+++ b/misc/examples/forfilter.c
@@ -0,0 +1,144 @@
+#include <stdio.h>
+#define i_extern
+#include <stc/cstr.h>
+#include <stc/csview.h>
+#include <stc/views.h>
+
+#define i_type IVec
+#define i_val int
+#include <stc/cstack.h>
+
+#define i_type SVec
+#define i_valclass csview
+#include <stc/cstack.h>
+
+// filters and transforms:
+#define flt_skipValue(i, x) (*i.ref != (x))
+#define flt_isEven(i) ((*i.ref & 1) == 0)
+#define flt_isOdd(i) (*i.ref & 1)
+#define flt_square(i) (*i.ref * *i.ref)
+
+void demo1(void)
+{
+ c_auto (IVec, vec) {
+ c_forlist (i, int, {0, 1, 2, 3, 4, 5, 80, 6, 7, 80, 8, 9, 80, 10, 11, 12, 13, 14, 15, 80, 16, 17})
+ IVec_push(&vec, *i.ref);
+
+ puts("demo1:");
+ c_forfilter (i, IVec, vec, flt_skipValue(i, 80))
+ printf(" %d", *i.ref);
+ puts("");
+
+ int res, sum = 0;
+ c_forfilter (i, IVec, vec
+ , c_flt_skipwhile(i, *i.ref != 80)
+ && c_flt_skip(i, 1)
+ && c_flt_skipwhile(i, *i.ref != 80)
+ && flt_isEven(i)
+ && flt_skipValue(i, 80)
+ , c_flt_take(i, 5) // short-circuit
+ ){
+ sum += res = flt_square(i);
+ printf(" %d", res);
+ }
+ printf("\n sum: %d\n", sum);
+ }
+}
+
+
+/* Rust:
+fn main() {
+ let vector = (1..) // Infinite range of integers
+ .skip_while(|x| *x != 11) // Skip initial numbers unequal 11
+ .filter(|x| x % 2 != 0) // Collect odd numbers
+ .take(5) // Only take five numbers
+ .map(|x| x * x) // Square each number
+ .collect::<Vec<usize>>(); // Return as a new Vec<usize>
+ println!("{:?}", vector); // Print result
+}
+*/
+
+void demo2(void)
+{
+ c_auto (IVec, vector) {
+ puts("demo2:");
+
+ c_forfilter (x, crange, crange_literal(INT64_MAX)
+ , c_flt_skipwhile(x, *x.ref != 11)
+ && *x.ref % 2 != 0
+ , c_flt_take(x, 5))
+ IVec_push(&vector, *x.ref * *x.ref);
+ c_foreach (x, IVec, vector) printf(" %d", *x.ref);
+ puts("");
+ }
+}
+
+/* Rust:
+fn main() {
+ let sentence = "This is a sentence in Rust.";
+ let words: Vec<&str> = sentence
+ .split_whitespace()
+ .collect();
+ let words_containing_i: Vec<&str> = words
+ .into_iter()
+ .filter(|word| word.contains("i"))
+ .collect();
+ println!("{:?}", words_containing_i);
+}
+*/
+void demo3(void)
+{
+ c_auto (SVec, words, words_containing_i) {
+ const char* sentence = "This is a sentence in C99.";
+ c_fortoken (w, sentence, " ")
+ SVec_push(&words, *w.ref);
+
+ c_forfilter (w, SVec, words,
+ csview_contains(*w.ref, "i"))
+ SVec_push(&words_containing_i, *w.ref);
+
+ puts("demo3:");
+ c_foreach (w, SVec, words_containing_i)
+ printf(" %.*s", c_ARGSV(*w.ref));
+ puts("");
+ }
+}
+
+void demo4(void)
+{
+ csview s = c_SV("ab123cReAghNGnΩoEp"); // Ω = multi-byte
+ c_auto (cstr, out) {
+ c_forfilter (i, csview, s, utf8_isupper(utf8_peek(i.ref))) {
+ char chr[4];
+ utf8_encode(chr, utf8_tolower(utf8_peek(i.ref)));
+ cstr_push(&out, chr);
+ }
+ puts("demo4:");
+ printf(" %s\n", cstr_str(&out));
+ }
+}
+
+void demo5(void)
+{
+ #define flt_even(i) ((*i.ref & 1) == 0)
+ #define flt_mid_decade(i) ((*i.ref % 10) != 0)
+ puts("demo5:");
+ crange r1 = crange_make(1963, INT32_MAX);
+ c_forfilter (i, crange, r1
+ , c_flt_skip(i,15)
+ && c_flt_skipwhile(i, flt_mid_decade(i))
+ && c_flt_skip(i,30)
+ && flt_even(i)
+ , c_flt_take(i,10))
+ printf(" %lld", *i.ref);
+ puts("");
+}
+
+int main(void)
+{
+ demo1();
+ demo2();
+ demo3();
+ demo4();
+ demo5();
+}
diff --git a/misc/examples/forloops.c b/misc/examples/forloops.c
new file mode 100644
index 00000000..2654f095
--- /dev/null
+++ b/misc/examples/forloops.c
@@ -0,0 +1,81 @@
+#include <stdio.h>
+#include <stc/views.h>
+
+#define i_type IVec
+#define i_val int
+#include <stc/cstack.h>
+
+#define i_type IMap
+#define i_key int
+#define i_val int
+#include <stc/cmap.h>
+
+
+int main()
+{
+ puts("c_forrange:");
+ c_forrange (30) printf(" xx");
+ puts("");
+
+ c_forrange (i, 30) printf(" %lld", i);
+ puts("");
+
+ c_forrange (i, 30, 60) printf(" %lld", i);
+ puts("");
+
+ c_forrange (i, 30, 90, 2) printf(" %lld", i);
+
+
+ puts("\n\nc_forlist:");
+ c_forlist (i, int, {12, 23, 453, 65, 676})
+ printf(" %d", *i.ref);
+ puts("");
+
+ c_forlist (i, const char*, {"12", "23", "453", "65", "676"})
+ printf(" %s", *i.ref);
+ puts("");
+
+ c_forlist (i, const char*, {"12", "23", "453", "65", "676"})
+ printf(" %s", i.data[i.size - 1 - i.index]);
+
+
+ c_auto (IVec, vec)
+ c_auto (IMap, map)
+ {
+ c_forlist (i, int, {12, 23, 453, 65, 113, 215, 676, 34, 67, 20, 27, 66, 189, 45, 280, 199})
+ IVec_push(&vec, *i.ref);
+
+ c_forlist (i, IMap_value, {{12, 23}, {453, 65}, {676, 123}, {34, 67}})
+ IMap_push(&map, *i.ref);
+
+ puts("\n\nc_foreach:");
+ c_foreach (i, IVec, vec)
+ printf(" %d", *i.ref);
+ puts("");
+
+ c_foreach (i, IMap, map)
+ printf(" (%d %d)", i.ref->first, i.ref->second);
+
+ puts("\n\nc_forpair:");
+ c_forpair (key, val, IMap, map)
+ printf(" (%d %d)", *_.key, *_.val);
+
+ puts("\n\nc_forwhile:");
+ c_forwhile (i, IVec, IVec_begin(&vec), i.index < 3)
+ printf(" %d", *i.ref);
+
+ #define isOdd(i) (*i.ref & 1)
+
+ puts("\n\nc_forfilter:");
+ c_forfilter (i, IVec, vec
+ , c_flt_skipwhile(i, *i.ref != 65)
+ && c_flt_takewhile(i, *i.ref != 280)
+ && c_flt_skipwhile(i, isOdd(i))
+ && isOdd(i)
+ && c_flt_skip(i, 2)
+ , c_flt_take(i, 1))
+ printf(" %d", *i.ref);
+ puts("");
+ // 189
+ }
+}
diff --git a/misc/examples/gauss1.c b/misc/examples/gauss1.c
new file mode 100644
index 00000000..675ff338
--- /dev/null
+++ b/misc/examples/gauss1.c
@@ -0,0 +1,56 @@
+#include <time.h>
+#include <math.h>
+
+#include <stc/crandom.h>
+#include <stc/cstr.h>
+
+// Declare int -> int hashmap. Uses typetag 'ii' for ints.
+#define i_key int
+#define i_val int
+#define i_tag ii
+#include <stc/cmap.h>
+
+// Declare int vector with entries from the cmap.
+#define i_val cmap_ii_value
+#define i_less(x, y) x->first < y->first
+#define i_tag ii
+#include <stc/cvec.h>
+
+int main()
+{
+ enum {N = 10000000};
+ const double Mean = -12.0, StdDev = 6.0, Scale = 74;
+
+ printf("Demo of gaussian / normal distribution of %d random samples\n", N);
+
+ // Setup random engine with normal distribution.
+ uint64_t seed = time(NULL);
+ stc64_t rng = stc64_new(seed);
+ stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev);
+
+ // Create and init histogram vec and map with defered destructors:
+ c_auto (cvec_ii, histvec)
+ c_auto (cmap_ii, histmap)
+ {
+ c_forrange (N) {
+ int index = (int) round( stc64_normalf(&rng, &dist) );
+ cmap_ii_insert(&histmap, index, 0).ref->second += 1;
+ }
+
+ // Transfer map to vec and sort it by map keys.
+ c_foreach (i, cmap_ii, histmap)
+ cvec_ii_push(&histvec, (cmap_ii_value){i.ref->first, i.ref->second});
+
+ cvec_ii_sort(&histvec);
+
+ // Print the gaussian bar chart
+ c_auto (cstr, bar)
+ c_foreach (i, cvec_ii, histvec) {
+ size_t n = (size_t) (i.ref->second * StdDev * Scale * 2.5 / (float)N);
+ if (n > 0) {
+ cstr_resize(&bar, n, '*');
+ printf("%4d %s\n", i.ref->first, cstr_str(&bar));
+ }
+ }
+ }
+}
diff --git a/misc/examples/gauss2.c b/misc/examples/gauss2.c
new file mode 100644
index 00000000..2e07c5a5
--- /dev/null
+++ b/misc/examples/gauss2.c
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <time.h>
+
+#define STC_IMPLEMENT
+#include <stc/crandom.h>
+#include <stc/cstr.h>
+
+// Declare int -> int sorted map.
+#define i_key int
+#define i_val size_t
+#include <stc/csmap.h>
+
+int main()
+{
+ enum {N = 10000000};
+ const double Mean = -12.0, StdDev = 6.0, Scale = 74;
+
+ printf("Demo of gaussian / normal distribution of %d random samples\n", N);
+
+ // Setup random engine with normal distribution.
+ uint64_t seed = time(NULL);
+ stc64_t rng = stc64_new(seed);
+ stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev);
+
+ // Create and init histogram map with defered destruct
+ c_auto (csmap_int, mhist)
+ {
+ c_forrange (N) {
+ int index = (int) round( stc64_normalf(&rng, &dist) );
+ csmap_int_insert(&mhist, index, 0).ref->second += 1;
+ }
+
+ // Print the gaussian bar chart
+ c_auto (cstr, bar)
+ c_forpair (index, count, csmap_int, mhist) {
+ size_t n = (size_t) (*_.count * StdDev * Scale * 2.5 / (float)N);
+ if (n > 0) {
+ cstr_resize(&bar, n, '*');
+ printf("%4d %s\n", *_.index, cstr_str(&bar));
+ }
+ }
+ }
+}
diff --git a/misc/examples/hashmap.c b/misc/examples/hashmap.c
new file mode 100644
index 00000000..f59ed824
--- /dev/null
+++ b/misc/examples/hashmap.c
@@ -0,0 +1,48 @@
+// https://doc.rust-lang.org/rust-by-example/std/hash.html
+#include <stc/cstr.h>
+#define i_key_str
+#define i_val_str
+#include <stdio.h>
+#include <stc/cmap.h>
+
+const char* call(const char* number) {
+ if (!strcmp(number, "798-1364"))
+ return "We're sorry, the call cannot be completed as dialed."
+ " Please hang up and try again.";
+ else if (!strcmp(number, "645-7689"))
+ return "Hello, this is Mr. Awesome's Pizza. My name is Fred."
+ " What can I get for you today?";
+ else
+ return "Hi! Who is this again?";
+}
+
+int main(void) {
+ c_auto (cmap_str, contacts)
+ {
+ cmap_str_emplace(&contacts, "Daniel", "798-1364");
+ cmap_str_emplace(&contacts, "Ashley", "645-7689");
+ cmap_str_emplace(&contacts, "Katie", "435-8291");
+ cmap_str_emplace(&contacts, "Robert", "956-1745");
+
+ const cmap_str_value* v;
+ if ((v = cmap_str_get(&contacts, "Daniel")))
+ printf("Calling Daniel: %s\n", call(cstr_str(&v->second)));
+ else
+ printf("Don't have Daniel's number.");
+
+ cmap_str_emplace_or_assign(&contacts, "Daniel", "164-6743");
+
+ if ((v = cmap_str_get(&contacts, "Ashley")))
+ printf("Calling Ashley: %s\n", call(cstr_str(&v->second)));
+ else
+ printf("Don't have Ashley's number.");
+
+ cmap_str_erase(&contacts, "Ashley");
+
+ puts("");
+ c_forpair (contact, number, cmap_str, contacts) {
+ printf("Calling %s: %s\n", cstr_str(_.contact), call(cstr_str(_.number)));
+ }
+ puts("");
+ }
+}
diff --git a/misc/examples/inits.c b/misc/examples/inits.c
new file mode 100644
index 00000000..021a3e0a
--- /dev/null
+++ b/misc/examples/inits.c
@@ -0,0 +1,116 @@
+#include <stc/cstr.h>
+
+#define i_key int
+#define i_val_str
+#define i_tag id // Map of int => cstr
+#include <stc/cmap.h>
+
+#define i_key_str
+#define i_val int
+#define i_tag cnt // Map of cstr => int
+#include <stc/cmap.h>
+
+typedef struct {int x, y;} ipair_t;
+inline static int ipair_cmp(const ipair_t* a, const ipair_t* b) {
+ int c = c_default_cmp(&a->x, &b->x);
+ return c ? c : c_default_cmp(&a->y, &b->y);
+}
+
+
+#define i_val ipair_t
+#define i_cmp ipair_cmp
+#define i_tag ip
+#include <stc/cvec.h>
+
+#define i_val ipair_t
+#define i_cmp ipair_cmp
+#define i_tag ip
+#define i_extern // define _clist_mergesort() once
+#include <stc/clist.h>
+
+#define i_val float
+#define i_tag f
+#include <stc/cpque.h>
+
+int main(void)
+{
+ // CVEC FLOAT / PRIORITY QUEUE
+
+ c_auto (cpque_f, floats) {
+ const float nums[] = {4.0f, 2.0f, 5.0f, 3.0f, 1.0f};
+
+ // PRIORITY QUEUE
+ c_forrange (i, c_arraylen(nums))
+ cpque_f_push(&floats, nums[i]);
+
+ puts("\npop and show high priorites first:");
+ while (! cpque_f_empty(&floats)) {
+ printf("%.1f ", *cpque_f_top(&floats));
+ cpque_f_pop(&floats);
+ }
+ puts("\n");
+ }
+
+ // CMAP ID
+
+ int year = 2020;
+ c_auto (cmap_id, idnames) {
+ cmap_id_emplace(&idnames, 100, "Hello");
+ cmap_id_insert(&idnames, 110, cstr_lit("World"));
+ cmap_id_insert(&idnames, 120, cstr_from_fmt("Howdy, -%d-", year));
+
+ c_foreach (i, cmap_id, idnames)
+ printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second));
+ puts("");
+ }
+
+ // CMAP CNT
+
+ c_auto (cmap_cnt, countries) {
+ c_forlist (i, cmap_cnt_raw, {
+ {"Norway", 100},
+ {"Denmark", 50},
+ {"Iceland", 10},
+ {"Belgium", 10},
+ {"Italy", 10},
+ {"Germany", 10},
+ {"Spain", 10},
+ {"France", 10},
+ }) cmap_cnt_emplace(&countries, c_PAIR(i.ref));
+
+ cmap_cnt_emplace(&countries, "Greenland", 0).ref->second += 20;
+ cmap_cnt_emplace(&countries, "Sweden", 0).ref->second += 20;
+ cmap_cnt_emplace(&countries, "Norway", 0).ref->second += 20;
+ cmap_cnt_emplace(&countries, "Finland", 0).ref->second += 20;
+
+ c_forpair (country, health, cmap_cnt, countries)
+ printf("%s: %d\n", cstr_str(_.country), *_.health);
+ puts("");
+ }
+
+ // CVEC PAIR
+
+ c_auto (cvec_ip, pairs1) {
+ c_forlist (i, ipair_t, {{5, 6}, {3, 4}, {1, 2}, {7, 8}})
+ cvec_ip_push_back(&pairs1, *i.ref);
+
+ cvec_ip_sort(&pairs1);
+
+ c_foreach (i, cvec_ip, pairs1)
+ printf("(%d %d) ", i.ref->x, i.ref->y);
+ puts("");
+ }
+
+ // CLIST PAIR
+
+ c_auto (clist_ip, pairs2) {
+ c_forlist (i, ipair_t, {{5, 6}, {3, 4}, {1, 2}, {7, 8}})
+ clist_ip_push_back(&pairs2, *i.ref);
+
+ clist_ip_sort(&pairs2);
+
+ c_foreach (i, clist_ip, pairs2)
+ printf("(%d %d) ", i.ref->x, i.ref->y);
+ puts("");
+ }
+}
diff --git a/misc/examples/intrusive.c b/misc/examples/intrusive.c
new file mode 100644
index 00000000..acf4416d
--- /dev/null
+++ b/misc/examples/intrusive.c
@@ -0,0 +1,52 @@
+// Example of intrusive list by using the node API and typesafe c_container_of().
+
+#include <stdio.h>
+
+#define i_type List1
+#define i_val int
+#define i_extern // implement List1_sort()
+#include <stc/clist.h>
+
+#define i_type List2
+#define i_val List1_node
+#define i_opt c_no_cmp // no elem. comparison
+#include <stc/clist.h>
+
+int main()
+{
+ c_auto (List2, list2)
+ {
+ List1 list1 = List1_init(); // should not be destroyed, list2 will destroy shared nodes.
+
+ c_forlist (i, int, {6, 9, 3, 1, 7, 4, 5, 2, 8})
+ List2_push_back(&list2, (List1_node){NULL, *i.ref});
+
+ c_foreach (i, List2, list2)
+ List1_push_node_back(&list1, c_container_of(&i.ref->value, List1_node, value));
+
+ printf("list1:");
+ c_foreach (i, List1, list1) printf(" %d", *i.ref);
+ printf("\nlist2:");
+ c_foreach (i, List2, list2) printf(" %d", i.ref->value);
+
+ printf("\nsort list1");
+ List1_sort(&list1);
+
+ printf("\nlist1:");
+ c_foreach (i, List1, list1) printf(" %d", *i.ref);
+ printf("\nlist2:");
+ c_foreach (i, List2, list2) printf(" %d", i.ref->value);
+
+ printf("\nremove 5 from both lists in O(1) time");
+ List1_iter it1 = List1_find(&list1, 5);
+ if (it1.ref) {
+ List1_unlink_node_after(&list1, it1.prev);
+ free(List2_unlink_node_after(&list2, c_container_of(it1.prev, List2_node, value)));
+ }
+ printf("\nlist1:");
+ c_foreach (i, List1, list1) printf(" %d", *i.ref);
+ printf("\nlist2:");
+ c_foreach (i, List2, list2) printf(" %d", i.ref->value);
+ puts("");
+ }
+}
diff --git a/misc/examples/list.c b/misc/examples/list.c
new file mode 100644
index 00000000..a538d93c
--- /dev/null
+++ b/misc/examples/list.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <time.h>
+
+#define STC_IMPLEMENT
+#define STC_EXTERN
+
+#define i_val double
+#define i_tag fx
+#include <stc/clist.h>
+#include <stc/crandom.h>
+
+int main() {
+ const int n = 2000000;
+
+ c_auto (clist_fx, list)
+ {
+ stc64_t rng = stc64_new(1234);
+ stc64_uniformf_t dist = stc64_uniformf_new(100.0f, n);
+ int m = 0;
+ c_forrange (n)
+ clist_fx_push_back(&list, stc64_uniformf(&rng, &dist)), ++m;
+ double sum = 0.0;
+ printf("sumarize %d:\n", m);
+ c_foreach (i, clist_fx, list)
+ sum += *i.ref;
+ printf("sum %f\n\n", sum);
+
+ c_forwhile (i, clist_fx, clist_fx_begin(&list), i.index < 10)
+ printf("%8d: %10f\n", (int)i.index, *i.ref);
+
+ puts("sort");
+ clist_fx_sort(&list); // mergesort O(n*log n)
+ puts("sorted");
+
+ c_forwhile (i, clist_fx, clist_fx_begin(&list), i.index < 10)
+ printf("%8d: %10f\n", (int)i.index, *i.ref);
+ puts("");
+
+ clist_fx_clear(&list);
+ c_forlist (i, int, {10, 20, 30, 40, 30, 50})
+ clist_fx_push_back(&list, *i.ref);
+
+ const double* v = clist_fx_get(&list, 30);
+ printf("found: %f\n", *v);
+ c_foreach (i, clist_fx, list) printf(" %g", *i.ref);
+ puts("");
+
+ clist_fx_remove(&list, 30);
+ clist_fx_insert_at(&list, clist_fx_begin(&list), 5); // same as push_front()
+ clist_fx_push_back(&list, 500);
+ clist_fx_push_front(&list, 1964);
+ clist_fx_iter it = clist_fx_begin(&list);
+ printf("Full: ");
+ c_foreach (i, clist_fx, list)
+ printf(" %g", *i.ref);
+ printf("\nSubs: ");
+ c_foreach (i, clist_fx, clist_fx_advance(it, 4), clist_fx_end(&list))
+ printf(" %g", *i.ref);
+ puts("");
+ }
+}
diff --git a/misc/examples/list_erase.c b/misc/examples/list_erase.c
new file mode 100644
index 00000000..c1a2aa97
--- /dev/null
+++ b/misc/examples/list_erase.c
@@ -0,0 +1,32 @@
+// erasing from clist
+#include <stdio.h>
+
+#define i_type IList
+#define i_val int
+#include <stc/clist.h>
+
+int main ()
+{
+ c_with (IList L = IList_init(), IList_drop(&L))
+ {
+ c_forlist (i, int, {10, 20, 30, 40, 50})
+ IList_push(&L, *i.ref);
+
+ c_foreach (x, IList, L)
+ printf("%d ", *x.ref);
+ puts("");
+ // 10 20 30 40 50
+ IList_iter it = IList_begin(&L); // ^
+ IList_next(&it);
+ it = IList_erase_at(&L, it); // 10 30 40 50
+ // ^
+ IList_iter end = IList_end(&L); //
+ IList_next(&it);
+ it = IList_erase_range(&L, it, end); // 10 30
+ // ^
+ printf("list contains:");
+ c_foreach (x, IList, L)
+ printf(" %d", *x.ref);
+ puts("");
+ }
+}
diff --git a/misc/examples/list_splice.c b/misc/examples/list_splice.c
new file mode 100644
index 00000000..f7bac0d6
--- /dev/null
+++ b/misc/examples/list_splice.c
@@ -0,0 +1,43 @@
+#include <stdio.h>
+
+#define i_val int
+#define i_tag i
+#define i_extern // define _clist_mergesort() once
+#include <stc/clist.h>
+
+void print_ilist(const char* s, clist_i list)
+{
+ printf("%s", s);
+ c_foreach (i, clist_i, list) {
+ printf(" %d", *i.ref);
+ }
+ puts("");
+}
+
+int main ()
+{
+ c_auto (clist_i, list1, list2)
+ {
+ c_forlist (i, int, {1, 2, 3, 4, 5})
+ clist_i_push_back(&list1, *i.ref);
+
+ c_forlist (i, int, {10, 20, 30, 40, 50})
+ clist_i_push_back(&list2, *i.ref);
+
+ print_ilist("list1:", list1);
+ print_ilist("list2:", list2);
+
+ clist_i_iter it = clist_i_advance(clist_i_begin(&list1), 2);
+ it = clist_i_splice(&list1, it, &list2);
+
+ puts("After splice");
+ print_ilist("list1:", list1);
+ print_ilist("list2:", list2);
+
+ clist_i_splice_range(&list2, clist_i_begin(&list2), &list1, it, clist_i_end(&list1));
+
+ puts("After splice_range");
+ print_ilist("list1:", list1);
+ print_ilist("list2:", list2);
+ }
+}
diff --git a/misc/examples/lower_bound.c b/misc/examples/lower_bound.c
new file mode 100644
index 00000000..2477bc14
--- /dev/null
+++ b/misc/examples/lower_bound.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+
+#define i_val int
+#include <stc/cvec.h>
+
+#define i_val int
+#include <stc/csset.h>
+
+int main()
+{
+ // TEST SORTED VECTOR
+ c_auto (cvec_int, vec)
+ {
+ int key, *res;
+
+ c_forlist (i, int, {40, 600, 1, 7000, 2, 500, 30})
+ cvec_int_push(&vec, *i.ref);
+
+ cvec_int_sort(&vec);
+
+ key = 500;
+ res = cvec_int_lower_bound(&vec, key).ref;
+ if (res != cvec_int_end(&vec).ref)
+ printf("Sorted Vec %d: lower bound: %d\n", key, *res); // 600
+
+ key = 550;
+ res = cvec_int_lower_bound(&vec, key).ref;
+ if (res != cvec_int_end(&vec).ref)
+ printf("Sorted Vec %d: lower_bound: %d\n", key, *res); // 500
+
+ key = 500;
+ res = cvec_int_binary_search(&vec, key).ref;
+ if (res != cvec_int_end(&vec).ref)
+ printf("Sorted Vec %d: bin. search: %d\n", key, *res); // 500
+ puts("");
+ }
+
+ // TEST SORTED SET
+ c_auto (csset_int, set)
+ {
+ int key, *res;
+
+ c_forlist (i, int, {40, 600, 1, 7000, 2, 500, 30})
+ csset_int_push(&set, *i.ref);
+
+ key = 500;
+ res = csset_int_lower_bound(&set, key).ref;
+ if (res != csset_int_end(&set).ref)
+ printf("Sorted Set %d: lower bound: %d\n", key, *res); // 600
+
+ key = 550;
+ res = csset_int_lower_bound(&set, key).ref;
+ if (res != csset_int_end(&set).ref)
+ printf("Sorted Set %d: lower bound: %d\n", key, *res); // 600
+
+ key = 500;
+ res = csset_int_find(&set, key).ref;
+ if (res != csset_int_end(&set).ref)
+ printf("Sorted Set %d: find : %d\n", key, *res); // 600
+ }
+ return 0;
+}
diff --git a/misc/examples/make.sh b/misc/examples/make.sh
new file mode 100755
index 00000000..bd1392fc
--- /dev/null
+++ b/misc/examples/make.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+if [ "$(uname)" = 'Linux' ]; then
+ sanitize='-fsanitize=address'
+ clibs='-lm' # -pthread
+ oflag='-o '
+fi
+
+#cc=gcc; cflags="-s -O2 -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall $sanitize"
+cc=gcc; cflags="-s -O2 -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall -Wsign-compare -Wwrite-strings" # -Wconversion
+#cc=tcc; cflags="-Wall -std=c99"
+#cc=clang; cflags="-s -O2 -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall -Wsign-compare -Wwrite-strings"
+#cc=clang; cflags="-s -O2 -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall -DSTC_CSTR_V1 -DSTC_CSMAP_V1"
+#cc=gcc; cflags="-x c++ -s -O2 -Wall -std=c++20"
+#cc=g++; cflags="-x c++ -s -O2 -Wall"
+#cc=cl; cflags="-O2 -nologo -W2 -MD"
+#cc=cl; cflags="-nologo -TP"
+#cc=cl; cflags="-nologo -std:c11"
+
+if [ "$cc" = "cl" ]; then
+ oflag='/Fe:'
+else
+ oflag='-o '
+fi
+
+run=0
+if [ "$1" = '-h' -o "$1" = '--help' ]; then
+ echo usage: runall.sh [-run] [compiler + options]
+ exit
+fi
+if [ "$1" = '-run' ]; then
+ run=1
+ shift
+fi
+if [ ! -z "$1" ] ; then
+ comp="$@"
+else
+ comp="$cc $cflags"
+fi
+
+if [ $run = 0 ] ; then
+ for i in *.c ; do
+ echo $comp -I../include $i $clibs $oflag$(basename $i .c).exe
+ $comp -I../include $i $clibs $oflag$(basename $i .c).exe
+ done
+else
+ for i in *.c ; do
+ echo $comp -I../include $i $clibs
+ $comp -I../include $i $clibs
+ if [ -f $(basename -s .c $i).exe ]; then ./$(basename -s .c $i).exe; fi
+ if [ -f ./a.exe ]; then ./a.exe; fi
+ if [ -f ./a.out ]; then ./a.out; fi
+ done
+fi
+
+rm -f a.out *.o *.obj # *.exe
diff --git a/misc/examples/mapmap.c b/misc/examples/mapmap.c
new file mode 100644
index 00000000..488cc539
--- /dev/null
+++ b/misc/examples/mapmap.c
@@ -0,0 +1,68 @@
+// create a structure like: std::map<std::string, std::map<std::string, std::string>>:
+
+#include <stc/cstr.h>
+
+// People: std::map<std::string, std::string>
+#define i_type People
+#define i_key_str
+#define i_val_str
+#define i_keydrop(p) (printf("kdrop: %s\n", cstr_str(p)), cstr_drop(p)) // override
+#include <stc/csmap.h>
+
+// Departments: std::map<std::string, People>
+#define i_type Departments
+#define i_key_str
+#define i_valclass People
+// Shorthand for:
+// #define i_val People
+// #define i_cmp People_cmp
+// #define i_valclone People_clone
+// #define i_valdrop People_drop
+#include <stc/csmap.h>
+
+
+void add(Departments* deps, const char* name, const char* email, const char* dep)
+{
+ People *people = &Departments_insert(deps, cstr_from(dep), People_init()).ref->second;
+ People_emplace_or_assign(people, name, email);
+}
+
+int contains(Departments* map, const char* name)
+{
+ int count = 0;
+ c_foreach (i, Departments, *map)
+ if (People_contains(&i.ref->second, name))
+ ++count;
+ return count;
+}
+
+int main(void)
+{
+ c_auto (Departments, map)
+ {
+ add(&map, "Anna Kendro", "[email protected]", "Support");
+ add(&map, "Terry Dane", "[email protected]", "Development");
+ add(&map, "Kik Winston", "[email protected]", "Finance");
+ add(&map, "Nancy Drew", "[email protected]", "Development");
+ add(&map, "Nick Denton", "[email protected]", "Finance");
+ add(&map, "Stan Whiteword", "[email protected]", "Marketing");
+ add(&map, "Serena Bath", "[email protected]", "Support");
+ add(&map, "Patrick Dust", "[email protected]", "Finance");
+ add(&map, "Red Winger", "[email protected]", "Marketing");
+ add(&map, "Nick Denton", "[email protected]", "Support");
+ add(&map, "Colin Turth", "[email protected]", "Support");
+ add(&map, "Dennis Kay", "[email protected]", "Marketing");
+ add(&map, "Anne Dickens", "[email protected]", "Development");
+
+ c_foreach (i, Departments, map)
+ c_forpair (name, email, People, i.ref->second)
+ printf("%s: %s - %s\n", cstr_str(&i.ref->first), cstr_str(_.name), cstr_str(_.email));
+ puts("");
+
+ printf("found Nick Denton: %d\n", contains(&map, "Nick Denton"));
+ printf("found Patrick Dust: %d\n", contains(&map, "Patrick Dust"));
+ printf("found Dennis Kay: %d\n", contains(&map, "Dennis Kay"));
+ printf("found Serena Bath: %d\n", contains(&map, "Serena Bath"));
+ puts("Done");
+ }
+}
diff --git a/misc/examples/mmap.c b/misc/examples/mmap.c
new file mode 100644
index 00000000..3934cf26
--- /dev/null
+++ b/misc/examples/mmap.c
@@ -0,0 +1,72 @@
+// This implements the multimap c++ example found at:
+// https://en.cppreference.com/w/cpp/container/multimap/insert
+
+// Multimap entries
+#include <stc/cstr.h>
+#define i_val_str
+//#define i_valdrop(x) (printf("drop %s\n", cstr_str(x)), cstr_drop(x))
+#define i_extern // define _clist_mergesort() once
+#include <stc/clist.h>
+
+// Map of int => clist_str.
+#define i_type Multimap
+#define i_key int
+#define i_valclass clist_str // uses clist_str as i_val and binds clist_str_clone, clist_str_drop
+#define i_cmp -c_default_cmp // like std::greater<int>
+#include <stc/csmap.h>
+
+void print(const char* lbl, const Multimap mmap)
+{
+ printf("%s ", lbl);
+ c_foreach (e, Multimap, mmap) {
+ c_foreach (s, clist_str, e.ref->second)
+ printf("{%d,%s} ", e.ref->first, cstr_str(s.ref));
+ }
+ puts("");
+}
+
+void insert(Multimap* mmap, int key, const char* str)
+{
+ clist_str *list = &Multimap_insert(mmap, key, clist_str_init()).ref->second;
+ clist_str_emplace_back(list, str);
+}
+
+int main()
+{
+ c_auto (Multimap, mmap)
+ {
+ typedef struct {int a; const char* b;} pair;
+
+ // list-initialize
+ c_forlist (i, pair, {{2, "foo"}, {2, "bar"}, {3, "baz"}, {1, "abc"}, {5, "def"}})
+ insert(&mmap, i.ref->a, i.ref->b);
+ print("#1", mmap);
+
+ // insert using value_type
+ insert(&mmap, 5, "pqr");
+ print("#2", mmap);
+
+ // insert using make_pair
+ insert(&mmap, 6, "uvw");
+ print("#3", mmap);
+
+ insert(&mmap, 7, "xyz");
+ print("#4", mmap);
+
+ // insert using initialization_list
+ c_forlist (i, pair, {{5, "one"}, {5, "two"}})
+ insert(&mmap, i.ref->a, i.ref->b);
+ print("#5", mmap);
+
+ // FOLLOWING NOT IN ORIGINAL EXAMPLE:
+ // erase all entries with key 5
+ Multimap_erase(&mmap, 5);
+ print("+5", mmap);
+
+
+ Multimap_clear(&mmap);
+ c_forlist (i, pair, {{1, "ä"}, {2, "ё"}, {2, "ö"}, {3, "ü"}})
+ insert(&mmap, i.ref->a, i.ref->b);
+ print("#6", mmap);
+ }
+}
diff --git a/misc/examples/multimap.c b/misc/examples/multimap.c
new file mode 100644
index 00000000..e72bdce3
--- /dev/null
+++ b/misc/examples/multimap.c
@@ -0,0 +1,99 @@
+#include <stc/cstr.h>
+
+// Olympics multimap example
+
+struct OlympicsData { int year; const char *city, *country, *date; } ol_data[] = {
+ {2026, "Milan and Cortina d'Ampezzo", "Italy", "February 6-22"},
+ {2022, "Beijing", "China", "February 4-20"},
+ {2018, "PyeongChang", "South Korea", "February 9-25"},
+ {2014, "Sochi", "Russia", "February 7-23"},
+ {2010, "Vancouver", "Canada", "February 12-28"},
+ {2006, "Torino", "Italy", "February 10-26"},
+ {2002, "Salt Lake City", "United States", "February 8-24"},
+ {1998, "Nagano", "Japan", "February 7-22"},
+ {1994, "Lillehammer", "Norway", "February 12-27"},
+ {1992, "Albertville", "France", "February 8-23"},
+ {1988, "Calgary", "Canada", "February 13-28"},
+ {1984, "Sarajevo", "Yugoslavia", "February 8-19"},
+ {1980, "Lake Placid", "United States", "February 13-24"},
+ {1976, "Innsbruck", "Austria", "February 4-15"},
+ {1972, "Sapporo", "Japan", "February 3-13"},
+ {1968, "Grenoble", "France", "February 6-18"},
+ {1964, "Innsbruck", "Austria", "January 29-February 9"},
+ {1960, "Squaw Valley", "United States", "February 18-28"},
+ {1956, "Cortina d'Ampezzo", "Italy", "January 26 - February 5"},
+ {1952, "Oslo", "Norway", "February 14 - 25"},
+ {1948, "St. Moritz", "Switzerland", "January 30 - February 8"},
+ {1944, "canceled", "canceled", "canceled"},
+ {1940, "canceled", "canceled", "canceled"},
+ {1936, "Garmisch-Partenkirchen", "Germany", "February 6 - 16"},
+ {1932, "Lake Placid", "United States", "February 4 - 15"},
+ {1928, "St. Moritz", "Switzerland", "February 11 - 19"},
+ {1924, "Chamonix", "France", "January 25 - February 5"},
+};
+
+typedef struct { int year; cstr city, date; } OlympicLocation;
+
+int OlympicLocation_cmp(const OlympicLocation* a, const OlympicLocation* b);
+OlympicLocation OlympicLocation_clone(OlympicLocation loc);
+void OlympicLocation_drop(OlympicLocation* self);
+
+// Create a clist<OlympicLocation>, can be sorted by year.
+#define i_valclass OlympicLocation // binds _cmp, _clone and _drop.
+#define i_tag OL
+#define i_extern // define _clist_mergesort()
+#include <stc/clist.h>
+
+// Create a csmap<cstr, clist_OL> where key is country name
+#define i_key_str // binds cstr_equ, cstr_hash, cstr_clone, ++
+#define i_valclass clist_OL // binds clist_OL_clone, clist_OL_drop
+#define i_tag OL
+#include <stc/csmap.h>
+
+int OlympicLocation_cmp(const OlympicLocation* a, const OlympicLocation* b) {
+ return a->year - b->year;
+}
+
+OlympicLocation OlympicLocation_clone(OlympicLocation loc) {
+ loc.city = cstr_clone(loc.city);
+ loc.date = cstr_clone(loc.date);
+ return loc;
+}
+void OlympicLocation_drop(OlympicLocation* self) {
+ c_drop(cstr, &self->city, &self->date);
+}
+
+int main()
+{
+ // Define the multimap with destructor defered to when block is completed.
+ c_auto (csmap_OL, multimap)
+ {
+ const clist_OL empty = clist_OL_init();
+
+ for (size_t i = 0; i < c_arraylen(ol_data); ++i)
+ {
+ struct OlympicsData* d = &ol_data[i];
+ OlympicLocation loc = {.year = d->year,
+ .city = cstr_from(d->city),
+ .date = cstr_from(d->date)};
+ // Insert an empty list for each new country, and append the entry to the list.
+ // If country already exist in map, its list is returned from the insert function.
+ clist_OL* list = &csmap_OL_insert(&multimap, cstr_from(d->country), empty).ref->second;
+ clist_OL_push_back(list, loc);
+ }
+ // Sort locations by year for each country.
+ c_foreach (country, csmap_OL, multimap)
+ clist_OL_sort(&country.ref->second);
+
+ // Print the multimap:
+ c_foreach (country, csmap_OL, multimap)
+ {
+ // Loop the locations for a country sorted by year
+ c_foreach (loc, clist_OL, country.ref->second)
+ printf("%s: %d, %s, %s\n", cstr_str(&country.ref->first),
+ loc.ref->year,
+ cstr_str(&loc.ref->city),
+ cstr_str(&loc.ref->date));
+ }
+ }
+}
diff --git a/misc/examples/music_arc.c b/misc/examples/music_arc.c
new file mode 100644
index 00000000..162c4c2f
--- /dev/null
+++ b/misc/examples/music_arc.c
@@ -0,0 +1,68 @@
+// shared_ptr-examples.cpp
+// based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160
+#include <stc/cstr.h>
+
+struct Song
+{
+ cstr artist;
+ cstr title;
+} typedef Song;
+
+int Song_cmp(const Song* x, const Song* y)
+ { return cstr_cmp(&x->title, &y->title); }
+
+Song Song_from(const char* artist, const char* title)
+ { return (Song){cstr_from(artist), cstr_from(title)}; }
+
+void Song_drop(Song* s) {
+ printf("drop: %s\n", cstr_str(&s->title));
+ c_drop(cstr, &s->artist, &s->title);
+}
+
+// Define the reference counted type
+#define i_type SongArc
+#define i_valclass Song
+#define i_opt c_no_hash
+#include <stc/carc.h>
+
+// ... and a vector of it
+#define i_type SongVec
+#define i_valboxed SongArc
+#include <stc/cstack.h>
+
+void example3()
+{
+ c_auto (SongVec, vec1, vec2)
+ {
+ c_forlist (i, Song, {
+ Song_from("Bob Dylan", "The Times They Are A Changing"),
+ Song_from("Aretha Franklin", "Bridge Over Troubled Water"),
+ Song_from("Thalia", "Entre El Mar y Una Estrella")
+ }) SongVec_emplace(&vec1, *i.ref);
+
+ // Share all entries in vec with vec2, except Bob Dylan.
+ c_foreach (s, SongVec, vec1)
+ if (!cstr_equals(&s.ref->get->artist, "Bob Dylan"))
+ SongVec_push(&vec2, SongArc_clone(*s.ref));
+
+ // Add a few more to vec2. We can use emplace when creating new entries
+ SongVec_emplace(&vec2, Song_from("Michael Jackson", "Billie Jean"));
+ SongVec_emplace(&vec2, Song_from("Rihanna", "Stay"));
+ // If we use push, we would need to construct the Arc explicitly (as in c++, make_shared):
+ // SongVec_push(&vec2, SongArc_from(Song_from("Rihanna", "Stay")));
+
+ // We now have two vectors with some shared, some unique entries.
+ c_forlist (i, SongVec, {vec1, vec2}) {
+ puts("VEC:");
+ c_foreach (s, SongVec, *i.ref)
+ printf(" %s - %s, REFS: %ld\n", cstr_str(&s.ref->get->artist),
+ cstr_str(&s.ref->get->title),
+ *s.ref->use_count);
+ }
+ } // because the shared elem. are ref. counted, they are only dropped once here.
+}
+
+int main()
+{
+ example3();
+}
diff --git a/misc/examples/new_arr.c b/misc/examples/new_arr.c
new file mode 100644
index 00000000..871cfae0
--- /dev/null
+++ b/misc/examples/new_arr.c
@@ -0,0 +1,57 @@
+#include <stc/cstr.h>
+
+#define i_val int
+#include <stc/carr2.h>
+
+#define i_val int
+#include <stc/carr3.h>
+
+#define i_val_str
+#include <stc/carr2.h>
+
+int main()
+{
+ int w = 7, h = 5, d = 3;
+
+ c_with (carr2_int volume = carr2_int_new_uninit(w, h), carr2_int_drop(&volume))
+ {
+ int *dat = carr2_int_data(&volume);
+ for (size_t i = 0; i < carr2_int_size(&volume); ++i)
+ dat[i] = i;
+
+ for (size_t x = 0; x < volume.xdim; ++x)
+ for (size_t y = 0; y < volume.ydim; ++y)
+ printf(" %d", volume.data[x][y]);
+ puts("");
+
+ c_foreach (i, carr2_int, volume)
+ printf(" %d", *i.ref);
+ puts("\n");
+ }
+
+ c_with (carr3_int volume = carr3_int_new_uninit(w, h, d), carr3_int_drop(&volume))
+ {
+ int *dat = carr3_int_data(&volume);
+ for (size_t i = 0; i < carr3_int_size(&volume); ++i)
+ dat[i] = i;
+
+ for (size_t x = 0; x < volume.xdim; ++x)
+ for (size_t y = 0; y < volume.ydim; ++y)
+ for (size_t z = 0; z < volume.zdim; ++z)
+ printf(" %d", volume.data[x][y][z]);
+ puts("");
+
+ c_foreach (i, carr3_int, volume)
+ printf(" %d", *i.ref);
+ puts("");
+ }
+
+ c_with (carr2_str text2d = carr2_str_with_size(h, d, cstr_NULL), carr2_str_drop(&text2d))
+ {
+ cstr_assign(&text2d.data[2][1], "hello");
+ cstr_assign(&text2d.data[4][0], "world");
+
+ c_foreach (i, carr2_str, text2d)
+ printf("line: %s\n", cstr_str(i.ref));
+ }
+}
diff --git a/misc/examples/new_deq.c b/misc/examples/new_deq.c
new file mode 100644
index 00000000..39149140
--- /dev/null
+++ b/misc/examples/new_deq.c
@@ -0,0 +1,61 @@
+#include <stc/cstr.h>
+#include <stc/forward.h>
+
+forward_cdeq(cdeq_i32, int);
+forward_cdeq(cdeq_pnt, struct Point);
+
+struct MyStruct {
+ cdeq_i32 intvec;
+ cdeq_pnt pntvec;
+} typedef MyStruct;
+
+
+#define i_val int
+#define i_opt c_is_forward
+#define i_tag i32
+#include <stc/cdeq.h>
+
+struct Point { int x, y; } typedef Point;
+int point_cmp(const Point* a, const Point* b) {
+ int c = a->x - b->x;
+ return c ? c : a->y - b->y;
+}
+
+#define i_val Point
+#define i_cmp point_cmp
+#define i_opt c_is_forward
+#define i_tag pnt
+#include <stc/cdeq.h>
+
+#define i_val float
+#include <stc/cdeq.h>
+
+#define i_val_str
+#include <stc/cdeq.h>
+
+
+int main()
+{
+ c_auto (cdeq_i32, vec)
+ {
+ cdeq_i32_push_back(&vec, 123);
+ }
+ c_auto (cdeq_float, fvec)
+ {
+ cdeq_float_push_back(&fvec, 123.3f);
+ }
+ c_auto (cdeq_pnt, pvec)
+ {
+ cdeq_pnt_push_back(&pvec, (Point){42, 14});
+ cdeq_pnt_push_back(&pvec, (Point){32, 94});
+ cdeq_pnt_push_front(&pvec, (Point){62, 81});
+ cdeq_pnt_sort(&pvec);
+ c_foreach (i, cdeq_pnt, pvec)
+ printf(" (%d %d)", i.ref->x, i.ref->y);
+ puts("");
+ }
+ c_auto (cdeq_str, svec)
+ {
+ cdeq_str_emplace_back(&svec, "Hello, friend");
+ }
+}
diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c
new file mode 100644
index 00000000..6dbe80b4
--- /dev/null
+++ b/misc/examples/new_list.c
@@ -0,0 +1,61 @@
+#include <stc/cstr.h>
+
+forward_clist(clist_i32, int);
+forward_clist(clist_pnt, struct Point);
+
+struct MyStruct {
+ clist_i32 intlst;
+ clist_pnt pntlst;
+} typedef MyStruct;
+
+#define i_val int
+#define i_opt c_is_forward
+#define i_tag i32
+#define i_extern // define _clist_mergesort()
+#include <stc/clist.h>
+
+struct Point { int x, y; } typedef Point;
+int point_cmp(const Point* a, const Point* b) {
+ int c = a->x - b->x;
+ return c ? c : a->y - b->y;
+}
+
+#define i_val Point
+#define i_cmp point_cmp
+#define i_opt c_is_forward
+#define i_tag pnt
+#include <stc/clist.h>
+
+#define i_val float
+#include <stc/clist.h>
+
+#define i_val_str
+#include <stc/clist.h>
+
+
+int main()
+{
+ c_auto (clist_i32, lst)
+ clist_i32_push_back(&lst, 123);
+
+ c_auto (clist_pnt, plst) {
+ c_forlist (i, Point, {{42, 14}, {32, 94}, {62, 81}})
+ clist_pnt_push_back(&plst, *i.ref);
+
+ clist_pnt_sort(&plst);
+
+ c_foreach (i, clist_pnt, plst)
+ printf(" (%d %d)", i.ref->x, i.ref->y);
+ puts("");
+ }
+
+ c_auto (clist_float, flst) {
+ c_forlist (i, float, {123.3f, 321.2f, -32.2f, 78.2f})
+ clist_float_push_back(&flst, *i.ref);
+
+ c_foreach (i, clist_float, flst) printf(" %g", *i.ref);
+ }
+
+ c_auto (clist_str, slst)
+ clist_str_emplace_back(&slst, "Hello, friend");
+}
diff --git a/misc/examples/new_map.c b/misc/examples/new_map.c
new file mode 100644
index 00000000..f43d4217
--- /dev/null
+++ b/misc/examples/new_map.c
@@ -0,0 +1,73 @@
+#include <stc/cstr.h>
+#include <stc/forward.h>
+
+forward_cmap(cmap_pnt, struct Point, int);
+
+struct MyStruct {
+ cmap_pnt pntmap;
+ cstr name;
+} typedef MyStruct;
+
+// int => int map
+#define i_key int
+#define i_val int
+#include <stc/cmap.h>
+
+// Point => int map
+struct Point { int x, y; } typedef Point;
+
+int point_cmp(const Point* a, const Point* b) {
+ int c = a->x - b->x;
+ return c ? c : a->y - b->y;
+}
+
+// Point => int map
+#define i_key Point
+#define i_val int
+#define i_cmp point_cmp
+#define i_hash c_default_hash
+#define i_opt c_is_forward
+#define i_tag pnt
+#include <stc/cmap.h>
+
+// cstr => cstr map
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
+
+// string set
+#define i_key_str
+#include <stc/cset.h>
+
+
+int main()
+{
+ c_auto (cmap_int, map)
+ c_auto (cmap_pnt, pmap)
+ c_auto (cmap_str, smap)
+ c_auto (cset_str, sset)
+ {
+ cmap_int_insert(&map, 123, 321);
+
+ c_forlist (i, cmap_pnt_raw, {{{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}})
+ cmap_pnt_insert(&pmap, c_PAIR(i.ref));
+
+ c_foreach (i, cmap_pnt, pmap)
+ printf(" (%d, %d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second);
+ puts("");
+
+ c_forlist (i, cmap_str_raw, {
+ {"Hello, friend", "long time no see"},
+ {"So long, friend", "see you around"},
+ }) cmap_str_emplace(&smap, c_PAIR(i.ref));
+
+ c_forlist (i, const char*, {
+ "Hello, friend",
+ "Nice to see you again",
+ "So long, friend",
+ }) cset_str_emplace(&sset, *i.ref);
+
+ c_foreach (i, cset_str, sset)
+ printf(" %s\n", cstr_str(i.ref));
+ }
+}
diff --git a/misc/examples/new_pque.c b/misc/examples/new_pque.c
new file mode 100644
index 00000000..2bb1d729
--- /dev/null
+++ b/misc/examples/new_pque.c
@@ -0,0 +1,55 @@
+#include <stdio.h>
+
+#define i_val int
+#include <stc/cstack.h>
+#define i_val int
+#include <stc/cpque.h>
+
+struct Point { int x, y; } typedef Point;
+
+int Point_cmp(const Point* a, const Point* b) {
+ int c = a->x - b->x;
+ return c ? c : a->y - b->y;
+}
+
+#define i_val Point
+#define i_cmp Point_cmp
+#define i_tag pnt
+#include <stc/cpque.h>
+
+
+int main()
+{
+ c_auto (cstack_int, istk)
+ {
+ cstack_int_push(&istk, 123);
+ cstack_int_push(&istk, 321);
+ // print
+ c_foreach (i, cstack_int, istk)
+ printf(" %d", *i.ref);
+ puts("");
+ }
+ c_auto (cpque_pnt, pque)
+ {
+ cpque_pnt_push(&pque, (Point){23, 80});
+ cpque_pnt_push(&pque, (Point){12, 32});
+ cpque_pnt_push(&pque, (Point){54, 74});
+ cpque_pnt_push(&pque, (Point){12, 62});
+ // print
+ while (!cpque_pnt_empty(&pque)) {
+ const cpque_pnt_value *v = cpque_pnt_top(&pque);
+ printf(" (%d,%d)", v->x, v->y);
+ cpque_pnt_pop(&pque);
+ }
+ puts("");
+ }
+ c_auto (cpque_int, ique)
+ {
+ cpque_int_push(&ique, 123);
+ cpque_int_push(&ique, 321);
+ // print
+ for (size_t i=0; i<cpque_int_size(&ique); ++i)
+ printf(" %d", ique.data[i]);
+ puts("");
+ }
+}
diff --git a/misc/examples/new_queue.c b/misc/examples/new_queue.c
new file mode 100644
index 00000000..bc7a95c9
--- /dev/null
+++ b/misc/examples/new_queue.c
@@ -0,0 +1,45 @@
+#include <stc/crandom.h>
+#include <stc/forward.h>
+#include <stdio.h>
+#include <time.h>
+
+forward_cqueue(cqueue_pnt, struct Point);
+
+struct Point { int x, y; } typedef Point;
+int point_cmp(const Point* a, const Point* b) {
+ int c = c_default_cmp(&a->x, &b->x);
+ return c ? c : c_default_cmp(&a->y, &b->y);
+}
+#define i_val Point
+#define i_cmp point_cmp
+#define i_opt c_is_forward
+#define i_tag pnt
+#include <stc/cqueue.h>
+
+#define i_type IQ
+#define i_val int
+#include <stc/cqueue.h>
+
+int main() {
+ int n = 50000000;
+ stc64_t rng = stc64_new(time(NULL));
+ stc64_uniform_t dist = stc64_uniform_new(0, n);
+
+ c_auto (IQ, Q)
+ {
+ // Push eight million random numbers onto the queue.
+ c_forrange (n)
+ IQ_push(&Q, stc64_uniform(&rng, &dist));
+
+ // Push or pop on the queue 50 million times
+ printf("befor: size %" c_ZU ", capacity %" c_ZU "\n", IQ_size(&Q), IQ_capacity(&Q));
+ c_forrange (n) {
+ int r = stc64_uniform(&rng, &dist);
+ if (r & 3)
+ IQ_push(&Q, r);
+ else
+ IQ_pop(&Q);
+ }
+ printf("after: size %" c_ZU ", capacity %" c_ZU "\n", IQ_size(&Q), IQ_capacity(&Q));
+ }
+}
diff --git a/misc/examples/new_smap.c b/misc/examples/new_smap.c
new file mode 100644
index 00000000..c77aa185
--- /dev/null
+++ b/misc/examples/new_smap.c
@@ -0,0 +1,77 @@
+#include <stc/cstr.h>
+#include <stc/forward.h>
+
+forward_csmap(PMap, struct Point, int);
+
+// Use forward declared PMap in struct
+struct MyStruct {
+ PMap pntmap;
+ cstr name;
+} typedef MyStruct;
+
+// int => int map
+#define i_key int
+#define i_val int
+#include <stc/csmap.h>
+
+// Point => int map
+struct Point { int x, y; } typedef Point;
+int point_cmp(const Point* a, const Point* b) {
+ int c = a->x - b->x;
+ return c ? c : a->y - b->y;
+}
+
+#define i_type PMap
+#define i_key Point
+#define i_val int
+#define i_cmp point_cmp
+#define i_opt c_is_forward
+#include <stc/csmap.h>
+
+// cstr => cstr map
+#define i_type SMap
+#define i_key_str
+#define i_val_str
+#include <stc/csmap.h>
+
+// cstr set
+#define i_type SSet
+#define i_key_str
+#include <stc/csset.h>
+
+
+int main()
+{
+ c_auto (csmap_int, imap) {
+ csmap_int_insert(&imap, 123, 321);
+ }
+
+ c_auto (PMap, pmap) {
+ c_forlist (i, PMap_value, {
+ {{42, 14}, 1},
+ {{32, 94}, 2},
+ {{62, 81}, 3},
+ }) PMap_insert(&pmap, c_PAIR(i.ref));
+
+ c_forpair (p, i, PMap, pmap)
+ printf(" (%d,%d: %d)", _.p->x, _.p->y, *_.i);
+ puts("");
+ }
+
+ c_auto (SMap, smap) {
+ c_forlist (i, SMap_raw, {
+ {"Hello, friend", "this is the mapped value"},
+ {"The brown fox", "jumped"},
+ {"This is the time", "for all good things"},
+ }) SMap_emplace(&smap, c_PAIR(i.ref));
+
+ c_forpair (i, j, SMap, smap)
+ printf(" (%s: %s)\n", cstr_str(_.i), cstr_str(_.j));
+ }
+
+ c_auto (SSet, sset) {
+ SSet_emplace(&sset, "Hello, friend");
+ SSet_emplace(&sset, "Goodbye, foe");
+ printf("Found? %s\n", SSet_contains(&sset, "Hello, friend") ? "true" : "false");
+ }
+}
diff --git a/misc/examples/new_sptr.c b/misc/examples/new_sptr.c
new file mode 100644
index 00000000..2c6b28d6
--- /dev/null
+++ b/misc/examples/new_sptr.c
@@ -0,0 +1,72 @@
+#include <stc/cstr.h>
+
+typedef struct { cstr name, last; } Person;
+Person Person_make(const char* name, const char* last);
+Person Person_clone(Person p);
+void Person_drop(Person* p);
+int Person_cmp(const Person* a, const Person* b);
+uint64_t Person_hash(const Person* p);
+
+#define i_type PersonArc
+#define i_valclass Person // "class" ensure Person_drop will be called
+#define i_cmp Person_cmp // enable carc object comparisons (not ptr to obj)
+#define i_hash Person_hash // enable carc object hash (not ptr to obj)
+#include <stc/carc.h>
+
+#define i_type IPtr
+#define i_val int
+#define i_valdrop(x) printf("drop: %d\n", *x)
+#include <stc/carc.h>
+
+#define i_type IPStack
+#define i_valboxed IPtr
+#include <stc/cstack.h>
+
+#define i_type PASet
+#define i_valboxed PersonArc
+#include <stc/cset.h>
+
+
+Person Person_make(const char* name, const char* last) {
+ return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+}
+int Person_cmp(const Person* a, const Person* b) {
+ return cstr_cmp(&a->name, &b->name);
+}
+uint64_t Person_hash(const Person* p) {
+ return cstr_hash(&p->name);
+}
+Person Person_clone(Person p) {
+ p.name = cstr_clone(p.name), p.last = cstr_clone(p.last);
+ return p;
+}
+void Person_drop(Person* p) {
+ printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
+ c_drop(cstr, &p->name, &p->last);
+}
+
+
+int main(void) {
+ c_auto (PersonArc, p, q, r, s)
+ {
+ puts("Ex1");
+ p = PersonArc_from(Person_make("John", "Smiths"));
+ q = PersonArc_clone(p); // share
+ r = PersonArc_clone(p);
+ s = PersonArc_from(Person_clone(*p.get)); // deep copy
+ printf("%s %s: refs %ld\n", cstr_str(&p.get->name), cstr_str(&p.get->last), *p.use_count);
+ }
+ c_auto (IPStack, vec)
+ {
+ puts("Ex2");
+ IPStack_push(&vec, IPtr_from(10));
+ IPStack_push(&vec, IPtr_from(20));
+ IPStack_emplace(&vec, 30); // same as IPStack_push(&vec, IPtr_from(30));
+ IPStack_push(&vec, IPtr_clone(*IPStack_back(&vec)));
+ IPStack_push(&vec, IPtr_clone(*IPStack_front(&vec)));
+
+ c_foreach (i, IPStack, vec)
+ printf(" (%d: refs %ld)", *i.ref->get, *i.ref->use_count);
+ puts("");
+ }
+}
diff --git a/misc/examples/new_vec.c b/misc/examples/new_vec.c
new file mode 100644
index 00000000..84e4c7b2
--- /dev/null
+++ b/misc/examples/new_vec.c
@@ -0,0 +1,58 @@
+#include <stc/cstr.h>
+#include <stc/forward.h>
+
+forward_cvec(cvec_i32, int);
+forward_cvec(cvec_pnt, struct Point);
+
+struct MyStruct {
+ cvec_i32 intvec;
+ cvec_pnt pntvec;
+} typedef MyStruct;
+
+#define i_val int
+#define i_opt c_is_forward
+#define i_tag i32
+#include <stc/cvec.h>
+
+struct Point { int x, y; } typedef Point;
+int point_cmp(const Point* a, const Point* b) {
+ int c = c_default_cmp(&a->x, &b->x);
+ return c ? c : c_default_cmp(&a->y, &b->y);
+}
+
+#define i_val Point
+//#define i_cmp point_cmp
+#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y)
+#define i_opt c_is_forward
+#define i_tag pnt
+#include <stc/cvec.h>
+
+#define i_val float
+#include <stc/cvec.h>
+
+#define i_val_str
+#include <stc/cvec.h>
+
+
+int main()
+{
+ c_auto (cvec_i32, vec)
+ c_auto (cvec_float, fvec)
+ c_auto (cvec_pnt, pvec)
+ c_auto (cvec_str, svec)
+ {
+ cvec_i32_push(&vec, 123);
+ cvec_float_push(&fvec, 123.3f);
+
+ cvec_pnt_push(&pvec, (Point){42, 14});
+ cvec_pnt_push(&pvec, (Point){32, 94});
+ cvec_pnt_push(&pvec, (Point){62, 81});
+ cvec_pnt_push(&pvec, (Point){32, 91});
+ cvec_pnt_sort(&pvec);
+ c_foreach (i, cvec_pnt, pvec)
+ printf(" (%d %d)", i.ref->x, i.ref->y);
+ puts("");
+
+ cvec_str_emplace(&svec, "Hello, friend");
+ }
+}
diff --git a/misc/examples/person_arc.c b/misc/examples/person_arc.c
new file mode 100644
index 00000000..a7bf2a6f
--- /dev/null
+++ b/misc/examples/person_arc.c
@@ -0,0 +1,74 @@
+/* cbox: heap allocated boxed type */
+#include <stc/cstr.h>
+
+typedef struct { cstr name, last; } Person;
+
+Person Person_make(const char* name, const char* last) {
+ return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+}
+
+int Person_cmp(const Person* a, const Person* b) {
+ int c = cstr_cmp(&a->name, &b->name);
+ return c ? c : cstr_cmp(&a->last, &b->last);
+}
+
+uint64_t Person_hash(const Person* a) {
+ return cstr_hash(&a->name) ^ cstr_hash(&a->last);
+}
+
+Person Person_clone(Person p) {
+ p.name = cstr_clone(p.name);
+ p.last = cstr_clone(p.last);
+ return p;
+}
+
+void Person_drop(Person* p) {
+ printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
+ c_drop(cstr, &p->name, &p->last);
+}
+
+#define i_type PSPtr
+#define i_valclass Person // ensure Person_drop
+#define i_cmp Person_cmp // specify object cmp, instead of ptr cmp for arc.
+#include <stc/carc.h>
+
+#define i_type Persons
+#define i_valboxed PSPtr // binds PSPtr_cmp, PSPtr_drop...
+#include <stc/cvec.h>
+
+
+int main()
+{
+ c_auto (Persons, vec)
+ c_auto (PSPtr, p, q)
+ {
+ p = PSPtr_from(Person_make("Laura", "Palmer"));
+
+ // We want a deep copy -- PSPtr_clone(p) only shares!
+ q = PSPtr_from(Person_clone(*p.get));
+ cstr_assign(&q.get->name, "Leland");
+
+ printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last));
+ printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last));
+
+ // Use Persons_emplace to implicitly call PSPtr_make on the argument.
+ // No need to do: Persons_push(&vec, PSPtr_make(Person_make("Audrey", "Home")));
+ Persons_emplace(&vec, Person_make("Audrey", "Home"));
+ Persons_emplace(&vec, Person_make("Dale", "Cooper"));
+
+ // Clone/share p and q to the vector
+ c_forlist (i, PSPtr, {p, q})
+ Persons_push(&vec, PSPtr_clone(*i.ref));
+
+ c_foreach (i, Persons, vec)
+ printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last));
+ puts("");
+
+ // Look-up Audrey!
+ c_with (Person a = Person_make("Audrey", "Home"), Person_drop(&a)) {
+ const PSPtr *v = Persons_get(&vec, a);
+ if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last));
+ }
+ puts("");
+ }
+}
diff --git a/misc/examples/phonebook.c b/misc/examples/phonebook.c
new file mode 100644
index 00000000..be068409
--- /dev/null
+++ b/misc/examples/phonebook.c
@@ -0,0 +1,82 @@
+// The MIT License (MIT)
+// Copyright (c) 2018 Maksim Andrianov
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+// Program to emulates the phone book.
+
+#include <stc/cstr.h>
+
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
+
+#define i_key_str
+#include <stc/cset.h>
+
+void print_phone_book(cmap_str phone_book)
+{
+ c_foreach (i, cmap_str, phone_book)
+ printf("%s\t- %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
+}
+
+int main(int argc, char **argv)
+{
+ c_auto (cset_str, names) {
+ c_forlist (i, const char*, {"Hello", "Cool", "True"})
+ cset_str_emplace(&names, *i.ref);
+
+ c_foreach (i, cset_str, names)
+ printf("%s ", cstr_str(i.ref));
+ puts("");
+ }
+
+ c_auto (cmap_str, phone_book) {
+ c_forlist (i, cmap_str_raw, {
+ {"Lilia Friedman", "(892) 670-4739"},
+ {"Tariq Beltran", "(489) 600-7575"},
+ {"Laiba Juarez", "(303) 885-5692"},
+ {"Elliott Mooney", "(945) 616-4482"},
+ }) cmap_str_emplace(&phone_book, c_PAIR(i.ref));
+
+ printf("Phone book:\n");
+ print_phone_book(phone_book);
+
+ cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1880");
+ cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1990");
+
+ printf("\nPhone book after adding Zak Byers:\n");
+ print_phone_book(phone_book);
+
+ if (cmap_str_contains(&phone_book, "Tariq Beltran"))
+ printf("\nTariq Beltran is in phone book\n");
+
+ cmap_str_erase(&phone_book, "Tariq Beltran");
+ cmap_str_erase(&phone_book, "Elliott Mooney");
+
+ printf("\nPhone book after erasing Tariq and Elliott:\n");
+ print_phone_book(phone_book);
+
+ cmap_str_emplace_or_assign(&phone_book, "Zak Byers", "(555) 396-188");
+
+ printf("\nPhone book after update phone of Zak Byers:\n");
+ print_phone_book(phone_book);
+ }
+ puts("done");
+}
diff --git a/misc/examples/prime.c b/misc/examples/prime.c
new file mode 100644
index 00000000..287fb69b
--- /dev/null
+++ b/misc/examples/prime.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <math.h>
+#include <time.h>
+#include <stc/cbits.h>
+#include <stc/views.h>
+
+cbits sieveOfEratosthenes(size_t n)
+{
+ cbits bits = cbits_with_size(n/2 + 1, true);
+ size_t q = (size_t) sqrt((double) n) + 1;
+ for (size_t i = 3; i < q; i += 2) {
+ size_t j = i;
+ for (; j < n; j += 2) {
+ if (cbits_test(&bits, j>>1)) {
+ i = j;
+ break;
+ }
+ }
+ for (size_t j = i*i; j < n; j += i*2)
+ cbits_reset(&bits, j>>1);
+ }
+ return bits;
+}
+
+int main(void)
+{
+ size_t n = 1000000000;
+ printf("computing prime numbers up to %" c_ZU "\n", n);
+
+ clock_t t1 = clock();
+ c_with (cbits primes = sieveOfEratosthenes(n + 1), cbits_drop(&primes)) {
+ puts("done");
+ size_t np = cbits_count(&primes);
+ clock_t t2 = clock();
+
+ printf("number of primes: %" c_ZU ", time: %f\n", np, (t2 - t1) / (float)CLOCKS_PER_SEC);
+ puts("Show all the primes in the range [2, 1000):");
+ printf("2");
+ c_forrange (i, 3, 1000, 2)
+ if (cbits_test(&primes, i>>1)) printf(" %lld", i);
+ puts("");
+
+ puts("Show the last 50 primes using a temporary crange generator:");
+ c_forfilter (i, crange, crange_literal(n - 1, 0, -2)
+ , cbits_test(&primes, *i.ref>>1)
+ , c_flt_take(i, 50)) {
+ printf("%lld ", *i.ref);
+ if (i.count % 10 == 0) puts("");
+ }
+ }
+}
diff --git a/misc/examples/priority.c b/misc/examples/priority.c
new file mode 100644
index 00000000..f6e63205
--- /dev/null
+++ b/misc/examples/priority.c
@@ -0,0 +1,35 @@
+
+#include <stdio.h>
+#include <time.h>
+#include <stc/crandom.h>
+
+#define i_val int64_t
+#define i_cmp -c_default_cmp // min-heap (increasing values)
+#define i_tag i
+#include <stc/cpque.h>
+
+int main() {
+ size_t N = 10000000;
+ stc64_t rng = stc64_new(time(NULL));
+ stc64_uniform_t dist = stc64_uniform_new(0, N * 10);
+ c_auto (cpque_i, heap)
+ {
+ // Push ten million random numbers to priority queue
+ printf("Push %" c_ZU " numbers\n", N);
+ c_forrange (N)
+ cpque_i_push(&heap, stc64_uniform(&rng, &dist));
+
+ // push some negative numbers too.
+ c_forlist (i, int, {-231, -32, -873, -4, -343})
+ cpque_i_push(&heap, *i.ref);
+
+ c_forrange (N)
+ cpque_i_push(&heap, stc64_uniform(&rng, &dist));
+
+ puts("Extract the hundred smallest.");
+ c_forrange (100) {
+ printf("%" PRId64 " ", *cpque_i_top(&heap));
+ cpque_i_pop(&heap);
+ }
+ }
+}
diff --git a/misc/examples/queue.c b/misc/examples/queue.c
new file mode 100644
index 00000000..f39c4b8b
--- /dev/null
+++ b/misc/examples/queue.c
@@ -0,0 +1,31 @@
+#include <stc/crandom.h>
+#include <stdio.h>
+
+#define i_val int
+#define i_tag i
+#include <stc/cqueue.h>
+
+int main() {
+ int n = 100000000;
+ stc64_uniform_t dist;
+ stc64_t rng = stc64_new(1234);
+ dist = stc64_uniform_new(0, n);
+
+ c_auto (cqueue_i, queue)
+ {
+ // Push ten million random numbers onto the queue.
+ c_forrange (n)
+ cqueue_i_push(&queue, stc64_uniform(&rng, &dist));
+
+ // Push or pop on the queue ten million times
+ printf("%d\n", n);
+ c_forrange (n) { // forrange uses initial n only.
+ int r = stc64_uniform(&rng, &dist);
+ if (r & 1)
+ ++n, cqueue_i_push(&queue, r);
+ else
+ --n, cqueue_i_pop(&queue);
+ }
+ printf("%d, %" c_ZU "\n", n, cqueue_i_size(&queue));
+ }
+}
diff --git a/misc/examples/random.c b/misc/examples/random.c
new file mode 100644
index 00000000..fe64290d
--- /dev/null
+++ b/misc/examples/random.c
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <time.h>
+#include <stc/crandom.h>
+
+int main()
+{
+ const size_t N = 1000000000;
+ const uint64_t seed = time(NULL), range = 1000000;
+ stc64_t rng = stc64_new(seed);
+
+ uint64_t sum;
+ clock_t diff, before;
+
+ printf("Compare speed of full and unbiased ranged random numbers...\n");
+ sum = 0;
+ before = clock();
+ c_forrange (N) {
+ sum += (uint32_t)stc64_rand(&rng);
+ }
+ diff = clock() - before;
+ printf("full range\t\t: %f secs, %" c_ZU ", avg: %f\n",
+ (float)diff / CLOCKS_PER_SEC, N, (double)sum / N);
+
+ stc64_uniform_t dist1 = stc64_uniform_new(0, range);
+ rng = stc64_new(seed);
+ sum = 0;
+ before = clock();
+ c_forrange (N) {
+ sum += stc64_uniform(&rng, &dist1); // unbiased
+ }
+ diff = clock() - before;
+ printf("unbiased 0-%" PRIu64 "\t: %f secs, %" c_ZU ", avg: %f\n",
+ range, (float)diff/CLOCKS_PER_SEC, N, (double)sum / N);
+
+ sum = 0;
+ rng = stc64_new(seed);
+ before = clock();
+ c_forrange (N) {
+ sum += stc64_rand(&rng) % (range + 1); // biased
+ }
+ diff = clock() - before;
+ printf("biased 0-%" PRIu64 " \t: %f secs, %" c_ZU ", avg: %f\n",
+ range, (float)diff / CLOCKS_PER_SEC, N, (double)sum / N);
+
+}
diff --git a/misc/examples/rawptr_elements.c b/misc/examples/rawptr_elements.c
new file mode 100644
index 00000000..4b3d2056
--- /dev/null
+++ b/misc/examples/rawptr_elements.c
@@ -0,0 +1,55 @@
+#include <stc/ccommon.h>
+#include <stdio.h>
+
+#include <stc/cstr.h>
+// Map of cstr => int64 pointers
+typedef int64_t inttype;
+
+// Do it without cbox:
+#define i_type SIPtrMap
+#define i_key_str
+#define i_val inttype*
+#define i_valraw inttype
+#define i_valfrom(raw) c_new(inttype, raw)
+#define i_valto(x) **x
+#define i_valclone(x) c_new(inttype, *x)
+#define i_valdrop(x) c_free(*x)
+#include <stc/cmap.h>
+
+// With cbox:
+#define i_type IBox
+#define i_val int
+#include <stc/cbox.h> //<stc/carc.h>
+
+#define i_type SIBoxMap
+#define i_key_str
+#define i_valboxed IBox
+#include <stc/cmap.h>
+
+int main()
+{
+ c_auto (SIPtrMap, map, m1)
+ c_auto (SIBoxMap, m2)
+ {
+ printf("\nMap with pointer elements:\n");
+ SIPtrMap_insert(&map, cstr_from("testing"), c_new(inttype, 1));
+ SIPtrMap_insert(&map, cstr_from("done"), c_new(inttype, 2));
+
+ // Emplace: implicit key, val construction:
+ SIPtrMap_emplace(&map, "hello", 3);
+ SIPtrMap_emplace(&map, "goodbye", 4);
+
+ m1 = SIPtrMap_clone(map);
+
+ c_forpair (name, number, SIPtrMap, m1)
+ printf("%s: %" PRId64 "\n", cstr_str(_.name), **_.number);
+
+
+ puts("\nIBox map:");
+ SIBoxMap_insert(&m2, cstr_from("Hello"), IBox_make(123));
+ SIBoxMap_emplace(&m2, "World", 999);
+ c_forpair (name, number, SIBoxMap, m2)
+ printf("%s: %d\n", cstr_str(_.name), *_.number->get);
+ puts("");
+ }
+}
diff --git a/misc/examples/read.c b/misc/examples/read.c
new file mode 100644
index 00000000..4efdcfeb
--- /dev/null
+++ b/misc/examples/read.c
@@ -0,0 +1,25 @@
+#include <stc/cstr.h>
+#define i_val_str
+#include <stc/cvec.h>
+#include <errno.h>
+
+cvec_str read_file(const char* name)
+{
+ cvec_str vec = cvec_str_init();
+ c_with (FILE* f = fopen(name, "r"), fclose(f))
+ c_with (cstr line = cstr_NULL, cstr_drop(&line))
+ while (cstr_getline(&line, f))
+ cvec_str_push(&vec, cstr_clone(line));
+ return vec;
+}
+
+int main()
+{
+ int n = 0;
+ c_with (cvec_str vec = read_file(__FILE__), cvec_str_drop(&vec))
+ c_foreach (i, cvec_str, vec)
+ printf("%5d: %s\n", ++n, cstr_str(i.ref));
+
+ if (errno)
+ printf("error: read_file(" __FILE__ "). errno: %d\n", errno);
+}
diff --git a/misc/examples/regex1.c b/misc/examples/regex1.c
new file mode 100644
index 00000000..7a22220d
--- /dev/null
+++ b/misc/examples/regex1.c
@@ -0,0 +1,30 @@
+#define i_extern
+#include <stc/cregex.h>
+
+int main(int argc, char* argv[])
+{
+ if (argc <= 1) {
+ printf("Usage: regex1 -i\n");
+ return 0;
+ }
+ c_auto (cstr, input)
+ c_auto (cregex, float_expr)
+ {
+ int res = cregex_compile(&float_expr, "^[+-]?[0-9]+((\\.[0-9]*)?|\\.[0-9]+)$", CREG_DEFAULT);
+ // Until "q" is given, ask for another number
+ if (res > 0) while (true)
+ {
+ printf("Enter a double precision number (q for quit): ");
+ cstr_getline(&input, stdin);
+
+ // Exit when the user inputs q
+ if (cstr_equals(&input, "q"))
+ break;
+
+ if (cregex_is_match(&float_expr, cstr_str(&input)))
+ printf("Input is a float\n");
+ else
+ printf("Invalid input : Not a float\n");
+ }
+ }
+}
diff --git a/misc/examples/regex2.c b/misc/examples/regex2.c
new file mode 100644
index 00000000..dbf6aae4
--- /dev/null
+++ b/misc/examples/regex2.c
@@ -0,0 +1,32 @@
+#define i_extern
+#include <stc/cregex.h>
+
+int main()
+{
+ struct { const char *pattern, *input; } s[] = {
+ {"(\\d\\d\\d\\d)[-_](1[0-2]|0[1-9])[-_](3[01]|[12][0-9]|0[1-9])",
+ "date: 2024-02-29 leapyear day, christmas eve is on 2022-12-24."
+ },
+ {"(https?://|ftp://|www\\.)([0-9A-Za-z@:%_+~#=-]+\\.)+([a-z][a-z][a-z]?)(/[/0-9A-Za-z\\.@:%_+~#=\\?&-]*)?",
+ "https://en.cppreference.com/w/cpp/regex/regex_search"
+ },
+ {"!((abc|123)+)!", "!123abcabc!"}
+ };
+
+ c_auto (cregex, re)
+ c_forrange (i, c_arraylen(s))
+ {
+ int res = cregex_compile(&re, s[i].pattern, CREG_DEFAULT);
+ if (res < 0) {
+ printf("error in regex pattern: %d\n", res);
+ continue;
+ }
+ printf("input: %s\n", s[i].input);
+
+ c_formatch (j, &re, s[i].input) {
+ c_forrange (k, cregex_captures(&re))
+ printf(" submatch %lld: %.*s\n", k, c_ARGSV(j.match[k]));
+ puts("");
+ }
+ }
+}
diff --git a/misc/examples/regex_match.c b/misc/examples/regex_match.c
new file mode 100644
index 00000000..376b002e
--- /dev/null
+++ b/misc/examples/regex_match.c
@@ -0,0 +1,34 @@
+#define i_extern
+#include <stc/cregex.h>
+#include <stc/csview.h>
+#define i_val float
+#include <stc/cstack.h>
+
+int main()
+{
+ // Lets find the first sequence of digits in a string
+ const char *str = "Hello numeric world, there are 24 hours in a day, 3600 seconds in an hour."
+ " Around 365.25 days a year, and 52 weeks in a year."
+ " Boltzmann const: 1.38064852E-23, is very small."
+ " Bohrradius is 5.29177210903e-11, and Avogadros number is 6.02214076e23.";
+
+ c_auto (cregex, re)
+ c_auto (cstack_float, vec)
+ c_auto (cstr, nums)
+ {
+ const char* pattern = "[+-]?([0-9]*\\.)?\\d+([Ee][+-]?\\d+)?";
+ int res = cregex_compile(&re, pattern, CREG_DEFAULT);
+ printf("%d: %s\n", res, pattern);
+
+ // extract and convert all numbers in str to floats
+ c_formatch (i, &re, str)
+ cstack_float_push(&vec, atof(i.match[0].str));
+
+ c_foreach (i, cstack_float, vec)
+ printf(" %g\n", *i.ref);
+
+ // extracts the numbers only to a comma separated string.
+ nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_R_STRIP);
+ printf("\n%s\n", cstr_str(&nums));
+ }
+}
diff --git a/misc/examples/regex_replace.c b/misc/examples/regex_replace.c
new file mode 100644
index 00000000..e296dfd8
--- /dev/null
+++ b/misc/examples/regex_replace.c
@@ -0,0 +1,53 @@
+#define i_extern
+#include <stc/cregex.h>
+#include <stc/csview.h>
+
+bool add_10_years(int i, csview match, cstr* out) {
+ if (i == 1) { // group 1 matches year
+ int year;
+ sscanf(match.str, "%4d", &year); // scan 4 chars only
+ cstr_printf(out, "%04d", year + 10);
+ return true;
+ }
+ return false;
+}
+
+int main()
+{
+ const char* pattern = "\\b(\\d\\d\\d\\d)-(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])\\b";
+ const char* input = "start date: 2015-12-31, end date: 2022-02-28";
+
+ c_auto (cstr, str)
+ {
+ printf("INPUT: %s\n", input);
+
+ /* replace with a fixed string, extended all-in-one call: */
+ cstr_take(&str, cregex_replace_pattern(pattern, input, "YYYY-MM-DD"));
+ printf("fixed: %s\n", cstr_str(&str));
+
+ /* US date format, and add 10 years to dates: */
+ cstr_take(&str, cregex_replace_pattern_n(pattern, input, "$1/$3/$2", 0, add_10_years, CREG_DEFAULT));
+ printf("us+10: %s\n", cstr_str(&str));
+
+ /* Wrap first date inside []: */
+ cstr_take(&str, cregex_replace_pattern_n(pattern, input, "[$0]", 1, NULL, CREG_DEFAULT));
+ printf("brack: %s\n", cstr_str(&str));
+
+ /* Shows how to compile RE separately */
+ c_with (cregex re = cregex_from(pattern, CREG_DEFAULT), cregex_drop(&re)) {
+ if (cregex_captures(&re) == 0)
+ continue; /* break c_with */
+ /* European date format. */
+ cstr_take(&str, cregex_replace(&re, input, "$3.$2.$1"));
+ printf("euros: %s\n", cstr_str(&str));
+
+ /* Strip out everything but the matches */
+ cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_R_STRIP));
+ printf("strip: %s\n", cstr_str(&str));
+ }
+
+ /* Wrap all words in ${} */
+ cstr_take(&str, cregex_replace_pattern("[a-z]+", "52 apples and 31 mangoes", "$${$0}"));
+ printf("curly: %s\n", cstr_str(&str));
+ }
+}
diff --git a/misc/examples/replace.c b/misc/examples/replace.c
new file mode 100644
index 00000000..15cf3bae
--- /dev/null
+++ b/misc/examples/replace.c
@@ -0,0 +1,34 @@
+#include <stc/cstr.h>
+
+int main ()
+{
+ const char *base = "this is a test string.";
+ const char *s2 = "n example";
+ const char *s3 = "sample phrase";
+
+ // replace signatures used in the same order as described above:
+
+ // Ustring positions: 0123456789*123456789*12345
+ cstr s = cstr_from(base); // "this is a test string."
+ cstr m = cstr_clone(s);
+ c_defer (cstr_drop(&s), cstr_drop(&m)) {
+ cstr_append(&m, cstr_str(&m));
+ cstr_append(&m, cstr_str(&m));
+ printf("%s\n", cstr_str(&m));
+
+ cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1)
+ printf("(1) %s\n", cstr_str(&s));
+
+ cstr_replace_at_sv(&s, 19, 6, c_SV(s3+7, 6)); // "this is an example phrase." (2)
+ printf("(2) %s\n", cstr_str(&s));
+
+ cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3)
+ printf("(3) %s\n", cstr_str(&s));
+
+ cstr_replace_at_sv(&s, 8, 6, c_SV("a shorty", 7)); // "this is a short phrase." (4)
+ printf("(4) %s\n", cstr_str(&s));
+
+ cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5)
+ printf("(5) %s\n", cstr_str(&s));
+ }
+}
diff --git a/misc/examples/shape.c b/misc/examples/shape.c
new file mode 100644
index 00000000..a17208ef
--- /dev/null
+++ b/misc/examples/shape.c
@@ -0,0 +1,159 @@
+// Demo of typesafe polymorphism in C99, using STC.
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stc/ccommon.h>
+
+#define c_dyn_cast(T, s) \
+ (&T##_api == (s)->api ? (T*)(s) : (T*)0)
+
+// Shape definition
+// ============================================================
+
+typedef struct {
+ float x, y;
+} Point;
+
+typedef struct Shape Shape;
+
+struct ShapeAPI {
+ void (*drop)(Shape*);
+ void (*draw)(const Shape*);
+};
+
+struct Shape {
+ struct ShapeAPI* api;
+ uint32_t color;
+ uint16_t style;
+ uint8_t thickness;
+ uint8_t hardness;
+};
+
+void Shape_drop(Shape* shape)
+{
+ printf("shape destructed\n");
+}
+
+void Shape_delete(Shape* shape)
+{
+ if (shape) {
+ shape->api->drop(shape);
+ c_free(shape);
+ }
+}
+
+// Triangle implementation
+// ============================================================
+
+typedef struct {
+ Shape shape;
+ Point p[3];
+} Triangle;
+
+static struct ShapeAPI Triangle_api;
+
+
+Triangle Triangle_from(Point a, Point b, Point c)
+{
+ Triangle t = {{.api=&Triangle_api}, .p={a, b, c}};
+ return t;
+}
+
+static void Triangle_draw(const Shape* shape)
+{
+ const Triangle* self = c_dyn_cast(Triangle, shape);
+ printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n",
+ self->p[0].x, self->p[0].y,
+ self->p[1].x, self->p[1].y,
+ self->p[2].x, self->p[2].y);
+}
+
+static struct ShapeAPI Triangle_api = {
+ .drop = Shape_drop,
+ .draw = Triangle_draw,
+};
+
+// Polygon implementation
+// ============================================================
+
+#define i_type PointVec
+#define i_val Point
+#include <stc/cstack.h>
+
+typedef struct {
+ Shape shape;
+ PointVec points;
+} Polygon;
+
+static struct ShapeAPI Polygon_api;
+
+
+Polygon Polygon_init(void)
+{
+ Polygon p = {{.api=&Polygon_api}, .points=PointVec_init()};
+ return p;
+}
+
+void Polygon_addPoint(Polygon* self, Point p)
+{
+ PointVec_push(&self->points, p);
+}
+
+static void Polygon_drop(Shape* shape)
+{
+ Polygon* self = c_dyn_cast(Polygon, shape);
+ printf("poly destructed\n");
+ PointVec_drop(&self->points);
+ Shape_drop(shape);
+}
+
+static void Polygon_draw(const Shape* shape)
+{
+ const Polygon* self = c_dyn_cast(Polygon, shape);
+ printf("Polygon :");
+ c_foreach (i, PointVec, self->points)
+ printf(" (%g,%g)", i.ref->x, i.ref->y);
+ puts("");
+}
+
+static struct ShapeAPI Polygon_api = {
+ .drop = Polygon_drop,
+ .draw = Polygon_draw,
+};
+
+// Test
+// ============================================================
+
+#define i_type Shapes
+#define i_val Shape*
+#define i_valdrop(x) Shape_delete(*x)
+#include <stc/cstack.h>
+
+void testShape(const Shape* shape)
+{
+ shape->api->draw(shape);
+}
+
+
+int main(void)
+{
+ c_auto (Shapes, shapes)
+ {
+ Triangle* tri1 = c_new(Triangle, Triangle_from((Point){5, 7}, (Point){12, 7}, (Point){12, 20}));
+ Polygon* pol1 = c_new(Polygon, Polygon_init());
+ Polygon* pol2 = c_new(Polygon, Polygon_init());
+
+ c_forlist (i, Point, {{50, 72}, {123, 73}, {127, 201}, {828, 333}})
+ Polygon_addPoint(pol1, *i.ref);
+
+ c_forlist (i, Point, {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}})
+ Polygon_addPoint(pol2, *i.ref);
+
+ Shapes_push(&shapes, &tri1->shape);
+ Shapes_push(&shapes, &pol1->shape);
+ Shapes_push(&shapes, &pol2->shape);
+
+ c_foreach (i, Shapes, shapes)
+ testShape(*i.ref);
+ }
+}
diff --git a/misc/examples/shape.cpp b/misc/examples/shape.cpp
new file mode 100644
index 00000000..ea1f53d2
--- /dev/null
+++ b/misc/examples/shape.cpp
@@ -0,0 +1,122 @@
+// Demo of polymorphism in C++
+
+#include <iostream>
+#include <memory>
+#include <vector>
+
+// Shape definition
+// ============================================================
+
+struct Point {
+ float x, y;
+};
+
+std::ostream& operator<<(std::ostream& os, const Point& p) {
+ os << " (" << p.x << "," << p.y << ")";
+ return os;
+}
+
+struct Shape {
+ virtual ~Shape();
+ virtual void draw() const = 0;
+
+ uint32_t color;
+ uint16_t style;
+ uint8_t thickness;
+ uint8_t hardness;
+};
+
+Shape::~Shape()
+{
+ std::cout << "base destructed" << std::endl;
+}
+
+// Triangle implementation
+// ============================================================
+
+struct Triangle : public Shape
+{
+ Triangle(Point a, Point b, Point c);
+ void draw() const override;
+
+ private: Point p[3];
+};
+
+
+Triangle::Triangle(Point a, Point b, Point c)
+ : p{a, b, c} {}
+
+void Triangle::draw() const
+{
+ std::cout << "Triangle :"
+ << p[0] << p[1] << p[2]
+ << std::endl;
+}
+
+
+// Polygon implementation
+// ============================================================
+
+
+struct Polygon : public Shape
+{
+ ~Polygon();
+ void draw() const override;
+ void addPoint(const Point& p);
+
+ private: std::vector<Point> points;
+};
+
+
+void Polygon::addPoint(const Point& p)
+{
+ points.push_back(p);
+}
+
+Polygon::~Polygon()
+{
+ std::cout << "poly destructed" << std::endl;
+}
+
+void Polygon::draw() const
+{
+ std::cout << "Polygon :";
+ for (auto& p : points)
+ std::cout << p ;
+ std::cout << std::endl;
+}
+
+
+// Test
+// ============================================================
+
+void testShape(const Shape* shape)
+{
+ shape->draw();
+}
+
+#include <array>
+
+int main(void)
+{
+ std::vector<std::unique_ptr<Shape>> shapes;
+
+ auto tri1 = std::make_unique<Triangle>(Point{5, 7}, Point{12, 7}, Point{12, 20});
+ auto pol1 = std::make_unique<Polygon>();
+ auto pol2 = std::make_unique<Polygon>();
+
+ for (auto& p: std::array<Point, 4>
+ {{{50, 72}, {123, 73}, {127, 201}, {828, 333}}})
+ pol1->addPoint(p);
+
+ for (auto& p: std::array<Point, 5>
+ {{{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}})
+ pol2->addPoint(p);
+
+ shapes.push_back(std::move(tri1));
+ shapes.push_back(std::move(pol1));
+ shapes.push_back(std::move(pol2));
+
+ for (auto& shape: shapes)
+ testShape(shape.get());
+}
diff --git a/misc/examples/sidebyside.cpp b/misc/examples/sidebyside.cpp
new file mode 100644
index 00000000..80c934a4
--- /dev/null
+++ b/misc/examples/sidebyside.cpp
@@ -0,0 +1,57 @@
+#include <iostream>
+#include <map>
+#include <string>
+#include <stc/cstr.h>
+
+#define i_type IIMap
+#define i_key int
+#define i_val int
+#include <stc/csmap.h>
+
+#define i_type SIMap
+#define i_key_str
+#define i_val int
+#include <stc/cmap.h>
+
+int main() {
+ {
+ std::map<int, int> hist;
+ hist.emplace(12, 100).first->second += 1;
+ hist.emplace(13, 100).first->second += 1;
+ hist.emplace(12, 100).first->second += 1;
+
+ for (auto i: hist)
+ std::cout << i.first << ", " << i.second << std::endl;
+ std::cout << std::endl;
+ }
+
+ c_auto (IIMap, hist)
+ {
+ IIMap_insert(&hist, 12, 100).ref->second += 1;
+ IIMap_insert(&hist, 13, 100).ref->second += 1;
+ IIMap_insert(&hist, 12, 100).ref->second += 1;
+
+ c_foreach (i, IIMap, hist)
+ printf("%d, %d\n", i.ref->first, i.ref->second);
+ puts("");
+ }
+ // ===================================================
+ {
+ std::map<std::string, int> food =
+ {{"burger", 5}, {"pizza", 12}, {"steak", 15}};
+
+ for (auto i: food)
+ std::cout << i.first << ", " << i.second << std::endl;
+ std::cout << std::endl;
+ }
+
+ c_auto (SIMap, food)
+ {
+ c_forlist (i, SIMap_raw, {{"burger", 5}, {"pizza", 12}, {"steak", 15}})
+ SIMap_emplace(&food, c_PAIR(i.ref));
+
+ c_foreach (i, SIMap, food)
+ printf("%s, %d\n", cstr_str(&i.ref->first), i.ref->second);
+ puts("");
+ }
+}
diff --git a/misc/examples/sorted_map.c b/misc/examples/sorted_map.c
new file mode 100644
index 00000000..c4a05c76
--- /dev/null
+++ b/misc/examples/sorted_map.c
@@ -0,0 +1,64 @@
+// https://iq.opengenus.org/containers-cpp-stl/
+
+#define i_key int
+#define i_val int
+#include <stc/csmap.h>
+#include <stdio.h>
+
+int main()
+{
+
+ // empty map containers
+ c_auto (csmap_int, gquiz1, gquiz2)
+ {
+ // insert elements in random order
+ csmap_int_insert(&gquiz1, 2, 30);
+ csmap_int_insert(&gquiz1, 4, 20);
+ csmap_int_insert(&gquiz1, 7, 10);
+ csmap_int_insert(&gquiz1, 5, 50);
+ csmap_int_insert(&gquiz1, 3, 60);
+ csmap_int_insert(&gquiz1, 1, 40);
+ csmap_int_insert(&gquiz1, 6, 50);
+
+ // printing map gquiz1
+ printf("\nThe map gquiz1 is :\n\tKEY\tELEMENT\n");
+ c_foreach (itr, csmap_int, gquiz1)
+ printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
+ printf("\n");
+
+ // assigning the elements from gquiz1 to gquiz2
+ c_foreach (i, csmap_int, gquiz1)
+ csmap_int_insert(&gquiz2, i.ref->first, i.ref->second);
+
+ // print all elements of the map gquiz2
+ printf("\nThe map gquiz2 is :\n\tKEY\tELEMENT\n");
+ c_foreach (itr, csmap_int, gquiz2)
+ printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
+ printf("\n");
+
+ // remove all elements up to element with key=3 in gquiz2
+ printf("\ngquiz2 after removal of elements less than key=3 :\n");
+ printf("\tKEY\tELEMENT\n");
+ csmap_int_erase_range(&gquiz2, csmap_int_begin(&gquiz2),
+ csmap_int_find(&gquiz2, 3));
+ c_foreach (itr, csmap_int, gquiz2)
+ printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
+ printf("\n");
+
+ // remove all elements with key = 4
+ int num = csmap_int_erase(&gquiz2, 4);
+ printf("\ngquiz2.erase(4) : %d removed\n", num);
+ printf("\tKEY\tELEMENT\n");
+ c_foreach (itr, csmap_int, gquiz2)
+ printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
+ printf("\n");
+
+ // lower bound and upper bound for map gquiz1 key = 5
+ printf("gquiz1.lower_bound(5) : ");
+ printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5).ref->first);
+ printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5).ref->second);
+ printf("gquiz1.upper_bound(5) : ");
+ printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5+1).ref->first);
+ printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5+1).ref->second);
+ }
+}
diff --git a/misc/examples/splitstr.c b/misc/examples/splitstr.c
new file mode 100644
index 00000000..a3c12a3a
--- /dev/null
+++ b/misc/examples/splitstr.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#define i_extern // cstr + utf8 functions
+#include <stc/cregex.h>
+#include <stc/csview.h>
+
+int main()
+{
+ puts("Split with c_fortoken (csview):");
+
+ c_fortoken (i, "Hello World C99!", " ")
+ printf("'%.*s'\n", c_ARGSV(i.token));
+
+
+ puts("\nSplit with c_formatch (regex):");
+
+ c_with (cregex re = cregex_from("[^ ]+", CREG_DEFAULT), cregex_drop(&re))
+ c_formatch (i, &re, " Hello World C99! ")
+ printf("'%.*s'\n", c_ARGSV(i.match[0]));
+}
diff --git a/misc/examples/sso_map.c b/misc/examples/sso_map.c
new file mode 100644
index 00000000..cc5e16a1
--- /dev/null
+++ b/misc/examples/sso_map.c
@@ -0,0 +1,17 @@
+#include <stc/cstr.h>
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
+
+int main()
+{
+ c_auto (cmap_str, m) {
+ cmap_str_emplace(&m, "Test short", "This is a short string.");
+ cmap_str_emplace(&m, "Test long ", "This is a longer string.");
+
+ c_forpair (k, v, cmap_str, m)
+ printf("%s: '%s' Len=%" c_ZU ", Is long: %s\n",
+ cstr_str(_.k), cstr_str(_.v), cstr_size(_.v),
+ cstr_is_long(_.v)?"true":"false");
+ }
+}
diff --git a/misc/examples/sso_substr.c b/misc/examples/sso_substr.c
new file mode 100644
index 00000000..be372a8d
--- /dev/null
+++ b/misc/examples/sso_substr.c
@@ -0,0 +1,20 @@
+#define STC_IMPLEMENT
+#include <stc/cstr.h>
+#include <stc/csview.h>
+
+int main ()
+{
+ cstr str = cstr_lit("We think in generalities, but we live in details.");
+ csview sv1 = cstr_substr_ex(&str, 3, 5); // "think"
+ size_t pos = cstr_find(&str, "live"); // position of "live"
+ csview sv2 = cstr_substr_ex(&str, pos, 4); // "live"
+ csview sv3 = cstr_slice_ex(&str, -8, -1); // "details"
+ printf("%.*s, %.*s, %.*s\n", c_ARGSV(sv1), c_ARGSV(sv2), c_ARGSV(sv3));
+
+ cstr_assign(&str, "apples are green or red");
+ cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red"
+ cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples"
+ printf("%s %s: %d, %d\n", cstr_str(&s2), cstr_str(&s3),
+ cstr_is_long(&str), cstr_is_long(&s2));
+ c_drop (cstr, &str, &s2, &s3);
+}
diff --git a/misc/examples/stack.c b/misc/examples/stack.c
new file mode 100644
index 00000000..a6a4a492
--- /dev/null
+++ b/misc/examples/stack.c
@@ -0,0 +1,30 @@
+
+#include <stdio.h>
+
+#define i_tag i
+#define i_capacity 100
+#define i_val int
+#include <stc/cstack.h>
+
+#define i_tag c
+#define i_val char
+#include <stc/cstack.h>
+
+int main() {
+ c_auto (cstack_i, stack)
+ c_auto (cstack_c, chars)
+ {
+ c_forrange (i, 101)
+ cstack_i_push(&stack, i*i);
+
+ printf("%d\n", *cstack_i_top(&stack));
+
+ c_forrange (i, 90)
+ cstack_i_pop(&stack);
+
+ c_foreach (i, cstack_i, stack)
+ printf(" %d", *i.ref);
+ puts("");
+ printf("top: %d\n", *cstack_i_top(&stack));
+ }
+}
diff --git a/misc/examples/sview_split.c b/misc/examples/sview_split.c
new file mode 100644
index 00000000..d22fccd1
--- /dev/null
+++ b/misc/examples/sview_split.c
@@ -0,0 +1,20 @@
+#define STC_IMPLEMENT
+#include <stc/cstr.h>
+#include <stc/csview.h>
+
+int main()
+{
+ // No memory allocations or string length calculations!
+ const csview date = c_SV("2021/03/12");
+ size_t pos = 0;
+ const csview year = csview_token(date, "/", &pos);
+ const csview month = csview_token(date, "/", &pos);
+ const csview day = csview_token(date, "/", &pos);
+
+ printf("%.*s, %.*s, %.*s\n", c_ARGSV(year), c_ARGSV(month), c_ARGSV(day));
+
+ c_auto (cstr, y, m, d) {
+ y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day);
+ printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d));
+ }
+}
diff --git a/misc/examples/unordered_set.c b/misc/examples/unordered_set.c
new file mode 100644
index 00000000..a0b639da
--- /dev/null
+++ b/misc/examples/unordered_set.c
@@ -0,0 +1,42 @@
+// https://iq.opengenus.org/containers-cpp-stl/
+// C program to demonstrate various function of stc cset
+#include <stc/cstr.h>
+#define i_key_str
+#include <stc/cset.h>
+
+int main()
+{
+ // declaring set for storing string data-type
+ c_auto (cset_str, stringSet)
+ {
+ // inserting various string, same string will be stored
+ // once in set
+ cset_str_emplace(&stringSet, "code");
+ cset_str_emplace(&stringSet, "in");
+ cset_str_emplace(&stringSet, "C");
+ cset_str_emplace(&stringSet, "is");
+ cset_str_emplace(&stringSet, "fast");
+
+ const char* key = "slow";
+
+ // find returns end iterator if key is not found,
+ // else it returns iterator to that key
+
+ if (cset_str_find(&stringSet, key).ref == cset_str_end(&stringSet).ref)
+ printf("\"%s\" not found\n", key);
+ else
+ printf("Found \"%s\"\n", key);
+
+ key = "C";
+ if (!cset_str_contains(&stringSet, key))
+ printf("\"%s\" not found\n", key);
+ else
+ printf("Found \"%s\"\n", key);
+
+ // now iterating over whole set and printing its
+ // content
+ printf("All elements :\n");
+ c_foreach (itr, cset_str, stringSet)
+ printf("%s\n", cstr_str(itr.ref));
+ }
+}
diff --git a/misc/examples/utf8replace_c.c b/misc/examples/utf8replace_c.c
new file mode 100644
index 00000000..22a5c990
--- /dev/null
+++ b/misc/examples/utf8replace_c.c
@@ -0,0 +1,23 @@
+#define i_extern // add utf8 dependencies
+#include <stc/cstr.h>
+#include <stc/csview.h>
+
+int main() {
+ c_auto (cstr, hello, upper) {
+ hello = cstr_lit("hell😀 w😀rld");
+ printf("%s\n", cstr_str(&hello));
+
+ /* replace second smiley at utf8 codepoint pos 7 */
+ cstr_u8_replace(&hello, cstr_u8_to_pos(&hello, 7), 1, c_SV("🐨"));
+ printf("%s\n", cstr_str(&hello));
+
+ cstr_replace(&hello, "🐨", "ø", 1);
+ printf("%s\n", cstr_str(&hello));
+
+ upper = cstr_toupper_sv(cstr_sv(&hello));
+
+ c_foreach (c, cstr, hello)
+ printf("%.*s,", c_ARGSV(c.u8.chr));
+ puts("");
+ }
+}
diff --git a/misc/examples/utf8replace_rs.rs b/misc/examples/utf8replace_rs.rs
new file mode 100644
index 00000000..717978aa
--- /dev/null
+++ b/misc/examples/utf8replace_rs.rs
@@ -0,0 +1,19 @@
+
+pub fn main() {
+ let mut hello = String::from("hell😀 world");
+ println!("{}", hello);
+
+ hello.replace_range(
+ hello
+ .char_indices()
+ .nth(4)
+ .map(|(pos, ch)| (pos..pos + ch.len_utf8()))
+ .unwrap(),
+ "🐨",
+ );
+ println!("{}", hello);
+
+ for c in hello.chars() {
+ print!("{},", c);
+ }
+}
diff --git a/misc/examples/vikings.c b/misc/examples/vikings.c
new file mode 100644
index 00000000..26a74757
--- /dev/null
+++ b/misc/examples/vikings.c
@@ -0,0 +1,66 @@
+#include <stc/cstr.h>
+
+typedef struct Viking {
+ cstr name;
+ cstr country;
+} Viking;
+
+void Viking_drop(Viking* vk) {
+ cstr_drop(&vk->name);
+ cstr_drop(&vk->country);
+}
+
+// Define Viking lookup struct with hash, cmp, and convertion functions between Viking and RViking structs:
+
+typedef struct RViking {
+ const char* name;
+ const char* country;
+} RViking;
+
+static inline int RViking_cmp(const RViking* rx, const RViking* ry) {
+ int c = strcmp(rx->name, ry->name);
+ return c ? c : strcmp(rx->country, ry->country);
+}
+
+static inline Viking Viking_from(RViking raw) { // note: parameter is by value
+ return c_INIT(Viking){cstr_from(raw.name), cstr_from(raw.country)};
+}
+
+static inline RViking Viking_toraw(const Viking* vp) {
+ return c_INIT(RViking){cstr_str(&vp->name), cstr_str(&vp->country)};
+}
+
+// With this in place, we define the Viking => int hash map type:
+#define i_type Vikings
+#define i_keyclass Viking // key type
+#define i_rawclass RViking // lookup type
+#define i_keyfrom Viking_from
+#define i_opt c_no_clone
+#define i_hash(rp) cstrhash(rp->name) ^ cstrhash(rp->country)
+#define i_val int // mapped type
+#include <stc/cmap.h>
+/*
+ i_keyclass implies these defines, unless they are already defined:
+ i_cmp => RViking_cmp
+ //i_hash => RViking_hash // already defined.
+ //i_keyclone => Viking_clone // not used, because of c_no_clone
+ i_keyto => Viking_toraw // because i_rawclass is defined
+ i_keydrop => Viking_drop
+*/
+
+int main()
+{
+ c_auto (Vikings, vikings) {
+ Vikings_emplace(&vikings, (RViking){"Einar", "Norway"}, 20);
+ Vikings_emplace(&vikings, (RViking){"Olaf", "Denmark"}, 24);
+ Vikings_emplace(&vikings, (RViking){"Harald", "Iceland"}, 12);
+ Vikings_emplace(&vikings, (RViking){"Björn", "Sweden"}, 10);
+
+ Vikings_value* v = Vikings_get_mut(&vikings, (RViking){"Einar", "Norway"});
+ v->second += 3; // add 3 hp points to Einar
+
+ c_forpair (vk, hp, Vikings, vikings) {
+ printf("%s of %s has %d hp\n", cstr_str(&_.vk->name), cstr_str(&_.vk->country), *_.hp);
+ }
+ }
+}
diff --git a/misc/examples/words.c b/misc/examples/words.c
new file mode 100644
index 00000000..097447aa
--- /dev/null
+++ b/misc/examples/words.c
@@ -0,0 +1,68 @@
+#include <math.h>
+#include <stc/cstr.h>
+
+#define i_val_str
+#include <stc/cvec.h>
+
+#define i_key_str
+#define i_val int
+#include <stc/cmap.h>
+
+int main1()
+{
+ c_auto (cvec_str, words)
+ c_auto (cmap_str, word_map)
+ {
+ c_forlist (i, const char*, {
+ "this", "sentence", "is", "not", "a", "sentence",
+ "this", "sentence", "is", "a", "hoax"
+ }) cvec_str_emplace_back(&words, *i.ref);
+
+ c_foreach (w, cvec_str, words) {
+ cmap_str_emplace(&word_map, cstr_str(w.ref), 0).ref->second += 1;
+ }
+
+ c_foreach (i, cmap_str, word_map) {
+ printf("%d occurrences of word '%s'\n",
+ i.ref->second, cstr_str(&i.ref->first));
+ }
+ }
+ return 0;
+}
+
+#ifdef __cplusplus
+#include <string>
+#include <iostream>
+#include <vector>
+#include <unordered_map>
+
+int main2()
+{
+ std::vector<std::string> words = {
+ "this", "sentence", "is", "not", "a", "sentence",
+ "this", "sentence", "is", "a", "hoax"
+ };
+
+ std::unordered_map<std::string, size_t> word_map;
+ for (const auto &w : words) {
+ word_map[w] += 1;
+ }
+
+ for (const auto &pair : word_map) {
+ std::cout << pair.second
+ << " occurrences of word '"
+ << pair.first << "'\n";
+ }
+ return 0;
+}
+
+int main() {
+ main1();
+ puts("");
+ main2();
+}
+#else
+int main() {
+ main1();
+}
+#endif