ポータブルなコルーチンライブラリ
が書けた!
#include <assert.h> #include <boost/preprocessor.hpp> #define GOTOC_CASE_GOTO_(Z, I, DATA) \ case BOOST_PP_ADD(I, 1): \ goto BOOST_PP_CAT(gotoc_label_, BOOST_PP_ADD(I, 1)); #define GOTOC_FUNC(NUM) \ static int gotoc_call_cnt_ = 0; \ switch (gotoc_call_cnt_) { \ case 0: \ break; \ BOOST_PP_REPEAT(NUM, GOTOC_CASE_GOTO_, dummy) \ default: \ assert(false); \ } #define GOTOC_YIELD(NUM) \ gotoc_call_cnt_ = NUM; \ return; \ BOOST_PP_CAT(gotoc_label_, NUM) :
不穏な感じ。使用例は以下のように。
#include <stdio.h> void coro1() { static int i = 0; /* cannot save local variable! */ GOTOC_FUNC(3); printf("coro1 1\n"); GOTOC_YIELD(1); printf("coro1 2\n"); for (i = 0; i < 2; i++) { GOTOC_YIELD(2); printf("coro1 3\n"); } GOTOC_YIELD(3); printf("coro1 4\n"); } void coro2() { GOTOC_FUNC(3); printf("coro2 1\n"); GOTOC_YIELD(1); printf("coro2 2\n"); GOTOC_YIELD(2); printf("coro2 3\n"); GOTOC_YIELD(3); printf("coro2 4\n"); } int main() { coro1(); coro2(); coro1(); coro2(); coro1(); coro2(); coro1(); coro2(); coro1(); return 0; }
ようするに入った回数覚えておいて進んだところまですっとばしてやろうというネタ。 GOTOC_FUNC(NUM) で NUM 個の YIELD があることを示しておいて、 GOTOC_YIELD(NUM) で NUM 番目の復帰位置であることを宣言します。もちろんスタックとか忘れてるので local 変数じゃなくて static 変数を使いましょう。
GOTOC_FUNC と GOTOC_YIELD に数字渡さにゃならんのがダメなところ。
void coro2() { #include GOTOC_INIT printf("coro2 1\n"); #include GOTOC_YIELD printf("coro2 2\n"); #include GOTOC_YIELD printf("coro2 3\n"); #include GOTOC_YIELD printf("coro2 4\n"); #include GOTOC_QUIT }
とかで良ければできると思います。