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