Информация об изменениях

Сообщение Re[17]: Вопрос по корутинам от 28.08.2025 10:08

Изменено 28.08.2025 10:10 rg45

Re[17]: Вопрос по корутинам
Здравствуйте, kov_serg, Вы писали:

_>https://coliru.stacked-crooked.com/a/86f2c863b4d93396


_>
int fn1_loop(fn1_t *my) {
_>    LOOP_BEGIN(my->loop)
    my->>value="Idle"; LOOP_POINT
    my->>value="Started"; LOOP_POINT
    my->>value="Processing"; LOOP_POINT
_>    while (*my->param < 10 + my->machineID) {
        my->>value="Waiting"; LOOP_POINT
_>    }
    my->>value="Stopped";
_>    LOOP_END
_>}
[cut]
typedef int loop_t;

Жульничаешь? Изюм выковыриваешь? Ну, я помогу тебе сделать этот нелёгкий шаг. Сравни следующие два варианта:

С корутинами:

[cpp]
#include <generator>
#include <iostream>
#include <string>
#include <ranges>
#include <vector>

std::generator<std::string> runMachine(const int& param) {
    co_yield "Idle";
    co_yield "Started";
    co_yield "Processing";
    while (param < 10)
    {
        co_yield "Waiting";
    }
    co_yield "Stopped";
}

std::generator<std::generator<std::string>> createMachines(const int& param, size_t n) {
    for (size_t i = 0; i < n; ++i)
        co_yield runMachine(param);
}

int main() {
    int param = 0;
    std::vector machines(std::from_range, createMachines(param, 333));
    
    for(bool active = true; active;) {
        active = false;
        for (size_t i = 0; i < machines.size(); ++i) {
            if (machines[i].begin() != machines[i].end()) {
                std::cout << "Machine " << i + 1 << ": " << *machines[i].begin() << std::endl;
                active = true;
            }
        }
        ++param;
    }
}
[/cpp]

На С со "вспомогательными макросами":

[c]
typedef int loop_t;

#define LOOP_RESET(loop) { loop=0; }
#if defined(__COUNTER__) && __COUNTER__!=__COUNTER__
#define LOOP_BEGIN(loop) { enum { __loop_base=__COUNTER__ };     loop_t *__loop=&(loop); __loop_switch: int __loop_rv=1;     switch(*__loop) { default: *__loop=0; case 0: {
#define LOOP_POINT { enum { __loop_case=__COUNTER__-__loop_base };     *__loop=__loop_case; goto __loop_leave; case __loop_case:{} }
#else
#define LOOP_BEGIN(loop) {loop_t*__loop=&(loop);__loop_switch:int __loop_rv=1;    switch(*__loop){ default: case 0: *__loop=__LINE__; case __LINE__:{
#define LOOP_POINT { *__loop=__LINE__; goto __loop_leave; case __LINE__:{} }
#endif
#define LOOP_END { __loop_end: *__loop=-1; case -1: return 0;     { goto __loop_end; goto __loop_switch; } }     }} __loop_leave: return __loop_rv; }
#define LOOP_SET_RV(rv) { __loop_rv=(rv); } /* rv must be non zero */
#define LOOP_INT(n) { __loop_rv=(n); LOOP_POINT } /* interrupt n */
/* for manual labeling: enum { L01=1,L02,L03,L04 }; ... LOOP_POINT_(L02) */
#define LOOP_POINT_(name) { *__loop=name; goto __loop_leave; case name:{} }
#define LOOP_INT_(n,name) { __loop_rv=(n); LOOP_POINT_(name) }

//------------------------------------------------------------------------------

enum { sevInit, sevDone };
typedef int (*afn_loop_fn)(void *ctx);
typedef int (*afn_setup_fn)(void *ctx,int sev);
typedef struct {
    void *ctx;
    int (*loop)(void *ctx);
    int (*setup)(void *ctx,int sev);
} afn_t;

//------------------------------------------------------------------------------

typedef struct {
    loop_t loop;
    int machineID, *param;
    const char* value;
} fn1_t;

int fn1_setup(fn1_t* my,int sev) {
    switch(sev) {
        case sevInit: {
            LOOP_RESET(my->loop);
            my->value="initialized";
        } break;
        case sevDone: {
            my->loop=-1;
        } break;
    }
    return 0;
}

int fn1_loop(fn1_t *my) {
    LOOP_BEGIN(my->loop)
    my->value="Idle"; LOOP_POINT
    my->value="Started"; LOOP_POINT
    my->value="Processing"; LOOP_POINT
    while (*my->param < 10 + my->machineID) {
        my->value="Waiting"; LOOP_POINT
    }
    my->value="Stopped";
    LOOP_END
}

//------------------------------------------------------------------------------
typedef void (*cycle_fn)(void *ctx);
typedef struct {
    afn_t *group; int current,count;
    void (*cycle)(void *ctx); void *cycle_ctx;
} fn2_t;

int fn2_setup(fn2_t* my, int sev) {
    int i,err=0;
    for(i=0;i<my->count;i++) {
        afn_t *fn=&my->group[i];
        if (fn->setup(fn->ctx,sev)) err++;
    }
    my->current=0;
    return err;
}

int fn2_loop(fn2_t* my) {
    if (my->count>0) {
        afn_t *fn=&my->group[my->current];
        if (fn->loop(fn->ctx)) my->current++; else {
            my->group[my->current]=my->group[--my->count];
        }
    }
    if (my->current>=my->count) { my->current=0;
        if (my->cycle) my->cycle(my->cycle_ctx);
    }
    return my->count>0 ? 1 : 0;
}

//------------------------------------------------------------------------------
#include <stdio.h>

typedef struct { fn1_t *list; int count, param; } show_ctx_t;

void show(show_ctx_t* my) {
    int i,n;
    n=my->count;
    for(i=0;i<n;i++) {
        fn1_t *f=&my->list[i];
        printf("| ");
        printf("Machine %d: %10s ",f->machineID, f->value);
    }
    printf("|\n");
    my->param++;
}

int main() {
    enum { N=5 }; 
    fn1_t fn[N]; afn_t afn[N];
    show_ctx_t show_ctx[1];
    fn2_t fn2[1];
    int i;

    for(i=0;i<N;i++) {
        fn[i].machineID=i+1;
        fn[i].param=&show_ctx->param;
    }
    show_ctx->param=0;
    show_ctx->list=fn;
    show_ctx->count=N;

    fn2->cycle=(cycle_fn)show;
    fn2->cycle_ctx=show_ctx;
    for(i=0;i<N;i++) {
        afn[i].ctx=&fn[i];
        afn[i].setup=(afn_setup_fn)fn1_setup;
        afn[i].loop=(afn_loop_fn)fn1_loop;
    }
    fn2->group=afn;
    fn2->count=N;

    fn2_setup(fn2,sevInit);
    while(fn2_loop(fn2)) {}
    fn2_setup(fn2,sevDone);

    return 0;
}


И что, тебе реально твой вариант больше нравится? Лично я бы не выбрал этот вариант из-за одних только "вспомогательных макросов". Ну и вообще...
Re[17]: Вопрос по корутинам
Здравствуйте, kov_serg, Вы писали:

_>https://coliru.stacked-crooked.com/a/86f2c863b4d93396


_>
int fn1_loop(fn1_t *my) {
_>    LOOP_BEGIN(my->loop)
    my->>value="Idle"; LOOP_POINT
    my->>value="Started"; LOOP_POINT
    my->>value="Processing"; LOOP_POINT
_>    while (*my->param < 10 + my->machineID) {
        my->>value="Waiting"; LOOP_POINT
_>    }
    my->>value="Stopped";
_>    LOOP_END
_>}


Жульничаешь? Изюм выковыриваешь? Ну, я помогу тебе сделать этот нелёгкий шаг. Сравни следующие два варианта:

С корутинами:

#include <generator>
#include <iostream>
#include <string>
#include <ranges>
#include <vector>

std::generator<std::string> runMachine(const int& param) {
    co_yield "Idle";
    co_yield "Started";
    co_yield "Processing";
    while (param < 10)
    {
        co_yield "Waiting";
    }
    co_yield "Stopped";
}

std::generator<std::generator<std::string>> createMachines(const int& param, size_t n) {
    for (size_t i = 0; i < n; ++i)
        co_yield runMachine(param);
}

int main() {
    int param = 0;
    std::vector machines(std::from_range, createMachines(param, 333));
    
    for(bool active = true; active;) {
        active = false;
        for (size_t i = 0; i < machines.size(); ++i) {
            if (machines[i].begin() != machines[i].end()) {
                std::cout << "Machine " << i + 1 << ": " << *machines[i].begin() << std::endl;
                active = true;
            }
        }
        ++param;
    }
}


На С со "вспомогательными макросами":

typedef int loop_t;

#define LOOP_RESET(loop) { loop=0; }
#if defined(__COUNTER__) && __COUNTER__!=__COUNTER__
#define LOOP_BEGIN(loop) { enum { __loop_base=__COUNTER__ }; \
    loop_t *__loop=&(loop); __loop_switch: int __loop_rv=1; \
    switch(*__loop) { default: *__loop=0; case 0: {
#define LOOP_POINT { enum { __loop_case=__COUNTER__-__loop_base }; \
    *__loop=__loop_case; goto __loop_leave; case __loop_case:{} }
#else
#define LOOP_BEGIN(loop) {loop_t*__loop=&(loop);__loop_switch:int __loop_rv=1;\
    switch(*__loop){ default: case 0: *__loop=__LINE__; case __LINE__:{
#define LOOP_POINT { *__loop=__LINE__; goto __loop_leave; case __LINE__:{} }
#endif
#define LOOP_END { __loop_end: *__loop=-1; case -1: return 0; \
    { goto __loop_end; goto __loop_switch; } } \
    }} __loop_leave: return __loop_rv; }
#define LOOP_SET_RV(rv) { __loop_rv=(rv); } /* rv must be non zero */
#define LOOP_INT(n) { __loop_rv=(n); LOOP_POINT } /* interrupt n */
/* for manual labeling: enum { L01=1,L02,L03,L04 }; ... LOOP_POINT_(L02) */
#define LOOP_POINT_(name) { *__loop=name; goto __loop_leave; case name:{} }
#define LOOP_INT_(n,name) { __loop_rv=(n); LOOP_POINT_(name) }

//------------------------------------------------------------------------------

enum { sevInit, sevDone };
typedef int (*afn_loop_fn)(void *ctx);
typedef int (*afn_setup_fn)(void *ctx,int sev);
typedef struct {
    void *ctx;
    int (*loop)(void *ctx);
    int (*setup)(void *ctx,int sev);
} afn_t;

//------------------------------------------------------------------------------

typedef struct {
    loop_t loop;
    int machineID, *param;
    const char* value;
} fn1_t;

int fn1_setup(fn1_t* my,int sev) {
    switch(sev) {
        case sevInit: {
            LOOP_RESET(my->loop);
            my->value="initialized";
        } break;
        case sevDone: {
            my->loop=-1;
        } break;
    }
    return 0;
}

int fn1_loop(fn1_t *my) {
    LOOP_BEGIN(my->loop)
    my->value="Idle"; LOOP_POINT
    my->value="Started"; LOOP_POINT
    my->value="Processing"; LOOP_POINT
    while (*my->param < 10 + my->machineID) {
        my->value="Waiting"; LOOP_POINT
    }
    my->value="Stopped";
    LOOP_END
}

//------------------------------------------------------------------------------
typedef void (*cycle_fn)(void *ctx);
typedef struct {
    afn_t *group; int current,count;
    void (*cycle)(void *ctx); void *cycle_ctx;
} fn2_t;

int fn2_setup(fn2_t* my, int sev) {
    int i,err=0;
    for(i=0;i<my->count;i++) {
        afn_t *fn=&my->group[i];
        if (fn->setup(fn->ctx,sev)) err++;
    }
    my->current=0;
    return err;
}

int fn2_loop(fn2_t* my) {
    if (my->count>0) {
        afn_t *fn=&my->group[my->current];
        if (fn->loop(fn->ctx)) my->current++; else {
            my->group[my->current]=my->group[--my->count];
        }
    }
    if (my->current>=my->count) { my->current=0;
        if (my->cycle) my->cycle(my->cycle_ctx);
    }
    return my->count>0 ? 1 : 0;
}

//------------------------------------------------------------------------------
#include <stdio.h>

typedef struct { fn1_t *list; int count, param; } show_ctx_t;

void show(show_ctx_t* my) {
    int i,n;
    n=my->count;
    for(i=0;i<n;i++) {
        fn1_t *f=&my->list[i];
        printf("| ");
        printf("Machine %d: %10s ",f->machineID, f->value);
    }
    printf("|\n");
    my->param++;
}

int main() {
    enum { N=5 }; 
    fn1_t fn[N]; afn_t afn[N];
    show_ctx_t show_ctx[1];
    fn2_t fn2[1];
    int i;

    for(i=0;i<N;i++) {
        fn[i].machineID=i+1;
        fn[i].param=&show_ctx->param;
    }
    show_ctx->param=0;
    show_ctx->list=fn;
    show_ctx->count=N;

    fn2->cycle=(cycle_fn)show;
    fn2->cycle_ctx=show_ctx;
    for(i=0;i<N;i++) {
        afn[i].ctx=&fn[i];
        afn[i].setup=(afn_setup_fn)fn1_setup;
        afn[i].loop=(afn_loop_fn)fn1_loop;
    }
    fn2->group=afn;
    fn2->count=N;

    fn2_setup(fn2,sevInit);
    while(fn2_loop(fn2)) {}
    fn2_setup(fn2,sevDone);

    return 0;
}


И что, тебе реально твой вариант больше нравится? Лично я бы не выбрал этот вариант из-за одних только "вспомогательных макросов". Ну и вообще...