From dc5fe7638c42b59b8c07c0c0529a084bfd68b284 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 12 Apr 2016 21:52:09 +0100 Subject: [PATCH] Update gb.h --- gb.h | 918 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 529 insertions(+), 389 deletions(-) diff --git a/gb.h b/gb.h index ed16d80..9a51b0f 100644 --- a/gb.h +++ b/gb.h @@ -1,5 +1,5 @@ -/* gb.h - v0.02 - Ginger Bill's C Helper Library - public domain - - no warranty implied; use at your own risk +/* gb.h - v0.02a - Ginger Bill's C Helper Library - public domain + - no warranty implied; use at your own risk This is a single header file with a bunch of useful stuff to replace the C/C++ standard library @@ -18,8 +18,16 @@ All other files should just #include "gb.h" without #define =========================================================================== +Conventions used: + gbTypes_Are_Like_This (None core types) + gb_functions_and_variables_like_this + Prefer // Comments + Never use _t suffix for types + Private "things" will have prefix `gbpriv` (e.g. Things the user shouldn't be touch if they don't know what they are doing) + Version History: + 0.02a - Bug fixes 0.02 - Change naming convention and gbArray(Type) 0.01 - Initial Version @@ -62,11 +70,30 @@ CREDITS extern "C" { #endif + +#ifndef GB_EXTERN + #if defined(__cplusplus) + #define GB_EXTERN extern "C" + #else + #define GB_EXTERN extern + #endif +#endif + +#ifndef GB_DLL_EXPORT +#define GB_DLL_EXPORT __declspec(dllexport) +#endif + +#ifndef GB_DLL_IMPORT +#define GB_DLL_IMPORT __declspec(dllimport) +#endif + + +// NOTE(bill): Redefine for DLL, etc. #ifndef GB_DEF #ifdef GB_STATIC #define GB_DEF static #else - #define GB_DEF extern + #define GB_DEF GB_EXTERN #endif #endif @@ -161,6 +188,11 @@ extern "C" { typedef int64_t i64; #endif +GB_STATIC_ASSERT(sizeof(u8) == sizeof(i8)); +GB_STATIC_ASSERT(sizeof(u16) == sizeof(i16)); +GB_STATIC_ASSERT(sizeof(u32) == sizeof(i32)); +GB_STATIC_ASSERT(sizeof(u64) == sizeof(i64)); + GB_STATIC_ASSERT(sizeof(u8) == 1); GB_STATIC_ASSERT(sizeof(u16) == 2); GB_STATIC_ASSERT(sizeof(u32) == 4); @@ -177,6 +209,7 @@ typedef intptr_t intptr; typedef float f32; typedef double f64; + GB_STATIC_ASSERT(sizeof(f32) == 4); GB_STATIC_ASSERT(sizeof(f64) == 8); @@ -187,7 +220,7 @@ typedef u32 char32; // NOTE(bill): I think C99 and C++ `bool` is stupid for numerous reasons but there are too many // to write in this small comment. typedef i32 b32; // NOTE(bill): Use this in structs if a boolean _is_ needed to be aligned well -typedef i8 b8; +typedef i8 b8; // TODO(bill): Do I really want a 8-bit boolean ever? // NOTE(bill): Get true and false #if !defined(__cplusplus) @@ -206,18 +239,18 @@ typedef i8 b8; #ifndef U8_MIN #define U8_MIN 0u #define U8_MAX 0xffu -#define S8_MIN (-0x7f - 1) -#define S8_MAX 0x7f +#define I8_MIN (-0x7f - 1) +#define I8_MAX 0x7f #define U16_MIN 0u #define U16_MAX 0xffffu -#define S16_MIN (-0x7fff - 1) -#define S16_MAX 0x7fff +#define I16_MIN (-0x7fff - 1) +#define I16_MAX 0x7fff #define U32_MIN 0u #define U32_MAX 0xffffffffu -#define S32_MIN (-0x7fffffff - 1) -#define S32_MAX 0x7fffffff +#define I32_MIN (-0x7fffffff - 1) +#define I32_MAX 0x7fffffff #define U64_MIN 0ull #define U64_MAX 0xffffffffffffffffull @@ -240,6 +273,13 @@ typedef i8 b8; #error Unknown architecture size #endif +#define F32_MIN 1.17549435e-38f +#define F32_MAX 3.40282347e+38f + +#define F64_MIN 2.2250738585072014e-308 +#define F64_MAX 1.7976931348623157e+308 + + #endif @@ -258,8 +298,9 @@ typedef i8 b8; -#if !defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER <= 1800 - #define inline __inline +#if !defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER <= 1800 + #define inline __inline + #define restrict __restrict #endif @@ -279,16 +320,6 @@ typedef i8 b8; #endif #endif -#ifndef GB_EXTERN - #if defined(__cplusplus) - #define GB_EXTERN extern "C" - #else - #define GB_EXTERN extern - #endif -#endif - - - // NOTE(bill): Easy to grep // NOTE(bill): Not needed in macros #ifndef cast @@ -296,40 +327,47 @@ typedef i8 b8; #endif +// NOTE(bill): Because a signed sizeof is more useful #ifndef gb_size_of -#define gb_size_of(x) cast(i64)(sizeof(x)) +#define gb_size_of(x) (isize)(sizeof(x)) #endif #ifndef gb_count_of -#define gb_count_of(x) ((gb_size_of(x)/gb_size_of(0[x])) / ((usize)(!(gb_size_of(x) % gb_size_of(0[x]))))) +#define gb_count_of(x) ((gb_size_of(x)/gb_size_of(0[x])) / ((isize)(!(gb_size_of(x) % gb_size_of(0[x]))))) #endif #ifndef gb_offset_of -#define gb_offset_of(Type, element) ((usize)&(((Type *)0)->element)) +#define gb_offset_of(Type, element) ((isize)&(((Type *)0)->element)) #endif #if defined(__cplusplus) extern "C++" { - #ifndef gb_align_of - template struct gb_Alignment_Trick { char c; T member; }; - #define gb_align_of(Type) offset_of(gb_Alignment_Trick, member) +#ifndef gb_align_of + #if __cplusplus >= 201103L + #define gb_align_of(Type) (isize)alignof(Type) + #else + // NOTE(bill): Fucking Templates! + template struct gbAlignment_Trick { char c; T member; }; + #define gb_align_of(Type) gb_offset_of(gbAlignment_Trick, member) #endif +#endif } #else #ifndef gb_align_of - #define gb_align_of(Type) offs(struct { char c; Type member; }, member) + #define gb_align_of(Type) gb_offset_of(struct { char c; Type member; }, member) #endif #endif +// NOTE(bill): I do which I had a type_of that was portable #ifndef gb_swap #define gb_swap(Type, a, b) do { Type tmp = (a); (a) = (b); (b) = tmp; } while (0) #endif // NOTE(bill): Because static means 3/4 different things in C/C++. Great design (!) #ifndef gb_global -#define gb_global static -#define gb_internal static -#define gb_local_persist static +#define gb_global static // Global variables +#define gb_internal static // Internal linkage +#define gb_local_persist static // Local Persisting variables #endif @@ -340,12 +378,14 @@ extern "C++" { + + //////////////////////////////////////////////////////////////// // // Defer statement -// - Akin to D's SCOPE_EXIT or similar to Go's defer but scope-based +// Akin to D's SCOPE_EXIT or +// similar to Go's defer but scope-based // -//////////////////////////////////////////////////////////////// #if defined(__cplusplus) extern "C++" { // NOTE(bill): Stupid fucking templates @@ -354,16 +394,17 @@ extern "C++" { template struct gbRemove_Reference { typedef T Type; }; // NOTE(bill): "Move" semantics - invented because the C++ committee are idiots (as a collective not as indiviuals (well a least some aren't)) - template gb_inline T &&gb_forward_ownership(typename gbRemove_Reference::Type &t) { return static_cast(t); } - template gb_inline T &&gb_forward_ownership(typename gbRemove_Reference::Type &&t) { return static_cast(t); } + template inline T &&gb_forward_ownership(typename gbRemove_Reference::Type &t) { return static_cast(t); } + template inline T &&gb_forward_ownership(typename gbRemove_Reference::Type &&t) { return static_cast(t); } + template inline T &&gb_move_ownership(T &&t) { return static::Type &&>(t); } template - struct gbImpl_Defer { + struct gbprivDefer { F f; - gbImpl_Defer(F &&f) : f(gb_forward_ownership(f)) {} - ~gbImpl_Defer() { f(); } + gbprivDefer(F &&f) : f(gb_forward_ownership(f)) {} + ~gbprivDefer() { f(); } }; - template gbImpl_Defer gb_defer_func(F &&f) { return gbImpl_Defer(gb_forward_ownership(f)); } + template gbprivDefer gb_defer_func(F &&f) { return gbprivDefer(gb_forward_ownership(f)); } #ifndef defer #define GB_DEFER_1(x, y) x##y @@ -375,6 +416,22 @@ extern "C++" { #endif +//////////////////////////////// +// +// Macro Fun! +// +// + +#ifndef GB_JOIN_MACROS +#define GB_JOIN_MACROS + #define GB_JOIN2_IND(a, b) a##b + #define GB_JOIN3_IND(a, b, c) a##b##c + + #define GB_JOIN2(a, b) GB_JOIN2_IND(a, b) + #define GB_JOIN3(a, b, c) GB_JOIN3_IND(a, b, c) +#endif + + #ifndef gb_min @@ -389,10 +446,10 @@ extern "C++" { //////////////////////////////// -// // -// Debug // -// // -//////////////////////////////// +// +// Debug +// +// #ifndef GB_DEBUG_TRAP @@ -407,7 +464,7 @@ extern "C++" { #ifndef GB_ASSERT_MSG #define GB_ASSERT_MSG(cond, msg, ...) do { \ if (!(cond)) { \ - gb_assert_handler(#cond, __FILE__, (long long)__LINE__, msg, ##__VA_ARGS__); \ + gb_assert_handler(#cond, __FILE__, cast(i64)__LINE__, msg, ##__VA_ARGS__); \ GB_DEBUG_TRAP(); \ } \ } while (0) @@ -421,32 +478,42 @@ extern "C++" { #define GB_PANIC(msg, ...) GB_ASSERT_MSG(0, msg, ##__VA_ARGS__) #endif -GB_DEF void gb_assert_handler(char const *condition, - char const *file, long long line, - char const *msg, ...); +GB_DEF void gb_assert_handler(char const *condition, char const *file, i64 line, char const *msg, ...); //////////////////////////////// -// // -// Printing // -// // -//////////////////////////////// +// +// Printing +// +// -GB_DEF int gb_sprintf(char const *fmt, ...); -GB_DEF int gb_snprintf(char *str, usize n, char const *fmt, ...); -GB_DEF int gb_vsprintf(char const *fmt, va_list v); -GB_DEF int gb_vsnprintf(char *str, usize n, char const *fmt, va_list v); +// Some compilers support applying printf-style warnings to user functions. +#if defined(__clang__) || defined(__GNUC__) +#define GB_PRINTF_ARGS(FMT) __attribute__((format(printf, FMT, (FMT+1)))) +#else +#define GB_PRINTF_ARGS(FMT) +#endif + +GB_DEF int gb_printf(char const *fmt, ...) GB_PRINTF_ARGS(1); +GB_DEF int gb_printf_var(char const *fmt, va_list v); +GB_DEF int gb_fprintf(FILE *f, char const *fmt, ...) GB_PRINTF_ARGS(2); +GB_DEF int gb_fprintf_var(FILE *f, char const *fmt, va_list v); +GB_DEF int gb_sprintf(char const *fmt, ...) GB_PRINTF_ARGS(1); +GB_DEF int gb_sprintf_var(char const *fmt, va_list v); +GB_DEF int gb_snprintf(char *str, isize n, char const *fmt, ...) GB_PRINTF_ARGS(3); +GB_DEF int gb_snprintf_var(char *str, isize n, char const *fmt, va_list v); -//////////////////////////////// -// // -// Memory // -// // -//////////////////////////////// + +//////////////////////////////////////////////////////////////// +// +// Memory +// +// #ifndef gb_align_to #define gb_align_to(value, alignment) (((value) + ((alignment)-1)) & ~((alignment) - 1)) @@ -456,17 +523,18 @@ GB_DEF int gb_vsnprintf(char *str, usize n, char const *fmt, va_list v); #define gb_is_power_of_two(x) ((x) != 0) && !((x) & ((x)-1)) #endif -GB_DEF void *gb_align_forward(void *ptr, usize alignment); +GB_DEF void *gb_align_forward(void *ptr, isize alignment); -GB_DEF void gb_zero_size(void *ptr, usize size); +GB_DEF void gb_zero_size(void *ptr, isize size); #ifndef gb_zero_struct #define gb_zero_struct(t) gb_zero_size((t), gb_size_of(*(t))) // NOTE(bill): Pass pointer of struct #define gb_zero_array(a, count) gb_zero_size((a), gb_size_of((a)[0])*count) #endif -GB_DEF void *gb_memcpy(void *dest, void const *source, usize size); -GB_DEF void *gb_memmove(void *dest, void const *source, usize size); +GB_DEF void *gb_memcpy(void *dest, void const *source, isize size); +GB_DEF void *gb_memmove(void *dest, void const *source, isize size); +GB_DEF void *gb_memset(void *data, u8 byte_value, isize size); @@ -478,23 +546,26 @@ GB_DEF void *gb_memmove(void *dest, void const *source, usize size); #endif +#if 0 +// NOTE(bill): Is it possible in C (easily) to create a mutex where the zero value is +// an unlocked mutex be default and also does not require make/destroy ever? // Mutex typedef struct gbMutex { void *handle; } gbMutex; -GB_DEF gbMutex gb_make_mutex(void); -GB_DEF void gb_destroy_mutex(gbMutex *m); -GB_DEF void gb_lock_mutex(gbMutex *m); -GB_DEF void gb_try_lock_mutex(gbMutex *m); -GB_DEF void gb_unlock_mutex(gbMutex *m); +GB_DEF gbMutex gb_mutex_make(void); +GB_DEF void gb_mutex_destroy(gbMutex *m); +GB_DEF void gb_mutex_lock(gbMutex *m); +GB_DEF void gb_mutex_try_lock(gbMutex *m); +GB_DEF void gb_mutex_unlock(gbMutex *m); +#endif - -//////////////////////////////// -// // -// Custom Allocation // -// // -//////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Custom Allocation +// +// typedef enum gbAllocation_Type { GB_ALLOCATION_TYPE_ALLOC, @@ -506,10 +577,10 @@ typedef enum gbAllocation_Type { // NOTE(bill): This is useful so you can define an allocator of the same type and parameters #define GB_ALLOCATOR_PROC(name) \ void *name(void *allocator_data, gbAllocation_Type type, \ - usize size, usize alignment, \ - void *old_memory, usize old_size, \ - u32 options) -typedef GB_ALLOCATOR_PROC(gbAllocator_Proc); + isize size, isize alignment, \ + void *old_memory, isize old_size, \ + u64 options) +;typedef GB_ALLOCATOR_PROC(gbAllocator_Proc); typedef struct gbAllocator { gbAllocator_Proc *proc; @@ -520,17 +591,17 @@ typedef struct gbAllocator { #define GB_DEFAULT_MEMORY_ALIGNMENT 4 #endif -GB_DEF void *gb_alloc_align(gbAllocator a, usize size, usize alignment); -GB_DEF void *gb_alloc(gbAllocator a, usize size); +GB_DEF void *gb_alloc_align(gbAllocator a, isize size, isize alignment); +GB_DEF void *gb_alloc(gbAllocator a, isize size); GB_DEF void gb_free(gbAllocator a, void *ptr); GB_DEF void gb_free_all(gbAllocator a); -GB_DEF void *gb_resize(gbAllocator a, void *ptr, usize old_size, usize new_size); -GB_DEF void *gb_resize_align(gbAllocator a, void *ptr, usize old_size, usize new_size, usize alignment); +GB_DEF void *gb_resize(gbAllocator a, void *ptr, isize old_size, isize new_size); +GB_DEF void *gb_resize_align(gbAllocator a, void *ptr, isize old_size, isize new_size, isize alignment); -GB_DEF void *gb_alloc_copy(gbAllocator a, void const *src, usize size); -GB_DEF void *gb_alloc_align_copy(gbAllocator a, void const *src, usize size, usize alignment); +GB_DEF void *gb_alloc_copy(gbAllocator a, void const *src, isize size); +GB_DEF void *gb_alloc_copy_align(gbAllocator a, void const *src, isize size, isize alignment); -GB_DEF char *gb_alloc_cstring(gbAllocator a, char const *str, usize len); +GB_DEF char *gb_alloc_cstring(gbAllocator a, char const *str); // NOTE(bill): These are very useful and the type case has saved me from numerous bugs @@ -557,19 +628,18 @@ GB_DEF GB_ALLOCATOR_PROC(gb_malloc_allocator_proc); typedef struct gbArena { gbAllocator backing; void *physical_start; - usize total_size; - usize total_allocated; + isize total_size; + isize total_allocated; u32 temp_count; - b32 clear_allocations_to_zero; } gbArena; -GB_DEF void gb_arena_init_from_memory(gbArena *arena, void *start, usize size); -GB_DEF void gb_arena_init_from_allocator(gbArena *arena, gbAllocator backing, usize size); -GB_DEF void gb_arena_init_subarena(gbArena *arena, gbArena *parent_arena, usize size); +GB_DEF void gb_arena_init_from_memory(gbArena *arena, void *start, isize size); +GB_DEF void gb_arena_init_from_allocator(gbArena *arena, gbAllocator backing, isize size); +GB_DEF void gb_arena_init_subarena(gbArena *arena, gbArena *parent_arena, isize size); GB_DEF void gb_arena_free(gbArena *arena); -GB_DEF usize gb_arena_alignment_of(gbArena *arena, usize alignment); -GB_DEF usize gb_arena_size_remaining(gbArena *arena, usize alignment); +GB_DEF isize gb_arena_alignment_of(gbArena *arena, isize alignment); +GB_DEF isize gb_arena_size_remaining(gbArena *arena, isize alignment); GB_DEF void gb_arena_check(gbArena *arena); @@ -580,11 +650,11 @@ GB_DEF GB_ALLOCATOR_PROC(gb_arena_allocator_proc); typedef struct gbTemp_Arena_Memory { gbArena *arena; - usize original_count; + isize original_count; } gbTemp_Arena_Memory; -GB_DEF gbTemp_Arena_Memory gb_begin_temp_arena_memory(gbArena *arena); -GB_DEF void gb_end_temp_arena_memory(gbTemp_Arena_Memory tmp_mem); +GB_DEF gbTemp_Arena_Memory gb_temp_arena_memory_begin(gbArena *arena); +GB_DEF void gb_temp_arena_memory_end(gbTemp_Arena_Memory tmp_mem); @@ -600,13 +670,13 @@ typedef struct gbPool { void *physical_start; void *free_list; - usize block_size; - usize block_align; - usize total_size; + isize block_size; + isize block_align; + isize total_size; } gbPool; -GB_DEF void gb_pool_init(gbPool *pool, gbAllocator backing, usize num_blocks, usize block_size); -GB_DEF void gb_pool_init_align(gbPool *pool, gbAllocator backing, usize num_blocks, usize block_size, usize block_align); +GB_DEF void gb_pool_init(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size); +GB_DEF void gb_pool_init_align(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size, isize block_align); GB_DEF void gb_pool_free(gbPool *pool); @@ -614,11 +684,11 @@ GB_DEF gbAllocator gb_pool_allocator(gbPool *pool); GB_DEF GB_ALLOCATOR_PROC(gb_pool_allocator_proc); -//////////////////////////////////////// -// // -// Char Functions // -// // -//////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Char Functions +// +// GB_DEF char gb_char_to_lower(char c); GB_DEF char gb_char_to_upper(char c); @@ -634,71 +704,65 @@ GB_DEF b32 gb_char_is_alphanumeric(char c); GB_DEF void gb_to_lower(char *str); GB_DEF void gb_to_upper(char *str); -GB_DEF usize gb_strlen(char const *str); -GB_DEF char *gb_strncpy(char *dest, char const *source, usize len); -GB_DEF int gb_strncmp(char const *s1, char const *s2, usize len); +GB_DEF isize gb_strlen(char const *str); +GB_DEF char *gb_strncpy(char *dest, char const *source, isize len); +GB_DEF int gb_strncmp(char const *s1, char const *s2, isize len); -//////////////////////////////////////// -// // -// Windows UTF-8 Handling // -// // -//////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Windows UTF-8 Handling +// +// // Windows doesn't handle 8 bit filenames well ('cause Micro$hit) -GB_DEF char16 *gb_from_utf8(char16 *buffer, char *str, usize len); -GB_DEF char *gb_to_utf8(char *buffer, char16 *str, usize len); +GB_DEF char16 *gb_from_utf8(char16 *buffer, char *str, isize len); +GB_DEF char *gb_to_utf8(char *buffer, char16 *str, isize len); -//////////////////////////////////////// -// // -// gbString - C Read-Only-Compatible // -// // -//////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// gbString - C Read-Only-Compatible +// +// // Pascal like strings in C typedef char *gbString; -#ifndef GB_STRING_SIZE -#define GB_STRING_SIZE -typedef u32 gbString_Size; -#endif - // This is stored at the beginning of the string -// NOTE(bill): It is (2*gb_size_of(gbString_Size) + 2*gb_size_of(void*)) (default: 16B (32bit), 24B (64bit)) -// NOTE(bill): If you only need a small string, just use a standard c string +// NOTE(bill): If you only need a small string, just use a standard c string or change the size typedef struct gbString_Header { - gbAllocator allocator; - gbString_Size length; - gbString_Size capacity; + gbAllocator allocator; + isize length; + isize capacity; } gbString_Header; -#define GB_STRING_HEADER(str) (cast(gbString_Header *)str - 1) +#define GB_STRING_HEADER(str) ((gbString_Header *)str - 1) GB_DEF gbString gb_string_make(gbAllocator a, char const *str); -GB_DEF gbString gb_string_make_length(gbAllocator a, void const *str, gbString_Size num_bytes); +GB_DEF gbString gb_string_make_length(gbAllocator a, void const *str, isize num_bytes); GB_DEF void gb_string_free(gbString str); GB_DEF gbString gb_string_duplicate(gbAllocator a, gbString const str); -GB_DEF gbString_Size gb_string_length(gbString const str); -GB_DEF gbString_Size gb_string_capacity(gbString const str); -GB_DEF gbString_Size gb_string_available_space(gbString const str); +GB_DEF isize gb_string_length(gbString const str); +GB_DEF isize gb_string_capacity(gbString const str); +GB_DEF isize gb_string_available_space(gbString const str); GB_DEF void gb_string_clear(gbString str); GB_DEF gbString gb_string_append_string(gbString str, gbString const other); -GB_DEF gbString gb_string_append_string_length(gbString str, void const *other, gbString_Size num_bytes); +GB_DEF gbString gb_string_append_string_length(gbString str, void const *other, isize num_bytes); GB_DEF gbString gb_string_append_cstring(gbString str, char const *other); GB_DEF gbString gb_string_set(gbString str, char const *cstr); -GB_DEF gbString gb_string_make_space_for(gbString str, gbString_Size add_len); -GB_DEF gbString_Size gb_string_allocation_size(gbString const str); +GB_DEF gbString gb_string_make_space_for(gbString str, isize add_len); +GB_DEF isize gb_string_allocation_size(gbString const str); GB_DEF b32 gb_strings_are_equal(gbString const lhs, gbString const rhs); @@ -708,59 +772,56 @@ GB_DEF gbString gb_string_trim_space(gbString str); /* Whitespace ` \t\r\n\v\f` -//////////////////////////////// -// // -// // -// // -// Dynamic Array (POD Types) // -// // -// // -// // -//////////////////////////////// +////////////////////////////////////////////////////////////////// +// +// Dynamic Array (POD Types) +// +// // NOTE(bill): I know this is a macro hell but C is an old (and shit) language with no proper arrays -// Also why the fuck not?! It fucking works! +// Also why the fuck not?! It fucking works! And it has custom allocation, which is already better than C++! -// NOTE(bill): Typedef every array -// e.g. typedef gbArray(int) gb_int_array; -#ifndef gbArray +// NOTE(bill): Typedef every array or you get anonymous structures everywhere! +// e.g. typedef gbArray(int) gb_Int_Array; +#ifndef GB_ARRAY_TYPE +#define GB_ARRAY_TYPE #define gbArray(Type) struct { \ gbAllocator allocator; \ - i64 count; \ - i64 capacity; \ - Type *e; \ + isize count; \ + isize capacity; \ + Type *data; \ } typedef gbArray(void) gbVoid_Array; // NOTE(bill): Used to generic stuff -/* Available Procedures for gbArray(Type) - gb_array_init - gb_array_free - gb_array_set_capacity - gb_array_grow - gb_array_append - gb_array_appendv - gb_array_pop - gb_array_clear - gb_array_resize - gb_array_reserve -*/ +// Available Procedures for gbArray(Type) +// gb_array_init +// gb_array_free +// gb_array_set_capacity +// gb_array_grow +// gb_array_append +// gb_array_appendv +// gb_array_pop +// gb_array_clear +// gb_array_resize +// gb_array_reserve +// #define gb_array_init(x, allocator_) do { gb_zero_struct(x); (x)->allocator = allocator_; } while (0) #define gb_array_free(x) do { \ if ((x)->allocator.proc) { \ gbAllocator a = (x)->allocator; \ - gb_free(a, (x)->e); \ + gb_free(a, (x)->data); \ gb_array_init((x), a); \ } \ } while (0) -#define gb_array_set_capacity(array, capacity) gb__array_set_capacity((array), (capacity), gb_size_of((array)->e[0])) +#define gb_array_set_capacity(array, capacity) gbprivarray_set_capacity((array), (capacity), gb_size_of((array)->data[0])) // NOTE(bill): Do not use directly the thing below, use the macro -GB_DEF void gb__array_set_capacity(void *array, i64 capacity, usize element_size); +GB_DEF void gbprivarray_set_capacity(void *array, i64 capacity, isize element_size); // TODO(bill): Decide on a decent growing formula for gbArray // Is 2*c+8 good enough @@ -775,15 +836,15 @@ GB_DEF void gb__array_set_capacity(void *array, i64 capacity, usize element_size #define gb_array_append(x, item) do { \ if ((x)->capacity < (x)->count+1) \ gb_array_grow(x, 0); \ - (x)->e[(x)->count++] = item; \ + (x)->data[(x)->count++] = item; \ } while (0) -#define gb_array_appendv(x, items, item_count) do { \ - GB_ASSERT(gb_size_of(items[0]) == gb_size_of((x)->e[0])); \ - if ((x)->capacity < (x)->count+item_count) \ - gb_array_grow(x, (x)->count+item_count); \ - gb_memcpy((x)->e[a->count], items, gb_size_of((x)->e[0])*item_count); \ - (x)->count += item_count; \ +#define gb_array_appendv(x, items, item_count) do { \ + GB_ASSERT(gb_size_of(items[0]) == gb_size_of((x)->data[0])); \ + if ((x)->capacity < (x)->count+item_count) \ + gb_array_grow(x, (x)->count+item_count); \ + gb_memcpy((x)->data[a->count], items, gb_size_of((x)->data[0])*item_count); \ + (x)->count += item_count; \ } while (0) @@ -798,51 +859,83 @@ GB_DEF void gb__array_set_capacity(void *array, i64 capacity, usize element_size } while (0) -#define gb_array_reserve(x, capacity) do { \ - if ((x)->capacity < capacity) \ - gb_array_set_capacity(x, capacity); \ +#define gb_array_reserve(x, new_capacity) do { \ + if ((x)->capacity < new_capacity) \ + gb_array_set_capacity(x, new_capacity); \ } while (0) -gb_no_inline void -gb__array_set_capacity(void *array_, i64 capacity, usize element_size) -{ - // NOTE(bill): I know this is unsafe so don't call this function directly - gbVoid_Array *a = cast(gbVoid_Array *)array_; - void *new_elements = NULL; +#endif /* GB_ARRAY_TYPE */ - GB_ASSERT(element_size > 0); - if (capacity == a->capacity) - return; - if (capacity < a->count) { - if (a->capacity < capacity) { - i64 new_capacity = 2*a->capacity + 8; - if (new_capacity < capacity) - new_capacity = capacity; - gb__array_set_capacity(a, new_capacity, element_size); - } - a->count = capacity; - } - if (capacity > 0) { - new_elements = gb_alloc(a->allocator, element_size*capacity); - gb_memcpy(new_elements, a->e, element_size*a->count); - } - gb_free(a->allocator, a->e); - a->e = new_elements; - a->capacity = capacity; + + + + +//////////////////////////////////////////////////////////////// +// +// +// Hash_Table (POD Types) +// +// + + +// TODO(bill): Hash Table and make it decent!!! + +// NOTE(bill): All keys are u64 +#ifndef GB_HASH_TABLE_TYPE +#define GB_HASH_TABLE_TYPE + +#define gbHash_Table_Entry(Type) struct { \ + u64 key; \ + Type value; \ } -#endif +#define gbHash_Table(Type) struct { \ + gbArray(isize) hashes; \ + gbArray(gbHash_Table_Entry(Type)) entries; \ +} + +#define gb_hash_table_init(h, allocator) do { \ + gb_array_init((h)->hashes, allocator); \ + gb_array_init((h)->entries, allocator); \ +} while (0) + +#define gb_hash_table_free(h) do { \ + gb_free(&(h)->hashes); \ + gb_free(&(h)->entries); \ +} while (0) -//////////////////////////////// -// // -// File Handling // -// // -//////////////////////////////// + +/* TODO(bill): Hash_Table Procs + gb_hash_table_init(h, allocator) + gb_hash_table_free(h) + + gb_hash_table_has(h, key) // Return false/true + gb_hash_table_get(h, key) // Return entries index + gb_hash_table_set(h, key, value) + gb_hash_table_remove(h, key) + gb_hash_table_reserve(h, capacity) + gb_hash_table_clear(h) + +*/ + + + + + +#endif /* GB_HASH_TABLE_TYPE */ + + + +//////////////////////////////////////////////////////////////// +// +// File Handling +// +// typedef struct gbFile { FILE *handle; // File to fread/fwrite @@ -851,14 +944,14 @@ typedef struct gbFile { GB_DEF b32 gb_file_create(gbFile *file, char const *filepath); // TODO(bill): Give file permissions GB_DEF b32 gb_file_open(gbFile *file, char const *filepath); GB_DEF b32 gb_file_close(gbFile *file); -GB_DEF b32 gb_file_read_at(gbFile *file, void *buffer, usize size, i64 offset); -GB_DEF b32 gb_file_write_at(gbFile *file, void const *buffer, usize size, i64 offset); +GB_DEF b32 gb_file_read_at(gbFile *file, void *buffer, isize size, i64 offset); +GB_DEF b32 gb_file_write_at(gbFile *file, void const *buffer, isize size, i64 offset); GB_DEF i64 gb_file_size(gbFile *file); typedef struct gbFile_Contents { void *data; - usize size; + isize size; } gbFile_Contents; GB_DEF gbFile_Contents gb_read_entire_file_contents(gbAllocator a, char const *filepath, b32 zero_terminate); @@ -870,31 +963,31 @@ GB_DEF gbFile_Contents gb_read_entire_file_contents(gbAllocator a, char const *f #endif /* GB_INCLUDE_GB_H */ -//////////////////////////////// -// // -// // -// // -// // -// // -// // -// // -// // -// // -// // -// // -// Implementation // -// // -// // -// // -// // -// // -// // -// // -// // -// // -// // -// // -//////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +// +// +// +// +// Implementation +// +// +// +// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////// #if defined(GB_IMPLEMENTATION) @@ -904,38 +997,25 @@ extern "C" { int -gb_vsnprintf(char *str, usize n, char const *fmt, va_list v) -{ - int res; - #if defined(_WIN32) - res = _vsnprintf(str, n, fmt, v); - #else - res = vsnprintf(str, n, fmt, v) - #endif - if (n) str[n-1] = 0; - // NOTE(bill): Unix returns length output would require, Windows returns negative when truncated. - return (res >= cast(int)n || res < 0) ? -1 : res; -} - - -int -gb_snprintf(char *str, usize n, char const *fmt, ...) +gb_printf(char const *fmt, ...) { int res; va_list v; - va_start(v,fmt); - res = gb_vsnprintf(str, n, fmt, v); + va_start(v, fmt); + res = gb_fprintf_var(stdout, fmt, v); va_end(v); return res; } int -gb_vsprintf(char const *fmt, va_list v) +gb_fprintf(FILE *f, char const *fmt, ...) { - gb_local_persist char buffer[1024]; int res; - res = gb_vsnprintf(buffer, gb_size_of(buffer), fmt, v); + va_list v; + va_start(v, fmt); + res = gb_fprintf_var(stdout, fmt, v); + va_end(v); return res; } @@ -946,11 +1026,48 @@ gb_sprintf(char const *fmt, ...) int res; va_list v; va_start(v, fmt); - res = gb_vsnprintf(buffer, gb_size_of(buffer), fmt, v); + res = gb_snprintf_var(buffer, gb_size_of(buffer), fmt, v); va_end(v); return res; } +int +gb_snprintf(char *str, isize n, char const *fmt, ...) +{ + int res; + va_list v; + va_start(v,fmt); + res = gb_snprintf_var(str, n, fmt, v); + va_end(v); + return res; +} + + +gb_inline int gb_printf_var(char const *fmt, va_list v) { return gb_fprintf_var(stdout, fmt, v); } +gb_inline int gb_fprintf_var(FILE *f, char const *fmt, va_list v) { return vfprintf(f, fmt, v); } + +gb_inline int +gb_sprintf_var(char const *fmt, va_list v) +{ + gb_local_persist char buffer[1024]; + int res; + res = gb_snprintf_var(buffer, gb_size_of(buffer), fmt, v); + return res; +} + +gb_inline int +gb_snprintf_var(char *str, isize n, char const *fmt, va_list v) +{ + int res; +#if defined(_WIN32) + res = _vsnprintf(str, n, fmt, v); +#else + res = vsnprintf(str, n, fmt, v) +#endif + if (n) str[n-1] = 0; + // NOTE(bill): Unix returns length output would require, Windows returns negative when truncated. + return (res >= n || res < 0) ? -1 : res; +} @@ -964,31 +1081,29 @@ gb_sprintf(char const *fmt, ...) void -gb_assert_handler(char const *condition, - char const *file, long long line, - char const *msg, ...) +gb_assert_handler(char const *condition, char const *file, i64 line, char const *msg, ...) { - fprintf(stderr, "%s:%lld: Assert Failure: ", file, line); + gb_fprintf(stderr, "%s:%d: Assert Failure: ", file, cast(int)line); if (condition) - fprintf(stderr, "`%s` ", condition); + gb_fprintf(stderr, "`%s` ", condition); if (msg) { va_list args; va_start(args, msg); - vfprintf(stderr, msg, args); + gb_fprintf(stderr, msg, args); va_end(args); } - fprintf(stderr, "\n"); + gb_fprintf(stderr, "\n"); } gb_inline void * -gb_align_forward(void *ptr, usize align) +gb_align_forward(void *ptr, isize align) { uintptr p; - usize modulo; + isize modulo; GB_ASSERT(gb_is_power_of_two(align)); @@ -998,35 +1113,32 @@ gb_align_forward(void *ptr, usize align) return cast(void *)p; } -gb_inline void -gb_zero_size(void *ptr, usize size) -{ - memset(ptr, 0, size); -} +gb_inline void gb_zero_size(void *ptr, isize size) { gb_memset(ptr, 0, size); } -gb_inline void *gb_memcpy(void *dest, void const *source, usize size) { return memcpy(dest, source, size); } -gb_inline void *gb_memmove(void *dest, void const *source, usize size) { return memmove(dest, source, size); } +gb_inline void *gb_memcpy(void *dest, void const *source, isize size) { return memcpy(dest, source, size); } +gb_inline void *gb_memmove(void *dest, void const *source, isize size) { return memmove(dest, source, size); } +gb_inline void *gb_memset(void *data, u8 byte_value, isize size) { return memset(data, byte_value, size); } -gb_inline void *gb_alloc_align(gbAllocator a, usize size, usize alignment) { return a.proc(a.data, GB_ALLOCATION_TYPE_ALLOC, size, alignment, NULL, 0, 0); } -gb_inline void *gb_alloc(gbAllocator a, usize size) { return gb_alloc_align(a, size, GB_DEFAULT_MEMORY_ALIGNMENT); } +gb_inline void *gb_alloc_align(gbAllocator a, isize size, isize alignment) { return a.proc(a.data, GB_ALLOCATION_TYPE_ALLOC, size, alignment, NULL, 0, 0); } +gb_inline void *gb_alloc(gbAllocator a, isize size) { return gb_alloc_align(a, size, GB_DEFAULT_MEMORY_ALIGNMENT); } gb_inline void gb_free(gbAllocator a, void *ptr) { a.proc(a.data, GB_ALLOCATION_TYPE_FREE, 0, 0, ptr, 0, 0); } gb_inline void gb_free_all(gbAllocator a) { a.proc(a.data, GB_ALLOCATION_TYPE_FREE_ALL, 0, 0, NULL, 0, 0); } -gb_inline void *gb_resize(gbAllocator a, void *ptr, usize old_size, usize new_size) { return gb_resize_align(a, ptr, old_size, new_size, GB_DEFAULT_MEMORY_ALIGNMENT); } -gb_inline void *gb_resize_align(gbAllocator a, void *ptr, usize old_size, usize new_size, usize alignment) { return a.proc(a.data, GB_ALLOCATION_TYPE_RESIZE, new_size, alignment, ptr, old_size, 0); }; +gb_inline void *gb_resize(gbAllocator a, void *ptr, isize old_size, isize new_size) { return gb_resize_align(a, ptr, old_size, new_size, GB_DEFAULT_MEMORY_ALIGNMENT); } +gb_inline void *gb_resize_align(gbAllocator a, void *ptr, isize old_size, isize new_size, isize alignment) { return a.proc(a.data, GB_ALLOCATION_TYPE_RESIZE, new_size, alignment, ptr, old_size, 0); }; -gb_inline void *gb_alloc_copy(gbAllocator a, void const *src, usize size) { return gb_memcpy(gb_alloc(a, size), src, size); } -gb_inline void *gb_alloc_align_copy(gbAllocator a, void const *src, usize size, usize alignment) { return gb_memcpy(gb_alloc_align(a, size, alignment), src, size); } +gb_inline void *gb_alloc_copy(gbAllocator a, void const *src, isize size) { return gb_memcpy(gb_alloc(a, size), src, size); } +gb_inline void *gb_alloc_copy_align(gbAllocator a, void const *src, isize size, isize alignment) { return gb_memcpy(gb_alloc_align(a, size, alignment), src, size); } gb_inline char * -gb_alloc_cstring(gbAllocator a, char const *str, usize len) +gb_alloc_cstring(gbAllocator a, char const *str) { char *result; - if (len == 0) len = strlen(str); + isize len = gb_strlen(str); result = cast(char *)gb_alloc_copy(a, str, len+1); result[len] = '\0'; return result; @@ -1064,7 +1176,7 @@ GB_ALLOCATOR_PROC(gb_malloc_allocator_proc) void *ptr = NULL; void *original_block; // Original block void **aligned_block; // Aligned block - usize offset = (alignment-1) + sizeof(void *); + isize offset = (alignment-1) + sizeof(void *); original_block = cast(void *)malloc(size + offset); if (original_block) { uintptr t = (cast(uintptr)original_block + offset) & ~(alignment-1); @@ -1090,15 +1202,25 @@ GB_ALLOCATOR_PROC(gb_malloc_allocator_proc) break; case GB_ALLOCATION_TYPE_RESIZE: { - #if defined(_MSC_VER) + gbAllocator a = gb_malloc_allocator(); + if (!old_memory) return gb_alloc_align(a, size, alignment); + + if (size < old_size) + size = old_size; + + if (old_size == size) { + return old_memory; + } else { +#if defined(_MSC_VER) return _aligned_realloc(old_memory, size, alignment); - #else - gbAllocator a = gb_malloc_allocator(); +#else void *new_memory = gb_alloc_align(a, size, alignment); + if (!new_memory) return NULL; gb_memmove(new_memory, old_memory, gb_min(size, old_size)); gb_free(a, old_memory); return new_memory; - #endif +#endif + } } break; } @@ -1111,7 +1233,7 @@ GB_ALLOCATOR_PROC(gb_malloc_allocator_proc) gb_inline void -gb_arena_init_from_memory(gbArena *arena, void *start, usize size) +gb_arena_init_from_memory(gbArena *arena, void *start, isize size) { arena->backing.proc = NULL; arena->backing.data = NULL; @@ -1122,7 +1244,7 @@ gb_arena_init_from_memory(gbArena *arena, void *start, usize size) } gb_inline void -gb_arena_init_from_allocator(gbArena *arena, gbAllocator backing, usize size) +gb_arena_init_from_allocator(gbArena *arena, gbAllocator backing, isize size) { arena->backing = backing; arena->physical_start = gb_alloc(backing, size); // NOTE(bill): Uses default alignment @@ -1131,7 +1253,7 @@ gb_arena_init_from_allocator(gbArena *arena, gbAllocator backing, usize size) arena->temp_count = 0; } -gb_inline void gb_arena_init_subarena(gbArena *arena, gbArena *parent_arena, usize size) { gb_arena_init_from_allocator(arena, gb_arena_allocator(parent_arena), size); } +gb_inline void gb_arena_init_subarena(gbArena *arena, gbArena *parent_arena, isize size) { gb_arena_init_from_allocator(arena, gb_arena_allocator(parent_arena), size); } gb_inline void @@ -1144,14 +1266,14 @@ gb_arena_free(gbArena *arena) } -gb_inline usize -gb_arena_alignment_of(gbArena *arena, usize alignment) +gb_inline isize +gb_arena_alignment_of(gbArena *arena, isize alignment) { - usize alignment_offset, result_pointer, mask; + isize alignment_offset, result_pointer, mask; GB_ASSERT(gb_is_power_of_two(alignment)); alignment_offset = 0; - result_pointer = cast(usize)arena->physical_start + arena->total_allocated; + result_pointer = cast(isize)arena->physical_start + arena->total_allocated; mask = alignment - 1; if (result_pointer & mask) alignment_offset = alignment - (result_pointer & mask); @@ -1159,10 +1281,10 @@ gb_arena_alignment_of(gbArena *arena, usize alignment) return alignment_offset; } -gb_inline usize -gb_arena_size_remaining(gbArena *arena, usize alignment) +gb_inline isize +gb_arena_size_remaining(gbArena *arena, isize alignment) { - usize result = arena->total_size - (arena->total_allocated + gb_arena_alignment_of(arena, alignment)); + isize result = arena->total_size - (arena->total_allocated + gb_arena_alignment_of(arena, alignment)); return result; } @@ -1193,22 +1315,21 @@ GB_ALLOCATOR_PROC(gb_arena_allocator_proc) switch (type) { case GB_ALLOCATION_TYPE_ALLOC: { void *ptr; - usize actual_size = size + alignment; + isize actual_size = size + alignment; // NOTE(bill): Out of memory - if (arena->total_allocated + actual_size > cast(usize)arena->total_size) + if (arena->total_allocated + actual_size > cast(isize)arena->total_size) return NULL; ptr = gb_align_forward(cast(u8 *)arena->physical_start + arena->total_allocated, alignment); arena->total_allocated += actual_size; - if (arena->clear_allocations_to_zero) - gb_zero_size(ptr, 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 + // TODO(bill): Free it if it's on top of the stack break; case GB_ALLOCATION_TYPE_FREE_ALL: @@ -1216,11 +1337,22 @@ GB_ALLOCATOR_PROC(gb_arena_allocator_proc) break; case GB_ALLOCATION_TYPE_RESIZE: { + // TODO(bill): Check if ptr is on top of stack and just extend gbAllocator a = gb_arena_allocator(arena); - void *new_memory = gb_alloc_align(a, size, alignment); - gb_memmove(new_memory, old_memory, gb_min(size, old_size)); - gb_free(a, old_memory); - return new_memory; + if (!old_memory) return gb_alloc_align(a, size, alignment); + + if (size < old_size) + size = old_size; + + if (old_size == size) { + return old_memory; + } else { + void *new_memory = gb_alloc_align(a, size, alignment); + if (!new_memory) return NULL; + gb_memmove(new_memory, old_memory, gb_min(size, old_size)); + gb_free(a, old_memory); + return new_memory; + } } break; } @@ -1229,7 +1361,7 @@ GB_ALLOCATOR_PROC(gb_arena_allocator_proc) gb_inline gbTemp_Arena_Memory -gb_begin_temp_arena_memory(gbArena *arena) +gb_temp_arena_memory_begin(gbArena *arena) { gbTemp_Arena_Memory tmp; tmp.arena = arena; @@ -1239,7 +1371,7 @@ gb_begin_temp_arena_memory(gbArena *arena) } gb_inline void -gb_end_temp_arena_memory(gbTemp_Arena_Memory tmp) +gb_temp_arena_memory_end(gbTemp_Arena_Memory tmp) { GB_ASSERT(tmp.arena->total_allocated >= tmp.original_count); GB_ASSERT(tmp.arena->temp_count > 0); @@ -1251,15 +1383,15 @@ gb_end_temp_arena_memory(gbTemp_Arena_Memory tmp) gb_inline void -gb_pool_init(gbPool *pool, gbAllocator backing, usize num_blocks, usize block_size) +gb_pool_init(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size) { gb_pool_init_align(pool, backing, num_blocks, block_size, GB_DEFAULT_MEMORY_ALIGNMENT); } void -gb_pool_init_align(gbPool *pool, gbAllocator backing, usize num_blocks, usize block_size, usize block_align) +gb_pool_init_align(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size, isize block_align) { - usize actual_block_size, pool_size, block_index; + isize actual_block_size, pool_size, block_index; u8 *data, *curr; uintptr *end; @@ -1282,7 +1414,7 @@ gb_pool_init_align(gbPool *pool, gbAllocator backing, usize num_blocks, usize bl curr += actual_block_size; } - end = cast(uintptr*)curr; + end = cast(uintptr *)curr; *end = cast(uintptr)NULL; pool->physical_start = data; @@ -1432,21 +1564,21 @@ gb_char_is_alphanumeric(char c) -gb_inline void gb__string_set_length(gbString str, gbString_Size len) { GB_STRING_HEADER(str)->length = len; } -gb_inline void gb__string_set_capacity(gbString str, gbString_Size cap) { GB_STRING_HEADER(str)->capacity = cap; } +gb_inline void gbprivstring_set_length(gbString str, isize len) { GB_STRING_HEADER(str)->length = len; } +gb_inline void gbprivstring_set_capacity(gbString str, isize cap) { GB_STRING_HEADER(str)->capacity = cap; } gb_inline gbString gb_string_make(gbAllocator a, char const *str) { - gbString_Size len = cast(gbString_Size)(str ? strlen(str) : 0); + isize len = str ? gb_strlen(str) : 0; return gb_string_make_length(a, str, len); } gbString -gb_string_make_length(gbAllocator a, void const *init_str, gbString_Size num_bytes) +gb_string_make_length(gbAllocator a, void const *init_str, isize num_bytes) { - gbString_Size header_size = gb_size_of(gbString_Header); + isize header_size = gb_size_of(gbString_Header); void *ptr = gb_alloc(a, header_size + num_bytes + 1); gbString str; @@ -1480,10 +1612,10 @@ gb_string_free(gbString str) gb_inline gbString gb_string_duplicate(gbAllocator a, gbString const str) { return gb_string_make_length(a, str, gb_string_length(str)); } -gb_inline gbString_Size gb_string_length(gbString const str) { return GB_STRING_HEADER(str)->length; } -gb_inline gbString_Size gb_string_capacity(gbString const str) { return GB_STRING_HEADER(str)->capacity; } +gb_inline isize gb_string_length(gbString const str) { return GB_STRING_HEADER(str)->length; } +gb_inline isize gb_string_capacity(gbString const str) { return GB_STRING_HEADER(str)->capacity; } -gb_inline gbString_Size +gb_inline isize gb_string_available_space(gbString const str) { gbString_Header *h = GB_STRING_HEADER(str); @@ -1493,14 +1625,14 @@ gb_string_available_space(gbString const str) } -gb_inline void gb_string_clear(gbString str) { gb__string_set_length(str, 0); str[0] = '\0'; } +gb_inline void gb_string_clear(gbString str) { gbprivstring_set_length(str, 0); str[0] = '\0'; } gb_inline gbString gb_string_append_string(gbString str, gbString const other) { return gb_string_append_string_length(str, other, gb_string_length(other)); } gbString -gb_string_append_string_length(gbString str, void const *other, gbString_Size other_len) +gb_string_append_string_length(gbString str, void const *other, isize other_len) { - gbString_Size curr_len = gb_string_length(str); + isize curr_len = gb_string_length(str); str = gb_string_make_space_for(str, other_len); if (str == NULL) @@ -1508,7 +1640,7 @@ gb_string_append_string_length(gbString str, void const *other, gbString_Size ot gb_memcpy(str + curr_len, other, other_len); str[curr_len + other_len] = '\0'; - gb__string_set_length(str, curr_len + other_len); + gbprivstring_set_length(str, curr_len + other_len); return str; } @@ -1516,14 +1648,14 @@ gb_string_append_string_length(gbString str, void const *other, gbString_Size ot gb_inline gbString gb_string_append_cstring(gbString str, char const *other) { - return gb_string_append_string_length(str, other, cast(gbString_Size)strlen(other)); + return gb_string_append_string_length(str, other, cast(isize)strlen(other)); } gbString gb_string_set(gbString str, char const *cstr) { - gbString_Size len = cast(gbString_Size)strlen(cstr); + isize len = gb_strlen(cstr); if (gb_string_capacity(str) < len) { str = gb_string_make_space_for(str, len - gb_string_length(str)); if (str == NULL) @@ -1532,63 +1664,41 @@ gb_string_set(gbString str, char const *cstr) gb_memcpy(str, cstr, len); str[len] = '\0'; - gb__string_set_length(str, len); + gbprivstring_set_length(str, len); return str; } -gb_internal void * -gb__string_realloc(gbAllocator a, void *ptr, gbString_Size old_size, gbString_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) { - return ptr; - } else { - void *new_ptr = gb_alloc(a, new_size); - if (!new_ptr) - return NULL; - - gb_memcpy(new_ptr, ptr, old_size); - gb_free(a, ptr); - return new_ptr; - } -} - - gbString -gb_string_make_space_for(gbString str, gbString_Size add_len) +gb_string_make_space_for(gbString str, isize add_len) { - gbString_Size available = gb_string_available_space(str); + isize available = gb_string_available_space(str); // Return if there is enough space left if (available >= add_len) { return str; } else { - gbString_Size new_len = gb_string_length(str) + add_len; + isize new_len = gb_string_length(str) + add_len; void *ptr = GB_STRING_HEADER(str); - gbString_Size old_size = gb_size_of(gbString_Header) + gb_string_length(str) + 1; - gbString_Size new_size = gb_size_of(gbString_Header) + new_len + 1; + isize old_size = gb_size_of(gbString_Header) + gb_string_length(str) + 1; + isize new_size = gb_size_of(gbString_Header) + new_len + 1; - void *new_ptr = gb__string_realloc(GB_STRING_HEADER(str)->allocator, ptr, old_size, new_size); + void *new_ptr = gb_resize(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); - gb__string_set_capacity(str, new_len); + gbprivstring_set_capacity(str, new_len); return str; } } -gb_inline gbString_Size +gb_inline isize gb_string_allocation_size(gbString const str) { - gbString_Size cap = gb_string_capacity(str); + isize cap = gb_string_capacity(str); return gb_size_of(gbString_Header) + cap; } @@ -1596,7 +1706,7 @@ gb_string_allocation_size(gbString const str) gb_inline b32 gb_strings_are_equal(gbString const lhs, gbString const rhs) { - gbString_Size lhs_len, rhs_len, i; + isize lhs_len, rhs_len, i; lhs_len = gb_string_length(lhs); rhs_len = gb_string_length(rhs); if (lhs_len != rhs_len) @@ -1615,7 +1725,7 @@ gbString gb_string_trim(gbString str, char const *cut_set) { char *start, *end, *start_pos, *end_pos; - gbString_Size len; + isize len; start_pos = start = str; end_pos = end = str + gb_string_length(str) - 1; @@ -1625,13 +1735,13 @@ gb_string_trim(gbString str, char const *cut_set) while (end_pos > start_pos && strchr(cut_set, *end_pos)) end_pos--; - len = cast(gbString_Size)((start_pos > end_pos) ? 0 : ((end_pos - start_pos)+1)); + len = cast(isize)((start_pos > end_pos) ? 0 : ((end_pos - start_pos)+1)); if (str != start_pos) gb_memmove(str, start_pos, len); str[len] = '\0'; - gb__string_set_length(str, len); + gbprivstring_set_length(str, len); return str; } @@ -1659,7 +1769,7 @@ gb_to_upper(char *str) } -gb_inline usize +gb_inline isize gb_strlen(char const *str) { char const *end; @@ -1670,7 +1780,7 @@ gb_strlen(char const *str) } gb_inline char * -gb_strncpy(char *dest, char const *source, usize len) +gb_strncpy(char *dest, char const *source, isize len) { char *str = dest; while (len > 0 && *source) { @@ -1685,7 +1795,7 @@ gb_strncpy(char *dest, char const *source, usize len) } gb_inline int -gb_strncmp(char const *s1, char const *s2, usize len) +gb_strncmp(char const *s1, char const *s2, isize len) { for(; len > 0; s1++, s2++, len--) { if (*s1 != *s2) @@ -1699,19 +1809,19 @@ gb_strncmp(char const *s1, char const *s2, usize len) -//////////////////////////////////////// -// // -// Windows UTF-8 Handling // -// // -//////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Windows UTF-8 Handling +// +// char16 * -gb_from_utf8(char16 *buffer, char *s, usize len) +gb_from_utf8(char16 *buffer, char *s, isize len) { u8 *str = cast(u8 *)s; u32 c; - usize i = 0; + isize i = 0; len--; while (*str) { if (i >= len) @@ -1774,9 +1884,9 @@ gb_from_utf8(char16 *buffer, char *s, usize len) } char * -gb_to_utf8(char *buffer, char16 *str, usize len) +gb_to_utf8(char *buffer, char16 *str, isize len) { - usize i = 0; + isize i = 0; len--; while (*str) { if (*str < 0x80) { @@ -1823,21 +1933,21 @@ gb_to_utf8(char *buffer, char16 *str, usize len) //////////////////////////////// gb_inline b32 -gb_create_file(gbFile *file, char const *filepath) +gb_file_create(gbFile *file, char const *filepath) { file->handle = fopen(filepath, "wb"); return (file->handle != NULL); // TODO(bill): Handle fopen errors } gb_inline b32 -gb_open_file(gbFile *file, char const *filepath) +gb_file_open(gbFile *file, char const *filepath) { file->handle = fopen(filepath, "rb"); return (file->handle != NULL); // TODO(bill): Handle fopen errors } gb_inline b32 -gb_close_file(gbFile *file) +gb_file_close(gbFile *file) { b32 result = true; if (file && file->handle) @@ -1846,7 +1956,7 @@ gb_close_file(gbFile *file) } gb_inline b32 -gb_read_file_at(gbFile *file, void *buffer, usize size, i64 offset) +gb_file_read_at(gbFile *file, void *buffer, isize size, i64 offset) { i64 prev_cursor_pos = ftell(file->handle); fseek(file->handle, offset, SEEK_SET); @@ -1856,9 +1966,9 @@ gb_read_file_at(gbFile *file, void *buffer, usize size, i64 offset) } gb_inline b32 -gb_write_file_at(gbFile *file, void const *buffer, usize size, i64 offset) +gb_file_write_at(gbFile *file, void const *buffer, isize size, i64 offset) { - usize written_size; + isize written_size; i64 prev_cursor_pos = ftell(file->handle); fseek(file->handle, offset, SEEK_SET); @@ -1876,10 +1986,10 @@ gb_write_file_at(gbFile *file, void const *buffer, usize size, i64 offset) gb_inline i64 gb_file_size(gbFile *file) { - usize result_size; + i64 result_size; fseek(file->handle, 0, SEEK_END); - result_size = cast(usize)ftell(file->handle); + result_size = cast(i64)ftell(file->handle); fseek(file->handle, 0, SEEK_SET); return result_size; } @@ -1893,16 +2003,16 @@ gb_read_entire_file_contents(gbAllocator a, char const *filepath, b32 zero_termi { gbFile_Contents result = {0}; gbFile file = {0}; - if (gb_open_file(&file, filepath)) { + if (gb_file_open(&file, filepath)) { i64 file_size = gb_file_size(&file); if (file_size > 0) { result.data = gb_alloc(a, zero_terminate ? file_size+1 : file_size); result.size = file_size; - gb_read_file_at(&file, result.data, result.size, 0); + gb_file_read_at(&file, result.data, result.size, 0); if (zero_terminate) (cast(u8 *)(result.data))[file_size] = '\0'; } - gb_close_file(&file); + gb_file_close(&file); } return result; @@ -1911,6 +2021,36 @@ gb_read_entire_file_contents(gbAllocator a, char const *filepath, b32 zero_termi +gb_no_inline void +gbprivarray_set_capacity(void *array_, isize capacity, isize element_size) +{ + // NOTE(bill): I know this is unsafe so don't call this function directly + gbVoid_Array *a = cast(gbVoid_Array *)array_; + void *data = NULL; + + GB_ASSERT(element_size > 0); + + if (capacity == a->capacity) + return; + + if (capacity < a->count) { + if (a->capacity < capacity) { + isize new_capacity = 2*a->capacity + 8; + if (new_capacity < capacity) + new_capacity = capacity; + gbprivarray_set_capacity(a, new_capacity, element_size); + } + a->count = capacity; + } + + if (capacity > 0) { + data = gb_alloc(a->allocator, element_size*capacity); + gb_memcpy(data, a->data, element_size*a->count); + } + gb_free(a->allocator, a->data); + a->data = data; + a->capacity = capacity; +}