From 6749cc21a2045d307c239d82891cb860687dfd2a Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Tue, 14 Dec 2021 19:50:10 +0100 Subject: Added and renamed some examples. --- docs/csview_api.md | 17 +++---- examples/books.c | 60 ++++++++++++++++++++++++ examples/box.c | 61 ++++++++++++++++++++++++ examples/box2.c | 86 ++++++++++++++++++++++++++++++++++ examples/hashmap.c | 48 +++++++++++++++++++ examples/ptr_elems.c | 62 ------------------------- examples/rawptr_elements.c | 62 +++++++++++++++++++++++++ examples/sharedptr.c | 56 ---------------------- examples/sptr_demo.c | 56 ++++++++++++++++++++++ examples/sptr_ex.c | 58 ----------------------- examples/sptr_music.c | 58 +++++++++++++++++++++++ examples/sview_split.c | 17 +++++++ include/stc/alt/cstr.h | 113 ++++++++++++++++++++++----------------------- include/stc/cstr.h | 18 ++++---- 14 files changed, 520 insertions(+), 252 deletions(-) create mode 100644 examples/books.c create mode 100644 examples/box.c create mode 100644 examples/box2.c create mode 100644 examples/hashmap.c delete mode 100644 examples/ptr_elems.c create mode 100644 examples/rawptr_elements.c delete mode 100644 examples/sharedptr.c create mode 100644 examples/sptr_demo.c delete mode 100644 examples/sptr_ex.c create mode 100644 examples/sptr_music.c create mode 100644 examples/sview_split.c diff --git a/docs/csview_api.md b/docs/csview_api.md index 2653dafa..7daa67ee 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -25,11 +25,11 @@ All csview definitions and prototypes are available by including a single header ## Methods ```c +csview c_sv(const char literal_only[]); // alias for csview_new csview csview_new(const char literal_only[]); // make csview from literal, no strlen() csview csview_from_s(cstr s); // same as cstr_sv() csview csview_from(const char* str); // make csview from const char* csview csview_from_n(const char* str, size_t n); // construct -csview c_sv(const char literal_only[]); // same as csview_new() size_t csview_size(csview sv); size_t csview_length(csview sv); @@ -57,10 +57,10 @@ void csview_next(csview_iter* it); #### Extended cstr methods ```c cstr cstr_from_v(csview sv); // construct cstr from csview +csview cstr_to_v(const cstr* self); // convert to csview from cstr* cstr cstr_from_replace_all_v(csview sv, csview find, csview replace); csview cstr_sv(cstr s); // convert to csview from cstr -csview cstr_to_v(const cstr* self); // convert to csview from cstr* csview cstr_substr(cstr s, intptr_t pos, size_t n); // negative pos counts from end csview cstr_slice(cstr s, intptr_t p1, intptr_t p2); // negative p1, p2 counts from end @@ -91,11 +91,12 @@ uint64_t csview_hash(const csview* x, size_t dummy); ## Constants and macros -| Name | Value | Usage | -|:-----------------|:--------------------|:----------------------------------| -| `csview_null` | same as `c_sv("")` | `sview = csview_null;` | -| `csview_npos` | same as `cstr_npos` | | -| `csview_ARG(sv)` | printf argument | `printf("%.*s", csview_ARG(sv));` | +| Name | Value | Usage | +|:---------------|:---------------------|:----------------------------------------------| +| `csview_null` | same as `c_sv("")` | `sview = csview_null;` | +| `csview_npos` | same as `cstr_npos` | | +| `c_svarg(sv)` | printf format csview | | +| `c_svfmt` | printf argument | `printf("view: " c_svfmt "\n", c_svarg(sv));` | ## Example ```c @@ -110,7 +111,7 @@ int main () size_t pos = cstr_find(str1, "live"); // position of "live" in str1 csview sv2 = cstr_substr(str1, pos, 4); // get "live" csview sv3 = cstr_slice(str1, -8, -1); // get "details" - printf("%.*s %.*s %.*s\n", csview_ARG(sv1), csview_ARG(sv2), csview_ARG(sv3)); + printf(c_svfmt c_svfmt c_svfmt "\n", c_svarg(sv1), c_svarg(sv2), c_svarg(sv3)); cstr s1 = cstr_new("Apples are red"); cstr s2 = cstr_from_v(cstr_substr(s1, -3, 3)); // "red" diff --git a/examples/books.c b/examples/books.c new file mode 100644 index 00000000..f9340679 --- /dev/null +++ b/examples/books.c @@ -0,0 +1,60 @@ +// https://doc.rust-lang.org/std/collections/struct.HashMap.html + +#define i_key_str +#define i_val_str +#include + +// Type inference lets us omit an explicit type signature (which +// would be `HashMap` 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_new("The Adventures of Sherlock Holmes"), + cstr_new("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 %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; + if ((b = cmap_str_get(&book_reviews, to_find[i]))) + printf("%s: %s\n", b->first.str, b->second.str); + 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", cmap_str_at(&book_reviews, "Pride and Prejudice")->str); + + // Iterate over everything. + c_forpair (book, review, cmap_str, book_reviews) { + printf("%s: \"%s\"\n", _.book.str, _.review.str); + } + } +} \ No newline at end of file diff --git a/examples/box.c b/examples/box.c new file mode 100644 index 00000000..c7763bb8 --- /dev/null +++ b/examples/box.c @@ -0,0 +1,61 @@ +/* cbox: heap allocated boxed type */ +#include + +typedef struct { cstr name, last; } Person; + +Person Person_from(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 = strcmp(a->name.str, b->name.str); + return c ? c : strcmp(a->last.str, b->last.str); +} + +Person Person_clone(Person p) { + p.name = cstr_clone(p.name); + p.last = cstr_clone(p.last); + return p; +} +void Person_del(Person* p) { + printf("del: %s %s\n", p->name.str, p->last.str); + c_del(cstr, &p->name, &p->last); +} + +#define i_val Person +#define i_cmp Person_cmp +#define i_from Person_clone +#define i_del Person_del +#define i_tag prs +#include + +#define i_val_ref cbox_prs +#define i_tag prs +#include + + +int main() +{ + c_auto (cvec_prs, vec) + c_auto (cbox_prs, p, q) + { + p = cbox_prs_new(Person_from("Dave", "Cooper")); + + q = cbox_prs_clone(p); + cstr_assign(&q.get->name, "Dale"); + + printf("%s %s.\n", p.get->name.str, p.get->last.str); + printf("%s %s.\n", q.get->name.str, q.get->last.str); + + cvec_prs_push_back(&vec, cbox_prs_new(Person_from("Laura", "Palmer"))); + cvec_prs_push_back(&vec, cbox_prs_new(Person_from("Shelly", "Johnson"))); + + c_foreach (i, cvec_prs, vec) + printf("%s: %s\n", i.ref->get->name.str, i.ref->get->last.str); + + c_autovar (Person per = Person_from("Laura", "Palmer"), Person_del(&per)) { + const cbox_prs *v = cvec_prs_get(&vec, (cbox_prs){&per}); + if (v) printf("found: %s: %s\n", v->get->name.str, v->get->last.str); + } + } +} diff --git a/examples/box2.c b/examples/box2.c new file mode 100644 index 00000000..79304609 --- /dev/null +++ b/examples/box2.c @@ -0,0 +1,86 @@ +// https://doc.rust-lang.org/rust-by-example/std/box.html + +#include +#include +#include +#include + +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_compare +#include + +#define i_val cbox_Point +#define i_opt c_no_compare +#define i_tag BoxPoint +#include + +#define i_val Rectangle +#define i_opt c_no_compare +#include + +Point origin(void) { + return (Point){ .x=0.0, .y=0.0 }; +} + +cbox_Point boxed_origin(void) { + // Allocate this point on the heap, and return a pointer to it + return cbox_Point_new((Point){ .x=0.0, .y=0.0 }); +} + + +int main(void) { + // (all the type annotations are superfluous) + // Stack allocated variables + Point point = origin(); + Rectangle rectangle = (Rectangle){ + .top_left = origin(), + .bottom_right = (Point){ .x=3.0, .y=-4.0 } + }; + + // Heap allocated rectangle + c_auto (cbox_Rectangle, boxed_rectangle) + c_auto (cbox_Point, boxed_point) + c_auto (cbox_BoxPoint, box_in_a_box) + { + boxed_rectangle = cbox_Rectangle_new((Rectangle){ + .top_left = origin(), + .bottom_right = (Point){ .x=3.0, .y=-4.0 } + }); + + // The output of functions can be boxed + boxed_point = cbox_Point_new(origin()); + + // Double indirection + box_in_a_box = cbox_BoxPoint_new(boxed_origin()); + + printf("Point occupies %zu bytes on the stack\n", + sizeof(point)); + printf("Rectangle occupies %zu bytes on the stack\n", + sizeof(rectangle)); + + // box size == pointer size + printf("Boxed point occupies %zu bytes on the stack\n", + sizeof(boxed_point)); + printf("Boxed rectangle occupies %zu bytes on the stack\n", + sizeof(boxed_rectangle)); + printf("Boxed box occupies %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 %zu bytes on the stack\n", + sizeof(unboxed_point)); + } +} \ No newline at end of file diff --git a/examples/hashmap.c b/examples/hashmap.c new file mode 100644 index 00000000..c3e9afce --- /dev/null +++ b/examples/hashmap.c @@ -0,0 +1,48 @@ +// https://doc.rust-lang.org/rust-by-example/std/hash.html + +#define i_key_str +#define i_val_str +#include +#include + +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(v->second.str)); + else + printf("Don't have Daniel's number."); + + cmap_str_emplace(&contacts, "Daniel", "164-6743"); + + if ((v = cmap_str_get(&contacts, "Ashley"))) + printf("Calling Ashley: %s\n", call(v->second.str)); + 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", _.contact.str, call(_.number.str)); + } + puts(""); + } +} diff --git a/examples/ptr_elems.c b/examples/ptr_elems.c deleted file mode 100644 index c5416822..00000000 --- a/examples/ptr_elems.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include - -struct { double x, y; } typedef Point; - -// Set of Point pointers: define all template parameters "in-line" -// Note it may be simpler to use a cbox for this. -#define i_key Point* -#define i_keydel(x) c_free(*(x)) -#define i_keyfrom(x) c_new(Point, *(x)) -#define i_hash(x, n) c_default_hash(*(x), sizeof *(x)) -#define i_equ(x, y) c_memcmp_equalto(*(x), *(y)) -#define i_tag pnt -#include - -// Map of int64 pointers: For fun, define valraw as int64_t for easy emplace call! -typedef int64_t inttype; -#define i_key_str -#define i_valraw inttype -#define i_val inttype* -#define i_valdel(x) c_free(*(x)) -#define i_valfrom(raw) c_new(inttype, raw) -#define i_valto(x) **(x) -#include - -int main() -{ - c_auto (cset_pnt, set, cpy) - { - printf("Set with pointer elements:\n"); - // c++: set.insert(new Point{1.2, 3.4}); - cset_pnt_insert(&set, c_new(Point, {1.2, 3.4})); - Point* q = *cset_pnt_insert(&set, c_new(Point, {6.1, 4.7})).ref; - cset_pnt_insert(&set, c_new(Point, {5.7, 2.3})); - - cpy = cset_pnt_clone(set); - cset_pnt_erase(&cpy, q); - - printf("set:"); - c_foreach (i, cset_pnt, set) - printf(" (%g %g)", i.ref[0]->x, i.ref[0]->y); - - printf("\ncpy:"); - c_foreach (i, cset_pnt, cpy) - printf(" (%g %g)", i.ref[0]->x, i.ref[0]->y); - puts(""); - } - - c_auto (cmap_str, map) - { - printf("\nMap with pointer elements:\n"); - cmap_str_insert(&map, cstr_new("testing"), c_new(inttype, 999)); - cmap_str_insert(&map, cstr_new("done"), c_new(inttype, 111)); - - // Emplace: implicit key, val construction using i_keyfrom/i_valfrom: - cmap_str_emplace(&map, "hello", 200); - cmap_str_emplace(&map, "goodbye", 400); - - c_forpair (name, number, cmap_str, map) - printf("%s: %zd\n", _.name.str, *_.number); - } -} diff --git a/examples/rawptr_elements.c b/examples/rawptr_elements.c new file mode 100644 index 00000000..c5416822 --- /dev/null +++ b/examples/rawptr_elements.c @@ -0,0 +1,62 @@ +#include +#include + +struct { double x, y; } typedef Point; + +// Set of Point pointers: define all template parameters "in-line" +// Note it may be simpler to use a cbox for this. +#define i_key Point* +#define i_keydel(x) c_free(*(x)) +#define i_keyfrom(x) c_new(Point, *(x)) +#define i_hash(x, n) c_default_hash(*(x), sizeof *(x)) +#define i_equ(x, y) c_memcmp_equalto(*(x), *(y)) +#define i_tag pnt +#include + +// Map of int64 pointers: For fun, define valraw as int64_t for easy emplace call! +typedef int64_t inttype; +#define i_key_str +#define i_valraw inttype +#define i_val inttype* +#define i_valdel(x) c_free(*(x)) +#define i_valfrom(raw) c_new(inttype, raw) +#define i_valto(x) **(x) +#include + +int main() +{ + c_auto (cset_pnt, set, cpy) + { + printf("Set with pointer elements:\n"); + // c++: set.insert(new Point{1.2, 3.4}); + cset_pnt_insert(&set, c_new(Point, {1.2, 3.4})); + Point* q = *cset_pnt_insert(&set, c_new(Point, {6.1, 4.7})).ref; + cset_pnt_insert(&set, c_new(Point, {5.7, 2.3})); + + cpy = cset_pnt_clone(set); + cset_pnt_erase(&cpy, q); + + printf("set:"); + c_foreach (i, cset_pnt, set) + printf(" (%g %g)", i.ref[0]->x, i.ref[0]->y); + + printf("\ncpy:"); + c_foreach (i, cset_pnt, cpy) + printf(" (%g %g)", i.ref[0]->x, i.ref[0]->y); + puts(""); + } + + c_auto (cmap_str, map) + { + printf("\nMap with pointer elements:\n"); + cmap_str_insert(&map, cstr_new("testing"), c_new(inttype, 999)); + cmap_str_insert(&map, cstr_new("done"), c_new(inttype, 111)); + + // Emplace: implicit key, val construction using i_keyfrom/i_valfrom: + cmap_str_emplace(&map, "hello", 200); + cmap_str_emplace(&map, "goodbye", 400); + + c_forpair (name, number, cmap_str, map) + printf("%s: %zd\n", _.name.str, *_.number); + } +} diff --git a/examples/sharedptr.c b/examples/sharedptr.c deleted file mode 100644 index c3da5287..00000000 --- a/examples/sharedptr.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include - -void int_del(int* x) { - printf("del: %d\n", *x); -} - -// csptr implements its own clone method using reference counting, -// so 'i_valfrom' need not be defined (will be ignored). - -#define i_type iref // set type name to be defined (instead of 'csptr_int') -#define i_val int -#define i_del int_del // optional, just to display the elements destroyed -#include // iref - -#define i_key_ref iref // note: use i_key_ref instead of i_key for csptr/cbox elements -#include // csset_iref (like: std::set>) - -#define i_val_ref iref // note: as above. -#include // cvec_iref (like: std::vector>) - -int main() -{ - c_auto (cvec_iref, vec) // declare and init vec, call cvec_iref_del() at scope exit - c_auto (csset_iref, set) // declare and init set, call csset_iref_del() at scope exit - { - const int years[] = {2021, 2012, 2022, 2015}; - c_forrange (i, c_arraylen(years)) - cvec_iref_push_back(&vec, iref_new(years[i])); - - printf("vec:"); - c_foreach (i, cvec_iref, vec) printf(" %d", *i.ref->get); - puts(""); - - // add odd numbers from vec to set - c_foreach (i, cvec_iref, vec) - if (*i.ref->get & 1) - csset_iref_emplace(&set, *i.ref); // copy shared pointer => increments counter. - - // erase the two last elements in vec - cvec_iref_pop_back(&vec); - cvec_iref_pop_back(&vec); - - printf("vec:"); - c_foreach (i, cvec_iref, vec) printf(" %d", *i.ref->get); - - printf("\nset:"); - c_foreach (i, csset_iref, set) printf(" %d", *i.ref->get); - - c_autovar (iref p = iref_clone(vec.data[0]), iref_del(&p)) { - printf("\n%d is now owned by %ld objects\n", *p.get, *p.use_count); - } - - puts("\nDone"); - } -} diff --git a/examples/sptr_demo.c b/examples/sptr_demo.c new file mode 100644 index 00000000..c3da5287 --- /dev/null +++ b/examples/sptr_demo.c @@ -0,0 +1,56 @@ +#include +#include + +void int_del(int* x) { + printf("del: %d\n", *x); +} + +// csptr implements its own clone method using reference counting, +// so 'i_valfrom' need not be defined (will be ignored). + +#define i_type iref // set type name to be defined (instead of 'csptr_int') +#define i_val int +#define i_del int_del // optional, just to display the elements destroyed +#include // iref + +#define i_key_ref iref // note: use i_key_ref instead of i_key for csptr/cbox elements +#include // csset_iref (like: std::set>) + +#define i_val_ref iref // note: as above. +#include // cvec_iref (like: std::vector>) + +int main() +{ + c_auto (cvec_iref, vec) // declare and init vec, call cvec_iref_del() at scope exit + c_auto (csset_iref, set) // declare and init set, call csset_iref_del() at scope exit + { + const int years[] = {2021, 2012, 2022, 2015}; + c_forrange (i, c_arraylen(years)) + cvec_iref_push_back(&vec, iref_new(years[i])); + + printf("vec:"); + c_foreach (i, cvec_iref, vec) printf(" %d", *i.ref->get); + puts(""); + + // add odd numbers from vec to set + c_foreach (i, cvec_iref, vec) + if (*i.ref->get & 1) + csset_iref_emplace(&set, *i.ref); // copy shared pointer => increments counter. + + // erase the two last elements in vec + cvec_iref_pop_back(&vec); + cvec_iref_pop_back(&vec); + + printf("vec:"); + c_foreach (i, cvec_iref, vec) printf(" %d", *i.ref->get); + + printf("\nset:"); + c_foreach (i, csset_iref, set) printf(" %d", *i.ref->get); + + c_autovar (iref p = iref_clone(vec.data[0]), iref_del(&p)) { + printf("\n%d is now owned by %ld objects\n", *p.get, *p.use_count); + } + + puts("\nDone"); + } +} diff --git a/examples/sptr_ex.c b/examples/sptr_ex.c deleted file mode 100644 index e8e08b5f..00000000 --- a/examples/sptr_ex.c +++ /dev/null @@ -1,58 +0,0 @@ -// 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 - -struct Song -{ - cstr artist; - cstr title; -} typedef Song; - -Song Song_from(const char* artist, const char* title) - { return (Song){cstr_from(artist), cstr_from(title)}; } - -void Song_del(Song* s) { - printf("del: %s\n", s->title.str); - c_del(cstr, &s->artist, &s->title); -} - -#define i_val Song -#define i_del Song_del -#define i_tag song -#define i_opt c_no_compare -#include // define csptr_song - -#define i_val_ref csptr_song -#define i_tag song -#include - -void example3() -{ - c_auto (cvec_song, v, v2) - { - c_apply(cvec_song, push_back, &v, { - csptr_song_new(Song_from("Bob Dylan", "The Times They Are A Changing")), - csptr_song_new(Song_from("Aretha Franklin", "Bridge Over Troubled Water")), - csptr_song_new(Song_from("Thalia", "Entre El Mar y Una Estrella")) - }); - - c_foreach (s, cvec_song, v) - if (!cstr_equals(s.ref->get->artist, "Bob Dylan")) - cvec_song_emplace_back(&v2, *s.ref); // note: calls csptr_song_clone() - - c_apply(cvec_song, push_back, &v2, { - csptr_song_new(Song_from("Michael Jackson", "Billie Jean")), - csptr_song_new(Song_from("Rihanna", "Stay")), - }); - - c_foreach (s, cvec_song, v2) - printf("%s - %s: refs %lu\n", s.ref->get->artist.str, s.ref->get->title.str, - *s.ref->use_count); - } -} - -int main() -{ - example3(); -} diff --git a/examples/sptr_music.c b/examples/sptr_music.c new file mode 100644 index 00000000..e8e08b5f --- /dev/null +++ b/examples/sptr_music.c @@ -0,0 +1,58 @@ +// 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 + +struct Song +{ + cstr artist; + cstr title; +} typedef Song; + +Song Song_from(const char* artist, const char* title) + { return (Song){cstr_from(artist), cstr_from(title)}; } + +void Song_del(Song* s) { + printf("del: %s\n", s->title.str); + c_del(cstr, &s->artist, &s->title); +} + +#define i_val Song +#define i_del Song_del +#define i_tag song +#define i_opt c_no_compare +#include // define csptr_song + +#define i_val_ref csptr_song +#define i_tag song +#include + +void example3() +{ + c_auto (cvec_song, v, v2) + { + c_apply(cvec_song, push_back, &v, { + csptr_song_new(Song_from("Bob Dylan", "The Times They Are A Changing")), + csptr_song_new(Song_from("Aretha Franklin", "Bridge Over Troubled Water")), + csptr_song_new(Song_from("Thalia", "Entre El Mar y Una Estrella")) + }); + + c_foreach (s, cvec_song, v) + if (!cstr_equals(s.ref->get->artist, "Bob Dylan")) + cvec_song_emplace_back(&v2, *s.ref); // note: calls csptr_song_clone() + + c_apply(cvec_song, push_back, &v2, { + csptr_song_new(Song_from("Michael Jackson", "Billie Jean")), + csptr_song_new(Song_from("Rihanna", "Stay")), + }); + + c_foreach (s, cvec_song, v2) + printf("%s - %s: refs %lu\n", s.ref->get->artist.str, s.ref->get->title.str, + *s.ref->use_count); + } +} + +int main() +{ + example3(); +} diff --git a/examples/sview_split.c b/examples/sview_split.c new file mode 100644 index 00000000..3a079583 --- /dev/null +++ b/examples/sview_split.c @@ -0,0 +1,17 @@ +#include +#define c_arg(a) a +int main() +{ + // No memory allocations or string length calculations! + const csview date = c_sv("2021/03/12"); + const csview year = csview_first_token(date, c_sv("/")); + const csview month = csview_next_token(date, c_sv("/"), year); + const csview day = csview_next_token(date, c_sv("/"), month); + + printf(c_svfmt ", " c_svfmt ", " c_svfmt "\n", c_svarg(year), c_svarg(month), c_svarg(day)); + + c_auto (cstr, y, m, d) { + y = cstr_from_v(year), m = cstr_from_v(month), d = cstr_from_v(day); + printf("%s, %s, %s\n", y.str, m.str, d.str); + } +} \ No newline at end of file diff --git a/include/stc/alt/cstr.h b/include/stc/alt/cstr.h index 1dc895ff..76b3a800 100644 --- a/include/stc/alt/cstr.h +++ b/include/stc/alt/cstr.h @@ -32,31 +32,27 @@ #include #include -#ifndef cstr_size_t -typedef size_t cstr_size_t; -#endif -typedef struct { char* data; cstr_size_t size, cap; } cstr_rep_t; -typedef const char cstr_literal_t[]; +typedef struct { char* data; size_t size, cap; } _cstr_rep_t; typedef union { - struct { char* data; cstr_size_t size, ncap; } lon; - struct { char data[sizeof(cstr_rep_t)]; } sso; + struct { char data[sizeof(_cstr_rep_t) - 1], cap_len; } sso; + struct { char* data; size_t size, ncap; } lon; } cstr; /**************************** PRIVATE API **********************************/ enum { SSO_CAP = offsetof(cstr, lon.ncap) + sizeof((cstr){{0}}.lon.ncap) - 1 }; -#define cstr_is_long(s) (bool)((s)->sso.data[SSO_CAP] & 128) +#define cstr_is_long(s) (bool)((s)->sso.cap_len & 128) #define cstr_select_(s, memb) (cstr_is_long(s) ? cstr_l_##memb : cstr_s_##memb) #define cstr_s_cap(s) SSO_CAP -#define cstr_s_size(s) ((cstr_size_t)(SSO_CAP - (s)->sso.data[SSO_CAP])) -#define cstr_s_set_size(s, len) ((s)->sso.data[SSO_CAP] = SSO_CAP - (len), (s)->sso.data[len] = 0) +#define cstr_s_size(s) ((size_t)(SSO_CAP - (s)->sso.cap_len)) +#define cstr_s_set_size(s, len) ((s)->sso.cap_len = SSO_CAP - (len), (s)->sso.data[len] = 0) #define cstr_s_data(s) (s)->sso.data #define cstr_s_end(s) ((s)->sso.data + cstr_s_size(s)) #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define byte_rotl_(x, b) ((x) << (b)*8 | (x) >> (sizeof(x) - (b))*8) +#define byte_rotl_(x, b) ((x) << (b)*8 | (x) >> (sizeof(x) - (b))*8) #define cstr_l_cap(s) (~byte_rotl_((s)->lon.ncap, sizeof((s)->lon.ncap) - 1)) #define cstr_l_set_cap(s, cap) ((s)->lon.ncap = ~byte_rotl_(cap, 1)) #else @@ -69,42 +65,41 @@ enum { SSO_CAP = offsetof(cstr, lon.ncap) + sizeof((cstr){{0}}.lon.ncap) - 1 }; #define cstr_l_end(s) ((s)->lon.data + cstr_l_size(s)) #define cstr_l_del(s) free((s)->lon.data) -STC_API char* cstr_init_(cstr* self, cstr_size_t len, cstr_size_t cap); +STC_API char* cstr_init_(cstr* self, size_t len, size_t cap); STC_API void cstr_internal_move_(cstr* self, size_t pos1, size_t pos2); -STC_INLINE void cstr_set_size_(cstr* self, cstr_size_t len) { +STC_INLINE void cstr_set_size_(cstr* self, size_t len) { cstr_select_(self, set_size(self, len)); } -STC_INLINE cstr_rep_t cstr_rep_(cstr* self) { +STC_INLINE _cstr_rep_t cstr_rep_(cstr* self) { return cstr_is_long(self) - ? c_make(cstr_rep_t){self->lon.data, cstr_l_size(self), cstr_l_cap(self)} - : c_make(cstr_rep_t){self->sso.data, cstr_s_size(self), cstr_s_cap(self)}; + ? c_make(_cstr_rep_t){self->lon.data, cstr_l_size(self), cstr_l_cap(self)} + : c_make(_cstr_rep_t){self->sso.data, cstr_s_size(self), cstr_s_cap(self)}; } /**************************** PUBLIC API **********************************/ -#define cstr_new(lit) cstr_from_n(lit, sizeof((cstr_literal_t){lit}) - 1) -#define cstr_npos (~(cstr_size_t)0 >> 1) +#define cstr_new(literal) cstr_from_n(literal, sizeof((c_strlit){literal}) - 1) +#define cstr_npos (SIZE_MAX >> 1) +#define cstr_null (cstr){.sso = {.cap_len = SSO_CAP}} -STC_API char* cstr_reserve(cstr* self, cstr_size_t cap); +STC_API char* cstr_reserve(cstr* self, size_t cap); STC_API void cstr_shrink_to_fit(cstr* self); -STC_API void cstr_resize(cstr* self, cstr_size_t size, char value); +STC_API void cstr_resize(cstr* self, size_t size, char value); STC_API char* strnstrn(const char *s, const char *needle, size_t slen, size_t nlen); -STC_API cstr_size_t cstr_find_n(cstr s, const char* needle, cstr_size_t pos, cstr_size_t nmax); -STC_API void cstr_assign_n(cstr* self, const char* str, cstr_size_t n); -STC_API void cstr_append_n(cstr* self, const char* str, cstr_size_t n); +STC_API size_t cstr_find_n(cstr s, const char* needle, size_t pos, size_t nmax); +STC_API void cstr_assign_n(cstr* self, const char* str, size_t n); +STC_API void cstr_append_n(cstr* self, const char* str, size_t n); STC_API bool cstr_getdelim(cstr *self, int delim, FILE *fp); STC_API void cstr_erase_n(cstr* self, size_t pos, size_t n); STC_INLINE cstr cstr_init(void) { - cstr s; - cstr_s_set_size(&s, 0); - return s; + return cstr_null; } -STC_INLINE cstr cstr_from_n(const char* str, cstr_size_t n) { +STC_INLINE cstr cstr_from_n(const char* str, size_t n) { cstr s; memcpy(cstr_init_(&s, n, n), str, n); return s; @@ -114,20 +109,20 @@ STC_INLINE cstr cstr_from(const char* str) { return cstr_from_n(str, strlen(str)); } -STC_INLINE cstr cstr_with_size(cstr_size_t size, char value) { +STC_INLINE cstr cstr_with_size(size_t size, char value) { cstr s; memset(cstr_init_(&s, size, size), value, size); return s; } -STC_INLINE cstr cstr_with_capacity(cstr_size_t cap) { +STC_INLINE cstr cstr_with_capacity(size_t cap) { cstr s; cstr_init_(&s, 0, cap); return s; } STC_INLINE cstr cstr_clone(cstr s) { - cstr_rep_t rep = cstr_rep_(&s); + _cstr_rep_t rep = cstr_rep_(&s); return cstr_from_n(rep.data, rep.size); } @@ -151,15 +146,15 @@ STC_INLINE bool cstr_empty(cstr s) { return cstr_select_(&s, size(&s)) == 0; } -STC_INLINE cstr_size_t cstr_size(cstr s) { +STC_INLINE size_t cstr_size(cstr s) { return cstr_select_(&s, size(&s)); } -STC_INLINE cstr_size_t cstr_length(cstr s) { +STC_INLINE size_t cstr_length(cstr s) { return cstr_select_(&s, size(&s)); } -STC_INLINE cstr_size_t cstr_capacity(cstr s) { +STC_INLINE size_t cstr_capacity(cstr s) { return cstr_select_(&s, cap(&s)); } @@ -179,7 +174,7 @@ STC_INLINE int cstr_compare(const cstr* s1, const cstr* s2) { return strcmp(cstr_str(s1), cstr_str(s2)); } -STC_INLINE cstr_size_t cstr_find(cstr s, const char* needle) { +STC_INLINE size_t cstr_find(cstr s, const char* needle) { const char *str = cstr_str(&s), *res = strstr(str, needle); return res ? res - str : cstr_npos; } @@ -207,7 +202,7 @@ STC_INLINE bool cstr_starts_with_s(cstr s, cstr sub) { } STC_INLINE bool cstr_ends_with(cstr s, const char* sub) { - cstr_rep_t rep = cstr_rep_(&s); cstr_size_t n = strlen(sub); + _cstr_rep_t rep = cstr_rep_(&s); size_t n = strlen(sub); return n <= rep.size && memcmp(rep.data + rep.size - n, sub, n) == 0; } @@ -220,7 +215,7 @@ STC_INLINE void cstr_assign(cstr* self, const char* str) { } STC_INLINE void cstr_copy(cstr* self, cstr s) { - cstr_rep_t rep = cstr_rep_(&s); + _cstr_rep_t rep = cstr_rep_(&s); cstr_assign_n(self, rep.data, rep.size); } @@ -229,7 +224,7 @@ STC_INLINE void cstr_append(cstr* self, const char* str) { } STC_INLINE void cstr_append_s(cstr* self, cstr s) { - cstr_rep_t rep = cstr_rep_(&s); + _cstr_rep_t rep = cstr_rep_(&s); cstr_append_n(self, rep.data, rep.size); } @@ -243,7 +238,7 @@ STC_INLINE void cstr_replace(cstr* self, size_t pos, size_t len, const char* str } STC_INLINE void cstr_replace_s(cstr* self, size_t pos, size_t len, cstr s) { - cstr_rep_t rep = cstr_rep_(&s); + _cstr_rep_t rep = cstr_rep_(&s); cstr_replace_n(self, pos, len, rep.data, rep.size); } @@ -256,7 +251,7 @@ STC_INLINE void cstr_insert(cstr* self, size_t pos, const char* str) { } STC_INLINE void cstr_insert_s(cstr* self, size_t pos, cstr s) { - cstr_rep_t rep = cstr_rep_(&s); + _cstr_rep_t rep = cstr_rep_(&s); cstr_replace_n(self, pos, 0, rep.data, rep.size); } @@ -271,15 +266,15 @@ STC_INLINE bool cstr_getline(cstr *self, FILE *fp) { STC_DEF void cstr_internal_move_(cstr* self, size_t pos1, size_t pos2) { if (pos1 == pos2) return; - cstr_rep_t rep = cstr_rep_(self); - cstr_size_t newlen = rep.size + pos2 - pos1; + _cstr_rep_t rep = cstr_rep_(self); + size_t newlen = rep.size + pos2 - pos1; if (newlen > rep.cap) rep.data = cstr_reserve(self, (rep.size*3 >> 1) + pos2 - pos1); memmove(&rep.data[pos2], &rep.data[pos1], rep.size - pos1); cstr_set_size_(self, newlen); } -STC_DEF char* cstr_init_(cstr* self, cstr_size_t len, cstr_size_t cap) { +STC_DEF char* cstr_init_(cstr* self, size_t len, size_t cap) { if (cap > SSO_CAP) { self->lon.data = (char *)malloc(cap + 1); cstr_l_set_size(self, len); @@ -291,7 +286,7 @@ STC_DEF char* cstr_init_(cstr* self, cstr_size_t len, cstr_size_t cap) { } STC_DEF void cstr_shrink_to_fit(cstr* self) { - cstr_rep_t rep = cstr_rep_(self); + _cstr_rep_t rep = cstr_rep_(self); if (rep.size == rep.cap) return; if (rep.size > SSO_CAP) { @@ -304,7 +299,7 @@ STC_DEF void cstr_shrink_to_fit(cstr* self) { } } -STC_DEF char* cstr_reserve(cstr* self, cstr_size_t cap) { +STC_DEF char* cstr_reserve(cstr* self, size_t cap) { if (cstr_is_long(self)) { if (cap > cstr_l_cap(self)) { self->lon.data = (char *)realloc(self->lon.data, cap + 1); @@ -315,7 +310,7 @@ STC_DEF char* cstr_reserve(cstr* self, cstr_size_t cap) { /* from short to long: */ if (cap > cstr_s_cap(self)) { char* data = (char *)malloc(cap + 1); - cstr_size_t len = cstr_s_size(self); + size_t len = cstr_s_size(self); memcpy(data, self->sso.data, len); self->lon.data = data; cstr_l_set_size(self, len); @@ -325,8 +320,8 @@ STC_DEF char* cstr_reserve(cstr* self, cstr_size_t cap) { return self->sso.data; } -STC_DEF void cstr_resize(cstr* self, cstr_size_t size, char value) { - cstr_rep_t rep = cstr_rep_(self); +STC_DEF void cstr_resize(cstr* self, size_t size, char value) { + _cstr_rep_t rep = cstr_rep_(self); if (size > rep.size) { if (size > rep.cap) rep.data = cstr_reserve(self, size); memset(rep.data + rep.size, value, size - rep.size); @@ -345,17 +340,17 @@ STC_DEF char* strnstrn(const char *s, const char *needle, size_t slen, size_t nl return NULL; } -STC_DEF cstr_size_t -cstr_find_n(cstr s, const char* needle, cstr_size_t pos, cstr_size_t nmax) { - cstr_rep_t rep = cstr_rep_(&s); - cstr_size_t nlen = (cstr_size_t) strlen(needle); +STC_DEF size_t +cstr_find_n(cstr s, const char* needle, size_t pos, size_t nmax) { + _cstr_rep_t rep = cstr_rep_(&s); + size_t nlen = (size_t) strlen(needle); if (pos > rep.size) return cstr_npos; char* res = strnstrn(rep.data + pos, needle, rep.size, nmax < nlen ? nmax : nlen); return res ? res - rep.data : cstr_npos; } -STC_DEF void cstr_assign_n(cstr* self, const char* str, cstr_size_t n) { - cstr_rep_t rep = cstr_rep_(self); +STC_DEF void cstr_assign_n(cstr* self, const char* str, size_t n) { + _cstr_rep_t rep = cstr_rep_(self); if (n > rep.cap) { rep.data = (char *)realloc(cstr_is_long(self) ? rep.data : NULL, n + 1); cstr_l_set_cap(self, n); @@ -364,10 +359,10 @@ STC_DEF void cstr_assign_n(cstr* self, const char* str, cstr_size_t n) { cstr_set_size_(self, n); } -STC_DEF void cstr_append_n(cstr* self, const char* str, cstr_size_t n) { - cstr_rep_t rep = cstr_rep_(self); +STC_DEF void cstr_append_n(cstr* self, const char* str, size_t n) { + _cstr_rep_t rep = cstr_rep_(self); if (rep.size + n > rep.cap) { - cstr_size_t off = (cstr_size_t)(str - rep.data); /* handle self append */ + size_t off = (size_t)(str - rep.data); /* handle self append */ rep.data = cstr_reserve(self, (rep.size*3 >> 1) + n); if (off <= rep.size) str = rep.data + off; } @@ -379,8 +374,8 @@ STC_DEF bool cstr_getdelim(cstr *self, int delim, FILE *fp) { int c = fgetc(fp); if (c == EOF) return false; - cstr_size_t pos = 0; - cstr_rep_t rep = cstr_rep_(self); + size_t pos = 0; + _cstr_rep_t rep = cstr_rep_(self); for (;;) { if (c == delim || c == EOF) { cstr_set_size_(self, pos); @@ -396,7 +391,7 @@ STC_DEF bool cstr_getdelim(cstr *self, int delim, FILE *fp) { } STC_DEF void cstr_erase_n(cstr* self, size_t pos, size_t n) { - cstr_rep_t rep = cstr_rep_(self); + _cstr_rep_t rep = cstr_rep_(self); if (n > rep.size - pos) n = rep.size - pos; memmove(&rep.data[pos], &rep.data[pos + n], rep.size - (pos + n)); cstr_set_size_(self, rep.size - n); diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 3d8d3097..a46de3c3 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -37,14 +37,14 @@ typedef char cstr_value; #define cstr_npos (SIZE_MAX >> 1) STC_LIBRARY_ONLY( extern const cstr cstr_null; ) -struct cstr_rep { size_t size, cap; char str[sizeof(size_t)]; }; -#define _cstr_rep(self) c_container_of((self)->str, struct cstr_rep, str) -STC_STATIC_ONLY( static struct cstr_rep _cstr_nullrep = {0, 0, {0}}; +typedef struct { size_t size, cap; char str[sizeof(size_t)]; } _cstr_rep_t; +#define _cstr_rep(self) c_container_of((self)->str, _cstr_rep_t, str) +STC_STATIC_ONLY( static _cstr_rep_t _cstr_nullrep = {0, 0, {0}}; static const cstr cstr_null = {_cstr_nullrep.str}; ) /* optimal memory: based on malloc_usable_size() sequence: 24, 40, 56, ... */ -#define _cstr_opt_mem(cap) ((((offsetof(struct cstr_rep, str) + (cap) + 8)>>4)<<4) + 8) +#define _cstr_opt_mem(cap) ((((offsetof(_cstr_rep_t, str) + (cap) + 8)>>4)<<4) + 8) /* optimal string capacity: 7, 23, 39, ... */ -#define _cstr_opt_cap(cap) (_cstr_opt_mem(cap) - offsetof(struct cstr_rep, str) - 1) +#define _cstr_opt_cap(cap) (_cstr_opt_mem(cap) - offsetof(_cstr_rep_t, str) - 1) STC_API cstr cstr_from_n(const char* str, size_t n); STC_API cstr cstr_from_fmt(const char* fmt, ...); @@ -174,15 +174,15 @@ cstr_ends_with(cstr s, const char* sub) { #if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) -STC_LIBRARY_ONLY( static struct cstr_rep _cstr_nullrep = {0, 0, {0}}; +STC_LIBRARY_ONLY( static _cstr_rep_t _cstr_nullrep = {0, 0, {0}}; const cstr cstr_null = {_cstr_nullrep.str}; ) STC_DEF size_t cstr_reserve(cstr* self, const size_t cap) { - struct cstr_rep* rep = _cstr_rep(self); + _cstr_rep_t* rep = _cstr_rep(self); const size_t oldcap = rep->cap; if (cap > oldcap) { - rep = (struct cstr_rep*) c_realloc(oldcap ? rep : NULL, _cstr_opt_mem(cap)); + rep = (_cstr_rep_t*) c_realloc(oldcap ? rep : NULL, _cstr_opt_mem(cap)); self->str = rep->str; if (oldcap == 0) self->str[rep->size = 0] = '\0'; return (rep->cap = _cstr_opt_cap(cap)); @@ -201,7 +201,7 @@ cstr_resize(cstr* self, const size_t len, const char fill) { STC_DEF cstr cstr_from_n(const char* str, const size_t n) { if (n == 0) return cstr_null; - struct cstr_rep* rep = (struct cstr_rep*) c_malloc(_cstr_opt_mem(n)); + _cstr_rep_t* rep = (_cstr_rep_t*) c_malloc(_cstr_opt_mem(n)); cstr s = {(char *) memcpy(rep->str, str, n)}; s.str[rep->size = n] = '\0'; rep->cap = _cstr_opt_cap(n); -- cgit v1.2.3