| #include "generator.h" |
| #include "coroutine.h" |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <assert.h> |
| #include "cor_platform.h" |
|
|
| _Cor_thread_local Generator *g_active_generator = NULL; |
|
|
| static void on_yield_gen( |
| void *this |
| ){ |
| Generator *gen = (Generator *)this; |
| Coroutine_NS(Continue)(gen->caller, Coroutine_NS(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_NS(Continue)(gen->caller, value, true); |
| return value; |
| } |
|
|
| void Generator_ctor( |
| Generator *gen, |
| size_t stack_size, |
| void *(*start)(void *), |
| void *param |
| ){ |
| gen->start = start; |
| gen->param = param; |
| gen->coroutine = Coroutine_NS(New)(stack_size, do_start); |
| gen->state = Generator_Running; |
| } |
|
|
| Generator *Generator_New( |
| size_t stack_size, |
| void *(*start)(void *), |
| void *param |
| ){ |
| Generator *gen = malloc(sizeof(Generator)); |
| Generator_ctor(gen, stack_size, 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_NS(GetActive)(); |
| Coroutine_NS(Continue)(gen->coroutine, gen, true); |
| Coroutine_NS(Yield)(NULL, on_yield_gen_caller, gen); |
| } |
| assert(gen->state == Generator_Complete); |
| Coroutine_NS(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_NS(GetActive)(); |
| Coroutine_NS(Continue)(gen->coroutine, gen, true); |
| *value = Coroutine_NS(Yield)(NULL, on_yield_gen_caller, gen); |
| return Coroutine_NS(IsRunning)(gen->coroutine); |
| } |
|
|
| bool Generator_Yield( |
| void *value |
| ) |
| { |
| assert(g_active_generator); |
| Generator *gen = g_active_generator; |
| g_active_generator = NULL; |
| Coroutine_NS(Yield)(value, on_yield_gen, gen); |
| g_active_generator = gen; |
| return gen->state == Generator_Running; |
| } |
|