Mirai's Miscellaneous Misadventures
M27 / core / behaviors.c
1
2
3
4#include <mimimi/behaviors.h>
5#include <mimimi/compound-behaviors.h>
6#include <mimimi/chapters.h>
7#include <mimimi/allocators.h>
8
9struct mimimi_compound_behavior
10{
11 struct mimimi_allocator *allocator;
12 struct mimimi_behavior *behavior;
13 int count;
14 struct mimimi_behavior **behaviors;
15};
16
17static void mimimi_compound_behave(void *data)
18{
19 struct mimimi_compound_behavior *compound = data;
20 for (int i = 0 ; i < compound->count ; i++)
21 {
22 struct mimimi_behavior *behavior = compound->behaviors[i];
23 (*behavior->behave)(behavior->data);
24 }
25}
26
27static void mimimi_compound_finish(void *data)
28{
29 struct mimimi_compound_behavior *compound = data;
30 for (int i = 0 ; i < compound->count ; i++)
31 {
32 struct mimimi_behavior *behavior = compound->behaviors[i];
33 (*behavior->finish)(behavior->data);
34 }
35
36 (*compound->allocator->deallocate)(compound->behaviors);
37 (*compound->allocator->deallocate)(compound->behavior);
38 (*compound->allocator->deallocate)(compound);
39}
40
41struct mimimi_behavior *mimimi_compound_behavior(struct mimimi_allocator *allocator)
42{
43 struct mimimi_compound_behavior *data = (*allocator->allocate)(sizeof *data);
44 data->allocator = allocator;
45
46 data->behavior = (*allocator->allocate)(sizeof *data->behavior);
47 data->behavior->behave = &mimimi_compound_behave;
48 data->behavior->finish = &mimimi_compound_finish;
49 data->behavior->data = data;
50
51 data->count = 0;
52 data->behaviors = allocator->null;
53
54 return data->behavior;
55}
56
57void mimimi_compound(struct mimimi_behavior *behavior, struct mimimi_behavior *other)
58{
59 struct mimimi_compound_behavior *compound = behavior->data;
60
61 compound->count++;
62 compound->behaviors = (*compound->allocator->reallocate)(compound->behaviors, compound->count * sizeof *compound->behaviors);
63 compound->behaviors[compound->count - 1] = other;
64}
65
66void mimimi_compound_remove(struct mimimi_behavior *behavior, struct mimimi_behavior *other)
67{
68 struct mimimi_compound_behavior *compound = behavior->data;
69 for (int i = 0 ; i < compound->count ; i++)
70 {
71 struct mimimi_behavior *behavior = compound->behaviors[i];
72 if (behavior == other)
73 {
74 compound->count--;
75 for (int j = i ; j < compound->count ; j++)
76 compound->behaviors[j] = compound->behaviors[j + 1];
77
78 if (compound->count == 0)
79 (*compound->allocator->deallocate)(compound->behaviors);
80 else
81 compound->behaviors = (*compound->allocator->reallocate)(compound->behaviors, compound->count * sizeof *compound->behaviors);
82 break;
83 }
84 }
85}
86
87char mimimi_compound_empty(struct mimimi_behavior *behavior)
88{
89 struct mimimi_compound_behavior *compound = behavior->data;
90 if (compound->count == 0) return 1;
91 else return 0;
92}
93
94void mimimi_ignore(void *data) { }
95
96static struct mimimi_behavior mimimi_noop_value = {&mimimi_ignore, &mimimi_ignore};
97struct mimimi_behavior *mimimi_noop = &mimimi_noop_value;
98
99struct mimimi_function
100{
101 struct mimimi_allocator *allocator;
102 struct mimimi_behavior *behavior;
103 struct mimimi_behavior *other;
104};
105
106static void mimimi_function_behave(void *data)
107{
108 struct mimimi_function *function = data;
109 (*function->other->behave)(function->other->data);
110}
111
112static void mimimi_function_finish(void *data)
113{
114 struct mimimi_function *function = data;
115 (*function->other->finish)(function->other->data);
116 (*function->allocator->deallocate)(function->other);
117 (*function->allocator->deallocate)(function->behavior);
118 (*function->allocator->deallocate)(function);
119}
120
121struct mimimi_behavior *mimimi_function(void *data, void (*behave)(void *data), struct mimimi_allocator *allocator)
122{
123 struct mimimi_function *function = (*allocator->allocate)(sizeof *function);
124 function->allocator = allocator;
125
126 function->other = (*allocator->allocate)(sizeof *function->other);
127 function->other->behave = behave;
128 function->other->finish = &mimimi_ignore;
129 function->other->data = data;
130
131 function->behavior = (*allocator->allocate)(sizeof *function->behavior);
132 function->behavior->behave = &mimimi_function_behave;
133 function->behavior->finish = &mimimi_function_finish;
134 function->behavior->data = function;
135
136 return function->behavior;
137}
138
139struct mimimi_behavior *mimimi_finalizer(void *data, void (*finish)(void *data), struct mimimi_allocator *allocator)
140{
141 struct mimimi_function *function = (*allocator->allocate)(sizeof *function);
142 function->allocator = allocator;
143
144 function->other = (*allocator->allocate)(sizeof *function->other);
145 function->other->behave = &mimimi_ignore;
146 function->other->finish = finish;
147 function->other->data = data;
148
149 function->behavior = (*allocator->allocate)(sizeof *function->behavior);
150 function->behavior->behave = &mimimi_function_behave;
151 function->behavior->finish = &mimimi_function_finish;
152 function->behavior->data = function;
153
154 return function->behavior;
155}
156
157struct mimimi_behavior *mimimi_allocator_behavior(void **data, unsigned int size, struct mimimi_allocator *allocator)
158{
159 *data = (*allocator->allocate)(size);
160 return mimimi_finalizer(*data, allocator->deallocate, allocator);
161}
162
163void *mimimi_compound_allocate(struct mimimi_behavior *compound, unsigned int size, struct mimimi_allocator *allocator)
164{
165 void *data;
166 mimimi_compound(compound, mimimi_allocator_behavior(&data, size, allocator));
167 return data;
168}
169
170struct mimimi_choice
171{
172 struct mimimi_allocator *allocator;
173 struct mimimi_behavior *behavior;
174 char *predicate;
175 struct mimimi_behavior *nonzero;
176 struct mimimi_behavior *zero;
177};
178
179static void mimimi_choose(void *data)
180{
181 struct mimimi_choice *choice = data;
182 struct mimimi_behavior *nonzero = choice->nonzero;
183 struct mimimi_behavior *zero = choice->zero;
184
185 if (*choice->predicate == 0)
186 (*zero->behave)(zero->data);
187 else
188 (*nonzero->behave)(nonzero->data);
189}
190
191static void mimimi_choice_finish(void *data)
192{
193 struct mimimi_choice *choice = data;
194 (*choice->nonzero->finish)(choice->nonzero->data);
195 (*choice->zero->finish)(choice->zero->data);
196 (*choice->allocator->deallocate)(choice->behavior);
197 (*choice->allocator->deallocate)(choice);
198}
199
200struct mimimi_behavior *mimimi_choice(char *predicate, struct mimimi_behavior *nonzero, struct mimimi_behavior *zero, struct mimimi_allocator *allocator)
201{
202 struct mimimi_choice *choice = (*allocator->allocate)(sizeof *choice);
203 choice->allocator = allocator;
204
205 choice->predicate = predicate;
206 choice->nonzero = nonzero;
207 choice->zero = zero;
208
209 choice->behavior = (*allocator->allocate)(sizeof *choice->behavior);
210 choice->behavior->behave = &mimimi_choose;
211 choice->behavior->finish = &mimimi_choice_finish;
212 choice->behavior->data = choice;
213
214 return choice->behavior;
215}
216
217struct mimimi_throttle
218{
219 struct mimimi_allocator *allocator;
220 struct mimimi_behavior *behavior;
221 struct mimimi_behavior *underlying;
222 int time;
223 int countdown;
224};
225
226static void mimimi_throttle_behave(void *data)
227{
228 struct mimimi_throttle *throttle = data;
229 if (throttle->countdown == 0)
230 {
231 throttle->countdown = throttle->time;
232 (*throttle->underlying->behave)(throttle->underlying->data);
233 }
234}
235
236static void mimimi_throttle_finish(void *data)
237{
238 struct mimimi_throttle *throttle = data;
239 (*throttle->underlying->finish)(throttle->underlying->data);
240 (*throttle->allocator->deallocate)(throttle->behavior);
241 (*throttle->allocator->deallocate)(throttle);
242}
243
244static void mimimi_countdown(void *data)
245{
246 int *n = data;
247 if (*n != 0) n[0]--;
248}
249
250struct mimimi_behavior *mimimi_throttle(struct mimimi_behavior *compound, struct mimimi_behavior *underlying, int time, struct mimimi_allocator *allocator)
251{
252 struct mimimi_throttle *throttle = (*allocator->allocate)(sizeof *throttle);
253 throttle->allocator = allocator;
254
255 throttle->underlying = underlying;
256 throttle->time = time;
257 throttle->countdown = 0;
258
259 throttle->behavior = (*allocator->allocate)(sizeof *throttle->behavior);
260 throttle->behavior->behave = &mimimi_throttle_behave;
261 throttle->behavior->finish = &mimimi_throttle_finish;
262 throttle->behavior->data = throttle;
263
264 mimimi_compound(compound, mimimi_function(&throttle->countdown, mimimi_countdown, allocator));
265
266 return throttle->behavior;
267}