From 6b060a2393cc3a20f19e0e482e335c959dd845bb Mon Sep 17 00:00:00 2001 From: Tylo Date: Mon, 22 Jun 2020 15:00:44 +0200 Subject: Updated CArray to support destructors, and added underscore before used defined tag - for consistency with the other containers. Changed map/set type-tag for CHash to upper case MAP/SET. Makes it clearer it is a tag and not a type or variable. Added complex example to README.md demonstrating capability of nested containers, using custom destructors. --- README.md | 69 +++++++++++++++--------- examples/advanced.c | 2 +- examples/benchmark.c | 2 +- examples/demos.c | 33 ++++++++++-- stc/carray.h | 147 +++++++++++++++++++++++++++++++-------------------- stc/chash.h | 8 +-- 6 files changed, 170 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index 1cdbb4fe..6903fb08 100644 --- a/README.md +++ b/README.md @@ -100,18 +100,39 @@ Demos The first example demonstrates an advanced complex type that shows some of the capability of the library. Look at the simpler to understand this better. This create one element into a large data structure (using C++ template syntax for describing the type): **CHash_map**< *CString*, *CHash_map*< *int*, *CList*< *CArray2*< *float* > > > > ``` -#include " -#include " -#include " -#include " +#include "stc/cstring.h" +#include "stc/chash.h" +#include "stc/clist.h" +#include "stc/carray.h" -declare_CArray2(f, float); -declare_CList(a2, CArray2_f, carray_f_destroy); -declare_CHash(m2, map, CList_a2, clist_a2_destroy); -declare_CHash(m, map, CHash_m2, chash_m2_destroy); +void check_destroy(float* v) {printf("destroy %g\n", *v);} + +declare_CArray(f, float, check_destroy); +declare_CList(t2, CArray2_f, carray2_f_destroy, c_noCompare); +declare_CHash(lm, MAP, int, CList_t2, clist_t2_destroy); +declare_CHash_string(m, MAP, CHash_lm, chash_lm_destroy); int main() { - + int dim1 = 4, dim2 = 6; + CHash_m theMap = chash_init; + { + // Construct. + CArray2_f table = carray2_f_make(dim1, dim2, 0.f); + CList_t2 tableList = clist_init; + CHash_lm listMap = chash_init; + + // Put in some data. + carray2_f_data(table, 2)[5] = 3.1415927; // table[2][5] + clist_t2_pushBack(&tableList, table); + chash_lm_put(&listMap, 42, tableList); + chash_m_put(&theMap, "First", listMap); + } + + // Access the data entry + CArray2_f tab = clist_back(chash_lm_get(&chash_m_get(&theMap, "First")->value, 42)->value); + printf("value is: %f\n", carray2_f_value(tab, 3, 5)); + + chash_m_destroy(&theMap); // destroy the whole shebang! } ``` **CString** @@ -179,7 +200,7 @@ int main() { **CHash map** of *int -> int* ``` #include -declare_CHash(ii, map, int, int); +declare_CHash(ii, MAP, int, int); int main() { CHash_ii nums = chash_init; @@ -194,7 +215,7 @@ int main() { ``` #include #include -declare_CHash_string(s, set); // Shorthand macro for the general declare_CHash expansion. +declare_CHash_string(s, SET); // Shorthand macro for the general declare_CHash expansion. // CString keys are managed internally, although CHash is ignorant of CString. int main() { @@ -213,7 +234,7 @@ int main() { ``` #include #include -declare_CHash_string(ss, map, CString, cstring_destroy); +declare_CHash_string(ss, MAP, CString, cstring_destroy); int main() { CHash_ss table = chash_init; @@ -249,26 +270,26 @@ int main() { clist_i_destroy(&list); } ``` -**CArray** +**CArray**. Heap allocated 1D, 2D and 3D array in one memory block, with sub-arrays. ``` #include declare_CArray(f, float); int main() { - CArray3f a3 = carray3f_make(30, 20, 10); - carray3f_data(a3, 5, 4)[3] = 10.2f; // a3[5][4][3] - CArray2f a2 = carray3f_at(a3, 5); // sub-array reference (no data copy). + CArray3_f a3 = carray3f_make(30, 20, 10, 0.f); + carray3_f_data(a3, 5, 4)[3] = 10.2f; // a3[5][4][3] + CArray2_f a2 = carray3_f_at(a3, 5); // sub-array reference (no data copy). - printf("%f\n", carray2f_value(a2, 4, 3)); // readonly lookup a2[4][3] (=10.2f) - printf("%f\n", carray2f_data(a2, 4)[3]); // same, but this is writable. - printf("%f\n", carray2f_at(a2, 4).data[3]); // same, via sub-array access. + printf("%f\n", carray2_f_value(a2, 4, 3)); // readonly lookup a2[4][3] (=10.2f) + printf("%f\n", carray2_f_data(a2, 4)[3]); // same, but this is writable. + printf("%f\n", carray2_f_at(a2, 4).data[3]); // same, via sub-array access. - printf("%f\n", carray3f_value(a3, 5, 4, 3)); // same data location, via a3 array. - printf("%f\n", carray3f_data(a3, 5, 4)[3]); - printf("%f\n", carray3f_at2(a3, 5, 4).data[3]); + printf("%f\n", carray3_f_value(a3, 5, 4, 3)); // same data location, via a3 array. + printf("%f\n", carray3_f_data(a3, 5, 4)[3]); + printf("%f\n", carray3_f_at2(a3, 5, 4).data[3]); - carray_destroy(a2); // does nothing, since it is a sub-array. - carray_destroy(a3); // also invalidates a2. + carray_f_destroy(&a2); // does nothing, since it is a sub-array. + carray_f_destroy(&a3); // also invalidates a2. } ``` diff --git a/examples/advanced.c b/examples/advanced.c index 092e3f01..37b67531 100644 --- a/examples/advanced.c +++ b/examples/advanced.c @@ -64,7 +64,7 @@ size_t personview_hash(const struct PersonView* pv, size_t ignore) { /*``` With this in place, we can declare the map Person -> int: ```*/ -declare_CHash(ex, map, struct Person, int, c_emptyDestroy, personview_hash, personview_compare, +declare_CHash(ex, MAP, struct Person, int, c_emptyDestroy, personview_hash, personview_compare, struct PersonView, person_destroy, person_getView, person_fromView); /*``` Note we use struct PersonView to put keys in the map, but keys are stored as struct Person with proper dynamically allocated CStrings to store name and surname. diff --git a/examples/benchmark.c b/examples/benchmark.c index 4d7a2fd1..dd070ff4 100644 --- a/examples/benchmark.c +++ b/examples/benchmark.c @@ -19,7 +19,7 @@ static inline uint32_t fibonacci_hash(const void* data, size_t len) { const uint64_t key = *(const uint64_t *) data; return (uint32_t) (key * 11400714819323198485llu); } -declare_CHash(ii, map, int64_t, int64_t, c_emptyDestroy, fibonacci_hash); // c_lowbias32Hash); +declare_CHash(ii, MAP, int64_t, int64_t, c_emptyDestroy, fibonacci_hash); // c_lowbias32Hash); KHASH_MAP_INIT_INT64(ii, uint64_t) diff --git a/examples/demos.c b/examples/demos.c index b2fa32ec..e05fa269 100644 --- a/examples/demos.c +++ b/examples/demos.c @@ -1,5 +1,6 @@ #include "../stc/cvector.h" #include "../stc/clist.h" +#include "../stc/carray.h" #include "../stc/chash.h" #include "../stc/cstring.h" @@ -98,7 +99,7 @@ void listdemo1() clist_ix_destroy(&nums); } -declare_CHash(i, set, int); +declare_CHash(i, SET, int); void setdemo1() { @@ -113,7 +114,7 @@ void setdemo1() } -declare_CHash(ii, map, int, int); +declare_CHash(ii, MAP, int, int); void mapdemo1() { @@ -127,7 +128,7 @@ void mapdemo1() } -declare_CHash_string(si, map, int); // Shorthand macro for the general declare_CHash expansion. +declare_CHash_string(si, MAP, int); // Shorthand macro for the general declare_CHash expansion. void mapdemo2() { @@ -149,7 +150,7 @@ void mapdemo2() } -declare_CHash_string(ss, map, CString, cstring_destroy); +declare_CHash_string(ss, MAP, CString, cstring_destroy); void mapdemo3() { @@ -169,6 +170,29 @@ void mapdemo3() +declare_CArray(f, float); + +int arraydemo1() +{ + printf("\nARRAYDEMO1\n"); + CArray3_f a3 = carray3_f_make(30, 20, 10, 0.f); + carray3_f_data(a3, 5, 4)[3] = 10.2f; // a3[5][4][3] + CArray2_f a2 = carray3_f_at(a3, 5); // sub-array reference (no data copy). + + printf("%f\n", carray2_f_value(a2, 4, 3)); // readonly lookup a2[4][3] (=10.2f) + printf("%f\n", carray2_f_data(a2, 4)[3]); // same, but this is writable. + printf("%f\n", carray2_f_at(a2, 4).data[3]); // same, via sub-array access. + + printf("%f\n", carray3_f_value(a3, 5, 4, 3)); // same data location, via a3 array. + printf("%f\n", carray3_f_data(a3, 5, 4)[3]); + printf("%f\n", carray3_f_at2(a3, 5, 4).data[3]); + + carray2_f_destroy(&a2); // does nothing, since it is a sub-array. + carray3_f_destroy(&a3); // also invalidates a2. +} + + + int main() { stringdemo1(); @@ -179,4 +203,5 @@ int main() mapdemo1(); mapdemo2(); mapdemo3(); + arraydemo1(); } diff --git a/stc/carray.h b/stc/carray.h index 502a0038..b85170b4 100644 --- a/stc/carray.h +++ b/stc/carray.h @@ -32,20 +32,20 @@ declare_CArray(f, float); int main() { - CArray3f a3 = carray3f_make(30, 20, 10); - carray3f_data(a3, 5, 4)[3] = 10.2f; - CArray2f a2 = carray3f_at(a3, 5); + CArray3_f a3 = carray3f_make(30, 20, 10, 0.f); + carray3_f_data(a3, 5, 4)[3] = 10.2f; // a3[5][4][3] + CArray2_f a2 = carray3_f_at(a3, 5); // sub-array reference (no data copy). - printf("%f\n", carray2f_value(a2, 4, 3)); - printf("%f\n", carray2f_data(a2, 4)[3]); - printf("%f\n", carray2f_at(a2, 4).data[3]); + printf("%f\n", carray2_f_value(a2, 4, 3)); // readonly lookup a2[4][3] (=10.2f) + printf("%f\n", carray2_f_data(a2, 4)[3]); // same, but this is writable. + printf("%f\n", carray2_f_at(a2, 4).data[3]); // same, via sub-array access. - printf("%f\n", carray3f_value(a3, 5, 4, 3)); - printf("%f\n", carray3f_data(a3, 5, 4)[3]); - printf("%f\n", carray3f_at2(a3, 5, 4).data[3]); + printf("%f\n", carray3_f_value(a3, 5, 4, 3)); // same data location, via a3 array. + printf("%f\n", carray3_f_data(a3, 5, 4)[3]); + printf("%f\n", carray3_f_at2(a3, 5, 4).data[3]); - carray_destroy(a3); - carray_destroy(a2); // not needed, but no harm. + carray_f_destroy(&a2); // does nothing, since it is a sub-array. + carray_f_destroy(&a3); // also invalidates a2. } */ @@ -55,67 +55,100 @@ int main() #define carray1_size(a) ((a).xdim) #define carray2_size(a) ((a)._yxdim) #define carray3_size(a) ((a)._zdim * (a)._yxdim) -#define carray_destroy(a) free((a)._array) -#define declare_CArray(tag, T) \ - c_struct (CArray1##tag) { \ - T *data, *_array; \ - uint32_t xdim; \ - }; \ - c_struct (CArray2##tag) { \ - T *data, *_array; \ - uint32_t xdim, _yxdim; \ - }; \ - c_struct (CArray3##tag) { \ - T *data, *_array; \ - uint32_t xdim, _yxdim, _zdim; \ - }; \ +#define declare_CArray(...) c_MACRO_OVERLOAD(declare_CArray, __VA_ARGS__) + +#define declare_CArray_2(tag, Value) \ + declare_CArray_3(tag, Value, c_emptyDestroy) + + +#define declare_CArray_3(tag, Value, valueDestroy) \ + typedef struct { \ + Value *data; uint32_t owned, xdim; \ + } CArray1_##tag; \ + \ + typedef struct { \ + Value *data; uint32_t owned, xdim; \ + size_t _yxdim; \ + } CArray2_##tag; \ + \ + typedef struct { \ + Value *data; uint32_t owned, xdim; \ + size_t _yxdim; uint32_t _zdim; \ + } CArray3_##tag; \ \ - static inline CArray1##tag \ - carray1##tag##_make(size_t xdim) { \ - T* m = c_new_2(T, xdim); \ - return (CArray1##tag) {m, m, xdim}; \ + static inline void \ + carray1_##tag##_destroy(CArray1_##tag* self) { \ + const size_t n = carray1_size(*self); Value* a = self->data; \ + if (self->owned) {for (size_t i=0; idata; \ + if (self->owned) {for (size_t i=0; idata; \ + if (self->owned) {for (size_t i=0; i