diff options
Diffstat (limited to 'docs/csptr_api.md')
| -rw-r--r-- | docs/csptr_api.md | 208 |
1 files changed, 124 insertions, 84 deletions
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 ``` |
