Foundationallib  1.0q
A complete Foundationallib for C
foundationallib.h
Go to the documentation of this file.
1 /*
2  * 2023, Gregory Cohen <gregorycohennew@gmail.com>
3  *
4  *
5  * DONATION REQUEST: If this free software has helped you and you find
6  * it valuable, please consider making a donation to support the ongoing
7  * development and maintenance of this project. Your contribution helps
8  * ensure the availability of this library to the community and encourages
9  * further improvements.
10  *
11  *
12  * Donations can be made at:
13  * https://www.paypal.com/paypalme/cfoundationallib
14  *
15  *
16  *
17  * This code is in the public domain.
18  *
19  * You are free to use it for any commercial or noncommercial purpose.
20  *
21  */
22 
23 #ifndef _FOUNDATIONAL_LIB_HEADER_GUARD
24 #define _FOUNDATIONAL_LIB_HEADER_GUARD
25 
26 #ifdef _WIN32
27 #define _CRT_RAND_S
28 #endif
29 
30 #include <stdint.h> /* FOR SIZE_MAX */
31 #include <ctype.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37 
38 /* Make sure memmem() is defined in all cases to avoid warnings or errors. */
39 void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);
40 
41 // structs (types)
42 struct Dict;
43 struct FrozenDict;
44 struct Set;
45 struct FrozenSet;
46 
47 #ifndef FOUNDATIONAL_LIB_AGGRESSIVE_DIE_TYPE
55 #define FOUNDATIONAL_LIB_AGGRESSIVE_DIE_TYPE unsigned char
56 #endif
57 
58 /*
59  * ---------------------------------------------------------------------
60  *
61  * This code is in the Public domain. It is 100% original code, and
62  * wholly in the public domain.
63  *
64  * It is by Gregory Cohen <gregorycohennew@gmail.com>, No Copyright, 2023.
65  *
66  * ---------------------------------------------------------------------
67  *
68  * This code is quite usable. While more and more tests can
69  * be added (currently there is the initial test program, and
70  * another test program that is designed to stress-test every
71  * single function, and a third work-in-progress test suite),
72  * it does not change the fact that this code fundamentally
73  * works. Try out the `run_test_suite` script, and if
74  * everything works, it will tell you in green text that
75  * things work on your system. Any errors or warnings are not
76  * tolerated. This code should be usable for production.
77  * Configure to your needs. Generate your own with a custom
78  * prefix with the script at the top-level of the code.
79  * Philosophy of this is in the 'Articles' folder - and it is
80  * very unequivocal. -Gregory
81  *
82  * ---------------------------------------------------------------------
83  */
84 
85 /* -DFOUNDATIONAL_LIB_UNSAFE_FUNCTIONS_ENABLED=0 to turn off popen() and backticks() and shellescape(). */
86 
92 #ifndef FOUNDATIONAL_LIB_USE_STATIC_ASSERTS_FOR_SAFETY
93 #define FOUNDATIONAL_LIB_USE_STATIC_ASSERTS_FOR_SAFETY 1
94 #endif
95 
96 #if FOUNDATIONAL_LIB_USE_STATIC_ASSERTS_FOR_SAFETY
97 
98 #ifdef __cplusplus
99 #ifndef FOUNDATIONAL_LIB_Static_assert
100 #define FOUNDATIONAL_LIB_Static_assert static_assert
101 #endif
102 #else
103 #ifndef FOUNDATIONAL_LIB_Static_assert
104 #define FOUNDATIONAL_LIB_Static_assert _Static_assert
105 #endif
106 #endif
107 
108 #define FOUNDATIONAL_LIB_STATIC_ASSERT_MSG(true_cond, failure_message) FOUNDATIONAL_LIB_Static_assert((true_cond), failure_message)
109 
110 #define FOUNDATIONAL_LIB_STATIC_ASSERT(true_cond) FOUNDATIONAL_LIB_Static_assert((true_cond), "(" #true_cond ") failed")
111 
112 #define FOUNDATIONAL_LIB_SIZE_STRING_OF_NUMBER_SIZE_PLUS_ZERO_TERMINATOR 21 /* length of "18446744073709551615" plus 1 == 21 */
113 FOUNDATIONAL_LIB_STATIC_ASSERT_MSG((sizeof(size_t) <= 8 && FOUNDATIONAL_LIB_SIZE_STRING_OF_NUMBER_SIZE_PLUS_ZERO_TERMINATOR >= 21), "Increase SIZE_STRING_OF_NUMBER_SIZE_PLUS_ZERO_TERMINATOR to more than 21");
114 
115 #endif
116 #ifndef FOUNDATIONAL_LIB_UNSAFE_FUNCTIONS_ENABLED
117 /* Default true */
118 #define FOUNDATIONAL_LIB_UNSAFE_FUNCTIONS_ENABLED 1
119 #endif
120 
121 #ifndef FOUNDATIONAL_LIB_VA_LIST
122 #define FOUNDATIONAL_LIB_VA_LIST va_list
123 #endif
124 
125 #ifndef FOUNDATIONAL_LIB_VA_START
126 #define FOUNDATIONAL_LIB_VA_START va_start
127 #endif
128 
129 #ifndef FOUNDATIONAL_LIB_VA_ARG
130 #define FOUNDATIONAL_LIB_VA_ARG va_arg
131 #endif
132 
133 #ifndef FOUNDATIONAL_LIB_VA_END
134 #define FOUNDATIONAL_LIB_VA_END va_end
135 #endif
136 
137 #ifdef __GNUC__
138 
139 #ifndef FOUNDATIONAL_LIB_LIBC_LOCKING_IO_OPERATIONS
140 
141 /* Set this to 0 to make the IO faster. */
142 #define FOUNDATIONAL_LIB_LIBC_LOCKING_IO_OPERATIONS 1
143 #endif
144 
145 #ifndef FOUNDATIONAL_LIB_ISSPACE
146 #define FOUNDATIONAL_LIB_ISSPACE __builtin_isspace
147 #endif
148 #ifndef FOUNDATIONAL_LIB_ISALPHA
149 #define FOUNDATIONAL_LIB_ISALPHA __builtin_isalpha
150 #endif
151 #ifndef FOUNDATIONAL_LIB_ISALNUM
152 #define FOUNDATIONAL_LIB_ISALNUM __builtin_isalnum
153 #endif
154 #ifndef FOUNDATIONAL_LIB_ISDIGIT
155 #define FOUNDATIONAL_LIB_ISDIGIT __builtin_isdigit
156 #endif
157 #ifndef FOUNDATIONAL_LIB_ISPRINT
158 #define FOUNDATIONAL_LIB_ISPRINT __builtin_isprint
159 #endif
160 #ifndef FOUNDATIONAL_LIB_ISUPPER
161 #define FOUNDATIONAL_LIB_ISUPPER __builtin_isupper
162 #endif
163 #ifndef FOUNDATIONAL_LIB_ISLOWER
164 #define FOUNDATIONAL_LIB_ISLOWER __builtin_islower
165 #endif
166 
167 #ifndef FOUNDATIONAL_LIB_STRLEN
168 #define FOUNDATIONAL_LIB_STRLEN __builtin_strlen
169 #endif
170 
171 #ifndef FOUNDATIONAL_LIB_PRINTF
172 #define FOUNDATIONAL_LIB_PRINTF __builtin_printf
173 #endif
174 
175 #ifndef FOUNDATIONAL_LIB_SPRINTF
176 #define FOUNDATIONAL_LIB_SPRINTF __builtin_sprintf
177 #endif
178 
179 #ifndef FOUNDATIONAL_LIB_SNPRINTF
180 #define FOUNDATIONAL_LIB_SNPRINTF __builtin_snprintf
181 #endif
182 
183 #ifndef FOUNDATIONAL_LIB_VSNPRINTF
184 #define FOUNDATIONAL_LIB_VSNPRINTF __builtin_vsnprintf
185 #endif
186 
187 #ifndef FOUNDATIONAL_LIB_FPRINTF
188 
189 #if FOUNDATIONAL_LIB_LIBC_LOCKING_IO_OPERATIONS /* Default mode IS thread-safe. */
190 #define FOUNDATIONAL_LIB_FPRINTF __builtin_fprintf
191 #else
192 #define FOUNDATIONAL_LIB_FPRINTF __builtin_fprintf /* GLIBC doesn't have an unlocked version of this. This is not a good thing. */
193 #endif
194 #endif
195 
196 #ifndef FOUNDATIONAL_LIB_FPUTS
197 #if FOUNDATIONAL_LIB_LIBC_LOCKING_IO_OPERATIONS /* Default mode IS thread-safe. */
198 #define FOUNDATIONAL_LIB_FPUTS __builtin_fputs
199 #else
200 #define FOUNDATIONAL_LIB_FPUTS __builtin_fputs_unlocked
201 #endif
202 #endif
203 
204 #ifndef FOUNDATIONAL_LIB_PUTCHAR
205 
206 #if FOUNDATIONAL_LIB_LIBC_LOCKING_IO_OPERATIONS /* Default mode IS thread-safe. */
207 
208 #define FOUNDATIONAL_LIB_PUTCHAR __builtin_putchar
209 #else
210 #define FOUNDATIONAL_LIB_PUTCHAR __builtin_putchar_unlocked
211 #endif
212 #endif
213 
214 #ifndef FOUNDATIONAL_LIB_FPUTC
215 
216 #if FOUNDATIONAL_LIB_LIBC_LOCKING_IO_OPERATIONS /* Default mode IS thread-safe. */
217 
218 #define FOUNDATIONAL_LIB_FPUTC __builtin_fputc
219 #else
220 #define FOUNDATIONAL_LIB_FPUTC __builtin_fputc_unlocked
221 #endif
222 #endif
223 
224 #ifndef FOUNDATIONAL_LIB_STRPBRK
225 #define FOUNDATIONAL_LIB_STRPBRK __builtin_strpbrk
226 #endif
227 
228 /*
229  * benchmark_libc.c output
230  *
231  * memcpy 0.000010
232  *
233  * memcpy copy 0.000005
234  * __builtin_memcpy 0.000003
235  * Custom memcpy() (probably using __builtin_memcpy()) is 2.000000 times faster than default memcpy()
236  * __builtin_memcpy() is 3.333333 times faster than default memcpy()
237  *
238  * This means, theoretically, a 6-day operation could take less than 2 days. That's speed.
239  *
240  */
241 #ifndef FOUNDATIONAL_LIB_MEMCPY
242 #define FOUNDATIONAL_LIB_MEMCPY __builtin_memcpy
243 #endif
244 
245 #ifndef FOUNDATIONAL_LIB_STRLEN
246 #define FOUNDATIONAL_LIB_STRLEN __builtin_strlen
247 #endif
248 
249 #ifndef FOUNDATIONAL_LIB_STRCMP
250 #define FOUNDATIONAL_LIB_STRCMP __builtin_strcmp
251 #endif
252 
253 #ifndef FOUNDATIONAL_LIB_MEMCMP
254 #define FOUNDATIONAL_LIB_MEMCMP __builtin_memcmp
255 #endif
256 
257 #ifndef FOUNDATIONAL_LIB_MEMMOVE
258 #define FOUNDATIONAL_LIB_MEMMOVE __builtin_memmove
259 #endif
260 
261 #ifndef FOUNDATIONAL_LIB_STRCHR
262 #define FOUNDATIONAL_LIB_STRCHR __builtin_strchr
263 #endif
264 
265 #ifndef FOUNDATIONAL_LIB_MEMCHR
266 #define FOUNDATIONAL_LIB_MEMCHR __builtin_memchr
267 #endif
268 
269 #ifndef FOUNDATIONAL_LIB_STRSTR
270 #define FOUNDATIONAL_LIB_STRSTR __builtin_strstr
271 #endif
272 
273 #define __attribute__((nonnull))
274 #define __attribute__((format(printf, 1, 2)))
275 #define __attribute__((warn_unused_result))
276 #define __attribute__((nothrow))
277 #define __attribute__((malloc))
278 
279 #define FOUNDATIONAL_LIB_CONST __attribute__((const))
280 #define __attribute__((pure))
281 
282 #else /* ifdef GNUC */
283 
284 #ifndef FOUNDATIONAL_LIB_PRINTF
285 #define FOUNDATIONAL_LIB_PRINTF printf
286 #endif
287 
288 #ifndef FOUNDATIONAL_LIB_SPRINTF
289 #define FOUNDATIONAL_LIB_SPRINTF sprintf
290 #endif
291 
292 #ifdef FOUNDATIONAL_LIB_SNPRINTF
293 #define FOUNDATIONAL_LIB_SNPRINTF snprintf
294 #endif
295 
296 #ifndef FOUNDATIONAL_LIB_VSNPRINTF
297 #define FOUNDATIONAL_LIB_VSNPRINTF vsnprintf
298 #endif
299 
300 #ifndef FOUNDATIONAL_LIB_FPRINTF
301 #define FOUNDATIONAL_LIB_FPRINTF fprintf
302 #endif
303 
304 #ifndef FOUNDATIONAL_LIB_MEMCPY
305 #define FOUNDATIONAL_LIB_MEMCPY memcpy
306 #endif
307 
308 #ifndef FOUNDATIONAL_LIB_STRLEN
309 #define FOUNDATIONAL_LIB_STRLEN strlen
310 #endif
311 
312 #ifndef FOUNDATIONAL_LIB_STRCMP
313 #define FOUNDATIONAL_LIB_STRCMP strcmp
314 #endif
315 
316 #ifndef FOUNDATIONAL_LIB_MEMCMP
317 #define FOUNDATIONAL_LIB_MEMCMP memcmp
318 #endif
319 
320 #ifndef FOUNDATIONAL_LIB_MEMMOVE
321 #define FOUNDATIONAL_LIB_MEMMOVE memmove
322 #endif
323 
324 #ifndef FOUNDATIONAL_LIB_FPUTS
325 #define FOUNDATIONAL_LIB_FPUTS fputs
326 #endif
327 
328 #ifndef FOUNDATIONAL_LIB_PUTCHAR
329 #define FOUNDATIONAL_LIB_PUTCHAR putchar
330 #endif
331 
332 #ifndef FOUNDATIONAL_LIB_FPUTC
333 #define FOUNDATIONAL_LIB_FPUTC fputc
334 #endif
335 
336 #ifndef FOUNDATIONAL_LIB_STRPBRK
337 #define FOUNDATIONAL_LIB_STRPBRK strpbrk
338 #endif
339 
340 #ifndef FOUNDATIONAL_LIB_STRCHR
341 #define FOUNDATIONAL_LIB_STRCHR
342 #endif
343 
344 #ifndef FOUNDATIONAL_LIB_MEMCHR
345 #define FOUNDATIONAL_LIB_MEMCHR
346 #endif
347 
348 #ifndef FOUNDATIONAL_LIB_STRSTR
349 #define FOUNDATIONAL_LIB_STRSTR strstr
350 #endif
351 
352 #ifndef FOUNDATIONAL_LIB_ISSPACE
353 #define FOUNDATIONAL_LIB_ISSPACE isspace
354 #endif
355 #ifndef FOUNDATIONAL_LIB_ISALPHA
356 #define FOUNDATIONAL_LIB_ISALPHA isalpha
357 #endif
358 #ifndef FOUNDATIONAL_LIB_ISALNUM
359 #define FOUNDATIONAL_LIB_ISALNUM isalnum
360 #endif
361 #ifndef FOUNDATIONAL_LIB_ISDIGIT
362 #define FOUNDATIONAL_LIB_ISDIGIT isdigit
363 #endif
364 #ifndef FOUNDATIONAL_LIB_ISPRINT
365 #define FOUNDATIONAL_LIB_ISPRINT isprint
366 #endif
367 #ifndef FOUNDATIONAL_LIB_ISUPPER
368 #define FOUNDATIONAL_LIB_ISUPPER isupper
369 #endif
370 #ifndef FOUNDATIONAL_LIB_ISLOWER
371 #define FOUNDATIONAL_LIB_ISLOWER islower
372 #endif
373 
374 #if _WIN32
375 #include <sal.h>
376 
377 /* All the functions that use nonnull, also work with declspec. */
378 #define __declspec(noalias)
379 #define FOUNDATIONAL_LIB_PRINTF _Printf_format_string_impl_
380 #define /* not defined for Windows at present. */
381 
382 #define /* not defined for Windows at present. */
383 #define /* not defined for Windows at present. */
384 
385 #define FOUNDATIONAL_LIB_CONST /* not defined for Windows at present. */
386 #define /* not defined for Windows at present. */
387 #else /* if WIN32 */
388 
389 /* All the functions that use nonnull, also work with declspec. */
390 #define /* not defined */
391 #define FOUNDATIONAL_LIB_PRINTF /* not defined */
392 #define /* not defined */
393 
394 #define /* not defined */
395 #define /* not defined */
396 
397 #define FOUNDATIONAL_LIB_CONST /* not defined */
398 #define /* not defined */
399 
400 #endif /* if WIN32 */
401 
402 #endif /* if GNUC */
403 
404 /* For the capacities of FrozenDict and FrozenSet. */
405 #ifndef FOUNDATIONAL_LIB_FROZEN_INITIALIZATION_SIZE_MULTIPLIER
406 #define FOUNDATIONAL_LIB_FROZEN_INITIALIZATION_SIZE_MULTIPLIER 3
407 #endif
408 
409 /* If allocating new strings (an array), how many should be allocated? */
410 #ifndef FOUNDATIONAL_LIB_INITIAL_STRING_ARRAY_ALLOC_COUNT
411 #define FOUNDATIONAL_LIB_INITIAL_STRING_ARRAY_ALLOC_COUNT 0
412 #endif
413 
414 /* If allocating new strings (an array), how much memory should be allocated at first? */
415 #ifndef FOUNDATIONAL_LIB_INITIAL_STRING_ARRAY_ALLOC_SIZE
416 #define FOUNDATIONAL_LIB_INITIAL_STRING_ARRAY_ALLOC_SIZE (sizeof(char *) * 1)
417 #endif
418 
419 #if defined(__GNUC__) || defined(__clang__)
420 #define FOUNDATIONAL_LIB_LIKELY(x) __builtin_expect(!!(x), 1)
421 #define FOUNDATIONAL_LIB_UNLIKELY(x) __builtin_expect(!!(x), 0)
422 #else
423 #define FOUNDATIONAL_LIB_LIKELY(x) (x)
424 #define FOUNDATIONAL_LIB_UNLIKELY(x) (x)
425 #endif
426 
427 #ifndef FOUNDATIONAL_LIB_ASSERT_ARGUMENT_CHECKING
428 #define FOUNDATIONAL_LIB_ASSERT_ARGUMENT_CHECKING 0 /* Argument NULL checks. Disabled by default. */
429 #endif
430 
431 #ifndef FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED
432 #if FOUNDATIONAL_LIB_ASSERT_ARGUMENT_CHECKING
433 #define FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(x) assert(x)
434 #else
435 #define FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(x) /* */
436 #endif
437 #endif /* assert checking. */
438 
439 #ifdef __GNUC__
446 static inline size_t FOUNDATIONAL_LIB_safe_mul(size_t a, size_t b)
447 {
448  size_t result;
449 
450  if (FOUNDATIONAL_LIB_UNLIKELY(__builtin_mul_overflow(a, b, &result)))
451  {
452  /* 0 on error (overflow). */
453  return 0;
454  }
455 
456  return result;
457 }
458 
461 static inline size_t FOUNDATIONAL_LIB_safe_mul_ptr(size_t a, size_t b, size_t *ptr)
462 {
463  if (FOUNDATIONAL_LIB_UNLIKELY(__builtin_mul_overflow(a, b, ptr)))
464  {
465  /* 0 on error (overflow). */
466  return 0;
467  }
468 
469  return 1;
470 }
471 
473 FOUNDATIONAL_LIB_CONST
474 static inline size_t FOUNDATIONAL_LIB_safe_add_2(size_t a, size_t b)
475 {
476  size_t result;
477 
478  if (FOUNDATIONAL_LIB_UNLIKELY(__builtin_add_overflow(a, b, &result)))
479  {
480  /* 0 on error (overflow). */
481  return 0;
482  }
483 
484  return result;
485 }
486 
488 FOUNDATIONAL_LIB_CONST
489 static inline size_t FOUNDATIONAL_LIB_safe_add_3(size_t a, size_t b, size_t c)
490 {
491  size_t result;
492 
493  if (FOUNDATIONAL_LIB_UNLIKELY(__builtin_add_overflow(a, b, &result)) || FOUNDATIONAL_LIB_UNLIKELY(__builtin_add_overflow(result, c, &result)))
494  {
495  /* 0 on error (overflow). */
496  return 0;
497  }
498 
499  return result;
500 }
501 
503 static inline int FOUNDATIONAL_LIB_safe_add_3_ptr(size_t a, size_t b, size_t c, size_t *out)
504 {
505  if (FOUNDATIONAL_LIB_UNLIKELY(__builtin_add_overflow(a, b, out)) || FOUNDATIONAL_LIB_UNLIKELY(__builtin_add_overflow(*out, c, out)))
506  {
507  /* 0 on error (overflow). */
508  return 0;
509  }
510 
511  return 1;
512 }
513 
515 static inline int FOUNDATIONAL_LIB_safe_add_2_ptr(size_t a, size_t b, size_t *out)
516 {
517  if (FOUNDATIONAL_LIB_UNLIKELY(__builtin_add_overflow(a, b, out)))
518  {
519  /* 0 on error (overflow). */
520  return 0;
521  }
522 
523  return 1;
524 }
525 
526 #else /* GNUC */
533 static inline size_t FOUNDATIONAL_LIB_safe_mul(size_t a, size_t b)
534 {
535  size_t result;
536 
537  if (b != 0 && a > SIZE_MAX / b)
538  {
539  /* Overflow */
540  return 0;
541  }
542 
543  result = a * b;
544  return result;
545 }
546 
549 static inline size_t FOUNDATIONAL_LIB_safe_mul_ptr(size_t a, size_t b, size_t *ptr)
550 {
551  if (b != 0 && a > SIZE_MAX / b)
552  {
553  /* Overflow */
554  return 0;
555  }
556 
557  *ptr = a * b;
558  return 1;
559 }
560 
562 FOUNDATIONAL_LIB_CONST
563 static inline size_t FOUNDATIONAL_LIB_safe_add_2(size_t a, size_t b)
564 {
565  size_t result;
566 
567  if (a > SIZE_MAX - b || a + b > SIZE_MAX - c)
568  {
569  /* Overflow */
570  return 0;
571  }
572 
573  result = a + b;
574  return result;
575 }
576 
578 FOUNDATIONAL_LIB_CONST
579 static inline size_t FOUNDATIONAL_LIB_safe_add_3(size_t a, size_t b, size_t c)
580 {
581  size_t result;
582 
583  if (a > SIZE_MAX - b || b > SIZE_MAX - c)
584  {
585  /* Overflow */
586  return 0;
587  }
588 
589  result = a + b + c;
590  return result;
591 }
592 
595 static inline size_t FOUNDATIONAL_LIB_safe_add_2_ptr(size_t a, size_t b, size_t *ptr)
596 {
597  if (a > SIZE_MAX - b)
598  {
599  /* Overflow */
600  return 0;
601  }
602 
603  *ptr = a + b;
604  return 1;
605 }
606 
609 static inline int FOUNDATIONAL_LIB_safe_add_3_ptr(size_t a, size_t b, size_t c, size_t *ptr)
610 {
611  if (a > SIZE_MAX - b || b > SIZE_MAX - c)
612  {
613  /* Overflow */
614  return 0;
615  }
616 
617  *ptr = a + b + c;
618  return 1;
619 }
620 #endif /* GNUC */
621 
622 #define FOUNDATIONAL_LIB_safe_increment(variable, label_if_fails) \
623  if (FOUNDATIONAL_LIB_UNLIKELY(FOUNDATIONAL_LIB_safe_add_2_ptr((variable), 1, &(variable)) == 0)) \
624  goto label_if_fails;
625 
626 // Adjust as needed. On embedded platforms or low memory systems, you might want to change the algorithm to be somewhat lower than 1.5x
627 // new len calculations need to be checked, before and after this, for overflow.
628 #ifndef FOUNDATIONAL_LIB_LOW_MEMORY_USAGE
629 #define FOUNDATIONAL_LIB_LOW_MEMORY_USAGE 12
630 #endif
631 
632 #ifndef FOUNDATIONAL_LIB_ALLOCATOR_DIV_AMOUNT
633 #define FOUNDATIONAL_LIB_ALLOCATOR_DIV_AMOUNT 2
634 #endif
635 
636 // Takes an argument and makes it at least 1 bigger.
637 #ifdef __GNUC__ // Check if GCC compiler is being used
638 
639 FOUNDATIONAL_LIB_CONST
640 static inline size_t FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(size_t old_size_to_add_at_least_one_to)
641 {
642  size_t addition;
643 
644  // In 49 / 50 for example, Would equal 0. We need at least 1 of an increase.
645  // Default div_amount is 2 or in low memory mode 12.
646  // On embedded you could use low amounts.
647 
648  const size_t div_amount = old_size_to_add_at_least_one_to < FOUNDATIONAL_LIB_ALLOCATOR_DIV_AMOUNT ? 1 /* divide by 1 and so double it. */
650  /*
651  * not a really small number (under div amount),
652  * and so use the div amount
653  */
654  ;
655 
656  if (__builtin_add_overflow(old_size_to_add_at_least_one_to, old_size_to_add_at_least_one_to / div_amount, &addition))
657  {
658  /* 0 on error. */
659  return 0;
660  }
661 
662  return addition;
663 }
664 
665 #else /* GNUC */
666 // Fallback implementation for other compilers
667 
668 static inline size_t FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(size_t siz)
669 {
670  // In 49 / 50 for example, Would equal 0. We need at least 1 of an increase.
671  // Default div_amount is 2 or in low memory mode 12.
672  // On embedded you could use low amounts.
673 
674  const size_t div_amount = old_size_to_add_at_least_one_to < FOUNDATIONAL_LIB_ALLOCATOR_DIV_AMOUNT ? 1 /* divide by 1 and so double it. */
676  /*
677  * not a really small number (under div amount),
678  * and so use the div amount
679  */
680  ;
681 
682  // Check for potential overflow before performing the addition
683  if (siz > SIZE_MAX / 2 || siz > (SIZE_MAX - siz) / 2)
684  {
685  /* 0 on error (overflow). */
686  return 0;
687  }
688 
689  // Calculate the new size after 1.5x reallocation
690  const size_t addition = siz + (siz / div_amount);
691 
692  // Return the result of the addition
693  return addition;
694 }
695 
696 #endif
697 
698 /* For copy_file() */
699 #ifndef FOUNDATIONAL_LIB_COPY_SIZE_AMOUNT
700 #define FOUNDATIONAL_LIB_COPY_SIZE_AMOUNT 4096
701 #endif
702 
703 #if FOUNDATIONAL_LIB_UNSAFE_FUNCTIONS_ENABLED
704 /* For backticks() */
705 #ifndef FOUNDATIONAL_LIB_POPEN_INITIAL_ALLOC_SIZE
706 #define FOUNDATIONAL_LIB_POPEN_INITIAL_ALLOC_SIZE 4096
707 #endif
708 #endif
709 
710 /* Choose which functions you want. */
711 
712 #ifndef FOUNDATIONAL_LIB_ATOI
713 #define FOUNDATIONAL_LIB_ATOI atoi
714 #endif
715 
716 /* File IO */
717 
718 #if FOUNDATIONAL_LIB_UNSAFE_FUNCTIONS_ENABLED
719 #ifdef _WIN32
720 #define FOUNDATIONAL_LIB_POPEN _popen
721 #define FOUNDATIONAL_LIB_PCLOSE _pclose
722 #else
723 #define FOUNDATIONAL_LIB_POPEN popen
724 #define FOUNDATIONAL_LIB_PCLOSE pclose
725 #endif
726 #endif
727 
728 #ifndef FOUNDATIONAL_LIB_FERROR
729 #define FOUNDATIONAL_LIB_FERROR ferror
730 #endif
731 
732 #ifdef _WIN32
733 #ifndef FOUNDATIONAL_LIB_FSEEKO
734 #define FOUNDATIONAL_LIB_FSEEKO _fseeki64
735 #endif
736 
737 #ifndef FOUNDATIONAL_LIB_FTELLO
738 #define FOUNDATIONAL_LIB_FTELLO _ftelli64
739 #endif
740 #else
741 #ifndef FOUNDATIONAL_LIB_FSEEKO
742 #define FOUNDATIONAL_LIB_FSEEKO fseeko
743 #endif
744 
745 #ifndef FOUNDATIONAL_LIB_FTELLO
746 #define FOUNDATIONAL_LIB_FTELLO ftello
747 #endif
748 
749 #endif
750 
751 #ifndef FOUNDATIONAL_LIB_FREAD
752 #define FOUNDATIONAL_LIB_FREAD fread
753 #endif
754 
755 #ifndef FOUNDATIONAL_LIB_FWRITE
756 #define FOUNDATIONAL_LIB_FWRITE fwrite
757 #endif
758 
759 #ifndef FOUNDATIONAL_LIB_FOPEN
760 #define FOUNDATIONAL_LIB_FOPEN fopen
761 #endif
762 
763 #ifndef FOUNDATIONAL_LIB_FCLOSE
764 #define FOUNDATIONAL_LIB_FCLOSE fclose
765 #endif
766 
767 /* Memory allocation macros that you can customize */
768 
769 #ifndef FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC
770 #define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC malloc
771 #endif
772 
773 #ifndef FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC
774 #define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC realloc
775 #endif
776 
777 #ifndef FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC
778 #define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC calloc
779 #endif
780 
781 #ifndef FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE
782 #define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE free
783 #endif
784 
785 #ifndef FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP
786 #define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP strdup
787 #endif
788 
792 #ifndef FOUNDATIONAL_LIB_NETWORK_FUNCTIONS_ENABLED
793 #define FOUNDATIONAL_LIB_NETWORK_FUNCTIONS_ENABLED 0
794 #endif
795 
796 #if FOUNDATIONAL_LIB_NETWORK_FUNCTIONS_ENABLED
797 #define FOUNDATIONAL_LIB_INITIAL_NETWORK_DOWNLOAD_BUFFER_SIZE 8192
798 #endif
799 
800 #ifndef FOUNDATIONAL_LIB_HASH_INITIAL_CAPACITY
808 #define FOUNDATIONAL_LIB_HASH_INITIAL_CAPACITY 16
809 #endif
810 
811 #ifndef FOUNDATIONAL_LIB_HASH_LOAD_FACTOR_THRESHOLD
820 #define FOUNDATIONAL_LIB_HASH_LOAD_FACTOR_THRESHOLD 0.75
821 #endif
822 
823 #ifndef FOUNDATIONAL_LIB_FUNC
824 /*
825  * One thing you can do, if you want "strict mode" on, you can define this to be and have -Werror on.
826  * That way, if any errors are not accounted for, instead of dealing with error handlers, the code just won't compile.
827  */
828 #define FOUNDATIONAL_LIB_FUNC static inline
829 #endif
830 
831 #ifndef FOUNDATIONAL_LIB_THREAD_FUNCTIONS_ENABLED
839 #define FOUNDATIONAL_LIB_THREAD_FUNCTIONS_ENABLED 1
840 #endif
841 
855 
863 #define FOUNDATIONAL_LIB_set_aggressive_die(mode) \
864  { \
865  FOUNDATIONAL_LIB_aggressive_die = (mode); \
866  }
867 
874 #define FOUNDATIONAL_LIB_get_aggressive_die() FOUNDATIONAL_LIB_aggressive_die
875 
876 #ifndef FOUNDATIONAL_LIB_die_aggressively_if_enabled
885 #define FOUNDATIONAL_LIB_die_aggressively_if_enabled() \
886  if (FOUNDATIONAL_LIB_UNLIKELY(FOUNDATIONAL_LIB_aggressive_die)) \
887  { \
888  FOUNDATIONAL_LIB_FPRINTF(stderr, "Error: %s: %s.\n", __func__, strerror(errno)); \
889  exit(EXIT_FAILURE); /* Use default exit, only place in library this is used, adjust as needed. */ \
890  }
891 #endif
892 
903 static inline void free_array(void **array, size_t len)
904 {
905  while (len--)
906  {
908  }
910 }
911 
922 static inline void free_string_array(char **array, size_t len)
923 {
924  while (len--)
925  {
927  }
929 }
930 
940 FOUNDATIONAL_LIB_FUNC char *int_to_string(long long int number)
941 {
942  // Allocate a fixed-size buffer for the string
944 
945  char *p;
946  long long a;
947  char *b;
948  char temp;
949  unsigned long long u;
950 
951  p = buffer;
952 
953  if (number < 0)
954  {
955  *p++ = '-';
956  number = 0 - number;
957  }
958  u = (long long)number;
959 
960  b = p;
961 
962  do
963  {
964  a = u % 10;
965  u /= 10;
966  *p++ = a + '0';
967  } while (u > 0);
968 
969  *p-- = '\0';
970  do
971  {
972  temp = *p;
973  *p = *b;
974  *b = temp;
975  --p;
976  ++b;
977  } while (b < p);
978 
979  // Duplicate the buffer using strdup
980  char *return_value = strdup(buffer);
981  if (FOUNDATIONAL_LIB_UNLIKELY(return_value == NULL))
982  {
983  // Handle allocation failure
985  return NULL;
986  }
987 
988  return return_value;
989 }
990 
1000 FOUNDATIONAL_LIB_FUNC void int_to_string_with_buffer(long long int number, char *buffer)
1001 {
1002  char *p;
1003  unsigned long long a;
1004  char *b;
1005  char temp;
1006  unsigned long long u;
1007 
1008  p = buffer;
1009 
1010  if (number < 0)
1011  {
1012  *p++ = '-';
1013  number = 0 - number;
1014  }
1015  u = (unsigned long)number;
1016 
1017  b = p;
1018 
1019  do
1020  {
1021  a = u % 10;
1022  u /= 10;
1023  *p++ = a + '0';
1024  } while (u > 0);
1025 
1026  *p-- = '\0';
1027  do
1028  {
1029  temp = *p;
1030  *p = *b;
1031  *b = temp;
1032  --p;
1033  ++b;
1034  } while (b < p);
1035 }
1036 
1037 /*
1038  * @brief
1039  * This function is for maximally-efficient conversion of unsigned numbers to strings - no nonsense.
1040  * Output should be large enough to hold the number. length of "18446744073709551615" + null byte = 21 chars.
1041  *
1042  * @param unsigned_value The number
1043  * @param output The output buffer. Should be 21 bytes, or fewer if you are certain the number is small, of more if sizeof(size_t) > 8 (which is unlikely).
1044  */
1045 FOUNDATIONAL_LIB_FUNC void utoa(size_t unsigned_value, char *output)
1046 {
1048 
1049  char *p = output;
1050  size_t a;
1051  char *b = output;
1052  char temp;
1053 
1054  do
1055  {
1056  a = unsigned_value % 10;
1057  unsigned_value /= 10;
1058  *p++ = a + '0';
1059  } while (unsigned_value);
1060 
1061  *p-- = '\0';
1062 
1063  do
1064  {
1065  temp = *p;
1066  *p = *b;
1067  *b = temp;
1068  --p;
1069  ++b;
1070  } while (b < p);
1071 }
1072 
1083 {
1085 
1086  utoa(number, buffer);
1087 
1088  char *return_value = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(buffer);
1089  if (FOUNDATIONAL_LIB_UNLIKELY(return_value == NULL))
1090  {
1092  return NULL;
1093  }
1094 
1095  return return_value;
1096 }
1097 
1108 FOUNDATIONAL_LIB_FUNC void print_uint_array(const unsigned long long *array, size_t size)
1109 {
1112 
1113  for (size_t i = 0; i < size; ++i)
1114  {
1115  const unsigned int value = array[i];
1117 
1118  utoa(value, buf);
1119  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1120  if (i < size - 1)
1121  {
1124  }
1125  }
1127 }
1139 FOUNDATIONAL_LIB_FUNC void print_uint_ptr_array(const unsigned int **array, size_t size)
1140 {
1143 
1144  for (size_t i = 0; i < size; ++i)
1145  {
1146  const unsigned int value = *array[i];
1148 
1149  utoa(value, buf);
1150  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1151  if (i < size - 1)
1152  {
1155  }
1156  }
1158 }
1159 
1170 FOUNDATIONAL_LIB_FUNC void print_int_array(const int *array, size_t size)
1171 {
1174 
1175  for (size_t i = 0; i < size; ++i)
1176  {
1177  const int value = array[i];
1179 
1180  int_to_string_with_buffer(value, buf);
1181  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1182  if (i < size - 1)
1183  {
1186  }
1187  }
1189 }
1190 
1202 FOUNDATIONAL_LIB_FUNC void print_int_ptr_array(const int **array, size_t size)
1203 {
1206 
1207  for (size_t i = 0; i < size; ++i)
1208  {
1209  const unsigned int value = *array[i];
1211 
1212  int_to_string_with_buffer(value, buf);
1213  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1214  if (i < size - 1)
1215  {
1218  }
1219  }
1221 }
1222 
1223 // print_uchar and print_uchar_array omitted because a uchar is too similar to a string.
1224 
1237 {
1240 
1241  for (size_t i = 0; i < size; ++i)
1242  {
1243  FOUNDATIONAL_LIB_FPUTS(array[i], stdout);
1244  if (i < size - 1)
1245  {
1248  }
1249  }
1251 }
1252 
1265 {
1268 
1269  for (size_t i = 0; i < size; ++i)
1270  {
1271  FOUNDATIONAL_LIB_FPUTS(*(array[i]), stdout);
1272  if (i < size - 1)
1273  {
1276  }
1277  }
1279 }
1280 
1291 FOUNDATIONAL_LIB_FUNC void print_ushort_array(const unsigned short *array, size_t size)
1292 {
1295 
1296  for (size_t i = 0; i < size; ++i)
1297  {
1298  const unsigned short value = array[i];
1300 
1301  utoa(value, buf);
1302  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1303  if (i < size - 1)
1304  {
1307  }
1308  }
1310 }
1311 
1324 FOUNDATIONAL_LIB_FUNC void print_ushort_ptr_array(const unsigned short **array, size_t size)
1325 {
1328 
1329  for (size_t i = 0; i < size; ++i)
1330  {
1331  const unsigned short value = *(array[i]);
1333 
1334  utoa(value, buf);
1335  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1336  if (i < size - 1)
1337  {
1340  }
1341  }
1343 }
1344 
1355 FOUNDATIONAL_LIB_FUNC void print_short_array(const short *array, size_t size)
1356 {
1359 
1360  for (size_t i = 0; i < size; ++i)
1361  {
1362  const short value = array[i];
1364 
1365  int_to_string_with_buffer(value, buf);
1366  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1367  if (i < size - 1)
1368  {
1371  }
1372  }
1374 }
1375 
1388 FOUNDATIONAL_LIB_FUNC void print_short_ptr_array(const short **array, size_t size)
1389 {
1392 
1393  for (size_t i = 0; i < size; ++i)
1394  {
1395  const short value = *(array[i]);
1397 
1398  int_to_string_with_buffer(value, buf);
1399  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1400  if (i < size - 1)
1401  {
1404  }
1405  }
1407 }
1408 
1419 FOUNDATIONAL_LIB_FUNC void print_ulong_array(const unsigned long *array, size_t size)
1420 {
1423 
1424  for (size_t i = 0; i < size; ++i)
1425  {
1426  const unsigned long value = array[i];
1428 
1429  utoa(value, buf);
1430  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1431  if (i < size - 1)
1432  {
1435  }
1436  }
1438 }
1439 
1452 FOUNDATIONAL_LIB_FUNC void print_ulong_ptr_array(const unsigned long **array, size_t size)
1453 {
1456 
1457  for (size_t i = 0; i < size; ++i)
1458  {
1459  const unsigned long value = *(array[i]);
1461 
1462  utoa(value, buf);
1463  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1464  if (i < size - 1)
1465  {
1468  }
1469  }
1471 }
1472 
1483 FOUNDATIONAL_LIB_FUNC void print_long_array(const long *array, size_t size)
1484 {
1487 
1488  for (size_t i = 0; i < size; ++i)
1489  {
1490  const long value = array[i];
1492 
1493  int_to_string_with_buffer(value, buf);
1494  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1495  if (i < size - 1)
1496  {
1499  }
1500  }
1502 }
1503 
1513 FOUNDATIONAL_LIB_FUNC void print_long_ptr_array(const long **array, size_t size)
1514 {
1517 
1518  for (size_t i = 0; i < size; ++i)
1519  {
1520  const long value = *(array[i]);
1522 
1523  int_to_string_with_buffer(value, buf);
1524  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1525  if (i < size - 1)
1526  {
1529  }
1530  }
1532 }
1533 
1543 FOUNDATIONAL_LIB_FUNC void print_ulong_long_array(const unsigned long long *array, size_t size)
1544 {
1547 
1548  for (size_t i = 0; i < size; ++i)
1549  {
1550  const unsigned long long value = array[i];
1552 
1553  utoa(value, buf);
1554  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1555  if (i < size - 1)
1556  {
1559  }
1560  }
1562 }
1563 
1574 FOUNDATIONAL_LIB_FUNC void print_ulong_long_ptr_array(const unsigned long long **array, size_t size)
1575 {
1578 
1579  for (size_t i = 0; i < size; ++i)
1580  {
1581  const unsigned long long value = *(array[i]);
1583 
1584  utoa(value, buf);
1585  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1586  if (i < size - 1)
1587  {
1590  }
1591  }
1593 }
1594 
1604 FOUNDATIONAL_LIB_FUNC void print_long_long_array(const long long *array, size_t size)
1605 {
1608 
1609  for (size_t i = 0; i < size; ++i)
1610  {
1611  const long long value = array[i];
1613 
1614  int_to_string_with_buffer(value, buf);
1615  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1616  if (i < size - 1)
1617  {
1620  }
1621  }
1623 }
1624 
1635 FOUNDATIONAL_LIB_FUNC void print_long_long_ptr_array(const long long **array, size_t size)
1636 {
1639 
1640  for (size_t i = 0; i < size; ++i)
1641  {
1642  const long long value = *(array[i]);
1644 
1645  int_to_string_with_buffer(value, buf);
1646  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1647  if (i < size - 1)
1648  {
1651  }
1652  }
1654 }
1655 
1665 FOUNDATIONAL_LIB_FUNC void print_float_array(const float *array, size_t size)
1666 {
1669  for (size_t i = 0; i < size; ++i)
1670  {
1671  FOUNDATIONAL_LIB_PRINTF("%f", array[i]);
1672  if (i < size - 1)
1673  {
1674  FOUNDATIONAL_LIB_FPUTS(", ", stdout);
1675  }
1676  }
1677 
1679 }
1680 
1691 FOUNDATIONAL_LIB_FUNC void print_float_ptr_array(const float **array, size_t size)
1692 {
1695  for (size_t i = 0; i < size; ++i)
1696  {
1697  FOUNDATIONAL_LIB_PRINTF("%f", *array[i]);
1698  if (i < size - 1)
1699  {
1700  FOUNDATIONAL_LIB_FPUTS(", ", stdout);
1701  }
1702  }
1703 
1705 }
1706 
1716 FOUNDATIONAL_LIB_FUNC void print_double_array(const double *array, size_t size)
1717 {
1720  for (size_t i = 0; i < size; ++i)
1721  {
1722  FOUNDATIONAL_LIB_PRINTF("%lf", array[i]);
1723  if (i < size - 1)
1724  {
1725  FOUNDATIONAL_LIB_FPUTS(", ", stdout);
1726  }
1727  }
1728 
1730 }
1731 
1742 FOUNDATIONAL_LIB_FUNC void print_double_ptr_array(const double **array, size_t size)
1743 {
1746  for (size_t i = 0; i < size; ++i)
1747  {
1748  FOUNDATIONAL_LIB_PRINTF("%lf", *array[i]);
1749  if (i < size - 1)
1750  {
1751  FOUNDATIONAL_LIB_FPUTS(", ", stdout);
1752  }
1753  }
1754 
1756 }
1757 
1767 FOUNDATIONAL_LIB_FUNC void print_size_t_array(const size_t *array, size_t size)
1768 {
1771 
1772  for (size_t i = 0; i < size; ++i)
1773  {
1774  const size_t value = array[i];
1776 
1777  int_to_string_with_buffer(value, buf);
1778  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1779  if (i < size - 1)
1780  {
1783  }
1784  }
1786 }
1787 
1798 FOUNDATIONAL_LIB_FUNC void print_size_t_ptr_array(const size_t **array, size_t size)
1799 {
1802 
1803  for (size_t i = 0; i < size; ++i)
1804  {
1805  const size_t value = *(array[i]);
1807 
1808  int_to_string_with_buffer(value, buf);
1809  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1810  if (i < size - 1)
1811  {
1814  }
1815  }
1817 }
1818 
1830 FOUNDATIONAL_LIB_FUNC void print_uint_array_to_stream(const unsigned int *array, size_t size, FILE *stream)
1831 {
1833  FOUNDATIONAL_LIB_FPUTC('[', stream);
1834  for (size_t i = 0; i < size; ++i)
1835  {
1836  FOUNDATIONAL_LIB_FPRINTF(stream, "%u", array[i]);
1837  if (i < size - 1)
1838  {
1839  FOUNDATIONAL_LIB_FPUTS(", ", stream);
1840  }
1841  }
1842  FOUNDATIONAL_LIB_FPUTS("]", stream);
1843 }
1844 
1857 FOUNDATIONAL_LIB_FUNC void print_uint_ptr_array_to_stream(const unsigned int **array, size_t size, FILE *stream)
1858 {
1860  FOUNDATIONAL_LIB_FPUTC('[', stream);
1861  for (size_t i = 0; i < size; ++i)
1862  {
1863  FOUNDATIONAL_LIB_FPRINTF(stream, "%u", *array[i]);
1864  if (i < size - 1)
1865  {
1866  FOUNDATIONAL_LIB_FPUTS(", ", stream);
1867  }
1868  }
1869  FOUNDATIONAL_LIB_FPUTS("]", stream);
1870 }
1871 
1882 FOUNDATIONAL_LIB_FUNC void print_int_array_to_stream(const int *array, size_t size, FILE *stream)
1883 {
1885  FOUNDATIONAL_LIB_FPUTC('[', stream);
1886  for (size_t i = 0; i < size; ++i)
1887  {
1888  FOUNDATIONAL_LIB_FPRINTF(stream, "%d", array[i]);
1889  if (i < size - 1)
1890  {
1891  FOUNDATIONAL_LIB_FPUTS(", ", stream);
1892  }
1893  }
1894  FOUNDATIONAL_LIB_FPUTS("]", stream);
1895 }
1896 
1909 FOUNDATIONAL_LIB_FUNC void print_int_ptr_array_to_stream(const int **array, size_t size, FILE *stream)
1910 {
1912  FOUNDATIONAL_LIB_FPUTC('[', stream);
1913  for (size_t i = 0; i < size; ++i)
1914  {
1915  FOUNDATIONAL_LIB_FPRINTF(stream, "%d", *array[i]);
1916  if (i < size - 1)
1917  {
1918  FOUNDATIONAL_LIB_FPUTS(", ", stream);
1919  }
1920  }
1921  FOUNDATIONAL_LIB_FPUTS("]", stream);
1922 }
1923 
1935 FOUNDATIONAL_LIB_FUNC void print_uchar_array_to_stream(const unsigned char *array, size_t size, FILE *stream)
1936 {
1938  FOUNDATIONAL_LIB_FPUTC('[', stream);
1939  for (size_t i = 0; i < size; ++i)
1940  {
1941  FOUNDATIONAL_LIB_FPRINTF(stream, "%c", array[i]);
1942  if (i < size - 1)
1943  {
1944  FOUNDATIONAL_LIB_FPUTS(", ", stream);
1945  }
1946  }
1947  FOUNDATIONAL_LIB_FPUTS("]", stream);
1948 }
1949 
1960 FOUNDATIONAL_LIB_FUNC void print_char_array_to_stream(const char *array, size_t size, FILE *stream)
1961 {
1963  FOUNDATIONAL_LIB_FPUTC('[', stream);
1964  for (size_t i = 0; i < size; ++i)
1965  {
1966  FOUNDATIONAL_LIB_FPRINTF(stream, "%c", array[i]);
1967  if (i < size - 1)
1968  {
1969  FOUNDATIONAL_LIB_FPUTS(", ", stream);
1970  }
1971  }
1972  FOUNDATIONAL_LIB_FPUTS("]", stream);
1973 }
1974 
1986 FOUNDATIONAL_LIB_FUNC void print_string_array_to_stream(char **array, size_t size, FILE *stream)
1987 {
1989  FOUNDATIONAL_LIB_FPUTC('[', stream);
1990  for (size_t i = 0; i < size; ++i)
1991  {
1992  FOUNDATIONAL_LIB_FPUTS(array[i], stream);
1993  if (i < size - 1)
1994  {
1995  FOUNDATIONAL_LIB_FPUTS(", ", stream);
1996  }
1997  }
1998  FOUNDATIONAL_LIB_FPUTS("]", stream);
1999 }
2000 
2013 FOUNDATIONAL_LIB_FUNC void print_string_array_array_to_stream(char ***array, size_t size, FILE *stream)
2014 {
2016  FOUNDATIONAL_LIB_FPUTC('[', stream);
2017  for (size_t i = 0; i < size; ++i)
2018  {
2019  FOUNDATIONAL_LIB_FPUTS(*array[i], stream);
2020  if (i < size - 1)
2021  {
2022  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2023  }
2024  }
2025  FOUNDATIONAL_LIB_FPUTS("]", stream);
2026 }
2027 
2039 FOUNDATIONAL_LIB_FUNC void print_ushort_array_to_stream(const unsigned short *array, size_t size, FILE *stream)
2040 {
2042  FOUNDATIONAL_LIB_FPUTC('[', stream);
2043  for (size_t i = 0; i < size; ++i)
2044  {
2045  FOUNDATIONAL_LIB_FPRINTF(stream, "%hu", array[i]);
2046  if (i < size - 1)
2047  {
2048  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2049  }
2050  }
2051  FOUNDATIONAL_LIB_FPUTS("]", stream);
2052 }
2053 
2066 FOUNDATIONAL_LIB_FUNC void print_ushort_ptr_array_to_stream(const unsigned short **array, size_t size, FILE *stream)
2067 {
2069  FOUNDATIONAL_LIB_FPUTC('[', stream);
2070  for (size_t i = 0; i < size; ++i)
2071  {
2072  FOUNDATIONAL_LIB_FPRINTF(stream, "%hu", *array[i]);
2073  if (i < size - 1)
2074  {
2075  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2076  }
2077  }
2078  FOUNDATIONAL_LIB_FPUTS("]", stream);
2079 }
2080 
2091 FOUNDATIONAL_LIB_FUNC void print_short_array_to_stream(const short *array, size_t size, FILE *stream)
2092 {
2094  FOUNDATIONAL_LIB_FPUTC('[', stream);
2095  for (size_t i = 0; i < size; ++i)
2096  {
2097  FOUNDATIONAL_LIB_FPRINTF(stream, "%d", array[i]);
2098  if (i < size - 1)
2099  {
2100  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2101  }
2102  }
2103  FOUNDATIONAL_LIB_FPUTS("]", stream);
2104 }
2105 
2118 FOUNDATIONAL_LIB_FUNC void print_short_ptr_array_to_stream(const short **array, size_t size, FILE *stream)
2119 {
2121  FOUNDATIONAL_LIB_FPUTC('[', stream);
2122  for (size_t i = 0; i < size; ++i)
2123  {
2124  FOUNDATIONAL_LIB_FPRINTF(stream, "%d", *array[i]);
2125  if (i < size - 1)
2126  {
2127  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2128  }
2129  }
2130  FOUNDATIONAL_LIB_FPUTS("]", stream);
2131 }
2132 
2144 FOUNDATIONAL_LIB_FUNC void print_ulong_array_to_stream(const unsigned long *array, size_t size, FILE *stream)
2145 {
2147  FOUNDATIONAL_LIB_FPUTC('[', stream);
2148  for (size_t i = 0; i < size; ++i)
2149  {
2150  FOUNDATIONAL_LIB_FPRINTF(stream, "%lu", array[i]);
2151  if (i < size - 1)
2152  {
2153  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2154  }
2155  }
2156  FOUNDATIONAL_LIB_FPUTS("]", stream);
2157 }
2158 
2171 FOUNDATIONAL_LIB_FUNC void print_ulong_ptr_array_to_stream(const unsigned long **array, size_t size, FILE *stream)
2172 {
2174  FOUNDATIONAL_LIB_FPUTC('[', stream);
2175  for (size_t i = 0; i < size; ++i)
2176  {
2177  FOUNDATIONAL_LIB_FPRINTF(stream, "%lu", *array[i]);
2178  if (i < size - 1)
2179  {
2180  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2181  }
2182  }
2183  FOUNDATIONAL_LIB_FPUTS("]", stream);
2184 }
2185 
2196 FOUNDATIONAL_LIB_FUNC void print_long_array_to_stream(const long *array, size_t size, FILE *stream)
2197 {
2199  FOUNDATIONAL_LIB_FPUTC('[', stream);
2200  for (size_t i = 0; i < size; ++i)
2201  {
2202  FOUNDATIONAL_LIB_FPRINTF(stream, "%ld", array[i]);
2203  if (i < size - 1)
2204  {
2205  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2206  }
2207  }
2208  FOUNDATIONAL_LIB_FPUTS("]", stream);
2209 }
2210 
2223 FOUNDATIONAL_LIB_FUNC void print_long_ptr_array_to_stream(const long **array, size_t size, FILE *stream)
2224 {
2226  FOUNDATIONAL_LIB_FPUTC('[', stream);
2227  for (size_t i = 0; i < size; ++i)
2228  {
2229  FOUNDATIONAL_LIB_FPRINTF(stream, "%ld", *array[i]);
2230  if (i < size - 1)
2231  {
2232  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2233  }
2234  }
2235  FOUNDATIONAL_LIB_FPUTS("]", stream);
2236 }
2237 
2250 FOUNDATIONAL_LIB_FUNC void print_ulong_long_array_to_stream(const unsigned long long *array, size_t size, FILE *stream)
2251 {
2253  FOUNDATIONAL_LIB_FPUTC('[', stream);
2254  for (size_t i = 0; i < size; ++i)
2255  {
2256  const unsigned long long value = array[i];
2258 
2259  utoa(value, buffer);
2260  FOUNDATIONAL_LIB_FPUTS(buffer, stream);
2261  if (i < size - 1)
2262  {
2263  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2264  }
2265  }
2266  FOUNDATIONAL_LIB_FPUTS("]", stream);
2267 }
2268 
2281 FOUNDATIONAL_LIB_FUNC void print_ulong_long_ptr_array_to_stream(const unsigned long long **array, size_t size, FILE *stream)
2282 {
2284  FOUNDATIONAL_LIB_FPUTC('[', stream);
2285  for (size_t i = 0; i < size; ++i)
2286  {
2287  const unsigned long long value = *(array[i]);
2289 
2290  utoa(value, buffer);
2291  FOUNDATIONAL_LIB_FPUTS(buffer, stream);
2292  if (i < size - 1)
2293  {
2294  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2295  }
2296  }
2297  FOUNDATIONAL_LIB_FPUTS("]", stream);
2298 }
2299 
2311 FOUNDATIONAL_LIB_FUNC void print_long_long_array_to_stream(const long long *array, size_t size, FILE *stream)
2312 {
2314  FOUNDATIONAL_LIB_FPUTC('[', stream);
2315  for (size_t i = 0; i < size; ++i)
2316  {
2317  const unsigned long long value = array[i];
2319 
2320  int_to_string_with_buffer(value, buffer);
2321 
2322  FOUNDATIONAL_LIB_FPUTS(buffer, stream);
2323  if (i < size - 1)
2324  {
2325  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2326  }
2327  }
2328  FOUNDATIONAL_LIB_FPUTS("]", stream);
2329 }
2330 
2344 FOUNDATIONAL_LIB_FUNC void print_long_long_ptr_array_to_stream(const long long **array, size_t size, FILE *stream)
2345 {
2347  FOUNDATIONAL_LIB_FPUTC('[', stream);
2348  for (size_t i = 0; i < size; ++i)
2349  {
2350  const long long value = *(array[i]);
2351 
2353 
2354  int_to_string_with_buffer(value, buffer);
2355  FOUNDATIONAL_LIB_FPUTS(buffer, stream);
2356  if (i < size - 1)
2357  {
2358  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2359  }
2360  }
2361  FOUNDATIONAL_LIB_FPUTS("]", stream);
2362 }
2363 
2375 FOUNDATIONAL_LIB_FUNC void print_float_array_to_stream(const float *array, size_t size, FILE *stream)
2376 {
2378  FOUNDATIONAL_LIB_FPUTC('[', stream);
2379  for (size_t i = 0; i < size; ++i)
2380  {
2381  FOUNDATIONAL_LIB_FPRINTF(stream, "%f", array[i]);
2382  if (i < size - 1)
2383  {
2384  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2385  }
2386  }
2387  FOUNDATIONAL_LIB_FPUTS("]", stream);
2388 }
2389 
2402 FOUNDATIONAL_LIB_FUNC void print_float_ptr_array_to_stream(const float **array, size_t size, FILE *stream)
2403 {
2405  FOUNDATIONAL_LIB_FPUTC('[', stream);
2406  for (size_t i = 0; i < size; ++i)
2407  {
2408  FOUNDATIONAL_LIB_FPRINTF(stream, "%f", *array[i]);
2409  if (i < size - 1)
2410  {
2411  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2412  }
2413  }
2414  FOUNDATIONAL_LIB_FPUTS("]", stream);
2415 }
2416 
2428 FOUNDATIONAL_LIB_FUNC void print_double_array_to_stream(const double *array, size_t size, FILE *stream)
2429 {
2431  FOUNDATIONAL_LIB_FPUTC('[', stream);
2432  for (size_t i = 0; i < size; ++i)
2433  {
2434  FOUNDATIONAL_LIB_FPRINTF(stream, "%lf", array[i]);
2435  if (i < size - 1)
2436  {
2437  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2438  }
2439  }
2440  FOUNDATIONAL_LIB_FPUTS("]", stream);
2441 }
2442 
2455 FOUNDATIONAL_LIB_FUNC void print_double_ptr_array_to_stream(const double **array, size_t size, FILE *stream)
2456 {
2458  FOUNDATIONAL_LIB_FPUTC('[', stream);
2459  for (size_t i = 0; i < size; ++i)
2460  {
2461  FOUNDATIONAL_LIB_FPRINTF(stream, "%lf", *array[i]);
2462  if (i < size - 1)
2463  {
2464  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2465  }
2466  }
2467  FOUNDATIONAL_LIB_FPUTS("]", stream);
2468 }
2469 
2481 FOUNDATIONAL_LIB_FUNC void print_size_t_array_to_stream(const size_t *array, size_t size, FILE *stream)
2482 {
2484  FOUNDATIONAL_LIB_FPUTC('[', stream);
2485  for (size_t i = 0; i < size; ++i)
2486  {
2487 #pragma GCC diagnostic push
2488 #pragma GCC diagnostic ignored "-Wpragmas"
2489 #pragma GCC diagnostic ignored "-Wformat"
2490 #pragma GCC diagnostic ignored "-Wformat-extra-args"
2491  FOUNDATIONAL_LIB_FPRINTF(stream, "%zu", array[i]);
2492 
2493 #pragma GCC diagnostic pop
2494  if (i < size - 1)
2495  {
2496  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2497  }
2498  }
2499  FOUNDATIONAL_LIB_FPUTS("]", stream);
2500 }
2501 
2514 FOUNDATIONAL_LIB_FUNC void print_size_t_ptr_array_to_stream(const size_t **array, size_t size, FILE *stream)
2515 {
2517  FOUNDATIONAL_LIB_FPUTC('[', stream);
2518  for (size_t i = 0; i < size; ++i)
2519  {
2520 #pragma GCC diagnostic push
2521 #pragma GCC diagnostic ignored "-Wpragmas"
2522 #pragma GCC diagnostic ignored "-Wformat"
2523 #pragma GCC diagnostic ignored "-Wformat-extra-args"
2524 
2525  FOUNDATIONAL_LIB_FPRINTF(stream, "%zu", *array[i]);
2526 #pragma GCC diagnostic pop
2527  if (i < size - 1)
2528  {
2529  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2530  }
2531  }
2532  FOUNDATIONAL_LIB_FPUTS("]", stream);
2533 }
2534 
2548 FOUNDATIONAL_LIB_FUNC void *arraydup(const void *array, size_t num_mem, size_t size)
2549 {
2551  const size_t tot_size = FOUNDATIONAL_LIB_safe_mul(num_mem, size);
2552 
2553  // Check num_mem so safe_mul doesn't get confused.
2554  if (FOUNDATIONAL_LIB_UNLIKELY(num_mem && tot_size == 0))
2555  {
2556  /* Handle memory allocation failure */
2558  return NULL;
2559  }
2560  char *duplicate = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(tot_size);
2561 
2562  if (FOUNDATIONAL_LIB_UNLIKELY(duplicate == NULL))
2563  {
2564  /* Handle memory allocation failure */
2566  return NULL;
2567  }
2568 
2569  for (size_t i = 0; i < tot_size; ++i)
2570  {
2571  duplicate[i] = ((char *)array)[i];
2572  }
2573 
2574  return (void *)duplicate;
2575 }
2576 
2587 static inline int equal_strings(const char *first, const char *second) { return FOUNDATIONAL_LIB_STRCMP(first, second) == 0; }
2588 
2602 static inline int equal_array_of_uints(const unsigned int *array, const unsigned int *array2, size_t size)
2603 {
2604  for (size_t i = 0; i < size; ++i)
2605  {
2606  if (array[i] != array2[i])
2607  {
2608  return 0;
2609  }
2610  }
2611  return 1;
2612 }
2613 
2627 static inline int equal_array_of_uint_ptrs(const unsigned int **array, const unsigned int **array2, size_t size)
2628 {
2629  for (size_t i = 0; i < size; ++i)
2630  {
2631  if (array[i] != array2[i])
2632  {
2633  return 0;
2634  }
2635  }
2636  return 1;
2637 }
2638 
2651 static inline int equal_array_of_ints(const int *array, const int *array2, size_t size)
2652 {
2653  for (size_t i = 0; i < size; ++i)
2654  {
2655  if (array[i] != array2[i])
2656  {
2657  return 0;
2658  }
2659  }
2660  return 1;
2661 }
2662 
2676 static inline int equal_array_of_int_ptrs(const int **array, const int **array2, size_t size)
2677 {
2678  for (size_t i = 0; i < size; ++i)
2679  {
2680  if (array[i] != array2[i])
2681  {
2682  return 0;
2683  }
2684  }
2685  return 1;
2686 }
2687 
2701 static inline int equal_array_of_uchars(const unsigned char *array, const unsigned char *array2, size_t size)
2702 {
2703  for (size_t i = 0; i < size; ++i)
2704  {
2705  if (array[i] != array2[i])
2706  {
2707  return 0;
2708  }
2709  }
2710  return 1;
2711 }
2712 
2726 static inline int equal_array_of_uchar_ptrs(const unsigned char **array, const unsigned char **array2, size_t size)
2727 {
2728  for (size_t i = 0; i < size; ++i)
2729  {
2730  if (array[i] != array2[i])
2731  {
2732  return 0;
2733  }
2734  }
2735  return 1;
2736 }
2737 
2750 static inline int equal_array_of_chars(const char *array, const char *array2, size_t size)
2751 {
2752  for (size_t i = 0; i < size; ++i)
2753  {
2754  if (array[i] != array2[i])
2755  {
2756  return 0;
2757  }
2758  }
2759  return 1;
2760 }
2761 
2775 static inline int equal_array_of_char_ptrs(const char **array, const char **array2, size_t size)
2776 {
2777  for (size_t i = 0; i < size; ++i)
2778  {
2779  if (array[i] != array2[i])
2780  {
2781  return 0;
2782  }
2783  }
2784  return 1;
2785 }
2786 
2800 static inline int equal_array_of_ushorts(const unsigned short *array, const unsigned short *array2, size_t size)
2801 {
2802  for (size_t i = 0; i < size; ++i)
2803  {
2804  if (array[i] != array2[i])
2805  {
2806  return 0;
2807  }
2808  }
2809  return 1;
2810 }
2811 
2827 static inline int equal_array_of_ushort_ptrs(const unsigned short **array, const unsigned short **array2, size_t size)
2828 {
2829  for (size_t i = 0; i < size; ++i)
2830  {
2831  if (array[i] != array2[i])
2832  {
2833  return 0;
2834  }
2835  }
2836  return 1;
2837 }
2838 
2852 static inline int equal_array_of_shorts(const short *array, const short *array2, size_t size)
2853 {
2854  for (size_t i = 0; i < size; ++i)
2855  {
2856  if (array[i] != array2[i])
2857  {
2858  return 0;
2859  }
2860  }
2861  return 1;
2862 }
2863 
2877 static inline int equal_array_of_short_ptrs(const short **array, const short **array2, size_t size)
2878 {
2879  for (size_t i = 0; i < size; ++i)
2880  {
2881  if (array[i] != array2[i])
2882  {
2883  return 0;
2884  }
2885  }
2886  return 1;
2887 }
2888 
2902 static inline int equal_array_of_ulongs(const unsigned long *array, const unsigned long *array2, size_t size)
2903 {
2904  for (size_t i = 0; i < size; ++i)
2905  {
2906  if (array[i] != array2[i])
2907  {
2908  return 0;
2909  }
2910  }
2911  return 1;
2912 }
2913 
2929 static inline int equal_array_of_ulong_ptrs(const unsigned long **array, const unsigned long **array2, size_t size)
2930 {
2931  for (size_t i = 0; i < size; ++i)
2932  {
2933  if (array[i] != array2[i])
2934  {
2935  return 0;
2936  }
2937  }
2938  return 1;
2939 }
2940 
2954 static inline int equal_array_of_longs(const long *array, const long *array2, size_t size)
2955 {
2956  for (size_t i = 0; i < size; ++i)
2957  {
2958  if (array[i] != array2[i])
2959  {
2960  return 0;
2961  }
2962  }
2963  return 1;
2964 }
2965 
2979 static inline int equal_array_of_long_ptrs(const long **array, const long **array2, size_t size)
2980 {
2981  for (size_t i = 0; i < size; ++i)
2982  {
2983  if (array[i] != array2[i])
2984  {
2985  return 0;
2986  }
2987  }
2988  return 1;
2989 }
2990 
3004 static inline int equal_array_of_ulong_longs(const unsigned long long *array, const unsigned long long *array2, size_t size)
3005 {
3006  for (size_t i = 0; i < size; ++i)
3007  {
3008  if (array[i] != array2[i])
3009  {
3010  return 0;
3011  }
3012  }
3013  return 1;
3014 }
3015 
3032 static inline int equal_array_of_ulong_long_ptrs(const unsigned long long **array, const unsigned long long **array2, size_t size)
3033 {
3034  for (size_t i = 0; i < size; ++i)
3035  {
3036  if (array[i] != array2[i])
3037  {
3038  return 0;
3039  }
3040  }
3041  return 1;
3042 }
3043 
3057 static inline int equal_array_of_long_longs(const long long *array, const long long *array2, size_t size)
3058 {
3059  for (size_t i = 0; i < size; ++i)
3060  {
3061  if (array[i] != array2[i])
3062  {
3063  return 0;
3064  }
3065  }
3066  return 1;
3067 }
3068 
3082 static inline int equal_array_of_long_long_ptrs(const long long **array, const long long **array2, size_t size)
3083 {
3084  for (size_t i = 0; i < size; ++i)
3085  {
3086  if (array[i] != array2[i])
3087  {
3088  return 0;
3089  }
3090  }
3091  return 1;
3092 }
3093 
3107 static inline int equal_array_of_floats(const float *array, const float *array2, size_t size)
3108 {
3109  for (size_t i = 0; i < size; ++i)
3110  {
3111  if (array[i] != array2[i])
3112  {
3113  return 0;
3114  }
3115  }
3116  return 1;
3117 }
3118 
3132 static inline int equal_array_of_float_ptrs(const float **array, const float **array2, size_t size)
3133 {
3134  for (size_t i = 0; i < size; ++i)
3135  {
3136  if (array[i] != array2[i])
3137  {
3138  return 0;
3139  }
3140  }
3141  return 1;
3142 }
3143 
3156 static inline int equal_array_of_doubles(const double *array, const double *array2, size_t size)
3157 {
3158  for (size_t i = 0; i < size; ++i)
3159  {
3160  if (array[i] != array2[i])
3161  {
3162  return 0;
3163  }
3164  }
3165  return 1;
3166 }
3167 
3180 static inline int equal_array_of_double_ptrs(const double **array, const double **array2, size_t size)
3181 {
3182  for (size_t i = 0; i < size; ++i)
3183  {
3184  if (array[i] != array2[i])
3185  {
3186  return 0;
3187  }
3188  }
3189  return 1;
3190 }
3191 
3204 static inline int equal_array_of_size_ts(const size_t *array, const size_t *array2, size_t size)
3205 {
3206  for (size_t i = 0; i < size; ++i)
3207  {
3208  if (array[i] != array2[i])
3209  {
3210  return 0;
3211  }
3212  }
3213  return 1;
3214 }
3215 
3228 static inline int equal_array_of_size_t_ptrs(const size_t **array, const size_t **array2, size_t size)
3229 {
3231  for (size_t i = 0; i < size; ++i)
3232  {
3233  if (array[i] != array2[i])
3234  {
3235  return 0;
3236  }
3237  }
3238  return 1;
3239 }
3240 
3253 FOUNDATIONAL_LIB_FUNC char *string_to_json(const char *input_string)
3254 {
3256  size_t escaped_length = 0;
3257  size_t input_length = 0;
3258 
3259  /* Calculate the length of the escaped string */
3260 
3261  while (input_string[input_length])
3262  {
3263  if (input_string[input_length] == '"' || input_string[input_length] == '\\')
3264  {
3265  // If the string uses most of memory and is filled with \ or ", there could be an overflow.
3266  // Check for this.
3267  // If you find this too slow, just change the macro definition.
3268  FOUNDATIONAL_LIB_safe_increment(escaped_length, overflow); // Need to escape with a backslash
3269  }
3270 
3271  // If the string uses most of memory and is filled with \ or ", there could be an overflow.
3272  // Check for this.
3273  FOUNDATIONAL_LIB_safe_increment(escaped_length, overflow);
3274 
3275  // Cannot overflow because it's a size_t that starts from 0.
3276  // (Actually, it can, if all of memory is nonzero.)
3277  // Do not check for this.
3278  ++input_length;
3279  }
3280 
3281  /* Calculate the length of the resulting JSON string */
3282 
3283  size_t json_length;
3284 
3285  json_length = escaped_length;
3286 
3287  // add 2 for double quotes
3288  if (FOUNDATIONAL_LIB_safe_add_2_ptr(json_length, 2, &json_length) == 0)
3289  goto overflow;
3290 
3291  size_t alloc_size;
3292 
3293  alloc_size = json_length + sizeof(""); // +1 for null terminator
3294  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size == 0))
3295  goto overflow;
3296 
3297  char *json_result;
3298 
3299  json_result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size);
3300 
3301  if (FOUNDATIONAL_LIB_UNLIKELY(json_result == NULL))
3302  {
3303  goto memory_error;
3304  }
3305 
3306  /* Add double quotes around the escaped string */
3307  json_result[0] = '"';
3308 
3309  // Start a 1 for j because index 0 is a quote mark.
3310  for (size_t j = 1, i = 0; i < input_length; ++i, ++j)
3311  {
3312  // Add unlikely because this isn't that probable.
3313  if (FOUNDATIONAL_LIB_UNLIKELY(input_string[i] == '"' || input_string[i] == '\\'))
3314  {
3315  json_result[j] = '\\';
3316  ++j;
3317  }
3318 
3319  // i is the index for the input string and j is the index for the json result
3320  json_result[j] = input_string[i];
3321  }
3322 
3323  // Add the second quote
3324  json_result[json_length - 1] = '"';
3325 
3326  // Null-terminate the string
3327  json_result[json_length] = '\0';
3328 
3329  return json_result;
3330 
3331 overflow:
3332 memory_error:
3334  return NULL;
3335 }
3336 
3349 FOUNDATIONAL_LIB_FUNC char *strip(const char *str)
3350 {
3352  size_t end = FOUNDATIONAL_LIB_STRLEN(str);
3353 
3354  size_t start;
3355 
3356  start = 0;
3357 
3358  /* Trim leading whitespace */
3359  while (FOUNDATIONAL_LIB_ISSPACE(str[start]))
3360  {
3361  ++start;
3362  }
3363 
3364  /* Trim trailing whitespace */
3365  while (end > start && FOUNDATIONAL_LIB_ISSPACE(str[end - 1]))
3366  {
3367  --end;
3368  }
3369 
3370  /* Copy the stripped portion into a new string */
3371 
3372  // End is always greater than start. Should never underflow.
3373 
3374  const size_t memcpy_len = end - start;
3375  size_t alloc_len = memcpy_len;
3376 
3377  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_len == SIZE_MAX))
3378  goto overflow;
3379  ++alloc_len;
3380 
3381  char *result;
3382  result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_len); /* Safe. */
3383 
3384  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
3385  goto memory_error;
3386 
3387  // Copy everything before the null byte.
3388  FOUNDATIONAL_LIB_MEMCPY(result, str + start, memcpy_len); /* Safe. */
3389  result[memcpy_len] = '\0';
3390 
3391  return result;
3392 
3393 overflow:
3394 memory_error:
3396  return NULL;
3397 }
3398 
3416 FOUNDATIONAL_LIB_FUNC char **split(const char *str, size_t *output_size, const char *delim, size_t max_times, int keep_delim_in_result)
3417 {
3421 
3422  /* Count the number of tokens */
3423  *output_size = 1;
3424  const size_t delim_len = FOUNDATIONAL_LIB_STRLEN(delim);
3425 
3426  for (const char *ptr = FOUNDATIONAL_LIB_STRSTR(str, delim); ptr != NULL && (max_times == 0 || *output_size < max_times); ptr = strstr(ptr + delim_len, delim))
3427  {
3428  ++(*output_size);
3429  }
3430 
3431  const size_t new_len = FOUNDATIONAL_LIB_safe_mul(*output_size, sizeof(char *));
3432 
3433  // Check output_size so safe_mul doesn't get confused.
3434  if (FOUNDATIONAL_LIB_UNLIKELY(new_len == 0 && *output_size))
3435  goto overflow;
3436 
3437  /* Allocate memory for the array of strings */
3438  char **result;
3439 
3440  result = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(new_len);
3441  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
3442  goto memory_error;
3443 
3444  const char *token_start;
3445 
3446  token_start = str;
3447  const char *ptr;
3448 
3449  /* Split the string into tokens */
3450  for (size_t i = 0; i < *output_size; ++i)
3451  {
3452  ptr = FOUNDATIONAL_LIB_STRSTR(token_start, delim);
3453 
3454  if (ptr != NULL)
3455  {
3456  // Should not overflow.
3457  size_t token_length = (size_t)(ptr - token_start);
3458 
3459  if (keep_delim_in_result)
3460  {
3461  token_length += delim_len;
3462  }
3463 
3464  const size_t alloc_len = token_length + sizeof("");
3465 
3466  result[i] = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_len); /* Safe. */
3467  if (FOUNDATIONAL_LIB_UNLIKELY(result[i] == NULL))
3468  {
3470  goto memory_error;
3471  }
3472 
3473  FOUNDATIONAL_LIB_MEMCPY(result[i], token_start, token_length); /* Safe. */
3474  result[i][token_length] = '\0';
3475 
3476  token_start = ptr + delim_len; // Move to the next token
3477  }
3478  else /* ptr is NULL */
3479  {
3480  // Last token, copy the remaining part of the string
3481  const size_t token_length = FOUNDATIONAL_LIB_STRLEN(token_start);
3482 
3483  // The only way this could overflow is if strlen(token_length) == SIZE_MAX.
3484  //
3485  // But I don't see how that would be possible, because there would have to
3486  // be a null terminator for strlen() to work. So it would have to be
3487  // SIZE_MAX - 1, unless strlen() is broken. Since it would have to be
3488  // SIZE_MAX - 1, adding 1 to it wouldn't cause an overflow.
3489  // Therefore, this is safe code.
3490 
3491  const size_t alloc_len = token_length + sizeof("");
3492 
3493  result[i] = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_len); /* Safe. */
3494 
3495  if (FOUNDATIONAL_LIB_UNLIKELY(result[i] == NULL))
3496  {
3498  goto memory_error;
3499  }
3500 
3501  FOUNDATIONAL_LIB_MEMCPY(result[i], token_start, token_length); /* Safe. */
3502  result[i][token_length] = '\0';
3503  }
3504  }
3505 
3506  return result;
3507 
3508 overflow:
3509 memory_error:
3511  return NULL;
3512 }
3513 
3529 FOUNDATIONAL_LIB_FUNC char *join(const char **array, size_t count, const char *delimiter)
3530 {
3533 
3534  const size_t new_size = FOUNDATIONAL_LIB_safe_mul(sizeof(size_t), count);
3535  // Check count so safe_mul doesn't get confused.
3536  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0 && count))
3537  goto overflow;
3538  size_t *lens;
3539 
3540  lens = (size_t *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(new_size);
3541  if (FOUNDATIONAL_LIB_UNLIKELY(lens == NULL))
3542  goto memory_error;
3543  size_t delimeter_length;
3544 
3545  delimeter_length = FOUNDATIONAL_LIB_STRLEN(delimiter);
3546  /* Calculate the total length of the resulting string */
3547  size_t total_length;
3548 
3549  total_length = 1; // NUL byte
3550  for (size_t i = 0; i < count; ++i)
3551  {
3552  const size_t new_len = FOUNDATIONAL_LIB_STRLEN(array[i]);
3553  lens[i] = new_len;
3554  total_length += new_len;
3555  if (i < count - 1)
3556  {
3557  total_length += delimeter_length;
3558  }
3559  }
3560 
3561  /* Allocate memory for the resulting string */
3562  char *result;
3563 
3564  result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(total_length);
3565  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
3566  {
3567  goto memory_error;
3568  }
3569  size_t len_so_far;
3570 
3571  len_so_far = 0;
3572  size_t array_index;
3573 
3574  /* Concatenate strings with the delimiter */
3575  for (array_index = 0; array_index < count; ++array_index)
3576  {
3577  const size_t len = lens[array_index];
3578 
3579  /* Copy string */
3580  for (size_t x = 0; x < len; ++x)
3581  {
3582  result[len_so_far + x] = array[array_index][x];
3583  }
3584 
3585  len_so_far += len;
3586  if (array_index < count - 1)
3587  {
3588  /* Copy delimiter */
3589  for (size_t i = 0; i < delimeter_length; ++i)
3590  {
3591  result[len_so_far + i] = delimiter[i];
3592  }
3593  len_so_far += delimeter_length;
3594  }
3595  }
3596 
3597  result[len_so_far] = '\0';
3598 
3600 
3601  return result;
3602 
3603 memory_error:
3604 overflow:
3606  return NULL;
3607 }
3608 #ifdef _WIN32
3609 #pragma GCC diagnostic push
3610 #pragma GCC diagnostic ignored "-Wpragmas"
3611 #pragma GCC diagnostic ignored "-Wformat"
3612 #pragma GCC diagnostic ignored "-Wformat-extra-args"
3613 #endif
3614 
3635 FOUNDATIONAL_LIB_FUNC int append_string_to_string(char **string, size_t *string_length, size_t *string_alloc_size, const char *string_to_get_appended, size_t string_to_get_appended_length)
3636 {
3640  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(string_to_get_appended);
3641 
3642  // Calculate the new length after appending the new string.
3643  size_t new_size = FOUNDATIONAL_LIB_safe_add_3(*string_length, string_to_get_appended_length, 1); // Adding 1 for null terminator.
3644 
3645  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
3646  goto overflow;
3647 
3648  // If the new length exceeds the current allocation size, reallocate memory.
3649  if (new_size > *string_alloc_size)
3650  {
3652 
3653  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
3654  goto overflow;
3655 
3656  char *new_string = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(*string, new_size);
3657 
3658  if (FOUNDATIONAL_LIB_UNLIKELY(new_string == NULL))
3659  goto memory_error;
3660  *string = new_string;
3661  *string_alloc_size = new_size;
3662  }
3663 
3664  // Append the new string to the target string.
3665  FOUNDATIONAL_LIB_MEMCPY(*string + *string_length, string_to_get_appended, string_to_get_appended_length); /* Safe. */
3666  *string_length = *string_length + string_to_get_appended_length;
3667 
3668  // Null-terminate the resulting string.
3669  (*string)[*string_length] = '\0';
3670 
3671  return 0;
3672 
3673 memory_error:
3674 overflow:
3676  return -1;
3677 }
3678 
3679 #define FOUNDATIONAL_LIB_INITIAL_DATA_ARRAY_ALLOC_SIZE FOUNDATIONAL_LIB_INITIAL_STRING_ARRAY_ALLOC_SIZE
3680 
3703 FOUNDATIONAL_LIB_FUNC int append_data_to_array(void **array, size_t *array_size, size_t *array_current_alloc_size, void *data, size_t data_size)
3704 {
3707 
3708  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(array_current_alloc_size);
3710 
3711  // The _no_alloc functions omit this for optimization.
3712  if (*array_current_alloc_size == 0)
3713  {
3715  if (FOUNDATIONAL_LIB_UNLIKELY(*array == NULL))
3716  {
3717  *array_size = 0;
3718  *array_current_alloc_size = 0;
3719  goto memory_error;
3720  }
3722  *array_current_alloc_size = FOUNDATIONAL_LIB_INITIAL_STRING_ARRAY_ALLOC_SIZE;
3723  }
3724 
3725  size_t new_size;
3726 
3727  new_size = FOUNDATIONAL_LIB_safe_add_2(*array_size, 1);
3728 
3729  size_t mul;
3730 
3731  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
3732  goto overflow;
3733 
3734  mul = FOUNDATIONAL_LIB_safe_mul(new_size, data_size);
3735 
3736  // Check new_size and data_size so safe_mul doesn't get confused.
3737  if (FOUNDATIONAL_LIB_UNLIKELY(mul == 0 && new_size && data_size))
3738  goto overflow;
3739 
3740  // Realloc if needed.
3741  if (mul > *array_current_alloc_size)
3742  {
3743  const size_t new_size_total = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(mul);
3744 
3745  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0))
3746  goto overflow;
3747 
3748  void **new_array = (void **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(*array, new_size_total);
3749  if (FOUNDATIONAL_LIB_UNLIKELY(new_array == NULL))
3750  goto memory_error;
3751 
3752  *array = new_array;
3753  *array_current_alloc_size = new_size_total;
3754  }
3755 
3756  /* Copy the data. */
3757 
3758  // Safe because *array_size * data_size is smaller than the number that
3759  // we checked for overflow.
3760  FOUNDATIONAL_LIB_MEMCPY((char *)*array + (*array_size) * data_size, data, data_size); /* Safe. */
3761  ++*array_size;
3762  return 0;
3763 
3764 overflow:
3765 memory_error:
3767  return -1;
3768 }
3769 
3793 FOUNDATIONAL_LIB_FUNC int append_data_to_array_no_initial_alloc(void **array, size_t *array_size, size_t *array_current_alloc_size, void *data, size_t data_size)
3794 {
3797 
3798  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(array_current_alloc_size);
3800 
3801  const size_t new_size = FOUNDATIONAL_LIB_safe_add_2(*array_size, 1);
3802 
3803  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
3804  goto overflow;
3805 
3806  size_t nsize;
3807 
3808  nsize = FOUNDATIONAL_LIB_safe_mul(new_size, data_size);
3809 
3810  if (FOUNDATIONAL_LIB_UNLIKELY(nsize == 0 && new_size && data_size))
3811  goto overflow;
3812 
3813  if (nsize > *array_current_alloc_size)
3814  {
3815  const size_t new_size_total = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(nsize);
3816 
3817  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0))
3818  goto overflow;
3819 
3820  void **new_array = (void **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(*array, new_size_total);
3821  if (FOUNDATIONAL_LIB_UNLIKELY(new_array == NULL))
3822  goto memory_error;
3823  *array = new_array;
3824  *array_current_alloc_size = new_size_total;
3825  }
3826 
3827  /* Copy the data. */
3828 
3829  // Safe because *array_size * data_size is smaller than the number that
3830  // we checked for overflow.
3831  FOUNDATIONAL_LIB_MEMCPY((char *)*array + (*array_size) * data_size, data, data_size); /* Safe. */
3832 
3833  ++*array_size;
3834  return 0;
3835 
3836 overflow:
3837 memory_error:
3839  return -1;
3840 }
3841 
3864 FOUNDATIONAL_LIB_FUNC int append_string_to_array(char ***array, size_t *array_size, size_t *array_current_alloc_size, const char *string)
3865 {
3868 
3869  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(array_current_alloc_size);
3871 
3872  // The _no_alloc functions omit this for optimization.
3873  if (*array_current_alloc_size == 0)
3874  {
3876  if (FOUNDATIONAL_LIB_UNLIKELY(*array == NULL))
3877  {
3878  *array_size = 0;
3879  *array_current_alloc_size = 0;
3880  goto memory_error;
3881  }
3883  *array_current_alloc_size = FOUNDATIONAL_LIB_INITIAL_STRING_ARRAY_ALLOC_SIZE;
3884  }
3885 
3886  size_t new_size;
3887 
3888  new_size = FOUNDATIONAL_LIB_safe_add_2(*array_size, 1); // Null terminator
3889 
3890  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
3891  goto overflow;
3892  size_t new_size_total;
3893 
3894  new_size_total = FOUNDATIONAL_LIB_safe_mul(new_size, sizeof(char *));
3895 
3896  // Array size can be 0, which would confuse FOUNDATIONAL_LIB_safe_mul.
3897  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0 && *array_size))
3898  goto overflow;
3899 
3900  if (new_size_total > *array_current_alloc_size)
3901  {
3902  new_size_total = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(new_size_total);
3903  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0))
3904  goto overflow;
3905 
3906  char **new_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(*array, new_size_total);
3907  if (FOUNDATIONAL_LIB_UNLIKELY(new_array == NULL))
3908  goto memory_error;
3909  *array = new_array;
3910  *array_current_alloc_size = new_size_total;
3911  }
3912 
3913  (*array)[*array_size] = (char *)string;
3914 
3915  ++*array_size;
3916  return 0;
3917 
3918 overflow:
3919 memory_error:
3921  return -1;
3922 }
3923 
3948 FOUNDATIONAL_LIB_FUNC int append_string_to_array_no_initial_alloc(char ***array, size_t *array_size, size_t *array_current_alloc_size, const char *string)
3949 {
3950 
3953 
3954  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(array_current_alloc_size);
3956 
3957  const size_t new_size = FOUNDATIONAL_LIB_safe_add_2(*array_size, 1); // Null terminator
3958 
3959  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
3960  goto overflow;
3961  size_t new_size_total;
3962 
3963  new_size_total = FOUNDATIONAL_LIB_safe_mul(new_size, sizeof(char *));
3964 
3965  // Array size can be 0, which would confuse FOUNDATIONAL_LIB_safe_mul.
3966  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0 && *array_size))
3967  goto overflow;
3968 
3969  if (new_size_total > *array_current_alloc_size)
3970  {
3971  new_size_total = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(new_size_total);
3972  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0))
3973  goto overflow;
3974 
3975  char **new_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(*array, new_size_total);
3976  if (FOUNDATIONAL_LIB_UNLIKELY(new_array == NULL))
3977  goto memory_error;
3978  *array = new_array;
3979  *array_current_alloc_size = new_size_total;
3980  }
3981 
3982  (*array)[*array_size] = (char *)string;
3983 
3984  ++*array_size;
3985  return 0;
3986 
3987 overflow:
3988 memory_error:
3990  return -1;
3991 }
3992 
4016 FOUNDATIONAL_LIB_FUNC int prepend_string_to_array(char ***array, size_t *array_size, size_t *array_current_alloc_size, char *string)
4017 {
4020 
4021  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(array_current_alloc_size);
4023  // The _no_alloc functions omit this for optimization.
4024  if (*array_current_alloc_size == 0)
4025  {
4027  if (FOUNDATIONAL_LIB_UNLIKELY(*array == NULL))
4028  {
4029  /* Die immediately if enabled */
4031 
4032  *array_size = *array_current_alloc_size = 0;
4033  return -1;
4034  }
4035 
4037  *array_current_alloc_size = FOUNDATIONAL_LIB_INITIAL_STRING_ARRAY_ALLOC_SIZE;
4038  }
4039 
4040  const size_t new_size = FOUNDATIONAL_LIB_safe_add_2(*array_size, 1);
4041 
4042  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
4043  goto overflow;
4044 
4045  if (new_size > *array_current_alloc_size)
4046  {
4047  const size_t new_size_total = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(new_size);
4048  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0))
4049  goto overflow;
4050 
4051  char **new_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(*array, new_size_total);
4052  if (FOUNDATIONAL_LIB_UNLIKELY(new_array == NULL))
4053  goto memory_error;
4054  *array = new_array;
4055 
4056  *array_current_alloc_size = new_size_total;
4057  }
4058 
4059  /* Move everything forward by 1 */
4060  FOUNDATIONAL_LIB_MEMMOVE(*array + 1 /* dest location */, *array /* src location */, ((*array_size++) * sizeof(char *)) /* size */);
4061 
4062  /* Set the string in the 0th position. */
4063  **array = string;
4064  return 0;
4065 
4066 overflow:
4067 memory_error:
4069  return -1;
4070 }
4071 
4097 FOUNDATIONAL_LIB_FUNC int prepend_string_to_array_no_initial_alloc(char ***array, size_t *array_size, size_t *array_current_alloc_size, char *string)
4098 {
4101 
4102  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(array_current_alloc_size);
4104  const size_t copy_size = FOUNDATIONAL_LIB_safe_mul((*array_size), sizeof(char *));
4105 
4106  if (FOUNDATIONAL_LIB_UNLIKELY(copy_size == 0 && *array_size))
4107  goto overflow;
4108 
4109  size_t new_size;
4110 
4111  new_size = FOUNDATIONAL_LIB_safe_add_2(*array_size, 1);
4112 
4113  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
4114  goto overflow;
4115 
4116  if (new_size > *array_current_alloc_size)
4117  {
4118  const size_t new_size_total = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(new_size);
4119 
4120  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0))
4121  goto overflow;
4122 
4123  char **new_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(*array, new_size_total);
4124 
4125  if (FOUNDATIONAL_LIB_UNLIKELY(new_array == NULL))
4126  goto memory_error;
4127 
4128  *array = new_array;
4129  *array_current_alloc_size = new_size_total;
4130  }
4131 
4132  /* Move everything forward by 1 */
4133  /* Does not return an error. */
4134 
4135  // If array size plus 1 does not overflow, this should be safe.
4136  FOUNDATIONAL_LIB_MEMMOVE(*array + 1 /* dest location */, *array /* src location */, (copy_size) /* size */);
4137  ++array_size;
4138 
4139  // Set the string in the 0th position.
4140  **array = string;
4141  return 0;
4142 
4143 overflow:
4144 memory_error:
4146  return -1;
4147 }
4159 FOUNDATIONAL_LIB_FUNC size_t array_total_string_length(char **array, size_t count)
4160 {
4162  size_t length = 0;
4163 
4164  for (size_t i = 0; i < count; ++i)
4165  {
4166  // NOTE: Do not check for overflows here.
4167  length += FOUNDATIONAL_LIB_STRLEN(array[i]);
4168  }
4169 
4170  return length;
4171 }
4172 
4173 #if FOUNDATIONAL_LIB_UNSAFE_FUNCTIONS_ENABLED
4174 
4192 FOUNDATIONAL_LIB_FUNC char *shellescape(const char *input)
4193 {
4195  const size_t input_len = FOUNDATIONAL_LIB_STRLEN(input);
4196 
4197  const size_t size_with_null_t = input_len + 1;
4198  if (FOUNDATIONAL_LIB_UNLIKELY(size_with_null_t == 0))
4199  goto overflow;
4200  size_t escaped_len;
4201 
4202  escaped_len = FOUNDATIONAL_LIB_safe_mul(2, size_with_null_t);
4203 
4204  if (FOUNDATIONAL_LIB_UNLIKELY(escaped_len == 0))
4205  goto overflow;
4206 
4207  char *escaped;
4208 
4209  escaped = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(escaped_len);
4210 
4211  if (FOUNDATIONAL_LIB_UNLIKELY(escaped == NULL))
4212  goto memory_error;
4213 
4214  size_t j;
4215 
4216  j = 0;
4217 
4218  for (size_t i = 0; i < input_len; ++i)
4219  {
4220  // Escape special characters
4221  if (input[i] == ' ' || input[i] == '\t' || input[i] == '\n' || input[i] == '*' || input[i] == '?' || input[i] == '\'' || input[i] == '"' || input[i] == '\\' || input[i] == '$' || input[i] == '`' || input[i] == '(' || input[i] == ')' || input[i] == '&' || input[i] == ';' || input[i] == '|' || input[i] == '>' || input[i] == '<')
4222  {
4223  escaped[j++] = '\\';
4224  }
4225  escaped[j++] = input[i];
4226  }
4227 
4228  escaped[j] = '\0';
4229 
4230  return escaped;
4231 
4232 overflow:
4233 memory_error:
4235  return NULL;
4236 }
4237 #endif
4238 
4252 {
4254  char *new_str = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(str);
4255  if (FOUNDATIONAL_LIB_UNLIKELY(new_str == NULL))
4256  {
4258  return NULL;
4259  }
4260  size_t length = FOUNDATIONAL_LIB_STRLEN(new_str);
4261  size_t i, j;
4262 
4263  for (i = 0, j = length - 1; i < j; ++i, j--)
4264  {
4265  char temp = new_str[i];
4266  new_str[i] = new_str[j];
4267  new_str[j] = temp;
4268  }
4269 
4270  return new_str;
4271 }
4272 
4284 static inline int starts_with(const char *str, const char *prefix) { return strncmp(str, prefix, FOUNDATIONAL_LIB_STRLEN(prefix)) == 0; }
4285 
4301 static inline int ends_with(const char *str, const char *suffix)
4302 {
4303  const size_t str_len = FOUNDATIONAL_LIB_STRLEN(str);
4304  const size_t suffix_len = FOUNDATIONAL_LIB_STRLEN(suffix);
4305 
4306  if (suffix_len > str_len)
4307  {
4308  return 0; // Suffix is longer than the string
4309  }
4310 
4311  return strncmp(str + str_len - suffix_len, suffix, suffix_len) == 0;
4312 }
4313 
4314 #if defined(__GNUC__) && !defined(_WIN32)
4315 
4316 /* @brief Cross platform memmem() */
4317 
4318 #define memory_locate memmem
4319 
4320 #else
4321 
4322 /* @brief Cross platform memmem(). Slower though. We need to find a faster solution for Windows. Maybe using assembly. */
4323 FOUNDATIONAL_LIB_FUNC void *memory_locate(const void *haystack, size_t haystack_len, const void *needle, size_t needle_len)
4324 {
4327  if (FOUNDATIONAL_LIB_UNLIKELY(needle_len == 0))
4328  {
4329  return (void *)haystack;
4330  }
4331 
4332  if (FOUNDATIONAL_LIB_UNLIKELY(haystack_len < needle_len))
4333  {
4334  return NULL;
4335  }
4336 
4337  const char *h = (const char *)haystack;
4338  const char *n = (const char *)needle;
4339 
4340  const size_t max_search = haystack_len - needle_len;
4341  for (size_t i = 0; i <= max_search; ++i)
4342  {
4343  if (FOUNDATIONAL_LIB_MEMCMP(h + i, n, needle_len) == 0)
4344  {
4345  return (void *)(h + i);
4346  }
4347  }
4348 
4349  return NULL;
4350 }
4351 #endif
4352 
4367 FOUNDATIONAL_LIB_FUNC size_t count_occurrences_of_substr(const char *str, const char *substring)
4368 {
4371  const size_t substring_length = FOUNDATIONAL_LIB_STRLEN(substring);
4372  const char *pos = str;
4373  size_t count = 0;
4374 
4375  while ((pos = FOUNDATIONAL_LIB_STRSTR(pos, substring)) != NULL)
4376  {
4377  ++count;
4378  pos += substring_length;
4379  }
4380 
4381  return count;
4382 }
4383 
4405 FOUNDATIONAL_LIB_FUNC int string_has_substr(const char *string, size_t string_length, const char *substring, size_t substring_length)
4406 {
4408 
4410 
4411  if (FOUNDATIONAL_LIB_UNLIKELY(string_length == 0))
4412  {
4413  return 0;
4414  }
4415 
4416  if (FOUNDATIONAL_LIB_UNLIKELY(substring_length == 0))
4417  {
4418  return 0;
4419  }
4420 
4421  const char *beginning_of_substr_or_null = FOUNDATIONAL_LIB_STRSTR(string, substring);
4422  return beginning_of_substr_or_null != NULL;
4423 }
4424 
4443 FOUNDATIONAL_LIB_FUNC int memory_has_subchunk(void *memory, size_t memory_length, void *subchunk, size_t subchunk_length)
4444 {
4446 
4448 
4449  if (FOUNDATIONAL_LIB_UNLIKELY(memory_length == 0))
4450  {
4451  return 0;
4452  }
4453 
4454  // Alias to memmem() if we can.
4455  return (const char *)memory_locate(memory, memory_length, subchunk, subchunk_length) != NULL;
4456 }
4457 
4476 FOUNDATIONAL_LIB_FUNC size_t count_occurrences_of_substr_len(const char *string, size_t string_length, const char *substring, size_t substring_length)
4477 {
4479 
4481 
4482  if (FOUNDATIONAL_LIB_UNLIKELY(string_length == 0))
4483  {
4484  return 0;
4485  }
4486 
4487  if (FOUNDATIONAL_LIB_UNLIKELY(substring_length == 0))
4488  {
4489  return 0;
4490  }
4491 
4492 #if defined(__GNUC__) && defined(__unix__)
4493  size_t count = 0;
4494  size_t pos = 0;
4495 
4496  const size_t orig_string_length = string_length;
4497  /* This might be significantly faster than FOUNDATIONAL_LIB_STRSTR() */
4498  for (;;)
4499  {
4500  const char *beginning_of_substr_or_null = (const char *)memmem(string + pos, string_length, substring, substring_length);
4501 
4502  if (FOUNDATIONAL_LIB_UNLIKELY(beginning_of_substr_or_null == NULL))
4503  break;
4504 
4505  ++count;
4506 
4507  /* Update pos */
4508  pos = beginning_of_substr_or_null - string + substring_length;
4509  string_length = orig_string_length - pos;
4510  }
4511 #else
4512  const char *pos = string;
4513  size_t count = 0;
4514  while ((pos = FOUNDATIONAL_LIB_STRSTR(pos, substring)) != NULL)
4515  {
4516  ++count;
4517  pos += substring_length;
4518  }
4519 #endif
4520 
4521  return count;
4522 }
4523 
4537 static inline ssize_t index_of_char(const char *str, char chr)
4538 {
4540  const char *result = FOUNDATIONAL_LIB_STRCHR(str, chr);
4541  return result != NULL ? result - str : -1;
4542 }
4543 
4559 static inline ssize_t last_index_of_char(const char *str, char chr)
4560 {
4562  const char *result = strrchr(str, chr);
4563  return result != NULL ? result - str : -1;
4564 }
4565 
4578 {
4579 
4581 
4582  const size_t len = FOUNDATIONAL_LIB_STRLEN(str);
4583 
4584  for (size_t i = 0; i < len; ++i)
4585  {
4586  if (!FOUNDATIONAL_LIB_ISDIGIT(str[i]))
4587  {
4588  return 0; // Contains non-numeric character
4589  }
4590  }
4591 
4592  return 1; // Contains only numeric characters
4593 }
4594 
4610 {
4612 
4613  size_t len = FOUNDATIONAL_LIB_STRLEN(str);
4614 
4615  for (size_t i = 0; i < len; ++i)
4616  {
4617  if (!FOUNDATIONAL_LIB_ISALNUM(str[i]))
4618  {
4619  return 0; // Contains non-alphanumeric character
4620  }
4621  }
4622 
4623  return 1; // Contains only alphanumeric characters
4624 }
4625 
4639 FOUNDATIONAL_LIB_FUNC char *longest_common_prefix(const char **strings, size_t count)
4640 {
4642  if (FOUNDATIONAL_LIB_UNLIKELY(count == 0))
4643  {
4644  char *ret = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(""); // Empty string for an empty array
4645  if (FOUNDATIONAL_LIB_UNLIKELY(ret == NULL))
4646  {
4648  return NULL;
4649  }
4650 
4651  return ret;
4652  }
4653 
4654  size_t max_common_len = FOUNDATIONAL_LIB_STRLEN(strings[0]);
4655 
4656  /* Find the max common length among the strings */
4657  for (size_t i = 1; i < count; ++i)
4658  {
4659  size_t current_len = FOUNDATIONAL_LIB_STRLEN(strings[i]);
4660  if (current_len < max_common_len)
4661  {
4662  max_common_len = current_len;
4663  }
4664  }
4665 
4666  /* Compare characters across the strings until a mismatch is found */
4667  for (size_t i = 0; i < max_common_len; ++i)
4668  {
4669  for (size_t j = 1; j < count; ++j)
4670  {
4671  if (strings[j][i] != strings[0][i])
4672  {
4673  /* Mismatch found, return the prefix up to this point */
4674 
4675  // Don't FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC 0.
4676  if (FOUNDATIONAL_LIB_UNLIKELY(i == SIZE_MAX))
4677  {
4679  return NULL;
4680  }
4681 
4682  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(i + sizeof("")); /* Safe. */
4683  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
4684  {
4686  return NULL;
4687  }
4688  FOUNDATIONAL_LIB_MEMCPY(result, strings[0], i);
4689  result[i] = '\0';
4690  return result;
4691  }
4692  }
4693  }
4694 
4695  /* All strings match up to the minimum length, return the entire prefix */
4696  char *dup = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(strings[0]);
4697  if (FOUNDATIONAL_LIB_UNLIKELY(dup == NULL))
4698  {
4700  return NULL;
4701  }
4702 
4703  return dup;
4704 }
4705 
4719 FOUNDATIONAL_LIB_FUNC char *longest_common_suffix(const char **strings, size_t count)
4720 {
4722 
4723  if (FOUNDATIONAL_LIB_UNLIKELY(count == 0))
4724  {
4725  char *return_value = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(""); // Empty string for an empty array
4726  if (FOUNDATIONAL_LIB_UNLIKELY(return_value == NULL))
4727  {
4729  return NULL;
4730  }
4731  return return_value;
4732  }
4733 
4734  size_t max_common_len = FOUNDATIONAL_LIB_STRLEN(strings[0]);
4735 
4736  /* Find the max common length among the strings */
4737  for (size_t i = 1; i < count; ++i)
4738  {
4739  size_t current_len = FOUNDATIONAL_LIB_STRLEN(strings[i]);
4740  if (current_len < max_common_len)
4741  {
4742  max_common_len = current_len;
4743  }
4744  }
4745 
4746  /* Compare characters across the strings until a mismatch is found */
4747  for (size_t i = 0; i < max_common_len; ++i)
4748  {
4749  for (size_t j = 1; j < count; ++j)
4750  {
4751  size_t current_len = FOUNDATIONAL_LIB_STRLEN(strings[j]);
4752  if (strings[j][current_len - i - 1] != strings[0][max_common_len - i - 1])
4753  {
4754  /* Mismatch found, return the suffix up to this point */
4755 
4756  // Don't FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC 0.
4757  if (FOUNDATIONAL_LIB_UNLIKELY(i == SIZE_MAX))
4758  {
4760  return NULL;
4761  }
4762 
4763  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(i + sizeof("")); /* Safe. */
4764  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
4765  {
4767  return NULL;
4768  }
4769 
4770  FOUNDATIONAL_LIB_MEMCPY(result, strings[0] + max_common_len - i, i); /* Safe. */
4771  result[i] = '\0';
4772  return result;
4773  }
4774  }
4775  }
4776 
4777  /* All strings match up to the minimum length, return the entire suffix */
4778  char *return_value = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(strings[0] + max_common_len); /* Should be Safe. */
4779  if (FOUNDATIONAL_LIB_UNLIKELY(return_value == NULL))
4780  {
4782  return NULL;
4783  }
4784 
4785  return return_value;
4786 }
4787 
4798 static inline double str_to_double(const char *string)
4799 {
4800 
4802 
4803  return atof(string);
4804 }
4805 
4817 FOUNDATIONAL_LIB_FUNC ssize_t find_first_of(const char *str, const char *char_set)
4818 {
4821 
4822  const char *result = strpbrk(str, char_set);
4823 
4824  return FOUNDATIONAL_LIB_LIKELY(result != NULL) ? result - str : -1;
4825 }
4826 
4840 FOUNDATIONAL_LIB_FUNC ssize_t find_last_of(const char *str, const char *char_set)
4841 {
4844 
4845  const size_t len = FOUNDATIONAL_LIB_STRLEN(str);
4846 
4847  for (ssize_t i = len - 1; i >= 0; i--)
4848  {
4849  if (FOUNDATIONAL_LIB_STRCHR(char_set, str[i]) != NULL)
4850  {
4851  return i;
4852  }
4853  }
4854  return -1;
4855 }
4856 
4866 {
4868 
4869  const size_t len = FOUNDATIONAL_LIB_STRLEN(str);
4870 
4871  /* Swap characters from both ends towards the center */
4872  for (size_t i = 0, j = len - 1; i < j; ++i, --j)
4873  {
4874  char temp = str[i];
4875  str[i] = str[j];
4876  str[j] = temp;
4877  }
4878 }
4879 
4890 {
4892 
4893  if (*str == '\0')
4894  {
4895  return 0; // Empty string is not a valid integer
4896  }
4897 
4898  /* Check for optional sign */
4899  if (*str == '+' || *str == '-')
4900  {
4901  ++str;
4902  }
4903 
4904  /* Check for at least one digit */
4905  if (!FOUNDATIONAL_LIB_ISDIGIT(*str))
4906  {
4907  return 0;
4908  }
4909 
4910  /* Check for remaining digits */
4911  while (*str != '\0')
4912  {
4913  if (!FOUNDATIONAL_LIB_ISDIGIT(*str))
4914  {
4915  return 0;
4916  }
4917  ++str;
4918  }
4919 
4920  return 1; // Valid integer
4921 }
4922 
4932 FOUNDATIONAL_LIB_FUNC size_t common_prefix_length(const char *str1, const char *str2)
4933 {
4936 
4937  const size_t len1 = FOUNDATIONAL_LIB_STRLEN(str1);
4938  const size_t len2 = FOUNDATIONAL_LIB_STRLEN(str2);
4939 
4940  const size_t min_len = (len1 < len2) ? len1 : len2;
4941 
4942  for (size_t i = 0; i < min_len; ++i)
4943  {
4944  if (str1[i] != str2[i])
4945  {
4946  return i; // Mismatch found, return current index
4947  }
4948  }
4949 
4950  return min_len; // No mismatch found, return the minimum length
4951 }
4952 
4962 FOUNDATIONAL_LIB_FUNC size_t common_suffix_length(const char *str1, const char *str2)
4963 {
4966 
4967  const size_t len1 = FOUNDATIONAL_LIB_STRLEN(str1);
4968  const size_t len2 = FOUNDATIONAL_LIB_STRLEN(str2);
4969 
4970  const size_t min_len = (len1 < len2) ? len1 : len2;
4971 
4972  for (size_t i = 1; i <= min_len; ++i)
4973  {
4974  if (str1[len1 - i] != str2[len2 - i])
4975  {
4976  return i - 1; // Mismatch found, return previous index
4977  }
4978  }
4979 
4980  return min_len; // No mismatch found, return the minimum length
4981 }
4982 
4994 {
4996 
4997  const size_t len = FOUNDATIONAL_LIB_STRLEN(str);
4998  if (FOUNDATIONAL_LIB_UNLIKELY(len == SIZE_MAX))
4999  {
5001  return NULL;
5002  }
5003 
5004  char *title_case = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(len + sizeof("")); /* Safe. */
5005 
5006  if (FOUNDATIONAL_LIB_UNLIKELY(title_case == NULL))
5007  {
5009  return NULL;
5010  }
5011 
5012  int make_upper = 1; // Start with the first character as uppercase
5013 
5014  for (size_t i = 0; i < len; ++i)
5015  {
5016  if (FOUNDATIONAL_LIB_ISSPACE(str[i]))
5017  {
5018  make_upper = 1; // Set the flag to capitalize the next character
5019  title_case[i] = str[i];
5020  }
5021  else
5022  {
5023  title_case[i] = make_upper ? toupper(str[i]) : tolower(str[i]);
5024  make_upper = 0; // Reset the flag
5025  }
5026  }
5027 
5028  title_case[len] = '\0';
5029 
5030  return title_case;
5031 }
5032 
5042 FOUNDATIONAL_LIB_FUNC int find_max_int_in_array(const int *array, size_t size)
5043 {
5045  if (FOUNDATIONAL_LIB_UNLIKELY(size == 0))
5046  {
5047  /* Handle empty array case */
5048  return -1;
5049  }
5050 
5051  int max = array[0];
5052 
5053  for (size_t i = 1; i < size; ++i)
5054  {
5055  if (array[i] > max)
5056  {
5057  max = array[i];
5058  }
5059  }
5060 
5061  return max;
5062 }
5063 
5073 FOUNDATIONAL_LIB_FUNC int find_min_int_in_array(const int *array, size_t size)
5074 {
5076  if (FOUNDATIONAL_LIB_UNLIKELY(size == 0))
5077  {
5078  /* Handle empty array case */
5079  return -1;
5080  }
5081 
5082  int min = array[0];
5083 
5084  for (size_t i = 1; i < size; ++i)
5085  {
5086  if (array[i] < min)
5087  {
5088  min = array[i];
5089  }
5090  }
5091 
5092  return min;
5093 }
5094 
5104 FOUNDATIONAL_LIB_FUNC int sum_of_int_array(const int *array, size_t size)
5105 {
5107  int sum = 0;
5108 
5109  for (size_t i = 0; i < size; ++i)
5110  {
5111  sum += array[i];
5112  }
5113 
5114  return sum;
5115 }
5116 
5126 {
5128 
5129  for (size_t i = 0, j = size - 1; i < j; ++i, --j)
5130  {
5131  int temp = array[i];
5132  array[i] = array[j];
5133  array[j] = temp;
5134  }
5135 }
5136 
5148 {
5150  for (size_t i = 1; i < size; ++i)
5151  {
5152  if (array[i] < array[i - 1])
5153  {
5154  return 0; // Not sorted in ascending order
5155  }
5156  }
5157  return 1; // Sorted in ascending order
5158 }
5159 
5171 {
5173  for (size_t i = 1; i < size; ++i)
5174  {
5175  if (array[i] > array[i - 1])
5176  {
5177  return 0; // Not sorted in descending order
5178  }
5179  }
5180  return 1; // Sorted in descending order
5181 }
5182 
5196 FOUNDATIONAL_LIB_FUNC size_t *generate_range(size_t start, size_t end, size_t step, size_t *range_size)
5197 {
5199  // Check for invalid range
5200  if (FOUNDATIONAL_LIB_UNLIKELY(start > end || step == 0))
5201  {
5203  return NULL;
5204  }
5205  const size_t size = (end - start) / step + 1;
5206 
5207  if (FOUNDATIONAL_LIB_UNLIKELY(size == 0))
5208  { // Overflow
5210  return NULL;
5211  }
5212 
5213  const size_t alloc_size = FOUNDATIONAL_LIB_safe_mul(size, sizeof(size_t));
5214 
5215  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size == 0))
5216  { // Overflow
5218  return NULL;
5219  }
5220 
5221  size_t *range = (size_t *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size);
5222 
5223  if (FOUNDATIONAL_LIB_UNLIKELY(range == NULL))
5224  {
5226  return NULL;
5227  }
5228 
5229  for (size_t i = 0, value = start; i < size; ++i, value += step)
5230  {
5231  range[i] = value;
5232  }
5233 
5234  *range_size = size;
5235  return range;
5236 }
5237 
5251 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmpstringp(const void *p1, const void *p2)
5252 {
5255  return FOUNDATIONAL_LIB_STRCMP(*(const char **)p1, *(const char **)p2);
5256 }
5257 
5264 FOUNDATIONAL_LIB_FUNC void sort_strings(char **strings, size_t size)
5265 {
5266 
5268  qsort(strings, size, sizeof(char *), FOUNDATIONAL_LIB_cmpstringp);
5269 }
5270 
5282 FOUNDATIONAL_LIB_FUNC char **sorted_strings(char **strings, size_t size)
5283 {
5284 
5286 
5287  char **dup_strings = (char **)arraydup(strings, size, sizeof(char *));
5288  if (FOUNDATIONAL_LIB_UNLIKELY(dup_strings == NULL))
5289  {
5290  return NULL; /* No need to re die aggressively. */
5291  }
5292  qsort(dup_strings, size, sizeof(char *), FOUNDATIONAL_LIB_cmpstringp);
5293  return dup_strings;
5294 }
5295 
5309 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_uints(const void *a, const void *b)
5310 {
5311 
5314  return (*(unsigned int *)a - *(unsigned int *)b);
5315 }
5316 
5326 FOUNDATIONAL_LIB_FUNC void sort_uints(unsigned int *uints, size_t size)
5327 {
5329 
5330  qsort(uints, size, sizeof(unsigned int), FOUNDATIONAL_LIB_cmp_uints);
5331 }
5332 
5345 FOUNDATIONAL_LIB_FUNC unsigned int *sorted_uints(unsigned int *uints, size_t size)
5346 {
5348 
5349  unsigned int *dup_uints = (unsigned int *)arraydup(uints, size, sizeof(unsigned int));
5350  if (FOUNDATIONAL_LIB_UNLIKELY(dup_uints == NULL))
5351  {
5352  return NULL;
5353  }
5354  qsort(uints, size, sizeof(unsigned int), FOUNDATIONAL_LIB_cmp_uints);
5355  return dup_uints;
5356 }
5357 
5372 {
5375  return (*(unsigned int **)a - *(unsigned int **)b);
5376 }
5377 
5387 FOUNDATIONAL_LIB_FUNC void sort_uint_ptrs(unsigned int **uint_ptrs, size_t size)
5388 {
5390 
5391  qsort(uint_ptrs, size, sizeof(unsigned int *), FOUNDATIONAL_LIB_cmp_uint_ptrs);
5392 }
5393 
5408 FOUNDATIONAL_LIB_FUNC unsigned int **sorted_uint_ptrs(unsigned int **uint_ptrs, size_t size)
5409 {
5410 
5412 
5413  unsigned int **dup_uint_ptrs = (unsigned int **)arraydup(uint_ptrs, size, sizeof(unsigned int *));
5414  if (FOUNDATIONAL_LIB_UNLIKELY(dup_uint_ptrs == NULL))
5415  {
5416  return NULL;
5417  }
5418  qsort(uint_ptrs, size, sizeof(unsigned int *), FOUNDATIONAL_LIB_cmp_uint_ptrs);
5419  return dup_uint_ptrs;
5420 }
5421 
5435 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ints(const void *a, const void *b)
5436 {
5437 
5440 
5441  return (*(int *)a - *(int *)b);
5442 }
5443 
5453 FOUNDATIONAL_LIB_FUNC void sort_ints(int *ints, size_t size)
5454 {
5455 
5457  qsort(ints, size, sizeof(int), FOUNDATIONAL_LIB_cmp_ints);
5458 }
5459 
5472 FOUNDATIONAL_LIB_FUNC int *sorted_ints(int *ints, size_t size)
5473 {
5474 
5476 
5477  int *dup_ints = (int *)arraydup(ints, size, sizeof(int));
5478  if (FOUNDATIONAL_LIB_UNLIKELY(dup_ints == NULL))
5479  {
5480  return NULL;
5481  }
5482 
5483  qsort(ints, size, sizeof(int), FOUNDATIONAL_LIB_cmp_ints);
5484  return dup_ints;
5485 }
5486 
5500 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_int_ptrs(const void *a, const void *b)
5501 {
5502 
5505  return (*(int **)a - *(int **)b);
5506 }
5507 
5517 FOUNDATIONAL_LIB_FUNC void sort_int_ptrs(int **int_ptrs, size_t size)
5518 {
5520  qsort(int_ptrs, size, sizeof(int *), FOUNDATIONAL_LIB_cmp_int_ptrs);
5521 }
5522 
5537 FOUNDATIONAL_LIB_FUNC int **sorted_int_ptrs(int **int_ptrs, size_t size)
5538 {
5540  int **dup_int_ptrs = (int **)arraydup(int_ptrs, size, sizeof(int *));
5541  if (FOUNDATIONAL_LIB_UNLIKELY(dup_int_ptrs == NULL))
5542  {
5543  return NULL;
5544  }
5545  qsort(int_ptrs, size, sizeof(int *), FOUNDATIONAL_LIB_cmp_int_ptrs);
5546  return dup_int_ptrs;
5547 }
5548 
5561 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_uchars(const void *a, const void *b)
5562 {
5565  return (*(unsigned char *)a - *(unsigned char *)b);
5566 }
5567 
5577 FOUNDATIONAL_LIB_FUNC void sort_uchars(unsigned char *uchars, size_t size)
5578 {
5579 
5581  qsort(uchars, size, sizeof(unsigned char), FOUNDATIONAL_LIB_cmp_uchars);
5582 }
5583 
5597 FOUNDATIONAL_LIB_FUNC unsigned char *sorted_uchars(unsigned char *uchars, size_t size)
5598 {
5600 
5601  unsigned char *dup_uchars = (unsigned char *)arraydup(uchars, size, sizeof(unsigned char));
5602  if (FOUNDATIONAL_LIB_UNLIKELY(dup_uchars == NULL))
5603  {
5604  return NULL;
5605  }
5606  qsort(uchars, size, sizeof(unsigned char), FOUNDATIONAL_LIB_cmp_uchars);
5607  return dup_uchars;
5608 }
5609 
5625 {
5628  return (*(unsigned char **)a - *(unsigned char **)b);
5629 }
5640 FOUNDATIONAL_LIB_FUNC void sort_uchar_ptrs(unsigned char **uchar_ptrs, size_t size)
5641 {
5642 
5644  qsort(uchar_ptrs, size, sizeof(unsigned char *), FOUNDATIONAL_LIB_cmp_uchar_ptrs);
5645 }
5646 
5662 FOUNDATIONAL_LIB_FUNC unsigned char **sorted_uchar_ptrs(unsigned char **uchar_ptrs, size_t size)
5663 {
5665  unsigned char **dup_uchar_ptrs = (unsigned char **)arraydup(uchar_ptrs, size, sizeof(unsigned char *));
5666  if (FOUNDATIONAL_LIB_UNLIKELY(dup_uchar_ptrs == NULL))
5667  {
5668  return NULL;
5669  }
5670  qsort(uchar_ptrs, size, sizeof(unsigned char *), FOUNDATIONAL_LIB_cmp_uchar_ptrs);
5671  return dup_uchar_ptrs;
5672 }
5673 
5686 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_chars(const void *a, const void *b)
5687 {
5690  return (*(char *)a - *(char *)b);
5691 }
5692 
5701 FOUNDATIONAL_LIB_FUNC void sort_chars(char *chars, size_t size)
5702 {
5704  qsort(chars, size, sizeof(char), FOUNDATIONAL_LIB_cmp_chars);
5705 }
5706 
5720 FOUNDATIONAL_LIB_FUNC char *sorted_chars(char *chars, size_t size)
5721 {
5723  char *dup_chars = (char *)arraydup(chars, size, sizeof(char));
5724  if (FOUNDATIONAL_LIB_UNLIKELY(dup_chars == NULL))
5725  {
5726  return NULL;
5727  }
5728  qsort(chars, size, sizeof(char), FOUNDATIONAL_LIB_cmp_chars);
5729  return dup_chars;
5730 }
5731 
5745 {
5748 
5749  return (*(char **)a - *(char **)b);
5750 }
5760 FOUNDATIONAL_LIB_FUNC void sort_char_ptrs(char **char_ptrs, size_t size)
5761 {
5763 
5764  qsort(char_ptrs, size, sizeof(char *), FOUNDATIONAL_LIB_cmp_char_ptrs);
5765 }
5766 
5781 FOUNDATIONAL_LIB_FUNC char **sorted_char_ptrs(char **char_ptrs, size_t size)
5782 {
5784  char **dup_char_ptrs = (char **)arraydup(char_ptrs, size, sizeof(char *));
5785 
5786  if (FOUNDATIONAL_LIB_UNLIKELY(dup_char_ptrs == NULL))
5787  {
5788  return NULL;
5789  }
5790 
5791  qsort(char_ptrs, size, sizeof(char *), FOUNDATIONAL_LIB_cmp_char_ptrs);
5792  return dup_char_ptrs;
5793 }
5794 
5807 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ushorts(const void *a, const void *b)
5808 {
5809 
5812  return (*(unsigned short *)a - *(unsigned short *)b);
5813 }
5814 
5824 FOUNDATIONAL_LIB_FUNC void sort_ushorts(unsigned short *ushorts, size_t size)
5825 {
5826 
5828 
5829  qsort(ushorts, size, sizeof(unsigned short), FOUNDATIONAL_LIB_cmp_ushorts);
5830 }
5831 
5845 FOUNDATIONAL_LIB_FUNC unsigned short *sorted_ushorts(unsigned short *ushorts, size_t size)
5846 {
5848  unsigned short *dup_ushorts = (unsigned short *)arraydup(ushorts, size, sizeof(unsigned short));
5849 
5850  if (FOUNDATIONAL_LIB_UNLIKELY(dup_ushorts == NULL))
5851  {
5852  return NULL;
5853  }
5854 
5855  qsort(ushorts, size, sizeof(unsigned short), FOUNDATIONAL_LIB_cmp_ushorts);
5856  return dup_ushorts;
5857 }
5858 
5874 {
5875 
5878 
5879  return (*(unsigned short **)a - *(unsigned short **)b);
5880 }
5881 
5892 FOUNDATIONAL_LIB_FUNC void sort_ushort_ptrs(unsigned short **ushort_ptrs, size_t size)
5893 {
5894 
5896  qsort(ushort_ptrs, size, sizeof(unsigned short *), FOUNDATIONAL_LIB_cmp_ushort_ptrs);
5897 }
5898 
5914 FOUNDATIONAL_LIB_FUNC unsigned short **sorted_ushort_ptrs(unsigned short **ushort_ptrs, size_t size)
5915 {
5917 
5918  unsigned short **dup_ushort_ptrs = (unsigned short **)arraydup(ushort_ptrs, size, sizeof(unsigned short *));
5919  if (FOUNDATIONAL_LIB_UNLIKELY(dup_ushort_ptrs == NULL))
5920  {
5921  return NULL;
5922  }
5923 
5924  qsort(ushort_ptrs, size, sizeof(unsigned short *), FOUNDATIONAL_LIB_cmp_ushort_ptrs);
5925  return dup_ushort_ptrs;
5926 }
5927 
5940 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_shorts(const void *a, const void *b)
5941 {
5944  return (*(short *)a - *(short *)b);
5945 }
5954 FOUNDATIONAL_LIB_FUNC void sort_shorts(short *shorts, size_t size)
5955 {
5956 
5958  qsort(shorts, size, sizeof(short), FOUNDATIONAL_LIB_cmp_shorts);
5959 }
5960 
5974 FOUNDATIONAL_LIB_FUNC short *sorted_shorts(short *shorts, size_t size)
5975 {
5977 
5978  short *dup_shorts = (short *)arraydup(shorts, size, sizeof(short));
5979 
5980  if (FOUNDATIONAL_LIB_UNLIKELY(dup_shorts == NULL))
5981  {
5982  return NULL;
5983  }
5984 
5985  qsort(shorts, size, sizeof(short), FOUNDATIONAL_LIB_cmp_shorts);
5986  return dup_shorts;
5987 }
5988 
6002 {
6003 
6006  return (*(short **)a - *(short **)b);
6007 }
6008 
6018 FOUNDATIONAL_LIB_FUNC void sort_short_ptrs(short **short_ptrs, size_t size)
6019 {
6020 
6022  qsort(short_ptrs, size, sizeof(short *), FOUNDATIONAL_LIB_cmp_short_ptrs);
6023 }
6024 
6038 FOUNDATIONAL_LIB_FUNC short **sorted_short_ptrs(short **short_ptrs, size_t size)
6039 {
6041 
6042  short **dup_short_ptrs = (short **)arraydup(short_ptrs, size, sizeof(short *));
6043 
6044  if (FOUNDATIONAL_LIB_UNLIKELY(dup_short_ptrs == NULL))
6045  {
6046  return NULL;
6047  }
6048 
6049  qsort(short_ptrs, size, sizeof(short *), FOUNDATIONAL_LIB_cmp_short_ptrs);
6050  return dup_short_ptrs;
6051 }
6052 
6065 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ulongs(const void *a, const void *b)
6066 {
6069  return (*(unsigned long *)a - *(unsigned long *)b);
6070 }
6071 
6081 FOUNDATIONAL_LIB_FUNC void sort_ulongs(unsigned long *ulongs, size_t size)
6082 {
6084  qsort(ulongs, size, sizeof(unsigned long), FOUNDATIONAL_LIB_cmp_ulongs);
6085 }
6086 
6100 FOUNDATIONAL_LIB_FUNC unsigned long *sorted_ulongs(unsigned long *ulongs, size_t size)
6101 {
6103  unsigned long *dup_ulongs = (unsigned long *)arraydup(ulongs, size, sizeof(unsigned long));
6104 
6105  if (FOUNDATIONAL_LIB_UNLIKELY(dup_ulongs == NULL))
6106  {
6107  return NULL;
6108  }
6109 
6110  qsort(ulongs, size, sizeof(unsigned long), FOUNDATIONAL_LIB_cmp_ulongs);
6111  return dup_ulongs;
6112 }
6113 
6129 {
6132 
6133  return (*(unsigned long **)a - *(unsigned long **)b);
6134 }
6135 
6146 FOUNDATIONAL_LIB_FUNC void sort_ulong_ptrs(unsigned long **ulong_ptrs, size_t size)
6147 {
6148 
6150  qsort(ulong_ptrs, size, sizeof(unsigned long *), FOUNDATIONAL_LIB_cmp_ulong_ptrs);
6151 }
6152 
6168 FOUNDATIONAL_LIB_FUNC unsigned long **sorted_ulong_ptrs(unsigned long **ulong_ptrs, size_t size)
6169 {
6171 
6172  unsigned long **dup_ulong_ptrs = (unsigned long **)arraydup(ulong_ptrs, size, sizeof(unsigned long *));
6173  if (FOUNDATIONAL_LIB_UNLIKELY(dup_ulong_ptrs == NULL))
6174  {
6175  return NULL;
6176  }
6177 
6178  qsort(ulong_ptrs, size, sizeof(unsigned long *), FOUNDATIONAL_LIB_cmp_ulong_ptrs);
6179  return dup_ulong_ptrs;
6180 }
6181 
6196 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_longs(const void *a, const void *b)
6197 {
6198 
6201  return (*(long *)a - *(long *)b);
6202 }
6203 
6214 FOUNDATIONAL_LIB_FUNC void sort_longs(long *longs, size_t size)
6215 {
6216 
6218 
6219  qsort(longs, size, sizeof(long), FOUNDATIONAL_LIB_cmp_longs);
6220 }
6221 
6237 FOUNDATIONAL_LIB_FUNC long *sorted_longs(long *longs, size_t size)
6238 {
6239 
6241 
6242  long *dup_longs = (long *)arraydup(longs, size, sizeof(long));
6243  if (FOUNDATIONAL_LIB_UNLIKELY(dup_longs == NULL))
6244  {
6245  return NULL;
6246  }
6247 
6248  qsort(longs, size, sizeof(long), FOUNDATIONAL_LIB_cmp_longs);
6249  return dup_longs;
6250 }
6251 
6265 {
6266 
6269  return (*(long **)a - *(long **)b);
6270 }
6280 FOUNDATIONAL_LIB_FUNC void sort_long_ptrs(long **long_ptrs, size_t size)
6281 {
6283  qsort(long_ptrs, size, sizeof(long *), FOUNDATIONAL_LIB_cmp_long_ptrs);
6284 }
6299 FOUNDATIONAL_LIB_FUNC long **sorted_long_ptrs(long **long_ptrs, size_t size)
6300 {
6302  long **dup_long_ptrs = (long **)arraydup(long_ptrs, size, sizeof(long *));
6303  if (FOUNDATIONAL_LIB_UNLIKELY(dup_long_ptrs == NULL))
6304  {
6305  return NULL;
6306  }
6307 
6308  qsort(long_ptrs, size, sizeof(long *), FOUNDATIONAL_LIB_cmp_long_ptrs);
6309  return dup_long_ptrs;
6310 }
6311 
6325 {
6328  return (*(unsigned long long *)a - *(unsigned long long *)b);
6329 }
6339 FOUNDATIONAL_LIB_FUNC void sort_ulong_longs(unsigned long long *ulong_longs, size_t size)
6340 {
6341 
6343 
6344  qsort(ulong_longs, size, sizeof(unsigned long long), FOUNDATIONAL_LIB_cmp_ulong_longs);
6345 }
6359 FOUNDATIONAL_LIB_FUNC unsigned long long *sorted_ulong_longs(unsigned long long *ulong_longs, size_t size)
6360 {
6362  unsigned long long *dup_ulong_longs = (unsigned long long *)arraydup(ulong_longs, size, sizeof(unsigned long long));
6363  if (FOUNDATIONAL_LIB_UNLIKELY(dup_ulong_longs == NULL))
6364  {
6365  return NULL;
6366  }
6367 
6368  qsort(ulong_longs, size, sizeof(unsigned long long), FOUNDATIONAL_LIB_cmp_ulong_longs);
6369  return dup_ulong_longs;
6370 }
6371 
6387 {
6390 
6391  return (*(unsigned long long **)a - *(unsigned long long **)b);
6392 }
6393 
6404 FOUNDATIONAL_LIB_FUNC void sort_ulong_long_ptrs(unsigned long long **ulong_long_ptrs, size_t size)
6405 {
6407  qsort(ulong_long_ptrs, size, sizeof(unsigned long long *), FOUNDATIONAL_LIB_cmp_ulong_long_ptrs);
6408 }
6424 FOUNDATIONAL_LIB_FUNC unsigned long long **sorted_ulong_long_ptrs(unsigned long long **ulong_long_ptrs, size_t size)
6425 {
6427 
6428  unsigned long long **dup_ulong_long_ptrs = (unsigned long long **)arraydup(ulong_long_ptrs, size, sizeof(unsigned long long *));
6429  if (FOUNDATIONAL_LIB_UNLIKELY(dup_ulong_long_ptrs == NULL))
6430  {
6431  return NULL;
6432  }
6433 
6434  qsort(ulong_long_ptrs, size, sizeof(unsigned long long *), FOUNDATIONAL_LIB_cmp_ulong_long_ptrs);
6435  return dup_ulong_long_ptrs;
6436 }
6437 
6451 {
6454  return (*(long long *)a - *(long long *)b);
6455 }
6464 FOUNDATIONAL_LIB_FUNC void sort_long_longs(long long *long_longs, size_t size)
6465 {
6467  qsort(long_longs, size, sizeof(long long), FOUNDATIONAL_LIB_cmp_long_longs);
6468 }
6482 FOUNDATIONAL_LIB_FUNC long long *sorted_long_longs(long long *long_longs, size_t size)
6483 {
6485  long long *dup_long_longs = (long long *)arraydup(long_longs, size, sizeof(long long));
6486 
6487  if (FOUNDATIONAL_LIB_UNLIKELY(dup_long_longs == NULL))
6488  {
6489  return NULL;
6490  }
6491 
6492  qsort(long_longs, size, sizeof(long long), FOUNDATIONAL_LIB_cmp_long_longs);
6493  return dup_long_longs;
6494 }
6495 
6509 {
6512  return (*(long long **)a - *(long long **)b);
6513 }
6514 
6525 FOUNDATIONAL_LIB_FUNC void sort_long_long_ptrs(long long **long_long_ptrs, size_t size)
6526 {
6528  qsort(long_long_ptrs, size, sizeof(long long *), FOUNDATIONAL_LIB_cmp_long_long_ptrs);
6529 }
6530 
6546 FOUNDATIONAL_LIB_FUNC long long **sorted_long_long_ptrs(long long **long_long_ptrs, size_t size)
6547 {
6549 
6550  long long **dup_long_long_ptrs = (long long **)arraydup(long_long_ptrs, size, sizeof(long long *));
6551  if (FOUNDATIONAL_LIB_UNLIKELY(dup_long_long_ptrs == NULL))
6552  {
6553  return NULL;
6554  }
6555 
6556  qsort(long_long_ptrs, size, sizeof(long long *), FOUNDATIONAL_LIB_cmp_long_long_ptrs);
6557  return dup_long_long_ptrs;
6558 }
6559 
6572 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_floats(const void *a, const void *b)
6573 {
6576  return (*(float *)a - *(float *)b);
6577 }
6578 
6587 FOUNDATIONAL_LIB_FUNC void sort_floats(float *floats, size_t size)
6588 {
6590  qsort(floats, size, sizeof(float), FOUNDATIONAL_LIB_cmp_floats);
6591 }
6592 
6606 FOUNDATIONAL_LIB_FUNC float *sorted_floats(float *floats, size_t size)
6607 {
6609 
6610  float *dup_floats = (float *)arraydup(floats, size, sizeof(float));
6611  if (FOUNDATIONAL_LIB_UNLIKELY(dup_floats == NULL))
6612  {
6613  return NULL;
6614  }
6615 
6616  qsort(floats, size, sizeof(float), FOUNDATIONAL_LIB_cmp_floats);
6617  return dup_floats;
6618 }
6619 
6633 {
6636  return (*(float **)a - *(float **)b);
6637 }
6638 
6648 FOUNDATIONAL_LIB_FUNC void sort_float_ptrs(float **float_ptrs, size_t size)
6649 {
6650 
6652  qsort(float_ptrs, size, sizeof(float *), FOUNDATIONAL_LIB_cmp_float_ptrs);
6653 }
6654 
6668 FOUNDATIONAL_LIB_FUNC float **sorted_float_ptrs(float **float_ptrs, size_t size)
6669 {
6671 
6672  float **dup_float_ptrs = (float **)arraydup(float_ptrs, size, sizeof(float *));
6673 
6674  if (FOUNDATIONAL_LIB_UNLIKELY(dup_float_ptrs == NULL))
6675  {
6676  return NULL;
6677  }
6678  qsort(float_ptrs, size, sizeof(float *), FOUNDATIONAL_LIB_cmp_float_ptrs);
6679  return dup_float_ptrs;
6680 }
6681 
6694 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_doubles(const void *a, const void *b)
6695 {
6698 
6699  return (*(double *)a - *(double *)b);
6700 }
6701 
6710 FOUNDATIONAL_LIB_FUNC void sort_doubles(double *doubles, size_t size)
6711 {
6713  qsort(doubles, size, sizeof(double), FOUNDATIONAL_LIB_cmp_doubles);
6714 }
6715 
6729 FOUNDATIONAL_LIB_FUNC double *sorted_doubles(double *doubles, size_t size)
6730 {
6732  double *dup_doubles = (double *)arraydup(doubles, size, sizeof(double));
6733  if (FOUNDATIONAL_LIB_UNLIKELY(dup_doubles == NULL))
6734  {
6735  return NULL;
6736  }
6737  qsort(doubles, size, sizeof(double), FOUNDATIONAL_LIB_cmp_doubles);
6738  return dup_doubles;
6739 }
6753 {
6754 
6757  return (*(double **)a - *(double **)b);
6758 }
6759 
6769 FOUNDATIONAL_LIB_FUNC void sort_double_ptrs(double **double_ptrs, size_t size)
6770 {
6771 
6773  qsort(double_ptrs, size, sizeof(double *), FOUNDATIONAL_LIB_cmp_double_ptrs);
6774 }
6775 
6789 FOUNDATIONAL_LIB_FUNC double **sorted_double_ptrs(double **double_ptrs, size_t size)
6790 {
6791 
6793 
6794  double **dup_double_ptrs = (double **)arraydup(double_ptrs, size, sizeof(double *));
6795  if (FOUNDATIONAL_LIB_UNLIKELY(dup_double_ptrs == NULL))
6796  {
6797  return NULL;
6798  }
6799  qsort(double_ptrs, size, sizeof(double *), FOUNDATIONAL_LIB_cmp_double_ptrs);
6800  return dup_double_ptrs;
6801 }
6802 
6815 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_size_ts(const void *a, const void *b)
6816 {
6817 
6820  return (*(size_t *)a - *(size_t *)b);
6821 }
6822 
6832 FOUNDATIONAL_LIB_FUNC void sort_size_ts(size_t *size_ts, size_t size)
6833 {
6834 
6836  qsort(size_ts, size, sizeof(size_t), FOUNDATIONAL_LIB_cmp_size_ts);
6837 }
6838 
6852 FOUNDATIONAL_LIB_FUNC size_t *sorted_size_ts(size_t *size_ts, size_t size)
6853 {
6855 
6856  size_t *dup_size_ts = (size_t *)arraydup(size_ts, size, sizeof(size_t));
6857  if (FOUNDATIONAL_LIB_UNLIKELY(dup_size_ts == NULL))
6858  {
6859  return NULL;
6860  }
6861  qsort(size_ts, size, sizeof(size_t), FOUNDATIONAL_LIB_cmp_size_ts);
6862  return dup_size_ts;
6863 }
6864 
6878 {
6881  return (*(size_t **)a - *(size_t **)b);
6882 }
6883 
6894 FOUNDATIONAL_LIB_FUNC void sort_size_t_ptrs(size_t **size_t_ptrs, size_t size)
6895 {
6896 
6898  qsort(size_t_ptrs, size, sizeof(size_t *), FOUNDATIONAL_LIB_cmp_size_t_ptrs);
6899 }
6915 FOUNDATIONAL_LIB_FUNC size_t **sorted_size_t_ptrs(size_t **size_t_ptrs, size_t size)
6916 {
6918 
6919  size_t **dup_size_t_ptrs = (size_t **)arraydup(size_t_ptrs, size, sizeof(size_t *));
6920 
6921  if (FOUNDATIONAL_LIB_UNLIKELY(dup_size_t_ptrs == NULL))
6922  {
6923  return NULL;
6924  }
6925 
6926  qsort(size_t_ptrs, size, sizeof(size_t *), FOUNDATIONAL_LIB_cmp_size_t_ptrs);
6927 
6928  return dup_size_t_ptrs;
6929 }
6930 
6942 {
6943 
6945  return FOUNDATIONAL_LIB_ATOI(str);
6946 }
6947 
6964 FOUNDATIONAL_LIB_FUNC char *read_file_into_string(const char *filename, size_t *size)
6965 {
6968 
6969  *size = 0;
6970 
6971  FILE *file = fopen(filename, "rb");
6972  if (FOUNDATIONAL_LIB_UNLIKELY(file == NULL))
6973  {
6975  return NULL; // Indicate error by returning NULL
6976  }
6977 
6978  // Determine the file size by seeking
6979  if (FOUNDATIONAL_LIB_FSEEKO(file, 0, SEEK_END) != 0)
6980  {
6981  FOUNDATIONAL_LIB_FCLOSE(file); // No need to error check here because already going wrong.
6983  return NULL;
6984  }
6985 
6986  // Get file size with tell
6987  const off_t file_size = FOUNDATIONAL_LIB_FTELLO(file); /* signed int type */
6988  if (FOUNDATIONAL_LIB_UNLIKELY(file_size == -1))
6989  {
6990  FOUNDATIONAL_LIB_FCLOSE(file); // No need to error check here because already going wrong.
6992  return NULL;
6993  }
6994 
6995  *size = (size_t)file_size;
6996 
6997  // Since off_t is signed, it should be less than SIZE_MAX, so don't check
6998  // if it equals SIZE_MAX before adding 1 more to it to FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC()
6999 
7000  // Seek to the beginning again
7001  if (FOUNDATIONAL_LIB_FSEEKO(file, 0, SEEK_SET) != 0)
7002  {
7003  FOUNDATIONAL_LIB_FCLOSE(file); // No need to error check here because already going wrong.
7005  return NULL;
7006  }
7007 
7008  // Allocate memory for the file contents
7009  char *content = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(file_size + 1); /* Safe. */
7010  if (FOUNDATIONAL_LIB_UNLIKELY(content == NULL))
7011  {
7012  FOUNDATIONAL_LIB_FCLOSE(file); // No need to error check here because already going wrong.
7014  return NULL;
7015  }
7016 
7017  // Read the file contents into the string
7018  size_t total_read = 0;
7019  const size_t file_size_size_t = (size_t)file_size;
7020 
7021  while (total_read < file_size_size_t)
7022  {
7023  const size_t read_size = FOUNDATIONAL_LIB_FREAD(content + total_read, 1, file_size - total_read, file);
7024 
7025  if (read_size == 0) // Not likely or unlikely.
7026  {
7027  const int error_code = FOUNDATIONAL_LIB_FERROR(file);
7028  if (FOUNDATIONAL_LIB_UNLIKELY(error_code))
7029  {
7031  FOUNDATIONAL_LIB_FCLOSE(file); // Don't need to error check here because things are going
7032  // wrong.
7034  return NULL;
7035  }
7036  else
7037  {
7038  break;
7039  }
7040  }
7041  total_read += read_size;
7042  }
7043 
7044  // Null-terminate the string
7045  content[total_read] = '\0';
7046 
7047  // Close the file
7048  if (FOUNDATIONAL_LIB_UNLIKELY(fclose(file) != 0)) // Check for errors.
7049  {
7052  return NULL;
7053  }
7054 
7055  return content;
7056 }
7057 
7072 FOUNDATIONAL_LIB_FUNC int write_to_file_with_mode(const char *filename, const char *content, size_t content_length, const char *mode)
7073 {
7077  FILE *file = fopen(filename, mode);
7078  if (FOUNDATIONAL_LIB_UNLIKELY(file == NULL))
7079  {
7081  return -1;
7082  }
7083 
7084  /* Write the string to the file */
7085  size_t write_size;
7086  size_t total_written = 0;
7087 
7088  /* No need to check for EINTR. It would just slow things down here. */
7089  while ((write_size = FOUNDATIONAL_LIB_FWRITE(content + total_written, 1, content_length - total_written, file)) > 0)
7090  {
7091  total_written += write_size;
7092  }
7093 
7094  // Close the file
7095  if (FOUNDATIONAL_LIB_UNLIKELY(fclose(file) != 0)) // Check for errors.
7096  {
7098  return -1;
7099  }
7100 
7101  return 0;
7102 }
7103 
7116 FOUNDATIONAL_LIB_FUNC int write_file(const char *filename, const char *content)
7117 {
7120 
7121  /* This function is inlined by default. */
7122  return write_to_file_with_mode(filename, content, FOUNDATIONAL_LIB_STRLEN(content), "w");
7123 }
7124 
7139 FOUNDATIONAL_LIB_FUNC int append_string_to_file(const char *filename, const char *content)
7140 {
7143 
7144  /* This function is inlined by default. */
7145  return write_to_file_with_mode(filename, content, FOUNDATIONAL_LIB_STRLEN(content), "a");
7146 }
7147 
7148 #ifdef _WIN32
7149 #include <io.h>
7150 #else
7151 #include <unistd.h>
7152 #endif
7153 
7154 #include <sys/stat.h>
7155 
7164 FOUNDATIONAL_LIB_FUNC int file_exists(const char *filename)
7165 {
7167 
7168 #ifdef _WIN32
7169  return _access(filename, 0) == 0;
7170 #else
7171  return access(filename, F_OK) == 0;
7172 #endif
7173 }
7174 
7184 FOUNDATIONAL_LIB_FUNC int file_is_regular(const char *filename)
7185 {
7187 
7188  struct stat st;
7189 #ifdef _WIN32
7190  if (stat(filename, &st) == 0)
7191  return (st.st_mode & _S_IFREG) != 0;
7192 #else
7193  if (stat(filename, &st) == 0)
7194  return S_ISREG(st.st_mode);
7195 #endif
7196  return 0;
7197 }
7198 
7207 FOUNDATIONAL_LIB_FUNC int file_is_directory(const char *filename)
7208 {
7210 
7211  struct stat st;
7212 #ifdef _WIN32
7213  if (stat(filename, &st) == 0)
7214  return (st.st_mode & _S_IFDIR) != 0;
7215 #else
7216  if (stat(filename, &st) == 0)
7217  return S_ISDIR(st.st_mode);
7218 #endif
7219  return 0;
7220 }
7221 
7232 FOUNDATIONAL_LIB_FUNC int file_is_readable(const char *filename)
7233 {
7235 
7236 #ifdef _WIN32
7237  return _access(filename, 4) == 0; // 4 is for read permission on Windows
7238 #else
7239  return access(filename, R_OK) == 0; // R_OK is for read permission on POSIX systems
7240 #endif
7241 }
7242 
7253 FOUNDATIONAL_LIB_FUNC int file_is_writable(const char *filename)
7254 {
7256 
7257 #ifdef _WIN32
7258  return _access(filename, 2) == 0; // 2 is for write permission on Windows
7259 #else
7260  return access(filename, W_OK) == 0; // W_OK is for write permission on POSIX systems
7261 #endif
7262 }
7263 
7275 {
7277 
7278 #ifdef _WIN32
7279  return _access(filename, 1) == 0; // 1 is for execute permission on Windows
7280 #else
7281  return access(filename, X_OK) == 0; // X_OK is for execute permission on POSIX systems
7282 #endif
7283 }
7284 
7297 FOUNDATIONAL_LIB_FUNC int get_file_size(const char *filename, size_t *size)
7298 {
7301 
7302  FILE *file = fopen(filename, "r");
7303  if (FOUNDATIONAL_LIB_UNLIKELY(file == NULL))
7304  {
7306  return -1;
7307  }
7308 
7309  // Determine the file size with seek
7310  if (FOUNDATIONAL_LIB_UNLIKELY(FOUNDATIONAL_LIB_FSEEKO(file, 0, SEEK_END) != 0))
7311  {
7312  FOUNDATIONAL_LIB_FCLOSE(file); // No need to error check here because already going wrong.
7314  return -1;
7315  }
7316 
7317  // Get the file size with tell
7318  const off_t file_size = ftello(file);
7319  if (FOUNDATIONAL_LIB_UNLIKELY(file_size == -1))
7320  {
7321  FOUNDATIONAL_LIB_FCLOSE(file); // No need to error check here because already going wrong.
7323  return -1;
7324  }
7325 
7326  // Close the file
7327  if (FOUNDATIONAL_LIB_UNLIKELY(fclose(file) != 0)) // Error check
7328  {
7330  return -1;
7331  }
7332 
7333  *size = file_size;
7334  return 0;
7335 }
7336 
7347 FOUNDATIONAL_LIB_FUNC int remove_file(const char *filename)
7348 {
7350 
7351  /* Standard c function */
7352  if (FOUNDATIONAL_LIB_UNLIKELY(remove(filename) != 0))
7353  {
7355  return -1;
7356  }
7357  return 0;
7358 }
7359 
7372 FOUNDATIONAL_LIB_FUNC int copy_file(const char *source_filename, const char *destination_filename)
7373 {
7375  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(destination_filename);
7376  FILE *source_file = fopen(source_filename, "rb");
7377 
7378  if (FOUNDATIONAL_LIB_UNLIKELY(source_file == NULL))
7379  {
7381  return -1;
7382  }
7383 
7384  FILE *destination_file = fopen(destination_filename, "wb");
7385  if (FOUNDATIONAL_LIB_UNLIKELY(destination_file == NULL))
7386  {
7387  FOUNDATIONAL_LIB_FCLOSE(source_file); // No need to error check here because already going
7388  // wrong.
7389 
7391  return -1;
7392  }
7393 
7394  char buffer[FOUNDATIONAL_LIB_COPY_SIZE_AMOUNT];
7395 
7396  for (;;)
7397  {
7398  // Read from the file.
7399  size_t read_size;
7400  int error_code;
7401 
7402  /* Handle interrupted system calls */
7403 
7404  do
7405  {
7406  read_size = FOUNDATIONAL_LIB_FREAD(buffer, 1, sizeof(buffer), source_file);
7407  } while (FOUNDATIONAL_LIB_UNLIKELY((error_code = FOUNDATIONAL_LIB_FERROR(source_file)) && errno == EINTR)); /* Check for EINTR */
7408 
7409  // If it has finished reading or if an error has occured.
7410  if (read_size == 0) // Not likely or unlikely.
7411  {
7412  if (FOUNDATIONAL_LIB_UNLIKELY(error_code))
7413  {
7414  /*
7415  * Here, we can distinuish between errors to ignore, and errors to to
7416  * about. Adjust this based on your environment or preferences.
7417  */
7418 
7419  FOUNDATIONAL_LIB_FCLOSE(destination_file); // Don't need to error check here because
7420  // things are going wrong.
7421  FOUNDATIONAL_LIB_FCLOSE(source_file); // Don't need to error check here because things
7422  // are going wrong.
7423 
7425  return -1;
7426  }
7427  else
7428  {
7429  break;
7430  }
7431  }
7432 
7433  /* Handle interrupted system calls */
7434 
7435  size_t write_size = 0;
7436  size_t new_write_size;
7437  do
7438  {
7439  new_write_size = FOUNDATIONAL_LIB_FWRITE(buffer + write_size, 1, read_size - write_size, destination_file);
7440  write_size += new_write_size;
7441  } while (write_size != read_size || FOUNDATIONAL_LIB_UNLIKELY(errno == EINTR)); /* Check for EINTR */
7442  }
7443 
7444  if (FOUNDATIONAL_LIB_UNLIKELY(ferror(source_file) != 0 || FOUNDATIONAL_LIB_FERROR(destination_file) != 0))
7445  {
7446  FOUNDATIONAL_LIB_FCLOSE(source_file); // No need to error check here because already going
7447  // wrong.
7448  FOUNDATIONAL_LIB_FCLOSE(destination_file); // No need to error check here because already
7449  // going wrong.
7450 
7452  return -1;
7453  }
7454 
7455  if (FOUNDATIONAL_LIB_UNLIKELY(fclose(source_file) != 0 || FOUNDATIONAL_LIB_FCLOSE(destination_file) != 0)) // Error check
7456  {
7458  return -1;
7459  }
7460 
7461  return 0;
7462 }
7463 
7464 #ifdef _WIN32
7465 #include <windows.h>
7466 
7486 FOUNDATIONAL_LIB_FUNC char **list_files_with_pattern(const char *directory, const char *pattern, size_t *len)
7487 {
7491 
7492  *len = 0;
7493  char search_path[MAX_PATH];
7494  FOUNDATIONAL_LIB_SNPRINTF(search_path, MAX_PATH, "%s\\%s", directory, pattern);
7495 
7496  WIN32_FIND_DATA find_file_data;
7497  HANDLE find_handle = FindFirstFile(search_path, &find_file_data);
7498 
7499  if (FOUNDATIONAL_LIB_UNLIKELY(find_handle == INVALID_HANDLE_VALUE))
7500  {
7501 
7502  /* One element of size zero. */
7503  char **new_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(sizeof(char *));
7504  *new_array = NULL;
7505  return new_array;
7506  }
7507 
7508  /* Count the number of files matching the pattern */
7509  int file_count = 0;
7510  do
7511  {
7512  if (!(find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
7513  {
7514  ++file_count;
7515  }
7516  } while (FindNextFile(find_handle, &find_file_data) != 0);
7517 
7518  size_t mul;
7519 
7520  if (FOUNDATIONAL_LIB_UNLIKELY(file_count == 0))
7521  {
7523  }
7524  else if (FOUNDATIONAL_LIB_UNLIKELY(FOUNDATIONAL_LIB_safe_mul_ptr(file_count, sizeof(char *), &mul) == 0))
7525  {
7527  return NULL;
7528  }
7529 
7530  /* Allocate memory for the array of strings */
7531  char **files_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(mul);
7532  if (FOUNDATIONAL_LIB_UNLIKELY(files_array == NULL))
7533  {
7535  return NULL;
7536  }
7537 
7538  /* Populate the array with file names matching the pattern */
7539  int index = 0;
7540  if (FOUNDATIONAL_LIB_UNLIKELY(FindClose(find_handle) == 0))
7541  {
7543  return NULL;
7544  }
7545  find_handle = FindFirstFile(search_path, &find_file_data);
7546  do
7547  {
7548  if (!(find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
7549  {
7550  files_array[index] = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(find_file_data.cFileName);
7551  if (FOUNDATIONAL_LIB_UNLIKELY(files_array[index] == NULL))
7552  {
7553  return NULL;
7554  }
7555  ++index;
7556  }
7557  } while (FindNextFile(find_handle, &find_file_data) != 0);
7558 
7559  /* Close the find handle */
7560  if (FOUNDATIONAL_LIB_UNLIKELY(FindClose(find_handle) == 0))
7561  {
7563  return NULL;
7564  }
7565 
7566  *len = index;
7567 
7568  return files_array;
7569 }
7570 
7571 #else
7572 
7573 #include <dirent.h>
7574 #include <fnmatch.h>
7575 
7595 FOUNDATIONAL_LIB_FUNC char **list_files_with_pattern(const char *directory, const char *pattern, size_t *len)
7596 {
7600 
7601  *len = 0;
7602  DIR *dir = opendir(directory);
7603  if (FOUNDATIONAL_LIB_UNLIKELY(dir == NULL))
7604  {
7606  return NULL;
7607  }
7608 
7609  /* Count the number of files matching the pattern */
7610  int file_count = 0;
7611  struct dirent *entry;
7612  while ((entry = readdir(dir)) != NULL)
7613  {
7614  if (fnmatch(pattern, entry->d_name, FNM_PERIOD) == 0)
7615  {
7616  ++file_count;
7617  }
7618  }
7619 
7620  rewinddir(dir); // No errors with this function
7621 
7622  size_t mul;
7623 
7624  if (FOUNDATIONAL_LIB_UNLIKELY(file_count == 0))
7625  {
7627  }
7628  else if (FOUNDATIONAL_LIB_UNLIKELY(FOUNDATIONAL_LIB_safe_mul_ptr(file_count, sizeof(char *), &mul) == 0))
7629  {
7631  return NULL;
7632  }
7633 
7634  /* Allocate memory for the array of strings */
7635  char **files_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(mul);
7636 
7637  /* Populate the array with file names matching the pattern */
7638  size_t index = 0;
7639  while ((entry = readdir(dir)) != NULL)
7640  {
7641  if (fnmatch(pattern, entry->d_name, FNM_PERIOD) == 0)
7642  {
7643  files_array[index] = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(entry->d_name);
7644  if (FOUNDATIONAL_LIB_UNLIKELY(files_array[index] == NULL))
7645  {
7647  return NULL;
7648  }
7649  ++index;
7650  }
7651  }
7652  if (FOUNDATIONAL_LIB_UNLIKELY(closedir(dir) == -1))
7653  {
7655  return NULL;
7656  }
7657 
7658  *len = index;
7659 
7660  return files_array;
7661 }
7662 
7663 #endif
7664 
7681 FOUNDATIONAL_LIB_FUNC char *concatenate_string_array(const char **strings, size_t num_strings)
7682 {
7684 
7685  /* Initialize total length and allocate initial memory for result */
7687  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size);
7688 
7689  // Check for initial memory allocation failure
7690  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
7691  goto memory_error;
7692 
7693  size_t new_len;
7694 
7695  // If no strings, new_len will still be 0, and then a null terminator will be put at byte 0.
7696  new_len = 0;
7697 
7698  // Concatenate the strings char by char using FOUNDATIONAL_LIB_MEMCPY and FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC
7699  for (size_t i = 0; i < num_strings; ++i)
7700  {
7701  const char *current_string = strings[i];
7702 
7703  // Iterate through each character and append to the result
7704  size_t current_length_of_current_string = 0;
7705  while (current_string[current_length_of_current_string] != '\0')
7706  {
7707  if (FOUNDATIONAL_LIB_UNLIKELY(new_len == SIZE_MAX))
7708  goto overflow;
7709  /* FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM returns always at least one more */
7710  const size_t new_size = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(new_len + sizeof("")); /* Safe. */
7711 
7712  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
7713  {
7715  goto memory_error;
7716  }
7717  // Resize the result string if necessary
7718  if (FOUNDATIONAL_LIB_UNLIKELY(new_size > alloc_size))
7719  {
7720  char *new_result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(result, new_size);
7721 
7722  // Check for realloc failure
7723  if (FOUNDATIONAL_LIB_UNLIKELY(new_result == NULL))
7724  {
7726  goto memory_error;
7727  }
7728 
7729  result = new_result;
7730  }
7731 
7732  // Append the current character to the result
7733  result[new_len++] = current_string[current_length_of_current_string++];
7734  }
7735  }
7736 
7737  // Add the null terminator
7738  result[new_len] = '\0';
7739 
7740  return result;
7741 
7742 overflow:
7743 memory_error:
7745  return NULL;
7746 }
7747 
7762 FOUNDATIONAL_LIB_FUNC char *concatenate_strings(const char *str1, const char *str2)
7763 {
7766 
7767  const char *strs[2] = {str1, str2};
7768 
7769  return concatenate_string_array(strs, 2);
7770 }
7771 
7812 FOUNDATIONAL_LIB_FUNC int replace_memory(void *source, size_t source_len, void *find, size_t find_len, void *replace, size_t replace_len, void **output, size_t *output_length_without_nullt, int *should_free_after_use, size_t matches_max /* 0 for unlimited replacement */, size_t *num_matches_found, int should_nullt)
7813 {
7818  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(output_length_without_nullt);
7819  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(should_free_after_use);
7821 
7822  if (FOUNDATIONAL_LIB_UNLIKELY(find_len == 0))
7823  goto no_matches;
7824 
7825  size_t matches;
7826 
7827  matches = 0;
7828 
7829  // Count the occurrences of 'find' in 'source'
7830  const char *p;
7831 
7832  p = (const char *)source;
7833 
7834  const char *end_of_memory;
7835  end_of_memory = (const char *)source + source_len;
7836 
7837  for (;;)
7838  {
7839  if ((p = (const char *)memory_locate((const void *)p, (end_of_memory - p), find, find_len)) == NULL)
7840  break;
7841  if (matches_max && matches == matches_max)
7842  break;
7843 
7844  ++matches;
7845  p += find_len;
7846  puts("FOR");
7847  }
7848 
7849  // Let's assume that it's 'likely' to find a match.
7850  if (FOUNDATIONAL_LIB_UNLIKELY(matches == 0))
7851  {
7852  no_matches:
7853  *should_free_after_use = 0;
7854  *output_length_without_nullt = source_len;
7855  *output = source;
7856  return 0;
7857  }
7858 
7859  *should_free_after_use = 1;
7860  *num_matches_found = matches;
7861 
7862  size_t final_len = source_len - matches * find_len + matches * replace_len; // Overflow should not be an issue here.
7863 
7864  if (should_nullt)
7865  {
7866  ++final_len;
7867  }
7868 
7869  // Allocate memory for the replaced string
7870  char *result;
7871 
7872  result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(final_len);
7873  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
7874  {
7875  goto memory_error;
7876  }
7877  *output_length_without_nullt = final_len;
7878 
7879  *output = result;
7880 
7881  // Perform the replacement
7882  char *rp;
7883 
7884  rp = result;
7885 
7886  p = (const char *)source;
7887 
7888  matches = 0;
7889 
7890  // If matches is 0, this is not run.
7891  for (matches = 0; !matches_max || (matches < matches_max); ++matches)
7892  {
7893  if ((p = (const char *)memory_locate((const void *)p, end_of_memory - p, find, find_len)) == NULL)
7894  break;
7895 
7896  if (matches_max && matches == matches_max)
7897  break;
7898 
7899  size_t prefix_len = p - (const char *)source;
7900  FOUNDATIONAL_LIB_MEMCPY(rp, source, prefix_len);
7901  rp += prefix_len;
7902  FOUNDATIONAL_LIB_MEMCPY(rp, replace, replace_len);
7903  rp += replace_len;
7904  p += find_len;
7905  source = (void *)p;
7906  }
7907 
7908  // Copy the remaining part of the source string
7909  size_t remaining_len;
7910 
7911  remaining_len = end_of_memory - (const char *)source;
7912  FOUNDATIONAL_LIB_MEMCPY(rp, source, remaining_len);
7913 
7914  if (should_nullt)
7915  {
7916  rp[remaining_len] = '\0';
7917  }
7918 
7919  return 0;
7920 
7921 memory_error:
7922  *output = NULL;
7923  *output_length_without_nullt = 0;
7925  return -1;
7926 }
7927 
7969 FOUNDATIONAL_LIB_FUNC int replace_all_with_lens(const char *source, size_t source_len, const char *find, size_t find_len, const char *replace, size_t replace_len, char **output, size_t *new_len, int *should_free_after_use, size_t matches_max, size_t *num_matches)
7970 {
7971  /* replace_memory checks args if enabled. */
7972  return replace_memory((void *)source, source_len, (void *)find, find_len, (void *)replace, replace_len, (void **)output, new_len, should_free_after_use, matches_max, num_matches, 1);
7973 }
7974 
7989 FOUNDATIONAL_LIB_FUNC char *replace_all(const char *source, const char *find, const char *replace)
7990 {
7991  /* replace_memory checks args if enabled. */
7992 
7993  size_t new_len;
7994  char *output;
7995  int should_free_after_use;
7996  size_t num_matches;
7997  const size_t matches_max = 0;
7998 
7999  if (replace_memory((void *)source, strlen(source), (void *)find, strlen(find), (void *)replace, strlen(replace), (void **)&output, &new_len, &should_free_after_use, matches_max, &num_matches, 1) == -1)
8000  {
8002  return NULL;
8003  }
8004 
8005  if (!should_free_after_use)
8006  {
8007  if (FOUNDATIONAL_LIB_UNLIKELY(new_len == SIZE_MAX))
8008  {
8010  return NULL;
8011  }
8012 
8013  char *new_output = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(new_len + 1); /* Safe. */
8014  memcpy(new_output, output, new_len + 1); /* It was already null terminated */
8015  return new_output;
8016  }
8017 
8018  return output;
8019 }
8020 
8035 FOUNDATIONAL_LIB_FUNC char *replace_first(const char *source, const char *find, const char *replace)
8036 {
8037  /* replace_memory checks args if enabled. */
8038 
8039  size_t new_len;
8040  char *output;
8041  int should_free_after_use;
8042  size_t num_matches;
8043  const size_t matches_max = 1;
8044 
8045  if (replace_memory((void *)source, strlen(source), (void *)find, strlen(find), (void *)replace, strlen(replace), (void **)&output, &new_len, &should_free_after_use, matches_max, &num_matches, 1) == -1)
8046  {
8048  return NULL;
8049  }
8050 
8051  if (!should_free_after_use)
8052  {
8053  if (FOUNDATIONAL_LIB_UNLIKELY(new_len == SIZE_MAX))
8054  {
8056  return NULL;
8057  }
8058 
8059  char *new_output = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(new_len + 1); /* Safe. */
8060  memcpy(new_output, output, new_len + 1); /* It was already null terminated */
8061  return new_output;
8062  }
8063 
8064  return output;
8065 }
8066 
8081 FOUNDATIONAL_LIB_FUNC char *replace_count(const char *source, const char *find, const char *replace, const size_t matches_max)
8082 {
8083  /* replace_memory checks args if enabled. */
8084 
8085  size_t new_len;
8086  char *output;
8087  int should_free_after_use;
8088  size_t num_matches;
8089  if (replace_memory((void *)source, strlen(source), (void *)find, strlen(find), (void *)replace, strlen(replace), (void **)&output, &new_len, &should_free_after_use, matches_max, &num_matches, 1) == -1)
8090  {
8092  return NULL;
8093  }
8094 
8095  if (!should_free_after_use)
8096  {
8097  if (FOUNDATIONAL_LIB_UNLIKELY(new_len == SIZE_MAX))
8098  {
8100  return NULL;
8101  }
8102 
8103  char *new_output = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(new_len + 1); /* Safe. */
8104  memcpy(new_output, output, new_len + 1); /* It was already null terminated */
8105  return new_output;
8106  }
8107 
8108  return output;
8109 }
8110 
8129 FOUNDATIONAL_LIB_FUNC char *replace_all_with_callback(const char *str, const char *old_substring, char *(*callback)(const char *, void *), void *data_for_callback)
8130 {
8134 
8135  const size_t str_len = strlen(str);
8136  const size_t old_substring_len = strlen(old_substring);
8137  size_t alloc_size = str_len + 1; // Start with the original string length + 1 for the null terminator
8138 
8139  // Allocate memory for the result string
8140  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(str_len);
8141  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
8142  {
8144  return NULL;
8145  }
8146 
8147  // Copy and replace substrings
8148  const char *pos = str;
8149 
8150  size_t new_len = 0;
8151 
8152  for (;;)
8153  {
8154  const char *found_pos = (const char *)memory_locate(pos, str_len - (pos - str), old_substring, old_substring_len);
8155  if (FOUNDATIONAL_LIB_UNLIKELY(found_pos == NULL))
8156  {
8157  size_t remaining_len = str_len - (pos - str);
8158  memcpy(result + new_len, pos, remaining_len);
8159  new_len += remaining_len;
8160 
8161  result[new_len] = '\0';
8162 
8163  new_len += remaining_len;
8164  break;
8165  }
8166 
8167  // Copy the segment
8168 
8169  char *replacement = callback(old_substring, data_for_callback);
8170 
8171  // Resize the result buffer if needed
8172  size_t replacement_len = strlen(replacement);
8173 
8174  size_t nlen;
8175 
8176  const size_t diff = found_pos - pos;
8177 
8178  if (FOUNDATIONAL_LIB_UNLIKELY(FOUNDATIONAL_LIB_safe_add_3_ptr(new_len, diff, replacement_len, &nlen) == 0))
8179  {
8180  goto overflow;
8181  }
8182 
8183  if (FOUNDATIONAL_LIB_UNLIKELY(nlen == SIZE_MAX))
8184  goto overflow;
8185 
8186  ++nlen;
8187 
8188  if (nlen >= alloc_size)
8189  {
8190  /* Makes it at least 1 bigger. */
8192  char *new_result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(result, alloc_size);
8193  if (FOUNDATIONAL_LIB_UNLIKELY(new_result == NULL))
8194  {
8196  goto error;
8197  }
8198  result = new_result;
8199  }
8200 
8201  memcpy(result + new_len, pos, found_pos - pos); /* Safe. */
8202  new_len += found_pos - pos;
8203  memcpy(result + new_len, replacement, replacement_len);
8205  new_len += replacement_len;
8206  pos = found_pos + old_substring_len;
8207  }
8208 
8209  return result;
8210 overflow:
8211 
8212 error:
8215  return NULL;
8216 }
8217 
8232 FOUNDATIONAL_LIB_FUNC char *dup_format(const char *format, ...)
8233 {
8235 
8237  FOUNDATIONAL_LIB_VA_START(args, format);
8238 
8239  /* Determine the length of the formatted string */
8240  const int len = FOUNDATIONAL_LIB_VSNPRINTF(NULL, 0, format, args);
8241 
8243 
8244  if (len == -1)
8245  goto memory_error;
8246 
8247  /* Would-be Overflow */
8248  if (FOUNDATIONAL_LIB_UNLIKELY(sizeof(int) >= sizeof(size_t) && (size_t)len == SIZE_MAX))
8249  goto memory_error;
8250 
8251  /* Allocate memory for the formatted string */
8252  char *result;
8253 
8254  result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(len + sizeof("")); /* Safe */
8255  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
8256  goto memory_error;
8257 
8258  FOUNDATIONAL_LIB_VA_START(args, format);
8259  if (FOUNDATIONAL_LIB_VSNPRINTF(result, len + 1, format, args) == -1)
8260  {
8263  goto memory_error;
8264  }
8265 
8267 
8268  return result;
8269 
8270 memory_error:
8272  return NULL;
8273 }
8302 FOUNDATIONAL_LIB_FUNC void map_ints(int *array, size_t size, int (*transform)(int))
8303 {
8306 
8307  for (size_t i = 0; i < size; ++i)
8308  {
8309  array[i] = transform(array[i]);
8310  }
8311 }
8312 
8344 FOUNDATIONAL_LIB_FUNC int reduce_ints(int *array, size_t size, int (*operation)(int, int))
8345 {
8348 
8349  int result = array[0];
8350  for (size_t i = 1; i < size; ++i)
8351  {
8352  result = operation(result, array[i]);
8353  }
8354  return result;
8355 }
8356 
8395 FOUNDATIONAL_LIB_FUNC int filter_ints(int *source, size_t source_size, int *destination, int (*condition)(int))
8396 {
8397 
8401 
8402  size_t count = 0;
8403  for (size_t i = 0; i < source_size; ++i)
8404  {
8405  if (condition(source[i]))
8406  {
8407  destination[count++] = source[i];
8408  }
8409  }
8410  return count;
8411 }
8412 
8442 FOUNDATIONAL_LIB_FUNC void map(void *array, size_t size, size_t elem_size, void (*transform)(void *))
8443 {
8444 
8447 
8448  for (size_t i = 0; i < size; ++i)
8449  {
8450  transform(((char *)array) + i * elem_size);
8451  }
8452 }
8453 
8488 FOUNDATIONAL_LIB_FUNC void reduce(void *array, size_t size, size_t elem_size, void *result, void (*operation)(void *, void *))
8489 {
8493 
8494  char *char_array = (char *)array;
8495  char *char_result = (char *)result;
8496 
8497  /* Initialize the result with the first element */
8498  for (size_t i = 0; i < elem_size; ++i)
8499  {
8500  char_result[i] = char_array[i];
8501  }
8502 
8503  for (size_t i = 1; i < size; ++i)
8504  {
8505  operation(char_result, char_array + i * elem_size);
8506  }
8507 }
8508 
8550 FOUNDATIONAL_LIB_FUNC size_t filter(void *source, size_t source_size, size_t elem_size, void *destination, size_t dest_size, int (*condition)(void *))
8551 {
8552 
8556 
8557  char *char_source = (char *)source;
8558  char *char_destination = (char *)destination;
8559 
8560  size_t count = 0;
8561  for (size_t i = 0; i < source_size; ++i)
8562  {
8563  if (condition(char_source + i * elem_size))
8564  {
8565  if (count < dest_size)
8566  {
8567  for (size_t j = 0; j < elem_size; ++j)
8568  {
8569  char_destination[count * elem_size + j] = char_source[i * elem_size + j];
8570  }
8571  }
8572 
8573  ++count;
8574  }
8575  }
8576  return count;
8577 }
8578 
8667 FOUNDATIONAL_LIB_FUNC void *list_comprehension(const void *input_array, size_t array_size, size_t elem_size, void (*transform_func)(void *value), int (*filter_func)(void *value), size_t *result_size)
8668 {
8672 
8674 
8675  // Set result size to 0 first thing.
8676  *result_size = 0;
8677 
8678  const size_t alloc_size = FOUNDATIONAL_LIB_safe_mul(array_size, elem_size);
8679 
8680  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size == 0))
8681  {
8682  /* Handle overflow error. */
8684  return NULL;
8685  }
8686 
8687  /* Allocate memory for the result array */
8688  void *result = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size);
8689 
8690  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
8691  {
8692  /* Handle memory allocation error */
8694  return NULL;
8695  }
8696 
8697  /* Iterate through the input array */
8698  for (size_t i = 0; i < array_size; ++i)
8699  {
8700  /* Apply the filter function */
8701 
8702  // Assume that there cannot be an overflow error
8703  // because iterating through a size_t array from 0.
8704  if (filter_func((void *)((char *)input_array + i * elem_size)))
8705  {
8706  /* Apply the transformation function */
8707 
8708  void *addr = (char *)result + (*result_size) * elem_size;
8709  FOUNDATIONAL_LIB_MEMCPY(addr, (char *)input_array + (i * elem_size), elem_size); /* Safe. */
8710  transform_func(addr);
8711  ++(*result_size);
8712  }
8713  }
8714 
8715  // We need this so that gcc with -std=c11 under mingw32 doesn't give a
8716  // warning about memory possibly being accessed after freeing()
8717  // This only seems to happen with mingw32, and is a bug in it.
8718  // I included a relevant ISO/IEC statement about realloc in this file.
8719  //
8720  // This code has no bug.
8721 
8722 #pragma GCC diagnostic push
8723 #pragma GCC diagnostic ignored "-Wpragmas"
8724 #pragma GCC diagnostic ignored "-Wuse-after-free"
8725 
8726  /*
8727  * Make the result smaller to free a bit of memory. Not necessary, but it saves memory.
8728  * array_size * (*result_size) will not be larger than the current size.
8729  *
8730  * Dont do safe mul here because this should be smaller than current amounts.
8731  */
8732  char *new_result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(result, array_size * (*result_size)); /* Safe. */
8733 
8734  if (FOUNDATIONAL_LIB_UNLIKELY(new_result == NULL))
8735  {
8737  return result;
8738  }
8739 
8740 #pragma GCC diagnostic pop
8741 
8742  /*
8743  ISO/IEC 9899:2011:
8744 
8745  "If memory for the new object cannot be allocated,
8746  the old object is not deallocated and its value is unchanged."
8747  */
8748 
8749  return new_result;
8750 }
8751 
8752 /* For Set */
8753 struct SetKey
8754 {
8755  char *key;
8756  struct SetKey *next;
8757 };
8758 
8759 struct Dict
8760 {
8762  size_t capacity;
8763  size_t size;
8764 };
8765 
8766 struct Set
8767 {
8768  struct SetKey **table;
8769  size_t capacity;
8770  size_t size;
8771 };
8772 
8775 {
8776  char *key;
8777  void *value;
8779 };
8780 /* FrozenDict struct */
8782 {
8784  size_t capacity;
8785  size_t size;
8786 };
8787 
8788 /* FrozenSet struct. */
8790 {
8791  struct SetKey **table;
8792  size_t capacity;
8793  size_t size;
8794 };
8795 
8796 /* Sets */
8797 typedef struct FrozenSet FrozenSet;
8798 typedef struct Set Set;
8799 
8800 /* Dicts */
8801 typedef struct Dict Dict;
8802 typedef struct FrozenDict FrozenDict;
8803 
8804 #if FOUNDATIONAL_LIB_THREAD_FUNCTIONS_ENABLED
8805 #include <threads.h>
8806 
8807 // Define a structure to hold thread-specific data
8809 {
8810  const void *input_array;
8811  size_t array_size;
8812  size_t elem_size;
8813  void (*transform_func)(void *value);
8814  int (*filter_func)(void *value);
8815  size_t *result_size;
8816  void *result;
8817  size_t start_index;
8818  size_t end_index;
8819 };
8820 
8821 /*
8822  * Define the worker function for each thread, as used by
8823  * list_comprehension_multithreaded()
8824  */
8826 {
8828  struct ThreadData *thread_data = (struct ThreadData *)data;
8829  *thread_data->result_size = 0;
8830 
8831  const size_t subtraction = (thread_data->end_index - thread_data->start_index);
8832 
8833  const size_t mul = FOUNDATIONAL_LIB_safe_mul(thread_data->elem_size, subtraction);
8834 
8835  if (FOUNDATIONAL_LIB_UNLIKELY(mul == 0)) // Overflow
8836  {
8838  return -1;
8839  }
8840 
8841  void *buffer = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(mul);
8842 
8843  if (FOUNDATIONAL_LIB_UNLIKELY(buffer == NULL))
8844  {
8846  return -1;
8847  }
8848 
8849  // Iterate through the assigned chunk of the input array
8850 
8851  // Start index and end index should be valid indices and no possiblity
8852  // for overflow error.
8853  for (size_t i = thread_data->start_index; i < thread_data->end_index; ++i)
8854  {
8855  // Apply the filter function
8856  if (thread_data->filter_func((void *)((char *)thread_data->input_array + i * thread_data->elem_size)))
8857  {
8858  // Copy the value to the result array
8859  FOUNDATIONAL_LIB_MEMCPY((char *)buffer + (*thread_data->result_size) * thread_data->elem_size, (char *)thread_data->input_array + i * thread_data->elem_size, thread_data->elem_size); /* Safe. */
8860 
8861  ++(*thread_data->result_size);
8862  }
8863  }
8864 
8865  // Apply the transformation function to the entire result chunk
8866  for (size_t i = 0; i < (*thread_data->result_size); ++i)
8867  {
8868  thread_data->transform_func((void *)((char *)buffer + i * thread_data->elem_size));
8869  }
8870 
8871  thread_data->result = buffer;
8872  return 0;
8873 }
8874 
8893 FOUNDATIONAL_LIB_FUNC void *list_comprehension_multithreaded(const void *input_array, size_t array_size, size_t elem_size, void (*transform_func)(void *value), int (*filter_func)(void *value), size_t *result_size, size_t thread_count)
8894 {
8899 
8900  if (FOUNDATIONAL_LIB_UNLIKELY(thread_count == 0))
8901  {
8902  // This doesn't make sense, so assume they mean 1.
8903  thread_count = 1;
8904  }
8905 
8906  // Set result size to 0 first thing.
8907  *result_size = 0;
8908 
8909  const size_t alloc_size_for_result = FOUNDATIONAL_LIB_safe_mul(array_size, elem_size);
8910 
8911  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size_for_result == 0))
8912  {
8913  /* Handle overflow error. */
8915  return NULL;
8916  }
8917 
8918  /* Allocate memory for the result array */
8919  void *result = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size_for_result);
8920 
8921  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
8922  {
8923  /* Handle memory allocation error */
8925  return NULL;
8926  }
8927 
8928  /* Allocate memory for result sizes */
8929 
8930  const size_t alloc_size_for_thread_result_sizes = FOUNDATIONAL_LIB_safe_mul(thread_count, sizeof(size_t));
8931  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size_for_thread_result_sizes == 0))
8932  {
8933  /* Handle overflow error. */
8936  return NULL;
8937  }
8938 
8939  size_t *thread_result_sizes = (size_t *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size_for_thread_result_sizes);
8940  if (FOUNDATIONAL_LIB_UNLIKELY(thread_result_sizes == NULL))
8941  {
8942  // Handle memory allocation error
8945  return NULL;
8946  }
8947 
8948  const size_t alloc_size_for_threads = FOUNDATIONAL_LIB_safe_mul(thread_count, sizeof(thrd_t));
8949  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size_for_threads == 0))
8950  {
8951  /* Handle overflow error. */
8953  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE(thread_result_sizes);
8955  return NULL;
8956  }
8957 
8958  // Initialize thread data
8959  thrd_t *threads = (thrd_t *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size_for_threads);
8960  if (FOUNDATIONAL_LIB_UNLIKELY(threads == NULL))
8961  {
8962  // Handle memory allocation error
8964  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE(thread_result_sizes);
8966  return NULL;
8967  }
8968  const size_t alloc_size_for_thread_data = FOUNDATIONAL_LIB_safe_mul(thread_count, sizeof(struct ThreadData));
8969  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size_for_thread_data == 0))
8970  {
8971  /* Handle overflow error. */
8973  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE(thread_result_sizes);
8975  return NULL;
8976  }
8977  struct ThreadData *thread_data = (struct ThreadData *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size_for_thread_data);
8978  if (FOUNDATIONAL_LIB_UNLIKELY(thread_data == NULL))
8979  {
8980  cannot_allocate_or_create:
8982  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE(thread_result_sizes);
8983 
8985 
8987  return NULL;
8988  }
8989 
8990  // Divide the input array into chunks for each thread
8991  size_t chunk_size = array_size / thread_count;
8992  size_t remaining = array_size % thread_count;
8993  size_t current_index = 0;
8994 
8995  for (size_t i = 0; i < thread_count; ++i)
8996  {
8997  size_t e_index;
8998  const size_t ret = FOUNDATIONAL_LIB_safe_add_3_ptr(current_index, chunk_size, (remaining > 0 ? 1 : 0), &e_index);
8999 
9000  if (FOUNDATIONAL_LIB_UNLIKELY(ret == 0))
9001  goto cannot_allocate_or_create; // Overflow
9002 
9003  thread_data[i].input_array = input_array;
9004  thread_data[i].array_size = array_size;
9005  thread_data[i].elem_size = elem_size;
9006  thread_data[i].transform_func = transform_func;
9007  thread_data[i].filter_func = filter_func;
9008  thread_data[i].result_size = &thread_result_sizes[i];
9009  thread_data[i].result = result;
9010  thread_data[i].start_index = current_index;
9011  thread_data[i].end_index = e_index;
9012 
9013  if (remaining > 0)
9014  {
9015  --remaining;
9016  }
9017 
9018  current_index = thread_data[i].end_index;
9019 
9020  // Create a thread for each chunk
9021  if (FOUNDATIONAL_LIB_UNLIKELY(thrd_create(&threads[i], FOUNDATIONAL_LIB_list_comprehension_worker, (void *)&thread_data[i]) != thrd_success))
9022  goto cannot_allocate_or_create;
9023  }
9024 
9025  // Wait for all threads to finish
9026  for (size_t i = 0; i < thread_count; ++i)
9027  {
9028  int return_value_of_thread;
9029  thrd_join(threads[i], &return_value_of_thread);
9030 
9031  // The thread failed.
9032  if (FOUNDATIONAL_LIB_UNLIKELY(return_value_of_thread == -1))
9033  goto cannot_allocate_or_create;
9034  }
9035  // Calculate the total result size
9036  size_t total_result_size = 0;
9037  for (size_t i = 0; i < thread_count; ++i)
9038  {
9039  FOUNDATIONAL_LIB_MEMCPY((char *)result + total_result_size * elem_size, thread_data[i].result, thread_result_sizes[i] * elem_size); /* Safe. */
9041 
9042  // Should always be <= SIZE_MAX
9043  total_result_size += thread_result_sizes[i];
9044  }
9045 
9046  // Update the final result size
9047  *result_size = total_result_size;
9048 
9049  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE(thread_result_sizes);
9052 
9053  return result;
9054 }
9055 
9056 #endif
9057 
9076 FOUNDATIONAL_LIB_FUNC void *reject_array(const void *source, size_t source_size, size_t elem_size, int (*condition)(const void *), size_t *result_size)
9077 {
9078 
9081 
9083  *result_size = 0;
9084  /* Allocate memory for the result array */
9085 
9086  const size_t mul = FOUNDATIONAL_LIB_safe_mul(source_size, elem_size);
9087  if (FOUNDATIONAL_LIB_UNLIKELY(mul == 0))
9088  {
9090  return NULL;
9091  }
9092 
9094  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
9095  {
9097  return NULL;
9098  }
9099 
9100  size_t result_index = 0;
9101 
9102  /* Apply the rejection condition to each element */
9103  for (size_t i = 0; i < source_size; ++i)
9104  {
9105  // Should be a valid index if passed a valid argument.
9106  const void *current_source = (char *)source + i * elem_size;
9107 
9108  /* Check condition */
9109  if (!condition(current_source))
9110  {
9111  void *current_result = (char *)result + result_index * elem_size;
9112  FOUNDATIONAL_LIB_MEMCPY(current_result, current_source, elem_size);
9113  result_index++;
9114  }
9115  }
9116 
9117  /* Set the result size */
9118  *result_size = result_index;
9119 
9120  return result;
9121 }
9122 
9141 FOUNDATIONAL_LIB_FUNC void *select_array(const void *source, size_t source_size, size_t elem_size, int (*condition)(const void *), size_t *result_size)
9142 {
9143 
9145 
9148 
9149  *result_size = 0;
9150  /* Allocate memory for the result array */
9151 
9152  const size_t mul = FOUNDATIONAL_LIB_safe_mul(source_size, elem_size);
9153  if (FOUNDATIONAL_LIB_UNLIKELY(mul == 0))
9154  {
9156  return NULL;
9157  }
9158 
9160  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
9161  {
9163  return NULL;
9164  }
9165 
9166  size_t result_index = 0;
9167 
9168  /* Apply the selection condition to each element */
9169  for (size_t i = 0; i < source_size; ++i)
9170  {
9171  const void *current_source = (char *)source + i * elem_size;
9172 
9173  /* Check condition */
9174  if (condition(current_source))
9175  {
9176  void *current_result = (char *)result + result_index * elem_size;
9177  FOUNDATIONAL_LIB_MEMCPY(current_result, current_source, elem_size);
9178  ++result_index;
9179  }
9180  }
9181 
9182  /* Set the result size */
9183  *result_size = result_index;
9184 
9185  return result;
9186 }
9187 
9203 FOUNDATIONAL_LIB_FUNC void *replicate(const void *source, size_t source_size, size_t elem_size, size_t repetitions)
9204 {
9205 
9207 
9208  /* elem_size * source_size * repetitions */
9209 
9210  const size_t elem_times_source = FOUNDATIONAL_LIB_safe_mul(elem_size, source_size);
9211  if (FOUNDATIONAL_LIB_UNLIKELY(elem_times_source == 0))
9212  {
9214  return NULL;
9215  }
9216 
9217  const size_t result_total_size = FOUNDATIONAL_LIB_safe_mul(elem_times_source, repetitions);
9218  if (FOUNDATIONAL_LIB_UNLIKELY(result_total_size == 0))
9219  {
9221  return NULL;
9222  }
9223 
9224  /* Allocate memory for the result array */
9225  void *result = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(result_total_size);
9226  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
9227  {
9229  return NULL;
9230  }
9231 
9232  /* Copy the source array to the result array multiple times */
9233  for (size_t i = 0; i < repetitions; ++i)
9234  {
9235  // Counting from zero so it should not be an overflow.
9236  FOUNDATIONAL_LIB_MEMCPY((char *)result + (i * elem_times_source), source, elem_times_source); /* Safe. */
9237  }
9238 
9239  return result;
9240 }
9241 
9257 {
9258 
9260 
9261  char *new_str = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(string);
9262 
9263  if (FOUNDATIONAL_LIB_UNLIKELY(new_str == NULL))
9264  {
9266  return NULL;
9267  }
9268  char *orig_str = new_str;
9269  while (*new_str)
9270  {
9271  *new_str = tolower(*new_str);
9272  ++new_str;
9273  }
9274 
9275  return orig_str;
9276 }
9277 
9293 {
9294 
9296  char *new_str = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(string);
9297  if (FOUNDATIONAL_LIB_UNLIKELY(new_str == NULL))
9298  {
9300  return NULL;
9301  }
9302  char *orig_str = new_str;
9303  while (*new_str)
9304  {
9305  *new_str = toupper(*new_str);
9306  ++new_str;
9307  }
9308 
9309  return orig_str;
9310 }
9311 
9325 {
9326 
9328  while (*string)
9329  {
9330  if (!FOUNDATIONAL_LIB_ISUPPER(*string))
9331  {
9332  return 0;
9333  }
9334  ++string;
9335  }
9336  return 1;
9337 }
9338 
9352 {
9354 
9355  while (*string)
9356  {
9357  if (!FOUNDATIONAL_LIB_ISLOWER(*string))
9358  {
9359  return 0;
9360  }
9361  ++string;
9362  }
9363  return 1;
9364 }
9365 
9379 {
9381  while (*string)
9382  {
9383  if (!FOUNDATIONAL_LIB_ISALNUM(*string))
9384  {
9385  return 0;
9386  }
9387 
9388  ++string;
9389  }
9390  return 1;
9391 }
9392 
9406 {
9408  while (*string)
9409  {
9410  if (!FOUNDATIONAL_LIB_ISDIGIT(*string))
9411  {
9412  return 0;
9413  }
9414  ++string;
9415  }
9416  return 1;
9417 }
9418 
9432 {
9434 
9435  while (*string)
9436  {
9437  if (!FOUNDATIONAL_LIB_ISSPACE(*string))
9438  {
9439  return 0;
9440  }
9441  ++string;
9442  }
9443  return 1;
9444 }
9465 {
9467  while (*string)
9468  {
9469  if (!FOUNDATIONAL_LIB_ISPRINT(*string))
9470  {
9471  return 0;
9472  }
9473  ++string;
9474  }
9475  return 1;
9476 }
9477 
9506 FOUNDATIONAL_LIB_FUNC int is_array_digit(const char **array, size_t size)
9507 {
9508 
9510  for (size_t i = 0; i < size; ++i)
9511  {
9512  const char *str = array[i];
9513  while (*str)
9514  {
9515  if (!FOUNDATIONAL_LIB_ISDIGIT(*str))
9516  {
9517  return 0;
9518  }
9519  ++str;
9520  }
9521  }
9522  return 1;
9523 }
9536 FOUNDATIONAL_LIB_FUNC int is_array_upper(const char **array, size_t size)
9537 {
9538 
9540  for (size_t i = 0; i < size; ++i)
9541  {
9542  const char *str = array[i];
9543  while (*str)
9544  {
9545  if (!FOUNDATIONAL_LIB_ISUPPER(*str))
9546  {
9547  return 0;
9548  }
9549  ++str;
9550  }
9551  }
9552  return 1;
9553 }
9554 
9567 FOUNDATIONAL_LIB_FUNC int is_array_lower(const char **array, size_t size)
9568 {
9569 
9571  for (size_t i = 0; i < size; ++i)
9572  {
9573  const char *str = array[i];
9574  while (*str)
9575  {
9576  if (!FOUNDATIONAL_LIB_ISLOWER(*str))
9577  {
9578  return 0;
9579  }
9580  ++str;
9581  }
9582  }
9583  return 1;
9584 }
9585 
9622 FOUNDATIONAL_LIB_FUNC int string_array_uniq(const char **array, size_t size, char ***output, size_t *output_size)
9623 {
9625 
9628 
9629  *output_size = 0;
9630 
9631  const size_t alloc_size = FOUNDATIONAL_LIB_safe_mul(size, sizeof(char *));
9632 
9633  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size == 0))
9634  {
9636  return -1;
9637  }
9638 
9639  // Count the number of unique strings
9640  size_t count = 0;
9641 
9642  // Allocate memory for the array to store unique strings
9643  *output = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size);
9644  if (FOUNDATIONAL_LIB_UNLIKELY(*output == NULL))
9645  {
9646  // Memory allocation failed
9648  return -1;
9649  }
9650 
9651  // Initialize all elements to NULL
9652  for (size_t i = 0; i < size; ++i)
9653  {
9654  (*output)[i] = NULL;
9655  }
9656 
9657  // Iterate through the input array to find unique strings
9658  for (size_t i = 0; i < size; ++i)
9659  {
9660  int is_unique = 1;
9661 
9662  // Check if the current string is not equal to any previous strings
9663  for (size_t j = 0; j < count; ++j)
9664  {
9665  if ((*output)[j] != NULL && FOUNDATIONAL_LIB_STRCMP(array[i], (*output)[j]) == 0)
9666  {
9667  is_unique = 0; // Not unique
9668  break;
9669  }
9670  }
9671 
9672  if (is_unique)
9673  {
9674  (*output)[count] = ((char **)array)[i]; // No strdup used.
9675 
9676  ++count;
9677  }
9678  }
9679 
9680  // Set the output size
9681  *output_size = count;
9682 
9683  return 0;
9684 }
9685 
9722 FOUNDATIONAL_LIB_FUNC int string_array_uniq_adjacent(const char **first_array, size_t size, char ***new_array, size_t *new_size)
9723 {
9725 
9728 
9732 
9733  *new_size = 0;
9734  const size_t alloc_size = FOUNDATIONAL_LIB_safe_mul(size, sizeof(char *));
9735 
9736  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size == 0))
9737  {
9739  return -1;
9740  }
9741 
9742  // Create a new dynamically allocated array
9743  *new_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size);
9744  if (FOUNDATIONAL_LIB_UNLIKELY(*new_array == NULL))
9745  {
9747  return -1;
9748  }
9749 
9750  // Remove adjacent duplicates from arr1 and copy to arr2
9751  for (size_t i = 0; i < size; ++i)
9752  {
9753  if (i == 0 || FOUNDATIONAL_LIB_STRCMP(first_array[i], first_array[i - 1]) != 0)
9754  {
9755  (*new_array)[(*new_size)++] = (char *)first_array[i]; // No strdup
9756  }
9757  }
9758 
9759  return 0;
9760 }
9761 
9778 FOUNDATIONAL_LIB_FUNC char *concatenate_three_strings(const char *str1, const char *str2, const char *str3)
9779 {
9783 
9784  const char *strs[3] = {str1, str2, str3};
9785 
9786  return concatenate_string_array(strs, 3);
9787 }
9788 
9806 FOUNDATIONAL_LIB_FUNC char *concatenate_four_strings(const char *str1, const char *str2, const char *str3, const char *str4)
9807 {
9812 
9813  const char *strs[4] = {str1, str2, str3, str4};
9814 
9815  return concatenate_string_array(strs, 4);
9816 }
9817 
9836 FOUNDATIONAL_LIB_FUNC char *concatenate_five_strings(const char *str1, const char *str2, const char *str3, const char *str4, const char *str5)
9837 {
9843 
9844  const char *strs[5] = {str1, str2, str3, str4, str5};
9845 
9846  return concatenate_string_array(strs, 5);
9847 }
9848 
9849 #ifdef _WIN32
9850 #include <tchar.h>
9851 #include <windows.h>
9852 #else
9853 #include <dirent.h>
9854 #endif
9855 
9856 #ifdef _WIN32
9857 #define FOUNDATIONAL_LIB_DIR_SEPARATOR '\\'
9858 #else
9859 #define FOUNDATIONAL_LIB_DIR_SEPARATOR '/'
9860 #endif
9861 
9885 FOUNDATIONAL_LIB_FUNC int map_filesystem_files_as_strings(const char *directory, char *(*map_function)(const char *file_string_data, size_t string_size))
9886 {
9887 
9890 
9891 #ifdef _WIN32
9892  WIN32_FIND_DATA findFileData;
9893  HANDLE hFind = FindFirstFile(directory, &findFileData);
9894 
9895  if (FOUNDATIONAL_LIB_UNLIKELY(hFind == INVALID_HANDLE_VALUE))
9896  {
9898  return -1;
9899  }
9900 
9901  do
9902  {
9903  if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
9904  {
9905  // Regular file
9906  char *file_data;
9907  size_t size;
9908 
9909  // Get the regular file.
9910  char fullFilePath[MAX_PATH];
9911  _stprintf(fullFilePath, _T("%s%c%s"), directory, FOUNDATIONAL_LIB_DIR_SEPARATOR, findFileData.cFileName);
9912 
9913  file_data = read_file_into_string(fullFilePath, &size);
9914  if (FOUNDATIONAL_LIB_UNLIKELY(file_data == NULL))
9915  {
9916  // No need to re-die aggressively.
9917  FindClose(hFind); /* No need to error check here because there already is an error. */
9918  return -1;
9919  }
9920 
9921  // The result of the map operation
9922  const char *new_str = map_function(file_data, size);
9923 
9924  // Write the result to disk
9925  if (FOUNDATIONAL_LIB_UNLIKELY(write_file(fullFilePath, new_str) == -1))
9926  {
9927  // No need to re-die aggressively.
9929  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE((char *)new_str);
9930  FindClose(hFind); // No need to error check here because there already is an error.
9931  return -1;
9932  }
9933 
9934  // Free memory.
9936  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE((char *)new_str);
9937  }
9938 
9939  } while (FindNextFile(hFind, &findFileData) != 0);
9940 
9941  if (FOUNDATIONAL_LIB_UNLIKELY(FindClose(hFind) == 0))
9942  {
9944  return -1;
9945  }
9946 
9947 #else
9948  DIR *dir = opendir(directory);
9949  if (FOUNDATIONAL_LIB_UNLIKELY(dir == NULL))
9950  {
9952  return -1;
9953  }
9954 
9955  struct dirent *entry;
9956  while ((entry = readdir(dir)) != NULL)
9957  {
9958  if (entry->d_type == DT_REG)
9959  { // Regular file
9960  char *file_data;
9961  size_t size;
9962 
9963  // Get the regular file.
9964  char fullFilePath[PATH_MAX];
9965  FOUNDATIONAL_LIB_SNPRINTF(fullFilePath, PATH_MAX, "%s%c%s", directory, FOUNDATIONAL_LIB_DIR_SEPARATOR, entry->d_name);
9966 
9967  file_data = read_file_into_string(fullFilePath, &size);
9968  if (FOUNDATIONAL_LIB_UNLIKELY(file_data == NULL))
9969  {
9970  // No need to re-die aggressively.
9971  return -1;
9972  }
9973 
9974  // The result of the map operation
9975  const char *new_str = map_function(file_data, size);
9976 
9977  // Write the result to disk
9978  if (write_file(fullFilePath, new_str) == -1)
9979  {
9980  // No need to re-die aggressively.
9982  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE((char *)new_str);
9983  return -1;
9984  }
9985 
9986  // Free memory.
9988  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE((char *)new_str);
9989  }
9990  }
9991 
9992  if (FOUNDATIONAL_LIB_UNLIKELY(closedir(dir) == -1))
9993  {
9995  return -1;
9996  }
9997 
9998 #endif
9999 
10000  return 0;
10001 }
10002 
10018 FOUNDATIONAL_LIB_FUNC int filter_filesystem_files_as_strings(const char *directory, int (*filter_function)(const char *filename))
10019 {
10022 #ifdef _WIN32
10023  WIN32_FIND_DATA findFileData;
10024  HANDLE hFind = FindFirstFile(directory, &findFileData);
10025 
10026  if (FOUNDATIONAL_LIB_UNLIKELY(hFind == INVALID_HANDLE_VALUE))
10027  {
10029  return -1;
10030  }
10031 
10032  do
10033  {
10034  if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !filter_function(findFileData.cFileName))
10035  {
10036  // Regular file to be removed
10037  char fullFilePath[MAX_PATH];
10038  _stprintf(fullFilePath, _T("%s%c%s"), directory, FOUNDATIONAL_LIB_DIR_SEPARATOR, findFileData.cFileName);
10039 
10040  if (remove_file(fullFilePath) == -1)
10041  {
10042  // Handle error or return -1
10043  if (FindClose(hFind) == 0)
10044  {
10046  return -1;
10047  }
10048  return -1;
10049  }
10050  }
10051 
10052  } while (FindNextFile(hFind, &findFileData) != 0);
10053 
10054  FindClose(hFind);
10055 
10056 #else
10057  DIR *dir = opendir(directory);
10058  if (FOUNDATIONAL_LIB_UNLIKELY(dir == NULL))
10059  {
10061  return -1;
10062  }
10063 
10064  struct dirent *entry;
10065  while ((entry = readdir(dir)) != NULL)
10066  {
10067  if (entry->d_type == DT_REG)
10068  {
10069  if (!filter_function(entry->d_name))
10070  {
10071  // Regular file to be removed
10072  char fullFilePath[PATH_MAX];
10073  FOUNDATIONAL_LIB_SNPRINTF(fullFilePath, PATH_MAX, "%s%c%s", directory, FOUNDATIONAL_LIB_DIR_SEPARATOR, entry->d_name);
10074 
10075  if (remove_file(fullFilePath) == -1)
10076  {
10077  // Handle error or return -1
10078  if (closedir(dir) == -1)
10079  {
10081  return -1;
10082  }
10083  return -1;
10084  }
10085  }
10086  }
10087  }
10088 
10089  if (FOUNDATIONAL_LIB_UNLIKELY(closedir(dir) == -1))
10090  {
10092  return -1;
10093  }
10094 #endif
10095 
10096  return 0;
10097 }
10098 
10120 FOUNDATIONAL_LIB_FUNC char *reduce_filesystem_files_as_strings(const char *directory, const char *out_file, char *(*reduce_function)(char *value1, ...))
10121 {
10125 #ifdef _WIN32
10126  WIN32_FIND_DATA findFileData;
10127  HANDLE hFind = FindFirstFile(directory, &findFileData);
10128 
10129  if (FOUNDATIONAL_LIB_UNLIKELY(hFind == INVALID_HANDLE_VALUE))
10130  {
10132  return NULL;
10133  }
10134 
10135  char *last_value = NULL;
10136  char *value = NULL;
10137 
10138  do
10139  {
10140  if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && findFileData.dwFileAttributes & FILE_ATTRIBUTE_NORMAL)
10141  {
10142  // Regular file
10143  size_t size;
10144 
10145  // Get the regular file.
10146  char fullFilePath[MAX_PATH];
10147  _stprintf(fullFilePath, _T("%s%c%s"), directory, FOUNDATIONAL_LIB_DIR_SEPARATOR, findFileData.cFileName);
10148 
10149  value = read_file_into_string(fullFilePath, &size);
10150  if (FOUNDATIONAL_LIB_UNLIKELY(value == NULL))
10151  {
10152  // No need to re-die aggressively.
10153  FindClose(hFind); /* Don't need to care about the return value because there already is an error. */
10154  return NULL;
10155  }
10156 
10157  char *new_value = reduce_function(last_value, value, findFileData.cFileName);
10158  if (last_value)
10159  {
10161  }
10162 
10164  last_value = new_value;
10165 
10166  if (FOUNDATIONAL_LIB_UNLIKELY(remove_file(fullFilePath) == -1))
10167  {
10169  return NULL;
10170  }
10171  }
10172 
10173  } while (FindNextFile(hFind, &findFileData) != 0);
10174 
10175  if (FOUNDATIONAL_LIB_UNLIKELY(FindClose(hFind) == 0))
10176  {
10178  return NULL;
10179  }
10180 #else
10181  DIR *dir = opendir(directory);
10182  if (FOUNDATIONAL_LIB_UNLIKELY(dir == NULL))
10183  {
10185  return NULL;
10186  }
10187 
10188  char *last_value = NULL;
10189  char *value = NULL;
10190  struct dirent *entry;
10191 
10192  while ((entry = readdir(dir)) != NULL)
10193  {
10194  if (entry->d_type == DT_REG)
10195  {
10196  // Regular file
10197  size_t size;
10198 
10199  // Get the regular file.
10200  char fullFilePath[PATH_MAX];
10201  FOUNDATIONAL_LIB_SNPRINTF(fullFilePath, PATH_MAX, "%s%c%s", directory, FOUNDATIONAL_LIB_DIR_SEPARATOR, entry->d_name);
10202 
10203  value = read_file_into_string(fullFilePath, &size);
10204  if (FOUNDATIONAL_LIB_UNLIKELY(value == NULL))
10205  {
10206  // No need to re-die aggressively.
10207  if (FOUNDATIONAL_LIB_UNLIKELY(closedir(dir) == -1))
10208  {
10210  return NULL;
10211  }
10212  return NULL;
10213  }
10214 
10215  char *new_value = reduce_function(last_value, value, entry->d_name);
10216  if (last_value)
10217  {
10219  }
10220 
10222  last_value = new_value;
10223 
10224  if (FOUNDATIONAL_LIB_UNLIKELY(remove_file(fullFilePath) == -1))
10225  {
10227  return NULL;
10228  }
10229  }
10230  }
10231 
10232  if (FOUNDATIONAL_LIB_UNLIKELY(closedir(dir) == -1))
10233  {
10235  return NULL;
10236  }
10237 #endif
10238 
10239  if (FOUNDATIONAL_LIB_UNLIKELY(write_file(out_file, value) == -1))
10240  {
10241  /* No need to re-die aggressively. */
10243  return NULL;
10244  }
10245 
10246  return last_value;
10247 }
10248 
10259 {
10260 
10262 
10263  for (size_t i = 0; i < dict->capacity; ++i)
10264  {
10265  struct DictKeyValue *current_pair = dict->table[i];
10266  while (current_pair != NULL)
10267  {
10268  struct DictKeyValue *next_pair = current_pair->next;
10271  current_pair = next_pair;
10272  }
10273  }
10276 }
10277 
10292 FOUNDATIONAL_LIB_FUNC size_t dict_hash(const char *key, size_t capacity)
10293 {
10295 
10296  size_t hash = 5381; // Initial hash value
10297  int c; // Variable to store the current character
10298 
10299  while ((c = *key++))
10300  {
10301  hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
10302  }
10303 
10304  return hash % capacity;
10305 }
10306 
10324 FOUNDATIONAL_LIB_FUNC int dict_reserve_more(struct Dict *dict, size_t number_of_new_elements_max_one_is_expecting)
10325 {
10327 
10328  const size_t new_capacity = FOUNDATIONAL_LIB_safe_add_2(dict->capacity, number_of_new_elements_max_one_is_expecting);
10329 
10330  if (FOUNDATIONAL_LIB_UNLIKELY(new_capacity == 0))
10331  {
10333  return -1;
10334  }
10335 
10336  /* Either calloc or realloc would be ideal here, but, if the block is large,
10337  then calloc might be better because there might be a cleared block of
10338  memory that is very large that is readily available. */
10339  struct DictKeyValue **new_table = (struct DictKeyValue **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(new_capacity, sizeof(struct DictKeyValue *));
10340  if (FOUNDATIONAL_LIB_UNLIKELY(new_table == NULL))
10341  {
10343  return -1;
10344  }
10345 
10346  for (size_t i = 0; i < dict->capacity; ++i)
10347  {
10348  struct DictKeyValue *current_pair = dict->table[i];
10349  while (current_pair)
10350  {
10351  struct DictKeyValue *next_pair = current_pair->next;
10352  const size_t new_index = dict_hash(current_pair->key, new_capacity);
10353  current_pair->next = new_table[new_index];
10354  new_table[new_index] = current_pair;
10355  current_pair = next_pair;
10356  }
10357  }
10358 
10360  dict->table = new_table;
10361  dict->capacity = new_capacity;
10362 
10363  return 0;
10364 }
10379 {
10380 
10382 
10383  const size_t new_capacity = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(dict->capacity);
10384  if (FOUNDATIONAL_LIB_UNLIKELY(new_capacity == 0)) // Overflow.
10385  {
10387  return -1;
10388  }
10389 
10390  /* Either calloc or realloc would be ideal here, but, if the block is large,
10391  then calloc might be better because there might be a cleared block of
10392  memory that is very large that is readily available. */
10393  struct DictKeyValue **new_table = (struct DictKeyValue **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(new_capacity, sizeof(struct DictKeyValue *));
10394  if (FOUNDATIONAL_LIB_UNLIKELY(new_table == NULL))
10395  {
10396  dict_destructor(dict);
10398  return -1;
10399  }
10400 
10401  for (size_t i = 0; i < dict->capacity; ++i)
10402  {
10403  struct DictKeyValue *current_pair = dict->table[i];
10404  while (current_pair)
10405  {
10406  struct DictKeyValue *next_pair = current_pair->next;
10407  const size_t new_index = dict_hash(current_pair->key, new_capacity);
10408  current_pair->next = new_table[new_index];
10409  new_table[new_index] = current_pair;
10410  current_pair = next_pair;
10411  }
10412  }
10413 
10415  dict->table = new_table;
10416  dict->capacity = new_capacity;
10417 
10418  return 0;
10419 }
10420 
10432 FOUNDATIONAL_LIB_FUNC void dict_del_key(struct Dict *dict, const char *key)
10433 {
10436  const size_t index = dict_hash(key, dict->capacity);
10437 
10438  struct DictKeyValue *current = dict->table[index];
10439  struct DictKeyValue *prev = NULL;
10440 
10441  while (current != NULL)
10442  {
10443  if (FOUNDATIONAL_LIB_STRCMP(current->key, key) == 0)
10444  {
10445  /* Key found, remove the entry */
10446  if (prev == NULL)
10447  {
10448  /* If it's the first node in the linked list */
10449  dict->table[index] = current->next;
10450  }
10451  else
10452  {
10453  prev->next = current->next;
10454  }
10455 
10456  /* Free memory */
10459 
10460  /* Update size */
10461  --dict->size;
10462 
10463  return;
10464  }
10465 
10466  /* Move to the next node in the linked list */
10467  prev = current;
10468  current = current->next;
10469  }
10470 }
10471 
10484 FOUNDATIONAL_LIB_FUNC int dict_add(struct Dict *dict, const char *key, void *value)
10485 {
10486 
10490  if ((double)dict->size / dict->capacity > FOUNDATIONAL_LIB_HASH_LOAD_FACTOR_THRESHOLD)
10491  {
10492  if (FOUNDATIONAL_LIB_UNLIKELY(dict_resize(dict) == -1))
10493  {
10494  // Don't need to re die aggressively if enabled here because dict resize
10495  // does it.
10496  return -1;
10497  }
10498  }
10499 
10500  const size_t index = dict_hash(key, dict->capacity);
10501 
10502  struct DictKeyValue *new_pair = (struct DictKeyValue *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(sizeof(struct DictKeyValue));
10503  if (FOUNDATIONAL_LIB_UNLIKELY(new_pair == NULL))
10504  {
10505  /* Keep the old key if there was one. */
10507  return -1;
10508  }
10509 
10511  if (FOUNDATIONAL_LIB_UNLIKELY(new_pair->key == NULL))
10512  {
10515  return -1;
10516  }
10517  new_pair->next = dict->table[index];
10518  new_pair->value = value;
10519 
10520  /* If there is a hash collision */
10521  if (dict->table[index] != NULL)
10522  {
10523  struct DictKeyValue *current = new_pair->next; // First one
10524  struct DictKeyValue *prev = new_pair; // New one
10525  /* Traverse the linked list to check for duplicates */
10526  do
10527  {
10528  /* This should only ever happen once unless the dict is corrupt, so we return. */
10529  if (FOUNDATIONAL_LIB_STRCMP(current->key, key) == 0)
10530  {
10531  prev->next = current->next;
10532  /* Duplicate key found */
10535  /* Dont increment size */
10536  /* Assume the list only has 1 key with the value (it should unless
10537  * something is really wrong). */
10538  goto end;
10539  }
10540 
10541  prev = current;
10542  current = current->next;
10543  } while (current != NULL);
10544  }
10545  ++dict->size;
10546 
10547 end:
10548  dict->table[index] = new_pair;
10549  return 0;
10550 }
10551 
10568 FOUNDATIONAL_LIB_FUNC void *dict_get(struct Dict *dict, const char *key)
10569 {
10572  const size_t index = dict_hash(key, dict->capacity);
10573  struct DictKeyValue *current_pair = dict->table[index];
10574 
10575  while (current_pair != NULL)
10576  {
10577  if (FOUNDATIONAL_LIB_STRCMP(current_pair->key, key) == 0)
10578  {
10579  return current_pair->value;
10580  }
10581 
10582  // Hash collision, continue with linked list.
10583  current_pair = current_pair->next;
10584  }
10585 
10586  return NULL;
10587 }
10588 
10607 FOUNDATIONAL_LIB_FUNC void *dict_get_check(struct Dict *dict, const char *key, int *key_is_in_dict)
10608 {
10612 
10613  const size_t index = dict_hash(key, dict->capacity);
10614  struct DictKeyValue *current_pair = dict->table[index];
10615 
10616  while (current_pair != NULL)
10617  {
10618  if (FOUNDATIONAL_LIB_STRCMP(current_pair->key, key) == 0)
10619  {
10620  *key_is_in_dict = 1;
10621  return current_pair->value;
10622  }
10623  current_pair = current_pair->next;
10624  }
10625 
10626  *key_is_in_dict = 0;
10627  return NULL;
10628 }
10629 
10642 {
10644  dict_destructor((struct Dict *)dict);
10645 }
10646 
10661 {
10662  struct FrozenDict *frozen_dict = (struct FrozenDict *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(sizeof(struct FrozenDict));
10663  if (FOUNDATIONAL_LIB_UNLIKELY(frozen_dict == NULL))
10664  {
10666  return NULL;
10667  }
10668 
10670  frozen_dict->size = 0;
10672  if (FOUNDATIONAL_LIB_UNLIKELY(frozen_dict->table == NULL))
10673  {
10676  return NULL;
10677  }
10678 
10680  FOUNDATIONAL_LIB_VA_START(args, num_pairs);
10681 
10682  for (size_t i = 0; i < num_pairs; ++i)
10683  {
10684  char *key;
10685  void *value;
10686 
10687  key = FOUNDATIONAL_LIB_VA_ARG(args, char *);
10688  value = FOUNDATIONAL_LIB_VA_ARG(args, void *);
10689 
10690  dict_add((struct Dict *)frozen_dict, key, value);
10691  }
10692 
10693  FOUNDATIONAL_LIB_VA_END(args); // Clean up the va_list
10694 
10695  return frozen_dict;
10696 }
10697 
10712 FOUNDATIONAL_LIB_FUNC void *frozen_dict_get(struct FrozenDict *dict, const char *key)
10713 {
10716  const size_t index = dict_hash(key, dict->capacity);
10717  struct DictKeyValue *current_pair = dict->table[index];
10718 
10719  while (current_pair != NULL)
10720  {
10721  if (FOUNDATIONAL_LIB_STRCMP(current_pair->key, key) == 0)
10722  {
10723  return current_pair->value;
10724  }
10725  current_pair = current_pair->next;
10726  }
10727 
10728  return NULL;
10729 }
10730 
10748 FOUNDATIONAL_LIB_FUNC void *frozen_dict_get_check(struct FrozenDict *dict, const char *key, int *key_is_in_dict)
10749 {
10753 
10754  const size_t index = dict_hash(key, dict->capacity);
10755  struct DictKeyValue *current_pair = dict->table[index];
10756 
10757  while (current_pair != NULL)
10758  {
10759  if (FOUNDATIONAL_LIB_STRCMP(current_pair->key, key) == 0)
10760  {
10761  *key_is_in_dict = 1;
10762  return current_pair->value;
10763  }
10764  current_pair = current_pair->next;
10765  }
10766 
10767  *key_is_in_dict = 0;
10768  return NULL;
10769 }
10770 
10784 FOUNDATIONAL_LIB_FUNC void dict_iter(struct Dict *dict, void (*callback)(char *key, void *value))
10785 {
10788 
10789  for (size_t i = 0; i < dict->capacity; ++i)
10790  {
10791  struct DictKeyValue *current = dict->table[i];
10792 
10793  while (current != NULL)
10794  {
10795  /* Call the callback function with the key and value */
10796  callback(current->key, current->value);
10797 
10798  /* Move to the next node in the linked list */
10799  current = current->next;
10800  }
10801  }
10802 }
10803 
10817 FOUNDATIONAL_LIB_FUNC void frozen_dict_iter(struct FrozenDict *frozen_dict, void (*callback)(char *key, void *value))
10818 {
10821  for (size_t i = 0; i < frozen_dict->capacity; ++i)
10822  {
10823  struct DictKeyValue *current = frozen_dict->table[i];
10824 
10825  while (current != NULL)
10826  {
10827  /* Call the callback function with the key and value */
10828  callback(current->key, current->value);
10829 
10830  /* Move to the next node in the linked list */
10831  current = current->next;
10832  }
10833  }
10834 }
10846 {
10847 
10849  return dict->size;
10850 }
10851 
10863 {
10865 
10866  return dict->size;
10867 }
10868 
10891 FOUNDATIONAL_LIB_FUNC int dict_to_array(struct Dict *dict, char ***keys, void ***values, size_t *size_of_keys_and_values)
10892 {
10896  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(size_of_keys_and_values);
10897 
10898  const size_t alloc_size1 = FOUNDATIONAL_LIB_safe_mul(dict->size, sizeof(char *));
10899  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size1 == 0))
10900  goto overflow;
10901  size_t alloc_size2;
10902 
10903  alloc_size2 = FOUNDATIONAL_LIB_safe_mul(dict->size, sizeof(void *));
10904  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size2 == 0))
10905  goto overflow;
10906 
10907  *keys = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size1);
10908  if (FOUNDATIONAL_LIB_UNLIKELY(*keys == NULL))
10909  goto error_handler;
10910 
10911  *values = (void **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size2);
10912 
10913  if (FOUNDATIONAL_LIB_UNLIKELY(*values == NULL))
10914  {
10916  *keys = NULL;
10917  // Values is already NULL here.
10918  goto error_handler;
10919  }
10920 
10921  for (size_t i = 0, index = 0; i < dict->capacity; ++i)
10922  {
10923  struct DictKeyValue *current_pair = dict->table[i];
10924  while (current_pair != NULL)
10925  {
10926  (*keys)[index] = (current_pair->key);
10927  (*values)[index] = current_pair->value;
10928 
10929  ++index;
10930  current_pair = current_pair->next;
10931  }
10932  }
10933 
10934  *size_of_keys_and_values = dict->size;
10935 
10936  return 0;
10937 
10938 overflow:
10939 error_handler:
10940 
10942  return -1;
10943 }
10944 
10967 FOUNDATIONAL_LIB_FUNC size_t frozen_dict_to_array(struct FrozenDict *dict, char ***keys, void ***values, size_t *size_of_keys_and_values)
10968 {
10969 
10973  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(size_of_keys_and_values);
10974 
10975  const size_t alloc_size1 = FOUNDATIONAL_LIB_safe_mul(dict->size, sizeof(char *));
10976  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size1 == 0))
10977  goto overflow;
10978  size_t alloc_size2;
10979 
10980  alloc_size2 = FOUNDATIONAL_LIB_safe_mul(dict->size, sizeof(void *));
10981  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size2 == 0))
10982  goto overflow;
10983 
10984  *keys = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size1);
10985  if (FOUNDATIONAL_LIB_UNLIKELY(*keys == NULL))
10986  goto error_handler;
10987 
10988  *values = (void **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size2);
10989 
10990  if (FOUNDATIONAL_LIB_UNLIKELY(*values == NULL))
10991  {
10993  *keys = NULL;
10994  // Values is already NULL here.
10995  goto error_handler;
10996  }
10997 
10998  for (size_t i = 0, index = 0; i < dict->capacity; ++i)
10999  {
11000  struct DictKeyValue *current_pair = dict->table[i];
11001  while (current_pair != NULL)
11002  {
11003  (*keys)[index] = (current_pair->key);
11004  (*values)[index] = current_pair->value;
11005 
11006  ++index;
11007  current_pair = current_pair->next;
11008  }
11009  }
11010 
11011  *size_of_keys_and_values = dict->size;
11012 
11013  return 0;
11014 
11015 overflow:
11016 error_handler:
11017 
11019  return -1;
11020 }
11021 
11032 static inline void dict_del_keys(char **keys)
11033 {
11034 
11037 }
11038 
11049 static inline void dict_del_values(void **values)
11050 {
11053 }
11054 
11073 FOUNDATIONAL_LIB_FUNC char *dict_to_string(struct Dict *dict, int pointer_or_string) /* 0 = pointer, 1 = string */
11074 {
11076  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(pointer_or_string == 0 || pointer_or_string == 1);
11077 
11078  /* Allocate memory for the string representation */
11079  size_t total_length = 2;
11080  for (size_t i = 0; i < dict->capacity; ++i)
11081  {
11082  struct DictKeyValue *current_pair = dict->table[i];
11083  while (current_pair != NULL)
11084  {
11085  /* Calculate the length of the string representation for each key-value
11086  * pair */
11087  total_length += FOUNDATIONAL_LIB_STRLEN(current_pair->key) + 2; // 2 for ": "
11088  if (pointer_or_string == 0)
11089  {
11090  total_length += FOUNDATIONAL_LIB_SNPRINTF(NULL, 0, "%p",
11091  current_pair->value); // Calculate the length of the value string
11092  }
11093  else
11094  {
11095  total_length += FOUNDATIONAL_LIB_SNPRINTF(NULL, 0, "%s",
11096  (char *)current_pair->value); // Calculate the length of the value string
11097  }
11098  total_length += 2; // 2 for ", "
11099  current_pair = current_pair->next;
11100  }
11101  }
11102 
11103  // Should not reach SIZE_MAX
11104 
11105  // Add 1 for the null-terminator, at least 3 chars additional
11106  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(total_length + sizeof("")); /* Should be Safe. */
11107  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
11108  {
11110  return NULL;
11111  }
11112 
11113  result[0] = '{';
11114  size_t index = 1;
11115 
11116  for (size_t i = 0; i < dict->capacity; ++i)
11117  {
11118  struct DictKeyValue *current_pair = dict->table[i];
11119  while (current_pair != NULL)
11120  {
11121  /* Append the key and value to the string representation */
11122  if (pointer_or_string == 0)
11123  {
11124  index += FOUNDATIONAL_LIB_SNPRINTF(result + index, total_length - index, "%s: %p", current_pair->key, current_pair->value);
11125  }
11126  else if (pointer_or_string == 1)
11127  {
11128  index += FOUNDATIONAL_LIB_SNPRINTF(result + index, total_length - index, "%s: %s", current_pair->key, (char *)current_pair->value);
11129  }
11130  current_pair = current_pair->next;
11131 
11132  /* Add a separator (comma) if there are more elements */
11133  if (index < total_length - 2)
11134  {
11135  result[index++] = ',';
11136  result[index++] = ' ';
11137  }
11138  }
11139  }
11140 
11141  if (dict->capacity)
11142  {
11143  index -= 2;
11144  }
11145 
11146  result[index++] = '}';
11147  result[index++] = '\0'; // Null-terminate the string
11148  return result;
11149 }
11150 
11170 FOUNDATIONAL_LIB_FUNC char *frozen_dict_to_string(struct FrozenDict *dict, int pointer_or_string) /* 0 = pointer, 1 = string */
11171 {
11173  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(pointer_or_string == 0 || pointer_or_string == 1);
11174  /* Allocate memory for the string representation */
11175  size_t total_length = 2;
11176  for (size_t i = 0; i < dict->capacity; ++i)
11177  {
11178  struct DictKeyValue *current_pair = dict->table[i];
11179  while (current_pair != NULL)
11180  {
11181  /* Calculate the length of the string representation for each key-value
11182  * pair */
11183  total_length += FOUNDATIONAL_LIB_STRLEN(current_pair->key) + 2; // 2 for ": "
11184 
11185  if (pointer_or_string == 0)
11186  {
11187  total_length += FOUNDATIONAL_LIB_SNPRINTF(NULL, 0, "%p",
11188  current_pair->value); // Calculate the length of the value string
11189  }
11190  else
11191  {
11192  total_length += FOUNDATIONAL_LIB_SNPRINTF(NULL, 0, "%s",
11193  (char *)current_pair->value); // Calculate the length of the value string
11194  }
11195  total_length += 2; // 2 for ", "
11196  current_pair = current_pair->next;
11197  }
11198  }
11199 
11200  // Should not reach SIZE_MAX
11201 
11202  // Add 1 for the null-terminator, at least 3 chars additional
11203  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(total_length + sizeof("")); /* Safe. */
11204  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
11205  {
11207  return NULL;
11208  }
11209 
11210  result[0] = '{';
11211  size_t index = 1;
11212 
11213  for (size_t i = 0; i < dict->capacity; ++i)
11214  {
11215  struct DictKeyValue *current_pair = dict->table[i];
11216  while (current_pair != NULL)
11217  {
11218  /* Append the key and value to the string representation */
11219  if (pointer_or_string == 0)
11220  {
11221  index += FOUNDATIONAL_LIB_SNPRINTF(result + index, total_length - index, "%s: %p", current_pair->key, current_pair->value);
11222  }
11223  else if (pointer_or_string == 1)
11224  {
11225  index += FOUNDATIONAL_LIB_SNPRINTF(result + index, total_length - index, "%s: %s", current_pair->key, (char *)current_pair->value);
11226  }
11227  current_pair = current_pair->next;
11228 
11229  /* Add a separator (comma) if there are more elements */
11230  if (index < total_length - 2)
11231  {
11232  result[index++] = ',';
11233  result[index++] = ' ';
11234  }
11235  }
11236  }
11237 
11238  if (dict->capacity)
11239  {
11240  index -= 2;
11241  }
11242 
11243  result[index++] = '}';
11244  result[index++] = '\0'; // Null-terminate the string
11245  return result;
11246 }
11247 
11256 static inline void frozen_dict_del_keys(char **keys)
11257 {
11260 }
11261 
11270 static inline void frozen_dict_del_values(void **values)
11271 {
11274 }
11275 
11284 {
11286 
11287  for (size_t i = 0; i < set->capacity; ++i)
11288  {
11289  struct SetKey *current_key = set->table[i];
11290  while (current_key != NULL)
11291  {
11292  struct SetKey *next_key = current_key->next;
11295  current_key = next_key;
11296  }
11297  }
11300 }
11301 
11310 {
11311  struct Set *set = (struct Set *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(sizeof(struct Set));
11312  if (FOUNDATIONAL_LIB_UNLIKELY(set == NULL))
11313  {
11315  return NULL;
11316  }
11317 
11319  set->size = 0;
11321  if (FOUNDATIONAL_LIB_UNLIKELY(set->table == NULL))
11322  {
11325  return NULL;
11326  }
11327 
11328  return set;
11329 }
11330 
11345 FOUNDATIONAL_LIB_FUNC size_t set_hash(const char *key, size_t capacity)
11346 {
11348  size_t hash = 5381; // Initial hash value
11349  int c; // Variable to store the current character
11350 
11351  while ((c = *key++))
11352  {
11353  hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
11354  }
11355 
11356  return hash % capacity;
11357 }
11358 
11368 {
11370 
11371  const size_t new_capacity = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(set->capacity);
11372  if (FOUNDATIONAL_LIB_UNLIKELY(new_capacity == 0)) // Overflow.
11373  {
11375  return -1;
11376  }
11377  /* Either calloc or realloc would be ideal here, but, if the block is large,
11378  then calloc might be better because there might be a cleared block of
11379  memory that is very large that is readily available. */
11380  struct SetKey **new_table = (struct SetKey **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(new_capacity, sizeof(struct SetKey *));
11381  if (FOUNDATIONAL_LIB_UNLIKELY(new_table == NULL))
11382  {
11383  set_destructor(set);
11385  return -1;
11386  }
11387 
11388  for (size_t i = 0; i < set->capacity; ++i)
11389  {
11390  struct SetKey *current_key = set->table[i];
11391  while (current_key)
11392  {
11393  struct SetKey *next_key = current_key->next;
11394  const size_t new_index = set_hash(current_key->key, new_capacity);
11395  current_key->next = new_table[new_index];
11396  new_table[new_index] = current_key;
11397  current_key = next_key;
11398  }
11399  }
11400 
11402  set->table = new_table;
11403  set->capacity = new_capacity;
11404 
11405  return 0;
11406 }
11407 
11416 FOUNDATIONAL_LIB_FUNC void set_del_key(struct Set *set, const char *key)
11417 {
11420 
11421  const size_t index = set_hash(key, set->capacity);
11422 
11423  struct SetKey *current = set->table[index];
11424  struct SetKey *prev = NULL;
11425 
11426  while (current != NULL)
11427  {
11428  if (FOUNDATIONAL_LIB_STRCMP(current->key, key) == 0)
11429  {
11430  /* Key found, remove the entry */
11431  if (prev == NULL)
11432  {
11433  /* If it's the first node in the linked list */
11434  set->table[index] = current->next;
11435  }
11436  else
11437  {
11438  prev->next = current->next;
11439  }
11440 
11441  /* Free memory */
11444 
11445  /* Update size */
11446  --set->size;
11447 
11448  return;
11449  }
11450 
11451  /* Move to the next node in the linked list */
11452  prev = current;
11453  current = current->next;
11454  }
11455 }
11456 
11468 FOUNDATIONAL_LIB_FUNC int set_add(struct Set *set, const char *key)
11469 {
11472 
11473  if ((double)set->size / set->capacity > FOUNDATIONAL_LIB_HASH_LOAD_FACTOR_THRESHOLD)
11474  {
11475  if (FOUNDATIONAL_LIB_UNLIKELY(set_resize(set) == -1))
11476  {
11477  // Don't need to re die aggressively if enabled here because set resize does it.
11478  return -1;
11479  }
11480  }
11481 
11482  const size_t index = set_hash(key, set->capacity);
11483 
11484  struct SetKey *new_set_key = (struct SetKey *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(sizeof(struct SetKey));
11485  if (FOUNDATIONAL_LIB_UNLIKELY(new_set_key == NULL))
11486  {
11487  /* Keep the old key if there was one. */
11489  return -1;
11490  }
11491 
11493  if (FOUNDATIONAL_LIB_UNLIKELY(new_set_key->key == NULL))
11494  {
11497  return -1;
11498  }
11499  new_set_key->next = set->table[index];
11500 
11501  /* If there is a hash collision */
11502  if (set->table[index] != NULL)
11503  {
11504  struct SetKey *current = new_set_key->next; // First one
11505  struct SetKey *prev = new_set_key; // New one
11506  /* Traverse the linked list to check for duplicates */
11507  do
11508  {
11509  /* This should only ever happen once unless the set is corrupt, so we return. */
11510 
11511  if (FOUNDATIONAL_LIB_STRCMP(current->key, key) == 0)
11512  { /* Duplicate key found */
11513  prev->next = current->next;
11514 
11515  // Free the old key
11518 
11519  /* Dont increment size */
11520  /* Assume the list only has 1 key with the value (it should unless
11521  * something is really wrong). */
11522 
11523  goto end;
11524  }
11525 
11526  prev = current;
11527  current = current->next;
11528  } while (current != NULL);
11529  }
11530 
11531  ++set->size;
11532 end:
11533  set->table[index] = new_set_key;
11534  return 0;
11535 }
11536 
11553 FOUNDATIONAL_LIB_FUNC int set_reserve_more(struct Set *set, size_t number_of_new_elements_max_one_is_expecting)
11554 {
11556 
11557  const size_t new_capacity = FOUNDATIONAL_LIB_safe_add_2(set->capacity, number_of_new_elements_max_one_is_expecting);
11558  if (FOUNDATIONAL_LIB_UNLIKELY(new_capacity == 0)) // Overflow.
11559  {
11561  return -1;
11562  }
11563  /* Either calloc or realloc would be ideal here, but, if the block is large,
11564  then calloc might be better because there might be a cleared block of
11565  memory that is very large that is readily available. */
11566  struct SetKey **new_table = (struct SetKey **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(new_capacity, sizeof(struct SetKey *));
11567  if (FOUNDATIONAL_LIB_UNLIKELY(new_table == NULL))
11568  {
11570  return -1;
11571  }
11572 
11573  for (size_t i = 0; i < set->capacity; ++i)
11574  {
11575  struct SetKey *current_key = set->table[i];
11576  while (current_key)
11577  {
11578  struct SetKey *next_key = current_key->next;
11579  const size_t new_index = set_hash(current_key->key, new_capacity);
11580  current_key->next = new_table[new_index];
11581  new_table[new_index] = current_key;
11582  current_key = next_key;
11583  }
11584  }
11585 
11587  set->table = new_table;
11588  set->capacity = new_capacity;
11589 
11590  return 0;
11591 }
11592 
11602 FOUNDATIONAL_LIB_FUNC int set_in(struct Set *set, const char *key)
11603 {
11606 
11607  const size_t index = set_hash(key, set->capacity);
11608  struct SetKey *current_key = set->table[index];
11609 
11610  while (current_key != NULL)
11611  {
11612  if (FOUNDATIONAL_LIB_STRCMP(current_key->key, key) == 0)
11613  {
11614  return 1;
11615  }
11616  current_key = current_key->next;
11617  }
11618 
11619  return 0;
11620 }
11621 
11630 {
11631 
11633  set_destructor((struct Set *)frozen_set);
11634 }
11635 
11646 {
11647  struct FrozenSet *frozen_set = (struct FrozenSet *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(sizeof(struct FrozenSet));
11648  if (FOUNDATIONAL_LIB_UNLIKELY(frozen_set == NULL))
11649  {
11651  return NULL;
11652  }
11653 
11655  frozen_set->size = 0;
11657  if (FOUNDATIONAL_LIB_UNLIKELY(frozen_set->table == NULL))
11658  {
11661  return NULL;
11662  }
11663 
11665  FOUNDATIONAL_LIB_VA_START(args, num_args);
11666 
11667  for (size_t i = 0; i < num_args; ++i)
11668  {
11669  char *key;
11670 
11671  key = FOUNDATIONAL_LIB_VA_ARG(args, char *);
11672  set_add((struct Set *)frozen_set, key);
11673  }
11674 
11675  FOUNDATIONAL_LIB_VA_END(args); // Clean up the va_list
11676 
11677  return frozen_set;
11678 }
11679 
11689 FOUNDATIONAL_LIB_FUNC int frozen_set_in(struct FrozenSet *set, const char *key)
11690 {
11692 
11693  const size_t index = set_hash(key, set->capacity);
11694  struct SetKey *current_key = set->table[index];
11695 
11696  while (current_key != NULL)
11697  {
11698  if (FOUNDATIONAL_LIB_STRCMP(current_key->key, key) == 0)
11699  {
11700  return 1;
11701  }
11702  current_key = current_key->next;
11703  }
11704 
11705  return 0;
11706 }
11707 
11716 FOUNDATIONAL_LIB_FUNC void set_iter(struct Set *set, void (*callback)(char *key))
11717 {
11719 
11721  for (size_t i = 0; i < set->capacity; ++i)
11722  {
11723  struct SetKey *current = set->table[i];
11724 
11725  while (current != NULL)
11726  {
11727  /* Call the callback function with the key and value */
11728  callback(current->key);
11729 
11730  /* Move to the next node in the linked list */
11731  current = current->next;
11732  }
11733  }
11734 }
11735 
11745 {
11746 
11748  return set->size;
11749 }
11750 
11760 {
11762  return set->size;
11763 }
11764 
11775 FOUNDATIONAL_LIB_FUNC int set_to_array(struct Set *set, char ***keys, size_t *size_of_keys)
11776 {
11779 
11781 
11782  const size_t alloc_size1 = FOUNDATIONAL_LIB_safe_mul(set->size, sizeof(char *));
11783  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size1 == 0))
11784  goto overflow;
11785 
11786  *keys = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size1);
11787  if (FOUNDATIONAL_LIB_UNLIKELY(*keys == NULL))
11788  goto error_handler;
11789 
11790  for (size_t i = 0, index = 0; i < set->capacity; ++i)
11791  {
11792  struct SetKey *current_pair = set->table[i];
11793  while (current_pair != NULL)
11794  {
11795  (*keys)[index] = (current_pair->key);
11796 
11797  ++index;
11798  current_pair = current_pair->next;
11799  }
11800  }
11801 
11802  *size_of_keys = set->size;
11803 
11804  return 0;
11805 
11806 overflow:
11807 error_handler:
11808 
11810  return -1;
11811 }
11812 
11823 FOUNDATIONAL_LIB_FUNC int frozen_set_to_array(struct FrozenSet *set, char ***keys, size_t *size_of_keys)
11824 {
11825 
11828 
11830 
11831  const size_t alloc_size1 = FOUNDATIONAL_LIB_safe_mul(set->size, sizeof(char *));
11832  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size1 == 0))
11833  goto overflow;
11834 
11835  *keys = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size1);
11836  if (FOUNDATIONAL_LIB_UNLIKELY(*keys == NULL))
11837  goto error_handler;
11838 
11839  for (size_t i = 0, index = 0; i < set->capacity; ++i)
11840  {
11841  struct SetKey *current_pair = set->table[i];
11842  while (current_pair != NULL)
11843  {
11844  (*keys)[index] = (current_pair->key);
11845 
11846  ++index;
11847  current_pair = current_pair->next;
11848  }
11849  }
11850 
11851  *size_of_keys = set->size;
11852 
11853  return 0;
11854 
11855 overflow:
11856 error_handler:
11857 
11859  return -1;
11860 }
11861 
11870 
11873 {
11874 
11876 
11877  /* Allocate memory for the string representation */
11878  size_t total_length = 2;
11879  for (size_t i = 0; i < set->capacity; ++i)
11880  {
11881  struct SetKey *current_key = set->table[i];
11882  while (current_key != NULL)
11883  {
11884  /* Calculate the length of the string representation for each key-value
11885  * pair */
11886  total_length += FOUNDATIONAL_LIB_STRLEN(current_key->key);
11887  total_length += 2; // 2 for ", "
11888  current_key = current_key->next;
11889  }
11890  }
11891 
11892  // Should not reach SIZE_MAX
11893 
11894  // Add 1 for the null-terminator, at least 3 chars additional
11895 
11896  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(total_length + sizeof("")); /* Safe */
11897 
11898  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
11899  {
11901  return NULL;
11902  }
11903 
11904  result[0] = '{';
11905  size_t index = 1;
11906 
11907  for (size_t i = 0; i < set->capacity; ++i)
11908  {
11909  struct SetKey *current_key = set->table[i];
11910  while (current_key != NULL)
11911  {
11912  /* Append the key and value to the string representation */
11913  index += FOUNDATIONAL_LIB_SNPRINTF(result + index, total_length - index, "%s", current_key->key);
11914  current_key = current_key->next;
11915 
11916  /* Add a separator (comma) if there are more elements */
11917  if (index < total_length - 2)
11918  {
11919  result[index++] = ',';
11920  result[index++] = ' ';
11921  }
11922  }
11923  }
11924 
11925  if (set->capacity)
11926  {
11927  index -= 2;
11928  }
11929  result[index++] = '}';
11930  result[index++] = '\0'; // Null-terminate the string
11931  return result;
11932 }
11933 
11948 {
11950 
11951  /* Allocate memory for the string representation */
11952  size_t total_length = 2;
11953  for (size_t i = 0; i < frozen_set->capacity; ++i)
11954  {
11955  struct SetKey *current_key = frozen_set->table[i];
11956  while (current_key != NULL)
11957  {
11958  /* Calculate the length of the string representation for each key-value
11959  * pair */
11960  total_length += FOUNDATIONAL_LIB_STRLEN(current_key->key);
11961  total_length += 2; // 2 for ", "
11962  current_key = current_key->next;
11963  }
11964  }
11965 
11966  // Should not reach SIZE_MAX
11967 
11968  // Add 1 for the null-terminator, at least 3 chars
11969  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(total_length + 1 /* Safe, should not reach SIZE_MAX */);
11970  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
11971  {
11973  return NULL;
11974  }
11975 
11976  result[0] = '{';
11977  size_t index = 1;
11978 
11979  for (size_t i = 0; i < frozen_set->capacity; ++i)
11980  {
11981  struct SetKey *current_key = frozen_set->table[i];
11982  while (current_key != NULL)
11983  {
11984  /* Append the key and value to the string representation */
11985  index += FOUNDATIONAL_LIB_SNPRINTF(result + index, total_length - index, "%s", current_key->key);
11986  current_key = current_key->next;
11987 
11988  /* Add a separator (comma) if there are more elements */
11989  if (index < total_length - 2)
11990  {
11991  result[index++] = ',';
11992  result[index++] = ' ';
11993  }
11994  }
11995  }
11996 
11997  if (frozen_set->capacity)
11998  {
11999  index -= 2;
12000  }
12001 
12002  result[index++] = '}';
12003  result[index++] = '\0'; // Null-terminate the string
12004 
12005  return result;
12006 }
12007 
12016 {
12019 }
12020 
12030 FOUNDATIONAL_LIB_FUNC void frozen_set_iter(struct Set *set, void (*callback)(char *key))
12031 {
12034 
12035  for (size_t i = 0; i < set->capacity; ++i)
12036  {
12037  struct SetKey *current_key = set->table[i];
12038 
12039  while (current_key != NULL)
12040  {
12041  /* Call the callback function with the key and value */
12042  callback(current_key->key);
12043 
12044  /* Move to the next node in the linked list */
12045  current_key = current_key->next;
12046  }
12047  }
12048 }
12049 
12059 FOUNDATIONAL_LIB_FUNC int is_valid_utf8(const char *str, size_t len)
12060 {
12062 
12063  size_t i = 0;
12064 
12065  while (i < len)
12066  {
12067  if ((str[i] & 0x80) == 0)
12068  {
12069  // ASCII character (0xxxxxxx)
12070  ++i;
12071  }
12072  else if ((str[i] & 0xE0) == 0xC0)
12073  {
12074  // 2-byte UTF-8 character (110xxxxx)
12075  if (i + 1 >= len || (str[i + 1] & 0xC0) != 0x80)
12076  return 0;
12077  i += 2;
12078  }
12079  else if ((str[i] & 0xF0) == 0xE0)
12080  {
12081  // 3-byte UTF-8 character (1110xxxx)
12082  if (i + 2 >= len || (str[i + 1] & 0xC0) != 0x80 || (str[i + 2] & 0xC0) != 0x80)
12083  return 0;
12084  i += 3;
12085  }
12086  else if ((str[i] & 0xF8) == 0xF0)
12087  {
12088  // 4-byte UTF-8 character (11110xxx)
12089  if (i + 3 >= len || (str[i + 1] & 0xC0) != 0x80 || (str[i + 2] & 0xC0) != 0x80 || (str[i + 3] & 0xC0) != 0x80)
12090  return 0;
12091  i += 4;
12092  }
12093  else
12094  {
12095  // Invalid UTF-8 encoding
12096  return 0;
12097  }
12098  }
12099 
12100  return 1;
12101 }
12102 
12112 FOUNDATIONAL_LIB_FUNC const char *sample_strings(const char **strings, size_t size) /* Does not dynamically allocate memory. */
12113 {
12115 
12116  long j;
12117 
12118 #ifdef _WIN32
12119  unsigned int rand_val;
12120  if (rand_s(&rand_val) != 0)
12121  {
12123  return NULL;
12124  }
12125 
12126  j = rand_val % size;
12127 #elif defined(__linux__)
12128  j = (long)(drand48() * size);
12129 #else
12130  j = rand() % size;
12131 #endif
12132 
12133  return strings[j];
12134 }
12135 
12145 FOUNDATIONAL_LIB_FUNC int shuffle_strings_in_place(char **strings, size_t size)
12146 {
12148 
12149  for (size_t i = size - 1; i; --i)
12150  {
12151  long j;
12152 #ifdef _WIN32
12153  unsigned int rand_val;
12154  if (FOUNDATIONAL_LIB_UNLIKELY(rand_s(&rand_val) != 0))
12155  {
12157  return -1;
12158  }
12159 
12160  j = rand_val % (i + 1);
12161 #elif defined(__linux__)
12162  j = (long)(drand48() * (i + 1));
12163 #else
12164  j = rand() % (i + 1);
12165 #endif
12166 
12167  // Swap strings[i] and strings[j]
12168  char *temp = strings[i];
12169  strings[i] = strings[j];
12170  strings[j] = temp;
12171  }
12172 
12173  return 0;
12174 }
12175 
12186 {
12187  const signed long long range = max - min + 1;
12188 
12189 #ifdef _WIN32
12190  unsigned int rand_val;
12191  if (rand_s(&rand_val) != 0)
12192  {
12194  return 0;
12195  }
12196 
12197  return min + (rand_val % range);
12198 #elif defined(__linux__)
12199  return min + (long)(drand48() * range);
12200 #else
12201  return min + (rand() % range);
12202 #endif
12203 }
12204 
12214 FOUNDATIONAL_LIB_FUNC unsigned long rand_number_from_range_inclusive_unsigned(unsigned long min, unsigned long max)
12215 {
12216  const unsigned long range = max - min + 1;
12217 
12218 #ifdef _WIN32
12219  unsigned int rand_val;
12220  if (rand_s(&rand_val) != 0)
12221  {
12223  return 0;
12224  }
12225 
12226  return min + (rand_val % range);
12227 #elif defined(__linux__)
12228  return min + (unsigned long)(drand48() * range);
12229 #else
12230  return min + (rand() % range);
12231 #endif
12232 }
12233 
12234 #if FOUNDATIONAL_LIB_UNSAFE_FUNCTIONS_ENABLED
12255 FOUNDATIONAL_LIB_FUNC char *backticks(const char *command, size_t *size)
12256 {
12259 
12260  FILE *pipe = FOUNDATIONAL_LIB_POPEN(command, "r");
12261  if (FOUNDATIONAL_LIB_UNLIKELY(pipe == NULL))
12262  {
12264  return NULL; // Indicate error by returning NULL
12265  }
12266 
12267  // Read the command output into the string
12268  size_t output_size = FOUNDATIONAL_LIB_POPEN_INITIAL_ALLOC_SIZE; // Initial output buffer size
12269  char *output = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(output_size);
12270  if (FOUNDATIONAL_LIB_UNLIKELY(output == NULL))
12271  {
12272  pclose(pipe); // No need to check errors here because things are already
12273  // going wrong.
12275  return NULL;
12276  }
12277 
12278  size_t total_read = 0;
12279 
12280  for (;;)
12281  {
12282  const size_t read_size = FOUNDATIONAL_LIB_FREAD(output + total_read, 1, 4096, pipe);
12283 
12284  if (FOUNDATIONAL_LIB_UNLIKELY(read_size == 0))
12285  {
12286  const int error_code = FOUNDATIONAL_LIB_FERROR(pipe);
12287  if (FOUNDATIONAL_LIB_UNLIKELY(error_code))
12288  {
12290  pclose(pipe); // No need to check errors here because things are already
12291  // going wrong.
12293  return NULL;
12294  }
12295  else
12296  {
12297  break;
12298  }
12299  }
12300  else if (total_read + read_size + 1 > output_size)
12301  {
12302  const size_t new_realloc_length = FOUNDATIONAL_LIB_safe_add_3(total_read, read_size, 1);
12303 
12304  if (FOUNDATIONAL_LIB_UNLIKELY(new_realloc_length == 0))
12305  {
12308  return NULL;
12309  }
12310  // Expand the buffer
12311  output_size = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(new_realloc_length);
12312 
12313  if (FOUNDATIONAL_LIB_UNLIKELY(output_size == 0)) // Overflow.
12314  {
12316  return NULL;
12317  }
12318  char *new_output = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(output, output_size);
12319 
12320  if (FOUNDATIONAL_LIB_UNLIKELY(new_output == NULL))
12321  {
12323  pclose(pipe); // No need to check errors here because things are already
12324  // going wrong.
12326  return NULL;
12327  }
12328 
12329  output = new_output;
12330  }
12331  total_read += read_size;
12332  }
12333 
12334  if (FOUNDATIONAL_LIB_UNLIKELY(ferror(pipe) != 0))
12335  {
12337 
12338  pclose(pipe); // No need to re check for errors because things are going wrong.
12339 
12341 
12342  return NULL; // Error reading from pipe
12343  }
12344 
12345  // Null-terminate the string
12346  output[total_read] = '\0';
12347 
12348  *size = total_read;
12349 
12350  // Close the pipe
12351  if (FOUNDATIONAL_LIB_UNLIKELY(pclose(pipe) != 0)) // Check for errors.
12352  {
12355  return NULL;
12356  }
12357 
12358  return output;
12359 }
12360 
12361 #endif
12362 
12383 FOUNDATIONAL_LIB_FUNC char **read_file_into_array(const char *filename, const char *delim, size_t *num_lines)
12384 {
12388 
12389  size_t size_of_file;
12390 
12391  *num_lines = 0;
12392 
12393  /*
12394  * This approach uses very few system calls and is rather efficient.
12395  * It first gets the entire file into memory, then splits it.
12396  * There would be very few fread() calls, and it can predict the buffer
12397  * size ahead of time, for low memory usage.
12398  *
12399  * One issue with this is that it has to allocate memory twice -
12400  * first for read_file_into_array - second for the new array,
12401  * after which the first array is freed(). So that means for
12402  * a time, the computer needs around 2x the memory.
12403  * However, if you are concerned about memory usage, probably
12404  * better might be read_file_into_string() with strtok() used
12405  * to extract the parts you want, or manual code withFOUNDATIONAL_LIB_FREAD().
12406  *
12407  * Any which way, this implementation is decent and efficient
12408  * for many purposes.
12409  */
12410  const char *file = read_file_into_string(filename, &size_of_file);
12411  if (FOUNDATIONAL_LIB_UNLIKELY(file == NULL))
12412  {
12413  /* read_file_into_string() would already call die_aggressively_if_enabled */
12414 
12415  return NULL;
12416  }
12417 
12418  char **lines = split(file, num_lines, delim, 0, 1);
12419 
12421  if (FOUNDATIONAL_LIB_UNLIKELY(lines == NULL))
12422  {
12423  /* split() would already call die_aggressively_if_enabled */
12424 
12425  return NULL;
12426  }
12427 
12428  return lines;
12429 }
12430 
12436 FOUNDATIONAL_LIB_FUNC void print_char(const char value) { FOUNDATIONAL_LIB_PRINTF("%c", value); }
12437 
12444 FOUNDATIONAL_LIB_FUNC void print_char_to_stream(const char value, FILE *stream)
12445 {
12447  FOUNDATIONAL_LIB_FPRINTF(stream, "%c", value);
12448 }
12449 
12455 FOUNDATIONAL_LIB_FUNC void print_double(const double value) { FOUNDATIONAL_LIB_PRINTF("%f", value); }
12456 
12463 FOUNDATIONAL_LIB_FUNC void print_double_to_stream(const double value, FILE *stream)
12464 {
12466  FOUNDATIONAL_LIB_FPRINTF(stream, "%f", value);
12467 }
12468 
12474 FOUNDATIONAL_LIB_FUNC void print_float(const float value) { FOUNDATIONAL_LIB_PRINTF("%f", value); }
12475 
12482 FOUNDATIONAL_LIB_FUNC void print_float_to_stream(const float value, FILE *stream)
12483 {
12485  FOUNDATIONAL_LIB_FPRINTF(stream, "%f", value);
12486 }
12487 
12493 FOUNDATIONAL_LIB_FUNC void print_int(const int value) { FOUNDATIONAL_LIB_PRINTF("%d", value); }
12494 
12501 FOUNDATIONAL_LIB_FUNC void print_int_to_stream(const int value, FILE *stream)
12502 {
12504  FOUNDATIONAL_LIB_FPRINTF(stream, "%d", value);
12505 }
12506 
12512 FOUNDATIONAL_LIB_FUNC void print_long(const long value) { FOUNDATIONAL_LIB_PRINTF("%ld", value); }
12513 
12520 FOUNDATIONAL_LIB_FUNC void print_long_to_stream(const long value, FILE *stream)
12521 {
12523  FOUNDATIONAL_LIB_FPRINTF(stream, "%ld", value);
12524 }
12525 
12531 FOUNDATIONAL_LIB_FUNC void print_long_long(const long long value) { FOUNDATIONAL_LIB_PRINTF("%lld", value); }
12532 
12539 FOUNDATIONAL_LIB_FUNC void print_long_long_to_stream(const long long value, FILE *stream)
12540 {
12542 
12543 #pragma GCC diagnostic push
12544 #pragma GCC diagnostic ignored "-Wpragmas"
12545 #pragma GCC diagnostic ignored "-Wformat"
12546 #pragma GCC diagnostic ignored "-Wformat-extra-args"
12547 
12548  FOUNDATIONAL_LIB_FPRINTF(stream, "%lld", value);
12549 #pragma GCC diagnostic pop
12550 }
12551 
12557 FOUNDATIONAL_LIB_FUNC void print_short(const short value) { FOUNDATIONAL_LIB_PRINTF("%hd", value); }
12558 
12565 FOUNDATIONAL_LIB_FUNC void print_short_to_stream(const short value, FILE *stream)
12566 {
12568  FOUNDATIONAL_LIB_FPRINTF(stream, "%hd", value);
12569 }
12575 FOUNDATIONAL_LIB_FUNC void print_size_t(const size_t value) { FOUNDATIONAL_LIB_PRINTF("%zu", value); }
12576 
12583 FOUNDATIONAL_LIB_FUNC void print_size_t_to_stream(const size_t value, FILE *stream)
12584 {
12586 
12587 #pragma GCC diagnostic push
12588 #pragma GCC diagnostic ignored "-Wpragmas"
12589 #pragma GCC diagnostic ignored "-Wformat"
12590 #pragma GCC diagnostic ignored "-Wformat-extra-args"
12591  FOUNDATIONAL_LIB_FPRINTF(stream, "%zu", value);
12592 #pragma GCC diagnostic pop
12593 }
12594 
12601 {
12603  FOUNDATIONAL_LIB_PRINTF("%s", value);
12604 }
12605 
12612 FOUNDATIONAL_LIB_FUNC void print_string_to_stream(char *value, FILE *stream)
12613 {
12616 
12617  FOUNDATIONAL_LIB_FPRINTF(stream, "%s", value);
12618 }
12619 
12625 FOUNDATIONAL_LIB_FUNC void print_uchar(const unsigned char value) { FOUNDATIONAL_LIB_PRINTF("%c", value); }
12626 
12633 FOUNDATIONAL_LIB_FUNC void print_uchar_to_stream(const unsigned char value, FILE *stream)
12634 {
12636  FOUNDATIONAL_LIB_FPRINTF(stream, "%c", value);
12637 }
12638 
12644 FOUNDATIONAL_LIB_FUNC void print_uint(const unsigned int value) { FOUNDATIONAL_LIB_PRINTF("%u", value); }
12645 
12652 FOUNDATIONAL_LIB_FUNC void print_uint_to_stream(const unsigned int value, FILE *stream)
12653 {
12655  FOUNDATIONAL_LIB_FPRINTF(stream, "%u", value);
12656 }
12662 FOUNDATIONAL_LIB_FUNC void print_ulong(const unsigned long value) { FOUNDATIONAL_LIB_PRINTF("%lu", value); }
12663 
12670 FOUNDATIONAL_LIB_FUNC void print_ulong_to_stream(const unsigned long value, FILE *stream)
12671 {
12673  FOUNDATIONAL_LIB_FPRINTF(stream, "%lu", value);
12674 }
12675 
12681 FOUNDATIONAL_LIB_FUNC void print_ulong_long(const unsigned long long value)
12682 {
12683 
12684 #pragma GCC diagnostic push
12685 #pragma GCC diagnostic ignored "-Wpragmas"
12686 #pragma GCC diagnostic ignored "-Wformat"
12687 #pragma GCC diagnostic ignored "-Wformat-extra-args"
12688  FOUNDATIONAL_LIB_PRINTF("%llu", value);
12689 #pragma GCC diagnostic pop
12690 }
12691 
12698 FOUNDATIONAL_LIB_FUNC void print_ulong_long_to_stream(const unsigned long long value, FILE *stream)
12699 {
12701 #pragma GCC diagnostic push
12702 #pragma GCC diagnostic ignored "-Wpragmas"
12703 #pragma GCC diagnostic ignored "-Wformat"
12704 #pragma GCC diagnostic ignored "-Wformat-extra-args"
12705  FOUNDATIONAL_LIB_FPRINTF(stream, "%llu", value);
12706 #pragma GCC diagnostic pop
12707 }
12713 FOUNDATIONAL_LIB_FUNC void print_ushort(const unsigned short value) { FOUNDATIONAL_LIB_PRINTF("%hu", value); }
12714 
12721 FOUNDATIONAL_LIB_FUNC void print_ushort_to_stream(const unsigned short value, FILE *stream)
12722 {
12723 
12725  FOUNDATIONAL_LIB_FPRINTF(stream, "%hu", value);
12726 }
12727 
12740 FOUNDATIONAL_LIB_FUNC size_t count_occurrences_of_string_in_array(const char **array, const char *string, size_t array_length)
12741 {
12743 
12745 
12746  size_t count = 0;
12747 
12748  // Iterate through the array
12749  for (size_t i = 0; i < array_length; ++i)
12750  {
12751  // Compare each string in the array with the target string
12752  if (FOUNDATIONAL_LIB_STRCMP(array[i], string) == 0)
12753  {
12754  ++count;
12755  }
12756  }
12757 
12758  return count;
12759 }
12760 
12774 FOUNDATIONAL_LIB_FUNC size_t count_occurrences_of_adjacent_data_in_array(const void *array_of_adjacent_values, size_t array_length, const void *memory, size_t memory_length)
12775 {
12776 
12777  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(array_of_adjacent_values);
12779  size_t count = 0;
12780 
12781  // Iterate through the array
12782  for (size_t i = 0; i < array_length; ++i)
12783  {
12784  // Dereferences each pointer in the array and compare memory_length bytes.
12785  if (FOUNDATIONAL_LIB_MEMCMP(array_of_adjacent_values, memory, memory_length) == 0)
12786  {
12787  count++;
12788  }
12789  }
12790 
12791  return count;
12792 }
12793 
12807 FOUNDATIONAL_LIB_FUNC size_t count_occurrences_of_data_in_array(const void **array_of_pointers, size_t array_length, const void *memory, size_t memory_length)
12808 {
12809 
12812 
12813  size_t count = 0;
12814 
12815  // Iterate through the array
12816  for (size_t i = 0; i < array_length; ++i)
12817  {
12818  // Dereferences each pointer in the array and compare memory_length bytes.
12819  if (FOUNDATIONAL_LIB_MEMCMP(array_of_pointers[i], memory, memory_length) == 0)
12820  {
12821  count++;
12822  }
12823  }
12824 
12825  return count;
12826 }
12827 
12828 #if FOUNDATIONAL_LIB_NETWORK_FUNCTIONS_ENABLED
12829 
12830 /* Chrome by default */
12831 
12832 #define FOUNDATIONAL_LIB_DEFAULT_USER_AGENT "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
12833 
12834 #include <curl/curl.h>
12835 
12836 /* Write callback */
12837 FOUNDATIONAL_LIB_FUNC size_t FOUNDATIONAL_LIB_libcurl_write_callback(char *data, size_t n, size_t l, void *userp)
12838 {
12839 
12841 
12843  struct StringData
12844  {
12845  char *string;
12846 
12847  size_t size;
12848  size_t alloc_size;
12849 
12850  size_t byte_max_cutoff;
12851  } *string = userp;
12852 
12853  const size_t both = n * l;
12854  append_string_to_string(&string->string, &string->size, &string->alloc_size, data, both);
12855 
12856  if (string->byte_max_cutoff != 0 && string->size >= string->byte_max_cutoff)
12857  {
12858  /* Curl can read in big blocks, like 9,370 bytes. So if the cutoff is low,
12859  * the read size still might be high. */
12860  /* FOUNDATIONAL_LIB_PRINTF("%zu.size >= %zu.byte_max_cutoff\n", string->size,
12861  string->byte_max_cutoff); */
12862  return CURLE_OK;
12863  }
12864  return both;
12865 }
12866 
12904 FOUNDATIONAL_LIB_FUNC int download_website(const char *website, char **string, size_t *size, size_t *str_alloc_size, size_t byte_max_cutoff, const char *user_agent)
12905 {
12906 
12911 
12912  CURL *curl = curl_easy_init();
12913  if (FOUNDATIONAL_LIB_UNLIKELY(curl == NULL))
12914  {
12915  return -1;
12916  }
12917 
12918  if (user_agent == NULL)
12919  {
12920  user_agent = FOUNDATIONAL_LIB_DEFAULT_USER_AGENT;
12921  }
12922 
12923  curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 102400L);
12924  curl_easy_setopt(curl, CURLOPT_URL, website);
12925  curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
12926  curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent);
12927  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
12928  curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L);
12929  curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
12930  curl_easy_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, 1L);
12931  curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
12932  struct StringData
12933  {
12934  char *string;
12935  size_t size;
12936  size_t alloc_size;
12937  size_t byte_max_cutoff;
12938  } data;
12939  data.string = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(FOUNDATIONAL_LIB_INITIAL_NETWORK_DOWNLOAD_BUFFER_SIZE);
12940  data.alloc_size = FOUNDATIONAL_LIB_INITIAL_NETWORK_DOWNLOAD_BUFFER_SIZE;
12941  data.size = 0;
12942  data.byte_max_cutoff = byte_max_cutoff;
12943 
12944  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, FOUNDATIONAL_LIB_libcurl_write_callback);
12945  curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
12946  CURLcode curlcode = curl_easy_perform(curl);
12947 
12948  curl_easy_cleanup(curl);
12949 
12950  *string = data.string;
12951  *size = data.size;
12952  *str_alloc_size = data.alloc_size;
12953 
12954  return curlcode == CURLE_OK;
12955 }
12956 
12977 FOUNDATIONAL_LIB_FUNC int download_websites(const char **websites_to_download, size_t num_websites, char ***outputs, size_t **lens, size_t byte_limit, int aggressive_stop_on_error)
12978 {
12979 
12980  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(websites_to_download);
12983  // Initalize all to NULL in case a site can't download
12984  *outputs = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(num_websites, sizeof(char *));
12985 
12986  // Initalize all to 0 in case a site can't download
12987  *lens = (size_t *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(num_websites, sizeof(size_t));
12988 
12989  for (size_t i = 0; i < num_websites; ++i)
12990  {
12991  size_t alloc_size;
12992  if (download_website(websites_to_download[i], (*outputs) + i, (*lens) + i, &alloc_size, byte_limit, NULL) == -1)
12993  {
12994  if (aggressive_stop_on_error)
12995  {
12997  return -1;
12998  }
12999  }
13000  }
13001 
13002  return 0;
13003 }
13004 
13005 #endif /* Networking. */
13006 
13036 FOUNDATIONAL_LIB_FUNC int read_files_into_array(const char **files_to_open, size_t num_files, char ***outputs, size_t **lens, int aggressive_stop_on_error)
13037 {
13041  // Initalize all to NULL in case a site can't download
13042  *outputs = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(num_files, sizeof(char *));
13043 
13044  // Initalize all to 0 in case a site can't download
13045  *lens = (size_t *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(num_files, sizeof(size_t));
13046 
13047  for (size_t i = 0; i < num_files; ++i)
13048  {
13049  size_t size;
13050 
13051  (*outputs)[i] = read_file_into_string(files_to_open[i], &size);
13052  (*lens)[i] = size;
13053 
13054  if ((*outputs)[i] == NULL)
13055  {
13056  if (aggressive_stop_on_error)
13057  {
13059  return -1;
13060  }
13061  }
13062  }
13063 
13064  return 0;
13065 }
13066 
13067 #pragma GCC diagnostic pop /* Niche Wformat issues */
13068 
13069 #endif
FOUNDATIONAL_LIB_FUNC int is_string_printable(const char *string)
Check if all characters in a string are printable.
Definition: foundationallib.h:9464
FOUNDATIONAL_LIB_FUNC void sort_long_long_ptrs(long long **long_long_ptrs, size_t size)
Sorts an array of pointers to long longs in ascending order.
Definition: foundationallib.h:6525
FOUNDATIONAL_LIB_FUNC int is_string_valid_integer(const char *str)
Checks if a string is a valid integer.
Definition: foundationallib.h:4889
FOUNDATIONAL_LIB_FUNC size_t frozen_dict_size(struct FrozenDict *dict)
Returns the number of key-value pairs in the frozen dictionary.
Definition: foundationallib.h:10862
FOUNDATIONAL_LIB_FUNC void print_ushort_array(const unsigned short *array, size_t size)
Prints the contents of an array of unsigned short integers.
Definition: foundationallib.h:1291
FOUNDATIONAL_LIB_FUNC int shuffle_strings_in_place(char **strings, size_t size)
Shuffles an array of strings in place.
Definition: foundationallib.h:12145
FOUNDATIONAL_LIB_FUNC unsigned int ** sorted_uint_ptrs(unsigned int **uint_ptrs, size_t size)
Definition: foundationallib.h:5408
FOUNDATIONAL_LIB_FUNC size_t frozen_dict_to_array(struct FrozenDict *dict, char ***keys, void ***values, size_t *size_of_keys_and_values)
Converts the key-value pairs from the frozen dictionary into separate arrays for keys and values.
Definition: foundationallib.h:10967
FOUNDATIONAL_LIB_FUNC void print_ulong_long_array(const unsigned long long *array, size_t size)
Prints the elements of an unsigned long long array.
Definition: foundationallib.h:1543
FOUNDATIONAL_LIB_FUNC unsigned long long * sorted_ulong_longs(unsigned long long *ulong_longs, size_t size)
Creates a new array containing sorted unsigned long longs.
Definition: foundationallib.h:6359
FOUNDATIONAL_LIB_FUNC unsigned char * sorted_uchars(unsigned char *uchars, size_t size)
Creates a new array containing sorted unsigned chars.
Definition: foundationallib.h:5597
static int equal_array_of_long_longs(const long long *array, const long long *array2, size_t size)
Checks if two arrays of long long integers are equal.
Definition: foundationallib.h:3057
#define FOUNDATIONAL_LIB_STRCHR
Definition: foundationallib.h:341
FOUNDATIONAL_LIB_FUNC void print_string_array(char **array, size_t size)
Prints an array of strings.
Definition: foundationallib.h:1236
#define FOUNDATIONAL_LIB_FUNC
Definition: foundationallib.h:828
FOUNDATIONAL_LIB_FUNC char * replace_all(const char *source, const char *find, const char *replace)
Replaces all occurrences of a specified substring in a given string.
Definition: foundationallib.h:7989
FOUNDATIONAL_LIB_FUNC int string_to_int(const char *str)
Converts a string to an integer.
Definition: foundationallib.h:6941
static void dict_del_keys(char **keys)
Deallocates memory associated with an array of keys.
Definition: foundationallib.h:11032
FOUNDATIONAL_LIB_FUNC unsigned long * sorted_ulongs(unsigned long *ulongs, size_t size)
Creates a new array containing sorted unsigned longs.
Definition: foundationallib.h:6100
FOUNDATIONAL_LIB_FUNC void print_float_ptr_array_to_stream(const float **array, size_t size, FILE *stream)
Outputs elements of an array of pointers to float to a stream.
Definition: foundationallib.h:2402
FOUNDATIONAL_LIB_FUNC int remove_file(const char *filename)
Removes a file.
Definition: foundationallib.h:7347
FOUNDATIONAL_LIB_FUNC void print_uint_array_to_stream(const unsigned int *array, size_t size, FILE *stream)
Prints the elements of an unsigned int array to a specified stream.
Definition: foundationallib.h:1830
FOUNDATIONAL_LIB_FUNC void print_ulong_array(const unsigned long *array, size_t size)
Prints the contents of an array of unsigned long integers.
Definition: foundationallib.h:1419
FOUNDATIONAL_LIB_FUNC char ** split(const char *str, size_t *output_size, const char *delim, size_t max_times, int keep_delim_in_result)
Splits a given string into an array based on a specified delimiter.
Definition: foundationallib.h:3416
FOUNDATIONAL_LIB_FUNC char * replace_first(const char *source, const char *find, const char *replace)
Replaces the first occurrence of a specified substring in a given string.
Definition: foundationallib.h:8035
FOUNDATIONAL_LIB_FUNC void sort_ushort_ptrs(unsigned short **ushort_ptrs, size_t size)
Sorts an array of pointers to unsigned shorts in ascending order.
Definition: foundationallib.h:5892
FOUNDATIONAL_LIB_FUNC unsigned char ** sorted_uchar_ptrs(unsigned char **uchar_ptrs, size_t size)
Creates a new array containing sorted pointers to unsigned chars.
Definition: foundationallib.h:5662
FOUNDATIONAL_LIB_FUNC void print_long_long_ptr_array(const long long **array, size_t size)
Prints the elements of a long long array through a pointer.
Definition: foundationallib.h:1635
FOUNDATIONAL_LIB_FUNC int append_string_to_array(char ***array, size_t *array_size, size_t *array_current_alloc_size, const char *string)
Appends a new string element to the end of a dynamically allocated array of strings and updates its s...
Definition: foundationallib.h:3864
static size_t FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(size_t siz)
Definition: foundationallib.h:668
FOUNDATIONAL_LIB_FUNC void sort_uints(unsigned int *uints, size_t size)
Definition: foundationallib.h:5326
FOUNDATIONAL_LIB_FUNC size_t * generate_range(size_t start, size_t end, size_t step, size_t *range_size)
Generates a range of integers.
Definition: foundationallib.h:5196
FOUNDATIONAL_LIB_FUNC void sort_ulong_ptrs(unsigned long **ulong_ptrs, size_t size)
Sorts an array of pointers to unsigned longs in ascending order.
Definition: foundationallib.h:6146
FOUNDATIONAL_LIB_FUNC size_t dict_size(struct Dict *dict)
Returns the number of key-value pairs in the dictionary.
Definition: foundationallib.h:10845
static ssize_t last_index_of_char(const char *str, char chr)
Finds the index of the last occurrence of a specified character in a given string.
Definition: foundationallib.h:4559
FOUNDATIONAL_LIB_FUNC int is_array_lower(const char **array, size_t size)
Checks if a string array contains only lowercase characters.
Definition: foundationallib.h:9567
static int equal_array_of_chars(const char *array, const char *array2, size_t size)
Checks if two arrays of characters are equal.
Definition: foundationallib.h:2750
FOUNDATIONAL_LIB_FUNC char * string_to_lowercase(char *string)
Convert a string to lowercase.
Definition: foundationallib.h:9256
FOUNDATIONAL_LIB_FUNC size_t common_prefix_length(const char *str1, const char *str2)
Finds the length of the common prefix of two strings.
Definition: foundationallib.h:4932
#define FOUNDATIONAL_LIB_LIKELY(x)
Definition: foundationallib.h:423
FOUNDATIONAL_LIB_FUNC void print_ulong_long(const unsigned long long value)
Prints an unsigned long long value to the standard output.
Definition: foundationallib.h:12681
FOUNDATIONAL_LIB_FUNC void * select_array(const void *source, size_t source_size, size_t elem_size, int(*condition)(const void *), size_t *result_size)
Definition: foundationallib.h:9141
FOUNDATIONAL_LIB_FUNC void sort_doubles(double *doubles, size_t size)
Sorts an array of doubles in ascending order.
Definition: foundationallib.h:6710
FOUNDATIONAL_LIB_FUNC char * replace_count(const char *source, const char *find, const char *replace, const size_t matches_max)
Replaces the first N occurrences of a specified substring in a given string.
Definition: foundationallib.h:8081
FOUNDATIONAL_LIB_FUNC void * replicate(const void *source, size_t source_size, size_t elem_size, size_t repetitions)
Definition: foundationallib.h:9203
FOUNDATIONAL_LIB_FUNC char * dict_to_string(struct Dict *dict, int pointer_or_string)
Converts a dictionary to a string representation.
Definition: foundationallib.h:11073
FOUNDATIONAL_LIB_FUNC void print_ulong_to_stream(const unsigned long value, FILE *stream)
Prints an unsigned long value to the specified stream.
Definition: foundationallib.h:12670
FOUNDATIONAL_LIB_FUNC void print_size_t_array(const size_t *array, size_t size)
Prints the elements of a size_t array.
Definition: foundationallib.h:1767
#define FOUNDATIONAL_LIB_VA_LIST
Definition: foundationallib.h:122
#define FOUNDATIONAL_LIB_FCLOSE
Definition: foundationallib.h:764
FOUNDATIONAL_LIB_FUNC void * list_comprehension(const void *input_array, size_t array_size, size_t elem_size, void(*transform_func)(void *value), int(*filter_func)(void *value), size_t *result_size)
Perform a list comprehension operation.
Definition: foundationallib.h:8667
FOUNDATIONAL_LIB_FUNC int dict_add(struct Dict *dict, const char *key, void *value)
Adds a key-value pair to the dictionary.
Definition: foundationallib.h:10484
FOUNDATIONAL_LIB_FUNC char * reverse_string(const char *str)
Reverses a given string.
Definition: foundationallib.h:4251
FOUNDATIONAL_LIB_FUNC void print_int(const int value)
Prints an integer value to the standard output.
Definition: foundationallib.h:12493
FOUNDATIONAL_LIB_FUNC void print_char_array_to_stream(const char *array, size_t size, FILE *stream)
Prints the elements of a char array to a specified stream.
Definition: foundationallib.h:1960
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_double_ptrs(const void *a, const void *b)
Compare function for sorting pointers to doubles.
Definition: foundationallib.h:6752
static int equal_array_of_uints(const unsigned int *array, const unsigned int *array2, size_t size)
Checks if two arrays of unsigned integers are equal.
Definition: foundationallib.h:2602
FOUNDATIONAL_LIB_FUNC void frozen_dict_iter(struct FrozenDict *frozen_dict, void(*callback)(char *key, void *value))
Iterates through the key-value pairs in the FrozenDict, applying a callback function.
Definition: foundationallib.h:10817
FOUNDATIONAL_LIB_FUNC int is_valid_utf8(const char *str, size_t len)
Checks if a string is a valid UTF-8 sequence.
Definition: foundationallib.h:12059
FOUNDATIONAL_LIB_FUNC int replace_all_with_lens(const char *source, size_t source_len, const char *find, size_t find_len, const char *replace, size_t replace_len, char **output, size_t *new_len, int *should_free_after_use, size_t matches_max, size_t *num_matches)
Performs string replacement with specified lengths.
Definition: foundationallib.h:7969
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_int_ptrs(const void *a, const void *b)
Definition: foundationallib.h:5500
FOUNDATIONAL_LIB_FUNC void * arraydup(const void *array, size_t num_mem, size_t size)
Duplicates an array of elements at a shallow level.
Definition: foundationallib.h:2548
FOUNDATIONAL_LIB_FUNC void print_ulong_long_ptr_array(const unsigned long long **array, size_t size)
Prints the elements of an unsigned long long array through a pointer.
Definition: foundationallib.h:1574
FOUNDATIONAL_LIB_FUNC char * concatenate_three_strings(const char *str1, const char *str2, const char *str3)
Concatenates three strings into a new dynamically allocated array.
Definition: foundationallib.h:9778
static int equal_array_of_ulong_long_ptrs(const unsigned long long **array, const unsigned long long **array2, size_t size)
Checks if two arrays of pointers to unsigned long long integers are equal.
Definition: foundationallib.h:3032
#define FOUNDATIONAL_LIB_INITIAL_STRING_ARRAY_ALLOC_COUNT
Definition: foundationallib.h:411
FOUNDATIONAL_LIB_FUNC void print_uchar_to_stream(const unsigned char value, FILE *stream)
Prints an unsigned char value to the specified stream.
Definition: foundationallib.h:12633
FOUNDATIONAL_LIB_FUNC short ** sorted_short_ptrs(short **short_ptrs, size_t size)
Creates a new array containing sorted pointers to shorts.
Definition: foundationallib.h:6038
FOUNDATIONAL_LIB_FUNC void print_ulong_long_array_to_stream(const unsigned long long *array, size_t size, FILE *stream)
Prints the elements of an unsigned long long array to a specified stream.
Definition: foundationallib.h:2250
FOUNDATIONAL_LIB_FUNC void print_float(const float value)
Prints a single-precision floating-point value to the standard output.
Definition: foundationallib.h:12474
#define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE
Definition: foundationallib.h:782
FOUNDATIONAL_LIB_FUNC char * replace_all_with_callback(const char *str, const char *old_substring, char *(*callback)(const char *, void *), void *data_for_callback)
Replaces all occurrences of a substring in a string using a callback function.
Definition: foundationallib.h:8129
#define FOUNDATIONAL_LIB_HASH_LOAD_FACTOR_THRESHOLD
Load factor threshold for hash tables in the foundational library.
Definition: foundationallib.h:820
#define FOUNDATIONAL_LIB_ISPRINT
Definition: foundationallib.h:365
FOUNDATIONAL_LIB_FUNC int frozen_set_to_array(struct FrozenSet *set, char ***keys, size_t *size_of_keys)
Converts a FrozenSet to an array of keys.
Definition: foundationallib.h:11823
FOUNDATIONAL_LIB_FUNC size_t count_occurrences_of_substr_len(const char *string, size_t string_length, const char *substring, size_t substring_length)
Counts the occurrences of a specified substring within a given string.
Definition: foundationallib.h:4476
FOUNDATIONAL_LIB_FUNC void print_uint(const unsigned int value)
Prints an unsigned int value to the standard output.
Definition: foundationallib.h:12644
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ints(const void *a, const void *b)
Definition: foundationallib.h:5435
FOUNDATIONAL_LIB_FUNC void sort_longs(long *longs, size_t size)
Sorts an array of pointers to unsigned longs in ascending order.
Definition: foundationallib.h:6214
FOUNDATIONAL_LIB_FUNC void print_ulong(const unsigned long value)
Prints an unsigned long value to the standard output.
Definition: foundationallib.h:12662
FOUNDATIONAL_LIB_FUNC size_t common_suffix_length(const char *str1, const char *str2)
Finds the length of the common suffix of two strings.
Definition: foundationallib.h:4962
FOUNDATIONAL_LIB_FUNC void print_char_to_stream(const char value, FILE *stream)
Prints a character value to the specified stream.
Definition: foundationallib.h:12444
static void frozen_dict_del_keys(char **keys)
Deletes keys from a frozen dictionary.
Definition: foundationallib.h:11256
FOUNDATIONAL_LIB_FUNC unsigned long ** sorted_ulong_ptrs(unsigned long **ulong_ptrs, size_t size)
Creates a new array containing sorted pointers to unsigned longs.
Definition: foundationallib.h:6168
FOUNDATIONAL_LIB_FUNC int is_string_digit(const char *string)
Check if all characters in a string are digits.
Definition: foundationallib.h:9405
static int equal_array_of_ints(const int *array, const int *array2, size_t size)
Checks if two arrays of integers are equal.
Definition: foundationallib.h:2651
FOUNDATIONAL_LIB_FUNC void sort_ulong_longs(unsigned long long *ulong_longs, size_t size)
Sorts an array of unsigned long longs in ascending order.
Definition: foundationallib.h:6339
FOUNDATIONAL_LIB_FUNC void print_size_t_ptr_array_to_stream(const size_t **array, size_t size, FILE *stream)
Outputs elements of an array of pointers to size_t to a stream.
Definition: foundationallib.h:2514
FOUNDATIONAL_LIB_FUNC void reverse_int_array_in_place(int *array, size_t size)
Reverses an array of integers in place.
Definition: foundationallib.h:5125
FOUNDATIONAL_LIB_FUNC int sum_of_int_array(const int *array, size_t size)
Calculates the sum of elements in an array of integers.
Definition: foundationallib.h:5104
FOUNDATIONAL_LIB_FUNC int dict_reserve_more(struct Dict *dict, size_t number_of_new_elements_max_one_is_expecting)
Reserves additional space in a Dictionary for anticipated new elements.
Definition: foundationallib.h:10324
FOUNDATIONAL_LIB_FUNC void sort_int_ptrs(int **int_ptrs, size_t size)
Definition: foundationallib.h:5517
static int equal_array_of_ulong_longs(const unsigned long long *array, const unsigned long long *array2, size_t size)
Checks if two arrays of unsigned long long integers are equal.
Definition: foundationallib.h:3004
#define FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(x)
Definition: foundationallib.h:435
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_long_longs(const void *a, const void *b)
Compare function for sorting long longs.
Definition: foundationallib.h:6450
FOUNDATIONAL_LIB_FUNC unsigned short * sorted_ushorts(unsigned short *ushorts, size_t size)
Creates a new array containing sorted unsigned shorts.
Definition: foundationallib.h:5845
static ssize_t index_of_char(const char *str, char chr)
Finds the index of the first occurrence of a specified character in a string.
Definition: foundationallib.h:4537
#define FOUNDATIONAL_LIB_MEMMOVE
Definition: foundationallib.h:321
static int equal_array_of_shorts(const short *array, const short *array2, size_t size)
Checks if two arrays of short integers are equal.
Definition: foundationallib.h:2852
FOUNDATIONAL_LIB_FUNC int is_string_numeric(const char *str)
Checks if the provided string consists solely of numeric characters.
Definition: foundationallib.h:4577
FOUNDATIONAL_LIB_FUNC unsigned int * sorted_uints(unsigned int *uints, size_t size)
Definition: foundationallib.h:5345
#define FOUNDATIONAL_LIB_safe_increment(variable, label_if_fails)
Definition: foundationallib.h:622
FOUNDATIONAL_LIB_FUNC void sort_ulong_long_ptrs(unsigned long long **ulong_long_ptrs, size_t size)
Sorts an array of pointers to unsigned long longs in ascending order.
Definition: foundationallib.h:6404
#define FOUNDATIONAL_LIB_ISUPPER
Definition: foundationallib.h:368
FOUNDATIONAL_LIB_FUNC void map(void *array, size_t size, size_t elem_size, void(*transform)(void *))
Applies a transformation to each element of an array (void* version).
Definition: foundationallib.h:8442
static int equal_array_of_int_ptrs(const int **array, const int **array2, size_t size)
Checks if two arrays of pointers to integers are equal.
Definition: foundationallib.h:2676
FOUNDATIONAL_LIB_FUNC double * sorted_doubles(double *doubles, size_t size)
Creates a new array containing sorted doubles.
Definition: foundationallib.h:6729
#define FOUNDATIONAL_LIB_AGGRESSIVE_DIE_TYPE
Type of the aggressive die variable.
Definition: foundationallib.h:55
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_uints(const void *a, const void *b)
Definition: foundationallib.h:5309
#define FOUNDATIONAL_LIB_POPEN_INITIAL_ALLOC_SIZE
Definition: foundationallib.h:706
static int equal_array_of_uchar_ptrs(const unsigned char **array, const unsigned char **array2, size_t size)
Checks if two arrays of pointers to unsigned characters are equal.
Definition: foundationallib.h:2726
FOUNDATIONAL_LIB_FUNC void sort_size_t_ptrs(size_t **size_t_ptrs, size_t size)
Sorts an array of pointers to size_t values in ascending order.
Definition: foundationallib.h:6894
FOUNDATIONAL_LIB_FUNC void utoa(size_t unsigned_value, char *output)
Definition: foundationallib.h:1045
static int equal_array_of_ushorts(const unsigned short *array, const unsigned short *array2, size_t size)
Checks if two arrays of unsigned short integers are equal.
Definition: foundationallib.h:2800
FOUNDATIONAL_LIB_FUNC void sort_double_ptrs(double **double_ptrs, size_t size)
Sorts an array of pointers to doubles in ascending order.
Definition: foundationallib.h:6769
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_long_long_ptrs(const void *a, const void *b)
Compare function for sorting pointers to long longs.
Definition: foundationallib.h:6508
FOUNDATIONAL_LIB_AGGRESSIVE_DIE_TYPE FOUNDATIONAL_LIB_aggressive_die
Global variable to control aggressive die behavior.
Definition: foundationallib.h:854
#define FOUNDATIONAL_LIB_VA_ARG
Definition: foundationallib.h:130
FOUNDATIONAL_LIB_FUNC void dict_del_key(struct Dict *dict, const char *key)
Deletes a key-value pair from the dictionary based on the provided key.
Definition: foundationallib.h:10432
#define FOUNDATIONAL_LIB_INITIAL_STRING_ARRAY_ALLOC_SIZE
Definition: foundationallib.h:416
FOUNDATIONAL_LIB_FUNC int file_is_executable(const char *filename)
Checks if a file is executable.
Definition: foundationallib.h:7274
FOUNDATIONAL_LIB_FUNC void print_string_array_array(char ***array, size_t size)
Prints an array of arrays of strings.
Definition: foundationallib.h:1264
FOUNDATIONAL_LIB_FUNC char ** read_file_into_array(const char *filename, const char *delim, size_t *num_lines)
Reads the contents of a file into an array of strings.
Definition: foundationallib.h:12383
FOUNDATIONAL_LIB_FUNC void set_del_keys(char **keys)
Deletes keys from a Set.
Definition: foundationallib.h:11869
FOUNDATIONAL_LIB_FUNC void print_double_ptr_array_to_stream(const double **array, size_t size, FILE *stream)
Outputs elements of an array of pointers to double to a stream.
Definition: foundationallib.h:2455
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_short_ptrs(const void *a, const void *b)
Compare function for sorting pointers to shorts.
Definition: foundationallib.h:6001
FOUNDATIONAL_LIB_FUNC void sort_float_ptrs(float **float_ptrs, size_t size)
Sorts an array of pointers to floats in ascending order.
Definition: foundationallib.h:6648
FOUNDATIONAL_LIB_FUNC void sort_floats(float *floats, size_t size)
Sorts an array of floats in ascending order.
Definition: foundationallib.h:6587
#define FOUNDATIONAL_LIB_VSNPRINTF
Definition: foundationallib.h:297
FOUNDATIONAL_LIB_FUNC void print_long(const long value)
Prints a long integer value to the standard output.
Definition: foundationallib.h:12512
static FOUNDATIONAL_LIB_CONST size_t FOUNDATIONAL_LIB_safe_add_3(size_t a, size_t b, size_t c)
Safely add 3 numbers to avoid unsigned integer overflows and security and stability issues....
Definition: foundationallib.h:579
static int equal_array_of_ulong_ptrs(const unsigned long **array, const unsigned long **array2, size_t size)
Checks if two arrays of pointers to unsigned long integers are equal.
Definition: foundationallib.h:2929
FOUNDATIONAL_LIB_FUNC void print_double_to_stream(const double value, FILE *stream)
Prints a double-precision floating-point value to the specified stream.
Definition: foundationallib.h:12463
FOUNDATIONAL_LIB_FUNC char * sorted_chars(char *chars, size_t size)
Creates a new array containing sorted chars.
Definition: foundationallib.h:5720
static int equal_array_of_longs(const long *array, const long *array2, size_t size)
Checks if two arrays of long integers are equal.
Definition: foundationallib.h:2954
FOUNDATIONAL_LIB_FUNC int append_string_to_file(const char *filename, const char *content)
Appends a string to a file.
Definition: foundationallib.h:7139
FOUNDATIONAL_LIB_FUNC void sort_chars(char *chars, size_t size)
Sorts an array of chars in ascending order.
Definition: foundationallib.h:5701
static int starts_with(const char *str, const char *prefix)
Definition: foundationallib.h:4284
FOUNDATIONAL_LIB_FUNC int dict_resize(struct Dict *dict)
Resizes the hash table of the dictionary to optimize performance.
Definition: foundationallib.h:10378
static int ends_with(const char *str, const char *suffix)
Checks whether a given string ends with a specified suffix.
Definition: foundationallib.h:4301
FOUNDATIONAL_LIB_FUNC void print_uint_to_stream(const unsigned int value, FILE *stream)
Prints an unsigned int value to the specified stream.
Definition: foundationallib.h:12652
FOUNDATIONAL_LIB_FUNC int frozen_set_in(struct FrozenSet *set, const char *key)
Checks if a key is in a FrozenSet.
Definition: foundationallib.h:11689
static int equal_array_of_double_ptrs(const double **array, const double **array2, size_t size)
Compares arrays of double pointers for equality.
Definition: foundationallib.h:3180
FOUNDATIONAL_LIB_FUNC void sort_char_ptrs(char **char_ptrs, size_t size)
Sorts an array of pointers to chars in ascending order.
Definition: foundationallib.h:5760
FOUNDATIONAL_LIB_FUNC char * frozen_set_to_string(struct FrozenSet *frozen_set)
Converts a frozen set to a string representation.
Definition: foundationallib.h:11947
static double str_to_double(const char *string)
Converts a string to a double-precision floating-point number.
Definition: foundationallib.h:4798
FOUNDATIONAL_LIB_FUNC int filter_ints(int *source, size_t source_size, int *destination, int(*condition)(int))
Filters elements of an integer array based on a specified condition.
Definition: foundationallib.h:8395
FOUNDATIONAL_LIB_FUNC int file_is_regular(const char *filename)
Checks if a file is a regular file.
Definition: foundationallib.h:7184
FOUNDATIONAL_LIB_FUNC void sort_ulongs(unsigned long *ulongs, size_t size)
Sorts an array of unsigned longs in ascending order.
Definition: foundationallib.h:6081
FOUNDATIONAL_LIB_FUNC void print_float_to_stream(const float value, FILE *stream)
Prints a single-precision floating-point value to the specified stream.
Definition: foundationallib.h:12482
FOUNDATIONAL_LIB_FUNC void print_ushort_array_to_stream(const unsigned short *array, size_t size, FILE *stream)
Prints the elements of an unsigned short array to a specified stream.
Definition: foundationallib.h:2039
#define FOUNDATIONAL_LIB_ISDIGIT
Definition: foundationallib.h:362
FOUNDATIONAL_LIB_FUNC void print_ushort_ptr_array_to_stream(const unsigned short **array, size_t size, FILE *stream)
Prints the elements of an unsigned short array through a pointer to a specified stream.
Definition: foundationallib.h:2066
FOUNDATIONAL_LIB_FUNC int file_is_writable(const char *filename)
Checks if a file is writable.
Definition: foundationallib.h:7253
FOUNDATIONAL_LIB_FUNC long long ** sorted_long_long_ptrs(long long **long_long_ptrs, size_t size)
Creates a new array containing sorted pointers to long longs.
Definition: foundationallib.h:6546
FOUNDATIONAL_LIB_FUNC int append_string_to_string(char **string, size_t *string_length, size_t *string_alloc_size, const char *string_to_get_appended, size_t string_to_get_appended_length)
Appends a new string to an existing string and updates its length and allocation size.
Definition: foundationallib.h:3635
void * memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen)
FOUNDATIONAL_LIB_FUNC int copy_file(const char *source_filename, const char *destination_filename)
Copies a file from source to destination.
Definition: foundationallib.h:7372
FOUNDATIONAL_LIB_FUNC void print_size_t_array_to_stream(const size_t *array, size_t size, FILE *stream)
Outputs elements of a size_t array to a stream.
Definition: foundationallib.h:2481
static size_t FOUNDATIONAL_LIB_safe_add_2_ptr(size_t a, size_t b, size_t *ptr)
Safely add 2 numbers to avoid unsigned integer overflows and security and stability issues....
Definition: foundationallib.h:595
FOUNDATIONAL_LIB_FUNC void print_long_long_to_stream(const long long value, FILE *stream)
Prints a long long integer value to the specified stream.
Definition: foundationallib.h:12539
FOUNDATIONAL_LIB_FUNC void print_double_ptr_array(const double **array, size_t size)
Prints the elements of a double array through a pointer.
Definition: foundationallib.h:1742
FOUNDATIONAL_LIB_FUNC char * dup_format(const char *format,...)
Duplicates a formatted string.
Definition: foundationallib.h:8232
FOUNDATIONAL_LIB_FUNC char * string_to_title_case(const char *str)
Converts a string to title case.
Definition: foundationallib.h:4993
FOUNDATIONAL_LIB_FUNC char * concatenate_five_strings(const char *str1, const char *str2, const char *str3, const char *str4, const char *str5)
Concatenates five strings into a new dynamically allocated array.
Definition: foundationallib.h:9836
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_char_ptrs(const void *a, const void *b)
Compare function for sorting pointers to chars.
Definition: foundationallib.h:5744
#define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP
Definition: foundationallib.h:786
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_shorts(const void *a, const void *b)
Compare function for sorting shorts.
Definition: foundationallib.h:5940
FOUNDATIONAL_LIB_FUNC void print_string_array_array_to_stream(char ***array, size_t size, FILE *stream)
Prints the elements of an array of string arrays to a specified stream.
Definition: foundationallib.h:2013
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_uchars(const void *a, const void *b)
Compare function for sorting unsigned chars.
Definition: foundationallib.h:5561
#define FOUNDATIONAL_LIB_PRINTF
Definition: foundationallib.h:285
FOUNDATIONAL_LIB_FUNC void * memory_locate(const void *haystack, size_t haystack_len, const void *needle, size_t needle_len)
Definition: foundationallib.h:4323
FOUNDATIONAL_LIB_FUNC int is_array_upper(const char **array, size_t size)
Checks if a string array contains only uppercase characters.
Definition: foundationallib.h:9536
FOUNDATIONAL_LIB_FUNC void sort_long_ptrs(long **long_ptrs, size_t size)
Sorts an array of pointers to longs in ascending order.
Definition: foundationallib.h:6280
#define FOUNDATIONAL_LIB_STRLEN
Definition: foundationallib.h:309
FOUNDATIONAL_LIB_FUNC struct FrozenDict * frozen_dict_new_instance(size_t num_pairs,...)
Creates a new instance of a frozen dictionary.
Definition: foundationallib.h:10660
static int equal_array_of_float_ptrs(const float **array, const float **array2, size_t size)
Checks if two arrays of pointers to float values are equal.
Definition: foundationallib.h:3132
static size_t FOUNDATIONAL_LIB_safe_mul_ptr(size_t a, size_t b, size_t *ptr)
Safely multiply 2 numbers to avoid unsigned integer overflows and security and stability issues....
Definition: foundationallib.h:549
FOUNDATIONAL_LIB_FUNC float * sorted_floats(float *floats, size_t size)
Creates a new array containing sorted floats.
Definition: foundationallib.h:6606
static int equal_array_of_long_ptrs(const long **array, const long **array2, size_t size)
Checks if two arrays of pointers to long integers are equal.
Definition: foundationallib.h:2979
static int equal_array_of_size_ts(const size_t *array, const size_t *array2, size_t size)
Checks if two arrays of size_t values are equal.
Definition: foundationallib.h:3204
FOUNDATIONAL_LIB_FUNC char * set_to_string(struct Set *set)
Definition: foundationallib.h:11872
FOUNDATIONAL_LIB_FUNC int is_string_upper(const char *string)
Check if all characters in a string are uppercase.
Definition: foundationallib.h:9324
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ulong_longs(const void *a, const void *b)
Compare function for sorting unsigned long longs.
Definition: foundationallib.h:6324
FOUNDATIONAL_LIB_FUNC unsigned long rand_number_from_range_inclusive_unsigned(unsigned long min, unsigned long max)
Generates a random unsigned number within a specified range (inclusive).
Definition: foundationallib.h:12214
FOUNDATIONAL_LIB_FUNC char * longest_common_suffix(const char **strings, size_t count)
Finds the longest common suffix among an array of strings.
Definition: foundationallib.h:4719
FOUNDATIONAL_LIB_FUNC size_t frozen_set_size(struct FrozenSet *set)
Returns the size of a FrozenSet.
Definition: foundationallib.h:11759
static size_t FOUNDATIONAL_LIB_safe_mul(size_t a, size_t b)
Safely multiply 2 numbers to avoid unsigned integer overflows and security and stability issues....
Definition: foundationallib.h:533
FOUNDATIONAL_LIB_FUNC char * frozen_dict_to_string(struct FrozenDict *dict, int pointer_or_string)
Converts a FrozenDict (frozen dictionary) to a string representation.
Definition: foundationallib.h:11170
FOUNDATIONAL_LIB_FUNC void print_uint_ptr_array_to_stream(const unsigned int **array, size_t size, FILE *stream)
Prints the elements of an unsigned int array through a pointer to a specified stream.
Definition: foundationallib.h:1857
FOUNDATIONAL_LIB_FUNC void print_double_array(const double *array, size_t size)
Prints the elements of a double array.
Definition: foundationallib.h:1716
FOUNDATIONAL_LIB_FUNC void print_int_array(const int *array, size_t size)
Prints the elements of an int array.
Definition: foundationallib.h:1170
FOUNDATIONAL_LIB_FUNC char * string_to_json(const char *input_string)
Converts a given input string to its JSON representation.
Definition: foundationallib.h:3253
FOUNDATIONAL_LIB_FUNC void frozen_set_del_keys(char **keys)
Deletes keys from a FrozenSet.
Definition: foundationallib.h:12015
FOUNDATIONAL_LIB_FUNC unsigned short ** sorted_ushort_ptrs(unsigned short **ushort_ptrs, size_t size)
Creates a new array containing sorted pointers to unsigned shorts.
Definition: foundationallib.h:5914
FOUNDATIONAL_LIB_FUNC int string_array_uniq_adjacent(const char **first_array, size_t size, char ***new_array, size_t *new_size)
Remove adjacent duplicate strings from a string array.
Definition: foundationallib.h:9722
FOUNDATIONAL_LIB_FUNC char ** sorted_char_ptrs(char **char_ptrs, size_t size)
Creates a new array containing sorted pointers to chars.
Definition: foundationallib.h:5781
FOUNDATIONAL_LIB_FUNC int read_files_into_array(const char **files_to_open, size_t num_files, char ***outputs, size_t **lens, int aggressive_stop_on_error)
Reads content from multiple files into an array.
Definition: foundationallib.h:13036
static void free_array(void **array, size_t len)
Frees a dynamic array and its elements up to one level deep.
Definition: foundationallib.h:903
FOUNDATIONAL_LIB_FUNC void print_long_long(const long long value)
Prints a long long integer value to the standard output.
Definition: foundationallib.h:12531
FOUNDATIONAL_LIB_FUNC char * string_to_uppercase(char *string)
Convert a string to uppercase.
Definition: foundationallib.h:9292
FOUNDATIONAL_LIB_FUNC int memory_has_subchunk(void *memory, size_t memory_length, void *subchunk, size_t subchunk_length)
Checks if a subchunk exists within a given memory block.
Definition: foundationallib.h:4443
FOUNDATIONAL_LIB_FUNC void print_int_ptr_array(const int **array, size_t size)
Prints the elements of an array of int pointers.
Definition: foundationallib.h:1202
FOUNDATIONAL_LIB_FUNC int get_file_size(const char *filename, size_t *size)
Gets the size of a file.
Definition: foundationallib.h:7297
FOUNDATIONAL_LIB_FUNC void * list_comprehension_multithreaded(const void *input_array, size_t array_size, size_t elem_size, void(*transform_func)(void *value), int(*filter_func)(void *value), size_t *result_size, size_t thread_count)
Definition: foundationallib.h:8893
FOUNDATIONAL_LIB_FUNC int is_array_digit(const char **array, size_t size)
Check if a string array contains only digits.
Definition: foundationallib.h:9506
FOUNDATIONAL_LIB_FUNC int file_is_directory(const char *filename)
Checks if a file is a directory.
Definition: foundationallib.h:7207
FOUNDATIONAL_LIB_FUNC long * sorted_longs(long *longs, size_t size)
Creates a new array containing sorted pointers to unsigned longs.
Definition: foundationallib.h:6237
FOUNDATIONAL_LIB_FUNC void print_int_ptr_array_to_stream(const int **array, size_t size, FILE *stream)
Prints the elements of an int array through a pointer to a specified stream.
Definition: foundationallib.h:1909
FOUNDATIONAL_LIB_FUNC int replace_memory(void *source, size_t source_len, void *find, size_t find_len, void *replace, size_t replace_len, void **output, size_t *output_length_without_nullt, int *should_free_after_use, size_t matches_max, size_t *num_matches_found, int should_nullt)
Performs memory replacement with specified lengths.
Definition: foundationallib.h:7812
static void free_string_array(char **array, size_t len)
Frees a dynamic string array and its elements up to one level deep.
Definition: foundationallib.h:922
FOUNDATIONAL_LIB_FUNC int is_string_lower(const char *string)
Check if all characters in a string are lowercase.
Definition: foundationallib.h:9351
FOUNDATIONAL_LIB_FUNC void print_ushort(const unsigned short value)
Print an unsigned short value.
Definition: foundationallib.h:12713
#define FOUNDATIONAL_LIB_COPY_SIZE_AMOUNT
Definition: foundationallib.h:700
FOUNDATIONAL_LIB_FUNC void print_char(const char value)
Prints a character value to the standard output.
Definition: foundationallib.h:12436
FOUNDATIONAL_LIB_FUNC int string_array_uniq(const char **array, size_t size, char ***output, size_t *output_size)
Remove duplicate strings from a string array.
Definition: foundationallib.h:9622
static int equal_array_of_short_ptrs(const short **array, const short **array2, size_t size)
Checks if two arrays of pointers to short integers are equal.
Definition: foundationallib.h:2877
FOUNDATIONAL_LIB_FUNC void print_ulong_long_ptr_array_to_stream(const unsigned long long **array, size_t size, FILE *stream)
Prints the elements of an unsigned long long array through a pointer to a specified stream.
Definition: foundationallib.h:2281
#define FOUNDATIONAL_LIB_ISLOWER
Definition: foundationallib.h:371
FOUNDATIONAL_LIB_FUNC struct FrozenSet * frozen_set_new_instance(size_t num_args,...)
Creates a new instance of a FrozenSet.
Definition: foundationallib.h:11645
#define FOUNDATIONAL_LIB_MEMCPY
Definition: foundationallib.h:305
FOUNDATIONAL_LIB_FUNC size_t * sorted_size_ts(size_t *size_ts, size_t size)
Creates a new array containing sorted size_t values.
Definition: foundationallib.h:6852
FOUNDATIONAL_LIB_FUNC int set_reserve_more(struct Set *set, size_t number_of_new_elements_max_one_is_expecting)
Reserves additional space in a Set for anticipated new elements.
Definition: foundationallib.h:11553
#define FOUNDATIONAL_LIB_STRSTR
Definition: foundationallib.h:349
FOUNDATIONAL_LIB_FUNC void set_del_key(struct Set *set, const char *key)
Deletes a key from a Set.
Definition: foundationallib.h:11416
FOUNDATIONAL_LIB_FUNC int write_to_file_with_mode(const char *filename, const char *content, size_t content_length, const char *mode)
Writes a string or data to a file with a specified mode.
Definition: foundationallib.h:7072
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ulong_ptrs(const void *a, const void *b)
Compare function for sorting pointers to unsigned longs.
Definition: foundationallib.h:6128
static int equal_array_of_uint_ptrs(const unsigned int **array, const unsigned int **array2, size_t size)
Checks if two arrays of pointers to unsigned integers are equal.
Definition: foundationallib.h:2627
FOUNDATIONAL_LIB_FUNC void dict_iter(struct Dict *dict, void(*callback)(char *key, void *value))
Iterates through the key-value pairs in the dictionary, applying a callback function.
Definition: foundationallib.h:10784
FOUNDATIONAL_LIB_FUNC void print_uint_array(const unsigned long long *array, size_t size)
Prints the elements of a uint array.
Definition: foundationallib.h:1108
FOUNDATIONAL_LIB_FUNC unsigned long long ** sorted_ulong_long_ptrs(unsigned long long **ulong_long_ptrs, size_t size)
Creates a new array containing sorted pointers to unsigned long longs.
Definition: foundationallib.h:6424
FOUNDATIONAL_LIB_FUNC void print_string_array_to_stream(char **array, size_t size, FILE *stream)
Prints the elements of a string array to a specified stream.
Definition: foundationallib.h:1986
FOUNDATIONAL_LIB_FUNC char * backticks(const char *command, size_t *size)
Executes a command and reads its output into a string.
Definition: foundationallib.h:12255
FOUNDATIONAL_LIB_FUNC size_t filter(void *source, size_t source_size, size_t elem_size, void *destination, size_t dest_size, int(*condition)(void *))
Filters elements of an array (void* version) based on a specified condition.
Definition: foundationallib.h:8550
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ulong_long_ptrs(const void *a, const void *b)
Compare function for sorting pointers to unsigned long longs.
Definition: foundationallib.h:6386
#define FOUNDATIONAL_LIB_FERROR
Definition: foundationallib.h:729
FOUNDATIONAL_LIB_FUNC char * concatenate_strings(const char *str1, const char *str2)
Concatenates two strings.
Definition: foundationallib.h:7762
FOUNDATIONAL_LIB_FUNC void sort_ushorts(unsigned short *ushorts, size_t size)
Sorts an array of unsigned shorts in ascending order.
Definition: foundationallib.h:5824
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_list_comprehension_worker(void *data)
Definition: foundationallib.h:8825
FOUNDATIONAL_LIB_FUNC int append_data_to_array_no_initial_alloc(void **array, size_t *array_size, size_t *array_current_alloc_size, void *data, size_t data_size)
Appends a new element to the end of a dynamically allocated array and updates its size.
Definition: foundationallib.h:3793
#define FOUNDATIONAL_LIB_UNLIKELY(x)
Definition: foundationallib.h:424
static int equal_array_of_uchars(const unsigned char *array, const unsigned char *array2, size_t size)
Checks if two arrays of unsigned characters are equal.
Definition: foundationallib.h:2701
#define FOUNDATIONAL_LIB_MEMCMP
Definition: foundationallib.h:317
static void frozen_dict_del_values(void **values)
Deletes values from a frozen dictionary.
Definition: foundationallib.h:11270
static int equal_array_of_long_long_ptrs(const long long **array, const long long **array2, size_t size)
Checks if two arrays of pointers to long long integers are equal.
Definition: foundationallib.h:3082
FOUNDATIONAL_LIB_FUNC long long * sorted_long_longs(long long *long_longs, size_t size)
Creates a new array containing sorted long longs.
Definition: foundationallib.h:6482
#define FOUNDATIONAL_LIB_STATIC_ASSERT_MSG(true_cond, failure_message)
Definition: foundationallib.h:108
FOUNDATIONAL_LIB_FUNC int dict_to_array(struct Dict *dict, char ***keys, void ***values, size_t *size_of_keys_and_values)
Converts the key-value pairs from the dictionary into separate arrays for keys and values.
Definition: foundationallib.h:10891
FOUNDATIONAL_LIB_FUNC void print_long_long_ptr_array_to_stream(const long long **array, size_t size, FILE *stream)
Outputs elements of an array of pointers to long long to a stream.
Definition: foundationallib.h:2344
FOUNDATIONAL_LIB_FUNC int * sorted_ints(int *ints, size_t size)
Definition: foundationallib.h:5472
FOUNDATIONAL_LIB_FUNC void int_to_string_with_buffer(long long int number, char *buffer)
Converts an integer to its string representation.
Definition: foundationallib.h:1000
FOUNDATIONAL_LIB_FUNC void print_long_long_array(const long long *array, size_t size)
Prints the elements of a long long array.
Definition: foundationallib.h:1604
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_chars(const void *a, const void *b)
Compare function for sorting chars.
Definition: foundationallib.h:5686
FOUNDATIONAL_LIB_FUNC long ** sorted_long_ptrs(long **long_ptrs, size_t size)
Creates a new array containing sorted pointers to longs.
Definition: foundationallib.h:6299
FOUNDATIONAL_LIB_FUNC char * reduce_filesystem_files_as_strings(const char *directory, const char *out_file, char *(*reduce_function)(char *value1,...))
Applies a reduce operation on files in the specified directory, and outputs the result as a string.
Definition: foundationallib.h:10120
FOUNDATIONAL_LIB_FUNC int set_to_array(struct Set *set, char ***keys, size_t *size_of_keys)
Converts a Set to an array of keys.
Definition: foundationallib.h:11775
FOUNDATIONAL_LIB_FUNC void sort_long_longs(long long *long_longs, size_t size)
Sorts an array of long longs in ascending order.
Definition: foundationallib.h:6464
FOUNDATIONAL_LIB_FUNC int string_has_substr(const char *string, size_t string_length, const char *substring, size_t substring_length)
Checks if a substring exists within a given string.
Definition: foundationallib.h:4405
FOUNDATIONAL_LIB_FUNC void print_int_array_to_stream(const int *array, size_t size, FILE *stream)
Prints the elements of an int array to a specified stream.
Definition: foundationallib.h:1882
FOUNDATIONAL_LIB_FUNC void print_long_long_array_to_stream(const long long *array, size_t size, FILE *stream)
Outputs elements of a long_long array to a stream.
Definition: foundationallib.h:2311
FOUNDATIONAL_LIB_FUNC void print_long_ptr_array_to_stream(const long **array, size_t size, FILE *stream)
Prints the elements of a long array through a pointer to a specified stream.
Definition: foundationallib.h:2223
#define FOUNDATIONAL_LIB_DIR_SEPARATOR
Definition: foundationallib.h:9859
#define FOUNDATIONAL_LIB_FTELLO
Definition: foundationallib.h:746
static int equal_array_of_ulongs(const unsigned long *array, const unsigned long *array2, size_t size)
Checks if two arrays of unsigned long integers are equal.
Definition: foundationallib.h:2902
#define FOUNDATIONAL_LIB_VA_END
Definition: foundationallib.h:134
FOUNDATIONAL_LIB_FUNC void print_short_to_stream(const short value, FILE *stream)
Prints a short integer value to the specified stream.
Definition: foundationallib.h:12565
FOUNDATIONAL_LIB_FUNC int append_string_to_array_no_initial_alloc(char ***array, size_t *array_size, size_t *array_current_alloc_size, const char *string)
Appends a new string element to the end of a dynamically allocated array of strings and updates its s...
Definition: foundationallib.h:3948
static int FOUNDATIONAL_LIB_safe_add_3_ptr(size_t a, size_t b, size_t c, size_t *ptr)
Safely add 3 numbers to avoid unsigned integer overflows and security and stability issues....
Definition: foundationallib.h:609
static int equal_array_of_doubles(const double *array, const double *array2, size_t size)
Checks if two arrays of doubles are equal.
Definition: foundationallib.h:3156
#define FOUNDATIONAL_LIB_ISALNUM
Definition: foundationallib.h:359
FOUNDATIONAL_LIB_FUNC void print_ushort_to_stream(const unsigned short value, FILE *stream)
Print an unsigned short value to a stream.
Definition: foundationallib.h:12721
FOUNDATIONAL_LIB_FUNC int write_file(const char *filename, const char *content)
Writes a string to a file.
Definition: foundationallib.h:7116
FOUNDATIONAL_LIB_FUNC int reduce_ints(int *array, size_t size, int(*operation)(int, int))
Performs a reduction on an integer array using a binary operation.
Definition: foundationallib.h:8344
#define FOUNDATIONAL_LIB_FROZEN_INITIALIZATION_SIZE_MULTIPLIER
Definition: foundationallib.h:406
FOUNDATIONAL_LIB_FUNC void sort_size_ts(size_t *size_ts, size_t size)
Sorts an array of size_t values in ascending order.
Definition: foundationallib.h:6832
#define FOUNDATIONAL_LIB_ISSPACE
Definition: foundationallib.h:353
#define FOUNDATIONAL_LIB_SIZE_STRING_OF_NUMBER_SIZE_PLUS_ZERO_TERMINATOR
Definition: foundationallib.h:112
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_size_t_ptrs(const void *a, const void *b)
Compare function for sorting pointers to size_t values.
Definition: foundationallib.h:6877
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_long_ptrs(const void *a, const void *b)
Compare function for sorting pointers to longs.
Definition: foundationallib.h:6264
FOUNDATIONAL_LIB_FUNC void print_uint_ptr_array(const unsigned int **array, size_t size)
Prints the elements of an array of uint pointers.
Definition: foundationallib.h:1139
FOUNDATIONAL_LIB_FUNC void print_short_array(const short *array, size_t size)
Prints the contents of an array of short integers.
Definition: foundationallib.h:1355
#define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC
Definition: foundationallib.h:770
FOUNDATIONAL_LIB_FUNC void print_int_to_stream(const int value, FILE *stream)
Prints an integer value to the specified stream.
Definition: foundationallib.h:12501
FOUNDATIONAL_LIB_FUNC char ** list_files_with_pattern(const char *directory, const char *pattern, size_t *len)
Lists files in a directory using a wildcard pattern.
Definition: foundationallib.h:7595
FOUNDATIONAL_LIB_FUNC void reduce(void *array, size_t size, size_t elem_size, void *result, void(*operation)(void *, void *))
Performs a reduction on an array (void* version) using a binary operation.
Definition: foundationallib.h:8488
FOUNDATIONAL_LIB_FUNC void print_float_array_to_stream(const float *array, size_t size, FILE *stream)
Outputs elements of a float array to a stream.
Definition: foundationallib.h:2375
static int equal_array_of_size_t_ptrs(const size_t **array, const size_t **array2, size_t size)
Compares arrays of size_t pointers for equality.
Definition: foundationallib.h:3228
FOUNDATIONAL_LIB_FUNC int ** sorted_int_ptrs(int **int_ptrs, size_t size)
Definition: foundationallib.h:5537
FOUNDATIONAL_LIB_FUNC void print_string_to_stream(char *value, FILE *stream)
Prints a string value to the specified stream.
Definition: foundationallib.h:12612
FOUNDATIONAL_LIB_FUNC char ** sorted_strings(char **strings, size_t size)
Creates a new array of strings sorted in ascending order.
Definition: foundationallib.h:5282
FOUNDATIONAL_LIB_FUNC void print_uchar_array_to_stream(const unsigned char *array, size_t size, FILE *stream)
Prints the elements of an unsigned char array to a specified stream.
Definition: foundationallib.h:1935
FOUNDATIONAL_LIB_FUNC int is_string_space(const char *string)
Check if all characters in a string are spaces.
Definition: foundationallib.h:9431
#define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC
Definition: foundationallib.h:778
FOUNDATIONAL_LIB_FUNC char * concatenate_four_strings(const char *str1, const char *str2, const char *str3, const char *str4)
Concatenates four strings into a new dynamically allocated array.
Definition: foundationallib.h:9806
FOUNDATIONAL_LIB_FUNC void map_ints(int *array, size_t size, int(*transform)(int))
Applies a transformation to each element of an integer array.
Definition: foundationallib.h:8302
FOUNDATIONAL_LIB_FUNC char * strip(const char *str)
Trims leading and trailing whitespace from a given string.
Definition: foundationallib.h:3349
FOUNDATIONAL_LIB_FUNC ssize_t find_last_of(const char *str, const char *char_set)
Finds the last occurrence of any character from a specified set within a given string.
Definition: foundationallib.h:4840
FOUNDATIONAL_LIB_FUNC size_t set_size(struct Set *set)
Returns the size of a Set.
Definition: foundationallib.h:11744
FOUNDATIONAL_LIB_FUNC void print_short_ptr_array_to_stream(const short **array, size_t size, FILE *stream)
Prints the elements of a short array through a pointer to a specified stream.
Definition: foundationallib.h:2118
#define FOUNDATIONAL_LIB_HASH_INITIAL_CAPACITY
Initial capacity for hash tables (dict, frozendict, set, frozenset).
Definition: foundationallib.h:808
FOUNDATIONAL_LIB_FUNC int set_resize(struct Set *set)
Resizes a Set data structure.
Definition: foundationallib.h:11367
FOUNDATIONAL_LIB_FUNC int filter_filesystem_files_as_strings(const char *directory, int(*filter_function)(const char *filename))
Applies a filter operation on files in the specified directory.
Definition: foundationallib.h:10018
static int equal_array_of_char_ptrs(const char **array, const char **array2, size_t size)
Checks if two arrays of pointers to characters are equal.
Definition: foundationallib.h:2775
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_floats(const void *a, const void *b)
Compare function for sorting floats.
Definition: foundationallib.h:6572
FOUNDATIONAL_LIB_FUNC char * shellescape(const char *input)
Escapes special characters in a given string for shell usage.
Definition: foundationallib.h:4192
#define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC
Definition: foundationallib.h:774
FOUNDATIONAL_LIB_FUNC size_t set_hash(const char *key, size_t capacity)
Hashes a null-terminated string using the djb2 algorithm.
Definition: foundationallib.h:11345
static void dict_del_values(void **values)
Deallocates memory associated with an array of values.
Definition: foundationallib.h:11049
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ushorts(const void *a, const void *b)
Compare function for sorting unsigned shorts.
Definition: foundationallib.h:5807
FOUNDATIONAL_LIB_FUNC char * read_file_into_string(const char *filename, size_t *size)
Reads the contents of a file into a string.
Definition: foundationallib.h:6964
FOUNDATIONAL_LIB_FUNC int prepend_string_to_array(char ***array, size_t *array_size, size_t *array_current_alloc_size, char *string)
Prepends a new string element to the beginning of a dynamically allocated array of strings and update...
Definition: foundationallib.h:4016
#define FOUNDATIONAL_LIB_ALLOCATOR_DIV_AMOUNT
Definition: foundationallib.h:633
FOUNDATIONAL_LIB_FUNC size_t array_total_string_length(char **array, size_t count)
Calculates the total length of strings in an array.
Definition: foundationallib.h:4159
FOUNDATIONAL_LIB_FUNC int prepend_string_to_array_no_initial_alloc(char ***array, size_t *array_size, size_t *array_current_alloc_size, char *string)
Prepends a new string element to the beginning of a dynamically allocated array of strings and update...
Definition: foundationallib.h:4097
FOUNDATIONAL_LIB_FUNC int set_in(struct Set *set, const char *key)
Checks if a key is in a Set.
Definition: foundationallib.h:11602
FOUNDATIONAL_LIB_FUNC void print_long_array_to_stream(const long *array, size_t size, FILE *stream)
Prints the elements of a long array to a specified stream.
Definition: foundationallib.h:2196
FOUNDATIONAL_LIB_FUNC void print_ulong_ptr_array_to_stream(const unsigned long **array, size_t size, FILE *stream)
Prints the elements of an unsigned long array through a pointer to a specified stream.
Definition: foundationallib.h:2171
FOUNDATIONAL_LIB_FUNC void sort_strings(char **strings, size_t size)
Sorts an array of strings.
Definition: foundationallib.h:5264
FOUNDATIONAL_LIB_FUNC size_t count_occurrences_of_substr(const char *str, const char *substring)
Counts the occurrences of a specified substring within a given string.
Definition: foundationallib.h:4367
#define FOUNDATIONAL_LIB_FPUTS
Definition: foundationallib.h:325
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmpstringp(const void *p1, const void *p2)
Definition: foundationallib.h:5251
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ulongs(const void *a, const void *b)
Compare function for sorting unsigned longs.
Definition: foundationallib.h:6065
static int equal_array_of_floats(const float *array, const float *array2, size_t size)
Checks if two arrays of float values are equal.
Definition: foundationallib.h:3107
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_doubles(const void *a, const void *b)
Compare function for sorting doubles.
Definition: foundationallib.h:6694
#define FOUNDATIONAL_LIB_ATOI
Definition: foundationallib.h:713
FOUNDATIONAL_LIB_FUNC char * concatenate_string_array(const char **strings, size_t num_strings)
Concatenates an array of strings into a single string.
Definition: foundationallib.h:7681
FOUNDATIONAL_LIB_FUNC void * reject_array(const void *source, size_t source_size, size_t elem_size, int(*condition)(const void *), size_t *result_size)
Definition: foundationallib.h:9076
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_size_ts(const void *a, const void *b)
Compare function for sorting size_t values.
Definition: foundationallib.h:6815
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_uchar_ptrs(const void *a, const void *b)
Compare function for sorting pointers to unsigned chars.
Definition: foundationallib.h:5624
FOUNDATIONAL_LIB_FUNC void print_float_ptr_array(const float **array, size_t size)
Prints the elements of a float array through a pointer.
Definition: foundationallib.h:1691
FOUNDATIONAL_LIB_FUNC int map_filesystem_files_as_strings(const char *directory, char *(*map_function)(const char *file_string_data, size_t string_size))
Applies a map operation on files in a directory, working with strings.
Definition: foundationallib.h:9885
FOUNDATIONAL_LIB_FUNC char * longest_common_prefix(const char **strings, size_t count)
Finds the longest common prefix among an array of strings.
Definition: foundationallib.h:4639
FOUNDATIONAL_LIB_FUNC void print_double(const double value)
Prints a double-precision floating-point value to the standard output.
Definition: foundationallib.h:12455
#define FOUNDATIONAL_LIB_PUTCHAR
Definition: foundationallib.h:329
FOUNDATIONAL_LIB_FUNC int find_min_int_in_array(const int *array, size_t size)
Finds the minimum element in an array of integers.
Definition: foundationallib.h:5073
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_float_ptrs(const void *a, const void *b)
Compare function for sorting pointers to floats.
Definition: foundationallib.h:6632
#define FOUNDATIONAL_LIB_INITIAL_DATA_ARRAY_ALLOC_SIZE
Definition: foundationallib.h:3679
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ushort_ptrs(const void *a, const void *b)
Compare function for sorting pointers to unsigned shorts.
Definition: foundationallib.h:5873
FOUNDATIONAL_LIB_FUNC double ** sorted_double_ptrs(double **double_ptrs, size_t size)
Creates a new array containing sorted pointers to doubles.
Definition: foundationallib.h:6789
FOUNDATIONAL_LIB_FUNC void print_short_array_to_stream(const short *array, size_t size, FILE *stream)
Prints the elements of a short array to a specified stream.
Definition: foundationallib.h:2091
FOUNDATIONAL_LIB_FUNC size_t dict_hash(const char *key, size_t capacity)
Hashes a null-terminated string using the djb2 algorithm.
Definition: foundationallib.h:10292
FOUNDATIONAL_LIB_FUNC void set_iter(struct Set *set, void(*callback)(char *key))
Iterates over a Set and applies a callback to each key.
Definition: foundationallib.h:11716
#define FOUNDATIONAL_LIB_STRCMP
Definition: foundationallib.h:313
FOUNDATIONAL_LIB_FUNC void print_short_ptr_array(const short **array, size_t size)
Prints an array of pointers to short integers.
Definition: foundationallib.h:1388
FOUNDATIONAL_LIB_FUNC void print_uchar(const unsigned char value)
Prints an unsigned char value to the standard output.
Definition: foundationallib.h:12625
#define FOUNDATIONAL_LIB_FPRINTF
Definition: foundationallib.h:301
FOUNDATIONAL_LIB_FUNC int file_is_readable(const char *filename)
Checks if a file is readable.
Definition: foundationallib.h:7232
FOUNDATIONAL_LIB_FUNC char * uint_to_string(size_t number)
Converts an integer to its string representation.
Definition: foundationallib.h:1082
static int equal_array_of_ushort_ptrs(const unsigned short **array, const unsigned short **array2, size_t size)
Checks if two arrays of pointers to unsigned short integers are equal.
Definition: foundationallib.h:2827
FOUNDATIONAL_LIB_FUNC void print_ulong_long_to_stream(const unsigned long long value, FILE *stream)
Prints an unsigned long long value to the specified stream.
Definition: foundationallib.h:12698
FOUNDATIONAL_LIB_FUNC size_t count_occurrences_of_adjacent_data_in_array(const void *array_of_adjacent_values, size_t array_length, const void *memory, size_t memory_length)
Counts the occurrences of a block of memory in an array of memory blocks.
Definition: foundationallib.h:12774
FOUNDATIONAL_LIB_FUNC size_t count_occurrences_of_data_in_array(const void **array_of_pointers, size_t array_length, const void *memory, size_t memory_length)
Counts the occurrences of a block of memory in an array of memory blocks.
Definition: foundationallib.h:12807
FOUNDATIONAL_LIB_FUNC float ** sorted_float_ptrs(float **float_ptrs, size_t size)
Creates a new array containing sorted pointers to floats.
Definition: foundationallib.h:6668
FOUNDATIONAL_LIB_FUNC long rand_number_from_range_inclusive_signed(signed long min, signed long max)
Generates a random signed number within a specified range (inclusive).
Definition: foundationallib.h:12185
FOUNDATIONAL_LIB_FUNC void frozen_dict_destructor(struct FrozenDict *dict)
Deallocates memory associated with a frozen dictionary, freeing resources.
Definition: foundationallib.h:10641
FOUNDATIONAL_LIB_FUNC void print_size_t_ptr_array(const size_t **array, size_t size)
Prints the elements of a size_t array through a pointer.
Definition: foundationallib.h:1798
FOUNDATIONAL_LIB_FUNC void * dict_get(struct Dict *dict, const char *key)
Retrieves the value associated with the specified key from the dictionary.
Definition: foundationallib.h:10568
FOUNDATIONAL_LIB_FUNC int append_data_to_array(void **array, size_t *array_size, size_t *array_current_alloc_size, void *data, size_t data_size)
Appends a new element to the end of a dynamically allocated array and updates its size.
Definition: foundationallib.h:3703
FOUNDATIONAL_LIB_FUNC size_t ** sorted_size_t_ptrs(size_t **size_t_ptrs, size_t size)
Creates a new array containing sorted pointers to size_t values.
Definition: foundationallib.h:6915
FOUNDATIONAL_LIB_FUNC void print_short(const short value)
Prints a short integer value to the standard output.
Definition: foundationallib.h:12557
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_uint_ptrs(const void *a, const void *b)
Definition: foundationallib.h:5371
FOUNDATIONAL_LIB_FUNC void sort_shorts(short *shorts, size_t size)
Sorts an array of shorts in ascending order.
Definition: foundationallib.h:5954
FOUNDATIONAL_LIB_FUNC void print_long_array(const long *array, size_t size)
Prints the elements of a long array.
Definition: foundationallib.h:1483
FOUNDATIONAL_LIB_FUNC void print_ushort_ptr_array(const unsigned short **array, size_t size)
Prints an array of pointers to unsigned short integers.
Definition: foundationallib.h:1324
FOUNDATIONAL_LIB_FUNC short * sorted_shorts(short *shorts, size_t size)
Creates a new array containing sorted shorts.
Definition: foundationallib.h:5974
FOUNDATIONAL_LIB_FUNC int ints_are_sorted_descending(const int *array, size_t size)
Checks if an array of integers is sorted in descending order.
Definition: foundationallib.h:5170
FOUNDATIONAL_LIB_FUNC void reverse_string_in_place(char *str)
Reverses a string in place.
Definition: foundationallib.h:4865
#define FOUNDATIONAL_LIB_FWRITE
Definition: foundationallib.h:756
FOUNDATIONAL_LIB_FUNC void sort_uchars(unsigned char *uchars, size_t size)
Sorts an array of unsigned chars in ascending order.
Definition: foundationallib.h:5577
FOUNDATIONAL_LIB_FUNC int ints_are_sorted_ascending(const int *array, size_t size)
Checks if an array of integers is sorted in ascending order.
Definition: foundationallib.h:5147
FOUNDATIONAL_LIB_FUNC const char * sample_strings(const char **strings, size_t size)
Selects a random string from an array of strings without dynamic memory allocation.
Definition: foundationallib.h:12112
FOUNDATIONAL_LIB_FUNC void print_long_ptr_array(const long **array, size_t size)
Prints the elements of a long array.
Definition: foundationallib.h:1513
FOUNDATIONAL_LIB_FUNC char * join(const char **array, size_t count, const char *delimiter)
Joins an array of strings into a single string using a specified delimiter.
Definition: foundationallib.h:3529
FOUNDATIONAL_LIB_FUNC void sort_uchar_ptrs(unsigned char **uchar_ptrs, size_t size)
Sorts an array of pointers to unsigned chars in ascending order.
Definition: foundationallib.h:5640
FOUNDATIONAL_LIB_FUNC char * int_to_string(long long int number)
Converts an integer to its string representation.
Definition: foundationallib.h:940
FOUNDATIONAL_LIB_FUNC void * frozen_dict_get(struct FrozenDict *dict, const char *key)
Retrieves the value associated with the specified key from the frozen dictionary.
Definition: foundationallib.h:10712
FOUNDATIONAL_LIB_FUNC void sort_uint_ptrs(unsigned int **uint_ptrs, size_t size)
Definition: foundationallib.h:5387
FOUNDATIONAL_LIB_FUNC void frozen_set_destructor(struct FrozenSet *frozen_set)
The destructor for a Frozen Set.
Definition: foundationallib.h:11629
#define FOUNDATIONAL_LIB_POPEN
Definition: foundationallib.h:723
FOUNDATIONAL_LIB_FUNC int is_string_alpha(const char *string)
Check if all characters in a string are alphanumeric.
Definition: foundationallib.h:9378
FOUNDATIONAL_LIB_FUNC void set_destructor(struct Set *set)
The destructor for a Set.
Definition: foundationallib.h:11283
FOUNDATIONAL_LIB_FUNC void print_string(char *value)
Prints a string value to the standard output.
Definition: foundationallib.h:12600
FOUNDATIONAL_LIB_FUNC struct Set * set_new_instance(void)
Creates a new instance of a Set.
Definition: foundationallib.h:11309
FOUNDATIONAL_LIB_FUNC void print_ulong_ptr_array(const unsigned long **array, size_t size)
Prints an array of pointers to unsigned long integers.
Definition: foundationallib.h:1452
FOUNDATIONAL_LIB_FUNC void print_size_t_to_stream(const size_t value, FILE *stream)
Prints a size_t value to the specified stream.
Definition: foundationallib.h:12583
FOUNDATIONAL_LIB_FUNC int set_add(struct Set *set, const char *key)
Adds a key pair to the set.
Definition: foundationallib.h:11468
FOUNDATIONAL_LIB_FUNC void * dict_get_check(struct Dict *dict, const char *key, int *key_is_in_dict)
Retrieves the value associated with the specified key from the dictionary.
Definition: foundationallib.h:10607
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_longs(const void *a, const void *b)
Compare function for sorting pointers to unsigned longs.
Definition: foundationallib.h:6196
FOUNDATIONAL_LIB_FUNC size_t count_occurrences_of_string_in_array(const char **array, const char *string, size_t array_length)
Counts the occurrences of a string in an array of strings.
Definition: foundationallib.h:12740
FOUNDATIONAL_LIB_FUNC void print_float_array(const float *array, size_t size)
Prints the elements of a float array.
Definition: foundationallib.h:1665
#define FOUNDATIONAL_LIB_FREAD
Definition: foundationallib.h:752
#define FOUNDATIONAL_LIB_die_aggressively_if_enabled()
Macro to die aggressively if enabled.
Definition: foundationallib.h:885
FOUNDATIONAL_LIB_FUNC ssize_t find_first_of(const char *str, const char *char_set)
Finds the first occurrence of any character from a set in a string.
Definition: foundationallib.h:4817
FOUNDATIONAL_LIB_FUNC int is_string_alphanumeric(const char *str)
Determines whether a given string consists solely of alphanumeric characters.
Definition: foundationallib.h:4609
FOUNDATIONAL_LIB_FUNC int file_exists(const char *filename)
Checks if a file exists.
Definition: foundationallib.h:7164
FOUNDATIONAL_LIB_FUNC void print_size_t(const size_t value)
Prints a size_t value to the standard output.
Definition: foundationallib.h:12575
static FOUNDATIONAL_LIB_CONST size_t FOUNDATIONAL_LIB_safe_add_2(size_t a, size_t b)
Safely add 2 numbers to avoid unsigned integer overflows and security and stability issues....
Definition: foundationallib.h:563
FOUNDATIONAL_LIB_FUNC void print_long_to_stream(const long value, FILE *stream)
Prints a long integer value to the specified stream.
Definition: foundationallib.h:12520
FOUNDATIONAL_LIB_FUNC void * frozen_dict_get_check(struct FrozenDict *dict, const char *key, int *key_is_in_dict)
Retrieves the value associated with the specified key from the frozen dictionary.
Definition: foundationallib.h:10748
#define FOUNDATIONAL_LIB_VA_START
Definition: foundationallib.h:126
FOUNDATIONAL_LIB_FUNC int find_max_int_in_array(const int *array, size_t size)
Finds the maximum element in an array of integers.
Definition: foundationallib.h:5042
FOUNDATIONAL_LIB_FUNC void print_ulong_array_to_stream(const unsigned long *array, size_t size, FILE *stream)
Prints the elements of an unsigned long array to a specified stream.
Definition: foundationallib.h:2144
FOUNDATIONAL_LIB_FUNC void print_double_array_to_stream(const double *array, size_t size, FILE *stream)
Outputs elements of a double array to a stream.
Definition: foundationallib.h:2428
FOUNDATIONAL_LIB_FUNC void sort_ints(int *ints, size_t size)
Definition: foundationallib.h:5453
#define FOUNDATIONAL_LIB_FSEEKO
Definition: foundationallib.h:742
#define FOUNDATIONAL_LIB_FPUTC
Definition: foundationallib.h:333
static int equal_strings(const char *first, const char *second)
Compares two strings for equality.
Definition: foundationallib.h:2587
FOUNDATIONAL_LIB_FUNC void frozen_set_iter(struct Set *set, void(*callback)(char *key))
Iterates over a Set and applies a callback to each key.
Definition: foundationallib.h:12030
FOUNDATIONAL_LIB_FUNC void dict_destructor(struct Dict *dict)
Deallocates memory associated with a dictionary, freeing resources.
Definition: foundationallib.h:10258
FOUNDATIONAL_LIB_FUNC void sort_short_ptrs(short **short_ptrs, size_t size)
Sorts an array of pointers to shorts in ascending order.
Definition: foundationallib.h:6018
Definition: foundationallib.h:8760
struct DictKeyValue ** table
Definition: foundationallib.h:8761
size_t size
Definition: foundationallib.h:8763
size_t capacity
Definition: foundationallib.h:8762
Definition: foundationallib.h:8775
void * value
Definition: foundationallib.h:8777
char * key
Definition: foundationallib.h:8776
struct DictKeyValue * next
Definition: foundationallib.h:8778
Definition: foundationallib.h:8782
size_t capacity
Definition: foundationallib.h:8784
struct DictKeyValue ** table
Definition: foundationallib.h:8783
size_t size
Definition: foundationallib.h:8785
Definition: foundationallib.h:8790
size_t capacity
Definition: foundationallib.h:8792
size_t size
Definition: foundationallib.h:8793
struct SetKey ** table
Definition: foundationallib.h:8791
Definition: foundationallib.h:8767
struct SetKey ** table
Definition: foundationallib.h:8768
size_t size
Definition: foundationallib.h:8770
size_t capacity
Definition: foundationallib.h:8769
Definition: foundationallib.h:8754
struct SetKey * next
Definition: foundationallib.h:8756
char * key
Definition: foundationallib.h:8755
Definition: foundationallib.h:8809
size_t elem_size
Definition: foundationallib.h:8812
size_t start_index
Definition: foundationallib.h:8817
size_t array_size
Definition: foundationallib.h:8811
void * result
Definition: foundationallib.h:8816
size_t end_index
Definition: foundationallib.h:8818
const void * input_array
Definition: foundationallib.h:8810
size_t * result_size
Definition: foundationallib.h:8815
void(* transform_func)(void *value)
Definition: foundationallib.h:8813
int(* filter_func)(void *value)
Definition: foundationallib.h:8814