diff options
Diffstat (limited to 'docs/ccommon_api.md')
| -rw-r--r-- | docs/ccommon_api.md | 186 |
1 files changed, 93 insertions, 93 deletions
diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 2c6db85f..a9961002 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -3,27 +3,27 @@ The following macros are recommended to use, and they safe/have no side-effects. ## Scope macros (RAII) -### c_auto, c_autodrop, c_with, c_scope, c_defer +### c_AUTO, c_AUTODROP, c_WITH, c_SCOPE, c_DEFER General ***defer*** mechanics for resource acquisition. These macros allows you to specify the freeing of the resources at the point where the acquisition takes place. -The **checkauto** utility described below, ensures that the `c_auto*` macros are used correctly. +The **checkauto** utility described below, ensures that the `c_AUTO*` macros are used correctly. | Usage | Description | |:---------------------------------------|:----------------------------------------------------------| -| `c_with (Type var=init, drop)` | Declare `var`. Defer `drop...` to end of scope | -| `c_with (Type var=init, pred, drop)` | Adds a predicate in order to exit early if init failed | -| `c_auto (Type, var1,...,var4)` | `c_with (Type var1=Type_init(), Type_drop(&var1))` ... | -| `c_autodrop (Type, var, init...)` | Like `c_with (Type var=init..., Type_drop(&var))` | -| `c_scope (init, drop)` | Execute `init` and defer `drop` to end of scope | -| `c_defer (drop...)` | Defer `drop...` to end of scope | +| `c_WITH (Type var=init, drop)` | Declare `var`. Defer `drop...` to end of scope | +| `c_WITH (Type var=init, pred, drop)` | Adds a predicate in order to exit early if init failed | +| `c_AUTO (Type, var1,...,var4)` | `c_WITH (Type var1=Type_init(), Type_drop(&var1))` ... | +| `c_AUTODROP (Type, var, init...)` | Like `c_WITH (Type var=init..., Type_drop(&var))` | +| `c_SCOPE (init, drop)` | Execute `init` and defer `drop` to end of scope | +| `c_DEFER (drop...)` | Defer `drop...` to end of scope | | `continue` | Exit a block above without memory leaks | -For multiple variables, use either multiple **c_with** in sequence, or declare variable outside -scope and use **c_scope**. For convenience, **c_auto** support up to 4 variables. +For multiple variables, use either multiple **c_WITH** in sequence, or declare variable outside +scope and use **c_SCOPE**. For convenience, **c_AUTO** support up to 4 variables. ```c -// `c_with` is similar to python `with`: it declares and can drop a variable after going out of scope. -c_with (uint8_t* buf = malloc(BUF_SIZE), free(buf)) -c_with (FILE* fp = fopen(fname, "rb"), fclose(fp)) +// `c_WITH` is similar to python `with`: it declares and can drop a variable after going out of scope. +c_WITH (uint8_t* buf = malloc(BUF_SIZE), free(buf)) +c_WITH (FILE* fp = fopen(fname, "rb"), fclose(fp)) { int n = 0; if (fp && buf) { @@ -32,14 +32,14 @@ c_with (FILE* fp = fopen(fname, "rb"), fclose(fp)) } } -c_with (cstr str = cstr_lit("Hello"), cstr_drop(&str)) +c_WITH (cstr str = cstr_lit("Hello"), cstr_drop(&str)) { cstr_append(&str, " world"); printf("%s\n", cstr_str(&str)); } -// `c_auto` automatically initialize and destruct up to 4 variables, like `c_with`. -c_auto (cstr, s1, s2) +// `c_AUTO` automatically initialize and destruct up to 4 variables, like `c_WITH`. +c_AUTO (cstr, s1, s2) { cstr_append(&s1, "Hello"); cstr_append(&s1, " world"); @@ -50,22 +50,22 @@ c_auto (cstr, s1, s2) printf("%s %s\n", cstr_str(&s1), cstr_str(&s2)); } -c_autodrop (cstr, str, cstr_lit("Hello")) +c_AUTODROP (cstr, str, cstr_lit("Hello")) { cstr_append(&str, " world"); printf("%s\n", cstr_str(&str)); } -// `c_scope` is like `c_with` but works with an already declared variable. +// `c_SCOPE` is like `c_WITH` but works with an already declared variable. static pthread_mutex_t mut; -c_scope (pthread_mutex_lock(&mut), pthread_mutex_unlock(&mut)) +c_SCOPE (pthread_mutex_lock(&mut), pthread_mutex_unlock(&mut)) { /* Do syncronized work. */ } -// `c_defer` executes the expressions when leaving scope. +// `c_DEFER` executes the expressions when leaving scope. cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world"); -c_defer (cstr_drop(&s1), cstr_drop(&s2)) +c_DEFER (cstr_drop(&s1), cstr_drop(&s2)) { printf("%s %s\n", cstr_str(&s1), cstr_str(&s2)); } @@ -83,8 +83,8 @@ cvec_str readFile(const char* name) { cvec_str vec = cvec_str_init(); // returned - c_with (FILE* fp = fopen(name, "r"), fclose(fp)) - c_with (cstr line = cstr_NULL, cstr_drop(&line)) + c_WITH (FILE* fp = fopen(name, "r"), fclose(fp)) + c_WITH (cstr line = cstr_NULL, cstr_drop(&line)) while (cstr_getline(&line, fp)) cvec_str_emplace_back(&vec, cstr_str(&line)); return vec; @@ -92,30 +92,30 @@ cvec_str readFile(const char* name) int main() { - c_with (cvec_str x = readFile(__FILE__), cvec_str_drop(&x)) - c_foreach (i, cvec_str, x) + c_WITH (cvec_str x = readFile(__FILE__), cvec_str_drop(&x)) + c_FOREACH (i, cvec_str, x) printf("%s\n", cstr_str(i.ref)); } ``` ### 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**, +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. A `break` may originally be intended to break a loop or switch -outside the `c_auto` scope. +outside the `c_AUTO` scope. -NOTE: 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: +from a `c_AUTO` scope: ```c int flag = 0; for (int i = 0; i<n; ++i) { - c_auto (cstr, text) - c_auto (List, list) + c_AUTO (cstr, text) + c_AUTO (List, list) { for (int j = 0; j<m; ++j) { List_push_back(&list, i*j); @@ -124,23 +124,23 @@ from a `c_auto` scope: } // WRONG: if (cond2()) - break; // checkauto ERROR! break inside c_auto. + break; // checkauto ERROR! break inside c_AUTO. if (cond3()) - return -1; // checkauto ERROR! return inside c_auto + 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 + continue; // cleanup and leave c_AUTO block } if (cond3()) { flag = -1; // return -1 - continue; // cleanup and leave c_auto block + continue; // cleanup and leave c_AUTO block } ... } - // do the return/break outside of c_auto + // do the return/break outside of c_AUTO if (flag < 0) return flag; else if (flag > 0) break; ... @@ -148,33 +148,33 @@ from a `c_auto` scope: ``` ## Loop abstraction macros -### c_forlist +### c_FORLIST Iterate compound literal array elements. Additional to `i.ref`, you can access `i.data`, `i.size`, and `i.index` of the input list/element. ```c // apply multiple push_backs -c_forlist (i, int, {1, 2, 3}) +c_FORLIST (i, int, {1, 2, 3}) cvec_i_push_back(&vec, *i.ref); // insert in existing map -c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} }) +c_FORLIST (i, cmap_ii_raw, { {4, 5}, {6, 7} }) cmap_ii_insert(&map, i.ref->first, i.ref->second); // string literals pushed to a stack of cstr: -c_forlist (i, const char*, {"Hello", "crazy", "world"}) +c_FORLIST (i, const char*, {"Hello", "crazy", "world"}) cstack_str_emplace(&stk, *i.ref); // reverse the list: -c_forlist (i, int, {1, 2, 3}) +c_FORLIST (i, int, {1, 2, 3}) cvec_i_push_back(&vec, i.data[i.size - 1 - i.index]); ``` -### c_foreach, c_forpair +### 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, val, ctype, container)` | Iterate with structured binding | +| `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 @@ -182,59 +182,59 @@ c_forlist (i, int, {1, 2, 3}) #define i_tag ii #include <stc/csmap.h> ... -c_forlist (i, csmap_ii_raw, { {23,1}, {3,2}, {7,3}, {5,4}, {12,5} }) +c_FORLIST (i, csmap_ii_raw, { {23,1}, {3,2}, {7,3}, {5,4}, {12,5} }) csmap_ii_insert(&map, i.ref->first, i.ref->second); -c_foreach (i, csmap_ii, map) +c_FOREACH (i, csmap_ii, map) printf(" %d", i.ref->first); // 3 5 7 12 23 csmap_ii_iter it = csmap_ii_find(&map, 7); -c_foreach (i, csmap_ii, it, csmap_ii_end(&map)) +c_FOREACH (i, csmap_ii, it, csmap_ii_end(&map)) printf(" %d", i.ref->first); // 7 12 23 -c_forpair (id, count, csmap_ii, map) +c_FORPAIR (id, count, csmap_ii, map) printf(" (%d %d)", *_.id, *_.count); // (3 2) (5 4) (7 3) (12 5) (23 1) ``` -### c_forrange +### c_FORRANGE Abstraction for iterating sequence of numbers. Like python's **for** *i* **in** *range()* loop. | Usage | Python equivalent | |:--------------------------------------------|:-------------------------------------| -| `c_forrange (stop)` | `for _ in range(stop):` | -| `c_forrange (i, stop) // i type = long long` | `for i in range(stop):` | -| `c_forrange (i, start, stop)` | `for i in range(start, stop):` | -| `c_forrange (i, start, stop, step)` | `for i in range(start, stop, step):` | +| `c_FORRANGE (stop)` | `for _ in range(stop):` | +| `c_FORRANGE (i, stop) // i type = long long` | `for i in range(stop):` | +| `c_FORRANGE (i, start, stop)` | `for i in range(start, stop):` | +| `c_FORRANGE (i, start, stop, step)` | `for i in range(start, stop, step):` | ```c -c_forrange (5) printf("x"); +c_FORRANGE (5) printf("x"); // xxxxx -c_forrange (i, 5) printf(" %lld", i); +c_FORRANGE (i, 5) printf(" %lld", i); // 0 1 2 3 4 -c_forrange (i, -3, 3) printf(" %lld", i); +c_FORRANGE (i, -3, 3) printf(" %lld", i); // -3 -2 -1 0 1 2 -c_forrange (i, 30, 0, -5) printf(" %lld", i); +c_FORRANGE (i, 30, 0, -5) printf(" %lld", i); // 30 25 20 15 10 5 ``` -### c_forwhile, c_forfilter +### c_FORWHILE, c_FORFILTER Iterate containers with stop-criteria and chained range filtering. | Usage | Description | |:----------------------------------------------------|:---------------------------------------| -| `c_forwhile (it, ctype, start, pred)` | Iterate until pred is false | -| `c_forfilter (it, ctype, container, filter)` | Filter out items in chain with && | -| `c_forfilter (it, ctype, container, filter, pred)` | Filter and iterate until pred is false | +| `c_FORWHILE (it, ctype, start, pred)` | Iterate until pred is false | +| `c_FORFILTER (it, ctype, container, filter)` | Filter out items in chain with && | +| `c_FORFILTER (it, ctype, container, filter, pred)` | Filter and iterate until pred is false | | Built-in filter | Description | |:----------------------------------|:-------------------------------------| -| `c_flt_skip(it, numItems)` | Skip numItems | -| `c_flt_take(it, numItems)` | Take numItems | -| `c_flt_skipwhile(it, predicate)` | Skip items until predicate is false | -| `c_flt_takewhile(it, predicate)` | Take items until predicate is false | +| `c_FLT_SKIP(it, numItems)` | Skip numItems | +| `c_FLT_TAKE(it, numItems)` | Take numItems | +| `c_FLT_SKIPWHILE(it, predicate)` | Skip items until predicate is false | +| `c_FLT_TAKEWHILE(it, predicate)` | Take items until predicate is false | `it.index` holds the index of the source item, and `it.count` the current number of items taken. ```c @@ -250,14 +250,14 @@ bool isPrime(int i) { #define isOdd(i) ((i) & 1) int main() { - c_auto (IVec, vec) { - c_forrange (i, 1000) IVec_push(&vec, 1000000 + i); + c_AUTO (IVec, vec) { + c_FORRANGE (i, 1000) IVec_push(&vec, 1000000 + i); - c_forfilter (i, IVec, vec, + c_FORFILTER (i, IVec, vec, isOdd(*i.ref) - && c_flt_skip(i, 100) // built-in + && c_FLT_SKIP(i, 100) // built-in && isPrime(*i.ref) - , c_flt_take(i, 10)) { // breaks loop on false. + , c_FLT_TAKE(i, 10)) { // breaks loop on false. printf(" %d", *i.ref); } puts(""); @@ -265,7 +265,7 @@ int main() { } // Out: 1000211 1000213 1000231 1000249 1000253 1000273 1000289 1000291 1000303 1000313 ``` -Note that `c_flt_take()` is given as an optional argument, which makes the loop stop when it becomes false (for efficiency). Chaining it after `isPrime()` instead will give same result, but the full input is processed. +Note that `c_FLT_TAKE()` is given as an optional argument, which makes the loop stop when it becomes false (for efficiency). Chaining it after `isPrime()` instead will give same result, but the full input is processed. ### crange **crange** is a number sequence generator type. The **crange_value** type is `long long`. Below, *start*, *stop*, *step* are type *crange_value*: @@ -281,57 +281,57 @@ void crange_next(crange_iter* it); // 1. All primes less than 32: crange r1 = crange_make(3, 32, 2); printf("2"); // first prime -c_forfilter (i, crange, r1 +c_FORFILTER (i, crange, r1 , isPrime(*i.ref)) printf(" %lld", *i.ref); // 2 3 5 7 11 13 17 19 23 29 31 // 2. The 11 first primes: printf("2"); -c_forfilter (i, crange, crange_literal(3, crange_MAX, 2) +c_FORFILTER (i, crange, crange_literal(3, crange_MAX, 2) , isPrime(*i.ref) - , c_flt_take(10)) + , c_FLT_TAKE(10)) printf(" %lld", *i.ref); // 2 3 5 7 11 13 17 19 23 29 31 ``` -### c_find_if, c_find_in, c_erase_if +### c_FIND_IF, c_find_in, c_ERASE_IF Find or erase linearily in containers using a predicate ```c // Search vec for first value > 2: cvec_i_iter i; -c_find_if(i, cvec_i, vec, *i.ref > 2); +c_FIND_IF(i, cvec_i, vec, *i.ref > 2); if (i.ref) printf("%d\n", *i.ref); // Search map for a string containing "hello" and erase it: cmap_str_iter it, it1 = ..., it2 = ...; -c_find_if(it, csmap_str, it1, it2, cstr_contains(it.ref, "hello")); +c_FIND_IF(it, csmap_str, it1, it2, cstr_contains(it.ref, "hello")); if (it.ref) cmap_str_erase_at(&map, it); // Erase all strings containing "hello": // Note 1: iter i need not be declared. // Note 2: variables index and count can be accessed in predicate. -c_erase_if(i, csmap_str, map, cstr_contains(i.ref, "hello")); +c_ERASE_IF(i, csmap_str, map, cstr_contains(i.ref, "hello")); ``` -### c_new, c_alloc, c_alloc_n, c_drop +### c_NEW, c_ALLOC, c_ALLOC_N, c_DROP | Usage | Meaning | |:-------------------------------|:----------------------------------------| -| `c_new (type, value)` | Move value to a new object on the heap | -| `c_alloc (type)` | `(type *) c_malloc(sizeof(type))` | -| `c_alloc_n (type, N)` | `(type *) c_malloc((N)*sizeof(type))` | -| `c_drop (ctype, &c1, ..., &cN)` | `ctype_drop(&c1); ... ctype_drop(&cN)` | +| `c_NEW (type, value)` | Move value to a new object on the heap | +| `c_ALLOC (type)` | `(type *) c_MALLOC(sizeof(type))` | +| `c_ALLOC_N (type, N)` | `(type *) c_MALLOC((N)*sizeof(type))` | +| `c_DROP (ctype, &c1, ..., &cN)` | `ctype_drop(&c1); ... ctype_drop(&cN)` | ```c struct Pnt { double x, y, z; }; -struct Pnt *pnt = c_new (struct Pnt, {1.2, 3.4, 5.6}); -c_free(pnt); +struct Pnt *pnt = c_NEW (struct Pnt, {1.2, 3.4, 5.6}); +c_FREE(pnt); -int* array = c_alloc_n (int, 100); -c_free(array); +int* array = c_ALLOC_N (int, 100); +c_FREE(array); cstr a = cstr_lit("Hello"), b = cstr_lit("World"); -c_drop(cstr, &a, &b); +c_DROP(cstr, &a, &b); ``` ### General predefined template parameter functions @@ -347,9 +347,9 @@ bool crawstr_eq(const crawstr* x, const crawstr* y); uint64_t crawstr_hash(const crawstr* x); ``` -### c_malloc, c_calloc, c_realloc, c_free +### c_MALLOC, c_CALLOC, c_REALLOC, c_FREE Memory allocator for the entire library. Macros can be overloaded by the user. -### c_swap, c_arraylen +### c_swap, c_ARRAYLEN - **c_swap(type, x, y)**: Simple macro for swapping internals of two objects. -- **c_arraylen(array)**: Return number of elements in an array, e.g. `int array[] = {1, 2, 3, 4};` +- **c_ARRAYLEN(array)**: Return number of elements in an array, e.g. `int array[] = {1, 2, 3, 4};` |
