From eb85069b669e754836b9d4587ba03d3af1a5e975 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sun, 26 Mar 2023 00:27:45 +0100 Subject: development branch for 4.2 Removed uses of c_auto and c_with in documentation examples and code examples. Still using c_defer a few places. Renamed c11/fmt.h to c11/print.h. Some additions in ccommon.h, e.g. c_const_cast(T, x). Improved docs. --- misc/examples/functor.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'misc/examples/functor.c') diff --git a/misc/examples/functor.c b/misc/examples/functor.c index 6d42c4f8..8952c710 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -51,18 +51,17 @@ int main() IPQueue q1 = {ipque_init(), int_less}; // Max priority queue IPQueue minq1 = {ipque_init(), int_greater}; // Min priority queue IPQueue q5 = {ipque_init(), int_lambda}; // Using lambda to compare elements. - c_defer (ipque_drop(&q1.Q), ipque_drop(&minq1.Q), ipque_drop(&q5.Q)) - { - c_forrange (i, n) - ipque_push(&q1.Q, data[i]); - print_queue("q1", q1); + c_forrange (i, n) + ipque_push(&q1.Q, data[i]); + print_queue("q1", q1); - c_forrange (i, n) - ipque_push(&minq1.Q, data[i]); - print_queue("minq1", minq1); + c_forrange (i, n) + ipque_push(&minq1.Q, data[i]); + print_queue("minq1", minq1); - c_forrange (i, n) - ipque_push(&q5.Q, data[i]); - print_queue("q5", q5); - } + c_forrange (i, n) + ipque_push(&q5.Q, data[i]); + print_queue("q5", q5); + + c_drop(ipque, &q1.Q, &minq1.Q, &q5.Q); } -- cgit v1.2.3 From e35036deef4fc8f17cc9221e2e666dfdb832ba78 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 27 Mar 2023 19:57:09 +0200 Subject: More RAII cleanup in examples. Also removed gauss1.c and new_deq.c --- misc/benchmarks/various/prng_bench.cpp | 2 +- misc/examples/arc_demo.c | 2 +- misc/examples/astar.c | 2 +- misc/examples/books.c | 2 +- misc/examples/coread.c | 13 +++--- misc/examples/forfilter.c | 39 ++++++++--------- misc/examples/forloops.c | 23 ++++------ misc/examples/functor.c | 6 ++- misc/examples/gauss1.c | 58 ------------------------- misc/examples/gauss2.c | 12 +++--- misc/examples/inits.c | 2 +- misc/examples/mapmap.c | 15 +------ misc/examples/multimap.c | 2 +- misc/examples/new_deq.c | 46 -------------------- misc/examples/prime.c | 5 ++- misc/examples/printspan.c | 52 +++++++++++------------ misc/examples/rawptr_elements.c | 78 +++++++++++++++++----------------- misc/examples/regex2.c | 2 +- misc/examples/replace.c | 35 +++++++-------- misc/examples/shape.c | 38 ++++++++--------- misc/examples/sidebyside.cpp | 11 +++-- misc/examples/splitstr.c | 1 + 22 files changed, 164 insertions(+), 282 deletions(-) delete mode 100644 misc/examples/gauss1.c delete mode 100644 misc/examples/new_deq.c (limited to 'misc/examples/functor.c') diff --git a/misc/benchmarks/various/prng_bench.cpp b/misc/benchmarks/various/prng_bench.cpp index 6f4e0e47..be07f799 100644 --- a/misc/benchmarks/various/prng_bench.cpp +++ b/misc/benchmarks/various/prng_bench.cpp @@ -122,7 +122,7 @@ using namespace std; int main(void) { - enum {N = 2000000000}; + enum {N = 500000000}; uint16_t* recipient = new uint16_t[N]; static stc64_t rng; init_state(rng.state, 12345123); diff --git a/misc/examples/arc_demo.c b/misc/examples/arc_demo.c index 88555177..2339adbb 100644 --- a/misc/examples/arc_demo.c +++ b/misc/examples/arc_demo.c @@ -25,7 +25,7 @@ int main() const int years[] = {2021, 2012, 2022, 2015}; cvec_Arc vec = {0}; - c_forrange (i, c_ARRAYLEN(years)) + c_forrange (i, c_arraylen(years)) cvec_Arc_push(&vec, Arc_from(years[i])); printf("vec:"); diff --git a/misc/examples/astar.c b/misc/examples/astar.c index 6c850b08..7dd12d50 100644 --- a/misc/examples/astar.c +++ b/misc/examples/astar.c @@ -103,7 +103,7 @@ astar(cstr* maze, int width) { -1, 0, 0, width }, /* ~ ~ ~ ~ ~ ~ ~ */ { 1, 0, 0, width }, { -1, -1, 0, width }, { 0, -1, 0, width }, { 1, -1, 0, width }, }; - for (size_t i = 0; i < c_ARRAYLEN(deltas); i++) + for (size_t i = 0; i < c_arraylen(deltas); i++) { point delta = deltas[i]; point next = point_init(current.x + delta.x, current.y + delta.y, width); diff --git a/misc/examples/books.c b/misc/examples/books.c index 40fe877f..a62769b0 100644 --- a/misc/examples/books.c +++ b/misc/examples/books.c @@ -41,7 +41,7 @@ int main() // 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)) { + c_forrange (i, c_arraylen(to_find)) { const cmap_str_value* b = cmap_str_get(&book_reviews, to_find[i]); if (b) printf("%s: %s\n", cstr_str(&b->first), cstr_str(&b->second)); diff --git a/misc/examples/coread.c b/misc/examples/coread.c index c5f85e08..0a7f4816 100644 --- a/misc/examples/coread.c +++ b/misc/examples/coread.c @@ -20,17 +20,20 @@ bool file_nextline(struct file_nextline* U) while (cstr_getline(&U->line, U->fp)) cco_yield(true); - cco_final: // required label. + cco_final: // this label is required. printf("finish\n"); cstr_drop(&U->line); fclose(U->fp); cco_end(false); } -int main(void) { - struct file_nextline z = {__FILE__}; +int main(void) +{ + struct file_nextline it = {__FILE__}; int n = 0; - while (file_nextline(&z)) { - printf("%3d %s\n", ++n, cstr_str(&z.line)); + while (file_nextline(&it)) + { + printf("%3d %s\n", ++n, cstr_str(&it.line)); + //if (n == 10) cco_stop(&it); } } diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c index fdf8be6f..0d72bd1b 100644 --- a/misc/examples/forfilter.c +++ b/misc/examples/forfilter.c @@ -28,17 +28,15 @@ void demo1(void) printf(" %d", *i.ref); puts(""); - int res, sum = 0; + int sum = 0; c_forfilter (i, IVec, vec, - c_flt_skipwhile(i, *i.ref != 80) && - c_flt_skip(i, 1) && - c_flt_skipwhile(i, *i.ref != 80) && - flt_isEven(i) && - flt_skipValue(i, 80) && - c_flt_take(i, 5) // short-circuit + c_flt_skipwhile(i, *i.ref != 80) && + c_flt_skip(i, 1) && + flt_isEven(i) && + flt_skipValue(i, 80) && + c_flt_take(i, 5) // short-circuit ){ - sum += res = flt_square(i); - printf(" %d", res); + sum += flt_square(i); } printf("\n sum: %d\n", sum); @@ -62,11 +60,13 @@ void demo2(void) { IVec vector = {0}; - c_forfilter (x, crange, crange_obj(INT64_MAX), - c_flt_skipwhile(x, *x.ref != 11) && - *x.ref % 2 != 0 && - c_flt_take(x, 5)) + c_forfilter (x, crange, crange_object(INT64_MAX), + c_flt_skipwhile(x, *x.ref != 11) && + (*x.ref % 2) != 0 && + c_flt_take(x, 5) + ){ IVec_push(&vector, (int)(*x.ref * *x.ref)); + } c_foreach (x, IVec, vector) printf(" %d", *x.ref); @@ -130,13 +130,14 @@ void demo5(void) crange R = crange_make(1963, INT32_MAX); c_forfilter (i, crange, R, - c_flt_skip(i,15) && - c_flt_skipwhile(i, flt_mid_decade(i)) && - c_flt_skip(i,30) && - flt_even(i) && - c_flt_take(i,5)) + c_flt_skip(i,15) && + c_flt_skipwhile(i, flt_mid_decade(i)) && + c_flt_skip(i,30) && + flt_even(i) && + c_flt_take(i,5) + ){ printf(" %lld", *i.ref); - + } puts(""); } diff --git a/misc/examples/forloops.c b/misc/examples/forloops.c index 54b49485..82126456 100644 --- a/misc/examples/forloops.c +++ b/misc/examples/forloops.c @@ -52,24 +52,17 @@ int main() puts("\n\nc_forpair:"); c_forpair (key, val, IMap, map) printf(" (%d %d)", *_.key, *_.val); - - puts("\n\nc_forfilter 1:"); - c_forfilter (i, IVec, vec, c_flt_take(i, 3)) - printf(" %d", *i.ref); - + #define isOdd(i) (*i.ref & 1) - puts("\n\nc_forfilter 2:"); - c_forfilter (i, IVec, vec, - c_flt_skipwhile(i, *i.ref != 65) && - c_flt_takewhile(i, *i.ref != 280) && - c_flt_skipwhile(i, isOdd(i)) && - isOdd(i) && - c_flt_skip(i, 2) && - c_flt_take(i, 2)) + puts("\n\nc_forfilter:"); + c_forfilter (i, IVec, vec, + isOdd(i) && + c_flt_skip(i, 4) && + c_flt_take(i, 4) + ){ printf(" %d", *i.ref); - puts(""); - // 189 + } IVec_drop(&vec); IMap_drop(&map); diff --git a/misc/examples/functor.c b/misc/examples/functor.c index 8952c710..f37e41d5 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -43,14 +43,16 @@ static bool int_lambda(const int* x, const int* y) { return (*x ^ 1) < (*y ^ 1); int main() { - const int data[] = {1,8,5,6,3,4,0,9,7,2}, n = c_ARRAYLEN(data); + const int data[] = {1,8,5,6,3,4,0,9,7,2}, n = c_arraylen(data); printf("data: \t"); - c_forrange (i, n) printf("%d ", data[i]); + c_forrange (i, n) + printf("%d ", data[i]); puts(""); IPQueue q1 = {ipque_init(), int_less}; // Max priority queue IPQueue minq1 = {ipque_init(), int_greater}; // Min priority queue IPQueue q5 = {ipque_init(), int_lambda}; // Using lambda to compare elements. + c_forrange (i, n) ipque_push(&q1.Q, data[i]); print_queue("q1", q1); diff --git a/misc/examples/gauss1.c b/misc/examples/gauss1.c deleted file mode 100644 index 67871aa9..00000000 --- a/misc/examples/gauss1.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include - -#include -#include - -// Declare int -> int hashmap. Uses typetag 'ii' for ints. -#define i_key int -#define i_val int -#define i_tag ii -#include - -// Declare int vector with entries from the cmap. -#define i_val cmap_ii_value -#define i_less(x, y) x->first < y->first -#define i_tag ii -#include - -int main() -{ - enum {N = 10000000}; - const double Mean = -12.0, StdDev = 6.0, Scale = 74; - - printf("Demo of gaussian / normal distribution of %d random samples\n", N); - - // Setup random engine with normal distribution. - uint64_t seed = (uint64_t)time(NULL); - stc64_t rng = stc64_new(seed); - stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev); - - // Create and init histogram vec and map with defered destructors: - cvec_ii histvec = {0}; - cmap_ii histmap = {0}; - - c_forrange (N) { - int index = (int)round( stc64_normalf(&rng, &dist) ); - cmap_ii_insert(&histmap, index, 0).ref->second += 1; - } - - // Transfer map to vec and sort it by map keys. - c_foreach (i, cmap_ii, histmap) - cvec_ii_push(&histvec, (cmap_ii_value){i.ref->first, i.ref->second}); - - cvec_ii_sort(&histvec); - - // Print the gaussian bar chart - c_foreach (i, cvec_ii, histvec) { - int n = (int)(i.ref->second * StdDev * Scale * 2.5 / (double)N); - if (n > 0) { - printf("%4d ", i.ref->first); - c_forrange (n) printf("*"); - puts(""); - } - } - - cvec_ii_drop(&histvec); - cmap_ii_drop(&histmap); -} diff --git a/misc/examples/gauss2.c b/misc/examples/gauss2.c index 79397f0c..be514c12 100644 --- a/misc/examples/gauss2.c +++ b/misc/examples/gauss2.c @@ -6,7 +6,7 @@ // Declare int -> int sorted map. #define i_key int -#define i_val size_t +#define i_val int #include int main() @@ -22,16 +22,16 @@ int main() stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev); // Create and init histogram map with defered destruct - csmap_int mhist = {0}; + csmap_int hist = {0}; cstr bar = {0}; c_forrange (N) { - int index = (int) round( stc64_normalf(&rng, &dist) ); - csmap_int_insert(&mhist, index, 0).ref->second += 1; + int index = (int)round( stc64_normalf(&rng, &dist) ); + csmap_int_insert(&hist, index, 0).ref->second += 1; } // Print the gaussian bar chart - c_forpair (index, count, csmap_int, mhist) { + c_forpair (index, count, csmap_int, hist) { int n = (int)((float)*_.count * StdDev * Scale * 2.5f / (float)N); if (n > 0) { cstr_resize(&bar, n, '*'); @@ -39,5 +39,5 @@ int main() } } cstr_drop(&bar); - csmap_int_drop(&mhist); + csmap_int_drop(&hist); } diff --git a/misc/examples/inits.c b/misc/examples/inits.c index 7530dd08..81bcdd3e 100644 --- a/misc/examples/inits.c +++ b/misc/examples/inits.c @@ -40,7 +40,7 @@ int main(void) const float nums[] = {4.0f, 2.0f, 5.0f, 3.0f, 1.0f}; // PRIORITY QUEUE - c_forrange (i, c_ARRAYLEN(nums)) + c_forrange (i, c_arraylen(nums)) cpque_f_push(&floats, nums[i]); puts("\npop and show high priorites first:"); diff --git a/misc/examples/mapmap.c b/misc/examples/mapmap.c index 8fc307ab..668da5de 100644 --- a/misc/examples/mapmap.c +++ b/misc/examples/mapmap.c @@ -7,24 +7,13 @@ #define i_key_str // name #define i_val_str // email #define i_keydrop(p) (printf("kdrop: %s\n", cstr_str(p)), cstr_drop(p)) // override -#include +#include // Departments: std::map #define i_type Departments #define i_key_str // dep. name #define i_valclass People -// i_key_str implies: -// #define i_tag str -// #define i_key cstr -// #define i_keyclone cstr_clone -// #define i_keydrop cstr_drop -// #define i_cmp cstr_cmp -// #define i_hash cstr_hash -// i_valclass implies: -// #define i_val People -// #define i_valclone People_clone -// #define i_valdrop People_drop -#include +#include void add(Departments* deps, const char* name, const char* email, const char* dep) diff --git a/misc/examples/multimap.c b/misc/examples/multimap.c index 9c37db6c..d8981a81 100644 --- a/misc/examples/multimap.c +++ b/misc/examples/multimap.c @@ -71,7 +71,7 @@ int main() csmap_OL multimap = {0}; const clist_OL empty = clist_OL_init(); - for (size_t i = 0; i < c_ARRAYLEN(ol_data); ++i) + for (size_t i = 0; i < c_arraylen(ol_data); ++i) { struct OlympicsData* d = &ol_data[i]; OlympicLoc loc = {.year = d->year, diff --git a/misc/examples/new_deq.c b/misc/examples/new_deq.c deleted file mode 100644 index 467fd4e5..00000000 --- a/misc/examples/new_deq.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -forward_cdeq(cdeq_i32, int); -forward_cdeq(cdeq_pnt, struct Point); - -struct MyStruct { - cdeq_i32 intvec; - cdeq_pnt pntvec; -} typedef MyStruct; - - -#define i_val int -#define i_opt c_is_forward -#define i_tag i32 -#include - -struct Point { int x, y; } typedef Point; -int point_cmp(const Point* a, const Point* b) { - int c = a->x - b->x; - return c ? c : a->y - b->y; -} - -#define i_val Point -#define i_cmp point_cmp -#define i_opt c_is_forward -#define i_tag pnt -#include - - -int main() -{ - cdeq_pnt pvec = {0}; - - cdeq_pnt_push_back(&pvec, (Point){42, 14}); - cdeq_pnt_push_back(&pvec, (Point){32, 94}); - cdeq_pnt_push_front(&pvec, (Point){62, 81}); - - cdeq_pnt_sort(&pvec); - - c_foreach (i, cdeq_pnt, pvec) - printf(" (%d %d)", i.ref->x, i.ref->y); - puts(""); - - cdeq_pnt_drop(&pvec); -} diff --git a/misc/examples/prime.c b/misc/examples/prime.c index 18bf3490..9ffb2f53 100644 --- a/misc/examples/prime.c +++ b/misc/examples/prime.c @@ -44,8 +44,9 @@ int main(void) puts("Show the last 50 primes using a temporary crange generator:"); crange R = crange_make(n - 1, 0, -2); c_forfilter (i, crange, R, - cbits_test(&primes, *i.ref>>1) && - c_flt_take(i, 50)) { + cbits_test(&primes, *i.ref>>1) && + c_flt_take(i, 50) + ){ printf("%lld ", *i.ref); if (c_flt_last(i) % 10 == 0) puts(""); } diff --git a/misc/examples/printspan.c b/misc/examples/printspan.c index 127b07b9..7459ac77 100644 --- a/misc/examples/printspan.c +++ b/misc/examples/printspan.c @@ -16,7 +16,8 @@ using_cspan(intspan, int, 1); void printMe(intspan container) { printf("%d:", (int)cspan_size(&container)); - c_foreach (e, intspan, container) printf(" %d", *e.ref); + c_foreach (e, intspan, container) + printf(" %d", *e.ref); puts(""); } @@ -31,31 +32,26 @@ int main() intspan sp2 = cspan_from_array(arr); printMe( (intspan)cspan_subspan(&sp2, 1, 4) ); - cvec_int vec; - cstack_int stk; - cdeq_int deq; - csset_str set; - c_defer( - cvec_int_drop(&vec), - cstack_int_drop(&stk), - cdeq_int_drop(&deq), - csset_str_drop(&set) - ) { - vec = c_make(cvec_int, {1, 2, 3, 4, 5}); - printMe( (intspan)cspan_from(&vec) ); - - printMe( sp2 ); - - stk = c_make(cstack_int, {1, 2, 3, 4, 5, 6, 7}); - printMe( (intspan)cspan_from(&stk) ); - - deq = c_make(cdeq_int, {1, 2, 3, 4, 5, 6, 7, 8}); - printMe( (intspan)cspan_from(&deq) ); - - set = c_make(csset_str, {"5", "7", "4", "3", "8", "2", "1", "9", "6"}); - printf("%d:", (int)csset_str_size(&set)); - c_foreach (e, csset_str, set) - printf(" %s", cstr_str(e.ref)); - puts(""); - } + cvec_int vec = c_make(cvec_int, {1, 2, 3, 4, 5}); + printMe( (intspan)cspan_from(&vec) ); + + printMe( sp2 ); + + cstack_int stk = c_make(cstack_int, {1, 2, 3, 4, 5, 6, 7}); + printMe( (intspan)cspan_from(&stk) ); + + cdeq_int deq = c_make(cdeq_int, {1, 2, 3, 4, 5, 6, 7, 8}); + printMe( (intspan)cspan_from(&deq) ); + + csset_str set = c_make(csset_str, {"5", "7", "4", "3", "8", "2", "1", "9", "6"}); + printf("%d:", (int)csset_str_size(&set)); + c_foreach (e, csset_str, set) + printf(" %s", cstr_str(e.ref)); + puts(""); + + // cleanup + cvec_int_drop(&vec); + cstack_int_drop(&stk); + cdeq_int_drop(&deq); + csset_str_drop(&set); } diff --git a/misc/examples/rawptr_elements.c b/misc/examples/rawptr_elements.c index f46a7f5e..01bcdc44 100644 --- a/misc/examples/rawptr_elements.c +++ b/misc/examples/rawptr_elements.c @@ -2,58 +2,58 @@ #include #include -// Map of cstr => int64 pointers -typedef int64_t inttype; -// Do it without cbox: +// Create cmap of cstr => long* #define i_type SIPtrMap #define i_key_str -#define i_val inttype* -#define i_valraw inttype -#define i_valfrom(raw) c_new(inttype, raw) +#define i_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(inttype, *x) +#define i_valclone(x) c_new(long, *x) #define i_valdrop(x) c_free(*x) #include -// With cbox: +// Alternatively, using cbox: #define i_type IBox -#define i_val int -#include // +#define i_val long +#include // unique_ptr alike. +// cmap of cstr => IBox #define i_type SIBoxMap #define i_key_str -#define i_valboxed IBox +#define i_valboxed IBox // i_valboxed: use properties from IBox automatically #include int main() { - SIPtrMap map = {0}, m1; - SIBoxMap m2 = {0}; - c_defer( - SIPtrMap_drop(&map), - SIPtrMap_drop(&m1), - SIBoxMap_drop(&m2) - ){ - printf("\nMap with pointer elements:\n"); - SIPtrMap_insert(&map, cstr_from("testing"), c_new(inttype, 1)); - SIPtrMap_insert(&map, cstr_from("done"), c_new(inttype, 2)); - - // Emplace: implicit key, val construction: - SIPtrMap_emplace(&map, "hello", 3); - SIPtrMap_emplace(&map, "goodbye", 4); - - m1 = SIPtrMap_clone(map); - - c_forpair (name, number, SIPtrMap, m1) - printf("%s: %" PRId64 "\n", cstr_str(_.name), **_.number); - - - puts("\nIBox map:"); - SIBoxMap_insert(&m2, cstr_from("Hello"), IBox_make(123)); - SIBoxMap_emplace(&m2, "World", 999); - c_forpair (name, number, SIBoxMap, m2) - printf("%s: %d\n", cstr_str(_.name), *_.number->get); - puts(""); - } + // 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); } diff --git a/misc/examples/regex2.c b/misc/examples/regex2.c index 883dd112..3133f7c2 100644 --- a/misc/examples/regex2.c +++ b/misc/examples/regex2.c @@ -16,7 +16,7 @@ int main() }; cregex re = {0}; - c_forrange (i, c_ARRAYLEN(s)) + c_forrange (i, c_arraylen(s)) { int res = cregex_compile(&re, s[i].pattern); if (res < 0) { diff --git a/misc/examples/replace.c b/misc/examples/replace.c index c22c71ff..cf5b45cb 100644 --- a/misc/examples/replace.c +++ b/misc/examples/replace.c @@ -8,27 +8,28 @@ int main () // replace signatures used in the same order as described above: - // Ustring positions: 0123456789*123456789*12345 - cstr s = cstr_from(base); // "this is a test string." + // Ustring positions: 0123456789*123456789*12345 + cstr s = cstr_from(base); // "this is a test string." cstr m = cstr_clone(s); - c_defer (cstr_drop(&s), cstr_drop(&m)) { - cstr_append(&m, cstr_str(&m)); - cstr_append(&m, cstr_str(&m)); - printf("%s\n", cstr_str(&m)); - cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) - printf("(1) %s\n", cstr_str(&s)); + cstr_append(&m, cstr_str(&m)); + cstr_append(&m, cstr_str(&m)); + printf("%s\n", cstr_str(&m)); - cstr_replace_at_sv(&s, 19, 6, c_sv(s3+7, 6)); // "this is an example phrase." (2) - printf("(2) %s\n", cstr_str(&s)); + cstr_replace_at(&s, 9, 5, s2); // "this is an example string." (1) + printf("(1) %s\n", cstr_str(&s)); - cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3) - printf("(3) %s\n", cstr_str(&s)); + cstr_replace_at_sv(&s, 19, 6, c_sv(s3+7, 6)); // "this is an example phrase." (2) + printf("(2) %s\n", cstr_str(&s)); - cstr_replace_at_sv(&s, 8, 6, c_sv("a shorty", 7)); // "this is a short phrase." (4) - printf("(4) %s\n", cstr_str(&s)); + cstr_replace_at(&s, 8, 10, "just a"); // "this is just a phrase." (3) + printf("(3) %s\n", cstr_str(&s)); - cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) - printf("(5) %s\n", cstr_str(&s)); - } + cstr_replace_at_sv(&s, 8, 6, c_sv("a shorty", 7)); // "this is a short phrase." (4) + printf("(4) %s\n", cstr_str(&s)); + + cstr_replace_at(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) + printf("(5) %s\n", cstr_str(&s)); + + c_drop(cstr, &s, &m); } diff --git a/misc/examples/shape.c b/misc/examples/shape.c index 2aabdcc2..e24f7fd7 100644 --- a/misc/examples/shape.c +++ b/misc/examples/shape.c @@ -139,23 +139,23 @@ void testShape(const Shape* shape) int main(void) { Shapes shapes = {0}; - c_defer (Shapes_drop(&shapes)) - { - Triangle* tri1 = c_new(Triangle, Triangle_from((Point){5, 7}, (Point){12, 7}, (Point){12, 20})); - Polygon* pol1 = c_new(Polygon, Polygon_init()); - Polygon* pol2 = c_new(Polygon, Polygon_init()); - - c_forlist (i, Point, {{50, 72}, {123, 73}, {127, 201}, {828, 333}}) - Polygon_addPoint(pol1, *i.ref); - - c_forlist (i, Point, {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}) - Polygon_addPoint(pol2, *i.ref); - - Shapes_push(&shapes, &tri1->shape); - Shapes_push(&shapes, &pol1->shape); - Shapes_push(&shapes, &pol2->shape); - - c_foreach (i, Shapes, shapes) - testShape(*i.ref); - } + + Triangle* tri1 = c_new(Triangle, Triangle_from((Point){5, 7}, (Point){12, 7}, (Point){12, 20})); + Polygon* pol1 = c_new(Polygon, Polygon_init()); + Polygon* pol2 = c_new(Polygon, Polygon_init()); + + c_forlist (i, Point, {{50, 72}, {123, 73}, {127, 201}, {828, 333}}) + Polygon_addPoint(pol1, *i.ref); + + c_forlist (i, Point, {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}) + Polygon_addPoint(pol2, *i.ref); + + Shapes_push(&shapes, &tri1->shape); + Shapes_push(&shapes, &pol1->shape); + Shapes_push(&shapes, &pol2->shape); + + c_foreach (i, Shapes, shapes) + testShape(*i.ref); + + Shapes_drop(&shapes); } diff --git a/misc/examples/sidebyside.cpp b/misc/examples/sidebyside.cpp index a817b5a5..a7c1008c 100644 --- a/misc/examples/sidebyside.cpp +++ b/misc/examples/sidebyside.cpp @@ -24,9 +24,8 @@ int main() { std::cout << i.first << ", " << i.second << std::endl; std::cout << std::endl; } - - IIMap hist = {0}; - c_defer (IIMap_drop(&hist)) { + { + IIMap hist = {0}; IIMap_insert(&hist, 12, 100).ref->second += 1; IIMap_insert(&hist, 13, 100).ref->second += 1; IIMap_insert(&hist, 12, 100).ref->second += 1; @@ -34,6 +33,7 @@ int main() { c_foreach (i, IIMap, hist) printf("%d, %d\n", i.ref->first, i.ref->second); puts(""); + IIMap_drop(&hist); } // =================================================== { @@ -44,15 +44,14 @@ int main() { std::cout << i.first << ", " << i.second << std::endl; std::cout << std::endl; } - - SIMap food = {0}; - c_defer (SIMap_drop(&food)) { + SIMap food = {0}; c_forlist (i, SIMap_raw, {{"burger", 5}, {"pizza", 12}, {"steak", 15}}) SIMap_emplace(&food, i.ref->first, i.ref->second); c_foreach (i, SIMap, food) printf("%s, %d\n", cstr_str(&i.ref->first), i.ref->second); puts(""); + SIMap_drop(&food); } } diff --git a/misc/examples/splitstr.c b/misc/examples/splitstr.c index bf90b5d4..2bc6fc07 100644 --- a/misc/examples/splitstr.c +++ b/misc/examples/splitstr.c @@ -15,5 +15,6 @@ int main() cregex re = cregex_from("[^ ]+"); c_formatch (i, &re, " Hello World C99! ") printf("'%.*s'\n", c_SV(i.match[0])); + cregex_drop(&re); } -- cgit v1.2.3 From 97d205f7ba096a9872afbce5e696a8806d7b72d1 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Wed, 29 Mar 2023 08:45:28 +0200 Subject: Removed i_less_functor, i_cmp_functor, i_eq_functor and i_hash_functor: not needed. Simplified cvec_X_eq() and cdeq_X_eq() --- docs/cmap_api.md | 4 +--- docs/cpque_api.md | 1 - docs/cset_api.md | 2 -- docs/csmap_api.md | 1 - docs/csset_api.md | 1 - include/stc/cdeq.h | 5 ++--- include/stc/cmap.h | 14 +++----------- include/stc/cpque.h | 10 +++------- include/stc/csmap.h | 18 +++++++----------- include/stc/cvec.h | 5 ++--- misc/examples/functor.c | 8 ++++---- 11 files changed, 22 insertions(+), 47 deletions(-) (limited to 'misc/examples/functor.c') diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 71e00265..8749bd09 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -36,9 +36,7 @@ See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/contain #define i_valto // convertion func i_val* => i_valraw #define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val -#define i_hash_functor // advanced, see examples/functor.c for similar usage. -#define i_eq_functor // advanced, see examples/functor.c for similar usage. -#define i_ssize // internal; default int32_t. If defined, table expand 2x (else 1.5x) +#define i_ssize // internal; default int32_t. If defined, table expand 2x (else 1.5x) #include ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. diff --git a/docs/cpque_api.md b/docs/cpque_api.md index 134a920f..1396dc1f 100644 --- a/docs/cpque_api.md +++ b/docs/cpque_api.md @@ -18,7 +18,6 @@ See the c++ class [std::priority_queue](https://en.cppreference.com/w/cpp/contai #define i_valfrom // convertion func i_valraw => i_val #define i_valto // convertion func i_val* => i_valraw. -#define i_less_functor // takes self as first argument. See examples/functor.c for usage. #define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_val #include ``` diff --git a/docs/cset_api.md b/docs/cset_api.md index a0af357f..db9fb802 100644 --- a/docs/cset_api.md +++ b/docs/cset_api.md @@ -19,8 +19,6 @@ A **cset** is an associative container that contains a set of unique objects of #define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy #define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val -#define i_hash_functor // advanced, see examples/functor.c for similar usage. -#define i_eq_functor // advanced, see examples/functor.c for similar usage. #define i_ssize // default int32_t. If defined, table expand 2x (else 1.5x) #include ``` diff --git a/docs/csmap_api.md b/docs/csmap_api.md index da0e6915..0eff8c26 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -33,7 +33,6 @@ See the c++ class [std::map](https://en.cppreference.com/w/cpp/container/map) fo #define i_valto // convertion func i_val* => i_valraw #define i_tag // alternative typename: csmap_{i_tag}. i_tag defaults to i_val -#define i_cmp_functor // advanced, see examples/functor.c for similar usage. #define i_ssize // internal size rep. defaults to int32_t #include ``` diff --git a/docs/csset_api.md b/docs/csset_api.md index 0989fd9b..1869327c 100644 --- a/docs/csset_api.md +++ b/docs/csset_api.md @@ -18,7 +18,6 @@ See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) fo #define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy #define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy -#define i_cmp_functor // advanced, see examples/functor.c for similar usage. #define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_val #define i_ssize // defaults to int32_t #include diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index c4f84a1b..09c0a7f8 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -198,9 +198,8 @@ _cx_memb(_get_mut)(_cx_self* self, _cx_raw raw) STC_INLINE bool _cx_memb(_eq)(const _cx_self* x, const _cx_self* y) { if (x->_len != y->_len) return false; - _cx_iter i = _cx_memb(_begin)(x), j = _cx_memb(_begin)(y); - for (; i.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) { - const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); + for (intptr_t i = 0; i < x->_len; ++i) { + const _cx_raw _rx = i_keyto(x->data+i), _ry = i_keyto(y->data+i); if (!(i_eq((&_rx), (&_ry)))) return false; } return true; diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 402038cb..c840523f 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -82,12 +82,6 @@ typedef struct { int64_t idx; uint8_t hx; } chash_bucket_t; #define _i_size i_ssize #endif #include "priv/template.h" -#ifndef i_hash_functor - #define i_hash_functor(self, x) i_hash(x) -#endif -#ifndef i_eq_functor - #define i_eq_functor(self, x, y) i_eq(x, y) -#endif #if !c_option(c_is_forward) _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); #endif @@ -371,14 +365,14 @@ STC_DEF void _cx_memb(_clear)(_cx_self* self) { STC_DEF chash_bucket_t _cx_memb(_bucket_)(const _cx_self* self, const _cx_rawkey* rkeyptr) { - const uint64_t _hash = i_hash_functor(self, rkeyptr); + const uint64_t _hash = i_hash(rkeyptr); int64_t _cap = self->bucket_count; chash_bucket_t b = {c_PASTE(fastrange_,_i_expandby)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)}; const uint8_t* _hx = self->_hashx; while (_hx[b.idx]) { if (_hx[b.idx] == b.hx) { const _cx_rawkey _raw = i_keyto(_i_keyref(self->table + b.idx)); - if (i_eq_functor(self, (&_raw), rkeyptr)) + if (i_eq((&_raw), rkeyptr)) break; } if (++b.idx == _cap) @@ -469,7 +463,7 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { if (! _hashx[j]) break; const _cx_rawkey _raw = i_keyto(_i_keyref(_slot + j)); - k = (i_ssize)c_PASTE(fastrange_,_i_expandby)(i_hash_functor(self, (&_raw)), (uint64_t)_cap); + k = (i_ssize)c_PASTE(fastrange_,_i_expandby)(i_hash((&_raw)), (uint64_t)_cap); if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */ _slot[i] = _slot[j], _hashx[i] = _hashx[j], i = j; } @@ -479,8 +473,6 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { #endif // i_implement #undef i_max_load_factor -#undef i_hash_functor -#undef i_eq_functor #undef _i_size #undef _i_isset #undef _i_ismap diff --git a/include/stc/cpque.h b/include/stc/cpque.h index 4955f2e0..00eaa49e 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -32,9 +32,6 @@ #endif #include "priv/template.h" -#ifndef i_less_functor - #define i_less_functor(self, x, y) i_less(x, y) -#endif #if !c_option(c_is_forward) _cx_deftypes(_c_cpque_types, _cx_self, i_key); #endif @@ -120,8 +117,8 @@ STC_DEF void _cx_memb(_sift_down_)(_cx_self* self, const intptr_t idx, const intptr_t n) { _cx_value t, *arr = self->data - 1; for (intptr_t r = idx, c = idx*2; c <= n; c *= 2) { - c += i_less_functor(self, (&arr[c]), (&arr[c + (c < n)])); - if (!(i_less_functor(self, (&arr[r]), (&arr[c])))) return; + c += i_less((&arr[c]), (&arr[c + (c < n)])); + if (!(i_less((&arr[r]), (&arr[c])))) return; t = arr[r], arr[r] = arr[c], arr[r = c] = t; } } @@ -156,12 +153,11 @@ _cx_memb(_push)(_cx_self* self, _cx_value value) { _cx_memb(_reserve)(self, self->_len*3/2 + 4); _cx_value *arr = self->data - 1; /* base 1 */ intptr_t c = ++self->_len; - for (; c > 1 && (i_less_functor(self, (&arr[c/2]), (&value))); c /= 2) + for (; c > 1 && (i_less((&arr[c/2]), (&value))); c /= 2) arr[c] = arr[c/2]; arr[c] = value; } #endif #define CPQUE_H_INCLUDED -#undef i_less_functor #include "priv/template.h" diff --git a/include/stc/csmap.h b/include/stc/csmap.h index 2b1910e9..50593ba3 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -80,9 +80,6 @@ int main(void) { #define _i_size i_ssize #endif #include "priv/template.h" -#ifndef i_cmp_functor - #define i_cmp_functor(self, x, y) i_cmp(x, y) -#endif #if !c_option(c_is_forward) _cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); #endif @@ -222,12 +219,12 @@ _cx_memb(_advance)(_cx_iter it, size_t n) { } STC_INLINE bool -_cx_memb(_eq)(const _cx_self* m1, const _cx_self* m2) { - if (_cx_memb(_size)(m1) != _cx_memb(_size)(m2)) return false; - _cx_iter i = _cx_memb(_begin)(m1), j = _cx_memb(_begin)(m2); +_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { + if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false; + _cx_iter i = _cx_memb(_begin)(self), j = _cx_memb(_begin)(other); for (; i.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) { const _cx_rawkey _rx = i_keyto(_i_keyref(i.ref)), _ry = i_keyto(_i_keyref(j.ref)); - if ((i_cmp_functor(m1, (&_rx), (&_ry))) != 0) return false; + if (!(i_eq((&_rx), (&_ry)))) return false; } return true; } @@ -357,7 +354,7 @@ _cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out) { out->_top = 0; while (tn) { int c; const _cx_rawkey _raw = i_keyto(_i_keyref(&d[tn].value)); - if ((c = i_cmp_functor(self, (&_raw), (&rkey))) < 0) + if ((c = i_cmp((&_raw), (&rkey))) < 0) tn = d[tn].link[1]; else if (c > 0) { out->_st[out->_top++] = tn; tn = d[tn].link[0]; } @@ -425,7 +422,7 @@ _cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_rawkey* rkey, _ while (tx) { up[top++] = tx; const _cx_rawkey _raw = i_keyto(_i_keyref(&d[tx].value)); - if (!(c = i_cmp_functor(self, (&_raw), rkey))) + if (!(c = i_cmp((&_raw), rkey))) { _res->ref = &d[tx].value; return tn; } dir = (c < 0); tx = d[tx].link[dir]; @@ -464,7 +461,7 @@ _cx_memb(_erase_r_)(_cx_self *self, i_ssize tn, const _cx_rawkey* rkey, int *era if (tn == 0) return 0; _cx_rawkey raw = i_keyto(_i_keyref(&d[tn].value)); - i_ssize tx; int c = i_cmp_functor(self, (&raw), rkey); + i_ssize tx; int c = i_cmp((&raw), rkey); if (c != 0) d[tn].link[c < 0] = _cx_memb(_erase_r_)(self, d[tn].link[c < 0], rkey, erased); else { @@ -594,7 +591,6 @@ _cx_memb(_drop)(_cx_self* self) { } #endif // i_implement -#undef i_cmp_functor #undef _i_size #undef _i_isset #undef _i_ismap diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 91cdb25c..8f35e5fc 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -236,9 +236,8 @@ _cx_memb(_get_mut)(const _cx_self* self, _cx_raw raw) STC_INLINE bool _cx_memb(_eq)(const _cx_self* x, const _cx_self* y) { if (x->_len != y->_len) return false; - _cx_iter i = _cx_memb(_begin)(x), j = _cx_memb(_begin)(y); - for (; i.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) { - const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); + for (intptr_t i = 0; i < x->_len; ++i) { + const _cx_raw _rx = i_keyto(x->data+i), _ry = i_keyto(y->data+i); if (!(i_eq((&_rx), (&_ry)))) return false; } return true; diff --git a/misc/examples/functor.c b/misc/examples/functor.c index f37e41d5..f8074c3a 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -1,9 +1,9 @@ // Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue // Example of per-instance less-function on a single priority queue type // -// Note: i_less_functor: available for cpque types only -// i_cmp_functor: available for csmap and csset types only -// i_hash_functor/i_eq_functor: available for cmap and cset types only +// Note: i_less: has self for cpque types only +// i_cmp: has self for csmap and csset types only +// i_hash/i_eq: has self for cmap and cset types only #include #include @@ -23,7 +23,7 @@ struct { #define i_type ipque #define i_val int #define i_opt c_is_forward // needed to avoid re-type-define container type -#define i_less_functor(self, x, y) c_container_of(self, IPQueue, Q)->less(x, y) +#define i_less(x, y) c_container_of(self, IPQueue, Q)->less(x, y) #include void print_queue(const char* name, IPQueue q) { -- cgit v1.2.3 From 5693ae9ae0d1a18627ba540e0240da010b282296 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Fri, 31 Mar 2023 22:08:07 +0200 Subject: Added stc/extend.h: A generalized way to type-safely extend a container with new members which can be accessed from the template parameters. See examples/functor.c --- README.md | 2 +- include/stc/carc.h | 18 ++++++------- include/stc/cbox.h | 18 ++++++------- include/stc/cdeq.h | 10 +++---- include/stc/clist.h | 6 ++--- include/stc/cmap.h | 10 +++---- include/stc/cpque.h | 2 +- include/stc/csmap.h | 2 +- include/stc/cstack.h | 2 +- include/stc/cvec.h | 12 ++++----- include/stc/extend.h | 65 +++++++++++++++++++++++++++++++++++++++++++++ include/stc/priv/template.h | 4 +++ misc/examples/functor.c | 47 +++++++++++++------------------- misc/examples/new_list.c | 4 +-- misc/examples/new_map.c | 2 +- misc/examples/new_queue.c | 2 +- misc/examples/new_smap.c | 2 +- misc/examples/new_vec.c | 4 +-- 18 files changed, 135 insertions(+), 77 deletions(-) create mode 100644 include/stc/extend.h (limited to 'misc/examples/functor.c') diff --git a/README.md b/README.md index b5f9ceb7..3f985b7a 100644 --- a/README.md +++ b/README.md @@ -518,7 +518,7 @@ typedef struct Dataset { ... // Implementation -#define i_opt c_is_forward // flag that the container was forward declared. +#define i_is_forward // flag that the container was forward declared. #define i_val struct Point #define i_tag pnt #include diff --git a/include/stc/carc.h b/include/stc/carc.h index 02bbaf52..5d38d2e7 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -90,7 +90,7 @@ typedef i_keyraw _cx_raw; #define _i_atomic_inc(v) (void)(++*(v)) #define _i_atomic_dec_and_test(v) !(--*(v)) #endif -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_carc_types, _cx_self, i_key); #endif struct _cx_memb(_rep_) { catomic_long counter; i_key value; }; @@ -177,8 +177,8 @@ STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self ptr) { STC_INLINE int _cx_memb(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry); } -STC_INLINE int _cx_memb(_cmp)(const _cx_self* x, const _cx_self* y) { - _cx_raw rx = i_keyto(x->get), ry = i_keyto(y->get); +STC_INLINE int _cx_memb(_cmp)(const _cx_self* self, const _cx_self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); return i_cmp((&rx), (&ry)); } #endif @@ -187,24 +187,24 @@ STC_INLINE int _cx_memb(_cmp)(const _cx_self* x, const _cx_self* y) { STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_eq(rx, ry); } -STC_INLINE bool _cx_memb(_eq)(const _cx_self* x, const _cx_self* y) { - _cx_raw rx = i_keyto(x->get), ry = i_keyto(y->get); +STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); return i_eq((&rx), (&ry)); } #elif !defined i_no_cmp STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry) == 0; } -STC_INLINE bool _cx_memb(_eq)(const _cx_self* x, const _cx_self* y) - { return _cx_memb(_cmp)(x, y) == 0; } +STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) + { return _cx_memb(_cmp)(self, other) == 0; } #endif #ifndef i_no_hash STC_INLINE uint64_t _cx_memb(_raw_hash)(const _cx_raw* rx) { return i_hash(rx); } -STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* x) - { _cx_raw rx = i_keyto(x->get); return i_hash((&rx)); } +STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* self) + { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); } #endif #undef _i_eq diff --git a/include/stc/cbox.h b/include/stc/cbox.h index 641fcbfc..6cc86c6f 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -76,7 +76,7 @@ int main() { #include "priv/template.h" typedef i_keyraw _cx_raw; -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_cbox_types, _cx_self, i_key); #endif @@ -163,8 +163,8 @@ STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self* moved) { STC_INLINE int _cx_memb(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry); } -STC_INLINE int _cx_memb(_cmp)(const _cx_self* x, const _cx_self* y) { - _cx_raw rx = i_keyto(x->get), ry = i_keyto(y->get); +STC_INLINE int _cx_memb(_cmp)(const _cx_self* self, const _cx_self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); return i_cmp((&rx), (&ry)); } #endif @@ -173,24 +173,24 @@ STC_INLINE int _cx_memb(_cmp)(const _cx_self* x, const _cx_self* y) { STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_eq(rx, ry); } -STC_INLINE bool _cx_memb(_eq)(const _cx_self* x, const _cx_self* y) { - _cx_raw rx = i_keyto(x->get), ry = i_keyto(y->get); +STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { + _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get); return i_eq((&rx), (&ry)); } #elif !defined i_no_cmp STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry) == 0; } -STC_INLINE bool _cx_memb(_eq)(const _cx_self* x, const _cx_self* y) - { return _cx_memb(_cmp)(x, y) == 0; } +STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) + { return _cx_memb(_cmp)(self, other) == 0; } #endif #ifndef i_no_hash STC_INLINE uint64_t _cx_memb(_raw_hash)(const _cx_raw* rx) { return i_hash(rx); } -STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* x) - { _cx_raw rx = i_keyto(x->get); return i_hash((&rx)); } +STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* self) + { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); } #endif #undef _i_eq diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 09c0a7f8..a032722b 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -36,7 +36,7 @@ #endif #include "priv/template.h" -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_cdeq_types, _cx_self, i_key); #endif typedef i_keyraw _cx_raw; @@ -196,10 +196,10 @@ _cx_memb(_get_mut)(_cx_self* self, _cx_raw raw) { return (_cx_value *) _cx_memb(_get)(self, raw); } STC_INLINE bool -_cx_memb(_eq)(const _cx_self* x, const _cx_self* y) { - if (x->_len != y->_len) return false; - for (intptr_t i = 0; i < x->_len; ++i) { - const _cx_raw _rx = i_keyto(x->data+i), _ry = i_keyto(y->data+i); +_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { + if (self->_len != other->_len) return false; + for (intptr_t i = 0; i < self->_len; ++i) { + const _cx_raw _rx = i_keyto(self->data+i), _ry = i_keyto(other->data+i); if (!(i_eq((&_rx), (&_ry)))) return false; } return true; diff --git a/include/stc/clist.h b/include/stc/clist.h index fa26fd65..ca02ae3c 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -82,7 +82,7 @@ #endif #include "priv/template.h" -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_clist_types, _cx_self, i_key); #endif _cx_deftypes(_c_clist_complete_types, _cx_self, dummy); @@ -204,8 +204,8 @@ _cx_memb(_get_mut)(_cx_self* self, _cx_raw val) { return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref; } -STC_INLINE bool _cx_memb(_eq)(const _cx_self* x, const _cx_self* y) { - _cx_iter i = _cx_memb(_begin)(x), j = _cx_memb(_begin)(y); +STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { + _cx_iter i = _cx_memb(_begin)(self), j = _cx_memb(_begin)(other); for (; i.ref && j.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) { const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref); if (!(i_eq((&_rx), (&_ry)))) return false; diff --git a/include/stc/cmap.h b/include/stc/cmap.h index c840523f..437a5982 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -82,7 +82,7 @@ typedef struct { int64_t idx; uint8_t hx; } chash_bucket_t; #define _i_size i_ssize #endif #include "priv/template.h" -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); #endif @@ -277,11 +277,11 @@ _cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { } STC_INLINE bool -_cx_memb(_eq)(const _cx_self* m1, const _cx_self* m2) { - if (_cx_memb(_size)(m1) != _cx_memb(_size)(m2)) return false; - for (_cx_iter i = _cx_memb(_begin)(m1); i.ref; _cx_memb(_next)(&i)) { +_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { + if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false; + for (_cx_iter i = _cx_memb(_begin)(self); i.ref; _cx_memb(_next)(&i)) { const _cx_rawkey _raw = i_keyto(_i_keyref(i.ref)); - if (!_cx_memb(_contains)(m2, _raw)) return false; + if (!_cx_memb(_contains)(other, _raw)) return false; } return true; } diff --git a/include/stc/cpque.h b/include/stc/cpque.h index 00eaa49e..f3ca7081 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -32,7 +32,7 @@ #endif #include "priv/template.h" -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_cpque_types, _cx_self, i_key); #endif typedef i_keyraw _cx_raw; diff --git a/include/stc/csmap.h b/include/stc/csmap.h index 50593ba3..d0a877c4 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -80,7 +80,7 @@ int main(void) { #define _i_size i_ssize #endif #include "priv/template.h" -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); #endif diff --git a/include/stc/cstack.h b/include/stc/cstack.h index f0c930e5..0f855dc9 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -33,7 +33,7 @@ #endif #include "priv/template.h" -#if !c_option(c_is_forward) +#ifndef i_is_forward #ifdef i_capacity #define i_no_clone _cx_deftypes(_c_cstack_fixed, _cx_self, i_key, i_capacity); diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 8f35e5fc..4fe5ddab 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -39,7 +39,7 @@ struct MyStruct { #include #define i_key int -#define i_opt c_is_forward // forward declared +#define i_is_forward // forward declared #define i_tag i32 #include @@ -73,7 +73,7 @@ int main() { #endif #include "priv/template.h" -#if !c_option(c_is_forward) +#ifndef i_is_forward _cx_deftypes(_c_cvec_types, _cx_self, i_key); #endif typedef i_keyraw _cx_raw; @@ -234,10 +234,10 @@ _cx_memb(_get_mut)(const _cx_self* self, _cx_raw raw) { return (_cx_value*) _cx_memb(_get)(self, raw); } STC_INLINE bool -_cx_memb(_eq)(const _cx_self* x, const _cx_self* y) { - if (x->_len != y->_len) return false; - for (intptr_t i = 0; i < x->_len; ++i) { - const _cx_raw _rx = i_keyto(x->data+i), _ry = i_keyto(y->data+i); +_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { + if (self->_len != other->_len) return false; + for (intptr_t i = 0; i < self->_len; ++i) { + const _cx_raw _rx = i_keyto(self->data+i), _ry = i_keyto(other->data+i); if (!(i_eq((&_rx), (&_ry)))) return false; } return true; diff --git a/include/stc/extend.h b/include/stc/extend.h new file mode 100644 index 00000000..a3efe02d --- /dev/null +++ b/include/stc/extend.h @@ -0,0 +1,65 @@ +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include + +#ifdef i_key_str + #define _i_key cstr +#elif defined i_keyclass + #define _i_key i_keyclass +#elif defined i_keyboxed + #define _i_key i_keyboxed +#elif defined i_key + #define _i_key i_key +#endif + +#ifdef i_val_str + #define _i_val cstr +#elif defined i_valclass + #define _i_val i_valclass +#elif defined i_valboxed + #define _i_val i_valboxed +#elif defined i_val + #define _i_val i_val +#endif + +#ifdef _i_key + c_PASTE(forward_, i_con)(i_type, _i_key, _i_val); +#else + c_PASTE(forward_, i_con)(i_type, _i_val); +#endif + +typedef struct { + i_ext; + i_type get; +} c_PASTE(i_type, Ext); + +#define c_getcon(cptr) c_container_of(cptr, _cx_memb(Ext), get) + +#define i_is_forward +#define _i_inc +#include _i_inc +#undef _i_inc +#undef _i_key +#undef _i_val +#undef i_con \ No newline at end of file diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index e352f488..d9e38dba 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -96,6 +96,9 @@ #endif #endif +#if c_option(c_is_forward) + #define i_is_forward +#endif #if c_option(c_no_cmp) #define i_no_cmp #endif @@ -341,6 +344,7 @@ #undef i_no_hash #undef i_no_clone #undef i_no_emplace +#undef i_is_forward #undef _i_prefix #undef _i_expandby diff --git a/misc/examples/functor.c b/misc/examples/functor.c index f8074c3a..45158cd1 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -6,35 +6,24 @@ // i_hash/i_eq: has self for cmap and cset types only #include -#include -#include -#include -#include -// predeclare -forward_cpque(ipque, int); - -struct { - ipque Q; - bool (*less)(const int*, const int*); -} typedef IPQueue; - - -#define i_type ipque +#define i_type IPQue #define i_val int -#define i_opt c_is_forward // needed to avoid re-type-define container type -#define i_less(x, y) c_container_of(self, IPQueue, Q)->less(x, y) -#include +#define i_ext bool (*less)(const int*, const int*) +#define i_less(x, y) c_getcon(self)->less(x, y) +#define i_con cpque +#include -void print_queue(const char* name, IPQueue q) { +void print_queue(const char* name, IPQueExt q) { // NB: make a clone because there is no way to traverse // priority_queue's content without erasing the queue. - IPQueue copy = {ipque_clone(q.Q), q.less}; + IPQueExt copy = {q.less, IPQue_clone(q.get)}; - for (printf("%s: \t", name); !ipque_empty(©.Q); ipque_pop(©.Q)) - printf("%d ", *ipque_top(©.Q)); + for (printf("%s: \t", name); !IPQue_empty(©.get); IPQue_pop(©.get)) + printf("%d ", *IPQue_top(©.get)); puts(""); - ipque_drop(©.Q); + + IPQue_drop(©.get); } static bool int_less(const int* x, const int* y) { return *x < *y; } @@ -49,21 +38,21 @@ int main() printf("%d ", data[i]); puts(""); - IPQueue q1 = {ipque_init(), int_less}; // Max priority queue - IPQueue minq1 = {ipque_init(), int_greater}; // Min priority queue - IPQueue q5 = {ipque_init(), int_lambda}; // Using lambda to compare elements. + IPQueExt q1 = {int_less}; // Max priority queue + IPQueExt minq1 = {int_greater}; // Min priority queue + IPQueExt q5 = {int_lambda}; // Using lambda to compare elements. c_forrange (i, n) - ipque_push(&q1.Q, data[i]); + IPQue_push(&q1.get, data[i]); print_queue("q1", q1); c_forrange (i, n) - ipque_push(&minq1.Q, data[i]); + IPQue_push(&minq1.get, data[i]); print_queue("minq1", minq1); c_forrange (i, n) - ipque_push(&q5.Q, data[i]); + IPQue_push(&q5.get, data[i]); print_queue("q5", q5); - c_drop(ipque, &q1.Q, &minq1.Q, &q5.Q); + c_drop(IPQue, &q1.get, &minq1.get, &q5.get); } diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c index eae4b8f5..8b291d34 100644 --- a/misc/examples/new_list.c +++ b/misc/examples/new_list.c @@ -11,7 +11,7 @@ typedef struct { #define i_val int #define i_tag i32 -#define i_opt c_is_forward +#define i_is_forward #include typedef struct Point { int x, y; } Point; @@ -22,7 +22,7 @@ int point_cmp(const Point* a, const Point* b) { #define i_val Point #define i_cmp point_cmp -#define i_opt c_is_forward +#define i_is_forward #define i_tag pnt #include diff --git a/misc/examples/new_map.c b/misc/examples/new_map.c index 4b02c46a..3a4f934d 100644 --- a/misc/examples/new_map.c +++ b/misc/examples/new_map.c @@ -26,7 +26,7 @@ int point_cmp(const Point* a, const Point* b) { #define i_val int #define i_cmp point_cmp #define i_hash c_default_hash -#define i_opt c_is_forward +#define i_is_forward #define i_tag pnt #include diff --git a/misc/examples/new_queue.c b/misc/examples/new_queue.c index 044e44cb..916f4dbc 100644 --- a/misc/examples/new_queue.c +++ b/misc/examples/new_queue.c @@ -12,7 +12,7 @@ int point_cmp(const Point* a, const Point* b) { } #define i_val Point #define i_cmp point_cmp -#define i_opt c_is_forward +#define i_is_forward #define i_tag pnt #include diff --git a/misc/examples/new_smap.c b/misc/examples/new_smap.c index d85d5c75..d8245b8b 100644 --- a/misc/examples/new_smap.c +++ b/misc/examples/new_smap.c @@ -20,7 +20,7 @@ int point_cmp(const Point* a, const Point* b) { #define i_key Point #define i_val int #define i_cmp point_cmp -#define i_opt c_is_forward +#define i_is_forward #include // cstr => cstr map diff --git a/misc/examples/new_vec.c b/misc/examples/new_vec.c index 988b78d9..df443b7f 100644 --- a/misc/examples/new_vec.c +++ b/misc/examples/new_vec.c @@ -10,7 +10,7 @@ struct MyStruct { } typedef MyStruct; #define i_val int -#define i_opt c_is_forward +#define i_is_forward #define i_tag i32 #include @@ -18,7 +18,7 @@ typedef struct Point { int x, y; } Point; #define i_val Point #define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) -#define i_opt c_is_forward +#define i_is_forward #define i_tag pnt #include -- cgit v1.2.3 From b81d7e44bd84a3c8513980a71a06d939f44af16b Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Sat, 1 Apr 2023 21:19:26 +0200 Subject: Update of stc/extend.h --- include/stc/extend.h | 5 +++-- include/stc/priv/template.h | 8 +++----- misc/examples/functor.c | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'misc/examples/functor.c') diff --git a/include/stc/extend.h b/include/stc/extend.h index a3efe02d..a8cb5f5b 100644 --- a/include/stc/extend.h +++ b/include/stc/extend.h @@ -50,7 +50,7 @@ #endif typedef struct { - i_ext; + i_extend; i_type get; } c_PASTE(i_type, Ext); @@ -62,4 +62,5 @@ typedef struct { #undef _i_inc #undef _i_key #undef _i_val -#undef i_con \ No newline at end of file +#undef i_con +#undef i_extend diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index d9e38dba..5ea0cf4f 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -25,7 +25,7 @@ #ifndef STC_TEMPLATE_H_INCLUDED #define STC_TEMPLATE_H_INCLUDED - #define _cx_self c_PASTE(_i_prefix, i_tag) + #define _cx_self i_type #define _cx_memb(name) c_PASTE(_cx_self, name) #define _cx_deftypes(macro, SELF, ...) c_EXPAND(macro(SELF, __VA_ARGS__)) #define _cx_value _cx_memb(_value) @@ -38,10 +38,8 @@ #define _cx_node _cx_memb(_node) #endif -#ifdef i_type - #define i_tag i_type - #undef _i_prefix - #define _i_prefix +#ifndef i_type + #define i_type c_PASTE(_i_prefix, i_tag) #endif #ifndef i_ssize diff --git a/misc/examples/functor.c b/misc/examples/functor.c index 45158cd1..7cc770d0 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -9,7 +9,7 @@ #define i_type IPQue #define i_val int -#define i_ext bool (*less)(const int*, const int*) +#define i_extend bool (*less)(const int*, const int*) #define i_less(x, y) c_getcon(self)->less(x, y) #define i_con cpque #include -- cgit v1.2.3 From 701b7af4aaf9fe3965c656c500d9200dd7c4831d Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Fri, 7 Apr 2023 22:51:45 +0200 Subject: More docs updating. --- README.md | 67 +++++++-------- docs/ccommon_api.md | 208 +++++++++++++++++++++++++---------------------- include/stc/ccommon.h | 2 +- include/stc/extend.h | 2 +- misc/examples/forloops.c | 2 +- misc/examples/functor.c | 2 +- 6 files changed, 148 insertions(+), 135 deletions(-) (limited to 'misc/examples/functor.c') diff --git a/README.md b/README.md index 224e7cb3..6f07f8ff 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ STC - Smart Template Containers for C ===================================== -### [Version 4.2](#version-history) +### [Version 4.2 RC](#version-history) --- Description @@ -35,13 +35,13 @@ Containers Algorithms ---------- -- [***common*** Generic container algorithms](docs/ccommon_api.md#algorithms) -- [***filter*** - Ranges-like filtering](docs/ccommon_api.md#c_forfilter) -- [***coroutine*** - Tiny, fast and portable coroutine implementation](docs/ccommon_api.md#coroutines) -- [***cregex*** - Regular expressions based on Rob Pike's regexp9](docs/cregex_api.md) -- [***crange*** - Generalized iota integer generator](docs/ccommon_api.md#crange) -- [***crand*** - A novel very fast *PRNG* based on ***sfc64***](docs/crandom_api.md) -- [***coption*** - A ***getopt***-alike command line argument parser](docs/coption_api.md) +- [***Ranged for-loops*** - c_foreach, c_forpair, c_forlist](docs/ccommon_api.md#ranged-for-loops) +- [***Range algorithms*** - c_forrange, crange, c_forfilter](docs/ccommon_api.md#range-algorithms) +- [***Generic algorithms*** - c_make, c_find_if, c_erase_if, etc.](docs/ccommon_api.md#generic-algorithms) +- [***Coroutines*** - Simon Tatham's coroutines done right](docs/ccommon_api.md#coroutines) +- [***Regular expressions*** - modernized Rob Pike's Plan-9 regexp](docs/cregex_api.md) +- [***Random numbers*** - a novel very fast *PRNG* based on *SFC64*](docs/crandom_api.md) +- [***Command line argument parser*** - similar to *getopt()*](docs/coption_api.md) --- List of contents @@ -49,7 +49,7 @@ List of contents - [Highlights](#highlights) - [STC is unique!](#stc-is-unique) - [Performance](#performance) -- [STC naming conventions](#stc-naming-conventions) +- [Naming conventions](#naming-conventions) - [Usage](#usage) - [Installation](#installation) - [Specifying template parameters](#specifying-template-parameters) @@ -57,19 +57,19 @@ List of contents - [The *erase* methods](#the-erase-methods) - [User-defined container type name](#user-defined-container-type-name) - [Forward declarations](#forward-declarations) -- [Per-container-instance customization](#per-container-instance-customization) +- [Per container-instance customization](#per-container-instance-customization) - [Memory efficiency](#memory-efficiency) --- ## Highlights -- **No boilerplate code** - Minimal code is needed to setup containers with any element type. Specify only what is needed, e.g. ***cmp***- and/or ***clone***-, ***drop***- functions, and leave the rest as defaults. +- **No boilerplate code** - Specify only the required template parameters, e.g. ***cmp***- and/or ***clone***-, ***drop***- functions, and leave the rest as defaults. - **Fully type safe** - Because of templating, it avoids error-prone casting of container types and elements back and forth from the containers. -- **User friendly** - Just include the headers and you are good. The API and functionality is very close to c++ STL, and is fully listed in the docs. +- **User friendly** - Just include the headers and you are good. The API and functionality is very close to c++ STL and is fully listed in the docs. - **Unparalleled performance** - Maps and sets are much faster than the C++ STL containers, the remaining are similar in speed. -- **Fully memory managed** - All containers will destruct keys/values via destructor (defined as macro parameters before including the container header). Also, smart pointers are supported and can be stored in containers, see ***carc*** and ***cbox***. -- **Uniform, easy-to-learn API** - Uniform and intuitive method/type names and usage across the various containers. -- **No signed/unsigned mixing** - Unsigned sizes and indices mixed with signed in comparisons and calculations is asking for trouble. STC uses only signed numbers in the API for this reason. +- **Fully memory managed** - Containers destructs keys/values via default or user supplied drop function. They may be cloned if element types are clonable. Also, smart pointers are supported and can be stored in containers. See ***carc*** and ***cbox***. +- **Uniform, easy-to-learn API** - Intuitive method/type names and uniform usage across the various containers. +- **No signed/unsigned mixing** - Unsigned sizes and indices mixed with signed for comparison and calculation is asking for trouble. STC only uses signed numbers in the API for this reason. - **Small footprint** - Small source code and generated executables. The executable from the example below using *four different* container types is only ***19 Kb in size*** compiled with gcc -O3 -s on Linux. - **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the Installation section. - **No callback functions** - All passed template argument functions/macros are directly called from the implementation, no slow callbacks which requires storage. @@ -87,7 +87,8 @@ that the elements are of basic types. For more complex types, additional templat 2. ***Alternative insert/lookup type***. You may specify an alternative type to use for lookup in containers. E.g., containers with STC string elements (**cstr**) uses `const char*` as lookup type, so construction of a `cstr` (which may allocate memory) for the lookup *is not needed*. Hence, the alt. lookup -key does not need to be destroyed after use, as it is normally a POD type. Finally, the alternative +key does not need to be destroyed after use as it is normally a POD type. Finally, the alternative +key does not need to be destroyed after use as it is normally a POD type. Finally, the alternative lookup type may be passed to an ***emplace***-function. E.g. instead of calling `cvec_str_push(&vec, cstr_from("Hello"))`, you may call `cvec_str_emplace(&vec, "Hello")`, which is functionally identical, but more convenient. @@ -100,7 +101,7 @@ same element access syntax. E.g.: --- ## Performance -STC is a fast and memory efficient library, and code compiles very fast: +STC is a fast and memory efficient library, and code compiles fast: ![Benchmark](misc/benchmarks/pics/benchmark.gif) @@ -114,7 +115,7 @@ Benchmark notes: - **map and unordered map**: *insert*: n/2 random numbers, n/2 sequential numbers. *erase*: n/2 keys in the map, n/2 random keys. --- -## STC naming conventions +## Naming conventions - Container names are prefixed by `c`, e.g. `cvec`, `cstr`. - Public STC macros are prefixed by `c_`, e.g. `c_foreach`, `c_make`. @@ -144,10 +145,10 @@ Benchmark notes: --- ## Usage -The functionality of STC containers is similar to C++ STL standard containers. All containers except for a few, +STC containers have similar functionality to C++ STL standard containers. All containers except for a few, like **cstr** and **cbits** are generic/templated. No type casting is done, so containers are type-safe like -templated types in C++. However, the specification of template parameters are naturally different. Here is -a basic usage example: +templated types in C++. However, the specification of template parameters are naturally different. In STC, +you specify template parameters by `#define` before including the container: ```c #define i_type Floats // Container type name; unless defined name would be cvec_float #define i_val float // Container element type @@ -166,7 +167,7 @@ int main(void) Floats_sort(&nums); - c_foreach (i, Floats, nums) // Alternative and recommended way to iterate nums. + c_foreach (i, Floats, nums) // Alternative and recommended way to iterate. printf(" %g", *i.ref); // i.ref is a pointer to the current element. Floats_drop(&nums); // cleanup memory @@ -181,7 +182,7 @@ You may switch to a different container type, e.g. a sorted set (csset): int main() { - Floats nums = c_make(Floats, {30.f, 10.f, 20.f}); // Initialize nums with a list of floats. + Floats nums = c_make(Floats, {30.f, 10.f, 20.f}); // Initialize with a list of floats. Floats_push(&nums, 50.f); Floats_push(&nums, 40.f); @@ -192,11 +193,11 @@ int main() Floats_drop(&nums); } ``` -For user-defined struct elements, `i_cmp` compare function should be defined, as the default `<` and `==` +For user-defined struct elements, `i_cmp` compare function should be defined as the default `<` and `==` only works for integral types. *Alternatively, `#define i_opt c_no_cmp` to disable sorting and searching*. Similarily, if an element destructor `i_valdrop` is defined, `i_valclone` function is required. *Alternatively `#define i_opt c_no_clone` to disable container cloning.* -Let's make a vector of vectors that can be cloned. All of its element vectors will be destroyed when destroying the Vec2D. +Let's make a vector of vectors, which can be cloned. All of its element vectors will be destroyed when destroying the Vec2D. ```c #include @@ -206,7 +207,7 @@ Let's make a vector of vectors that can be cloned. All of its element vectors wi #define i_type Vec2D #define i_valclass Vec // Use i_valclass when element type has "members" _clone(), _drop() and _cmp(). -#define i_opt c_no_cmp // However, disable search/sort for Vec2D because Vec_cmp() is not defined. +#define i_opt c_no_cmp // Disable cmp (search/sort) for Vec2D because Vec_cmp() is not defined. #include int main(void) @@ -542,11 +543,11 @@ typedef struct Dataset { ``` --- -## Per-container-instance customization -Sometimes it is useful to extend a container type to hold extra data, e.g. a comparison -or allocator function pointer or some context that the function pointers can use. Most -libraries solve this by adding an opaque pointer (void*) or some function pointer(s) into -the data structure for the user to manage. This solution has a few disadvantages, e.g. the +## Per container-instance customization +Sometimes it is useful to extend a container type to store extra data, e.g. a comparison +or allocator function pointer or a context which the function pointers can use. Most +libraries solve this by adding an opaque pointer (void*) or function pointer(s) into +the data structure for the user to manage. This solution has a few disadvantages: the pointers are not typesafe, and they take up space when not needed. STC solves this by letting the user create a container wrapper struct where both the container and extra data fields can be stored. The template parameters may then access the extra data using the "container_of" @@ -564,10 +565,10 @@ the by inclusion of ``. #define i_allocator pgs #define i_no_clone -#define i_extend MemoryContext memctx +#define i_extend MemoryContext memctx; #include ``` -Define both `i_type` and `i_con` (the container type) before including the custom header: +To use it, define both `i_type` and `i_con` (the container type) before including the custom header: ```c #define i_type IMap #define i_key int diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index af27bd1d..21eaf884 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -2,16 +2,17 @@ The following macros are recommended to use, and they safe/have no side-effects. -## Loop abstraction macros +--- +## Ranged for-loops -### c_foreach, c_foreach_r, c_forpair +### c_foreach, c_foreach_rv, c_forpair -| Usage | Description | -|:-----------------------------------------|:----------------------------------------| -| `c_foreach (it, ctype, container)` | Iteratate all elements | -| `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) | -| `c_foreach_r (it, ctype, container)` | Iteratate in reverse (cstack,cvec,cdeq) | -| `c_forpair (key, val, ctype, container)` | Iterate with structured binding | +| Usage | Description | +|:-----------------------------------------|:------------------------------------------| +| `c_foreach (it, ctype, container)` | Iteratate all elements | +| `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) | +| `c_foreach_rv (it, ctype, container)` | Iteratate in reverse (cstack, cvec, cdeq) | +| `c_forpair (key, val, ctype, container)` | Iterate with structured binding | ```c #define i_key int @@ -40,6 +41,25 @@ c_forpair (id, count, csmap_ii, map) // (3 2) (5 4) (7 3) (12 5) (23 1) ``` +### c_forlist +Iterate compound literal array elements. Additional to `i.ref`, you can access `i.data`, `i.size`, and `i.index` of the input list/element. +```c +// apply multiple push_backs +c_forlist (i, int, {1, 2, 3}) + cvec_i_push_back(&vec, *i.ref); + +// insert in existing map +c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} }) + cmap_ii_insert(&map, i.ref->first, i.ref->second); + +// string literals pushed to a stack of cstr: +c_forlist (i, const char*, {"Hello", "crazy", "world"}) + cstack_str_emplace(&stk, *i.ref); +``` + +--- +## Range algorithms + ### c_forrange Abstraction for iterating sequence of integers. Like python's **for** *i* **in** *range()* loop. @@ -61,24 +81,38 @@ c_forrange (i, 30, 0, -5) printf(" %lld", i); // 30 25 20 15 10 5 ``` -### c_forlist -Iterate compound literal array elements. Additional to `i.ref`, you can access `i.data`, `i.size`, and `i.index` of the input list/element. +### crange +A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: ```c -// apply multiple push_backs -c_forlist (i, int, {1, 2, 3}) - cvec_i_push_back(&vec, *i.ref); +crange& crange_object(...) // create a compound literal crange object +crange crange_make(stop); // will generate 0, 1, ..., stop-1 +crange crange_make(start, stop); // will generate start, start+1, ... stop-1 +crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop + // note that step may be negative. +crange_iter crange_begin(crange* self); +crange_iter crange_end(crange* self); +void crange_next(crange_iter* it); -// insert in existing map -c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} }) - cmap_ii_insert(&map, i.ref->first, i.ref->second); +// 1. All primes less than 32: +crange r1 = crange_make(3, 32, 2); +printf("2"); // first prime +c_forfilter (i, crange, r1, isPrime(*i.ref)) + printf(" %lld", *i.ref); +// 2 3 5 7 11 13 17 19 23 29 31 -// string literals pushed to a stack of cstr: -c_forlist (i, const char*, {"Hello", "crazy", "world"}) - cstack_str_emplace(&stk, *i.ref); +// 2. The first 11 primes: +printf("2"); +c_forfilter (i, crange, crange_object(3, INT64_MAX, 2), + isPrime(*i.ref) && + c_flt_take(10) +){ + printf(" %lld", *i.ref); +} +// 2 3 5 7 11 13 17 19 23 29 31 ``` ### c_forfilter -Iterate containers with stop-criteria and chained range filtering. +Iterate a container/range with chained range filtering. | Usage | Description | |:----------------------------------------------------|:---------------------------------------| @@ -122,46 +156,14 @@ int main() { ``` Note that `c_flt_take()` and `c_flt_takewhile()` breaks the loop on false. -## Generators - -### crange -A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: -```c -crange& crange_object(...) // create a compound literal crange object -crange crange_make(stop); // will generate 0, 1, ..., stop-1 -crange crange_make(start, stop); // will generate start, start+1, ... stop-1 -crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop - // note that step may be negative. -crange_iter crange_begin(crange* self); -crange_iter crange_end(crange* self); -void crange_next(crange_iter* it); - -// 1. All primes less than 32: -crange r1 = crange_make(3, 32, 2); -printf("2"); // first prime -c_forfilter (i, crange, r1, isPrime(*i.ref)) - printf(" %lld", *i.ref); -// 2 3 5 7 11 13 17 19 23 29 31 - -// 2. The first 11 primes: -printf("2"); -c_forfilter (i, crange, crange_object(3, INT64_MAX, 2), - isPrime(*i.ref) && - c_flt_take(10) -){ - printf(" %lld", *i.ref); -} -// 2 3 5 7 11 13 17 19 23 29 31 -``` -## Algorithms +--- +## Generic algorithms -### c_make, c_new, c_delete +### c_make, c_drop -- *c_make(C, {...})*: Make any container from an initializer list. Example: +Make any container from an initializer list: ```c -#define i_val_str // owned cstr string value type -//#define i_valclass crawstr // non-owning const char* values with strcmp/cstrhash -//#define i_val const char* // non-owning const char* values with pointer cmp/hash. +#define i_val_str // owned cstr string value type #include #define i_key int @@ -170,26 +172,21 @@ c_forfilter (i, crange, crange_object(3, INT64_MAX, 2), ... // Initializes with const char*, internally converted to cstr! cset_str myset = c_make(cset_str, {"This", "is", "the", "story"}); +cset_str myset2 = c_clone(myset); int x = 7, y = 8; cmap_int mymap = c_make(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} }); ``` - -- ***c_new(Type)***: Allocate *and init* a new object on the heap -- ***c_delete(Type, ptr)***: Drop *and free* an object allocated on the heap +Drop multiple containers of the same type: ```c -#include - -cstr *stringptr = c_new(cstr, cstr_from("Hello")); -printf("%s\n", cstr_str(stringptr)); -c_delete(cstr, stringptr); +c_drop(cset_str, &myset, &myset2); ``` ### c_find_if, c_erase_if, c_eraseremove_if Find or erase linearily in containers using a predicate -- For *c_find_if (iter, C, c, pred)*, ***iter*** must be declared outside/prior to call. -- Use *c_erase_if (iter, C, c, pred)* with **clist**, **cmap**, **cset**, **csmap**, and **csset**. -- Use *c_eraseremove_if (iter, C, c, pred)* with **cstack**, **cvec**, **cdeq**, and **cqueue**. +- For `c_find_if(iter, C, c, pred)`, ***iter*** is in/out and must be declared prior to call. +- Use `c_erase_if(iter, C, c, pred)` with **clist**, **cmap**, **cset**, **csmap**, and **csset**. +- Use `c_eraseremove_if(iter, C, c, pred)` with **cstack**, **cvec**, **cdeq**, and **cqueue**. ```c // Search vec for first value > 2: cvec_i_iter i; @@ -208,51 +205,66 @@ if (it.ref) cmap_str_erase_at(&map, it); c_erase_if(i, csmap_str, map, cstr_contains(i.ref, "hello")); ``` -### c_swap, c_drop, c_const_cast +### c_new, c_delete + +- `c_new(Type, val)` - Allocate *and init* a new object on the heap +- `c_delete(Type, ptr)` - Drop *and free* an object allocated on the heap. NULL is OK. +```c +#include + +cstr *str_p = c_new(cstr, cstr_from("Hello")); +printf("%s\n", cstr_str(str_p)); +c_delete(cstr, str_p); +``` + +### c_malloc, c_calloc, c_realloc, c_free +Memory allocator wrappers that uses signed sizes. + +### c_arraylen +Return number of elements in an array. array must not be a pointer! +```c +int array[] = {1, 2, 3, 4}; +intptr_t n = c_arraylen(array); +``` + +### c_swap, c_const_cast ```c // Safe macro for swapping internals of two objects of same type: c_swap(cmap_int, &map1, &map2); -// Drop multiple containers of same type: -c_drop(cvec_i, &vec1, &vec2, &vec3); - // Type-safe casting a from const (pointer): const char cs[] = "Hello"; char* s = c_const_cast(char*, cs); // OK int* ip = c_const_cast(int*, cs); // issues a warning! ``` -### General predefined template parameter functions +### Predefined template parameter functions +**crawstr** - Non-owned `const char*` "class" element type: `#define i_valclass crawstr` ```c -int c_default_cmp(const Type*, const Type*); -Type c_default_clone(Type val); // simple copy -Type c_default_toraw(const Type* val); // dereference val -void c_default_drop(Type* val); // does nothing - typedef const char* crawstr; int crawstr_cmp(const crawstr* x, const crawstr* y); bool crawstr_eq(const crawstr* x, const crawstr* y); uint64_t crawstr_hash(const crawstr* x); ``` - -### c_malloc, c_calloc, c_realloc, c_free: customizable allocators -Memory allocator wrappers that uses signed sizes. - -### c_arraylen -Return number of elements in an array. array must not be a pointer! +Default implementations ```c -int array[] = {1, 2, 3, 4}; -intptr_t n = c_arraylen(array); +int c_default_cmp(const Type*, const Type*); // <=> +bool c_default_less(const Type*, const Type*); // < +bool c_default_eq(const Type*, const Type*); // == +uint64_t c_default_hash(const Type*); +Type c_default_clone(Type val); // return val +Type c_default_toraw(const Type* p); // return *p +void c_default_drop(Type* p); // does nothing ``` --- ## Coroutines This is an improved implementation of Simon Tatham's classic C code, which utilizes the *Duff's device* trick. However, Tatham's implementation is not typesafe, -and it always allocates the coroutine's internal state dynamically. Also, -it does not let the coroutine do self-cleanup on early finish, i.e. it -just frees the dynamically allocated memory. +and it always allocates the coroutine's internal state dynamically. But most crucially, +it does not let the coroutine do self-cleanup on early finish - i.e. it +only frees the initial dynamically allocated memory. In this implementation a coroutine may have any signature, but it should take some struct pointer as parameter, which must contain the member `int cco_state;` @@ -260,8 +272,8 @@ The struct should normally store all the *local* variables to be used in the coroutine. It can also store input and output data if desired. The coroutine example below generates Pythagorian triples, but the main user-loop -skips the triples which are upscaled version of smaller ones, by checking -the gcd() function, and breaks when diagonal length >= 100: +skips the triples which are upscaled version of smaller ones by checking +the gcd() function, and breaks when the diagonal size >= 100: ```c #include @@ -271,14 +283,14 @@ struct triples { int cco_state; // required member }; -bool triples_next(struct triples* I) { // coroutine - cco_begin(I); - for (I->c = 5; I->n; ++I->c) { - for (I->a = 1; I->a < I->c; ++I->a) { - for (I->b = I->a + 1; I->b < I->c; ++I->b) { - if ((int64_t)I->a*I->a + (int64_t)I->b*I->b == (int64_t)I->c*I->c) { +bool triples_next(struct triples* i) { // coroutine + cco_begin(i); + for (i->c = 5; i->n; ++i->c) { + for (i->a = 1; i->a < i->c; ++i->a) { + for (i->b = i->a + 1; i->b < i->c; ++i->b) { + if ((int64_t)i->a*i->a + (int64_t)i->b*i->b == (int64_t)i->c*i->c) { cco_yield(true); - if (--I->n == 0) cco_return; + if (--i->n == 0) cco_return; } } } diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 362b09ce..24ad59f9 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -182,7 +182,7 @@ STC_INLINE char* cstrnstrn(const char *str, const char *needle, for (C##_iter it = start, *_endref = (C##_iter*)(finish).ref \ ; it.ref != (C##_value*)_endref; C##_next(&it)) -#define c_foreach_r(it, C, cnt) \ +#define c_foreach_rv(it, C, cnt) \ for (C##_iter it = {.ref=C##_end(&cnt).end - 1, .end=(cnt).data - 1} \ ; it.ref != it.end; --it.ref) diff --git a/include/stc/extend.h b/include/stc/extend.h index a8cb5f5b..cbfc4a12 100644 --- a/include/stc/extend.h +++ b/include/stc/extend.h @@ -50,7 +50,7 @@ #endif typedef struct { - i_extend; + i_extend i_type get; } c_PASTE(i_type, Ext); diff --git a/misc/examples/forloops.c b/misc/examples/forloops.c index 82126456..1fc00614 100644 --- a/misc/examples/forloops.c +++ b/misc/examples/forloops.c @@ -42,7 +42,7 @@ int main() printf(" %d", *i.ref); puts("\n\nc_foreach_r: reverse"); - c_foreach_r (i, IVec, vec) + c_foreach_rv (i, IVec, vec) printf(" %d", *i.ref); puts("\n\nc_foreach in map:"); diff --git a/misc/examples/functor.c b/misc/examples/functor.c index 7cc770d0..7417080b 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -9,7 +9,7 @@ #define i_type IPQue #define i_val int -#define i_extend bool (*less)(const int*, const int*) +#define i_extend bool (*less)(const int*, const int*); #define i_less(x, y) c_getcon(self)->less(x, y) #define i_con cpque #include -- cgit v1.2.3 From d92ffe3da29b3352c90b2d356e395914ba5b3f52 Mon Sep 17 00:00:00 2001 From: Tyge Lovset Date: Sat, 8 Apr 2023 11:02:39 +0200 Subject: More docs updates, and a change in stc/extend.h. --- README.md | 51 +++++++++++++++++++++++++++-------------------- docs/ccommon_api.md | 33 +++++++++++++++--------------- include/stc/algo/crange.h | 4 ++-- include/stc/ccommon.h | 3 ++- include/stc/extend.h | 4 ++-- misc/examples/forfilter.c | 2 +- misc/examples/functor.c | 10 +++++----- misc/examples/prime.c | 2 +- 8 files changed, 59 insertions(+), 50 deletions(-) (limited to 'misc/examples/functor.c') diff --git a/README.md b/README.md index 6f07f8ff..220349b3 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,10 @@ STC - Smart Template Containers for C --- Description ----------- -STC is a *modern*, *fully typesafe*, *fast* and *compact* container and algorithm library for C99. +STC is a *modern*, *typesafe*, *fast* and *compact* container and algorithms library for C99. The API naming is similar to C++ STL, but it takes inspiration from Rust and Python as well. -The library let you store and manage trivial and highly complex data in a variety of -containers with ease. It is optimized for speed, usage ergonomics, consistency, -and it creates small binaries. +The library handles everything from trivial to highly complex data using *templates*, and it +supports a variety of containers. Containers ---------- @@ -80,18 +79,18 @@ List of contents ## STC is unique! 1. ***Centralized analysis of template parameters***. The analyser assigns values to all -non-specified template parameters (based on the specified ones) using meta-programming, -so that you don't have to! You may specify a set of "standard" template parameters for each container, -but as a minimum *only one is required*: `i_val` (+ `i_key` for maps). In this case STC assumes -that the elements are of basic types. For more complex types, additional template parameters must be given. -2. ***Alternative insert/lookup type***. You may specify an alternative type to use for lookup in -containers. E.g., containers with STC string elements (**cstr**) uses `const char*` as lookup type, -so construction of a `cstr` (which may allocate memory) for the lookup *is not needed*. Hence, the alt. lookup -key does not need to be destroyed after use as it is normally a POD type. Finally, the alternative -key does not need to be destroyed after use as it is normally a POD type. Finally, the alternative -lookup type may be passed to an ***emplace***-function. E.g. instead of calling -`cvec_str_push(&vec, cstr_from("Hello"))`, you may call `cvec_str_emplace(&vec, "Hello")`, -which is functionally identical, but more convenient. +non-specified template parameters (based on the specified ones) using meta-programming, so +that you don't have to! You may specify a set of "standard" template parameters for each +container, but as a minimum *only one is required*: `i_val` (+ `i_key` for maps). In this +case, STC assumes that the elements are of basic types. For non-trivial types, additional +template parameters must be given. +2. ***Alternative insert/lookup type***. You may specify an alternative type to use for +lookup in containers. E.g., containers with STC string elements (**cstr**) uses `const char*` +as lookup type, so constructing a `cstr` (which may allocate memory) for the lookup +*is not needed*. Hence, the alternative lookup key does not need to be destroyed after use, +as it is normally a POD type. Finally, the key may be passed to an ***emplace***-function. +So instead of calling e.g. `cvec_str_push(&vec, cstr_from("Hello"))`, you may call +`cvec_str_emplace(&vec, "Hello")`, which is functionally identical, but more convenient. 3. ***Standardized container iterators***. All containers can be iterated in the same manner, and all use the same element access syntax. E.g.: - `c_foreach (it, MyInts, myints) *it.ref += 42;` works for any container defined as @@ -146,9 +145,9 @@ Benchmark notes: --- ## Usage STC containers have similar functionality to C++ STL standard containers. All containers except for a few, -like **cstr** and **cbits** are generic/templated. No type casting is done, so containers are type-safe like -templated types in C++. However, the specification of template parameters are naturally different. In STC, -you specify template parameters by `#define` before including the container: +like **cstr** and **cbits** are generic/templated. No type casting is used, so containers are type-safe like +templated types in C++. However, to specify template parameters with STC, you define them as macros prior to +including the container: ```c #define i_type Floats // Container type name; unless defined name would be cvec_float #define i_val float // Container element type @@ -576,10 +575,10 @@ To use it, define both `i_type` and `i_con` (the container type) before includin #define i_con csmap #include "stcpgs.h" -// Note the wrapper struct type is IMapExt. IMap is accessed by .get +// Note the wrapper struct type is IMap_ext. IMap is accessed by .get void maptest() { - IMapExt map = {.memctx=CurrentMemoryContext}; + IMap_ext map = {.memctx=CurrentMemoryContext}; c_forrange (i, 1, 16) IMap_insert(&map.get, i*i, i); @@ -605,9 +604,17 @@ STC is generally very memory efficient. Memory usage for the different container --- # Version History +## Version 4.2 +- Much improved documentation +- Added Coroutines + documentation +- Added `c_const_cast()` typesafe macro. +- Renamed c_foreach_r => `c_foreach_rv` +- Renamed c_flt_count(i) => `c_flt_counter(i)` +- Renamed c_flt_last(i) => `c_flt_getcount(i)` +- Removed c_PAIR ## Version 4.1.1 -I am happy to finally announce a new release! Major changes: +Major changes: - A new exciting [**cspan**](docs/cspan_api.md) single/multi-dimensional array view (with numpy-like slicing). - Signed sizes and indices for all containers. See C++ Core Guidelines by Stroustrup/Sutter: [ES.100](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es100-dont-mix-signed-and-unsigned-arithmetic), [ES.102](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es102-use-signed-types-for-arithmetic), [ES.106](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es106-dont-try-to-avoid-negative-values-by-using-unsigned), and [ES.107](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es107-dont-use-unsigned-for-subscripts-prefer-gslindex). - Customizable allocator [per templated container type](https://github.com/tylov/STC/discussions/44#discussioncomment-4891925). diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 21eaf884..90191e40 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -84,7 +84,7 @@ c_forrange (i, 30, 0, -5) printf(" %lld", i); ### crange A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: ```c -crange& crange_object(...) // create a compound literal crange object +crange& crange_obj(...) // create a compound literal crange object crange crange_make(stop); // will generate 0, 1, ..., stop-1 crange crange_make(start, stop); // will generate start, start+1, ... stop-1 crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop @@ -102,7 +102,7 @@ c_forfilter (i, crange, r1, isPrime(*i.ref)) // 2. The first 11 primes: printf("2"); -c_forfilter (i, crange, crange_object(3, INT64_MAX, 2), +c_forfilter (i, crange, crange_obj(3, INT64_MAX, 2), isPrime(*i.ref) && c_flt_take(10) ){ @@ -260,22 +260,23 @@ void c_default_drop(Type* p); // does nothing --- ## Coroutines -This is an improved implementation of Simon Tatham's classic C code, which utilizes -the *Duff's device* trick. However, Tatham's implementation is not typesafe, -and it always allocates the coroutine's internal state dynamically. But most crucially, +This is a much improved implementation of +[Simon Tatham's coroutines](https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html), +which utilizes the *Duff's device* trick. Tatham's implementation is not typesafe, +and it always allocates the coroutine's internal state dynamically. But crucially, it does not let the coroutine do self-cleanup on early finish - i.e. it only frees the initial dynamically allocated memory. -In this implementation a coroutine may have any signature, but it should -take some struct pointer as parameter, which must contain the member `int cco_state;` +In this implementation, a coroutine may have any signature, but it should +take a struct pointer as parameter, which must contain the member `int cco_state;` The struct should normally store all the *local* variables to be used in the coroutine. It can also store input and output data if desired. -The coroutine example below generates Pythagorian triples, but the main user-loop -skips the triples which are upscaled version of smaller ones by checking -the gcd() function, and breaks when the diagonal size >= 100: +The coroutine example below generates Pythagorian triples, but the calling loop +skips the triples which are upscaled version of smaller ones, by checking +the gcd() function. It also ensures that it stops when the diagonal size >= 100: ```c -#include +#include struct triples { int n; // input: max number of triples to be generated. @@ -311,8 +312,7 @@ int gcd(int a, int b) { // greatest common denominator int main() { - puts("\nCoroutine triples:"); - struct triples t = {INT32_MAX}; + struct triples t = {.n=INT32_MAX}; int n = 0; while (triples_next(&t)) { @@ -324,12 +324,13 @@ int main() if (t.c < 100) printf("%d: {%d, %d, %d}\n", ++n, t.a, t.b, t.c); else - cco_stop(&t); // make sure coroutine cleanup is done + cco_stop(&t); // cleanup in next coroutine call/resume } } ``` ### Coroutine API -**Note**: `cco_yield()` may not be called inside a `switch` statement. Use `if-else-if` constructs instead. +**Note**: *cco_yield()* may not be called inside a `switch` statement. Use `if-else-if` constructs instead. +To resume the coroutine from where it was suspended with *cco_yield()*, simply call the coroutine again. | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| @@ -340,7 +341,7 @@ int main() | `void` | `cco_begin(ctx)` | Begin coroutine block | | `rettype` | `cco_end(retval)` | End coroutine block with return value | | `rettype` | `cco_end()` | End coroutine block with (void) | -| `rettype` | `cco_yield(retval)` | Yield a value | +| `rettype` | `cco_yield(retval)` | Return a value and suspend execution | | `rettype` | `cco_yield(corocall2, ctx2, retval)` | Yield from another coroutine and return val | | `rettype` | `cco_yield(corocall2, ctx2)` | Yield from another coroutine (void) | | | From the caller side: | | diff --git a/include/stc/algo/crange.h b/include/stc/algo/crange.h index 91ffdd56..ca06c258 100644 --- a/include/stc/algo/crange.h +++ b/include/stc/algo/crange.h @@ -34,7 +34,7 @@ int main() // use a temporary crange object. int a = 100, b = INT32_MAX; - c_forfilter (i, crange, crange_object(a, b, 8), + c_forfilter (i, crange, crange_obj(a, b, 8), c_flt_skip(i, 10) && c_flt_take(i, 3)) printf(" %lld", *i.ref); @@ -46,7 +46,7 @@ int main() #include -#define crange_object(...) \ +#define crange_obj(...) \ (*(crange[]){crange_make(__VA_ARGS__)}) typedef long long crange_value; diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 24ad59f9..1a2b3c3f 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -122,8 +122,9 @@ #define c_make(C, ...) \ C##_from_n((C##_raw[])__VA_ARGS__, c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw)) -#define c_arraylen(a) (intptr_t)(sizeof(a)/sizeof 0[a]) #define c_litstrlen(literal) (c_sizeof("" literal) - 1) +#define c_arraylen(a) (c_ARRAYLEN(a) + c_static_assert(sizeof(a) != sizeof(uintptr_t))) +#define c_ARRAYLEN(a) (intptr_t)(sizeof(a)/sizeof 0[a]) // Non-owning c-string typedef const char* crawstr; diff --git a/include/stc/extend.h b/include/stc/extend.h index cbfc4a12..66b3ebd1 100644 --- a/include/stc/extend.h +++ b/include/stc/extend.h @@ -52,9 +52,9 @@ typedef struct { i_extend i_type get; -} c_PASTE(i_type, Ext); +} c_PASTE(i_type, _ext); -#define c_getcon(cptr) c_container_of(cptr, _cx_memb(Ext), get) +#define c_getcon(cptr) c_container_of(cptr, _cx_memb(_ext), get) #define i_is_forward #define _i_inc diff --git a/misc/examples/forfilter.c b/misc/examples/forfilter.c index daea68b9..fbb7280f 100644 --- a/misc/examples/forfilter.c +++ b/misc/examples/forfilter.c @@ -54,7 +54,7 @@ fn main() { void demo2(void) { IVec vector = {0}; - c_forfilter (x, crange, crange_object(INT64_MAX), + c_forfilter (x, crange, crange_obj(INT64_MAX), c_flt_skipwhile(x, *x.ref != 11) && (*x.ref % 2) != 0 && c_flt_take(x, 5) diff --git a/misc/examples/functor.c b/misc/examples/functor.c index 7417080b..c0a4f8e8 100644 --- a/misc/examples/functor.c +++ b/misc/examples/functor.c @@ -14,10 +14,10 @@ #define i_con cpque #include -void print_queue(const char* name, IPQueExt q) { +void print_queue(const char* name, IPQue_ext q) { // NB: make a clone because there is no way to traverse // priority_queue's content without erasing the queue. - IPQueExt copy = {q.less, IPQue_clone(q.get)}; + IPQue_ext copy = {q.less, IPQue_clone(q.get)}; for (printf("%s: \t", name); !IPQue_empty(©.get); IPQue_pop(©.get)) printf("%d ", *IPQue_top(©.get)); @@ -38,9 +38,9 @@ int main() printf("%d ", data[i]); puts(""); - IPQueExt q1 = {int_less}; // Max priority queue - IPQueExt minq1 = {int_greater}; // Min priority queue - IPQueExt q5 = {int_lambda}; // Using lambda to compare elements. + IPQue_ext q1 = {int_less}; // Max priority queue + IPQue_ext minq1 = {int_greater}; // Min priority queue + IPQue_ext q5 = {int_lambda}; // Using lambda to compare elements. c_forrange (i, n) IPQue_push(&q1.get, data[i]); diff --git a/misc/examples/prime.c b/misc/examples/prime.c index a576a85c..d0887353 100644 --- a/misc/examples/prime.c +++ b/misc/examples/prime.c @@ -42,7 +42,7 @@ int main(void) puts("\n"); puts("Show the last 50 primes using a temporary crange generator:"); - c_forfilter (i, crange, crange_object(n - 1, 0, -2), + c_forfilter (i, crange, crange_obj(n - 1, 0, -2), cbits_test(&primes, *i.ref/2) && c_flt_take(i, 50) ){ -- cgit v1.2.3