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 | |
| 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.
| -rw-r--r-- | README.md | 52 | ||||
| -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 | ||||
| -rw-r--r-- | examples/cpque.c | 2 | ||||
| -rw-r--r-- | examples/csmap_erase.c | 2 | ||||
| -rw-r--r-- | examples/ex_gauss2.c | 6 | ||||
| -rw-r--r-- | examples/inits.c | 10 | ||||
| -rw-r--r-- | examples/new_map.c | 3 | ||||
| -rw-r--r-- | examples/new_sptr.c | 13 | ||||
| -rw-r--r-- | examples/ptr_elems.c | 53 | ||||
| -rw-r--r-- | examples/queue.c | 2 | ||||
| -rw-r--r-- | examples/sharedptr.c | 55 | ||||
| -rw-r--r-- | examples/splitstr.c | 2 | ||||
| -rw-r--r-- | examples/sptr_ex.c | 13 | ||||
| -rw-r--r-- | examples/sptr_pthread.c | 3 | ||||
| -rw-r--r-- | include/stc/cbox.h | 174 | ||||
| -rw-r--r-- | include/stc/ccommon.h | 99 | ||||
| -rw-r--r-- | include/stc/clist.h | 1 | ||||
| -rw-r--r-- | include/stc/csptr.h | 74 | ||||
| -rw-r--r-- | include/stc/csview.h | 4 | ||||
| -rw-r--r-- | include/stc/forward.h | 7 | ||||
| -rw-r--r-- | include/stc/template.h | 150 |
24 files changed, 804 insertions, 341 deletions
@@ -1,22 +1,26 @@  STC - Smart Template Containers for C -====================================== +===================================== News ---- -Breaking changes for i_cmp_none and i_fwd: -- Removed: i_cmp_none and i_fwd (replaced by c_no_compare and c_is_fwd args to i_opt). -- Added compile-time disabling of clonable and comparable container elements, controlled by i_opt (c_no_clone | c_no_compare) -- Added i_opt: can define multiple compile-time options: c_no_compare, c_no_clone, c_no_atomic, c_is_fwd: may be combined with | separator. -- Except for csptr, when i_del / i_valdel / i_keydel is defined, also i_from / i_keyfrom / i_valfrom must be defined or i_opt c_no_clone. -- For struct elements, either i_cmp must be defined (as before), or define i_opt c_no_compare (for non-associative containers only). - -**VERSION 2.X RELEASED**: There are two main breaking changes from V1.X. +- Added **cbox** type: container of one element: similar to [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr) +- 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. + +Previous: +- Added `i_opt` template parameter: compile-time options: `c_no_compare`, `c_no_clone`, `c_no_atomic`, `c_is_fwd`; may be combined with `|` +- Removed: i_cmp_none and i_fwd: replaced by `c_no_compare` and `c_is_fwd` args to `i_opt`. + +VERSION 2.0 released. Two main breaking changes from V1.X. - Uses a different way to instantiate templated containers, which is incompatible with v1.X. -- c_forauto, c_forvar, c_forscope macros are now renamed to **c_auto**, **c_autovar**, and **c_autoscope**. These are for automatic scope resource management, aka RAII. - -The new template instantiation style has multiple advantages, e.g. implementation does not contain long macro definitions for code generation. Also, specifying template arguments is more user friendly and flexible. +- New **c_auto**, **c_autovar**, and **c_autoscope** macros. These are for automatic scope resource management, aka RAII. +- The new template instantiation style has multiple advantages, e.g. implementation does not contain long macro definitions for code generation. Also, specifying template arguments is more user friendly and flexible. Introduction ------------ @@ -32,6 +36,7 @@ which by the compiler is seen as different code because of macro name substituti - [***carr2, carr3*** - **2d** and **3d** dynamic **array** type](docs/carray_api.md) - [***cbits*** - **std::bitset** alike type](docs/cbits_api.md) +- [***cbox*** - **std::unique_ptr** alike type](docs/cbox_api.md) - [***cdeq*** - **std::deque** alike type](docs/cdeq_api.md) - [***clist*** - **std::forward_list** alike type](docs/clist_api.md) - [***cmap*** - **std::unordered_map** alike type](docs/cmap_api.md) @@ -260,13 +265,13 @@ The template parameters are given by a `#define i_xxxx` statement, where *xxxx* The list of template parameters: - `i_tag` - Container type tag. Defaults to same as `i_key` -- `i_cnt` - Container type name. -- `i_opt` - Boolean properties: may combine `c_no_compare`, `c_no_clone`, `c_is_fwd` with `|` character. +- `i_type` - Full container type name (optional, alternative to `i_tag`). +- `i_opt` - Boolean properties: may combine `c_no_compare`, `c_no_clone`, `c_no_atomic`, `c_is_fwd` with `|` separator. - `i_key` - Maps key type. **[required]** for cmap/csmap. - `i_val` - The container **[required]** element type. For cmap/csmap, it is the mapped value. - `i_cmp` - Three-way comparison of two `i_keyraw`, **[required]** for non-integral `i_keyraw`. -- `i_equ` - Equality comparison of two `i_keyraw`, `i_cmp` alternative. +- `i_equ` - Equality comparison of two `i_keyraw`- defaults to `!i_cmp`. - `i_keydel` - Destroy map key func - defaults to empty destructor. - `i_keyraw` - Convertion "raw" type - defaults to `i_key` type. @@ -278,10 +283,11 @@ The list of template parameters: - `i_valfrom` - Convertion func `i_valraw` => `i_val` - defaults to simple copy. - `i_valto` - Convertion func `i_val` => `i_valraw` - defaults to simple copy. -An alternative to defining `i_cmp`, you may `#define i_opt c_no_compare` to disable methods using comparison. +Instead of defining `i_cmp`, you may define `i_opt c_no_compare` to disable methods using comparison. + +Instead of defining `i_valfrom`, you may define `i_opt c_no_clone` to disable methods using deep copy. -Similarly, if a destructor `i_del` is defined, either define `i_valfrom` constructor/clone function -or `#define i_opt c_no_clone` to disable cloning and the emplace methods. Unless these requirements are met, +If a destructor `i_del` is defined, then define either `i_valfrom` or `i_opt c_no_clone`, otherwise compile errors are generated. The *emplace* versus non-emplace container methods @@ -291,7 +297,7 @@ with **emplace**, e.g. *cvec_X_emplace_back()*. This is a convenient alternative *cvec_X_push_back()* when dealing non-trivial container elements, e.g. strings, shared pointers or other elements using dynamic memory or shared resources. -The **emplace** methods ***constructs*** or ***clones*** the given elements before they are added +The **emplace** methods ***constructs*** or ***clones*** the given elements when they are added to the container. In contrast, the *non-emplace* methods ***moves*** the given elements into the container. For containers of integral or trivial element types, **emplace** and corresponding *non-emplace* methods are identical. @@ -387,14 +393,14 @@ typedef struct Dataset { User-defined container type name -------------------------------- -Define `i_cnt` instead of `i_tag`: +Define `i_type` instead of `i_tag`: ```c +#define i_type MyVec #define i_val int -#define i_cnt myvec #include <stc/cvec.h> -myvec vec = myvec_init(); -myvec_push_back(&vec, 1); +myvec vec = MyVec_init(); +MyVec_push_back(&vec, 1); ... ``` 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 ``` diff --git a/examples/cpque.c b/examples/cpque.c index db7bc02c..b3ee4adf 100644 --- a/examples/cpque.c +++ b/examples/cpque.c @@ -7,7 +7,7 @@ static int (*icmp_fn)(const int* x, const int* y); #define i_val int #define i_cmp icmp_fn -#define i_cnt ipque +#define i_type ipque #include <stc/cpque.h> #define imix_less(left, right) ((*(left) ^ 1) < (*(right) ^ 1)) diff --git a/examples/csmap_erase.c b/examples/csmap_erase.c index bbb69a35..627c11d4 100644 --- a/examples/csmap_erase.c +++ b/examples/csmap_erase.c @@ -5,7 +5,7 @@ #define i_key int #define i_val_str -#define i_cnt mymap +#define i_type mymap #include <stc/csmap.h> void printmap(mymap m) diff --git a/examples/ex_gauss2.c b/examples/ex_gauss2.c index b3890ecf..702c8ff3 100644 --- a/examples/ex_gauss2.c +++ b/examples/ex_gauss2.c @@ -30,11 +30,11 @@ int main() // Print the gaussian bar chart
c_auto (cstr, bar)
- c_foreach (i, csmap_int, mhist) {
- size_t n = (size_t) (i.ref->second * StdDev * Scale * 2.5 / (float)N);
+ c_forpair (index, count, csmap_int, mhist) {
+ size_t n = (size_t) (_.count * StdDev * Scale * 2.5 / (float)N);
if (n > 0) {
cstr_resize(&bar, n, '*');
- printf("%4d %s\n", i.ref->first, bar.str);
+ printf("%4d %s\n", _.index, bar.str);
}
}
}
diff --git a/examples/inits.c b/examples/inits.c index be0914c2..a9751ba5 100644 --- a/examples/inits.c +++ b/examples/inits.c @@ -13,8 +13,8 @@ typedef struct {int x, y;} ipair_t;
inline static int ipair_compare(const ipair_t* a, const ipair_t* b) {
- int cx = c_default_compare(&a->x, &b->x);
- return cx == 0 ? c_default_compare(&a->y, &b->y) : cx;
+ int c = c_default_compare(&a->x, &b->x);
+ return c ? c : c_default_compare(&a->y, &b->y);
}
@@ -45,7 +45,7 @@ int main(void) }
puts("");
- // CVEC PRIORITY QUEUE
+ // PRIORITY QUEUE
cpque_f_make_heap(&floats);
c_apply(cpque_f, push, &floats, {40.0f, 20.0f, 50.0f, 30.0f, 10.0f});
@@ -89,8 +89,8 @@ int main(void) cmap_cnt_emplace(&countries, "Norway", 0).ref->second += 20;
cmap_cnt_emplace(&countries, "Finland", 0).ref->second += 20;
- c_foreach (i, cmap_cnt, countries)
- printf("%s: %d\n", i.ref->first.str, i.ref->second);
+ c_forpair (country, health, cmap_cnt, countries)
+ printf("%s: %d\n", _.country.str, _.health);
puts("");
}
diff --git a/examples/new_map.c b/examples/new_map.c index 7f4d19ee..8975cd77 100644 --- a/examples/new_map.c +++ b/examples/new_map.c @@ -21,6 +21,7 @@ int point_compare(const Point* a, const Point* b) { return c ? c : c_default_compare(&a->y, &b->y);
}
+// Point => int map
#define i_key Point
#define i_val int
#define i_cmp point_compare
@@ -28,7 +29,7 @@ int point_compare(const Point* a, const Point* b) { #define i_tag pnt
#include <stc/cmap.h>
-// int => int map
+// cstr => cstr map
#define i_key_str
#define i_val_str
#include <stc/cmap.h>
diff --git a/examples/new_sptr.c b/examples/new_sptr.c index 036ce581..4a715160 100644 --- a/examples/new_sptr.c +++ b/examples/new_sptr.c @@ -2,7 +2,7 @@ struct Person { cstr name, last; } typedef Person;
-Person Person_init(const char* name, const char* last) {
+Person Person_from(const char* name, const char* last) {
return (Person){.name = cstr_from(name), .last = cstr_from(last)};
}
void Person_del(Person* p) {
@@ -12,6 +12,7 @@ void Person_del(Person* p) { #define i_val Person
#define i_del Person_del
+#define i_opt c_no_compare
#define i_tag person
#include <stc/csptr.h>
@@ -21,21 +22,21 @@ void Person_del(Person* p) { #define i_del(x) printf("del: %d\n", *(x))
#include <stc/csptr.h>
-#define i_val_csptr csptr_int
+#define i_val_ref csptr_int
#define i_tag iptr
#include <stc/cstack.h>
int main(void) {
- c_autovar (csptr_person p = csptr_person_make(Person_init("John", "Smiths")), csptr_person_del(&p))
+ c_autovar (csptr_person p = csptr_person_new(Person_from("John", "Smiths")), csptr_person_del(&p))
c_autovar (csptr_person q = csptr_person_clone(p), csptr_person_del(&q)) // share the pointer
{
printf("%s %s. uses: %lu\n", q.get->name.str, q.get->last.str, *q.use_count);
}
c_auto (cstack_iptr, stk) {
- cstack_iptr_push(&stk, csptr_int_make(10));
- cstack_iptr_push(&stk, csptr_int_make(20));
- cstack_iptr_push(&stk, csptr_int_make(30));
+ cstack_iptr_push(&stk, csptr_int_new(10));
+ cstack_iptr_push(&stk, csptr_int_new(20));
+ cstack_iptr_push(&stk, csptr_int_new(30));
cstack_iptr_emplace(&stk, *cstack_iptr_top(&stk));
cstack_iptr_emplace(&stk, *cstack_iptr_begin(&stk).ref);
diff --git a/examples/ptr_elems.c b/examples/ptr_elems.c index 1b4f881a..7cb35043 100644 --- a/examples/ptr_elems.c +++ b/examples/ptr_elems.c @@ -3,38 +3,45 @@ struct { double x, y; } typedef Point;
-#define i_val Point*
-#define i_from(val) c_new(Point, *(val))
-#define i_del(pval) c_free(*(pval))
+// Set of Point pointers: define all template parameters "in-line"
+// Note it may be simpler to use a cbox for this.
+#define i_key Point*
+#define i_keydel(x) c_free(*(x))
+#define i_keyfrom(x) c_new(Point, *(x))
+#define i_hash(x, n) c_default_hash(*(x), sizeof *(x))
+#define i_equ(x, y) c_memcmp_equalto(*(x), *(y))
#define i_tag pnt
-#include <stc/cvec.h>
+#include <stc/cset.h>
+// Map of int64 pointers: For fun, define valraw as int64_t for easy emplace call!
#define i_key_str
-#define i_val int*
-#define i_valraw int
-#define i_valfrom(raw) c_new(int, raw)
-#define i_valto(pval) **(pval)
-#define i_valdel(pval) c_free(*(pval))
+#define i_valraw int64_t
+#define i_val i_valraw*
+#define i_valdel(x) c_free(*(x))
+#define i_valfrom(raw) c_new(i_valraw, raw)
+#define i_valto(x) **(x)
#include <stc/cmap.h>
int main()
{
- c_auto (cvec_pnt, vec, cpy)
+ c_auto (cset_pnt, set, cpy)
{
- printf("Vector with pointer elements:\n");
- // c++: vec.push_back(new Point{1.2, 3.4});
- cvec_pnt_push_back(&vec, c_new(Point, {1.2, 3.4}));
- cvec_pnt_push_back(&vec, c_new(Point, {6.1, 4.7}));
+ printf("Set with pointer elements:\n");
+ // c++: set.insert(new Point{1.2, 3.4});
+ cset_pnt_insert(&set, c_new(Point, {1.2, 3.4}));
+ Point* q = *cset_pnt_insert(&set, c_new(Point, {6.1, 4.7})).ref;
+ cset_pnt_insert(&set, c_new(Point, {5.7, 2.3}));
- cpy = cvec_pnt_clone(vec);
- cpy.data[1]->x = 100;
+ cpy = cset_pnt_clone(set);
+ cset_pnt_erase(&cpy, q);
+
+ printf("set:");
+ c_foreach (i, cset_pnt, set)
+ printf(" (%g %g)", i.ref[0]->x, i.ref[0]->y);
- printf("vec:");
- c_foreach (i, cvec_pnt, vec)
- printf(" (%g %g)", (*i.ref)->x, (*i.ref)->y);
printf("\ncpy:");
- c_foreach (i, cvec_pnt, cpy)
- printf(" (%g %g)", (*i.ref)->x, (*i.ref)->y);
+ c_foreach (i, cset_pnt, cpy)
+ printf(" (%g %g)", i.ref[0]->x, i.ref[0]->y);
puts("");
}
@@ -48,7 +55,7 @@ int main() cmap_str_emplace(&map, "hello", 200);
cmap_str_emplace(&map, "goodbye", 400);
- c_foreach (i, cmap_str, map)
- printf("%s: %d\n", i.ref->first.str, *i.ref->second);
+ c_forpair (name, number, cmap_str, map)
+ printf("%s: %d\n", _.name.str, *_.number);
}
}
diff --git a/examples/queue.c b/examples/queue.c index 2c2052e5..4acaa4d6 100644 --- a/examples/queue.c +++ b/examples/queue.c @@ -2,6 +2,8 @@ #include <stdio.h>
#define i_val int
+#define i_del(x) printf("drop %d\n", *(x))
+#define i_from c_default_clone
#define i_tag i
#include <stc/cqueue.h>
diff --git a/examples/sharedptr.c b/examples/sharedptr.c index dbb3746f..a8e3e3ae 100644 --- a/examples/sharedptr.c +++ b/examples/sharedptr.c @@ -1,53 +1,56 @@ #include <stdio.h>
+#include <string.h>
-void int_del(int* x) { printf("del: %d\n", *x); }
+void int_del(int* x) {
+ printf("del: %d\n", *x);
+}
+// csptr implements its own clone method using ref counting, so 'i_valfrom'
+// should not be defined (ignored).
#define i_val int
-#define i_valdel int_del // optional func to show elements destroyed
-#include <stc/csptr.h> // csptr_int: shared pointer to int
+#define i_del int_del // optional func, just to display elements destroyed
+#include <stc/csptr.h> // csptr_int
-#define i_key_csptr csptr_int
-#define i_tag intp
-#include <stc/csset.h> // csset_intp: csset<csptr_int>
+#define i_key_ref csptr_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::shared_ptr<int>>)
-#define i_val_csptr csptr_int
-#define i_tag intp
-#include <stc/cvec.h> // cvec_intp: cvec<csptr_int>
+#define i_val_ref csptr_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::shared_ptr<int>>)
int main()
{
- c_auto (cvec_intp, vec)
- c_auto (csset_intp, set) // declare and init set, call del at scope exit
+ 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_intp, push_back, &vec, {
- csptr_int_make(2021),
- csptr_int_make(2012),
- csptr_int_make(2022),
- csptr_int_make(2015),
- });
+ const int years[] = {2021, 2012, 2022, 2015};
+ c_forrange (i, c_arraylen(years))
+ cvec_int_push_back(&vec, csptr_int_new(years[i]));
+
printf("vec:");
- c_foreach (i, cvec_intp, vec) printf(" %d", *i.ref->get);
+ c_foreach (i, cvec_int, vec) printf(" %d", *i.ref->get);
puts("");
// add odd numbers from vec to set
- c_foreach (i, cvec_intp, vec)
+ c_foreach (i, cvec_int, vec)
if (*i.ref->get & 1)
- csset_intp_emplace(&set, *i.ref); // copy shared pointer => increments counter.
+ csset_int_emplace(&set, *i.ref); // copy shared pointer => increments counter.
// erase the two last elements in vec
- cvec_intp_pop_back(&vec);
- cvec_intp_pop_back(&vec);
+ cvec_int_pop_back(&vec);
+ cvec_int_pop_back(&vec);
printf("vec:");
- c_foreach (i, cvec_intp, vec) printf(" %d", *i.ref->get);
+ c_foreach (i, cvec_int, vec) printf(" %d", *i.ref->get);
printf("\nset:");
- c_foreach (i, csset_intp, set) printf(" %d", *i.ref->get);
+ 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 %lu objects\n", *p.get, *p.use_count);
+ printf("\n%d is now owned by %zu objects\n", *p.get, *p.use_count);
}
- puts("Done");
+ puts("\nDone");
}
}
diff --git a/examples/splitstr.c b/examples/splitstr.c index 82914485..baa48d21 100644 --- a/examples/splitstr.c +++ b/examples/splitstr.c @@ -5,7 +5,7 @@ void print_split(csview str, csview sep) csview token = csview_first_token(str, sep);
for (;;) {
// print non-null-terminated csview
- printf("\t\"%.*s\"\n", csview_ARG(token));
+ printf("\t\"%.*s\"\n", c_svarg(token));
if (csview_end(&token).ref == csview_end(&str).ref) break;
token = csview_next_token(str, sep, token);
}
diff --git a/examples/sptr_ex.c b/examples/sptr_ex.c index 702edef9..e8e08b5f 100644 --- a/examples/sptr_ex.c +++ b/examples/sptr_ex.c @@ -20,9 +20,10 @@ void Song_del(Song* s) { #define i_val Song
#define i_del Song_del
#define i_tag song
+#define i_opt c_no_compare
#include <stc/csptr.h> // define csptr_song
-#define i_val_csptr csptr_song
+#define i_val_ref csptr_song
#define i_tag song
#include <stc/cvec.h>
@@ -31,9 +32,9 @@ void example3() c_auto (cvec_song, v, v2)
{
c_apply(cvec_song, push_back, &v, {
- csptr_song_make(Song_from("Bob Dylan", "The Times They Are A Changing")),
- csptr_song_make(Song_from("Aretha Franklin", "Bridge Over Troubled Water")),
- csptr_song_make(Song_from("Thalia", "Entre El Mar y Una Estrella"))
+ csptr_song_new(Song_from("Bob Dylan", "The Times They Are A Changing")),
+ csptr_song_new(Song_from("Aretha Franklin", "Bridge Over Troubled Water")),
+ csptr_song_new(Song_from("Thalia", "Entre El Mar y Una Estrella"))
});
c_foreach (s, cvec_song, v)
@@ -41,8 +42,8 @@ void example3() cvec_song_emplace_back(&v2, *s.ref); // note: calls csptr_song_clone()
c_apply(cvec_song, push_back, &v2, {
- csptr_song_make(Song_from("Michael Jackson", "Billie Jean")),
- csptr_song_make(Song_from("Rihanna", "Stay")),
+ csptr_song_new(Song_from("Michael Jackson", "Billie Jean")),
+ csptr_song_new(Song_from("Rihanna", "Stay")),
});
c_foreach (s, cvec_song, v2)
diff --git a/examples/sptr_pthread.c b/examples/sptr_pthread.c index 0a1b7c79..d82ea938 100644 --- a/examples/sptr_pthread.c +++ b/examples/sptr_pthread.c @@ -15,6 +15,7 @@ void Base_del(Base* b) { printf("Base::~Base()\n"); } #define i_val Base
#define i_del Base_del
+#define i_opt c_no_compare
#define i_tag base
#include <stc/csptr.h>
@@ -34,7 +35,7 @@ void* thr(csptr_base* lp) int main()
{
- csptr_base p = csptr_base_make((Base){42});
+ csptr_base p = csptr_base_new((Base){42});
printf("Created a Base\n"
" p.get() = %p, p.use_count() = %ld\n", (void*)p.get, *p.use_count);
diff --git a/include/stc/cbox.h b/include/stc/cbox.h new file mode 100644 index 00000000..445057dd --- /dev/null +++ b/include/stc/cbox.h @@ -0,0 +1,174 @@ +/* MIT License
+ *
+ * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* cbox: heap allocated boxed type
+#include <stc/cstr.h>
+
+typedef struct { cstr name, last; } Person;
+
+Person Person_from(const char* name, const char* last) {
+ return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+}
+Person Person_clone(Person p) {
+ p.name = cstr_clone(p.name);
+ p.last = cstr_clone(p.last);
+ return p;
+}
+void Person_del(Person* p) {
+ printf("del: %s %s\n", p->name.str, p->last.str);
+ c_del(cstr, &p->name, &p->last);
+}
+
+#define i_val Person
+#define i_valdel Person_del
+#define i_valfrom Person_clone
+#define i_opt c_no_compare // compare by .get addresses only
+#define i_tag prs
+#include <stc/cbox.h>
+
+int main() {
+ c_autovar (cbox_prs p = cbox_prs_new(Person_from("John", "Smiths")), cbox_prs_del(&p))
+ c_autovar (cbox_prs q = cbox_prs_clone(p), cbox_prs_del(&q))
+ {
+ cstr_assign(&q.get->name, "Joe");
+
+ printf("%s %s.\n", p.get->name.str, p.get->last.str);
+ printf("%s %s.\n", q.get->name.str, q.get->last.str);
+ }
+}
+*/
+
+#ifndef CBOX_H_INCLUDED
+#define CBOX_H_INCLUDED
+#include "ccommon.h"
+#include "forward.h"
+#include <stdlib.h>
+
+#define cbox_null {NULL}
+#endif // CBOX_H_INCLUDED
+
+#ifndef _i_prefix
+#define _i_prefix cbox_
+#endif
+#include "template.h"
+
+#if !c_option(c_is_fwd)
+_cx_deftypes(_c_cbox_types, _cx_self, i_val);
+#endif
+
+// constructors (takes ownsership)
+STC_INLINE _cx_self
+_cx_memb(_init)(void) { return c_make(_cx_self){NULL}; }
+
+STC_INLINE _cx_self
+_cx_memb(_with)(i_val* p) { return c_make(_cx_self){p}; }
+
+STC_INLINE _cx_self
+_cx_memb(_new)(i_val val) {
+ return c_make(_cx_self){c_new(i_val, val)};
+}
+
+// destructor
+STC_INLINE void
+_cx_memb(_del)(_cx_self* self) {
+ if (self->get) { i_valdel(self->get); c_free(self->get); }
+}
+
+STC_INLINE _cx_self
+_cx_memb(_move)(_cx_self* self) {
+ _cx_self ptr = *self; self->get = NULL;
+ return ptr;
+}
+
+STC_INLINE void
+_cx_memb(_reset)(_cx_self* self) {
+ _cx_memb(_del)(self); self->get = NULL;
+}
+
+// take ownership of *p
+STC_INLINE void
+_cx_memb(_reset_with)(_cx_self* self, _cx_value* p) {
+ _cx_memb(_del)(self); self->get = p;
+}
+
+// take ownership of val
+STC_INLINE void
+_cx_memb(_reset_new)(_cx_self* self, i_val val) {
+ if (self->get) { i_valdel(self->get); *self->get = val; }
+ else self->get = c_new(i_val, val);
+}
+
+#if !c_option(c_no_clone)
+ STC_INLINE _cx_self
+ _cx_memb(_from)(i_valraw raw) {
+ return c_make(_cx_self){c_new(i_val, i_valfrom(raw))};
+ }
+
+ STC_INLINE void
+ _cx_memb(_reset_from)(_cx_self* self, i_valraw raw) {
+ _cx_memb(_reset_new)(self, i_valfrom(raw));
+ }
+
+ STC_INLINE _cx_self
+ _cx_memb(_clone)(_cx_self other) {
+ if (!other.get) return other;
+ return c_make(_cx_self){c_new(i_val, i_valfrom(i_valto(other.get)))};
+ }
+
+ STC_INLINE void
+ _cx_memb(_copy)(_cx_self* self, _cx_self other) {
+ if (self->get == other.get) return;
+ if (other.get) _cx_memb(_reset_new)(self, *other.get);
+ else _cx_memb(_reset)(self);
+ }
+#endif
+
+STC_INLINE void
+_cx_memb(_take)(_cx_self* self, _cx_self other) {
+ if (other.get != self->get) _cx_memb(_del)(self);
+ *self = other;
+}
+
+STC_INLINE uint64_t
+_cx_memb(_hash)(const _cx_self* self, size_t n) {
+ #if c_option(c_no_compare) && SIZE_MAX >> 32
+ return c_hash64(&self->get, 8);
+ #elif c_option(c_no_compare)
+ return c_hash32(&self->get, 4);
+ #else
+ i_valraw raw = i_valto(self->get);
+ return i_hash(&raw, sizeof raw);
+ #endif
+}
+
+STC_INLINE int
+_cx_memb(_compare)(const _cx_self* x, const _cx_self* y) {
+ #if c_option(c_no_compare)
+ return (int)(x->get - y->get);
+ #else
+ i_valraw rx = i_valto(x->get);
+ i_valraw ry = i_valto(y->get);
+ return i_cmp(&rx, &ry);
+ #endif
+}
+#include "template.h"
\ No newline at end of file diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 794948e6..e7775b58 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -92,60 +92,65 @@ # define c_free(p) free(p)
#endif
-#define c_delete(T, ptr) do { T* _p = ptr; T##_del(_p); c_free(_p); } while(0)
+#define c_delete(T, ptr) do { T *_c_p = ptr; T##_del(_c_p); c_free(_c_p); } while (0)
#define c_swap(T, x, y) do { T _c_t = x; x = y; y = _c_t; } while (0)
#define c_arraylen(a) (sizeof (a)/sizeof (a)[0])
+#define c_less_compare(less, x, y) (less(y, x) - less(x, y))
+#define c_default_less(x, y) (*(x) < *(y))
#define c_default_compare(x, y) c_less_compare(c_default_less, x, y)
-#define c_default_less(x, y) (*(x) < *(y))
#define c_default_equalto(x, y) (*(x) == *(y))
#define c_memcmp_equalto(x, y) (memcmp(x, y, sizeof *(x)) == 0)
-#define c_less_compare(less, x, y) (less(y, x) - less(x, y))
#define c_rawstr_compare(x, y) strcmp(*(x), *(y))
#define c_rawstr_equalto(x, y) (strcmp(*(x), *(y)) == 0)
-#define c_rawstr_hash(p, dummy) c_strhash(*(p))
+#define c_rawstr_hash(x, dummy) c_strhash(*(x))
+
+#define c_default_clone(x) (x)
+#define c_default_fromraw(x) (x) // [deprecated]
+#define c_default_toraw(ptr) (*(ptr))
+#define c_default_del(ptr) ((void) (ptr))
#define c_option(flag) ((i_opt) & (flag))
#define c_is_fwd 1
-#define c_no_compare 2
+#define c_no_atomic 2
#define c_no_clone 4
-#define c_no_atomic 8
-
-#define c_default_fromraw(x) (x)
-#define c_default_toraw(ptr) (*(ptr))
-#define c_default_del(ptr) ((void) (ptr))
+#define c_no_compare 8
/* Generic algorithms */
-#define _c_rotl(x, k) (x << (k) | x >> (8*sizeof(x) - (k)))
+#define _c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k)))
STC_INLINE uint64_t c_strhash(const char *s) {
int c; uint64_t h = *s++;
if (h) while ((c = *s++)) h = (h << 10) - h + c;
- return _c_rotl(h, 26) ^ h;
+ return _c_ROTL(h, 26) ^ h;
}
// len >= 1
STC_INLINE uint64_t c_default_hash(const void* key, size_t len) {
const uint8_t *x = (const uint8_t*) key;
uint64_t h = *x++;
while (--len) h = (h << 10) - h + *x++;
- return _c_rotl(h, 26) ^ h;
+ return _c_ROTL(h, 26) ^ h;
}
#define c_hash32(data, len_is_4) \
((*(const uint32_t*)data * 0xc6a4a7935bd1e99d) >> 15)
#define c_hash64(data, len_is_8) \
(*(const uint64_t *)data * 0xc6a4a7935bd1e99d)
-#define c_default_hash32 c_hash32 // [deprecated]
-#define c_default_hash64 c_hash64 // [deprecated]
#define c_foreach(...) c_MACRO_OVERLOAD(c_foreach, __VA_ARGS__)
-#define c_foreach_3(it, CX, cnt) \
- for (CX##_iter it = CX##_begin(&cnt), it##_end_ = CX##_end(&cnt) \
- ; it.ref != it##_end_.ref; CX##_next(&it))
-#define c_foreach_4(it, CX, start, finish) \
- for (CX##_iter it = start, it##_end_ = finish \
- ; it.ref != it##_end_.ref; CX##_next(&it))
+#define c_foreach_3(it, C, cnt) \
+ for (C##_iter it = C##_begin(&cnt), it##_end_ = C##_end(&cnt) \
+ ; it.ref != it##_end_.ref; C##_next(&it))
+#define c_foreach_4(it, C, start, finish) \
+ for (C##_iter it = start, it##_end_ = finish \
+ ; it.ref != it##_end_.ref; C##_next(&it))
+
+#define c_forpair(key, val, C, cnt) /* structured binding */ \
+ for (struct {C##_iter _it, _end; C##_key key; C##_mapped val;} \
+ _ = {C##_begin(&cnt), C##_end(&cnt)} \
+ ; _._it.ref != _._end.ref && (_.key = _._it.ref->first, _.val = _._it.ref->second, true) \
+ ; C##_next(&_._it))
#define c_forrange(...) c_MACRO_OVERLOAD(c_forrange, __VA_ARGS__)
#define c_forrange_1(stop) for (size_t _c_ii=0, _c_end=stop; _c_ii < _c_end; ++_c_ii)
@@ -156,20 +161,22 @@ STC_INLINE uint64_t c_default_hash(const void* key, size_t len) { for (type i=start, _c_inc=step, _c_end=(stop) - (0 < _c_inc) \
; (i <= _c_end) == (0 < _c_inc); i += _c_inc)
-#define c_autoscope(init, ...) for (int _c_ii = (init, 0); !_c_ii; ++_c_ii, __VA_ARGS__)
#define c_autovar(declvar, ...) for (declvar, *_c_ii = NULL; !_c_ii; ++_c_ii, __VA_ARGS__)
+#define c_autoscope(init, ...) for (int _c_ii = (init, 0); !_c_ii; ++_c_ii, __VA_ARGS__)
#define c_autodefer(...) for (int _c_ii = 0; !_c_ii; ++_c_ii, __VA_ARGS__)
-#define c_exitauto continue
#define c_auto(...) c_MACRO_OVERLOAD(c_auto, __VA_ARGS__)
-#define c_auto_2(CX, a) \
- c_autovar(CX a = CX##_init(), CX##_del(&a))
-#define c_auto_3(CX, a, b) \
- c_autovar(c_EXPAND(CX a = CX##_init(), b = CX##_init()), \
- CX##_del(&b), CX##_del(&a))
-#define c_auto_4(CX, a, b, c) \
- c_autovar(c_EXPAND(CX a = CX##_init(), b = CX##_init(), c = CX##_init()), \
- CX##_del(&c), CX##_del(&b), CX##_del(&a))
+#define c_auto_2(C, a) \
+ c_autovar(C a = C##_init(), C##_del(&a))
+#define c_auto_3(C, a, b) \
+ c_autovar(c_EXPAND(C a = C##_init(), b = C##_init()), \
+ C##_del(&b), C##_del(&a))
+#define c_auto_4(C, a, b, c) \
+ c_autovar(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init()), \
+ C##_del(&c), C##_del(&b), C##_del(&a))
+#define c_auto_5(C, a, b, c, d) \
+ c_autovar(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init(), d = C##_init()), \
+ C##_del(&d), C##_del(&c), C##_del(&b), C##_del(&a))
#define c_autobuf(b, type, n) c_autobuf_N(b, type, n, 256)
#define c_autobuf_N(b, type, n, BYTES) \
@@ -177,28 +184,28 @@ STC_INLINE uint64_t c_default_hash(const void* key, size_t len) { *b = (n)*sizeof *b > (BYTES) ? c_alloc_n(type, n) : _c_b \
; b; b != _c_b ? c_free(b) : (void)0, b = NULL)
-#define c_apply(CX, method, cx, ...) do { \
- const CX##_rawvalue _c_arr[] = __VA_ARGS__; \
- CX* _c_cx = cx; \
+#define c_apply(C, method, cx, ...) do { \
+ const C##_rawvalue _c_arr[] = __VA_ARGS__; \
+ C* _c_cx = cx; \
for (size_t _c_i = 0; _c_i < c_arraylen(_c_arr); ++_c_i) \
- CX##_##method(_c_cx, _c_arr[_c_i]); \
+ C##_##method(_c_cx, _c_arr[_c_i]); \
} while (0)
-#define c_apply_pair(CX, method, cx, ...) do { \
- const CX##_rawvalue _c_arr[] = __VA_ARGS__; \
- CX* _c_cx = cx; \
+#define c_apply_pair(C, method, cx, ...) do { \
+ const C##_rawvalue _c_arr[] = __VA_ARGS__; \
+ C* _c_cx = cx; \
for (size_t _c_i = 0; _c_i < c_arraylen(_c_arr); ++_c_i) \
- CX##_##method(_c_cx, _c_arr[_c_i].first, _c_arr[_c_i].second); \
+ C##_##method(_c_cx, _c_arr[_c_i].first, _c_arr[_c_i].second); \
} while (0)
-#define c_apply_n(CX, method, cx, arr, n) do { \
- CX* _c_cx = cx; \
- for (const CX##_rawvalue *_c_i = arr, *_c_end = _c_i+(n); _c_i != _c_end; ++_c_i) \
- CX##_##method(_c_cx, *_c_i); \
+#define c_apply_n(C, method, cx, arr, n) do { \
+ C* _c_cx = cx; \
+ for (const C##_rawvalue *_c_i = arr, *_c_end = _c_i+(n); _c_i != _c_end; ++_c_i) \
+ C##_##method(_c_cx, *_c_i); \
} while (0)
-#define c_del(CX, ...) do { \
- CX* _c_arr[] = {__VA_ARGS__}; \
+#define c_del(C, ...) do { \
+ C* _c_arr[] = {__VA_ARGS__}; \
for (size_t _c_i = 0; _c_i < c_arraylen(_c_arr); ++_c_i) \
- CX##_del(_c_arr[_c_i]); \
+ C##_del(_c_arr[_c_i]); \
} while (0)
#if defined(__SIZEOF_INT128__)
diff --git a/include/stc/clist.h b/include/stc/clist.h index bb090a62..7cd2df50 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -125,6 +125,7 @@ _cx_memb(_copy)(_cx_self *self, _cx_self other) { }
#endif
STC_INLINE _cx_self _cx_memb(_init)(void) { return c_make(_cx_self){NULL}; }
+STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, size_t n) { return true; }
STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return cx.last == NULL; }
STC_INLINE size_t _cx_memb(_count)(_cx_self cx)
{ return _clist_count((const clist_VOID*) &cx); }
diff --git a/include/stc/csptr.h b/include/stc/csptr.h index a8496654..06790e01 100644 --- a/include/stc/csptr.h +++ b/include/stc/csptr.h @@ -26,7 +26,7 @@ typedef struct { cstr name, last; } Person;
-Person Person_init(const char* name, const char* last) {
+Person Person_from(const char* name, const char* last) {
return (Person){.name = cstr_from(name), .last = cstr_from(last)};
}
void Person_del(Person* p) {
@@ -40,7 +40,7 @@ void Person_del(Person* p) { #include <stc/csptr.h>
int main() {
- csptr_person p = csptr_person_make(Person_init("John", "Smiths"));
+ csptr_person p = csptr_person_new(Person_from("John", "Smiths"));
csptr_person q = csptr_person_clone(p); // share the pointer
printf("%s %s. uses: %zu\n", q.get->name.str, q.get->last.str, *q.use_count);
@@ -54,7 +54,6 @@ int main() { #include "forward.h"
#include <stdlib.h>
-typedef long atomic_count_t;
#if defined(__GNUC__) || defined(__clang__)
#define c_atomic_inc(v) (void)__atomic_add_fetch(v, 1, __ATOMIC_SEQ_CST)
#define c_atomic_dec_and_test(v) !__atomic_sub_fetch(v, 1, __ATOMIC_SEQ_CST)
@@ -75,10 +74,9 @@ typedef long atomic_count_t; #ifndef _i_prefix
#define _i_prefix csptr_
#endif
-#define i_valfrom _not_to_be_used_
+#define _i_has_internal_clone
#include "template.h"
-
#if !c_option(c_no_atomic)
#define _i_atomic_inc(v) c_atomic_inc(v)
#define _i_atomic_dec_and_test(v) c_atomic_dec_and_test(v)
@@ -89,30 +87,38 @@ typedef long atomic_count_t; #if !c_option(c_is_fwd)
_cx_deftypes(_c_csptr_types, _cx_self, i_val);
#endif
-_cx_csptr_rep { atomic_count_t counter; _cx_value value; };
+_cx_csptr_rep { long counter; i_val value; };
STC_INLINE _cx_self
_cx_memb(_init)(void) { return c_make(_cx_self){NULL, NULL}; }
-STC_INLINE atomic_count_t
+STC_INLINE long
_cx_memb(_use_count)(_cx_self ptr) { return ptr.use_count ? *ptr.use_count : 0; }
STC_INLINE _cx_self
-_cx_memb(_from)(_cx_value* p) {
+_cx_memb(_with)(_cx_value* p) {
_cx_self ptr = {p};
- if (p) *(ptr.use_count = c_alloc(atomic_count_t)) = 1;
+ if (p) *(ptr.use_count = c_alloc(long)) = 1;
+ return ptr;
+}
+
+STC_INLINE _cx_self
+_cx_memb(_view)(const _cx_value* p) {
+ _cx_self ptr = {(_cx_value*) p};
return ptr;
}
STC_INLINE _cx_self
-_cx_memb(_make)(_cx_value val) {
+_cx_memb(_new)(i_val val) {
_cx_self ptr; _cx_csptr_rep *rep = c_alloc(_cx_csptr_rep);
*(ptr.use_count = &rep->counter) = 1;
*(ptr.get = &rep->value) = val;
return ptr;
}
+STC_INLINE _cx_self _cx_memb(_make)(i_val val) // [deprecated]
+ { return _cx_memb(_new)(val); }
-STC_INLINE _cx_self
+STC_INLINE _cx_self // does not use i_valfrom, so we can bypass c_no_clone
_cx_memb(_clone)(_cx_self ptr) {
if (ptr.use_count) _i_atomic_inc(ptr.use_count);
return ptr;
@@ -142,17 +148,29 @@ _cx_memb(_reset)(_cx_self* self) { }
STC_INLINE void
-_cx_memb(_reset_from)(_cx_self* self, _cx_value* p) {
+_cx_memb(_reset_with)(_cx_self* self, _cx_value* p) {
_cx_memb(_del)(self);
- *self = _cx_memb(_from)(p);
+ *self = _cx_memb(_with)(p);
}
STC_INLINE void
-_cx_memb(_reset_with)(_cx_self* self, _cx_value val) {
+_cx_memb(_reset_new)(_cx_self* self, i_val val) {
_cx_memb(_del)(self);
- *self = _cx_memb(_make)(val);
+ *self = _cx_memb(_new)(val);
}
+#if !c_option(c_no_clone)
+ STC_INLINE _cx_self _cx_memb(_from)(i_valraw raw) {
+ return _cx_memb(_new)(i_valfrom(raw));
+ }
+
+ STC_INLINE void
+ _cx_memb(_reset_from)(_cx_self* self, i_valraw raw) {
+ _cx_memb(_del)(self);
+ *self = _cx_memb(_new)(i_valfrom(raw));
+ }
+#endif
+
STC_INLINE void
_cx_memb(_copy)(_cx_self* self, _cx_self ptr) {
if (ptr.use_count) _i_atomic_inc(ptr.use_count);
@@ -165,16 +183,28 @@ _cx_memb(_take)(_cx_self* self, _cx_self ptr) { *self = ptr;
}
-#if !c_option(c_no_compare)
+STC_INLINE uint64_t
+_cx_memb(_hash)(const _cx_self* self, size_t n) {
+ #if c_option(c_no_compare) && SIZE_MAX >> 32
+ return c_hash64(&self->get, 8);
+ #elif c_option(c_no_compare)
+ return c_hash32(&self->get, 4);
+ #else
+ i_valraw raw = i_valto(self->get);
+ return i_hash(&raw, sizeof raw);
+ #endif
+}
+
STC_INLINE int
_cx_memb(_compare)(const _cx_self* x, const _cx_self* y) {
-#ifdef _i_cmp_default
- return c_default_compare(&x->get, &y->get);
-#else
- return i_cmp(x->get, y->get);
-#endif
+ #if c_option(c_no_compare)
+ return (int)(x->get - y->get);
+ #else
+ i_valraw rx = i_valto(x->get);
+ i_valraw ry = i_valto(y->get);
+ return i_cmp(&rx, &ry);
+ #endif
}
-#endif
#undef _i_atomic_inc
#undef _i_atomic_dec_and_test
#include "template.h"
\ No newline at end of file diff --git a/include/stc/csview.h b/include/stc/csview.h index 87707d84..ce08bd1a 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -31,8 +31,8 @@ typedef char csview_value; #define csview_null c_make(csview){"", 0}
#define csview_npos cstr_npos
-#define csview_ARG(sv) (int)(sv).size, (sv).str
-
+#define c_svfmt "%.*s"
+#define c_svarg(sv) (int)(sv).size, (sv).str
#define c_sv(literal) csview_lit(literal)
#define cstr_sv(s) csview_from_s(s)
diff --git a/include/stc/forward.h b/include/stc/forward.h index 11a32550..bf2ba698 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -33,6 +33,7 @@ #define forward_csmap(CX, KEY, VAL) _c_aatree_types(CX, KEY, VAL, c_true, c_false)
#define forward_cset(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, c_false, c_true)
#define forward_csset(CX, KEY) _c_aatree_types(CX, KEY, KEY, c_false, c_true)
+#define forward_cbox(CX, VAL) _c_cbox_types(CX, VAL)
#define forward_csptr(CX, VAL) _c_csptr_types(CX, VAL)
#define forward_cpque(CX, VAL) _c_cpque_types(CX, VAL)
#define forward_cstack(CX, VAL) _c_cstack_types(CX, VAL)
@@ -125,6 +126,12 @@ SELF##_node *nodes; \
} SELF
+#define _c_cbox_types(SELF, VAL) \
+ typedef VAL SELF##_value; \
+ typedef struct { \
+ SELF##_value* get; \
+ } SELF
+
#define _c_csptr_types(SELF, VAL) \
typedef VAL SELF##_value; \
\
diff --git a/include/stc/template.h b/include/stc/template.h index b8f6dfc4..757f9443 100644 --- a/include/stc/template.h +++ b/include/stc/template.h @@ -41,63 +41,98 @@ #endif
#if defined i_valraw && !(defined i_valto && defined i_valfrom)
- #error if i_valraw or i_valto defined, i_valfrom must be defined
+ #error "if i_valraw or i_valto defined, i_valfrom must be defined"
#endif
#if defined i_keyraw && !(defined i_keyto && defined i_keyfrom)
- #error if i_keyraw or i_keyto defined, i_keyfrom a must be defined
+ #error "if i_keyraw or i_keyto defined, i_keyfrom a must be defined"
#endif
-
-#if defined i_key_str || defined i_val_str
- #include "cstr.h"
+#ifdef i_key_csptr // [deprecated]
+ #define i_key_ref i_key_csptr
+ #error "i_key_csptr no longer supported: use new name i_key_ref"
+#endif
+#ifdef i_val_csptr // [deprecated]
+ #define i_val_ref i_val_csptr
+ #error "i_val_csptr no longer supported: use new name i_val_ref"
+#endif
+#ifdef i_cnt // [deprecated]
+ #define i_type i_cnt
+ #error "i_cnt no longer supported: use new name i_type"
#endif
-#ifdef i_cnt
- #define i_tag i_cnt
+#ifdef i_type
+ #define i_tag i_type
#undef _i_prefix
#define _i_prefix
#endif
-#ifdef i_key_csptr
- #define i_key i_key_csptr
- #define i_cmp c_PASTE(i_key_csptr, _compare)
- #define i_keydel c_PASTE(i_key_csptr, _del)
- #define i_keyfrom c_PASTE(i_key_csptr, _clone)
+#if defined i_key_str || defined i_val_str
+ #include "cstr.h"
#endif
-#ifdef i_key_str
- #define i_key cstr
+#if defined i_key_ref
+ #define i_key i_key_ref
+ #define i_keyfrom c_PASTE(i_key, _clone)
#ifndef i_tag
- #define i_tag str
+ #define i_tag ref
+ #endif
+ #ifndef i_cmp
+ #define i_cmp c_PASTE(i_key, _compare)
#endif
- #define i_cmp c_rawstr_compare
- #define i_hash c_rawstr_hash
- #define i_keydel cstr_del
+ #ifndef i_hash
+ #define i_hash c_PASTE(i_key, _hash)
+ #endif
+ #ifndef i_keydel
+ #define i_keydel c_PASTE(i_key, _del)
+ #endif
+
+#elif defined i_key_str
+
+ #define i_key cstr
#define i_keyfrom cstr_from
- #define i_keyto cstr_str
- #define i_keyraw const char*
+ #define i_keyto cstr_str
+ #define i_keyraw const char*
+ #ifndef i_tag
+ #define i_tag str
+ #endif
+ #ifndef i_cmp
+ #define i_cmp c_rawstr_compare
+ #endif
+ #ifndef i_hash
+ #define i_hash c_rawstr_hash
+ #endif
+ #if !defined i_keydel
+ #define i_keydel cstr_del
+ #endif
#endif
-#ifdef i_val_csptr
- #define i_val i_val_csptr
- #ifndef i_key
- #define i_cmp c_PASTE(i_val_csptr, _compare)
+#if defined i_val_ref
+ #define i_val i_val_ref
+ #define i_valfrom c_PASTE(i_val, _clone)
+ #if !defined i_tag && !defined i_key
+ #define i_tag ref
#endif
- #define i_valdel c_PASTE(i_val_csptr, _del)
- #define i_valfrom c_PASTE(i_val_csptr, _clone)
-#endif
+ #if !defined i_cmp && !defined i_key
+ #define i_cmp c_PASTE(i_val, _compare)
+ #endif
+ #if !defined i_valdel && !defined i_del
+ #define i_valdel c_PASTE(i_val, _del)
+ #endif
+
+#elif defined i_val_str
-#ifdef i_val_str
#define i_val cstr
+ #define i_valfrom cstr_from
+ #define i_valto cstr_str
+ #define i_valraw const char*
#if !defined i_tag && !defined i_key
#define i_tag str
#endif
- #ifndef i_key
+ #if !defined i_cmp && !defined i_key
#define i_cmp c_rawstr_compare
#endif
- #define i_valdel cstr_del
- #define i_valfrom cstr_from
- #define i_valto cstr_str
- #define i_valraw const char*
+ #if !defined i_valdel && !defined i_del
+ #define i_valdel cstr_del
+ #endif
#endif
#if defined i_del && defined i_isset
@@ -105,14 +140,14 @@ #elif defined i_del && !defined i_key
#define i_valdel i_del
#elif defined i_del
- #error i_del not supported for maps, define i_keydel / i_valdel instead.
+ #error "i_del not supported for maps, define i_keydel / i_valdel instead."
#endif
#if defined i_from && defined i_isset
#define i_keyfrom i_from
#elif defined i_from && !defined i_key
#define i_valfrom i_from
#elif defined i_from
- #error i_from not supported for maps, define i_keyfrom / i_valfrom instead.
+ #error "i_from not supported for maps, define i_keyfrom / i_valfrom instead."
#endif
#ifdef i_key
@@ -122,10 +157,11 @@ #ifndef i_tag
#define i_tag i_key
#endif
- #if defined i_keydel && !defined i_keyfrom && !c_option(c_no_clone)
- #error i_keydel defined requires defining i_keyfrom or '#define i_opt c_no_clone'
- #elif !defined i_keyfrom
- #define i_keyfrom c_default_fromraw
+ #if !defined _i_has_internal_clone && defined i_keydel && !defined i_keyfrom && !c_option(c_no_clone)
+ #error "i_keydel defined but not i_keyfrom (e.g. as c_default_clone), or no 'i_opt c_no_clone'"
+ #endif
+ #if !defined i_keyfrom
+ #define i_keyfrom c_default_clone
#endif
#ifndef i_keyraw
#define i_keyraw i_key
@@ -136,23 +172,21 @@ #elif !defined i_equ
#define i_equ c_default_equalto
#endif
- #ifndef i_hash
- #define i_hash c_default_hash
- #endif
#ifndef i_keydel
#define i_keydel c_default_del
#endif
-#elif defined _i_isset || defined i_hash || defined i_equ
- #error i_key define is missing.
+#elif defined _i_isset
+ #error "i_key define is missing."
#endif
#ifndef i_tag
#define i_tag i_val
#endif
-#if defined i_valdel && !defined i_valfrom && !c_option(c_no_clone)
- #error i_del/i_valdel defined: requires also defining i_valfrom or '#define i_opt c_no_clone'
-#elif !defined i_valfrom
- #define i_valfrom c_default_fromraw
+#if !defined _i_has_internal_clone && defined i_valdel && !defined i_valfrom && !c_option(c_no_clone)
+ #error "i_valdel/i_del defined but not i_valfrom (e.g. as c_default_clone), or no 'i_opt c_no_clone'"
+#endif
+#if !defined i_valfrom
+ #define i_valfrom c_default_clone
#endif
#ifndef i_valraw
#define i_valraw i_val
@@ -163,12 +197,14 @@ #endif
#ifndef i_cmp
#define i_cmp c_default_compare
- #define _i_cmp_default
+#endif
+#ifndef i_hash
+ #define i_hash c_default_hash
#endif
#else // -------------------------------------------------------
-#undef i_cnt
+#undef i_type
#undef i_tag
#undef i_imp
#undef i_opt
@@ -176,23 +212,25 @@ #undef i_del
#undef i_equ
#undef i_hash
+#undef i_from
+
#undef i_val
#undef i_val_str
+#undef i_val_ref
#undef i_valdel
+#undef i_valraw
#undef i_valfrom
-#undef i_from
#undef i_valto
-#undef i_valraw
+
#undef i_key
#undef i_key_str
+#undef i_key_ref
#undef i_keydel
+#undef i_keyraw
#undef i_keyfrom
#undef i_keyto
-#undef i_keyraw
-#undef i_key_csptr
-#undef i_val_csptr
#undef _i_prefix
-#undef _i_cmp_default
+#undef _i_has_internal_clone
#undef _i_template
#endif
|
