summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--docs/carray_api.md117
-rw-r--r--docs/cdeq_api.md14
-rw-r--r--docs/clist_api.md14
-rw-r--r--docs/cmap_api.md32
-rw-r--r--docs/cpque_api.md14
-rw-r--r--docs/cqueue_api.md14
-rw-r--r--docs/cset_api.md16
-rw-r--r--docs/csmap_api.md19
-rw-r--r--docs/csptr_api.md144
-rw-r--r--docs/csset_api.md14
-rw-r--r--docs/cstack_api.md14
-rw-r--r--docs/cvec_api.md14
-rw-r--r--examples/advanced.c2
-rw-r--r--include/stc/template.h45
14 files changed, 249 insertions, 224 deletions
diff --git a/docs/carray_api.md b/docs/carray_api.md
index e8ca7ffc..ce3407ab 100644
--- a/docs/carray_api.md
+++ b/docs/carray_api.md
@@ -11,81 +11,84 @@ See the c++ class [boost::multi_array](https://www.boost.org/doc/libs/release/li
## Header file and declaration
```c
-#include <stc/carray.h>
-
-using_carray2(X, Value);
-using_carray2(X, Value, valueDel, valueClone);
-using_carray3(X, Value);
-using_carray3(X, Value, valueDel, valueClone);
+#define i_tag // defaults to i_val name
+#define i_val // value: REQUIRED
+#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type
+#define i_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
+
+#include <stc/carr2.h> // or <stc/carr3.h>
```
-The macro `using_carray2()` must be instantiated in the global scope. `X` and `N` are type tags and
-will affect the names of all cset types and methods. E.g. declaring `using_carray3(i, int);`, `X` should
-be replaced by `i` in all of the following documentation.
+`X` should be replaced by the value of i_tag in all of the following documentation.
-```c
-#include <stc/carray.h>
-```
## Methods
+carr2_X:
```c
-carray2X carray2X_init(size_t xdim, size_t ydim);
-carray2X carray2X_with_values(size_t xdim, size_t ydim, Value val);
-carray2X carray2X_with_storage(size_t xdim, size_t ydim, Value* array);
-carray2X carray2X_clone(carray2X arr);
-Value* carray2X_release(carray2X* self); // release storage (not freed)
-void carray2X_del(carray2X* self);
-
-size_t carray2X_size(carray2X arr);
-Value* carray2X_data(carray2X* self); // access storage data
-Value* carray2X_at(carray2X* self, size_t x, size_t y);
-
-carray2X_iter_t carray2X_begin(const carray2X* self);
-carray2X_iter_t carray2X_end(const carray2X* self);
-void carray2X_next(carray2X_iter_t* it);
+carr2_X carr2_X_init(size_t xdim, size_t ydim);
+carr2_X carr2_X_with_values(size_t xdim, size_t ydim, Value val);
+carr2_X carr2_X_with_storage(size_t xdim, size_t ydim, Value* array);
+carr2_X carr2_X_clone(carr2_X arr);
+Value* carr2_X_release(carr2_X* self); // release storage (not freed)
+void carr2_X_del(carr2_X* self);
+
+size_t carr2_X_size(carr2_X arr);
+Value* carr2_X_data(carr2_X* self); // access storage data
+Value* carr2_X_at(carr2_X* self, size_t x, size_t y);
+
+carr2_X_iter_t carr2_X_begin(const carr2_X* self);
+carr2_X_iter_t carr2_X_end(const carr2_X* self);
+void carr2_X_next(carr2_X_iter_t* it);
```
+carr3:
```c
-carray3X carray3X_init(size_t xdim, size_t ydim, size_t zdim);
-carray3X carray3X_with_values(size_t xdim, size_t ydim, size_t zdim, Value val);
-carray3X carray3X_with_storage(size_t xdim, size_t ydim, size_t zdim, Value* array);
-carray3X carray3X_clone(carray3X arr);
-Value* carray3X_release(carray3X* self); // release storage (not freed)
-void carray3X_del(carray3X* self);
-
-size_t carray3X_size(carray3X arr);
-Value* carray3X_data(carray3X* self); // access storage data
-Value* carray3X_at(carray3X* self, size_t x, size_t y, size_t z);
-
-carray3X_iter_t carray3X_begin(const carray3X* self);
-carray3X_iter_t carray3X_end(const carray3X* self);
-void carray3X_next(carray3X_iter_t* it);
+carr3_X carr3_X_init(size_t xdim, size_t ydim, size_t zdim);
+carr3_X carr3_X_with_values(size_t xdim, size_t ydim, size_t zdim, Value val);
+carr3_X carr3_X_with_storage(size_t xdim, size_t ydim, size_t zdim, Value* array);
+carr3_X carr3_X_clone(carr3_X arr);
+Value* carr3_X_release(carr3_X* self); // release storage (not freed)
+void carr3_X_del(carr3_X* self);
+
+size_t carr3_X_size(carr3_X arr);
+Value* carr3_X_data(carr3_X* self); // access storage data
+Value* carr3_X_at(carr3_X* self, size_t x, size_t y, size_t z);
+
+carr3_X_iter_t carr3_X_begin(const carr3_X* self);
+carr3_X_iter_t carr3_X_end(const carr3_X* self);
+void carr3_X_next(carr3_X_iter_t* it);
```
## Types
-| Type name | Type definition | Used to represent... |
-|:---------------------|:-----------------------------------------------------|:--------------------------|
-| `carray2X` | `struct { Value **data; size_t xdim, ydim; }` | The carray2 type |
-| `carray2X_value_t` | `Value` | The value type |
-| `carray2X_iter_t` | `struct { Value *ref; }` | Iterator type |
-| `carray3X` | `struct { Value ***data; size_t xdim, ydim, zdim; }` | The carray3 type |
-| `carray3X_value_t` | `Value` | The value type |
-| `carray3X_iter_t` | `struct { Value *ref; }` | Iterator type |
+| Type name | Type definition | Used to represent... |
+|:------------------|:-----------------------------------------------------|:---------------------|
+| `carr2_X` | `struct { Value **data; size_t xdim, ydim; }` | The carray2 type |
+| `carr2_X_value_t` | `Value` | The value type |
+| `carr2_X_iter_t` | `struct { Value *ref; }` | Iterator type |
+| `carr3_X` | `struct { Value ***data; size_t xdim, ydim, zdim; }` | The carray3 type |
+| `carr3_X_value_t` | `Value` | The value type |
+| `carr3_X_iter_t` | `struct { Value *ref; }` | Iterator type |
The **carray** elements can be accessed like `carray3i arr = ...; int val = arr.data[x][y][z];`, or with `carray3i_at(&arr, x, y, z)`.
## Example
```c
#include <stdio.h>
-#include <stc/carray.h>
-using_carray3(f, float);
-using_carray2(i, uint32_t);
+#define i_tag i
+#define i_val uint32_t
+#include <stc/carr2.h>
+
+#define i_tag f
+#define i_val float
+#include <stc/carr3.h>
int main()
{
// Ex1
int xd = 30, yd = 20, zd = 10;
// define arr3[30][20][10], initialized with zeros.
- carray3f arr3 = carray3f_with_values(xd, yd, zd, 0.0f);
+ carr3_f arr3 = carr3_f_with_values(xd, yd, zd, 0.0f);
arr3.data[5][4][3] = 3.14f;
float *arr1 = arr3.data[5][4];
@@ -94,20 +97,20 @@ int main()
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
- carray3f_del(&arr3); // free array
+ carr3_f_del(&arr3); // free array
// Ex2
int w = 256, h = 128;
- carray2i image = carray2i_init(w, h);
+ carr2_i image = carr2_i_init(w, h);
int n = 0;
- c_foreach (i, carray2i, image) {
+ 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)
+ for (int y = 0; y < image.ydim; ++y)
image.data[y][y] = 0xffffffff;
- carray2i_del(&image);
+ carr2_i_del(&image);
}
```
Output:
diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md
index a79b6d4c..1ad754a1 100644
--- a/docs/cdeq_api.md
+++ b/docs/cdeq_api.md
@@ -8,13 +8,13 @@ See the c++ class [std::deque](https://en.cppreference.com/w/cpp/container/deque
## Header file and declaration
```c
-#define i_tag
-#define i_val // required
-#define i_cmp // required if i_val is a struct
-#define i_valdel
-#define i_valfrom
-#define i_valto
-#define i_valraw
+#define i_tag // defaults to i_val name
+#define i_val // value: REQUIRED
+#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type
+#define i_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
#include <stc/cdeq.h>
```
`X` should be replaced by the value of i_tag in all of the following documentation.
diff --git a/docs/clist_api.md b/docs/clist_api.md
index b4f1d750..3f866815 100644
--- a/docs/clist_api.md
+++ b/docs/clist_api.md
@@ -22,13 +22,13 @@ See the c++ class [std::list](https://en.cppreference.com/w/cpp/container/list)
## Header file and declaration
```c
-#define i_tag
-#define i_val // required
-#define i_cmp // required if i_val is a struct
-#define i_valdel
-#define i_valfrom
-#define i_valto
-#define i_valraw
+#define i_tag // defaults to i_val name
+#define i_val // value: REQUIRED
+#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type
+#define i_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
#include <stc/clist.h>
```
diff --git a/docs/cmap_api.md b/docs/cmap_api.md
index 28ffc872..f84a4aef 100644
--- a/docs/cmap_api.md
+++ b/docs/cmap_api.md
@@ -17,13 +17,19 @@ See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/contain
## Header file and declaration
```c
-#define i_tag
-#define i_val // required
-#define i_cmp // required if i_val is a struct
-#define i_valdel
-#define i_valfrom
-#define i_valto
-#define i_valraw
+#define i_tag // defaults to i_key name
+#define i_key // key: REQUIRED
+#define i_val // value: REQUIRED
+#define i_equ // equality comparison two i_keyraw*. REQUIRED IF i_keyraw is non-integral type
+#define i_cmp // three-way compare two i_keyraw* : may be defined instead of i_equ
+#define i_keyraw // convertion "raw" type - defaults to i_key
+#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy
+#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
+#define i_keydel // destroy key func - defaults to empty destruct
+#define i_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
#include <stc/cmap.h>
```
`X` should be replaced by the value of i_tag in all of the following documentation.
@@ -277,9 +283,9 @@ static void Viking_del(Viking* v) {
#define i_tag vk
#define i_key Viking
#define i_val int
-#define i_valdel Viking_del
#define i_equ Viking_equals
#define i_hash Viking_hash
+#define i_keydel Viking_del
#include <stc/cmap.h>
int main()
@@ -347,12 +353,12 @@ static RViking Viking_toR(const Viking* v) {return (RViking){v->name.str, v->cou
#define i_tag vk
#define i_key Viking
#define i_val int
-#define i_valdel Viking_del
-#define i_valraw RViking
#define i_equ RViking_equals
#define i_hash RViking_hash
+#define i_keyraw RViking
#define i_keyfrom Viking_fromR
#define i_keyto Viking_toR
+#define i_keydel Viking_del
#include <stc/cmap.h>
int main()
@@ -364,14 +370,14 @@ int main()
cmap_vk_insert(&vikings, (Viking){cstr_from("Einar"), cstr_from("Norway")}, 25);
cmap_vk_insert(&vikings, (Viking){cstr_from("Olaf"), cstr_from("Denmark")}, 24);
- // emplace is simple to use now.
+ // but emplace is simpler to use now.
cmap_vk_emplace(&vikings, (RViking){"Harald", "Iceland"}, 12);
cmap_vk_emplace(&vikings, (RViking){"Einar", "Denmark"}, 21);
- // And lookup uses "raw" key type, so no need construct/destruct key:
+ // and lookup uses "raw" key type, so no need construct/destruct key:
printf("Lookup: Einar of Norway has %d hp\n\n", *cmap_vk_at(&vikings, (RViking){"Einar", "Norway"}));
- // Print the status of the vikings.
+ // print the status of the vikings.
c_foreach (i, cmap_vk, vikings) {
printf("%s of %s has %d hp\n", i.ref->first.name.str, i.ref->first.country.str, i.ref->second);
}
diff --git a/docs/cpque_api.md b/docs/cpque_api.md
index dba3fe3a..343215bf 100644
--- a/docs/cpque_api.md
+++ b/docs/cpque_api.md
@@ -8,13 +8,13 @@ See the c++ class [std::priority_queue](https://en.cppreference.com/w/cpp/contai
## Header file and declaration
```c
-#define i_tag
-#define i_val // required
-#define i_cmp // required if i_val is a struct
-#define i_valdel
-#define i_valfrom
-#define i_valto
-#define i_valraw
+#define i_tag // defaults to i_val name
+#define i_val // value: REQUIRED
+#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type
+#define i_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
#include <stc/cpque.h>
```
`X` should be replaced by the value of i_tag in all of the following documentation.
diff --git a/docs/cqueue_api.md b/docs/cqueue_api.md
index eb1450a3..16e87d47 100644
--- a/docs/cqueue_api.md
+++ b/docs/cqueue_api.md
@@ -7,13 +7,13 @@ See the c++ class [std::queue](https://en.cppreference.com/w/cpp/container/queue
## Header file and declaration
```c
-#define i_tag
-#define i_val // required
-#define i_cmp // required if i_val is a struct
-#define i_valdel
-#define i_valfrom
-#define i_valto
-#define i_valraw
+#define i_tag // defaults to i_val name
+#define i_val // value: REQUIRED
+#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type
+#define i_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
#include <stc/cqueue.h>
```
`X` should be replaced by the value of i_tag in all of the following documentation.
diff --git a/docs/cset_api.md b/docs/cset_api.md
index fc12c5bd..8b645d29 100644
--- a/docs/cset_api.md
+++ b/docs/cset_api.md
@@ -7,13 +7,15 @@ A **cset** is an associative container that contains a set of unique objects of
## Header file and declaration
```c
-#define i_tag
-#define i_val // required
-#define i_cmp // required if i_val is a struct
-#define i_valdel
-#define i_valfrom
-#define i_valto
-#define i_valraw
+#define i_tag // defaults to i_key name
+#define i_key // key: REQUIRED
+#define i_hash // hash func: REQUIRED IF i_keyraw is a non-pod type
+#define i_equ // equality comparison two i_keyraw*. REQUIRED IF i_keyraw is a non-integral type
+#define i_cmp // three-way compare two i_keyraw* : alternative to i_equ
+#define i_keyraw // convertion "raw" type - defaults to i_key
+#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy
+#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
+#define i_keydel // destroy key func - defaults to empty destruct
#include <stc/cset.h>
```
`X` should be replaced by the value of i_tag in all of the following documentation.
diff --git a/docs/csmap_api.md b/docs/csmap_api.md
index 6fdd3857..338758ce 100644
--- a/docs/csmap_api.md
+++ b/docs/csmap_api.md
@@ -15,13 +15,18 @@ See the c++ class [std::map](https://en.cppreference.com/w/cpp/container/map) fo
## Header file and declaration
```c
-#define i_tag
-#define i_val // required
-#define i_cmp // required if i_val is a struct
-#define i_valdel
-#define i_valfrom
-#define i_valto
-#define i_valraw
+#define i_tag // defaults to i_key name
+#define i_key // value: REQUIRED
+#define i_val // key: REQUIRED
+#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
+#define i_keyraw // convertion "raw" type - defaults to i_key
+#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy
+#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
+#define i_keydel // destroy key func - defaults to empty destruct
+#define i_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
#include <stc/csmap.h>
```
`X` should be replaced by the value of i_tag in all of the following documentation.
diff --git a/docs/csptr_api.md b/docs/csptr_api.md
index a7f37481..afef2154 100644
--- a/docs/csptr_api.md
+++ b/docs/csptr_api.md
@@ -21,13 +21,10 @@ See the c++ classes [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/s
## Header file and declaration
```c
-#define i_tag
-#define i_val // required
-#define i_cmp // required if i_val is a struct
-#define i_valdel
-#define i_valfrom
-#define i_valto
-#define i_valraw
+#define i_tag // defaults to i_val name
+#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_valdel // destroy value func - defaults to empty destruct
#include <stc/csptr.h>
```
`X` should be replaced by the value of i_tag in all of the following documentation.
@@ -69,30 +66,31 @@ bool csptr_X_equals(const csptr_X* x, const csptr_X* y);
## Example
```c
-#include <stc/csptr.h>
#include <stc/cstr.h>
-typedef struct { cstr name, last; } Person;
+typedef struct { cstr name, surname; } Person;
-Person Person_init(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+Person Person_init(const char* name, const char* surname) {
+ return (Person){.name = cstr_from(name), .surname = cstr_from(surname)};
}
void Person_del(Person* p) {
- printf("Destroy: %s %s\n", p->name.str, p->last.str);
- c_del(cstr, &p->name, &p->last);
+ printf("Person_del: %s %s\n", p->name.str, p->surname.str);
+ c_del(cstr, &p->name, &p->surname);
}
-
-using_csptr(person, Person, c_no_compare, Person_del);
+#define i_val Person
+#define i_cmp c_no_compare
+#define i_valdel Person_del
+#include <stc/csptr.h>
int main() {
csptr_person p = csptr_person_make(Person_init("John", "Smiths"));
csptr_person q = csptr_person_clone(p); // means: share the pointer
- printf("Person: %s %s. uses: %zu\n", p.get->name.str, p.get->last.str, *p.use_count);
+ printf("Person: %s %s. uses: %zu\n", p.get->name.str, p.get->surname.str, *p.use_count);
csptr_person_del(&p);
- printf("Last man standing: %s %s. uses: %zu\n", q.get->name.str, q.get->last.str, *q.use_count);
+ printf("Last man standing: %s %s. uses: %zu\n", q.get->name.str, q.get->surname.str, *q.use_count);
csptr_person_del(&q);
}
```
@@ -100,38 +98,37 @@ Output:
```
Person: John Smiths. uses: 2
Last man standing: John Smiths. uses: 1
-Destroy: John Smiths
+Person_del: John Smiths
```
### Example 2
-Advanced: Two different ways to store Person in vectors: 1) `cvec<Person>`, 2) `cvec< csptr<Person> >`.
+Vector of shared pointers to Person:
```c
-#include <stc/csptr.h>
#include <stc/cstr.h>
-#include <stc/cvec.h>
-typedef struct { cstr name, last; } Person;
+typedef struct { cstr name, surname; } Person;
-Person* Person_make(Person* p, const char* name, const char* last) {
- p->name = cstr_from(name), p->last = cstr_from(last);
- return p;
-}
-int Person_compare(const Person* p, const Person* q) {
- int cmp = strcmp(p->name.str, q->name.str);
- return cmp == 0 ? strcmp(p->last.str, q->last.str) : cmp;
+Person Person_init(const char* name, const char* surname) {
+ return (Person){.name = cstr_from(name), .surname = cstr_from(surname)};
}
void Person_del(Person* p) {
- printf("del: %s\n", p->name.str);
- c_del(cstr, &p->name, &p->last);
+ printf("Person_del: %s %s\n", p->name.str, p->surname.str);
+ c_del(cstr, &p->name, &p->surname);
+}
+int Person_compare(const Person* p, const Person* q) {
+ int cmp = strcmp(p->surname.str, q->surname.str);
+ return cmp == 0 ? strcmp(p->name.str, q->name.str) : cmp;
}
-// 1. cvec of Person struct; emplace and cloning disabled.
-using_cvec(pe, Person, Person_compare, Person_del, c_no_clone);
+#define i_tag pers
+#define i_val Person
+#define i_cmp Person_compare
+#define i_valdel Person_del
+#include <stc/csptr.h>
-// 2. cvec of shared-ptr to Person - with emplace_back() and cloning cvec ENABLED.
-using_csptr(pe, Person, Person_compare, Person_del);
-using_cvec(ps, csptr_pe, csptr_pe_compare, csptr_pe_del, csptr_pe_clone);
+#define i_val_csptr pers // shorthand: derives other i_xxx defines from this. i_tag may be defined.
+#include <stc/cvec.h>
const char* names[] = {
"Joe", "Jordan",
@@ -140,60 +137,43 @@ const char* names[] = {
};
int main() {
- cvec_pe vec1 = cvec_pe_init();
- cvec_ps vec2 = cvec_ps_init();
+ cvec_pers vec = cvec_pers_init();
- for (int i = 0; i < 6; i += 2) {
- Person tmp;
- cvec_pe_push_back(&vec1, *Person_make(&tmp, names[i], names[i+1]));
- cvec_ps_push_back(&vec2, csptr_pe_from(Person_make(c_new(Person), names[i], names[i+1])));
+ for (int i = 0; i < c_arraylen(names); i += 2) {
+ cvec_pers_push_back(&vec, csptr_pers_make(Person_init(names[i], names[i+1])));
}
- puts("1. Sorted vec1 of Person:");
- cvec_pe_sort(&vec1);
- c_foreach (i, cvec_pe, vec1)
- printf(" %s %s\n", i.ref->name.str, i.ref->last.str);
-
- // Append a shared copy of vec2.data[0]. Will only be destructed once!
- cvec_ps_emplace_back(&vec2, vec2.data[0]); // emplace will internally call csptr_ps_clone()!
- puts("\n2. Sorted vec2 of shared-pointer to Person:");
- cvec_ps_sort(&vec2);
- c_foreach (i, cvec_ps, vec2)
- printf(" %s %s\n", i.ref->get->name.str, i.ref->get->last.str);
-
- // Share vec2.data[1] with elem1 variable.
- csptr_pe elem1 = csptr_pe_clone(vec2.data[1]);
-
- puts("\nDestroy vec1:");
- cvec_pe_del(&vec1);
- puts("\nDestroy vec2:");
- cvec_ps_del(&vec2);
+
+ // Append a shared copy of vec.data[0]. Will only be destructed once!
+ cvec_pers_emplace_back(&vec, vec.data[0]); // will internally call csptr_pers_clone()!
+
+ puts("\nSorted vec of shared-pointer to Person:");
+ cvec_pers_sort(&vec);
+
+ c_foreach (i, cvec_pers, vec)
+ printf(" %s, %s\n", i.ref->get->surname.str, i.ref->get->name.str);
+
+ // Share vec.data[1] with elem1 variable.
+ csptr_pers elem1 = csptr_pers_clone(vec.data[1]);
+
+ puts("\nDestroy vec:");
+ cvec_pers_del(&vec);
puts("\nDestroy elem1:");
- csptr_pe_del(&elem1);
+ csptr_pers_del(&elem1);
}
```
Output:
```
-1. Sorted vec1 of Person:
- Annie Aniston
- Jane Jacobs
- Joe Jordan
-
-2. Sorted vec2 of shared-pointer to Person:
- Annie Aniston
- Jane Jacobs
- Joe Jordan
- Joe Jordan
-
-Destroy vec1:
-del: Annie
-del: Jane
-del: Joe
-
-Destroy vec2:
-del: Annie
-del: Joe
+Sorted vec of shared-pointer to Person:
+ Aniston, Annie
+ Jacobs, Jane
+ Jordan, Joe
+ Jordan, Joe
+
+Destroy vec:
+Person_del: Annie Aniston
+Person_del: Joe Jordan
Destroy elem1:
-del: Jane
+Person_del: Jane Jacobs
```
diff --git a/docs/csset_api.md b/docs/csset_api.md
index 8bf83a17..0fdb8086 100644
--- a/docs/csset_api.md
+++ b/docs/csset_api.md
@@ -8,13 +8,13 @@ See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) fo
## Header file and declaration
```c
-#define i_tag
-#define i_val // required
-#define i_cmp // required if i_val is a struct
-#define i_valdel
-#define i_valfrom
-#define i_valto
-#define i_valraw
+#define i_tag // defaults to i_key name
+#define i_key // key: REQUIRED
+#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
+#define i_keyraw // convertion "raw" type - defaults to i_key
+#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy
+#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
+#define i_keydel // destroy key func - defaults to empty destruct
#include <stc/csset.h>
```
`X` should be replaced by the value of i_tag in all of the following documentation.
diff --git a/docs/cstack_api.md b/docs/cstack_api.md
index b971811c..68f22b57 100644
--- a/docs/cstack_api.md
+++ b/docs/cstack_api.md
@@ -8,13 +8,13 @@ See the c++ class [std::stack](https://en.cppreference.com/w/cpp/container/stack
## Header file and declaration
```c
-#define i_tag
-#define i_val // required
-#define i_cmp // required if i_val is a struct
-#define i_valdel
-#define i_valfrom
-#define i_valto
-#define i_valraw
+#define i_tag // defaults to i_val name
+#define i_val // value: REQUIRED
+#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type
+#define i_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
#include <stc/cstack.h>
```
`X` should be replaced by the value of i_tag in all of the following documentation.
diff --git a/docs/cvec_api.md b/docs/cvec_api.md
index e04c0a8d..07164e46 100644
--- a/docs/cvec_api.md
+++ b/docs/cvec_api.md
@@ -12,13 +12,13 @@ See the c++ class [std::vector](https://en.cppreference.com/w/cpp/container/vect
## Header file and declaration
```c
-#define i_tag
-#define i_val // required
-#define i_cmp // required if i_val is a struct
-#define i_valdel
-#define i_valfrom
-#define i_valto
-#define i_valraw
+#define i_tag // defaults to i_val name
+#define i_val // value: REQUIRED
+#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type
+#define i_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
#include <stc/cvec.h>
```
`X` should be replaced by the value of i_tag in all of the following documentation.
diff --git a/examples/advanced.c b/examples/advanced.c
index 5d54275f..8044594e 100644
--- a/examples/advanced.c
+++ b/examples/advanced.c
@@ -39,10 +39,10 @@ static inline VikingRaw viking_toRaw(const Viking* vk) {
#define i_val int
#define i_equ vikingraw_equals
#define i_hash vikingraw_hash
-#define i_keydel viking_del
#define i_keyraw VikingRaw
#define i_keyfrom viking_fromRaw
#define i_keyto viking_toRaw
+#define i_keydel viking_del
#include <stc/cmap.h>
int main()
diff --git a/include/stc/template.h b/include/stc/template.h
index dc83c167..b255d647 100644
--- a/include/stc/template.h
+++ b/include/stc/template.h
@@ -29,7 +29,7 @@
#define Self c_PASTE(i_prefix, i_tag)
// typedef container types defined in forward.h. VC requires c_EXPAND.
#define cx_deftypes(macro, SELF, ...) c_EXPAND(macro(SELF, __VA_ARGS__))
-
+
#define cx_value_t cx_memb(_value_t)
#define cx_key_t cx_memb(_key_t)
#define cx_mapped_t cx_memb(_mapped_t)
@@ -47,10 +47,36 @@
#define i_fwd
#endif
+#ifndef i_prefix_csptr
+#define i_prefix_csptr csptr_
+#endif
+#ifdef i_key_csptr
+ #ifndef i_tag
+ #define i_tag i_key_csptr
+ #endif
+ #define i_key c_PASTE(i_prefix_csptr, i_key_csptr)
+ #define i_cmp c_PASTE3(i_prefix_csptr, i_key_csptr, _compare)
+ #define i_keydel c_PASTE3(i_prefix_csptr, i_key_csptr, _del)
+ #define i_keyfrom c_PASTE3(i_prefix_csptr, i_key_csptr, _clone)
+#endif
+#ifdef i_val_csptr
+ #if !defined i_tag && !defined i_key
+ #define i_tag i_val_csptr
+ #endif
+ #define i_val c_PASTE(i_prefix_csptr, i_val_csptr)
+ #ifndef i_key
+ #define i_cmp c_PASTE3(i_prefix_csptr, i_val_csptr, _compare)
+ #endif
+ #define i_valdel c_PASTE3(i_prefix_csptr, i_val_csptr, _del)
+ #define i_valfrom c_PASTE3(i_prefix_csptr, i_val_csptr, _clone)
+#endif
+
#ifdef i_key_str
#define i_key cstr
+ #ifndef i_tag
+ #define i_tag str
+ #endif
#define i_cmp c_rawstr_compare
- #define i_equ c_rawstr_equals
#define i_hash c_rawstr_hash
#define i_keydel cstr_del
#define i_keyfrom cstr_from
@@ -59,6 +85,9 @@
#endif
#ifdef i_val_str
#define i_val cstr
+ #if !defined i_tag && !defined i_key
+ #define i_tag str
+ #endif
#ifndef i_key
#define i_cmp c_rawstr_compare
#endif
@@ -67,16 +96,13 @@
#define i_valto cstr_str
#define i_valraw const char*
#endif
+
#if defined i_key && !defined i_val
#define i_val i_key
#endif
-#if !defined i_tag && defined i_key_str
- #define i_tag str
-#elif !defined i_tag && defined i_key
+#if !defined i_tag && defined i_key
#define i_tag i_key
-#elif !defined i_tag && defined i_val_str
- #define i_tag str
-#elif !defined i_tag && defined i_val
+#elif !defined i_tag
#define i_tag i_val
#endif
@@ -148,6 +174,9 @@
#undef i_keyfrom
#undef i_keyto
#undef i_keyraw
+#undef i_key_csptr
+#undef i_val_csptr
+#undef i_prefix_csptr
#undef i_template
#endif