Make all NanoCoat types closeable; Make unrefing closeable the default.
[SquirrelJME.git] / nanocoat / tests / testAllocFreeMerge.c
blob5912c35c642144aa10c1cb2258c4cf75004126f7
1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // -------------------------------------------------------------------------*/
10 #include <string.h>
12 #include "proto.h"
13 #include "sjme/alloc.h"
14 #include "test.h"
15 #include "unit.h"
17 /** The number of links to allocate. */
18 #define NUM_LINKS 3
20 /** The number of which sequences. */
21 #define NUM_WHICH (NUM_LINKS + 3)
23 /** Identifier for the front link. */
24 #define FRONT (NUM_LINKS + 1)
26 /** Identifier for the back link. */
27 #define BACK (NUM_LINKS + 2)
29 /** Identifier of the end of link list. */
30 #define END NUM_LINKS
32 /** Free bit. */
33 #define FREE 64
35 /** The mask for removing free. */
36 #define FREE_MASK 63
38 /** The scenarios available. */
39 typedef enum testScenarioId
41 /** Left to right. */
42 sjme_attrUnusedEnum(SCENARIO_LMR),
44 /** Left, Right, then middle. */
45 sjme_attrUnusedEnum(SCENARIO_LRM),
47 /** Middle, then left to right. */
48 sjme_attrUnusedEnum(SCENARIO_MLR),
50 /** Middle, then right to left. */
51 sjme_attrUnusedEnum(SCENARIO_MRL),
53 /** Right to left. */
54 sjme_attrUnusedEnum(SCENARIO_RML),
56 /** Right, left, then middle. */
57 sjme_attrUnusedEnum(SCENARIO_RLM),
59 /** The number of scenarios. */
60 NUM_SCENARIO
61 } testScenarioId;
63 /** The sequence of links. */
64 typedef struct testSequenceType
66 /** The number of used links. */
67 sjme_jint numUsed;
69 /** The number of free links. */
70 sjme_jint numFree;
72 /** Which links are on the entire chain? */
73 sjme_jint which[NUM_WHICH];
74 } testSequenceType;
76 /** The order of the links. */
77 typedef struct testOrderType
79 /** The order used. */
80 sjme_jint order[NUM_LINKS];
82 /** How many there should be after being freed. */
83 testSequenceType sequence[NUM_LINKS];
84 } testOrderType;
86 /** The actual order to use. */
87 const testOrderType testLinkOrder[NUM_SCENARIO] =
90 {0, 1, 2},
92 {2, 1,
93 {FRONT, 0 | FREE, 1, 2, BACK,
94 END}},
95 {1, 1,
96 {FRONT, 0 | FREE, 2, BACK,
97 END}},
98 {0, 1,
99 {FRONT, 0 | FREE, BACK,
100 END}}
104 {0, 2, 1},
106 {2, 1,
107 {FRONT, 0 | FREE, 1, 2, BACK,
108 END}},
109 {1, 2,
110 {FRONT, 0 | FREE, 1, 2 | FREE, BACK,
111 END}},
112 {0, 1,
113 {FRONT, 0 | FREE, BACK,
114 END}}
118 {1, 0, 2},
120 {2, 1,
121 {FRONT, 0, 1 | FREE, 2, BACK,
122 END}},
123 {1, 1,
124 {FRONT, 0 | FREE, 2, BACK,
125 END}},
126 {0, 1,
127 {FRONT, 0 | FREE, BACK,
128 END}}
132 {1, 2, 0},
134 {2, 1,
135 {FRONT, 0, 1 | FREE, 2, BACK,
136 END}},
137 {1, 1,
138 {FRONT, 0, 1 | FREE, BACK,
139 END}},
140 {0, 1,
141 {FRONT, 0 | FREE, BACK,
142 END}}
146 {2, 1, 0},
148 {2, 1,
149 {FRONT, 0, 1, 2 | FREE, BACK,
150 END}},
151 {1, 1,
152 {FRONT, 0, 1 | FREE, BACK,
153 END}},
154 {0, 1,
155 {FRONT, 0 | FREE, BACK,
156 END}}
160 {2, 0, 1},
162 {2, 1,
163 {FRONT, 0, 1, 2 | FREE, BACK,
164 END}},
165 {1, 2,
166 {FRONT, 0 | FREE, 1, 2 | FREE, BACK,
167 END}},
168 {0, 1,
169 {FRONT, 0 | FREE, BACK,
170 END}}
175 static void dumpPool(sjme_alloc_pool* pool, sjme_lpcstr what)
177 sjme_alloc_link* rover;
178 sjme_jint x;
180 /* Debug view. */
181 sjme_message("---------------------------------------------");
182 for (rover = pool->frontLink,
183 x = 0; rover != NULL; rover = rover->next, x++)
185 sjme_message("%s %d: @%p %s %d/%d bytes",
186 what, x, rover, (rover->space == SJME_ALLOC_POOL_SPACE_FREE ?
187 "FREE" : (rover->space == SJME_ALLOC_POOL_SPACE_USED ?
188 "USED" : "OTHER")),
189 rover->allocSize, rover->blockSize);
191 sjme_message("---------------------------------------------");
195 * Tests merging of allocation blocks when freeing them accordingly.
197 * @since 2023/11/25
199 SJME_TEST_DECLARE(testAllocFreeMerge)
201 sjme_pointer chunk;
202 sjme_jboolean isLast, isFree, wantFree;
203 sjme_jint chunkLen, linkNum, scenario, numUsed, numFree, x, atId;
204 uint8_t* block;
205 sjme_alloc_link* link;
206 sjme_alloc_pool* pool;
207 sjme_alloc_link* rover;
208 sjme_alloc_link* at;
209 sjme_pointer blocks[NUM_WHICH];
210 sjme_alloc_link* links[NUM_WHICH];
211 const testOrderType* order;
212 const testSequenceType* sequence;
214 /* Allocate data on the stack so it gets cleared. */
215 chunkLen = 65536;
216 chunk = sjme_alloca(chunkLen);
217 if (chunk == NULL)
218 return sjme_unit_skip(test, "Could not alloca(%d).",
219 (int)chunkLen);
221 /* Use multiple scenarios regarding the order of blocks to free. */
222 for (scenario = 0; scenario < NUM_SCENARIO; scenario++)
224 /* Get the order data. */
225 order = &testLinkOrder[scenario];
227 /* Initialize the pool. */
228 pool = NULL;
229 if (sjme_error_is(sjme_alloc_poolInitStatic(&pool,
230 chunk, chunkLen)) || pool == NULL)
231 return sjme_unit_fail(test, "Could not initialize static pool?");
233 /* Cleanup for run. */
234 memset(&blocks, 0, sizeof(blocks));
235 memset(&links, 0, sizeof(links));
237 /* Allocate each of the links. */
238 for (linkNum = 0; linkNum < NUM_LINKS; linkNum++)
240 /* Is this the last link? */
241 isLast = linkNum >= (NUM_LINKS - 1);
243 /* Debug. */
244 sjme_message("Link %d of %d (last? %d)",
245 (linkNum + 1), NUM_LINKS, isLast);
247 /* Allocate block. */
248 blocks[linkNum] = NULL;
249 if (sjme_error_is(sjme_alloc(pool,
250 pool->space[SJME_ALLOC_POOL_SPACE_FREE].usable /
251 (isLast ? 1 : 2),
252 &blocks[linkNum])) || blocks[linkNum] == NULL)
253 return sjme_unit_fail(test, "Could not allocate link?");
255 /* Get the link. */
256 links[linkNum] = NULL;
257 if (sjme_error_is(sjme_alloc_getLink(blocks[linkNum],
258 &links[linkNum])) || links[linkNum] == NULL)
259 return sjme_unit_fail(test, "Could not get link?");
261 /* The last block should claim all the free space. */
262 if (isLast)
263 sjme_unit_equalI(test,
264 0, pool->space[SJME_ALLOC_POOL_SPACE_FREE].usable,
265 "All of the free space was not taken?");
268 /* Seed front and back links which are constant. */
269 links[FRONT] = pool->frontLink;
270 links[BACK] = pool->backLink;
272 /* Free the links in the specified order and test the result. */
273 for (linkNum = 0; linkNum < NUM_LINKS; linkNum++)
275 /* Get the sequence from the order. */
276 sequence = &order->sequence[linkNum];
278 /* Which link is this? */
279 block = blocks[order->order[linkNum]];
280 link = links[order->order[linkNum]];
282 /* Debug view. */
283 dumpPool(pool, "BEFORE FREE");
285 /* Free the link. */
286 if (sjme_error_is(sjme_alloc_free(block)))
287 return sjme_unit_fail(test, "Could not free link.");
289 /* Debug view. */
290 dumpPool(pool, "AFTER FREE");
292 /* Go through the entire chain. */
293 numUsed = numFree = 0;
294 rover = pool->frontLink;
295 for (x = 0; x < NUM_WHICH; x++)
297 /* End of list? Stop. */
298 if (sequence->which[x] == END)
299 break;
301 /* Get the link this is. */
302 atId = sequence->which[x] & FREE_MASK;
303 at = links[atId];
305 /* Must be this one. */
306 sjme_unit_equalP(test, rover, at,
307 "Incorrect pointer %p != %p... %d.%d.%d?",
308 rover, at, scenario, linkNum, x);
310 /* Is the block free or not? */
311 if (atId != FRONT && atId != BACK)
313 /* Is this block free? */
314 isFree = (rover->space == SJME_ALLOC_POOL_SPACE_FREE);
316 /* The freeness should match. */
317 wantFree = ((sequence->which[x] & FREE) != 0);
318 sjme_unit_equalI(test,
319 isFree, wantFree,
320 "Incorrect freeness %d.%d.%d?", scenario, linkNum, x);
322 /* Count up. */
323 if (isFree)
324 numFree++;
325 else
326 numUsed++;
329 /* Go the next link. */
330 rover = rover->next;
333 /* Free and used counts should match. */
334 sjme_unit_equalI(test, numFree, sequence->numFree,
335 "Free match incorrect %d.%d?", scenario, linkNum);
336 sjme_unit_equalI(test, numUsed, sequence->numUsed,
337 "Free match incorrect %d.%d?", scenario, linkNum);
341 /* Success! */
342 return SJME_TEST_RESULT_PASS;