aboutsummaryrefslogtreecommitdiffstats
path: root/gb.h
blob: 29b1406204b58bc937ea35a15f3bbac26f9c7628 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
/* gb.h - v0.01 - public domain C89/C99 helper library - no warranty implied; use at your own risk */
/* (Experimental) A C89/99 helper library geared towards game development */

/*
 * LICENSE
 *  	This software is in the public domain. Where that dedication is not
 *  	recognized, you are granted a perpetual, irrevocable license to copy,
 *  	distribute, and modify this file as you see fit.
 *
 * WARNING
 * 	- This library is _highly_ experimental and features may not work as expected.
 * 	- This also means that many functions are not documented.
 *
 */

#ifndef GB_INCLUDE_GB_H
#define GB_INCLUDE_GB_H

#if defined(__cplusplus)
extern "C" {
#endif /* extern "C" */

/* NOTE(bill): Because static means three different things in C/C++
 *             Great Design(!)
 */
#ifndef global_variable
#define global_variable  static
#define internal_linkage static
#define local_persist    static
#endif

/* Example for static defines

	global_variable const f32 TAU = 6.283185f;
	global_variable void* g_memory;

	internal_linkage void
	some_function(...)
	{
		local_persist u32 count = 0;
		...
		count++;
		...
	}
*/


#if defined(_MSC_VER)
	#define _ALLOW_KEYWORD_MACROS

	#ifndef alignof /* Needed for MSVC 2013 'cause Microsoft "loves" standards */
	#define alignof(x) __alignof(x)
	#endif
#endif

/*
 * System OS
 */
#if defined(_WIN32) || defined(_WIN64)
	#ifndef GB_SYSTEM_WINDOWS
	#define GB_SYSTEM_WINDOWS 1
	#endif
#elif defined(__APPLE__) && defined(__MACH__)
	#ifndef GB_SYSTEM_OSX
	#define GB_SYSTEM_OSX 1
	#endif
#elif defined(__unix__)
	#ifndef GB_SYSTEM_UNIX
	#define GB_SYSTEM_UNIX 1
	#endif

	#if defined(__linux__)
		#ifndef GB_SYSTEM_LINUX
		#define GB_SYSTEM_LINUX 1
		#endif
	#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
		#ifndef GB_SYSTEM_FREEBSD
		#define GB_SYSTEM_FREEBSD 1
		#endif
	#else
		#error This UNIX operating system is not supported by gb.hpp
	#endif
#else
	#error This operating system is not supported by gb.hpp
#endif


#if defined(_MSC_VER)
	/* Microsoft Visual Studio */
	#define GB_COMPILER_MSVC 1
#elif defined(__clang__)
	/* Clang */
	#define GB_COMPILER_CLANG 1
#elif defined(__GNUC__) || defined(__GNUG__) && !(defined(__clang__) || defined(__INTEL_COMPILER))
	/* GNU GCC/G++ Compiler */
	#define GB_COMPILER_GNU_GCC 1
#elif defined(__INTEL_COMPILER)
	/* Intel C++ Compiler */
	#define GB_COMPILER_INTEL 1
#endif

/* Environment Bit Size */
#if defined(_WIN32) || defined(_WIN64)
	#if defined(_WIN64)
		#ifndef GB_ARCH_64_BIT
		#define GB_ARCH_64_BIT 1
		#endif
	#else
		#ifndef GB_ARCH_32_BIT
		#define GB_ARCH_32_BIT 1
		#endif
	#endif
#endif

/* TODO(bill): Check if this works on clang */
#if defined(__GNUC__)
	#if defined(__x86_64__) || defined(__ppc64__)
		#ifndef GB_ARCH_64_BIT
		#define GB_ARCH_64_BIT 1
		#endif
	#else
		#ifndef GB_ARCH_32_BIT
		#define GB_ARCH_32_BIT 1
		#endif
	#endif
#endif


#ifndef GB_EDIAN_ORDER
#define GB_EDIAN_ORDER
	#define GB_IS_BIG_EDIAN    (!*(unsigned char *)&(unsigned short){1})
	#define GB_IS_LITTLE_EDIAN (!GB_IS_BIG_EDIAN)
#endif

#define GB_IS_POWER_OF_TWO(x) ((x) != 0) && !((x) & ((x) - 1))


#if !defined(GB_HAS_NO_CONSTEXPR)
	#if defined(_GNUC_VER) && _GNUC_VER < 406  /* Less than gcc 4.06 */
		#define GB_HAS_NO_CONSTEXPR 1
	#elif defined(_MSC_VER) && _MSC_VER < 1900 /* Less than Visual Studio 2015/MSVC++ 14.0 */
		#define GB_HAS_NO_CONSTEXPR 1
	#elif !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L
		#define GB_HAS_NO_CONSTEXPR 1
	#endif
#endif

#if defined(GB_HAS_NO_CONSTEXPR)
	#define GB_CONSTEXPR
#else
	#define GB_CONSTEXPR constexpr
#endif

#ifndef GB_FORCE_INLINE
	#if defined(_MSC_VER)
		#define GB_FORCE_INLINE __forceinline
	#else
		#define GB_FORCE_INLINE __attribute__ ((__always_inline__))
	#endif
#endif

#include <math.h>
#include <stdio.h>
#include <assert.h>

#if defined(GB_SYSTEM_WINDOWS)
	#define NOMINMAX            1
	#define VC_EXTRALEAN        1
	#define WIN32_EXTRA_LEAN    1
	#define WIN32_LEAN_AND_MEAN 1

	#include <windows.h> /* TODO(bill): Should we include only the needed headers? */
	#include <mmsystem.h> /* Time functions */

	#undef NOMINMAX
	#undef VC_EXTRALEAN
	#undef WIN32_EXTRA_LEAN
	#undef WIN32_LEAN_AND_MEAN

	#include <intrin.h>
#else
	#include <pthread.h>
	#include <sys/time.h>
#endif

#ifndef true
#define true  (0==0)
#define false (0!=0)
#endif

#ifndef NULL
#define NULL ((void *)0)
#endif

#if !defined(GB_NO_DEBUG)
	/* TODO(bill): Do a better assert */
	#define GB_ASSERT(cond) assert(cond)
#else
	#define GB_ASSERT(cond) ((void)(cond))
#endif

#define GB_STATIC_ASSERT(COND, MSG) typedef char gb__static_assertion_##MSG[(!!(COND))*2-1]
// token pasting madness:
#define GB_COMPILE_TIME_ASSERT3(cond, line) GB_STATIC_ASSERT(cond, static_assertion_at_line_##line)
#define GB_COMPILE_TIME_ASSERT2(cond, line) GB_COMPILE_TIME_ASSERT3(cond, line)
#define GB_COMPILE_TIME_ASSERT(cond)        GB_COMPILE_TIME_ASSERT2(cond, __LINE__)
/* snprintf_msvc */
#if defined(_MSC_VER)
	int gb__vsnprintf_compatible(char *buffer, size_t size, const char *format, va_list args)
	{
		int result = -1;
		if (size > 0) result = _vsnprintf_s(buffer, size, _TRUNCATE, format, args);
		if (result == -1) return _vscprintf(format, args);
		return result;
	}

	int gb__snprintf_compatible(char *buffer, size_t size, const char *format, ...)
	{
		va_list args;
		va_start(args, format);
		int result = gb__vsnprintf_compatible(buffer, size, format, args);
		va_end(args);
		return result;
	}

	#if !defined(GB_DO_NOT_USE_MSVC_SPRINTF_FIX)
		#define snprintf  gb__snprintf_compatible
		#define vsnprintf gb__vsnprintf_compatible
	#endif /* GB_DO_NOT_USE_MSVC_SPRINTF_FIX */
#endif

#if defined(_MSC_VER)
	typedef unsigned __int8  u8;
	typedef   signed __int8  s8;
	typedef unsigned __int16 u16;
	typedef   signed __int16 s16;
	typedef unsigned __int32 u32;
	typedef   signed __int32 s32;
	typedef unsigned __int64 u64;
	typedef   signed __int64 s64;
#else
	typedef uint8_t  u8;
	typedef  int8_t  s8;
	typedef uint16_t u16;
	typedef  int16_t s16;
	typedef uint32_t u32;
	typedef  int32_t s32;
	typedef uint64_t u64;
	typedef  int64_t s64;
#endif

GB_COMPILE_TIME_ASSERT(sizeof(s8)==1);
GB_COMPILE_TIME_ASSERT(sizeof(s16)==2);
GB_COMPILE_TIME_ASSERT(sizeof(s32)==4);
GB_COMPILE_TIME_ASSERT(sizeof(s64)==8);

typedef float  f32;
typedef double f64;

typedef s32 bool32;

#if defined(GB_ARCH_32_BIT)
	typedef u32 usize;
	typedef s32 ssize;
#elif defined(GB_ARCH_64_BIT)
	typedef u64 usize;
	typedef s64 ssize;
#else
	#error Unknown architecture bit size
#endif

typedef uintptr_t uintptr;
typedef intptr_t  intptr;
typedef ptrdiff_t ptrdiff;

#define U8_MIN 0u
#define U8_MAX 0xffu
#define S8_MIN (-0x7f - 1)
#define S8_MAX 0x7f

#define U16_MIN 0u
#define U16_MAX 0xffffu
#define S16_MIN (-0x7fff - 1)
#define S16_MAX 0x7fff

#define U32_MIN 0u
#define U32_MAX 0xffffffffu
#define S32_MIN (-0x7fffffff - 1)
#define S32_MAX 0x7fffffff

#define U64_MIN 0ull
#define U64_MAX 0xffffffffffffffffull
#define S64_MIN (-0x7fffffffffffffffll - 1)
#define S64_MAX 0x7fffffffffffffffll

#if defined(GB_ARCH_64_BIT) && !defined(GB_USIZE_MIX)
	#define USIZE_MIX U64_MIN
	#define USIZE_MAX U64_MAX

	#define SSIZE_MIX S64_MIN
	#define SSIZE_MAX S64_MAX
#elif defined(GB_ARCH_32_BIT) && !defined(GB_USIZE_MIX)
	#define USIZE_MIX U32_MIN
	#define USIZE_MAX U32_MAX

	#define SSIZE_MIX S32_MIN
	#define SSIZE_MAX S32_MAX
#endif

/* Casts */
/* NOTE(bill): Easier to grep/find for casts */
#define cast(Type, var) ((Type)(var))

/*
 * Memory
 */

#define ARRAY_COUNT(x) ((sizeof(x)/sizeof(0[x])) / (cast(size_t, !(sizeof(x) % sizeof(0[x])))))

#define KILOBYTES(x) (         (x) * 1024ll)
#define MEGABYTES(x) (KILOBYTES(x) * 1024ll)
#define GIGABYTES(x) (MEGABYTES(x) * 1024ll)
#define TERABYTES(x) (GIGABYTES(x) * 1024ll)


typedef struct Mutex {
#if defined(GB_SYSTEM_WINDOWS)
	HANDLE win32_mutex;
#else
	pthread_mutex_t posix_mutex;
#endif
} Mutex;

Mutex  mutex_make(void);
void   mutex_destroy(Mutex *mutex);
void   mutex_lock(Mutex *mutex);
bool32 mutex_try_lock(Mutex *mutex);
void   mutex_unlock(Mutex *mutex);


typedef struct Atomic32 { u32 nonatomic; } Atomic32;
typedef struct Atomic64 { u64 nonatomic; } Atomic64;

u32  atomic32_load(const volatile Atomic32 *a);
void atomic32_store(volatile Atomic32 *a, u32 value);
u32 atomic32_compare_exchange_strong(volatile Atomic32 *a, u32 expected, u32 desired);
u32 atomic32_exchanged(volatile Atomic32 *a, u32 desired);
u32 atomic32_fetch_add(volatile Atomic32 *a, s32 desired);
u32 atomic32_fetch_and(volatile Atomic32 *a, u32 desired);
u32 atomic32_fetch_or(volatile Atomic32 *a, u32 desired);

u64  atomic64_load(const volatile Atomic64 *a);
void atomic64_store(volatile Atomic64 *a, u64 value);
u64 atomic64_compare_exchange_strong(volatile Atomic64 *a, u64 expected, u64 desired);
u64 atomic64_exchanged(volatile Atomic64 *a, u64 desired);
u64 atomic64_fetch_add(volatile Atomic64 *a, s64 desired);
u64 atomic64_fetch_and(volatile Atomic64 *a, u64 desired);
u64 atomic64_fetch_or(volatile Atomic64 *a, u64 desired);





typedef struct Semaphore {
#if defined(GB_SYSTEM_WINDOWS)
	HANDLE win32_handle;
#else
	Mutex          mutex;
	pthread_cond_t cond;
	s32            count;
#endif
} Semaphore;

Semaphore semaphore_make(void);
void semaphore_destroy(Semaphore *s);
void semaphore_post(Semaphore *s);
void semaphore_post_count(Semaphore *s, u32 count);
void semaphore_wait(Semaphore *s);





typedef void(Thread_Procedure)(void*);

typedef struct Thread {
#if defined(GB_SYSTEM_WINDOWS)
	HANDLE win32_handle;
#else
	pthread_t posix_handle;
#endif

	Thread_Procedure *functions;
	void             *data;

	Semaphore semaphore;
	usize     stack_size;
	bool32    is_running;
} Thread;

Thread thread_make(void);
void   thread_destroy(Thread* t);
void   thread_start(Thread* t, Thread_Procedure *func, void *data);
void   thread_start_with_stack(Thread* t, Thread_Procedure *func, void *data, usize stack_size);
void   thread_join(Thread* t);
bool32 thread_is_running(const Thread* t); /* NOTE(bill): Can this be just pass by value? */

u32 thread_current_id(void);





/* Default aligment for memory allocations */
#ifndef GB_DEFAULT_ALIGNMENT
#define GB_DEFAULT_ALIGNMENT 8
#endif

typedef struct Allocator {
	/* Allocates the specified amount of memory aligned to the specified alignment */
	void *(*alloc)(struct Allocator *a, usize size, usize align);

	/* Deallocates an allocation made with alloc() */
	void (*dealloc)(struct Allocator *a, void *ptr);

	/* Returns the amount of usuable memory allocated at `ptr`.
	 * If the allocator does not support tracking of the allocation size,
	 * the function will return -1
	 */
	s64 (*allocated_size)(struct Allocator *a, const void *ptr);

	/* Returns the total amount of memory allocated by this allocator */
	/* If the allocator does not track memory, the function will return -1 */
	s64 (*total_allocated)(struct Allocator *a);
} Allocator;

void *alloc_align(Allocator *a, usize size, usize align) { GB_ASSERT(a != NULL); return a->alloc(a, size, align); }
void *alloc(Allocator *a, usize size) { GB_ASSERT(a != NULL); return alloc_align(a, size, GB_DEFAULT_ALIGNMENT); }

#define alloc_struct(allocator, Type)       cast(Type *, alloc_align(allocator, sizeof(Type), alignof(Type)))
#define alloc_array(allocator, Type, count) cast(Type *, alloc_align(allocator, sizeof(Type)*(count), alignof(Type)))

void dealloc(Allocator *a, void *ptr) { GB_ASSERT(a != NULL); if (ptr) a->dealloc(a, ptr); }

s64 allocated_size(Allocator *a, const void *ptr) { GB_ASSERT(a != NULL); return a->allocated_size(a, ptr); }
s64 total_allocated(Allocator *a) { GB_ASSERT(a != NULL); return a->total_allocated(a); }




typedef struct Heap {
	Allocator base; /* NOTE(bill): Must be first into order to allow for polymorphism */

	Mutex  mutex;
	bool32 use_mutex;
	s64 total_allocated_count;
	s64 allocation_count;

#if defined(GB_SYSTEM_WINDOWS)
	HANDLE win32_heap_handle;
#endif
} Heap;

Heap heap_make(bool32 use_mutex);
void heap_destroy(Heap *heap);


typedef struct Arena {
	Allocator base; /* NOTE(bill): Must be first into order to allow for polymorphism */

	Allocator *backing;
	void      *physical_start;
	s64        total_size;
	s64        total_allocated_count;
	s64        temp_count;
} Arena;


Arena arena_make_from_backing(Allocator *backing, usize size);
Arena arena_make_from_pointer(void *start, usize size);
void  arena_destroy(Arena *arena);
void  arena_clear(Arena *arena);


typedef struct Temporary_Arena_Memory {
	Arena *arena;
	s64    original_count;
} Temporary_Arena_Memory;

Temporary_Arena_Memory make_temporary_arena_memory(Arena *arena);
void temporary_arena_memory_free(Temporary_Arena_Memory t);


typedef struct Pool {
	Allocator base; /* NOTE(bill): Must be first into order to allow for polymorphism */

	Allocator *backing;

	void *physical_start;
	void *free_list;

	usize block_size;
	usize block_align;
	s64   total_size;
} Pool;

Pool pool_make(Allocator *backing, usize num_blocks, usize block_size);
Pool pool_make_align(Allocator *backing, usize num_blocks, usize block_size, usize block_align);
void pool_destroy(Pool *pool);



/*
 * Memory
 */
void *align_forward(void *ptr, usize align);

#define zero_struct(element) ((void)zero_size(&(element), sizeof(element)))
#define zero_array(ptr, Type, count) cast(Type, zero_size((ptr), sizeof(Type)*(count)))
void   *zero_size(void *ptr, usize bytes);



/*
 * Array
 */
/*
 * Array structure:
 *
 *
 * | Allocator * | usize count | usize capacity | char * |
 *                                              |
 *                                               `-- Returned pointer
 */

typedef struct Array_Header {
	Allocator *allocator;
	usize      count;
	usize      capacity;
} Array_Header;

/* TODO(bill): Implement a c style array maybe like stb/stretchy_buffer.h but with a custom allocator */

#define array_header(arr)           (cast(Array_Header *, arr) - 1)

#define array_make_count(allocator, Type, count) /* TODO(bill): */
#define array_make(allocator, Type) (array_make_count(allocator, Type, 0))
#define array_free(arr)             (dealloc(array_header(arr)->allocator, array_header(arr)))

#define array_allocator(arr) (array_header(arr)->allocator)
#define array_count(arr)     (array_header(arr)->count)
#define array_capacity(arr)  (array_header(arr)->capacity)

#define array_append(arr, item)               /* TODO(bill): */
#define array_append_array(arr, items, count) /* TODO(bill): */

#define array_pop(arr)  (GB_ASSERT(array_header(arr)->count > 0), array_header(arr)->count--)

#define array_clear(arr) (array_header(arr)->count = 0)
#define array_resize(arr, count)          /* TODO(bill): */
#define array_reserve(arr, capacity)      /* TODO(bill): */
#define array_set_capacity(arr, capacity) /* TODO(bill): */
#define array_grow(arr, min_capacity)     /* TODO(bill): */


/*
 * String - c compatible strings
 */

typedef char * String;

typedef u32 String_Size;

typedef struct String_Header {
	Allocator  *allocator;
	String_Size length;
	String_Size capacity;
} String_Header;

#define GB_STRING_HEADER(str) (cast(String_Header *, str) - 1)

String string_make(Allocator *a, const char* str);
String string_make_length(Allocator *a, const void* str, String_Size num_bytes);
void   string_free(String str);

String string_duplicate(Allocator *a, const String str);

String_Size string_length(const String str);
String_Size string_capacity(const String str);
String_Size string_available_space(const String str);

void string_clear(String str);

String string_append_string(String *str, const String other);
String string_append_string_length(String *str, const void *other, String_Size num_bytes);
String string_append_cstring(String *str, const char *other);

String string_set(String str, const char *cstr);

String      string_make_space_for(String str, String_Size add_len);
String_Size string_allocation_size(const String str);

bool32 strings_are_equal(const String lhs, const String rhs);

String string_trim(String str, const char *cut_set);
String string_trim_space(String str); /* Whitespace ` \t\r\n\v\f` */



/*
 * Hash
 */

u32 hash_adler32(const void *ket, u32 num_bytes);

u32 hash_crc32(const void* key, u32 num_bytes);
u64 hash_crc64(const void* key, usize num_bytes);

u32 hash_fnv32(const void* key, usize num_bytes);
u64 hash_fnv64(const void* key, usize num_bytes);
u32 hash_fnv32a(const void* key, usize num_bytes);
u64 hash_fnv64a(const void* key, usize num_bytes);

u32 hash_murmur32(const void* key, u32 num_bytes, u32 seed);
u64 hash_murmur64(const void* key, usize num_bytes, u64 seed);

/*
 * Time
 */

/* TODO(bill): How should I this  */
typedef struct Time { s64 microseconds; } Time;

#define TIME_ZERO (cast(Time, {0}))

Time time_now(void);
void time_sleep(Time time);

Time time_seconds(f32 s);
Time time_milliseconsd(s32 ms);
Time time_microseconds(s64 us);

f32 time_as_seconds(Time t);
s32 time_as_milliseconds(Time t);
s64 time_as_microseconds(Time t);

#if defined(__cplusplus)
}
#endif /* extern "C" */

#if defined(GB_IMPLEMENTATION)


#endif /* GB_IMPLEMENTATION */

#endif