diff options
| author | 2016-03-03 11:37:48 +0000 | |
|---|---|---|
| committer | 2016-03-03 11:37:48 +0000 | |
| commit | de04cbcee732ba43c9645cc02e48f8323c2bbf07 (patch) | |
| tree | da2e9bbd820d51045b6a4baf36e8b0d000a9c8ea /gb.h | |
| parent | Explicit Everything! (diff) | |
New Libraries
Diffstat (limited to 'gb.h')
| -rw-r--r-- | gb.h | 2517 |
1 files changed, 418 insertions, 2099 deletions
@@ -1,27 +1,39 @@ -/* gb.h - v0.04a - public domain C helper library - no warranty implied; use at your own risk */ -/* (Experimental) A C helper library geared towards game development */ +// gb.h - v0.01 - public domain C helper library - no warranty implied; use at your own risk +// (Experimental) A C 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. + +CONTENTS + - Common Macros + - Assert + - Types + - Cast macro (easy grepping) + - Memory + - Custom Allocation + - gb_Allocator + - gb_Arena + - gb_Pool + - gb_String + +TODO + - Mutex + - Atomics + - Semaphore + - Thread + - OS Types and Functions (File/IO/OS/etc.) +*/ /* - * 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. - * - */ - - /* Version History: - 0.06 - Explicit Everything - 0.05 - Fix Macros - 0.04a - Change conventions to be in keeping with `gb.hpp` - 0.04 - Allow for no <stdio.h> - 0.03 - Allocators can be passed to gb_alloc/free/etc. without cast using `typedef void* gb_Allocator_Ptr` - 0.02 - Implement all functions (from gb.hpp) - 0.01 - Initial Version (just prototypes) + 0.01 - Initial Version */ @@ -32,190 +44,63 @@ Version History: extern "C" { #endif -#ifndef GB_DO_NOT_USE_CUSTOM_STATIC - /* 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 f32 const TAU = 6.283185f; - global_variable void* g_memory; - - internal_linkage void - some_function(...) - { - local_persist u32 count = 0; - ... - count++; - ... - } - */ -#endif - -#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 +#include <stdarg.h> +#include <stddef.h> - #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 +// NOTE(bill): Because static means three different things in C/C++ +// Great design(!) +#ifndef local_persist +#define global static +#define internal static +#define local_persist static #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 - -#ifndef GB_IS_POWER_OF_TWO -#define GB_IS_POWER_OF_TWO(x) ((x) != 0) && !((x) & ((x) - 1)) -#endif - -#ifndef GB_FORCE_INLINE +// NOTE(bill): If I put gb_inline, I _want_ it inlined +#ifndef gb_inline #if defined(_MSC_VER) - #define GB_FORCE_INLINE __forceinline + #define gb_inline __forceinline #else - #define GB_FORCE_INLINE __attribute__ ((__always_inline__)) + #define gb_inline __attribute__ ((__always_inline__)) #endif #endif + #if !defined(GB_NO_STDIO) #include <stdio.h> #endif -#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 -#else - #include <pthread.h> - #include <sys/time.h> -#endif -#if defined(NDEBUG) - #define GB_ASSERT(cond) ((void)(0)) -#else - /* TODO(bill): Do a better assert */ - #define GB_ASSERT(cond) assert(cond) +#ifndef GB_ASSERT +#include <assert.h> +#define GB_ASSERT(cond) assert(cond) #endif #define GB_STATIC_ASSERT(cond, msg) typedef char gb__static_assertion_##msg[(!!(cond))*2-1] -/* token pasting madness: */ +// NOTE(bill): 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__) - #if !defined(GB_NO_STDIO) && defined(_MSC_VER) - /* snprintf_msvc */ - GB_FORCE_INLINE int - gb__vsnprintf_compatible(char* buffer, size_t size, char const* format, va_list args) + // snprintf_msvc + gb_inline int + gb__vsnprintf_compatible(char* buffer, size_t size, char const *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); + if (size > 0) + result = _vsnprintf_s(buffer, size, _TRUNCATE, format, args); + if (result == -1) + return _vscprintf(format, args); return result; } - GB_FORCE_INLINE int - gb__snprintf_compatible(char* buffer, size_t size, char const* format, ...) + gb_inline int + gb__snprintf_compatible(char* buffer, size_t size, char const *format, ...) { + int result = -1; va_list args; va_start(args, format); - int result = gb__vsnprintf_compatible(buffer, size, format, args); + result = gb__vsnprintf_compatible(buffer, size, format, args); va_end(args); return result; } @@ -226,9 +111,13 @@ extern "C" { #endif /* GB_DO_NOT_USE_MSVC_SPRINTF_FIX */ #endif /* !defined(GB_NO_STDIO) */ + + + + #if defined(_MSC_VER) - typedef unsigned __int8 u8; - typedef signed __int8 s8; + typedef unsigned __int8 u8; + typedef signed __int8 s8; typedef unsigned __int16 u16; typedef signed __int16 s16; typedef unsigned __int32 u32; @@ -237,9 +126,8 @@ extern "C" { typedef signed __int64 s64; #else #include <stdint.h> - - typedef uint8_t u8; - typedef int8_t s8; + typedef uint8_t u8; + typedef int8_t s8; typedef uint16_t u16; typedef int16_t s16; typedef uint32_t u32; @@ -253,38 +141,20 @@ 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; - -#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 -GB_COMPILE_TIME_ASSERT(sizeof(usize) == sizeof(size_t)); - +typedef size_t usize; +typedef uintptr_t uintptr; -typedef enum bool32 -{ - false = 0 != 0, - true = !false, -} bool32; +typedef float f32; +typedef double f64; -#ifndef NULL -#define NULL ((void*)0) -#endif +#include <stdbool.h> // NOTE(bill): To get false/true -GB_COMPILE_TIME_ASSERT(sizeof(bool32) == sizeof(s32)); +// Boolean Types +typedef s8 b8; +typedef s32 b32; -typedef uintptr_t uintptr; -typedef intptr_t intptr; -typedef ptrdiff_t ptrdiff; #define U8_MIN 0u #define U8_MAX 0xffu @@ -306,1449 +176,484 @@ typedef ptrdiff_t ptrdiff; #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 */ -/* */ -/**********************************/ +#ifndef COUNT_OF +#define COUNT_OF(x) (sizeof((x)) / sizeof(0[(x)])) +#endif -/* NOTE(bill): Easier to grep/find for casts */ -/* NOTE(bill): Still not as type safe as C++ static_cast, reinterpret_cast, const_cast */ +// NOTE(bill): Allows for easy grep of casts +// NOTE(bill): Still not as type safe as C++ static_cast, reinterpret_cast, const_cast #ifndef cast -#define cast(Type, src) ((Type)(src)) +#define cast(x) (x) #endif +#ifndef NULL +#define NULL ((void *)0) +#endif -#ifndef pseudo_cast -#define pseudo_cast(Type, src) (*cast(Type*, &(src))) +#ifndef GB_UNUSED +#define GB_UNUSED(x) ((void)(sizeof(x))) #endif -#if defined(GB_COMPILER_GNU_GCC) - #ifndef bit_cast - #define bit_cast(Type, src) ({ GB_ASSERT(sizeof(Type) <= sizeof(src)); Type dst; memcpy(&dst, &(src), sizeof(Type)); dst; }) +#ifndef gb_inline + #if defined(_MSC_VER) + #define gb_inline __forceinline #else - // TODO(bill): Figure out a version for `bit_cast` that is not `pseudo_cast` - #define bit_cast(Type, src) (pseudo_cast(Type, src)) + #define gb_inline __attribute__ ((__always_inline__)) #endif #endif -#ifndef GB_UNUSED -#define GB_UNUSED(x) cast(void, sizeof(x)) -#endif -/**********************************/ -/* */ -/* Memory */ -/* */ -/**********************************/ -/* NOTE(bill): 0[x] is used to prevent C++ style arrays with operator overloading */ -#ifndef GB_ARRAY_COUNT -#define GB_ARRAY_COUNT(x) ((sizeof(x)/sizeof(0[x])) / (cast(usize, !(sizeof(x) % sizeof(0[x]))))) -#endif +//////////////////////////////// +// // +// Memory // +// // +//////////////////////////////// -#ifndef GB_KILOBYTES -#define GB_KILOBYTES(x) ( (x) * 1024ll) -#define GB_MEGABYTES(x) (GB_KILOBYTES(x) * 1024ll) -#define GB_GIGABYTES(x) (GB_MEGABYTES(x) * 1024ll) -#define GB_TERABYTES(x) (GB_GIGABYTES(x) * 1024ll) -#endif +#include <string.h> // For memcpy/memmove/memset/etc. -typedef struct gb_Mutex -{ -#if defined(GB_SYSTEM_WINDOWS) - HANDLE win32_mutex; -#else - pthread_mutex_t posix_mutex; +#ifndef GB_IS_POWER_OF_TWO +#define GB_IS_POWER_OF_TWO(x) ((x) != 0) && !((x) & ((x)-1)) #endif -} gb_Mutex; - -gb_Mutex gb_mutex_make(void); -void gb_mutex_destroy(gb_Mutex* mutex); -void gb_mutex_lock(gb_Mutex* mutex); -bool32 gb_mutex_try_lock(gb_Mutex* mutex); -void gb_mutex_unlock(gb_Mutex* mutex); - - - - - -typedef struct gb_Atomic32 { u32 nonatomic; } gb_Atomic32; -typedef struct gb_Atomic64 { u64 nonatomic; } gb_Atomic64; - -u32 gb_atomic32_load(gb_Atomic32 const volatile* a); -void gb_atomic32_store(gb_Atomic32 volatile* a, u32 value); -u32 gb_atomic32_compare_exchange_strong(gb_Atomic32 volatile* a, u32 expected, u32 desired); -u32 gb_atomic32_exchanged(gb_Atomic32 volatile* a, u32 desired); -u32 gb_atomic32_fetch_add(gb_Atomic32 volatile* a, s32 operand); -u32 gb_atomic32_fetch_and(gb_Atomic32 volatile* a, u32 operand); -u32 gb_atomic32_fetch_or(gb_Atomic32 volatile* a, u32 operand); -u64 gb_atomic64_load(gb_Atomic64 const volatile* a); -void gb_atomic64_store(gb_Atomic64 volatile* a, u64 value); -u64 gb_atomic64_compare_exchange_strong(gb_Atomic64 volatile* a, u64 expected, u64 desired); -u64 gb_atomic64_exchanged(gb_Atomic64 volatile* a, u64 desired); -u64 gb_atomic64_fetch_add(gb_Atomic64 volatile* a, s64 operand); -u64 gb_atomic64_fetch_and(gb_Atomic64 volatile* a, u64 operand); -u64 gb_atomic64_fetch_or(gb_Atomic64 volatile* a, u64 operand); +void *gb_align_forward(void *ptr, usize align); +void gb_zero_size(void *ptr, usize size); +#define gb_zero_struct(t) gb_zero_size((t), sizeof(*(t))) // NOTE(bill): Pass pointer of struct +#define gb_zero_array(a, count) gb_zero_size((a), sizeof((a)[0])*count) - - -typedef struct gb_Semaphore +#if defined(GB_IMPLEMENTATION) +gb_inline void * +gb_align_forward(void *ptr, usize align) { -#if defined(GB_SYSTEM_WINDOWS) - HANDLE win32_handle; -#else - gb_Mutex mutex; - pthread_cond_t cond; - s32 count; -#endif -} gb_Semaphore; - -gb_Semaphore gb_semaphore_make(void); -void gb_semaphore_destroy(gb_Semaphore* s); -void gb_semaphore_post(gb_Semaphore* s); -void gb_semaphore_post_count(gb_Semaphore* s, u32 count); -void gb_semaphore_wait(gb_Semaphore* s); - - + uintptr p; + usize modulo; + GB_ASSERT(GB_IS_POWER_OF_TWO(align)); + p = cast(uintptr)ptr; + modulo = p % align; + if (modulo) p += (align - modulo); + return cast(void *)p; +} -typedef void(gb_Thread_Procedure)(void* data); +gb_inline void gb_zero_size(void *ptr, usize size) { memset(ptr, 0, size); } -typedef struct gb_Thread -{ -#if defined(GB_SYSTEM_WINDOWS) - HANDLE win32_handle; -#else - pthread_t posix_handle; -#endif +#endif // GB_IMPLEMENTATION - gb_Thread_Procedure* proc; - void* data; - gb_Semaphore semaphore; - usize stack_size; - bool32 is_running; -} gb_Thread; -gb_Thread gb_thread_make(void); -void gb_thread_destroy(gb_Thread* t); -void gb_thread_start(gb_Thread* t, gb_Thread_Procedure* proc, void* data); -void gb_thread_start_with_stack(gb_Thread* t, gb_Thread_Procedure* proc, void* data, usize stack_size); -void gb_thread_join(gb_Thread* t); -bool32 gb_thread_is_running(gb_Thread t); -u32 gb_thread_current_id(void); -/**********************************/ -/* */ -/* Allocators */ -/* */ -/**********************************/ +//////////////////////////////// +// // +// Custom Allocation // +// // +//////////////////////////////// +typedef enum gb_Allocation_Type +{ + GB_ALLOCATION_TYPE_ALLOC, + GB_ALLOCATION_TYPE_FREE, + GB_ALLOCATION_TYPE_FREE_ALL, + GB_ALLOCATION_TYPE_RESIZE, +} gb_Allocation_Type; -/* Default aligment for memory allocations */ -#ifndef GB_DEFAULT_ALIGNMENT -#define GB_DEFAULT_ALIGNMENT 8 -#endif +#define GB_ALLOCATOR_PROCEDURE(name) void *name(void *allocator_data, gb_Allocation_Type type, usize size, usize alignment, void *old_memory, usize old_size, u32 options) +typedef GB_ALLOCATOR_PROCEDURE(gb_Allocator_Procedure); -/* - * NOTE(bill): The cost of the function pointer lookup is minor compared to the actually allocation in most cases - */ typedef struct gb_Allocator { - /* Allocates the specified amount of memory aligned to the specified alignment */ - void* (*alloc)(struct gb_Allocator* a, usize size, usize align); - - /* Frees an allocation made with alloc() */ - void (*free)(struct gb_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 gb_Allocator* a, void const* 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 gb_Allocator* a); + gb_Allocator_Procedure *procedure; + void *data; } gb_Allocator; - -void* -gb_alloc_align(gb_Allocator* allocator, usize size, usize align) -{ - GB_ASSERT(allocator != NULL); - return allocator->alloc(allocator, size, align); -} -void* -gb_alloc(gb_Allocator* allocator, usize size) -{ - GB_ASSERT(allocator != NULL); - return gb_alloc_align(allocator, size, GB_DEFAULT_ALIGNMENT); -} - -#ifndef gb_alloc_struct -#define gb_alloc_struct(allocator, Type) cast(Type*, gb_alloc_align(allocator, sizeof(Type), alignof(Type))) -#define gb_alloc_array(allocator, Type, count) cast(Type*, gb_alloc_align(allocator, sizeof(Type)*(count), alignof(Type))) +#ifndef GB_DEFAULT_ALIGNMENT +#define GB_DEFAULT_ALIGNMENT 8 #endif -void -gb_free(gb_Allocator* allocator, void* ptr) -{ - GB_ASSERT(allocator != NULL); - if (ptr) allocator->free(allocator, ptr); -} +gb_inline void *gb_alloc_align(gb_Allocator a, usize size, usize alignment) { return a.procedure(a.data, GB_ALLOCATION_TYPE_ALLOC, size, alignment, NULL, 0, 0); } +gb_inline void *gb_alloc(gb_Allocator a, usize size) { return gb_alloc_align(a, size, GB_DEFAULT_ALIGNMENT); } +gb_inline void gb_free(gb_Allocator a, void *ptr) { a.procedure(a.data, GB_ALLOCATION_TYPE_FREE, 0, 0, ptr, 0, 0); } +gb_inline void gb_free_all(gb_Allocator a) { a.procedure(a.data, GB_ALLOCATION_TYPE_FREE_ALL, 0, 0, NULL, 0, 0); } +gb_inline void *gb_resize(gb_Allocator a, void *ptr, usize new_size) { return a.procedure(a.data, GB_ALLOCATION_TYPE_RESIZE, new_size, 0, ptr, 0, 0); } -s64 -gb_allocated_size(gb_Allocator* allocator, void const* ptr) -{ - GB_ASSERT(allocator != NULL); - return allocator->allocated_size(allocator, ptr); -} - -s64 -gb_total_allocated(gb_Allocator* allocator) -{ - GB_ASSERT(allocator != NULL); - return allocator->total_allocated(allocator); -} +gb_inline void *gb_alloc_copy(gb_Allocator a, void* src, usize size) { return memcpy(gb_alloc(a, size), src, size); } +gb_inline void *gb_alloc_align_copy(gb_Allocator a, void* src, usize size, usize alignment) { return memcpy(gb_alloc_align(a, size, alignment), src, size); } +#define gb_alloc_struct(allocator, Type) (Type *)gb_alloc_align(allocator, sizeof(Type)) +#define gb_alloc_array(allocator, Type, count) (Type *)gb_alloc(allocator, sizeof(Type) * (count)) -typedef struct gb_Heap -{ - gb_Allocator base; /* NOTE(bill): Must be first into order to act as a vtable */ - - gb_Mutex mutex; - bool32 use_mutex; - s64 total_allocated_count; - s64 allocation_count; - -#if defined(GB_SYSTEM_WINDOWS) - HANDLE win32_heap_handle; -#endif -} gb_Heap; - -gb_Heap gb_heap_make(bool32 use_mutex); -void gb_heap_destroy(gb_Heap* heap); - typedef struct gb_Arena { - gb_Allocator base; /* NOTE(bill): Must be first into order to act as a vtable */ - - gb_Allocator* backing; - void* physical_start; - s64 total_size; - s64 total_allocated_count; - s64 temp_count; + gb_Allocator backing; + void *physical_start; + usize total_size; + usize total_allocated_count; + usize prev_allocated_count; + u32 temp_count; } gb_Arena; +void gb_init_arena_from_memory(gb_Arena *arena, void *start, usize size); +void gb_init_arena_from_allocator(gb_Arena *arena, gb_Allocator backing, usize size); +void gb_free_arena(gb_Arena *arena); + +gb_Allocator gb_make_arena_allocator(gb_Arena *arena); +GB_ALLOCATOR_PROCEDURE(gb_arena_allocator_procedure); -gb_Arena gb_arena_make_from_backing(gb_Allocator* backing, usize size); -gb_Arena gb_arena_make_from_pointer(void* start, usize size); -void gb_arena_destroy(gb_Arena* arena); -void gb_arena_clear(gb_Arena* arena); -typedef struct gb_Temporary_Arena_Memory +typedef struct gb_Temp_Arena_Memory { - gb_Arena* arena; - s64 original_count; -} gb_Temporary_Arena_Memory; + gb_Arena *arena; + usize original_count; +} gb_Temp_Arena_Memory; + +gb_Temp_Arena_Memory gb_begin_temp_arena_memory(gb_Arena *arena); +void gb_end_temp_arena_memory(gb_Temp_Arena_Memory tmp_mem); -gb_Temporary_Arena_Memory gb_make_temporary_arena_memory(gb_Arena* arena); -void gb_temporary_arena_memory_free(gb_Temporary_Arena_Memory t); typedef struct gb_Pool { - gb_Allocator base; /* NOTE(bill): Must be first into order to act as a vtable */ - - gb_Allocator* backing; + gb_Allocator backing; - void* physical_start; - void* free_list; + void *physical_start; + void *free_list; usize block_size; usize block_align; - s64 total_size; + usize total_size; } gb_Pool; -gb_Pool gb_pool_make(gb_Allocator* backing, usize num_blocks, usize block_size); -gb_Pool gb_pool_make_align(gb_Allocator* backing, usize num_blocks, usize block_size, usize block_align); -void gb_pool_destroy(gb_Pool* pool); - - - - -/**********************************/ -/* */ -/* Memory */ -/* */ -/**********************************/ - -void* gb_align_forward(void* ptr, usize align); - -void* gb_zero_size(void* ptr, usize bytes); -#ifndef gb_zero_struct -#define gb_zero_struct(element) (cast(void, gb_zero_size(&(element), sizeof(element)))) -#define gb_zero_array(ptr, Type, count) cast(Type, gb_zero_size((ptr), sizeof(Type)*(count))) -#endif - - - - -/**********************************/ -/* */ -/* Array */ -/* */ -/**********************************/ - -/* - * Array structure: - * - * - * | Allocator * | usize count | usize capacity | char* | - * | - * `-- Returned pointer - */ - -typedef struct gb_Array_Header -{ - gb_Allocator* allocator; - usize count; - usize capacity; -} gb_Array_Header; - -/* TODO(bill): Implement a c style array maybe like stb/stretchy_buffer.h but with a custom allocator */ - -#define gb_array_header(arr) (cast(gb_Array_Header*, arr) - 1) - -#define gb_array_make_count(allocator, Type, count) /* TODO(bill): */ -#define gb_array_make(allocator, Type) (gb_array_make_count(allocator, Type, 0)) -#define gb_array_free(arr) (gb_free(gb_array_header(arr)->allocator, gb_array_header(arr))) - -#define gb_array_allocator(arr) (gb_array_header(arr)->allocator) -#define gb_array_count(arr) (gb_array_header(arr)->count) -#define gb_array_capacity(arr) (gb_array_header(arr)->capacity) - -#define gb_array_append(arr, item) /* TODO(bill): */ -#define gb_array_append_array(arr, items, count) /* TODO(bill): */ - -#define gb_array_pop(arr) (GB_ASSERT(gb_array_header(arr)->count > 0), gb_array_header(arr)->count--) - -#define gb_array_clear(arr) (gb_array_header(arr)->count = 0) -#define gb_array_resize(arr, count) /* TODO(bill): */ -#define gb_array_reserve(arr, capacity) /* TODO(bill): */ -#define gb_array_set_capacity(arr, capacity) /* TODO(bill): */ -#define gb_array_grow(arr, min_capacity) /* TODO(bill): */ +void gb_init_pool(gb_Pool *pool, gb_Allocator backing, usize num_blocks, usize block_size); +void gb_init_pool_align(gb_Pool *pool, gb_Allocator backing, usize num_blocks, usize block_size, usize block_align); +void gb_free_pool(gb_Pool *pool); +gb_Allocator gb_make_pool_allocator(gb_Pool *pool); +GB_ALLOCATOR_PROCEDURE(gb_pool_allocator_procedure); -/**********************************/ -/* */ -/* String - C Compatibile */ -/* */ -/**********************************/ -/* Pascal like strings in C */ -typedef char* gb_String; - -#ifndef GB_STRING_SIZE -#define GB_STRING_SIZE -/* define GB_STRING_SIZE to allow for a custom size e.g. u16, usize, int, etc. */ -typedef u32 gb_String_Size; -#endif - -typedef struct gb_String_Header -{ - gb_Allocator* allocator; - gb_String_Size length; - gb_String_Size capacity; -} gb_String_Header; - -#define GB_STRING_HEADER(str) (cast(gb_String_Header*, str) - 1) - -gb_String gb_string_make(gb_Allocator* a, char const* str); -gb_String gb_string_make_length(gb_Allocator* a, void const* str, gb_String_Size num_bytes); -void gb_string_free(gb_String str); - -gb_String gb_string_duplicate(gb_Allocator* a, gb_String const str); - -gb_String_Size gb_string_length(gb_String const str); -gb_String_Size gb_string_capacity(gb_String const str); -gb_String_Size gb_string_available_space(gb_String const str); - -void gb_string_clear(gb_String str); - -gb_String gb_string_append_string(gb_String str, gb_String const other); -gb_String gb_string_append_string_length(gb_String str, void const* other, gb_String_Size num_bytes); -gb_String gb_string_append_cstring(gb_String str, char const* other); - -gb_String gb_string_set(gb_String str, char const* cstr); - -gb_String gb_string_make_space_for(gb_String str, gb_String_Size add_len); -gb_String_Size gb_string_allocation_size(gb_String const str); - -bool32 gb_strings_are_equal(gb_String const lhs, gb_String const rhs); - -gb_String gb_string_trim(gb_String str, char const* cut_set); -gb_String gb_string_trim_space(gb_String str); /* Whitespace ` \t\r\n\v\f` */ - - - - - -/**********************************/ -/* */ -/* Hash */ -/* */ -/**********************************/ - - -u32 gb_hash_adler32(void const* ket, u32 num_bytes); - -u32 gb_hash_crc32(void const* key, u32 num_bytes); -u64 gb_hash_crc64(void const* key, usize num_bytes); - -u32 gb_hash_fnv32(void const* key, usize num_bytes); -u64 gb_hash_fnv64(void const* key, usize num_bytes); -u32 gb_hash_fnv32a(void const* key, usize num_bytes); -u64 gb_hash_fnv64a(void const* key, usize num_bytes); - -u32 gb_hash_murmur32(void const* key, u32 num_bytes, u32 seed); -u64 gb_hash_murmur64(void const* key, usize num_bytes, u64 seed); - - - - - -/**********************************/ -/* */ -/* Time */ -/* */ -/**********************************/ - -/* TODO(bill): How should I this */ -typedef struct gb_Time -{ - s64 microseconds; -} gb_Time; - -#ifndef GB_TIME_ZERO -#define GB_TIME_ZERO (cast(gb_Time, {0})) -#endif - -gb_Time gb_time_now(void); -void gb_time_sleep(gb_Time time); - -gb_Time gb_time_seconds(f32 s); -gb_Time gb_time_milliseconsd(s32 ms); -gb_Time gb_time_microseconds(s64 us); - -f32 gb_time_as_seconds(gb_Time t); -s32 gb_time_as_milliseconds(gb_Time t); -s64 gb_time_as_microseconds(gb_Time t); - -/* - * lhs < rhs -1 - * lhs == rhs 0 - * lhs > rhs +1 - */ -s32 gb_time_cmp(gb_Time lhs, gb_Time rhs); - -gb_Time gb_time_add(gb_Time lhs, gb_Time rhs); -gb_Time gb_time_sub(gb_Time lhs, gb_Time rhs); -gb_Time gb_time_mod(gb_Time lhs, gb_Time rhs); -gb_Time gb_time_mul(gb_Time t, f32 s); -gb_Time gb_time_div(gb_Time t, f32 s); -f32 gb_time_div_time(gb_Time num, gb_Time dom); - - -#if defined(__cplusplus) -} -#endif /* extern "C" */ -#endif - -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// Woo hoo! -// -// -// -// -// -//////////////////////////////// -// // -// Implemenation // -// // -//////////////////////////////// #if defined(GB_IMPLEMENTATION) -#if defined(__cplusplus) -extern "C" { -#endif -/**********************************/ -/* */ -/* Memory */ -/* */ -/**********************************/ -gb_Mutex -gb_mutex_make(void) -{ - gb_Mutex m = {0}; -#if defined(GB_SYSTEM_WINDOWS) - m.win32_mutex = CreateMutex(0, false, 0); -#else - pthread_mutex_init(&m.posix_mutex, NULL); -#endif - return m; -} - -void -gb_mutex_destroy(gb_Mutex* m) -{ -#if defined(GB_SYSTEM_WINDOWS) - CloseHandle(m->win32_mutex); -#else - pthread_mutex_destroy(&m->posix_mutex); -#endif -} -void -gb_mutex_lock(gb_Mutex* m) +gb_inline void +gb_init_arena_from_memory(gb_Arena *arena, void *start, usize size) { -#if defined(GB_SYSTEM_WINDOWS) - WaitForSingleObject(m->win32_mutex, INFINITE); -#else - pthread_mutex_lock(&m->posix_mutex); -#endif + arena->backing.procedure = NULL; + arena->backing.data = NULL; + arena->physical_start = start; + arena->total_size = size; + arena->total_allocated_count = 0; + arena->temp_count = 0; } -bool32 -gb_mutex_try_lock(gb_Mutex* m) +gb_inline void +gb_init_arena_from_allocator(gb_Arena *arena, gb_Allocator backing, usize size) { -#if defined(GB_SYSTEM_WINDOWS) - return WaitForSingleObject(m->win32_mutex, 0) == WAIT_OBJECT_0; -#else - return pthread_mutex_trylock(&m->posix_mutex) == 0; -#endif + arena->backing = backing; + arena->physical_start = gb_alloc(backing, size); + arena->total_size = size; + arena->total_allocated_count = 0; + arena->temp_count = 0; } -void -gb_mutex_unlock(gb_Mutex* m) +gb_inline void +gb_free_arena(gb_Arena *arena) { -#if defined(GB_SYSTEM_WINDOWS) - ReleaseMutex(m->win32_mutex); -#else - pthread_mutex_unlock(&m->posix_mutex); -#endif + if (arena->backing.procedure) { + gb_free(arena->backing, arena->physical_start); + arena->physical_start = NULL; + } } -#if defined(_MSC_VER) -u32 -gb_atomic32_load(gb_Atomic32 const volatile* object) +gb_inline gb_Allocator +gb_make_arena_allocator(gb_Arena *arena) { - return object->nonatomic; + gb_Allocator allocator; + allocator.procedure = gb_arena_allocator_procedure; + allocator.data = arena; + return allocator; } -void -gb_atomic32_store(gb_Atomic32 volatile* object, u32 value) -{ - object->nonatomic = value; -} -u32 -gb_atomic32_compare_exchange_strong(gb_Atomic32 volatile* object, u32 expected, u32 desired) +GB_ALLOCATOR_PROCEDURE(gb_arena_allocator_procedure) { - return _InterlockedCompareExchange(cast(long volatile*, object), desired, expected); -} + gb_Arena *arena = cast(gb_Arena *)allocator_data; -u32 -gb_atomic32_exchanged(gb_Atomic32 volatile* object, u32 operand) -{ - return _InterlockedExchangeAdd(cast(long volatile*, object), operand); -} + GB_UNUSED(options); + GB_UNUSED(old_size); -u32 -gb_atomic32_fetch_add(gb_Atomic32 volatile* object, s32 operand) -{ - return _InterlockedExchangeAdd(cast(long volatile*, object), operand); -} + switch (type) { + case GB_ALLOCATION_TYPE_ALLOC: { + void *ptr; + usize actual_size = size + alignment; -u32 -gb_atomic32_fetch_and(gb_Atomic32 volatile* object, u32 operand) -{ - return _InterlockedAnd(cast(long volatile*, object), operand); -} + // NOTE(bill): Out of memory + if (arena->total_allocated_count + actual_size > cast(usize)arena->total_size) + return NULL; -u32 -gb_atomic32_fetch_or(gb_Atomic32 volatile* object, u32 operand) -{ - return _InterlockedOr(cast(long volatile*, object), operand); -} + ptr = gb_align_forward(cast(u8 *)arena->physical_start + arena->total_allocated_count, alignment); + arena->prev_allocated_count = arena->total_allocated_count; + arena->total_allocated_count += actual_size; + return ptr; + } break; + case GB_ALLOCATION_TYPE_FREE: { + // NOTE(bill): Free all at once + // NOTE(bill): Use Temp_Arena_Memory if you want to free a block + } break; -u64 -gb_atomic64_load(gb_Atomic64 const volatile* object) -{ -#if defined(GB_ARCH_64_BIT) - return object->nonatomic; -#else - /* NOTE(bill): The most compatible way to get an atomic 64-bit load on x86 is with cmpxchg8b */ - u64 result; - __asm { - mov esi, object; - mov ebx, eax; - mov ecx, edx; - lock cmpxchg8b [esi]; - mov dword ptr result, eax; - mov dword ptr result[4], edx; - } - return result; -#endif -} + case GB_ALLOCATION_TYPE_FREE_ALL: + arena->total_allocated_count = 0; + break; -void -gb_atomic64_store(gb_Atomic64 volatile* object, u64 value) -{ -#if defined(GB_ARCH_64_BIT) - object->nonatomic = value; -#else - /* NOTE(bill): The most compatible way to get an atomic 64-bit store on x86 is with cmpxchg8b */ - __asm { - mov esi, object; - mov ebx, dword ptr value; - mov ecx, dword ptr value[4]; - retry: - cmpxchg8b [esi]; - jne retry; + case GB_ALLOCATION_TYPE_RESIZE: { + // TODO(bill): Check if ptr is at the top + void *ptr = gb_alloc_align(gb_make_arena_allocator(arena), size, alignment); + memcpy(ptr, old_memory, size); + return ptr; + } break; } -#endif -} -u64 -gb_atomic64_compare_exchange_strong(gb_Atomic64 volatile* object, u64 expected, u64 desired) -{ - return _InterlockedCompareExchange64(cast(s64 volatile*, object), desired, expected); + return NULL; // NOTE(bill): Default return value } -u64 -gb_atomic64_exchanged(gb_Atomic64 volatile* object, u64 desired) -{ -#if defined(GB_ARCH_64_BIT) - return _InterlockedExchange64(cast(s64 volatile*, object), desired); -#else - u64 expected = object->nonatomic; - while (true) - { - u64 original = _InterlockedCompareExchange64(cast(s64 volatile*, object), desired, expected); - if (original == expected) return original; - expected = original; - } -#endif -} -u64 -gb_atomic64_fetch_add(gb_Atomic64 volatile* object, s64 operand) +gb_inline gb_Temp_Arena_Memory +gb_begin_temp_arena_memory(gb_Arena *arena) { -#if defined(GB_ARCH_64_BIT) - return _InterlockedExchangeAdd64(cast(s64 volatile*, object), operand); -#else - u64 expected = object->nonatomic; - while (true) - { - u64 original = _InterlockedExchange64(cast(s64 volatile*, object), expected + operand, expected); - if (original == expected) return original; - expected = original; - } -#endif + gb_Temp_Arena_Memory tmp; + tmp.arena = arena; + tmp.original_count = arena->total_allocated_count; + arena->temp_count++; + return tmp; } -u64 -gb_atomic64_fetch_and(gb_Atomic64 volatile* object, u64 operand) +gb_inline void +gb_end_temp_arena_memory(gb_Temp_Arena_Memory tmp) { -#if defined(GB_ARCH_64_BIT) - return _InterlockedAnd64(cast(s64 volatile*, object), operand); -#else - u64 expected = object->nonatomic; - while (true) - { - u64 original = _InterlockedCompareExchange64(cast(s64 volatile*, object), expected & operand, expected); - if (original == expected) - return original; - expected = original; - } -#endif -} -u64 -gb_atomic64_fetch_or(gb_Atomic64 volatile* object, u64 operand) -{ -#if defined(GB_ARCH_64_BIT) - return _InterlockedAnd64(cast(s64 volatile*, object), operand); -#else - u64 expected = object->nonatomic; - while (true) - { - u64 original = _InterlockedCompareExchange64(cast(s64 volatile*, object), expected | operand, expected); - if (original == expected) - return original; - expected = original; - } -#endif + GB_ASSERT(tmp.arena->total_allocated_count >= tmp.original_count); + GB_ASSERT(tmp.arena->temp_count > 0); + tmp.arena->total_allocated_count = tmp.original_count; + tmp.arena->temp_count--; } -#else -#error TODO(bill): Implement atomics for this platform -#endif -gb_Semaphore -gb_semaphore_make(void) -{ - gb_Semaphore semaphore = {0}; -#if defined(GB_SYSTEM_WINDOWS) - semaphore.win32_handle = CreateSemaphore(NULL, 0, S32_MAX, NULL); - GB_ASSERT(semaphore.win32_handle != NULL); - -#else - semaphore.count = 0; - s32 result = pthread_cond_init(&semaphore.cond, NULL); - GB_ASSERT(result == 0); - - semaphore.mutex = gb_mutex_make(); -#endif - - return semaphore; -} void -gb_semaphore_destroy(gb_Semaphore* s) +gb_init_pool(gb_Pool *pool, gb_Allocator backing, usize num_blocks, usize block_size) { -#if defined(GB_SYSTEM_WINDOWS) - BOOL err = CloseHandle(s->win32_handle); - GB_ASSERT(err != 0); -#else - s32 result = pthread_cond_destroy(&s->cond); - GB_ASSERT(result == 0); - gb_mutex_destroy(&s->mutex); -#endif + gb_init_pool_align(pool, backing, num_blocks, block_size, GB_DEFAULT_ALIGNMENT); } void -gb_semaphore_post(gb_Semaphore* s) +gb_init_pool_align(gb_Pool *pool, gb_Allocator backing, usize num_blocks, usize block_size, usize block_align) { - gb_semaphore_post_count(s, 1); -} + memset(pool, 0, sizeof(gb_Pool)); -void -gb_semaphore_post_count(gb_Semaphore* s, u32 count) -{ -#if defined(GB_SYSTEM_WINDOWS) - BOOL err = ReleaseSemaphore(s->win32_handle, count, NULL); - GB_ASSERT(err != 0); -#else - gb_mutex_lock(&s->mutex); - - for (u32 i = 0; i < count; i++) { - s32 result = pthread_cond_signal(&s->cond); - GB_ASSERT(result == 0); - } + pool->backing = backing; + pool->block_size = block_size; + pool->block_align = block_align; - s->count += count; - - gb_mutex_unlock(&s->mutex); -#endif -} + usize actual_block_size = block_size + block_align; + usize pool_size = num_blocks * actual_block_size; -void -gb_semaphore_wait(gb_Semaphore* s) -{ -#if defined(GB_SYSTEM_WINDOWS) - DWORD result = WaitForSingleObject(s->win32_handle, INFINITE); - GB_ASSERT(result == WAIT_OBJECT_0); -#else - gb_mutex_lock(&s->mutex); + u8 *data = cast(u8 *)gb_alloc_align(backing, pool_size, block_align); - while (count <= 0) { - s32 result = pthread_cond_wait(&s->cond, &s->mutex.posix_mutex); - GB_ASSERT(result == 0); + // Init intrusive freelist + u8 *curr = data; + for (usize block_index = 0; block_index < num_blocks-1; block_index++) { + uintptr *next = cast(uintptr *)curr; + *next = cast(uintptr)curr + actual_block_size; + curr += actual_block_size; } - count--; - - gb_mutex_unlock(&s->mutex); -#endif -} - - - -gb_Thread -gb_thread_make(void) -{ - gb_Thread t = {0}; -#if defined(GB_SYSTEM_WINDOWS) - t.win32_handle = INVALID_HANDLE_VALUE; -#else - t.posix_handle = 0; -#endif - t.proc = NULL; - t.data = NULL; - t.stack_size = 0; - t.is_running = false; - t.semaphore = gb_semaphore_make(); - - return t; -} - -void -gb_thread_destroy(gb_Thread* t) -{ - if (t->is_running) gb_thread_join(t); - gb_semaphore_destroy(&t->semaphore); -} - -static void -gb__thread_run(gb_Thread* t) -{ - gb_semaphore_post(&t->semaphore); - t->proc(t->data); -} - -#if defined(GB_SYSTEM_WINDOWS) -static DWORD WINAPI -gb__thread_proc(void* arg) -{ - gb__thread_run(cast(gb_Thread* , arg)); - return 0; -} + uintptr *end = cast(uintptr*)curr; + *end = cast(uintptr)NULL; -#else -static void* -gb__thread_proc(void* arg) -{ - gb__thread_run(cast(gb_Thread* , arg)); - return NULL; + pool->physical_start = data; + pool->free_list = data; } -#endif void -gb_thread_start(gb_Thread* t, gb_Thread_Procedure* proc, void* data) +gb_free_pool(gb_Pool *pool) { - gb_thread_start_with_stack(t, proc, data, 0); -} - -void -gb_thread_start_with_stack(gb_Thread* t, gb_Thread_Procedure* proc, void* data, usize stack_size) -{ - GB_ASSERT(!t->is_running); - GB_ASSERT(proc != NULL); - t->proc = proc; - t->data = data; - t->stack_size = stack_size; - -#if defined(GB_SYSTEM_WINDOWS) - t->win32_handle = CreateThread(NULL, stack_size, gb__thread_proc, t, 0, NULL); - GB_ASSERT(t->win32_handle != NULL); - -#else - pthread_attr_t attr; - s32 result = pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - GB_ASSERT(result == 0); - - if (t->stack_size != 0) - { - result = pthread_attr_setstacksize(&attr, t->stack_size); - GB_ASSERT(result == 0); + if (pool->backing.procedure) { + gb_free(pool->backing, pool->physical_start); } - - result = pthread_create(&t->posix_handle, &attr, gb__thread_proc, thread); - GB_ASSERT(result == 0); - - /* NOTE(bill): Free attr memory */ - result = pthread_attr_destroy(&attr); - GB_ASSERT(result == 0); - - /* NOTE(bill): So much boiler patch compared to windows.h (for once) */ -#endif - - t->is_running = true; - gb_semaphore_wait(&t->semaphore); -} - -void -gb_thread_join(gb_Thread* t) -{ - if (!t->is_running) return; - -#if defined(GB_SYSTEM_WINDOWS) - WaitForSingleObject(t->win32_handle, INFINITE); - CloseHandle(t->win32_handle); - t->win32_handle = INVALID_HANDLE_VALUE; -#else - int result = pthread_join(t->posix_handle, NULL); - t->posix_handle = 0; -#endif - - t->is_running = false; -} - -bool32 -gb_thread_is_running(gb_Thread t) -{ - return t.is_running != 0; } -u32 -gb_thread_current_id(void) -{ - u32 thread_id; - -#if defined(GB_SYSTEM_WINDOWS) - u8* thread_local_storage = cast(u8*, __readgsqword(0x30)); - thread_id = *cast(u32*, thread_local_storage + 0x48); - -#elif defined(GB_SYSTEM_OSX) && defined(GB_ARCH_64_BIT) - asm("mov %%gs:0x00,%0" : "=r"(thread_id)); -#elif defined(GB_ARCH_32_BIT) - asm("mov %%gs:0x08,%0" : "=r"(thread_id)); -#elif defined(GB_ARCH_64_BIT) - asm("mov %%gs:0x10,%0" : "=r"(thread_id)); -#else - #error Unsupported architecture for thread::current_id() -#endif - - return thread_id; -} - - - - -/**********************************/ -/* */ -/* Allocators */ -/* */ -/**********************************/ - -typedef struct gb__Heap_Header -{ - usize size; -} gb__Heap_Header; - -static void* -gb__heap_alloc(gb_Allocator* a, usize size, usize align) +gb_Allocator +gb_make_pool_allocator(gb_Pool *pool) { - gb_Heap* heap = cast(gb_Heap*, a); - - if (heap->use_mutex) gb_mutex_lock(&heap->mutex); - - usize total = size + align - (size % align); - -#if defined(GB_SYSTEM_WINDOWS) - total += sizeof(gb__Heap_Header); - - void* data = HeapAlloc(heap->win32_heap_handle, 0, total); - - gb__Heap_Header* h = cast(gb__Heap_Header*, data); - h->size = total; - data = (h + 1); - -#else - /* TODO(bill): Find a better malloc alternative for this platform */ - void* data = malloc(total); -#endif - - heap->total_allocated_count += total; - heap->allocation_count++; - - if (heap->use_mutex) gb_mutex_unlock(&heap->mutex); - - return data; -} - - - -static void -gb__heap_free(gb_Allocator* a, void* ptr) -{ - if (!ptr) return; - - gb_Heap* heap = cast(gb_Heap*, a); - - if (heap->use_mutex) gb_mutex_lock(&heap->mutex); - - heap->total_allocated_count -= gb_allocated_size(a, ptr); - heap->allocation_count--; - -#if defined (GB_SYSTEM_WINDOWS) - gb__Heap_Header* header = cast(gb__Heap_Header*, ptr) - 1; - HeapFree(heap->win32_heap_handle, 0, header); -#else - free(ptr); -#endif - - if (heap->use_mutex) gb_mutex_unlock(&heap->mutex); + gb_Allocator allocator; + allocator.procedure = gb_pool_allocator_procedure; + allocator.data = pool; + return allocator; } -static s64 -gb__heap_allocated_size(gb_Allocator* a, void const* ptr) +GB_ALLOCATOR_PROCEDURE(gb_pool_allocator_procedure) { -#if defined(GB_SYSTEM_WINDOWS) - gb_Heap* heap = cast(gb_Heap*, a); + gb_Pool *pool = cast(gb_Pool *)allocator_data; - if (heap->use_mutex) gb_mutex_lock(&heap->mutex); - - gb__Heap_Header const* h = cast(gb__Heap_Header const*, ptr) - 1; - s64 result = h->size; - - if (heap->use_mutex) gb_mutex_unlock(&heap->mutex); - - return cast(s64, result); - -#elif defined(GB_SYSTEM_OSX) - return cast(s64, malloc_size(ptr)); - -#elif defined(GB_SYSTEM_LINUX) - return cast(s64, malloc_usable_size(ptr)); - -#else - #error Implement Heap::allocated_size -#endif -} - -static s64 -gb__heap_total_allocated(gb_Allocator* a) -{ - gb_Heap* heap = cast(gb_Heap*, a); - - if (heap->use_mutex) gb_mutex_lock(&heap->mutex); - - s64 result = heap->total_allocated_count; - - if (heap->use_mutex) gb_mutex_unlock(&heap->mutex); - - return result; -} - - - - -gb_Heap -gb_heap_make(bool32 use_mutex) -{ - gb_Heap heap = {0}; - - heap.use_mutex = use_mutex; - if (use_mutex) heap.mutex = gb_mutex_make(); - -#if defined(GB_SYSTEM_WINDOWS) - heap.win32_heap_handle = HeapCreate(0, 0, 0); -#endif - - heap.base.alloc = gb__heap_alloc; - heap.base.free = gb__heap_free; - heap.base.allocated_size = gb__heap_allocated_size; - heap.base.total_allocated = gb__heap_total_allocated; - - return heap; -} - -void -gb_heap_destroy(gb_Heap* heap) -{ - if (heap->use_mutex) gb_mutex_destroy(&heap->mutex); - -#if defined (GB_SYSTEM_WINDOWS) - HeapDestroy(heap->win32_heap_handle); -#endif -} + GB_UNUSED(options); + GB_UNUSED(old_size); + switch (type) { + case GB_ALLOCATION_TYPE_ALLOC: { + uintptr next_free; + void *ptr; + GB_ASSERT(size == pool->block_size); + GB_ASSERT(alignment == pool->block_align); + GB_ASSERT(pool->free_list != NULL); + next_free = *cast(uintptr *)pool->free_list; + ptr = pool->free_list; + pool->free_list = cast(void *)next_free; + pool->total_size += pool->block_size; + return ptr; + } break; + case GB_ALLOCATION_TYPE_FREE: { + uintptr *next; + if (old_memory == NULL) return NULL; + next = cast(uintptr *)old_memory; + *next = cast(uintptr)pool->free_list; + pool->free_list = old_memory; + pool->total_size -= pool->block_size; + } break; -static void* -gb__arena_alloc(gb_Allocator* a, usize size, usize align) -{ - gb_Arena* arena = cast(gb_Arena*, a); + case GB_ALLOCATION_TYPE_FREE_ALL: { + // TODO(bill): + } break; - s64 actual_size = size + align; - - if (arena->total_allocated_count + actual_size > arena->total_size) - { - GB_ASSERT(arena->total_allocated_count + actual_size <= arena->total_size); - return NULL; + case GB_ALLOCATION_TYPE_RESIZE: { + // NOTE(bill): Cannot resize + } break; } - void* ptr = gb_align_forward(cast(u8*, arena->physical_start) + arena->total_allocated_count, align); - - arena->total_allocated_count += actual_size; - - return ptr; -} - -static void -gb__arena_free(gb_Allocator* a, void* ptr) /* NOTE(bill): Arenas free all at once */ -{ - GB_UNUSED(a); - GB_UNUSED(ptr); -} - -static s64 -gb__arena_allocated_size(gb_Allocator* a, void const* ptr) -{ - GB_UNUSED(a); - GB_UNUSED(ptr); - return -1; -} - -static s64 -gb__arena_total_allocated(gb_Allocator* a) -{ - return cast(gb_Arena*, a)->total_allocated_count; -} - - - -gb_Arena -gb_arena_make_from_backing(gb_Allocator* backing, usize size) -{ - gb_Arena arena = {0}; - - arena.backing = backing; - arena.physical_start = NULL; - arena.total_size = size; - arena.temp_count = 0; - arena.total_allocated_count = 0; - - arena.physical_start = gb_alloc(arena.backing, size); - - arena.base.alloc = gb__arena_alloc; - arena.base.free = gb__arena_free; - arena.base.allocated_size = gb__arena_allocated_size; - arena.base.total_allocated = gb__arena_total_allocated; - - return arena; -} - -gb_Arena -gb_arena_make_from_pointer(void* start, usize size) -{ - gb_Arena arena = {0}; - - arena.backing = NULL; - arena.physical_start = start; - arena.total_size = size; - arena.temp_count = 0; - arena.total_allocated_count = 0; - - arena.base.alloc = gb__arena_alloc; - arena.base.free = gb__arena_free; - arena.base.allocated_size = gb__arena_allocated_size; - arena.base.total_allocated = gb__arena_total_allocated; - - return arena; -} - -void -gb_arena_destroy(gb_Arena* arena) -{ - if (arena->backing) - gb_free(arena->backing, arena->physical_start); - - gb_arena_clear(arena); -} - -void -gb_arena_clear(gb_Arena* arena) -{ - GB_ASSERT(arena->temp_count == 0); - - arena->total_allocated_count = 0; -} - - - -gb_Temporary_Arena_Memory -gb_make_temporary_arena_memory(gb_Arena* arena) -{ - gb_Temporary_Arena_Memory tmp = {0}; - tmp.arena = arena; - tmp.original_count = arena->total_allocated_count; - arena->temp_count++; - return tmp; -} - -void -gb_temporary_arena_memory_free(gb_Temporary_Arena_Memory tmp) -{ - GB_ASSERT(gb_total_allocated(cast(gb_Allocator*, tmp.arena)) >= tmp.original_count); - tmp.arena->total_allocated_count = tmp.original_count; - GB_ASSERT(tmp.arena->temp_count > 0); - tmp.arena->temp_count--; -} - - - - - - - - -static void* -gb__pool_alloc(gb_Allocator* a, usize size, usize align) -{ - gb_Pool* pool = cast(gb_Pool*, a); - - GB_ASSERT(size == pool->block_size); - GB_ASSERT(align == pool->block_align); - GB_ASSERT(pool->free_list != NULL); - - uintptr next_free = *cast(uintptr*, pool->free_list); - void* ptr = pool->free_list; - pool->free_list = cast(void*, next_free); - - pool->total_size += pool->block_size; - - return ptr; + return NULL; } -static void -gb__pool_free(gb_Allocator* a, void* ptr) -{ - if (!ptr) return; - gb_Pool* pool = cast(gb_Pool*, a); - uintptr* next = cast(uintptr*, ptr); - *next = cast(uintptr, pool->free_list); - pool->free_list = ptr; - pool->total_size -= pool->block_size; -} -static s64 -gb__pool_allocated_size(gb_Allocator* a, void const* ptr) -{ - GB_UNUSED(a); - GB_UNUSED(ptr); - return -1; -} -static s64 -gb__pool_total_allocated(gb_Allocator* a) -{ - gb_Pool* pool = cast(gb_Pool*, a); - return pool->total_size; -} - - -gb_Pool -gb_pool_make(gb_Allocator* backing, usize num_blocks, usize block_size) -{ - return gb_pool_make_align(backing, num_blocks, block_size, GB_DEFAULT_ALIGNMENT); -} -gb_Pool -gb_pool_make_align(gb_Allocator* backing, usize num_blocks, usize block_size, usize block_align) -{ - gb_Pool pool = {0}; - pool.backing = backing; - pool.block_size = block_size; - pool.block_align = block_align; - usize actual_block_size = block_size + block_align; - usize pool_size = num_blocks * actual_block_size; - u8* data = cast(u8*, gb_alloc_align(backing, pool_size, block_align)); +#endif // GB_IMPLEMENTATION - /* Init intrusive freelist */ - u8* curr = data; - for (usize block_index = 0; block_index < num_blocks-1; block_index++) - { - uintptr* next = cast(uintptr*, curr); - *next = cast(uintptr, curr) + actual_block_size; - curr += actual_block_size; - } +//////////////////////////////// +// // +// gb_String - C Compatible // +// // +//////////////////////////////// - uintptr* end = cast(uintptr*, curr); - *end = cast(uintptr, NULL); - pool.physical_start = data; - pool.free_list = data; +// Pascal like strings in C +typedef char *gb_String; - /* Set functions pointers */ - pool.base.alloc = gb__pool_alloc; - pool.base.free = gb__pool_free; - pool.base.allocated_size = gb__pool_allocated_size; - pool.base.total_allocated = gb__pool_total_allocated; +#ifndef GB_STRING_SIZE +#define GB_STRING_SIZE +typedef u32 gb_String_Size; +#endif - return pool; -} -void -gb_pool_destroy(gb_Pool* pool) +// This is stored at the beginning of the string +// NOTE(bill): It is (2*sizeof(gb_String_Size) + 2*sizeof(void*)) (default: 16B (32bit), 24B (64bit)) +// NOTE(bill): If you only need a small string, just use a standard c string +typedef struct gb_String_Header { - gb_free(pool->backing, pool->physical_start); -} - - + gb_Allocator allocator; + gb_String_Size length; + gb_String_Size capacity; +} gb_String_Header; +#define GB_STRING_HEADER(str) (cast(gb_String_Header *)str - 1) -/**********************************/ -/* */ -/* Memory */ -/* */ -/**********************************/ +gb_String gb_string_make(gb_Allocator a, char const *str); +gb_String gb_string_make_length(gb_Allocator a, void const *str, gb_String_Size num_bytes); +void gb_string_free(gb_String str); -void* -gb_align_forward(void* ptr, usize align) -{ - GB_ASSERT(GB_IS_POWER_OF_TWO(align)); +gb_String gb_string_duplicate(gb_Allocator a, gb_String const str); - uintptr p = cast(uintptr, ptr); - usize modulo = p % align; - if (modulo) p += (align - modulo); - return cast(void*, p); -} +gb_String_Size gb_string_length(gb_String const str); +gb_String_Size gb_string_capacity(gb_String const str); +gb_String_Size gb_string_available_space(gb_String const str); -void* gb_zero_size(void* ptr, usize bytes) { return memset(ptr, 0, bytes); } +void gb_string_clear(gb_String str); +gb_String gb_string_append_string(gb_String str, gb_String const other); +gb_String gb_string_append_string_length(gb_String str, void const *other, gb_String_Size num_bytes); +gb_String gb_string_append_cstring(gb_String str, char const *other); +gb_String gb_string_set(gb_String str, char const *cstr); +gb_String gb_string_make_space_for(gb_String str, gb_String_Size add_len); +gb_String_Size gb_string_allocation_size(gb_String const str); -/**********************************/ -/* */ -/* String - C Compatibile */ -/* */ -/**********************************/ +b32 gb_strings_are_equal(gb_String const lhs, gb_String const rhs); +gb_String gb_string_trim(gb_String str, char const *cut_set); +gb_String gb_string_trim_space(gb_String str); /* Whitespace ` \t\r\n\v\f` */ -static void -gb__string_set_length(gb_String str, gb_String_Size len) -{ - GB_STRING_HEADER(str)->length = len; -} +#if defined(GB_IMPLEMENTATION) -static void -gb__string_set_capacity(gb_String str, gb_String_Size cap) -{ - GB_STRING_HEADER(str)->capacity = cap; -} +gb_inline void gb__string_set_length(gb_String str, gb_String_Size len) { GB_STRING_HEADER(str)->length = len; } +gb_inline void gb__string_set_capacity(gb_String str, gb_String_Size cap) { GB_STRING_HEADER(str)->capacity = cap; } -gb_String -gb_string_make(gb_Allocator* a, char const* str) +gb_inline gb_String +gb_string_make(gb_Allocator a, char const *str) { - gb_String_Size len = cast(gb_String_Size, str ? strlen(str) : 0); + gb_String_Size len = cast(gb_String_Size)(str ? strlen(str) : 0); return gb_string_make_length(a, str, len); } gb_String -gb_string_make_length(gb_Allocator* a, void const* init_str, gb_String_Size num_bytes) +gb_string_make_length(gb_Allocator a, void const *init_str, gb_String_Size num_bytes) { gb_String_Size header_size = sizeof(gb_String_Header); - void* ptr = gb_alloc(a, header_size + num_bytes + 1); - if (!init_str) gb_zero_size(ptr, header_size + num_bytes + 1); + void *ptr = gb_alloc(a, header_size + num_bytes + 1); + + gb_String str; + gb_String_Header *header; + if (!init_str) gb_zero_size(ptr, header_size + num_bytes + 1); if (ptr == NULL) return NULL; - gb_String str = (char*)ptr + header_size; - gb_String_Header* header = GB_STRING_HEADER(str); + str = cast(char *)ptr + header_size; + header = GB_STRING_HEADER(str); header->allocator = a; header->length = num_bytes; header->capacity = num_bytes; @@ -1759,61 +664,38 @@ gb_string_make_length(gb_Allocator* a, void const* init_str, gb_String_Size num_ return str; } -void +gb_inline void gb_string_free(gb_String str) { - if (str == NULL) return; - - gb_String_Header* header = GB_STRING_HEADER(str); - gb_free(header->allocator, header); -} - - -gb_String -gb_string_duplicate(gb_Allocator* a, gb_String const str) -{ - return gb_string_make_length(a, str, gb_string_length(str)); + if (str) { + gb_String_Header *header; + header = GB_STRING_HEADER(str); + gb_free(header->allocator, header); + } } -gb_String_Size -gb_string_length(gb_String const str) -{ - return GB_STRING_HEADER(str)->length; -} +gb_inline gb_String gb_string_duplicate(gb_Allocator a, gb_String const str) { return gb_string_make_length(a, str, gb_string_length(str)); } -gb_String_Size -gb_string_capacity(gb_String const str) -{ - return GB_STRING_HEADER(str)->capacity; -} +gb_inline gb_String_Size gb_string_length(gb_String const str) { return GB_STRING_HEADER(str)->length; } +gb_inline gb_String_Size gb_string_capacity(gb_String const str) { return GB_STRING_HEADER(str)->capacity; } -gb_String_Size +gb_inline gb_String_Size gb_string_available_space(gb_String const str) { - gb_String_Header* h = GB_STRING_HEADER(str); + gb_String_Header *h = GB_STRING_HEADER(str); if (h->capacity > h->length) return h->capacity - h->length; return 0; } -void -gb_string_clear(gb_String str) -{ - gb__string_set_length(str, 0); - str[0] = '\0'; -} - +gb_inline void gb_string_clear(gb_String str) { gb__string_set_length(str, 0); str[0] = '\0'; } -gb_String -gb_string_append_string(gb_String str, gb_String const other) -{ - return gb_string_append_string_length(str, other, gb_string_length(other)); -} +gb_inline gb_String gb_string_append_string(gb_String str, gb_String const other) { return gb_string_append_string_length(str, other, gb_string_length(other)); } gb_String -gb_string_append_string_length(gb_String str, void const* other, gb_String_Size other_len) +gb_string_append_string_length(gb_String str, void const *other, gb_String_Size other_len) { gb_String_Size curr_len = gb_string_length(str); @@ -1828,19 +710,18 @@ gb_string_append_string_length(gb_String str, void const* other, gb_String_Size return str; } -gb_String -gb_string_append_cstring(gb_String str, char const* other) +gb_inline gb_String +gb_string_append_cstring(gb_String str, char const *other) { - return gb_string_append_string_length(str, other, cast(gb_String_Size, strlen(other))); + return gb_string_append_string_length(str, other, cast(gb_String_Size)strlen(other)); } gb_String -gb_string_set(gb_String str, char const* cstr) +gb_string_set(gb_String str, char const *cstr) { - gb_String_Size len = cast(gb_String_Size, strlen(cstr)); - if (gb_string_capacity(str) < len) - { + gb_String_Size len = cast(gb_String_Size)strlen(cstr); + if (gb_string_capacity(str) < len) { str = gb_string_make_space_for(str, len - gb_string_length(str)); if (str == NULL) return NULL; @@ -1854,26 +735,25 @@ gb_string_set(gb_String str, char const* cstr) } -static void* -gb__string_realloc(gb_Allocator* a, void* ptr, gb_String_Size old_size, gb_String_Size new_size) +local_persist void * +gb__string_realloc(gb_Allocator a, void *ptr, gb_String_Size old_size, gb_String_Size new_size) { if (!ptr) return gb_alloc(a, new_size); if (new_size < old_size) new_size = old_size; - if (old_size == new_size) + if (old_size == new_size) { return ptr; + } else { + void *new_ptr = gb_alloc(a, new_size); + if (!new_ptr) + return NULL; - void* new_ptr = gb_alloc(a, new_size); - if (!new_ptr) - return NULL; - - memcpy(new_ptr, ptr, old_size); - - gb_free(a, ptr); - - return new_ptr; + memcpy(new_ptr, ptr, old_size); + gb_free(a, ptr); + return new_ptr; + } } @@ -1881,29 +761,28 @@ gb__string_realloc(gb_Allocator* a, void* ptr, gb_String_Size old_size, gb_Strin gb_String gb_string_make_space_for(gb_String str, gb_String_Size add_len) { - gb_String_Size len = gb_string_length(str); - gb_String_Size new_len = len + add_len; - gb_String_Size available = gb_string_available_space(str); - if (available >= add_len) /* Return if there is enough space left */ - return str; - - void* ptr = GB_STRING_HEADER(str); - gb_String_Size old_size = sizeof(struct gb_String_Header) + gb_string_length(str) + 1; - gb_String_Size new_size = sizeof(struct gb_String_Header) + new_len + 1; + // Return if there is enough space left + if (available >= add_len) { + return str; + } else { + gb_String_Size new_len = gb_string_length(str) + add_len; + void *ptr = GB_STRING_HEADER(str); + gb_String_Size old_size = sizeof(struct gb_String_Header) + gb_string_length(str) + 1; + gb_String_Size new_size = sizeof(struct gb_String_Header) + new_len + 1; - void* new_ptr = gb__string_realloc(GB_STRING_HEADER(str)->allocator, ptr, old_size, new_size); - if (new_ptr == NULL) - return NULL; - str = cast(char*, GB_STRING_HEADER(new_ptr) + 1); + void *new_ptr = gb__string_realloc(GB_STRING_HEADER(str)->allocator, ptr, old_size, new_size); + if (new_ptr == NULL) return NULL; - gb__string_set_capacity(str, new_len); + str = cast(char *)(GB_STRING_HEADER(new_ptr) + 1); + gb__string_set_capacity(str, new_len); - return str; + return str; + } } -gb_String_Size +gb_inline gb_String_Size gb_string_allocation_size(gb_String const str) { gb_String_Size cap = gb_string_capacity(str); @@ -1911,15 +790,16 @@ gb_string_allocation_size(gb_String const str) } -bool32 +gb_inline b32 gb_strings_are_equal(gb_String const lhs, gb_String const rhs) { - gb_String_Size lhs_len = gb_string_length(lhs); - gb_String_Size rhs_len = gb_string_length(rhs); + gb_String_Size lhs_len, rhs_len, i; + lhs_len = gb_string_length(lhs); + rhs_len = gb_string_length(rhs); if (lhs_len != rhs_len) return false; - for (gb_String_Size i = 0; i < lhs_len; i++) { + for (i = 0; i < lhs_len; i++) { if (lhs[i] != rhs[i]) return false; } @@ -1929,12 +809,10 @@ gb_strings_are_equal(gb_String const lhs, gb_String const rhs) gb_String -gb_string_trim(gb_String str, char const* cut_set) +gb_string_trim(gb_String str, char const *cut_set) { - char* start; - char* end; - char* start_pos; - char* end_pos; + char *start, *end, *start_pos, *end_pos; + gb_String_Size len; start_pos = start = str; end_pos = end = str + gb_string_length(str) - 1; @@ -1944,7 +822,7 @@ gb_string_trim(gb_String str, char const* cut_set) while (end_pos > start_pos && strchr(cut_set, *end_pos)) end_pos--; - gb_String_Size len = cast(gb_String_Size, (start_pos > end_pos) ? 0 : ((end_pos - start_pos)+1)); + len = cast(gb_String_Size)((start_pos > end_pos) ? 0 : ((end_pos - start_pos)+1)); if (str != start_pos) memmove(str, start_pos, len); @@ -1955,582 +833,23 @@ gb_string_trim(gb_String str, char const* cut_set) return str; } -gb_String gb_string_trim_space(gb_String str) { return gb_string_trim(str, " \t\r\n\v\f"); } - - - -u32 -gb_hash_adler32(void const* key, u32 num_bytes) -{ - const u32 MOD_ADLER = 65521; - - u32 a = 1; - u32 b = 0; - - u8 const* bytes = cast(u8 const*, key); - for (u32 i = 0; i < num_bytes; i++) - { - a = (a + bytes[i]) % MOD_ADLER; - b = (b + a) % MOD_ADLER; - } - - return (b << 16) | a; -} - -static const u32 GB_CRC32_TABLE[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, -}; - -static const u64 GB_CRC64_TABLE[256] = { - 0x0000000000000000ull, 0x42F0E1EBA9EA3693ull, 0x85E1C3D753D46D26ull, 0xC711223CFA3E5BB5ull, - 0x493366450E42ECDFull, 0x0BC387AEA7A8DA4Cull, 0xCCD2A5925D9681F9ull, 0x8E224479F47CB76Aull, - 0x9266CC8A1C85D9BEull, 0xD0962D61B56FEF2Dull, 0x17870F5D4F51B498ull, 0x5577EEB6E6BB820Bull, - 0xDB55AACF12C73561ull, 0x99A54B24BB2D03F2ull, 0x5EB4691841135847ull, 0x1C4488F3E8F96ED4ull, - 0x663D78FF90E185EFull, 0x24CD9914390BB37Cull, 0xE3DCBB28C335E8C9ull, 0xA12C5AC36ADFDE5Aull, - 0x2F0E1EBA9EA36930ull, 0x6DFEFF5137495FA3ull, 0xAAEFDD6DCD770416ull, 0xE81F3C86649D3285ull, - 0xF45BB4758C645C51ull, 0xB6AB559E258E6AC2ull, 0x71BA77A2DFB03177ull, 0x334A9649765A07E4ull, - 0xBD68D2308226B08Eull, 0xFF9833DB2BCC861Dull, 0x388911E7D1F2DDA8ull, 0x7A79F00C7818EB3Bull, - 0xCC7AF1FF21C30BDEull, 0x8E8A101488293D4Dull, 0x499B3228721766F8ull, 0x0B6BD3C3DBFD506Bull, - 0x854997BA2F81E701ull, 0xC7B97651866BD192ull, 0x00A8546D7C558A27ull, 0x4258B586D5BFBCB4ull, - 0x5E1C3D753D46D260ull, 0x1CECDC9E94ACE4F3ull, 0xDBFDFEA26E92BF46ull, 0x990D1F49C77889D5ull, - 0x172F5B3033043EBFull, 0x55DFBADB9AEE082Cull, 0x92CE98E760D05399ull, 0xD03E790CC93A650Aull, - 0xAA478900B1228E31ull, 0xE8B768EB18C8B8A2ull, 0x2FA64AD7E2F6E317ull, 0x6D56AB3C4B1CD584ull, - 0xE374EF45BF6062EEull, 0xA1840EAE168A547Dull, 0x66952C92ECB40FC8ull, 0x2465CD79455E395Bull, - 0x3821458AADA7578Full, 0x7AD1A461044D611Cull, 0xBDC0865DFE733AA9ull, 0xFF3067B657990C3Aull, - 0x711223CFA3E5BB50ull, 0x33E2C2240A0F8DC3ull, 0xF4F3E018F031D676ull, 0xB60301F359DBE0E5ull, - 0xDA050215EA6C212Full, 0x98F5E3FE438617BCull, 0x5FE4C1C2B9B84C09ull, 0x1D14202910527A9Aull, - 0x93366450E42ECDF0ull, 0xD1C685BB4DC4FB63ull, 0x16D7A787B7FAA0D6ull, 0x5427466C1E109645ull, - 0x4863CE9FF6E9F891ull, 0x0A932F745F03CE02ull, 0xCD820D48A53D95B7ull, 0x8F72ECA30CD7A324ull, - 0x0150A8DAF8AB144Eull, 0x43A04931514122DDull, 0x84B16B0DAB7F7968ull, 0xC6418AE602954FFBull, - 0xBC387AEA7A8DA4C0ull, 0xFEC89B01D3679253ull, 0x39D9B93D2959C9E6ull, 0x7B2958D680B3FF75ull, - 0xF50B1CAF74CF481Full, 0xB7FBFD44DD257E8Cull, 0x70EADF78271B2539ull, 0x321A3E938EF113AAull, - 0x2E5EB66066087D7Eull, 0x6CAE578BCFE24BEDull, 0xABBF75B735DC1058ull, 0xE94F945C9C3626CBull, - 0x676DD025684A91A1ull, 0x259D31CEC1A0A732ull, 0xE28C13F23B9EFC87ull, 0xA07CF2199274CA14ull, - 0x167FF3EACBAF2AF1ull, 0x548F120162451C62ull, 0x939E303D987B47D7ull, 0xD16ED1D631917144ull, - 0x5F4C95AFC5EDC62Eull, 0x1DBC74446C07F0BDull, 0xDAAD56789639AB08ull, 0x985DB7933FD39D9Bull, - 0x84193F60D72AF34Full, 0xC6E9DE8B7EC0C5DCull, 0x01F8FCB784FE9E69ull, 0x43081D5C2D14A8FAull, - 0xCD2A5925D9681F90ull, 0x8FDAB8CE70822903ull, 0x48CB9AF28ABC72B6ull, 0x0A3B7B1923564425ull, - 0x70428B155B4EAF1Eull, 0x32B26AFEF2A4998Dull, 0xF5A348C2089AC238ull, 0xB753A929A170F4ABull, - 0x3971ED50550C43C1ull, 0x7B810CBBFCE67552ull, 0xBC902E8706D82EE7ull, 0xFE60CF6CAF321874ull, - 0xE224479F47CB76A0ull, 0xA0D4A674EE214033ull, 0x67C58448141F1B86ull, 0x253565A3BDF52D15ull, - 0xAB1721DA49899A7Full, 0xE9E7C031E063ACECull, 0x2EF6E20D1A5DF759ull, 0x6C0603E6B3B7C1CAull, - 0xF6FAE5C07D3274CDull, 0xB40A042BD4D8425Eull, 0x731B26172EE619EBull, 0x31EBC7FC870C2F78ull, - 0xBFC9838573709812ull, 0xFD39626EDA9AAE81ull, 0x3A28405220A4F534ull, 0x78D8A1B9894EC3A7ull, - 0x649C294A61B7AD73ull, 0x266CC8A1C85D9BE0ull, 0xE17DEA9D3263C055ull, 0xA38D0B769B89F6C6ull, - 0x2DAF4F0F6FF541ACull, 0x6F5FAEE4C61F773Full, 0xA84E8CD83C212C8Aull, 0xEABE6D3395CB1A19ull, - 0x90C79D3FEDD3F122ull, 0xD2377CD44439C7B1ull, 0x15265EE8BE079C04ull, 0x57D6BF0317EDAA97ull, - 0xD9F4FB7AE3911DFDull, 0x9B041A914A7B2B6Eull, 0x5C1538ADB04570DBull, 0x1EE5D94619AF4648ull, - 0x02A151B5F156289Cull, 0x4051B05E58BC1E0Full, 0x87409262A28245BAull, 0xC5B073890B687329ull, - 0x4B9237F0FF14C443ull, 0x0962D61B56FEF2D0ull, 0xCE73F427ACC0A965ull, 0x8C8315CC052A9FF6ull, - 0x3A80143F5CF17F13ull, 0x7870F5D4F51B4980ull, 0xBF61D7E80F251235ull, 0xFD913603A6CF24A6ull, - 0x73B3727A52B393CCull, 0x31439391FB59A55Full, 0xF652B1AD0167FEEAull, 0xB4A25046A88DC879ull, - 0xA8E6D8B54074A6ADull, 0xEA16395EE99E903Eull, 0x2D071B6213A0CB8Bull, 0x6FF7FA89BA4AFD18ull, - 0xE1D5BEF04E364A72ull, 0xA3255F1BE7DC7CE1ull, 0x64347D271DE22754ull, 0x26C49CCCB40811C7ull, - 0x5CBD6CC0CC10FAFCull, 0x1E4D8D2B65FACC6Full, 0xD95CAF179FC497DAull, 0x9BAC4EFC362EA149ull, - 0x158E0A85C2521623ull, 0x577EEB6E6BB820B0ull, 0x906FC95291867B05ull, 0xD29F28B9386C4D96ull, - 0xCEDBA04AD0952342ull, 0x8C2B41A1797F15D1ull, 0x4B3A639D83414E64ull, 0x09CA82762AAB78F7ull, - 0x87E8C60FDED7CF9Dull, 0xC51827E4773DF90Eull, 0x020905D88D03A2BBull, 0x40F9E43324E99428ull, - 0x2CFFE7D5975E55E2ull, 0x6E0F063E3EB46371ull, 0xA91E2402C48A38C4ull, 0xEBEEC5E96D600E57ull, - 0x65CC8190991CB93Dull, 0x273C607B30F68FAEull, 0xE02D4247CAC8D41Bull, 0xA2DDA3AC6322E288ull, - 0xBE992B5F8BDB8C5Cull, 0xFC69CAB42231BACFull, 0x3B78E888D80FE17Aull, 0x7988096371E5D7E9ull, - 0xF7AA4D1A85996083ull, 0xB55AACF12C735610ull, 0x724B8ECDD64D0DA5ull, 0x30BB6F267FA73B36ull, - 0x4AC29F2A07BFD00Dull, 0x08327EC1AE55E69Eull, 0xCF235CFD546BBD2Bull, 0x8DD3BD16FD818BB8ull, - 0x03F1F96F09FD3CD2ull, 0x41011884A0170A41ull, 0x86103AB85A2951F4ull, 0xC4E0DB53F3C36767ull, - 0xD8A453A01B3A09B3ull, 0x9A54B24BB2D03F20ull, 0x5D45907748EE6495ull, 0x1FB5719CE1045206ull, - 0x919735E51578E56Cull, 0xD367D40EBC92D3FFull, 0x1476F63246AC884Aull, 0x568617D9EF46BED9ull, - 0xE085162AB69D5E3Cull, 0xA275F7C11F7768AFull, 0x6564D5FDE549331Aull, 0x279434164CA30589ull, - 0xA9B6706FB8DFB2E3ull, 0xEB46918411358470ull, 0x2C57B3B8EB0BDFC5ull, 0x6EA7525342E1E956ull, - 0x72E3DAA0AA188782ull, 0x30133B4B03F2B111ull, 0xF7021977F9CCEAA4ull, 0xB5F2F89C5026DC37ull, - 0x3BD0BCE5A45A6B5Dull, 0x79205D0E0DB05DCEull, 0xBE317F32F78E067Bull, 0xFCC19ED95E6430E8ull, - 0x86B86ED5267CDBD3ull, 0xC4488F3E8F96ED40ull, 0x0359AD0275A8B6F5ull, 0x41A94CE9DC428066ull, - 0xCF8B0890283E370Cull, 0x8D7BE97B81D4019Full, 0x4A6ACB477BEA5A2Aull, 0x089A2AACD2006CB9ull, - 0x14DEA25F3AF9026Dull, 0x562E43B4931334FEull, 0x913F6188692D6F4Bull, 0xD3CF8063C0C759D8ull, - 0x5DEDC41A34BBEEB2ull, 0x1F1D25F19D51D821ull, 0xD80C07CD676F8394ull, 0x9AFCE626CE85B507ull, -}; - -u32 -gb_hash_crc32(void const* key, u32 num_bytes) -{ - u32 result = cast(u32, ~0); - u8 const* c = cast(u8 const*, key); - - for (u32 remaining = num_bytes; remaining--; c++) - result = (result >> 8) ^ (GB_CRC32_TABLE[(result ^ *c) & 0xff]); - - return ~result; -} - -u64 -gb_hash_crc64(void const* key, usize num_bytes) -{ - u64 result = cast(u64, ~0); - u8 const* c = cast(u8 const*, key); - for (usize remaining = num_bytes; remaining--; c++) - result = (result >> 8) ^ (GB_CRC64_TABLE[(result ^ *c) & 0xff]); - - return ~result; -} - - -u32 -gb_hash_fnv32(void const* key, usize num_bytes) -{ - u32 h = 0x811c9dc5; - u8 const* buffer = cast(u8 const*, key); - - for (usize i = 0; i < num_bytes; i++) - h = (h * 0x01000193) ^ buffer[i]; - - return h; -} +gb_inline gb_String gb_string_trim_space(gb_String str) { return gb_string_trim(str, " \t\r\n\v\f"); } -u64 -gb_hash_fnv64(void const* key, usize num_bytes) -{ - u64 h = 0xcbf29ce484222325ull; - u8 const* buffer = cast(u8 const*, key); - - for (usize i = 0; i < num_bytes; i++) - h = (h * 0x100000001b3ll) ^ buffer[i]; - - return h; -} - -u32 -gb_hash_fnv32a(void const* key, usize num_bytes) -{ - u32 h = 0x811c9dc5; - u8 const* buffer = cast(u8 const*, key); - - for (usize i = 0; i < num_bytes; i++) - h = (h ^ buffer[i]) * 0x01000193; - - return h; -} - -u64 -gb_hash_fnv64a(void const* key, usize num_bytes) -{ - u64 h = 0xcbf29ce484222325ull; - u8 const* buffer = cast(u8 const*, key); - - for (usize i = 0; i < num_bytes; i++) - h = (h ^ buffer[i]) * 0x100000001b3ll; - - return h; -} - - -u32 -gb_hash_murmur32(void const* key, u32 num_bytes, u32 seed) -{ - const u32 c1 = 0xcc9e2d51; - const u32 c2 = 0x1b873593; - const u32 r1 = 15; - const u32 r2 = 13; - const u32 m = 5; - const u32 n = 0xe6546b64; - - u32 hash = seed; - - const usize nblocks = num_bytes / 4; - const u32* blocks = cast(const u32*, key); - for (usize i = 0; i < nblocks; i++) - { - u32 k = blocks[i]; - k *= c1; - k = (k << r1) | (k >> (32 - r1)); - k *= c2; - - hash ^= k; - hash = ((hash << r2) | (hash >> (32 - r2))) * m + n; - } - - u8 const* tail = (cast(u8 const*, key)) + nblocks * 4; - u32 k1 = 0; - - switch (num_bytes & 3) - { - case 3: - k1 ^= tail[2] << 16; - case 2: - k1 ^= tail[1] << 8; - case 1: - k1 ^= tail[0]; - - k1 *= c1; - k1 = (k1 << r1) | (k1 >> (32 - r1)); - k1 *= c2; - hash ^= k1; - } - - hash ^= num_bytes; - hash ^= (hash >> 16); - hash *= 0x85ebca6b; - hash ^= (hash >> 13); - hash *= 0xc2b2ae35; - hash ^= (hash >> 16); - - return hash; -} - -#if defined(GB_ARCH_64_BIT) - u64 - gb_hash_murmur64(void const* key, usize num_bytes, u64 seed) - { - const u64 m = 0xc6a4a7935bd1e995ULL; - const s32 r = 47; - - u64 h = seed ^ (num_bytes * m); - - const u64* data = cast(const u64*, key); - const u64* end = data + (num_bytes / 8); - - while (data != end) - { - u64 k = *data++; - - k *= m; - k ^= k >> r; - k *= m; - - h ^= k; - h *= m; - } - - u8 const* data2 = cast(u8 const*, data); - - switch (num_bytes & 7) - { - case 7: h ^= cast(u64, data2[6]) << 48; - case 6: h ^= cast(u64, data2[5]) << 40; - case 5: h ^= cast(u64, data2[4]) << 32; - case 4: h ^= cast(u64, data2[3]) << 24; - case 3: h ^= cast(u64, data2[2]) << 16; - case 2: h ^= cast(u64, data2[1]) << 8; - case 1: h ^= cast(u64, data2[0]); - h *= m; - }; - - h ^= h >> r; - h *= m; - h ^= h >> r; - - return h; - } -#elif GB_ARCH_32_BIT - u64 - gb_hash_murmur64(void const* key, usize num_bytes, u64 seed) - { - const u32 m = 0x5bd1e995; - const s32 r = 24; - - u32 h1 = cast(u32, seed) ^ cast(u32, num_bytes); - u32 h2 = cast(u32, seed >> 32); - - const u32* data = cast(const u32*, key); - - while (num_bytes >= 8) - { - u32 k1 = *data++; - k1 *= m; - k1 ^= k1 >> r; - k1 *= m; - h1 *= m; - h1 ^= k1; - num_bytes -= 4; - - u32 k2 = *data++; - k2 *= m; - k2 ^= k2 >> r; - k2 *= m; - h2 *= m; - h2 ^= k2; - num_bytes -= 4; - } - - if (num_bytes >= 4) - { - u32 k1 = *data++; - k1 *= m; - k1 ^= k1 >> r; - k1 *= m; - h1 *= m; - h1 ^= k1; - num_bytes -= 4; - } - - switch (num_bytes) - { - case 3: h2 ^= cast(u8 const*, data)[2] << 16; - case 2: h2 ^= cast(u8 const*, data)[1] << 8; - case 1: h2 ^= cast(u8 const*, data)[0] << 0; - h2 *= m; - }; - - h1 ^= h2 >> 18; - h1 *= m; - h2 ^= h1 >> 22; - h2 *= m; - h1 ^= h2 >> 17; - h1 *= m; - h2 ^= h1 >> 19; - h2 *= m; - - u64 h = h1; - - h = (h << 32) | h2; - - return h; - } -#else - #error gb_hash_murmur64 function not supported on this architecture -#endif - - -/**********************************/ -/* */ -/* Hash */ -/* */ -/**********************************/ - - -#if defined(GB_SYSTEM_WINDOWS) - gb_Time - gb_time_now() - { - /* NOTE(bill): std::chrono does not have a good enough precision in MSVC12 - * and below. This may have been fixed in MSVC14 but unsure as of yet. - */ - - /* Force the following code to run on first core */ - /* NOTE(bill, 2015): See - * http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx - */ - HANDLE currentThread = GetCurrentThread(); - DWORD_PTR previousMask = SetThreadAffinityMask(currentThread, 1); - - /* Get the frequency of the performance counter */ - /* It is constant across the program's lifetime */ - static LARGE_INTEGER s_frequency; - QueryPerformanceFrequency(&s_frequency); /* TODO(bill): Is this fast enough? */ - - /* Get the current time */ - LARGE_INTEGER t; - QueryPerformanceCounter(&t); - - /* Restore the thread affinity */ - SetThreadAffinityMask(currentThread, previousMask); - - return gb_time_microseconds(1000000ll * t.QuadPart / s_frequency.QuadPart); - } - - void - gb_time_sleep(gb_Time t) - { - if (t.microseconds <= 0) return; - - /* Get the supported timer resolutions on this system */ - TIMECAPS tc; - timeGetDevCaps(&tc, sizeof(TIMECAPS)); - /* Set the timer resolution to the minimum for the Sleep call */ - timeBeginPeriod(tc.wPeriodMin); - - /* Wait... */ - Sleep(gb_time_as_milliseconds(t)); - - /* Reset the timer resolution back to the system default */ - timeBeginPeriod(tc.wPeriodMin); - } - -#else - gb_Time - gb_time_now() - { - #if defined(GB_SYSTEM_OSX) - s64 t = cast(s64, mach_absolute_time()); - return gb_time_microseconds(t); - #else - struct timeval t; - gettimeofday(&t, nullptr); - - return gb_time_microseconds((t.tv_sec * 1000000ll) + (t.tv_usec * 1ll)); - #endif - } - - void - gb_time_sleep(gb_Time t) - { - if (t.microseconds <= 0) return; - - struct timespec spec = {}; - spec.tv_sec = cast(s64, gb_time_as_seconds(t)); - spec.tv_nsec = 1000ll * (gb_time_as_microseconds(t) % 1000000ll); - - nanosleep(&spec, nullptr); - } #endif -gb_Time -gb_time_seconds(f32 s) -{ - gb_Time result; - result.microseconds = cast(s64, s * 1000000ll); - return result; -} - -gb_Time -gb_time_milliseconsd(s32 ms) -{ - gb_Time result; - result.microseconds = cast(s64, ms * 1000ll); - return result; -} - -gb_Time -gb_time_microseconds(s64 us) -{ - gb_Time result; - result.microseconds = us; - return result; -} - -f32 gb_time_as_seconds(gb_Time t) { return cast(f32, t.microseconds / 1000000.0f); } -s32 gb_time_as_milliseconds(gb_Time t) { return cast(s32, t.microseconds / 1000l); } -s64 gb_time_as_microseconds(gb_Time t) { return t.microseconds; } - -/**********************************/ -/* */ -/* Time */ -/* */ -/**********************************/ - -/* - * lhs < rhs -1 - * lhs == rhs 0 - * lhs > rhs +1 - */ -s32 -gb_time_cmp(gb_Time lhs, gb_Time rhs) -{ - if (lhs.microseconds < rhs.microseconds) - return -1; - if (lhs.microseconds == rhs.microseconds) - return 0; - return +1; -} - -gb_Time -gb_time_add(gb_Time lhs, gb_Time rhs) -{ - lhs.microseconds += rhs.microseconds; - return lhs; -} - -gb_Time -gb_time_sub(gb_Time lhs, gb_Time rhs) -{ - lhs.microseconds -= rhs.microseconds; - return lhs; -} - -gb_Time -gb_time_mod(gb_Time lhs, gb_Time rhs) -{ - lhs.microseconds %= rhs.microseconds; - return lhs; -} -gb_Time -gb_time_mul(gb_Time t, f32 s) -{ - gb_Time result = gb_time_seconds(gb_time_as_seconds(t) * s); - return result; -} -gb_Time -gb_time_div(gb_Time t, f32 s) -{ - gb_Time result = gb_time_seconds(gb_time_as_seconds(t) / s); - return result; -} +//////////////////////////////// +// // +// Unfinished code // +// // +//////////////////////////////// -f32 -gb_time_div_time(gb_Time num, gb_Time dom) -{ - f32 result = num.microseconds / cast(f32, dom.microseconds); - return result; -} #if defined(__cplusplus) } -#endif /* extern "C" */ - -#endif /* GB_IMPLEMENTATION */ - +#endif +#endif // GB_INCLUDE_GB_H |
