From 2e71adcb742278523e14f1e9eebc9635e7510a7a Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 22 Mar 2021 19:38:59 +0100 Subject: Rewrote carray.h completely. Somewhat different API, much easier/natural usage. Uses still a contiguous block of memory. --- benchmarks/others/carray_v1.h | 215 ++++++++++++++++++++++++++++++++ docs/carray_api.md | 123 +++++++++++-------- examples/complex.c | 43 ++++--- examples/demos.c | 23 ++-- stc/carray.h | 280 ++++++++++++++++++++---------------------- 5 files changed, 454 insertions(+), 230 deletions(-) create mode 100644 benchmarks/others/carray_v1.h diff --git a/benchmarks/others/carray_v1.h b/benchmarks/others/carray_v1.h new file mode 100644 index 00000000..fdd69013 --- /dev/null +++ b/benchmarks/others/carray_v1.h @@ -0,0 +1,215 @@ +/* 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. + */ +#ifndef CARRAY_H_INCLUDED +#define CARRAY_H_INCLUDED + +#include +#include "ccommon.h" + +/* + Multi-dimensional generic array allocated as one block of heap-memory. + // demo: +#include +#include "stc/carray.h" +using_carray3(f, float); + +int main() +{ + carray3f a3 = carray3f_init(30, 20, 10, 0.0f); + *carray3f_at(&a3, 5, 4, 3) = 10.2f; // a3[5][4][3] + carray2f a2 = carray3f_at1(&a3, 5); // sub-array reference: a2 = a3[5] + printf("%g\n", *carray2f_at(&a2, 4, 3)); // lookup a2[4][3] (=10.2f) + printf("%g\n", *carray3f_at(&a3, 5, 4, 3)); // same data location, via a3 array. + + carray2f_del(&a2); // does nothing, since it is a sub-array. + carray3f_del(&a3); // destroy a3, invalidates a2. +} +*/ + +#define using_carray2(...) c_MACRO_OVERLOAD(using_carray2, __VA_ARGS__) + +#define using_carray2_2(X, Value) \ + using_carray2_4(X, Value, c_trivial_del, c_trivial_fromraw) + +#define using_carray2_4(X, Value, valueDel, valueClone) \ +\ + typedef Value carray1##X##_value_t, carray2##X##_value_t; \ +\ + typedef struct { \ + carray1##X##_value_t *data; \ + size_t _xdim; \ + } carray1##X; \ +\ + typedef struct { \ + carray2##X##_value_t *data; \ + size_t _xdim, _ydim; \ + } carray2##X; \ +\ + STC_INLINE size_t \ + carray1##X##_size(carray1##X a) {return _carray_xdim(a);} \ + STC_INLINE size_t \ + carray2##X##_size(carray2##X a) {return _carray_xdim(a)*_carray_ydim(a);} \ + STC_INLINE size_t \ + carray2##X##_ydim(carray2##X a) {return _carray_ydim(a);} \ +\ + _using_carray_common(1, X, Value, valueDel, valueClone) \ + _using_carray_common(2, X, Value, valueDel, valueClone) \ +\ + STC_INLINE carray1##X \ + carray1##X##_init(size_t xdim, Value val) { \ + carray1##X##_value_t* m = c_new_2(carray1##X##_value_t, xdim); \ + for (size_t i=0; idata + x; } \ + \ + STC_INLINE carray1##X \ + carray2##X##_at1(const carray2##X *a, size_t y) { \ + carray1##X sub = {a->data + y*_carray_xdim(*a), _carray_xdim(*a)}; \ + return sub; \ + } \ + STC_INLINE carray2##X##_value_t* \ + carray2##X##_at(const carray2##X *a, size_t y, size_t x) { \ + return a->data + y*_carray_xdim(*a) + x; \ + } \ + typedef carray2##X carray2##X##_t + + +#define using_carray3(...) c_MACRO_OVERLOAD(using_carray3, __VA_ARGS__) + +#define using_carray3_2(X, Value) \ + using_carray3_4(X, Value, c_trivial_del, c_trivial_fromraw) + +#define using_carray3_4(X, Value, valueDel, valueClone) \ +\ + using_carray2_4(X, Value, valueDel, valueClone); \ + typedef Value carray3##X##_value_t; \ +\ + typedef struct { \ + carray3##X##_value_t *data; \ + size_t _xdim, _ydim, _zdim; \ + } carray3##X; \ +\ + STC_INLINE size_t \ + carray3##X##_size(carray3##X a) {return _carray_xdim(a)*_carray_ydim(a)*_carray_zdim(a);} \ + STC_INLINE size_t \ + carray3##X##_ydim(carray3##X a) {return _carray_ydim(a);} \ + STC_INLINE size_t \ + carray3##X##_zdim(carray3##X a) {return _carray_zdim(a);} \ +\ + _using_carray_common(3, X, Value, valueDel, valueClone) \ +\ + STC_INLINE carray3##X \ + carray3##X##_init(size_t zdim, size_t ydim, size_t xdim, Value val) { \ + const size_t n = zdim * ydim * xdim; \ + carray3##X##_value_t* m = c_new_2(carray3##X##_value_t, n); \ + for (size_t i=0; idata + z*_carray_ydim(*a)*_carray_xdim(*a), _carray_xdim(*a), _carray_ydim(*a)}; \ + return sub; \ + } \ + STC_INLINE carray1##X \ + carray3##X##_at2(const carray3##X *a, size_t z, size_t y) { \ + carray1##X sub = {a->data + (z*_carray_ydim(*a) + y)*_carray_xdim(*a), _carray_xdim(*a)}; \ + return sub; \ + } \ + STC_INLINE carray3##X##_value_t* \ + carray3##X##_at(const carray3##X *a, size_t z, size_t y, size_t x) { \ + return a->data + (z*_carray_ydim(*a) + y)*_carray_xdim(*a) + x; \ + } \ + typedef carray3##X carray3##X##_t + + +#define _carray_SUB (SIZE_MAX >> 1) +#define _carray_OWN (_carray_SUB + 1) +#define _carray_xdim(a) ((a)._xdim & _carray_SUB) +#define _carray_ydim(a) (a)._ydim +#define _carray_zdim(a) (a)._zdim + +#define _using_carray_common(D, X, Value, valueDel, valueClone) \ + typedef struct { carray1##X##_value_t *ref; } carray##D##X##_iter_t; \ +\ + STC_INLINE carray##D##X##_iter_t \ + carray##D##X##_begin(const carray##D##X* a) { \ + carray##D##X##_iter_t it = {a->data}; return it; \ + } \ + STC_INLINE carray##D##X##_iter_t \ + carray##D##X##_end(const carray##D##X* a) { \ + carray##D##X##_iter_t it = {a->data + carray##D##X##_size(*a)}; return it; \ + } \ + STC_INLINE void \ + carray##D##X##_next(carray##D##X##_iter_t* it) {++it->ref;} \ +\ + STC_INLINE void \ + carray##D##X##_del(carray##D##X* self) { \ + if (self->_xdim & _carray_OWN) { \ + c_foreach_3 (i, carray##D##X, *self) \ + valueDel(i.ref); \ + c_free(self->data); \ + } \ + } \ + STC_INLINE carray##D##X \ + carray##D##X##_clone(carray##D##X arr) { \ + carray##D##X cp = arr; size_t k = 0; \ + cp.data = c_new_2(carray1##X##_value_t, carray##D##X##_size(arr)); \ + c_foreach_3 (i, carray##D##X, arr) \ + cp.data[k++] = valueClone(*i.ref); \ + return cp; \ + } \ + STC_INLINE size_t \ + carray##D##X##_xdim(carray##D##X a) {return _carray_xdim(a);} \ + +#endif diff --git a/docs/carray_api.md b/docs/carray_api.md index 356b09ad..b9b3451d 100644 --- a/docs/carray_api.md +++ b/docs/carray_api.md @@ -1,89 +1,106 @@ # STC [carray](../stc/carray.h): Multi-dimensional Array ![Array](pics/array.jpg) -The **carray** containers provides templates for multidimensional arrays of contiguous data It supports 1-, 2- and +The **carray** containers provides templates for multidimensional arrays. It supports 2- and 3-dimensional arrays, which are allocated from the heap as a single contiguous block of memory. +The carrays can be used almost like regular constant size multi-dimensional arrays in C, and has +the same property of storing data in one block of memory, which can be passed to any method. See the c++ class [boost::multi_array](https://www.boost.org/doc/libs/release/libs/multi_array) for similar functionality. ## Declaration ```c -using_carray(X, Value); -using_carray(X, Value, valueDel, valueClone); +using_carray2(X, Value); +using_carray2(X, Value, valueDel, valueClone); +using_carray3(X, Value); +using_carray3(X, Value, valueDel, valueClone); ``` -The macro `using_carray()` 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_carray(i, int);`, `X` should -be replaced by `i` in all of the following documentation. The `N` character should be replaced by `1`, `2` or `3`. +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. ## Header file All carray definitions and prototypes are available by including a single header file. ```c -#include "stc/carray.h" +#include ``` ## Methods ```c -carray1X carray1X_init(size_t xdim, Value val); -carray2X carray2X_init(size_t ydim, size_t xdim, Value val); -carray3X carray3X_init(size_t zdim, size_t ydim, size_t xdim, Value val); -carray1X carray1X_from(Value* array, size_t xdim); -carray2X carray2X_from(Value* array, size_t ydim, size_t xdim); -carray3X carray3X_from(Value* array, size_t zdim, size_t ydim, size_t xdim); -carrayNX carrayNX_clone(carrayNX arr); - -void carrayNX_del(carrayNX* self); - -size_t carrayNX_size(carrayNX arr); -size_t carrayNX_xdim(carrayNX arr); -size_t carrayNX_ydim(carrayNX arr); // not N=3 -size_t carrayNX_zdim(carrayNX arr); // only N=3 - -Value* carray1X_at(const carray1X *self, size_t x); -Value* carray2X_at(const carray2X *self, size_t y, size_t x); -Value* carray3X_at(const carray3X *self, size_t z, size_t y, size_t x); - -carray1X carray2X_at1(const carray2X *self, size_t y); -carray2X carray3X_at1(const carray3X *self, size_t z); -carray1X carray3X_at2(const carray3X *self, size_t z, size_t y); - -carrayNX_iter_t carrayNX_begin(const carrayNX* self); -carrayNX_iter_t carrayNX_end(const carrayNX* self); -void carrayNX_next(carrayNX_iter_t* it); -carrayNX_value_t* carrayNX_itval(carrayNX_iter_t it); +carray2X carray2X_init(size_t xdim, size_t ydim, Value val); +carray2X carray2X_from(Value* array, size_t xdim, size_t ydim); +carray2X carray2X_clone(carray2X arr); +void carray2X_del(carray2X* self); +void carray2X_del_internals(carray2X* self); // destroy pointers only + +size_t carray2X_size(carray2X arr); +Value* carray2X_data(carray2X* self); // contiguous memory + +carray2X_iter_t carray2X_begin(const carray2X* self); +carray2X_iter_t carray2X_end(const carray2X* self); +void carray2X_next(carray2X_iter_t* it); +``` +```c +carray3X carray3X_init(size_t xdim, size_t ydim, size_t zdim, Value val); +carray3X carray3X_from(Value* array, size_t xdim, size_t ydim, size_t zdim); +carray3X carray3X_clone(carray3X arr); +void carray3X_del(carray3X* self); +void carray3X_del_internals(carray3X* self); // destroy pointers only + +size_t carray3X_size(carray3X arr); +Value* carray3X_data(carray3X* self); // contiguous memory + +carray3X_iter_t carray3X_begin(const carray3X* self); +carray3X_iter_t carray3X_end(const carray3X* self); +void carray3X_next(carray3X_iter_t* it); ``` ## Types -| Type name | Type definition | Used to represent... | -|:---------------------|:------------------------------|:--------------------------| -| `carrayNX` | `struct { ... }` | The carray type | -| `carrayNX_value_t` | `Value` | The value type | -| `carrayNX_iter_t` | `struct { Value *ref; }` | Iterator type | +| Type name | Type definition | Used to represent... | +|:---------------------|:-------------------------------------------------|:--------------------------| +| `carray2X` | `struct { Value **at; 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 ***at; size_t xdim,ydim,zdim; }` | The carray3 type | +| `carray3X_value_t` | `Value` | The value type | +| `carray3X_iter_t` | `struct { Value *ref; }` | Iterator type | ## Example ```c -#include #include "stc/carray.h" +#include -using_carray(f, float); +using_carray3(f, float); +using_carray2(i, uint32_t); int main() { + // Ex1 carray3f a3 = carray3f_init(30, 20, 10, 0.0f); // define a3[30][20][10], init with 0.0f. - *carray3f_at(&a3, 5, 4, 3) = 3.14f; // a3[5][4][3] = 3.14 - - carray1f a1 = carray3f_at2(&a3, 5, 4); // sub-array a3[5][4] (no data copy). - carray2f a2 = carray3f_at1(&a3, 5); // sub-array a3[5] - - printf("%f\n", *carray1f_at(&a1, 3)); // a1[3] (3.14f) - printf("%f\n", *carray2f_at(&a2, 4, 3)); // a2[4][3] (3.14f) - printf("%f\n", *carray3f_at(&a3, 5, 4, 3)); // a3[5][4][3] (3.14f) - // ... - carray1f_del(&a1); // does nothing, since it is a sub-array. - carray2f_del(&a2); // same. - carray3f_del(&a3); // free array, and invalidates a1, a2. + a3.at[5][4][3] = 3.14f; + + float *a1 = a3.at[5][4]; + float **a2 = a3.at[5]; + + printf("%f\n", a1[3]); // 3.14 + printf("%f\n", a2[4][3]); // 3.14 + printf("%f\n", a3.at[5][4][3]); // 3.14 + carray3f_del(&a3); // free array + + // Ex2 + carray2i image = carray2i_from(c_new(uint32_t, 256*128), 256, 128); // no value init + int n = 0; + c_foreach (i, carray2i, image) { + uint32_t t = n++ % 256; + *i.ref = t | t << 8 | t << 16 | 255; + } + + for (int y=0; y, 4>>; +// using map_lst = std::unordered_map>; +// using map_map = std::unordered_map; int main() { int xdim = 4, ydim = 6; - int x = 1, y = 5, tableKey = 42; + int x = 1, y = 3, tableKey = 42; const char* strKey = "first"; - cmap_l listMap = cmap_l_init(); - cmap_s myMap = cmap_s_init(); + cmap_map myMap = cmap_map_init(); + cmap_lst listMap = cmap_lst_init(); + clist_arr tableList = clist_arr_init(); + carray2f arr2 = carray2f_init(xdim, ydim, 1.f); - // Construct. - carray2f arr_a = carray2f_init(ydim, xdim, 0.f); - printf("arr_a: (%zu, %zu)\n", carray2f_ydim(arr_a), carray2f_xdim(arr_a)); + printf("arr2 size: %zu x %zu\n", arr2.xdim, arr2.ydim); - clist_a tableList = clist_a_init(); - // Put in some data. - *carray2f_at(&arr_a, y, x) = 3.1415927f; // aa[y][x] - clist_a_push_back(&tableList, arr_a); - cmap_l_insert(&listMap, tableKey, tableList); - cmap_s_insert(&myMap, cstr_from(strKey), listMap); + // Put in some data in 2D array + arr2.at[x][y] = 3.1415927f; + clist_arr_push_back(&tableList, arr2); + cmap_lst_insert(&listMap, tableKey, tableList); + cmap_map_insert(&myMap, cstr_from(strKey), listMap); // Access the data entry - carray2f arr_b = *clist_a_back(&cmap_l_find(&cmap_s_find(&myMap, strKey).ref->second, tableKey).ref->second); - printf("value (%d, %d) is: %f\n", y, x, *carray2f_at(&arr_b, y, x)); + cmap_lst* mapl = &cmap_map_find(&myMap, strKey).ref->second; + clist_arr* lsta = &cmap_lst_find(mapl, tableKey).ref->second; + carray2f arr = *clist_arr_back(lsta); - cmap_s_del(&myMap); // free up everything! + printf("value (%d, %d) is: %f\n", x, y, arr.at[x][y]); + + arr2.at[x][y] = 1.41421356f; // change the value in array + cmap_map_del(&myMap); // free up everything! } diff --git a/examples/demos.c b/examples/demos.c index eca5609f..9d7f894c 100644 --- a/examples/demos.c +++ b/examples/demos.c @@ -181,23 +181,22 @@ void arraydemo1() { printf("\nARRAYDEMO1\n"); carray3f a3 = carray3f_init(30, 20, 10, 0.0f); - *carray3f_at(&a3, 5, 4, 3) = 10.2f; // a3[5][4][3] - carray2f a2 = carray3f_at1(&a3, 5); // sub-array reference: a2 = a3[5] - carray1f a1 = carray3f_at2(&a3, 5, 4); // sub-array reference: a1 = a3[5][4] + a3.at[5][4][3] = 10.2f; + float **a2 = a3.at[5]; + float *a1 = a3.at[5][4]; - printf("a3: %zu: (%zu, %zu, %zu) = %zu\n", sizeof(a3), carray3f_xdim(a3), carray3f_ydim(a3), carray3f_zdim(a3), carray3f_size(a3)); - printf("a2: %zu: (%zu, %zu) = %zu\n", sizeof(a2), carray2f_xdim(a2), carray2f_ydim(a2), carray2f_size(a2)); + printf("a3: %zu: (%zu, %zu, %zu) = %zu\n", sizeof(a3), a3.xdim, a3.ydim, a3.zdim, carray3f_size(a3)); - printf("%f\n", a1.data[3]); // lookup a1[3] (=10.2f) - printf("%f\n", *carray2f_at(&a2, 4, 3)); // lookup a2[4][3] (=10.2f) - printf("%f\n", *carray3f_at(&a3, 5, 4, 3)); // lookup a3[5][4][3] (=10.2f) + printf("%g\n", a1[3]); // = 10.2 + printf("%g\n", a2[4][3]); // = 10.2 + printf("%g\n", a3.at[5][4][3]); // = 10.2 + float x = 0.0; c_foreach (i, carray3f, a3) - *i.ref = 1.0f; - printf("%f\n", *carray3f_at(&a3, 29, 19, 9)); + *i.ref = ++x; + printf("%g\n", a3.at[29][19][9]); // = 6000 - carray2f_del(&a2); // does nothing, since it is a sub-array. - carray3f_del(&a3); // also invalidates a2. + carray3f_del(&a3); } diff --git a/stc/carray.h b/stc/carray.h index fdd69013..3fe60bf6 100644 --- a/stc/carray.h +++ b/stc/carray.h @@ -23,29 +23,37 @@ #ifndef CARRAY_H_INCLUDED #define CARRAY_H_INCLUDED -#include #include "ccommon.h" - +#include /* - Multi-dimensional generic array allocated as one block of heap-memory. - // demo: +// carray2 and carray3 - 2D and 3D dynamic arrays in one memory block with easy indexing. +#include #include -#include "stc/carray.h" -using_carray3(f, float); - -int main() -{ - carray3f a3 = carray3f_init(30, 20, 10, 0.0f); - *carray3f_at(&a3, 5, 4, 3) = 10.2f; // a3[5][4][3] - carray2f a2 = carray3f_at1(&a3, 5); // sub-array reference: a2 = a3[5] - printf("%g\n", *carray2f_at(&a2, 4, 3)); // lookup a2[4][3] (=10.2f) - printf("%g\n", *carray3f_at(&a3, 5, 4, 3)); // same data location, via a3 array. - - carray2f_del(&a2); // does nothing, since it is a sub-array. - carray3f_del(&a3); // destroy a3, invalidates a2. +using_carray2(i, int); + +int main() { + int w = 7, h = 5; + carray2i image = carray2i_init(w, h, 0); + + int *dat = carray2i_data(&image); + for (int i = 0; i < carray2i_size(image); ++i) + dat[i] = i; + + for (int x = 0; x < image.xdim; ++x) + for (int y = 0; y < image.ydim; ++y) + printf(" %d", image.at[x][y]); + puts("\n"); + + c_foreach (i, carray2i, image) + printf(" %d", *i.ref); + puts(""); + + carray2i_del(&image); } */ +// carray2: + #define using_carray2(...) c_MACRO_OVERLOAD(using_carray2, __VA_ARGS__) #define using_carray2_2(X, Value) \ @@ -53,69 +61,30 @@ int main() #define using_carray2_4(X, Value, valueDel, valueClone) \ \ - typedef Value carray1##X##_value_t, carray2##X##_value_t; \ -\ - typedef struct { \ - carray1##X##_value_t *data; \ - size_t _xdim; \ - } carray1##X; \ -\ - typedef struct { \ - carray2##X##_value_t *data; \ - size_t _xdim, _ydim; \ - } carray2##X; \ -\ - STC_INLINE size_t \ - carray1##X##_size(carray1##X a) {return _carray_xdim(a);} \ - STC_INLINE size_t \ - carray2##X##_size(carray2##X a) {return _carray_xdim(a)*_carray_ydim(a);} \ - STC_INLINE size_t \ - carray2##X##_ydim(carray2##X a) {return _carray_ydim(a);} \ -\ - _using_carray_common(1, X, Value, valueDel, valueClone) \ - _using_carray_common(2, X, Value, valueDel, valueClone) \ -\ - STC_INLINE carray1##X \ - carray1##X##_init(size_t xdim, Value val) { \ - carray1##X##_value_t* m = c_new_2(carray1##X##_value_t, xdim); \ - for (size_t i=0; iat[0]; } \ + STC_INLINE void carray2##X##_del_internals(carray2##X* self) { c_free(self->at); } \ \ - STC_INLINE carray1##X##_value_t* \ - carray1##X##_at(const carray1##X *a, size_t x) { return a->data + x; } \ - \ - STC_INLINE carray1##X \ - carray2##X##_at1(const carray2##X *a, size_t y) { \ - carray1##X sub = {a->data + y*_carray_xdim(*a), _carray_xdim(*a)}; \ - return sub; \ + STC_INLINE carray2##X##_iter_t carray2##X##_begin(const carray2##X* self) { \ + carray2##X##_iter_t it = {self->at[0]}; return it; \ } \ - STC_INLINE carray2##X##_value_t* \ - carray2##X##_at(const carray2##X *a, size_t y, size_t x) { \ - return a->data + y*_carray_xdim(*a) + x; \ + STC_INLINE carray2##X##_iter_t carray2##X##_end(const carray2##X* self) { \ + carray2##X##_iter_t it = {self->at[0] + carray2##X##_size(*self)}; return it; \ } \ - typedef carray2##X carray2##X##_t + STC_INLINE void carray2##X##_next(carray2##X##_iter_t* it) { ++it->ref; } \ +\ + _c_implement_carray2_4(X, Value, valueDel, valueClone) \ + STC_API void carray2##X##_del(carray2##X* self) +// carray3: #define using_carray3(...) c_MACRO_OVERLOAD(using_carray3, __VA_ARGS__) @@ -124,92 +93,109 @@ int main() #define using_carray3_4(X, Value, valueDel, valueClone) \ \ - using_carray2_4(X, Value, valueDel, valueClone); \ typedef Value carray3##X##_value_t; \ + typedef struct { carray3##X##_value_t ***at; size_t xdim, ydim, zdim; } carray3##X; \ + typedef struct { carray3##X##_value_t *ref; } carray3##X##_iter_t; \ \ - typedef struct { \ - carray3##X##_value_t *data; \ - size_t _xdim, _ydim, _zdim; \ - } carray3##X; \ -\ - STC_INLINE size_t \ - carray3##X##_size(carray3##X a) {return _carray_xdim(a)*_carray_ydim(a)*_carray_zdim(a);} \ - STC_INLINE size_t \ - carray3##X##_ydim(carray3##X a) {return _carray_ydim(a);} \ - STC_INLINE size_t \ - carray3##X##_zdim(carray3##X a) {return _carray_zdim(a);} \ -\ - _using_carray_common(3, X, Value, valueDel, valueClone) \ -\ - STC_INLINE carray3##X \ - carray3##X##_init(size_t zdim, size_t ydim, size_t xdim, Value val) { \ - const size_t n = zdim * ydim * xdim; \ - carray3##X##_value_t* m = c_new_2(carray3##X##_value_t, n); \ - for (size_t i=0; iat[0][0]; } \ + STC_INLINE void carray3##X##_del_internals(carray3##X* self) { c_free(self->at); } \ \ - STC_INLINE carray2##X \ - carray3##X##_at1(const carray3##X *a, size_t z) { \ - carray2##X sub = {a->data + z*_carray_ydim(*a)*_carray_xdim(*a), _carray_xdim(*a), _carray_ydim(*a)}; \ - return sub; \ + STC_INLINE carray3##X##_iter_t carray3##X##_begin(const carray3##X* self) { \ + carray3##X##_iter_t it = {self->at[0][0]}; return it; \ } \ - STC_INLINE carray1##X \ - carray3##X##_at2(const carray3##X *a, size_t z, size_t y) { \ - carray1##X sub = {a->data + (z*_carray_ydim(*a) + y)*_carray_xdim(*a), _carray_xdim(*a)}; \ - return sub; \ + STC_INLINE carray3##X##_iter_t carray3##X##_end(const carray3##X* self) { \ + carray3##X##_iter_t it = {self->at[0][0] + carray3##X##_size(*self)}; return it; \ } \ - STC_INLINE carray3##X##_value_t* \ - carray3##X##_at(const carray3##X *a, size_t z, size_t y, size_t x) { \ - return a->data + (z*_carray_ydim(*a) + y)*_carray_xdim(*a) + x; \ - } \ - typedef carray3##X carray3##X##_t + STC_INLINE void carray3##X##_next(carray3##X##_iter_t* it) { ++it->ref; } \ +\ + _c_implement_carray3_4(X, Value, valueDel, valueClone) \ + STC_API void carray3##X##_del(carray3##X* self) +/* -------------------------- IMPLEMENTATION ------------------------- */ -#define _carray_SUB (SIZE_MAX >> 1) -#define _carray_OWN (_carray_SUB + 1) -#define _carray_xdim(a) ((a)._xdim & _carray_SUB) -#define _carray_ydim(a) (a)._ydim -#define _carray_zdim(a) (a)._zdim +#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) -#define _using_carray_common(D, X, Value, valueDel, valueClone) \ - typedef struct { carray1##X##_value_t *ref; } carray##D##X##_iter_t; \ +#define _c_implement_carray2_4(X, Value, valueDel, valueClone) \ +\ + STC_DEF carray2##X carray2##X##_from(carray2##X##_value_t* block, size_t xdim, size_t ydim) { \ + size_t n = xdim * ydim; \ + carray2##X _arr = {c_new_2(carray2##X##_value_t*, xdim), xdim, ydim}; \ + _arr.at[0] = block; \ + for (size_t x = 1; x < xdim; ++x) \ + _arr.at[x] = _arr.at[x - 1] + ydim; \ + return _arr; \ + } \ \ - STC_INLINE carray##D##X##_iter_t \ - carray##D##X##_begin(const carray##D##X* a) { \ - carray##D##X##_iter_t it = {a->data}; return it; \ + STC_DEF carray2##X carray2##X##_init(size_t xdim, size_t ydim, Value value) { \ + size_t n = xdim*ydim; \ + carray2##X _arr = carray2##X##_from(c_new_2(carray2##X##_value_t, n), xdim, ydim); \ + for (carray2##X##_value_t* p = _arr.at[0], *e = p + n; p != e; ++p) \ + *p = value; \ + return _arr; \ } \ - STC_INLINE carray##D##X##_iter_t \ - carray##D##X##_end(const carray##D##X* a) { \ - carray##D##X##_iter_t it = {a->data + carray##D##X##_size(*a)}; return it; \ +\ + STC_DEF carray2##X carray2##X##_clone(carray2##X src) { \ + size_t n = src.xdim*src.ydim; \ + carray2##X _arr = carray2##X##_from(c_new_2(carray2##X##_value_t, n), src.xdim, src.ydim); \ + for (carray2##X##_value_t* p = _arr.at[0], *q = src.at[0], *e = p + n; p != e; ++p, ++q) \ + *p = valueClone(*q); \ + return _arr; \ } \ - STC_INLINE void \ - carray##D##X##_next(carray##D##X##_iter_t* it) {++it->ref;} \ -\ - STC_INLINE void \ - carray##D##X##_del(carray##D##X* self) { \ - if (self->_xdim & _carray_OWN) { \ - c_foreach_3 (i, carray##D##X, *self) \ - valueDel(i.ref); \ - c_free(self->data); \ +\ + STC_DEF void carray2##X##_del(carray2##X* self) { \ + for (carray2##X##_value_t* p = self->at[0], *e = p + self->xdim*self->ydim; p != e; ++p) \ + valueDel(p); \ + c_free(self->at[0]); /* data */ \ + c_free(self->at); \ + } + +#define _c_implement_carray3_4(X, Value, valueDel, valueClone) \ +\ + STC_DEF carray3##X carray3##X##_from(carray3##X##_value_t* block, size_t xdim, size_t ydim, size_t zdim) { \ + carray3##X _arr = {c_new_2(carray3##X##_value_t**, xdim*(ydim + 1)), xdim, ydim, zdim}; \ + _arr.at[0] = (carray3##X##_value_t**) &_arr.at[xdim]; \ + _arr.at[0][0] = block; \ + for (size_t x = 1, m = zdim*ydim; x < xdim; ++x) { \ + _arr.at[x] = _arr.at[x - 1] + ydim; \ + _arr.at[x][0] = _arr.at[x - 1][0] + m; \ } \ + for (size_t x = 0; x < xdim; ++x) \ + for (size_t y = 1; y < ydim; ++y) \ + _arr.at[x][y] = _arr.at[x][y - 1] + zdim; \ + return _arr; \ + } \ +\ + STC_DEF carray3##X carray3##X##_init(size_t xdim, size_t ydim, size_t zdim, Value value) { \ + size_t n = xdim*ydim*zdim; \ + carray3##X _arr = carray3##X##_from(c_new_2(carray3##X##_value_t, n), xdim, ydim, zdim); \ + for (carray3##X##_value_t* p = **_arr.at, *e = p + n; p != e; ++p) \ + *p = value; \ + return _arr; \ } \ - STC_INLINE carray##D##X \ - carray##D##X##_clone(carray##D##X arr) { \ - carray##D##X cp = arr; size_t k = 0; \ - cp.data = c_new_2(carray1##X##_value_t, carray##D##X##_size(arr)); \ - c_foreach_3 (i, carray##D##X, arr) \ - cp.data[k++] = valueClone(*i.ref); \ - return cp; \ +\ + STC_DEF carray3##X carray3##X##_clone(carray3##X src) { \ + size_t n = carray3##X##_size(src); \ + carray3##X _arr = carray3##X##_from(c_new_2(carray3##X##_value_t, n), src.xdim, src.ydim, src.zdim); \ + for (carray3##X##_value_t* p = **_arr.at, *q = **src.at, *e = p + n; p != e; ++p, ++q) \ + *p = valueClone(*q); \ + return _arr; \ } \ - STC_INLINE size_t \ - carray##D##X##_xdim(carray##D##X a) {return _carray_xdim(a);} \ +\ + STC_DEF void carray3##X##_del(carray3##X* self) { \ + for (carray3##X##_value_t* p = **self->at, *e = p + carray3##X##_size(*self); p != e; ++p) \ + valueDel(p); \ + c_free(self->at[0][0]); /* data */ \ + c_free(self->at); /* pointers */ \ + } + +#else +#define _c_implement_carray2_4(X, Value, valueDel, valueClone) +#define _c_implement_carray3_4(X, Value, valueDel, valueClone) +#endif #endif -- cgit v1.2.3