Mirai's Miscellaneous Misadventures

M27 / core / behaviors.c

1// copyright 2022 zamfofex
2// license: AGPLv3 or later
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}