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 putc
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__
441 FOUNDATIONAL_LIB_CONST
442 static inline size_t FOUNDATIONAL_LIB_safe_mul(size_t a, size_t b)
443 {
444  size_t result;
445 
446  if (FOUNDATIONAL_LIB_UNLIKELY(__builtin_mul_overflow(a, b, &result)))
447  {
448  /* 0 on error (overflow). */
449  return 0;
450  }
451 
452  return result;
453 }
454 
457 static inline size_t FOUNDATIONAL_LIB_safe_mul_ptr(size_t a, size_t b, size_t *ptr)
458 {
459  if (FOUNDATIONAL_LIB_UNLIKELY(__builtin_mul_overflow(a, b, ptr)))
460  {
461  /* 0 on error (overflow). */
462  return 0;
463  }
464 
465  return 1;
466 }
467 
469 FOUNDATIONAL_LIB_CONST
470 static inline size_t FOUNDATIONAL_LIB_safe_add_2(size_t a, size_t b)
471 {
472  size_t result;
473 
474  if (FOUNDATIONAL_LIB_UNLIKELY(__builtin_add_overflow(a, b, &result)))
475  {
476  /* 0 on error (overflow). */
477  return 0;
478  }
479 
480  return result;
481 }
482 
484 FOUNDATIONAL_LIB_CONST
485 static inline size_t FOUNDATIONAL_LIB_safe_add_3(size_t a, size_t b, size_t c)
486 {
487  size_t result;
488 
489  if (FOUNDATIONAL_LIB_UNLIKELY(__builtin_add_overflow(a, b, &result)) || FOUNDATIONAL_LIB_UNLIKELY(__builtin_add_overflow(result, c, &result)))
490  {
491  /* 0 on error (overflow). */
492  return 0;
493  }
494 
495  return result;
496 }
497 
499 static inline int FOUNDATIONAL_LIB_safe_add_3_ptr(size_t a, size_t b, size_t c, size_t *out)
500 {
501  if (FOUNDATIONAL_LIB_UNLIKELY(__builtin_add_overflow(a, b, out)) || FOUNDATIONAL_LIB_UNLIKELY(__builtin_add_overflow(*out, c, out)))
502  {
503  /* 0 on error (overflow). */
504  return 0;
505  }
506 
507  return 1;
508 }
509 
511 static inline int FOUNDATIONAL_LIB_safe_add_2_ptr(size_t a, size_t b, size_t *out)
512 {
513  if (FOUNDATIONAL_LIB_UNLIKELY(__builtin_add_overflow(a, b, out)))
514  {
515  /* 0 on error (overflow). */
516  return 0;
517  }
518 
519  return 1;
520 }
521 
522 #else /* GNUC */
524 FOUNDATIONAL_LIB_CONST
525 static inline size_t FOUNDATIONAL_LIB_safe_mul(size_t a, size_t b)
526 {
527  size_t result;
528 
529  if (b != 0 && a > SIZE_MAX / b)
530  {
531  /* Overflow */
532  return 0;
533  }
534 
535  result = a * b;
536  return result;
537 }
538 
541 static inline size_t FOUNDATIONAL_LIB_safe_mul_ptr(size_t a, size_t b, size_t *ptr)
542 {
543  if (b != 0 && a > SIZE_MAX / b)
544  {
545  /* Overflow */
546  return 0;
547  }
548 
549  *ptr = a * b;
550  return 1;
551 }
552 
554 FOUNDATIONAL_LIB_CONST
555 static inline size_t FOUNDATIONAL_LIB_safe_add_2(size_t a, size_t b)
556 {
557  size_t result;
558 
559  if (a > SIZE_MAX - b || a + b > SIZE_MAX - c)
560  {
561  /* Overflow */
562  return 0;
563  }
564 
565  result = a + b;
566  return result;
567 }
568 
570 FOUNDATIONAL_LIB_CONST
571 static inline size_t FOUNDATIONAL_LIB_safe_add_3(size_t a, size_t b, size_t c)
572 {
573  size_t result;
574 
575  if (a > SIZE_MAX - b || b > SIZE_MAX - c)
576  {
577  /* Overflow */
578  return 0;
579  }
580 
581  result = a + b + c;
582  return result;
583 }
584 
587 static inline size_t FOUNDATIONAL_LIB_safe_add_2_ptr(size_t a, size_t b, size_t *ptr)
588 {
589  if (a > SIZE_MAX - b)
590  {
591  /* Overflow */
592  return 0;
593  }
594 
595  *ptr = a + b;
596  return 1;
597 }
598 
601 static inline int FOUNDATIONAL_LIB_safe_add_3_ptr(size_t a, size_t b, size_t c, size_t *ptr)
602 {
603  if (a > SIZE_MAX - b || b > SIZE_MAX - c)
604  {
605  /* Overflow */
606  return 0;
607  }
608 
609  *ptr = a + b + c;
610  return 1;
611 }
612 #endif /* GNUC */
613 
614 #define FOUNDATIONAL_LIB_safe_increment(variable, label_if_fails) \
615  if (FOUNDATIONAL_LIB_UNLIKELY(FOUNDATIONAL_LIB_safe_add_2_ptr((variable), 1, &(variable)) == 0)) \
616  goto label_if_fails;
617 
618 // Adjust as needed. On embedded platforms or low memory systems, you might want to change the algorithm to be somewhat lower than 1.5x
619 // new len calculations need to be checked, before and after this, for overflow.
620 
621 #ifndef FOUNDATIONAL_LIB_LOW_MEMORY_USAGE
622 #define FOUNDATIONAL_LIB_LOW_MEMORY_USAGE 12
623 #endif
624 
625 #ifndef FOUNDATIONAL_LIB_ALLOCATOR_DIV_AMOUNT
626 #define FOUNDATIONAL_LIB_ALLOCATOR_DIV_AMOUNT 2
627 #endif
628 
629 // Takes an argument and makes it at least 1 bigger.
630 #ifdef __GNUC__ // Check if GCC compiler is being used
631 
632 FOUNDATIONAL_LIB_CONST
633 static inline size_t FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(size_t old_size_to_add_at_least_one_to)
634 {
635  size_t addition;
636 
637  // In 49 / 50 for example, Would equal 0. We need at least 1 of an increase.
638  // Default div_amount is 2 or in low memory mode 12.
639  // On embedded you could use low amounts.
640 
641  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. */
643  /*
644  * not a really small number (under div amount),
645  * and so use the div amount
646  */
647  ;
648 
649  if (__builtin_add_overflow(old_size_to_add_at_least_one_to, old_size_to_add_at_least_one_to / div_amount, &addition))
650  {
651  /* 0 on error. */
652  return 0;
653  }
654 
655  return addition;
656 }
657 
658 #else /* GNUC */
659 // Fallback implementation for other compilers
660 
661 static inline size_t FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(size_t siz)
662 {
663  // In 49 / 50 for example, Would equal 0. We need at least 1 of an increase.
664  // Default div_amount is 2 or in low memory mode 12.
665  // On embedded you could use low amounts.
666 
667  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. */
669  /*
670  * not a really small number (under div amount),
671  * and so use the div amount
672  */
673  ;
674 
675  // Check for potential overflow before performing the addition
676  if (siz > SIZE_MAX / 2 || siz > (SIZE_MAX - siz) / 2)
677  {
678  /* 0 on error (overflow). */
679  return 0;
680  }
681 
682  // Calculate the new size after 1.5x reallocation
683  const size_t addition = siz + (siz / div_amount);
684 
685  // Return the result of the addition
686  return addition;
687 }
688 
689 #endif
690 
691 /* For copy_file() */
692 #ifndef FOUNDATIONAL_LIB_COPY_SIZE_AMOUNT
693 #define FOUNDATIONAL_LIB_COPY_SIZE_AMOUNT 4096
694 #endif
695 
696 #if FOUNDATIONAL_LIB_UNSAFE_FUNCTIONS_ENABLED
697 /* For backticks() */
698 #ifndef FOUNDATIONAL_LIB_POPEN_INITIAL_ALLOC_SIZE
699 #define FOUNDATIONAL_LIB_POPEN_INITIAL_ALLOC_SIZE 4096
700 #endif
701 #endif
702 
703 /* Choose which functions you want. */
704 
705 #ifndef FOUNDATIONAL_LIB_ATOI
706 #define FOUNDATIONAL_LIB_ATOI atoi
707 #endif
708 
709 /* File IO */
710 
711 #if FOUNDATIONAL_LIB_UNSAFE_FUNCTIONS_ENABLED
712 #ifdef _WIN32
713 #define FOUNDATIONAL_LIB_POPEN _popen
714 #define FOUNDATIONAL_LIB_PCLOSE _pclose
715 #else
716 #define FOUNDATIONAL_LIB_POPEN popen
717 #define FOUNDATIONAL_LIB_PCLOSE pclose
718 #endif
719 #endif
720 
721 #ifndef FOUNDATIONAL_LIB_FERROR
722 #define FOUNDATIONAL_LIB_FERROR ferror
723 #endif
724 
725 #ifdef _WIN32
726 #ifndef FOUNDATIONAL_LIB_FSEEKO
727 #define FOUNDATIONAL_LIB_FSEEKO _fseeki64
728 #endif
729 
730 #ifndef FOUNDATIONAL_LIB_FTELLO
731 #define FOUNDATIONAL_LIB_FTELLO _ftelli64
732 #endif
733 #else
734 #ifndef FOUNDATIONAL_LIB_FSEEKO
735 #define FOUNDATIONAL_LIB_FSEEKO fseeko
736 #endif
737 
738 #ifndef FOUNDATIONAL_LIB_FTELLO
739 #define FOUNDATIONAL_LIB_FTELLO ftello
740 #endif
741 
742 #endif
743 
744 #ifndef FOUNDATIONAL_LIB_FREAD
745 #define FOUNDATIONAL_LIB_FREAD fread
746 #endif
747 
748 #ifndef FOUNDATIONAL_LIB_FWRITE
749 #define FOUNDATIONAL_LIB_FWRITE fwrite
750 #endif
751 
752 #ifndef FOUNDATIONAL_LIB_FOPEN
753 #define FOUNDATIONAL_LIB_FOPEN fopen
754 #endif
755 
756 #ifndef FOUNDATIONAL_LIB_FCLOSE
757 #define FOUNDATIONAL_LIB_FCLOSE fclose
758 #endif
759 
760 /* Memory allocation macros that you can customize */
761 
762 #ifndef FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC
763 #define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC malloc
764 #endif
765 
766 #ifndef FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC
767 #define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC realloc
768 #endif
769 
770 #ifndef FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC
771 #define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC calloc
772 #endif
773 
774 #ifndef FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE
775 #define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE free
776 #endif
777 
778 #ifndef FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP
779 #define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP strdup
780 #endif
781 
785 #ifndef FOUNDATIONAL_LIB_NETWORK_FUNCTIONS_ENABLED
786 #define FOUNDATIONAL_LIB_NETWORK_FUNCTIONS_ENABLED 0
787 #endif
788 
789 #if FOUNDATIONAL_LIB_NETWORK_FUNCTIONS_ENABLED
790 #define FOUNDATIONAL_LIB_INITIAL_NETWORK_DOWNLOAD_BUFFER_SIZE 8192
791 #endif
792 
793 #ifndef FOUNDATIONAL_LIB_HASH_INITIAL_CAPACITY
801 #define FOUNDATIONAL_LIB_HASH_INITIAL_CAPACITY 16
802 #endif
803 
804 #ifndef FOUNDATIONAL_LIB_HASH_LOAD_FACTOR_THRESHOLD
813 #define FOUNDATIONAL_LIB_HASH_LOAD_FACTOR_THRESHOLD 0.75
814 #endif
815 
816 #ifndef FOUNDATIONAL_LIB_FUNC
817 /*
818  * One thing you can do, if you want "strict mode" on, you can define this to be and have -Werror on.
819  * That way, if any errors are not accounted for, instead of dealing with error handlers, the code just won't compile.
820  */
821 #define FOUNDATIONAL_LIB_FUNC static inline
822 #endif
823 
824 #ifndef FOUNDATIONAL_LIB_THREAD_FUNCTIONS_ENABLED
832 #define FOUNDATIONAL_LIB_THREAD_FUNCTIONS_ENABLED 1
833 #endif
834 
848 
856 #define FOUNDATIONAL_LIB_set_aggressive_die(mode) \
857  { \
858  FOUNDATIONAL_LIB_aggressive_die = (mode); \
859  }
860 
867 #define FOUNDATIONAL_LIB_get_aggressive_die() FOUNDATIONAL_LIB_aggressive_die
868 
869 #ifndef FOUNDATIONAL_LIB_die_aggressively_if_enabled
878 #define FOUNDATIONAL_LIB_die_aggressively_if_enabled() \
879  if (FOUNDATIONAL_LIB_UNLIKELY(FOUNDATIONAL_LIB_aggressive_die)) \
880  { \
881  FOUNDATIONAL_LIB_FPRINTF(stderr, "Error: %s: %s.\n", __func__, strerror(errno)); \
882  exit(EXIT_FAILURE); /* Use default exit, only place in library this is used, adjust as needed. */ \
883  }
884 #endif
885 
896 static inline void free_array(void **array, size_t len)
897 {
898  while (len--)
899  {
901  }
903 }
904 
915 static inline void free_string_array(char **array, size_t len)
916 {
917  while (len--)
918  {
920  }
922 }
923 
933 FOUNDATIONAL_LIB_FUNC char *int_to_string(long long int number)
934 {
935  // Allocate a fixed-size buffer for the string
937 
938  char *p;
939  long long a;
940  char *b;
941  char temp;
942  unsigned long long u;
943 
944  p = buffer;
945 
946  if (number < 0)
947  {
948  *p++ = '-';
949  number = 0 - number;
950  }
951  u = (long long)number;
952 
953  b = p;
954 
955  do
956  {
957  a = u % 10;
958  u /= 10;
959  *p++ = a + '0';
960  } while (u > 0);
961 
962  *p-- = '\0';
963  do
964  {
965  temp = *p;
966  *p = *b;
967  *b = temp;
968  --p;
969  ++b;
970  } while (b < p);
971 
972  // Duplicate the buffer using strdup
973  char *return_value = strdup(buffer);
974  if (FOUNDATIONAL_LIB_UNLIKELY(return_value == NULL))
975  {
976  // Handle allocation failure
978  return NULL;
979  }
980 
981  return return_value;
982 }
983 
993 FOUNDATIONAL_LIB_FUNC void int_to_string_with_buffer(long long int number, char *buffer)
994 {
995  char *p;
996  unsigned long long a;
997  char *b;
998  char temp;
999  unsigned long long u;
1000 
1001  p = buffer;
1002 
1003  if (number < 0)
1004  {
1005  *p++ = '-';
1006  number = 0 - number;
1007  }
1008  u = (unsigned long)number;
1009 
1010  b = p;
1011 
1012  do
1013  {
1014  a = u % 10;
1015  u /= 10;
1016  *p++ = a + '0';
1017  } while (u > 0);
1018 
1019  *p-- = '\0';
1020  do
1021  {
1022  temp = *p;
1023  *p = *b;
1024  *b = temp;
1025  --p;
1026  ++b;
1027  } while (b < p);
1028 }
1029 
1030 /*
1031  * @brief
1032  * This function is for maximally-efficient conversion of unsigned numbers to strings - no nonsense.
1033  * Output should be large enough to hold the number. length of "18446744073709551615" + null byte = 21 chars.
1034  *
1035  * @param unsigned_value The number
1036  * @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).
1037  */
1038 FOUNDATIONAL_LIB_FUNC void utoa(size_t unsigned_value, char *output)
1039 {
1041 
1042  char *p = output;
1043  size_t a;
1044  char *b = output;
1045  char temp;
1046 
1047  do
1048  {
1049  a = unsigned_value % 10;
1050  unsigned_value /= 10;
1051  *p++ = a + '0';
1052  } while (unsigned_value);
1053 
1054  *p-- = '\0';
1055 
1056  do
1057  {
1058  temp = *p;
1059  *p = *b;
1060  *b = temp;
1061  --p;
1062  ++b;
1063  } while (b < p);
1064 }
1065 
1076 {
1078 
1079  utoa(number, buffer);
1080 
1081  char *return_value = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(buffer);
1082  if (FOUNDATIONAL_LIB_UNLIKELY(return_value == NULL))
1083  {
1085  return NULL;
1086  }
1087 
1088  return return_value;
1089 }
1090 
1101 FOUNDATIONAL_LIB_FUNC void print_uint_array(const unsigned long long *array, size_t size)
1102 {
1105 
1106  for (size_t i = 0; i < size; ++i)
1107  {
1108  const unsigned int value = array[i];
1110 
1111  utoa(value, buf);
1112  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1113  if (i < size - 1)
1114  {
1117  }
1118  }
1120 }
1132 FOUNDATIONAL_LIB_FUNC void print_uint_ptr_array(const unsigned int **array, size_t size)
1133 {
1136 
1137  for (size_t i = 0; i < size; ++i)
1138  {
1139  const unsigned int value = *array[i];
1141 
1142  utoa(value, buf);
1143  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1144  if (i < size - 1)
1145  {
1148  }
1149  }
1151 }
1152 
1163 FOUNDATIONAL_LIB_FUNC void print_int_array(const int *array, size_t size)
1164 {
1167 
1168  for (size_t i = 0; i < size; ++i)
1169  {
1170  const int value = array[i];
1172 
1173  int_to_string_with_buffer(value, buf);
1174  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1175  if (i < size - 1)
1176  {
1179  }
1180  }
1182 }
1183 
1195 FOUNDATIONAL_LIB_FUNC void print_int_ptr_array(const int **array, size_t size)
1196 {
1199 
1200  for (size_t i = 0; i < size; ++i)
1201  {
1202  const unsigned int value = *array[i];
1204 
1205  int_to_string_with_buffer(value, buf);
1206  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1207  if (i < size - 1)
1208  {
1211  }
1212  }
1214 }
1215 
1216 // print_uchar and print_uchar_array omitted because a uchar is too similar to a string.
1217 
1230 {
1233 
1234  for (size_t i = 0; i < size; ++i)
1235  {
1236  FOUNDATIONAL_LIB_FPUTS(array[i], stdout);
1237  if (i < size - 1)
1238  {
1241  }
1242  }
1244 }
1245 
1258 {
1261 
1262  for (size_t i = 0; i < size; ++i)
1263  {
1264  FOUNDATIONAL_LIB_FPUTS(*(array[i]), stdout);
1265  if (i < size - 1)
1266  {
1269  }
1270  }
1272 }
1273 
1284 FOUNDATIONAL_LIB_FUNC void print_ushort_array(const unsigned short *array, size_t size)
1285 {
1288 
1289  for (size_t i = 0; i < size; ++i)
1290  {
1291  const unsigned short value = array[i];
1293 
1294  utoa(value, buf);
1295  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1296  if (i < size - 1)
1297  {
1300  }
1301  }
1303 }
1304 
1317 FOUNDATIONAL_LIB_FUNC void print_ushort_ptr_array(const unsigned short **array, size_t size)
1318 {
1321 
1322  for (size_t i = 0; i < size; ++i)
1323  {
1324  const unsigned short value = *(array[i]);
1326 
1327  utoa(value, buf);
1328  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1329  if (i < size - 1)
1330  {
1333  }
1334  }
1336 }
1337 
1348 FOUNDATIONAL_LIB_FUNC void print_short_array(const short *array, size_t size)
1349 {
1352 
1353  for (size_t i = 0; i < size; ++i)
1354  {
1355  const short value = array[i];
1357 
1358  int_to_string_with_buffer(value, buf);
1359  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1360  if (i < size - 1)
1361  {
1364  }
1365  }
1367 }
1368 
1381 FOUNDATIONAL_LIB_FUNC void print_short_ptr_array(const short **array, size_t size)
1382 {
1385 
1386  for (size_t i = 0; i < size; ++i)
1387  {
1388  const short value = *(array[i]);
1390 
1391  int_to_string_with_buffer(value, buf);
1392  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1393  if (i < size - 1)
1394  {
1397  }
1398  }
1400 }
1401 
1412 FOUNDATIONAL_LIB_FUNC void print_ulong_array(const unsigned long *array, size_t size)
1413 {
1416 
1417  for (size_t i = 0; i < size; ++i)
1418  {
1419  const unsigned long value = array[i];
1421 
1422  utoa(value, buf);
1423  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1424  if (i < size - 1)
1425  {
1428  }
1429  }
1431 }
1432 
1445 FOUNDATIONAL_LIB_FUNC void print_ulong_ptr_array(const unsigned long **array, size_t size)
1446 {
1449 
1450  for (size_t i = 0; i < size; ++i)
1451  {
1452  const unsigned long value = *(array[i]);
1454 
1455  utoa(value, buf);
1456  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1457  if (i < size - 1)
1458  {
1461  }
1462  }
1464 }
1465 
1476 FOUNDATIONAL_LIB_FUNC void print_long_array(const long *array, size_t size)
1477 {
1480 
1481  for (size_t i = 0; i < size; ++i)
1482  {
1483  const long value = array[i];
1485 
1486  int_to_string_with_buffer(value, buf);
1487  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1488  if (i < size - 1)
1489  {
1492  }
1493  }
1495 }
1496 
1506 FOUNDATIONAL_LIB_FUNC void print_long_ptr_array(const long **array, size_t size)
1507 {
1510 
1511  for (size_t i = 0; i < size; ++i)
1512  {
1513  const long value = *(array[i]);
1515 
1516  int_to_string_with_buffer(value, buf);
1517  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1518  if (i < size - 1)
1519  {
1522  }
1523  }
1525 }
1526 
1536 FOUNDATIONAL_LIB_FUNC void print_ulong_long_array(const unsigned long long *array, size_t size)
1537 {
1540 
1541  for (size_t i = 0; i < size; ++i)
1542  {
1543  const unsigned long long value = array[i];
1545 
1546  utoa(value, buf);
1547  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1548  if (i < size - 1)
1549  {
1552  }
1553  }
1555 }
1556 
1567 FOUNDATIONAL_LIB_FUNC void print_ulong_long_ptr_array(const unsigned long long **array, size_t size)
1568 {
1571 
1572  for (size_t i = 0; i < size; ++i)
1573  {
1574  const unsigned long long value = *(array[i]);
1576 
1577  utoa(value, buf);
1578  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1579  if (i < size - 1)
1580  {
1583  }
1584  }
1586 }
1587 
1597 FOUNDATIONAL_LIB_FUNC void print_long_long_array(const long long *array, size_t size)
1598 {
1601 
1602  for (size_t i = 0; i < size; ++i)
1603  {
1604  const long long value = array[i];
1606 
1607  int_to_string_with_buffer(value, buf);
1608  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1609  if (i < size - 1)
1610  {
1613  }
1614  }
1616 }
1617 
1628 FOUNDATIONAL_LIB_FUNC void print_long_long_ptr_array(const long long **array, size_t size)
1629 {
1632 
1633  for (size_t i = 0; i < size; ++i)
1634  {
1635  const long long value = *(array[i]);
1637 
1638  int_to_string_with_buffer(value, buf);
1639  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1640  if (i < size - 1)
1641  {
1644  }
1645  }
1647 }
1648 
1658 FOUNDATIONAL_LIB_FUNC void print_float_array(const float *array, size_t size)
1659 {
1662  for (size_t i = 0; i < size; ++i)
1663  {
1664  FOUNDATIONAL_LIB_PRINTF("%f", array[i]);
1665  if (i < size - 1)
1666  {
1667  FOUNDATIONAL_LIB_FPUTS(", ", stdout);
1668  }
1669  }
1670 
1672 }
1673 
1684 FOUNDATIONAL_LIB_FUNC void print_float_ptr_array(const float **array, size_t size)
1685 {
1688  for (size_t i = 0; i < size; ++i)
1689  {
1690  FOUNDATIONAL_LIB_PRINTF("%f", *array[i]);
1691  if (i < size - 1)
1692  {
1693  FOUNDATIONAL_LIB_FPUTS(", ", stdout);
1694  }
1695  }
1696 
1698 }
1699 
1709 FOUNDATIONAL_LIB_FUNC void print_double_array(const double *array, size_t size)
1710 {
1713  for (size_t i = 0; i < size; ++i)
1714  {
1715  FOUNDATIONAL_LIB_PRINTF("%lf", array[i]);
1716  if (i < size - 1)
1717  {
1718  FOUNDATIONAL_LIB_FPUTS(", ", stdout);
1719  }
1720  }
1721 
1723 }
1724 
1735 FOUNDATIONAL_LIB_FUNC void print_double_ptr_array(const double **array, size_t size)
1736 {
1739  for (size_t i = 0; i < size; ++i)
1740  {
1741  FOUNDATIONAL_LIB_PRINTF("%lf", *array[i]);
1742  if (i < size - 1)
1743  {
1744  FOUNDATIONAL_LIB_FPUTS(", ", stdout);
1745  }
1746  }
1747 
1749 }
1750 
1760 FOUNDATIONAL_LIB_FUNC void print_size_t_array(const size_t *array, size_t size)
1761 {
1764 
1765  for (size_t i = 0; i < size; ++i)
1766  {
1767  const size_t value = array[i];
1769 
1770  int_to_string_with_buffer(value, buf);
1771  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1772  if (i < size - 1)
1773  {
1776  }
1777  }
1779 }
1780 
1791 FOUNDATIONAL_LIB_FUNC void print_size_t_ptr_array(const size_t **array, size_t size)
1792 {
1795 
1796  for (size_t i = 0; i < size; ++i)
1797  {
1798  const size_t value = *(array[i]);
1800 
1801  int_to_string_with_buffer(value, buf);
1802  FOUNDATIONAL_LIB_FPUTS(buf, stdout);
1803  if (i < size - 1)
1804  {
1807  }
1808  }
1810 }
1811 
1823 FOUNDATIONAL_LIB_FUNC void print_uint_array_to_stream(const unsigned int *array, size_t size, FILE *stream)
1824 {
1826  FOUNDATIONAL_LIB_FPUTC('[', stream);
1827  for (size_t i = 0; i < size; ++i)
1828  {
1829  FOUNDATIONAL_LIB_FPRINTF(stream, "%u", array[i]);
1830  if (i < size - 1)
1831  {
1832  FOUNDATIONAL_LIB_FPUTS(", ", stream);
1833  }
1834  }
1835  FOUNDATIONAL_LIB_FPUTS("]", stream);
1836 }
1837 
1850 FOUNDATIONAL_LIB_FUNC void print_uint_ptr_array_to_stream(const unsigned int **array, size_t size, FILE *stream)
1851 {
1853  FOUNDATIONAL_LIB_FPUTC('[', stream);
1854  for (size_t i = 0; i < size; ++i)
1855  {
1856  FOUNDATIONAL_LIB_FPRINTF(stream, "%u", *array[i]);
1857  if (i < size - 1)
1858  {
1859  FOUNDATIONAL_LIB_FPUTS(", ", stream);
1860  }
1861  }
1862  FOUNDATIONAL_LIB_FPUTS("]", stream);
1863 }
1864 
1875 FOUNDATIONAL_LIB_FUNC void print_int_array_to_stream(const int *array, size_t size, FILE *stream)
1876 {
1878  FOUNDATIONAL_LIB_FPUTC('[', stream);
1879  for (size_t i = 0; i < size; ++i)
1880  {
1881  FOUNDATIONAL_LIB_FPRINTF(stream, "%d", array[i]);
1882  if (i < size - 1)
1883  {
1884  FOUNDATIONAL_LIB_FPUTS(", ", stream);
1885  }
1886  }
1887  FOUNDATIONAL_LIB_FPUTS("]", stream);
1888 }
1889 
1902 FOUNDATIONAL_LIB_FUNC void print_int_ptr_array_to_stream(const int **array, size_t size, FILE *stream)
1903 {
1905  FOUNDATIONAL_LIB_FPUTC('[', stream);
1906  for (size_t i = 0; i < size; ++i)
1907  {
1908  FOUNDATIONAL_LIB_FPRINTF(stream, "%d", *array[i]);
1909  if (i < size - 1)
1910  {
1911  FOUNDATIONAL_LIB_FPUTS(", ", stream);
1912  }
1913  }
1914  FOUNDATIONAL_LIB_FPUTS("]", stream);
1915 }
1916 
1928 FOUNDATIONAL_LIB_FUNC void print_uchar_array_to_stream(const unsigned char *array, size_t size, FILE *stream)
1929 {
1931  FOUNDATIONAL_LIB_FPUTC('[', stream);
1932  for (size_t i = 0; i < size; ++i)
1933  {
1934  FOUNDATIONAL_LIB_FPRINTF(stream, "%c", array[i]);
1935  if (i < size - 1)
1936  {
1937  FOUNDATIONAL_LIB_FPUTS(", ", stream);
1938  }
1939  }
1940  FOUNDATIONAL_LIB_FPUTS("]", stream);
1941 }
1942 
1953 FOUNDATIONAL_LIB_FUNC void print_char_array_to_stream(const char *array, size_t size, FILE *stream)
1954 {
1956  FOUNDATIONAL_LIB_FPUTC('[', stream);
1957  for (size_t i = 0; i < size; ++i)
1958  {
1959  FOUNDATIONAL_LIB_FPRINTF(stream, "%c", array[i]);
1960  if (i < size - 1)
1961  {
1962  FOUNDATIONAL_LIB_FPUTS(", ", stream);
1963  }
1964  }
1965  FOUNDATIONAL_LIB_FPUTS("]", stream);
1966 }
1967 
1979 FOUNDATIONAL_LIB_FUNC void print_string_array_to_stream(char **array, size_t size, FILE *stream)
1980 {
1982  FOUNDATIONAL_LIB_FPUTC('[', stream);
1983  for (size_t i = 0; i < size; ++i)
1984  {
1985  FOUNDATIONAL_LIB_FPUTS(array[i], stream);
1986  if (i < size - 1)
1987  {
1988  FOUNDATIONAL_LIB_FPUTS(", ", stream);
1989  }
1990  }
1991  FOUNDATIONAL_LIB_FPUTS("]", stream);
1992 }
1993 
2006 FOUNDATIONAL_LIB_FUNC void print_string_array_array_to_stream(char ***array, size_t size, FILE *stream)
2007 {
2009  FOUNDATIONAL_LIB_FPUTC('[', stream);
2010  for (size_t i = 0; i < size; ++i)
2011  {
2012  FOUNDATIONAL_LIB_FPUTS(*array[i], stream);
2013  if (i < size - 1)
2014  {
2015  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2016  }
2017  }
2018  FOUNDATIONAL_LIB_FPUTS("]", stream);
2019 }
2020 
2032 FOUNDATIONAL_LIB_FUNC void print_ushort_array_to_stream(const unsigned short *array, size_t size, FILE *stream)
2033 {
2035  FOUNDATIONAL_LIB_FPUTC('[', stream);
2036  for (size_t i = 0; i < size; ++i)
2037  {
2038  FOUNDATIONAL_LIB_FPRINTF(stream, "%hu", array[i]);
2039  if (i < size - 1)
2040  {
2041  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2042  }
2043  }
2044  FOUNDATIONAL_LIB_FPUTS("]", stream);
2045 }
2046 
2059 FOUNDATIONAL_LIB_FUNC void print_ushort_ptr_array_to_stream(const unsigned short **array, size_t size, FILE *stream)
2060 {
2062  FOUNDATIONAL_LIB_FPUTC('[', stream);
2063  for (size_t i = 0; i < size; ++i)
2064  {
2065  FOUNDATIONAL_LIB_FPRINTF(stream, "%hu", *array[i]);
2066  if (i < size - 1)
2067  {
2068  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2069  }
2070  }
2071  FOUNDATIONAL_LIB_FPUTS("]", stream);
2072 }
2073 
2084 FOUNDATIONAL_LIB_FUNC void print_short_array_to_stream(const short *array, size_t size, FILE *stream)
2085 {
2087  FOUNDATIONAL_LIB_FPUTC('[', stream);
2088  for (size_t i = 0; i < size; ++i)
2089  {
2090  FOUNDATIONAL_LIB_FPRINTF(stream, "%d", array[i]);
2091  if (i < size - 1)
2092  {
2093  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2094  }
2095  }
2096  FOUNDATIONAL_LIB_FPUTS("]", stream);
2097 }
2098 
2111 FOUNDATIONAL_LIB_FUNC void print_short_ptr_array_to_stream(const short **array, size_t size, FILE *stream)
2112 {
2114  FOUNDATIONAL_LIB_FPUTC('[', stream);
2115  for (size_t i = 0; i < size; i++)
2116  {
2117  FOUNDATIONAL_LIB_FPRINTF(stream, "%d", *array[i]);
2118  if (i < size - 1)
2119  {
2120  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2121  }
2122  }
2123  FOUNDATIONAL_LIB_FPUTS("]", stream);
2124 }
2125 
2137 FOUNDATIONAL_LIB_FUNC void print_ulong_array_to_stream(const unsigned long *array, size_t size, FILE *stream)
2138 {
2140  FOUNDATIONAL_LIB_FPUTC('[', stream);
2141  for (size_t i = 0; i < size; i++)
2142  {
2143  FOUNDATIONAL_LIB_FPRINTF(stream, "%lu", array[i]);
2144  if (i < size - 1)
2145  {
2146  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2147  }
2148  }
2149  FOUNDATIONAL_LIB_FPUTS("]", stream);
2150 }
2151 
2164 FOUNDATIONAL_LIB_FUNC void print_ulong_ptr_array_to_stream(const unsigned long **array, size_t size, FILE *stream)
2165 {
2167  FOUNDATIONAL_LIB_FPUTC('[', stream);
2168  for (size_t i = 0; i < size; i++)
2169  {
2170  FOUNDATIONAL_LIB_FPRINTF(stream, "%lu", *array[i]);
2171  if (i < size - 1)
2172  {
2173  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2174  }
2175  }
2176  FOUNDATIONAL_LIB_FPUTS("]", stream);
2177 }
2178 
2189 FOUNDATIONAL_LIB_FUNC void print_long_array_to_stream(const long *array, size_t size, FILE *stream)
2190 {
2192  FOUNDATIONAL_LIB_FPUTC('[', stream);
2193  for (size_t i = 0; i < size; i++)
2194  {
2195  FOUNDATIONAL_LIB_FPRINTF(stream, "%ld", array[i]);
2196  if (i < size - 1)
2197  {
2198  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2199  }
2200  }
2201  FOUNDATIONAL_LIB_FPUTS("]", stream);
2202 }
2203 
2216 FOUNDATIONAL_LIB_FUNC void print_long_ptr_array_to_stream(const long **array, size_t size, FILE *stream)
2217 {
2219  FOUNDATIONAL_LIB_FPUTC('[', stream);
2220  for (size_t i = 0; i < size; i++)
2221  {
2222  FOUNDATIONAL_LIB_FPRINTF(stream, "%ld", *array[i]);
2223  if (i < size - 1)
2224  {
2225  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2226  }
2227  }
2228  FOUNDATIONAL_LIB_FPUTS("]", stream);
2229 }
2230 
2243 FOUNDATIONAL_LIB_FUNC void print_ulong_long_array_to_stream(const unsigned long long *array, size_t size, FILE *stream)
2244 {
2246  FOUNDATIONAL_LIB_FPUTC('[', stream);
2247  for (size_t i = 0; i < size; i++)
2248  {
2249  const unsigned long long value = array[i];
2251 
2252  utoa(value, buffer);
2253  FOUNDATIONAL_LIB_FPUTS(buffer, stream);
2254  if (i < size - 1)
2255  {
2256  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2257  }
2258  }
2259  FOUNDATIONAL_LIB_FPUTS("]", stream);
2260 }
2261 
2274 FOUNDATIONAL_LIB_FUNC void print_ulong_long_ptr_array_to_stream(const unsigned long long **array, size_t size, FILE *stream)
2275 {
2277  FOUNDATIONAL_LIB_FPUTC('[', stream);
2278  for (size_t i = 0; i < size; i++)
2279  {
2280  const unsigned long long value = *(array[i]);
2282 
2283  utoa(value, buffer);
2284  FOUNDATIONAL_LIB_FPUTS(buffer, stream);
2285  if (i < size - 1)
2286  {
2287  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2288  }
2289  }
2290  FOUNDATIONAL_LIB_FPUTS("]", stream);
2291 }
2292 
2304 FOUNDATIONAL_LIB_FUNC void print_long_long_array_to_stream(const long long *array, size_t size, FILE *stream)
2305 {
2307  FOUNDATIONAL_LIB_FPUTC('[', stream);
2308  for (size_t i = 0; i < size; i++)
2309  {
2310  const unsigned long long value = array[i];
2312 
2313  int_to_string_with_buffer(value, buffer);
2314 
2315  FOUNDATIONAL_LIB_FPUTS(buffer, stream);
2316  if (i < size - 1)
2317  {
2318  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2319  }
2320  }
2321  FOUNDATIONAL_LIB_FPUTS("]", stream);
2322 }
2323 
2337 FOUNDATIONAL_LIB_FUNC void print_long_long_ptr_array_to_stream(const long long **array, size_t size, FILE *stream)
2338 {
2340  FOUNDATIONAL_LIB_FPUTC('[', stream);
2341  for (size_t i = 0; i < size; i++)
2342  {
2343  const long long value = *(array[i]);
2344 
2346 
2347  int_to_string_with_buffer(value, buffer);
2348  FOUNDATIONAL_LIB_FPUTS(buffer, stream);
2349  if (i < size - 1)
2350  {
2351  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2352  }
2353  }
2354  FOUNDATIONAL_LIB_FPUTS("]", stream);
2355 }
2356 
2368 FOUNDATIONAL_LIB_FUNC void print_float_array_to_stream(const float *array, size_t size, FILE *stream)
2369 {
2371  FOUNDATIONAL_LIB_FPUTC('[', stream);
2372  for (size_t i = 0; i < size; i++)
2373  {
2374  FOUNDATIONAL_LIB_FPRINTF(stream, "%f", array[i]);
2375  if (i < size - 1)
2376  {
2377  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2378  }
2379  }
2380  FOUNDATIONAL_LIB_FPUTS("]", stream);
2381 }
2382 
2395 FOUNDATIONAL_LIB_FUNC void print_float_ptr_array_to_stream(const float **array, size_t size, FILE *stream)
2396 {
2398  FOUNDATIONAL_LIB_FPUTC('[', stream);
2399  for (size_t i = 0; i < size; i++)
2400  {
2401  FOUNDATIONAL_LIB_FPRINTF(stream, "%f", *array[i]);
2402  if (i < size - 1)
2403  {
2404  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2405  }
2406  }
2407  FOUNDATIONAL_LIB_FPUTS("]", stream);
2408 }
2409 
2421 FOUNDATIONAL_LIB_FUNC void print_double_array_to_stream(const double *array, size_t size, FILE *stream)
2422 {
2424  FOUNDATIONAL_LIB_FPUTC('[', stream);
2425  for (size_t i = 0; i < size; i++)
2426  {
2427  FOUNDATIONAL_LIB_FPRINTF(stream, "%lf", array[i]);
2428  if (i < size - 1)
2429  {
2430  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2431  }
2432  }
2433  FOUNDATIONAL_LIB_FPUTS("]", stream);
2434 }
2435 
2448 FOUNDATIONAL_LIB_FUNC void print_double_ptr_array_to_stream(const double **array, size_t size, FILE *stream)
2449 {
2451  FOUNDATIONAL_LIB_FPUTC('[', stream);
2452  for (size_t i = 0; i < size; i++)
2453  {
2454  FOUNDATIONAL_LIB_FPRINTF(stream, "%lf", *array[i]);
2455  if (i < size - 1)
2456  {
2457  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2458  }
2459  }
2460  FOUNDATIONAL_LIB_FPUTS("]", stream);
2461 }
2462 
2474 FOUNDATIONAL_LIB_FUNC void print_size_t_array_to_stream(const size_t *array, size_t size, FILE *stream)
2475 {
2477  FOUNDATIONAL_LIB_FPUTC('[', stream);
2478  for (size_t i = 0; i < size; i++)
2479  {
2480 #pragma GCC diagnostic push
2481 #pragma GCC diagnostic ignored "-Wpragmas"
2482 #pragma GCC diagnostic ignored "-Wformat"
2483 #pragma GCC diagnostic ignored "-Wformat-extra-args"
2484  FOUNDATIONAL_LIB_FPRINTF(stream, "%zu", array[i]);
2485 
2486 #pragma GCC diagnostic pop
2487  if (i < size - 1)
2488  {
2489  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2490  }
2491  }
2492  FOUNDATIONAL_LIB_FPUTS("]", stream);
2493 }
2494 
2507 FOUNDATIONAL_LIB_FUNC void print_size_t_ptr_array_to_stream(const size_t **array, size_t size, FILE *stream)
2508 {
2510  FOUNDATIONAL_LIB_FPUTC('[', stream);
2511  for (size_t i = 0; i < size; i++)
2512  {
2513 #pragma GCC diagnostic push
2514 #pragma GCC diagnostic ignored "-Wpragmas"
2515 #pragma GCC diagnostic ignored "-Wformat"
2516 #pragma GCC diagnostic ignored "-Wformat-extra-args"
2517 
2518  FOUNDATIONAL_LIB_FPRINTF(stream, "%zu", *array[i]);
2519 #pragma GCC diagnostic pop
2520  if (i < size - 1)
2521  {
2522  FOUNDATIONAL_LIB_FPUTS(", ", stream);
2523  }
2524  }
2525  FOUNDATIONAL_LIB_FPUTS("]", stream);
2526 }
2527 
2541 FOUNDATIONAL_LIB_FUNC void *arraydup(const void *array, size_t num_mem, size_t size)
2542 {
2544  const size_t tot_size = FOUNDATIONAL_LIB_safe_mul(num_mem, size);
2545 
2546  // Check num_mem so safe_mul doesn't get confused.
2547  if (FOUNDATIONAL_LIB_UNLIKELY(num_mem && tot_size == 0))
2548  {
2549  /* Handle memory allocation failure */
2551  return NULL;
2552  }
2553  char *duplicate = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(tot_size);
2554 
2555  if (FOUNDATIONAL_LIB_UNLIKELY(duplicate == NULL))
2556  {
2557  /* Handle memory allocation failure */
2559  return NULL;
2560  }
2561 
2562  for (size_t i = 0; i < tot_size; i++)
2563  {
2564  duplicate[i] = ((char *)array)[i];
2565  }
2566 
2567  return (void *)duplicate;
2568 }
2569 
2580 static inline int equal_strings(const char *first, const char *second) { return FOUNDATIONAL_LIB_STRCMP(first, second) == 0; }
2581 
2595 static inline int equal_array_of_uints(const unsigned int *array, const unsigned int *array2, size_t size)
2596 {
2597  for (size_t i = 0; i < size; ++i)
2598  {
2599  if (array[i] != array2[i])
2600  {
2601  return 0;
2602  }
2603  }
2604  return 1;
2605 }
2606 
2620 static inline int equal_array_of_uint_ptrs(const unsigned int **array, const unsigned int **array2, size_t size)
2621 {
2622  for (size_t i = 0; i < size; ++i)
2623  {
2624  if (array[i] != array2[i])
2625  {
2626  return 0;
2627  }
2628  }
2629  return 1;
2630 }
2631 
2644 static inline int equal_array_of_ints(const int *array, const int *array2, size_t size)
2645 {
2646  for (size_t i = 0; i < size; ++i)
2647  {
2648  if (array[i] != array2[i])
2649  {
2650  return 0;
2651  }
2652  }
2653  return 1;
2654 }
2655 
2669 static inline int equal_array_of_int_ptrs(const int **array, const int **array2, size_t size)
2670 {
2671  for (size_t i = 0; i < size; ++i)
2672  {
2673  if (array[i] != array2[i])
2674  {
2675  return 0;
2676  }
2677  }
2678  return 1;
2679 }
2680 
2694 static inline int equal_array_of_uchars(const unsigned char *array, const unsigned char *array2, size_t size)
2695 {
2696  for (size_t i = 0; i < size; ++i)
2697  {
2698  if (array[i] != array2[i])
2699  {
2700  return 0;
2701  }
2702  }
2703  return 1;
2704 }
2705 
2719 static inline int equal_array_of_uchar_ptrs(const unsigned char **array, const unsigned char **array2, size_t size)
2720 {
2721  for (size_t i = 0; i < size; ++i)
2722  {
2723  if (array[i] != array2[i])
2724  {
2725  return 0;
2726  }
2727  }
2728  return 1;
2729 }
2730 
2743 static inline int equal_array_of_chars(const char *array, const char *array2, size_t size)
2744 {
2745  for (size_t i = 0; i < size; ++i)
2746  {
2747  if (array[i] != array2[i])
2748  {
2749  return 0;
2750  }
2751  }
2752  return 1;
2753 }
2754 
2768 static inline int equal_array_of_char_ptrs(const char **array, const char **array2, size_t size)
2769 {
2770  for (size_t i = 0; i < size; ++i)
2771  {
2772  if (array[i] != array2[i])
2773  {
2774  return 0;
2775  }
2776  }
2777  return 1;
2778 }
2779 
2793 static inline int equal_array_of_ushorts(const unsigned short *array, const unsigned short *array2, size_t size)
2794 {
2795  for (size_t i = 0; i < size; ++i)
2796  {
2797  if (array[i] != array2[i])
2798  {
2799  return 0;
2800  }
2801  }
2802  return 1;
2803 }
2804 
2820 static inline int equal_array_of_ushort_ptrs(const unsigned short **array, const unsigned short **array2, size_t size)
2821 {
2822  for (size_t i = 0; i < size; ++i)
2823  {
2824  if (array[i] != array2[i])
2825  {
2826  return 0;
2827  }
2828  }
2829  return 1;
2830 }
2831 
2845 static inline int equal_array_of_shorts(const short *array, const short *array2, size_t size)
2846 {
2847  for (size_t i = 0; i < size; ++i)
2848  {
2849  if (array[i] != array2[i])
2850  {
2851  return 0;
2852  }
2853  }
2854  return 1;
2855 }
2856 
2870 static inline int equal_array_of_short_ptrs(const short **array, const short **array2, size_t size)
2871 {
2872  for (size_t i = 0; i < size; ++i)
2873  {
2874  if (array[i] != array2[i])
2875  {
2876  return 0;
2877  }
2878  }
2879  return 1;
2880 }
2881 
2895 static inline int equal_array_of_ulongs(const unsigned long *array, const unsigned long *array2, size_t size)
2896 {
2897  for (size_t i = 0; i < size; ++i)
2898  {
2899  if (array[i] != array2[i])
2900  {
2901  return 0;
2902  }
2903  }
2904  return 1;
2905 }
2906 
2922 static inline int equal_array_of_ulong_ptrs(const unsigned long **array, const unsigned long **array2, size_t size)
2923 {
2924  for (size_t i = 0; i < size; ++i)
2925  {
2926  if (array[i] != array2[i])
2927  {
2928  return 0;
2929  }
2930  }
2931  return 1;
2932 }
2933 
2947 static inline int equal_array_of_longs(const long *array, const long *array2, size_t size)
2948 {
2949  for (size_t i = 0; i < size; ++i)
2950  {
2951  if (array[i] != array2[i])
2952  {
2953  return 0;
2954  }
2955  }
2956  return 1;
2957 }
2958 
2972 static inline int equal_array_of_long_ptrs(const long **array, const long **array2, size_t size)
2973 {
2974  for (size_t i = 0; i < size; ++i)
2975  {
2976  if (array[i] != array2[i])
2977  {
2978  return 0;
2979  }
2980  }
2981  return 1;
2982 }
2983 
2997 static inline int equal_array_of_ulong_longs(const unsigned long long *array, const unsigned long long *array2, size_t size)
2998 {
2999  for (size_t i = 0; i < size; ++i)
3000  {
3001  if (array[i] != array2[i])
3002  {
3003  return 0;
3004  }
3005  }
3006  return 1;
3007 }
3008 
3025 static inline int equal_array_of_ulong_long_ptrs(const unsigned long long **array, const unsigned long long **array2, size_t size)
3026 {
3027  for (size_t i = 0; i < size; ++i)
3028  {
3029  if (array[i] != array2[i])
3030  {
3031  return 0;
3032  }
3033  }
3034  return 1;
3035 }
3036 
3050 static inline int equal_array_of_long_longs(const long long *array, const long long *array2, size_t size)
3051 {
3052  for (size_t i = 0; i < size; ++i)
3053  {
3054  if (array[i] != array2[i])
3055  {
3056  return 0;
3057  }
3058  }
3059  return 1;
3060 }
3061 
3075 static inline int equal_array_of_long_long_ptrs(const long long **array, const long long **array2, size_t size)
3076 {
3077  for (size_t i = 0; i < size; ++i)
3078  {
3079  if (array[i] != array2[i])
3080  {
3081  return 0;
3082  }
3083  }
3084  return 1;
3085 }
3086 
3100 static inline int equal_array_of_floats(const float *array, const float *array2, size_t size)
3101 {
3102  for (size_t i = 0; i < size; ++i)
3103  {
3104  if (array[i] != array2[i])
3105  {
3106  return 0;
3107  }
3108  }
3109  return 1;
3110 }
3111 
3125 static inline int equal_array_of_float_ptrs(const float **array, const float **array2, size_t size)
3126 {
3127  for (size_t i = 0; i < size; ++i)
3128  {
3129  if (array[i] != array2[i])
3130  {
3131  return 0;
3132  }
3133  }
3134  return 1;
3135 }
3136 
3149 static inline int equal_array_of_doubles(const double *array, const double *array2, size_t size)
3150 {
3151  for (size_t i = 0; i < size; ++i)
3152  {
3153  if (array[i] != array2[i])
3154  {
3155  return 0;
3156  }
3157  }
3158  return 1;
3159 }
3160 
3173 static inline int equal_array_of_double_ptrs(const double **array, const double **array2, size_t size)
3174 {
3175  for (size_t i = 0; i < size; ++i)
3176  {
3177  if (array[i] != array2[i])
3178  {
3179  return 0;
3180  }
3181  }
3182  return 1;
3183 }
3184 
3197 static inline int equal_array_of_size_ts(const size_t *array, const size_t *array2, size_t size)
3198 {
3199  for (size_t i = 0; i < size; ++i)
3200  {
3201  if (array[i] != array2[i])
3202  {
3203  return 0;
3204  }
3205  }
3206  return 1;
3207 }
3208 
3221 static inline int equal_array_of_size_t_ptrs(const size_t **array, const size_t **array2, size_t size)
3222 {
3224  for (size_t i = 0; i < size; ++i)
3225  {
3226  if (array[i] != array2[i])
3227  {
3228  return 0;
3229  }
3230  }
3231  return 1;
3232 }
3233 
3246 FOUNDATIONAL_LIB_FUNC char *string_to_json(const char *input_string)
3247 {
3249  size_t escaped_length = 0;
3250  size_t input_length = 0;
3251 
3252  /* Calculate the length of the escaped string */
3253 
3254  while (input_string[input_length])
3255  {
3256  if (input_string[input_length] == '"' || input_string[input_length] == '\\')
3257  {
3258  // If the string uses most of memory and is filled with \ or ", there could be an overflow.
3259  // Check for this.
3260  // If you find this too slow, just change the macro definition.
3261  FOUNDATIONAL_LIB_safe_increment(escaped_length, overflow); // Need to escape with a backslash
3262  }
3263 
3264  // If the string uses most of memory and is filled with \ or ", there could be an overflow.
3265  // Check for this.
3266  FOUNDATIONAL_LIB_safe_increment(escaped_length, overflow);
3267 
3268  // Cannot overflow because it's a size_t that starts from 0.
3269  // (Actually, it can, if all of memory is nonzero.)
3270  // Do not check for this.
3271  ++input_length;
3272  }
3273 
3274  /* Calculate the length of the resulting JSON string */
3275 
3276  size_t json_length;
3277 
3278  json_length = escaped_length;
3279 
3280  // add 2 for double quotes
3281  if (FOUNDATIONAL_LIB_safe_add_2_ptr(json_length, 2, &json_length) == 0)
3282  goto overflow;
3283 
3284  size_t alloc_size;
3285 
3286  alloc_size = json_length + sizeof(""); // +1 for null terminator
3287  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size == 0))
3288  goto overflow;
3289 
3290  char *json_result;
3291 
3292  json_result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size);
3293 
3294  if (FOUNDATIONAL_LIB_UNLIKELY(json_result == NULL))
3295  {
3296  goto memory_error;
3297  }
3298 
3299  /* Add double quotes around the escaped string */
3300  json_result[0] = '"';
3301 
3302  // Start a 1 for j because index 0 is a quote mark.
3303  for (size_t j = 1, i = 0; i < input_length; ++i, ++j)
3304  {
3305  // Add unlikely because this isn't that probable.
3306  if (FOUNDATIONAL_LIB_UNLIKELY(input_string[i] == '"' || input_string[i] == '\\'))
3307  {
3308  json_result[j] = '\\';
3309  ++j;
3310  }
3311 
3312  // i is the index for the input string and j is the index for the json result
3313  json_result[j] = input_string[i];
3314  }
3315 
3316  // Add the second quote
3317  json_result[json_length - 1] = '"';
3318 
3319  // Null-terminate the string
3320  json_result[json_length] = '\0';
3321 
3322  return json_result;
3323 
3324 overflow:
3325 memory_error:
3327  return NULL;
3328 }
3329 
3342 FOUNDATIONAL_LIB_FUNC char *strip(const char *str)
3343 {
3345  size_t end = FOUNDATIONAL_LIB_STRLEN(str);
3346 
3347  size_t start;
3348 
3349  start = 0;
3350 
3351  /* Trim leading whitespace */
3352  while (FOUNDATIONAL_LIB_ISSPACE(str[start]))
3353  {
3354  ++start;
3355  }
3356 
3357  /* Trim trailing whitespace */
3358  while (end > start && FOUNDATIONAL_LIB_ISSPACE(str[end - 1]))
3359  {
3360  --end;
3361  }
3362 
3363  /* Copy the stripped portion into a new string */
3364 
3365  // End is always greater than start. Should never underflow.
3366 
3367  const size_t memcpy_len = end - start;
3368  size_t alloc_len = memcpy_len;
3369 
3370  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_len == SIZE_MAX))
3371  goto overflow;
3372  ++alloc_len;
3373 
3374  char *result;
3375  result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_len); /* Safe. */
3376 
3377  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
3378  goto memory_error;
3379 
3380  // Copy everything before the null byte.
3381  FOUNDATIONAL_LIB_MEMCPY(result, str + start, memcpy_len); /* Safe. */
3382  result[memcpy_len] = '\0';
3383 
3384  return result;
3385 
3386 overflow:
3387 memory_error:
3389  return NULL;
3390 }
3391 
3409 FOUNDATIONAL_LIB_FUNC char **split(const char *str, size_t *output_size, const char *delim, size_t max_times, int keep_delim_in_result)
3410 {
3414 
3415  /* Count the number of tokens */
3416  *output_size = 1;
3417  const size_t delim_len = FOUNDATIONAL_LIB_STRLEN(delim);
3418 
3419  for (const char *ptr = FOUNDATIONAL_LIB_STRSTR(str, delim); ptr != NULL && (max_times == 0 || *output_size < max_times); ptr = strstr(ptr + delim_len, delim))
3420  {
3421  ++(*output_size);
3422  }
3423 
3424  const size_t new_len = FOUNDATIONAL_LIB_safe_mul(*output_size, sizeof(char *));
3425 
3426  // Check output_size so safe_mul doesn't get confused.
3427  if (FOUNDATIONAL_LIB_UNLIKELY(new_len == 0 && *output_size))
3428  goto overflow;
3429 
3430  /* Allocate memory for the array of strings */
3431  char **result;
3432 
3433  result = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(new_len);
3434  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
3435  goto memory_error;
3436 
3437  const char *token_start;
3438 
3439  token_start = str;
3440  const char *ptr;
3441 
3442  /* Split the string into tokens */
3443  for (size_t i = 0; i < *output_size; i++)
3444  {
3445  ptr = FOUNDATIONAL_LIB_STRSTR(token_start, delim);
3446 
3447  if (ptr != NULL)
3448  {
3449  // Should not overflow.
3450  size_t token_length = (size_t)(ptr - token_start);
3451 
3452  if (keep_delim_in_result)
3453  {
3454  token_length += delim_len;
3455  }
3456 
3457  const size_t alloc_len = token_length + sizeof("");
3458 
3459  result[i] = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_len); /* Safe. */
3460  if (FOUNDATIONAL_LIB_UNLIKELY(result[i] == NULL))
3461  {
3463  goto memory_error;
3464  }
3465 
3466  FOUNDATIONAL_LIB_MEMCPY(result[i], token_start, token_length); /* Safe. */
3467  result[i][token_length] = '\0';
3468 
3469  token_start = ptr + delim_len; // Move to the next token
3470  }
3471  else /* ptr is NULL */
3472  {
3473  // Last token, copy the remaining part of the string
3474  const size_t token_length = FOUNDATIONAL_LIB_STRLEN(token_start);
3475 
3476  // The only way this could overflow is if strlen(token_length) == SIZE_MAX.
3477  //
3478  // But I don't see how that would be possible, because there would have to
3479  // be a null terminator for strlen() to work. So it would have to be
3480  // SIZE_MAX - 1, unless strlen() is broken. Since it would have to be
3481  // SIZE_MAX - 1, adding 1 to it wouldn't cause an overflow.
3482  // Therefore, this is safe code.
3483 
3484  const size_t alloc_len = token_length + sizeof("");
3485 
3486  result[i] = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_len); /* Safe. */
3487 
3488  if (FOUNDATIONAL_LIB_UNLIKELY(result[i] == NULL))
3489  {
3491  goto memory_error;
3492  }
3493 
3494  FOUNDATIONAL_LIB_MEMCPY(result[i], token_start, token_length); /* Safe. */
3495  result[i][token_length] = '\0';
3496  }
3497  }
3498 
3499  return result;
3500 
3501 overflow:
3502 memory_error:
3504  return NULL;
3505 }
3506 
3522 FOUNDATIONAL_LIB_FUNC char *join(const char **array, size_t count, const char *delimiter)
3523 {
3526 
3527  const size_t new_size = FOUNDATIONAL_LIB_safe_mul(sizeof(size_t), count);
3528  // Check count so safe_mul doesn't get confused.
3529  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0 && count))
3530  goto overflow;
3531  size_t *lens;
3532 
3533  lens = (size_t *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(new_size);
3534  if (FOUNDATIONAL_LIB_UNLIKELY(lens == NULL))
3535  goto memory_error;
3536  size_t delimeter_length;
3537 
3538  delimeter_length = FOUNDATIONAL_LIB_STRLEN(delimiter);
3539  /* Calculate the total length of the resulting string */
3540  size_t total_length;
3541 
3542  total_length = 1; // NUL byte
3543  for (size_t i = 0; i < count; i++)
3544  {
3545  const size_t new_len = FOUNDATIONAL_LIB_STRLEN(array[i]);
3546  lens[i] = new_len;
3547  total_length += new_len;
3548  if (i < count - 1)
3549  {
3550  total_length += delimeter_length;
3551  }
3552  }
3553 
3554  /* Allocate memory for the resulting string */
3555  char *result;
3556 
3557  result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(total_length);
3558  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
3559  {
3560  goto memory_error;
3561  }
3562  size_t len_so_far;
3563 
3564  len_so_far = 0;
3565  size_t array_index;
3566 
3567  /* Concatenate strings with the delimiter */
3568  for (array_index = 0; array_index < count; ++array_index)
3569  {
3570  const size_t len = lens[array_index];
3571 
3572  /* Copy string */
3573  for (size_t x = 0; x < len; ++x)
3574  {
3575  result[len_so_far + x] = array[array_index][x];
3576  }
3577 
3578  len_so_far += len;
3579  if (array_index < count - 1)
3580  {
3581  /* Copy delimiter */
3582  for (size_t i = 0; i < delimeter_length; ++i)
3583  {
3584  result[len_so_far + i] = delimiter[i];
3585  }
3586  len_so_far += delimeter_length;
3587  }
3588  }
3589 
3590  result[len_so_far] = '\0';
3591 
3593 
3594  return result;
3595 
3596 memory_error:
3597 overflow:
3599  return NULL;
3600 }
3601 #ifdef _WIN32
3602 #pragma GCC diagnostic push
3603 #pragma GCC diagnostic ignored "-Wpragmas"
3604 #pragma GCC diagnostic ignored "-Wformat"
3605 #pragma GCC diagnostic ignored "-Wformat-extra-args"
3606 #endif
3607 
3628 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)
3629 {
3633  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(string_to_get_appended);
3634 
3635  // Calculate the new length after appending the new string.
3636  size_t new_size = FOUNDATIONAL_LIB_safe_add_3(*string_length, string_to_get_appended_length, 1); // Adding 1 for null terminator.
3637 
3638  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
3639  goto overflow;
3640 
3641  // If the new length exceeds the current allocation size, reallocate memory.
3642  if (new_size > *string_alloc_size)
3643  {
3645 
3646  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
3647  goto overflow;
3648 
3649  char *new_string = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(*string, new_size);
3650 
3651  if (FOUNDATIONAL_LIB_UNLIKELY(new_string == NULL))
3652  goto memory_error;
3653  *string = new_string;
3654  *string_alloc_size = new_size;
3655  }
3656 
3657  // Append the new string to the target string.
3658  FOUNDATIONAL_LIB_MEMCPY(*string + *string_length, string_to_get_appended, string_to_get_appended_length); /* Safe. */
3659  *string_length = *string_length + string_to_get_appended_length;
3660 
3661  // Null-terminate the resulting string.
3662  (*string)[*string_length] = '\0';
3663 
3664  return 0;
3665 
3666 memory_error:
3667 overflow:
3669  return -1;
3670 }
3671 
3672 #define FOUNDATIONAL_LIB_INITIAL_DATA_ARRAY_ALLOC_SIZE FOUNDATIONAL_LIB_INITIAL_STRING_ARRAY_ALLOC_SIZE
3673 
3696 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)
3697 {
3700 
3701  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(array_current_alloc_size);
3703 
3704  // The _no_alloc functions omit this for optimization.
3705  if (*array_current_alloc_size == 0)
3706  {
3708  if (FOUNDATIONAL_LIB_UNLIKELY(*array == NULL))
3709  {
3710  *array_size = 0;
3711  *array_current_alloc_size = 0;
3712  goto memory_error;
3713  }
3715  *array_current_alloc_size = FOUNDATIONAL_LIB_INITIAL_STRING_ARRAY_ALLOC_SIZE;
3716  }
3717 
3718  size_t new_size;
3719 
3720  new_size = FOUNDATIONAL_LIB_safe_add_2(*array_size, 1);
3721 
3722  size_t mul;
3723 
3724  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
3725  goto overflow;
3726 
3727  mul = FOUNDATIONAL_LIB_safe_mul(new_size, data_size);
3728 
3729  // Check new_size and data_size so safe_mul doesn't get confused.
3730  if (FOUNDATIONAL_LIB_UNLIKELY(mul == 0 && new_size && data_size))
3731  goto overflow;
3732 
3733  // Realloc if needed.
3734  if (mul > *array_current_alloc_size)
3735  {
3736  const size_t new_size_total = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(mul);
3737 
3738  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0))
3739  goto overflow;
3740 
3741  void **new_array = (void **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(*array, new_size_total);
3742  if (FOUNDATIONAL_LIB_UNLIKELY(new_array == NULL))
3743  goto memory_error;
3744 
3745  *array = new_array;
3746  *array_current_alloc_size = new_size_total;
3747  }
3748 
3749  /* Copy the data. */
3750 
3751  // Safe because *array_size * data_size is smaller than the number that
3752  // we checked for overflow.
3753  FOUNDATIONAL_LIB_MEMCPY((char *)*array + (*array_size) * data_size, data, data_size); /* Safe. */
3754  ++*array_size;
3755  return 0;
3756 
3757 overflow:
3758 memory_error:
3760  return -1;
3761 }
3762 
3786 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)
3787 {
3790 
3791  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(array_current_alloc_size);
3793 
3794  const size_t new_size = FOUNDATIONAL_LIB_safe_add_2(*array_size, 1);
3795 
3796  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
3797  goto overflow;
3798 
3799  size_t nsize;
3800 
3801  nsize = FOUNDATIONAL_LIB_safe_mul(new_size, data_size);
3802 
3803  if (FOUNDATIONAL_LIB_UNLIKELY(nsize == 0 && new_size && data_size))
3804  goto overflow;
3805 
3806  if (nsize > *array_current_alloc_size)
3807  {
3808  const size_t new_size_total = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(nsize);
3809 
3810  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0))
3811  goto overflow;
3812 
3813  void **new_array = (void **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(*array, new_size_total);
3814  if (FOUNDATIONAL_LIB_UNLIKELY(new_array == NULL))
3815  goto memory_error;
3816  *array = new_array;
3817  *array_current_alloc_size = new_size_total;
3818  }
3819 
3820  /* Copy the data. */
3821 
3822  // Safe because *array_size * data_size is smaller than the number that
3823  // we checked for overflow.
3824  FOUNDATIONAL_LIB_MEMCPY((char *)*array + (*array_size) * data_size, data, data_size); /* Safe. */
3825 
3826  ++*array_size;
3827  return 0;
3828 
3829 overflow:
3830 memory_error:
3832  return -1;
3833 }
3834 
3857 FOUNDATIONAL_LIB_FUNC int append_string_to_array(char ***array, size_t *array_size, size_t *array_current_alloc_size, const char *string)
3858 {
3861 
3862  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(array_current_alloc_size);
3864 
3865  // The _no_alloc functions omit this for optimization.
3866  if (*array_current_alloc_size == 0)
3867  {
3869  if (FOUNDATIONAL_LIB_UNLIKELY(*array == NULL))
3870  {
3871  *array_size = 0;
3872  *array_current_alloc_size = 0;
3873  goto memory_error;
3874  }
3876  *array_current_alloc_size = FOUNDATIONAL_LIB_INITIAL_STRING_ARRAY_ALLOC_SIZE;
3877  }
3878 
3879  size_t new_size;
3880 
3881  new_size = FOUNDATIONAL_LIB_safe_add_2(*array_size, 1); // Null terminator
3882 
3883  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
3884  goto overflow;
3885  size_t new_size_total;
3886 
3887  new_size_total = FOUNDATIONAL_LIB_safe_mul(new_size, sizeof(char *));
3888 
3889  // Array size can be 0, which would confuse FOUNDATIONAL_LIB_safe_mul.
3890  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0 && *array_size))
3891  goto overflow;
3892 
3893  if (new_size_total > *array_current_alloc_size)
3894  {
3895  new_size_total = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(new_size_total);
3896  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0))
3897  goto overflow;
3898 
3899  char **new_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(*array, new_size_total);
3900  if (FOUNDATIONAL_LIB_UNLIKELY(new_array == NULL))
3901  goto memory_error;
3902  *array = new_array;
3903  *array_current_alloc_size = new_size_total;
3904  }
3905 
3906  (*array)[*array_size] = (char *)string;
3907 
3908  ++*array_size;
3909  return 0;
3910 
3911 overflow:
3912 memory_error:
3914  return -1;
3915 }
3916 
3941 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)
3942 {
3943 
3946 
3947  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(array_current_alloc_size);
3949 
3950  const size_t new_size = FOUNDATIONAL_LIB_safe_add_2(*array_size, 1); // Null terminator
3951 
3952  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
3953  goto overflow;
3954  size_t new_size_total;
3955 
3956  new_size_total = FOUNDATIONAL_LIB_safe_mul(new_size, sizeof(char *));
3957 
3958  // Array size can be 0, which would confuse FOUNDATIONAL_LIB_safe_mul.
3959  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0 && *array_size))
3960  goto overflow;
3961 
3962  if (new_size_total > *array_current_alloc_size)
3963  {
3964  new_size_total = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(new_size_total);
3965  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0))
3966  goto overflow;
3967 
3968  char **new_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(*array, new_size_total);
3969  if (FOUNDATIONAL_LIB_UNLIKELY(new_array == NULL))
3970  goto memory_error;
3971  *array = new_array;
3972  *array_current_alloc_size = new_size_total;
3973  }
3974 
3975  (*array)[*array_size] = (char *)string;
3976 
3977  ++*array_size;
3978  return 0;
3979 
3980 overflow:
3981 memory_error:
3983  return -1;
3984 }
3985 
4009 FOUNDATIONAL_LIB_FUNC int prepend_string_to_array(char ***array, size_t *array_size, size_t *array_current_alloc_size, char *string)
4010 {
4013 
4014  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(array_current_alloc_size);
4016  // The _no_alloc functions omit this for optimization.
4017  if (*array_current_alloc_size == 0)
4018  {
4020  if (FOUNDATIONAL_LIB_UNLIKELY(*array == NULL))
4021  {
4022  /* Die immediately if enabled */
4024 
4025  *array_size = *array_current_alloc_size = 0;
4026  return -1;
4027  }
4028 
4030  *array_current_alloc_size = FOUNDATIONAL_LIB_INITIAL_STRING_ARRAY_ALLOC_SIZE;
4031  }
4032 
4033  const size_t new_size = FOUNDATIONAL_LIB_safe_add_2(*array_size, 1);
4034 
4035  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
4036  goto overflow;
4037 
4038  if (new_size > *array_current_alloc_size)
4039  {
4040  const size_t new_size_total = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(new_size);
4041  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0))
4042  goto overflow;
4043 
4044  char **new_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(*array, new_size_total);
4045  if (FOUNDATIONAL_LIB_UNLIKELY(new_array == NULL))
4046  goto memory_error;
4047  *array = new_array;
4048 
4049  *array_current_alloc_size = new_size_total;
4050  }
4051 
4052  /* Move everything forward by 1 */
4053  FOUNDATIONAL_LIB_MEMMOVE(*array + 1 /* dest location */, *array /* src location */, ((*array_size++) * sizeof(char *)) /* size */);
4054 
4055  /* Set the string in the 0th position. */
4056  **array = string;
4057  return 0;
4058 
4059 overflow:
4060 memory_error:
4062  return -1;
4063 }
4064 
4090 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)
4091 {
4094 
4095  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(array_current_alloc_size);
4097  const size_t copy_size = FOUNDATIONAL_LIB_safe_mul((*array_size), sizeof(char *));
4098 
4099  if (FOUNDATIONAL_LIB_UNLIKELY(copy_size == 0 && *array_size))
4100  goto overflow;
4101 
4102  size_t new_size;
4103 
4104  new_size = FOUNDATIONAL_LIB_safe_add_2(*array_size, 1);
4105 
4106  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
4107  goto overflow;
4108 
4109  if (new_size > *array_current_alloc_size)
4110  {
4111  const size_t new_size_total = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(new_size);
4112 
4113  if (FOUNDATIONAL_LIB_UNLIKELY(new_size_total == 0))
4114  goto overflow;
4115 
4116  char **new_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(*array, new_size_total);
4117 
4118  if (FOUNDATIONAL_LIB_UNLIKELY(new_array == NULL))
4119  goto memory_error;
4120 
4121  *array = new_array;
4122  *array_current_alloc_size = new_size_total;
4123  }
4124 
4125  /* Move everything forward by 1 */
4126  /* Does not return an error. */
4127 
4128  // If array size plus 1 does not overflow, this should be safe.
4129  FOUNDATIONAL_LIB_MEMMOVE(*array + 1 /* dest location */, *array /* src location */, (copy_size) /* size */);
4130  ++array_size;
4131 
4132  // Set the string in the 0th position.
4133  **array = string;
4134  return 0;
4135 
4136 overflow:
4137 memory_error:
4139  return -1;
4140 }
4152 FOUNDATIONAL_LIB_FUNC size_t array_total_string_length(char **array, size_t count)
4153 {
4155  size_t length = 0;
4156 
4157  for (size_t i = 0; i < count; i++)
4158  {
4159  // NOTE: Do not check for overflows here.
4160  length += FOUNDATIONAL_LIB_STRLEN(array[i]);
4161  }
4162 
4163  return length;
4164 }
4165 
4166 #if FOUNDATIONAL_LIB_UNSAFE_FUNCTIONS_ENABLED
4167 
4185 FOUNDATIONAL_LIB_FUNC char *shellescape(const char *input)
4186 {
4188  const size_t input_len = FOUNDATIONAL_LIB_STRLEN(input);
4189 
4190  const size_t size_with_null_t = input_len + 1;
4191  if (FOUNDATIONAL_LIB_UNLIKELY(size_with_null_t == 0))
4192  goto overflow;
4193  size_t escaped_len;
4194 
4195  escaped_len = FOUNDATIONAL_LIB_safe_mul(2, size_with_null_t);
4196 
4197  if (FOUNDATIONAL_LIB_UNLIKELY(escaped_len == 0))
4198  goto overflow;
4199 
4200  char *escaped;
4201 
4202  escaped = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(escaped_len);
4203 
4204  if (FOUNDATIONAL_LIB_UNLIKELY(escaped == NULL))
4205  goto memory_error;
4206 
4207  size_t j;
4208 
4209  j = 0;
4210 
4211  for (size_t i = 0; i < input_len; ++i)
4212  {
4213  // Escape special characters
4214  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] == '<')
4215  {
4216  escaped[j++] = '\\';
4217  }
4218  escaped[j++] = input[i];
4219  }
4220 
4221  escaped[j] = '\0';
4222 
4223  return escaped;
4224 
4225 overflow:
4226 memory_error:
4228  return NULL;
4229 }
4230 #endif
4231 
4245 {
4247  char *new_str = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(str);
4248  if (FOUNDATIONAL_LIB_UNLIKELY(new_str == NULL))
4249  {
4251  return NULL;
4252  }
4253  size_t length = FOUNDATIONAL_LIB_STRLEN(new_str);
4254  size_t i, j;
4255 
4256  for (i = 0, j = length - 1; i < j; i++, j--)
4257  {
4258  char temp = new_str[i];
4259  new_str[i] = new_str[j];
4260  new_str[j] = temp;
4261  }
4262 
4263  return new_str;
4264 }
4265 
4277 static inline int starts_with(const char *str, const char *prefix) { return strncmp(str, prefix, FOUNDATIONAL_LIB_STRLEN(prefix)) == 0; }
4278 
4294 static inline int ends_with(const char *str, const char *suffix)
4295 {
4296  const size_t str_len = FOUNDATIONAL_LIB_STRLEN(str);
4297  const size_t suffix_len = FOUNDATIONAL_LIB_STRLEN(suffix);
4298 
4299  if (suffix_len > str_len)
4300  {
4301  return 0; // Suffix is longer than the string
4302  }
4303 
4304  return strncmp(str + str_len - suffix_len, suffix, suffix_len) == 0;
4305 }
4306 
4307 #if defined(__GNUC__) && !defined(_WIN32)
4308 
4309 /* @brief Cross platform memmem() */
4310 
4311 #define memory_locate memmem
4312 
4313 #else
4314 
4315 /* @brief Cross platform memmem(). Slower though. We need to find a faster solution for Windows. Maybe using assembly. */
4316 FOUNDATIONAL_LIB_FUNC void *memory_locate(const void *haystack, size_t haystack_len, const void *needle, size_t needle_len)
4317 {
4320  if (FOUNDATIONAL_LIB_UNLIKELY(needle_len == 0))
4321  {
4322  return (void *)haystack;
4323  }
4324 
4325  if (FOUNDATIONAL_LIB_UNLIKELY(haystack_len < needle_len))
4326  {
4327  return NULL;
4328  }
4329 
4330  const char *h = (const char *)haystack;
4331  const char *n = (const char *)needle;
4332 
4333  const size_t max_search = haystack_len - needle_len;
4334  for (size_t i = 0; i <= max_search; ++i)
4335  {
4336  if (FOUNDATIONAL_LIB_MEMCMP(h + i, n, needle_len) == 0)
4337  {
4338  return (void *)(h + i);
4339  }
4340  }
4341 
4342  return NULL;
4343 }
4344 #endif
4345 
4360 FOUNDATIONAL_LIB_FUNC size_t count_occurrences_of_substr(const char *str, const char *substring)
4361 {
4364  const size_t substring_length = FOUNDATIONAL_LIB_STRLEN(substring);
4365  const char *pos = str;
4366  size_t count = 0;
4367 
4368  while ((pos = FOUNDATIONAL_LIB_STRSTR(pos, substring)) != NULL)
4369  {
4370  ++count;
4371  pos += substring_length;
4372  }
4373 
4374  return count;
4375 }
4376 
4398 FOUNDATIONAL_LIB_FUNC int string_has_substr(const char *string, size_t string_length, const char *substring, size_t substring_length)
4399 {
4401 
4403 
4404  if (FOUNDATIONAL_LIB_UNLIKELY(string_length == 0))
4405  {
4406  return 0;
4407  }
4408 
4409  if (FOUNDATIONAL_LIB_UNLIKELY(substring_length == 0))
4410  {
4411  return 0;
4412  }
4413 
4414  const char *beginning_of_substr_or_null = FOUNDATIONAL_LIB_STRSTR(string, substring);
4415  return beginning_of_substr_or_null != NULL;
4416 }
4417 
4436 FOUNDATIONAL_LIB_FUNC int memory_has_subchunk(void *memory, size_t memory_length, void *subchunk, size_t subchunk_length)
4437 {
4439 
4441 
4442  if (FOUNDATIONAL_LIB_UNLIKELY(memory_length == 0))
4443  {
4444  return 0;
4445  }
4446 
4447  // Alias to memmem() if we can.
4448  return (const char *)memory_locate(memory, memory_length, subchunk, subchunk_length) != NULL;
4449 }
4450 
4469 FOUNDATIONAL_LIB_FUNC size_t count_occurrences_of_substr_len(const char *string, size_t string_length, const char *substring, size_t substring_length)
4470 {
4472 
4474 
4475  if (FOUNDATIONAL_LIB_UNLIKELY(string_length == 0))
4476  {
4477  return 0;
4478  }
4479 
4480  if (FOUNDATIONAL_LIB_UNLIKELY(substring_length == 0))
4481  {
4482  return 0;
4483  }
4484 
4485 #if defined(__GNUC__) && defined(__unix__)
4486  size_t count = 0;
4487  size_t pos = 0;
4488 
4489  const size_t orig_string_length = string_length;
4490  /* This might be significantly faster than FOUNDATIONAL_LIB_STRSTR() */
4491  for (;;)
4492  {
4493  const char *beginning_of_substr_or_null = (const char *)memmem(string + pos, string_length, substring, substring_length);
4494 
4495  if (FOUNDATIONAL_LIB_UNLIKELY(beginning_of_substr_or_null == NULL))
4496  break;
4497 
4498  ++count;
4499 
4500  /* Update pos */
4501  pos = beginning_of_substr_or_null - string + substring_length;
4502  string_length = orig_string_length - pos;
4503  }
4504 #else
4505  const char *pos = string;
4506  size_t count = 0;
4507  while ((pos = FOUNDATIONAL_LIB_STRSTR(pos, substring)) != NULL)
4508  {
4509  ++count;
4510  pos += substring_length;
4511  }
4512 #endif
4513 
4514  return count;
4515 }
4516 
4530 static inline ssize_t index_of_char(const char *str, char chr)
4531 {
4533  const char *result = FOUNDATIONAL_LIB_STRCHR(str, chr);
4534  return result != NULL ? result - str : -1;
4535 }
4536 
4552 static inline ssize_t last_index_of_char(const char *str, char chr)
4553 {
4555  const char *result = strrchr(str, chr);
4556  return result != NULL ? result - str : -1;
4557 }
4558 
4571 {
4572 
4574 
4575  const size_t len = FOUNDATIONAL_LIB_STRLEN(str);
4576 
4577  for (size_t i = 0; i < len; i++)
4578  {
4579  if (!FOUNDATIONAL_LIB_ISDIGIT(str[i]))
4580  {
4581  return 0; // Contains non-numeric character
4582  }
4583  }
4584 
4585  return 1; // Contains only numeric characters
4586 }
4587 
4603 {
4605 
4606  size_t len = FOUNDATIONAL_LIB_STRLEN(str);
4607 
4608  for (size_t i = 0; i < len; i++)
4609  {
4610  if (!FOUNDATIONAL_LIB_ISALNUM(str[i]))
4611  {
4612  return 0; // Contains non-alphanumeric character
4613  }
4614  }
4615 
4616  return 1; // Contains only alphanumeric characters
4617 }
4618 
4632 FOUNDATIONAL_LIB_FUNC char *longest_common_prefix(const char **strings, size_t count)
4633 {
4635  if (FOUNDATIONAL_LIB_UNLIKELY(count == 0))
4636  {
4637  char *ret = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(""); // Empty string for an empty array
4638  if (FOUNDATIONAL_LIB_UNLIKELY(ret == NULL))
4639  {
4641  return NULL;
4642  }
4643 
4644  return ret;
4645  }
4646 
4647  size_t max_common_len = FOUNDATIONAL_LIB_STRLEN(strings[0]);
4648 
4649  /* Find the max common length among the strings */
4650  for (size_t i = 1; i < count; ++i)
4651  {
4652  size_t current_len = FOUNDATIONAL_LIB_STRLEN(strings[i]);
4653  if (current_len < max_common_len)
4654  {
4655  max_common_len = current_len;
4656  }
4657  }
4658 
4659  /* Compare characters across the strings until a mismatch is found */
4660  for (size_t i = 0; i < max_common_len; ++i)
4661  {
4662  for (size_t j = 1; j < count; ++j)
4663  {
4664  if (strings[j][i] != strings[0][i])
4665  {
4666  /* Mismatch found, return the prefix up to this point */
4667 
4668  // Don't FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC 0.
4669  if (FOUNDATIONAL_LIB_UNLIKELY(i == SIZE_MAX))
4670  {
4672  return NULL;
4673  }
4674 
4675  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(i + sizeof("")); /* Safe. */
4676  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
4677  {
4679  return NULL;
4680  }
4681  FOUNDATIONAL_LIB_MEMCPY(result, strings[0], i);
4682  result[i] = '\0';
4683  return result;
4684  }
4685  }
4686  }
4687 
4688  /* All strings match up to the minimum length, return the entire prefix */
4689  char *dup = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(strings[0]);
4690  if (FOUNDATIONAL_LIB_UNLIKELY(dup == NULL))
4691  {
4693  return NULL;
4694  }
4695 
4696  return dup;
4697 }
4698 
4712 FOUNDATIONAL_LIB_FUNC char *longest_common_suffix(const char **strings, size_t count)
4713 {
4715 
4716  if (FOUNDATIONAL_LIB_UNLIKELY(count == 0))
4717  {
4718  char *return_value = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(""); // Empty string for an empty array
4719  if (FOUNDATIONAL_LIB_UNLIKELY(return_value == NULL))
4720  {
4722  return NULL;
4723  }
4724  return return_value;
4725  }
4726 
4727  size_t max_common_len = FOUNDATIONAL_LIB_STRLEN(strings[0]);
4728 
4729  /* Find the max common length among the strings */
4730  for (size_t i = 1; i < count; ++i)
4731  {
4732  size_t current_len = FOUNDATIONAL_LIB_STRLEN(strings[i]);
4733  if (current_len < max_common_len)
4734  {
4735  max_common_len = current_len;
4736  }
4737  }
4738 
4739  /* Compare characters across the strings until a mismatch is found */
4740  for (size_t i = 0; i < max_common_len; ++i)
4741  {
4742  for (size_t j = 1; j < count; ++j)
4743  {
4744  size_t current_len = FOUNDATIONAL_LIB_STRLEN(strings[j]);
4745  if (strings[j][current_len - i - 1] != strings[0][max_common_len - i - 1])
4746  {
4747  /* Mismatch found, return the suffix up to this point */
4748 
4749  // Don't FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC 0.
4750  if (FOUNDATIONAL_LIB_UNLIKELY(i == SIZE_MAX))
4751  {
4753  return NULL;
4754  }
4755 
4756  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(i + sizeof("")); /* Safe. */
4757  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
4758  {
4760  return NULL;
4761  }
4762 
4763  FOUNDATIONAL_LIB_MEMCPY(result, strings[0] + max_common_len - i, i); /* Safe. */
4764  result[i] = '\0';
4765  return result;
4766  }
4767  }
4768  }
4769 
4770  /* All strings match up to the minimum length, return the entire suffix */
4771  char *return_value = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(strings[0] + max_common_len); /* Should be Safe. */
4772  if (FOUNDATIONAL_LIB_UNLIKELY(return_value == NULL))
4773  {
4775  return NULL;
4776  }
4777 
4778  return return_value;
4779 }
4780 
4791 static inline double str_to_double(const char *string)
4792 {
4793 
4795 
4796  return atof(string);
4797 }
4798 
4810 FOUNDATIONAL_LIB_FUNC ssize_t find_first_of(const char *str, const char *char_set)
4811 {
4814 
4815  const char *result = strpbrk(str, char_set);
4816 
4817  return FOUNDATIONAL_LIB_likely(result != NULL) ? result - str : -1;
4818 }
4819 
4833 FOUNDATIONAL_LIB_FUNC ssize_t find_last_of(const char *str, const char *char_set)
4834 {
4837 
4838  const size_t len = FOUNDATIONAL_LIB_STRLEN(str);
4839 
4840  for (ssize_t i = len - 1; i >= 0; i--)
4841  {
4842  if (FOUNDATIONAL_LIB_STRCHR(char_set, str[i]) != NULL)
4843  {
4844  return i;
4845  }
4846  }
4847  return -1;
4848 }
4849 
4859 {
4861 
4862  const size_t len = FOUNDATIONAL_LIB_STRLEN(str);
4863 
4864  /* Swap characters from both ends towards the center */
4865  for (size_t i = 0, j = len - 1; i < j; ++i, --j)
4866  {
4867  char temp = str[i];
4868  str[i] = str[j];
4869  str[j] = temp;
4870  }
4871 }
4872 
4883 {
4885 
4886  if (*str == '\0')
4887  {
4888  return 0; // Empty string is not a valid integer
4889  }
4890 
4891  /* Check for optional sign */
4892  if (*str == '+' || *str == '-')
4893  {
4894  ++str;
4895  }
4896 
4897  /* Check for at least one digit */
4898  if (!FOUNDATIONAL_LIB_ISDIGIT(*str))
4899  {
4900  return 0;
4901  }
4902 
4903  /* Check for remaining digits */
4904  while (*str != '\0')
4905  {
4906  if (!FOUNDATIONAL_LIB_ISDIGIT(*str))
4907  {
4908  return 0;
4909  }
4910  ++str;
4911  }
4912 
4913  return 1; // Valid integer
4914 }
4915 
4925 FOUNDATIONAL_LIB_FUNC size_t common_prefix_length(const char *str1, const char *str2)
4926 {
4929 
4930  const size_t len1 = FOUNDATIONAL_LIB_STRLEN(str1);
4931  const size_t len2 = FOUNDATIONAL_LIB_STRLEN(str2);
4932 
4933  const size_t min_len = (len1 < len2) ? len1 : len2;
4934 
4935  for (size_t i = 0; i < min_len; i++)
4936  {
4937  if (str1[i] != str2[i])
4938  {
4939  return i; // Mismatch found, return current index
4940  }
4941  }
4942 
4943  return min_len; // No mismatch found, return the minimum length
4944 }
4945 
4955 FOUNDATIONAL_LIB_FUNC size_t common_suffix_length(const char *str1, const char *str2)
4956 {
4959 
4960  const size_t len1 = FOUNDATIONAL_LIB_STRLEN(str1);
4961  const size_t len2 = FOUNDATIONAL_LIB_STRLEN(str2);
4962 
4963  const size_t min_len = (len1 < len2) ? len1 : len2;
4964 
4965  for (size_t i = 1; i <= min_len; i++)
4966  {
4967  if (str1[len1 - i] != str2[len2 - i])
4968  {
4969  return i - 1; // Mismatch found, return previous index
4970  }
4971  }
4972 
4973  return min_len; // No mismatch found, return the minimum length
4974 }
4975 
4987 {
4989 
4990  const size_t len = FOUNDATIONAL_LIB_STRLEN(str);
4991  if (FOUNDATIONAL_LIB_UNLIKELY(len == SIZE_MAX))
4992  {
4994  return NULL;
4995  }
4996 
4997  char *title_case = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(len + sizeof("")); /* Safe. */
4998 
4999  if (FOUNDATIONAL_LIB_UNLIKELY(title_case == NULL))
5000  {
5002  return NULL;
5003  }
5004 
5005  int make_upper = 1; // Start with the first character as uppercase
5006 
5007  for (size_t i = 0; i < len; i++)
5008  {
5009  if (FOUNDATIONAL_LIB_ISSPACE(str[i]))
5010  {
5011  make_upper = 1; // Set the flag to capitalize the next character
5012  title_case[i] = str[i];
5013  }
5014  else
5015  {
5016  title_case[i] = make_upper ? toupper(str[i]) : tolower(str[i]);
5017  make_upper = 0; // Reset the flag
5018  }
5019  }
5020 
5021  title_case[len] = '\0';
5022 
5023  return title_case;
5024 }
5025 
5035 FOUNDATIONAL_LIB_FUNC int find_max_int_in_array(const int *array, size_t size)
5036 {
5038  if (FOUNDATIONAL_LIB_UNLIKELY(size == 0))
5039  {
5040  /* Handle empty array case */
5041  return -1;
5042  }
5043 
5044  int max = array[0];
5045 
5046  for (size_t i = 1; i < size; i++)
5047  {
5048  if (array[i] > max)
5049  {
5050  max = array[i];
5051  }
5052  }
5053 
5054  return max;
5055 }
5056 
5066 FOUNDATIONAL_LIB_FUNC int find_min_int_in_array(const int *array, size_t size)
5067 {
5069  if (FOUNDATIONAL_LIB_UNLIKELY(size == 0))
5070  {
5071  /* Handle empty array case */
5072  return -1;
5073  }
5074 
5075  int min = array[0];
5076 
5077  for (size_t i = 1; i < size; i++)
5078  {
5079  if (array[i] < min)
5080  {
5081  min = array[i];
5082  }
5083  }
5084 
5085  return min;
5086 }
5087 
5097 FOUNDATIONAL_LIB_FUNC int sum_of_int_array(const int *array, size_t size)
5098 {
5100  int sum = 0;
5101 
5102  for (size_t i = 0; i < size; ++i)
5103  {
5104  sum += array[i];
5105  }
5106 
5107  return sum;
5108 }
5109 
5119 {
5121 
5122  for (size_t i = 0, j = size - 1; i < j; ++i, --j)
5123  {
5124  int temp = array[i];
5125  array[i] = array[j];
5126  array[j] = temp;
5127  }
5128 }
5129 
5141 {
5143  for (size_t i = 1; i < size; ++i)
5144  {
5145  if (array[i] < array[i - 1])
5146  {
5147  return 0; // Not sorted in ascending order
5148  }
5149  }
5150  return 1; // Sorted in ascending order
5151 }
5152 
5164 {
5166  for (size_t i = 1; i < size; ++i)
5167  {
5168  if (array[i] > array[i - 1])
5169  {
5170  return 0; // Not sorted in descending order
5171  }
5172  }
5173  return 1; // Sorted in descending order
5174 }
5175 
5189 FOUNDATIONAL_LIB_FUNC size_t *generate_range(size_t start, size_t end, size_t step, size_t *range_size)
5190 {
5192  // Check for invalid range
5193  if (FOUNDATIONAL_LIB_UNLIKELY(start > end || step == 0))
5194  {
5196  return NULL;
5197  }
5198  const size_t size = (end - start) / step + 1;
5199 
5200  if (FOUNDATIONAL_LIB_UNLIKELY(size == 0))
5201  { // Overflow
5203  return NULL;
5204  }
5205 
5206  const size_t alloc_size = FOUNDATIONAL_LIB_safe_mul(size, sizeof(size_t));
5207 
5208  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size == 0))
5209  { // Overflow
5211  return NULL;
5212  }
5213 
5214  size_t *range = (size_t *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size);
5215 
5216  if (FOUNDATIONAL_LIB_UNLIKELY(range == NULL))
5217  {
5219  return NULL;
5220  }
5221 
5222  for (size_t i = 0, value = start; i < size; ++i, value += step)
5223  {
5224  range[i] = value;
5225  }
5226 
5227  *range_size = size;
5228  return range;
5229 }
5230 
5244 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmpstringp(const void *p1, const void *p2)
5245 {
5248  return FOUNDATIONAL_LIB_STRCMP(*(const char **)p1, *(const char **)p2);
5249 }
5250 
5257 FOUNDATIONAL_LIB_FUNC void sort_strings(char **strings, size_t size)
5258 {
5259 
5261  qsort(strings, size, sizeof(char *), FOUNDATIONAL_LIB_cmpstringp);
5262 }
5263 
5275 FOUNDATIONAL_LIB_FUNC char **sorted_strings(char **strings, size_t size)
5276 {
5277 
5279 
5280  char **dup_strings = (char **)arraydup(strings, size, sizeof(char *));
5281  if (FOUNDATIONAL_LIB_UNLIKELY(dup_strings == NULL))
5282  {
5283  return NULL; /* No need to re die aggressively. */
5284  }
5285  qsort(dup_strings, size, sizeof(char *), FOUNDATIONAL_LIB_cmpstringp);
5286  return dup_strings;
5287 }
5288 
5302 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_uints(const void *a, const void *b)
5303 {
5304 
5307  return (*(unsigned int *)a - *(unsigned int *)b);
5308 }
5309 
5319 FOUNDATIONAL_LIB_FUNC void sort_uints(unsigned int *uints, size_t size)
5320 {
5322 
5323  qsort(uints, size, sizeof(unsigned int), FOUNDATIONAL_LIB_cmp_uints);
5324 }
5325 
5338 FOUNDATIONAL_LIB_FUNC unsigned int *sorted_uints(unsigned int *uints, size_t size)
5339 {
5341 
5342  unsigned int *dup_uints = (unsigned int *)arraydup(uints, size, sizeof(unsigned int));
5343  if (FOUNDATIONAL_LIB_UNLIKELY(dup_uints == NULL))
5344  {
5345  return NULL;
5346  }
5347  qsort(uints, size, sizeof(unsigned int), FOUNDATIONAL_LIB_cmp_uints);
5348  return dup_uints;
5349 }
5350 
5365 {
5368  return (*(unsigned int **)a - *(unsigned int **)b);
5369 }
5370 
5380 FOUNDATIONAL_LIB_FUNC void sort_uint_ptrs(unsigned int **uint_ptrs, size_t size)
5381 {
5383 
5384  qsort(uint_ptrs, size, sizeof(unsigned int *), FOUNDATIONAL_LIB_cmp_uint_ptrs);
5385 }
5386 
5401 FOUNDATIONAL_LIB_FUNC unsigned int **sorted_uint_ptrs(unsigned int **uint_ptrs, size_t size)
5402 {
5403 
5405 
5406  unsigned int **dup_uint_ptrs = (unsigned int **)arraydup(uint_ptrs, size, sizeof(unsigned int *));
5407  if (FOUNDATIONAL_LIB_UNLIKELY(dup_uint_ptrs == NULL))
5408  {
5409  return NULL;
5410  }
5411  qsort(uint_ptrs, size, sizeof(unsigned int *), FOUNDATIONAL_LIB_cmp_uint_ptrs);
5412  return dup_uint_ptrs;
5413 }
5414 
5428 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ints(const void *a, const void *b)
5429 {
5430 
5433 
5434  return (*(int *)a - *(int *)b);
5435 }
5436 
5446 FOUNDATIONAL_LIB_FUNC void sort_ints(int *ints, size_t size)
5447 {
5448 
5450  qsort(ints, size, sizeof(int), FOUNDATIONAL_LIB_cmp_ints);
5451 }
5452 
5465 FOUNDATIONAL_LIB_FUNC int *sorted_ints(int *ints, size_t size)
5466 {
5467 
5469 
5470  int *dup_ints = (int *)arraydup(ints, size, sizeof(int));
5471  if (FOUNDATIONAL_LIB_UNLIKELY(dup_ints == NULL))
5472  {
5473  return NULL;
5474  }
5475 
5476  qsort(ints, size, sizeof(int), FOUNDATIONAL_LIB_cmp_ints);
5477  return dup_ints;
5478 }
5479 
5493 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_int_ptrs(const void *a, const void *b)
5494 {
5495 
5498  return (*(int **)a - *(int **)b);
5499 }
5500 
5510 FOUNDATIONAL_LIB_FUNC void sort_int_ptrs(int **int_ptrs, size_t size)
5511 {
5513  qsort(int_ptrs, size, sizeof(int *), FOUNDATIONAL_LIB_cmp_int_ptrs);
5514 }
5515 
5530 FOUNDATIONAL_LIB_FUNC int **sorted_int_ptrs(int **int_ptrs, size_t size)
5531 {
5533  int **dup_int_ptrs = (int **)arraydup(int_ptrs, size, sizeof(int *));
5534  if (FOUNDATIONAL_LIB_UNLIKELY(dup_int_ptrs == NULL))
5535  {
5536  return NULL;
5537  }
5538  qsort(int_ptrs, size, sizeof(int *), FOUNDATIONAL_LIB_cmp_int_ptrs);
5539  return dup_int_ptrs;
5540 }
5541 
5554 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_uchars(const void *a, const void *b)
5555 {
5558  return (*(unsigned char *)a - *(unsigned char *)b);
5559 }
5560 
5570 FOUNDATIONAL_LIB_FUNC void sort_uchars(unsigned char *uchars, size_t size)
5571 {
5572 
5574  qsort(uchars, size, sizeof(unsigned char), FOUNDATIONAL_LIB_cmp_uchars);
5575 }
5576 
5590 FOUNDATIONAL_LIB_FUNC unsigned char *sorted_uchars(unsigned char *uchars, size_t size)
5591 {
5593 
5594  unsigned char *dup_uchars = (unsigned char *)arraydup(uchars, size, sizeof(unsigned char));
5595  if (FOUNDATIONAL_LIB_UNLIKELY(dup_uchars == NULL))
5596  {
5597  return NULL;
5598  }
5599  qsort(uchars, size, sizeof(unsigned char), FOUNDATIONAL_LIB_cmp_uchars);
5600  return dup_uchars;
5601 }
5602 
5618 {
5621  return (*(unsigned char **)a - *(unsigned char **)b);
5622 }
5633 FOUNDATIONAL_LIB_FUNC void sort_uchar_ptrs(unsigned char **uchar_ptrs, size_t size)
5634 {
5635 
5637  qsort(uchar_ptrs, size, sizeof(unsigned char *), FOUNDATIONAL_LIB_cmp_uchar_ptrs);
5638 }
5639 
5655 FOUNDATIONAL_LIB_FUNC unsigned char **sorted_uchar_ptrs(unsigned char **uchar_ptrs, size_t size)
5656 {
5658  unsigned char **dup_uchar_ptrs = (unsigned char **)arraydup(uchar_ptrs, size, sizeof(unsigned char *));
5659  if (FOUNDATIONAL_LIB_UNLIKELY(dup_uchar_ptrs == NULL))
5660  {
5661  return NULL;
5662  }
5663  qsort(uchar_ptrs, size, sizeof(unsigned char *), FOUNDATIONAL_LIB_cmp_uchar_ptrs);
5664  return dup_uchar_ptrs;
5665 }
5666 
5679 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_chars(const void *a, const void *b)
5680 {
5683  return (*(char *)a - *(char *)b);
5684 }
5685 
5694 FOUNDATIONAL_LIB_FUNC void sort_chars(char *chars, size_t size)
5695 {
5697  qsort(chars, size, sizeof(char), FOUNDATIONAL_LIB_cmp_chars);
5698 }
5699 
5713 FOUNDATIONAL_LIB_FUNC char *sorted_chars(char *chars, size_t size)
5714 {
5716  char *dup_chars = (char *)arraydup(chars, size, sizeof(char));
5717  if (FOUNDATIONAL_LIB_UNLIKELY(dup_chars == NULL))
5718  {
5719  return NULL;
5720  }
5721  qsort(chars, size, sizeof(char), FOUNDATIONAL_LIB_cmp_chars);
5722  return dup_chars;
5723 }
5724 
5738 {
5741 
5742  return (*(char **)a - *(char **)b);
5743 }
5753 FOUNDATIONAL_LIB_FUNC void sort_char_ptrs(char **char_ptrs, size_t size)
5754 {
5756 
5757  qsort(char_ptrs, size, sizeof(char *), FOUNDATIONAL_LIB_cmp_char_ptrs);
5758 }
5759 
5774 FOUNDATIONAL_LIB_FUNC char **sorted_char_ptrs(char **char_ptrs, size_t size)
5775 {
5777  char **dup_char_ptrs = (char **)arraydup(char_ptrs, size, sizeof(char *));
5778 
5779  if (FOUNDATIONAL_LIB_UNLIKELY(dup_char_ptrs == NULL))
5780  {
5781  return NULL;
5782  }
5783 
5784  qsort(char_ptrs, size, sizeof(char *), FOUNDATIONAL_LIB_cmp_char_ptrs);
5785  return dup_char_ptrs;
5786 }
5787 
5800 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ushorts(const void *a, const void *b)
5801 {
5802 
5805  return (*(unsigned short *)a - *(unsigned short *)b);
5806 }
5807 
5817 FOUNDATIONAL_LIB_FUNC void sort_ushorts(unsigned short *ushorts, size_t size)
5818 {
5819 
5821 
5822  qsort(ushorts, size, sizeof(unsigned short), FOUNDATIONAL_LIB_cmp_ushorts);
5823 }
5824 
5838 FOUNDATIONAL_LIB_FUNC unsigned short *sorted_ushorts(unsigned short *ushorts, size_t size)
5839 {
5841  unsigned short *dup_ushorts = (unsigned short *)arraydup(ushorts, size, sizeof(unsigned short));
5842 
5843  if (FOUNDATIONAL_LIB_UNLIKELY(dup_ushorts == NULL))
5844  {
5845  return NULL;
5846  }
5847 
5848  qsort(ushorts, size, sizeof(unsigned short), FOUNDATIONAL_LIB_cmp_ushorts);
5849  return dup_ushorts;
5850 }
5851 
5867 {
5868 
5871 
5872  return (*(unsigned short **)a - *(unsigned short **)b);
5873 }
5874 
5885 FOUNDATIONAL_LIB_FUNC void sort_ushort_ptrs(unsigned short **ushort_ptrs, size_t size)
5886 {
5887 
5889  qsort(ushort_ptrs, size, sizeof(unsigned short *), FOUNDATIONAL_LIB_cmp_ushort_ptrs);
5890 }
5891 
5907 FOUNDATIONAL_LIB_FUNC unsigned short **sorted_ushort_ptrs(unsigned short **ushort_ptrs, size_t size)
5908 {
5910 
5911  unsigned short **dup_ushort_ptrs = (unsigned short **)arraydup(ushort_ptrs, size, sizeof(unsigned short *));
5912  if (FOUNDATIONAL_LIB_UNLIKELY(dup_ushort_ptrs == NULL))
5913  {
5914  return NULL;
5915  }
5916 
5917  qsort(ushort_ptrs, size, sizeof(unsigned short *), FOUNDATIONAL_LIB_cmp_ushort_ptrs);
5918  return dup_ushort_ptrs;
5919 }
5920 
5933 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_shorts(const void *a, const void *b)
5934 {
5937  return (*(short *)a - *(short *)b);
5938 }
5947 FOUNDATIONAL_LIB_FUNC void sort_shorts(short *shorts, size_t size)
5948 {
5949 
5951  qsort(shorts, size, sizeof(short), FOUNDATIONAL_LIB_cmp_shorts);
5952 }
5953 
5967 FOUNDATIONAL_LIB_FUNC short *sorted_shorts(short *shorts, size_t size)
5968 {
5970 
5971  short *dup_shorts = (short *)arraydup(shorts, size, sizeof(short));
5972 
5973  if (FOUNDATIONAL_LIB_UNLIKELY(dup_shorts == NULL))
5974  {
5975  return NULL;
5976  }
5977 
5978  qsort(shorts, size, sizeof(short), FOUNDATIONAL_LIB_cmp_shorts);
5979  return dup_shorts;
5980 }
5981 
5995 {
5996 
5999  return (*(short **)a - *(short **)b);
6000 }
6001 
6011 FOUNDATIONAL_LIB_FUNC void sort_short_ptrs(short **short_ptrs, size_t size)
6012 {
6013 
6015  qsort(short_ptrs, size, sizeof(short *), FOUNDATIONAL_LIB_cmp_short_ptrs);
6016 }
6017 
6031 FOUNDATIONAL_LIB_FUNC short **sorted_short_ptrs(short **short_ptrs, size_t size)
6032 {
6034 
6035  short **dup_short_ptrs = (short **)arraydup(short_ptrs, size, sizeof(short *));
6036 
6037  if (FOUNDATIONAL_LIB_UNLIKELY(dup_short_ptrs == NULL))
6038  {
6039  return NULL;
6040  }
6041 
6042  qsort(short_ptrs, size, sizeof(short *), FOUNDATIONAL_LIB_cmp_short_ptrs);
6043  return dup_short_ptrs;
6044 }
6045 
6058 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ulongs(const void *a, const void *b)
6059 {
6062  return (*(unsigned long *)a - *(unsigned long *)b);
6063 }
6064 
6074 FOUNDATIONAL_LIB_FUNC void sort_ulongs(unsigned long *ulongs, size_t size)
6075 {
6077  qsort(ulongs, size, sizeof(unsigned long), FOUNDATIONAL_LIB_cmp_ulongs);
6078 }
6079 
6093 FOUNDATIONAL_LIB_FUNC unsigned long *sorted_ulongs(unsigned long *ulongs, size_t size)
6094 {
6096  unsigned long *dup_ulongs = (unsigned long *)arraydup(ulongs, size, sizeof(unsigned long));
6097 
6098  if (FOUNDATIONAL_LIB_UNLIKELY(dup_ulongs == NULL))
6099  {
6100  return NULL;
6101  }
6102 
6103  qsort(ulongs, size, sizeof(unsigned long), FOUNDATIONAL_LIB_cmp_ulongs);
6104  return dup_ulongs;
6105 }
6106 
6122 {
6125 
6126  return (*(unsigned long **)a - *(unsigned long **)b);
6127 }
6128 
6139 FOUNDATIONAL_LIB_FUNC void sort_ulong_ptrs(unsigned long **ulong_ptrs, size_t size)
6140 {
6141 
6143  qsort(ulong_ptrs, size, sizeof(unsigned long *), FOUNDATIONAL_LIB_cmp_ulong_ptrs);
6144 }
6145 
6161 FOUNDATIONAL_LIB_FUNC unsigned long **sorted_ulong_ptrs(unsigned long **ulong_ptrs, size_t size)
6162 {
6164 
6165  unsigned long **dup_ulong_ptrs = (unsigned long **)arraydup(ulong_ptrs, size, sizeof(unsigned long *));
6166  if (FOUNDATIONAL_LIB_UNLIKELY(dup_ulong_ptrs == NULL))
6167  {
6168  return NULL;
6169  }
6170 
6171  qsort(ulong_ptrs, size, sizeof(unsigned long *), FOUNDATIONAL_LIB_cmp_ulong_ptrs);
6172  return dup_ulong_ptrs;
6173 }
6174 
6189 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_longs(const void *a, const void *b)
6190 {
6191 
6194  return (*(long *)a - *(long *)b);
6195 }
6196 
6207 FOUNDATIONAL_LIB_FUNC void sort_longs(long *longs, size_t size)
6208 {
6209 
6211 
6212  qsort(longs, size, sizeof(long), FOUNDATIONAL_LIB_cmp_longs);
6213 }
6214 
6230 FOUNDATIONAL_LIB_FUNC long *sorted_longs(long *longs, size_t size)
6231 {
6232 
6234 
6235  long *dup_longs = (long *)arraydup(longs, size, sizeof(long));
6236  if (FOUNDATIONAL_LIB_UNLIKELY(dup_longs == NULL))
6237  {
6238  return NULL;
6239  }
6240 
6241  qsort(longs, size, sizeof(long), FOUNDATIONAL_LIB_cmp_longs);
6242  return dup_longs;
6243 }
6244 
6258 {
6259 
6262  return (*(long **)a - *(long **)b);
6263 }
6273 FOUNDATIONAL_LIB_FUNC void sort_long_ptrs(long **long_ptrs, size_t size)
6274 {
6276  qsort(long_ptrs, size, sizeof(long *), FOUNDATIONAL_LIB_cmp_long_ptrs);
6277 }
6292 FOUNDATIONAL_LIB_FUNC long **sorted_long_ptrs(long **long_ptrs, size_t size)
6293 {
6295  long **dup_long_ptrs = (long **)arraydup(long_ptrs, size, sizeof(long *));
6296  if (FOUNDATIONAL_LIB_UNLIKELY(dup_long_ptrs == NULL))
6297  {
6298  return NULL;
6299  }
6300 
6301  qsort(long_ptrs, size, sizeof(long *), FOUNDATIONAL_LIB_cmp_long_ptrs);
6302  return dup_long_ptrs;
6303 }
6304 
6318 {
6321  return (*(unsigned long long *)a - *(unsigned long long *)b);
6322 }
6332 FOUNDATIONAL_LIB_FUNC void sort_ulong_longs(unsigned long long *ulong_longs, size_t size)
6333 {
6334 
6336 
6337  qsort(ulong_longs, size, sizeof(unsigned long long), FOUNDATIONAL_LIB_cmp_ulong_longs);
6338 }
6352 FOUNDATIONAL_LIB_FUNC unsigned long long *sorted_ulong_longs(unsigned long long *ulong_longs, size_t size)
6353 {
6355  unsigned long long *dup_ulong_longs = (unsigned long long *)arraydup(ulong_longs, size, sizeof(unsigned long long));
6356  if (FOUNDATIONAL_LIB_UNLIKELY(dup_ulong_longs == NULL))
6357  {
6358  return NULL;
6359  }
6360 
6361  qsort(ulong_longs, size, sizeof(unsigned long long), FOUNDATIONAL_LIB_cmp_ulong_longs);
6362  return dup_ulong_longs;
6363 }
6364 
6380 {
6383 
6384  return (*(unsigned long long **)a - *(unsigned long long **)b);
6385 }
6386 
6397 FOUNDATIONAL_LIB_FUNC void sort_ulong_long_ptrs(unsigned long long **ulong_long_ptrs, size_t size)
6398 {
6400  qsort(ulong_long_ptrs, size, sizeof(unsigned long long *), FOUNDATIONAL_LIB_cmp_ulong_long_ptrs);
6401 }
6417 FOUNDATIONAL_LIB_FUNC unsigned long long **sorted_ulong_long_ptrs(unsigned long long **ulong_long_ptrs, size_t size)
6418 {
6420 
6421  unsigned long long **dup_ulong_long_ptrs = (unsigned long long **)arraydup(ulong_long_ptrs, size, sizeof(unsigned long long *));
6422  if (FOUNDATIONAL_LIB_UNLIKELY(dup_ulong_long_ptrs == NULL))
6423  {
6424  return NULL;
6425  }
6426 
6427  qsort(ulong_long_ptrs, size, sizeof(unsigned long long *), FOUNDATIONAL_LIB_cmp_ulong_long_ptrs);
6428  return dup_ulong_long_ptrs;
6429 }
6430 
6444 {
6447  return (*(long long *)a - *(long long *)b);
6448 }
6457 FOUNDATIONAL_LIB_FUNC void sort_long_longs(long long *long_longs, size_t size)
6458 {
6460  qsort(long_longs, size, sizeof(long long), FOUNDATIONAL_LIB_cmp_long_longs);
6461 }
6475 FOUNDATIONAL_LIB_FUNC long long *sorted_long_longs(long long *long_longs, size_t size)
6476 {
6478  long long *dup_long_longs = (long long *)arraydup(long_longs, size, sizeof(long long));
6479 
6480  if (FOUNDATIONAL_LIB_UNLIKELY(dup_long_longs == NULL))
6481  {
6482  return NULL;
6483  }
6484 
6485  qsort(long_longs, size, sizeof(long long), FOUNDATIONAL_LIB_cmp_long_longs);
6486  return dup_long_longs;
6487 }
6488 
6502 {
6505  return (*(long long **)a - *(long long **)b);
6506 }
6507 
6518 FOUNDATIONAL_LIB_FUNC void sort_long_long_ptrs(long long **long_long_ptrs, size_t size)
6519 {
6521  qsort(long_long_ptrs, size, sizeof(long long *), FOUNDATIONAL_LIB_cmp_long_long_ptrs);
6522 }
6523 
6539 FOUNDATIONAL_LIB_FUNC long long **sorted_long_long_ptrs(long long **long_long_ptrs, size_t size)
6540 {
6542 
6543  long long **dup_long_long_ptrs = (long long **)arraydup(long_long_ptrs, size, sizeof(long long *));
6544  if (FOUNDATIONAL_LIB_UNLIKELY(dup_long_long_ptrs == NULL))
6545  {
6546  return NULL;
6547  }
6548 
6549  qsort(long_long_ptrs, size, sizeof(long long *), FOUNDATIONAL_LIB_cmp_long_long_ptrs);
6550  return dup_long_long_ptrs;
6551 }
6552 
6565 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_floats(const void *a, const void *b)
6566 {
6569  return (*(float *)a - *(float *)b);
6570 }
6571 
6580 FOUNDATIONAL_LIB_FUNC void sort_floats(float *floats, size_t size)
6581 {
6583  qsort(floats, size, sizeof(float), FOUNDATIONAL_LIB_cmp_floats);
6584 }
6585 
6599 FOUNDATIONAL_LIB_FUNC float *sorted_floats(float *floats, size_t size)
6600 {
6602 
6603  float *dup_floats = (float *)arraydup(floats, size, sizeof(float));
6604  if (FOUNDATIONAL_LIB_UNLIKELY(dup_floats == NULL))
6605  {
6606  return NULL;
6607  }
6608 
6609  qsort(floats, size, sizeof(float), FOUNDATIONAL_LIB_cmp_floats);
6610  return dup_floats;
6611 }
6612 
6626 {
6629  return (*(float **)a - *(float **)b);
6630 }
6631 
6641 FOUNDATIONAL_LIB_FUNC void sort_float_ptrs(float **float_ptrs, size_t size)
6642 {
6643 
6645  qsort(float_ptrs, size, sizeof(float *), FOUNDATIONAL_LIB_cmp_float_ptrs);
6646 }
6647 
6661 FOUNDATIONAL_LIB_FUNC float **sorted_float_ptrs(float **float_ptrs, size_t size)
6662 {
6664 
6665  float **dup_float_ptrs = (float **)arraydup(float_ptrs, size, sizeof(float *));
6666 
6667  if (FOUNDATIONAL_LIB_UNLIKELY(dup_float_ptrs == NULL))
6668  {
6669  return NULL;
6670  }
6671  qsort(float_ptrs, size, sizeof(float *), FOUNDATIONAL_LIB_cmp_float_ptrs);
6672  return dup_float_ptrs;
6673 }
6674 
6687 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_doubles(const void *a, const void *b)
6688 {
6691 
6692  return (*(double *)a - *(double *)b);
6693 }
6694 
6703 FOUNDATIONAL_LIB_FUNC void sort_doubles(double *doubles, size_t size)
6704 {
6706  qsort(doubles, size, sizeof(double), FOUNDATIONAL_LIB_cmp_doubles);
6707 }
6708 
6722 FOUNDATIONAL_LIB_FUNC double *sorted_doubles(double *doubles, size_t size)
6723 {
6725  double *dup_doubles = (double *)arraydup(doubles, size, sizeof(double));
6726  if (FOUNDATIONAL_LIB_UNLIKELY(dup_doubles == NULL))
6727  {
6728  return NULL;
6729  }
6730  qsort(doubles, size, sizeof(double), FOUNDATIONAL_LIB_cmp_doubles);
6731  return dup_doubles;
6732 }
6746 {
6747 
6750  return (*(double **)a - *(double **)b);
6751 }
6752 
6762 FOUNDATIONAL_LIB_FUNC void sort_double_ptrs(double **double_ptrs, size_t size)
6763 {
6764 
6766  qsort(double_ptrs, size, sizeof(double *), FOUNDATIONAL_LIB_cmp_double_ptrs);
6767 }
6768 
6782 FOUNDATIONAL_LIB_FUNC double **sorted_double_ptrs(double **double_ptrs, size_t size)
6783 {
6784 
6786 
6787  double **dup_double_ptrs = (double **)arraydup(double_ptrs, size, sizeof(double *));
6788  if (FOUNDATIONAL_LIB_UNLIKELY(dup_double_ptrs == NULL))
6789  {
6790  return NULL;
6791  }
6792  qsort(double_ptrs, size, sizeof(double *), FOUNDATIONAL_LIB_cmp_double_ptrs);
6793  return dup_double_ptrs;
6794 }
6795 
6808 FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_size_ts(const void *a, const void *b)
6809 {
6810 
6813  return (*(size_t *)a - *(size_t *)b);
6814 }
6815 
6825 FOUNDATIONAL_LIB_FUNC void sort_size_ts(size_t *size_ts, size_t size)
6826 {
6827 
6829  qsort(size_ts, size, sizeof(size_t), FOUNDATIONAL_LIB_cmp_size_ts);
6830 }
6831 
6845 FOUNDATIONAL_LIB_FUNC size_t *sorted_size_ts(size_t *size_ts, size_t size)
6846 {
6848 
6849  size_t *dup_size_ts = (size_t *)arraydup(size_ts, size, sizeof(size_t));
6850  if (FOUNDATIONAL_LIB_UNLIKELY(dup_size_ts == NULL))
6851  {
6852  return NULL;
6853  }
6854  qsort(size_ts, size, sizeof(size_t), FOUNDATIONAL_LIB_cmp_size_ts);
6855  return dup_size_ts;
6856 }
6857 
6871 {
6874  return (*(size_t **)a - *(size_t **)b);
6875 }
6876 
6887 FOUNDATIONAL_LIB_FUNC void sort_size_t_ptrs(size_t **size_t_ptrs, size_t size)
6888 {
6889 
6891  qsort(size_t_ptrs, size, sizeof(size_t *), FOUNDATIONAL_LIB_cmp_size_t_ptrs);
6892 }
6908 FOUNDATIONAL_LIB_FUNC size_t **sorted_size_t_ptrs(size_t **size_t_ptrs, size_t size)
6909 {
6911 
6912  size_t **dup_size_t_ptrs = (size_t **)arraydup(size_t_ptrs, size, sizeof(size_t *));
6913 
6914  if (FOUNDATIONAL_LIB_UNLIKELY(dup_size_t_ptrs == NULL))
6915  {
6916  return NULL;
6917  }
6918 
6919  qsort(size_t_ptrs, size, sizeof(size_t *), FOUNDATIONAL_LIB_cmp_size_t_ptrs);
6920 
6921  return dup_size_t_ptrs;
6922 }
6923 
6935 {
6936 
6938  return FOUNDATIONAL_LIB_ATOI(str);
6939 }
6940 
6957 FOUNDATIONAL_LIB_FUNC char *read_file_into_string(const char *filename, size_t *size)
6958 {
6961 
6962  *size = 0;
6963 
6964  FILE *file = fopen(filename, "rb");
6965  if (FOUNDATIONAL_LIB_UNLIKELY(file == NULL))
6966  {
6968  return NULL; // Indicate error by returning NULL
6969  }
6970 
6971  // Determine the file size by seeking
6972  if (FOUNDATIONAL_LIB_FSEEKO(file, 0, SEEK_END) != 0)
6973  {
6974  FOUNDATIONAL_LIB_FCLOSE(file); // No need to error check here because already going wrong.
6976  return NULL;
6977  }
6978 
6979  // Get file size with tell
6980  const off_t file_size = FOUNDATIONAL_LIB_FTELLO(file); /* signed int type */
6981  if (FOUNDATIONAL_LIB_UNLIKELY(file_size == -1))
6982  {
6983  FOUNDATIONAL_LIB_FCLOSE(file); // No need to error check here because already going wrong.
6985  return NULL;
6986  }
6987 
6988  *size = (size_t)file_size;
6989 
6990  // Since off_t is signed, it should be less than SIZE_MAX, so don't check
6991  // if it equals SIZE_MAX before adding 1 more to it to FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC()
6992 
6993  // Seek to the beginning again
6994  if (FOUNDATIONAL_LIB_FSEEKO(file, 0, SEEK_SET) != 0)
6995  {
6996  FOUNDATIONAL_LIB_FCLOSE(file); // No need to error check here because already going wrong.
6998  return NULL;
6999  }
7000 
7001  // Allocate memory for the file contents
7002  char *content = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(file_size + 1); /* Safe. */
7003  if (FOUNDATIONAL_LIB_UNLIKELY(content == NULL))
7004  {
7005  FOUNDATIONAL_LIB_FCLOSE(file); // No need to error check here because already going wrong.
7007  return NULL;
7008  }
7009 
7010  // Read the file contents into the string
7011  size_t total_read = 0;
7012  const size_t file_size_size_t = (size_t)file_size;
7013 
7014  while (total_read < file_size_size_t)
7015  {
7016  const size_t read_size = FOUNDATIONAL_LIB_FREAD(content + total_read, 1, file_size - total_read, file);
7017 
7018  if (read_size == 0) // Not likely or unlikely.
7019  {
7020  const int error_code = FOUNDATIONAL_LIB_FERROR(file);
7021  if (FOUNDATIONAL_LIB_UNLIKELY(error_code))
7022  {
7024  FOUNDATIONAL_LIB_FCLOSE(file); // Don't need to error check here because things are going
7025  // wrong.
7027  return NULL;
7028  }
7029  else
7030  {
7031  break;
7032  }
7033  }
7034  total_read += read_size;
7035  }
7036 
7037  // Null-terminate the string
7038  content[total_read] = '\0';
7039 
7040  // Close the file
7041  if (FOUNDATIONAL_LIB_UNLIKELY(fclose(file) != 0)) // Check for errors.
7042  {
7045  return NULL;
7046  }
7047 
7048  return content;
7049 }
7050 
7065 FOUNDATIONAL_LIB_FUNC int write_to_file_with_mode(const char *filename, const char *content, size_t content_length, const char *mode)
7066 {
7070  FILE *file = fopen(filename, mode);
7071  if (FOUNDATIONAL_LIB_UNLIKELY(file == NULL))
7072  {
7074  return -1;
7075  }
7076 
7077  /* Write the string to the file */
7078  size_t write_size;
7079  size_t total_written = 0;
7080 
7081  /* No need to check for EINTR. It would just slow things down here. */
7082  while ((write_size = FOUNDATIONAL_LIB_FWRITE(content + total_written, 1, content_length - total_written, file)) > 0)
7083  {
7084  total_written += write_size;
7085  }
7086 
7087  // Close the file
7088  if (FOUNDATIONAL_LIB_UNLIKELY(fclose(file) != 0)) // Check for errors.
7089  {
7091  return -1;
7092  }
7093 
7094  return 0;
7095 }
7096 
7109 FOUNDATIONAL_LIB_FUNC int write_file(const char *filename, const char *content)
7110 {
7113 
7114  /* This function is inlined by default. */
7115  return write_to_file_with_mode(filename, content, FOUNDATIONAL_LIB_STRLEN(content), "w");
7116 }
7117 
7132 FOUNDATIONAL_LIB_FUNC int append_string_to_file(const char *filename, const char *content)
7133 {
7136 
7137  /* This function is inlined by default. */
7138  return write_to_file_with_mode(filename, content, FOUNDATIONAL_LIB_STRLEN(content), "a");
7139 }
7140 
7141 #ifdef _WIN32
7142 #include <io.h>
7143 #else
7144 #include <unistd.h>
7145 #endif
7146 
7147 #include <sys/stat.h>
7148 
7157 FOUNDATIONAL_LIB_FUNC int file_exists(const char *filename)
7158 {
7160 
7161 #ifdef _WIN32
7162  return _access(filename, 0) == 0;
7163 #else
7164  return access(filename, F_OK) == 0;
7165 #endif
7166 }
7167 
7177 FOUNDATIONAL_LIB_FUNC int file_is_regular(const char *filename)
7178 {
7180 
7181  struct stat st;
7182 #ifdef _WIN32
7183  if (stat(filename, &st) == 0)
7184  return (st.st_mode & _S_IFREG) != 0;
7185 #else
7186  if (stat(filename, &st) == 0)
7187  return S_ISREG(st.st_mode);
7188 #endif
7189  return 0;
7190 }
7191 
7200 FOUNDATIONAL_LIB_FUNC int file_is_directory(const char *filename)
7201 {
7203 
7204  struct stat st;
7205 #ifdef _WIN32
7206  if (stat(filename, &st) == 0)
7207  return (st.st_mode & _S_IFDIR) != 0;
7208 #else
7209  if (stat(filename, &st) == 0)
7210  return S_ISDIR(st.st_mode);
7211 #endif
7212  return 0;
7213 }
7214 
7225 FOUNDATIONAL_LIB_FUNC int file_is_readable(const char *filename)
7226 {
7228 
7229 #ifdef _WIN32
7230  return _access(filename, 4) == 0; // 4 is for read permission on Windows
7231 #else
7232  return access(filename, R_OK) == 0; // R_OK is for read permission on POSIX systems
7233 #endif
7234 }
7235 
7246 FOUNDATIONAL_LIB_FUNC int file_is_writable(const char *filename)
7247 {
7249 
7250 #ifdef _WIN32
7251  return _access(filename, 2) == 0; // 2 is for write permission on Windows
7252 #else
7253  return access(filename, W_OK) == 0; // W_OK is for write permission on POSIX systems
7254 #endif
7255 }
7256 
7268 {
7270 
7271 #ifdef _WIN32
7272  return _access(filename, 1) == 0; // 1 is for execute permission on Windows
7273 #else
7274  return access(filename, X_OK) == 0; // X_OK is for execute permission on POSIX systems
7275 #endif
7276 }
7277 
7290 FOUNDATIONAL_LIB_FUNC int get_file_size(const char *filename, size_t *size)
7291 {
7294 
7295  FILE *file = fopen(filename, "r");
7296  if (FOUNDATIONAL_LIB_UNLIKELY(file == NULL))
7297  {
7299  return -1;
7300  }
7301 
7302  // Determine the file size with seek
7303  if (FOUNDATIONAL_LIB_UNLIKELY(FOUNDATIONAL_LIB_FSEEKO(file, 0, SEEK_END) != 0))
7304  {
7305  FOUNDATIONAL_LIB_FCLOSE(file); // No need to error check here because already going wrong.
7307  return -1;
7308  }
7309 
7310  // Get the file size with tell
7311  const off_t file_size = ftello(file);
7312  if (FOUNDATIONAL_LIB_UNLIKELY(file_size == -1))
7313  {
7314  FOUNDATIONAL_LIB_FCLOSE(file); // No need to error check here because already going wrong.
7316  return -1;
7317  }
7318 
7319  // Close the file
7320  if (FOUNDATIONAL_LIB_UNLIKELY(fclose(file) != 0)) // Error check
7321  {
7323  return -1;
7324  }
7325 
7326  *size = file_size;
7327  return 0;
7328 }
7329 
7340 FOUNDATIONAL_LIB_FUNC int remove_file(const char *filename)
7341 {
7343 
7344  /* Standard c function */
7345  if (FOUNDATIONAL_LIB_UNLIKELY(remove(filename) != 0))
7346  {
7348  return -1;
7349  }
7350  return 0;
7351 }
7352 
7365 FOUNDATIONAL_LIB_FUNC int copy_file(const char *source_filename, const char *destination_filename)
7366 {
7368  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(destination_filename);
7369  FILE *source_file = fopen(source_filename, "rb");
7370 
7371  if (FOUNDATIONAL_LIB_UNLIKELY(source_file == NULL))
7372  {
7374  return -1;
7375  }
7376 
7377  FILE *destination_file = fopen(destination_filename, "wb");
7378  if (FOUNDATIONAL_LIB_UNLIKELY(destination_file == NULL))
7379  {
7380  FOUNDATIONAL_LIB_FCLOSE(source_file); // No need to error check here because already going
7381  // wrong.
7382 
7384  return -1;
7385  }
7386 
7387  char buffer[FOUNDATIONAL_LIB_COPY_SIZE_AMOUNT];
7388 
7389  for (;;)
7390  {
7391  // Read from the file.
7392  size_t read_size;
7393  int error_code;
7394 
7395  /* Handle interrupted system calls */
7396 
7397  do
7398  {
7399  read_size = FOUNDATIONAL_LIB_FREAD(buffer, 1, sizeof(buffer), source_file);
7400  } while (FOUNDATIONAL_LIB_UNLIKELY((error_code = FOUNDATIONAL_LIB_FERROR(source_file)) && errno == EINTR)); /* Check for EINTR */
7401 
7402  // If it has finished reading or if an error has occured.
7403  if (read_size == 0) // Not likely or unlikely.
7404  {
7405  if (FOUNDATIONAL_LIB_UNLIKELY(error_code))
7406  {
7407  /*
7408  * Here, we can distinuish between errors to ignore, and errors to to
7409  * about. Adjust this based on your environment or preferences.
7410  */
7411 
7412  FOUNDATIONAL_LIB_FCLOSE(destination_file); // Don't need to error check here because
7413  // things are going wrong.
7414  FOUNDATIONAL_LIB_FCLOSE(source_file); // Don't need to error check here because things
7415  // are going wrong.
7416 
7418  return -1;
7419  }
7420  else
7421  {
7422  break;
7423  }
7424  }
7425 
7426  /* Handle interrupted system calls */
7427 
7428  size_t write_size = 0;
7429  size_t new_write_size;
7430  do
7431  {
7432  new_write_size = FOUNDATIONAL_LIB_FWRITE(buffer + write_size, 1, read_size - write_size, destination_file);
7433  write_size += new_write_size;
7434  } while (write_size != read_size || FOUNDATIONAL_LIB_UNLIKELY(errno == EINTR)); /* Check for EINTR */
7435  }
7436 
7437  if (FOUNDATIONAL_LIB_UNLIKELY(ferror(source_file) != 0 || FOUNDATIONAL_LIB_FERROR(destination_file) != 0))
7438  {
7439  FOUNDATIONAL_LIB_FCLOSE(source_file); // No need to error check here because already going
7440  // wrong.
7441  FOUNDATIONAL_LIB_FCLOSE(destination_file); // No need to error check here because already
7442  // going wrong.
7443 
7445  return -1;
7446  }
7447 
7448  if (FOUNDATIONAL_LIB_UNLIKELY(fclose(source_file) != 0 || FOUNDATIONAL_LIB_FCLOSE(destination_file) != 0)) // Error check
7449  {
7451  return -1;
7452  }
7453 
7454  return 0;
7455 }
7456 
7457 #ifdef _WIN32
7458 #include <windows.h>
7459 
7479 FOUNDATIONAL_LIB_FUNC char **list_files_with_pattern(const char *directory, const char *pattern, size_t *len)
7480 {
7484 
7485  *len = 0;
7486  char search_path[MAX_PATH];
7487  FOUNDATIONAL_LIB_SNPRINTF(search_path, MAX_PATH, "%s\\%s", directory, pattern);
7488 
7489  WIN32_FIND_DATA find_file_data;
7490  HANDLE find_handle = FindFirstFile(search_path, &find_file_data);
7491 
7492  if (FOUNDATIONAL_LIB_UNLIKELY(find_handle == INVALID_HANDLE_VALUE))
7493  {
7494 
7495  /* One element of size zero. */
7496  char **new_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(sizeof(char *));
7497  *new_array = NULL;
7498  return new_array;
7499  }
7500 
7501  /* Count the number of files matching the pattern */
7502  int file_count = 0;
7503  do
7504  {
7505  if (!(find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
7506  {
7507  ++file_count;
7508  }
7509  } while (FindNextFile(find_handle, &find_file_data) != 0);
7510 
7511  size_t mul;
7512 
7513  if (FOUNDATIONAL_LIB_UNLIKELY(file_count == 0))
7514  {
7516  }
7517  else if (FOUNDATIONAL_LIB_UNLIKELY(FOUNDATIONAL_LIB_safe_mul_ptr(file_count, sizeof(char *), &mul) == 0))
7518  {
7520  return NULL;
7521  }
7522 
7523  /* Allocate memory for the array of strings */
7524  char **files_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(mul);
7525  if (FOUNDATIONAL_LIB_UNLIKELY(files_array == NULL))
7526  {
7528  return NULL;
7529  }
7530 
7531  /* Populate the array with file names matching the pattern */
7532  int index = 0;
7533  if (FOUNDATIONAL_LIB_UNLIKELY(FindClose(find_handle) == 0))
7534  {
7536  return NULL;
7537  }
7538  find_handle = FindFirstFile(search_path, &find_file_data);
7539  do
7540  {
7541  if (!(find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
7542  {
7543  files_array[index] = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(find_file_data.cFileName);
7544  if (FOUNDATIONAL_LIB_UNLIKELY(files_array[index] == NULL))
7545  {
7546  return NULL;
7547  }
7548  ++index;
7549  }
7550  } while (FindNextFile(find_handle, &find_file_data) != 0);
7551 
7552  /* Close the find handle */
7553  if (FOUNDATIONAL_LIB_UNLIKELY(FindClose(find_handle) == 0))
7554  {
7556  return NULL;
7557  }
7558 
7559  *len = index;
7560 
7561  return files_array;
7562 }
7563 
7564 #else
7565 
7566 #include <dirent.h>
7567 #include <fnmatch.h>
7568 
7588 FOUNDATIONAL_LIB_FUNC char **list_files_with_pattern(const char *directory, const char *pattern, size_t *len)
7589 {
7593 
7594  *len = 0;
7595  DIR *dir = opendir(directory);
7596  if (FOUNDATIONAL_LIB_UNLIKELY(dir == NULL))
7597  {
7599  return NULL;
7600  }
7601 
7602  /* Count the number of files matching the pattern */
7603  int file_count = 0;
7604  struct dirent *entry;
7605  while ((entry = readdir(dir)) != NULL)
7606  {
7607  if (fnmatch(pattern, entry->d_name, FNM_PERIOD) == 0)
7608  {
7609  ++file_count;
7610  }
7611  }
7612 
7613  rewinddir(dir); // No errors with this function
7614 
7615  size_t mul;
7616 
7617  if (FOUNDATIONAL_LIB_UNLIKELY(file_count == 0))
7618  {
7620  }
7621  else if (FOUNDATIONAL_LIB_UNLIKELY(FOUNDATIONAL_LIB_safe_mul_ptr(file_count, sizeof(char *), &mul) == 0))
7622  {
7624  return NULL;
7625  }
7626 
7627  /* Allocate memory for the array of strings */
7628  char **files_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(mul);
7629 
7630  /* Populate the array with file names matching the pattern */
7631  size_t index = 0;
7632  while ((entry = readdir(dir)) != NULL)
7633  {
7634  if (fnmatch(pattern, entry->d_name, FNM_PERIOD) == 0)
7635  {
7636  files_array[index] = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(entry->d_name);
7637  if (FOUNDATIONAL_LIB_UNLIKELY(files_array[index] == NULL))
7638  {
7640  return NULL;
7641  }
7642  ++index;
7643  }
7644  }
7645  if (FOUNDATIONAL_LIB_UNLIKELY(closedir(dir) == -1))
7646  {
7648  return NULL;
7649  }
7650 
7651  *len = index;
7652 
7653  return files_array;
7654 }
7655 
7656 #endif
7657 
7674 FOUNDATIONAL_LIB_FUNC char *concatenate_string_array(const char **strings, size_t num_strings)
7675 {
7677 
7678  /* Initialize total length and allocate initial memory for result */
7680  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size);
7681 
7682  // Check for initial memory allocation failure
7683  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
7684  goto memory_error;
7685 
7686  size_t new_len;
7687 
7688  // If no strings, new_len will still be 0, and then a null terminator will be put at byte 0.
7689  new_len = 0;
7690 
7691  // Concatenate the strings char by char using FOUNDATIONAL_LIB_MEMCPY and FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC
7692  for (size_t i = 0; i < num_strings; ++i)
7693  {
7694  const char *current_string = strings[i];
7695 
7696  // Iterate through each character and append to the result
7697  size_t current_length_of_current_string = 0;
7698  while (current_string[current_length_of_current_string] != '\0')
7699  {
7700  if (FOUNDATIONAL_LIB_UNLIKELY(new_len == SIZE_MAX))
7701  goto overflow;
7702  /* FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM returns always at least one more */
7703  const size_t new_size = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(new_len + sizeof("")); /* Safe. */
7704 
7705  if (FOUNDATIONAL_LIB_UNLIKELY(new_size == 0))
7706  {
7708  goto memory_error;
7709  }
7710  // Resize the result string if necessary
7711  if (FOUNDATIONAL_LIB_UNLIKELY(new_size > alloc_size))
7712  {
7713  char *new_result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(result, new_size);
7714 
7715  // Check for realloc failure
7716  if (FOUNDATIONAL_LIB_UNLIKELY(new_result == NULL))
7717  {
7719  goto memory_error;
7720  }
7721 
7722  result = new_result;
7723  }
7724 
7725  // Append the current character to the result
7726  result[new_len++] = current_string[current_length_of_current_string++];
7727  }
7728  }
7729 
7730  // Add the null terminator
7731  result[new_len] = '\0';
7732 
7733  return result;
7734 
7735 overflow:
7736 memory_error:
7738  return NULL;
7739 }
7740 
7755 FOUNDATIONAL_LIB_FUNC char *concatenate_strings(const char *str1, const char *str2)
7756 {
7759 
7760  const char *strs[2] = {str1, str2};
7761 
7762  return concatenate_string_array(strs, 2);
7763 }
7764 
7805 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)
7806 {
7811  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(output_length_without_nullt);
7812  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(should_free_after_use);
7814 
7815  if (FOUNDATIONAL_LIB_UNLIKELY(find_len == 0))
7816  goto no_matches;
7817 
7818  size_t matches;
7819 
7820  matches = 0;
7821 
7822  // Count the occurrences of 'find' in 'source'
7823  const char *p;
7824 
7825  p = (const char *)source;
7826 
7827  const char *end_of_memory;
7828  end_of_memory = (const char *)source + source_len;
7829 
7830  for (;;)
7831  {
7832  if ((p = (const char *)memory_locate((const void *)p, (end_of_memory - p), find, find_len)) == NULL)
7833  break;
7834  if (matches_max && matches == matches_max)
7835  break;
7836 
7837  ++matches;
7838  p += find_len;
7839  puts("FOR");
7840  }
7841 
7842  // Let's assume that it's 'likely' to find a match.
7843  if (FOUNDATIONAL_LIB_UNLIKELY(matches == 0))
7844  {
7845  no_matches:
7846  *should_free_after_use = 0;
7847  *output_length_without_nullt = source_len;
7848  *output = source;
7849  return 0;
7850  }
7851 
7852  *should_free_after_use = 1;
7853  *num_matches_found = matches;
7854 
7855  size_t final_len = source_len - matches * find_len + matches * replace_len; // Overflow should not be an issue here.
7856 
7857  if (should_nullt)
7858  {
7859  ++final_len;
7860  }
7861 
7862  // Allocate memory for the replaced string
7863  char *result;
7864 
7865  result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(final_len);
7866  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
7867  {
7868  goto memory_error;
7869  }
7870  *output_length_without_nullt = final_len;
7871 
7872  *output = result;
7873 
7874  // Perform the replacement
7875  char *rp;
7876 
7877  rp = result;
7878 
7879  p = (const char *)source;
7880 
7881  matches = 0;
7882 
7883  // If matches is 0, this is not run.
7884  for (matches = 0; !matches_max || (matches < matches_max); ++matches)
7885  {
7886  if ((p = (const char *)memory_locate((const void *)p, end_of_memory - p, find, find_len)) == NULL)
7887  break;
7888 
7889  if (matches_max && matches == matches_max)
7890  break;
7891 
7892  size_t prefix_len = p - (const char *)source;
7893  FOUNDATIONAL_LIB_MEMCPY(rp, source, prefix_len);
7894  rp += prefix_len;
7895  FOUNDATIONAL_LIB_MEMCPY(rp, replace, replace_len);
7896  rp += replace_len;
7897  p += find_len;
7898  source = (void *)p;
7899  }
7900 
7901  // Copy the remaining part of the source string
7902  size_t remaining_len;
7903 
7904  remaining_len = end_of_memory - (const char *)source;
7905  FOUNDATIONAL_LIB_MEMCPY(rp, source, remaining_len);
7906 
7907  if (should_nullt)
7908  {
7909  rp[remaining_len] = '\0';
7910  }
7911 
7912  return 0;
7913 
7914 memory_error:
7915  *output = NULL;
7916  *output_length_without_nullt = 0;
7918  return -1;
7919 }
7920 
7962 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)
7963 {
7964  /* replace_memory checks args if enabled. */
7965  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);
7966 }
7967 
7982 FOUNDATIONAL_LIB_FUNC char *replace_all(const char *source, const char *find, const char *replace)
7983 {
7984  /* replace_memory checks args if enabled. */
7985 
7986  size_t new_len;
7987  char *output;
7988  int should_free_after_use;
7989  size_t num_matches;
7990  const size_t matches_max = 0;
7991 
7992  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)
7993  {
7995  return NULL;
7996  }
7997 
7998  if (!should_free_after_use)
7999  {
8000  if (FOUNDATIONAL_LIB_UNLIKELY(new_len == SIZE_MAX))
8001  {
8003  return NULL;
8004  }
8005 
8006  char *new_output = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(new_len + 1); /* Safe. */
8007  memcpy(new_output, output, new_len + 1); /* It was already null terminated */
8008  return new_output;
8009  }
8010 
8011  return output;
8012 }
8013 
8028 FOUNDATIONAL_LIB_FUNC char *replace_first(const char *source, const char *find, const char *replace)
8029 {
8030  /* replace_memory checks args if enabled. */
8031 
8032  size_t new_len;
8033  char *output;
8034  int should_free_after_use;
8035  size_t num_matches;
8036  const size_t matches_max = 1;
8037 
8038  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)
8039  {
8041  return NULL;
8042  }
8043 
8044  if (!should_free_after_use)
8045  {
8046  if (FOUNDATIONAL_LIB_UNLIKELY(new_len == SIZE_MAX))
8047  {
8049  return NULL;
8050  }
8051 
8052  char *new_output = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(new_len + 1); /* Safe. */
8053  memcpy(new_output, output, new_len + 1); /* It was already null terminated */
8054  return new_output;
8055  }
8056 
8057  return output;
8058 }
8059 
8074 FOUNDATIONAL_LIB_FUNC char *replace_count(const char *source, const char *find, const char *replace, const size_t matches_max)
8075 {
8076  /* replace_memory checks args if enabled. */
8077 
8078  size_t new_len;
8079  char *output;
8080  int should_free_after_use;
8081  size_t num_matches;
8082  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)
8083  {
8085  return NULL;
8086  }
8087 
8088  if (!should_free_after_use)
8089  {
8090  if (FOUNDATIONAL_LIB_UNLIKELY(new_len == SIZE_MAX))
8091  {
8093  return NULL;
8094  }
8095 
8096  char *new_output = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(new_len + 1); /* Safe. */
8097  memcpy(new_output, output, new_len + 1); /* It was already null terminated */
8098  return new_output;
8099  }
8100 
8101  return output;
8102 }
8103 
8122 FOUNDATIONAL_LIB_FUNC char *replace_all_with_callback(const char *str, const char *old_substring, char *(*callback)(const char *, void *), void *data_for_callback)
8123 {
8127 
8128  const size_t str_len = strlen(str);
8129  const size_t old_substring_len = strlen(old_substring);
8130  size_t alloc_size = str_len + 1; // Start with the original string length + 1 for the null terminator
8131 
8132  // Allocate memory for the result string
8133  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(str_len);
8134  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
8135  {
8137  return NULL;
8138  }
8139 
8140  // Copy and replace substrings
8141  const char *pos = str;
8142 
8143  size_t new_len = 0;
8144 
8145  for (;;)
8146  {
8147  const char *found_pos = (const char *)memory_locate(pos, str_len - (pos - str), old_substring, old_substring_len);
8148  if (FOUNDATIONAL_LIB_UNLIKELY(found_pos == NULL))
8149  {
8150  size_t remaining_len = str_len - (pos - str);
8151  memcpy(result + new_len, pos, remaining_len);
8152  new_len += remaining_len;
8153 
8154  result[new_len] = '\0';
8155 
8156  new_len += remaining_len;
8157  break;
8158  }
8159 
8160  // Copy the segment
8161 
8162  char *replacement = callback(old_substring, data_for_callback);
8163 
8164  // Resize the result buffer if needed
8165  size_t replacement_len = strlen(replacement);
8166 
8167  size_t nlen;
8168 
8169  const size_t diff = found_pos - pos;
8170 
8171  if (FOUNDATIONAL_LIB_UNLIKELY(FOUNDATIONAL_LIB_safe_add_3_ptr(new_len, diff, replacement_len, &nlen) == 0))
8172  {
8173  goto overflow;
8174  }
8175 
8176  if (FOUNDATIONAL_LIB_UNLIKELY(nlen == SIZE_MAX))
8177  goto overflow;
8178 
8179  ++nlen;
8180 
8181  if (nlen >= alloc_size)
8182  {
8183  /* Makes it at least 1 bigger. */
8185  char *new_result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(result, alloc_size);
8186  if (FOUNDATIONAL_LIB_UNLIKELY(new_result == NULL))
8187  {
8189  goto error;
8190  }
8191  result = new_result;
8192  }
8193 
8194  memcpy(result + new_len, pos, found_pos - pos); /* Safe. */
8195  new_len += found_pos - pos;
8196  memcpy(result + new_len, replacement, replacement_len);
8198  new_len += replacement_len;
8199  pos = found_pos + old_substring_len;
8200  }
8201 
8202  return result;
8203 overflow:
8204 
8205 error:
8208  return NULL;
8209 }
8210 
8225 FOUNDATIONAL_LIB_FUNC char *dup_format(const char *format, ...)
8226 {
8228 
8230  FOUNDATIONAL_LIB_VA_START(args, format);
8231 
8232  /* Determine the length of the formatted string */
8233  const int len = FOUNDATIONAL_LIB_VSNPRINTF(NULL, 0, format, args);
8234 
8236 
8237  if (len == -1)
8238  goto memory_error;
8239 
8240  /* Would-be Overflow */
8241  if (FOUNDATIONAL_LIB_UNLIKELY(sizeof(int) >= sizeof(size_t) && (size_t)len == SIZE_MAX))
8242  goto memory_error;
8243 
8244  /* Allocate memory for the formatted string */
8245  char *result;
8246 
8247  result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(len + sizeof("")); /* Safe */
8248  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
8249  goto memory_error;
8250 
8251  FOUNDATIONAL_LIB_VA_START(args, format);
8252  if (FOUNDATIONAL_LIB_VSNPRINTF(result, len + 1, format, args) == -1)
8253  {
8256  goto memory_error;
8257  }
8258 
8260 
8261  return result;
8262 
8263 memory_error:
8265  return NULL;
8266 }
8295 FOUNDATIONAL_LIB_FUNC void map_ints(int *array, size_t size, int (*transform)(int))
8296 {
8299 
8300  for (size_t i = 0; i < size; i++)
8301  {
8302  array[i] = transform(array[i]);
8303  }
8304 }
8305 
8337 FOUNDATIONAL_LIB_FUNC int reduce_ints(int *array, size_t size, int (*operation)(int, int))
8338 {
8341 
8342  int result = array[0];
8343  for (size_t i = 1; i < size; i++)
8344  {
8345  result = operation(result, array[i]);
8346  }
8347  return result;
8348 }
8349 
8388 FOUNDATIONAL_LIB_FUNC int filter_ints(int *source, size_t source_size, int *destination, int (*condition)(int))
8389 {
8390 
8394 
8395  size_t count = 0;
8396  for (size_t i = 0; i < source_size; i++)
8397  {
8398  if (condition(source[i]))
8399  {
8400  destination[count++] = source[i];
8401  }
8402  }
8403  return count;
8404 }
8405 
8435 FOUNDATIONAL_LIB_FUNC void map(void *array, size_t size, size_t elem_size, void (*transform)(void *))
8436 {
8437 
8440 
8441  for (size_t i = 0; i < size; i++)
8442  {
8443  transform(((char *)array) + i * elem_size);
8444  }
8445 }
8446 
8481 FOUNDATIONAL_LIB_FUNC void reduce(void *array, size_t size, size_t elem_size, void *result, void (*operation)(void *, void *))
8482 {
8486 
8487  char *char_array = (char *)array;
8488  char *char_result = (char *)result;
8489 
8490  /* Initialize the result with the first element */
8491  for (size_t i = 0; i < elem_size; i++)
8492  {
8493  char_result[i] = char_array[i];
8494  }
8495 
8496  for (size_t i = 1; i < size; i++)
8497  {
8498  operation(char_result, char_array + i * elem_size);
8499  }
8500 }
8501 
8543 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 *))
8544 {
8545 
8549 
8550  char *char_source = (char *)source;
8551  char *char_destination = (char *)destination;
8552 
8553  size_t count = 0;
8554  for (size_t i = 0; i < source_size; i++)
8555  {
8556  if (condition(char_source + i * elem_size))
8557  {
8558  if (count < dest_size)
8559  {
8560  for (size_t j = 0; j < elem_size; j++)
8561  {
8562  char_destination[count * elem_size + j] = char_source[i * elem_size + j];
8563  }
8564  }
8565  count++;
8566  }
8567  }
8568  return count;
8569 }
8570 
8659 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)
8660 {
8664 
8666 
8667  // Set result size to 0 first thing.
8668  *result_size = 0;
8669 
8670  const size_t alloc_size = FOUNDATIONAL_LIB_safe_mul(array_size, elem_size);
8671 
8672  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size == 0))
8673  {
8674  /* Handle overflow error. */
8676  return NULL;
8677  }
8678 
8679  /* Allocate memory for the result array */
8680  void *result = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size);
8681 
8682  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
8683  {
8684  /* Handle memory allocation error */
8686  return NULL;
8687  }
8688 
8689  /* Iterate through the input array */
8690  for (size_t i = 0; i < array_size; ++i)
8691  {
8692  /* Apply the filter function */
8693 
8694  // Assume that there cannot be an overflow error
8695  // because iterating through a size_t array from 0.
8696  if (filter_func((void *)((char *)input_array + i * elem_size)))
8697  {
8698  /* Apply the transformation function */
8699 
8700  void *addr = (char *)result + (*result_size) * elem_size;
8701  FOUNDATIONAL_LIB_MEMCPY(addr, (char *)input_array + (i * elem_size), elem_size); /* Safe. */
8702  transform_func(addr);
8703  ++(*result_size);
8704  }
8705  }
8706 
8707  // We need this so that gcc with -std=c11 under mingw32 doesn't give a
8708  // warning about memory possibly being accessed after freeing()
8709  // This only seems to happen with mingw32, and is a bug in it.
8710  // I included a relevant ISO/IEC statement about realloc in this file.
8711  //
8712  // This code has no bug.
8713 
8714 #pragma GCC diagnostic push
8715 #pragma GCC diagnostic ignored "-Wpragmas"
8716 #pragma GCC diagnostic ignored "-Wuse-after-free"
8717 
8718  /*
8719  * Make the result smaller to free a bit of memory. Not necessary, but it saves memory.
8720  * array_size * (*result_size) will not be larger than the current size.
8721  *
8722  * Dont do safe mul here because this should be smaller than current amounts.
8723  */
8724  char *new_result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(result, array_size * (*result_size)); /* Safe. */
8725 
8726  if (FOUNDATIONAL_LIB_UNLIKELY(new_result == NULL))
8727  {
8729  return result;
8730  }
8731 
8732 #pragma GCC diagnostic pop
8733 
8734  /*
8735  ISO/IEC 9899:2011:
8736 
8737  "If memory for the new object cannot be allocated,
8738  the old object is not deallocated and its value is unchanged."
8739  */
8740 
8741  return new_result;
8742 }
8743 
8744 /* For Set */
8745 struct SetKey
8746 {
8747  char *key;
8748  struct SetKey *next;
8749 };
8750 
8751 struct Dict
8752 {
8754  size_t capacity;
8755  size_t size;
8756 };
8757 
8758 struct Set
8759 {
8760  struct SetKey **table;
8761  size_t capacity;
8762  size_t size;
8763 };
8764 
8767 {
8768  char *key;
8769  void *value;
8771 };
8772 /* FrozenDict struct */
8774 {
8776  size_t capacity;
8777  size_t size;
8778 };
8779 
8780 /* FrozenSet struct. */
8782 {
8783  struct SetKey **table;
8784  size_t capacity;
8785  size_t size;
8786 };
8787 
8788 /* Sets */
8789 typedef struct FrozenSet FrozenSet;
8790 typedef struct Set Set;
8791 
8792 /* Dicts */
8793 typedef struct Dict Dict;
8794 typedef struct FrozenDict FrozenDict;
8795 
8796 #if FOUNDATIONAL_LIB_THREAD_FUNCTIONS_ENABLED
8797 #include <threads.h>
8798 
8799 // Define a structure to hold thread-specific data
8801 {
8802  const void *input_array;
8803  size_t array_size;
8804  size_t elem_size;
8805  void (*transform_func)(void *value);
8806  int (*filter_func)(void *value);
8807  size_t *result_size;
8808  void *result;
8809  size_t start_index;
8810  size_t end_index;
8811 };
8812 
8813 /*
8814  * Define the worker function for each thread, as used by
8815  * list_comprehension_multithreaded()
8816  */
8818 {
8820  struct ThreadData *thread_data = (struct ThreadData *)data;
8821  *thread_data->result_size = 0;
8822 
8823  const size_t subtraction = (thread_data->end_index - thread_data->start_index);
8824 
8825  const size_t mul = FOUNDATIONAL_LIB_safe_mul(thread_data->elem_size, subtraction);
8826 
8827  if (FOUNDATIONAL_LIB_UNLIKELY(mul == 0)) // Overflow
8828  {
8830  return -1;
8831  }
8832 
8833  void *buffer = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(mul);
8834 
8835  if (FOUNDATIONAL_LIB_UNLIKELY(buffer == NULL))
8836  {
8838  return -1;
8839  }
8840 
8841  // Iterate through the assigned chunk of the input array
8842 
8843  // Start index and end index should be valid indices and no possiblity
8844  // for overflow error.
8845  for (size_t i = thread_data->start_index; i < thread_data->end_index; ++i)
8846  {
8847  // Apply the filter function
8848  if (thread_data->filter_func((void *)((char *)thread_data->input_array + i * thread_data->elem_size)))
8849  {
8850  // Copy the value to the result array
8851  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. */
8852 
8853  ++(*thread_data->result_size);
8854  }
8855  }
8856 
8857  // Apply the transformation function to the entire result chunk
8858  for (size_t i = 0; i < (*thread_data->result_size); ++i)
8859  {
8860  thread_data->transform_func((void *)((char *)buffer + i * thread_data->elem_size));
8861  }
8862 
8863  thread_data->result = buffer;
8864  return 0;
8865 }
8866 
8885 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)
8886 {
8891 
8892  if (FOUNDATIONAL_LIB_UNLIKELY(thread_count == 0))
8893  {
8894  // This doesn't make sense, so assume they mean 1.
8895  thread_count = 1;
8896  }
8897 
8898  // Set result size to 0 first thing.
8899  *result_size = 0;
8900 
8901  const size_t alloc_size_for_result = FOUNDATIONAL_LIB_safe_mul(array_size, elem_size);
8902 
8903  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size_for_result == 0))
8904  {
8905  /* Handle overflow error. */
8907  return NULL;
8908  }
8909 
8910  /* Allocate memory for the result array */
8911  void *result = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size_for_result);
8912 
8913  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
8914  {
8915  /* Handle memory allocation error */
8917  return NULL;
8918  }
8919 
8920  /* Allocate memory for result sizes */
8921 
8922  const size_t alloc_size_for_thread_result_sizes = FOUNDATIONAL_LIB_safe_mul(thread_count, sizeof(size_t));
8923  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size_for_thread_result_sizes == 0))
8924  {
8925  /* Handle overflow error. */
8928  return NULL;
8929  }
8930 
8931  size_t *thread_result_sizes = (size_t *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size_for_thread_result_sizes);
8932  if (FOUNDATIONAL_LIB_UNLIKELY(thread_result_sizes == NULL))
8933  {
8934  // Handle memory allocation error
8937  return NULL;
8938  }
8939 
8940  const size_t alloc_size_for_threads = FOUNDATIONAL_LIB_safe_mul(thread_count, sizeof(thrd_t));
8941  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size_for_threads == 0))
8942  {
8943  /* Handle overflow error. */
8945  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE(thread_result_sizes);
8947  return NULL;
8948  }
8949 
8950  // Initialize thread data
8951  thrd_t *threads = (thrd_t *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size_for_threads);
8952  if (FOUNDATIONAL_LIB_UNLIKELY(threads == NULL))
8953  {
8954  // Handle memory allocation error
8956  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE(thread_result_sizes);
8958  return NULL;
8959  }
8960  const size_t alloc_size_for_thread_data = FOUNDATIONAL_LIB_safe_mul(thread_count, sizeof(struct ThreadData));
8961  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size_for_thread_data == 0))
8962  {
8963  /* Handle overflow error. */
8965  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE(thread_result_sizes);
8967  return NULL;
8968  }
8969  struct ThreadData *thread_data = (struct ThreadData *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size_for_thread_data);
8970  if (FOUNDATIONAL_LIB_UNLIKELY(thread_data == NULL))
8971  {
8972  cannot_allocate_or_create:
8974  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE(thread_result_sizes);
8975 
8977 
8979  return NULL;
8980  }
8981 
8982  // Divide the input array into chunks for each thread
8983  size_t chunk_size = array_size / thread_count;
8984  size_t remaining = array_size % thread_count;
8985  size_t current_index = 0;
8986 
8987  for (size_t i = 0; i < thread_count; ++i)
8988  {
8989  size_t e_index;
8990  const size_t ret = FOUNDATIONAL_LIB_safe_add_3_ptr(current_index, chunk_size, (remaining > 0 ? 1 : 0), &e_index);
8991 
8992  if (FOUNDATIONAL_LIB_UNLIKELY(ret == 0))
8993  goto cannot_allocate_or_create; // Overflow
8994 
8995  thread_data[i].input_array = input_array;
8996  thread_data[i].array_size = array_size;
8997  thread_data[i].elem_size = elem_size;
8998  thread_data[i].transform_func = transform_func;
8999  thread_data[i].filter_func = filter_func;
9000  thread_data[i].result_size = &thread_result_sizes[i];
9001  thread_data[i].result = result;
9002  thread_data[i].start_index = current_index;
9003  thread_data[i].end_index = e_index;
9004 
9005  if (remaining > 0)
9006  {
9007  --remaining;
9008  }
9009 
9010  current_index = thread_data[i].end_index;
9011 
9012  // Create a thread for each chunk
9013  if (FOUNDATIONAL_LIB_UNLIKELY(thrd_create(&threads[i], FOUNDATIONAL_LIB_list_comprehension_worker, (void *)&thread_data[i]) != thrd_success))
9014  goto cannot_allocate_or_create;
9015  }
9016 
9017  // Wait for all threads to finish
9018  for (size_t i = 0; i < thread_count; ++i)
9019  {
9020  int return_value_of_thread;
9021  thrd_join(threads[i], &return_value_of_thread);
9022 
9023  // The thread failed.
9024  if (FOUNDATIONAL_LIB_UNLIKELY(return_value_of_thread == -1))
9025  goto cannot_allocate_or_create;
9026  }
9027  // Calculate the total result size
9028  size_t total_result_size = 0;
9029  for (size_t i = 0; i < thread_count; ++i)
9030  {
9031  FOUNDATIONAL_LIB_MEMCPY((char *)result + total_result_size * elem_size, thread_data[i].result, thread_result_sizes[i] * elem_size); /* Safe. */
9033 
9034  // Should always be <= SIZE_MAX
9035  total_result_size += thread_result_sizes[i];
9036  }
9037 
9038  // Update the final result size
9039  *result_size = total_result_size;
9040 
9041  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE(thread_result_sizes);
9044 
9045  return result;
9046 }
9047 
9048 #endif
9049 
9068 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)
9069 {
9070 
9073 
9075  *result_size = 0;
9076  /* Allocate memory for the result array */
9077 
9078  const size_t mul = FOUNDATIONAL_LIB_safe_mul(source_size, elem_size);
9079  if (FOUNDATIONAL_LIB_UNLIKELY(mul == 0))
9080  {
9082  return NULL;
9083  }
9084 
9086  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
9087  {
9089  return NULL;
9090  }
9091 
9092  size_t result_index = 0;
9093 
9094  /* Apply the rejection condition to each element */
9095  for (size_t i = 0; i < source_size; ++i)
9096  {
9097  // Should be a valid index if passed a valid argument.
9098  const void *current_source = (char *)source + i * elem_size;
9099 
9100  /* Check condition */
9101  if (!condition(current_source))
9102  {
9103  void *current_result = (char *)result + result_index * elem_size;
9104  FOUNDATIONAL_LIB_MEMCPY(current_result, current_source, elem_size);
9105  result_index++;
9106  }
9107  }
9108 
9109  /* Set the result size */
9110  *result_size = result_index;
9111 
9112  return result;
9113 }
9114 
9133 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)
9134 {
9135 
9137 
9140 
9141  *result_size = 0;
9142  /* Allocate memory for the result array */
9143 
9144  const size_t mul = FOUNDATIONAL_LIB_safe_mul(source_size, elem_size);
9145  if (FOUNDATIONAL_LIB_UNLIKELY(mul == 0))
9146  {
9148  return NULL;
9149  }
9150 
9152  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
9153  {
9155  return NULL;
9156  }
9157 
9158  size_t result_index = 0;
9159 
9160  /* Apply the selection condition to each element */
9161  for (size_t i = 0; i < source_size; ++i)
9162  {
9163  const void *current_source = (char *)source + i * elem_size;
9164 
9165  /* Check condition */
9166  if (condition(current_source))
9167  {
9168  void *current_result = (char *)result + result_index * elem_size;
9169  FOUNDATIONAL_LIB_MEMCPY(current_result, current_source, elem_size);
9170  ++result_index;
9171  }
9172  }
9173 
9174  /* Set the result size */
9175  *result_size = result_index;
9176 
9177  return result;
9178 }
9179 
9195 FOUNDATIONAL_LIB_FUNC void *replicate(const void *source, size_t source_size, size_t elem_size, size_t repetitions)
9196 {
9197 
9199 
9200  /* elem_size * source_size * repetitions */
9201 
9202  const size_t elem_times_source = FOUNDATIONAL_LIB_safe_mul(elem_size, source_size);
9203  if (FOUNDATIONAL_LIB_UNLIKELY(elem_times_source == 0))
9204  {
9206  return NULL;
9207  }
9208 
9209  const size_t result_total_size = FOUNDATIONAL_LIB_safe_mul(elem_times_source, repetitions);
9210  if (FOUNDATIONAL_LIB_UNLIKELY(result_total_size == 0))
9211  {
9213  return NULL;
9214  }
9215 
9216  /* Allocate memory for the result array */
9217  void *result = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(result_total_size);
9218  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
9219  {
9221  return NULL;
9222  }
9223 
9224  /* Copy the source array to the result array multiple times */
9225  for (size_t i = 0; i < repetitions; ++i)
9226  {
9227  // Counting from zero so it should not be an overflow.
9228  FOUNDATIONAL_LIB_MEMCPY((char *)result + (i * elem_times_source), source, elem_times_source); /* Safe. */
9229  }
9230 
9231  return result;
9232 }
9233 
9249 {
9250 
9252 
9253  char *new_str = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(string);
9254 
9255  if (FOUNDATIONAL_LIB_UNLIKELY(new_str == NULL))
9256  {
9258  return NULL;
9259  }
9260  char *orig_str = new_str;
9261  while (*new_str)
9262  {
9263  *new_str = tolower(*new_str);
9264  ++new_str;
9265  }
9266 
9267  return orig_str;
9268 }
9269 
9285 {
9286 
9288  char *new_str = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP(string);
9289  if (FOUNDATIONAL_LIB_UNLIKELY(new_str == NULL))
9290  {
9292  return NULL;
9293  }
9294  char *orig_str = new_str;
9295  while (*new_str)
9296  {
9297  *new_str = toupper(*new_str);
9298  ++new_str;
9299  }
9300 
9301  return orig_str;
9302 }
9303 
9317 {
9318 
9320  while (*string)
9321  {
9322  if (!FOUNDATIONAL_LIB_ISUPPER(*string))
9323  {
9324  return 0;
9325  }
9326  ++string;
9327  }
9328  return 1;
9329 }
9330 
9344 {
9346 
9347  while (*string)
9348  {
9349  if (!FOUNDATIONAL_LIB_ISLOWER(*string))
9350  {
9351  return 0;
9352  }
9353  ++string;
9354  }
9355  return 1;
9356 }
9357 
9371 {
9373  while (*string)
9374  {
9375  if (!FOUNDATIONAL_LIB_ISALNUM(*string))
9376  {
9377  return 0;
9378  }
9379 
9380  ++string;
9381  }
9382  return 1;
9383 }
9384 
9398 {
9400  while (*string)
9401  {
9402  if (!FOUNDATIONAL_LIB_ISDIGIT(*string))
9403  {
9404  return 0;
9405  }
9406  ++string;
9407  }
9408  return 1;
9409 }
9410 
9424 {
9426 
9427  while (*string)
9428  {
9429  if (!FOUNDATIONAL_LIB_ISSPACE(*string))
9430  {
9431  return 0;
9432  }
9433  ++string;
9434  }
9435  return 1;
9436 }
9457 {
9459  while (*string)
9460  {
9461  if (!FOUNDATIONAL_LIB_ISPRINT(*string))
9462  {
9463  return 0;
9464  }
9465  ++string;
9466  }
9467  return 1;
9468 }
9469 
9498 FOUNDATIONAL_LIB_FUNC int is_array_digit(const char **array, size_t size)
9499 {
9500 
9502  for (size_t i = 0; i < size; ++i)
9503  {
9504  const char *str = array[i];
9505  while (*str)
9506  {
9507  if (!FOUNDATIONAL_LIB_ISDIGIT(*str))
9508  {
9509  return 0;
9510  }
9511  ++str;
9512  }
9513  }
9514  return 1;
9515 }
9528 FOUNDATIONAL_LIB_FUNC int is_array_upper(const char **array, size_t size)
9529 {
9530 
9532  for (size_t i = 0; i < size; ++i)
9533  {
9534  const char *str = array[i];
9535  while (*str)
9536  {
9537  if (!FOUNDATIONAL_LIB_ISUPPER(*str))
9538  {
9539  return 0;
9540  }
9541  ++str;
9542  }
9543  }
9544  return 1;
9545 }
9546 
9559 FOUNDATIONAL_LIB_FUNC int is_array_lower(const char **array, size_t size)
9560 {
9561 
9563  for (size_t i = 0; i < size; ++i)
9564  {
9565  const char *str = array[i];
9566  while (*str)
9567  {
9568  if (!FOUNDATIONAL_LIB_ISLOWER(*str))
9569  {
9570  return 0;
9571  }
9572  ++str;
9573  }
9574  }
9575  return 1;
9576 }
9577 
9614 FOUNDATIONAL_LIB_FUNC int string_array_uniq(const char **array, size_t size, char ***output, size_t *output_size)
9615 {
9617 
9620 
9621  *output_size = 0;
9622 
9623  const size_t alloc_size = FOUNDATIONAL_LIB_safe_mul(size, sizeof(char *));
9624 
9625  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size == 0))
9626  {
9628  return -1;
9629  }
9630 
9631  // Count the number of unique strings
9632  size_t count = 0;
9633 
9634  // Allocate memory for the array to store unique strings
9635  *output = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size);
9636  if (FOUNDATIONAL_LIB_UNLIKELY(*output == NULL))
9637  {
9638  // Memory allocation failed
9640  return -1;
9641  }
9642 
9643  // Initialize all elements to NULL
9644  for (size_t i = 0; i < size; i++)
9645  {
9646  (*output)[i] = NULL;
9647  }
9648 
9649  // Iterate through the input array to find unique strings
9650  for (size_t i = 0; i < size; i++)
9651  {
9652  int is_unique = 1;
9653 
9654  // Check if the current string is not equal to any previous strings
9655  for (size_t j = 0; j < count; j++)
9656  {
9657  if ((*output)[j] != NULL && FOUNDATIONAL_LIB_STRCMP(array[i], (*output)[j]) == 0)
9658  {
9659  is_unique = 0; // Not unique
9660  break;
9661  }
9662  }
9663 
9664  if (is_unique)
9665  {
9666  (*output)[count] = ((char **)array)[i]; // No strdup used.
9667 
9668  ++count;
9669  }
9670  }
9671 
9672  // Set the output size
9673  *output_size = count;
9674 
9675  return 0;
9676 }
9677 
9714 FOUNDATIONAL_LIB_FUNC int string_array_uniq_adjacent(const char **first_array, size_t size, char ***new_array, size_t *new_size)
9715 {
9717 
9720 
9724 
9725  *new_size = 0;
9726  const size_t alloc_size = FOUNDATIONAL_LIB_safe_mul(size, sizeof(char *));
9727 
9728  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size == 0))
9729  {
9731  return -1;
9732  }
9733 
9734  // Create a new dynamically allocated array
9735  *new_array = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size);
9736  if (FOUNDATIONAL_LIB_UNLIKELY(*new_array == NULL))
9737  {
9739  return -1;
9740  }
9741 
9742  // Remove adjacent duplicates from arr1 and copy to arr2
9743  for (size_t i = 0; i < size; ++i)
9744  {
9745  if (i == 0 || FOUNDATIONAL_LIB_STRCMP(first_array[i], first_array[i - 1]) != 0)
9746  {
9747  (*new_array)[(*new_size)++] = (char *)first_array[i]; // No strdup
9748  }
9749  }
9750 
9751  return 0;
9752 }
9753 
9770 FOUNDATIONAL_LIB_FUNC char *concatenate_three_strings(const char *str1, const char *str2, const char *str3)
9771 {
9775 
9776  const char *strs[3] = {str1, str2, str3};
9777 
9778  return concatenate_string_array(strs, 3);
9779 }
9780 
9798 FOUNDATIONAL_LIB_FUNC char *concatenate_four_strings(const char *str1, const char *str2, const char *str3, const char *str4)
9799 {
9804 
9805  const char *strs[4] = {str1, str2, str3, str4};
9806 
9807  return concatenate_string_array(strs, 4);
9808 }
9809 
9828 FOUNDATIONAL_LIB_FUNC char *concatenate_five_strings(const char *str1, const char *str2, const char *str3, const char *str4, const char *str5)
9829 {
9835 
9836  const char *strs[5] = {str1, str2, str3, str4, str5};
9837 
9838  return concatenate_string_array(strs, 5);
9839 }
9840 
9841 #ifdef _WIN32
9842 #include <tchar.h>
9843 #include <windows.h>
9844 #else
9845 #include <dirent.h>
9846 #endif
9847 
9848 #ifdef _WIN32
9849 #define FOUNDATIONAL_LIB_DIR_SEPARATOR '\\'
9850 #else
9851 #define FOUNDATIONAL_LIB_DIR_SEPARATOR '/'
9852 #endif
9853 
9877 FOUNDATIONAL_LIB_FUNC int map_filesystem_files_as_strings(const char *directory, char *(*map_function)(const char *file_string_data, size_t string_size))
9878 {
9879 
9882 
9883 #ifdef _WIN32
9884  WIN32_FIND_DATA findFileData;
9885  HANDLE hFind = FindFirstFile(directory, &findFileData);
9886 
9887  if (FOUNDATIONAL_LIB_UNLIKELY(hFind == INVALID_HANDLE_VALUE))
9888  {
9890  return -1;
9891  }
9892 
9893  do
9894  {
9895  if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
9896  {
9897  // Regular file
9898  char *file_data;
9899  size_t size;
9900 
9901  // Get the regular file.
9902  char fullFilePath[MAX_PATH];
9903  _stprintf(fullFilePath, _T("%s%c%s"), directory, FOUNDATIONAL_LIB_DIR_SEPARATOR, findFileData.cFileName);
9904 
9905  file_data = read_file_into_string(fullFilePath, &size);
9906  if (FOUNDATIONAL_LIB_UNLIKELY(file_data == NULL))
9907  {
9908  // No need to re-die aggressively.
9909  FindClose(hFind); /* No need to error check here because there already is an error. */
9910  return -1;
9911  }
9912 
9913  // The result of the map operation
9914  const char *new_str = map_function(file_data, size);
9915 
9916  // Write the result to disk
9917  if (FOUNDATIONAL_LIB_UNLIKELY(write_file(fullFilePath, new_str) == -1))
9918  {
9919  // No need to re-die aggressively.
9921  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE((char *)new_str);
9922  FindClose(hFind); // No need to error check here because there already is an error.
9923  return -1;
9924  }
9925 
9926  // Free memory.
9928  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE((char *)new_str);
9929  }
9930 
9931  } while (FindNextFile(hFind, &findFileData) != 0);
9932 
9933  if (FOUNDATIONAL_LIB_UNLIKELY(FindClose(hFind) == 0))
9934  {
9936  return -1;
9937  }
9938 
9939 #else
9940  DIR *dir = opendir(directory);
9941  if (FOUNDATIONAL_LIB_UNLIKELY(dir == NULL))
9942  {
9944  return -1;
9945  }
9946 
9947  struct dirent *entry;
9948  while ((entry = readdir(dir)) != NULL)
9949  {
9950  if (entry->d_type == DT_REG)
9951  { // Regular file
9952  char *file_data;
9953  size_t size;
9954 
9955  // Get the regular file.
9956  char fullFilePath[PATH_MAX];
9957  FOUNDATIONAL_LIB_SNPRINTF(fullFilePath, PATH_MAX, "%s%c%s", directory, FOUNDATIONAL_LIB_DIR_SEPARATOR, entry->d_name);
9958 
9959  file_data = read_file_into_string(fullFilePath, &size);
9960  if (FOUNDATIONAL_LIB_UNLIKELY(file_data == NULL))
9961  {
9962  // No need to re-die aggressively.
9963  return -1;
9964  }
9965 
9966  // The result of the map operation
9967  const char *new_str = map_function(file_data, size);
9968 
9969  // Write the result to disk
9970  if (write_file(fullFilePath, new_str) == -1)
9971  {
9972  // No need to re-die aggressively.
9974  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE((char *)new_str);
9975  return -1;
9976  }
9977 
9978  // Free memory.
9980  FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE((char *)new_str);
9981  }
9982  }
9983 
9984  if (FOUNDATIONAL_LIB_UNLIKELY(closedir(dir) == -1))
9985  {
9987  return -1;
9988  }
9989 
9990 #endif
9991 
9992  return 0;
9993 }
9994 
10010 FOUNDATIONAL_LIB_FUNC int filter_filesystem_files_as_strings(const char *directory, int (*filter_function)(const char *filename))
10011 {
10014 #ifdef _WIN32
10015  WIN32_FIND_DATA findFileData;
10016  HANDLE hFind = FindFirstFile(directory, &findFileData);
10017 
10018  if (FOUNDATIONAL_LIB_UNLIKELY(hFind == INVALID_HANDLE_VALUE))
10019  {
10021  return -1;
10022  }
10023 
10024  do
10025  {
10026  if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !filter_function(findFileData.cFileName))
10027  {
10028  // Regular file to be removed
10029  char fullFilePath[MAX_PATH];
10030  _stprintf(fullFilePath, _T("%s%c%s"), directory, FOUNDATIONAL_LIB_DIR_SEPARATOR, findFileData.cFileName);
10031 
10032  if (remove_file(fullFilePath) == -1)
10033  {
10034  // Handle error or return -1
10035  if (FindClose(hFind) == 0)
10036  {
10038  return -1;
10039  }
10040  return -1;
10041  }
10042  }
10043 
10044  } while (FindNextFile(hFind, &findFileData) != 0);
10045 
10046  FindClose(hFind);
10047 
10048 #else
10049  DIR *dir = opendir(directory);
10050  if (FOUNDATIONAL_LIB_UNLIKELY(dir == NULL))
10051  {
10053  return -1;
10054  }
10055 
10056  struct dirent *entry;
10057  while ((entry = readdir(dir)) != NULL)
10058  {
10059  if (entry->d_type == DT_REG)
10060  {
10061  if (!filter_function(entry->d_name))
10062  {
10063  // Regular file to be removed
10064  char fullFilePath[PATH_MAX];
10065  FOUNDATIONAL_LIB_SNPRINTF(fullFilePath, PATH_MAX, "%s%c%s", directory, FOUNDATIONAL_LIB_DIR_SEPARATOR, entry->d_name);
10066 
10067  if (remove_file(fullFilePath) == -1)
10068  {
10069  // Handle error or return -1
10070  if (closedir(dir) == -1)
10071  {
10073  return -1;
10074  }
10075  return -1;
10076  }
10077  }
10078  }
10079  }
10080 
10081  if (FOUNDATIONAL_LIB_UNLIKELY(closedir(dir) == -1))
10082  {
10084  return -1;
10085  }
10086 #endif
10087 
10088  return 0;
10089 }
10090 
10112 FOUNDATIONAL_LIB_FUNC char *reduce_filesystem_files_as_strings(const char *directory, const char *out_file, char *(*reduce_function)(char *value1, ...))
10113 {
10117 #ifdef _WIN32
10118  WIN32_FIND_DATA findFileData;
10119  HANDLE hFind = FindFirstFile(directory, &findFileData);
10120 
10121  if (FOUNDATIONAL_LIB_UNLIKELY(hFind == INVALID_HANDLE_VALUE))
10122  {
10124  return NULL;
10125  }
10126 
10127  char *last_value = NULL;
10128  char *value = NULL;
10129 
10130  do
10131  {
10132  if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && findFileData.dwFileAttributes & FILE_ATTRIBUTE_NORMAL)
10133  {
10134  // Regular file
10135  size_t size;
10136 
10137  // Get the regular file.
10138  char fullFilePath[MAX_PATH];
10139  _stprintf(fullFilePath, _T("%s%c%s"), directory, FOUNDATIONAL_LIB_DIR_SEPARATOR, findFileData.cFileName);
10140 
10141  value = read_file_into_string(fullFilePath, &size);
10142  if (FOUNDATIONAL_LIB_UNLIKELY(value == NULL))
10143  {
10144  // No need to re-die aggressively.
10145  FindClose(hFind); /* Don't need to care about the return value because there already is an error. */
10146  return NULL;
10147  }
10148 
10149  char *new_value = reduce_function(last_value, value, findFileData.cFileName);
10150  if (last_value)
10151  {
10153  }
10154 
10156  last_value = new_value;
10157 
10158  if (FOUNDATIONAL_LIB_UNLIKELY(remove_file(fullFilePath) == -1))
10159  {
10161  return NULL;
10162  }
10163  }
10164 
10165  } while (FindNextFile(hFind, &findFileData) != 0);
10166 
10167  if (FOUNDATIONAL_LIB_UNLIKELY(FindClose(hFind) == 0))
10168  {
10170  return NULL;
10171  }
10172 #else
10173  DIR *dir = opendir(directory);
10174  if (FOUNDATIONAL_LIB_UNLIKELY(dir == NULL))
10175  {
10177  return NULL;
10178  }
10179 
10180  char *last_value = NULL;
10181  char *value = NULL;
10182  struct dirent *entry;
10183 
10184  while ((entry = readdir(dir)) != NULL)
10185  {
10186  if (entry->d_type == DT_REG)
10187  {
10188  // Regular file
10189  size_t size;
10190 
10191  // Get the regular file.
10192  char fullFilePath[PATH_MAX];
10193  FOUNDATIONAL_LIB_SNPRINTF(fullFilePath, PATH_MAX, "%s%c%s", directory, FOUNDATIONAL_LIB_DIR_SEPARATOR, entry->d_name);
10194 
10195  value = read_file_into_string(fullFilePath, &size);
10196  if (FOUNDATIONAL_LIB_UNLIKELY(value == NULL))
10197  {
10198  // No need to re-die aggressively.
10199  if (FOUNDATIONAL_LIB_UNLIKELY(closedir(dir) == -1))
10200  {
10202  return NULL;
10203  }
10204  return NULL;
10205  }
10206 
10207  char *new_value = reduce_function(last_value, value, entry->d_name);
10208  if (last_value)
10209  {
10211  }
10212 
10214  last_value = new_value;
10215 
10216  if (FOUNDATIONAL_LIB_UNLIKELY(remove_file(fullFilePath) == -1))
10217  {
10219  return NULL;
10220  }
10221  }
10222  }
10223 
10224  if (FOUNDATIONAL_LIB_UNLIKELY(closedir(dir) == -1))
10225  {
10227  return NULL;
10228  }
10229 #endif
10230 
10231  if (FOUNDATIONAL_LIB_UNLIKELY(write_file(out_file, value) == -1))
10232  {
10233  /* No need to re-die aggressively. */
10235  return NULL;
10236  }
10237 
10238  return last_value;
10239 }
10240 
10251 {
10252 
10254 
10255  for (size_t i = 0; i < dict->capacity; ++i)
10256  {
10257  struct DictKeyValue *current_pair = dict->table[i];
10258  while (current_pair != NULL)
10259  {
10260  struct DictKeyValue *next_pair = current_pair->next;
10263  current_pair = next_pair;
10264  }
10265  }
10268 }
10269 
10284 FOUNDATIONAL_LIB_FUNC size_t dict_hash(const char *key, size_t capacity)
10285 {
10287 
10288  size_t hash = 5381; // Initial hash value
10289  int c; // Variable to store the current character
10290 
10291  while ((c = *key++))
10292  {
10293  hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
10294  }
10295 
10296  return hash % capacity;
10297 }
10298 
10316 FOUNDATIONAL_LIB_FUNC int dict_reserve_more(struct Dict *dict, size_t number_of_new_elements_max_one_is_expecting)
10317 {
10319 
10320  const size_t new_capacity = FOUNDATIONAL_LIB_safe_add_2(dict->capacity, number_of_new_elements_max_one_is_expecting);
10321 
10322  if (FOUNDATIONAL_LIB_UNLIKELY(new_capacity == 0))
10323  {
10325  return -1;
10326  }
10327 
10328  /* Either calloc or realloc would be ideal here, but, if the block is large,
10329  then calloc might be better because there might be a cleared block of
10330  memory that is very large that is readily available. */
10331  struct DictKeyValue **new_table = (struct DictKeyValue **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(new_capacity, sizeof(struct DictKeyValue *));
10332  if (FOUNDATIONAL_LIB_UNLIKELY(new_table == NULL))
10333  {
10335  return -1;
10336  }
10337 
10338  for (size_t i = 0; i < dict->capacity; ++i)
10339  {
10340  struct DictKeyValue *current_pair = dict->table[i];
10341  while (current_pair)
10342  {
10343  struct DictKeyValue *next_pair = current_pair->next;
10344  const size_t new_index = dict_hash(current_pair->key, new_capacity);
10345  current_pair->next = new_table[new_index];
10346  new_table[new_index] = current_pair;
10347  current_pair = next_pair;
10348  }
10349  }
10350 
10352  dict->table = new_table;
10353  dict->capacity = new_capacity;
10354 
10355  return 0;
10356 }
10371 {
10372 
10374 
10375  const size_t new_capacity = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(dict->capacity);
10376  if (FOUNDATIONAL_LIB_UNLIKELY(new_capacity == 0)) // Overflow.
10377  {
10379  return -1;
10380  }
10381 
10382  /* Either calloc or realloc would be ideal here, but, if the block is large,
10383  then calloc might be better because there might be a cleared block of
10384  memory that is very large that is readily available. */
10385  struct DictKeyValue **new_table = (struct DictKeyValue **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(new_capacity, sizeof(struct DictKeyValue *));
10386  if (FOUNDATIONAL_LIB_UNLIKELY(new_table == NULL))
10387  {
10388  dict_destructor(dict);
10390  return -1;
10391  }
10392 
10393  for (size_t i = 0; i < dict->capacity; ++i)
10394  {
10395  struct DictKeyValue *current_pair = dict->table[i];
10396  while (current_pair)
10397  {
10398  struct DictKeyValue *next_pair = current_pair->next;
10399  const size_t new_index = dict_hash(current_pair->key, new_capacity);
10400  current_pair->next = new_table[new_index];
10401  new_table[new_index] = current_pair;
10402  current_pair = next_pair;
10403  }
10404  }
10405 
10407  dict->table = new_table;
10408  dict->capacity = new_capacity;
10409 
10410  return 0;
10411 }
10412 
10424 FOUNDATIONAL_LIB_FUNC void dict_del_key(struct Dict *dict, const char *key)
10425 {
10428  const size_t index = dict_hash(key, dict->capacity);
10429 
10430  struct DictKeyValue *current = dict->table[index];
10431  struct DictKeyValue *prev = NULL;
10432 
10433  while (current != NULL)
10434  {
10435  if (FOUNDATIONAL_LIB_STRCMP(current->key, key) == 0)
10436  {
10437  /* Key found, remove the entry */
10438  if (prev == NULL)
10439  {
10440  /* If it's the first node in the linked list */
10441  dict->table[index] = current->next;
10442  }
10443  else
10444  {
10445  prev->next = current->next;
10446  }
10447 
10448  /* Free memory */
10451 
10452  /* Update size */
10453  --dict->size;
10454 
10455  return;
10456  }
10457 
10458  /* Move to the next node in the linked list */
10459  prev = current;
10460  current = current->next;
10461  }
10462 }
10463 
10476 FOUNDATIONAL_LIB_FUNC int dict_add(struct Dict *dict, const char *key, void *value)
10477 {
10478 
10482  if ((double)dict->size / dict->capacity > FOUNDATIONAL_LIB_HASH_LOAD_FACTOR_THRESHOLD)
10483  {
10484  if (FOUNDATIONAL_LIB_UNLIKELY(dict_resize(dict) == -1))
10485  {
10486  // Don't need to re die aggressively if enabled here because dict resize
10487  // does it.
10488  return -1;
10489  }
10490  }
10491 
10492  const size_t index = dict_hash(key, dict->capacity);
10493 
10494  struct DictKeyValue *new_pair = (struct DictKeyValue *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(sizeof(struct DictKeyValue));
10495  if (FOUNDATIONAL_LIB_UNLIKELY(new_pair == NULL))
10496  {
10497  /* Keep the old key if there was one. */
10499  return -1;
10500  }
10501 
10503  if (FOUNDATIONAL_LIB_UNLIKELY(new_pair->key == NULL))
10504  {
10507  return -1;
10508  }
10509  new_pair->next = dict->table[index];
10510  new_pair->value = value;
10511 
10512  /* If there is a hash collision */
10513  if (dict->table[index] != NULL)
10514  {
10515  struct DictKeyValue *current = new_pair->next; // First one
10516  struct DictKeyValue *prev = new_pair; // New one
10517  /* Traverse the linked list to check for duplicates */
10518  do
10519  {
10520  /* This should only ever happen once unless the dict is corrupt, so we return. */
10521  if (FOUNDATIONAL_LIB_STRCMP(current->key, key) == 0)
10522  {
10523  prev->next = current->next;
10524  /* Duplicate key found */
10527  /* Dont increment size */
10528  /* Assume the list only has 1 key with the value (it should unless
10529  * something is really wrong). */
10530  goto end;
10531  }
10532 
10533  prev = current;
10534  current = current->next;
10535  } while (current != NULL);
10536  }
10537  ++dict->size;
10538 
10539 end:
10540  dict->table[index] = new_pair;
10541  return 0;
10542 }
10543 
10560 FOUNDATIONAL_LIB_FUNC void *dict_get(struct Dict *dict, const char *key)
10561 {
10564  const size_t index = dict_hash(key, dict->capacity);
10565  struct DictKeyValue *current_pair = dict->table[index];
10566 
10567  while (current_pair != NULL)
10568  {
10569  if (FOUNDATIONAL_LIB_STRCMP(current_pair->key, key) == 0)
10570  {
10571  return current_pair->value;
10572  }
10573 
10574  // Hash collision, continue with linked list.
10575  current_pair = current_pair->next;
10576  }
10577 
10578  return NULL;
10579 }
10580 
10599 FOUNDATIONAL_LIB_FUNC void *dict_get_check(struct Dict *dict, const char *key, int *key_is_in_dict)
10600 {
10604 
10605  const size_t index = dict_hash(key, dict->capacity);
10606  struct DictKeyValue *current_pair = dict->table[index];
10607 
10608  while (current_pair != NULL)
10609  {
10610  if (FOUNDATIONAL_LIB_STRCMP(current_pair->key, key) == 0)
10611  {
10612  *key_is_in_dict = 1;
10613  return current_pair->value;
10614  }
10615  current_pair = current_pair->next;
10616  }
10617 
10618  *key_is_in_dict = 0;
10619  return NULL;
10620 }
10621 
10634 {
10636  dict_destructor((struct Dict *)dict);
10637 }
10638 
10653 {
10654  struct FrozenDict *frozen_dict = (struct FrozenDict *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(sizeof(struct FrozenDict));
10655  if (FOUNDATIONAL_LIB_UNLIKELY(frozen_dict == NULL))
10656  {
10658  return NULL;
10659  }
10660 
10662  frozen_dict->size = 0;
10664  if (FOUNDATIONAL_LIB_UNLIKELY(frozen_dict->table == NULL))
10665  {
10668  return NULL;
10669  }
10670 
10672  FOUNDATIONAL_LIB_VA_START(args, num_pairs);
10673 
10674  for (size_t i = 0; i < num_pairs; ++i)
10675  {
10676  char *key;
10677  void *value;
10678 
10679  key = FOUNDATIONAL_LIB_VA_ARG(args, char *);
10680  value = FOUNDATIONAL_LIB_VA_ARG(args, void *);
10681 
10682  dict_add((struct Dict *)frozen_dict, key, value);
10683  }
10684 
10685  FOUNDATIONAL_LIB_VA_END(args); // Clean up the va_list
10686 
10687  return frozen_dict;
10688 }
10689 
10704 FOUNDATIONAL_LIB_FUNC void *frozen_dict_get(struct FrozenDict *dict, const char *key)
10705 {
10708  const size_t index = dict_hash(key, dict->capacity);
10709  struct DictKeyValue *current_pair = dict->table[index];
10710 
10711  while (current_pair != NULL)
10712  {
10713  if (FOUNDATIONAL_LIB_STRCMP(current_pair->key, key) == 0)
10714  {
10715  return current_pair->value;
10716  }
10717  current_pair = current_pair->next;
10718  }
10719 
10720  return NULL;
10721 }
10722 
10740 FOUNDATIONAL_LIB_FUNC void *frozen_dict_get_check(struct FrozenDict *dict, const char *key, int *key_is_in_dict)
10741 {
10745 
10746  const size_t index = dict_hash(key, dict->capacity);
10747  struct DictKeyValue *current_pair = dict->table[index];
10748 
10749  while (current_pair != NULL)
10750  {
10751  if (FOUNDATIONAL_LIB_STRCMP(current_pair->key, key) == 0)
10752  {
10753  *key_is_in_dict = 1;
10754  return current_pair->value;
10755  }
10756  current_pair = current_pair->next;
10757  }
10758 
10759  *key_is_in_dict = 0;
10760  return NULL;
10761 }
10762 
10776 FOUNDATIONAL_LIB_FUNC void dict_iter(struct Dict *dict, void (*callback)(char *key, void *value))
10777 {
10780 
10781  for (size_t i = 0; i < dict->capacity; ++i)
10782  {
10783  struct DictKeyValue *current = dict->table[i];
10784 
10785  while (current != NULL)
10786  {
10787  /* Call the callback function with the key and value */
10788  callback(current->key, current->value);
10789 
10790  /* Move to the next node in the linked list */
10791  current = current->next;
10792  }
10793  }
10794 }
10795 
10809 FOUNDATIONAL_LIB_FUNC void frozen_dict_iter(struct FrozenDict *frozen_dict, void (*callback)(char *key, void *value))
10810 {
10813  for (size_t i = 0; i < frozen_dict->capacity; ++i)
10814  {
10815  struct DictKeyValue *current = frozen_dict->table[i];
10816 
10817  while (current != NULL)
10818  {
10819  /* Call the callback function with the key and value */
10820  callback(current->key, current->value);
10821 
10822  /* Move to the next node in the linked list */
10823  current = current->next;
10824  }
10825  }
10826 }
10838 {
10839 
10841  return dict->size;
10842 }
10843 
10855 {
10857 
10858  return dict->size;
10859 }
10860 
10883 FOUNDATIONAL_LIB_FUNC int dict_to_array(struct Dict *dict, char ***keys, void ***values, size_t *size_of_keys_and_values)
10884 {
10888  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(size_of_keys_and_values);
10889 
10890  const size_t alloc_size1 = FOUNDATIONAL_LIB_safe_mul(dict->size, sizeof(char *));
10891  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size1 == 0))
10892  goto overflow;
10893  size_t alloc_size2;
10894 
10895  alloc_size2 = FOUNDATIONAL_LIB_safe_mul(dict->size, sizeof(void *));
10896  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size2 == 0))
10897  goto overflow;
10898 
10899  *keys = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size1);
10900  if (FOUNDATIONAL_LIB_UNLIKELY(*keys == NULL))
10901  goto error_handler;
10902 
10903  *values = (void **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size2);
10904 
10905  if (FOUNDATIONAL_LIB_UNLIKELY(*values == NULL))
10906  {
10908  *keys = NULL;
10909  // Values is already NULL here.
10910  goto error_handler;
10911  }
10912 
10913  for (size_t i = 0, index = 0; i < dict->capacity; ++i)
10914  {
10915  struct DictKeyValue *current_pair = dict->table[i];
10916  while (current_pair != NULL)
10917  {
10918  (*keys)[index] = (current_pair->key);
10919  (*values)[index] = current_pair->value;
10920 
10921  ++index;
10922  current_pair = current_pair->next;
10923  }
10924  }
10925 
10926  *size_of_keys_and_values = dict->size;
10927 
10928  return 0;
10929 
10930 overflow:
10931 error_handler:
10932 
10934  return -1;
10935 }
10936 
10959 FOUNDATIONAL_LIB_FUNC size_t frozen_dict_to_array(struct FrozenDict *dict, char ***keys, void ***values, size_t *size_of_keys_and_values)
10960 {
10961 
10965  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(size_of_keys_and_values);
10966 
10967  const size_t alloc_size1 = FOUNDATIONAL_LIB_safe_mul(dict->size, sizeof(char *));
10968  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size1 == 0))
10969  goto overflow;
10970  size_t alloc_size2;
10971 
10972  alloc_size2 = FOUNDATIONAL_LIB_safe_mul(dict->size, sizeof(void *));
10973  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size2 == 0))
10974  goto overflow;
10975 
10976  *keys = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size1);
10977  if (FOUNDATIONAL_LIB_UNLIKELY(*keys == NULL))
10978  goto error_handler;
10979 
10980  *values = (void **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size2);
10981 
10982  if (FOUNDATIONAL_LIB_UNLIKELY(*values == NULL))
10983  {
10985  *keys = NULL;
10986  // Values is already NULL here.
10987  goto error_handler;
10988  }
10989 
10990  for (size_t i = 0, index = 0; i < dict->capacity; ++i)
10991  {
10992  struct DictKeyValue *current_pair = dict->table[i];
10993  while (current_pair != NULL)
10994  {
10995  (*keys)[index] = (current_pair->key);
10996  (*values)[index] = current_pair->value;
10997 
10998  ++index;
10999  current_pair = current_pair->next;
11000  }
11001  }
11002 
11003  *size_of_keys_and_values = dict->size;
11004 
11005  return 0;
11006 
11007 overflow:
11008 error_handler:
11009 
11011  return -1;
11012 }
11013 
11024 static inline void dict_del_keys(char **keys)
11025 {
11026 
11029 }
11030 
11041 static inline void dict_del_values(void **values)
11042 {
11045 }
11046 
11065 FOUNDATIONAL_LIB_FUNC char *dict_to_string(struct Dict *dict, int pointer_or_string) /* 0 = pointer, 1 = string */
11066 {
11068  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(pointer_or_string == 0 || pointer_or_string == 1);
11069 
11070  /* Allocate memory for the string representation */
11071  size_t total_length = 2;
11072  for (size_t i = 0; i < dict->capacity; ++i)
11073  {
11074  struct DictKeyValue *current_pair = dict->table[i];
11075  while (current_pair != NULL)
11076  {
11077  /* Calculate the length of the string representation for each key-value
11078  * pair */
11079  total_length += FOUNDATIONAL_LIB_STRLEN(current_pair->key) + 2; // 2 for ": "
11080  if (pointer_or_string == 0)
11081  {
11082  total_length += FOUNDATIONAL_LIB_SNPRINTF(NULL, 0, "%p",
11083  current_pair->value); // Calculate the length of the value string
11084  }
11085  else
11086  {
11087  total_length += FOUNDATIONAL_LIB_SNPRINTF(NULL, 0, "%s",
11088  (char *)current_pair->value); // Calculate the length of the value string
11089  }
11090  total_length += 2; // 2 for ", "
11091  current_pair = current_pair->next;
11092  }
11093  }
11094 
11095  // Should not reach SIZE_MAX
11096 
11097  // Add 1 for the null-terminator, at least 3 chars additional
11098  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(total_length + sizeof("")); /* Should be Safe. */
11099  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
11100  {
11102  return NULL;
11103  }
11104 
11105  result[0] = '{';
11106  size_t index = 1;
11107 
11108  for (size_t i = 0; i < dict->capacity; ++i)
11109  {
11110  struct DictKeyValue *current_pair = dict->table[i];
11111  while (current_pair != NULL)
11112  {
11113  /* Append the key and value to the string representation */
11114  if (pointer_or_string == 0)
11115  {
11116  index += FOUNDATIONAL_LIB_SNPRINTF(result + index, total_length - index, "%s: %p", current_pair->key, current_pair->value);
11117  }
11118  else if (pointer_or_string == 1)
11119  {
11120  index += FOUNDATIONAL_LIB_SNPRINTF(result + index, total_length - index, "%s: %s", current_pair->key, (char *)current_pair->value);
11121  }
11122  current_pair = current_pair->next;
11123 
11124  /* Add a separator (comma) if there are more elements */
11125  if (index < total_length - 2)
11126  {
11127  result[index++] = ',';
11128  result[index++] = ' ';
11129  }
11130  }
11131  }
11132 
11133  if (dict->capacity)
11134  {
11135  index -= 2;
11136  }
11137 
11138  result[index++] = '}';
11139  result[index++] = '\0'; // Null-terminate the string
11140  return result;
11141 }
11142 
11162 FOUNDATIONAL_LIB_FUNC char *frozen_dict_to_string(struct FrozenDict *dict, int pointer_or_string) /* 0 = pointer, 1 = string */
11163 {
11165  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(pointer_or_string == 0 || pointer_or_string == 1);
11166  /* Allocate memory for the string representation */
11167  size_t total_length = 2;
11168  for (size_t i = 0; i < dict->capacity; ++i)
11169  {
11170  struct DictKeyValue *current_pair = dict->table[i];
11171  while (current_pair != NULL)
11172  {
11173  /* Calculate the length of the string representation for each key-value
11174  * pair */
11175  total_length += FOUNDATIONAL_LIB_STRLEN(current_pair->key) + 2; // 2 for ": "
11176 
11177  if (pointer_or_string == 0)
11178  {
11179  total_length += FOUNDATIONAL_LIB_SNPRINTF(NULL, 0, "%p",
11180  current_pair->value); // Calculate the length of the value string
11181  }
11182  else
11183  {
11184  total_length += FOUNDATIONAL_LIB_SNPRINTF(NULL, 0, "%s",
11185  (char *)current_pair->value); // Calculate the length of the value string
11186  }
11187  total_length += 2; // 2 for ", "
11188  current_pair = current_pair->next;
11189  }
11190  }
11191 
11192  // Should not reach SIZE_MAX
11193 
11194  // Add 1 for the null-terminator, at least 3 chars additional
11195  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(total_length + sizeof("")); /* Safe. */
11196  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
11197  {
11199  return NULL;
11200  }
11201 
11202  result[0] = '{';
11203  size_t index = 1;
11204 
11205  for (size_t i = 0; i < dict->capacity; ++i)
11206  {
11207  struct DictKeyValue *current_pair = dict->table[i];
11208  while (current_pair != NULL)
11209  {
11210  /* Append the key and value to the string representation */
11211  if (pointer_or_string == 0)
11212  {
11213  index += FOUNDATIONAL_LIB_SNPRINTF(result + index, total_length - index, "%s: %p", current_pair->key, current_pair->value);
11214  }
11215  else if (pointer_or_string == 1)
11216  {
11217  index += FOUNDATIONAL_LIB_SNPRINTF(result + index, total_length - index, "%s: %s", current_pair->key, (char *)current_pair->value);
11218  }
11219  current_pair = current_pair->next;
11220 
11221  /* Add a separator (comma) if there are more elements */
11222  if (index < total_length - 2)
11223  {
11224  result[index++] = ',';
11225  result[index++] = ' ';
11226  }
11227  }
11228  }
11229 
11230  if (dict->capacity)
11231  {
11232  index -= 2;
11233  }
11234 
11235  result[index++] = '}';
11236  result[index++] = '\0'; // Null-terminate the string
11237  return result;
11238 }
11239 
11248 static inline void frozen_dict_del_keys(char **keys)
11249 {
11252 }
11253 
11262 static inline void frozen_dict_del_values(void **values)
11263 {
11266 }
11267 
11276 {
11278 
11279  for (size_t i = 0; i < set->capacity; ++i)
11280  {
11281  struct SetKey *current_key = set->table[i];
11282  while (current_key != NULL)
11283  {
11284  struct SetKey *next_key = current_key->next;
11287  current_key = next_key;
11288  }
11289  }
11292 }
11293 
11302 {
11303  struct Set *set = (struct Set *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(sizeof(struct Set));
11304  if (FOUNDATIONAL_LIB_UNLIKELY(set == NULL))
11305  {
11307  return NULL;
11308  }
11309 
11311  set->size = 0;
11313  if (FOUNDATIONAL_LIB_UNLIKELY(set->table == NULL))
11314  {
11317  return NULL;
11318  }
11319 
11320  return set;
11321 }
11322 
11337 FOUNDATIONAL_LIB_FUNC size_t set_hash(const char *key, size_t capacity)
11338 {
11340  size_t hash = 5381; // Initial hash value
11341  int c; // Variable to store the current character
11342 
11343  while ((c = *key++))
11344  {
11345  hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
11346  }
11347 
11348  return hash % capacity;
11349 }
11350 
11360 {
11362 
11363  const size_t new_capacity = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(set->capacity);
11364  if (FOUNDATIONAL_LIB_UNLIKELY(new_capacity == 0)) // Overflow.
11365  {
11367  return -1;
11368  }
11369  /* Either calloc or realloc would be ideal here, but, if the block is large,
11370  then calloc might be better because there might be a cleared block of
11371  memory that is very large that is readily available. */
11372  struct SetKey **new_table = (struct SetKey **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(new_capacity, sizeof(struct SetKey *));
11373  if (FOUNDATIONAL_LIB_UNLIKELY(new_table == NULL))
11374  {
11375  set_destructor(set);
11377  return -1;
11378  }
11379 
11380  for (size_t i = 0; i < set->capacity; ++i)
11381  {
11382  struct SetKey *current_key = set->table[i];
11383  while (current_key)
11384  {
11385  struct SetKey *next_key = current_key->next;
11386  const size_t new_index = set_hash(current_key->key, new_capacity);
11387  current_key->next = new_table[new_index];
11388  new_table[new_index] = current_key;
11389  current_key = next_key;
11390  }
11391  }
11392 
11394  set->table = new_table;
11395  set->capacity = new_capacity;
11396 
11397  return 0;
11398 }
11399 
11408 FOUNDATIONAL_LIB_FUNC void set_del_key(struct Set *set, const char *key)
11409 {
11412 
11413  const size_t index = set_hash(key, set->capacity);
11414 
11415  struct SetKey *current = set->table[index];
11416  struct SetKey *prev = NULL;
11417 
11418  while (current != NULL)
11419  {
11420  if (FOUNDATIONAL_LIB_STRCMP(current->key, key) == 0)
11421  {
11422  /* Key found, remove the entry */
11423  if (prev == NULL)
11424  {
11425  /* If it's the first node in the linked list */
11426  set->table[index] = current->next;
11427  }
11428  else
11429  {
11430  prev->next = current->next;
11431  }
11432 
11433  /* Free memory */
11436 
11437  /* Update size */
11438  --set->size;
11439 
11440  return;
11441  }
11442 
11443  /* Move to the next node in the linked list */
11444  prev = current;
11445  current = current->next;
11446  }
11447 }
11448 
11460 FOUNDATIONAL_LIB_FUNC int set_add(struct Set *set, const char *key)
11461 {
11464 
11465  if ((double)set->size / set->capacity > FOUNDATIONAL_LIB_HASH_LOAD_FACTOR_THRESHOLD)
11466  {
11467  if (FOUNDATIONAL_LIB_UNLIKELY(set_resize(set) == -1))
11468  {
11469  // Don't need to re die aggressively if enabled here because set resize does it.
11470  return -1;
11471  }
11472  }
11473 
11474  const size_t index = set_hash(key, set->capacity);
11475 
11476  struct SetKey *new_set_key = (struct SetKey *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(sizeof(struct SetKey));
11477  if (FOUNDATIONAL_LIB_UNLIKELY(new_set_key == NULL))
11478  {
11479  /* Keep the old key if there was one. */
11481  return -1;
11482  }
11483 
11485  if (FOUNDATIONAL_LIB_UNLIKELY(new_set_key->key == NULL))
11486  {
11489  return -1;
11490  }
11491  new_set_key->next = set->table[index];
11492 
11493  /* If there is a hash collision */
11494  if (set->table[index] != NULL)
11495  {
11496  struct SetKey *current = new_set_key->next; // First one
11497  struct SetKey *prev = new_set_key; // New one
11498  /* Traverse the linked list to check for duplicates */
11499  do
11500  {
11501  /* This should only ever happen once unless the set is corrupt, so we return. */
11502 
11503  if (FOUNDATIONAL_LIB_STRCMP(current->key, key) == 0)
11504  { /* Duplicate key found */
11505  prev->next = current->next;
11506 
11507  // Free the old key
11510 
11511  /* Dont increment size */
11512  /* Assume the list only has 1 key with the value (it should unless
11513  * something is really wrong). */
11514 
11515  goto end;
11516  }
11517 
11518  prev = current;
11519  current = current->next;
11520  } while (current != NULL);
11521  }
11522 
11523  ++set->size;
11524 end:
11525  set->table[index] = new_set_key;
11526  return 0;
11527 }
11528 
11545 FOUNDATIONAL_LIB_FUNC int set_reserve_more(struct Set *set, size_t number_of_new_elements_max_one_is_expecting)
11546 {
11548 
11549  const size_t new_capacity = FOUNDATIONAL_LIB_safe_add_2(set->capacity, number_of_new_elements_max_one_is_expecting);
11550  if (FOUNDATIONAL_LIB_UNLIKELY(new_capacity == 0)) // Overflow.
11551  {
11553  return -1;
11554  }
11555  /* Either calloc or realloc would be ideal here, but, if the block is large,
11556  then calloc might be better because there might be a cleared block of
11557  memory that is very large that is readily available. */
11558  struct SetKey **new_table = (struct SetKey **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(new_capacity, sizeof(struct SetKey *));
11559  if (FOUNDATIONAL_LIB_UNLIKELY(new_table == NULL))
11560  {
11562  return -1;
11563  }
11564 
11565  for (size_t i = 0; i < set->capacity; ++i)
11566  {
11567  struct SetKey *current_key = set->table[i];
11568  while (current_key)
11569  {
11570  struct SetKey *next_key = current_key->next;
11571  const size_t new_index = set_hash(current_key->key, new_capacity);
11572  current_key->next = new_table[new_index];
11573  new_table[new_index] = current_key;
11574  current_key = next_key;
11575  }
11576  }
11577 
11579  set->table = new_table;
11580  set->capacity = new_capacity;
11581 
11582  return 0;
11583 }
11584 
11594 FOUNDATIONAL_LIB_FUNC int set_in(struct Set *set, const char *key)
11595 {
11598 
11599  const size_t index = set_hash(key, set->capacity);
11600  struct SetKey *current_key = set->table[index];
11601 
11602  while (current_key != NULL)
11603  {
11604  if (FOUNDATIONAL_LIB_STRCMP(current_key->key, key) == 0)
11605  {
11606  return 1;
11607  }
11608  current_key = current_key->next;
11609  }
11610 
11611  return 0;
11612 }
11613 
11622 {
11623 
11625  set_destructor((struct Set *)frozen_set);
11626 }
11627 
11638 {
11639  struct FrozenSet *frozen_set = (struct FrozenSet *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(sizeof(struct FrozenSet));
11640  if (FOUNDATIONAL_LIB_UNLIKELY(frozen_set == NULL))
11641  {
11643  return NULL;
11644  }
11645 
11647  frozen_set->size = 0;
11649  if (FOUNDATIONAL_LIB_UNLIKELY(frozen_set->table == NULL))
11650  {
11653  return NULL;
11654  }
11655 
11657  FOUNDATIONAL_LIB_VA_START(args, num_args);
11658 
11659  for (size_t i = 0; i < num_args; ++i)
11660  {
11661  char *key;
11662 
11663  key = FOUNDATIONAL_LIB_VA_ARG(args, char *);
11664  set_add((struct Set *)frozen_set, key);
11665  }
11666 
11667  FOUNDATIONAL_LIB_VA_END(args); // Clean up the va_list
11668 
11669  return frozen_set;
11670 }
11671 
11681 FOUNDATIONAL_LIB_FUNC int frozen_set_in(struct FrozenSet *set, const char *key)
11682 {
11684 
11685  const size_t index = set_hash(key, set->capacity);
11686  struct SetKey *current_key = set->table[index];
11687 
11688  while (current_key != NULL)
11689  {
11690  if (FOUNDATIONAL_LIB_STRCMP(current_key->key, key) == 0)
11691  {
11692  return 1;
11693  }
11694  current_key = current_key->next;
11695  }
11696 
11697  return 0;
11698 }
11699 
11708 FOUNDATIONAL_LIB_FUNC void set_iter(struct Set *set, void (*callback)(char *key))
11709 {
11711 
11713  for (size_t i = 0; i < set->capacity; ++i)
11714  {
11715  struct SetKey *current = set->table[i];
11716 
11717  while (current != NULL)
11718  {
11719  /* Call the callback function with the key and value */
11720  callback(current->key);
11721 
11722  /* Move to the next node in the linked list */
11723  current = current->next;
11724  }
11725  }
11726 }
11727 
11737 {
11738 
11740  return set->size;
11741 }
11742 
11752 {
11754  return set->size;
11755 }
11756 
11767 FOUNDATIONAL_LIB_FUNC int set_to_array(struct Set *set, char ***keys, size_t *size_of_keys)
11768 {
11771 
11773 
11774  const size_t alloc_size1 = FOUNDATIONAL_LIB_safe_mul(set->size, sizeof(char *));
11775  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size1 == 0))
11776  goto overflow;
11777 
11778  *keys = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size1);
11779  if (FOUNDATIONAL_LIB_UNLIKELY(*keys == NULL))
11780  goto error_handler;
11781 
11782  for (size_t i = 0, index = 0; i < set->capacity; ++i)
11783  {
11784  struct SetKey *current_pair = set->table[i];
11785  while (current_pair != NULL)
11786  {
11787  (*keys)[index] = (current_pair->key);
11788 
11789  ++index;
11790  current_pair = current_pair->next;
11791  }
11792  }
11793 
11794  *size_of_keys = set->size;
11795 
11796  return 0;
11797 
11798 overflow:
11799 error_handler:
11800 
11802  return -1;
11803 }
11804 
11815 FOUNDATIONAL_LIB_FUNC int frozen_set_to_array(struct FrozenSet *set, char ***keys, size_t *size_of_keys)
11816 {
11817 
11820 
11822 
11823  const size_t alloc_size1 = FOUNDATIONAL_LIB_safe_mul(set->size, sizeof(char *));
11824  if (FOUNDATIONAL_LIB_UNLIKELY(alloc_size1 == 0))
11825  goto overflow;
11826 
11827  *keys = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(alloc_size1);
11828  if (FOUNDATIONAL_LIB_UNLIKELY(*keys == NULL))
11829  goto error_handler;
11830 
11831  for (size_t i = 0, index = 0; i < set->capacity; ++i)
11832  {
11833  struct SetKey *current_pair = set->table[i];
11834  while (current_pair != NULL)
11835  {
11836  (*keys)[index] = (current_pair->key);
11837 
11838  ++index;
11839  current_pair = current_pair->next;
11840  }
11841  }
11842 
11843  *size_of_keys = set->size;
11844 
11845  return 0;
11846 
11847 overflow:
11848 error_handler:
11849 
11851  return -1;
11852 }
11853 
11862 
11865 {
11866 
11868 
11869  /* Allocate memory for the string representation */
11870  size_t total_length = 2;
11871  for (size_t i = 0; i < set->capacity; ++i)
11872  {
11873  struct SetKey *current_key = set->table[i];
11874  while (current_key != NULL)
11875  {
11876  /* Calculate the length of the string representation for each key-value
11877  * pair */
11878  total_length += FOUNDATIONAL_LIB_STRLEN(current_key->key);
11879  total_length += 2; // 2 for ", "
11880  current_key = current_key->next;
11881  }
11882  }
11883 
11884  // Should not reach SIZE_MAX
11885 
11886  // Add 1 for the null-terminator, at least 3 chars additional
11887 
11888  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(total_length + sizeof("")); /* Safe */
11889 
11890  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
11891  {
11893  return NULL;
11894  }
11895 
11896  result[0] = '{';
11897  size_t index = 1;
11898 
11899  for (size_t i = 0; i < set->capacity; ++i)
11900  {
11901  struct SetKey *current_key = set->table[i];
11902  while (current_key != NULL)
11903  {
11904  /* Append the key and value to the string representation */
11905  index += FOUNDATIONAL_LIB_SNPRINTF(result + index, total_length - index, "%s", current_key->key);
11906  current_key = current_key->next;
11907 
11908  /* Add a separator (comma) if there are more elements */
11909  if (index < total_length - 2)
11910  {
11911  result[index++] = ',';
11912  result[index++] = ' ';
11913  }
11914  }
11915  }
11916 
11917  if (set->capacity)
11918  {
11919  index -= 2;
11920  }
11921  result[index++] = '}';
11922  result[index++] = '\0'; // Null-terminate the string
11923  return result;
11924 }
11925 
11940 {
11942 
11943  /* Allocate memory for the string representation */
11944  size_t total_length = 2;
11945  for (size_t i = 0; i < frozen_set->capacity; ++i)
11946  {
11947  struct SetKey *current_key = frozen_set->table[i];
11948  while (current_key != NULL)
11949  {
11950  /* Calculate the length of the string representation for each key-value
11951  * pair */
11952  total_length += FOUNDATIONAL_LIB_STRLEN(current_key->key);
11953  total_length += 2; // 2 for ", "
11954  current_key = current_key->next;
11955  }
11956  }
11957 
11958  // Should not reach SIZE_MAX
11959 
11960  // Add 1 for the null-terminator, at least 3 chars
11961  char *result = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(total_length + 1 /* Safe, should not reach SIZE_MAX */);
11962  if (FOUNDATIONAL_LIB_UNLIKELY(result == NULL))
11963  {
11965  return NULL;
11966  }
11967 
11968  result[0] = '{';
11969  size_t index = 1;
11970 
11971  for (size_t i = 0; i < frozen_set->capacity; ++i)
11972  {
11973  struct SetKey *current_key = frozen_set->table[i];
11974  while (current_key != NULL)
11975  {
11976  /* Append the key and value to the string representation */
11977  index += FOUNDATIONAL_LIB_SNPRINTF(result + index, total_length - index, "%s", current_key->key);
11978  current_key = current_key->next;
11979 
11980  /* Add a separator (comma) if there are more elements */
11981  if (index < total_length - 2)
11982  {
11983  result[index++] = ',';
11984  result[index++] = ' ';
11985  }
11986  }
11987  }
11988 
11989  if (frozen_set->capacity)
11990  {
11991  index -= 2;
11992  }
11993 
11994  result[index++] = '}';
11995  result[index++] = '\0'; // Null-terminate the string
11996 
11997  return result;
11998 }
11999 
12008 {
12011 }
12012 
12022 FOUNDATIONAL_LIB_FUNC void frozen_set_iter(struct Set *set, void (*callback)(char *key))
12023 {
12026 
12027  for (size_t i = 0; i < set->capacity; ++i)
12028  {
12029  struct SetKey *current_key = set->table[i];
12030 
12031  while (current_key != NULL)
12032  {
12033  /* Call the callback function with the key and value */
12034  callback(current_key->key);
12035 
12036  /* Move to the next node in the linked list */
12037  current_key = current_key->next;
12038  }
12039  }
12040 }
12041 
12051 FOUNDATIONAL_LIB_FUNC int is_valid_utf8(const char *str, size_t len)
12052 {
12054 
12055  size_t i = 0;
12056 
12057  while (i < len)
12058  {
12059  if ((str[i] & 0x80) == 0)
12060  {
12061  // ASCII character (0xxxxxxx)
12062  i++;
12063  }
12064  else if ((str[i] & 0xE0) == 0xC0)
12065  {
12066  // 2-byte UTF-8 character (110xxxxx)
12067  if (i + 1 >= len || (str[i + 1] & 0xC0) != 0x80)
12068  return 0;
12069  i += 2;
12070  }
12071  else if ((str[i] & 0xF0) == 0xE0)
12072  {
12073  // 3-byte UTF-8 character (1110xxxx)
12074  if (i + 2 >= len || (str[i + 1] & 0xC0) != 0x80 || (str[i + 2] & 0xC0) != 0x80)
12075  return 0;
12076  i += 3;
12077  }
12078  else if ((str[i] & 0xF8) == 0xF0)
12079  {
12080  // 4-byte UTF-8 character (11110xxx)
12081  if (i + 3 >= len || (str[i + 1] & 0xC0) != 0x80 || (str[i + 2] & 0xC0) != 0x80 || (str[i + 3] & 0xC0) != 0x80)
12082  return 0;
12083  i += 4;
12084  }
12085  else
12086  {
12087  // Invalid UTF-8 encoding
12088  return 0;
12089  }
12090  }
12091 
12092  return 1;
12093 }
12094 
12104 FOUNDATIONAL_LIB_FUNC const char *sample_strings(const char **strings, size_t size) /* Does not dynamically allocate memory. */
12105 {
12107 
12108  long j;
12109 
12110 #ifdef _WIN32
12111  unsigned int rand_val;
12112  if (rand_s(&rand_val) != 0)
12113  {
12115  return NULL;
12116  }
12117 
12118  j = rand_val % size;
12119 #elif defined(__linux__)
12120  j = (long)(drand48() * size);
12121 #else
12122  j = rand() % size;
12123 #endif
12124 
12125  return strings[j];
12126 }
12127 
12137 FOUNDATIONAL_LIB_FUNC int shuffle_strings_in_place(char **strings, size_t size)
12138 {
12140 
12141  for (size_t i = size - 1; i; --i)
12142  {
12143  long j;
12144 #ifdef _WIN32
12145  unsigned int rand_val;
12146  if (FOUNDATIONAL_LIB_UNLIKELY(rand_s(&rand_val) != 0))
12147  {
12149  return -1;
12150  }
12151 
12152  j = rand_val % (i + 1);
12153 #elif defined(__linux__)
12154  j = (long)(drand48() * (i + 1));
12155 #else
12156  j = rand() % (i + 1);
12157 #endif
12158 
12159  // Swap strings[i] and strings[j]
12160  char *temp = strings[i];
12161  strings[i] = strings[j];
12162  strings[j] = temp;
12163  }
12164 
12165  return 0;
12166 }
12167 
12178 {
12179  const signed long long range = max - min + 1;
12180 
12181 #ifdef _WIN32
12182  unsigned int rand_val;
12183  if (rand_s(&rand_val) != 0)
12184  {
12186  return 0;
12187  }
12188 
12189  return min + (rand_val % range);
12190 #elif defined(__linux__)
12191  return min + (long)(drand48() * range);
12192 #else
12193  return min + (rand() % range);
12194 #endif
12195 }
12196 
12206 FOUNDATIONAL_LIB_FUNC unsigned long rand_number_from_range_inclusive_unsigned(unsigned long min, unsigned long max)
12207 {
12208  const unsigned long range = max - min + 1;
12209 
12210 #ifdef _WIN32
12211  unsigned int rand_val;
12212  if (rand_s(&rand_val) != 0)
12213  {
12215  return 0;
12216  }
12217 
12218  return min + (rand_val % range);
12219 #elif defined(__linux__)
12220  return min + (unsigned long)(drand48() * range);
12221 #else
12222  return min + (rand() % range);
12223 #endif
12224 }
12225 
12226 #if FOUNDATIONAL_LIB_UNSAFE_FUNCTIONS_ENABLED
12247 FOUNDATIONAL_LIB_FUNC char *backticks(const char *command, size_t *size)
12248 {
12251 
12252  FILE *pipe = FOUNDATIONAL_LIB_POPEN(command, "r");
12253  if (FOUNDATIONAL_LIB_UNLIKELY(pipe == NULL))
12254  {
12256  return NULL; // Indicate error by returning NULL
12257  }
12258 
12259  // Read the command output into the string
12260  size_t output_size = FOUNDATIONAL_LIB_POPEN_INITIAL_ALLOC_SIZE; // Initial output buffer size
12261  char *output = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(output_size);
12262  if (FOUNDATIONAL_LIB_UNLIKELY(output == NULL))
12263  {
12264  pclose(pipe); // No need to check errors here because things are already
12265  // going wrong.
12267  return NULL;
12268  }
12269 
12270  size_t total_read = 0;
12271 
12272  for (;;)
12273  {
12274  const size_t read_size = FOUNDATIONAL_LIB_FREAD(output + total_read, 1, 4096, pipe);
12275 
12276  if (FOUNDATIONAL_LIB_UNLIKELY(read_size == 0))
12277  {
12278  const int error_code = FOUNDATIONAL_LIB_FERROR(pipe);
12279  if (FOUNDATIONAL_LIB_UNLIKELY(error_code))
12280  {
12282  pclose(pipe); // No need to check errors here because things are already
12283  // going wrong.
12285  return NULL;
12286  }
12287  else
12288  {
12289  break;
12290  }
12291  }
12292  else if (total_read + read_size + 1 > output_size)
12293  {
12294  const size_t new_realloc_length = FOUNDATIONAL_LIB_safe_add_3(total_read, read_size, 1);
12295 
12296  if (FOUNDATIONAL_LIB_UNLIKELY(new_realloc_length == 0))
12297  {
12300  return NULL;
12301  }
12302  // Expand the buffer
12303  output_size = FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(new_realloc_length);
12304 
12305  if (FOUNDATIONAL_LIB_UNLIKELY(output_size == 0)) // Overflow.
12306  {
12308  return NULL;
12309  }
12310  char *new_output = (char *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC(output, output_size);
12311 
12312  if (FOUNDATIONAL_LIB_UNLIKELY(new_output == NULL))
12313  {
12315  pclose(pipe); // No need to check errors here because things are already
12316  // going wrong.
12318  return NULL;
12319  }
12320 
12321  output = new_output;
12322  }
12323  total_read += read_size;
12324  }
12325 
12326  if (FOUNDATIONAL_LIB_UNLIKELY(ferror(pipe) != 0))
12327  {
12329 
12330  pclose(pipe); // No need to re check for errors because things are going wrong.
12331 
12333 
12334  return NULL; // Error reading from pipe
12335  }
12336 
12337  // Null-terminate the string
12338  output[total_read] = '\0';
12339 
12340  *size = total_read;
12341 
12342  // Close the pipe
12343  if (FOUNDATIONAL_LIB_UNLIKELY(pclose(pipe) != 0)) // Check for errors.
12344  {
12347  return NULL;
12348  }
12349 
12350  return output;
12351 }
12352 
12353 #endif
12354 
12375 FOUNDATIONAL_LIB_FUNC char **read_file_into_array(const char *filename, const char *delim, size_t *num_lines)
12376 {
12380 
12381  size_t size_of_file;
12382 
12383  *num_lines = 0;
12384 
12385  /*
12386  * This approach uses very few system calls and is rather efficient.
12387  * It first gets the entire file into memory, then splits it.
12388  * There would be very few fread() calls, and it can predict the buffer
12389  * size ahead of time, for low memory usage.
12390  *
12391  * One issue with this is that it has to allocate memory twice -
12392  * first for read_file_into_array - second for the new array,
12393  * after which the first array is freed(). So that means for
12394  * a time, the computer needs around 2x the memory.
12395  * However, if you are concerned about memory usage, probably
12396  * better might be read_file_into_string() with strtok() used
12397  * to extract the parts you want, or manual code withFOUNDATIONAL_LIB_FREAD().
12398  *
12399  * Any which way, this implementation is decent and efficient
12400  * for many purposes.
12401  */
12402  const char *file = read_file_into_string(filename, &size_of_file);
12403  if (FOUNDATIONAL_LIB_UNLIKELY(file == NULL))
12404  {
12405  /* read_file_into_string() would already call die_aggressively_if_enabled */
12406 
12407  return NULL;
12408  }
12409 
12410  char **lines = split(file, num_lines, delim, 0, 1);
12411 
12413  if (FOUNDATIONAL_LIB_UNLIKELY(lines == NULL))
12414  {
12415  /* split() would already call die_aggressively_if_enabled */
12416 
12417  return NULL;
12418  }
12419 
12420  return lines;
12421 }
12422 
12428 FOUNDATIONAL_LIB_FUNC void print_char(const char value) { FOUNDATIONAL_LIB_PRINTF("%c", value); }
12429 
12436 FOUNDATIONAL_LIB_FUNC void print_char_to_stream(const char value, FILE *stream)
12437 {
12439  FOUNDATIONAL_LIB_FPRINTF(stream, "%c", value);
12440 }
12441 
12447 FOUNDATIONAL_LIB_FUNC void print_double(const double value) { FOUNDATIONAL_LIB_PRINTF("%f", value); }
12448 
12455 FOUNDATIONAL_LIB_FUNC void print_double_to_stream(const double value, FILE *stream)
12456 {
12458  FOUNDATIONAL_LIB_FPRINTF(stream, "%f", value);
12459 }
12460 
12466 FOUNDATIONAL_LIB_FUNC void print_float(const float value) { FOUNDATIONAL_LIB_PRINTF("%f", value); }
12467 
12474 FOUNDATIONAL_LIB_FUNC void print_float_to_stream(const float value, FILE *stream)
12475 {
12477  FOUNDATIONAL_LIB_FPRINTF(stream, "%f", value);
12478 }
12479 
12485 FOUNDATIONAL_LIB_FUNC void print_int(const int value) { FOUNDATIONAL_LIB_PRINTF("%d", value); }
12486 
12493 FOUNDATIONAL_LIB_FUNC void print_int_to_stream(const int value, FILE *stream)
12494 {
12496  FOUNDATIONAL_LIB_FPRINTF(stream, "%d", value);
12497 }
12498 
12504 FOUNDATIONAL_LIB_FUNC void print_long(const long value) { FOUNDATIONAL_LIB_PRINTF("%ld", value); }
12505 
12512 FOUNDATIONAL_LIB_FUNC void print_long_to_stream(const long value, FILE *stream)
12513 {
12515  FOUNDATIONAL_LIB_FPRINTF(stream, "%ld", value);
12516 }
12517 
12523 FOUNDATIONAL_LIB_FUNC void print_long_long(const long long value) { FOUNDATIONAL_LIB_PRINTF("%lld", value); }
12524 
12531 FOUNDATIONAL_LIB_FUNC void print_long_long_to_stream(const long long value, FILE *stream)
12532 {
12534 
12535 #pragma GCC diagnostic push
12536 #pragma GCC diagnostic ignored "-Wpragmas"
12537 #pragma GCC diagnostic ignored "-Wformat"
12538 #pragma GCC diagnostic ignored "-Wformat-extra-args"
12539 
12540  FOUNDATIONAL_LIB_FPRINTF(stream, "%lld", value);
12541 #pragma GCC diagnostic pop
12542 }
12543 
12549 FOUNDATIONAL_LIB_FUNC void print_short(const short value) { FOUNDATIONAL_LIB_PRINTF("%hd", value); }
12550 
12557 FOUNDATIONAL_LIB_FUNC void print_short_to_stream(const short value, FILE *stream)
12558 {
12560  FOUNDATIONAL_LIB_FPRINTF(stream, "%hd", value);
12561 }
12567 FOUNDATIONAL_LIB_FUNC void print_size_t(const size_t value) { FOUNDATIONAL_LIB_PRINTF("%zu", value); }
12568 
12575 FOUNDATIONAL_LIB_FUNC void print_size_t_to_stream(const size_t value, FILE *stream)
12576 {
12578 
12579 #pragma GCC diagnostic push
12580 #pragma GCC diagnostic ignored "-Wpragmas"
12581 #pragma GCC diagnostic ignored "-Wformat"
12582 #pragma GCC diagnostic ignored "-Wformat-extra-args"
12583  FOUNDATIONAL_LIB_FPRINTF(stream, "%zu", value);
12584 #pragma GCC diagnostic pop
12585 }
12586 
12593 {
12595  FOUNDATIONAL_LIB_PRINTF("%s", value);
12596 }
12597 
12604 FOUNDATIONAL_LIB_FUNC void print_string_to_stream(char *value, FILE *stream)
12605 {
12608 
12609  FOUNDATIONAL_LIB_FPRINTF(stream, "%s", value);
12610 }
12611 
12617 FOUNDATIONAL_LIB_FUNC void print_uchar(const unsigned char value) { FOUNDATIONAL_LIB_PRINTF("%c", value); }
12618 
12625 FOUNDATIONAL_LIB_FUNC void print_uchar_to_stream(const unsigned char value, FILE *stream)
12626 {
12628  FOUNDATIONAL_LIB_FPRINTF(stream, "%c", value);
12629 }
12630 
12636 FOUNDATIONAL_LIB_FUNC void print_uint(const unsigned int value) { FOUNDATIONAL_LIB_PRINTF("%u", value); }
12637 
12644 FOUNDATIONAL_LIB_FUNC void print_uint_to_stream(const unsigned int value, FILE *stream)
12645 {
12647  FOUNDATIONAL_LIB_FPRINTF(stream, "%u", value);
12648 }
12654 FOUNDATIONAL_LIB_FUNC void print_ulong(const unsigned long value) { FOUNDATIONAL_LIB_PRINTF("%lu", value); }
12655 
12662 FOUNDATIONAL_LIB_FUNC void print_ulong_to_stream(const unsigned long value, FILE *stream)
12663 {
12665  FOUNDATIONAL_LIB_FPRINTF(stream, "%lu", value);
12666 }
12667 
12673 FOUNDATIONAL_LIB_FUNC void print_ulong_long(const unsigned long long value)
12674 {
12675 
12676 #pragma GCC diagnostic push
12677 #pragma GCC diagnostic ignored "-Wpragmas"
12678 #pragma GCC diagnostic ignored "-Wformat"
12679 #pragma GCC diagnostic ignored "-Wformat-extra-args"
12680  FOUNDATIONAL_LIB_PRINTF("%llu", value);
12681 #pragma GCC diagnostic pop
12682 }
12683 
12690 FOUNDATIONAL_LIB_FUNC void print_ulong_long_to_stream(const unsigned long long value, FILE *stream)
12691 {
12693 #pragma GCC diagnostic push
12694 #pragma GCC diagnostic ignored "-Wpragmas"
12695 #pragma GCC diagnostic ignored "-Wformat"
12696 #pragma GCC diagnostic ignored "-Wformat-extra-args"
12697  FOUNDATIONAL_LIB_FPRINTF(stream, "%llu", value);
12698 #pragma GCC diagnostic pop
12699 }
12705 FOUNDATIONAL_LIB_FUNC void print_ushort(const unsigned short value) { FOUNDATIONAL_LIB_PRINTF("%hu", value); }
12706 
12713 FOUNDATIONAL_LIB_FUNC void print_ushort_to_stream(const unsigned short value, FILE *stream)
12714 {
12715 
12717  FOUNDATIONAL_LIB_FPRINTF(stream, "%hu", value);
12718 }
12719 
12732 FOUNDATIONAL_LIB_FUNC size_t count_occurrences_of_string_in_array(const char **array, const char *string, size_t array_length)
12733 {
12735 
12737 
12738  size_t count = 0;
12739 
12740  // Iterate through the array
12741  for (size_t i = 0; i < array_length; ++i)
12742  {
12743  // Compare each string in the array with the target string
12744  if (FOUNDATIONAL_LIB_STRCMP(array[i], string) == 0)
12745  {
12746  ++count;
12747  }
12748  }
12749 
12750  return count;
12751 }
12752 
12766 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)
12767 {
12768 
12769  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(array_of_adjacent_values);
12771  size_t count = 0;
12772 
12773  // Iterate through the array
12774  for (size_t i = 0; i < array_length; ++i)
12775  {
12776  // Dereferences each pointer in the array and compare memory_length bytes.
12777  if (FOUNDATIONAL_LIB_MEMCMP(array_of_adjacent_values, memory, memory_length) == 0)
12778  {
12779  count++;
12780  }
12781  }
12782 
12783  return count;
12784 }
12785 
12799 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)
12800 {
12801 
12804 
12805  size_t count = 0;
12806 
12807  // Iterate through the array
12808  for (size_t i = 0; i < array_length; ++i)
12809  {
12810  // Dereferences each pointer in the array and compare memory_length bytes.
12811  if (FOUNDATIONAL_LIB_MEMCMP(array_of_pointers[i], memory, memory_length) == 0)
12812  {
12813  count++;
12814  }
12815  }
12816 
12817  return count;
12818 }
12819 
12820 #if FOUNDATIONAL_LIB_NETWORK_FUNCTIONS_ENABLED
12821 
12822 /* Chrome by default */
12823 
12824 #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"
12825 
12826 #include <curl/curl.h>
12827 
12828 /* Write callback */
12829 FOUNDATIONAL_LIB_FUNC size_t FOUNDATIONAL_LIB_libcurl_write_callback(char *data, size_t n, size_t l, void *userp)
12830 {
12831 
12833 
12835  struct StringData
12836  {
12837  char *string;
12838 
12839  size_t size;
12840  size_t alloc_size;
12841 
12842  size_t byte_max_cutoff;
12843  } *string = userp;
12844 
12845  const size_t both = n * l;
12846  append_string_to_string(&string->string, &string->size, &string->alloc_size, data, both);
12847 
12848  if (string->byte_max_cutoff != 0 && string->size >= string->byte_max_cutoff)
12849  {
12850  /* Curl can read in big blocks, like 9,370 bytes. So if the cutoff is low,
12851  * the read size still might be high. */
12852  /* FOUNDATIONAL_LIB_PRINTF("%zu.size >= %zu.byte_max_cutoff\n", string->size,
12853  string->byte_max_cutoff); */
12854  return CURLE_OK;
12855  }
12856  return both;
12857 }
12858 
12896 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)
12897 {
12898 
12903 
12904  CURL *curl = curl_easy_init();
12905  if (FOUNDATIONAL_LIB_UNLIKELY(curl == NULL))
12906  {
12907  return -1;
12908  }
12909 
12910  if (user_agent == NULL)
12911  {
12912  user_agent = FOUNDATIONAL_LIB_DEFAULT_USER_AGENT;
12913  }
12914 
12915  curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 102400L);
12916  curl_easy_setopt(curl, CURLOPT_URL, website);
12917  curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
12918  curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent);
12919  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
12920  curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L);
12921  curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
12922  curl_easy_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, 1L);
12923  curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
12924  struct StringData
12925  {
12926  char *string;
12927  size_t size;
12928  size_t alloc_size;
12929  size_t byte_max_cutoff;
12930  } data;
12931  data.string = FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC(FOUNDATIONAL_LIB_INITIAL_NETWORK_DOWNLOAD_BUFFER_SIZE);
12932  data.alloc_size = FOUNDATIONAL_LIB_INITIAL_NETWORK_DOWNLOAD_BUFFER_SIZE;
12933  data.size = 0;
12934  data.byte_max_cutoff = byte_max_cutoff;
12935 
12936  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, FOUNDATIONAL_LIB_libcurl_write_callback);
12937  curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
12938  CURLcode curlcode = curl_easy_perform(curl);
12939 
12940  curl_easy_cleanup(curl);
12941 
12942  *string = data.string;
12943  *size = data.size;
12944  *str_alloc_size = data.alloc_size;
12945 
12946  return curlcode == CURLE_OK;
12947 }
12948 
12969 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)
12970 {
12971 
12972  FOUNDATIONAL_LIB_ASSERT_ARGUMENT_IF_ENABLED(websites_to_download);
12975  // Initalize all to NULL in case a site can't download
12976  *outputs = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(num_websites, sizeof(char *));
12977 
12978  // Initalize all to 0 in case a site can't download
12979  *lens = (size_t *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(num_websites, sizeof(size_t));
12980 
12981  for (size_t i = 0; i < num_websites; ++i)
12982  {
12983  size_t alloc_size;
12984  if (download_website(websites_to_download[i], (*outputs) + i, (*lens) + i, &alloc_size, byte_limit, NULL) == -1)
12985  {
12986  if (aggressive_stop_on_error)
12987  {
12989  return -1;
12990  }
12991  }
12992  }
12993 
12994  return 0;
12995 }
12996 
12997 #endif /* Networking. */
12998 
13028 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)
13029 {
13033  // Initalize all to NULL in case a site can't download
13034  *outputs = (char **)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(num_files, sizeof(char *));
13035 
13036  // Initalize all to 0 in case a site can't download
13037  *lens = (size_t *)FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC(num_files, sizeof(size_t));
13038 
13039  for (size_t i = 0; i < num_files; ++i)
13040  {
13041  size_t size;
13042 
13043  (*outputs)[i] = read_file_into_string(files_to_open[i], &size);
13044  (*lens)[i] = size;
13045 
13046  if ((*outputs)[i] == NULL)
13047  {
13048  if (aggressive_stop_on_error)
13049  {
13051  return -1;
13052  }
13053  }
13054  }
13055 
13056  return 0;
13057 }
13058 
13059 #pragma GCC diagnostic pop /* Niche Wformat issues */
13060 
13061 #endif
FOUNDATIONAL_LIB_FUNC int is_string_printable(const char *string)
Check if all characters in a string are printable.
Definition: foundationallib.h:9456
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:6518
FOUNDATIONAL_LIB_FUNC int is_string_valid_integer(const char *str)
Checks if a string is a valid integer.
Definition: foundationallib.h:4882
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:10854
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:1284
FOUNDATIONAL_LIB_FUNC int shuffle_strings_in_place(char **strings, size_t size)
Shuffles an array of strings in place.
Definition: foundationallib.h:12137
FOUNDATIONAL_LIB_FUNC unsigned int ** sorted_uint_ptrs(unsigned int **uint_ptrs, size_t size)
Definition: foundationallib.h:5401
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:10959
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:1536
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:6352
FOUNDATIONAL_LIB_FUNC unsigned char * sorted_uchars(unsigned char *uchars, size_t size)
Creates a new array containing sorted unsigned chars.
Definition: foundationallib.h:5590
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:3050
#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:1229
#define FOUNDATIONAL_LIB_FUNC
Definition: foundationallib.h:821
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:7982
FOUNDATIONAL_LIB_FUNC int string_to_int(const char *str)
Converts a string to an integer.
Definition: foundationallib.h:6934
static void dict_del_keys(char **keys)
Deallocates memory associated with an array of keys.
Definition: foundationallib.h:11024
FOUNDATIONAL_LIB_FUNC unsigned long * sorted_ulongs(unsigned long *ulongs, size_t size)
Creates a new array containing sorted unsigned longs.
Definition: foundationallib.h:6093
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:2395
FOUNDATIONAL_LIB_FUNC int remove_file(const char *filename)
Removes a file.
Definition: foundationallib.h:7340
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:1823
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:1412
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:3409
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:8028
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:5885
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:5655
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:1628
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:3857
static size_t FOUNDATIONAL_LIB_REALLOC_REALLOCATION_ALGORITHM(size_t siz)
Definition: foundationallib.h:661
FOUNDATIONAL_LIB_FUNC void sort_uints(unsigned int *uints, size_t size)
Definition: foundationallib.h:5319
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:5189
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:6139
FOUNDATIONAL_LIB_FUNC size_t dict_size(struct Dict *dict)
Returns the number of key-value pairs in the dictionary.
Definition: foundationallib.h:10837
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:4552
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:9559
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:2743
FOUNDATIONAL_LIB_FUNC char * string_to_lowercase(char *string)
Convert a string to lowercase.
Definition: foundationallib.h:9248
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:4925
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:12673
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:9133
FOUNDATIONAL_LIB_FUNC void sort_doubles(double *doubles, size_t size)
Sorts an array of doubles in ascending order.
Definition: foundationallib.h:6703
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:8074
FOUNDATIONAL_LIB_FUNC void * replicate(const void *source, size_t source_size, size_t elem_size, size_t repetitions)
Definition: foundationallib.h:9195
FOUNDATIONAL_LIB_FUNC char * dict_to_string(struct Dict *dict, int pointer_or_string)
Converts a dictionary to a string representation.
Definition: foundationallib.h:11065
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:12662
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:1760
#define FOUNDATIONAL_LIB_VA_LIST
Definition: foundationallib.h:122
#define FOUNDATIONAL_LIB_FCLOSE
Definition: foundationallib.h:757
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:8659
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:10476
FOUNDATIONAL_LIB_FUNC char * reverse_string(const char *str)
Reverses a given string.
Definition: foundationallib.h:4244
FOUNDATIONAL_LIB_FUNC void print_int(const int value)
Prints an integer value to the standard output.
Definition: foundationallib.h:12485
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:1953
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:6745
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:2595
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:10809
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:12051
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:7962
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_int_ptrs(const void *a, const void *b)
Definition: foundationallib.h:5493
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:2541
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:1567
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:9770
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:3025
#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:12625
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:6031
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:2243
FOUNDATIONAL_LIB_FUNC void print_float(const float value)
Prints a single-precision floating-point value to the standard output.
Definition: foundationallib.h:12466
#define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_FREE
Definition: foundationallib.h:775
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:8122
#define FOUNDATIONAL_LIB_HASH_LOAD_FACTOR_THRESHOLD
Load factor threshold for hash tables in the foundational library.
Definition: foundationallib.h:813
#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:11815
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:4469
FOUNDATIONAL_LIB_FUNC void print_uint(const unsigned int value)
Prints an unsigned int value to the standard output.
Definition: foundationallib.h:12636
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ints(const void *a, const void *b)
Definition: foundationallib.h:5428
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:6207
FOUNDATIONAL_LIB_FUNC void print_ulong(const unsigned long value)
Prints an unsigned long value to the standard output.
Definition: foundationallib.h:12654
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:4955
FOUNDATIONAL_LIB_FUNC void print_char_to_stream(const char value, FILE *stream)
Prints a character value to the specified stream.
Definition: foundationallib.h:12436
static void frozen_dict_del_keys(char **keys)
Deletes keys from a frozen dictionary.
Definition: foundationallib.h:11248
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:6161
FOUNDATIONAL_LIB_FUNC int is_string_digit(const char *string)
Check if all characters in a string are digits.
Definition: foundationallib.h:9397
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:2644
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:6332
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:2507
FOUNDATIONAL_LIB_FUNC void reverse_int_array_in_place(int *array, size_t size)
Reverses an array of integers in place.
Definition: foundationallib.h:5118
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:5097
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:10316
FOUNDATIONAL_LIB_FUNC void sort_int_ptrs(int **int_ptrs, size_t size)
Definition: foundationallib.h:5510
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:2997
#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:6443
FOUNDATIONAL_LIB_FUNC unsigned short * sorted_ushorts(unsigned short *ushorts, size_t size)
Creates a new array containing sorted unsigned shorts.
Definition: foundationallib.h:5838
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:4530
#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:2845
FOUNDATIONAL_LIB_FUNC int is_string_numeric(const char *str)
Checks if the provided string consists solely of numeric characters.
Definition: foundationallib.h:4570
FOUNDATIONAL_LIB_FUNC unsigned int * sorted_uints(unsigned int *uints, size_t size)
Definition: foundationallib.h:5338
#define FOUNDATIONAL_LIB_safe_increment(variable, label_if_fails)
Definition: foundationallib.h:614
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:6397
#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:8435
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:2669
FOUNDATIONAL_LIB_FUNC double * sorted_doubles(double *doubles, size_t size)
Creates a new array containing sorted doubles.
Definition: foundationallib.h:6722
#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:5302
#define FOUNDATIONAL_LIB_POPEN_INITIAL_ALLOC_SIZE
Definition: foundationallib.h:699
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:2719
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:6887
FOUNDATIONAL_LIB_FUNC void utoa(size_t unsigned_value, char *output)
Definition: foundationallib.h:1038
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:2793
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:6762
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:6501
FOUNDATIONAL_LIB_AGGRESSIVE_DIE_TYPE FOUNDATIONAL_LIB_aggressive_die
Global variable to control aggressive die behavior.
Definition: foundationallib.h:847
#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:10424
#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:7267
FOUNDATIONAL_LIB_FUNC void print_string_array_array(char ***array, size_t size)
Prints an array of arrays of strings.
Definition: foundationallib.h:1257
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:12375
FOUNDATIONAL_LIB_FUNC void set_del_keys(char **keys)
Deletes keys from a Set.
Definition: foundationallib.h:11861
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:2448
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:5994
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:6641
FOUNDATIONAL_LIB_FUNC void sort_floats(float *floats, size_t size)
Sorts an array of floats in ascending order.
Definition: foundationallib.h:6580
#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:12504
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:571
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:2922
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:12455
FOUNDATIONAL_LIB_FUNC char * sorted_chars(char *chars, size_t size)
Creates a new array containing sorted chars.
Definition: foundationallib.h:5713
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:2947
FOUNDATIONAL_LIB_FUNC int append_string_to_file(const char *filename, const char *content)
Appends a string to a file.
Definition: foundationallib.h:7132
FOUNDATIONAL_LIB_FUNC void sort_chars(char *chars, size_t size)
Sorts an array of chars in ascending order.
Definition: foundationallib.h:5694
static int starts_with(const char *str, const char *prefix)
Definition: foundationallib.h:4277
FOUNDATIONAL_LIB_FUNC int dict_resize(struct Dict *dict)
Resizes the hash table of the dictionary to optimize performance.
Definition: foundationallib.h:10370
static int ends_with(const char *str, const char *suffix)
Checks whether a given string ends with a specified suffix.
Definition: foundationallib.h:4294
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:12644
FOUNDATIONAL_LIB_FUNC int frozen_set_in(struct FrozenSet *set, const char *key)
Checks if a key is in a FrozenSet.
Definition: foundationallib.h:11681
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:3173
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:5753
FOUNDATIONAL_LIB_FUNC char * frozen_set_to_string(struct FrozenSet *frozen_set)
Converts a frozen set to a string representation.
Definition: foundationallib.h:11939
static double str_to_double(const char *string)
Converts a string to a double-precision floating-point number.
Definition: foundationallib.h:4791
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:8388
FOUNDATIONAL_LIB_FUNC int file_is_regular(const char *filename)
Checks if a file is a regular file.
Definition: foundationallib.h:7177
FOUNDATIONAL_LIB_FUNC void sort_ulongs(unsigned long *ulongs, size_t size)
Sorts an array of unsigned longs in ascending order.
Definition: foundationallib.h:6074
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:12474
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:2032
#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:2059
FOUNDATIONAL_LIB_FUNC int file_is_writable(const char *filename)
Checks if a file is writable.
Definition: foundationallib.h:7246
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:6539
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:3628
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:7365
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:2474
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:587
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:12531
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:1735
FOUNDATIONAL_LIB_FUNC char * dup_format(const char *format,...)
Duplicates a formatted string.
Definition: foundationallib.h:8225
FOUNDATIONAL_LIB_FUNC char * string_to_title_case(const char *str)
Converts a string to title case.
Definition: foundationallib.h:4986
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:9828
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:5737
#define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_STRDUP
Definition: foundationallib.h:779
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_shorts(const void *a, const void *b)
Compare function for sorting shorts.
Definition: foundationallib.h:5933
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:2006
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_uchars(const void *a, const void *b)
Compare function for sorting unsigned chars.
Definition: foundationallib.h:5554
#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:4316
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:9528
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:6273
#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:10652
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:3125
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:541
FOUNDATIONAL_LIB_FUNC float * sorted_floats(float *floats, size_t size)
Creates a new array containing sorted floats.
Definition: foundationallib.h:6599
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:2972
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:3197
FOUNDATIONAL_LIB_FUNC char * set_to_string(struct Set *set)
Definition: foundationallib.h:11864
FOUNDATIONAL_LIB_FUNC int is_string_upper(const char *string)
Check if all characters in a string are uppercase.
Definition: foundationallib.h:9316
static FOUNDATIONAL_LIB_CONST 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:525
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:6317
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:12206
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:4712
FOUNDATIONAL_LIB_FUNC size_t frozen_set_size(struct FrozenSet *set)
Returns the size of a FrozenSet.
Definition: foundationallib.h:11751
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:11162
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:1850
FOUNDATIONAL_LIB_FUNC void print_double_array(const double *array, size_t size)
Prints the elements of a double array.
Definition: foundationallib.h:1709
FOUNDATIONAL_LIB_FUNC void print_int_array(const int *array, size_t size)
Prints the elements of an int array.
Definition: foundationallib.h:1163
FOUNDATIONAL_LIB_FUNC char * string_to_json(const char *input_string)
Converts a given input string to its JSON representation.
Definition: foundationallib.h:3246
FOUNDATIONAL_LIB_FUNC void frozen_set_del_keys(char **keys)
Deletes keys from a FrozenSet.
Definition: foundationallib.h:12007
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:5907
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:9714
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:5774
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:13028
static void free_array(void **array, size_t len)
Frees a dynamic array and its elements up to one level deep.
Definition: foundationallib.h:896
FOUNDATIONAL_LIB_FUNC void print_long_long(const long long value)
Prints a long long integer value to the standard output.
Definition: foundationallib.h:12523
FOUNDATIONAL_LIB_FUNC char * string_to_uppercase(char *string)
Convert a string to uppercase.
Definition: foundationallib.h:9284
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:4436
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:1195
FOUNDATIONAL_LIB_FUNC int get_file_size(const char *filename, size_t *size)
Gets the size of a file.
Definition: foundationallib.h:7290
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:8885
FOUNDATIONAL_LIB_FUNC int is_array_digit(const char **array, size_t size)
Check if a string array contains only digits.
Definition: foundationallib.h:9498
FOUNDATIONAL_LIB_FUNC int file_is_directory(const char *filename)
Checks if a file is a directory.
Definition: foundationallib.h:7200
FOUNDATIONAL_LIB_FUNC long * sorted_longs(long *longs, size_t size)
Creates a new array containing sorted pointers to unsigned longs.
Definition: foundationallib.h:6230
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:1902
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:7805
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:915
FOUNDATIONAL_LIB_FUNC int is_string_lower(const char *string)
Check if all characters in a string are lowercase.
Definition: foundationallib.h:9343
FOUNDATIONAL_LIB_FUNC void print_ushort(const unsigned short value)
Print an unsigned short value.
Definition: foundationallib.h:12705
#define FOUNDATIONAL_LIB_COPY_SIZE_AMOUNT
Definition: foundationallib.h:693
FOUNDATIONAL_LIB_FUNC void print_char(const char value)
Prints a character value to the standard output.
Definition: foundationallib.h:12428
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:9614
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:2870
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:2274
#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:11637
#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:6845
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:11545
#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:11408
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:7065
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:6121
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:2620
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:10776
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:1101
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:6417
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:1979
FOUNDATIONAL_LIB_FUNC char * backticks(const char *command, size_t *size)
Executes a command and reads its output into a string.
Definition: foundationallib.h:12247
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:8543
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:6379
#define FOUNDATIONAL_LIB_FERROR
Definition: foundationallib.h:722
FOUNDATIONAL_LIB_FUNC char * concatenate_strings(const char *str1, const char *str2)
Concatenates two strings.
Definition: foundationallib.h:7755
FOUNDATIONAL_LIB_FUNC void sort_ushorts(unsigned short *ushorts, size_t size)
Sorts an array of unsigned shorts in ascending order.
Definition: foundationallib.h:5817
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_list_comprehension_worker(void *data)
Definition: foundationallib.h:8817
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:3786
#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:2694
#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:11262
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:3075
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:6475
#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:10883
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:2337
FOUNDATIONAL_LIB_FUNC int * sorted_ints(int *ints, size_t size)
Definition: foundationallib.h:5465
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:993
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:1597
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_chars(const void *a, const void *b)
Compare function for sorting chars.
Definition: foundationallib.h:5679
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:6292
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:10112
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:11767
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:6457
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:4398
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:1875
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:2304
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:2216
#define FOUNDATIONAL_LIB_DIR_SEPARATOR
Definition: foundationallib.h:9851
#define FOUNDATIONAL_LIB_FTELLO
Definition: foundationallib.h:739
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:2895
#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:12557
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:3941
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:601
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:3149
#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:12713
FOUNDATIONAL_LIB_FUNC int write_file(const char *filename, const char *content)
Writes a string to a file.
Definition: foundationallib.h:7109
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:8337
#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:6825
#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:6870
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:6257
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:1132
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:1348
#define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_MALLOC
Definition: foundationallib.h:763
FOUNDATIONAL_LIB_FUNC void print_int_to_stream(const int value, FILE *stream)
Prints an integer value to the specified stream.
Definition: foundationallib.h:12493
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:7588
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:8481
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:2368
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:3221
FOUNDATIONAL_LIB_FUNC int ** sorted_int_ptrs(int **int_ptrs, size_t size)
Definition: foundationallib.h:5530
FOUNDATIONAL_LIB_FUNC void print_string_to_stream(char *value, FILE *stream)
Prints a string value to the specified stream.
Definition: foundationallib.h:12604
FOUNDATIONAL_LIB_FUNC char ** sorted_strings(char **strings, size_t size)
Creates a new array of strings sorted in ascending order.
Definition: foundationallib.h:5275
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:1928
FOUNDATIONAL_LIB_FUNC int is_string_space(const char *string)
Check if all characters in a string are spaces.
Definition: foundationallib.h:9423
#define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_CALLOC
Definition: foundationallib.h:771
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:9798
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:8295
FOUNDATIONAL_LIB_FUNC char * strip(const char *str)
Trims leading and trailing whitespace from a given string.
Definition: foundationallib.h:3342
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:4833
FOUNDATIONAL_LIB_FUNC size_t set_size(struct Set *set)
Returns the size of a Set.
Definition: foundationallib.h:11736
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:2111
#define FOUNDATIONAL_LIB_HASH_INITIAL_CAPACITY
Initial capacity for hash tables (dict, frozendict, set, frozenset).
Definition: foundationallib.h:801
FOUNDATIONAL_LIB_FUNC int set_resize(struct Set *set)
Resizes a Set data structure.
Definition: foundationallib.h:11359
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:10010
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:2768
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_floats(const void *a, const void *b)
Compare function for sorting floats.
Definition: foundationallib.h:6565
FOUNDATIONAL_LIB_FUNC char * shellescape(const char *input)
Escapes special characters in a given string for shell usage.
Definition: foundationallib.h:4185
#define FOUNDATIONAL_LIB_MEMORY_ALLOCATOR_REALLOC
Definition: foundationallib.h:767
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:11337
static void dict_del_values(void **values)
Deallocates memory associated with an array of values.
Definition: foundationallib.h:11041
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ushorts(const void *a, const void *b)
Compare function for sorting unsigned shorts.
Definition: foundationallib.h:5800
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:6957
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:4009
#define FOUNDATIONAL_LIB_ALLOCATOR_DIV_AMOUNT
Definition: foundationallib.h:626
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:4152
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:4090
FOUNDATIONAL_LIB_FUNC int set_in(struct Set *set, const char *key)
Checks if a key is in a Set.
Definition: foundationallib.h:11594
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:2189
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:2164
FOUNDATIONAL_LIB_FUNC void sort_strings(char **strings, size_t size)
Sorts an array of strings.
Definition: foundationallib.h:5257
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:4360
#define FOUNDATIONAL_LIB_FPUTS
Definition: foundationallib.h:325
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmpstringp(const void *p1, const void *p2)
Definition: foundationallib.h:5244
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_ulongs(const void *a, const void *b)
Compare function for sorting unsigned longs.
Definition: foundationallib.h:6058
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:3100
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_doubles(const void *a, const void *b)
Compare function for sorting doubles.
Definition: foundationallib.h:6687
#define FOUNDATIONAL_LIB_ATOI
Definition: foundationallib.h:706
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:7674
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:9068
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:6808
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:5617
#define FOUNDATIONAL_LIB_likely(x)
Definition: foundationallib.h:423
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:1684
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:9877
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:4632
FOUNDATIONAL_LIB_FUNC void print_double(const double value)
Prints a double-precision floating-point value to the standard output.
Definition: foundationallib.h:12447
#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:5066
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:6625
#define FOUNDATIONAL_LIB_INITIAL_DATA_ARRAY_ALLOC_SIZE
Definition: foundationallib.h:3672
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:5866
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:6782
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:2084
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:10284
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:11708
#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:1381
FOUNDATIONAL_LIB_FUNC void print_uchar(const unsigned char value)
Prints an unsigned char value to the standard output.
Definition: foundationallib.h:12617
#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:7225
FOUNDATIONAL_LIB_FUNC char * uint_to_string(size_t number)
Converts an integer to its string representation.
Definition: foundationallib.h:1075
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:2820
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:12690
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:12766
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:12799
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:6661
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:12177
FOUNDATIONAL_LIB_FUNC void frozen_dict_destructor(struct FrozenDict *dict)
Deallocates memory associated with a frozen dictionary, freeing resources.
Definition: foundationallib.h:10633
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:1791
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:10560
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:3696
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:6908
FOUNDATIONAL_LIB_FUNC void print_short(const short value)
Prints a short integer value to the standard output.
Definition: foundationallib.h:12549
FOUNDATIONAL_LIB_FUNC int FOUNDATIONAL_LIB_cmp_uint_ptrs(const void *a, const void *b)
Definition: foundationallib.h:5364
FOUNDATIONAL_LIB_FUNC void sort_shorts(short *shorts, size_t size)
Sorts an array of shorts in ascending order.
Definition: foundationallib.h:5947
FOUNDATIONAL_LIB_FUNC void print_long_array(const long *array, size_t size)
Prints the elements of a long array.
Definition: foundationallib.h:1476
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:1317
FOUNDATIONAL_LIB_FUNC short * sorted_shorts(short *shorts, size_t size)
Creates a new array containing sorted shorts.
Definition: foundationallib.h:5967
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:5163
FOUNDATIONAL_LIB_FUNC void reverse_string_in_place(char *str)
Reverses a string in place.
Definition: foundationallib.h:4858
#define FOUNDATIONAL_LIB_FWRITE
Definition: foundationallib.h:749
FOUNDATIONAL_LIB_FUNC void sort_uchars(unsigned char *uchars, size_t size)
Sorts an array of unsigned chars in ascending order.
Definition: foundationallib.h:5570
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:5140
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:12104
FOUNDATIONAL_LIB_FUNC void print_long_ptr_array(const long **array, size_t size)
Prints the elements of a long array.
Definition: foundationallib.h:1506
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:3522
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:5633
FOUNDATIONAL_LIB_FUNC char * int_to_string(long long int number)
Converts an integer to its string representation.
Definition: foundationallib.h:933
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:10704
FOUNDATIONAL_LIB_FUNC void sort_uint_ptrs(unsigned int **uint_ptrs, size_t size)
Definition: foundationallib.h:5380
FOUNDATIONAL_LIB_FUNC void frozen_set_destructor(struct FrozenSet *frozen_set)
The destructor for a Frozen Set.
Definition: foundationallib.h:11621
#define FOUNDATIONAL_LIB_POPEN
Definition: foundationallib.h:716
FOUNDATIONAL_LIB_FUNC int is_string_alpha(const char *string)
Check if all characters in a string are alphanumeric.
Definition: foundationallib.h:9370
FOUNDATIONAL_LIB_FUNC void set_destructor(struct Set *set)
The destructor for a Set.
Definition: foundationallib.h:11275
FOUNDATIONAL_LIB_FUNC void print_string(char *value)
Prints a string value to the standard output.
Definition: foundationallib.h:12592
FOUNDATIONAL_LIB_FUNC struct Set * set_new_instance(void)
Creates a new instance of a Set.
Definition: foundationallib.h:11301
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:1445
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:12575
FOUNDATIONAL_LIB_FUNC int set_add(struct Set *set, const char *key)
Adds a key pair to the set.
Definition: foundationallib.h:11460
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:10599
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:6189
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:12732
FOUNDATIONAL_LIB_FUNC void print_float_array(const float *array, size_t size)
Prints the elements of a float array.
Definition: foundationallib.h:1658
#define FOUNDATIONAL_LIB_FREAD
Definition: foundationallib.h:745
#define FOUNDATIONAL_LIB_die_aggressively_if_enabled()
Macro to die aggressively if enabled.
Definition: foundationallib.h:878
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:4810
FOUNDATIONAL_LIB_FUNC int is_string_alphanumeric(const char *str)
Determines whether a given string consists solely of alphanumeric characters.
Definition: foundationallib.h:4602
FOUNDATIONAL_LIB_FUNC int file_exists(const char *filename)
Checks if a file exists.
Definition: foundationallib.h:7157
FOUNDATIONAL_LIB_FUNC void print_size_t(const size_t value)
Prints a size_t value to the standard output.
Definition: foundationallib.h:12567
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:555
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:12512
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:10740
#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:5035
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:2137
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:2421
FOUNDATIONAL_LIB_FUNC void sort_ints(int *ints, size_t size)
Definition: foundationallib.h:5446
#define FOUNDATIONAL_LIB_FSEEKO
Definition: foundationallib.h:735
#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:2580
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:12022
FOUNDATIONAL_LIB_FUNC void dict_destructor(struct Dict *dict)
Deallocates memory associated with a dictionary, freeing resources.
Definition: foundationallib.h:10250
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:6011
Definition: foundationallib.h:8752
struct DictKeyValue ** table
Definition: foundationallib.h:8753
size_t size
Definition: foundationallib.h:8755
size_t capacity
Definition: foundationallib.h:8754
Definition: foundationallib.h:8767
void * value
Definition: foundationallib.h:8769
char * key
Definition: foundationallib.h:8768
struct DictKeyValue * next
Definition: foundationallib.h:8770
Definition: foundationallib.h:8774
size_t capacity
Definition: foundationallib.h:8776
struct DictKeyValue ** table
Definition: foundationallib.h:8775
size_t size
Definition: foundationallib.h:8777
Definition: foundationallib.h:8782
size_t capacity
Definition: foundationallib.h:8784
size_t size
Definition: foundationallib.h:8785
struct SetKey ** table
Definition: foundationallib.h:8783
Definition: foundationallib.h:8759
struct SetKey ** table
Definition: foundationallib.h:8760
size_t size
Definition: foundationallib.h:8762
size_t capacity
Definition: foundationallib.h:8761
Definition: foundationallib.h:8746
struct SetKey * next
Definition: foundationallib.h:8748
char * key
Definition: foundationallib.h:8747
Definition: foundationallib.h:8801
size_t elem_size
Definition: foundationallib.h:8804
size_t start_index
Definition: foundationallib.h:8809
size_t array_size
Definition: foundationallib.h:8803
void * result
Definition: foundationallib.h:8808
size_t end_index
Definition: foundationallib.h:8810
const void * input_array
Definition: foundationallib.h:8802
size_t * result_size
Definition: foundationallib.h:8807
void(* transform_func)(void *value)
Definition: foundationallib.h:8805
int(* filter_func)(void *value)
Definition: foundationallib.h:8806