Duff's deviceを用いてC/C++でPythonのyieldをシミュレートする

2391 ワード

簡単なPython関数を考えます.
def gen():
    for i in range(10):
        yield i

CまたはC++で実現する可能性はありますか?
C言語で実現可能性をCoroutines in Cで詳しく紹介した.
簡単に説明します.
バージョン1:
int gen(void) {
    static int i, state = 0;
    switch (state) {
        case 0: goto LABEL0;
        case 1: goto LABEL1;
    }
    LABEL0: /* start of function */
    for (i = 0; i < 10; i++) {
         state = 1; /* so we will come back to LABEL1 */
        return i;
        LABEL1:; /* resume control straight after the return */
    }
}

バージョン1ではstatic変数stateを用いて前回関数を終了したときの状態を記録し,次回関数に入ったときにstateを判断しgoto文を用いて前回終了した位置にジャンプする.この方法は直感的ではなく、書くのが面倒なので、Duff's deviceを利用して改造することができます.Duff's deviceは、switch文でもジャンプできる原理を利用しています.
switch (count % 8) {
    case 0:        do {  *to = *from++;
    case 7:              *to = *from++;
    case 6:              *to = *from++;
    case 5:              *to = *from++;
    case 4:              *to = *from++;
    case 3:              *to = *from++;
    case 2:              *to = *from++;
    case 1:              *to = *from++;
                   } while ((count -= 8) > 0);
}

バージョン2:
int gen(void) {
    static int i, state = 0;
    switch (state) {
        case 0: /* start of function */
        for (i = 0; i < 10; i++) {
            state = 1; /* so we will come back to "case 1" */
            return i;
            case 1:; /* resume control straight after the return */
        }
    }
}

バージョン2は、バージョン1よりも直感的であり、マクロを定義して書きやすくすることができる.
バージョン3:
#define crBegin static int state=0; switch(state) { case 0:
#define crReturn(i,x) do { state=i; return x; case i:; } while (0)
#define crFinish }
int gen(void) {
    static int i;
    crBegin;
    for (i = 0; i < 10; i++)
        crReturn(1, i);
    crFinish;
}

バージョン3に複数のcrReturnがある場合は、crReturnに設定する最初のパラメータがそれぞれ異なるため、面倒なので、持参マクロ__を利用することができます.LINE__さらに簡略化:
バージョン4:
#define crBegin static int state=0; switch(state) { case 0:
#define crReturn(x) do { state=__LINE__; return x; \
    case __LINE__:; } while (0)
#define crFinish }
int gen(void) {
    static int i;
    crBegin;
    for (i = 0; i < 10; i++)
        crReturn(i);
    crFinish;
}

C++の場合、boostライブラリでは、専用の実装があります:Boost.Coroutineこのライブラリの一部の実装ではアセンブリ言語が使用されています.