1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
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 // -------------------------------------------------------------------------*/
13 #include "sjme/list.h"
14 #include "sjme/alloc.h"
15 #include "sjme/debug.h"
16 #include "sjme/util.h"
19 * Contains new list data information.
23 typedef struct sjme_list_newData
25 /** The allocation size of the list. */
28 /** The resultant list pointer. */
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
)
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 ||
54 return SJME_ERROR_INVALID_ARGUMENT
;
56 /* Contains root elements only? */
57 if (numPointerStars
== 0)
58 newData
->allocSize
= elementOffset
+ (rootElementSize
* length
) +
61 /* Is a list of pointer types. */
63 newData
->allocSize
= elementOffset
+ (elementSize
* length
) +
67 if (newData
->allocSize
<= 0)
68 return SJME_ERROR_INVALID_ARGUMENT
;
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
;
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
)
98 if (inPool
== NULL
|| outList
== NULL
)
99 return SJME_ERROR_NULL_ARGUMENTS
;
101 if (inLength
< 0 || elementSize
<= 0 || elementOffset
<= 0 ||
103 return SJME_ERROR_INVALID_ARGUMENT
;
105 /* Calculate the size of the list. */
106 size
= elementOffset
+ (elementSize
* inLength
);
108 return SJME_ERROR_INVALID_ARGUMENT
;
110 /* Forward allocation. */
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
)) ||
117 if (sjme_error_is(error
= sjme_alloc(inPool
, size
, &result
)) ||
120 return sjme_error_default(error
);
122 /* Perform direct list initialization. */
123 sjme_list_directInitR(inLength
, result
, elementSize
, elementOffset
,
126 /* Give the 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
;
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
;
150 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
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
);
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
)
186 sjme_list_sjme_jint
* fakeList
;
189 return SJME_ERROR_NULL_ARGUMENTS
;
191 if (inLength
< 0 || elementSize
<= 0 || elementOffset
<= 0 ||
193 return SJME_ERROR_INVALID_ARGUMENT
;
195 /* Calculate the size of the list. */
196 size
= elementOffset
+ (elementSize
* inLength
);
198 return SJME_ERROR_INVALID_ARGUMENT
;
200 /* Seed with a fake list. */
203 /* Set sizes of the resultant list. */
204 fakeList
->length
= inLength
;
205 fakeList
->elementSize
= elementSize
;
206 fakeList
->elementOffset
= elementOffset
;
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
;
223 sjme_pointer destPtr
;
225 if (inPool
== NULL
|| outList
== NULL
|| argV
== NULL
)
226 return SJME_ERROR_NULL_ARGUMENTS
;
229 return SJME_ERROR_INVALID_ARGUMENT
;
231 /* Determine the amount of extra fill to store. */
233 for (i
= 0; i
< argC
; i
++)
235 /* Get next, skip any NULLs. */
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;
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
),
257 offsetof(sjme_list_sjme_lpstr
, elements
), 4,
258 SJME_BASIC_TYPE_ID_OBJECT
, 1, argC
,
260 return sjme_error_default(error
);
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. */
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. */
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
)
301 if (inPool
== NULL
|| outList
== NULL
|| inNulString
== NULL
)
302 return SJME_ERROR_NULL_ARGUMENTS
;
304 /* Determine the number of strings within. */
306 for (at
= inNulString
; *at
!= '\0'; at
+= strlen(at
) + 1)
310 argV
= sjme_alloca(count
* sizeof(*argV
));
312 return sjme_error_outOfMemory(inPool
, 0);
314 /* Allocate temporary argument set. */
315 memset(argV
, 0, count
* sizeof(*argV
));
317 for (at
= inNulString
; *at
!= '\0' && i
< count
;
318 at
+= strlen(at
) + 1, i
++)
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
;
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
,
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
);
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
,
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); \
405 sjme_errorCode error
;
406 sjme_list_newData newData
;
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. */
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. */
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
;
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
;