diff options
36 files changed, 256 insertions, 198 deletions
@@ -107,7 +107,7 @@ are familiar with them. All containers are generic/templated, except for **cstr* No casting is used, so containers are type-safe like templates in c++. A basic usage example: ```c #define i_type FVec // if not defined, vector type would be cvec_float -#define i_val float // element type +#define i_val float // container value type #include <stc/cvec.h> // defines the FVec type int main(void) { @@ -118,31 +118,34 @@ int main(void) { for (size_t i = 0; i < FVec_size(vec); ++i) printf(" %g", vec.data[i]); + FVec_drop(&vec); // free memory } ``` -An alternative way to write this code with STC is: +Below is an alternative way to write this code with STC. It uses three +macros: `c_auto`, `c_forarray`, and `c_foreach`. These macro not only +simplifies the code, but more importantly makes it less prone to errors, +while maintaining readability: ```c -int main(void) { - c_auto (FVec, vec) // RAII - specify create and free at one place. +int main() { + c_auto (FVec, vec) // RAII: init + free at one location in the code. { - float arr[] = {10.f, 20.f, 30.f}; + c_forarray (float, v, {10.f, 20.f, 30.f}) // use array literals. + FVec_push(&vec, *v); // alias for push_back. - for (int i=0; i<3; ++i) - FVec_push_back(&vec, arr[i]); - - c_foreach (i, FVec, vec) // generic iteration and element access + c_foreach (i, FVec, vec) // works for all containers. printf(" %g", *i.ref); } } ``` -In order to include two **cvec**s with different element types, include cvec.h twice. For struct, a `i_cmp` -compare function is required to enable sorting and searching (`<` and `==` operators is default and works -for integral types only). Alternatively, `#define i_opt c_no_cmp` to disable methods using comparison. +For struct element types, an `i_cmp` compare function is required (uses `<` and `==` by default, +but works only for integral types). Alternatively, `#define i_opt c_no_cmp` to disable sorting +and searching methods. + +Similarily, if an element destructor `i_valdrop` is defined, a `i_valclone` function is required as well, +or `#define i_opt c_no_clone` to disable container cloning methods. -Similarly, if a destructor `i_valdrop` is defined, either define a `i_valclone` clone function -or `#define i_opt c_no_clone` to disable cloning and emplace methods. Unless these requirements are met, -compile errors are generated. +In order to include two **cvec**s with different element types, include <stc/cvec.h> twice: ```c #define i_val struct One #define i_opt c_no_cmp @@ -489,7 +492,6 @@ Memory efficiency - `CNT_empty(const CNT *self)` - Now both **cstack** and **cbits** can be used with template `i_cap` parameter: `#define i_cap <NUM>`. They then use fixed sized arrays, and no heap allocated memory. - Renamed *cstr_rename_n()* => *cstr_rename_with_n()* as it could be confused with replacing n instances instead of n bytes. -- Renamed macro *c_apply_arr()* => *c_apply_array()* - Fixed bug in `csmap.h`: begin() on empty map was not fully initialized. ## Changes version 3.6 diff --git a/docs/carc_api.md b/docs/carc_api.md index 534e3da3..2604e13a 100644 --- a/docs/carc_api.md +++ b/docs/carc_api.md @@ -100,25 +100,26 @@ int main() // POPULATE the stack with shared pointers to Map: Map *map; map = Stack_push(&stack, Arc_make(Map_init()))->get; - c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, { + c_forarray (Map_raw, v, { {"Joey", 1990}, {"Mary", 1995}, - {"Joanna", 1992} - }); + {"Joanna", 1992}, + }) Map_emplace(map, v->first, v->second); + map = Stack_push(&stack, Arc_make(Map_init()))->get; - c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, { + c_forarray (Map_raw, v, { {"Rosanna", 2001}, {"Brad", 1999}, {"Jack", 1980} - }); + }) Map_emplace(map, v->first, v->second); // POPULATE the list: map = List_push_back(&list, Arc_make(Map_init()))->get; - c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, { + c_forarray (Map_raw, v, { {"Steve", 1979}, {"Rick", 1974}, {"Tracy", 2003} - }); + }) Map_emplace(map, v->first, v->second); // Share two Maps from the stack with the list by cloning(=sharing) the carc: List_push_back(&list, Arc_clone(stack.data[0])); diff --git a/docs/cbox_api.md b/docs/cbox_api.md index 4087ffa3..1119d930 100644 --- a/docs/cbox_api.md +++ b/docs/cbox_api.md @@ -84,10 +84,10 @@ int main() c_auto (IVec, vec) // declare and init vec, call drop at scope exit c_auto (ISet, set) // similar { - c_apply(v, IVec_push(&vec, *v), IBox, { + c_forarray (IBox, v, { IBox_make(2021), IBox_make(2012), IBox_make(2022), IBox_make(2015), - }); + }) IVec_push(&vec, *v); printf("vec:"); c_foreach (i, IVec, vec) diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 1a9fb30e..61791a20 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -13,7 +13,7 @@ The **checkauto** utility described below, ensures that the `c_auto*` macros are | `c_autovar (Type var=init, end...)` | Declare `var`. Defer `end...` to end of block | | `c_autoscope (init, end...)` | Execute `init`. Defer `end...` to end of block | | `c_autodefer (end...)` | Defer `end...` to end of block | -| `c_breakauto;` | Break out of a `c_auto*`-block/scope without memleak | +| `c_breakauto` or `continue` | Break out of a `c_auto*`-block/scope without memleak | For multiple variables, use either multiple **c_autovar** in sequence, or declare variable outside scope and use **c_autoscope**. Also, **c_auto** support up to 4 variables. @@ -84,44 +84,82 @@ int main() printf("%s\n", cstr_str(i.ref)); } ``` -### The checkauto utility program (for RAII) +### The **checkauto** utility program (for RAII) The **checkauto** program will check the source code for any misuses of the `c_auto*` macros which may lead to resource leakages. The `c_auto*`- macros are implemented as one-time executed **for-loops**, so any `return` or `break` appearing within such a block will lead to resource leaks, as it will disable -the cleanup/drop method to be called. However, a `break` may (originally) been intended to break the immediate -loop/switch outside the `c_auto` scope, so it would not work as intended in any case. The **checkauto** -tool will report any such misusages. In general, one should therefore first break out of any inner loops -with `break`, then use `c_breakauto` to break out of the `c_auto` scope(s). After this `return` may be used. +the cleanup/drop method to be called. A `break` may originally be intended to break a loop or switch +outside the `c_auto` scope. -Note that this is not a particular issue with the `c_auto*`-macros, as one must always make sure to unwind -temporary allocated resources before a `return` in C. However, by using `c_auto*`-macros, +NOTE: One must always make sure to unwind temporary allocated resources before a `return` in C. However, by using `c_auto*`-macros, - it is much easier to automatically detect misplaced return/break between resource acquisition and destruction. - it prevents forgetting to call the destructor at the end. + +The **checkauto** utility will report any misusages. The following example shows how to correctly break/return +from a `c_auto` scope: ```c -for (int i = 0; i<n; ++i) { - c_auto (List, list) { - List_push_back(&list, i); - if (cond1()) - break; // checkauto: Error - for (j = 0; j<m; ++j) { + int flag = 0; + for (int i = 0; i<n; ++i) { + c_auto (cstr, text) + c_auto (List, list) + { + for (int j = 0; j<m; ++j) { + List_push_back(&list, i*j); + if (cond1()) + break; // OK: breaks current for-loop only + } + // WRONG: if (cond2()) - break; // OK (breaks for-loop only) + break; // checkauto ERROR! break inside c_auto. + + if (cond3()) + return -1; // checkauto ERROR! return inside c_auto + + // CORRECT: + if (cond2()) { + flag = 1; // flag to break outer for-loop + continue; // cleanup and leave c_auto block + } + if (cond3()) { + flag = -1; // return -1 + continue; // cleanup and leave c_auto block + } + ... } - if (cond3()) - return; // checkauto: Error - } - if (cond4()) - return; // OK (outside c_auto) -} + // do the return/break outside of c_auto + if (flag < 0) return flag; + else if (flag > 0) break; + ... + } // for +``` + +### c_forarray, c_forarray_p +Iterate compound literal array elements +```c +// apply multiple push_backs +c_forarray (int, v, {1, 2, 3}) + cvec_i_push_back(&vec, *v); + +// insert in existing map +c_forarray (cmap_ii_raw, v, {{4, 5}, {6, 7}}) + cmap_ii_insert(&map, v->first, v->second); + +// even define an anonymous struct inside it (no commas allowed) +c_forarray (struct { int a; int b; }, v, {{1, 2}, {3, 4}, {5, 6}}) + printf("{%d %d} ", v->a, v->b); + +// `c_forarray_p` is required for pointer type elements +c_forarray_p (const char*, v, {"Hello", "crazy", "world"}) + cstack_s_push(&stk, *v); ``` ### c_foreach, c_forpair -| Usage | Description | -|:-------------------------------------------|:--------------------------------| -| `c_foreach (it, ctype, container)` | Iteratate all elements | -| `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) | -| `c_forpair (key, value, 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_forpair (key, val, ctype, container)` | Iterate with structured binding | ```c #define i_key int @@ -129,8 +167,9 @@ for (int i = 0; i<n; ++i) { #define i_tag ii #include <stc/csmap.h> ... -c_apply(v, csmap_ii_insert(&map, c_pair(v)), csmap_ii_value, - { {23,1}, {3,2}, {7,3}, {5,4}, {12,5} }); +c_forarray (csmap_ii_value, v, {{23,1}, {3,2}, {7,3}, {5,4}, {12,5}}) + csmap_ii_insert(&map, v->first, v->second); + c_foreach (i, csmap_ii, map) printf(" %d", i.ref->first); // out: 3 5 7 12 23 @@ -167,35 +206,20 @@ c_forrange (int, i, 30, 0, -5) printf(" %d", i); // 30 25 20 15 10 5 ``` -### c_apply, c_apply_array, c_pair, c_find_if, c_find_it -**c_apply** applies an expression on a container with each of the elements in the given array: -```c -// apply multiple push_backs -c_apply(v, cvec_i_push_back(&vec, v), int, {1, 2, 3}); - -// inserts to existing map -c_apply(v, cmap_i_insert(&map, c_pair(v)), cmap_i_raw, { {4, 5}, {6, 7} }); - -int arr[] = {1, 2, 3}; -c_apply_array(v, cvec_i_push_back(&vec, v), int, arr, c_arraylen(arr)); -``` -**c_find_if**, **c_find_in** searches linearily in containers using a predicate +### c_find_if, c_find_in +Search linearily in containers using a predicate ``` // NOTE: it.ref is NULL if not found, not cvec_i_end(&vec).ref // This makes it easier to test. cvec_i_iter it; -// Search the the whole vec -c_find_if(cvec_i, vec, it, *it.ref == 2); +// Search vec for first value > 2: +c_find_if(cvec_i, vec, it, *it.ref > 2); if (it.ref) printf("%d\n", *it.ref); -// Search from iter's current position -c_find_from(cvec_i, vec, it, index == 2); // index is internal in find_if. -if (it.ref) printf("%d\n", *it.ref); // 3 - -// Search in the range +// Search within a range: c_find_in(csmap_str, it1, it2, it, cstr_contains(*it.ref, "hello")); -cmap_str_erase_at(&map, it); // assume found +if (it.ref) cmap_str_erase_at(&map, it); ``` ### c_new, c_alloc, c_alloc_n, c_drop, c_make diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md index 1840468c..6826946c 100644 --- a/docs/cdeq_api.md +++ b/docs/cdeq_api.md @@ -110,7 +110,9 @@ int main() { printf(" %d", *i.ref); puts(""); - c_apply(v, cdeq_i_push_back(&q, *v), int, {1, 4, 5, 22, 33, 2}); + c_forarray (int, v, {1, 4, 5, 22, 33, 2}) + cdeq_i_push_back(&q, *v) + c_foreach (i, cdeq_i, q) printf(" %d", *i.ref); puts(""); diff --git a/docs/clist_api.md b/docs/clist_api.md index a3a59b7c..274c0f6f 100644 --- a/docs/clist_api.md +++ b/docs/clist_api.md @@ -152,7 +152,8 @@ Use of *erase_at()* and *erase_range()*: int main () { clist_i L = clist_i_init(); - c_apply(v, clist_i_push_back(&L, *v), int, {10, 20, 30, 40, 50}); + c_forarray (int, v, {10, 20, 30, 40, 50}) + clist_i_push_back(&L, *v); // 10 20 30 40 50 clist_i_iter it = clist_i_begin(&L); // ^ clist_i_next(&it); @@ -187,8 +188,8 @@ Splice `[30, 40]` from *L2* into *L1* before `3`: int main() { c_auto (clist_i, L1, L2) { - c_apply(v, clist_i_push_back(&L1, *v), int, {1, 2, 3, 4, 5}); - c_apply(v, clist_i_push_back(&L2, *v), int, {10, 20, 30, 40, 50}); + c_forarray (int, v, {1, 2, 3, 4, 5}) clist_i_push_back(&L1, *v); + c_forarray (int, v, {10, 20, 30, 40, 50}) clist_i_push_back(&L2, *v); clist_i_iter i = clist_i_advance(clist_i_begin(&L1), 2); clist_i_iter j1 = clist_i_advance(clist_i_begin(&L2), 2), j2 = clist_i_advance(j1, 2); diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 89d7f408..8fbfb30b 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -126,11 +126,11 @@ int main() // Create an unordered_map of three strings (that map to strings) c_auto (cmap_str, u) { - c_apply(v, cmap_str_emplace(&u, c_pair(v)), cmap_str_raw, { + c_forarray (cmap_str_raw, v, { {"RED", "#FF0000"}, {"GREEN", "#00FF00"}, {"BLUE", "#0000FF"} - }); + }) cmap_str_emplace(&u, v->first, v->second); // Iterate and print keys and values of unordered map c_foreach (n, cmap_str, u) { @@ -172,9 +172,9 @@ int main() c_auto (cmap_id, idnames) { - c_apply(v, cmap_id_emplace(&idnames, c_pair(v)), cmap_id_raw, { - {100, "Red"}, {110, "Blue"} - }); + c_forarray (cmap_id_raw, v, {{100, "Red"}, {110, "Blue"}}) + cmap_id_emplace(&idnames, v->first, v->second); + // replace existing mapped value: cmap_id_emplace_or_assign(&idnames, 110, "White"); diff --git a/docs/cset_api.md b/docs/cset_api.md index 95a236b1..2d3ab6e7 100644 --- a/docs/cset_api.md +++ b/docs/cset_api.md @@ -86,10 +86,11 @@ int main () c_auto (cset_str, first, second) c_auto (cset_str, third, fourth) { - c_apply(v, cset_str_emplace(&second, *v), const char*, - {"red", "green", "blue"}); - c_apply(v, cset_str_emplace(&third, *v), const char*, - {"orange", "pink", "yellow"}); + c_forarray_p (const char*, v, {"red", "green", "blue"}) + cset_str_emplace(&second, *v); + + c_forarray_p (const char*, v, {"orange", "pink", "yellow"}) + cset_str_emplace(&third, *v); cset_str_emplace(&fourth, "potatoes"); cset_str_emplace(&fourth, "milk"); @@ -98,6 +99,7 @@ int main () fifth = cset_str_clone(second); c_foreach (i, cset_str, third) cset_str_emplace(&fifth, cstr_str(i.ref)); + c_foreach (i, cset_str, fourth) cset_str_emplace(&fifth, cstr_str(i.ref)); } diff --git a/docs/csmap_api.md b/docs/csmap_api.md index 01b77cb4..c3e3f3ea 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -113,11 +113,11 @@ int main() // Create a sorted map of three strings (maps to string) c_auto (csmap_str, colors) // RAII { - c_apply(v, csmap_str_emplace(&colors, c_pair(v)), csmap_str_raw, { + c_forarray (csmap_str_raw, v, { {"RED", "#FF0000"}, {"GREEN", "#00FF00"}, {"BLUE", "#0000FF"} - }); + }) csmap_str_emplace(&colors, v->first, v->second); // Iterate and print keys and values of sorted map c_foreach (i, csmap_str, colors) { @@ -159,14 +159,15 @@ int main() csmap_id idnames = csmap_id_init(); c_autodefer (csmap_id_drop(&idnames)) { - c_apply(v, csmap_id_emplace(&idnames, c_pair(v)), csmap_id_raw, { - {100, "Red"}, - {110, "Blue"}, - }); + c_forarray (csmap_id_raw, v, {{100, "Red"}, {110, "Blue"}}) + csmap_id_emplace(&idnames, v->first, v->second); + // put replaces existing mapped value: csmap_id_emplace_or_assign(&idnames, 110, "White"); + // put a constructed mapped value into map: csmap_id_insert_or_assign(&idnames, 120, cstr_from_fmt("#%08x", col)); + // emplace adds only when key does not exist: csmap_id_emplace(&idnames, 100, "Green"); diff --git a/docs/csset_api.md b/docs/csset_api.md index 30e57ca4..f2667376 100644 --- a/docs/csset_api.md +++ b/docs/csset_api.md @@ -85,10 +85,11 @@ c_auto (csset_str, fifth) c_auto (csset_str, first, second) c_auto (csset_str, third, fourth) { - c_apply(v, csset_str_emplace(&second, *v), const char*, - {"red", "green", "blue"}); - c_apply(v, csset_str_emplace(&third, *v), const char*, - {"orange", "pink", "yellow"}); + c_forarray_p (const char*, v, {"red", "green", "blue"}) + csset_str_emplace(&second, *v); + + c_forarray_p (const char*, v, {"orange", "pink", "yellow"}) + csset_str_emplace(&third, *v); csset_str_emplace(&fourth, "potatoes"); csset_str_emplace(&fourth, "milk"); diff --git a/docs/cvec_api.md b/docs/cvec_api.md index db2bd8ce..a907c827 100644 --- a/docs/cvec_api.md +++ b/docs/cvec_api.md @@ -123,7 +123,8 @@ int main() cvec_int_push(&vec, 13); // Append a set of numbers - c_apply(v, cvec_int_push(&vec, *v), int, {7, 5, 16, 8}); + c_forarray (int, v, {7, 5, 16, 8}) + cvec_int_push(&vec, *v); printf("initial:"); c_foreach (k, cvec_int, vec) { diff --git a/examples/city.c b/examples/city.c index d70edbf7..c22693f9 100644 --- a/examples/city.c +++ b/examples/city.c @@ -52,13 +52,15 @@ int main(void) { struct City_s { const char *name, *country; float lat, lon; int pop; }; - c_apply(c, Cities_push(&cities, CityArc_make((City){cstr_from(c->name), cstr_from(c->country), - c->lat, c->lon, c->pop})), struct City_s, { + c_forarray (struct City_s, c, { {"New York", "US", 4.3, 23.2, 9000000}, {"Paris", "France", 4.3, 23.2, 9000000}, {"Berlin", "Germany", 4.3, 23.2, 9000000}, {"London", "UK", 4.3, 23.2, 9000000}, - }); + }) { + Cities_push(&cities, CityArc_make((City){cstr_from(c->name), cstr_from(c->country), + c->lat, c->lon, c->pop})); + } copy = Cities_clone(cities); // share each element! diff --git a/examples/convert.c b/examples/convert.c index 56cd1eca..5d58574d 100644 --- a/examples/convert.c +++ b/examples/convert.c @@ -17,11 +17,12 @@ int main() c_auto (cvec_str, keys, values) c_auto (clist_str, list) { - c_apply(v, cmap_str_emplace(&map, c_pair(v)), cmap_str_raw, { + c_forarray (cmap_str_raw, v, { {"green", "#00ff00"}, {"blue", "#0000ff"}, {"yellow", "#ffff00"}, - }); + }) cmap_str_emplace(&map, c_pair(v)); + puts("MAP:"); c_foreach (i, cmap_str, map) printf(" %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); diff --git a/examples/cpque.c b/examples/cpque.c index 00d2697e..5866f17b 100644 --- a/examples/cpque.c +++ b/examples/cpque.c @@ -31,17 +31,15 @@ int main() c_auto (ipque, q, q2, q3) // init() and defered drop() { less_fn = int_less; - c_forrange (i, n) - ipque_push(&q, data[i]); - + c_forrange (i, n) ipque_push(&q, data[i]); print_queue(q); less_fn = int_greater; - c_apply_array(v, ipque_push(&q2, *v), const int, data, n); + c_forrange (i, n) ipque_push(&q2, data[i]); print_queue(q2); less_fn = int_lambda; - c_apply_array(v, ipque_push(&q3, *v), const int, data, n); + c_forrange (i, n) ipque_push(&q3, data[i]); print_queue(q3); } } diff --git a/examples/csmap_erase.c b/examples/csmap_erase.c index 37d25f37..1c533a99 100644 --- a/examples/csmap_erase.c +++ b/examples/csmap_erase.c @@ -36,14 +36,14 @@ int main() c_auto (mymap, m2) { - // Fill in some data to test with, one at a time, using c_apply() - c_apply(v, mymap_emplace(&m2, c_pair(v)), mymap_raw, { + // Fill in some data to test with, one at a time + c_forarray (mymap_raw, v, { {10, "Bob"}, {11, "Rob"}, {12, "Robert"}, {13, "Bert"}, - {14, "Bobby"} - }); + {14, "Bobby"}, + }) mymap_emplace(&m2, v->first, v->second); puts("Starting data of map m2 is:"); printmap(m2); diff --git a/examples/csmap_find.c b/examples/csmap_find.c index f74f7fb9..ae8aeb85 100644 --- a/examples/csmap_find.c +++ b/examples/csmap_find.c @@ -45,8 +45,9 @@ int main() c_auto (csmap_istr, m1) c_auto (cvec_istr, v) { - c_apply(v, csmap_istr_emplace(&m1, c_pair(v)), csmap_istr_raw, - {{40, "Zr"}, {45, "Rh"}}); + c_forarray (csmap_istr_raw, v, {{40, "Zr"}, {45, "Rh"}}) + csmap_istr_emplace(&m1, c_pair(v)); + puts("The starting map m1 is (key, value):"); print_collection_csmap_istr(&m1); diff --git a/examples/csmap_insert.c b/examples/csmap_insert.c index 3a739cd8..7652fd59 100644 --- a/examples/csmap_insert.c +++ b/examples/csmap_insert.c @@ -101,9 +101,10 @@ int main() c_auto (csmap_ii, m4) { // Insert the elements from an initializer_list - c_apply(v, csmap_ii_insert(&m4, c_pair(v)), csmap_ii_raw, { - { 4, 44 }, { 2, 22 }, { 3, 33 }, { 1, 11 }, { 5, 55 } - }); + c_forarray (csmap_ii_raw, v, {{ 4, 44 }, { 2, 22 }, { 3, 33 }, + { 1, 11 }, { 5, 55 }}) + csmap_ii_insert(&m4, v->first, v->second); + puts("After initializer_list insertion, m4 contains:"); print_ii(m4); puts(""); diff --git a/examples/csset_erase.c b/examples/csset_erase.c index 7c8c1d97..9ca23aab 100644 --- a/examples/csset_erase.c +++ b/examples/csset_erase.c @@ -7,8 +7,9 @@ int main() { c_auto (csset_int, set) { - c_apply(v, csset_int_insert(&set, *v), - int, {30, 20, 80, 40, 60, 90, 10, 70, 50}); + c_forarray (int, v, {30, 20, 80, 40, 60, 90, 10, 70, 50}) + csset_int_insert(&set, *v); + c_foreach (k, csset_int, set) printf(" %d", *k.ref); puts(""); diff --git a/examples/inits.c b/examples/inits.c index a2fb51cb..9ce96dc9 100644 --- a/examples/inits.c +++ b/examples/inits.c @@ -67,7 +67,7 @@ int main(void) // CMAP CNT c_auto (cmap_cnt, countries) { - c_apply(v, cmap_cnt_emplace(&countries, c_pair(v)), cmap_cnt_raw, { + c_forarray (cmap_cnt_raw, v, { {"Norway", 100}, {"Denmark", 50}, {"Iceland", 10}, @@ -76,7 +76,8 @@ int main(void) {"Germany", 10}, {"Spain", 10}, {"France", 10}, - }); + }) cmap_cnt_emplace(&countries, v->first, v->second); + cmap_cnt_emplace(&countries, "Greenland", 0).ref->second += 20; cmap_cnt_emplace(&countries, "Sweden", 0).ref->second += 20; cmap_cnt_emplace(&countries, "Norway", 0).ref->second += 20; @@ -90,8 +91,9 @@ int main(void) // CVEC PAIR c_auto (cvec_ip, pairs1) { - c_apply(p, cvec_ip_push_back(&pairs1, *p), ipair_t, - {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); + c_forarray (ipair_t, p, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}) + cvec_ip_push_back(&pairs1, *p); + cvec_ip_sort(&pairs1); c_foreach (i, cvec_ip, pairs1) @@ -102,8 +104,9 @@ int main(void) // CLIST PAIR c_auto (clist_ip, pairs2) { - c_apply(p, clist_ip_push_back(&pairs2, *p), ipair_t, - {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); + c_forarray (ipair_t, p, {{5, 6}, {3, 4}, {1, 2}, {7, 8}}) + clist_ip_push_back(&pairs2, *p); + clist_ip_sort(&pairs2); c_foreach (i, clist_ip, pairs2) diff --git a/examples/list.c b/examples/list.c index d76490f8..2dc19704 100644 --- a/examples/list.c +++ b/examples/list.c @@ -39,7 +39,9 @@ int main() { puts(""); clist_fx_clear(&list); - c_apply(v, clist_fx_push_back(&list, *v), int, {10, 20, 30, 40, 30, 50}); + c_forarray (int, v, {10, 20, 30, 40, 30, 50}) + clist_fx_push_back(&list, *v); + const double* v = clist_fx_get(&list, 30); printf("found: %f\n", *v); c_foreach (i, clist_fx, list) printf(" %g", *i.ref); diff --git a/examples/list_erase.c b/examples/list_erase.c index ad062131..9155e38d 100644 --- a/examples/list_erase.c +++ b/examples/list_erase.c @@ -8,7 +8,9 @@ int main () { c_auto (clist_int, L) { - c_apply(i, clist_int_push_back(&L, *i), int, {10, 20, 30, 40, 50}); + c_forarray (int, i, {10, 20, 30, 40, 50}) + clist_int_push_back(&L, *i); + c_foreach (x, clist_int, L) printf("%d ", *x.ref); puts(""); diff --git a/examples/list_splice.c b/examples/list_splice.c index cc041a73..8ba022f8 100644 --- a/examples/list_splice.c +++ b/examples/list_splice.c @@ -18,8 +18,12 @@ int main () { c_auto (clist_i, list1, list2) { - c_apply(v, clist_i_push_back(&list1, *v), int, {1, 2, 3, 4, 5}); - c_apply(v, clist_i_push_back(&list2, *v), int, {10, 20, 30, 40, 50}); + c_forarray (int, v, {1, 2, 3, 4, 5}) + clist_i_push_back(&list1, *v); + + c_forarray (int, v, {10, 20, 30, 40, 50}) + clist_i_push_back(&list2, *v); + print_ilist("list1:", list1); print_ilist("list2:", list2); diff --git a/examples/lower_bound.c b/examples/lower_bound.c index a1de1cfd..c8beed6f 100644 --- a/examples/lower_bound.c +++ b/examples/lower_bound.c @@ -13,9 +13,8 @@ int main() { int key, *res; - c_apply(t, cvec_int_push(&vec, *t), int, { - 40, 600, 1, 7000, 2, 500, 30, - }); + c_forarray (int, t, {40, 600, 1, 7000, 2, 500, 30}) + cvec_int_push(&vec, *t); cvec_int_sort(&vec); @@ -41,9 +40,8 @@ int main() { int key, *res; - c_apply(t, csset_int_push(&set, *t), int, { - 40, 600, 1, 7000, 2, 500, 30, - }); + c_forarray (int, t, {40, 600, 1, 7000, 2, 500, 30}) + csset_int_push(&set, *t); key = 500; res = csset_int_lower_bound(&set, key).ref; diff --git a/examples/music_arc.c b/examples/music_arc.c index e1e715a1..ac730bc3 100644 --- a/examples/music_arc.c +++ b/examples/music_arc.c @@ -30,20 +30,20 @@ void example3() { c_auto (SongVec, vec, vec2) { - c_apply(v, SongVec_push_back(&vec, *v), SongPtr, { + c_forarray (SongPtr, v, { SongPtr_make(Song_new("Bob Dylan", "The Times They Are A Changing")), SongPtr_make(Song_new("Aretha Franklin", "Bridge Over Troubled Water")), SongPtr_make(Song_new("Thalia", "Entre El Mar y Una Estrella")) - }); + }) SongVec_push_back(&vec, *v); c_foreach (s, SongVec, vec) if (!cstr_equals(s.ref->get->artist, "Bob Dylan")) SongVec_push_back(&vec2, SongPtr_clone(*s.ref)); - c_apply(v, SongVec_push_back(&vec2, *v), SongPtr, { + c_forarray (SongPtr, v, { SongPtr_make(Song_new("Michael Jackson", "Billie Jean")), SongPtr_make(Song_new("Rihanna", "Stay")), - }); + }) SongVec_push_back(&vec2, *v); c_foreach (s, SongVec, vec2) printf("%s - %s: refs %lu\n", cstr_str(&s.ref->get->artist), diff --git a/examples/new_list.c b/examples/new_list.c index 9bbbd8ce..e760a093 100644 --- a/examples/new_list.c +++ b/examples/new_list.c @@ -39,8 +39,9 @@ int main() clist_i32_push_back(&lst, 123); c_auto (clist_pnt, plst) { - c_apply(v, clist_pnt_push_back(&plst, *v), - Point, {{42, 14}, {32, 94}, {62, 81}}); + c_forarray (Point, v, {{42, 14}, {32, 94}, {62, 81}}) + clist_pnt_push_back(&plst, *v); + clist_pnt_sort(&plst); c_foreach (i, clist_pnt, plst) @@ -49,8 +50,9 @@ int main() } c_auto (clist_float, flst) { - c_apply(v, clist_float_push_back(&flst, *v), - float, {123.3f, 321.2f, -32.2f, 78.2f}); + c_forarray (float, v, {123.3f, 321.2f, -32.2f, 78.2f}) + clist_float_push_back(&flst, *v); + c_foreach (i, clist_float, flst) printf(" %g", *i.ref); } diff --git a/examples/new_map.c b/examples/new_map.c index b0752d53..c94c2b44 100644 --- a/examples/new_map.c +++ b/examples/new_map.c @@ -49,23 +49,24 @@ int main() { cmap_int_insert(&map, 123, 321); - c_apply(v, cmap_pnt_insert(&pmap, c_pair(v)), cmap_pnt_raw, { - {{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3} - }); + c_forarray (cmap_pnt_raw, v, {{{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}}) + cmap_pnt_insert(&pmap, v->first, v->second); + c_foreach (i, cmap_pnt, pmap) printf(" (%d, %d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second); puts(""); - c_apply(v, cmap_str_emplace(&smap, c_pair(v)), cmap_str_raw, { + c_forarray (cmap_str_raw, v, { {"Hello, friend", "long time no see"}, {"So long, friend", "see you around"}, - }); + }) cmap_str_emplace(&smap, v->first, v->second); - c_apply(v, cset_str_emplace(&sset, *v), const char*, { + c_forarray_p (const char*, v, { "Hello, friend", "Nice to see you again", "So long, friend", - }); + }) cset_str_emplace(&sset, *v); + c_foreach (i, cset_str, sset) printf(" %s\n", cstr_str(i.ref)); } diff --git a/examples/new_smap.c b/examples/new_smap.c index 368775dc..7c2ddb35 100644 --- a/examples/new_smap.c +++ b/examples/new_smap.c @@ -47,22 +47,24 @@ int main() } c_auto (PMap, pmap) { - c_apply(v, PMap_insert(&pmap, c_pair(v)), PMap_value, { + c_forarray (PMap_value, v, { {{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}, - }); + }) PMap_insert(&pmap, c_pair(v)); + c_forpair (p, i, PMap, pmap) printf(" (%d,%d: %d)", _.p->x, _.p->y, *_.i); puts(""); } c_auto (SMap, smap) { - c_apply(v, SMap_emplace(&smap, c_pair(v)), SMap_raw, { + c_forarray (SMap_raw, v, { {"Hello, friend", "this is the mapped value"}, {"The brown fox", "jumped"}, {"This is the time", "for all good things"}, - }); + }) SMap_emplace(&smap, c_pair(v)); + c_forpair (i, j, SMap, smap) printf(" (%s: %s)\n", cstr_str(_.i), cstr_str(_.j)); } diff --git a/examples/person_arc.c b/examples/person_arc.c index d0af690e..272a3f72 100644 --- a/examples/person_arc.c +++ b/examples/person_arc.c @@ -54,7 +54,8 @@ int main() Persons_push_back(&vec, PSPtr_make(Person_new("Audrey", "Home"))); // Clone/share p and q to the vector - c_apply(v, Persons_push_back(&vec, PSPtr_clone(*v)), PSPtr, {p, q}); + c_forarray (PSPtr, v, {p, q}) + Persons_push_back(&vec, PSPtr_clone(*v)); c_foreach (i, Persons, vec) printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last)); diff --git a/examples/phonebook.c b/examples/phonebook.c index eebc8008..1455c978 100644 --- a/examples/phonebook.c +++ b/examples/phonebook.c @@ -39,19 +39,21 @@ void print_phone_book(cmap_str phone_book) int main(int argc, char **argv) { c_auto (cset_str, names) { - c_apply(v, cset_str_emplace(&names, *v), const char*, - {"Hello", "Cool", "True"}); - c_foreach (i, cset_str, names) printf("%s ", cstr_str(i.ref)); + c_forarray_p (const char*, v, {"Hello", "Cool", "True"}) + cset_str_emplace(&names, *v); + + c_foreach (i, cset_str, names) + printf("%s ", cstr_str(i.ref)); puts(""); } c_auto (cmap_str, phone_book) { - c_apply(v, cmap_str_emplace(&phone_book, c_pair(v)), cmap_str_raw, { + c_forarray (cmap_str_raw, v, { {"Lilia Friedman", "(892) 670-4739"}, {"Tariq Beltran", "(489) 600-7575"}, {"Laiba Juarez", "(303) 885-5692"}, {"Elliott Mooney", "(945) 616-4482"}, - }); + }) cmap_str_emplace(&phone_book, c_pair(v)); printf("Phone book:\n"); print_phone_book(phone_book); diff --git a/examples/priority.c b/examples/priority.c index 7ba9e59b..b8766a77 100644 --- a/examples/priority.c +++ b/examples/priority.c @@ -20,7 +20,8 @@ int main() { cpque_i_push(&heap, stc64_uniform(&rng, &dist)); // push some negative numbers too. - c_apply(v, cpque_i_push(&heap, *v), int, {-231, -32, -873, -4, -343}); + c_forarray (int, v, {-231, -32, -873, -4, -343}) + cpque_i_push(&heap, *v); c_forrange (N) cpque_i_push(&heap, stc64_uniform(&rng, &dist)); diff --git a/examples/shape.c b/examples/shape.c index b052d921..4c2a7542 100644 --- a/examples/shape.c +++ b/examples/shape.c @@ -145,11 +145,11 @@ int main(void) Polygon* pol1 = Polygon_new(); Polygon* pol2 = Polygon_new(); - c_apply(p, Polygon_addPoint(pol1, *p), Point, - {{50, 72}, {123, 73}, {127, 201}, {828, 333}}); + c_forarray (Point, p, {{50, 72}, {123, 73}, {127, 201}, {828, 333}}) + Polygon_addPoint(pol1, *p); - c_apply(p, Polygon_addPoint(pol2, *p), Point, - {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}); + c_forarray (Point, p, {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}) + Polygon_addPoint(pol2, *p); Shapes_push(&shapes, &tri1->shape); Shapes_push(&shapes, &pol1->shape); diff --git a/examples/sidebyside.cpp b/examples/sidebyside.cpp index f2021436..282beefb 100644 --- a/examples/sidebyside.cpp +++ b/examples/sidebyside.cpp @@ -47,8 +47,8 @@ int main() { c_auto (cmap_si, food) { - c_apply(v, cmap_si_emplace(&food, c_pair(v)), cmap_si_raw, - {{"burger", 5}, {"pizza", 12}, {"steak", 15}}); + c_forarray (cmap_si_raw, v, {{"burger", 5}, {"pizza", 12}, {"steak", 15}}) + cmap_si_emplace(&food, c_pair(v)); c_foreach (i, cmap_si, food) printf("%s, %d\n", cstr_str(&i.ref->first), i.ref->second); diff --git a/examples/vikings.c b/examples/vikings.c index 2cef1991..667c4426 100644 --- a/examples/vikings.c +++ b/examples/vikings.c @@ -51,11 +51,12 @@ static inline RViking Viking_toraw(const Viking* vp) { int main() { c_auto (Vikings, vikings) { - c_apply(v, Vikings_emplace(&vikings, c_pair(v)), Vikings_raw, { + c_forarray (Vikings_raw, v, { {{"Einar", "Norway"}, 20}, {{"Olaf", "Denmark"}, 24}, {{"Harald", "Iceland"}, 12}, - }); + }) Vikings_emplace(&vikings, c_pair(v)); + RViking bjorn = {"Bjorn", "Sweden"}; Vikings_emplace_or_assign(&vikings, bjorn, 10); diff --git a/examples/words.c b/examples/words.c index 8a86ba7f..888f7abb 100644 --- a/examples/words.c +++ b/examples/words.c @@ -13,10 +13,10 @@ int main1() c_auto (cvec_str, words) c_auto (cmap_str, word_map) { - c_apply(v, cvec_str_emplace_back(&words, *v), const char*, { + c_forarray_p (const char*, v, { "this", "sentence", "is", "not", "a", "sentence", "this", "sentence", "is", "a", "hoax" - }); + }) cvec_str_emplace_back(&words, *v); c_foreach (w, cvec_str, words) { cmap_str_emplace(&word_map, cstr_str(w.ref), 0).ref->second += 1; diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 449bceec..e2c63b8c 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -173,10 +173,10 @@ STC_INLINE char* c_strnstrn(const char *s, const char *needle, #define c_forrange1(stop) c_forrange4(size_t, _c_i, 0, stop) #define c_forrange2(i, stop) c_forrange4(size_t, i, 0, stop) #define c_forrange3(itype, i, stop) c_forrange4(itype, i, 0, stop) -#define c_forrange4(itype, i, start, stop) for (itype i=start, _c_end=stop; i < _c_end; ++i) +#define c_forrange4(itype, i, start, stop) for (itype i=start, _end=stop; i < _end; ++i) #define c_forrange5(itype, i, start, stop, step) \ - for (itype i=start, _c_inc=step, _c_end=(stop) - (0 < _c_inc) \ - ; (i <= _c_end) == (0 < _c_inc); i += _c_inc) + for (itype i=start, _inc=step, _end=(stop) - (0 < _inc) \ + ; (i <= _end) == (0 < _inc); i += _inc) #define c_autovar(...) c_MACRO_OVERLOAD(c_autovar, __VA_ARGS__) #define c_autovar2(declvar, drop) for (declvar, **_c_i = NULL; !_c_i; ++_c_i, drop) @@ -204,26 +204,26 @@ STC_INLINE char* c_strnstrn(const char *s, const char *needle, *b = (n)*sizeof *b > (BYTES) ? c_alloc_n(type, n) : _c_b \ ; b; b != _c_b ? c_free(b) : (void)0, b = NULL) +// [deprecated] use c_forarray. #define c_apply(v, action, T, ...) do { \ - typedef T _c_T; \ - _c_T _c_arr[] = __VA_ARGS__, *v = _c_arr; \ - const _c_T *_c_end = v + c_arraylen(_c_arr); \ - while (v != _c_end) { action; ++v; } \ + typedef T _T; \ + _T _arr[] = __VA_ARGS__, *v = _arr; \ + const _T *_end = v + c_arraylen(_arr); \ + while (v != _end) { action; ++v; } \ } while (0) -#define c_apply_array(v, action, T, arr, n) do { \ - typedef T _c_T; \ - _c_T *v = arr, *_c_end = v + (n); \ - while (v != _c_end) { action; ++v; } \ -} while (0) +#define c_forarray(T, v, ...) \ + for (T _a[] = __VA_ARGS__, *v = _a; v != _a + c_arraylen(_a); ++v) + +#define c_forarray_p(T, v, ...) \ + for (T _a[] = __VA_ARGS__, **v = _a; v != _a + c_arraylen(_a); ++v) #define c_pair(v) (v)->first, (v)->second -#define c_drop(C, ...) c_apply(_p, C##_drop(*_p), C*, {__VA_ARGS__}) +#define c_drop(C, ...) do { c_forarray_p(C*, _p, {__VA_ARGS__}) C##_drop(*_p); } while(0) #define c_find_if(C, cnt, it, pred) \ c_find_in(C, C##_begin(&cnt), C##_end(&cnt), it, pred) -#define c_find_from(C, cnt, it, pred) \ - c_find_in(C, it, C##_end(&cnt), it, pred) + // NB: it.ref == NULL when not found, not end.ref: #define c_find_in(C, start, end, it, pred) do { \ size_t index = 0; \ @@ -232,18 +232,6 @@ STC_INLINE char* c_strnstrn(const char *s, const char *needle, ++index; \ if (it.ref == _end.ref) it.ref = NULL; \ } while (0) - -#if defined(__SIZEOF_INT128__) - #define c_umul128(a, b, lo, hi) \ - do { __uint128_t _z = (__uint128_t)(a)*(b); \ - *(lo) = (uint64_t)_z, *(hi) = _z >> 64; } while(0) -#elif defined(_MSC_VER) && defined(_WIN64) - #include <intrin.h> - #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi))) -#elif defined(__x86_64__) - #define c_umul128(a, b, lo, hi) \ - asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b)) -#endif #endif // CCOMMON_H_INCLUDED #undef STC_API diff --git a/include/stc/crandom.h b/include/stc/crandom.h index 0e34e850..49f6d3ae 100644 --- a/include/stc/crandom.h +++ b/include/stc/crandom.h @@ -145,6 +145,18 @@ STC_DEF stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high) { return dist; } +#if defined(__SIZEOF_INT128__) + #define c_umul128(a, b, lo, hi) \ + do { __uint128_t _z = (__uint128_t)(a)*(b); \ + *(lo) = (uint64_t)_z, *(hi) = _z >> 64; } while(0) +#elif defined(_MSC_VER) && defined(_WIN64) + #include <intrin.h> + #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi))) +#elif defined(__x86_64__) + #define c_umul128(a, b, lo, hi) \ + asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b)) +#endif + /* Int uniform distributed RNG, range [low, high]. */ STC_DEF int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* d) { #ifdef c_umul128 |
