still figuring out some allocator strats around offering opt out of Area

This commit is contained in:
2025-02-06 10:12:17 -05:00
parent 259cb23810
commit 4221064785
8 changed files with 502 additions and 186 deletions
+4 -1
View File
@@ -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",
+13 -57
View File
@@ -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;
}
+51 -20
View File
@@ -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;
+32
View File
@@ -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
+122 -15
View File
@@ -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;
}
+44 -14
View File
@@ -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) {
+216 -62
View File
@@ -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){
+20 -17
View File
@@ -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