9 months ago |
4 |
1 |
#include "generator.h" | ||
2 |
#include "coroutine.h" | ||||
3 |
#include <stdlib.h> | ||||
4 |
#include <stdio.h> | ||||
5 |
#include <assert.h> | ||||
9 months ago |
6 |
#include "cor_thread_local.h" | |||
9 months ago |
4 |
7 |
|||
8 |
enum { | ||||
9 |
Generator_Running, | ||||
10 |
Generator_Deleting, | ||||
11 |
Generator_Complete | ||||
12 |
}; | ||||
13 |
|||||
14 |
struct Generator { | ||||
15 |
Coroutine *coroutine; | ||||
16 |
Coroutine *caller; | ||||
17 |
void *(*start)(void *); | ||||
18 |
void *param; | ||||
19 |
char state; | ||||
20 |
}; | ||||
21 |
|||||
9 months ago |
22 |
_Cor_thread_local Generator *g_active_generator = NULL; | |||
23 |
|||||
24 |
static void on_yield_gen(void *this){ | ||||
9 months ago |
4 |
25 |
Generator *gen = (Generator *)this; | ||
26 |
Coroutine_Continue(gen->caller, Coroutine_GetValue(gen->coroutine), true); | ||||
27 |
} | ||||
28 |
|||||
9 months ago |
29 |
static void on_yield_gen_caller(void *this){ | |||
30 |
(void)this; | ||||
31 |
} | ||||
32 |
|||||
9 months ago |
4 |
33 |
static void *do_start(void *this){ | ||
34 |
Generator *gen = (Generator *)this; | ||||
9 months ago |
35 |
g_active_generator = this; | |||
9 months ago |
4 |
36 |
assert(gen->state == Generator_Running || gen->state == Generator_Deleting); | ||
37 |
void *value; | ||||
38 |
if (gen->state == Generator_Running){ | ||||
9 months ago |
39 |
g_active_generator = gen; | |||
9 months ago |
4 |
40 |
value = gen->start(gen->param); | ||
9 months ago |
41 |
g_active_generator = NULL; | |||
9 months ago |
4 |
42 |
} else { | ||
43 |
// we are being deleted | ||||
44 |
value = NULL; | ||||
45 |
} | ||||
46 |
gen->state = Generator_Complete; | ||||
47 |
Coroutine_Continue(gen->caller, value, true); | ||||
48 |
return value; | ||||
49 |
} | ||||
50 |
|||||
51 |
Generator *Generator_New(void *(*start)(void *), void *param){ | ||||
52 |
Generator *gen = malloc(sizeof(Generator)); | ||||
53 |
gen->start = start; | ||||
54 |
gen->param = param; | ||||
9 months ago |
55 |
gen->coroutine = Coroutine_New(do_start); | |||
9 months ago |
4 |
56 |
gen->state = Generator_Running; | ||
57 |
return gen; | ||||
58 |
} | ||||
59 |
|||||
60 |
void Generator_Delete(Generator *gen){ | ||||
61 |
assert(gen->state != Generator_Deleting); | ||||
62 |
if (gen->state == Generator_Running){ | ||||
63 |
gen->state = Generator_Deleting; | ||||
64 |
gen->caller = Coroutine_GetActive(); | ||||
65 |
Coroutine_Continue(gen->coroutine, gen, true); | ||||
9 months ago |
66 |
Coroutine_Yield(NULL, on_yield_gen_caller, gen); | |||
9 months ago |
4 |
67 |
} | ||
68 |
assert(gen->state == Generator_Complete); | ||||
69 |
Coroutine_Delete(gen->coroutine); | ||||
70 |
free(gen); | ||||
71 |
} | ||||
72 |
|||||
73 |
bool Generator_Next(Generator *gen, void **value){ | ||||
74 |
assert(gen->state != Generator_Deleting); | ||||
75 |
if (gen->state == Generator_Complete){ | ||||
76 |
return false; | ||||
77 |
} | ||||
78 |
gen->caller = Coroutine_GetActive(); | ||||
79 |
Coroutine_Continue(gen->coroutine, gen, true); | ||||
9 months ago |
80 |
*value = Coroutine_Yield(NULL, on_yield_gen_caller, gen); | |||
9 months ago |
4 |
81 |
return Coroutine_IsRunning(gen->coroutine); | ||
82 |
} | ||||
83 |
|||||
84 |
bool Generator_Yield(void *value) | ||||
85 |
{ | ||||
9 months ago |
86 |
assert(g_active_generator); | |||
87 |
Generator *gen = g_active_generator; | ||||
88 |
g_active_generator = NULL; | ||||
89 |
Coroutine_Yield(value, on_yield_gen, gen); | ||||
90 |
g_active_generator = gen; | ||||
9 months ago |
4 |
91 |
return gen->state == Generator_Running; | ||
92 |
} | ||||
93 |