Compile fixes.
[SquirrelJME.git] / nanocoat / lib / base / util.c
blobc0f3d0a575d2f71566c26f410f38d26569bfccd8
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 "sjme/stdTypes.h"
13 #include "sjme/util.h"
14 #include "sjme/debug.h"
16 sjme_jint sjme_compare_null(
17 sjme_attrInNullable sjme_cpointer a,
18 sjme_attrInNullable sjme_cpointer b)
20 /* Nulls before non-null. */
21 if (a == NULL)
23 if (b == NULL)
24 return 0;
25 else
26 return -1;
29 return 1;
32 /**
33 * Initializes the random number generator.
35 * @param outRandom The random state to initialize.
36 * @param seedHi The high seed value.
37 * @param seedLo The low seed value.
38 * @return Returns @c SJME_JNI_TRUE on success.
39 * @since 2023/12/02
41 sjme_errorCode sjme_randomInit(
42 sjme_attrInOutNotNull sjme_random* outRandom,
43 sjme_attrInValue sjme_jint seedHi,
44 sjme_attrInValue sjme_jint seedLo)
46 sjme_todo("Implement this?");
47 return SJME_ERROR_NOT_IMPLEMENTED;
50 sjme_errorCode sjme_randomInitL(
51 sjme_attrInOutNotNull sjme_random* outRandom,
52 sjme_attrInValue sjme_jlong seed)
54 sjme_todo("Implement this?");
55 return SJME_ERROR_NOT_IMPLEMENTED;
58 sjme_errorCode sjme_randomNextInt(
59 sjme_attrInOutNotNull sjme_random* random,
60 sjme_attrOutNotNull sjme_jint* outValue)
62 sjme_todo("Implement this?");
63 return SJME_ERROR_NOT_IMPLEMENTED;
66 sjme_errorCode sjme_randomNextIntMax(
67 sjme_attrInOutNotNull sjme_random* random,
68 sjme_attrOutNotNull sjme_jint* outValue,
69 sjme_attrInPositiveNonZero sjme_jint maxValue)
71 sjme_todo("Implement this?");
72 return SJME_ERROR_NOT_IMPLEMENTED;
75 sjme_jint sjme_string_charAt(sjme_lpcstr string, sjme_jint index)
77 sjme_jint at;
78 sjme_jchar c;
79 sjme_lpcstr p;
81 /* Not valid? */
82 if (string == NULL)
83 return -1;
85 /* Read until end of string. */
86 at = 0;
87 for (p = string; *p != 0;)
89 /* Decode character. */
90 c = sjme_string_decodeChar(p, &p);
92 /* Not valid? */
93 if (c < 0)
94 return -1;
96 /* If this is the desired character then return it. */
97 if ((at++) == index)
98 return c;
101 /* Could not find character. */
102 return -1;
105 sjme_jint sjme_string_compareN(sjme_lpcstr aString, sjme_jint aLen,
106 sjme_lpcstr bString, sjme_jint bLen)
108 sjme_jint result, limit;
110 /* Compare null. */
111 if (aString == NULL || bString == NULL)
112 return sjme_compare_null(aString, bString);
114 /* Determine the max number of characters to compare. */
115 if (aLen < bLen)
116 limit = aLen;
117 else
118 limit = bLen;
120 /* Compare strings up to the limit. */
121 result = strncmp(aString, bString, limit);
122 if (result != 0)
123 return result;
125 /* If the lengths differ, smaller is first. */
126 if (aLen != bLen)
127 return aLen - bLen;
129 /* Equal otherwise. */
130 return 0;
133 sjme_jint sjme_string_decodeChar(sjme_lpcstr at, sjme_lpcstr* stringP)
135 sjme_jubyte c;
136 sjme_jint result;
138 if (at == NULL)
139 return -1;
141 /* Read first character. */
142 c = (*(at++)) & 0xFF;
144 /* Invalid, cannot be this. */
145 if (c == 0)
146 return -1;
148 /* Single byte character? */
149 if ((c & 0x80) == 0)
150 result = c;
152 /* Double byte character? */
153 else if ((c & 0xE0) == 0xC0)
155 /* Upper bits. */
156 result = (c & 0x1F) << 6;
158 /* Read next. */
159 c = (*(at++)) & 0xFF;
161 /* Invalid continuation? */
162 if ((c & 0xC0) != 0x80)
163 return -1;
165 /* Lower bits. */
166 result |= (c & 0x3F);
168 /* Too low of a character? */
169 if (result < 0x80 && result != 0)
170 return -1;
173 /* Triple byte character. */
174 else if ((c & 0xF0) == 0xE0)
176 /* Upper bits. */
177 result = (c & 0x0F) << 12;
179 /* Read next. */
180 c = (*(at++)) & 0xFF;
182 /* Invalid continuation? */
183 if ((c & 0xC0) != 0x80)
184 return -1;
186 /* Middle bits. */
187 result |= (c & 0x3F) << 6;
189 /* Read next. */
190 c = (*(at++)) & 0xFF;
192 /* Invalid continuation? */
193 if ((c & 0xC0) != 0x80)
194 return -1;
196 /* Lower bits. */
197 result |= (c & 0x3F);
199 /* Too low of a character? */
200 if (result < 0x800)
201 return -1;
204 /* Invalid sequence. */
205 else
206 return -1;
208 /* Return the result. */
209 if (stringP != NULL)
210 *stringP = at;
211 return result;
214 sjme_jint sjme_string_hash(sjme_lpcstr string)
216 sjme_jint result;
217 sjme_jint c;
218 sjme_lpcstr p;
220 if (string == NULL)
221 return 0;
223 /* Initial result. */
224 result = 0;
226 /* Read until end of string. */
227 for (p = string; *p != 0;)
229 /* Decode character. */
230 c = sjme_string_decodeChar(p, &p);
232 /* Not valid. */
233 if (c < 0)
234 return -1;
236 /* Calculate the hashCode(), the JavaDoc gives the following formula:
237 * == s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] .... yikes! */
238 result = ((result << 5) - result) + (sjme_jint)c;
241 /* Return calculated result. */
242 return result;
245 sjme_jint sjme_string_hashN(sjme_lpcstr string, sjme_jint limit)
247 sjme_jint result;
248 sjme_jint c;
249 sjme_lpcstr p, end;
251 if (string == NULL || limit <= 0)
252 return 0;
254 /* Initial result. */
255 result = 0;
257 /* Read until end of string. */
258 for (p = string, end = p + limit; *p != 0 && p < end;)
260 /* Decode character. */
261 c = sjme_string_decodeChar(p, &p);
263 /* Not valid. */
264 if (c < 0)
265 return -1;
267 /* Calculate the hashCode(), the JavaDoc gives the following formula:
268 * == s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] .... yikes! */
269 result = ((result << 5) - result) + (sjme_jint)c;
272 /* Return calculated result. */
273 return result;
276 sjme_jint sjme_string_length(sjme_lpcstr string)
278 sjme_jint result;
279 sjme_jint c;
280 sjme_lpcstr p;
282 if (string == NULL)
283 return -1;
285 /* Read until end of string. */
286 result = 0;
287 for (p = string; *p != 0;)
289 /* Decode character. */
290 c = sjme_string_decodeChar(p, &p);
292 /* Not valid? */
293 if (c < 0)
294 return -1;
296 /* Counts as a single character. */
297 result++;
300 /* Use whatever length we found. */
301 return result;
304 sjme_jint sjme_string_lengthN(sjme_lpcstr string, sjme_jint limit)
306 sjme_jint result;
307 sjme_jint c;
308 sjme_lpcstr p;
310 if (string == NULL || limit < 0)
311 return -1;
313 /* Read until end of string. */
314 result = 0;
315 for (p = string; *p != 0 && result < limit;)
317 /* Decode character. */
318 c = sjme_string_decodeChar(p, &p);
320 /* Not valid? */
321 if (c < 0)
322 return -1;
324 /* Counts as a single character. */
325 result++;
328 /* Use whatever length we found. */
329 return result;
332 sjme_errorCode sjme_swap_shu8_uint_memmove(
333 sjme_attrInNotNull sjme_pointer dest,
334 sjme_attrInNotNull sjme_pointer src,
335 sjme_attrInPositiveNonZero sjme_jint n)
337 sjme_juint* iDest;
338 sjme_jint i, count;
340 if (dest == NULL || src == NULL)
341 return SJME_ERROR_NULL_ARGUMENTS;
343 if (n < 0)
344 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
346 /* Pointless? */
347 if (n == 0)
348 return SJME_ERROR_NONE;
350 /* Perform initial move. */
351 memmove(dest, src, n);
353 /* Then perform swapping. */
354 iDest = dest;
355 count = n / sizeof(sjme_juint);
356 for (i = 0; i < count; i++)
357 iDest[i] = sjme_swap_uint(iDest[i] << 8);
359 /* Success! */
360 return SJME_ERROR_NONE;
363 sjme_errorCode sjme_swap_uint_memmove(
364 sjme_attrInNotNull sjme_pointer dest,
365 sjme_attrInNotNull sjme_pointer src,
366 sjme_attrInPositiveNonZero sjme_jint n)
368 sjme_juint* iDest;
369 sjme_jint i, count;
371 if (dest == NULL || src == NULL)
372 return SJME_ERROR_NULL_ARGUMENTS;
374 if (n < 0)
375 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
377 /* Pointless? */
378 if (n == 0)
379 return SJME_ERROR_NONE;
381 /* Perform initial move. */
382 memmove(dest, src, n);
384 /* Then perform swapping. */
385 iDest = dest;
386 count = n / sizeof(sjme_juint);
387 for (i = 0; i < count; i++)
388 iDest[i] = sjme_swap_uint(iDest[i]);
390 /* Success! */
391 return SJME_ERROR_NONE;
394 sjme_juint sjme_util_intBitCountU(
395 sjme_attrInValue sjme_juint v)
397 v = v - ((v >> 1) & UINT32_C(0x55555555));
398 v = (v & UINT32_C(0x33333333)) + ((v >> 2) & UINT32_C(0x33333333));
399 return ((v + (v >> 4) & UINT32_C(0xF0F0F0F)) * UINT32_C(0x1010101)) >> 24;
402 sjme_juint sjme_util_intHighestOneBit(
403 sjme_attrInValue sjme_juint v)
405 v = v | (v >> 1);
406 v = v | (v >> 2);
407 v = v | (v >> 4);
408 v = v | (v >> 8);
409 v = v | (v >> 16);
411 return v - (v >> 1);
414 sjme_juint sjme_util_intLeadingZeroesU(
415 sjme_attrInValue sjme_juint v)
417 v = v | (v >> 1);
418 v = v | (v >> 2);
419 v = v | (v >> 4);
420 v = v | (v >> 8);
421 v = v | (v >> 16);
423 return sjme_util_intBitCountU(~v);
426 sjme_juint sjme_util_intOverShiftU(
427 sjme_attrInValue sjme_juint v,
428 sjme_attrInRange(-32, 32) sjme_jint sh)
430 /* Shifting more than this always results in zero. */
431 if (sh <= -32 || sh >= 32)
432 return 0;
434 /* Shift by zero does nothing. */
435 else if (sh == 0)
436 return v;
438 /* Otherwise the shifted amount. */
439 if (sh < 0)
440 return v >> (sjme_juint)(-sh);
441 return v << (sjme_juint)sh;
444 sjme_jint sjme_util_intReverse(sjme_jint v)
446 return (sjme_jint)sjme_util_intReverseU((sjme_juint)v);
449 sjme_juint sjme_util_intReverseU(sjme_juint v)
451 v = (((v & UINT32_C(0xAAAAAAAA)) >> 1) |
452 ((v & UINT32_C(0x55555555)) << 1));
453 v = (((v & UINT32_C(0xCCCCCCCC)) >> 2) |
454 ((v & UINT32_C(0x33333333)) << 2));
455 v = (((v & UINT32_C(0xF0F0F0F0)) >> 4) |
456 ((v & UINT32_C(0x0F0F0F0F)) << 4));
457 v = (((v & UINT32_C(0xFF00FF00)) >> 8) |
458 ((v & UINT32_C(0x00FF00FF)) << 8));
460 return ((v >> 16) | (v << 16));
463 sjme_errorCode sjme_util_intToBinary(
464 sjme_attrInNotNullBuf(destLen) sjme_lpstr destBuf,
465 sjme_attrInPositiveNonZero sjme_jint destLen,
466 sjme_attrInValue sjme_juint inVal,
467 sjme_attrInPositiveNonZero sjme_juint bitCount)
469 sjme_juint sh;
470 sjme_cchar* wp;
472 if (destBuf == NULL)
473 return SJME_ERROR_NULL_ARGUMENTS;
475 /* Correct bit count. */
476 if (bitCount <= 0 || bitCount > 32)
477 bitCount = 32;
479 /* 0b([01]*32). */
480 if (destLen <= (3 + bitCount))
481 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
483 /* Start with the prefix. */
484 wp = destBuf;
485 *(wp++) = '0';
486 *(wp++) = 'b';
488 /* Start from the top and go down. */
489 for (sh = (1 << (bitCount - 1)); sh > 0; sh >>= 1)
490 *(wp++) = ((inVal & sh) != 0 ? '1' : '0');
492 /* End with NUL. */
493 *(wp++) = '\0';
494 return SJME_ERROR_NONE;
497 sjme_errorCode sjme_util_lpstrTrimEnd(
498 sjme_attrInNotNullBuf(length) sjme_lpstr buf,
499 sjme_attrInPositiveNonZero sjme_jint length)
501 sjme_jint at;
502 sjme_cchar c;
504 if (buf == NULL)
505 return SJME_ERROR_NULL_ARGUMENTS;
507 if (length <= 0)
508 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
510 /* Find end of string first. */
511 for (at = 0; at < length;)
513 if (buf[at] == 0)
515 if (at > 0)
516 at--;
517 break;
520 at++;
523 /* Past the end? */
524 if (at >= length)
525 at = length - 1;
527 /* Remove any whitespace. */
528 while (at >= 0)
530 c = buf[at];
532 /* NUL out whitespace. */
533 if (c == ' ' || c == '\r' || c == '\n' || c == '\t')
534 buf[at--] = 0;
536 /* Nothing here anymore. */
537 else
538 break;
541 /* Success! */
542 return SJME_ERROR_NONE;