summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md34
-rw-r--r--docs/carc_api.md15
-rw-r--r--docs/cbox_api.md4
-rw-r--r--docs/ccommon_api.md122
-rw-r--r--docs/cdeq_api.md4
-rw-r--r--docs/clist_api.md7
-rw-r--r--docs/cmap_api.md10
-rw-r--r--docs/cset_api.md10
-rw-r--r--docs/csmap_api.md13
-rw-r--r--docs/csset_api.md9
-rw-r--r--docs/cvec_api.md3
-rw-r--r--examples/city.c8
-rw-r--r--examples/convert.c5
-rw-r--r--examples/cpque.c8
-rw-r--r--examples/csmap_erase.c8
-rw-r--r--examples/csmap_find.c5
-rw-r--r--examples/csmap_insert.c7
-rw-r--r--examples/csset_erase.c5
-rw-r--r--examples/inits.c15
-rw-r--r--examples/list.c4
-rw-r--r--examples/list_erase.c4
-rw-r--r--examples/list_splice.c8
-rw-r--r--examples/lower_bound.c10
-rw-r--r--examples/music_arc.c8
-rw-r--r--examples/new_list.c10
-rw-r--r--examples/new_map.c15
-rw-r--r--examples/new_smap.c10
-rw-r--r--examples/person_arc.c3
-rw-r--r--examples/phonebook.c12
-rw-r--r--examples/priority.c3
-rw-r--r--examples/shape.c8
-rw-r--r--examples/sidebyside.cpp4
-rw-r--r--examples/vikings.c5
-rw-r--r--examples/words.c4
-rw-r--r--include/stc/ccommon.h42
-rw-r--r--include/stc/crandom.h12
36 files changed, 256 insertions, 198 deletions
diff --git a/README.md b/README.md
index 2a939f45..62a60045 100644
--- a/README.md
+++ b/README.md
@@ -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