131 lines2.7 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 Generator *gen = (Generator *)this;
17 Coroutine_NS(Continue)(gen->caller, Coroutine_NS(GetValue)(gen->coroutine), true);
18}
19
20
21static void
22on_yield_gen_caller(
23 void *this
24){
25 (void)this;
26}
27
28
29static void *
30do_start(
31 void *this
32){
33 Generator *gen = (Generator *)this;
34 g_active_generator = this;
35 assert(gen->state == Generator_Running || gen->state == Generator_Deleting);
36 void *value;
37 if (gen->state == Generator_Running){
38 g_active_generator = gen;
39 value = gen->start(gen->param);
40 g_active_generator = NULL;
41 } else {
42 // we are being deleted
43 value = NULL;
44 }
45 gen->state = Generator_Complete;
46 Coroutine_NS(Continue)(gen->caller, value, true);
47 return value;
48}
49
50
51void
52Generator_ctor(
53 Generator *gen,
54 size_t min_stack,
55 size_t min_stack_headroom,
56 void *(*start)(void *),
57 void *param
58){
59 gen->start = start;
60 gen->param = param;
61 gen->coroutine = Coroutine_NS(New)(min_stack, min_stack_headroom, do_start);
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->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->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 Coroutine_NS(Yield)(value, on_yield_gen, gen);
128 g_active_generator = gen;
129 return gen->state == Generator_Running;
130}
131