summaryrefslogtreecommitdiffhomepage
path: root/misc/examples/smartpointers
diff options
context:
space:
mode:
Diffstat (limited to 'misc/examples/smartpointers')
-rw-r--r--misc/examples/smartpointers/arc_containers.c80
-rw-r--r--misc/examples/smartpointers/arc_demo.c63
-rw-r--r--misc/examples/smartpointers/arcvec_erase.c52
-rw-r--r--misc/examples/smartpointers/box.c70
-rw-r--r--misc/examples/smartpointers/box2.c81
-rw-r--r--misc/examples/smartpointers/map_box.c34
-rw-r--r--misc/examples/smartpointers/map_ptr.c34
-rw-r--r--misc/examples/smartpointers/music_arc.c67
-rw-r--r--misc/examples/smartpointers/new_sptr.c76
-rw-r--r--misc/examples/smartpointers/person_arc.c78
10 files changed, 635 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..79211d2b
--- /dev/null
+++ b/misc/examples/smartpointers/arc_containers.c
@@ -0,0 +1,80 @@
+// 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>
+#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 // use i_keyboxed for carc/cbox 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..a66d84b0
--- /dev/null
+++ b/misc/examples/smartpointers/arc_demo.c
@@ -0,0 +1,63 @@
+#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_use_cmp // 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.
+#define i_use_cmp
+#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..0526b6a0
--- /dev/null
+++ b/misc/examples/smartpointers/arcvec_erase.c
@@ -0,0 +1,52 @@
+#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_use_cmp // enable sort/search for int type
+#include <stc/carc.h> // Shared pointer to int
+
+#define i_type Vec
+#define i_keyboxed Arc
+#define i_use_cmp
+#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])); // => share vec.data[2]
+ Vec_emplace(&vec, *vec.data[2].get); // => deep-copy 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..5c8018d4
--- /dev/null
+++ b/misc/examples/smartpointers/box.c
@@ -0,0 +1,70 @@
+/* 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.
+#define i_use_cmp
+#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..9b782c74
--- /dev/null
+++ b/misc/examples/smartpointers/box2.c
@@ -0,0 +1,81 @@
+// 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!
+#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/map_box.c b/misc/examples/smartpointers/map_box.c
new file mode 100644
index 00000000..f651b302
--- /dev/null
+++ b/misc/examples/smartpointers/map_box.c
@@ -0,0 +1,34 @@
+#include <stc/ccommon.h>
+#include <stdio.h>
+#define i_implement
+#include <stc/cstr.h>
+
+#define i_type IBox
+#define i_key long
+#include <stc/cbox.h> // unique_ptr<long> alike.
+
+// cmap of cstr => IBox
+#define i_type Boxmap
+#define i_key_str
+#define i_valboxed IBox // i_valboxed: use properties from IBox automatically
+#include <stc/cmap.h>
+
+
+int main(void)
+{
+ Boxmap map = {0};
+
+ puts("Map cstr => IBox:");
+ Boxmap_insert(&map, cstr_from("Test1"), IBox_make(1));
+ Boxmap_insert(&map, cstr_from("Test2"), IBox_make(2));
+
+ // Simpler: emplace() implicitly creates cstr from const char* and IBox from long!
+ Boxmap_emplace(&map, "Test3", 3);
+ Boxmap_emplace(&map, "Test4", 4);
+
+ c_forpair (name, number, Boxmap, map)
+ printf("%s: %ld\n", cstr_str(_.name), *_.number->get);
+ puts("");
+
+ Boxmap_drop(&map);
+}
diff --git a/misc/examples/smartpointers/map_ptr.c b/misc/examples/smartpointers/map_ptr.c
new file mode 100644
index 00000000..453322c5
--- /dev/null
+++ b/misc/examples/smartpointers/map_ptr.c
@@ -0,0 +1,34 @@
+#include <stc/ccommon.h>
+#include <stdio.h>
+#define i_implement
+#include <stc/cstr.h>
+
+// cmap of cstr => long*
+#define i_type Ptrmap
+#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>
+
+int main(void)
+{
+ Ptrmap map = {0};
+
+ puts("Map cstr => long*:");
+ Ptrmap_insert(&map, cstr_from("Test1"), c_new(long, 1));
+ Ptrmap_insert(&map, cstr_from("Test2"), c_new(long, 2));
+
+ // Simple: emplace() implicitly creates cstr from const char* and an owned long* from long!
+ Ptrmap_emplace(&map, "Test3", 3);
+ Ptrmap_emplace(&map, "Test4", 4);
+
+ c_forpair (name, number, Ptrmap, map)
+ printf("%s: %ld\n", cstr_str(_.name), **_.number);
+ puts("");
+
+ Ptrmap_drop(&map);
+}
diff --git a/misc/examples/smartpointers/music_arc.c b/misc/examples/smartpointers/music_arc.c
new file mode 100644
index 00000000..e9ebbbfe
--- /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_init(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_opt c_use_cmp|c_no_hash
+#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_init("Bob Dylan", "The Times They Are A Changing"),
+ Song_init("Aretha Franklin", "Bridge Over Troubled Water"),
+ Song_init("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_init("Michael Jackson", "Billie Jean"));
+ SongVec_emplace(&vec2, Song_init("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();
+} \ No newline at end of file
diff --git a/misc/examples/smartpointers/new_sptr.c b/misc/examples/smartpointers/new_sptr.c
new file mode 100644
index 00000000..50e28ae2
--- /dev/null
+++ b/misc/examples/smartpointers/new_sptr.c
@@ -0,0 +1,76 @@
+#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.
+#define i_use_cmp
+#include <stc/carc.h>
+
+#define i_type IPtr
+#define i_key int
+#define i_keydrop(x) printf("drop: %d\n", *x)
+#define i_use_cmp
+#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..11040cd2
--- /dev/null
+++ b/misc/examples/smartpointers/person_arc.c
@@ -0,0 +1,78 @@
+/* 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_use_cmp
+#include <stc/carc.h>
+
+#define i_type Persons
+#define i_keyboxed PSPtr // binds PSPtr_cmp, PSPtr_drop...
+#define i_use_cmp
+#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);
+ }
+}