diff options
| -rw-r--r-- | docs/cbox_api.md | 2 | ||||
| -rw-r--r-- | docs/ccommon_api.md | 119 | ||||
| -rw-r--r-- | include/stc/carc.h | 12 | ||||
| -rw-r--r-- | include/stc/cbox.h | 14 | ||||
| -rw-r--r-- | include/stc/ccommon.h | 18 | ||||
| -rw-r--r-- | include/stc/cdeq.h | 1 | ||||
| -rw-r--r-- | include/stc/cstack.h | 3 | ||||
| -rw-r--r-- | include/stc/cvec.h | 4 | ||||
| -rw-r--r-- | misc/examples/box2.c | 74 | ||||
| -rw-r--r-- | misc/examples/list.c | 8 |
10 files changed, 141 insertions, 114 deletions
diff --git a/docs/cbox_api.md b/docs/cbox_api.md index eff0fbc1..8b03d004 100644 --- a/docs/cbox_api.md +++ b/docs/cbox_api.md @@ -42,7 +42,7 @@ cbox_X cbox_X_make(i_val val); // create a cbox f cbox_X cbox_X_clone(cbox_X other); // return deep copied clone cbox_X cbox_X_move(cbox_X* self); // transfer ownership to receiving cbox returned. self becomes NULL. void cbox_X_take(cbox_X* self, cbox_X unowned); // take ownership of unowned box object. -void cbox_X_assign(cbox_X* self, cbox_X* dying); // transfer ownership from dying to self; dying becomes NULL. +void cbox_X_assign(cbox_X* self, cbox_X* moved); // transfer ownership from moved to self; moved becomes NULL. void cbox_X_drop(cbox_X* self); // destruct the contained object and free its heap memory. void cbox_X_reset(cbox_X* self); diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 60167c06..034e52f5 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -94,26 +94,6 @@ int main() ``` ## Loop abstraction macros -### c_forlist -Iterate compound literal array elements. Additional to `i.ref`, you can access `i.data`, `i.size`, and `i.index` of the input list/element. -```c -// apply multiple push_backs -c_forlist (i, int, {1, 2, 3}) - cvec_i_push_back(&vec, *i.ref); - -// insert in existing map -c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} }) - cmap_ii_insert(&map, i.ref->first, i.ref->second); - -// string literals pushed to a stack of cstr: -c_forlist (i, const char*, {"Hello", "crazy", "world"}) - cstack_str_emplace(&stk, *i.ref); - -// reverse the list: -c_forlist (i, int, {1, 2, 3}) - cvec_i_push_back(&vec, i.data[i.size - 1 - i.index]); -``` - ### c_foreach, c_forpair | Usage | Description | @@ -150,10 +130,10 @@ c_forpair (id, count, csmap_ii, map) ``` ### c_forrange -Abstraction for iterating sequence of numbers. Like python's **for** *i* **in** *range()* loop. +Abstraction for iterating sequence of integers. Like python's **for** *i* **in** *range()* loop. -| Usage | Python equivalent | -|:--------------------------------------------|:-------------------------------------| +| 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):` | @@ -170,6 +150,26 @@ c_forrange (i, 30, 0, -5) printf(" %lld", i); // 30 25 20 15 10 5 ``` +### c_forlist +Iterate compound literal array elements. Additional to `i.ref`, you can access `i.data`, `i.size`, and `i.index` of the input list/element. +```c +// apply multiple push_backs +c_forlist (i, int, {1, 2, 3}) + cvec_i_push_back(&vec, *i.ref); + +// insert in existing map +c_forlist (i, cmap_ii_raw, { {4, 5}, {6, 7} }) + cmap_ii_insert(&map, i.ref->first, i.ref->second); + +// string literals pushed to a stack of cstr: +c_forlist (i, const char*, {"Hello", "crazy", "world"}) + cstack_str_emplace(&stk, *i.ref); + +// reverse the list: +c_forlist (i, int, {1, 2, 3}) + cvec_i_push_back(&vec, i.data[i.size - 1 - i.index]); +``` + ### c_forfilter Iterate containers with stop-criteria and chained range filtering. @@ -218,33 +218,7 @@ int main() { Note that `c_flt_take()` is given as an optional argument, which breaks the loop on false. With `&&` instead of the comma it will give same result, but the full input is processed first. -### c_make, c_new, c_delete - -- **c_make**: Make any container from an initializer list. Example: -```c -#define i_val_str // cstr value type -#include <stc/cset.h> - -#define i_key int -#define i_val int -#include <stc/cmap.h> -... -// Initializes with const char*, internally converted to cstr! -cset_str myset = c_make(cset_str, {"This", "is", "the", "story"}); - -int x = 7, y = 8; -cmap_int mymap = c_make(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} }); -``` - -- **c_new(Type)**: Allocate *and init* a new object on the heap -- **c_delete(Type, ptr)**: Drop *and free* an object allocated on the heap -```c -#include <stc/cstr.h> - -cstr *stringptr = c_new(cstr, cstr_from("Hello")); -printf("%s\n", cstr_str(stringptr)); -c_delete(cstr, stringptr); -``` +## Generators ### crange A number sequence generator type, similar to [boost::irange](https://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/ranges/irange.html). The **crange_value** type is `long long`. Below *start*, *stop*, and *step* are of type *crange_value*: @@ -274,24 +248,61 @@ c_forfilter (i, crange, crange_obj(3, INT64_MAX, 2) printf(" %lld", *i.ref); // 2 3 5 7 11 13 17 19 23 29 31 ``` -### c_find_if, c_erase_if, c_swap, c_drop +## Algorithms + +### c_make, c_new, c_delete + +- *c_make(C, {...})*: Make any container from an initializer list. Example: +```c +#define i_val_str // cstr value type +#include <stc/cset.h> + +#define i_key int +#define i_val int +#include <stc/cmap.h> +... +// Initializes with const char*, internally converted to cstr! +cset_str myset = c_make(cset_str, {"This", "is", "the", "story"}); + +int x = 7, y = 8; +cmap_int mymap = c_make(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} }); +``` + +- ***c_new(Type)***: Allocate *and init* a new object on the heap +- ***c_delete(Type, ptr)***: Drop *and free* an object allocated on the heap +```c +#include <stc/cstr.h> + +cstr *stringptr = c_new(cstr, cstr_from("Hello")); +printf("%s\n", cstr_str(stringptr)); +c_delete(cstr, stringptr); +``` + +### c_find_if, c_erase_if, c_eraseremove_if Find or erase linearily in containers using a predicate +- For *c_find_if (iter, C, c, pred)*, ***iter*** must be declared outside/prior to call. +- Use *c_erase_if (iter, C, c, pred)* with **clist**, **cmap**, **cset**, **csmap**, and **csset**. +- Use *c_eraseremove_if (iter, C, c, pred)* with **cstack**, **cvec**, **cdeq**, and **cqueue**. ```c // Search vec for first value > 2: cvec_i_iter i; c_find_if(i, cvec_i, vec, *i.ref > 2); if (i.ref) printf("%d\n", *i.ref); +// Erase all values > 2 in vec: +c_eraseremove_if(i, cvec_i, vec, *i.ref > 2); + // 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")); 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. +// Erase all strings containing "hello" in a sorted map: c_erase_if(i, csmap_str, map, cstr_contains(i.ref, "hello")); +``` +### c_swap, c_drop +```c // Safe macro for swapping internals of two objects of same type: c_swap(cmap_int, &map1, &map2); diff --git a/include/stc/carc.h b/include/stc/carc.h index d606ac6e..02bbaf52 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -160,6 +160,12 @@ STC_INLINE _cx_self _cx_memb(_clone)(_cx_self ptr) { return ptr; } +// take ownership of unowned +STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self unowned) { + _cx_memb(_drop)(self); + *self = unowned; +} +// share ownership with ptr STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self ptr) { if (ptr.use_count) _i_atomic_inc(ptr.use_count); @@ -167,12 +173,6 @@ STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self ptr) { *self = ptr; } -STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self unowned) { - if (self->get != unowned.get) - _cx_memb(_drop)(self); - *self = unowned; -} - #ifndef i_no_cmp STC_INLINE int _cx_memb(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry) { return i_cmp(rx, ry); } diff --git a/include/stc/cbox.h b/include/stc/cbox.h index 44c819dd..641fcbfc 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -145,18 +145,18 @@ STC_INLINE _cx_self _cx_memb(_from)(_cx_value val) } #endif // !i_no_clone +// take ownership of unowned STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self unowned) { - if (unowned.get != self->get) - _cx_memb(_drop)(self); + _cx_memb(_drop)(self); *self = unowned; } -/* transfer ownership; set dying to NULL */ -STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self* dying) { - if (dying->get == self->get) +// transfer ownership from moved; set moved to NULL +STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self* moved) { + if (moved->get == self->get) return; _cx_memb(_drop)(self); - *self = *dying; - dying->get = NULL; + *self = *moved; + moved->get = NULL; } #ifndef i_no_cmp diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index dae991ed..711a9c6d 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -244,14 +244,26 @@ STC_INLINE char* cstrnstrn(const char *str, const char *needle, if (it.ref == _endref) it.ref = NULL; \ } while (0) +// use with: clist, cmap, cset, csmap, csset, cstr: #define c_erase_if(it, C, cnt, pred) do { \ - C##_iter it = C##_begin(&cnt); \ - for (intptr_t index = 0; it.ref; ++index) { \ - if (pred) it = C##_erase_at(&cnt, it); \ + C* _cnt = &cnt; \ + for (C##_iter it = C##_begin(_cnt); it.ref;) { \ + if (pred) it = C##_erase_at(_cnt, it); \ else C##_next(&it); \ } \ } while (0) +// use with: cstack, cvec, cdeq, cqueue: +#define c_eraseremove_if(it, C, cnt, pred) do { \ + C* _cnt = &cnt; \ + intptr_t _n = 0; \ + C##_iter _first = C##_begin(_cnt), it = _first; \ + for (; it.ref; C##_next(&it)) \ + if (pred) ++_n; \ + else C##_value_drop(_first.ref), *_first.ref = *it.ref, C##_next(&_first); \ + _cnt->_len -= _n; \ +} while (0) + #endif // CCOMMON_H_INCLUDED #undef STC_API diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index fd508bf6..8ca06ada 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -52,6 +52,7 @@ STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, int { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); } STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n) { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } +STC_INLINE void _cx_memb(_value_drop)(_cx_value* val) { i_keydrop(val); } #if !defined _i_queue #if !defined i_no_emplace STC_API _cx_iter _cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos, diff --git a/include/stc/cstack.h b/include/stc/cstack.h index 54bf7850..f0c930e5 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -82,7 +82,6 @@ STC_INLINE void _cx_memb(_drop)(_cx_self* self) { i_free(self->data); #endif } - STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* self) { return self->_len; } @@ -96,6 +95,8 @@ STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* self) { return i_capacity; #endif } +STC_INLINE void _cx_memb(_value_drop)(_cx_value* val) + { i_keydrop(val); } STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, intptr_t n) { if (n < self->_len) return true; diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 84c91228..88153912 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -92,6 +92,7 @@ STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw); STC_API _cx_iter _cx_memb(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound); #endif +STC_INLINE void _cx_memb(_value_drop)(_cx_value* val) { i_keydrop(val); } #if !defined i_no_emplace STC_API _cx_iter _cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos, @@ -413,8 +414,7 @@ _cx_memb(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw, i1.ref = NULL; return i1; } -STC_DEF int -_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { +STC_DEF int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { const _cx_raw rx = i_keyto(x); const _cx_raw ry = i_keyto(y); return i_cmp((&rx), (&ry)); diff --git a/misc/examples/box2.c b/misc/examples/box2.c index 943b2ae8..f7d21976 100644 --- a/misc/examples/box2.c +++ b/misc/examples/box2.c @@ -1,36 +1,31 @@ -// https://doc.rust-lang.org/rust-by-example/std/box.html - -#include <stdlib.h> +// example: https://doc.rust-lang.org/rust-by-example/std/box.html #include <stdio.h> -#include <string.h> -#include <stc/ccommon.h> -struct { +typedef struct { double x; double y; -} typedef Point; +} Point; // A Rectangle can be specified by where its top left and bottom right // corners are in space -struct { +typedef struct { Point top_left; Point bottom_right; -} typedef Rectangle; +} Rectangle; #define i_val Point -#define i_opt c_no_cmp +#define i_no_cmp #include <stc/cbox.h> // cbox_Point #define i_val Rectangle -#define i_opt c_no_cmp +#define i_no_cmp #include <stc/cbox.h> // cbox_Rectangle // Box in box: -#define i_valboxed cbox_Point // NB: use i_valboxed when value is a cbox or carc! - // it will auto define i_valdrop, i_valfrom, and i_cmp. -#define i_tag BoxPoint -#define i_opt c_no_cmp -#include <stc/cbox.h> // cbox_BoxPoint +#define i_valboxed cbox_Point // NB: use i_valboxed when value is a cbox or carc! +#define i_type BoxBoxPoint +#define i_no_cmp +#include <stc/cbox.h> // BoxBoxPoint Point origin(void) { return (Point){ .x=1.0, .y=2.0 }; @@ -38,7 +33,7 @@ Point origin(void) { cbox_Point boxed_origin(void) { // Allocate this point on the heap, and return a pointer to it - return cbox_Point_make((Point){ .x=2.0, .y=3.0 }); + return cbox_Point_make((Point){ .x=1.0, .y=2.0 }); } @@ -47,44 +42,47 @@ int main(void) { Point point = origin(); Rectangle rectangle = (Rectangle){ .top_left = origin(), - .bottom_right = (Point){ .x=3.0, .y=-4.0 } + .bottom_right = { .x=3.0, .y=-4.0 } }; - // Declare auto-deleted box objects + // Declare RAII'ed box objects c_auto (cbox_Rectangle, boxed_rectangle) c_auto (cbox_Point, boxed_point) - c_auto (cbox_BoxPoint, box_in_a_box, boxbox2) + c_auto (BoxBoxPoint, box_in_a_box) { // Heap allocated rectangle boxed_rectangle = cbox_Rectangle_make((Rectangle){ .top_left = origin(), - .bottom_right = (Point){ .x=3.0, .y=-4.0 } + .bottom_right = { .x=3.0, .y=-4.0 } }); // The output of functions can be boxed - boxed_point = cbox_Point_from(origin()); + boxed_point = cbox_Point_make(origin()); // Double indirection - box_in_a_box = cbox_BoxPoint_make(boxed_origin()); - boxbox2 = cbox_BoxPoint_from(point); // !! - printf("boxbox2: x=%f\n", boxbox2.get->get->x); - - printf("Point occupies %" c_ZU " bytes on the stack\n", - sizeof(point)); - printf("Rectangle occupies %" c_ZU " bytes on the stack\n", - sizeof(rectangle)); + //box_in_a_box = BoxBoxPoint_make(boxed_origin()); + //printf("box_in_a_box: x = %g\n", box_in_a_box.get->get->x); + + // Can use from(raw) and toraw instead: + box_in_a_box = BoxBoxPoint_from(origin()); + printf("box_in_a_box: x = %g\n", BoxBoxPoint_toraw(&box_in_a_box).x); + + printf("Point occupies %d bytes on the stack\n", + (int)sizeof(point)); + printf("Rectangle occupies %d bytes on the stack\n", + (int)sizeof(rectangle)); // box size == pointer size - printf("Boxed point occupies %" c_ZU " bytes on the stack\n", - sizeof(boxed_point)); - printf("Boxed rectangle occupies %" c_ZU " bytes on the stack\n", - sizeof(boxed_rectangle)); - printf("Boxed box occupies %" c_ZU " bytes on the stack\n", - sizeof(box_in_a_box)); + printf("Boxed point occupies %d bytes on the stack\n", + (int)sizeof(boxed_point)); + printf("Boxed rectangle occupies %d bytes on the stack\n", + (int)sizeof(boxed_rectangle)); + printf("Boxed box occupies %d bytes on the stack\n", + (int)sizeof(box_in_a_box)); // Copy the data contained in `boxed_point` into `unboxed_point` Point unboxed_point = *boxed_point.get; - printf("Unboxed point occupies %" c_ZU " bytes on the stack\n", - sizeof(unboxed_point)); + printf("Unboxed point occupies %d bytes on the stack\n", + (int)sizeof(unboxed_point)); } } diff --git a/misc/examples/list.c b/misc/examples/list.c index 6a655800..b345bd16 100644 --- a/misc/examples/list.c +++ b/misc/examples/list.c @@ -17,6 +17,7 @@ int main() { int m = 0; c_forrange (n) clist_fx_push_back(&list, stc64_uniformf(&rng, &dist)), ++m; + double sum = 0.0; printf("sumarize %d:\n", m); c_foreach (i, clist_fx, list) @@ -46,18 +47,21 @@ int main() { const double* v = clist_fx_get(&list, 30); printf("found: %f\n", *v); - c_foreach (i, clist_fx, list) printf(" %g", *i.ref); + c_foreach (i, clist_fx, list) + printf(" %g", *i.ref); puts(""); clist_fx_remove(&list, 30); clist_fx_insert_at(&list, clist_fx_begin(&list), 5); // same as push_front() clist_fx_push_back(&list, 500); clist_fx_push_front(&list, 1964); - clist_fx_iter it = clist_fx_begin(&list); + printf("Full: "); c_foreach (i, clist_fx, list) printf(" %g", *i.ref); + printf("\nSubs: "); + clist_fx_iter it = clist_fx_begin(&list); c_foreach (i, clist_fx, clist_fx_advance(it, 4), clist_fx_end(&list)) printf(" %g", *i.ref); puts(""); |
