From 6270e01be0f105e3512cfde04a7f7d6b67aa8a2e Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 20 May 2021 11:19:37 +0200 Subject: Changed new API: c_sv(literal) => c_sv(cstr), cstr_new(literal) => cstr_lit(literal), csview_new() => csview_lit(). Added c_lit(literal) alias to csview_lit(literal). --- README.md | 2 +- docs/cstr_api.md | 4 +-- docs/csview_api.md | 47 ++++++++++++++++-------------- examples/csmap_erase.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++ examples/mmap.c | 64 ++++++++++++++++++++++++++++++++++++++++ examples/svmap.c | 14 ++++----- stc/csmap.h | 6 ++++ stc/cstr.h | 2 +- stc/csview.h | 14 +++++---- 9 files changed, 194 insertions(+), 38 deletions(-) create mode 100644 examples/csmap_erase.c create mode 100644 examples/mmap.c diff --git a/README.md b/README.md index ba2eaefa..1af744ef 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,7 @@ and non-emplace methods: using_cvec_str(); // vector of string (cstr) ... cvec_str vec = cvec_str_init(); -cstr s = cstr_new("a string literal"); // cstr_new() for literals; no strlen() usage +cstr s = cstr_lit("a string literal"); // cstr_lit() for literals; no strlen() usage c_defer (cvec_str_del(&vec), cstr_del(&s)) // defer the destructors to end of block: { cvec_str_push_back(&vec, cstr_from("Hello")); // construct and add string from const char* diff --git a/docs/cstr_api.md b/docs/cstr_api.md index a2b23a70..094f41e0 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -16,7 +16,7 @@ All cstr definitions and prototypes are available by including a single header f ```c cstr cstr_init(void); // constructor; same as cstr_null. -cstr cstr_new(const char literal_only[]); // cstr from literal; no strlen(). +cstr cstr_lit(const char literal_only[]); // cstr from literal; no strlen(). cstr cstr_from(const char* str); // constructor using strlen() cstr cstr_from_n(const char* str, size_t n); // constructor with specified length cstr cstr_with_capacity(size_t cap); @@ -120,7 +120,7 @@ char* c_strncasestrn(const char* str, const char* needle, size_t slen, si #include int main() { - cstr s0 = cstr_new("Initialization without using strlen()."); + cstr s0 = cstr_lit("Initialization without using strlen()."); printf("%s\nLength: %zu\n\n", s0.str, cstr_size(s0)); cstr s1 = cstr_from("one-nine-three-seven-five."); diff --git a/docs/csview_api.md b/docs/csview_api.md index dfa9a5a6..ba5daed8 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -22,19 +22,22 @@ All csview definitions and prototypes are available by including a single header ## Methods ```c -csview c_sv(const char literal_only[]); // shorthand for csview_new() -csview csview_new(const char literal_only[]); // csview from literal, no strlen() -csview csview_from(const char* str); // construct -csview csview_from_n(const char* str, size_t n); // construct -csview csview_from_s(cstr s); // construct +csview c_lit(const char literal_only[]); // csview from literal, no strlen() +csview c_sv(cstr s); // construct csview from cstr + +csview csview_from(const char* str); // construct from (const char*) +csview csview_from_n(const char* str, size_t n); // construct +csview csview_from_s(cstr s); // same as c_sv() +csview csview_lit(const char literal_only[]); // same as c_lit() + csview csview_remove_prefix(csview sv, size_t n); csview csview_remove_suffix(csview sv, size_t n); csview csview_substr(csview sv, size_t pos, size_t n); - + size_t csview_size(csview sv); size_t csview_length(csview sv); bool csview_empty(csview sv); - + void csview_clear(csview* self); bool csview_equals(csview sv, csview sv2); @@ -81,11 +84,11 @@ uint64_t csview_hash_ref(const csview* x, size_t ignored); ## Constants and macros -| Name | Value | Usage | -|:-----------------|:-------------------|:---------------------------------| -| `csview_null` | same as `c_sv("")` | `sview = csview_null;` | -| `c_sv(literal)` | csview constructor | `sview = c_sv("hello, world");` | -| `csview_PRN(sv)` | printf argument | `printf("%.*s", csview_PRN(sv));`| +| Name | Value | Usage | +|:-----------------|:------------------ -|:---------------------------------| +| `csview_null` | same as `c_lit("")` | `sview = csview_null;` | +| `c_lit(literal)` | csview constructor | `sview = c_lit("hello, world");` | +| `csview_ARG(sv)` | printf argument | `printf("%.*s", csview_ARG(sv));`| ## Container adaptors ``` @@ -121,21 +124,21 @@ using_cvec_sv(); int main() { - csview text = c_sv("The length of this literal is evaluated at compile time and stored in csview text."); + csview text = c_lit("The length of this literal is evaluated at compile time and stored in csview text."); printf("%s\nLength: %zu\n\n", text.str, text.size); // cvec of cstr elements, using csview as "emplace" type c_var (cvec_sv, vec, { // defines vec with 3 cstr elements. - c_sv("Element 1"), // will be converted to cstr. - c_sv("Element 2"), - c_sv("Element 3") + c_lit("Element 1"), // will be converted to cstr. + c_lit("Element 2"), + c_lit("Element 3") }); c_defer (cvec_sv_del(&vec)) // defer destruction to end of block. { // push constructed cstr directly - cvec_sv_push_back(&vec, cstr_new("Second last element")); + cvec_sv_push_back(&vec, cstr_lit("Second last element")); // emplace constructs cstr from a csview - cvec_sv_emplace_back(&vec, c_sv("Last element")); + cvec_sv_emplace_back(&vec, c_lit("Last element")); c_foreach (i, cvec_sv, vec) printf("%s\n", i.ref->str); @@ -143,12 +146,12 @@ int main() c_withvar (cmap_si, map) // defines map and defers destruction. { - cmap_si_emplace(&map, c_sv("hello"), 100); - cmap_si_emplace(&map, c_sv("world"), 200); - cmap_si_emplace(&map, c_sv("gone mad"), 300); + cmap_si_emplace(&map, c_lit("hello"), 100); + cmap_si_emplace(&map, c_lit("world"), 200); + cmap_si_emplace(&map, c_lit("gone mad"), 300); // Efficient lookup: no string allocation or strlen() takes place: - cmap_si_value_t* v = cmap_si_get(&map, c_sv("world")); + cmap_si_value_t* v = cmap_si_get(&map, c_lit("world")); printf("\n%s: %d\n", v->first.str, v->second); } } diff --git a/examples/csmap_erase.c b/examples/csmap_erase.c new file mode 100644 index 00000000..eb3700b1 --- /dev/null +++ b/examples/csmap_erase.c @@ -0,0 +1,79 @@ +// map_erase.c +// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#emplace +#include +#include +#include + +using_csmap_strval(my, int); + +void printmap(csmap_my map) +{ + c_foreach (e, csmap_my, map) + printf(" [%d, %s]", e.ref->first, e.ref->second.str); + printf("\nsize() == %zu\n\n", csmap_my_size(map)); +} + +int main() +{ + c_with (csmap_my m1 = csmap_my_init(), csmap_my_del(&m1)) + { + // Fill in some data to test with, one at a time + csmap_my_emplace(&m1, 1, "A"); + csmap_my_emplace(&m1, 2, "B"); + csmap_my_emplace(&m1, 3, "C"); + csmap_my_emplace(&m1, 4, "D"); + csmap_my_emplace(&m1, 5, "E"); + + puts("Starting data of map m1 is:"); + printmap(m1); + // The 1st member function removes an element at a given position + csmap_my_iter_t it = csmap_my_begin(&m1); csmap_my_next(&it); + csmap_my_erase_at(&m1, it); + puts("After the 2nd element is deleted, the map m1 is:"); + printmap(m1); + } + + c_with (csmap_my m2 = csmap_my_init(), csmap_my_del(&m2)) + { + // Fill in some data to test with, one at a time, using emplace + c_emplace(csmap_my, m2, { + {10, "Bob"}, + {11, "Rob"}, + {12, "Robert"}, + {13, "Bert"}, + {14, "Bobby"} + }); + + puts("Starting data of map m2 is:"); + printmap(m2); + csmap_my_iter_t it1 = csmap_my_fwd(csmap_my_begin(&m2), 1); + csmap_my_iter_t it2 = csmap_my_find(&m2, csmap_my_back(&m2)->first); + // The 2nd member function removes elements + // in the range [First, Last) + csmap_my_erase_range(&m2, it1, it2); + puts("After the middle elements are deleted, the map m2 is:"); + printmap(m2); + } + + c_with (csmap_my m3 = csmap_my_init(), csmap_my_del(&m3)) + { + // Fill in some data to test with, one at a time, using emplace + csmap_my_emplace(&m3, 1, "red"); + csmap_my_emplace(&m3, 2, "yellow"); + csmap_my_emplace(&m3, 3, "blue"); + csmap_my_emplace(&m3, 4, "green"); + csmap_my_emplace(&m3, 5, "orange"); + csmap_my_emplace(&m3, 5, "purple"); + csmap_my_emplace(&m3, 5, "pink"); + + puts("Starting data of map m3 is:"); + printmap(m3); + // The 3rd member function removes elements with a given Key + size_t count = csmap_my_erase(&m3, 2); + // The 3rd member function also returns the number of elements removed + printf("The number of elements removed from m3 is: %zu\n", count); + puts("After the element with a key of 2 is deleted, the map m3 is:"); + printmap(m3); + } + +} \ No newline at end of file diff --git a/examples/mmap.c b/examples/mmap.c new file mode 100644 index 00000000..c925db39 --- /dev/null +++ b/examples/mmap.c @@ -0,0 +1,64 @@ +#include +#include +#include + +// This implements the multimap c++ example found at: +// https://en.cppreference.com/w/cpp/container/multimap/insert + +// Map of int => clist_str. Note the negation of c_default_compare +using_clist_str(); +using_csmap(m, int, clist_str, -c_default_compare, clist_str_del); + +void print(const csmap_m mmap) +{ + c_foreach (e, csmap_m, mmap) { + c_foreach (s, clist_str, e.ref->second) + printf("{%d,%s} ", e.ref->first, s.ref->str); + } + puts(""); +} + +void insert(csmap_m* mmap, int key, const char* str) +{ + clist_str *list = &csmap_m_insert(mmap, key, clist_str_init()).ref->second; + clist_str_emplace_back(list, str); +} + +int main() +{ + c_with (csmap_m mmap = csmap_m_init(), csmap_m_del(&mmap)) + { + // list-initialize + struct {int i; const char* s;} vals[] = {{2, "foo"}, {2, "bar"}, {3, "baz"}, {1, "abc"}, {5, "def"}}; + c_forrange (i, c_arraylen(vals)) insert(&mmap, vals[i].i, vals[i].s); + + // insert using value_type + insert(&mmap, 5, "pqr"); + print(mmap); + + // insert using make_pair + insert(&mmap, 6, "uvw"); + print(mmap); + + insert(&mmap, 7, "xyz"); + print(mmap); + + // insert using initialization_list + insert(&mmap, 5, "one"); + insert(&mmap, 5, "two"); + print(mmap); + + // erase all entries with key 5 + csmap_m_erase(&mmap, 5); + print(mmap); + + // find and erase a specific entry + clist_str_iter_t pos; + c_foreach (e, csmap_m, mmap) + if ((pos = clist_str_find(&e.ref->second, "bar")).ref) { + clist_str_erase(&e.ref->second, pos); + break; + } + print(mmap); + } +} diff --git a/examples/svmap.c b/examples/svmap.c index 9fd89755..c45ff1ae 100644 --- a/examples/svmap.c +++ b/examples/svmap.c @@ -6,25 +6,25 @@ using_cmap_svkey(si, int); int main() { - csview fox = c_sv("The quick brown fox jumps over the lazy dog."); + csview fox = c_lit("The quick brown fox jumps over the lazy dog."); printf("\"%s\", length=%zu\n", fox.str, fox.size); c_withvar (cmap_si, frequencies) { // Non-emplace: cstr element API - cmap_si_insert(&frequencies, cstr_new("thousand"), 1000); - cmap_si_insert_or_assign(&frequencies, cstr_new("thousand"), 2000); // update; same as put() - cmap_si_insert(&frequencies, cstr_new("thousand"), 3000); // ignored + cmap_si_insert(&frequencies, cstr_lit("thousand"), 1000); + cmap_si_insert_or_assign(&frequencies, cstr_lit("thousand"), 2000); // update; same as put() + cmap_si_insert(&frequencies, cstr_lit("thousand"), 3000); // ignored // Emplace: csview element API const char* key = "hundred"; - cmap_si_emplace(&frequencies, c_sv("hundred"), 300); // c_sv() shorthand for csview_new() + cmap_si_emplace(&frequencies, c_lit("hundred"), 300); // c_lit() shorthand for csview_lit() cmap_si_emplace(&frequencies, csview_from_n(key, 4), 400); // insert "hund" cmap_si_emplace_or_assign(&frequencies, csview_from(key), 500); // update - cmap_si_emplace(&frequencies, c_sv("hundred"), 600); // ignored, already inserted + cmap_si_emplace(&frequencies, c_lit("hundred"), 600); // ignored, already inserted // Lookup always uses "raw" type API, i.e. csview here. - printf("at(\"hundred\"): %d\n", *cmap_si_at(&frequencies, c_sv("hundred"))); + printf("at(\"hundred\"): %d\n", *cmap_si_at(&frequencies, c_lit("hundred"))); c_foreach (i, cmap_si, frequencies) printf("%s: %d\n", i.ref->first.str, i.ref->second); diff --git a/stc/csmap.h b/stc/csmap.h index 3c6bf10e..4a57ee33 100644 --- a/stc/csmap.h +++ b/stc/csmap.h @@ -288,6 +288,12 @@ struct csmap_rep { size_t root, disp, head, size, cap; void* nodes[]; }; CX##_end(const CX* self) {\ return c_make(CX##_iter_t){.ref = NULL}; \ } \ +\ + STC_INLINE CX##_iter_t \ + CX##_fwd(CX##_iter_t it, size_t n) { \ + while (n-- && it.ref) CX##_next(&it); \ + return it; \ + } \ \ _c_implement_aatree(CX, C, Key, Mapped, keyCompareRaw, \ mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \ diff --git a/stc/cstr.h b/stc/cstr.h index 4e70189a..131a3d78 100644 --- a/stc/cstr.h +++ b/stc/cstr.h @@ -66,7 +66,7 @@ STC_API char* c_strnstrn(const char* s, const char* needle, size_t sle STC_API char* c_strncasestrn(const char* s, const char* needle, size_t slen, size_t nmax); STC_INLINE cstr cstr_init() { return cstr_null; } -#define cstr_new(literal) \ +#define cstr_lit(literal) \ cstr_from_n(literal, sizeof c_make(strlit_t){literal} - 1) STC_INLINE cstr cstr_from(const char* str) { return cstr_from_n(str, strlen(str)); } diff --git a/stc/csview.h b/stc/csview.h index ccd63770..19f89983 100644 --- a/stc/csview.h +++ b/stc/csview.h @@ -29,18 +29,22 @@ typedef struct { const char* str; size_t size; } csview; typedef struct { const char *ref; } csview_iter_t; typedef char csview_value_t; #define csview_null c_make(csview){"", 0} -#define csview_PRN(sv) (int)(sv).size, (sv).str +#define csview_ARG(sv) (int)(sv).size, (sv).str -#define csview_new(literal) \ - c_make(csview){literal, sizeof c_make(strlit_t){literal} - 1} -#define c_sv(literal) \ - csview_new(literal) +#define c_lit(literal) \ + csview_lit(literal) +STC_INLINE csview c_sv(cstr s) + { return c_make(csview){s.str, _cstr_rep(&s)->size}; } STC_INLINE csview csview_from(const char* str) { return c_make(csview){str, strlen(str)}; } STC_INLINE csview csview_from_n(const char* str, size_t n) { return c_make(csview){str, n}; } + +#define csview_lit(literal) \ + c_make(csview){literal, sizeof c_make(strlit_t){literal} - 1} STC_INLINE csview csview_from_s(cstr s) { return c_make(csview){s.str, _cstr_rep(&s)->size}; } + STC_INLINE csview csview_remove_prefix(csview sv, size_t n) { sv.str += n, sv.size -= n; return sv; } STC_INLINE csview csview_remove_suffix(csview sv, size_t n) -- cgit v1.2.3