· 4 years ago · Dec 15, 2020, 08:06 PM
1#ifndef __GS_INCLUDED_H__
2#define __GS_INCLUDED_H__
3
4/*═█═════════════════════════════════════════════════════════════════════════════════════█═╗
5████ ██████╗ ██╗ ██╗███╗ ██╗███████╗██╗ ██╗███╗ ██╗ ██████╗ ███████╗██████╗ ██████═█
6█║█ ██╔════╝ ██║ ██║████╗ ██║██╔════╝██║ ██║████╗ ██║██╔════╝ ██╔════╝██╔══██╗ ██═████
7███ ██║ ███╗██║ ██║██╔██╗ ██║███████╗██║ ██║██╔██╗ ██║██║ ███╗█████╗ ██████╔╝ █████═██
8╚██ ██║ ██║██║ ██║██║╚██╗██║╚════██║██║ ██║██║╚██╗██║██║ ██║██╔══╝ ██╔══██╗ ███ █╝█
9█║█ ╚██████╔╝╚██████╔╝██║ ╚████║███████║███████╗██║██║ ╚████║╚██████╔╝███████╗██║ ██║ ██═████
10████ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ █═█═██
11╚═██════════════════════════════════════════════════════════════════════════════════════██═╝*/
12
13/*===== Gunslinger Include ======*/
14
15#ifdef __cplusplus
16extern "C" {
17#endif
18
19/*========================
20// Defines
21========================*/
22
23#include <stdarg.h> // valist
24#include <stdlib.h> // malloc, realloc, free
25#include <stdint.h> // standard types
26#include <limits.h> // INT32_MAX, UINT32_MAX
27#include <string.h> // memset
28#include <float.h> // FLT_MAX
29#include <stdio.h> // FILE
30#include <time.h> // time
31#include <ctype.h> // tolower
32
33/* Platform Apple */
34#if (defined __APPLE__ || defined _APPLE)
35
36 #define GS_PLATFORM_APPLE
37
38/* Platform Windows */
39#elif (defined _WIN32 || defined _WIN64)
40
41 #define GS_PLATFORM_WIN
42 #include <windows.h>
43
44 #define WIN32_LEAN_AND_MEAN
45
46/* Platform Linux */
47#elif (defined linux || defined _linux || defined __linux__)
48
49 #define GS_PLATFORM_LINUX
50
51/* Else - Platform Undefined and Unsupported */
52
53#endif
54
55/*===========================================================
56// gs_inline, gs_global, gs_local_persist, gs_force_inline
57===========================================================*/
58
59#ifndef gs_inline
60 #define gs_inline static inline
61#endif
62
63#ifndef gs_local_persist
64 #define gs_local_persist static
65#endif
66
67 #if (defined _WIN32 || defined _WIN64)
68 #define gs_force_inline gs_inline
69#elif (defined __APPLE__ || defined _APPLE)
70 #define gs_force_inline static __attribute__((always_inline))
71#else
72 #define gs_force_inline gs_inline
73#endif
74
75#ifndef gs_global
76 #define gs_global static
77#endif
78
79/*===================
80// GS_API_DECL
81===================*/
82#ifdef __cplusplus
83 #define GS_API_DECL extern "C"
84#else
85 #define GS_API_DECL extern
86#endif
87
88/*============================================================
89// gs_result
90============================================================*/
91
92typedef enum gs_result
93{
94 gs_result_success,
95 gs_result_in_progress,
96 gs_result_incomplete,
97 gs_result_failure
98} gs_result;
99
100/*===================================
101// gs_color, gs_hsv
102===================================*/
103
104#define gs_hsv(...) gs_hsv_ctor(__VA_ARGS__)
105#define gs_color(...) gs_color_ctor(__VA_ARGS__)
106
107typedef struct gs_hsv_t
108{
109 union
110 {
111 float hsv[3];
112 struct
113 {
114 float h, s, v;
115 };
116 };
117} gs_hsv_t;
118
119gs_force_inline
120gs_hsv_t gs_hsv_ctor(float h, float s, float v)
121{
122 gs_hsv_t hsv;
123 hsv.h = h;
124 hsv.s = s;
125 hsv.v = v;
126 return hsv;
127}
128
129typedef struct gs_color_t
130{
131 union
132 {
133 uint8_t rgba[4];
134 struct
135 {
136 uint8_t r, g, b, a;
137 };
138 };
139} gs_color_t;
140
141gs_force_inline
142gs_color_t gs_color_ctor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
143{
144 gs_color_t color;
145 color.r = r;
146 color.g = g;
147 color.b = b;
148 color.a = a;
149 return color;
150}
151
152#define gs_color_black gs_color(0, 0, 0, 255)
153#define gs_color_white gs_color(255, 255, 255, 255)
154#define gs_color_red gs_color(255, 0, 0, 255)
155#define gs_color_green gs_color(0, 255, 0, 255)
156#define gs_color_blue gs_color(0, 0, 255, 255)
157#define gs_color_orange gs_color(255, 100, 0, 255)
158#define gs_color_purple gs_color(128, 0, 128, 255)
159
160gs_force_inline
161gs_color_t gs_color_alpha(gs_color_t c, uint8_t a)
162{
163 return gs_color(c.r, c.g, c.b, a);
164}
165
166/*============================================================
167// C primitive types
168============================================================*/
169
170#ifndef __cplusplus
171 #define false 0
172 #define true 1
173#endif
174
175#ifdef __cplusplus
176 typedef bool b8;
177#else
178 typedef _Bool bool;
179 typedef _Bool b8;
180#endif
181
182typedef size_t usize;
183
184typedef uint8_t u8;
185typedef int8_t s8;
186typedef uint16_t u16;
187typedef int16_t s16;
188typedef uint32_t u32;
189typedef int32_t s32;
190typedef s32 b32;
191typedef uint64_t u64;
192typedef int64_t s64;
193typedef float f32;
194typedef double f64;
195typedef const char* const_str;
196
197#define uint16_max UINT16_MAX
198#define uint32_max UINT32_MAX
199#define int32_max INT32_MAX
200#define float_max FLT_MAX
201#define float_min FLT_MIN
202
203/*============================================================
204// gs utils
205============================================================*/
206
207// Helper macro for compiling to nothing
208#define gs_empty_instruction(...)
209
210#define gs_array_size(arr) sizeof(arr) / sizeof(arr[0])
211
212#define gs_assert(x) if (!(x)) {\
213 gs_printf("assertion failed: (%s), function %s, file %s, line %d.\n", #x, __func__, __FILE__, __LINE__);\
214 abort();\
215}
216
217#if defined (__cplusplus)
218 #define gs_default_val() {}
219#else
220 #define gs_default_val() {0}
221#endif
222
223// Helper macro for an in place for-range loop
224#define gs_for_range_i(count)\
225 for (uint32_t i = 0; i < count; ++i)
226
227// Helper macro for an in place for-range loop
228#define gs_for_range_j(count)\
229 for (uint32_t j = 0; j < count; ++j)
230
231#define gs_for_range(iter_type, iter_name, iter_end)\
232 for(iter_type iter_name = 0; iter_name < iter_end; ++iter_name)
233
234#define gs_max(a, b) ((a) > (b) ? (a) : (b))
235
236#define gs_min(a, b) ((a) < (b) ? (a) : (b))
237
238#define gs_clamp(v, min, max) ((v) > (max) ? (max) : (v) < (min) ? (min) : (v))
239
240// Helpful macro for casting one type to another
241#define gs_cast(a, b) ((a*)(b))
242
243// Helpful marco for calculating offset (in bytes) of an element from a given structure type
244#define gs_offset(type, element) ((size_t)(&(((type*)(0))->element)))
245
246// macro for turning any given type into a const char* of itself
247#define gs_to_str(type) ((const char*)#type)
248
249#define gs_timed_action(interval, ...)\
250 do {\
251 static uin32_t __t__##__LINE__ = 0;\
252 if (__t__##__LINE__++ > interval) {\
253 __t__##__LINE__ = 0;\
254 __VA_ARGS__\
255 }\
256 } while (0)
257
258/*===================================
259// Memory Allocation Utils
260===================================*/
261
262#ifndef gs_malloc
263 #define gs_malloc(sz) malloc(sz)
264#endif
265
266#ifndef gs_free
267 #define gs_free(mem) free(mem)
268#endif
269
270#ifndef gs_realloc
271 #define gs_realloc(mem, sz) realloc(mem, sz)
272#endif
273
274#ifndef gs_calloc
275 #define gs_calloc(num, sz) calloc(num, sz)
276#endif
277
278gs_force_inline
279void* _gs_malloc_init_impl(size_t sz)
280{
281 void* data = gs_malloc(sz);
282 memset(data, 0, sz);
283 return data;
284}
285
286#define gs_malloc_init(type) (type*)_gs_malloc_init_impl(sizeof(type))
287
288/*===================================
289// String Utils
290===================================*/
291
292gs_force_inline uint32_t
293gs_string_length(const char* txt)
294{
295 uint32_t sz = 0;
296 while (txt != NULL && txt[ sz ] != '\0')
297 {
298 sz++;
299 }
300 return sz;
301}
302
303// Expects null terminated strings
304gs_force_inline b32
305gs_string_compare_equal
306(
307 const char* txt,
308 const char* cmp
309)
310{
311 // Grab sizes of both strings
312 uint32_t a_sz = gs_string_length(txt);
313 uint32_t b_sz = gs_string_length(cmp);
314
315 // Return false if sizes do not match
316 if (a_sz != b_sz)
317 {
318 return false;
319 }
320
321 for(uint32_t i = 0; i < a_sz; ++i)
322 {
323 if (*txt++ != *cmp++)
324 {
325 return false;
326 }
327 };
328
329 return true;
330}
331
332gs_force_inline b32
333gs_string_compare_equal_n
334(
335 const char* txt,
336 const char* cmp,
337 uint32_t n
338)
339{
340 uint32_t a_sz = gs_string_length(txt);
341 uint32_t b_sz = gs_string_length(cmp);
342
343 // Not enough characters to do operation
344 if (a_sz < n || b_sz < n)
345 {
346 return false;
347 }
348
349 for (uint32_t i = 0; i < n; ++i)
350 {
351 if (*txt++ != *cmp++)
352 {
353 return false;
354 }
355 };
356
357 return true;
358}
359
360gs_force_inline void
361gs_util_str_to_lower
362(
363 const char* src,
364 char* buffer,
365 size_t buffer_sz
366)
367{
368 uint32_t src_sz = gs_string_length(src);
369 uint32_t len = gs_min(src_sz, buffer_sz);
370
371 for (uint32_t i = 0; i < len; ++i) {
372 buffer[i] = tolower(src[i]);
373 }
374}
375
376gs_force_inline b32
377gs_util_str_is_numeric(const char* str)
378{
379 const char* at = str;
380 while (at && *at)
381 {
382 while (*at == '\n' || *at == '\t' || *at == ' ' || *at == '\r') at++;;
383 char c = *at++;
384 if (c >= '0' && c <= '9')
385 {
386 return false;
387 }
388 }
389
390 return true;
391}
392
393// Will return a null buffer if file does not exist or allocation fails
394gs_force_inline
395char* gs_read_file_contents_into_string_null_term
396(
397 const char* file_path,
398 const char* mode,
399 size_t* sz
400)
401{
402 char* buffer = 0;
403 FILE* fp = fopen(file_path, mode);
404 if (fp)
405 {
406 fseek(fp, 0, SEEK_END);
407 *sz = ftell(fp);
408 fseek(fp, 0, SEEK_SET);
409 buffer = (char*)gs_malloc(*sz + 1);
410 if (buffer)
411 {
412 fread(buffer, 1, *sz, fp);
413 }
414 fclose(fp);
415 buffer[ *sz ] = '0';
416 }
417 return buffer;
418}
419
420gs_force_inline
421b32 gs_util_file_exists(const char* file_path)
422{
423 FILE* fp = fopen(file_path, "r");
424 if (fp)
425 {
426 fclose(fp);
427 return true;
428 }
429 return false;
430}
431
432gs_force_inline
433void gs_util_get_file_extension
434(
435 char* buffer,
436 uint32_t buffer_size,
437 const char* file_path
438)
439{
440 uint32_t str_len = gs_string_length(file_path);
441 const char* at = (file_path + str_len - 1);
442 while (*at != '.' && at != file_path)
443 {
444 at--;
445 }
446
447 if (*at == '.')
448 {
449 at++;
450 uint32_t i = 0;
451 while (*at)
452 {
453 char c = *at;
454 buffer[ i++ ] = *at++;
455 }
456 buffer[ i ] = '\0';
457 }
458}
459
460gs_force_inline
461void gs_util_get_dir_from_file
462(
463 char* buffer,
464 uint32_t buffer_size,
465 const char* file_path
466)
467{
468 uint32_t str_len = gs_string_length(file_path);
469 const char* end = (file_path + str_len);
470 while (*end != '/' && end != file_path)
471 {
472 end--;
473 }
474 memcpy(buffer, file_path, gs_min(buffer_size, (end - file_path) + 1));
475}
476
477gs_force_inline
478void gs_util_get_file_name
479(
480 char* buffer,
481 uint32_t buffer_size,
482 const char* file_path
483)
484{
485 uint32_t str_len = gs_string_length(file_path);
486 const char* end = (file_path + str_len);
487 const char* dot_at = end;
488 while (*end != '.' && end != file_path)
489 {
490 end--;
491 }
492 const char* start = end;
493 while (*start != '/' && start != file_path)
494 {
495 start--;
496 }
497 memcpy(buffer, start, (end - start));
498}
499
500gs_force_inline
501void gs_util_string_substring
502(
503 const char* src,
504 char* dst,
505 size_t sz,
506 uint32_t start,
507 uint32_t end
508)
509{
510 uint32_t str_len = gs_string_length(src);
511 if (end > str_len) {
512 end = str_len;
513 }
514 if (start > str_len) {
515 start = str_len;
516 }
517
518 const char* at = src + start;
519 const char* e = src + end;
520 uint32_t ct = 0;
521 while (at && *at != '\0' && at != e)
522 {
523 dst[ ct ] = *at;
524 at++;
525 ct++;
526 }
527}
528
529gs_force_inline
530void gs_util_string_remove_character
531(
532 const char* src,
533 char* buffer,
534 uint32_t buffer_size,
535 char delimiter
536)
537{
538 uint32_t ct = 0;
539 uint32_t str_len = gs_string_length(src);
540 const char* at = src;
541 while (at && *at != '\0' && ct < buffer_size)
542 {
543 char c = *at;
544 if (c != delimiter) {
545 buffer[ ct ] = c;
546 ct++;
547 }
548 at++;
549 }
550}
551
552gs_force_inline
553void gs_util_string_replace
554(
555 const char* source_str,
556 char* buffer,
557 uint32_t buffer_size,
558 char delimiter,
559 char replace
560)
561{
562 uint32_t str_len = gs_string_length(source_str);
563 const char* at = source_str;
564 while (at && *at != '\0')
565 {
566 char c = *at;
567 if (c == delimiter) {
568 c = replace;
569 }
570 buffer[(at - source_str)] = c;
571 at++;
572 }
573}
574
575gs_force_inline
576void gs_util_normalize_path
577(
578 const char* path,
579 char* buffer,
580 uint32_t buffer_size
581)
582{
583 // Normalize the path somehow...
584}
585
586#ifdef __MINGW32__
587 #define gs_printf(fmt, ...) __mingw_printf(fmt, ##__VA_ARGS__)
588#else
589 gs_force_inline void
590 gs_printf
591 (
592 const char* fmt,
593 ...
594 )
595 {
596 va_list args;
597 va_start (args, fmt);
598 vprintf(fmt, args);
599 va_end(args);
600 }
601#endif
602
603#define gs_println(fmt, ...)\
604 do {\
605 gs_printf(fmt, ##__VA_ARGS__);\
606 gs_printf("\n");\
607 } while (0)
608
609gs_force_inline
610void gs_fprintf
611(
612 FILE* fp,
613 const char* fmt,
614 ...
615)
616{
617 va_list args;
618 va_start (args, fmt);
619 vfprintf(fp, fmt, args);
620 va_end(args);
621}
622
623gs_force_inline
624void gs_fprintln
625(
626 FILE* fp,
627 const char* fmt,
628 ...
629)
630{
631 va_list args;
632 va_start(args, fmt);
633 vfprintf(fp, fmt, args);
634 va_end(args);
635 gs_fprintf(fp, "\n");
636}
637
638#ifdef __MINGW32__
639#define gs_snprintf(name, size, fmt, ...) __mingw_snprintf(name, size, fmt, __VA_ARGS__)
640#else
641gs_force_inline
642void gs_snprintf
643(
644 char* buffer,
645 size_t buffer_size,
646 const char* fmt,
647 ...
648)
649{
650 va_list args;
651 va_start(args, fmt);
652 vsnprintf(buffer, buffer_size, fmt, args);
653 va_end(args);
654}
655#endif
656
657#define gs_snprintfc(name, size, fmt, ...)\
658 char name[size] = gs_default_val();\
659 gs_snprintf(name, size, fmt, __VA_ARGS__);
660
661gs_force_inline
662uint32_t gs_hash_uint32_t(uint32_t x)
663{
664 x = ((x >> 16) ^ x) * 0x45d9f3b;
665 x = ((x >> 16) ^ x) * 0x45d9f3b;
666 x = (x >> 16) ^ x;
667 return x;
668}
669
670#define gs_hash_u32_ip(x, out)\
671 do {\
672 out = ((x >> 16) ^ x) * 0x45d9f3b;\
673 out = ((out >> 16) ^ out) * 0x45d9f3b;\
674 out = (out >> 16) ^ out;\
675 } while (0)
676
677gs_force_inline
678uint32_t gs_hash_u64(uint64_t x)
679{
680 x = (x ^ (x >> 31) ^ (x >> 62)) * UINT64_C(0x319642b2d24d8ec3);
681 x = (x ^ (x >> 27) ^ (x >> 54)) * UINT64_C(0x96de1b173f119089);
682 x = x ^ (x >> 30) ^ (x >> 60);
683 return (uint32_t)x;
684}
685
686// Note(john): source: http://www.cse.yorku.ca/~oz/hash.html
687// djb2 hash by dan bernstein
688gs_force_inline
689uint32_t gs_hash_str(const char* str)
690{
691 uint32_t hash = 5381;
692 s32 c;
693 while ((c = *str++))
694 {
695 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
696 }
697 return hash;
698}
699
700gs_force_inline
701uint64_t gs_hash_str_64(const char* str)
702{
703 uint32_t hash1 = 5381;
704 uint32_t hash2 = 52711;
705 uint32_t i = gs_string_length(str);
706 while(i--)
707 {
708 char c = str[ i ];
709 hash1 = (hash1 * 33) ^ c;
710 hash2 = (hash2 * 33) ^ c;
711 }
712
713 return (hash1 >> 0) * 4096 + (hash2 >> 0);
714}
715
716bool gs_compare_bytes(void* b0, void* b1, size_t len)
717{
718 return 0 == memcmp(b0, b1, len);
719}
720
721// Hash generic bytes using (ripped directly from Sean Barret's stb_ds.h)
722#define GS_SIZE_T_BITS ((sizeof(size_t)) * 8)
723#define GS_SIPHASH_C_ROUNDS 1
724#define GS_SIPHASH_D_ROUNDS 1
725#define gs_rotate_left(val, n) (((val) << (n)) | ((val) >> (GS_SIZE_T_BITS - (n))))
726#define gs_rotate_right(val, n) (((val) >> (n)) | ((val) << (GS_SIZE_T_BITS - (n))))
727
728#ifdef _MSC_VER
729#pragma warning(push)
730#pragma warning(disable:4127) // conditional expression is constant, for do..while(0) and sizeof()==
731#endif
732
733gs_force_inline
734size_t gs_hash_siphash_bytes(void *p, size_t len, size_t seed)
735{
736 unsigned char *d = (unsigned char *) p;
737 size_t i,j;
738 size_t v0,v1,v2,v3, data;
739
740 // hash that works on 32- or 64-bit registers without knowing which we have
741 // (computes different results on 32-bit and 64-bit platform)
742 // derived from siphash, but on 32-bit platforms very different as it uses 4 32-bit state not 4 64-bit
743 v0 = ((((size_t) 0x736f6d65 << 16) << 16) + 0x70736575) ^ seed;
744 v1 = ((((size_t) 0x646f7261 << 16) << 16) + 0x6e646f6d) ^ ~seed;
745 v2 = ((((size_t) 0x6c796765 << 16) << 16) + 0x6e657261) ^ seed;
746 v3 = ((((size_t) 0x74656462 << 16) << 16) + 0x79746573) ^ ~seed;
747
748 #ifdef STBDS_TEST_SIPHASH_2_4
749 // hardcoded with key material in the siphash test vectors
750 v0 ^= 0x0706050403020100ull ^ seed;
751 v1 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed;
752 v2 ^= 0x0706050403020100ull ^ seed;
753 v3 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed;
754 #endif
755
756 #define gs_sipround() \
757 do { \
758 v0 += v1; v1 = gs_rotate_left(v1, 13); v1 ^= v0; v0 = gs_rotate_left(v0,GS_SIZE_T_BITS/2); \
759 v2 += v3; v3 = gs_rotate_left(v3, 16); v3 ^= v2; \
760 v2 += v1; v1 = gs_rotate_left(v1, 17); v1 ^= v2; v2 = gs_rotate_left(v2,GS_SIZE_T_BITS/2); \
761 v0 += v3; v3 = gs_rotate_left(v3, 21); v3 ^= v0; \
762 } while (0)
763
764 for (i=0; i+sizeof(size_t) <= len; i += sizeof(size_t), d += sizeof(size_t)) {
765 data = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
766 data |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // discarded if size_t == 4
767
768 v3 ^= data;
769 for (j=0; j < GS_SIPHASH_C_ROUNDS; ++j)
770 gs_sipround();
771 v0 ^= data;
772 }
773 data = len << (GS_SIZE_T_BITS-8);
774 switch (len - i) {
775 case 7: data |= ((size_t) d[6] << 24) << 24; // fall through
776 case 6: data |= ((size_t) d[5] << 20) << 20; // fall through
777 case 5: data |= ((size_t) d[4] << 16) << 16; // fall through
778 case 4: data |= (d[3] << 24); // fall through
779 case 3: data |= (d[2] << 16); // fall through
780 case 2: data |= (d[1] << 8); // fall through
781 case 1: data |= d[0]; // fall through
782 case 0: break;
783 }
784 v3 ^= data;
785 for (j=0; j < GS_SIPHASH_C_ROUNDS; ++j)
786 gs_sipround();
787 v0 ^= data;
788 v2 ^= 0xff;
789 for (j=0; j < GS_SIPHASH_D_ROUNDS; ++j)
790 gs_sipround();
791
792#if 0
793 return v0^v1^v2^v3;
794#else
795 return v1^v2^v3; // slightly stronger since v0^v3 in above cancels out final round operation? I tweeted at the authors of SipHash about this but they didn't reply
796#endif
797}
798
799size_t gs_hash_bytes(void *p, size_t len, size_t seed)
800{
801#if 0
802 return gs_hash_table_siphash_bytes(p,len,seed);
803#else
804 unsigned char *d = (unsigned char *) p;
805
806 // Len == 4 (off for now, so to force 64 bit hash)
807 if (false) {
808 unsigned int hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
809 hash ^= seed;
810 hash *= 0xcc9e2d51;
811 hash = (hash << 17) | (hash >> 15);
812 hash *= 0x1b873593;
813 hash ^= seed;
814 hash = (hash << 19) | (hash >> 13);
815 hash = hash*5 + 0xe6546b64;
816 hash ^= hash >> 16;
817 hash *= 0x85ebca6b;
818 hash ^= seed;
819 hash ^= hash >> 13;
820 hash *= 0xc2b2ae35;
821 hash ^= hash >> 16;
822 return (((size_t) hash << 16 << 16) | hash) ^ seed;
823 } else if (len == 8 && sizeof(size_t) == 8) {
824 size_t hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
825 hash |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // avoid warning if size_t == 4
826 hash ^= seed;
827 hash = (~hash) + (hash << 21);
828 hash ^= gs_rotate_right(hash,24);
829 hash *= 265;
830 hash ^= gs_rotate_right(hash,14);
831 hash ^= seed;
832 hash *= 21;
833 hash ^= gs_rotate_right(hash,28);
834 hash += (hash << 31);
835 hash = (~hash) + (hash << 18);
836 return hash;
837 } else {
838 return gs_hash_siphash_bytes(p,len,seed);
839 }
840#endif
841}
842#ifdef _MSC_VER
843#pragma warning(pop)
844#endif
845
846// Contained within:
847// GS_CONTAINERS
848// GS_MATH
849// GS_PLATFORM
850// GS_GRAPHICS
851// GS_AUDIO
852
853/*========================
854// GS_CONTAINERS
855========================*/
856
857/*========================
858// Byte Buffer
859========================*/
860
861#define GS_BYTE_BUFFER_DEFAULT_CAPCITY 1024
862
863typedef struct gs_byte_buffer_t
864{
865 uint8_t* data; // Buffer that actually holds all relevant byte data
866 uint32_t size; // Current size of the stored buffer data
867 uint32_t position; // Current read/write position in the buffer
868 uint32_t capacity; // Current max capacity for the buffer
869} gs_byte_buffer_t;
870
871// Generic "write" function for a byte buffer
872#define gs_byte_buffer_write(bb, T, val)\
873do {\
874 gs_byte_buffer_t* _buffer = bb;\
875 usize sz = sizeof(T);\
876 usize total_write_size = _buffer->position + sz;\
877 if (total_write_size >= _buffer->capacity)\
878 {\
879 usize capacity = _buffer->capacity * 2;\
880 while(capacity < total_write_size)\
881 {\
882 capacity *= 2;\
883 }\
884 gs_byte_buffer_resize(_buffer, capacity);\
885 }\
886 *(T*)(_buffer->data + _buffer->position) = val;\
887 _buffer->position += sz;\
888 _buffer->size += sz;\
889} while (0)
890
891// Generic "read" function
892#define gs_byte_buffer_read(_buffer, T, _val_p)\
893do {\
894 T* _v = (T*)(_val_p);\
895 gs_byte_buffer_t* _bb = (_buffer);\
896 *(_v) = *(T*)(_bb->data + _bb->position);\
897 _bb->position += sizeof(T);\
898} while (0)
899
900// Defines variable and sets value from buffer in place
901// Use to construct a new variable
902#define gs_byte_buffer_readc(_buffer, T, name)\
903 T name = gs_default_val();\
904 gs_byte_buffer_read((_buffer), T, &name);
905
906/* Desc */
907GS_API_DECL void gs_byte_buffer_init(gs_byte_buffer_t* buffer);
908
909/* Desc */
910GS_API_DECL gs_byte_buffer_t gs_byte_buffer_new();
911
912/* Desc */
913GS_API_DECL void gs_byte_buffer_free(gs_byte_buffer_t* buffer);
914
915/* Desc */
916GS_API_DECL void gs_byte_buffer_clear(gs_byte_buffer_t* buffer);
917
918/* Desc */
919GS_API_DECL void gs_byte_buffer_resize(gs_byte_buffer_t* buffer, size_t sz);
920
921/* Desc */
922GS_API_DECL void gs_byte_buffer_seek_to_beg(gs_byte_buffer_t* buffer);
923
924/* Desc */
925GS_API_DECL void gs_byte_buffer_seek_to_end(gs_byte_buffer_t* buffer);
926
927/* Desc */
928GS_API_DECL void gs_byte_buffer_advance_position(gs_byte_buffer_t* buffer, size_t sz);
929
930/* Desc */
931GS_API_DECL void gs_byte_buffer_write_str(gs_byte_buffer_t* buffer, const char* str); // Expects a null terminated string
932
933/* Desc */
934GS_API_DECL void gs_byte_buffer_read_str(gs_byte_buffer_t* buffer, char* str); // Expects an allocated string
935
936/* Desc */
937GS_API_DECL void gs_byte_buffer_bulk_write(gs_byte_buffer_t* buffer, void* src, size_t sz);
938
939/* Desc */
940GS_API_DECL void gs_byte_buffer_bulk_read(gs_byte_buffer_t* buffer, void* dst, size_t sz);
941
942/* Desc */
943GS_API_DECL gs_result gs_byte_buffer_write_to_file(gs_byte_buffer_t* buffer, const char* output_path); // Assumes that the output directory exists
944
945/* Desc */
946GS_API_DECL gs_result gs_byte_buffer_read_from_file(gs_byte_buffer_t* buffer, const char* file_path); // Assumes an allocated byte buffer
947
948/*===================================
949// Dynamic Array
950===================================*/
951
952typedef struct gs_dyn_array
953{
954 int32_t size;
955 int32_t capacity;
956} gs_dyn_array;
957
958#define gs_dyn_array_head(arr)\
959 ((gs_dyn_array*)((uint8_t*)(arr) - sizeof(gs_dyn_array)))
960
961#define gs_dyn_array_size(arr)\
962 (gs_dyn_array_head((arr))->size)
963
964#define gs_dyn_array_capacity(arr)\
965 (gs_dyn_array_head((arr))->capacity)
966
967#define gs_dyn_array_full(arr)\
968 ((gs_dyn_array_size((arr)) == gs_dyn_array_capacity((arr))))
969
970gs_inline
971void* gs_dyn_array_resize_impl(void* arr, size_t sz, size_t amount)
972{
973 size_t capacity;
974
975 if (arr) {
976 capacity = amount;
977 } else {
978 capacity = 0;
979 }
980
981 // Create new gs_dyn_array with just the header information
982 gs_dyn_array* data = (gs_dyn_array*)gs_realloc(arr ? gs_dyn_array_head(arr) : 0, capacity * sz + sizeof(gs_dyn_array));
983
984 if (data) {
985 if (!arr) {
986 data->size = 0;
987 }
988 data->capacity = capacity;
989 return ((int32_t*)data + 2);
990 }
991
992 return NULL;
993}
994
995#define gs_dyn_array_need_grow(arr, n)\
996 ((arr) == 0 || gs_dyn_array_size(arr) + n >= gs_dyn_array_capacity(arr))
997
998#define gs_dyn_array_grow(arr)\
999 gs_dyn_array_resize_impl(arr, sizeof(*(arr)), gs_dyn_array_capacity(arr) ? gs_dyn_array_capacity(arr) * 2 : 1)
1000
1001#define gs_dyn_array_push(arr, val)\
1002 do {\
1003 if (!(arr) || ((arr) && gs_dyn_array_need_grow(arr, 1))) {\
1004 *((void **)&(arr)) = gs_dyn_array_grow(arr); \
1005 }\
1006 (arr)[ gs_dyn_array_size(arr) ] = (val);\
1007 gs_dyn_array_size(arr) += 1;\
1008 } while(0)
1009
1010#define gs_dyn_array_reserve(arr, amount)\
1011 do {\
1012 if ((!arr) || amount > gs_dyn_array_capacity(arr)) {\
1013 *((void **)&(arr)) = gs_dyn_array_resize_impl(arr, sizeof(*arr), amount);\
1014 }\
1015 } while(0)
1016
1017#define gs_dyn_array_empty(arr)\
1018 (arr && (gs_dyn_array_size(arr) == 0))
1019
1020#define gs_dyn_array_pop(arr)\
1021 do {\
1022 if (arr && !gs_dyn_array_empty(arr)) {\
1023 gs_dyn_array_size(arr) -= 1;\
1024 }\
1025 } while (0)
1026
1027#define gs_dyn_array_back(arr)\
1028 *(arr + (gs_dyn_array_size(arr) ? gs_dyn_array_size(arr) - 1 : 0))
1029
1030#define gs_dyn_array_for(arr, type, iter_name)\
1031 for (type* iter_name = arr; iter_name != gs_dyn_array_back(arr); ++iter_name)
1032
1033#define gs_dyn_array_new(type)\
1034 ((type)*)gs_dyn_array_resize_impl(NULL, sizeof((type)), 0)
1035
1036#define gs_dyn_array_clear(arr)\
1037 gs_dyn_array_size(arr) = 0
1038
1039#define gs_dyn_array(type) type*
1040
1041#define gs_dyn_array_free(arr)\
1042 do {\
1043 if (arr) {\
1044 gs_free(gs_dyn_array_head(arr));\
1045 (arr) = NULL;\
1046 }\
1047 } while (0)
1048
1049/*===================================
1050// Hash Table
1051===================================*/
1052
1053#define GS_HASH_TABLE_HASH_SEED 0x31415296
1054#define GS_HASH_TABLE_INVALID_INDEX UINT32_MAX
1055
1056typedef enum gs_hash_table_entry_state
1057{
1058 gs_hash_table_entry_inactive = 0x00,
1059 gs_hash_table_entry_active = 0x01
1060} gs_hash_table_entry_state;
1061
1062#define __gs_hash_table_entry(HMK, HMV)\
1063 struct\
1064 {\
1065 HMK key;\
1066 HMV val;\
1067 gs_hash_table_entry_state state;\
1068 }
1069
1070#define gs_hash_table(HMK, HMV)\
1071 struct {\
1072 __gs_hash_table_entry(HMK, HMV)* data;\
1073 HMK tmp_key;\
1074 HMV tmp_val;\
1075 }*
1076
1077// Need a way to create a temporary key so I can take the address of it
1078
1079#define gs_hash_table_new(K, V)\
1080 NULL
1081
1082#define gs_hash_table_init(__ht, __k, __v)\
1083 do {\
1084 size_t entry_sz = sizeof(__k) + sizeof(__v) + sizeof(gs_hash_table_entry_state);\
1085 size_t ht_sz = sizeof(__k) + sizeof(__v) + sizeof(size_t);\
1086 (__ht) = gs_malloc(ht_sz);\
1087 memset((__ht), 0, ht_sz);\
1088 (__ht)->data = gs_dyn_array_resize_impl(NULL, entry_sz, 0);\
1089 } while (0)
1090
1091#define gs_hash_table_size(__ht)\
1092 ((__ht) != NULL ? gs_dyn_array_size((__ht)->data) : 0)
1093
1094#define gs_hash_table_capacity(__ht)\
1095 ((__ht) != NULL ? gs_dyn_array_capacity((__ht)->data) : 0)
1096
1097#define gs_hash_table_load_factor(__ht)\
1098 (gs_hash_table_capacity(__ht) ? (float)(gs_hash_table_size(__ht)) / (float)(gs_hash_table_capacity(__ht)) : 0.f)
1099
1100#define gs_hash_table_grow(__ht, __c)\
1101 ((__ht)->data = gs_dyn_array_resize_impl((__ht)->data, sizeof(*((__ht)->data)), (__c)))
1102
1103#define gs_hash_table_empty(__ht)\
1104 ((__ht) != NULL ? gs_dyn_array_size((__ht)->data) == 0 : true)
1105
1106#define gs_hash_table_free(__ht)\
1107 do {\
1108 if ((__ht) != NULL) {\
1109 gs_dyn_array_free((__ht)->data);\
1110 (__ht)->data = NULL;\
1111 gs_free(__ht);\
1112 (__ht) = NULL;\
1113 }\
1114 } while (0)
1115
1116// Find available slot to insert k/v pair into
1117#define gs_hash_table_insert(__ht, __hmk, __hmv)\
1118 do {\
1119 /* Check for null hash table, init if necessary */\
1120 if ((__ht) == NULL) {\
1121 gs_hash_table_init((__ht), (__hmk), (__hmv));\
1122 }\
1123 \
1124 /* Grow table if necessary */\
1125 uint32_t capacity = gs_hash_table_capacity(__ht);\
1126 float load_factor = gs_hash_table_load_factor(__ht);\
1127 if (load_factor >= 0.5f || !capacity)\
1128 {\
1129 gs_hash_table_grow(__ht, capacity ? capacity * 2 : 1);\
1130 /* Iterate through data and set state to null, from capacity -> capacity * 2 */\
1131 for (uint32_t i = capacity; i < capacity * 2; ++i) {\
1132 (__ht)->data[i].state = gs_hash_table_entry_inactive;\
1133 }\
1134 capacity = gs_hash_table_capacity(__ht);\
1135 }\
1136 \
1137 /* Get hash of key */\
1138 (__ht)->tmp_key = (__hmk);\
1139 size_t hash = gs_hash_bytes(&((__ht)->tmp_key), sizeof((__hmk)), GS_HASH_TABLE_HASH_SEED);\
1140 size_t hash_idx = hash % capacity;\
1141 (__ht)->tmp_key = (__ht)->data[hash_idx].key;\
1142 uint32_t c = 0;\
1143 \
1144 /* Find valid idx and place data */\
1145 while (\
1146 c < capacity\
1147 && hash != gs_hash_bytes(&__ht->tmp_key, sizeof(__hmk), GS_HASH_TABLE_HASH_SEED)\
1148 && __ht->data[hash_idx].state == gs_hash_table_entry_active)\
1149 {\
1150 hash_idx = ((hash_idx + 1) % capacity);\
1151 (__ht)->tmp_key = (__ht)->data[hash_idx].key;\
1152 ++c;\
1153 }\
1154 (__ht)->data[hash_idx].key = (__hmk);\
1155 (__ht)->data[hash_idx].val = (__hmv);\
1156 (__ht)->data[hash_idx].state = gs_hash_table_entry_active;\
1157 gs_dyn_array_size((__ht)->data)++;\
1158 } while (0)
1159
1160gs_force_inline
1161uint32_t get_key_index_function(void* data, void* key, size_t key_len, size_t val_len)
1162{
1163 uint32_t capacity = gs_dyn_array_capacity(data);
1164 uint32_t idx = GS_HASH_TABLE_INVALID_INDEX;
1165 uint32_t hash = gs_hash_bytes(key, key_len, GS_HASH_TABLE_HASH_SEED);
1166 uint32_t hash_idx = (hash % capacity);
1167 size_t entry_sz = (key_len + val_len + sizeof(gs_hash_table_entry_state));
1168
1169 // Iterate through data
1170 for (uint32_t i = hash_idx, c = 0; c < capacity; ++c, i = ((i + 1) % capacity))
1171 {
1172 uint32_t offset = (i * entry_sz);
1173 void* k = (data + offset);
1174 uint32_t kh = gs_hash_bytes(k, key_len, GS_HASH_TABLE_HASH_SEED);
1175 bool comp = gs_compare_bytes(k, key, key_len);
1176 gs_hash_table_entry_state state = *(gs_hash_table_entry_state*)(data + offset + (key_len + val_len));
1177 if (comp && hash == kh && state == gs_hash_table_entry_active)
1178 {
1179 idx = i;
1180 break;
1181 }
1182 }
1183 return idx;
1184}
1185
1186// Get key at index
1187#define gs_hash_table_getk(__ht, __i)\
1188 (((__ht))->data[(__i) % gs_hash_table_capacity((__ht))].key)
1189
1190// Get val at index
1191#define gs_hash_table_geti(__ht, __i)\
1192 (((__ht)->data[(__i) % gs_hash_table_capacity(__ht)].val))
1193
1194// Could search for the index in the macro instead now. Does this help me?
1195#define gs_hash_table_get(__ht, __k)\
1196 ((__ht)->tmp_key = (__k),\
1197 (gs_hash_table_geti((__ht),\
1198 get_key_index_function((__ht)->data, (void*)&((__ht)->tmp_key), sizeof(__k), sizeof((__ht)->tmp_val)))))
1199
1200#define gs_hash_table_key_exists(__ht, __k)\
1201 ((__ht)->tmp_key = (__k),\
1202 (get_key_index_function((__ht)->data, (void*)&((__ht)->tmp_key), sizeof(__k), sizeof((__ht)->tmp_val))) != GS_HASH_TABLE_INVALID_INDEX)
1203
1204#define gs_hash_table_erase(__ht, __k)\
1205 do {\
1206 /* Get idx for key */\
1207 (__ht)->tmp_key = (__k);\
1208 uint32_t idx = get_key_index_function((__ht)->data, (void*)&((__ht)->tmp_key), sizeof(__k), sizeof((__ht)->tmp_val));\
1209 if (idx != GS_HASH_TABLE_INVALID_INDEX) {\
1210 (__ht)->data[idx].state = gs_hash_table_entry_inactive;\
1211 }\
1212 } while (0)
1213
1214/*===== Hash Table Iterator ====*/
1215
1216typedef uint32_t gs_hash_table_iter;
1217
1218gs_force_inline
1219uint32_t __gs_find_first_valid_iterator(void* data, size_t key_len, size_t val_len)
1220{
1221 uint32_t it = 0;
1222 size_t entry_sz = (key_len + val_len + sizeof(gs_hash_table_entry_state));
1223 for (; it < gs_dyn_array_capacity(data); ++it)
1224 {
1225 uint32_t offset = (it * entry_sz);
1226 gs_hash_table_entry_state state = *(gs_hash_table_entry_state*)(data + offset + (key_len + val_len));
1227 if (state == gs_hash_table_entry_active)
1228 {
1229 break;
1230 }
1231 }
1232 return it;
1233}
1234
1235/* Find first valid iterator idx */
1236#define gs_hash_table_iter_new(__ht)\
1237 (__gs_find_first_valid_iterator((__ht)->data, sizeof(__ht)->tmp_key, sizeof(__ht)->tmp_val))
1238
1239
1240#define gs_hash_table_iter_valid(__ht, __it)\
1241 ((__it) < gs_hash_table_capacity((__ht)))
1242
1243// Have to be able to do this for hash table...
1244gs_force_inline
1245void __gs_hash_table_iter_advance_func(void* data, size_t key_len, size_t val_len, uint32_t* it)
1246{
1247 size_t entry_sz = (key_len + val_len + sizeof(gs_hash_table_entry_state));
1248
1249 (*it)++;
1250 for (; *it < gs_dyn_array_capacity(data); ++*it)
1251 {
1252 uint32_t offset = (*it * entry_sz);
1253 gs_hash_table_entry_state state = *(gs_hash_table_entry_state*)(data + offset + (key_len + val_len));
1254 if (state == gs_hash_table_entry_active)
1255 {
1256 break;
1257 }
1258 }
1259}
1260
1261#define gs_hash_table_iter_advance(__ht, __it)\
1262 __gs_hash_table_iter_advance_func((__ht)->data, sizeof(__ht)->tmp_key, sizeof(__ht)->tmp_val, &(__it))
1263
1264/*===================================
1265// Slot Array
1266===================================*/
1267
1268#define GS_SLOT_ARRAY_INVALID_HANDLE UINT32_MAX
1269
1270#define gs_slot_array_handle_valid(__sa, __id)\
1271 (__id < gs_dyn_array_size((__sa)->indices) && (__sa)->indices[__id] != GS_SLOT_ARRAY_INVALID_HANDLE)
1272
1273typedef struct __gs_slot_array_dummy_header {
1274 gs_dyn_array(uint32_t) vals[2];
1275 uint32_t idx;
1276} __gs_slot_array_dummy_header;
1277
1278#define __gs_slot_array_header(T)\
1279 struct\
1280 {\
1281 gs_dyn_array(uint32_t) indices;\
1282 gs_dyn_array(T) data;\
1283 /* Try to get rid of this */\
1284 uint32_t free_idx;\
1285 }
1286
1287#define gs_slot_array(T)\
1288 __gs_slot_array_header(T)*
1289
1290#define gs_slot_array_new(T)\
1291 NULL
1292
1293gs_force_inline
1294uint32_t __gs_slot_array_find_next_available_index(gs_dyn_array(uint32_t) indices, uint32_t* idx_p)
1295{
1296 uint32_t idx = GS_SLOT_ARRAY_INVALID_HANDLE;
1297 for (uint32_t i = 0; i < gs_dyn_array_size(indices); ++i)
1298 {
1299 uint32_t handle = indices[i];
1300 if (handle == GS_SLOT_ARRAY_INVALID_HANDLE)
1301 {
1302 idx = i;
1303 break;
1304 }
1305 }
1306 if (idx == GS_SLOT_ARRAY_INVALID_HANDLE)
1307 {
1308 idx = gs_dyn_array_size(indices);
1309 }
1310
1311 *idx_p = idx;
1312 return idx;
1313}
1314
1315// Figure out a better way to do this
1316// Evals to rvalue
1317#define gs_slot_array_insert(__sa, __sav)\
1318 (__sa == NULL ? 0 : __gs_slot_array_find_next_available_index(__sa->indices, &__sa->free_idx));\
1319 do {\
1320 if ((__sa) == NULL) {\
1321 (__sa) = gs_malloc(sizeof(__gs_slot_array_dummy_header));\
1322 memset((__sa), 0, sizeof(__gs_slot_array_dummy_header));\
1323 (__sa)->indices = gs_dyn_array_resize_impl(NULL, sizeof(uint32_t), 0);\
1324 (__sa)->data = gs_dyn_array_resize_impl(NULL, sizeof((__sav)), 0);\
1325 (__sa)->free_idx = 0;\
1326 }\
1327 if ((__sa)->free_idx == gs_dyn_array_size((__sa)->indices)) {\
1328 gs_dyn_array_push((__sa)->indices, 0);\
1329 }\
1330 gs_dyn_array_push((__sa)->data, (__sav));\
1331 (__sa)->indices[(__sa)->free_idx] = gs_dyn_array_size((__sa)->data) - 1;\
1332 } while (0)
1333
1334#define gs_slot_array_size(__sa)\
1335 ((__sa) == NULL ? 0 : gs_dyn_array_size((__sa)->data))
1336
1337#define gs_slot_array_clear(__sa)\
1338 do {\
1339 if ((__sa) != NULL) {\
1340 gs_dyn_array_clear((__sa)->data);\
1341 gs_dyn_array_clear((__sa)->indices);\
1342 (__sa)->free_idx = 0;\
1343 }\
1344 } while (0)
1345
1346 #define gs_slot_array_get(__sa, __sid)\
1347 ((__sa)->data[(__sa)->indices[(__sid)]])
1348
1349 #define gs_slot_array_getp(__sa, __sid)\
1350 (&(gs_slot_array_get(__sa, (__sid))))
1351
1352 #define gs_slot_array_free(__sa)\
1353 do {\
1354 if ((__sa) != NULL) {\
1355 gs_dyn_array_free((__sa)->data);\
1356 gs_dyn_array_free((__sa)->indices);\
1357 (__sa)->indices = NULL;\
1358 (__sa)->data = NULL;\
1359 gs_free(__sa);\
1360 (__sa) = NULL;\
1361 }\
1362 } while (0)
1363
1364 #define gs_slot_array_erase(__sa, __id)\
1365 do {\
1366 if (gs_slot_array_size(__sa) == 1) {\
1367 gs_slot_array_clear(__sa);\
1368 }\
1369 else if (!gs_slot_array_handle_valid(__sa, __id)) {\
1370 gs_println("Warning: Attempting to erase invalid slot array handle (%zu)", __id);\
1371 }\
1372 else {\
1373 uint32_t og_data_idx = (__sa)->indices[__id];\
1374 /* Iterate through handles until last index of data found */\
1375 uint32_t __h = 0;\
1376 for (uint32_t i = 0; i < gs_dyn_array_size((__sa)->indices); ++i)\
1377 {\
1378 if ((__sa)->indices[i] == gs_dyn_array_size((__sa)->data) - 1)\
1379 {\
1380 __h = i;\
1381 break;\
1382 }\
1383 }\
1384 \
1385 /* Swap and pop data */\
1386 (__sa)->data[og_data_idx] = gs_dyn_array_back((__sa)->data);\
1387 gs_dyn_array_pop((__sa)->data);\
1388 \
1389 /* Point new handle, Set og handle to invalid */\
1390 (__sa)->indices[__h] = og_data_idx;\
1391 (__sa)->indices[__id] = GS_SLOT_ARRAY_INVALID_HANDLE;\
1392 }\
1393 } while (0)
1394
1395#define gs_slot_array(T)\
1396 __gs_slot_array_header(T)*
1397
1398#define gs_slot_array_new(T)\
1399 NULL
1400
1401/*=== Slot Array Iterator ===*/
1402
1403// Slot array iterator new
1404typedef uint32_t gs_slot_array_iter;
1405
1406#define gs_slot_array_iter_valid(__sa, __it)\
1407 ((__it) < gs_dyn_array_size((__sa)->indices))
1408
1409gs_force_inline
1410void __gs_slot_array_iter_advance_func(gs_dyn_array(uint32_t) indices, uint32_t* it)
1411{
1412 (*it)++;
1413 for (; *it < gs_dyn_array_size(indices); ++*it)
1414 {\
1415 if (indices[*it] != GS_SLOT_ARRAY_INVALID_HANDLE)\
1416 {\
1417 break;\
1418 }\
1419 }\
1420}
1421
1422#define gs_slot_array_iter_advance(__sa, __it)\
1423 __gs_slot_array_iter_advance_func((__sa)->indices, &(__it))
1424
1425/*===================================
1426// Slot Map
1427===================================*/
1428
1429#define gs_slot_map(SMK, SMV)\
1430 struct {\
1431 gs_hash_table(SMK, uint32_t) ht;\
1432 gs_slot_array(SMV) sa;\
1433 }*
1434
1435#define gs_slot_map_insert(__sm, __smk, __smv)\
1436 do {\
1437 if ((__sm) == NULL) {\
1438 (__sm) = gs_malloc(sizeof(size_t) * 2);\
1439 memset((__sm), 0, sizeof(size_t) * 2);\
1440 }\
1441 uint32_t h = gs_slot_array_insert((__sm)->sa, (__smv));\
1442 gs_hash_table_insert((__sm)->ht, (__smk), h);\
1443 for (\
1444 gs_hash_table_iter it = gs_hash_table_iter_new(__sm->ht);\
1445 gs_hash_table_iter_valid(__sm->ht, it);\
1446 gs_hash_table_iter_advance(__sm->ht, it))\
1447 {\
1448 uint32_t v = gs_hash_table_geti(sm->ht, it);\
1449 }\
1450 } while (0)
1451
1452#define gs_slot_map_get(__sm, __smk)\
1453 ((__sm)->sa->data[gs_hash_table_get((__sm)->ht, (__smk))])
1454
1455#define gs_slot_map_getp(__sm, __smk)\
1456 gs_slot_array_getp((__sm)->sa, gs_hash_table_get((__sm)->ht, (__smk)))
1457
1458/*===================================
1459// Command Buffer
1460===================================*/
1461
1462typedef struct gs_command_buffer_t
1463{
1464 u32 num_commands;
1465 gs_byte_buffer_t commands;
1466} gs_command_buffer_t;
1467
1468gs_force_inline
1469gs_command_buffer_t gs_command_buffer_new()
1470{
1471 gs_command_buffer_t cb = gs_default_val();
1472 cb.commands = gs_byte_buffer_new();
1473 return cb;
1474}
1475
1476#define gs_command_buffer_write(cb, T, val)\
1477 do {\
1478 gs_byte_buffer_write(&cb->commands, T, val);\
1479 cb->num_commands++;\
1480 } while (0)
1481
1482gs_force_inline
1483void gs_command_buffer_clear(gs_command_buffer_t* cb)
1484{
1485 cb->num_commands = 0;
1486 gs_byte_buffer_clear(&cb->commands);
1487}
1488
1489gs_force_inline
1490void gs_command_buffer_free(gs_command_buffer_t* cb)
1491{
1492 gs_byte_buffer_free(&cb->commands);
1493}
1494
1495/*========================
1496// GS_PLATFORM
1497========================*/
1498
1499/*============================================================
1500// Platform Time
1501============================================================*/
1502
1503typedef struct gs_platform_time_t
1504{
1505 f64 max_fps;
1506 f64 current;
1507 f64 previous;
1508 f64 update;
1509 f64 render;
1510 f64 delta;
1511 f64 frame;
1512} gs_platform_time_t;
1513
1514/*============================================================
1515// Platform UUID
1516============================================================*/
1517
1518#define GS_UUID_STR_SIZE_CONSTANT 32
1519
1520// 33 characters, all set to 0
1521#define gs_uuid_temp_str_buffer()\
1522 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
1523
1524typedef struct gs_uuid_t
1525{
1526 const char* id;
1527 uint8_t bytes[16];
1528} gs_uuid_t;
1529
1530/*===== Gunslinger Implementation =================*/
1531
1532#ifdef GS_IMPL
1533
1534/*========================
1535// gs_byte_buffer
1536========================*/
1537
1538void gs_byte_buffer_init(gs_byte_buffer_t* buffer)
1539{
1540 buffer->data = gs_malloc(GS_BYTE_BUFFER_DEFAULT_CAPCITY);
1541 buffer->capacity = GS_BYTE_BUFFER_DEFAULT_CAPCITY;
1542 buffer->size = 0;
1543 buffer->position = 0;
1544}
1545
1546gs_byte_buffer_t gs_byte_buffer_new()
1547{
1548 gs_byte_buffer_t buffer;
1549 gs_byte_buffer_init(&buffer);
1550 return buffer;
1551}
1552
1553void gs_byte_buffer_free(gs_byte_buffer_t* buffer)
1554{
1555 if (buffer && buffer->data) {
1556 gs_free(buffer->data);
1557 }
1558}
1559
1560void gs_byte_buffer_clear(gs_byte_buffer_t* buffer)
1561{
1562 buffer->size = 0;
1563 buffer->position = 0;
1564}
1565
1566void gs_byte_buffer_resize(gs_byte_buffer_t* buffer, size_t sz)
1567{
1568 uint8_t* data = gs_realloc(buffer->data, sz);
1569
1570 if (data == NULL) {
1571 return;
1572 }
1573
1574 buffer->data = data;
1575 buffer->capacity = sz;
1576}
1577
1578void gs_byte_buffer_seek_to_beg(gs_byte_buffer_t* buffer)
1579{
1580 buffer->position = 0;
1581}
1582
1583void gs_byte_buffer_seek_to_end(gs_byte_buffer_t* buffer)
1584{
1585 buffer->position = buffer->size;
1586}
1587
1588void gs_byte_buffer_advance_position(gs_byte_buffer_t* buffer, size_t sz)
1589{
1590 buffer->position += sz;
1591}
1592
1593void gs_byte_buffer_bulk_write(gs_byte_buffer_t* buffer, void* src, size_t size)
1594{
1595 // Check for necessary resize
1596 u32 total_write_size = buffer->position + size;
1597 if (total_write_size >= buffer->capacity)
1598 {
1599 size_t capacity = buffer->capacity * 2;
1600 while(capacity <= total_write_size)
1601 {
1602 capacity *= 2;
1603 }
1604
1605 gs_byte_buffer_resize(buffer, capacity);
1606 }
1607
1608 // memcpy data
1609 memcpy((buffer->data + buffer->position), src, size);
1610
1611 buffer->size += size;
1612 buffer->position += size;
1613}
1614
1615void gs_byte_buffer_bulk_read(gs_byte_buffer_t* buffer, void* dst, size_t size)
1616{
1617 memcpy(dst, (buffer->data + buffer->position), size);
1618 buffer->position += size;
1619}
1620
1621void gs_byte_buffer_write_str(gs_byte_buffer_t* buffer, const char* str)
1622{
1623 // Write size of string
1624 uint32_t str_len = gs_string_length(str);
1625 gs_byte_buffer_write(buffer, uint16_t, str_len);
1626
1627 size_t i;
1628 for (i = 0; i < str_len; ++i)
1629 {
1630 gs_byte_buffer_write(buffer, uint8_t, str[i]);
1631 }
1632}
1633
1634void gs_byte_buffer_read_str(gs_byte_buffer_t* buffer, char* str)
1635{
1636 // Read in size of string from buffer
1637 uint16_t sz;
1638 gs_byte_buffer_read(buffer, uint16_t, &sz);
1639
1640 u32 i;
1641 for (i = 0; i < sz; ++i)
1642 {
1643 gs_byte_buffer_read(buffer, uint8_t, &str[i]);
1644 }
1645 str[i] = '\0';
1646}
1647
1648gs_result
1649gs_byte_buffer_write_to_file
1650(
1651 gs_byte_buffer_t* buffer,
1652 const char* output_path
1653)
1654{
1655 FILE* fp = fopen(output_path, "wb");
1656 if (fp)
1657 {
1658 s32 ret = fwrite(buffer->data, sizeof(u8), buffer->size, fp);
1659 if (ret == buffer->size)
1660 {
1661 return gs_result_success;
1662 }
1663 }
1664 return gs_result_failure;
1665}
1666
1667gs_result
1668gs_byte_buffer_read_from_file
1669(
1670 gs_byte_buffer_t* buffer,
1671 const char* file_path
1672)
1673{
1674 buffer->data = (u8*)gs_read_file_contents_into_string_null_term(file_path, "rb", (usize*)&buffer->size);
1675 if (!buffer->data) {
1676 gs_assert(false);
1677 return gs_result_failure;
1678 }
1679 buffer->position = 0;
1680 buffer->capacity = buffer->size;
1681 return gs_result_success;
1682}
1683
1684#ifdef __cplusplus
1685}
1686#endif // c++
1687
1688#endif // GS_IMPL
1689#endif // __GS_INCLUDED_H__
1690
1691