diff options
| author | tylov <[email protected]> | 2023-07-21 00:37:28 +0200 |
|---|---|---|
| committer | tylov <[email protected]> | 2023-07-21 00:37:28 +0200 |
| commit | 2d67f4040f6eecd41f1b864b43c62823ed75aff0 (patch) | |
| tree | 084ce603dc4edfa1ccad3aabab5b671a817bc67e /include/stc/algo/coroutine.h | |
| parent | 900295256d825fc323149cd223c49787f32a3696 (diff) | |
| download | STC-modified-2d67f4040f6eecd41f1b864b43c62823ed75aff0.tar.gz STC-modified-2d67f4040f6eecd41f1b864b43c62823ed75aff0.zip | |
Renamed badly abbreviated names in crand.h.
Moved coroutine.h from algo subfolder to stc.
Updated coroutine.h and docs.
Diffstat (limited to 'include/stc/algo/coroutine.h')
| -rw-r--r-- | include/stc/algo/coroutine.h | 274 |
1 files changed, 0 insertions, 274 deletions
diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h deleted file mode 100644 index 7c6989c3..00000000 --- a/include/stc/algo/coroutine.h +++ /dev/null @@ -1,274 +0,0 @@ -/* MIT License - * - * Copyright (c) 2023 Tyge Løvset - * - * 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 STC_COROUTINE_INCLUDED -#define STC_COROUTINE_INCLUDED -/* -#include <stdio.h> -#include <stc/algo/coroutine.h> - -struct iterpair { - int max_x, max_y; - int x, y; - int cco_state; // required member -}; - -int iterpair(struct iterpair* I) { - cco_routine(I) { - for (I->x = 0; I->x < I->max_x; I->x++) - for (I->y = 0; I->y < I->max_y; I->y++) - cco_yield(); - - cco_cleanup: // required if there is cleanup code - puts("final"); - } - return 0; // CCO_DONE -} - -int main(void) { - struct iterpair it = {.max_x=3, .max_y=3}; - int n = 0; - while (iterpair(&it)) - { - printf("%d %d\n", it.x, it.y); - // example of early stop: - if (++n == 7) cco_stop(&it); // signal to stop/finalize in next - } - return 0; -} -*/ -#include "../ccommon.h" - -enum { - CCO_STATE_CLEANUP = -1, - CCO_STATE_DONE = -2, -}; -typedef enum { - CCO_DONE = 0, - CCO_AWAIT = 1<<0, - CCO_YIELD = 1<<1, -} cco_result; - -#define cco_initial(co) ((co)->cco_state == 0) -#define cco_suspended(co) ((co)->cco_state > 0) -#define cco_done(co) ((co)->cco_state == CCO_STATE_DONE) - -#define cco_routine(co) \ - for (int *_state = &(co)->cco_state; *_state != CCO_STATE_DONE; *_state = CCO_STATE_DONE) \ - _resume: switch (*_state) case 0: // thanks, @liigo! - -#define cco_yield() cco_yield_v(CCO_YIELD) -#define cco_yield_v(ret) \ - do { \ - *_state = __LINE__; return ret; goto _resume; \ - 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) \ - 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) \ - do { \ - *_state = __LINE__; \ - case __LINE__: { int _r = corocall; if (_r != CCO_DONE) {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) - -#define cco_cleanup \ - *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP - -#define cco_return \ - do { \ - *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ - goto _resume; \ - } while (0) - -#define cco_yield_final() cco_yield_final_v(CCO_YIELD) -#define cco_yield_final_v(value) \ - do { \ - *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ - return value; \ - } while (0) - -#define cco_stop(co) \ - do { \ - int* _s = &(co)->cco_state; \ - if (*_s > 0) *_s = CCO_STATE_CLEANUP; \ - else if (*_s == 0) *_s = CCO_STATE_DONE; \ - } while (0) - -#define cco_reset(co) \ - (void)((co)->cco_state = 0) - -/* - * Tasks (optional) - */ - -struct cco_runtime; - -#define cco_task_struct(Name, ...) \ - struct Name { \ - int (*cco_fn)(struct Name*, struct cco_runtime*); \ - int cco_state, cco_expect; \ - __VA_ARGS__ \ - } - -typedef cco_task_struct(cco_task, /**/) cco_task; - -typedef struct cco_runtime { - int result, top; - cco_task* stack[]; -} cco_runtime; - -#define cco_cast_task(task) \ - ((cco_task *)(task) + 0*sizeof((task)->cco_fn(task, (cco_runtime*)0) + ((int*)0 == &(task)->cco_state))) - -#define cco_resume(task, rt) \ - (task)->cco_fn(task, rt) - -#define cco_block_task(...) c_MACRO_OVERLOAD(cco_block_task, __VA_ARGS__) -#define cco_block_task_1(task) cco_block_task_3(task, rt, 16) -#define cco_block_task_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); ) - -#define cco_await_task(...) c_MACRO_OVERLOAD(cco_await_task, __VA_ARGS__) -#define cco_await_task_2(task, rt) cco_await_task_3(task, rt, CCO_DONE) -#define cco_await_task_3(task, rt, resultbits) \ - do { \ - cco_runtime* _rt = rt; \ - (_rt->stack[++_rt->top] = cco_cast_task(task))->cco_expect = ~(resultbits); \ - cco_yield_v(CCO_AWAIT); \ - } while (0) - -/* - * Semaphore - */ - -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) \ - do { \ - cco_await_v_2((sem)->count > 0, ret); \ - --(sem)->count; \ - } while (0) - -#define cco_sem_release(sem) ++(sem)->count -#define cco_sem_from(value) ((cco_sem){value}) -#define cco_sem_set(sem, value) ((sem)->count = value) - -/* - * Timer - */ - -#ifdef _WIN32 - #ifdef __cplusplus - #define _c_LINKC extern "C" __declspec(dllimport) - #else - #define _c_LINKC __declspec(dllimport) - #endif - #if 1 // _WIN32_WINNT < _WIN32_WINNT_WIN8 || defined __TINYC__ - #define _c_getsystime GetSystemTimeAsFileTime - #else - #define _c_getsystime GetSystemTimePreciseAsFileTime - #endif - struct _FILETIME; - _c_LINKC void _c_getsystime(struct _FILETIME*); - _c_LINKC void Sleep(unsigned long); - - static inline double cco_time(void) { /* seconds since epoch */ - unsigned long long quad; /* 64-bit value representing 1/10th usecs since Jan 1 1601, 00:00 UTC */ - _c_getsystime((struct _FILETIME*)&quad); - return (double)(quad - 116444736000000000ULL)*1e-7; /* time diff Jan 1 1601-Jan 1 1970 in 1/10th usecs */ - } - - static inline void cco_sleep(double sec) { - Sleep((unsigned long)(sec*1000.0)); - } -#else - #include <sys/time.h> - static inline double cco_time(void) { /* seconds since epoch */ - struct timeval tv; - gettimeofday(&tv, NULL); - return (double)tv.tv_sec + (double)tv.tv_usec*1e-6; - } - - static inline void cco_sleep(double sec) { - struct timeval tv; - tv.tv_sec = (time_t)sec; - tv.tv_usec = (suseconds_t)((sec - (double)(long)sec)*1e6); - select(0, NULL, NULL, NULL, &tv); - } -#endif - -typedef struct { double interval, start; } cco_timer; - -#define cco_timer_await(tm, sec) cco_timer_await_v_3(tm, sec, CCO_AWAIT) -#define cco_timer_await_v(...) c_MACRO_OVERLOAD(cco_timer_await_v, __VA_ARGS__) -#define cco_timer_await_v_2(tm, sec) cco_timer_await_v_3(tm, sec, ) -#define cco_timer_await_v_3(tm, sec, ret) \ - do { \ - cco_timer_start(tm, sec); \ - cco_await_v_2(cco_timer_expired(tm), ret); \ - } while (0) - -static inline void cco_timer_start(cco_timer* tm, double sec) { - tm->interval = sec; - tm->start = cco_time(); -} - -static inline cco_timer cco_timer_from(double sec) { - cco_timer tm = {.interval=sec, .start=cco_time()}; - return tm; -} - -static inline void cco_timer_restart(cco_timer* tm) { - tm->start = cco_time(); -} - -static inline bool cco_timer_expired(cco_timer* tm) { - return cco_time() - tm->start >= tm->interval; -} - -static inline double cco_timer_elapsed(cco_timer* tm) { - return cco_time() - tm->start; -} - -static inline double cco_timer_remaining(cco_timer* tm) { - return tm->start + tm->interval - cco_time(); -} - -#endif |
