| #include "generator.h" |
| #include "coroutine.h" |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <assert.h> |
| #include "cor_thread_local.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| _Cor_thread_local Generator *g_active_generator = NULL; |
|
|
| static void on_yield_gen( |
| void *this |
| ){ |
| Generator *gen = (Generator *)this; |
| Coroutine_Continue(gen->caller, Coroutine_GetValue(gen->coroutine), true); |
| } |
|
|
| static void on_yield_gen_caller( |
| void *this |
| ){ |
| (void)this; |
| } |
|
|
| static void *do_start( |
| void *this |
| ){ |
| Generator *gen = (Generator *)this; |
| g_active_generator = this; |
| assert(gen->state == Generator_Running || gen->state == Generator_Deleting); |
| void *value; |
| if (gen->state == Generator_Running){ |
| g_active_generator = gen; |
| value = gen->start(gen->param); |
| g_active_generator = NULL; |
| } else { |
| // we are being deleted |
| value = NULL; |
| } |
| gen->state = Generator_Complete; |
| Coroutine_Continue(gen->caller, value, true); |
| return value; |
| } |
|
|
| void Generator_ctor( |
| Generator *gen, |
| void *(*start)(void *), |
| void *param |
| ){ |
| gen->start = start; |
| gen->param = param; |
| gen->coroutine = Coroutine_New(do_start); |
| gen->state = Generator_Running; |
| } |
|
|
| Generator *Generator_New( |
| void *(*start)(void *), |
| void *param |
| ){ |
| Generator *gen = malloc(sizeof(Generator)); |
| Generator_ctor(gen, start, param); |
|
|
|
| return gen; |
| } |
|
|
| void Generator_dtor( |
| Generator *gen |
| ){ |
| assert(gen->state != Generator_Deleting); |
| if (gen->state == Generator_Running){ |
| gen->state = Generator_Deleting; |
| gen->caller = Coroutine_GetActive(); |
| Coroutine_Continue(gen->coroutine, gen, true); |
| Coroutine_Yield(NULL, on_yield_gen_caller, gen); |
| } |
| assert(gen->state == Generator_Complete); |
| Coroutine_Delete(gen->coroutine); |
| } |
|
| void Generator_Delete( |
| Generator *gen |
| ){ |
| Generator_dtor(gen); |
| free(gen); |
| } |
|
|
| bool Generator_Next( |
| Generator *gen, |
| void **value |
| ){ |
| assert(gen->state != Generator_Deleting); |
| if (gen->state == Generator_Complete){ |
| return false; |
| } |
| gen->caller = Coroutine_GetActive(); |
| Coroutine_Continue(gen->coroutine, gen, true); |
| *value = Coroutine_Yield(NULL, on_yield_gen_caller, gen); |
| return Coroutine_IsRunning(gen->coroutine); |
| } |
|
|
| bool Generator_Yield( |
| void *value |
| ) |
| { |
| assert(g_active_generator); |
| Generator *gen = g_active_generator; |
| g_active_generator = NULL; |
| Coroutine_Yield(value, on_yield_gen, gen); |
| g_active_generator = gen; |
| return gen->state == Generator_Running; |
| } |
|