diff options
| author | Tyge Løvset <[email protected]> | 2022-08-08 08:25:29 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-08-08 08:25:29 +0200 |
| commit | 9e529c1ba7e575881656265b468b35863ae9e82a (patch) | |
| tree | 5acb7d6b29eda46abee7410ed0e629a5842853b3 | |
| parent | 8884747775e922e20b0646eeb29ce8a2b4a1c7cc (diff) | |
| parent | 010f954e739ca781fa3c71668938e2d2ca314662 (diff) | |
| download | STC-modified-9e529c1ba7e575881656265b468b35863ae9e82a.tar.gz STC-modified-9e529c1ba7e575881656265b468b35863ae9e82a.zip | |
Merge pull request #32 from tylov/v4_dev
V4.0 BETA
53 files changed, 556 insertions, 470 deletions
@@ -3,10 +3,13 @@ STC - Smart Template Containers for C ===================================== -News: Version 3.9 released (July 2022) +News: Version 4.0 BETA (Aug 2022) --------------------------------------- -- "ccommon API: `c_forrange` with 3 to 5 args swapped 1st <-> 2nd. -- **csview** fully inlined and tokenizer fix +- Removed macro `c_apply` - usage was not intuitive. +- `c_forarray` macro replaces usages of `c_apply`. +- Minor changes in API of **cregex**, and improved documentation. +- Version 3.9: + - "ccommon API: `c_forrange` with 3 to 5 args swapped 1st <-> 2nd. - Version 3.8: - "Officially" added **cregex** - powerful regular expressions. - Added back **coption** - command line argument parsing. @@ -107,7 +110,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,28 +121,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 and often preferred way to write this code with STL 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 destruct at one place. +int main() { + c_auto (FVec, vec) // RAII: init + free at one location in the code. { - c_apply(v, FVec_push_back(&vec, *v), float, {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. - 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 @@ -189,7 +198,7 @@ int Point_cmp(const struct Point* a, const struct Point* b) { #include <stc/csmap.h> // csmap_int: sorted map int => int int main(void) { - // define six containers with automatic call of init and drop (destruction after scope exit) + /* define six containers with automatic call of init and drop (destruction after scope exit) */ c_auto (cset_int, set) c_auto (cvec_pnt, vec) c_auto (cdeq_int, deq) @@ -197,24 +206,21 @@ int main(void) { c_auto (cstack_int, stk) c_auto (csmap_int, map) { - // add some elements to each container - c_apply(v, cset_int_insert(&set, *v), int, {10, 20, 30}); - c_apply(v, cvec_pnt_push_back(&vec, *v), struct Point, { {10, 1}, {20, 2}, {30, 3} }); - c_apply(v, cdeq_int_push_back(&deq, *v), int, {10, 20, 30}); - c_apply(v, clist_int_push_back(&lst, *v), int, {10, 20, 30}); - c_apply(v, cstack_int_push(&stk, *v), int, {10, 20, 30}); - c_apply(v, csmap_int_insert(&map, c_pair(v)), - csmap_int_raw, { {20, 2}, {10, 1}, {30, 3} }); - - // add one more element to each container - cset_int_insert(&set, 40); - cvec_pnt_push_back(&vec, (struct Point){40, 4}); - cdeq_int_push_front(&deq, 5); - clist_int_push_front(&lst, 5); - cstack_int_push(&stk, 40); - csmap_int_insert(&map, 40, 4); - - // find an element in each container + int nums[4] = {10, 20, 30, 40}; + struct Point pts[4] = {{10, 1}, {20, 2}, {30, 3}, {40, 4}}; + int pairs[4][2] = {{20, 2}, {10, 1}, {30, 3}, {40, 4}}; + + /* add some elements to each container */ + for (int i = 0; i < 4; ++i) { + cset_int_insert(&set, nums[i]); + cvec_pnt_push(&vec, pts[i]); + cdeq_int_push_back(&deq, nums[i]); + clist_int_push_back(&lst, nums[i]); + cstack_int_push(&set, nums[i]); + csmap_int_insert(&map, pairs[i][0], pairs[i][1]); + } + + /* find an element in each container (except cstack) */ cset_int_iter i1 = cset_int_find(&set, 20); cvec_pnt_iter i2 = cvec_pnt_find(&vec, (struct Point){20, 2}); cdeq_int_iter i3 = cdeq_int_find(&deq, 20); @@ -223,7 +229,7 @@ int main(void) { printf("\nFound: %d, (%g, %g), %d, %d, [%d: %d]\n", *i1.ref, i2.ref->x, i2.ref->y, *i3.ref, *i4.ref, i5.ref->first, i5.ref->second); - // erase the elements found + /* erase the elements found */ cset_int_erase_at(&set, i1); cvec_pnt_erase_at(&vec, i2); cdeq_int_erase_at(&deq, i3); @@ -489,7 +495,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 e870c8c6..45caeb93 100644 --- a/docs/clist_api.md +++ b/docs/clist_api.md @@ -101,34 +101,35 @@ clist_X_value clist_X_value_clone(clist_X_value val); Interleave *push_front()* / *push_back()* then *sort()*: ```c +#define i_type DList #define i_val double -#define i_tag d +#define i_extern // link with sort() fn. #include <stc/clist.h> #include <stdio.h> int main() { - clist_d list = clist_d_init(); - c_apply(v, clist_d_push_back(&list, *v), double, { - 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0 - }); + DList list = DList_init(); + + c_forarray (double, v, {10., 20., 30., 40., 50., 60., 70., 80., 90.}) + DList_push_back(&list, *v); c_forrange (int, i, 1, 10) { - if (i & 1) clist_d_push_front(&list, (float) i); - else clist_d_push_back(&list, (float) i); + if (i & 1) DList_push_front(&list, (double) i); + else DList_push_back(&list, (double) i); } printf("initial: "); - c_foreach (i, clist_d, list) + c_foreach (i, DList, list) printf(" %g", *i.ref); - clist_d_sort(&list); // mergesort O(n*log n) + DList_sort(&list); // mergesort O(n*log n) printf("\nsorted: "); - c_foreach (i, clist_d, list) + c_foreach (i, DList, list) printf(" %g", *i.ref); - clist_d_drop(&list); + DList_drop(&list); } ``` Output: @@ -150,7 +151,9 @@ 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); @@ -161,7 +164,8 @@ int main () it = clist_i_erase_range(&L, it, end); // 10 30 // ^ printf("mylist contains:"); - c_foreach (x, clist_i, L) printf(" %d", *x.ref); + c_foreach (x, clist_i, L) + printf(" %d", *x.ref); puts(""); clist_i_drop(&L); @@ -185,16 +189,20 @@ 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); clist_i_splice_range(&L1, i, &L2, j1, j2); - c_foreach (i, clist_i, L1) printf(" %d", *i.ref); puts(""); - c_foreach (i, clist_i, L2) printf(" %d", *i.ref); puts(""); + c_foreach (i, clist_i, L1) + printf(" %d", *i.ref); puts(""); + c_foreach (i, clist_i, L2) + printf(" %d", *i.ref); puts(""); } } ``` diff --git a/docs/cmap_api.md b/docs/cmap_api.md index bb760b4d..9a4a2ef1 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"); @@ -264,8 +264,8 @@ Output: 1: { 100, 0, 0 } ``` -### Example 5 -Advanced 1: Key type is struct. +### Example 5: Advanced +Key type is struct. ```c #include <stc/cstr.h> @@ -300,10 +300,10 @@ static inline void Viking_drop(Viking* vk) { #define i_key_bind Viking #define i_val int /* - i_key_bind auto-binds: + i_key_bind makes these defines, unless they are already defined: #define i_cmp Viking_cmp #define i_hash Viking_hash - #define i_keyfrom Viking_clone + #define i_keyclone Viking_clone #define i_keydrop Viking_drop */ #include <stc/cmap.h> @@ -338,8 +338,8 @@ Einar of Norway has 25 hp Harald of Iceland has 12 hp ``` -### Example 6 -Advanced 2: In example 5 we needed to construct a lookup key which allocated strings, and then had to free it after. +### Example 6: More advanced +In example 5 we needed to construct a lookup key which allocated strings, and then had to free it after. In this example we use rawtype feature to make it even simpler to use. Note that we must use the emplace() methods to add "raw" type entries (otherwise compile error): ```c @@ -354,7 +354,7 @@ static inline void Viking_drop(Viking* v) { c_drop(cstr, &v->name, &v->country); } -// Define Viking raw struct with hash, equalto, and convertion functions between Viking and RViking structs: +// Define Viking raw struct with cmp, hash, and convertion functions between Viking and RViking structs: typedef struct RViking { const char* name; @@ -366,14 +366,10 @@ static inline int RViking_cmp(const RViking* rx, const RViking* ry) { return c ? c : strcmp(rx->country, ry->country); } -static inline Viking Viking_clone(RViking v) { - v.name = cstr_clone(v.name), v.country = cstr_clone(v.country); - return vk; -} - static inline Viking Viking_from(RViking raw) { return (Viking){cstr_from(raw.name), cstr_from(raw.country)}; } + static inline RViking Viking_toraw(const Viking* vp) { return (RViking){cstr_str(&vp->name), cstr_str(&vp->country)}; } @@ -382,34 +378,33 @@ static inline RViking Viking_toraw(const Viking* vp) { #define i_type Vikings #define i_key_bind Viking #define i_keyraw RViking -#define i_keyfrom Viking_from // optional to enable emplace funcs. +#define i_keyfrom Viking_from #define i_hash(rp) (c_strhash(rp->name) ^ c_strhash(rp->country)) #define i_val int /* - i_key_bind macro auto-binds these functions: - #define i_hash RViking_hash + i_key_bind makes these defines, unless they are already defined: #define i_cmp RViking_cmp - #define i_keyclone Viking_clone - #define i_keyto Viking_toraw // because i_keyraw type is defined + //#define i_hash RViking_hash // already defined above. + #define i_keyclone c_derived_keyclone // because i_keyfrom is defined. + #define i_keyto Viking_toraw // because i_keyraw type is defined #define i_keydrop Viking_drop */ #include <stc/cmap.h> int main() { - c_auto (Vikings, vikings) { - c_apply(v, Vikings_emplace(&vikings, c_pair(v)), Vikings_raw, { - { {"Einar", "Norway"}, 20 }, - { {"Olaf", "Denmark"}, 24 }, - { {"Harald", "Iceland"}, 12 }, - }); - Vikings_emplace_or_assign(&vikings, (RViking){"Bjorn", "Sweden"}, 10); + c_auto (Vikings, vikings) + { + Vikings_emplace(&vikings, (RViking){"Einar", "Norway"}, 20); + Vikings_emplace(&vikings, (RViking){"Olaf", "Denmark"}, 24); + Vikings_emplace(&vikings, (RViking){"Harald", "Iceland"}, 12); + Vikings_emplace(&vikings, (RViking){"Björn", "Sweden"}, 10); Vikings_value *v = Vikings_get_mut(&vikings, (RViking){"Einar", "Norway"}); if (v) v->second += 3; // add 3 hp points to Einar - c_forpair (vik, health, Vikings, vikings) { - printf("%s of %s has %d hp\n", cstr_str(&_.vik->name), cstr_str(&_.vik->country), *_.health); + c_forpair (vk, hp, Vikings, vikings) { + printf("%s of %s has %d hp\n", cstr_str(&_.vk->name), cstr_str(&_.vk->country), *_.hp); } } } diff --git a/docs/cpque_api.md b/docs/cpque_api.md index 12f5c3bc..8b990be8 100644 --- a/docs/cpque_api.md +++ b/docs/cpque_api.md @@ -75,10 +75,14 @@ int main() // Declare heap, with defered drop() c_auto (cpque_i, heap) { - // Push ten million random numbers to priority queue, plus some negative ones. + // Push ten million random numbers to priority queue. c_forrange (N) cpque_i_push(&heap, stc64_uniform(&rng, &dist)); - c_apply(v, cpque_i_push(&heap, *v), int, {-231, -32, -873, -4, -343}); + + // Add some negative ones. + int nums[] = {-231, -32, -873, -4, -343}; + c_forrange (i, c_arraylen(nums)) + cpque_i_push(&heap, nums[i]); // Extract and display the fifty smallest. c_forrange (50) { diff --git a/docs/cregex_api.md b/docs/cregex_api.md index a71ae31b..34278905 100644 --- a/docs/cregex_api.md +++ b/docs/cregex_api.md @@ -37,15 +37,15 @@ int cregex_find_sv(csview input, const cregex* re, csview match[]); // takes string pattern instead of re. (for one-time matches) int cregex_find_p(const char* input, const char* pattern, csview match[], int cmflags); -bool cregex_is_match(const char* input, const cregex* re, int mflags); +bool cregex_is_match(const char* input, const cregex* re); -cstr cregex_replace(const char* input, const cregex* re, const char* replace); -cstr cregex_replace_re(const char* input, const cregex* re, const char* replace, // extended args: - bool (*mfun)(int grp, csview match, cstr* mstr), unsigned count, int rflags); +cstr cregex_replace(const char* input, const cregex* re, const char* replace, unsigned count); +cstr cregex_replace_ex(const char* input, const cregex* re, const char* replace, unsigned count, + int rflags, bool (*mfun)(int grp, csview match, cstr* mstr)); // takes string pattern instead of re -cstr cregex_replace_p(const char* input, const char* pattern, const char* replace); -cstr cregex_replace_pe(const char* input, const char* pattern, const char* replace, - bool (*mfun)(int grp, csview match, cstr* mstr), unsigned count, int crflags); +cstr cregex_replace_p(const char* input, const char* pattern, const char* replace, unsigned count); +cstr cregex_replace_pe(const char* input, const char* pattern, const char* replace, unsigned count, + int crflags, bool (*mfun)(int grp, csview match, cstr* mstr)); void cregex_drop(cregex* self); // destroy ``` @@ -125,6 +125,26 @@ if (cregex_find_p(input, pattern, match, 0)) To compile, use: `gcc first_match.c src/cregex.c src/utf8code.c`. In order to use a callback function in the replace call, see `examples/regex_replace.c`. +### Iterate through matches, c_foreach_match + +To iterate multiple matches in an input string, you may use: +```c +csview match[5] = {0}; +while (cregex_find(input, &re, match, cre_m_next) == cre_success) { + c_forrange (int, i, cregex_captures(&re)) + printf("submatch %d: %.*s\n", i, c_ARGsv(match[i])); + puts(""); +} +``` +There is also a safe macro that simplifies it a bit: +```c +c_foreach_match (m, &re, input) { + c_forrange (int, i, cregex_captures(&re)) + printf("submatch %d: %.*s\n", i, c_ARGsv(m.ref[i])); + puts(""); +} +``` + ## Using cregex in a project **cregex** uses the following files: 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/cstr_api.md b/docs/cstr_api.md index a05dc1ae..e4edb4c5 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -49,7 +49,7 @@ void cstr_clear(cstr* self); char* cstr_assign(cstr* self, const char* str); char* cstr_assign_n(cstr* self, const char* str, size_t n); // assign n first bytes of str -char* cstr_assign_sv(cstr* self, csview sv) +char* cstr_assign_sv(cstr* self, csview sv); char* cstr_copy(cstr* self, cstr s); // copy-assign a cstr int cstr_printf(cstr* self, const char* fmt, ...); // source and target must not overlap. diff --git a/docs/csview_api.md b/docs/csview_api.md index d0ca44e1..09f377d1 100644 --- a/docs/csview_api.md +++ b/docs/csview_api.md @@ -51,21 +51,21 @@ csview csview_token(csview sv, csview sep, size_t* start); // *start size_t csview_u8_size(csview sv); csview csview_u8_substr(csview sv, size_t u8pos, size_t u8len); csview csview_u8_slice(csview sv, size_t u8p1, size_t u8p2); +bool csview_valid_utf8(csview sv); // requires linking with src/utf8code.c csview_iter csview_begin(const csview* self); csview_iter csview_end(const csview* self); void csview_next(csview_iter* it); // utf8 codepoint step, not byte! -// requires linking with src/utf8code.c: -bool csview_valid_utf8(csview sv); -// from utf8.h, linking src/utf8code.c: -bool utf8_valid(const char* s); -bool utf8_valid_n(const char* s, size_t nbytes); +// from utf8.h size_t utf8_size(const char *s); size_t utf8_size_n(const char *s, size_t nbytes); // number of UTF8 codepoints within n bytes const char* utf8_at(const char *s, size_t index); // from UTF8 index to char* position size_t utf8_pos(const char* s, size_t index); // from UTF8 index to byte index position -unsigned utf8_chr_size(const char* s); // 0-4 (0 if s[0] means illegal utf8) +unsigned utf8_chr_size(const char* s); // UTF8 character size: 1-4 +// implemented in src/utf8code.c: +bool utf8_valid(const char* s); +bool utf8_valid_n(const char* s, size_t nbytes); uint32_t utf8_decode(utf8_decode_t *d, uint8_t byte); // decode next byte to utf8, return state. unsigned utf8_encode(char *out, uint32_t codepoint); // encode unicode cp into out buffer uint32_t utf8_peek(const char* s, int pos); // codepoint value at utf8 pos (may be negative) 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/arc_containers.c b/examples/arc_containers.c index 969825eb..e8716129 100644 --- a/examples/arc_containers.c +++ b/examples/arc_containers.c @@ -32,19 +32,20 @@ int main() // POPULATE stack with shared pointers to Maps: Map *map; map = Stack_push(&stack, Arc_make(Map_init()))->get; - c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, { - {"Joey", 1990}, {"Mary", 1995}, {"Joanna", 1992} - }); + Map_emplace(map, "Joey", 1990); + Map_emplace(map, "Mary", 1995); + Map_emplace(map, "Joanna", 1992); + map = Stack_push(&stack, Arc_make(Map_init()))->get; - c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, { - {"Rosanna", 2001}, {"Brad", 1999}, {"Jack", 1980} - }); + Map_emplace(map, "Rosanna", 2001); + Map_emplace(map, "Brad", 1999); + Map_emplace(map, "Jack", 1980); // POPULATE list: map = List_push_back(&list, Arc_make(Map_init()))->get; - c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, { - {"Steve", 1979}, {"Rick", 1974}, {"Tracy", 2003} - }); + Map_emplace(map, "Steve", 1979); + Map_emplace(map, "Rick", 1974); + Map_emplace(map, "Tracy", 2003); // Share two Maps from the stack with the list using emplace (clone the carc): List_push_back(&list, Arc_clone(stack.data[0])); diff --git a/examples/box.c b/examples/box.c index ef2ff28b..c7e649bf 100644 --- a/examples/box.c +++ b/examples/box.c @@ -41,7 +41,6 @@ int main() c_auto (PBox, p, q) { p = PBox_make(Person_new("Laura", "Palmer")); - q = PBox_clone(p); cstr_assign(&q.get->name, "Leland"); @@ -52,7 +51,8 @@ int main() Persons_push(&vec, PBox_make(Person_new("Audrey", "Home"))); // NB! Clone p and q to the vector using emplace_back() - c_apply(v, Persons_push(&vec, PBox_clone(*v)), PBox, {p, q}); + Persons_push(&vec, PBox_clone(p)); + Persons_push(&vec, PBox_clone(q)); c_foreach (i, Persons, vec) printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last)); 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 608dd146..9ce96dc9 100644 --- a/examples/inits.c +++ b/examples/inits.c @@ -40,8 +40,8 @@ int main(void) const float nums[] = {4.0f, 2.0f, 5.0f, 3.0f, 1.0f}; // PRIORITY QUEUE - - c_apply_array(v, cpque_f_push(&floats, *v), const float, nums, c_arraylen(nums)); + c_forrange (i, c_arraylen(nums)) + cpque_f_push(&floats, nums[i]); puts("\npop and show high priorites first:"); while (! cpque_f_empty(&floats)) { @@ -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/regex1.c b/examples/regex1.c index 7e8040ac..5981e878 100644 --- a/examples/regex1.c +++ b/examples/regex1.c @@ -22,7 +22,7 @@ int main(int argc, char* argv[]) if (cstr_equals(input, "q")) break; - if (cregex_is_match(cstr_str(&input), &float_expr, 0)) + if (cregex_is_match(cstr_str(&input), &float_expr)) printf("Input is a float\n"); else printf("Invalid input : Not a float\n"); diff --git a/examples/regex2.c b/examples/regex2.c index cc9464c3..30602444 100644 --- a/examples/regex2.c +++ b/examples/regex2.c @@ -4,30 +4,30 @@ int main() { - const char* inputs[] = {"date: 2024-02-29 leapyear day", "https://en.cppreference.com/w/cpp/regex/regex_search", "!123abcabc!"}; - const char* patterns[] = {"(\\d\\d\\d\\d)[-_](1[0-2]|0[1-9])[-_](3[01]|[12][0-9]|0[1-9])", - "(https?://|ftp://|www\\.)([0-9A-Za-z@:%_+~#=-]+\\.)+([a-z][a-z][a-z]?)(/[/0-9A-Za-z\\.@:%_+~#=\\?&-]*)?", - "!((abc|123)+)!", + struct { const char *pattern, *input; } s[] = { + {"(\\d\\d\\d\\d)[-_](1[0-2]|0[1-9])[-_](3[01]|[12][0-9]|0[1-9])", + "date: 2024-02-29 leapyear day, christmas eve is on 2022-12-24." + }, + {"(https?://|ftp://|www\\.)([0-9A-Za-z@:%_+~#=-]+\\.)+([a-z][a-z][a-z]?)(/[/0-9A-Za-z\\.@:%_+~#=\\?&-]*)?", + "https://en.cppreference.com/w/cpp/regex/regex_search" + }, + {"!((abc|123)+)!", "!123abcabc!"} }; - c_forrange (i, c_arraylen(inputs)) + + c_auto (cregex, re) + c_forrange (i, c_arraylen(s)) { - c_auto (cregex, re) - { - int res = cregex_compile(&re, patterns[i], 0); - if (res < 0) { - printf("error in regex pattern: %d\n", res); - continue; - } - csview m[20]; - printf("input: %s\n", inputs[i]); - if (cregex_find(inputs[i], &re, m, 0) == 1) - { - c_forrange (j, cregex_captures(&re)) - { - printf(" submatch %" PRIuMAX ": %.*s\n", j, c_ARGsv(m[j])); - } - puts(""); - } + int res = cregex_compile(&re, s[i].pattern, 0); + if (res < 0) { + printf("error in regex pattern: %d\n", res); + continue; + } + printf("input: %s\n", s[i].input); + + c_foreach_match (j, &re, s[i].input) { + c_forrange (k, cregex_captures(&re)) + printf(" submatch %d: %.*s\n", (int)k, c_ARGsv(j.ref[k])); + puts(""); } } } diff --git a/examples/regex_match.c b/examples/regex_match.c index 72039fde..1e87affb 100644 --- a/examples/regex_match.c +++ b/examples/regex_match.c @@ -1,38 +1,35 @@ #define i_implement #include <stc/cstr.h> #include <stc/cregex.h> +#define i_val float +#include <stc/cstack.h> int main() { // Lets find the first sequence of digits in a string - const char *s = "Hello numeric world, there are 24 hours in a day, 3600 seconds in an hour." - " Around 365.25 days a year, and 52 weeks in a year." - " Boltzmann const: 1.38064852E-23, is very small." - " Bohrradius is 5.29177210903e-11, and Avogadros number is 6.02214076e23."; + const char *str = "Hello numeric world, there are 24 hours in a day, 3600 seconds in an hour." + " Around 365.25 days a year, and 52 weeks in a year." + " Boltzmann const: 1.38064852E-23, is very small." + " Bohrradius is 5.29177210903e-11, and Avogadros number is 6.02214076e23."; c_auto (cregex, re) + c_auto (cstack_float, vec) + c_auto (cstr, nums) { - int res = cregex_compile(&re, "[+-]?([0-9]*\\.)?\\d+([Ee][+-]?\\d+)?", 0); - printf("%d\n", res); - csview m[5]; - if (cregex_find(s, &re, m, 0) == 1) { - printf("Found digits at position %" PRIuMAX "-%" PRIuMAX "\n", m[0].str - s, m[0].str - s + m[0].size); - } else { - printf("Could not find any digits\n"); - } + const char* pattern = "[+-]?([0-9]*\\.)?\\d+([Ee][+-]?\\d+)?"; + int res = cregex_compile(&re, pattern, 0); + printf("%d: %s\n", res, pattern); - while (cregex_find(s, &re, m, cre_m_next) == 1) { - printf("%.*s ; ", c_ARGsv(m[0])); - } - puts(""); + // extract and convert all numbers in str to floats + c_foreach_match (i, &re, str) + cstack_float_push(&vec, atof(i.ref->str)); - res = cregex_compile(&re, "(.+)\\b(.+)", 0); - printf("groups: %d\n", res); - if ((res = cregex_find("hello@wørld", &re, m, 0)) == 1) { - c_forrange (i, res) - printf("match: [%.*s]\n", c_ARGsv(m[i])); - } else - printf("err: %d\n", res); + c_foreach (i, cstack_float, vec) + printf(" %g\n", *i.ref); + + // extracts the numbers only to a comma separated string. + nums = cregex_replace_ex(str, &re, " $0,", 0, cre_r_strip, NULL); + printf("\n%s\n", cstr_str(&nums)); } } diff --git a/examples/regex_replace.c b/examples/regex_replace.c index 35b3c696..eba31491 100644 --- a/examples/regex_replace.c +++ b/examples/regex_replace.c @@ -22,15 +22,15 @@ int main() printf("INPUT: %s\n", input); /* replace with a fixed string, extended all-in-one call: */ - cstr_take(&str, cregex_replace_p(input, pattern, "YYYY-MM-DD")); + cstr_take(&str, cregex_replace_p(input, pattern, "YYYY-MM-DD", 0)); printf("fixed: %s\n", cstr_str(&str)); /* US date format, and add 10 years to dates: */ - cstr_take(&str, cregex_replace_pe(input, pattern, "$1/$3/$2", add_10_years, 0, 0)); + cstr_take(&str, cregex_replace_pe(input, pattern, "$1/$3/$2", 0, 0, add_10_years)); printf("us+10: %s\n", cstr_str(&str)); /* Wrap first date inside []: */ - cstr_take(&str, cregex_replace_pe(input, pattern, "[$0]", NULL, 1, 0)); + cstr_take(&str, cregex_replace_p(input, pattern, "[$0]", 1)); printf("brack: %s\n", cstr_str(&str)); /* Shows how to compile RE separately */ @@ -38,16 +38,16 @@ int main() if (cregex_captures(&re) == 0) continue; /* European date format. */ - cstr_take(&str, cregex_replace(input, &re, "$3.$2.$1")); + cstr_take(&str, cregex_replace(input, &re, "$3.$2.$1", 0)); printf("euros: %s\n", cstr_str(&str)); /* Strip out everything but the matches */ - cstr_take(&str, cregex_replace_re(input, &re, "$3.$2.$1;", NULL, 0, cre_r_strip)); + cstr_take(&str, cregex_replace_ex(input, &re, "$3.$2.$1;", 0, cre_r_strip, NULL)); printf("strip: %s\n", cstr_str(&str)); } /* Wrap all words in ${} */ - cstr_take(&str, cregex_replace_p("[52] apples and [31] mangoes", "[a-z]+", "$${$0}")); + cstr_take(&str, cregex_replace_p("[52] apples and [31] mangoes", "[a-z]+", "$${$0}", 0)); printf("curly: %s\n", cstr_str(&str)); } } 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..b5b3417b 100644 --- a/examples/vikings.c +++ b/examples/vikings.c @@ -25,10 +25,7 @@ static inline int RViking_cmp(const RViking* rx, const RViking* ry) { static inline Viking Viking_from(RViking raw) { // note: parameter is by value return c_make(Viking){cstr_from(raw.name), cstr_from(raw.country)}; } -static inline Viking Viking_clone(Viking vk) { // note: parameter is by value - vk.name = cstr_clone(vk.name), vk.country = cstr_clone(vk.country); - return vk; -} + static inline RViking Viking_toraw(const Viking* vp) { return c_make(RViking){cstr_str(&vp->name), cstr_str(&vp->country)}; } @@ -37,35 +34,32 @@ static inline RViking Viking_toraw(const Viking* vp) { #define i_type Vikings #define i_key_bind Viking // key type #define i_keyraw RViking // lookup type -#define i_keyfrom Viking_from // convert from lookup type (enables emplace) +#define i_keyfrom Viking_from #define i_hash(rp) c_strhash(rp->name) ^ c_strhash(rp->country) #define i_val int // mapped type -// i_key_bind auto-binds these functions (unless they are defined by i_...): + +// i_key_bind makes up these defines, unless they are already defined: // i_cmp => RViking_cmp -// i_hash => RViking_hash -// i_keyclone => Viking_clone -// i_keyto => Viking_toraw // because i_keyraw is defined +// //i_hash => RViking_hash // already defined. +// i_keyclone => c_derived_keyclone // because i_keyfrom is defined +// i_keyto => Viking_toraw // because i_keyraw is defined // i_keydrop => Viking_drop + #include <stc/cmap.h> int main() { c_auto (Vikings, vikings) { - c_apply(v, Vikings_emplace(&vikings, c_pair(v)), Vikings_raw, { - {{"Einar", "Norway"}, 20}, - {{"Olaf", "Denmark"}, 24}, - {{"Harald", "Iceland"}, 12}, - }); - RViking bjorn = {"Bjorn", "Sweden"}; - Vikings_emplace_or_assign(&vikings, bjorn, 10); + Vikings_emplace(&vikings, (RViking){"Einar", "Norway"}, 20); + Vikings_emplace(&vikings, (RViking){"Olaf", "Denmark"}, 24); + Vikings_emplace(&vikings, (RViking){"Harald", "Iceland"}, 12); + Vikings_emplace(&vikings, (RViking){"Björn", "Sweden"}, 10); - RViking einar = {"Einar", "Norway"}; - Vikings_value* v = Vikings_get_mut(&vikings, einar); + Vikings_value* v = Vikings_get_mut(&vikings, (RViking){"Einar", "Norway"}); v->second += 3; // add 3 hp points to Einar - Vikings_emplace(&vikings, einar, 0).ref->second += 5; // add 5 more to Einar - c_forpair (vik, hp, Vikings, vikings) { - printf("%s of %s has %d hp\n", cstr_str(&_.vik->name), cstr_str(&_.vik->country), *_.hp); + c_forpair (vk, hp, Vikings, vikings) { + printf("%s of %s has %d hp\n", cstr_str(&_.vk->name), cstr_str(&_.vk->country), *_.hp); } } } 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 diff --git a/include/stc/cregex.h b/include/stc/cregex.h index 8f6464d4..7c4d0a4c 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -70,12 +70,19 @@ typedef struct { int error; } cregex; -typedef csview cregmatch; +typedef struct { + const cregex* re; + const char* input; + csview ref[cre_MAXCAPTURES]; +} cregex_iter; + +#define c_foreach_match(i, _re, _input) \ + for (cregex_iter i = {_re, _input}; cregex_find(i.input, i.re, i.ref, cre_m_next) == cre_success;) static inline cregex cregex_init(void) { - cregex rx = {0}; - return rx; + cregex re = {0}; + return re; } /* return 1 on success, or negative error code on failure. */ @@ -83,9 +90,9 @@ int cregex_compile(cregex *self, const char* pattern, int cflags); static inline cregex cregex_from(const char* pattern, int cflags) { - cregex rx = {0}; - cregex_compile(&rx, pattern, cflags); - return rx; + cregex re = {0}; + cregex_compile(&re, pattern, cflags); + return re; } /* number of capture groups in a regex pattern, 0 if regex is invalid */ @@ -105,22 +112,22 @@ int cregex_find_p(const char* input, const char* pattern, csview match[], int cmflags); static inline -bool cregex_is_match(const char* input, const cregex* re, int mflags) - { return cregex_find(input, re, NULL, mflags) == 1; } +bool cregex_is_match(const char* input, const cregex* re) + { return cregex_find(input, re, NULL, 0) == cre_success; } /* replace regular expression */ -cstr cregex_replace_re(const char* input, const cregex* re, const char* replace, - bool (*mfun)(int i, csview match, cstr* mstr), unsigned count, int rflags); +cstr cregex_replace_ex(const char* input, const cregex* re, const char* replace, unsigned count, + int rflags, bool (*mfun)(int i, csview match, cstr* mstr)); static inline -cstr cregex_replace(const char* input, const cregex* re, const char* replace) - { return cregex_replace_re(input, re, replace, NULL, 0, 0); } +cstr cregex_replace(const char* input, const cregex* re, const char* replace, unsigned count) + { return cregex_replace_ex(input, re, replace, count, 0, NULL); } /* replace + compile RE pattern, and extra arguments */ -cstr cregex_replace_pe(const char* input, const char* pattern, const char* replace, - bool (*mfun)(int i, csview match, cstr* mstr), unsigned count, int crflags); +cstr cregex_replace_pe(const char* input, const char* pattern, const char* replace, unsigned count, + int crflags, bool (*mfun)(int i, csview match, cstr* mstr)); static inline -cstr cregex_replace_p(const char* input, const char* pattern, const char* replace) - { return cregex_replace_pe(input, pattern, replace, NULL, 0, 0); } +cstr cregex_replace_p(const char* input, const char* pattern, const char* replace, unsigned count) + { return cregex_replace_pe(input, pattern, replace, count, 0, NULL); } /* destroy regex */ void cregex_drop(cregex* self); diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 92f49d92..68f35674 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -261,10 +261,7 @@ STC_INLINE size_t cstr_find(cstr s, const char* search) { return res ? res - str : cstr_npos; } -STC_INLINE size_t cstr_find_sv(cstr s, csview search) { - char* res = c_strnstrn(cstr_str(&s), search.str, cstr_size(s), search.size); - return res ? res - cstr_str(&s) : cstr_npos; -} +STC_API size_t cstr_find_sv(cstr s, csview search); STC_INLINE size_t cstr_find_s(cstr s, cstr search) { return cstr_find(s, cstr_str(&search)); } @@ -274,7 +271,7 @@ STC_INLINE bool cstr_contains(cstr s, const char* search) { return strstr(cstr_data(&s), search) != NULL; } STC_INLINE bool cstr_contains_sv(cstr s, csview search) - { return c_strnstrn(cstr_str(&s), search.str, cstr_size(s), search.size) != NULL; } + { return cstr_find_sv(s, search) != cstr_npos; } STC_INLINE bool cstr_contains_s(cstr s, cstr search) { return strstr(cstr_data(&s), cstr_str(&search)) != NULL; } @@ -377,13 +374,20 @@ STC_INLINE void cstr_insert_s(cstr* self, size_t pos, cstr s) { STC_INLINE bool cstr_getline(cstr *self, FILE *fp) { return cstr_getdelim(self, '\n', fp); } -STC_INLINE uint64_t cstr_hash(const cstr *self) { +STC_API uint64_t cstr_hash(const cstr *self); + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) || defined(i_extern) + +STC_DEF uint64_t cstr_hash(const cstr *self) { csview sv = cstr_sv(self); return c_fasthash(sv.str, sv.size); } -/* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) || defined(i_extern) +STC_DEF size_t cstr_find_sv(cstr s, csview search) { + char* res = c_strnstrn(cstr_str(&s), search.str, cstr_size(s), search.size); + return res ? res - cstr_str(&s) : cstr_npos; +} STC_DEF char* _cstr_internal_move(cstr* self, const size_t pos1, const size_t pos2) { cstr_buf r = cstr_buffer(self); diff --git a/include/stc/csview.h b/include/stc/csview.h index b4b701f2..2ebcaabe 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -42,13 +42,10 @@ STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; } STC_INLINE bool csview_equals(csview sv, csview sv2) { return sv.size == sv2.size && !memcmp(sv.str, sv2.str, sv.size); } -STC_INLINE size_t csview_find(csview sv, csview search) { - char* res = c_strnstrn(sv.str, search.str, sv.size, search.size); - return res ? res - sv.str : csview_npos; -} +STC_API size_t csview_find(csview sv, csview search); STC_INLINE bool csview_contains(csview sv, csview search) - { return c_strnstrn(sv.str, search.str, sv.size, search.size) != NULL; } + { return csview_find(sv, search) != csview_npos; } STC_INLINE bool csview_starts_with(csview sv, csview sub) { if (sub.size > sv.size) return false; @@ -98,40 +95,9 @@ STC_INLINE csview csview_u8_slice(csview sv, size_t u8p1, size_t u8p2) STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c { return utf8_valid_n(sv.str, sv.size); } -/* "Rarely" used extended substr_ex(), slice_ex(), and token() function */ - -STC_INLINE csview -csview_substr_ex(csview sv, intptr_t pos, size_t n) { - if (pos < 0) { - pos += sv.size; - if (pos < 0) pos = 0; - } - if (pos > (intptr_t)sv.size) pos = sv.size; - if (pos + n > sv.size) n = sv.size - pos; - sv.str += pos, sv.size = n; - return sv; -} - -STC_INLINE csview -csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { - if (p1 < 0) { - p1 += sv.size; - if (p1 < 0) p1 = 0; - } - if (p2 < 0) p2 += sv.size; - if (p2 > (intptr_t)sv.size) p2 = sv.size; - sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0; - return sv; -} - -STC_INLINE csview -csview_token(csview sv, csview sep, size_t* start) { - csview slice = {sv.str + *start, sv.size - *start}; - const char* res = c_strnstrn(slice.str, sep.str, slice.size, sep.size); - csview tok = {slice.str, res ? res - slice.str : slice.size}; - *start += tok.size + sep.size; - return tok; -} +STC_API csview csview_substr_ex(csview sv, intptr_t pos, size_t n); +STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); +STC_API csview csview_token(csview sv, csview sep, size_t* start); /* csview interaction with cstr: */ #ifdef CSTR_H_INCLUDED @@ -166,9 +132,50 @@ STC_INLINE int csview_icmp(const csview* x, const csview* y) STC_INLINE bool csview_eq(const csview* x, const csview* y) { return x->size == y->size && !memcmp(x->str, y->str, x->size); } -STC_INLINE uint64_t csview_hash(const csview *self) +STC_API uint64_t csview_hash(const csview *self); + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) || defined(i_extern) + +STC_DEF size_t csview_find(csview sv, csview search) { + char* res = c_strnstrn(sv.str, search.str, sv.size, search.size); + return res ? res - sv.str : csview_npos; +} + +STC_DEF uint64_t csview_hash(const csview *self) { return c_fasthash(self->str, self->size); } +STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, size_t n) { + if (pos < 0) { + pos += sv.size; + if (pos < 0) pos = 0; + } + if (pos > (intptr_t)sv.size) pos = sv.size; + if (pos + n > sv.size) n = sv.size - pos; + sv.str += pos, sv.size = n; + return sv; +} + +STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { + if (p1 < 0) { + p1 += sv.size; + if (p1 < 0) p1 = 0; + } + if (p2 < 0) p2 += sv.size; + if (p2 > (intptr_t)sv.size) p2 = sv.size; + sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0; + return sv; +} + +STC_DEF csview csview_token(csview sv, csview sep, size_t* start) { + csview slice = {sv.str + *start, sv.size - *start}; + const char* res = c_strnstrn(slice.str, sep.str, slice.size, sep.size); + csview tok = {slice.str, res ? res - slice.str : slice.size}; + *start += tok.size + sep.size; + return tok; +} + +#endif #endif #undef i_opt #undef i_header diff --git a/include/stc/template.h b/include/stc/template.h index d7289ba7..e77aa781 100644 --- a/include/stc/template.h +++ b/include/stc/template.h @@ -95,6 +95,7 @@ #define i_key_bind cstr #define i_keyraw crawstr #define i_keyfrom cstr_from + #define i_keyclone cstr_clone #ifndef i_tag #define i_tag str #endif @@ -103,6 +104,7 @@ #define i_keyraw csview #define i_keyfrom cstr_from_sv #define i_keyto cstr_sv + #define i_keyclone cstr_clone #define i_eq csview_eq #ifndef i_tag #define i_tag ssv @@ -116,7 +118,9 @@ #ifdef i_key_bind #define i_key i_key_bind - #ifndef i_keyclone + #if !defined i_keyclone && defined i_keyfrom + #define i_keyclone c_derived_keyclone + #elif !defined i_keyclone #define i_keyclone c_paste(i_key, _clone) #endif #if !defined i_keyto && defined i_keyraw @@ -189,20 +193,24 @@ #define i_val_bind cstr #define i_valraw crawstr #define i_valfrom cstr_from + #define i_valclone cstr_clone #elif defined i_val_ssv #define i_val_bind cstr #define i_valraw csview #define i_valfrom cstr_from_sv #define i_valto cstr_sv + #define i_valclone cstr_clone #elif defined i_val_arcbox #define i_val_bind i_val_arcbox #define i_valraw c_paste(i_val_arcbox, _value) - #define i_valto c_paste(i_val, _toval) + #define i_valto c_paste(i_val, _toval) #endif #ifdef i_val_bind #define i_val i_val_bind - #ifndef i_valclone + #if !defined i_valclone && defined i_valfrom + #define i_valclone c_derived_valclone + #elif !defined i_valclone #define i_valclone c_paste(i_val, _clone) #endif #if !defined i_valto && defined i_valraw diff --git a/include/stc/utf8.h b/include/stc/utf8.h index c6fb6944..34368737 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -1,46 +1,27 @@ #ifndef UTF8_H_INCLUDED #define UTF8_H_INCLUDED -/* -// Example: -#include <stc/cstr.h> -#include <stc/csview.h> -int main() -{ - c_auto (cstr, s1) { - s1 = cstr_new("hell😀 w😀rld"); - printf("%s\n", cstr_str(&s1)); - cstr_replace_sv(&s1, utf8_substr(cstr_str(&s1), 7, 1), c_sv("🐨")); - printf("%s\n", cstr_str(&s1)); - - c_foreach (i, cstr, s1) - printf("%.*s,", c_ARGsv(i.chr)); - } -} -// Output: -// hell😀 w😀rld -// hell😀 w🐨rld -// h,e,l,l,😀, ,w,🐨,r,l,d, -*/ #include "ccommon.h" #include <ctype.h> // utf8 methods defined in src/utf8code.c: -bool utf8_islower(uint32_t c); -bool utf8_isupper(uint32_t c); -bool utf8_isspace(uint32_t c); -bool utf8_isdigit(uint32_t c); -bool utf8_isxdigit(uint32_t c); -bool utf8_isalpha(uint32_t c); -bool utf8_isalnum(uint32_t c); -uint32_t utf8_casefold(uint32_t c); -uint32_t utf8_tolower(uint32_t c); -uint32_t utf8_toupper(uint32_t c); -bool utf8_valid_n(const char* s, size_t nbytes); -int utf8_icmp_n(size_t u8max, const char* s1, size_t n1, - const char* s2, size_t n2); -unsigned utf8_encode(char *out, uint32_t c); -uint32_t utf8_peek(const char *s, int u8pos); +extern bool utf8_islower(uint32_t c); +extern bool utf8_isupper(uint32_t c); +extern bool utf8_isspace(uint32_t c); +extern bool utf8_isdigit(uint32_t c); +extern bool utf8_isxdigit(uint32_t c); +extern bool utf8_isalpha(uint32_t c); +extern bool utf8_isalnum(uint32_t c); +extern uint32_t utf8_casefold(uint32_t c); +extern uint32_t utf8_tolower(uint32_t c); +extern uint32_t utf8_toupper(uint32_t c); +extern bool utf8_valid_n(const char* s, size_t nbytes); +extern int utf8_icmp_n(size_t u8max, const char* s1, size_t n1, + const char* s2, size_t n2); +extern unsigned utf8_encode(char *out, uint32_t c); +extern uint32_t utf8_peek(const char *s, int u8pos); + +/* following functions uses src/utf8code.c */ /* decode next utf8 codepoint. https://bjoern.hoehrmann.de/utf-8/decoder/dfa */ typedef struct { uint32_t state, codep; } utf8_decode_t; @@ -62,15 +43,17 @@ STC_INLINE bool utf8_valid(const char* s) { return utf8_valid_n(s, ~(size_t)0); } +/* following functions are independent but assume valid utf8 strings: */ + /* number of bytes in the utf8 codepoint from s */ STC_INLINE unsigned utf8_chr_size(const char *s) { unsigned b = (uint8_t)*s; if (b < 0x80) return 1; - if (b < 0xC2) return 0; + /*if (b < 0xC2) return 0;*/ if (b < 0xE0) return 2; if (b < 0xF0) return 3; - if (b < 0xF5) return 4; - return 0; + /*if (b < 0xF5)*/ return 4; + /*return 0;*/ } /* number of codepoints in the utf8 string s */ diff --git a/src/cregex.c b/src/cregex.c index 612a6965..d1f9c133 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -1229,8 +1229,8 @@ int cregex_find_p(const char* input, const char* pattern, } cstr -cregex_replace_re(const char* input, const cregex* re, const char* replace, - bool (*mfun)(int i, csview match, cstr* mstr), unsigned count, int rflags) { +cregex_replace_ex(const char* input, const cregex* re, const char* replace, unsigned count, + int rflags, bool (*mfun)(int i, csview match, cstr* mstr)) { cstr out = cstr_null; cstr subst = cstr_null; size_t from = 0; @@ -1252,13 +1252,13 @@ cregex_replace_re(const char* input, const cregex* re, const char* replace, } cstr -cregex_replace_pe(const char* input, const char* pattern, const char* replace, - bool (*mfun)(int i, csview match, cstr* mstr), unsigned count, int crflags) { +cregex_replace_pe(const char* input, const char* pattern, const char* replace, unsigned count, + int crflags, bool (*mfun)(int i, csview match, cstr* mstr)) { cregex re = cregex_init(); int res = cregex_compile(&re, pattern, crflags); if (res != cre_success) return cstr_new("[[error: invalid regex pattern]]"); - cstr out = cregex_replace_re(input, &re, replace, mfun, count, crflags); + cstr out = cregex_replace_ex(input, &re, replace, count, crflags, mfun); cregex_drop(&re); return out; } diff --git a/src/libstc.c b/src/libstc.c index 0c78272d..30c610c6 100644 --- a/src/libstc.c +++ b/src/libstc.c @@ -8,5 +8,4 @@ #include "../include/stc/cstr.h" #include "../include/stc/csview.h" -#include "../include/stc/cbits.h" #include "../include/stc/crandom.h" |
