133 lines2.8 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
13on_yield_gen(
14 void *this
15){
16 (void)this;
17}
18
19
20static void
21on_yield_gen_caller(
22 void *this
23){
24 (void)this;
25}
26
27
28static void *
29do_start(
30 void *this
31){
32 Generator *gen = (Generator *)this;
33 g_active_generator = this;
34 assert(gen->state == Generator_Running || gen->state == Generator_Deleting);
35 void *value;
36 if (gen->state == Generator_Running){
37 g_active_generator = gen;
38 value = gen->start(gen->param);
39 g_active_generator = NULL;
40 } else {
41 // we are being deleted
42 value = NULL;
43 }
44 gen->state = Generator_Complete;
45 Coroutine_NS(Continue)(gen->caller, value, true);
46 return value;
47}
48
49
50void
51Generator_ctor(
52 Generator *gen,
53 size_t min_stack,
54 size_t min_stack_headroom,
55 void *(*start)(void *),
56 void *param
57){
58 gen->start = start;
59 gen->param = param;
60 gen->coroutine = Coroutine_NS(New)(min_stack, min_stack_headroom, do_start);
61 gen->yielded_coroutine = gen->coroutine;
62 gen->state = Generator_Running;
63}
64
65
66Generator *
67Generator_New(
68 size_t min_stack,
69 size_t min_stack_headroom,
70 void *(*start)(void *),
71 void *param
72){
73 Generator *gen = malloc(sizeof(Generator));
74 Generator_ctor(gen, min_stack, min_stack_headroom, start, param);
75 return gen;
76}
77
78
79void
80Generator_dtor(
81 Generator *gen
82){
83 assert(gen->state != Generator_Deleting);
84 if (gen->state == Generator_Running){
85 gen->state = Generator_Deleting;
86 gen->caller = Coroutine_NS(GetActive)();
87 Coroutine_NS(Continue)(gen->yielded_coroutine, gen, true);
88 Coroutine_NS(Yield)(NULL, on_yield_gen_caller, gen);
89 }
90 assert(gen->state == Generator_Complete);
91 Coroutine_NS(Delete)(gen->coroutine);
92}
93
94void
95Generator_Delete(
96 Generator *gen
97){
98 Generator_dtor(gen);
99 free(gen);
100}
101
102
103bool
104Generator_Next(
105 Generator *gen,
106 void **value
107){
108 assert(gen->state != Generator_Deleting);
109 if (gen->state == Generator_Complete){
110 return false;
111 }
112 gen->caller = Coroutine_NS(GetActive)();
113 Coroutine_NS(Continue)(gen->yielded_coroutine, gen, true);
114 *value = Coroutine_NS(Yield)(NULL, on_yield_gen_caller, gen);
115 return Coroutine_NS(IsRunning)(gen->coroutine);
116}
117
118
119bool
120Generator_Yield(
121 void *value
122)
123{
124 assert(g_active_generator);
125 Generator *gen = g_active_generator;
126 g_active_generator = NULL;
127 gen->yielded_coroutine = Coroutine_NS(GetActive)();
128 Coroutine_NS(Continue)(gen->caller, value, true);
129 Coroutine_NS(Yield)(value, on_yield_gen, NULL);
130 g_active_generator = gen;
131 return gen->state == Generator_Running;
132}
133