diff options
| -rw-r--r-- | docs/cspan_api.md | 110 | ||||
| -rw-r--r-- | docs/cstr_api.md | 5 | ||||
| -rw-r--r-- | include/stc/cspan.h | 24 | ||||
| -rw-r--r-- | include/stc/cstr.h | 6 | ||||
| -rw-r--r-- | include/stc/priv/altnames.h | 12 | ||||
| -rw-r--r-- | misc/examples/demos.c | 2 | ||||
| -rw-r--r-- | misc/examples/multidim.c | 6 | ||||
| -rw-r--r-- | misc/tests/cspan_test.c | 39 |
8 files changed, 141 insertions, 63 deletions
diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 32ef49c4..c4cb7c16 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -1,9 +1,8 @@ # STC [cspan](../include/stc/cspan.h): Multi-dimensional Array View  -The **cspan** is templated non-owning multi-dimensional view of an array. - -See the c++ classes [std::span](https://en.cppreference.com/w/cpp/container/span) and +The **cspan** is templated non-owning multi-dimensional view of an array. See the c++ classes +[std::span](https://en.cppreference.com/w/cpp/container/span) and [std::mdspan](https://en.cppreference.com/w/cpp/container/mdspan) for similar functionality. ## Header file and declaration @@ -18,17 +17,14 @@ using_cspan3(S, ValueType); // define span types S, S2, S3 with rank using_cspan4(S, ValueType); // define span types S, S2, S3, S4 with ranks 1, 2, 3, 4. ``` ## Methods -Note that `cspan_multidim()`, `cmake_from*()`, `cspan_atN()`, `and cspan_subspanN()` require a (safe) cast to its span-type +Note that `cspan_md()`, `cmake_from*()`, `cspan_atN()`, `and cspan_subspanN()` require a (safe) cast to its span-type on assignment, but not on initialization of a span variable. All functions are type-safe, and arguments are side-effect safe, except for SpanType arg. which must not have side-effects. ```c +SpanTypeN cspan_md(ValueType* data, size_t xdim, ...); // create a multi-dimensional cspan SpanType cspan_make(T SpanType, {v1, v2, ...}); // make a 1d-dimensional cspan from values -SpanTypeN cspan_multidim(ValueType* data, size_t xdim, ...); // create a multi-dimensional cspan SpanType cspan_from(STCContainer* cnt); // create a 1d cspan from a compatible STC container SpanType cspan_from_array(ValueType array[]); // create a 1d cspan from a C array -SpanType cspan_flatten(SpanTypeN* span); // create a 1d cspan from a multidim span -void cspan_resize(SpanTypeN* self, size_t xdim, ...); // change the extent of each dimension - size_t cspan_size(const SpanTypeN* self); // return number of elements unsigned cspan_rank(const SpanTypeN* self); // return number of dimensions size_t cspan_index(const SpanTypeN* self, size_t x, ...); // index of element @@ -37,13 +33,15 @@ ValueType* cspan_at(SpanTypeN* self, size_t x, ...); // at(): ValueType* cspan_front(SpanTypeN* self); ValueType* cspan_back(SpanTypeN* self); -SpanType cspan_at2(SpanType2* self, size_t x); // return a 1d subspan from a 2d span. -SpanTypeN cspan_at3(SpanType3* self, size_t x, ...); // return a 1d or 2d subspan from a 3d span. -SpanTypeN cspan_at4(SpanType4* self, size_t x, ...); // number of args determines rank of output span. + // return a subspan of lower rank: +SpanType cspan_submd2(SpanType2* self, size_t x); // return a 1d subspan from a 2d span. +SpanTypeN cspan_submd3(SpanType3* self, size_t x, ...); // return a 1d or 2d subspan from a 3d span. +SpanTypeN cspan_submd4(SpanType4* self, size_t x, ...); // number of args determines rank of output span. + // return a sliced span of same rank: void cspan_slice(SpanTypeN* self, {x0,x1}, {y0,y1},...); // slice multidim span into a md subspan. - // return a subspan of same rank: + // return a subspan of same rank. Like e.g. cspan_slice(&ms3, {offset, offset+count}, {0}, {0}); SpanType cspan_subspan(const SpanType* self, size_t offset, size_t count); SpanType2 cspan_subspan2(const SpanType2 self, size_t offset, size_t count); SpanType3 cspan_subspan3(const SpanType3 self, size_t offset, size_t count); @@ -61,9 +59,73 @@ void SpanType_next(SpanTypeN_iter* it); | SpanTypeN`_value` | `ValueType` | The ValueType | | SpanTypeN`_iter` | `struct { ValueType *ref; ... }` | Iterator type | -## Example +## Example 1 + +The *cspan_slice()* function is similar to pythons numpy multi-dimensional arrays slicing, e.g.: +```py +import numpy as np +ms3 = np.array((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24), int) + +ms3 = np.reshape(ms3, (2, 3, 4)) +ss3 = ms3[:, 1:3, 2:] +ss2 = ss3[1] + +for i in range(ss2.shape[0]): + for j in range(ss2.shape[1]): + print(" {}".format(ss2[i, j]), end='') +print('') + +for i in ss2.flat: + print(" {}".format(i), end='') +# 19 20 23 24 +# 19 20 23 24 +``` +... can be done in C with STC: +```c +#include <c11/fmt.h> +#include <stc/cspan.h> +using_cspan3(myspan, int); // define myspan, myspan2, myspan3. + +int main() { + int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}; + + myspan3 ms3 = cspan_md(arr, 2, 3, 4), ss3 = ms3; + cspan_slice(&ss3, {0}, {1,3}, {2,}); + myspan2 ss2 = cspan_submd3(&ss3, 1); + + c_FORRANGE (i, ss2.dim[0]) + c_FORRANGE (j, ss2.dim[1]) + fmt_print(" {}", *cspan_at(&ss2, i, j)); + puts(""); + + c_FOREACH (i, myspan2, ss2) + fmt_print(" {}", *i.ref); +} +``` +... or (mostly) in C++23: +```c++ +#include <print> +#include <mdspan> +#include <tuple> + +int main() { + int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}; + + std::mdspan ms3(arr, 2, 3, 4); + auto ss3 = std::submdspan(ms3, std::full_extent, std::tuple{1,3}, std::tuple{2,4}); + auto ss2 = std::submdspan(ss3, 1, std::full_extent, std::full_extent); + + for (std::size_t i = 0; i < ss2.extent(0); ++i) + for (std::size_t j = 0; j < ss2.extent(1); ++j) + std::print(" {}", ss2[i, j]); + std::println(); + + // mdspan can't printed as a flat array, afaik. +} +``` +## Example 2 ```c -#include <stdio.h> +#include <c11/fmt.h> #include <stc/cspan.h> #define i_val float #include <stc/cstack.h> @@ -79,33 +141,33 @@ int main() cstack_float_push(&vec, i); // define "span3[xd][yd][zd]" - Span3 span3 = cspan_multidim(vec.data, xd, yd, zd); + Span3 span3 = cspan_md(vec.data, xd, yd, zd); *cspan_at(&span3, 4, 3, 2) = 3.14159f; - printf("index: %d", (int)cspan_index(&span3, 4, 3, 2)); + fmt_print("index: {}", cspan_index(&span3, 4, 3, 2)); - Span span1 = cspan_at3(&span3, 4, 3); + Span span1 = cspan_submd3(&span3, 4, 3); printf("\niterate span1: "); c_FOREACH (i, Span, span1) - printf("%g ", *i.ref); + fmt_print("{} ", *i.ref); - Span2 span2 = cspan_at3(&span3, 4); + Span2 span2 = cspan_submd3(&span3, 4); printf("\niterate span2: "); c_FOREACH (i, Span2, span2) - printf("%g ", *i.ref); + fmt_print("{} ", *i.ref); puts("\niterate span3 by dimensions:"); c_FORRANGE (i, span3.dim[0]) { c_FORRANGE (j, span3.dim[1]) { c_FORRANGE (k, span3.dim[2]) - printf(" %2g", *cspan_at(&span3, i, j, k)); + fmt_printf(" {:2}", *cspan_at(&span3, i, j, k)); printf(" |"); } puts(""); } - printf("%g\n", *cspan_at(&span3, 4, 3, 2)); - printf("%g\n", *cspan_at(&span2, 3, 2)); - printf("%g\n", *cspan_at(&span1, 2)); + fmt_println("{}", *cspan_at(&span3, 4, 3, 2)); + fmt_println("{}", *cspan_at(&span2, 3, 2)); + fmt_println("{}", *cspan_at(&span1, 2)); } } ``` diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 4f895549..48999654 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -68,8 +68,7 @@ void cstr_insert_s(cstr* self, size_t pos, cstr ins); void cstr_erase(cstr* self, size_t pos, size_t len); // erase len bytes from pos -void cstr_replace(cstr* self, const char* search, const char* repl); -void cstr_replace_ex(cstr* self, const char* search, const char* repl, unsigned count); +void cstr_replace(cstr* self, const char* search, const char* repl, unsigned count = MAX_INT); cstr cstr_replace_sv(csview in, csview search, csview repl, unsigned count); void cstr_replace_at(cstr* self, size_t pos, size_t len, const char* repl); // replace at a position void cstr_replace_at_sv(cstr* self, size_t pos, size_t len, const csview repl); @@ -174,7 +173,7 @@ int main() { cstr_erase(&s1, 7, 5); // -nine printf("%s\n", cstr_str(&s1)); - cstr_replace_ex(&s1, "seven", "four", 1); + cstr_replace(&s1, "seven", "four", 1); printf("%s\n", cstr_str(&s1)); // reassign: diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 19dd74d4..7886c9f6 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -30,7 +30,7 @@ using_cspan(Intspan, int, 1); int demo1() { float raw[4*5]; - Span2f ms = cspan_multidim(raw, 4, 5); + Span2f ms = cspan_md(raw, 4, 5); for (size_t i=0; i<ms.dim[0]; i++) for (size_t j=0; j<ms.dim[1]; j++) @@ -94,7 +94,7 @@ typedef struct { uint32_t d[2]; } cspan_idx2; typedef struct { uint32_t d[3]; } cspan_idx3; typedef struct { uint32_t d[4]; } cspan_idx4; -#define cspan_multidim(array, ...) \ +#define cspan_md(array, ...) \ {.data=array, .dim={__VA_ARGS__}, .stride={.d={__VA_ARGS__}}} /* For static initialization, use cspan_make(). c_make() for non-static only. */ @@ -117,7 +117,7 @@ typedef struct { uint32_t d[4]; } cspan_idx4; #define cspan_front(self) ((self)->data) #define cspan_back(self) ((self)->data + cspan_size(self) - 1) -// cspan_subspan: +// cspan_subspanN: #define cspan_subspan(self, offset, count) \ {.data=cspan_at(self, offset), .dim={count}} @@ -130,24 +130,24 @@ typedef struct { uint32_t d[4]; } cspan_idx4; {.data=cspan_at(self, offset, 0, 0, 0), .dim={count, (self)->dim[1], (self)->dim[2], (self)->dim[3]}, \ .stride={(self)->stride}} -// cspan_atN: +// cspan_submdN: -#define cspan_at4(...) c_MACRO_OVERLOAD(cspan_at4, __VA_ARGS__) -#define cspan_at3(...) c_MACRO_OVERLOAD(cspan_at3, __VA_ARGS__) -#define cspan_at2(self, x) \ +#define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__) +#define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__) +#define cspan_submd2(self, x) \ {.data=cspan_at(self, x, 0), .dim={(self)->dim[1]}} -#define cspan_at3_2(self, x) \ +#define cspan_submd3_2(self, x) \ {.data=cspan_at(self, x, 0, 0), .dim={(self)->dim[1], (self)->dim[2]}, \ .stride={.d={0, (self)->stride.d[2]}}} -#define cspan_at3_3(self, x, y) \ +#define cspan_submd3_3(self, x, y) \ {.data=cspan_at(self, x, y, 0), .dim={(self)->dim[2]}} -#define cspan_at4_2(self, x) \ +#define cspan_submd4_2(self, x) \ {.data=cspan_at(self, x, 0, 0, 0), .dim={(self)->dim[1], (self)->dim[2], (self)->dim[3]}, \ .stride={.d={0, (self)->stride.d[2], (self)->stride.d[3]}}} -#define cspan_at4_3(self, x, y) \ +#define cspan_submd4_3(self, x, y) \ {.data=cspan_at(self, x, y, 0, 0), .dim={(self)->dim[2], (self)->dim[3]}, \ .stride={.d={0, (self)->stride.d[3]}}} -#define cspan_at4_4(self, x, y, z) \ +#define cspan_submd4_4(self, x, y, z) \ {.data=cspan_at(self, x, y, z, 0), .dim={(self)->dim[3]}} // cspan_slice: diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 04091968..071e40e8 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -373,12 +373,12 @@ STC_INLINE char* cstr_append_s(cstr* self, cstr s) { return cstr_append_n(self, sv.str, sv.size); } -STC_INLINE void cstr_replace_ex(cstr* self, const char* search, const char* repl, unsigned count) { +#define cstr_replace(...) c_MACRO_OVERLOAD(cstr_replace, __VA_ARGS__) +#define cstr_replace_3(self, search, repl) cstr_replace_4(self, search, repl, ~0U) +STC_INLINE void cstr_replace_4(cstr* self, const char* search, const char* repl, unsigned count) { cstr_take(self, cstr_replace_sv(cstr_sv(self), c_SV(search, strlen(search)), c_SV(repl, strlen(repl)), count)); } -STC_INLINE void cstr_replace(cstr* self, const char* search, const char* repl) - { cstr_replace_ex(self, search, repl, ~0U); } STC_INLINE void cstr_replace_at_sv(cstr* self, size_t pos, size_t len, const csview repl) { char* d = _cstr_internal_move(self, pos + len, pos + repl.size); diff --git a/include/stc/priv/altnames.h b/include/stc/priv/altnames.h index 7f58384c..695d3ebc 100644 --- a/include/stc/priv/altnames.h +++ b/include/stc/priv/altnames.h @@ -42,15 +42,3 @@ #define c_scope c_SCOPE #define c_defer c_DEFER #define c_sv c_SV - -#define c_DROP c_drop -#define c_DELETE c_delete -#define c_SWAP c_swap -#define c_FIND_IF c_find_if -#define c_ERASE_IF c_erase_if -#define c_FLT_TAKE c_flt_take -#define c_FLT_SKIP c_flt_skip -#define c_FLT_SKIPWHILE c_flt_skipwhile -#define c_FLT_TAKEWHILE c_flt_takewhile -#define c_CONTAINER_OF c_container_of -#define c_STATIC_ASSERT c_static_assert diff --git a/misc/examples/demos.c b/misc/examples/demos.c index 4455b840..c92f95b2 100644 --- a/misc/examples/demos.c +++ b/misc/examples/demos.c @@ -13,7 +13,7 @@ void stringdemo1() cstr_erase(&cs, 7, 5); // -nine printf("%s.\n", cstr_str(&cs)); - cstr_replace_ex(&cs, "seven", "four", 1); + cstr_replace(&cs, "seven", "four", 1); printf("%s.\n", cstr_str(&cs)); cstr_take(&cs, cstr_from_fmt("%s *** %s", cstr_str(&cs), cstr_str(&cs))); diff --git a/misc/examples/multidim.c b/misc/examples/multidim.c index e25d727e..b7ee46fb 100644 --- a/misc/examples/multidim.c +++ b/misc/examples/multidim.c @@ -16,7 +16,7 @@ int main() ispan ms1 = cspan_from(&v); // View the same data as a 3D array 2 x 3 x 4 - ispan3 ms3 = cspan_multidim(v.data, 2, 3, 4); + ispan3 ms3 = cspan_md(v.data, 2, 3, 4); puts("ms3:"); for (unsigned i=0; i != ms3.dim[0]; i++) { @@ -47,7 +47,7 @@ int main() printf(" %d", *i.ref); puts(""); - ispan2 ms2 = cspan_at3(&ms3, 0); + ispan2 ms2 = cspan_submd3(&ms3, 0); // write data using 2D view for (unsigned i=0; i != ms2.dim[0]; i++) @@ -60,7 +60,7 @@ int main() puts(""); puts("iterate subspan ms3[1]:"); - ispan2 sub = cspan_at3(&ms3, 1); + ispan2 sub = cspan_submd3(&ms3, 1); c_FOREACH (i, ispan2, sub) printf(" %d", *i.ref); puts(""); diff --git a/misc/tests/cspan_test.c b/misc/tests/cspan_test.c index 6b85af00..32634795 100644 --- a/misc/tests/cspan_test.c +++ b/misc/tests/cspan_test.c @@ -7,12 +7,12 @@ using_cspan3(intspan, int); CTEST(cspan, subdim) { int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - intspan3 m = cspan_multidim(array, 2, 2, 3); + intspan3 m = cspan_md(array, 2, 2, 3); for (size_t i = 0; i < m.dim[0]; ++i) { - intspan2 sub_i = cspan_at3(&m, i); + intspan2 sub_i = cspan_submd3(&m, i); for (size_t j = 0; j < m.dim[1]; ++j) { - intspan sub_i_j = cspan_at2(&sub_i, j); + intspan sub_i_j = cspan_submd2(&sub_i, j); for (size_t k = 0; k < m.dim[2]; ++k) { ASSERT_EQ(*cspan_at(&sub_i_j, k), *cspan_at(&m, i, j, k)); } @@ -22,7 +22,7 @@ CTEST(cspan, subdim) { CTEST(cspan, slice) { int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - intspan2 m1 = cspan_multidim(array, 3, 4); + intspan2 m1 = cspan_md(array, 3, 4); size_t sum1 = 0; for (size_t i = 0; i < m1.dim[0]; ++i) { @@ -32,7 +32,7 @@ CTEST(cspan, slice) { } intspan2 m2 = m1; - cspan_slice(&m2, c_SLICE(0), c_SLICE(2,4)); + cspan_slice(&m2, {0}, {2,4}); size_t sum2 = 0; for (size_t i = 0; i < m2.dim[0]; ++i) { @@ -43,3 +43,32 @@ CTEST(cspan, slice) { ASSERT_EQ(78, sum1); ASSERT_EQ(45, sum2); } + +#define i_val int +#include <stc/cstack.h> + +CTEST(cspan, slice2) { + c_AUTO (cstack_int, stack) + { + c_FORRANGE (i, 10*20*30) + cstack_int_push(&stack, i); + + intspan3 ms3 = cspan_md(stack.data, 10, 20, 30); + cspan_slice(&ms3, {1,4}, {3,7}, {20,24}); + + size_t sum = 0; + for (size_t i = 0; i < ms3.dim[0]; ++i) { + for (size_t j = 0; j < ms3.dim[1]; ++j) { + for (size_t k = 0; k < ms3.dim[2]; ++k) { + sum += *cspan_at(&ms3, i, j, k); + } + } + } + ASSERT_EQ(65112, sum); + + sum = 0; + c_FOREACH (i, intspan3, ms3) + sum += *i.ref; + ASSERT_EQ(65112, sum); + } +} |
