-
-
Save Ronsor/66ee016470fcb12231cd68c1647597f4 to your computer and use it in GitHub Desktop.
Simple coroutine library for C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Coroutines for C | |
| * | |
| * Copyright (C) 2025 Ronsor Labs. All rights reserved. | |
| * | |
| * Anyone is free to use, copy, modify, or distribute this software for any | |
| * purpose as long as this notice appears in all copies. This software is | |
| * provided "as is" without any warranty, and the author will not be liable for | |
| * any damages related to this software. | |
| */ | |
| #ifndef CO_H | |
| #define CO_H | |
| #define _(...) __VA_ARGS__ | |
| #define co_type(name) struct co_state_##name##_ | |
| #define co_new(name, ...) ((co_type(name)) { 0, { __VA_ARGS__ }, {} }) | |
| #define co_yield_(n) { _s->pc = n; return 1; case n:; } | |
| #define co_ckpt_(n) { _s->pc = n; case n:; } | |
| #if defined(__GNUC__) || defined(__clang__) || defined(__TINYC__) | |
| #define co_yield() co_yield_(__COUNTER__+1) | |
| #define co_ckpt() co_ckpt_(__COUNTER__+1) | |
| #else | |
| #define co_yield() co_yield_(__LINE__) | |
| #define co_ckpt() co_ckpt_(__LINE__) | |
| #endif | |
| #define co_await(ctx, name, ...) \ | |
| { \ | |
| ctx = co_new(name, __VA_ARGS__); \ | |
| while (name(&ctx)) { co_yield(); } \ | |
| } | |
| #define co_args() _s->args | |
| #define co_vars() _s->locals | |
| #define co_arg(name) co_args().name | |
| #define co_var(name) co_vars().name | |
| #define $arg(name) co_arg(name) | |
| #define $(name) co_var(name) | |
| #define co(name, args_, locals_, body_) \ | |
| co_type(name) { \ | |
| int pc; \ | |
| struct args_ args; \ | |
| struct locals_ locals; \ | |
| }; \ | |
| int name(co_type(name) *_s) { \ | |
| switch (_s->pc) { \ | |
| case 0: \ | |
| body_; \ | |
| co_ckpt(); \ | |
| } \ | |
| return 0; \ | |
| } | |
| #ifdef CO_TEST | |
| #include <stdio.h> | |
| co(simple_rng, _({ unsigned int s; }), _({}), _({ | |
| while (1) { | |
| $arg(s) >>= 5; | |
| $arg(s) *= 94712; | |
| $arg(s) &= 0xffff; | |
| co_yield(); | |
| } | |
| })) | |
| co(rng_printer, _({ | |
| const char *prefix; | |
| unsigned int s; | |
| }), _({ | |
| char str[64]; | |
| co_type(simple_rng) rng; | |
| }), _({ | |
| $(rng) = co_new(simple_rng, $arg(s)); | |
| while (1) { | |
| simple_rng(&$(rng)); | |
| sprintf($(str), "%s%u", $arg(prefix) ? $arg(prefix) : "", $(rng).args.s); | |
| co_yield(); | |
| } | |
| })) | |
| int main() { | |
| co_type(rng_printer) printer = co_new(rng_printer, "rng: ", 42); | |
| for (int i = 0; i < 10; i++) { | |
| rng_printer(&printer); | |
| puts(printer.locals.str); | |
| } | |
| } | |
| #endif | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment