summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md52
-rw-r--r--docs/carray_api.md35
-rw-r--r--docs/cbox_api.md136
-rw-r--r--docs/ccommon_api.md41
-rw-r--r--docs/csptr_api.md208
-rw-r--r--examples/cpque.c2
-rw-r--r--examples/csmap_erase.c2
-rw-r--r--examples/ex_gauss2.c6
-rw-r--r--examples/inits.c10
-rw-r--r--examples/new_map.c3
-rw-r--r--examples/new_sptr.c13
-rw-r--r--examples/ptr_elems.c53
-rw-r--r--examples/queue.c2
-rw-r--r--examples/sharedptr.c55
-rw-r--r--examples/splitstr.c2
-rw-r--r--examples/sptr_ex.c13
-rw-r--r--examples/sptr_pthread.c3
-rw-r--r--include/stc/cbox.h174
-rw-r--r--include/stc/ccommon.h99
-rw-r--r--include/stc/clist.h1
-rw-r--r--include/stc/csptr.h74
-rw-r--r--include/stc/csview.h4
-rw-r--r--include/stc/forward.h7
-rw-r--r--include/stc/template.h150
24 files changed, 804 insertions, 341 deletions
diff --git a/README.md b/README.md
index fd865a7e..28ee068e 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,26 @@
![STC](docs/pics/containers.jpg)
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