diff options
| author | Tyge Løvset <[email protected]> | 2021-12-12 21:33:22 +0100 |
|---|---|---|
| committer | Tyge Løvset <[email protected]> | 2021-12-12 21:33:22 +0100 |
| commit | d57b9bb7666753c7cf7ab5a0da6d7d11f303c2af (patch) | |
| tree | 258690df4a5ab62055261579967d6dfffaf5b0fd /docs | |
| parent | 9cd20ebfc4f1e10153ff814085499223265ef902 (diff) | |
| download | STC-modified-d57b9bb7666753c7cf7ab5a0da6d7d11f303c2af.tar.gz STC-modified-d57b9bb7666753c7cf7ab5a0da6d7d11f303c2af.zip | |
- Added **cbox** type: container of one element: similar to std::unique_ptr / Rust Box.
- Replaced example for **csptr** in docs.
- Added [**c_forpair**](docs/ccommon_api.md) macro: for-loop with "structural binding" as in c++.
- Deprecated *csptr_X_make()*. Renamed to *csptr_X_new()*. Corresponding **cbox** method is *cbox_X_new()*.
- Deprecated *c_default_fromraw(raw)*. Renamed to *c_default_clone(raw)*.
- Deprecated `i_key_csptr` / `i_val_csptr`. Use `i_key_ref` / `i_val_ref` when specifying containers with **csptr** or **cbox** elements.
- Deprecated `i_cnt`. Use `i_type` instead to define the full container type name.
- Bugfixes and docs updates.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/carray_api.md | 35 | ||||
| -rw-r--r-- | docs/cbox_api.md | 136 | ||||
| -rw-r--r-- | docs/ccommon_api.md | 41 | ||||
| -rw-r--r-- | docs/csptr_api.md | 208 |
4 files changed, 302 insertions, 118 deletions
diff --git a/docs/carray_api.md b/docs/carray_api.md index eb5123b3..5e26f658 100644 --- a/docs/carray_api.md +++ b/docs/carray_api.md @@ -90,29 +90,30 @@ int main() // Ex1 int xd = 30, yd = 20, zd = 10; // define arr3[30][20][10], initialized with zeros. - carr3_f arr3 = carr3_f_with_values(xd, yd, zd, 0.0f); - arr3.data[5][4][3] = 3.14f; + c_autovar (carr3_f arr3 = carr3_f_with_values(xd, yd, zd, 0.0f), + carr3_f_del(&arr3)) { + arr3.data[5][4][3] = 3.14f; - float *arr1 = arr3.data[5][4]; - float **arr2 = arr3.data[5]; + float *arr1 = arr3.data[5][4]; + float **arr2 = arr3.data[5]; - printf("%f\n", arr1[3]); // 3.14 - printf("%f\n", arr2[4][3]); // 3.14 - printf("%f\n", arr3.data[5][4][3]); // 3.14 - carr3_f_del(&arr3); // free array + printf("%f\n", arr1[3]); // 3.14 + printf("%f\n", arr2[4][3]); // 3.14 + printf("%f\n", arr3.data[5][4][3]); // 3.14 + } // Ex2 int w = 256, h = 128; - carr2_i image = carr2_i_init(w, h); - int n = 0; - c_foreach (i, carr2_i, image) { - uint32_t t = n++ % 256; - *i.ref = t | t << 8 | t << 16 | 255; + c_autovar (carr2_i image = carr2_i_init(w, h), carr2_i_del(&image)) { + int n = 0; + c_foreach (i, carr2_i, image) { + uint32_t t = n++ % 256; + *i.ref = t | t << 8 | t << 16 | 255; + } + + for (int y = 0; y < image.ydim; ++y) + image.data[y][y] = 0xffffffff; } - - for (int y = 0; y < image.ydim; ++y) - image.data[y][y] = 0xffffffff; - carr2_i_del(&image); } ``` Output: diff --git a/docs/cbox_api.md b/docs/cbox_api.md new file mode 100644 index 00000000..7c632919 --- /dev/null +++ b/docs/cbox_api.md @@ -0,0 +1,136 @@ +# STC [cbox](../include/stc/cbox.h): Shared Pointers + +**cbox** is a container for one heap allocated object. A **cbox** is empty by default. +The *cbox_X_compare()*, *cbox_X_del()* methods are defined based on the `i_cmp` +and `i_valdel` macros specified. Use *cbox_X_clone(p)* to make a deep copy, which +uses the `i_valfrom` macro if defined. + +When declaring a container with cbox elements, define `i_val_ref` as the cbox type, see example. + +For containers, make sure to pass the result of create functions like *cbox_X_new()* **only** to +*insert()*, *push_back()*, and *push()* functions. Use *emplace()* functions to deep clone +already existing/owned cbox elements. + +See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr) for a functional reference, or Rust [std::boxed::Box](https://doc.rust-lang.org/std/boxed/struct.Box.html) + +## Header file and declaration + +```c +#define i_val // value: REQUIRED +#define i_cmp // three-way compare two i_val* : REQUIRED IF i_val is a non-integral type +#define i_del // destroy value func - defaults to empty destruct +#define i_tag // defaults to i_val +#include <stc/cbox.h> +``` +`X` should be replaced by the value of `i_tag` in all of the following documentation. + +## Methods +```c +cbox_X cbox_X_init(); // return an empty cbox +cbox_X cbox_X_new(i_val val); // allocate new heap object with val. Take ownership of val. +cbox_X cbox_X_from(i_rawval raw); // like cbox_X_new(), but create owned value from raw. +cbox_X cbox_X_with(i_val* p); // create a cbox from a pointer. Takes ownership of p. + +cbox_X cbox_X_clone(cbox_X other); // return deep copied clone +cbox_X cbox_X_move(cbox_X* self); // transfer ownership to another cbox. +void cbox_X_take(cbox_X* self, cbox_X other); // take ownership of other. +void cbox_X_copy(cbox_X* self, cbox_X other); // deep copy to self + +void cbox_X_del(cbox_X* self); // destruct the contained object and free's it. + +void cbox_X_reset(cbox_X* self); +void cbox_X_reset_new(cbox_X* self, i_val val); // assign new cbox with value. Takes ownership of val. +void cbox_X_reset_from(cbox_X* self, i_rawval raw); // make and assign new cbox from raw value. +void cbox_X_reset_with(cbox_X* self, i_val* p); // create cbox with pointer p. Takes ownership of p. + +int cbox_X_compare(const cbox_X* x, const cbox_X* y); // compares pointer addresses if 'i_opt c_no_compare' + // is defined. Otherwise uses 'i_cmp' or default compare. +``` +## Types and constants + +| Type name | Type definition | Used to represent... | +|:-------------------|:--------------------------------|:------------------------| +| `cbox_null` | `{NULL}` | Init nullptr const | +| `cbox_X` | `struct { cbox_X_value* get; }` | The cbox type | +| `cbox_X_value` | `i_val` | The cbox element type | + +## Example + +```c +#include <stdio.h> +#include <string.h> + +void int_del(int* x) { + printf("del: %d\n", *x); +} + +// When 'i_del' is defined, you are also forced to define a clone function with +// 'i_valfrom', as it is normally required when i_del destroys resources. +// +// If cloning is not needed, define 'i_opt c_no_clone' instead of 'i_valfrom' +// both for the cbox type and the container of cbox elements. It will also +// disable emplace container functions. +// +// This applies to all container types, except those with csptr elements, as they +// define cloning internally. + +#define i_val int +#define i_del int_del // optional func, just to display elements destroyed +#define i_valfrom c_default_clone +#include <stc/cbox.h> // cbox_int + +#define i_key_ref cbox_int // note: use i_key_ref instead of i_key +#define i_tag int // tag otherwise defaults to 'ref' +#include <stc/csset.h> // csset_int (like: std::set<std::unique_ptr<int>>) + +#define i_val_ref cbox_int // note: use i_val_ref instead of i_val +#define i_tag int // tag otherwise defaults to 'ref' +#include <stc/cvec.h> // cvec_int (like: std::vector<std::unique_ptr<int>>) + +int main() +{ + c_auto (cvec_int, vec) // declare and init vec, call del at scope exit + c_auto (csset_int, set) // declare and init set, call del at scope exit + { + c_apply(cvec_int, push_back, &vec, { + cbox_int_new(2021), + cbox_int_new(2012), + cbox_int_new(2022), + cbox_int_new(2015), + }); + printf("vec:"); + c_foreach (i, cvec_int, vec) printf(" %d", *i.ref->get); + puts(""); + + // add odd numbers from vec to set + c_foreach (i, cvec_int, vec) + if (*i.ref->get & 1) + csset_int_emplace(&set, *i.ref); // deep copy (clones) *i.ref object + + // erase the two last elements in vec + cvec_int_pop_back(&vec); + cvec_int_pop_back(&vec); + + printf("vec:"); + c_foreach (i, cvec_int, vec) printf(" %d", *i.ref->get); + + printf("\nset:"); + c_foreach (i, csset_int, set) printf(" %d", *i.ref->get); + + puts("\nDone"); + } +} +``` +Output: +``` +vec: 2021 2012 2022 2015 +del: 2015 +del: 2022 +vec: 2021 2012 +set: 2015 2021 +Done +del: 2021 +del: 2015 +del: 2021 +del: 2012 +``` diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 3d353e6c..8c749e8e 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -79,26 +79,33 @@ int main() } ``` -### c_foreach +### 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) | +| 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 structural binding | ```c -#define i_tag x #define i_key int -#include <stc/csset.h> +#define i_val int +#define i_tag ii +#include <stc/csmap.h> ... -c_apply(csset_x, insert, &set, {23, 3, 7, 5, 12}); -c_foreach (i, csset_x, set) - printf(" %d", *i.ref); -// 3 5 7 12 23 -csset_x_iter it = csset_x_find(&set, 7); -c_foreach (i, csset_x, it, csset_x_end(&set)) - printf(" %d", *i.ref); -// 7 12 23 +c_apply_pair(csmap_ii, insert, &map, {{23,1}, {3,2}, {7,3}, {5,4}, {12,5}}); +c_foreach (i, csmap_ii, map) + printf(" %d", i.ref->first); +// out: 3 5 7 12 23 + +csmap_ii_iter it = csmap_ii_find(&map, 7); +c_foreach (i, csmap_ii, it, csmap_ii_end(&map)) + printf(" %d", i.ref->first); +// out: 7 12 23 + +c_forpair (id, count, csmap_ii, map) + printf(" (%d %d)", _.id, _.count); +// out: (3 2) (5 4) (7 3) (12 5) (23 1) ``` ### c_forrange @@ -124,7 +131,7 @@ c_forrange (i, int, 30, 0, -5) printf(" %d", i); ``` ### c_apply, c_apply_pair, c_apply_n -**c_apply** will apply a method on an existing container with the given array elements: +**c_apply** will apply a method on a container with each of the elements in the given array: ```c c_apply(cvec_i, push_back, &vec, {1, 2, 3}); // apply multiple push_backs c_apply_pair(cmap_i, insert, &map, { {4, 5}, {6, 7} }); // inserts to existing map @@ -158,7 +165,7 @@ c_del(cstr, &a, &b); ### General predefined template parameter functions ``` int c_default_compare(const Type*, const Type*); -Type c_default_fromraw(Type val); // simple copy +Type c_default_clone(Type val); // simple copy Type c_default_toraw(const Type* val); // dereference val void c_default_del(Type* val); // does nothing diff --git a/docs/csptr_api.md b/docs/csptr_api.md index ba85ba8c..ca1e8893 100644 --- a/docs/csptr_api.md +++ b/docs/csptr_api.md @@ -13,124 +13,164 @@ All **csptr** functions can be called by multiple threads on different instances additional synchronization even if these instances are copies and share ownership of the same object. **csptr** uses thread-safe atomic reference counting, through the *csptr_X_clone()* and *csptr_X_del()* methods. -When declaring a container with shared pointers, define the `i_val_csptr` with the full csptr type. -See example. +When declaring a container with shared pointers, define `i_val_ref` as the csptr type, see example. -Also for containers, make sure to pass the result of *csptr_X_make()* to *insert*, *push_back*, -or *push*, and not an *emplace* function. The *csptr_X_make()* method creates a **csptr** with -use-count 1, and *emplace* will ***clone*** it and increase the count, causing a memory leak. Use -*emplace* functions when sharing **csptr**s between containers or other existing shared pointers. +For containers, make sure to pass the result of create functions *csptr_X_new()* **only** to *insert()*, +*push_back()*, and *push()* functions. Use *emplace()* method for sharing existing **csptr**s between +containers or other existing shared pointers, as they internally clone/share the input. -See the c++ classes [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr) for a functional reference. +See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr) for a functional reference, or Rust [std::sync::Arc](https://doc.rust-lang.org/std/sync/struct.Arc.html) / [std::rc::Rc](https://doc.rust-lang.org/std/rc/struct.Rc.html). ## Header file and declaration ```c -#define i_val // value: REQUIRED -#define i_cmp // three-way compare two i_val* : REQUIRED IF i_val is a non-integral type -#define i_del // destroy value func - defaults to empty destruct -#define i_tag // defaults to i_val +#define i_val // value: REQUIRED +#define i_cmp // three-way compare two i_val* : REQUIRED IF i_val is a non-integral type +#define i_del // destroy value func - defaults to empty destruct +#define i_tag // defaults to i_val +#define i_opt c_no_atomic // Non-atomic reference counting, like Rust Rc. #include <stc/csptr.h> ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. ## Methods ```c -csptr_X csptr_X_init(); // empty constructor -csptr_X csptr_X_make(i_val val); // make_shared constructor, like std::make_shared() -csptr_X csptr_X_from(i_val* p); // construct from raw pointer -csptr_X csptr_X_clone(csptr_X ptr); // return ptr with increased use count -csptr_X csptr_X_move(csptr_X* self); // transfer ownership to another sptr. -void csptr_X_take(csptr_X* self, csptr_X other); // take a new-created or moved csptr -void csptr_X_copy(csptr_X* self, csptr_X other); // copy shared (increase use count) - -void csptr_X_del(csptr_X* self); // destruct (decrease use count, free at 0) -long csptr_X_use_count(csptr_X ptr); - -void csptr_X_reset(csptr_X* self); -void csptr_X_reset_with(csptr_X* self, i_val val); // make and assign new csptr with value -void csptr_X_reset_from(csptr_X* self, i_val* p); // create csptr from p. - -int csptr_X_compare(const csptr_X* x, const csptr_X* y); +csptr_X csptr_X_init(); // empty shared pointer +csptr_X csptr_X_new(i_val val); // create new heap allocated object. Take ownership of val. +csptr_X csptr_X_from(i_rawval raw); // like csptr_X_new(), but construct owned value from raw. +csptr_X csptr_X_with(i_val* p); // create a csptr from raw pointer. Takes ownership of p. + +csptr_X csptr_X_clone(csptr_X other); // return other with increased use count +csptr_X csptr_X_move(csptr_X* self); // transfer ownership to another csptr. +void csptr_X_take(csptr_X* self, csptr_X other); // take ownership of other. +void csptr_X_copy(csptr_X* self, csptr_X other); // copy shared (increase use count) + +void csptr_X_del(csptr_X* self); // destruct (decrease use count, free at 0) +long csptr_X_use_count(csptr_X ptr); + +void csptr_X_reset(csptr_X* self); +void csptr_X_reset_new(csptr_X* self, i_val val); // assign new csptr with value. Takes ownership of val. +void csptr_X_reset_from(csptr_X* self, i_rawval raw); // make and assign new csptr from raw value. +void csptr_X_reset_with(csptr_X* self, i_val* p); // create csptr with pointer p. Takes ownership of p. + +int csptr_X_compare(const csptr_X* x, const csptr_X* y); // compares pointer addresses if 'i_opt c_no_compare' + // is defined. Otherwise uses 'i_cmp' or default compare. ``` ## Types and constants | Type name | Type definition | Used to represent... | -|:--------------------|:--------------------------------------------------------------|:-------------------------| -| `csptr_null` | `{NULL, NULL}` | Init nullptr const | -| `csptr_X` | `struct { csptr_X_value* get; atomic_count_t* use_count; }` | The csptr type | -| `csptr_X_value` | `i_val` | The csptr element type | -| `atomic_count_t` | `long` | The reference counter | +|:--------------------|:--------------------------------------------------|:-------------------------| +| `csptr_null` | `{NULL, NULL}` | Init nullptr const | +| `csptr_X` | `struct { csptr_X_value* get; long* use_count; }` | The csptr type | +| `csptr_X_value` | `i_val` | The csptr element type | ## Example ```c -#include <stdio.h> - -void int_del(int* x) { - printf("del: %d\n", *x); -} - +// Create a stack and a list of shared pointers to maps, +// and demonstrate sharing and cloning of maps. +#define i_type Map +#define i_key_str // strings #define i_val int -#define i_valdel int_del // optional func to display elements destroyed -#include <stc/csptr.h> // csptr_int +#define i_keydel(p) (printf("del name: %s\n", (p)->str), cstr_del(p)) +#include <stc/csmap.h> + +#define i_type Arc // (atomic) ref. counted type +#define i_val Map +#define i_from Map_clone +#define i_del(p) (printf("del Arc:\n"), Map_del(p)) +// no comparison of Maps needed (or available), and +// no need for atomic ref. count in single thread: +#define i_opt c_no_compare|c_no_atomic +#include <stc/csptr.h> -#define i_key_csptr csptr_int -#define i_tag int -#include <stc/csset.h> // csset_int: csset<csptr_int> +#define i_type Stack +#define i_val_ref Arc // define i_val_ref for csptr / cbox value, not i_val +#include <stc/cstack.h> -#define i_val_csptr csptr_int -#define i_tag int -#include <stc/cvec.h> // cvec_int: cvec<csptr_int> +#define i_type List +#define i_val_ref Arc // as above +#include <stc/clist.h> int main() { - c_auto (cvec_int, vec) // declare and init vec, call del at scope exit - c_auto (csset_int, set) // declare and init set, call del at scope exit + c_auto (Stack, stack) + c_auto (List, list) { - c_apply(cvec_int, push_back, &vec, { - csptr_int_make(2021)), - csptr_int_make(2012)), - csptr_int_make(2022)), - csptr_int_make(2015)), + // POPULATE the stack with shared pointers to Map: + Map *map; + map = Stack_push(&stack, Arc_new(Map_init()))->get; + c_apply_pair (Map, emplace, map, { + {"Joey", 1990}, {"Mary", 1995}, {"Joanna", 1992} + }); + map = Stack_push(&stack, Arc_new(Map_init()))->get; + c_apply_pair (Map, emplace, map, { + {"Rosanna", 2001}, {"Brad", 1999}, {"Jack", 1980} }); - printf("vec:"); - c_foreach (i, cvec_int, vec) printf(" %d", *i.ref->get); - puts(""); - - // add odd numbers from vec to set - c_foreach (i, cvec_int, vec) - if (*i.ref->get & 1) - csset_int_emplace(&set, *i.ref); // copy shared pointer => increments counter. - - // erase the two last elements in vec - cvec_int_pop_back(&vec); - cvec_int_pop_back(&vec); - - printf("vec:"); - c_foreach (i, cvec_int, vec) printf(" %d", *i.ref->get); - - printf("\nset:"); - c_foreach (i, csset_int, set) printf(" %d", *i.ref->get); - c_autovar (csptr_int p = csptr_int_clone(vec.data[0]), csptr_int_del(&p)) { - printf("\n%d is now owned by %zu objects\n", *p.get, *p.use_count); + // POPULATE the list: + map = List_push_back(&list, Arc_new(Map_init()))->get; + c_apply_pair (Map, emplace, map, { + {"Steve", 1979}, {"Rick", 1974}, {"Tracy", 2003} + }); + + // Share two Maps from the stack with the list using emplace (clones the csptr): + List_emplace_back(&list, stack.data[0]); + List_emplace_back(&list, stack.data[1]); + + // Clone (deep copy) a Map from the stack to the list + // List will contain two shared and two unshared maps. + map = List_push_back(&list, Arc_new(Map_clone(*stack.data[1].get)))->get; + + // Add one more element to the cloned map: + Map_emplace_or_assign(map, "CLONED", 2021); + + // Add one more element to the shared map: + Map_emplace_or_assign(stack.data[1].get, "SHARED", 2021); + + + puts("STACKS"); + c_foreach (i, Stack, stack) { + c_forpair (name, year, Map, *i.ref->get) + printf(" %s:%d", _.name, _.year); + puts(""); + } + puts("LIST"); + c_foreach (i, List, list) { + c_forpair (name, year, Map, *i.ref->get) + printf(" %s:%d", _.name, _.year); + puts(""); } - - puts("\nDone"); } } ``` Output: ``` -vec: 2021 2012 2022 2015 -del: 2022 -vec: 2021 2012 -set: 2015 2021 -2021 is now owned by 3 objects -Done -del: 2015 -del: 2021 -del: 2012 +STACKS + Joanna:1992 Joey:1990 Mary:1995 + Brad:1999 Jack:1980 Rosanna:2001 SHARED:2021 +LIST + Rick:1974 Steve:1979 Tracy:2003 + Joanna:1992 Joey:1990 Mary:1995 + Brad:1999 Jack:1980 Rosanna:2001 SHARED:2021 + Brad:1999 CLONED:2021 Jack:1980 Rosanna:2001 +del Arc: +del name: Rick +del name: Tracy +del name: Steve +del Arc: +del name: CLONED +del name: Brad +del name: Rosanna +del name: Jack +del Arc: +del name: Brad +del name: SHARED +del name: Rosanna +del name: Jack +del Arc: +del name: Joanna +del name: Mary +del name: Joey ``` |
