summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authortylov <[email protected]>2023-07-21 10:49:45 +0200
committertylov <[email protected]>2023-07-21 10:49:45 +0200
commitdbcc13635402bd466675f4f41e865d02abc6f918 (patch)
tree269bbb8e641aaad34b0cca0bbd23c854faa3a960
parent2d67f4040f6eecd41f1b864b43c62823ed75aff0 (diff)
downloadSTC-modified-dbcc13635402bd466675f4f41e865d02abc6f918.tar.gz
STC-modified-dbcc13635402bd466675f4f41e865d02abc6f918.zip
NB! Changed some coroutine API for consistency/simplicity: Added full task support.
-rw-r--r--docs/ccommon_api.md30
-rw-r--r--include/stc/ccommon.h2
-rw-r--r--include/stc/coroutine.h44
-rw-r--r--misc/examples/coroutines/cointerleave.c2
-rw-r--r--misc/examples/coroutines/coread.c2
-rw-r--r--misc/examples/coroutines/coroutines.c8
-rw-r--r--misc/examples/coroutines/cotasks1.c2
-rw-r--r--misc/examples/coroutines/cotasks2.c4
-rw-r--r--misc/examples/smartpointers/map_box.c34
-rw-r--r--misc/examples/smartpointers/map_ptr.c34
-rw-r--r--misc/examples/smartpointers/rawptr_elements.c59
-rw-r--r--misc/examples/spans/mdspan.c12
12 files changed, 119 insertions, 114 deletions
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 <stc/ccommon.h>
+#include <stdio.h>
+#define i_implement
+#include <stc/cstr.h>
+
+#define i_type IBox
+#define i_key long
+#include <stc/cbox.h> // unique_ptr<long> 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 <stc/cmap.h>
+
+
+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 <stc/ccommon.h>
+#include <stdio.h>
+#define i_implement
+#include <stc/cstr.h>
+
+// 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 <stc/cmap.h>
+
+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 <stc/ccommon.h>
-#include <stdio.h>
-#define i_implement
-#include <stc/cstr.h>
-
-// 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 <stc/cmap.h>
-
-// Alternatively, using cbox:
-#define i_type IBox
-#define i_key long
-#include <stc/cbox.h> // unique_ptr<long> 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 <stc/cmap.h>
-
-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("");
}