summaryrefslogtreecommitdiffhomepage
path: root/misc/examples/smartpointers
diff options
context:
space:
mode:
authortylov <[email protected]>2023-07-20 15:09:10 +0200
committertylov <[email protected]>2023-07-20 15:12:29 +0200
commit900295256d825fc323149cd223c49787f32a3696 (patch)
tree6c79cf4209e3975bb6865e2940b9cb56ea469c73 /misc/examples/smartpointers
parent224a04f7fa7549ed94d2a1415eb25829e39a7cca (diff)
downloadSTC-modified-900295256d825fc323149cd223c49787f32a3696.tar.gz
STC-modified-900295256d825fc323149cd223c49787f32a3696.zip
Moved examples to sub-directories. Added cotask1.c cotask2.c examples.
Diffstat (limited to 'misc/examples/smartpointers')
-rw-r--r--misc/examples/smartpointers/arc_containers.c81
-rw-r--r--misc/examples/smartpointers/arc_demo.c62
-rw-r--r--misc/examples/smartpointers/arcvec_erase.c50
-rw-r--r--misc/examples/smartpointers/box.c69
-rw-r--r--misc/examples/smartpointers/box2.c82
-rw-r--r--misc/examples/smartpointers/music_arc.c67
-rw-r--r--misc/examples/smartpointers/new_sptr.c75
-rw-r--r--misc/examples/smartpointers/person_arc.c77
-rw-r--r--misc/examples/smartpointers/rawptr_elements.c59
9 files changed, 622 insertions, 0 deletions
diff --git a/misc/examples/smartpointers/arc_containers.c b/misc/examples/smartpointers/arc_containers.c
new file mode 100644
index 00000000..2fb04c56
--- /dev/null
+++ b/misc/examples/smartpointers/arc_containers.c
@@ -0,0 +1,81 @@
+// Create a stack and a list of shared pointers to maps,
+// and demonstrate sharing and cloning of maps.
+#define i_implement
+#include <stc/cstr.h>
+#include <stc/algo/raii.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_key Map
+#define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p))
+// no need for atomic ref. count in single thread:
+#define i_opt c_no_atomic
+#include <stc/carc.h>
+
+#define i_type Stack
+#define i_keyboxed Arc // define i_keyboxed for carc/cbox value (not i_key)
+#include <stc/cvec.h>
+
+#define i_type List
+#define i_keyboxed Arc // as above
+#include <stc/clist.h>
+
+int main(void)
+{
+ Stack stack = {0};
+ List list = {0};
+ c_defer(
+ Stack_drop(&stack),
+ List_drop(&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/smartpointers/arc_demo.c b/misc/examples/smartpointers/arc_demo.c
new file mode 100644
index 00000000..929a48a1
--- /dev/null
+++ b/misc/examples/smartpointers/arc_demo.c
@@ -0,0 +1,62 @@
+#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_keyclone' is not required to be defined (ignored).
+
+#define i_type Arc // set type name to be defined (instead of 'carc_int')
+#define i_key int
+#define i_keydrop int_drop // optional, just to display the elements destroyed
+#define i_cmp_native // use int comparison (x < y, x == y).
+#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_keyboxed Arc // note: as above.
+#include <stc/cvec.h> // cvec_Arc (like: std::vector<std::shared_ptr<int>>)
+
+int main(void)
+{
+ const int years[] = {2021, 2012, 2022, 2015};
+
+ cvec_Arc vec = {0};
+ c_forrange (i, c_arraylen(years)) {
+ cvec_Arc_emplace(&vec, years[i]);
+ // cvec_Arc_push(&vec, Arc_from(years[i])); // alt.
+ }
+
+ cvec_Arc_sort(&vec);
+
+ printf("vec:");
+ c_foreach (i, cvec_Arc, vec)
+ printf(" %d", *i.ref->get);
+ puts("");
+
+ // add odd numbers from vec to set
+ csset_Arc set = {0};
+ 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);
+
+ Arc p = Arc_clone(vec.data[0]);
+ printf("\n%d is now owned by %ld objects\n", *p.get, *p.use_count);
+
+ Arc_drop(&p);
+ cvec_Arc_drop(&vec);
+ csset_Arc_drop(&set);
+}
diff --git a/misc/examples/smartpointers/arcvec_erase.c b/misc/examples/smartpointers/arcvec_erase.c
new file mode 100644
index 00000000..ba54c1c7
--- /dev/null
+++ b/misc/examples/smartpointers/arcvec_erase.c
@@ -0,0 +1,50 @@
+#include <stdio.h>
+
+void show_drop(int* x) { printf("drop: %d\n", *x); }
+
+#define i_type Arc
+#define i_key int
+#define i_keydrop show_drop
+#define i_cmp_native // enable sort/search for int type
+#include <stc/carc.h> // Shared pointer to int
+
+#define i_type Vec
+#define i_keyboxed Arc
+#include <stc/cvec.h> // Vec: cvec<Arc>
+
+
+int main(void)
+{
+ Vec vec = c_init(Vec, {2012, 1990, 2012, 2019, 2015});
+
+ // 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_erase_at(&vec, it);
+
+ int year = 2015;
+ it = Vec_find(&vec, year); // Ok as tmp only.
+ if (it.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");
+ Vec_drop(&vec);
+}
diff --git a/misc/examples/smartpointers/box.c b/misc/examples/smartpointers/box.c
new file mode 100644
index 00000000..94d126c0
--- /dev/null
+++ b/misc/examples/smartpointers/box.c
@@ -0,0 +1,69 @@
+/* cbox: heap allocated boxed type */
+#define i_implement
+#include <stc/cstr.h>
+
+typedef struct { cstr name, last; } Person;
+
+Person Person_make(const char* name, const char* last) {
+ return c_LITERAL(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_keyclass Person // "class" binds _cmp, _clone, _drop functions.
+#include <stc/cbox.h>
+
+#define i_type Persons
+#define i_keyboxed PBox // "arcbox" informs that PBox is a smart pointer.
+#include <stc/csset.h>
+
+int main(void)
+{
+ Persons vec = {0};
+ PBox p = PBox_from(Person_make("Laura", "Palmer"));
+ PBox 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.
+ Person a = Person_make("Audrey", "Home");
+ 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));
+
+ Person_drop(&a);
+ PBox_drop(&p);
+ PBox_drop(&q);
+ Persons_drop(&vec);
+}
diff --git a/misc/examples/smartpointers/box2.c b/misc/examples/smartpointers/box2.c
new file mode 100644
index 00000000..eaab1c47
--- /dev/null
+++ b/misc/examples/smartpointers/box2.c
@@ -0,0 +1,82 @@
+// example: https://doc.rust-lang.org/rust-by-example/std/box.html
+#include <stdio.h>
+
+typedef struct {
+ double x;
+ double y;
+} Point;
+
+// A Rectangle can be specified by where its top left and bottom right
+// corners are in space
+typedef struct {
+ Point top_left;
+ Point bottom_right;
+} Rectangle;
+
+#define i_key Point
+#include <stc/cbox.h> // cbox_Point
+
+#define i_key Rectangle
+#include <stc/cbox.h> // cbox_Rectangle
+
+// Box in box:
+#define i_type BoxBoxPoint
+#define i_keyboxed cbox_Point // NB: use i_keyboxed when value is a cbox or carc!
+#define i_no_cmp
+#include <stc/cbox.h> // BoxBoxPoint
+
+Point origin(void) {
+ return c_LITERAL(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(c_LITERAL(Point){ .x=1.0, .y=2.0 });
+}
+
+
+int main(void) {
+ // Stack allocated variables
+ Point point = origin();
+ Rectangle rectangle = {
+ .top_left = origin(),
+ .bottom_right = { .x=3.0, .y=-4.0 }
+ };
+
+ // Heap allocated rectangle
+ cbox_Rectangle boxed_rectangle = cbox_Rectangle_make(c_LITERAL(Rectangle){
+ .top_left = origin(),
+ .bottom_right = { .x=3.0, .y=-4.0 }
+ });
+ // The output of functions can be boxed
+ cbox_Point boxed_point = cbox_Point_make(origin());
+
+ // Can use from(raw) and toraw instead:
+ BoxBoxPoint box_in_a_box = BoxBoxPoint_from(origin());
+
+ c_defer(
+ BoxBoxPoint_drop(&box_in_a_box),
+ cbox_Point_drop(&boxed_point),
+ cbox_Rectangle_drop(&boxed_rectangle)
+ ){
+ printf("box_in_a_box: x = %g\n", BoxBoxPoint_toraw(&box_in_a_box).x);
+
+ printf("Point occupies %d bytes on the stack\n",
+ (int)sizeof(point));
+ printf("Rectangle occupies %d bytes on the stack\n",
+ (int)sizeof(rectangle));
+
+ // box size == pointer size
+ printf("Boxed point occupies %d bytes on the stack\n",
+ (int)sizeof(boxed_point));
+ printf("Boxed rectangle occupies %d bytes on the stack\n",
+ (int)sizeof(boxed_rectangle));
+ printf("Boxed box occupies %d bytes on the stack\n",
+ (int)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 %d bytes on the stack\n",
+ (int)sizeof(unboxed_point));
+ }
+}
diff --git a/misc/examples/smartpointers/music_arc.c b/misc/examples/smartpointers/music_arc.c
new file mode 100644
index 00000000..16111b0b
--- /dev/null
+++ b/misc/examples/smartpointers/music_arc.c
@@ -0,0 +1,67 @@
+// 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
+#define i_implement
+#include <stc/cstr.h>
+
+typedef struct
+{
+ cstr artist;
+ cstr title;
+} Song;
+
+int Song_cmp(const Song* x, const Song* y)
+ { return cstr_cmp(&x->title, &y->title); }
+
+Song Song_make(const char* artist, const char* title)
+ { return c_LITERAL(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 shared pointer:
+#define i_type SongArc
+#define i_keyclass Song
+#define i_no_hash // no hash fn for Song, fallback hash pointer to Song.
+#include <stc/carc.h>
+
+// ... and a vector of them
+#define i_type SongVec
+#define i_keyboxed SongArc // use i_keyboxed on carc / cbox (instead of i_key)
+#include <stc/cvec.h>
+
+void example3(void)
+{
+ SongVec vec1 = c_init(SongVec, {
+ Song_make("Bob Dylan", "The Times They Are A Changing"),
+ Song_make("Aretha Franklin", "Bridge Over Troubled Water"),
+ Song_make("Thalia", "Entre El Mar y Una Estrella")
+ });
+
+ SongVec vec2 = {0};
+ // 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
+ // Emplace calls SongArc_from() on the argument to create the Arc:
+ SongVec_emplace(&vec2, Song_make("Michael Jackson", "Billie Jean"));
+ SongVec_emplace(&vec2, Song_make("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);
+ }
+ c_drop(SongVec, &vec1, &vec2);
+}
+
+int main(void)
+{
+ example3();
+}
diff --git a/misc/examples/smartpointers/new_sptr.c b/misc/examples/smartpointers/new_sptr.c
new file mode 100644
index 00000000..3c6fa16c
--- /dev/null
+++ b/misc/examples/smartpointers/new_sptr.c
@@ -0,0 +1,75 @@
+#define i_implement
+#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_keyclass Person // "class" assume _clone, _drop, _cmp, _hash is defined.
+#include <stc/carc.h>
+
+#define i_type IPtr
+#define i_key int
+#define i_keydrop(x) printf("drop: %d\n", *x)
+#define i_cmp_native
+#include <stc/carc.h>
+
+#define i_type IPStack
+#define i_keyboxed IPtr
+#include <stc/cstack.h>
+
+#define i_type PASet
+#define i_keyboxed PersonArc
+#include <stc/cset.h>
+
+
+Person Person_make(const char* name, const char* last) {
+ Person p = {.name = cstr_from(name), .last = cstr_from(last)};
+ return p;
+}
+
+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) {
+ puts("Ex1");
+ PersonArc p = PersonArc_from(Person_make("John", "Smiths"));
+ PersonArc q = PersonArc_clone(p); // share
+ PersonArc r = PersonArc_clone(p);
+ PersonArc 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_drop(PersonArc, &p, &q, &r, &s);
+
+ puts("Ex2");
+ IPStack vec = {0};
+ 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("");
+ IPStack_drop(&vec);
+}
diff --git a/misc/examples/smartpointers/person_arc.c b/misc/examples/smartpointers/person_arc.c
new file mode 100644
index 00000000..38c883a7
--- /dev/null
+++ b/misc/examples/smartpointers/person_arc.c
@@ -0,0 +1,77 @@
+/* cbox: heap allocated boxed type */
+#define i_implement
+#include <stc/cstr.h>
+
+typedef struct { cstr name, last; } Person;
+
+Person Person_make(const char* name, const char* last) {
+ Person p = {.name = cstr_from(name), .last = cstr_from(last)};
+ return p;
+}
+
+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_keyclass 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_keyboxed PSPtr // binds PSPtr_cmp, PSPtr_drop...
+#include <stc/cvec.h>
+
+
+int main(void)
+{
+ PSPtr p = PSPtr_from(Person_make("Laura", "Palmer"));
+ PSPtr q = PSPtr_from(Person_clone(*p.get)); // deep copy
+ Persons vec = {0};
+
+ c_defer(
+ PSPtr_drop(&p),
+ PSPtr_drop(&q),
+ Persons_drop(&vec)
+ ){
+ 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!
+ Person a = Person_make("Audrey", "Home");
+ const PSPtr *v = Persons_get(&vec, a);
+ if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last));
+ Person_drop(&a);
+ }
+}
diff --git a/misc/examples/smartpointers/rawptr_elements.c b/misc/examples/smartpointers/rawptr_elements.c
new file mode 100644
index 00000000..694ce12e
--- /dev/null
+++ b/misc/examples/smartpointers/rawptr_elements.c
@@ -0,0 +1,59 @@
+#include <stc/ccommon.h>
+#include <stdio.h>
+#define i_implement
+#include <stc/cstr.h>
+
+// Create cmap of cstr => long*
+#define i_type SIPtrMap
+#define i_key_str
+#define i_val long*
+#define i_valraw long
+#define i_valfrom(raw) c_new(long, raw)
+#define i_valto(x) **x
+#define i_valclone(x) c_new(long, *x)
+#define i_valdrop(x) c_free(*x)
+#include <stc/cmap.h>
+
+// Alternatively, using cbox:
+#define i_type IBox
+#define i_key long
+#include <stc/cbox.h> // unique_ptr<long> alike.
+
+// cmap of cstr => IBox
+#define i_type SIBoxMap
+#define i_key_str
+#define i_valboxed IBox // i_valboxed: use properties from IBox automatically
+#include <stc/cmap.h>
+
+int main(void)
+{
+ // These have the same behaviour, except IBox has a get member:
+ SIPtrMap map1 = {0};
+ SIBoxMap map2 = {0};
+
+ printf("\nMap cstr => long*:\n");
+ SIPtrMap_insert(&map1, cstr_from("Test1"), c_new(long, 1));
+ SIPtrMap_insert(&map1, cstr_from("Test2"), c_new(long, 2));
+
+ // Emplace implicitly creates cstr from const char* and an owned long* from long!
+ SIPtrMap_emplace(&map1, "Test3", 3);
+ SIPtrMap_emplace(&map1, "Test4", 4);
+
+ c_forpair (name, number, SIPtrMap, map1)
+ printf("%s: %ld\n", cstr_str(_.name), **_.number);
+
+ puts("\nMap cstr => IBox:");
+ SIBoxMap_insert(&map2, cstr_from("Test1"), IBox_make(1));
+ SIBoxMap_insert(&map2, cstr_from("Test2"), IBox_make(2));
+
+ // Emplace implicitly creates cstr from const char* and IBox from long!
+ SIBoxMap_emplace(&map2, "Test3", 3);
+ SIBoxMap_emplace(&map2, "Test4", 4);
+
+ c_forpair (name, number, SIBoxMap, map2)
+ printf("%s: %ld\n", cstr_str(_.name), *_.number->get);
+ puts("");
+
+ SIPtrMap_drop(&map1);
+ SIBoxMap_drop(&map2);
+}