diff --git a/.vscode/settings.json b/.vscode/settings.json index 596505e..0c4056d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -34,7 +34,10 @@ "limits": "cpp", "toolchain.h": "c", "thread_context.h": "c", - "stb_sprintf.h": "c" + "stb_sprintf.h": "c", + "base_types.h": "c", + "platform.h": "c", + "macros.h": "c" }, "workbench.colorCustomizations": { "activityBar.activeBackground": "#713fb8", diff --git a/code/base/arena.c b/code/base/arena.c index 2730517..34bba47 100644 --- a/code/base/arena.c +++ b/code/base/arena.c @@ -94,63 +94,19 @@ arena_push(Arena *arena, U64 size, U64 align) return result; } -internal U64 -arena_pos(Arena *arena) -{ - Arena *current = arena->current; - U64 pos = current->base_pos + current->pos; - return pos; -} - -internal void +void arena_pop_to(Arena *arena, U64 pos) { - U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos); - Arena *current = arena->current; - for(Arena *prev = 0; current->base_pos >= big_pos; current = prev) - { - prev = current->prev; - os_release(current, current->res); - } - arena->current = current; - U64 new_pos = big_pos - current->base_pos; - AssertAlways(new_pos <= current->pos); - AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos)); - current->pos = new_pos; -} - -//- rjf: arena push/pop helpers - -internal void -arena_clear(Arena *arena) -{ - arena_pop_to(arena, 0); -} - -internal void -arena_pop(Arena *arena, U64 amt) -{ - U64 pos_old = arena_pos(arena); - U64 pos_new = pos_old; - if(amt < pos_old) - { - pos_new = pos_old - amt; - } - arena_pop_to(arena, pos_new); -} - -//- rjf: temporary arena scopes - -internal TempArena -temp_begin(Arena *arena) -{ - U64 pos = arena_pos(arena); - TempArena temp = {arena, pos}; - return temp; -} - -internal void -temp_end(TempArena temp) -{ - arena_pop_to(temp.arena, temp.pos); + U64 big_pos = clamp_bot(size_of(Arena), pos); + Arena* current = arena->current; + for(Arena* prev = 0; current->pos >= big_pos; current = prev) + { + prev = current->prev; + alloc_free(current->backing, current); + } + arena->current = current; + U64 new_pos = big_pos - current->pos; + assert_always(new_pos <= current->pos); + asan_poison_memory_region((U8*)current + new_pos, (current->pos - new_pos)); + current->pos = new_pos; } diff --git a/code/base/arena.h b/code/base/arena.h index 27a28dc..b6bcc8f 100644 --- a/code/base/arena.h +++ b/code/base/arena.h @@ -70,7 +70,7 @@ struct TempArena MD_API void* arena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags); -inline +force_inline AllocatorInfo arena_allocator(Arena* arena) { AllocatorInfo info = { arena_allocator_proc, arena}; return info; @@ -85,19 +85,19 @@ void arena_release(Arena *arena); //- rjf: arena push/pop/pos core functions -internal void *arena_push (Arena* arena, SSIZE size, SSIZE align); -internal U64 arena_pos (Arena* arena); -internal void arena_pop_to(Arena* arena, SSIZE pos); +MD_API void *arena_push (Arena* arena, SSIZE size, SSIZE align); + U64 arena_pos (Arena* arena); +MD_API void arena_pop_to(Arena* arena, SSIZE pos); //- rjf: arena push/pop helpers -internal void arena_clear(Arena* arena); -internal void arena_pop (Arena* arena, SSIZE amt); +void arena_clear(Arena* arena); +void arena_pop (Arena* arena, SSIZE amt); //- rjf: temporary arena scopes -internal TempArena temp_arena_begin(Arena* arena); -internal void temp_arena_end(TempArena temp); +TempArena temp_arena_begin(Arena* arena); +void temp_arena_end(TempArena temp); //- rjf: push helper macros @@ -111,27 +111,58 @@ internal void temp_arena_end(TempArena temp); // Inlines inline void -arena_release(Arena* arena) -{ - for (Arena* n = arena->current, *prev = 0; n != 0; n = prev) - { +arena_release(Arena* arena) { + for (Arena* n = arena->current, *prev = 0; n != 0; n = prev) { prev = n->prev; alloc_free(arena->backing, n); } } -// DEFAULT_ALLOCATOR +inline U64 +arena_pos(Arena *arena) { + U64 const header_size = size_of(Arena); + Arena* current = arena->current; + U64 pos = current + header_size + current->pos; + return pos; +} + +//- rjf: arena push/pop helpers + +force_inline void arena_clear(Arena* arena) { arena_pop_to(arena, 0); } + +inline void +arena_pop(Arena* arena, U64 amt) { + U64 pos_old = arena_pos(arena); + U64 pos_new = pos_old; + if (amt < pos_old) + { + pos_new = pos_old - amt; + } + arena_pop_to(arena, pos_new); +} + +//- rjf: temporary arena scopes + +inline TempArena +temp_begin(Arena *arena) { + U64 pos = arena_pos(arena); + TempArena temp = {arena, pos}; + return temp; +} + +force_inline void temp_end(TempArena temp) { arena_pop_to(temp.arena, temp.pos); } + +// ======================================== DEFAULT_ALLOCATOR ===================================================== + #ifndef MD_OVERRIDE_DEFAULT_ALLOCATOR // The default allocator for this base module is the Arena allocator with a VArena backing -inline -AllocatorInfo default_allocator() +inline AllocatorInfo +default_allocator() { - // NOTE(Ed): Technically we don't need the backing_vmem var tracked here, but its nice for debug. - local_persist thread_local VArena* backing_vmem = nullptr; - local_persist thread_local Arena* arena = nullptr; + local_persist thread_local Arena* arena = nullptr; if (arena == nullptr) { - backing_vmem = varena_alloc(.flags = 0, .base_addr = 0x0, .reserve_size = VARENA_DEFAULT_RESERVE, .commit_size = VARENA_DEFAULT_COMMIT); - arena = arena_alloc(.backing = varena_allocator(backing_vmem), .block_size = VARENA_DEFAULT_RESERVE); + VArena* backing_vmem = varena_alloc(.flags = 0, .base_addr = 0x0, .reserve_size = VARENA_DEFAULT_RESERVE, .commit_size = VARENA_DEFAULT_COMMIT); + arena = arena_alloc(.backing = varena_allocator(backing_vmem), .block_size = VARENA_DEFAULT_RESERVE); } AllocatorInfo info = { arena_allocator_proc, arena }; return info; diff --git a/code/base/macros.h b/code/base/macros.h index 9c4f317..a3c82fd 100644 --- a/code/base/macros.h +++ b/code/base/macros.h @@ -96,6 +96,38 @@ # endif #endif +#ifndef force_inline +# if COMPILER_MSVC +# define force_inline __forceinline +# elif COMPILER_GCC +# define force_inline inline __attribute__((__always_inline__)) +# elif COMPILER_CLANG +# if __has_attribute(__always_inline__) +# define force_inline inline __attribute__((__always_inline__)) +# else +# define force_inline +# endif +# else +# define force_inline +# endif +#endif + +#ifndef never_inline +# if COMPILER_MSVC +# define never_inline __declspec( noinline ) +# elif COMPILER_GCC +# define never_inline __attribute__( ( __noinline__ ) ) +# elif COMPILER_CLANG +# if __has_attribute(__always_inline__) +# define never_inline __attribute__( ( __noinline__ ) ) +# else +# define never_inline +# endif +# else +# define never_inline +# endif +#endif + //////////////////////////////// //~ rjf: For-Loop Construct Macros diff --git a/code/base/memory_substrate.c b/code/base/memory_substrate.c index d6a3967..4b0b7be 100644 --- a/code/base/memory_substrate.c +++ b/code/base/memory_substrate.c @@ -186,6 +186,13 @@ void* heap_allocator_proc( void* allocator_data, AllocatorMode mode, SSIZE size, VArena varena__alloc(VArenaParams params) { + if (params.reserve_size == 0) { + params.reserve_size = VARENA_DEFAULT_RESERVE; + } + if (params.commit_size == 0) { + params.commit_size = VARENA_DEFAULT_COMMIT; + } + // rjf: round up reserve/commit sizes U64 reserve_size = params.reserve_size; U64 commit_size = params.commit_size; @@ -222,12 +229,13 @@ VArena varena__alloc(VArenaParams params) SPTR header_size = size_of(VArena); asan_unpoison_memory_region(base, header_size); - VArena* vm = (VArena* ) base; + VArena* vm = rcast(VArena*, base); + vm->reserve_start = rcast(SPTR, base) + header_size; vm->reserve = reserve_size; + vm->commit_size = params.commit_size; vm->committed = commit_size; - vm->reserve_start = (SPTR)base + header_size; - vm->flags = params.flags; vm->commit_used = 0; + vm->flags = params.flags; } void varena_release(VArena* arena) @@ -236,81 +244,180 @@ void varena_release(VArena* arena) arena = nullptr; } -void* varena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags) +void* varena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE requested_size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags) { OS_SystemInfo const* info = os_get_system_info(); - SPTR requested_size = size; + VArena* vm = rcast(VArena*, allocator_data); - void* result = nullptr; + void* allocated_mem = nullptr; switch (mode) { case AllocatorMode_Alloc: { - if (requested_size == 0) assert(requested_size != 0); - return result; + UPTR alignment_offset = 0; + UPTR current_offset = vm->reserve_start + vm->commit_used; + UPTR mask = scast(UPTR, alignment) - 1; + if ((current_offset & mask) != 0) { + alignment_offset = alignment - (current_offset & mask); + } + + UPTR size_to_allocate = requested_size + alignment_offset; + UPTR to_be_used = vm->commit_used + size_to_allocate; + + UPTR header_offset = vm->reserve_start - scast(UPTR, vm); + + UPTR commit_left = vm->committed - vm->commit_used - header_offset; + B32 needs_more_commited = commit_left < size_to_allocate; + if (needs_more_commited) + { + SPTR reserve_left = vm->reserve - vm->committed; + UPTR next_commit_size = reserve_left > 0 ? vm->commit_size : scast(UPTR, align_pow2( -reserve_left, os_get_system_info()->page_size)); + if (next_commit_size) { + B32 commit_result = os_commit(vm, next_commit_size); + if (commit_result == false) { + break; + } + } + } + + allocated_mem = rcast(void*, current_offset + alignment_offset); + vm->commit_used += size_to_allocate } break; case AllocatorMode_Free: { - } break; case AllocatorMode_FreeAll: { - + vm->commit_used = 0; } break; case AllocatorMode_Resize: { + assert(old_memory != nullptr); + assert(old_size > 0); + assert_msg(old_size == requested_size, "Requested resize when none needed"); + UPTR alignment_offset = scast(UPTR, old_memory) & (scast(UPTR, alignment) - 1); + assert_msg(alignment_offset != 0 && requested_size >= old_size, "Requested shrink from VArena"); + + UPTR old_memory_offset = scast(UPTR, old_memory) + scast(UPTR, old_size); + UPTR current_offset = scast(UPTR, vm->reserve_start) + scast(UPTR, vm->commit_used); + + assert_msg(old_memory_offset == current_offset, "Cannot resize existing allocation in VArena to a larger size unless it was the last allocated"); + + UPTR size_to_allocate = requested_size - old_size + alignment_offset; + + UPTR header_offset = vm->reserve_start - scast(UPTR, vm); + UPTR commit_left = vm->committed - vm->commit_used - header_offset; + B32 needs_more_commited = commit_left < size_to_allocate; + if (needs_more_commited) + { + SPTR reserve_left = vm->reserve - vm->committed; + UPTR next_commit_size = reserve_left > 0 ? vm->commit_size : scast(UPTR, align_pow2( -reserve_left, os_get_system_info()->page_size)); + if (next_commit_size) { + B32 commit_result = os_commit(vm, next_commit_size); + if (commit_result == false) { + break; + } + } + } + + allocated_mem = old_memory; + vm->commit_used += size_to_allocate } break; + // case AllocatorMode_Pop: + // { + + // } + // break; + + // case AllocatorMode_Pop_To: + // { + + // } + // break; + case AllocatorMode_QueryType: { - + return (void*) AllocatorType_VArena; } break; case AllocatorMode_QuerySupport: { - + return (void*) (AllocatorQuery_Alloc | AllocatorQuery_FreeAll | AllocatorQuery_Resize + // | AllocatorQuery_Pop | AllocatorQuery_Pop_To + ); } break; } - return result; + return allocated_mem; } void* farena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags) { - void* result = nullptr; + FArena* arena = rcast(FArena*, allocator_data); + + void* allocated_mem = nullptr; switch (mode) { case AllocatorMode_Alloc: + { + UPTR end = arena->slice.data + arena->used; + SSIZE total_size = align_pow2(size, alignment); + if (arena->used + total_size > arena->slice.len ) { + return allocated_mem; + } + + allocated_mem = align_pow2(end, alignment); + arena->used += total_size; + } break; case AllocatorMode_Free: + { + } break; case AllocatorMode_FreeAll: + { + arena->used = 0; + } break; case AllocatorMode_Resize: + { + allocated_mem = default_resize_align(farena_allocator(arena), old_memory, old_size, size, alignment); + } break; + // case AllocatorMode_Pop: + // break; + + // case AllocatorMode_Pop_To: + // break; + case AllocatorMode_QueryType: + return (void*) AllocatorType_FArena; break; case AllocatorMode_QuerySupport: + return (void*) (AllocatorQuery_Alloc | AllocatorQuery_Free | AllocatorQuery_FreeAll | AllocatorQuery_Resize + // | AllocatorQuery_Pop | AllocatorQuery_Pop_To + ); break; } - return result; + return allocated_mem; } diff --git a/code/base/memory_substrate.h b/code/base/memory_substrate.h index c337b9a..23f9f5c 100644 --- a/code/base/memory_substrate.h +++ b/code/base/memory_substrate.h @@ -36,16 +36,20 @@ enum AllocatorMode AllocatorMode_Free, AllocatorMode_FreeAll, AllocatorMode_Resize, + // AllocatorMode_Pop, + // AllocatorMode_Pop_To, AllocatorMode_QueryType, AllocatorMode_QuerySupport, }; typedef U64 AllocatorQueryFlags; enum { - AllocatorQuery_Alloc = (1 << 0), - AllocatorQuery_Free = (1 << 1), - AllocatorQuery_FreeAll = (1 << 2), - AllocatorQuery_Resize = (1 << 3), + AllocatorQuery_Alloc = (1 << 0), + AllocatorQuery_Free = (1 << 1), + AllocatorQuery_FreeAll = (1 << 2), + AllocatorQuery_Resize = (1 << 3), + // AllocatorQuery_Pop = (1 << 3), + // AllocatorQuery_Pop_To = (1 << 3), }; typedef void*(AllocatorProc)( void* allocator_data, AllocatorMode type, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags ); @@ -62,7 +66,7 @@ AllocatorInfo default_allocator(); enum AllocFlag { - ALLOCATOR_FLAG_CLEAR_TO_ZERO = 0, + ALLOCATOR_FLAG_CLEAR_TO_ZERO = (1 << 0), }; #ifndef MD_DEFAULT_MEMORY_ALIGNMENT @@ -87,6 +91,10 @@ void* alloc_align( AllocatorInfo a, SSIZE size, SSIZE alignment ); // Free allocated memory. void alloc_free( AllocatorInfo a, void* ptr ); +// void alloc_pop(AllocatorInfo a, SSIZE amt); + +// void alloc_pop_to(AllocatorInfo a, SSIZE pos); + // Free all memory allocated by an allocator. void free_all( AllocatorInfo a ); @@ -98,12 +106,15 @@ void* resize_align( AllocatorInfo a, void* ptr, SSIZE old_size, SSIZE new_size, #ifndef alloc_item // Allocate memory for an item. -#define alloc_item( allocator_, Type ) ( Type* )alloc( allocator_, size_of( Type ) ) +#define alloc_item(allocator, Type) (Type*)memory_zero(alloc(allocator, size_of(Type)), size_of(Type)) +// Allocate memory for an item. +#define alloc_item_no_zero( allocator, Type ) (Type*) alloc(allocator, size_of(Type)) #endif #ifndef alloc_array // Allocate memory for an array of items. -#define alloc_array( allocator_, Type, count ) ( Type* )alloc( allocator_, size_of( Type ) * ( count ) ) +#define alloc_array( allocator_, Type, count ) (Type*)memory_zero(alloc( allocator_, size_of(Type) * (count) ), size_of(Type) * (count)) +#define alloc_array_no_zero( allocator_, Type, count ) (Type*) alloc( allocator_, size_of(Type) * (count) ) #endif // Allocate/Resize memory using default options. @@ -174,18 +185,14 @@ struct VArenaParams typedef struct VArena VArena; struct VArena { - VArenaFlags flags; SSIZE reserve_start; SSIZE reserve; + SSIZE commit_size; SSIZE committed; SSIZE commit_used; + VArenaFlags flags; }; -AllocatorInfo vm_allocator(VArena* vm) { - AllocatorInfo info = { varena_allocator_proc, vm }; - return info; -} - MD_API VArena* varena__alloc(VArenaParams params PARAM_DEFAULT); #define varena_alloc(...) varena__alloc( (VArenaParams){__VA_ARGS__} ) @@ -194,6 +201,8 @@ MD_API VArenaParams varena_release (VArena vm); MD_API void* varena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags); +#define varena_allocator(vm) (AllocatorInfo) { varena_allocator_proc, vm } + typedef struct ByteSlice ByteSlice; struct ByteSlice { @@ -201,6 +210,8 @@ struct ByteSlice SSIZE len; }; +#define mem_to_byteslice(data, len) (ByteSlice){ (U8*)(data), (SSIZE)(len) } + // Fixed size arena typedef struct FArena FArena; struct FArena @@ -209,10 +220,13 @@ struct FArena SSIZE used; }; -FArena farena_from_byteslice(ByteSlice slice); +#define farena_from_byteslice(slice) (FArena) { slice, 0 } +#define farena_from_memory(data, len) (FArena) { mem_to_byteslice(data, len), 0 } MD_API void* farena_allocator_proc(void* allocator_data, AllocatorMode mode, SSIZE size, SSIZE alignment, void* old_memory, SSIZE old_size, U64 flags); +#define farena_allocator(arena) (AllocatorInfo){ farena_allocator_proc, & arena } + // Inlines inline @@ -257,6 +271,22 @@ void alloc_free( AllocatorInfo a, void* ptr ) { } } +// inline +// void alloc_pop(AllocatorInfo a, SSIZE amt) { +// if (a.proc == nullptr) { +// a = default_allocator(); +// } +// a.proc(a.data, AllocatorMode_Pop, amt, 0, nullptr, 0, MD_DEFAULT_ALLOCATOR_FLAGS); +// } + +// inline +// void alloc_pop_to(AllocatorInfo a, SSIZE pos) { +// if (a.proc == nullptr) { +// a = default_allocator(); +// } +// a.proc(a.data, AllocatorMode_Pop_To, 0, 0, rcast(void*, pos), 0, 0); +// } + inline void free_all( AllocatorInfo a ) { if (a.proc == nullptr) { diff --git a/code/base/strings.c b/code/base/strings.c index 0324aa8..d67ee7f 100644 --- a/code/base/strings.c +++ b/code/base/strings.c @@ -196,7 +196,7 @@ push_str8fv(Arena *arena, char *fmt, va_list args){ } String8 -str8__cat(String8 s1, String8 s2, AllocatorInfo ainfo) +str8_cat(AllocatorInfo ainfo, String8 s1, String8 s2) { String8 str; str.size = s1.size + s2.size; @@ -208,7 +208,7 @@ str8__cat(String8 s1, String8 s2, AllocatorInfo ainfo) } String8 -str8__copy(String8 s, AllocatorInfo ainfo) +str8_copy(AllocatorInfo ainfo, String8 s) { String8 str; str.size = s.size; @@ -224,7 +224,7 @@ str8fv(AllocatorInfo ainfo, char *fmt, va_list args){ va_copy(args2, args); U32 needed_bytes = raddbg_vsnprintf(0, 0, fmt, args) + 1; String8 result = {0}; - result.str = alloc_array(ainfo, U8, needed_bytes); + result.str = alloc_array_no_zero(ainfo, U8, needed_bytes); result.size = raddbg_vsnprintf((char*)result.str, needed_bytes, fmt, args2); result.str[result.size] = 0; va_end(args2); @@ -330,6 +330,24 @@ str8_from_memory_size(Arena *arena, U64 z) { return(result); } +String8 +str8__from_allocator_size(AllocatorInfo ainfo, U64 z) { + String8 result = {0}; + if (z < KB(1)) { + result = str8f(ainfo, "%llu b", z); + } + else if (z < MB(1)) { + result = str8f(ainfo, "%llu.%02llu Kb", z/KB(1), ((100*z)/KB(1))%100); + } + else if (z < GB(1)) { + result = str8f(ainfo, "%llu.%02llu Mb", z/MB(1), ((100*z)/MB(1))%100); + } + else{ + result = str8f(ainfo, "%llu.%02llu Gb", z/GB(1), ((100*z)/GB(1))%100); + } + return(result); +} + String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator) { @@ -419,6 +437,95 @@ str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_se return result; } +String8 +str8__from_allocator_u64(AllocatorInfo ainfo, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator) +{ + String8 result = {0}; + { + // rjf: prefix + String8 prefix = {0}; + switch(radix) + { + case 16:{prefix = str8_lit("0x");}break; + case 8: {prefix = str8_lit("0o");}break; + case 2: {prefix = str8_lit("0b");}break; + } + + // rjf: determine # of chars between separators + U8 digit_group_size = 3; + switch(radix) + { + default:break; + case 2: + case 8: + case 16: + {digit_group_size = 4;} break; + } + + // rjf: prep + U64 needed_leading_0s = 0; + { + U64 needed_digits = 1; + { + U64 u64_reduce = u64; + for(;;) + { + u64_reduce /= radix; + if(u64_reduce == 0) { + break; + } + needed_digits += 1; + } + } + needed_leading_0s = (min_digits > needed_digits) ? min_digits - needed_digits : 0; + U64 needed_separators = 0; + if (digit_group_separator != 0) + { + needed_separators = (needed_digits+needed_leading_0s)/digit_group_size; + if(needed_separators > 0 && (needed_digits+needed_leading_0s)%digit_group_size == 0) + { + needed_separators -= 1; + } + } + result.size = prefix.size + needed_leading_0s + needed_separators + needed_digits; + result.str = alloc_array(ainfo, U8, result.size + 1); + result.str[result.size] = 0; + } + + // rjf: fill contents + { + U64 u64_reduce = u64; + U64 digits_until_separator = digit_group_size; + for (U64 idx = 0; idx < result.size; idx += 1) + { + if(digits_until_separator == 0 && digit_group_separator != 0) { + result.str[result.size - idx - 1] = digit_group_separator; + digits_until_separator = digit_group_size+1; + } + else { + result.str[result.size - idx - 1] = char_to_lower(integer_symbols[u64_reduce%radix]); + u64_reduce /= radix; + } + digits_until_separator -= 1; + if(u64_reduce == 0) { + break; + } + } + for(U64 leading_0_idx = 0; leading_0_idx < needed_leading_0s; leading_0_idx += 1) + { + result.str[prefix.size + leading_0_idx] = '0'; + } + } + + // rjf: fill prefix + if(prefix.size != 0) + { + memory_copy(result.str, prefix.str, prefix.size); + } + } + return result; +} + String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator) { @@ -436,10 +543,26 @@ str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_se return result; } +String8 +str8__from_alloctor_s64(AllocatorInfo ainfo, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator) +{ + String8 result = {0}; + if(s64 < 0) { + U8 bytes[KB(8)]; + FArena scratch = farena_from_memory(bytes, size_of(bytes)); + String8 numeric_part = str8__from_allocator_u64((U64)(-s64), radix, min_digits, digit_group_separator, farena_allocator(scratch)); + result = str8f(ainfo, "-%S", numeric_part); + } + else { + result = str8__from_allocator_u64((U64)s64, radix, min_digits, digit_group_separator, ainfo); + } + return result; +} + //////////////////////////////// //~ rjf: String <=> Float Conversions -internal F64 +F64 f64_from_str8(String8 string) { // TODO(rjf): crappy implementation for now that just uses atof. @@ -484,67 +607,98 @@ f64_from_str8(String8 string) //////////////////////////////// //~ rjf: String List Construction Functions -internal void -str8_list_concat_in_place(String8List *list, String8List *to_push){ - if(to_push->node_count != 0){ - if (list->last){ - list->node_count += to_push->node_count; - list->total_size += to_push->total_size; - list->last->next = to_push->first; - list->last = to_push->last; - } - else{ - *list = *to_push; - } - MemoryZeroStruct(to_push); - } +void +str8_list_concat_in_place(String8List* list, String8List* to_push) { + if(to_push->node_count != 0) + { + if (list->last) { + list->node_count += to_push->node_count; + list->total_size += to_push->total_size; + list->last->next = to_push->first; + list->last = to_push->last; + } + else { + *list = *to_push; + } + MemoryZeroStruct(to_push); + } } -internal String8Node* -str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align){ - String8Node *node = push_array_no_zero(arena, String8Node, 1); - U64 new_size = list->total_size + min; - U64 increase_size = 0; - if (align > 1){ - // NOTE(allen): assert is power of 2 - Assert(((align - 1) & align) == 0); - U64 mask = align - 1; - new_size += mask; - new_size &= (~mask); - increase_size = new_size - list->total_size; - } - local_persist const U8 zeroes_buffer[64] = {0}; - Assert(increase_size <= ArrayCount(zeroes_buffer)); - SLLQueuePush(list->first, list->last, node); - list->node_count += 1; - list->total_size = new_size; - node->string.str = (U8*)zeroes_buffer; - node->string.size = increase_size; - return(node); +String8Node* +str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align) +{ + String8Node* node = push_array_no_zero(arena, String8Node, 1); + U64 new_size = list->total_size + min; + U64 increase_size = 0; + + if (align > 1) { + // NOTE(allen): assert is power of 2 + assert(((align - 1) & align) == 0); + U64 mask = align - 1; + new_size += mask; + new_size &= (~mask); + increase_size = new_size - list->total_size; + } + + local_persist const U8 zeroes_buffer[64] = {0}; + assert(increase_size <= array_count(zeroes_buffer)); + + sll_queue_push(list->first, list->last, node); + list->node_count += 1; + list->total_size = new_size; + node->string.str = (U8*)zeroes_buffer; + node->string.size = increase_size; + return(node); } -internal String8Node* -str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...){ - va_list args; - va_start(args, fmt); - String8 string = push_str8fv(arena, fmt, args); - String8Node *result = str8_list_push(arena, list, string); - va_end(args); - return(result); +String8Node* +str8_list_aligner(AllocatorInfo ainfo, String8List* list, U64 min, U64 align) { + String8Node* node = alloc_array(ainfo, String8Node, 1); + U64 new_size = list->total_size + min; + U64 increase_size = 0; + + if (align > 1) { + // NOTE(allen): assert is power of 2 + assert(((align - 1) & align) == 0); + U64 mask = align - 1; + new_size += mask; + new_size &= (~mask); + increase_size = new_size - list->total_size; + } + + local_persist const U8 zeroes_buffer[64] = {0}; + assert(increase_size <= array_count(zeroes_buffer)); + + sll_queue_push(list->first, list->last, node); + list->node_count += 1; + list->total_size = new_size; + node->string.str = (U8*)zeroes_buffer; + node->string.size = increase_size; + return(node); } -internal String8Node* -str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...){ - va_list args; - va_start(args, fmt); - String8 string = push_str8fv(arena, fmt, args); - String8Node *result = str8_list_push_front(arena, list, string); - va_end(args); - return(result); +String8Node* +str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...) { + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(arena, fmt, args); + String8Node *result = str8_list_push(arena, list, string); + va_end(args); + return(result); } -internal String8List -str8_list_copy(Arena *arena, String8List *list){ +String8Node* +str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...) { + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(arena, fmt, args); + String8Node *result = str8_list_push_front(arena, list, string); + va_end(args); + return(result); +} + +String8List +str8_list_copy(Arena *arena, String8List *list) { String8List result = {0}; for (String8Node *node = list->first; node != 0; @@ -556,7 +710,7 @@ str8_list_copy(Arena *arena, String8List *list){ return(result); } -internal String8List +String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags){ String8List list = {0}; @@ -590,13 +744,13 @@ str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, return(list); } -internal String8List +String8List str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags){ String8List list = str8_split(arena, string, split_chars.str, split_chars.size, flags); return list; } -internal String8List +String8List str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags){ String8List result = {0}; for (String8Node *node = list.first; node != 0; node = node->next){ @@ -606,7 +760,7 @@ str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_ch return result; } -internal String8 +String8 str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params){ StringJoin join = {0}; if (optional_params != 0){ @@ -642,7 +796,7 @@ str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params){ return(result); } -internal void +void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count){ for (U32 i = 0; i < flag_string_count; i += 1){ diff --git a/code/base/strings.h b/code/base/strings.h index 376bacf..390da26 100644 --- a/code/base/strings.h +++ b/code/base/strings.h @@ -206,13 +206,6 @@ str8_cstring_capped(void *cstr, void *cap) { return(result); } -//////////////////////////////// -//~ rjf: String Stylization - -inline String8 upper_from_str8 (Arena* arena, String8 string) { string = push_str8_copy(arena, string); for(U64 idx = 0; idx < string.size; idx += 1) { string.str[idx] = char_to_upper(string.str[idx]); } return string; } -inline String8 lower_from_str8 (Arena* arena, String8 string) { string = push_str8_copy(arena, string); for(U64 idx = 0; idx < string.size; idx += 1) { string.str[idx] = char_to_lower(string.str[idx]); } return string; } -inline String8 backslashed_from_str8(Arena *arena, String8 string) { string = push_str8_copy(arena, string); for(U64 idx = 0; idx < string.size; idx += 1) { string.str[idx] = char_is_slash(string.str[idx]) ? '\\' : string.str[idx]; } return string; } - //////////////////////////////// //~ rjf: String Matching @@ -284,13 +277,10 @@ MD_API String8 push_str8_copy(Arena* arena, String8 s); MD_API String8 push_str8fv (Arena* arena, char* fmt, va_list args); String8 push_str8f (Arena* arena, char* fmt, ...); -MD_API String8 str8__cat (String8 s1, String8 s2, AllocatorInfo ainfo); -MD_API String8 str8__copy(String8 s, AllocatorInfo ainfo); -MD_API String8 str8fv (AllocatorInfo ainfo, char* fmt, va_list args); - String8 str8f (AllocatorInfo ainfo, char* fmt, ...); - -#define str8_cat(s1, s2, ...) str8__cat (s1, s2, (AllocatorInfo) {__VA_ARGS__}) -#define str8_copy(s, ...) str8__copy(s, (AllocatorInfo) {__VA_ARGS__}) +MD_API String8 str8_cat (AllocatorInfo ainfo, String8 s1, String8 s2); +MD_API String8 str8_copy(AllocatorInfo ainfo, String8 s); +MD_API String8 str8fv (AllocatorInfo ainfo, char* fmt, va_list args); + String8 str8f (AllocatorInfo ainfo, char* fmt, ...); inline String8 push_str8f(Arena *arena, char *fmt, ...){ @@ -310,6 +300,13 @@ str8f(AllocatorInfo ainfo, char *fmt, ...){ return(result); } +//////////////////////////////// +//~ rjf: String Stylization + +inline String8 upper_from_str8 (Arena* arena, String8 string) { string = push_str8_copy(arena, string); for(U64 idx = 0; idx < string.size; idx += 1) { string.str[idx] = char_to_upper(string.str[idx]); } return string; } +inline String8 lower_from_str8 (Arena* arena, String8 string) { string = push_str8_copy(arena, string); for(U64 idx = 0; idx < string.size; idx += 1) { string.str[idx] = char_to_lower(string.str[idx]); } return string; } +inline String8 backslashed_from_str8(Arena *arena, String8 string) { string = push_str8_copy(arena, string); for(U64 idx = 0; idx < string.size; idx += 1) { string.str[idx] = char_is_slash(string.str[idx]) ? '\\' : string.str[idx]; } return string; } + //////////////////////////////// //~ rjf: String <=> Integer Conversions @@ -322,10 +319,14 @@ MD_API B32 try_u64_from_str8_c_rules(String8 string, U64* x); B32 try_s64_from_str8_c_rules(String8 string, S64* x); //- rjf: integer -> string - String8 str8_from_memory_size(Arena *arena, U64 z); +MD_API String8 str8_from_memory_size(Arena *arena, U64 z); MD_API String8 str8_from_u64 (Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator); MD_API String8 str8_from_s64 (Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator); +String8 str8_from_allocator_size(U64 z, AllocatorInfo ainfo); +String8 str8_from_allocator_u64 (AllocatorInfo ainfo, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator); +String8 str8_from_alloctor_s64 (AllocatorInfo ainfo, S64 u64, U32 radix, U8 min_digits, U8 digit_group_separator); + inline U64 u64_from_str8(String8 string, U32 radix) { U64 x = 0; @@ -412,6 +413,10 @@ String8Node* str8_list_pushf (Arena* arena, String8List* list, char* fmt, String8Node* str8_list_push_frontf (Arena* arena, String8List* list, char* fmt, ...); String8List str8_list_copy (Arena* arena, String8List* list); +String8Node* str8_list_alloc (AllocatorInfo ainfo, String8List* list, String8 string); +String8Node* str8_list_alloc_front (AllocatorInfo ainfo, String8List* list, String8 string); +String8Node* str8_list_alloc_aligner(AllocatorInfo ainfo, String8List* list, U64 min, U64 align); + inline String8Node* str8_list_push(Arena* arena, String8List* list, String8 string) { String8Node* node = push_array_no_zero(arena, String8Node, 1); @@ -426,8 +431,6 @@ str8_list_push_front(Arena* arena, String8List* list, String8 string) { return(node); } - - //////////////////////////////// //~ rjf: String Splitting & Joining