aboutsummaryrefslogtreecommitdiffstats
path: root/gb.h
diff options
context:
space:
mode:
authorGravatar gingerBill 2015-12-14 15:42:52 +0000
committerGravatar gingerBill 2015-12-14 15:42:52 +0000
commit2e594a584986aff490f20ae2e6448e5912f2f773 (patch)
treee01a7fdd4f1fbe5f3b938e601450e7c4b8b5553b /gb.h
parentRemove `_Allocator` suffix for allocator types (diff)
Add gb.h - Just the prototypes
C89/C99 version of gb.hpp
Diffstat (limited to 'gb.h')
-rw-r--r--gb.h656
1 files changed, 656 insertions, 0 deletions
diff --git a/gb.h b/gb.h
new file mode 100644
index 0000000..29b1406
--- /dev/null
+++ b/gb.h
@@ -0,0 +1,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