Skip to content

Instantly share code, notes, and snippets.

@bakerface
Created April 25, 2022 11:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bakerface/8fe2499c79e3284fa97c1ee07e960271 to your computer and use it in GitHub Desktop.
Save bakerface/8fe2499c79e3284fa97c1ee07e960271 to your computer and use it in GitHub Desktop.
A single-file coroutine implementation in pure C
/**
* Copyright (c) 2022 Chris Baker
*
* 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 __CO_H__
#define __CO_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned int co_t;
#define co_init(co) ((*(co)) = 0)
#define co_routine(co) \
switch (*(co)) \
case 0: \
if ((*(co) = -1))
#define co_yield(co) \
if (!(*(co) = __LINE__)) { \
case __LINE__: \
*(co) = -1; \
} else if (*(co) == __LINE__)
#ifdef __cplusplus
}
#endif
#ifdef CO_TEST
#include "mocha.h"
static void co_test_return_void(co_t *co, int *out) {
co_routine(co) {
/* single-statement yield */
*out = 0;
co_yield(co) return;
/* multi-statement yield */
co_yield(co) {
*out = 1;
return;
}
}
*out = 2;
return;
}
static int co_test_return_int(co_t *co) {
co_routine(co) {
co_yield(co) return 0;
co_yield(co) return 1;
}
return 2;
}
static void co_test(mocha_t *mocha) {
co_t co;
mocha_describe(mocha, "co") {
mocha_before_each(mocha) {
co_init(&co);
}
mocha_after_each(mocha) {
/* no cleanup */
}
mocha_it(mocha, "can yield return void") {
int out;
co_test_return_void(&co, &out);
mocha_assert(mocha, out == 0);
co_test_return_void(&co, &out);
mocha_assert(mocha, out == 1);
co_test_return_void(&co, &out);
mocha_assert(mocha, out == 2);
co_test_return_void(&co, &out);
mocha_assert(mocha, out == 2);
}
mocha_it(mocha, "can yield return a value") {
mocha_assert(mocha, co_test_return_int(&co) == 0);
mocha_assert(mocha, co_test_return_int(&co) == 1);
mocha_assert(mocha, co_test_return_int(&co) == 2);
mocha_assert(mocha, co_test_return_int(&co) == 2);
}
}
}
#endif /* CO_TEST */
#endif /* __CO_H__ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment