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