0 branches 0 tags
17 18
19
20 21
Add Generator ctor and dtor to interface
on 6:49 PM Sep 10 2025
trunk/coroutine/generator.c
18
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "generator.h"
#include "coroutine.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "cor_thread_local.h"
enum {
Generator_Running,
Generator_Deleting,
Generator_Complete
};
struct Generator {
Coroutine *coroutine;
Coroutine *caller;
void *(*start)(void *);
void *param;
char state;
};
_Cor_thread_local Generator *g_active_generator = NULL;
static void on_yield_gen(
void *this
){
Generator *gen = (Generator *)this;
Coroutine_Continue(gen->caller, Coroutine_GetValue(gen->coroutine), true);
}
static void on_yield_gen_caller(
void *this
){
(void)this;
}
static void *do_start(
void *this
){
Generator *gen = (Generator *)this;
g_active_generator = this;
assert(gen->state == Generator_Running || gen->state == Generator_Deleting);
void *value;
if (gen->state == Generator_Running){
g_active_generator = gen;
value = gen->start(gen->param);
g_active_generator = NULL;
} else {
// we are being deleted
value = NULL;
}
gen->state = Generator_Complete;
Coroutine_Continue(gen->caller, value, true);
return value;
}
Generator *Generator_New(
void *(*start)(void *),
void *param
){
Generator *gen = malloc(sizeof(Generator));
gen->start = start;
gen->param = param;
gen->coroutine = Coroutine_New(do_start);
gen->state = Generator_Running;
return gen;
}
void Generator_Delete(
Generator *gen
){
assert(gen->state != Generator_Deleting);
if (gen->state == Generator_Running){
gen->state = Generator_Deleting;
gen->caller = Coroutine_GetActive();
Coroutine_Continue(gen->coroutine, gen, true);
Coroutine_Yield(NULL, on_yield_gen_caller, gen);
}
assert(gen->state == Generator_Complete);
Coroutine_Delete(gen->coroutine);
free(gen);
}
bool Generator_Next(
Generator *gen,
void **value
){
assert(gen->state != Generator_Deleting);
if (gen->state == Generator_Complete){
return false;
}
gen->caller = Coroutine_GetActive();
Coroutine_Continue(gen->coroutine, gen, true);
*value = Coroutine_Yield(NULL, on_yield_gen_caller, gen);
return Coroutine_IsRunning(gen->coroutine);
}
bool Generator_Yield(
void *value
)
{
assert(g_active_generator);
Generator *gen = g_active_generator;
g_active_generator = NULL;
Coroutine_Yield(value, on_yield_gen, gen);
g_active_generator = gen;
return gen->state == Generator_Running;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "generator.h"
#include "coroutine.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "cor_thread_local.h"
_Cor_thread_local Generator *g_active_generator = NULL;
static void on_yield_gen(
void *this
){
Generator *gen = (Generator *)this;
Coroutine_Continue(gen->caller, Coroutine_GetValue(gen->coroutine), true);
}
static void on_yield_gen_caller(
void *this
){
(void)this;
}
static void *do_start(
void *this
){
Generator *gen = (Generator *)this;
g_active_generator = this;
assert(gen->state == Generator_Running || gen->state == Generator_Deleting);
void *value;
if (gen->state == Generator_Running){
g_active_generator = gen;
value = gen->start(gen->param);
g_active_generator = NULL;
} else {
// we are being deleted
value = NULL;
}
gen->state = Generator_Complete;
Coroutine_Continue(gen->caller, value, true);
return value;
}
void Generator_ctor(
Generator *gen,
void *(*start)(void *),
void *param
){
gen->start = start;
gen->param = param;
gen->coroutine = Coroutine_New(do_start);
gen->state = Generator_Running;
}
Generator *Generator_New(
void *(*start)(void *),
void *param
){
Generator *gen = malloc(sizeof(Generator));
Generator_ctor(gen, start, param);
return gen;
}
void Generator_dtor(
Generator *gen
){
assert(gen->state != Generator_Deleting);
if (gen->state == Generator_Running){
gen->state = Generator_Deleting;
gen->caller = Coroutine_GetActive();
Coroutine_Continue(gen->coroutine, gen, true);
Coroutine_Yield(NULL, on_yield_gen_caller, gen);
}
assert(gen->state == Generator_Complete);
Coroutine_Delete(gen->coroutine);
}
void Generator_Delete(
Generator *gen
){
Generator_dtor(gen);
free(gen);
}
bool Generator_Next(
Generator *gen,
void **value
){
assert(gen->state != Generator_Deleting);
if (gen->state == Generator_Complete){
return false;
}
gen->caller = Coroutine_GetActive();
Coroutine_Continue(gen->coroutine, gen, true);
*value = Coroutine_Yield(NULL, on_yield_gen_caller, gen);
return Coroutine_IsRunning(gen->coroutine);
}
bool Generator_Yield(
void *value
)
{
assert(g_active_generator);
Generator *gen = g_active_generator;
g_active_generator = NULL;
Coroutine_Yield(value, on_yield_gen, gen);
g_active_generator = gen;
return gen->state == Generator_Running;
}
trunk/include/generator.h
18
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef GENERATOR_H
#define GENERATOR_H
#include <stdbool.h>
typedef struct Generator Generator;
Generator *Generator_New(void *(*)(void *), void *);
void Generator_Delete(Generator *);
// Returns true if generator yielded a value, false if generator is complete
// *value is set to generator's value (yield / return value from exit)
bool Generator_Next(Generator *, void **value);
// Yield a value from the generator
// Returns true if generator should continue, false for generator to exit PDQ
bool Generator_Yield(void *);
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#ifndef GENERATOR_H
#define GENERATOR_H
#include "coroutine.h"
#include <stdbool.h>
typedef enum Generator_State {
Generator_Running,
Generator_Deleting,
Generator_Complete
} Generator_State;
typedef struct Generator {
Coroutine *coroutine;
Coroutine *caller;
void *(*start)(void *);
void *param;
Generator_State state;
} Generator;
void Generator_ctor(Generator *gen, void *(*start)(void *), void *param);
Generator *Generator_New(void *(*)(void *), void *);
void Generator_dtor(Generator *gen);
void Generator_Delete(Generator *);
// Returns true if generator yielded a value, false if generator is complete
// *value is set to generator's value (yield / return value from exit)
bool Generator_Next(Generator *, void **value);
// Yield a value from the generator
// Returns true if generator should continue, false for generator to exit PDQ
bool Generator_Yield(void *);
#endif