Indentations break the feed.
[SquirrelJME.git] / nanocoat / lib / base / list.c
blob001baca3076be9c6ba8b007b276991c33dcc34a5
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>
11 #include <stdarg.h>
13 #include "sjme/list.h"
14 #include "sjme/alloc.h"
15 #include "sjme/debug.h"
16 #include "sjme/util.h"
18 /**
19 * Contains new list data information.
21 * @since 2023/12/17
23 typedef struct sjme_list_newData
25 /** The allocation size of the list. */
26 sjme_jint allocSize;
28 /** The resultant list pointer. */
29 sjme_pointer outList;
30 } sjme_list_newData;
32 static sjme_errorCode sjme_list_newInit(
33 sjme_attrOutNotNull sjme_list_newData* newData,
34 sjme_attrInNotNull sjme_alloc_pool* inPool,
35 sjme_attrInPositive sjme_jint elementSize,
36 sjme_attrInPositive sjme_jint rootElementSize,
37 sjme_attrInPositive sjme_jint elementOffset,
38 sjme_attrInValue sjme_jint pointerCheck,
39 sjme_attrInNotNull sjme_basicTypeId basicTypeId,
40 sjme_attrInPositive sjme_jint numPointerStars,
41 sjme_attrInPositive sjme_jint length,
42 sjme_attrInPositive sjme_jint extraFill)
44 sjme_errorCode error;
45 sjme_list_sjme_jint* fakeList;
47 if (inPool == NULL || newData == NULL)
48 return SJME_ERROR_NULL_ARGUMENTS;
50 if (elementSize <= 0 || elementOffset <= 0 || pointerCheck <= 0 ||
51 basicTypeId < 0 || basicTypeId >= SJME_NUM_BASIC_TYPE_IDS ||
52 numPointerStars < 0 || length < 0 || rootElementSize <= 0 ||
53 extraFill < 0)
54 return SJME_ERROR_INVALID_ARGUMENT;
56 /* Contains root elements only? */
57 if (numPointerStars == 0)
58 newData->allocSize = elementOffset + (rootElementSize * length) +
59 extraFill;
61 /* Is a list of pointer types. */
62 else
63 newData->allocSize = elementOffset + (elementSize * length) +
64 extraFill;
66 /* Underflow? */
67 if (newData->allocSize <= 0)
68 return SJME_ERROR_INVALID_ARGUMENT;
70 /* Allocate list. */
71 if (sjme_error_is(error = sjme_alloc(inPool, newData->allocSize,
72 &newData->outList)) || newData->outList == NULL)
73 return sjme_error_default(error);
75 /* Store list length. */
76 fakeList = (sjme_list_sjme_jint*)newData->outList;
77 fakeList->length = length;
78 fakeList->elementSize = elementSize;
79 fakeList->elementOffset = elementOffset;
81 /* Success! */
82 return SJME_ERROR_NONE;
85 sjme_errorCode sjme_list_allocR(
86 sjme_attrInNotNull sjme_alloc_pool* inPool,
87 sjme_attrInPositive sjme_jint inLength,
88 sjme_attrOutNotNull sjme_pointer* outList,
89 sjme_attrInPositive sjme_jint elementSize,
90 sjme_attrInPositive sjme_jint elementOffset,
91 sjme_attrInValue sjme_jint pointerCheck
92 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL)
94 sjme_errorCode error;
95 sjme_pointer result;
96 sjme_jint size;
98 if (inPool == NULL || outList == NULL)
99 return SJME_ERROR_NULL_ARGUMENTS;
101 if (inLength < 0 || elementSize <= 0 || elementOffset <= 0 ||
102 pointerCheck <= 0)
103 return SJME_ERROR_INVALID_ARGUMENT;
105 /* Calculate the size of the list. */
106 size = elementOffset + (elementSize * inLength);
107 if (size <= 0)
108 return SJME_ERROR_INVALID_ARGUMENT;
110 /* Forward allocation. */
111 result = NULL;
112 #if defined(SJME_CONFIG_DEBUG)
113 if (sjme_error_is(error = sjme_allocR(inPool, size,
114 &result SJME_DEBUG_ONLY_COMMA SJME_DEBUG_FILE_LINE_COPY)) ||
115 result == NULL)
116 #else
117 if (sjme_error_is(error = sjme_alloc(inPool, size, &result)) ||
118 result == NULL)
119 #endif
120 return sjme_error_default(error);
122 /* Perform direct list initialization. */
123 sjme_list_directInitR(inLength, result, elementSize, elementOffset,
124 pointerCheck);
126 /* Give the result! */
127 *outList = result;
128 return SJME_ERROR_NONE;
131 sjme_errorCode sjme_list_copyR(
132 sjme_attrInNotNull sjme_alloc_pool* inPool,
133 sjme_attrInPositive sjme_jint inNewLength,
134 sjme_attrInNotNull sjme_pointer inOldList,
135 sjme_attrOutNotNull sjme_pointer* outNewList,
136 sjme_attrInPositive sjme_jint elementSize,
137 sjme_attrInPositive sjme_jint elementOffset,
138 sjme_attrInValue sjme_jint pointerCheck
139 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_DECL_FILE_LINE_FUNC_OPTIONAL)
141 sjme_errorCode error;
142 sjme_jint i, limit;
143 sjme_list_sjme_jint* fakeOld;
144 sjme_list_sjme_jint* fakeNew;
146 if (inPool == NULL || inOldList == NULL || outNewList == NULL)
147 return SJME_ERROR_NULL_ARGUMENTS;
149 if (inNewLength < 0)
150 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
152 /* Map fake. */
153 fakeOld = (sjme_list_sjme_jint*)inOldList;
155 /* Wrong element size and/or offset? Might be different types. */
156 if (fakeOld->elementSize != elementSize ||
157 fakeOld->elementOffset != elementOffset)
158 return SJME_ERROR_INVALID_ARGUMENT;
160 /* Allocate new list first. */
161 if (sjme_error_is(error = sjme_list_allocR(inPool,
162 inNewLength, (sjme_pointer*)&fakeNew, elementSize,
163 elementOffset, pointerCheck
164 SJME_DEBUG_ONLY_COMMA SJME_DEBUG_FILE_LINE_COPY)))
165 return sjme_error_default(error);
167 /* Copy over elements with direct memory copy. */
168 limit = (fakeOld->length < inNewLength ? fakeOld->length : inNewLength);
169 memmove((sjme_pointer)(((sjme_intPointer)fakeNew) + elementOffset),
170 (sjme_pointer)(((sjme_intPointer)fakeOld) + elementOffset),
171 elementSize * limit);
173 /* Success! */
174 *outNewList = fakeNew;
175 return SJME_ERROR_NONE;
178 sjme_errorCode sjme_list_directInitR(
179 sjme_attrInPositive sjme_jint inLength,
180 sjme_attrOutNotNull sjme_pointer outList,
181 sjme_attrInPositive sjme_jint elementSize,
182 sjme_attrInPositive sjme_jint elementOffset,
183 sjme_attrInValue sjme_jint pointerCheck)
185 sjme_jint size;
186 sjme_list_sjme_jint* fakeList;
188 if (outList == NULL)
189 return SJME_ERROR_NULL_ARGUMENTS;
191 if (inLength < 0 || elementSize <= 0 || elementOffset <= 0 ||
192 pointerCheck <= 0)
193 return SJME_ERROR_INVALID_ARGUMENT;
195 /* Calculate the size of the list. */
196 size = elementOffset + (elementSize * inLength);
197 if (size <= 0)
198 return SJME_ERROR_INVALID_ARGUMENT;
200 /* Seed with a fake list. */
201 fakeList = outList;
203 /* Set sizes of the resultant list. */
204 fakeList->length = inLength;
205 fakeList->elementSize = elementSize;
206 fakeList->elementOffset = elementOffset;
208 /* Success! */
209 return SJME_ERROR_NONE;
212 sjme_errorCode sjme_list_flattenArgCV(
213 sjme_attrInNotNull sjme_alloc_pool* inPool,
214 sjme_attrOutNotNull sjme_list_sjme_lpstr** outList,
215 sjme_attrInPositive sjme_jint argC,
216 sjme_attrInNotNull sjme_lpcstr* argV)
218 sjme_errorCode error;
219 sjme_list_newData newData;
220 sjme_list_sjme_lpstr* result;
221 sjme_jint extraFill, i, len;
222 sjme_lpcstr arg;
223 sjme_pointer destPtr;
225 if (inPool == NULL || outList == NULL || argV == NULL)
226 return SJME_ERROR_NULL_ARGUMENTS;
228 if (argC < 0)
229 return SJME_ERROR_INVALID_ARGUMENT;
231 /* Determine the amount of extra fill to store. */
232 extraFill = 0;
233 for (i = 0; i < argC; i++)
235 /* Get next, skip any NULLs. */
236 arg = argV[i];
237 if (arg == NULL)
238 continue;
240 /* Determine length of string. */
241 /* Use normal string length because we treat everything as a char */
242 /* and we do not want to handle modified UTF-8. */
243 /* Count string along with NUL terminator. */
244 extraFill += strlen(arg) + 1;
247 /* Overflow? */
248 if (extraFill < 0)
249 return SJME_ERROR_INVALID_ARGUMENT;
251 /* Common initialization of new lists. */
252 error = SJME_ERROR_UNKNOWN;
253 memset(&newData, 0, sizeof(newData));
254 if (sjme_error_is(error = sjme_list_newInit(&newData,
255 inPool, sizeof(sjme_lpstr),
256 sizeof(sjme_lpstr),
257 offsetof(sjme_list_sjme_lpstr, elements), 4,
258 SJME_BASIC_TYPE_ID_OBJECT, 1, argC,
259 extraFill)))
260 return sjme_error_default(error);
262 /* Map result. */
263 result = (sjme_list_sjme_lpstr*)newData.outList;
265 /* The destination pointer is at the very end of the element set. */
266 destPtr = &result->elements[argC];
268 /* Copy strings into sub-splices. */
269 for (i = 0; i < argC; i++)
271 /* Get next, skip any NULLs. */
272 arg = argV[i];
273 if (arg == NULL)
274 continue;
276 /* Element points to this address. */
277 result->elements[i] = destPtr;
279 /* Copy entire string chunk here. */
280 len = strlen(arg) + 1;
281 memmove(destPtr, arg, len);
283 /* Move up pointer. */
284 destPtr = (sjme_pointer)(((intptr_t)destPtr) + len);
287 /* Output resultant list. */
288 *outList = result;
289 return SJME_ERROR_NONE;
292 sjme_errorCode sjme_list_flattenArgNul(
293 sjme_attrInNotNull sjme_alloc_pool* inPool,
294 sjme_attrOutNotNull sjme_list_sjme_lpcstr** outList,
295 sjme_attrInNotNull sjme_lpcstr inNulString)
297 sjme_jint count, i;
298 sjme_lpcstr at;
299 sjme_lpcstr* argV;
301 if (inPool == NULL || outList == NULL || inNulString == NULL)
302 return SJME_ERROR_NULL_ARGUMENTS;
304 /* Determine the number of strings within. */
305 count = 0;
306 for (at = inNulString; *at != '\0'; at += strlen(at) + 1)
307 count++;
309 /* Allocate. */
310 argV = sjme_alloca(count * sizeof(*argV));
311 if (argV == NULL)
312 return sjme_error_outOfMemory(inPool, 0);
314 /* Allocate temporary argument set. */
315 memset(argV, 0, count * sizeof(*argV));
316 i = 0;
317 for (at = inNulString; *at != '\0' && i < count;
318 at += strlen(at) + 1, i++)
319 argV[i] = at;
321 /* Perform the flattening. */
322 return sjme_list_flattenArgCV(inPool,
323 (sjme_list_sjme_lpstr**)outList, count, argV);
326 sjme_errorCode sjme_list_newAR(
327 sjme_attrInNotNull sjme_alloc_pool* inPool,
328 sjme_attrInPositive sjme_jint elementSize,
329 sjme_attrInPositive sjme_jint rootElementSize,
330 sjme_attrInPositive sjme_jint elementOffset,
331 sjme_attrInValue sjme_jint pointerCheck,
332 sjme_attrInNotNull sjme_basicTypeId basicTypeId,
333 sjme_attrInPositive sjme_jint numPointerStars,
334 sjme_attrInPositive sjme_jint length,
335 sjme_attrOutNotNull sjme_pointer* outList,
336 sjme_attrInNotNull sjme_pointer inElements)
338 sjme_errorCode error;
339 sjme_list_newData newData;
340 sjme_jint at, toOff, fromOff;
341 sjme_pointer toPtr;
342 sjme_pointer fromPtr;
344 /* Common initialization of new lists. */
345 error = SJME_ERROR_UNKNOWN;
346 memset(&newData, 0, sizeof(newData));
347 if (sjme_error_is(error = sjme_list_newInit(&newData,
348 inPool, elementSize, rootElementSize, elementOffset, pointerCheck,
349 basicTypeId, numPointerStars, length, 0)))
350 return sjme_error_default(error);
352 /* Because the input is a sequential "array", we can just copy it all. */
353 /* This can turn out to be a very fast operation. */
354 memmove((sjme_pointer)(((intptr_t)newData.outList) + elementOffset),
355 inElements, elementSize * length);
357 /* Return resultant list. */
358 *outList = newData.outList;
359 return SJME_ERROR_NONE;
362 sjme_errorCode sjme_list_newVR(
363 sjme_attrInNotNull sjme_alloc_pool* inPool,
364 sjme_attrInPositive sjme_jint elementSize,
365 sjme_attrInPositive sjme_jint rootElementSize,
366 sjme_attrInPositive sjme_jint elementOffset,
367 sjme_attrInValue sjme_jint pointerCheck,
368 sjme_attrInNotNull sjme_basicTypeId basicTypeId,
369 sjme_attrInPositive sjme_jint numPointerStars,
370 sjme_attrInPositive sjme_jint length,
371 sjme_attrOutNotNull sjme_pointer* outList,
372 ...)
374 va_list list;
375 sjme_errorCode result;
377 va_start(list, outList);
379 result = sjme_list_newVAR(inPool, elementSize, rootElementSize,
380 elementOffset, pointerCheck, basicTypeId, numPointerStars,
381 length, outList, list);
383 va_end(list);
385 return result;
388 sjme_errorCode sjme_list_newVAR(
389 sjme_attrInNotNull sjme_alloc_pool* inPool,
390 sjme_attrInPositive sjme_jint elementSize,
391 sjme_attrInPositive sjme_jint rootElementSize,
392 sjme_attrInPositive sjme_jint elementOffset,
393 sjme_attrInValue sjme_jint pointerCheck,
394 sjme_attrInNotNull sjme_basicTypeId basicTypeId,
395 sjme_attrInPositive sjme_jint numPointerStars,
396 sjme_attrInPositive sjme_jint length,
397 sjme_attrOutNotNull sjme_pointer* outList,
398 va_list elements)
400 #define SJME_BLA(basicType, cType, pType) \
401 case SJME_TOKEN_PASTE_PP(SJME_BASIC_TYPE_ID_, basicType): \
402 *((cType*)atPtr) = va_arg(elements, pType); \
403 break
405 sjme_errorCode error;
406 sjme_list_newData newData;
407 sjme_jint at, off;
408 sjme_pointer atPtr;
410 /* Common initialization of new lists. */
411 error = SJME_ERROR_UNKNOWN;
412 memset(&newData, 0, sizeof(newData));
413 if (sjme_error_is(error = sjme_list_newInit(&newData,
414 inPool, elementSize, rootElementSize, elementOffset, pointerCheck,
415 basicTypeId, numPointerStars, length, 0)))
416 return sjme_error_default(error);
418 /* Store elements from variadic arguments. */
419 for (at = 0, off = elementOffset; at < length; at++, off += elementSize)
421 /* Calculate the base pointer address. */
422 atPtr = (sjme_pointer)(((intptr_t)newData.outList) + off);
424 /* Read in depending on the basic type. */
425 switch (basicTypeId)
427 SJME_BLA(BOOLEAN, sjme_jboolean, int);
428 SJME_BLA(BYTE, sjme_jbyte, int);
429 SJME_BLA(SHORT, sjme_jshort, int);
430 SJME_BLA(CHARACTER, sjme_jchar, int);
431 SJME_BLA(INTEGER, sjme_jint, sjme_jint);
432 SJME_BLA(LONG, sjme_jlong, sjme_jlong);
433 SJME_BLA(FLOAT, sjme_jfloat, sjme_jfloat);
434 SJME_BLA(DOUBLE, sjme_jdouble, sjme_jdouble);
435 SJME_BLA(OBJECT, sjme_pointer, sjme_pointer);
437 /* Type not implemented. */
438 default:
439 sjme_todo("Implement: %d", basicTypeId);
440 return SJME_ERROR_NOT_IMPLEMENTED;
444 /* Return resultant list. */
445 *outList = newData.outList;
446 return SJME_ERROR_NONE;
447 #undef SJME_BLA
450 sjme_errorCode sjme_list_search(
451 sjme_attrInNotNull sjme_pointer inList,
452 sjme_attrInNotNull sjme_comparator comparator,
453 sjme_attrInNotNull sjme_cpointer findWhat,
454 sjme_attrOutNotNull sjme_jint* outIndex)
456 sjme_todo("Implement this?");
457 return SJME_ERROR_NOT_IMPLEMENTED;
460 sjme_errorCode sjme_list_searchBinary(
461 sjme_attrInNotNull sjme_pointer inList,
462 sjme_attrInNotNull sjme_comparator comparator,
463 sjme_attrInNotNull sjme_cpointer findWhat,
464 sjme_attrOutNotNull sjme_jint* outIndex)
466 sjme_todo("Implement this?");
467 return SJME_ERROR_NOT_IMPLEMENTED;
470 sjme_errorCode sjme_list_searchReverse(
471 sjme_attrInNotNull sjme_pointer inList,
472 sjme_attrInNotNull sjme_comparator comparator,
473 sjme_attrInNotNull sjme_cpointer findWhat,
474 sjme_attrOutNotNull sjme_jint* outIndex)
476 sjme_todo("Implement this?");
477 return SJME_ERROR_NOT_IMPLEMENTED;
480 sjme_errorCode sjme_list_sort(
481 sjme_attrInNotNull sjme_pointer inList,
482 sjme_attrInNotNull sjme_comparator comparator)
484 sjme_todo("Implement this?");
485 return SJME_ERROR_NOT_IMPLEMENTED;