1 contributor
120 lines2.5 KB
1#include "generator.h"
2#include "coroutine.h"
3#include <stdlib.h>
4#include <stdio.h>
5#include <assert.h>
6#include "cor_platform.h"
7
8
9_Cor_thread_local Generator *g_active_generator = NULL;
10
11
12static void on_yield_gen(
13 void *this
14){
15 Generator *gen = (Generator *)this;
16 Coroutine_Continue(gen->caller, Coroutine_GetValue(gen->coroutine), true);
17}
18
19
20static void on_yield_gen_caller(
21 void *this
22){
23 (void)this;
24}
25
26
27static void *do_start(
28 void *this
29){
30 Generator *gen = (Generator *)this;
31 g_active_generator = this;
32 assert(gen->state == Generator_Running || gen->state == Generator_Deleting);
33 void *value;
34 if (gen->state == Generator_Running){
35 g_active_generator = gen;
36 value = gen->start(gen->param);
37 g_active_generator = NULL;
38 } else {
39 // we are being deleted
40 value = NULL;
41 }
42 gen->state = Generator_Complete;
43 Coroutine_Continue(gen->caller, value, true);
44 return value;
45}
46
47
48void Generator_ctor(
49 Generator *gen,
50 size_t stack_size,
51 void *(*start)(void *),
52 void *param
53){
54 gen->start = start;
55 gen->param = param;
56 gen->coroutine = Coroutine_New(stack_size, do_start);
57 gen->state = Generator_Running;
58}
59
60
61Generator *Generator_New(
62 size_t stack_size,
63 void *(*start)(void *),
64 void *param
65){
66 Generator *gen = malloc(sizeof(Generator));
67 Generator_ctor(gen, stack_size, start, param);
68 return gen;
69}
70
71
72void Generator_dtor(
73 Generator *gen
74){
75 assert(gen->state != Generator_Deleting);
76 if (gen->state == Generator_Running){
77 gen->state = Generator_Deleting;
78 gen->caller = Coroutine_GetActive();
79 Coroutine_Continue(gen->coroutine, gen, true);
80 Coroutine_Yield(NULL, on_yield_gen_caller, gen);
81 }
82 assert(gen->state == Generator_Complete);
83 Coroutine_Delete(gen->coroutine);
84}
85
86void Generator_Delete(
87 Generator *gen
88){
89 Generator_dtor(gen);
90 free(gen);
91}
92
93
94bool Generator_Next(
95 Generator *gen,
96 void **value
97){
98 assert(gen->state != Generator_Deleting);
99 if (gen->state == Generator_Complete){
100 return false;
101 }
102 gen->caller = Coroutine_GetActive();
103 Coroutine_Continue(gen->coroutine, gen, true);
104 *value = Coroutine_Yield(NULL, on_yield_gen_caller, gen);
105 return Coroutine_IsRunning(gen->coroutine);
106}
107
108
109bool Generator_Yield(
110 void *value
111)
112{
113 assert(g_active_generator);
114 Generator *gen = g_active_generator;
115 g_active_generator = NULL;
116 Coroutine_Yield(value, on_yield_gen, gen);
117 g_active_generator = gen;
118 return gen->state == Generator_Running;
119}
120