From 2d67f4040f6eecd41f1b864b43c62823ed75aff0 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 21 Jul 2023 00:37:28 +0200 Subject: Renamed badly abbreviated names in crand.h. Moved coroutine.h from algo subfolder to stc. Updated coroutine.h and docs. --- misc/examples/spans/mdspan.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 misc/examples/spans/mdspan.c (limited to 'misc/examples/spans/mdspan.c') diff --git a/misc/examples/spans/mdspan.c b/misc/examples/spans/mdspan.c new file mode 100644 index 00000000..4427299c --- /dev/null +++ b/misc/examples/spans/mdspan.c @@ -0,0 +1,51 @@ +#include +#include +#include + +using_cspan3(DSpan, double); + +int main(void) { + const int nx=5, ny=4, nz=3; + double* data = c_new_n(double, nx*ny*nz); + + printf("\nMultidim span ms[5, 4, 3], fortran ordered"); + DSpan3 ms = cspan_md_order('F', data, nx, ny, nz); // Fortran, not 'C' + + int idx = 0; + c_forrange (i, ms.shape[0]) + c_forrange (j, ms.shape[1]) + c_forrange (k, ms.shape[2]) + *cspan_at(&ms, i, j, k) = ++idx; + + cspan_transpose(&ms); + + printf(", transposed:\n\n"); + c_forrange (i, ms.shape[0]) { + c_forrange (j, ms.shape[1]) { + c_forrange (k, ms.shape[2]) + printf(" %3g", *cspan_at(&ms, i, j, k)); + puts(""); + } + puts(""); + } + + DSpan2 sub; + + puts("Slicing:"); + printf("\nms[0, :, :] "); + sub = cspan_slice(DSpan2, &ms, {0}, {c_ALL}, {c_ALL}); + c_foreach (i, DSpan2, sub) printf(" %g", *i.ref); + puts(""); + + printf("\nms[:, 0, :] "); + sub = cspan_slice(DSpan2, &ms, {c_ALL}, {0}, {c_ALL}); + c_foreach (i, DSpan2, sub) printf(" %g", *i.ref); + puts(""); + + sub = cspan_slice(DSpan2, &ms, {c_ALL}, {c_ALL}, {0}); + printf("\nms[:, :, 0] "); + c_foreach (i, DSpan2, sub) printf(" %g", *i.ref); + puts(""); + + free(data); +} -- cgit v1.2.3 From dbcc13635402bd466675f4f41e865d02abc6f918 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 21 Jul 2023 10:49:45 +0200 Subject: NB! Changed some coroutine API for consistency/simplicity: Added full task support. --- docs/ccommon_api.md | 30 ++++++-------- include/stc/ccommon.h | 2 +- include/stc/coroutine.h | 44 ++++++++++---------- misc/examples/coroutines/cointerleave.c | 2 +- misc/examples/coroutines/coread.c | 2 +- misc/examples/coroutines/coroutines.c | 8 ++-- misc/examples/coroutines/cotasks1.c | 2 +- misc/examples/coroutines/cotasks2.c | 4 +- misc/examples/smartpointers/map_box.c | 34 +++++++++++++++ misc/examples/smartpointers/map_ptr.c | 34 +++++++++++++++ misc/examples/smartpointers/rawptr_elements.c | 59 --------------------------- misc/examples/spans/mdspan.c | 12 +++--- 12 files changed, 119 insertions(+), 114 deletions(-) create mode 100644 misc/examples/smartpointers/map_box.c create mode 100644 misc/examples/smartpointers/map_ptr.c delete mode 100644 misc/examples/smartpointers/rawptr_elements.c (limited to 'misc/examples/spans/mdspan.c') diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 9189d7e8..0752beb5 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -374,36 +374,32 @@ cco_routine scope; Use `if-else-if` constructs instead. | | Function / operator | Description | |:----------|:-------------------------------------|:----------------------------------------| -| | Function / 'keywords': | | -|`cco_result` | Enum `CCO_DONE=0`, `CCO_YIELD`, `CCO_AWAIT` | Recommended return values in coroutines | -| | Function / 'keywords': | | +|`cco_result` | `CCO_DONE`, `CCO_AWAIT`, `CCO_YIELD` | Default set of return values from coroutines | | | `cco_cleanup:` | Label for cleanup position in coroutine | | `bool` | `cco_done(co)` | Is coroutine done? | -| | `cco_routine(co) { }` | The coroutine scope | +| | `cco_routine(co) {}` | The coroutine scope | | | `cco_yield();` | Yield/suspend execution (return CCO_YIELD)| -| | `cco_yield_v();` | Yield/suspend execution (return void) | | | `cco_yield_v(ret);` | Yield/suspend execution (return ret) | -| | `cco_yield_final();` | Yield final time, enables cleanup-state | -| | `cco_yield_final(ret);` | Yield a final value (e.g. CCO_ERROR) | +| | `cco_yield_final();` | Yield final suspend, enter cleanup-state | +| | `cco_yield_final(ret);` | Yield a final value | | | `cco_await(condition);` | Suspend until condition is true (return CCO_AWAIT)| -| | `cco_await_v(condition);` | Suspend until condition is true (return void) | -| | `cco_await_v(condition, ret);` | Suspend until condition is true (return ret)| -| | `cco_await_on(cocall);` | Await on sub-coroutine to finish (return its ret) | +| | `cco_call_await(cocall);` | Await for subcoro to finish (returns its ret value) | +| | `cco_call_await(cocall, retbit);` | Await for subcoro's return to be in (retbit \| CCO_DONE) | | | `cco_return;` | Return from coroutine (inside cco_routine) | | | Task objects: | | | | `cco_task_struct(Name, ...);` | Define a coroutine task struct | -| | `cco_task_await(task, ...);` | Await for task to finish or optionally yield a value | +| | `cco_task_await(task, cco_runtime* rt);`| Await for task to finish | +| | `cco_task_await(task, rt, retbit);` | Await for task's return to be in (retbit \| CCO_DONE) | +|`cco_result`| `cco_task_resume(task, rt);` | Resume suspended task | | | Semaphores: | | | | `cco_sem` | Semaphore type | | `cco_sem` | `cco_sem_from(long value)` | Create semaphore | | | `cco_sem_set(sem, long value)` | Set semaphore value | | | `cco_sem_await(sem)` | Await for the semaphore count > 0 | -| | `cco_sem_await(sem, ret)` | Await with ret on the semaphore | | | `cco_sem_release(sem)` | Signal the semaphore (count += 1) | | | Timers: | | | | `cco_timer` | Timer type | | | `cco_timer_await(tm, double sec)` | Await secs for timer to expire (usec prec.)| -| | `cco_timer_await(tm, double sec, ret)`| Await secs for timer with ret value | | | `cco_timer_start(tm, double sec)` | Start timer for secs duration | | | `cco_timer_restart(tm)` | Restart timer with same duration | | `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | @@ -412,10 +408,10 @@ cco_routine scope; Use `if-else-if` constructs instead. | | From caller side: | | | `void` | `cco_stop(co)` | Next call of coroutine finalizes | | `void` | `cco_reset(co)` | Reset state to initial (for reuse) | -| `void` | `cco_block_on(cocall) { }` | Run blocking until cocall is finished | -| `void` | `cco_block_on(cocall, int *result) {}`| Run blocking until cocall is finished | -| | `cco_task_block_on(task) {}` | Run blocking until task is finished | -| | `cco_task_block_on(task, rt, STACKSZ) {}`| Run blocking until task is finished | +| `void` | `cco_call_blocking(cocall) {}` | Run blocking until cocall is finished | +| `void` | `cco_call_blocking(cocall, int* outres) {}`| Run blocking until cocall is finished | +| | `cco_task_blocking(task) {}` | Run blocking until task is finished | +| | `cco_task_blocking(task, rt, STACKSZ) {}`| Run blocking until task is finished | | | Time functions: | | | `double` | `cco_time(void)` | Return secs with usec prec. since Epoch | | | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) | diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 1f9ea80d..316a8ee7 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -69,7 +69,7 @@ typedef long long _llong; #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), ((T[]){__VA_ARGS__}), sizeof(T))) #define c_LITERAL(T) (T) #endif -#define c_new_n(T, n) ((T*)malloc(sizeof(T)*(n))) +#define c_new_n(T, n) ((T*)malloc(sizeof(T)*(size_t)(n))) #define c_malloc(sz) malloc(c_i2u(sz)) #define c_calloc(n, sz) calloc(c_i2u(n), c_i2u(sz)) #define c_realloc(p, sz) realloc(p, c_i2u(sz)) diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h index f89d20af..42905744 100644 --- a/include/stc/coroutine.h +++ b/include/stc/coroutine.h @@ -83,26 +83,27 @@ typedef enum { case __LINE__:; \ } while (0) -#define cco_await(promise) cco_await_v_2(promise, CCO_AWAIT) -#define cco_await_v(...) c_MACRO_OVERLOAD(cco_await_v, __VA_ARGS__) -#define cco_await_v_1(promise) cco_await_v_2(promise, ) -#define cco_await_v_2(promise, ret) \ +#define cco_await(promise) cco_await_and_return(promise, CCO_AWAIT) +#define cco_await_v(promise) cco_await_and_return(promise, ) +#define cco_await_and_return(promise, ret) \ do { \ *_state = __LINE__; \ case __LINE__: if (!(promise)) {return ret; goto _resume;} \ } while (0) -/* cco_await_on(): assumes coroutine returns a cco_result value (int) */ -#define cco_await_on(corocall) \ +/* cco_call_await(): assumes coroutine returns a cco_result value (int) */ +#define cco_call_await(...) c_MACRO_OVERLOAD(cco_call_await, __VA_ARGS__) +#define cco_call_await_1(corocall) cco_call_await_2(corocall, CCO_DONE) +#define cco_call_await_2(corocall, resultbits) \ do { \ *_state = __LINE__; \ - case __LINE__: { int _r = corocall; if (_r != CCO_DONE) {return _r; goto _resume;} } \ + case __LINE__: { int _r = corocall; if (!(_r & ~(resultbits))) {return _r; goto _resume;} } \ } while (0) -/* cco_block_on(): assumes coroutine returns a cco_result value (int) */ -#define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__) -#define cco_block_on_1(corocall) while ((corocall) != CCO_DONE) -#define cco_block_on_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) +/* cco_call_blocking(): assumes coroutine returns a cco_result value (int) */ +#define cco_call_blocking(...) c_MACRO_OVERLOAD(cco_call_blocking, __VA_ARGS__) +#define cco_call_blocking_1(corocall) while ((corocall) != CCO_DONE) +#define cco_call_blocking_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) #define cco_cleanup \ *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP @@ -152,7 +153,7 @@ typedef struct cco_runtime { #define cco_cast_task(task) \ ((cco_task *)(task) + 0*sizeof((task)->cco_func(task, (cco_runtime*)0) + ((int*)0 == &(task)->cco_state))) -#define cco_resume(task, rt) \ +#define cco_task_resume(task, rt) \ (task)->cco_func(task, rt) #define cco_task_await(...) c_MACRO_OVERLOAD(cco_task_await, __VA_ARGS__) @@ -164,11 +165,11 @@ typedef struct cco_runtime { cco_yield_v(CCO_AWAIT); \ } while (0) -#define cco_task_block_on(...) c_MACRO_OVERLOAD(cco_task_block_on, __VA_ARGS__) -#define cco_task_block_on_1(task) cco_task_block_on_3(task, _rt, 16) -#define cco_task_block_on_3(task, rt, STACKDEPTH) \ +#define cco_task_blocking(...) c_MACRO_OVERLOAD(cco_task_blocking, __VA_ARGS__) +#define cco_task_blocking_1(task) cco_task_blocking_3(task, _rt, 16) +#define cco_task_blocking_3(task, rt, STACKDEPTH) \ for (struct { int result, top; cco_task* stack[STACKDEPTH]; } rt = {.stack={cco_cast_task(task)}}; \ - (((rt.result = cco_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & ~rt.stack[rt.top]->cco_expect) || --rt.top >= 0); ) + (((rt.result = cco_task_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & ~rt.stack[rt.top]->cco_expect) || --rt.top >= 0); ) /* * Semaphore @@ -176,12 +177,11 @@ typedef struct cco_runtime { typedef struct { intptr_t count; } cco_sem; -#define cco_sem_await(sem) cco_sem_await_v_2(sem, CCO_AWAIT) -#define cco_sem_await_v(...) c_MACRO_OVERLOAD(cco_sem_await_v, __VA_ARGS__) -#define cco_sem_await_v_1(sem) cco_sem_await_v_2(sem, ) -#define cco_sem_await_v_2(sem, ret) \ +#define cco_sem_await(sem) cco_sem_await_and_return(sem, CCO_AWAIT) +#define cco_sem_await_v(sem) cco_sem_await_and_return(sem, ) +#define cco_sem_await_and_return(sem, ret) \ do { \ - cco_await_v_2((sem)->count > 0, ret); \ + cco_await_and_return((sem)->count > 0, ret); \ --(sem)->count; \ } while (0) @@ -241,7 +241,7 @@ typedef struct { double interval, start; } cco_timer; #define cco_timer_await_v_3(tm, sec, ret) \ do { \ cco_timer_start(tm, sec); \ - cco_await_v_2(cco_timer_expired(tm), ret); \ + cco_await_and_return(cco_timer_expired(tm), ret); \ } while (0) static inline void cco_timer_start(cco_timer* tm, double sec) { diff --git a/misc/examples/coroutines/cointerleave.c b/misc/examples/coroutines/cointerleave.c index ea0d4dac..f3710ba3 100644 --- a/misc/examples/coroutines/cointerleave.c +++ b/misc/examples/coroutines/cointerleave.c @@ -49,7 +49,7 @@ void Use(void) struct Generator g = {{&a}, {&b}}; - cco_block_on(interleaved(&g)) { + cco_call_blocking(interleaved(&g)) { printf("%d ", g.value); } puts(""); diff --git a/misc/examples/coroutines/coread.c b/misc/examples/coroutines/coread.c index 56248108..ebaaf19d 100644 --- a/misc/examples/coroutines/coread.c +++ b/misc/examples/coroutines/coread.c @@ -33,7 +33,7 @@ int main(void) { struct file_read g = {__FILE__}; int n = 0; - cco_block_on(file_read(&g)) + cco_call_blocking(file_read(&g)) { printf("%3d %s\n", ++n, cstr_str(&g.line)); //if (n == 10) cco_stop(&g); diff --git a/misc/examples/coroutines/coroutines.c b/misc/examples/coroutines/coroutines.c index de0fcda5..489c3ed6 100644 --- a/misc/examples/coroutines/coroutines.c +++ b/misc/examples/coroutines/coroutines.c @@ -84,13 +84,13 @@ struct combined { int combined(struct combined* g) { cco_routine(g) { - cco_await_on(prime(&g->prm)); - cco_await_on(fibonacci(&g->fib)); + cco_call_await(prime(&g->prm)); + cco_call_await(fibonacci(&g->fib)); // Reuse the g->prm context and extend the count: g->prm.count = 8, g->prm.result += 2; cco_reset(&g->prm); - cco_await_on(prime(&g->prm)); + cco_call_await(prime(&g->prm)); cco_cleanup: puts("final combined"); @@ -103,7 +103,7 @@ int main(void) struct combined c = {.prm={.count=8}, .fib={14}}; int res; - cco_block_on(combined(&c), &res) { + cco_call_blocking(combined(&c), &res) { if (res == CCO_YIELD) printf("Prime(%d)=%lld, Fib(%d)=%lld\n", c.prm.idx, c.prm.result, diff --git a/misc/examples/coroutines/cotasks1.c b/misc/examples/coroutines/cotasks1.c index 27999ccf..e4afbe2b 100644 --- a/misc/examples/coroutines/cotasks1.c +++ b/misc/examples/coroutines/cotasks1.c @@ -88,7 +88,7 @@ int main(void) struct consume_items consume = {.n=5}; int count = 0; - cco_block_on(consume_items(&consume, &produce)) + cco_call_blocking(consume_items(&consume, &produce)) { ++count; //cco_sleep(0.001); diff --git a/misc/examples/coroutines/cotasks2.c b/misc/examples/coroutines/cotasks2.c index 9ca69bda..24a9f23f 100644 --- a/misc/examples/coroutines/cotasks2.c +++ b/misc/examples/coroutines/cotasks2.c @@ -77,7 +77,7 @@ int consume_items(struct consume_items* c, cco_runtime* rt) } cco_cleanup: cco_stop(&c->produce); - cco_resume(&c->produce, rt); + cco_task_resume(&c->produce, rt); puts("done consume"); } return 0; @@ -92,7 +92,7 @@ int main(void) }; int count = 0; - cco_task_block_on(&consume) + cco_task_blocking(&consume) { ++count; //cco_sleep(0.001); diff --git a/misc/examples/smartpointers/map_box.c b/misc/examples/smartpointers/map_box.c new file mode 100644 index 00000000..f651b302 --- /dev/null +++ b/misc/examples/smartpointers/map_box.c @@ -0,0 +1,34 @@ +#include +#include +#define i_implement +#include + +#define i_type IBox +#define i_key long +#include // unique_ptr alike. + +// cmap of cstr => IBox +#define i_type Boxmap +#define i_key_str +#define i_valboxed IBox // i_valboxed: use properties from IBox automatically +#include + + +int main(void) +{ + Boxmap map = {0}; + + puts("Map cstr => IBox:"); + Boxmap_insert(&map, cstr_from("Test1"), IBox_make(1)); + Boxmap_insert(&map, cstr_from("Test2"), IBox_make(2)); + + // Simpler: emplace() implicitly creates cstr from const char* and IBox from long! + Boxmap_emplace(&map, "Test3", 3); + Boxmap_emplace(&map, "Test4", 4); + + c_forpair (name, number, Boxmap, map) + printf("%s: %ld\n", cstr_str(_.name), *_.number->get); + puts(""); + + Boxmap_drop(&map); +} diff --git a/misc/examples/smartpointers/map_ptr.c b/misc/examples/smartpointers/map_ptr.c new file mode 100644 index 00000000..453322c5 --- /dev/null +++ b/misc/examples/smartpointers/map_ptr.c @@ -0,0 +1,34 @@ +#include +#include +#define i_implement +#include + +// cmap of cstr => long* +#define i_type Ptrmap +#define i_key_str +#define i_val long* +#define i_valraw long +#define i_valfrom(raw) c_new(long, raw) +#define i_valto(x) **x +#define i_valclone(x) c_new(long, *x) +#define i_valdrop(x) c_free(*x) +#include + +int main(void) +{ + Ptrmap map = {0}; + + puts("Map cstr => long*:"); + Ptrmap_insert(&map, cstr_from("Test1"), c_new(long, 1)); + Ptrmap_insert(&map, cstr_from("Test2"), c_new(long, 2)); + + // Simple: emplace() implicitly creates cstr from const char* and an owned long* from long! + Ptrmap_emplace(&map, "Test3", 3); + Ptrmap_emplace(&map, "Test4", 4); + + c_forpair (name, number, Ptrmap, map) + printf("%s: %ld\n", cstr_str(_.name), **_.number); + puts(""); + + Ptrmap_drop(&map); +} diff --git a/misc/examples/smartpointers/rawptr_elements.c b/misc/examples/smartpointers/rawptr_elements.c deleted file mode 100644 index 694ce12e..00000000 --- a/misc/examples/smartpointers/rawptr_elements.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#define i_implement -#include - -// Create cmap of cstr => long* -#define i_type SIPtrMap -#define i_key_str -#define i_val long* -#define i_valraw long -#define i_valfrom(raw) c_new(long, raw) -#define i_valto(x) **x -#define i_valclone(x) c_new(long, *x) -#define i_valdrop(x) c_free(*x) -#include - -// Alternatively, using cbox: -#define i_type IBox -#define i_key long -#include // unique_ptr alike. - -// cmap of cstr => IBox -#define i_type SIBoxMap -#define i_key_str -#define i_valboxed IBox // i_valboxed: use properties from IBox automatically -#include - -int main(void) -{ - // These have the same behaviour, except IBox has a get member: - SIPtrMap map1 = {0}; - SIBoxMap map2 = {0}; - - printf("\nMap cstr => long*:\n"); - SIPtrMap_insert(&map1, cstr_from("Test1"), c_new(long, 1)); - SIPtrMap_insert(&map1, cstr_from("Test2"), c_new(long, 2)); - - // Emplace implicitly creates cstr from const char* and an owned long* from long! - SIPtrMap_emplace(&map1, "Test3", 3); - SIPtrMap_emplace(&map1, "Test4", 4); - - c_forpair (name, number, SIPtrMap, map1) - printf("%s: %ld\n", cstr_str(_.name), **_.number); - - puts("\nMap cstr => IBox:"); - SIBoxMap_insert(&map2, cstr_from("Test1"), IBox_make(1)); - SIBoxMap_insert(&map2, cstr_from("Test2"), IBox_make(2)); - - // Emplace implicitly creates cstr from const char* and IBox from long! - SIBoxMap_emplace(&map2, "Test3", 3); - SIBoxMap_emplace(&map2, "Test4", 4); - - c_forpair (name, number, SIBoxMap, map2) - printf("%s: %ld\n", cstr_str(_.name), *_.number->get); - puts(""); - - SIPtrMap_drop(&map1); - SIBoxMap_drop(&map2); -} diff --git a/misc/examples/spans/mdspan.c b/misc/examples/spans/mdspan.c index 4427299c..db601850 100644 --- a/misc/examples/spans/mdspan.c +++ b/misc/examples/spans/mdspan.c @@ -12,17 +12,17 @@ int main(void) { DSpan3 ms = cspan_md_order('F', data, nx, ny, nz); // Fortran, not 'C' int idx = 0; - c_forrange (i, ms.shape[0]) - c_forrange (j, ms.shape[1]) - c_forrange (k, ms.shape[2]) + for (int i = 0; i < ms.shape[0]; ++i) + for (int j = 0; j < ms.shape[1]; ++j) + for (int k = 0; k < ms.shape[2]; ++k) *cspan_at(&ms, i, j, k) = ++idx; cspan_transpose(&ms); printf(", transposed:\n\n"); - c_forrange (i, ms.shape[0]) { - c_forrange (j, ms.shape[1]) { - c_forrange (k, ms.shape[2]) + for (int i = 0; i < ms.shape[0]; ++i) { + for (int j = 0; j < ms.shape[1]; ++j) { + for (int k = 0; k < ms.shape[2]; ++k) printf(" %3g", *cspan_at(&ms, i, j, k)); puts(""); } -- cgit v1.2.3 From 2d33308d36063f3726f3652b0b0cbe3668b8bc68 Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 21 Aug 2023 18:31:49 +0200 Subject: Changed 'order' to 'layout' in cspan md. Neigher the 'C' / 'F' convension from python, nor left / right from std::mdspan are great names => changed to c_ROWMAJOR / c_COLMAJOR like in matlab. --- docs/cspan_api.md | 18 +++++++++++------- include/stc/cspan.h | 23 ++++++++++++++--------- misc/examples/spans/matmult.c | 4 ++-- misc/examples/spans/mdspan.c | 2 +- 4 files changed, 28 insertions(+), 19 deletions(-) (limited to 'misc/examples/spans/mdspan.c') diff --git a/docs/cspan_api.md b/docs/cspan_api.md index 39b97473..c3556dc3 100644 --- a/docs/cspan_api.md +++ b/docs/cspan_api.md @@ -44,12 +44,15 @@ SpanTypeN_iter SpanType_begin(const SpanTypeN* self); SpanTypeN_iter SpanType_end(const SpanTypeN* self); void SpanType_next(SpanTypeN_iter* it); -SpanTypeN cspan_md(ValueType* data, d1, d2, ...); // make a multi-dim cspan, row-major order. -SpanTypeN cspan_md_order(char order, ValueType* data, d1, d2, ...); // order='C': row-major, 'F': column-major (FORTRAN). + // make a multi-dim cspan +SpanTypeN cspan_md(ValueType* data, d1, d2, ...); // row-major +SpanTypeN cspan_md_layout(cspan_layout layout, ValueType* data, d1, d2, ...); - // transpose a md span (inverse axes). No changes to the underlying array. + // transpose a md span. Inverses layout and axes only. void cspan_transpose(const SpanTypeN* self); -bool cspan_is_order_F(const SpanTypeN* self); +cspan_layout cspan_get_layout(const SpanTypeN* self); +bool cspan_is_rowmajor(const SpanTypeN* self); +bool cspan_is_colmajor(const SpanTypeN* self); // create a subspan of input span rank. Like e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL}); SpanType cspan_subspan(const SpanType* span, intptr_t offset, intptr_t count); @@ -70,8 +73,9 @@ OutSpanN cspan_slice(TYPE OutSpanN, const SpanTypeM* parent, {x0,x1}, {y0 |:------------------|:----------------------------------------------------|:---------------------| | SpanTypeN | `struct { ValueType *data; uint32_t shape[N]; .. }` | SpanType with rank N | | SpanTypeN`_value` | `ValueType` | The ValueType | -| `c_ALL` | Use with `cspan_slice()`. | Full extent | -| `c_END` | " | End of extent | +| `c_ALL` | `cspan_slice(&md, {1,3}, {c_ALL})` | Full extent | +| `c_END` | `cspan_slice(&md, {1,c_END}, {2,c_END})` | End of extent | +| `cspan_layout` | `enum { c_ROWMAJOR, c_COLMAJOR }` | Multi-dim layout | ## Example 1 @@ -182,7 +186,7 @@ void print_span(myspan2 ms) { int main(void) { 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_order('C', arr, 2, 3, 4); // row-major ('F' column-major) + myspan3 ms3 = cspan_md(arr, 2, 3, 4); // row-major layout myspan3 ss3 = cspan_slice(myspan3, &ms3, {c_ALL}, {0,3}, {2,c_END}); myspan2 a = cspan_submd3(&ss3, 1); myspan2 b = a; diff --git a/include/stc/cspan.h b/include/stc/cspan.h index 6f8de8ec..f9f3b02a 100644 --- a/include/stc/cspan.h +++ b/include/stc/cspan.h @@ -98,7 +98,7 @@ int demo2() { } \ STC_INLINE void Self##_next(Self##_iter* it) { \ int i, inc, done; \ - if (it->_s->stride.d[0] < it->_s->stride.d[RANK - 1]) i=0, inc=1; else i=RANK-1, inc=-1; \ + if (cspan_is_colmajor(it->_s)) i=0, inc=1; else i=RANK-1, inc=-1; \ it->ref += _cspan_next##RANK(it->pos, it->_s->shape, it->_s->stride.d, RANK, i, inc, &done); \ if (done) it->ref = NULL; \ } \ @@ -115,6 +115,7 @@ using_cspan_tuple(7); using_cspan_tuple(8); #define c_END -1 #define c_ALL 0,c_END +typedef enum {c_ROWMAJOR, c_COLMAJOR} cspan_layout; /* Use cspan_init() for static initialization only. c_init() for non-static init. */ #define cspan_init(SpanType, ...) \ @@ -132,7 +133,9 @@ using_cspan_tuple(7); using_cspan_tuple(8); #define cspan_size(self) _cspan_size((self)->shape, cspan_rank(self)) #define cspan_rank(self) c_arraylen((self)->shape) -#define cspan_is_order_F(self) ((self)->stride.d[0] < (self)->stride.d[cspan_rank(self) - 1]) +#define cspan_is_colmajor(self) ((self)->stride.d[0] < (self)->stride.d[cspan_rank(self) - 1]) +#define cspan_is_rowmajor(self) (!cspan_is_colmajor(self)) +#define cspan_get_layout(self) (cspan_is_colmajor(self) ? c_COLMAJOR : c_ROWMAJOR) #define cspan_index(self, ...) c_PASTE(cspan_idx_, c_NUMARGS(__VA_ARGS__))(self, __VA_ARGS__) #define cspan_at(self, ...) ((self)->data + cspan_index(self, __VA_ARGS__)) #define cspan_front(self) ((self)->data) @@ -165,10 +168,10 @@ using_cspan_tuple(7); using_cspan_tuple(8); #define cspan_submd4_4(self, x, y, z) \ {.data=cspan_at(self, x, y, z, 0), .shape={(self)->shape[3]}, .stride=(cspan_tuple1){.d={(self)->stride.d[3]}}} -#define cspan_md(array, ...) cspan_md_order('C', array, __VA_ARGS__) -#define cspan_md_order(order, array, ...) /* order='C' or 'F' */ \ +#define cspan_md(array, ...) cspan_md_layout(c_ROWMAJOR, array, __VA_ARGS__) +#define cspan_md_layout(layout, array, ...) \ {.data=array, .shape={__VA_ARGS__}, \ - .stride=*(c_PASTE(cspan_tuple, c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(order, ((int32_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} + .stride=*(c_PASTE(cspan_tuple, c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(layout, ((int32_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))} #define cspan_transpose(self) \ _cspan_transpose((self)->shape, (self)->stride.d, cspan_rank(self)) @@ -225,7 +228,7 @@ STC_INLINE intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t s } STC_API intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc, int* done); -#define _cspan_next1(pos, shape, stride, rank, i, inc, done) (*done = ++pos[0]==shape[0], stride[0]) +#define _cspan_next1(pos, shape, stride, rank, i, inc, done) (*done = ++pos[0]==shape[0], (void)(i|inc), stride[0]) #define _cspan_next3 _cspan_next2 #define _cspan_next4 _cspan_next2 #define _cspan_next5 _cspan_next2 @@ -237,7 +240,7 @@ STC_API intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, const int32_t shape[], const int32_t stride[], int rank, const int32_t a[][2]); -STC_API int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank); +STC_API int32_t* _cspan_shape2stride(cspan_layout layout, int32_t shape[], int rank); #endif // STC_CSPAN_H_INCLUDED /* --------------------- IMPLEMENTATION --------------------- */ @@ -246,6 +249,7 @@ STC_API int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank); STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_t stride[], int rank, int i, int inc, int* done) { intptr_t off = stride[i]; ++pos[i]; + while (--rank && pos[i] == shape[i]) { pos[i] = 0; ++pos[i + inc]; off += stride[i + inc] - stride[i]*shape[i]; @@ -255,9 +259,9 @@ STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const int32_ return off; } -STC_DEF int32_t* _cspan_shape2stride(char order, int32_t shape[], int rank) { +STC_DEF int32_t* _cspan_shape2stride(cspan_layout layout, int32_t shape[], int rank) { int i, inc; - if (order == 'F') i = 0, inc = 1; + if (layout == c_COLMAJOR) i = 0, inc = 1; else i = rank - 1, inc = -1; int32_t k = 1, s1 = shape[i], s2; @@ -277,6 +281,7 @@ STC_DEF intptr_t _cspan_slice(int32_t oshape[], int32_t ostride[], int* orank, intptr_t off = 0; int i = 0, oi = 0; int32_t end; + for (; i < rank; ++i) { off += stride[i]*a[i][0]; switch (a[i][1]) { diff --git a/misc/examples/spans/matmult.c b/misc/examples/spans/matmult.c index 35dad7a9..266fa121 100644 --- a/misc/examples/spans/matmult.c +++ b/misc/examples/spans/matmult.c @@ -70,8 +70,8 @@ int main(void) Values_push(&values, (crandf() - 0.5)*4.0); double out[D1*D2]; - Mat3 data = cspan_md_order('C', values.data, N, D1, D2); - OutMat c = cspan_md_order('C', out, D1, D2); + Mat3 data = cspan_md_layout(c_ROWMAJOR, values.data, N, D1, D2); + OutMat c = cspan_md_layout(c_ROWMAJOR, out, D1, D2); Mat2 a = cspan_submd3(&data, 0); double sum = 0.0; clock_t t = clock(); diff --git a/misc/examples/spans/mdspan.c b/misc/examples/spans/mdspan.c index db601850..630ffddb 100644 --- a/misc/examples/spans/mdspan.c +++ b/misc/examples/spans/mdspan.c @@ -9,7 +9,7 @@ int main(void) { double* data = c_new_n(double, nx*ny*nz); printf("\nMultidim span ms[5, 4, 3], fortran ordered"); - DSpan3 ms = cspan_md_order('F', data, nx, ny, nz); // Fortran, not 'C' + DSpan3 ms = cspan_md_layout(c_COLMAJOR, data, nx, ny, nz); int idx = 0; for (int i = 0; i < ms.shape[0]; ++i) -- cgit v1.2.3