From ea37ceb3bd1cd75785dddc3e35a0238824136c80 Mon Sep 17 00:00:00 2001 From: Charlie <66182434+asbott@users.noreply.github.com> Date: Mon, 1 Jul 2024 13:10:06 +0200 Subject: [PATCH] Explicit allocators --- entry.c | 9 +-- oogabooga/base.c | 23 +++--- oogabooga/drawing.c | 20 ++--- oogabooga/gfx_impl_d3d11.c | 2 +- oogabooga/gfx_interface.c | 1 + oogabooga/memory.c | 23 +++--- oogabooga/oogabooga.c | 18 +++-- oogabooga/os_impl_windows.c | 43 +++++------ oogabooga/os_interface.c | 8 +- oogabooga/string.c | 63 +++------------- oogabooga/string_format.c | 38 ++++------ oogabooga/tests.c | 145 +++++++++++++++++++----------------- 12 files changed, 172 insertions(+), 221 deletions(-) diff --git a/entry.c b/entry.c index 3670df3..d55d946 100644 --- a/entry.c +++ b/entry.c @@ -18,9 +18,9 @@ int start(int argc, char **argv) { window.clear_color = hex_to_rgba(0x2a2d3aff); - Gfx_Image *bush_image = load_image_from_disk(fixed_string("berry_bush.png")); + Gfx_Image *bush_image = load_image_from_disk(fixed_string("berry_bush.png"), get_heap_allocator()); assert(bush_image, "Failed loading berry_bush.png"); - Gfx_Image *hammer_image = load_image_from_disk(fixed_string("hammer.png")); + Gfx_Image *hammer_image = load_image_from_disk(fixed_string("hammer.png"), get_heap_allocator()); assert(hammer_image, "Failed loading hammer.png"); seed_for_random = os_get_current_cycle_count(); @@ -33,7 +33,6 @@ int start(int argc, char **argv) { float64 last_time = os_get_current_time_in_seconds(); while (!window.should_close) { reset_temporary_storage(); - context.allocator = temp; float64 now = os_get_current_time_in_seconds(); float64 delta = now - last_time; @@ -58,11 +57,9 @@ int start(int argc, char **argv) { } if (is_key_just_released('Q')) { - push_allocator(get_heap_allocator()); delete_image(bush_image); - bush_image = load_image_from_disk(fixed_string("berry_bush.png")); + bush_image = load_image_from_disk(fixed_string("berry_bush.png"), get_heap_allocator()); assert(bush_image, "Failed loading berry_bush.png"); - pop_allocator(); } const float32 cam_move_speed = 4.0; diff --git a/oogabooga/base.c b/oogabooga/base.c index 99191ee..8fcb01d 100644 --- a/oogabooga/base.c +++ b/oogabooga/base.c @@ -101,11 +101,12 @@ void printf(const char* fmt, ...); #define FIRST_ARG(arg1, ...) arg1 +#define SECOND_ARG(arg1, arg2, ...) arg2 #define print(...) _Generic((FIRST_ARG(__VA_ARGS__)), \ string: prints, \ default: printf \ )(__VA_ARGS__) -#define sprint(...) _Generic((FIRST_ARG(__VA_ARGS__)), \ +#define sprint(...) _Generic((SECOND_ARG(__VA_ARGS__)), \ string: sprints, \ default: sprintf \ )(__VA_ARGS__) @@ -125,7 +126,7 @@ typedef enum Allocator_Message { ALLOCATOR_DEALLOCATE, ALLOCATOR_REALLOCATE, } Allocator_Message; -typedef void*(*Allocator_Proc)(u64, void*, Allocator_Message); +typedef void*(*Allocator_Proc)(u64, void*, Allocator_Message, void*); typedef enum Log_Level { LOG_ERROR, @@ -142,7 +143,6 @@ typedef struct Allocator { } Allocator; typedef struct Context { - Allocator allocator; void *logger; // void(*Logger_Proc)(Log_Level level, string fmt, ...) CONTEXT_EXTRA extra; @@ -154,8 +154,14 @@ thread_local Context context; thread_local Context context_stack[CONTEXT_STACK_MAX]; thread_local u64 num_contexts = 0; -void* alloc(u64 size) { return context.allocator.proc(size, NULL, ALLOCATOR_ALLOCATE); } -void dealloc(void *p) { context.allocator.proc(0, p, ALLOCATOR_DEALLOCATE); } +forward_global thread_local Allocator temp; + +void* alloc(Allocator allocator, u64 size) { + return allocator.proc(size, 0, ALLOCATOR_ALLOCATE, allocator.data); +} +void dealloc(Allocator allocator, void *p) { + allocator.proc(0, p, ALLOCATOR_DEALLOCATE, allocator.data); +} void push_context(Context c) { assert(num_contexts < CONTEXT_STACK_MAX, "Context stack overflow"); @@ -170,11 +176,4 @@ void pop_context() { context = context_stack[num_contexts]; } -void push_allocator(Allocator a) { - Context c = context; - c.allocator = a; - push_context(c); -} -void pop_allocator() { pop_context(); } - diff --git a/oogabooga/drawing.c b/oogabooga/drawing.c index 45256f8..be5c3a0 100644 --- a/oogabooga/drawing.c +++ b/oogabooga/drawing.c @@ -185,16 +185,17 @@ Draw_Quad *draw_image_xform(Gfx_Image *image, Matrix4 xform, Vector2 size, Vecto #define COLOR_WHITE ((Vector4){1.0, 1.0, 1.0, 1.0}) #define COLOR_BLACK ((Vector4){0.0, 0.0, 0.0, 1.0}) -// context.allocator -Gfx_Image *load_image_from_disk(string path) { +Gfx_Image *load_image_from_disk(string path, Allocator allocator) { string png; - bool ok = os_read_entire_file(path, &png); + bool ok = os_read_entire_file(path, &png, allocator); if (!ok) return 0; - Gfx_Image *image = alloc(sizeof(Gfx_Image)); + Gfx_Image *image = alloc(allocator, sizeof(Gfx_Image)); // This is fucking terrible I gotta write my own decoder + lodepng_allocator = allocator; + LodePNGState state; lodepng_state_init(&state); u32 error = lodepng_inspect(&image->width, &image->height, &state, png.data, png.count); @@ -214,7 +215,7 @@ Gfx_Image *load_image_from_disk(string path) { lodepng_state_cleanup(&state); - dealloc_string(png); + dealloc_string(allocator, png); if (error) { return 0; @@ -222,7 +223,7 @@ Gfx_Image *load_image_from_disk(string path) { // We need to flip the image u32 row_bytes = image->width * 4; // #Magicvalue assuming 4 bytes - u8* temp_row = (u8*)alloc(row_bytes); + u8* temp_row = (u8*)alloc(temp, row_bytes); for (u32 i = 0; i < image->height / 2; i++) { u8* top_row = image->data + i * row_bytes; u8* bottom_row = image->data + (image->height - i - 1) * row_bytes; @@ -232,17 +233,18 @@ Gfx_Image *load_image_from_disk(string path) { memcpy(top_row, bottom_row, row_bytes); memcpy(bottom_row, temp_row, row_bytes); } - dealloc(temp_row); image->gfx_handle = GFX_INVALID_HANDLE; // This is handled in gfx + image->allocator = allocator; + return image; } void delete_image(Gfx_Image *image) { - dealloc(image->data); + dealloc(image->allocator, image->data); image->width = 0; image->height = 0; draw_frame.garbage_stack[draw_frame.garbage_stack_count] = image->gfx_handle; draw_frame.garbage_stack_count += 1; - dealloc(image); + dealloc(image->allocator, image); } \ No newline at end of file diff --git a/oogabooga/gfx_impl_d3d11.c b/oogabooga/gfx_impl_d3d11.c index a2384f4..7bedb0d 100644 --- a/oogabooga/gfx_impl_d3d11.c +++ b/oogabooga/gfx_impl_d3d11.c @@ -313,7 +313,7 @@ void gfx_init() { #if OOGABOOGA_DEV string source; - bool source_ok = os_read_entire_file(fxstr("oogabooga/dev/d3d11_image_shader.hlsl"), &source); + bool source_ok = os_read_entire_file(fxstr("oogabooga/dev/d3d11_image_shader.hlsl"), &source, get_heap_allocator()); // #Leak assert(source_ok, "Could not open d3d11_image_shader source"); // Compile vertex shader diff --git a/oogabooga/gfx_interface.c b/oogabooga/gfx_interface.c index 836644e..2bbd4a8 100644 --- a/oogabooga/gfx_interface.c +++ b/oogabooga/gfx_interface.c @@ -33,5 +33,6 @@ typedef struct Gfx_Image { u32 width, height; u8 *data; Gfx_Handle gfx_handle; + Allocator allocator; } Gfx_Image; diff --git a/oogabooga/memory.c b/oogabooga/memory.c index c66ba72..cd0503c 100644 --- a/oogabooga/memory.c +++ b/oogabooga/memory.c @@ -12,7 +12,7 @@ u64 program_memory_size = 0; u8 init_memory_arena[INIT_MEMORY_SIZE]; u8 *init_memory_head = init_memory_arena; -void* initialization_allocator_proc(u64 size, void *p, Allocator_Message message) { +void* initialization_allocator_proc(u64 size, void *p, Allocator_Message message, void *data) { switch (message) { case ALLOCATOR_ALLOCATE: { p = init_memory_head; @@ -35,6 +35,12 @@ void* initialization_allocator_proc(u64 size, void *p, Allocator_Message message return 0; } +Allocator get_initialization_allocator() { + Allocator a; + a.proc = initialization_allocator_proc; + return a; +} + /// /// // Basic general heap allocator, free list @@ -206,7 +212,7 @@ void heap_init() { if (heap_initted) return; heap_initted = true; heap_head = make_heap_block(0, DEFAULT_HEAP_BLOCK_SIZE); - heap_lock = os_make_spinlock(); + heap_lock = os_make_spinlock(get_initialization_allocator()); } void *heap_alloc(u64 size) { @@ -376,7 +382,7 @@ void heap_dealloc(void *p) { os_spinlock_unlock(heap_lock); } -void* heap_allocator_proc(u64 size, void *p, Allocator_Message message) { +void* heap_allocator_proc(u64 size, void *p, Allocator_Message message, void* data) { switch (message) { case ALLOCATOR_ALLOCATE: { return heap_alloc(size); @@ -421,7 +427,7 @@ Allocator get_heap_allocator() { #endif void* talloc(u64); -void* temp_allocator_proc(u64 size, void *p, Allocator_Message message); +void* temp_allocator_proc(u64 size, void *p, Allocator_Message message, void*); thread_local void * temporary_storage = 0; thread_local bool temporary_storage_initted = false; @@ -430,7 +436,7 @@ thread_local bool has_warned_temporary_storage_overflow = false; thread_local Allocator temp; -void* temp_allocator_proc(u64 size, void *p, Allocator_Message message) { +void* temp_allocator_proc(u64 size, void *p, Allocator_Message message, void* data) { switch (message) { case ALLOCATOR_ALLOCATE: { return talloc(size); @@ -457,6 +463,8 @@ void temporary_storage_init() { temp.data = 0; temporary_storage_initted = true; + + temp.proc = temp_allocator_proc; } void* talloc(u64 size) { @@ -487,8 +495,3 @@ void reset_temporary_storage() { has_warned_temporary_storage_overflow = true; } -// So we can do this in code included before this. -void push_temp_allocator() { - if (!temporary_storage_initted) temporary_storage_init(); - push_allocator(temp); -} \ No newline at end of file diff --git a/oogabooga/oogabooga.c b/oogabooga/oogabooga.c index 65670ac..2750017 100644 --- a/oogabooga/oogabooga.c +++ b/oogabooga/oogabooga.c @@ -32,16 +32,22 @@ #include +Allocator get_heap_allocator(); + // Custom allocators for lodepng +Allocator lodepng_allocator = {0}; void* lodepng_malloc(size_t size) { - return context.allocator.proc((u64)size, 0, ALLOCATOR_ALLOCATE); + if (lodepng_allocator.proc) return alloc(lodepng_allocator, size); + return alloc(get_heap_allocator(), size); } void* lodepng_realloc(void* ptr, size_t new_size) { - return context.allocator.proc((u64)new_size, ptr, ALLOCATOR_REALLOCATE); + if (lodepng_allocator.proc) return lodepng_allocator.proc(new_size, ptr, ALLOCATOR_REALLOCATE, lodepng_allocator.data); + return get_heap_allocator().proc(new_size, ptr, ALLOCATOR_REALLOCATE, get_heap_allocator().data); } void lodepng_free(void* ptr) { if (!ptr) return; - context.allocator.proc(0, ptr, ALLOCATOR_DEALLOCATE); + if (lodepng_allocator.proc) dealloc(lodepng_allocator, ptr); + else dealloc(get_heap_allocator(), ptr); } #define LODEPNG_NO_COMPILE_ALLOCATORS //#define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS @@ -124,7 +130,7 @@ void lodepng_free(void* ptr) { #undef near #endif #ifdef far -#undef far +#undef far #endif #include "random.c" @@ -161,10 +167,11 @@ void lodepng_free(void* ptr) { void oogabooga_init(u64 program_memory_size) { context.logger = default_logger; + temp = get_initialization_allocator(); os_init(program_memory_size); - gfx_init(); heap_init(); temporary_storage_init(); + gfx_init(); } #ifndef INITIAL_PROGRAM_MEMORY_SIZE @@ -178,7 +185,6 @@ void oogabooga_init(u64 program_memory_size) { int ENTRY_PROC(int argc, char **argv); int main(int argc, char **argv) { - context.allocator.proc = initialization_allocator_proc; oogabooga_init(INITIAL_PROGRAM_MEMORY_SIZE); printf("Ooga booga program started\n"); diff --git a/oogabooga/os_impl_windows.c b/oogabooga/os_impl_windows.c index b845189..2c83e26 100644 --- a/oogabooga/os_impl_windows.c +++ b/oogabooga/os_impl_windows.c @@ -162,7 +162,6 @@ void os_init(u64 program_memory_size) { heap_init(); - context.allocator = get_heap_allocator(); os.crt = os_load_dynamic_library(const_string("msvcrt.dll")); assert(os.crt != 0, "Could not load win32 crt library. Might be compiled with non-msvc? #Incomplete #Portability"); @@ -308,8 +307,8 @@ DWORD WINAPI win32_thread_invoker(LPVOID param) { return 0; } -Thread* os_make_thread(Thread_Proc proc) { - Thread *t = (Thread*)alloc(sizeof(Thread)); +Thread* os_make_thread(Thread_Proc proc, Allocator allocator) { + Thread *t = (Thread*)alloc(allocator, sizeof(Thread)); t->id = 0; // This is set when we start it t->proc = proc; t->initial_context = context; @@ -365,8 +364,9 @@ void os_unlock_mutex(Mutex_Handle m) { /// // Spinlock "primitive" -Spinlock *os_make_spinlock() { - Spinlock *l = cast(Spinlock*)alloc(sizeof(Spinlock)); +Spinlock *os_make_spinlock(Allocator allocator) { + // #Memory #Cleanup do we need to heap allocate this ? + Spinlock *l = cast(Spinlock*)alloc(allocator, sizeof(Spinlock)); l->locked = false; return l; } @@ -490,15 +490,14 @@ void os_write_string_to_stdout(string s) { WriteFile(win32_stdout, s.data, s.count, 0, NULL); } -// context.allocator -u16 *win32_fixed_utf8_to_null_terminated_wide(string utf8) { +u16 *win32_fixed_utf8_to_null_terminated_wide(string utf8, Allocator allocator) { u64 utf16_length = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)utf8.data, (int)utf8.count, 0, 0); - u16 *utf16_str = (u16 *)alloc((utf16_length + 1) * sizeof(u16)); + u16 *utf16_str = (u16 *)alloc(allocator, (utf16_length + 1) * sizeof(u16)); int result = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)utf8.data, (int)utf8.count, utf16_str, utf16_length); if (result == 0) { - dealloc(utf16_str); + dealloc(allocator, utf16_str); return NULL; } @@ -507,19 +506,16 @@ u16 *win32_fixed_utf8_to_null_terminated_wide(string utf8) { return utf16_str; } u16 *temp_win32_fixed_utf8_to_null_terminated_wide(string utf8) { - push_temp_allocator(); - u16 *result = win32_fixed_utf8_to_null_terminated_wide(utf8); - pop_allocator(); - return result; + return win32_fixed_utf8_to_null_terminated_wide(utf8, temp); } -string win32_null_terminated_wide_to_fixed_utf8(const u16 *utf16) { +string win32_null_terminated_wide_to_fixed_utf8(const u16 *utf16, Allocator allocator) { u64 utf8_length = WideCharToMultiByte(CP_UTF8, 0, (LPCWCH)utf16, -1, 0, 0, 0, 0); - u8 *utf8_str = (u8 *)alloc(utf8_length * sizeof(u8)); + u8 *utf8_str = (u8 *)alloc(allocator, utf8_length * sizeof(u8)); int result = WideCharToMultiByte(CP_UTF8, 0, (LPCWCH)utf16, -1, (LPSTR)utf8_str, (int)utf8_length, 0, 0); if (result == 0) { - dealloc(utf8_str); + dealloc(allocator, utf8_str); return (string){0, 0}; } @@ -531,10 +527,7 @@ string win32_null_terminated_wide_to_fixed_utf8(const u16 *utf16) { } string temp_win32_null_terminated_wide_to_fixed_utf8(const u16 *utf16) { - push_temp_allocator(); - string result = win32_null_terminated_wide_to_fixed_utf8(utf16); - pop_allocator(); - return result; + return win32_null_terminated_wide_to_fixed_utf8(utf16, temp); } @@ -600,19 +593,19 @@ bool os_write_entire_file(string path, string data) { return result; } -bool os_read_entire_file_handle(File f, string *result) { +bool os_read_entire_file_handle(File f, string *result, Allocator allocator) { LARGE_INTEGER file_size; if (!GetFileSizeEx(f, &file_size)) { return false; } u64 actual_read = 0; - result->data = (u8*)alloc(file_size.QuadPart); + result->data = (u8*)alloc(allocator, file_size.QuadPart); result->count = file_size.QuadPart; bool ok = os_file_read(f, result->data, file_size.QuadPart, &actual_read); if (!ok) { - dealloc(result->data); + dealloc(allocator, result->data); result->data = 0; return false; } @@ -620,12 +613,12 @@ bool os_read_entire_file_handle(File f, string *result) { return actual_read == file_size.QuadPart; } -bool os_read_entire_file(string path, string *result) { +bool os_read_entire_file(string path, string *result, Allocator allocator) { File file = os_file_open(path, O_READ); if (file == OS_INVALID_FILE) { return false; } - bool res = os_read_entire_file_handle(file, result); + bool res = os_read_entire_file_handle(file, result, allocator); os_file_close(file); return res; } diff --git a/oogabooga/os_interface.c b/oogabooga/os_interface.c index 8551506..79be3aa 100644 --- a/oogabooga/os_interface.c +++ b/oogabooga/os_interface.c @@ -127,7 +127,7 @@ typedef struct Thread { /// // Thread primitive -Thread* os_make_thread(Thread_Proc proc); +Thread* os_make_thread(Thread_Proc proc, Allocator allocator); void os_start_thread(Thread* t); void os_join_thread(Thread* t); @@ -145,7 +145,7 @@ void os_unlock_mutex(Mutex_Handle m); typedef struct Spinlock { bool locked; } Spinlock; -Spinlock *os_make_spinlock(); +Spinlock *os_make_spinlock(Allocator allocator); void os_spinlock_lock(Spinlock* l); void os_spinlock_unlock(Spinlock* l); @@ -210,8 +210,8 @@ bool os_file_read(File f, void* buffer, u64 bytes_to_read, u64 *actual_read_byte bool os_write_entire_file_handle(File f, string data); bool os_write_entire_file(string path, string data); -bool os_read_entire_file_handle(File f, string *result); -bool os_read_entire_file(string path, string *result); +bool os_read_entire_file_handle(File f, string *result, Allocator allocator); +bool os_read_entire_file(string path, string *result, Allocator allocator); bool os_is_file(string path); bool os_is_directory(string path); diff --git a/oogabooga/string.c b/oogabooga/string.c index 7e0f0ec..9a24b00 100644 --- a/oogabooga/string.c +++ b/oogabooga/string.c @@ -1,41 +1,6 @@ /* -Usage: - // We need to use macro const_string to convert literal to string - string fmt = const_string("Pointer address: 0x%x"); - print(fmt, cast(u64)&a); // Print to stdout - - // Format a string and allocate with context.allocator - string a = sprint("Hello, %cs!\n", "balls"); // %cs for char* - - string balls = const_string("balls"); - // tprint for temporary allocation - string b = tprint("Hello, %s!\n", balls); // %s for string - - // Allocate a new string of length 12 (with context allocator) - string c = alloc_string(12); - dealloc_string(c); - - // We can use raw char* for format with printf/sprintf/tprintf - printf("Hello, %!\n", balls); - - // concatenation - string concatenated = string_concat(a, b); - - // Use temporary memory to make a null-terminated copy of fixed-length string - char* cstring = temp_convert_to_null_terminated_string(balls); - - // To convert a cstring to string (using same memory) - string s; - s.data = (u8*)cstring; - s.count = strlen(cstring); - - // String matching - bool match = strings_match(a, b); - - // View into "Hello, balls!\n" from index 7 with a count of 5; "balls" - string balls2 = string_view(a, 7, 5); */ @@ -48,8 +13,6 @@ typedef struct string { u8 *data; } string; -void push_temp_allocator(); - // Not sure what to call this lol #define fxstr fixed_string #define fixed_string const_string @@ -65,43 +28,37 @@ inline u64 length_of_null_terminated_string(const char* cstring) { return len; } -string alloc_string(u64 count) { +string alloc_string(Allocator allocator, u64 count) { string s; s.count = count; - s.data = cast(u8*)alloc(count); + s.data = cast(u8*)alloc(allocator, count); return s; } -void dealloc_string(string s) { - dealloc(s.data); +void dealloc_string(Allocator allocator, string s) { + dealloc(allocator, s.data); } string talloc_string(u64 count) { - push_temp_allocator(); - string s = alloc_string(count); - pop_allocator(); + string s = alloc_string(temp, count); return s; } -// context.allocator ! -string string_concat(const string left, const string right) { +string string_concat(const string left, const string right, Allocator allocator) { string result; result.count = left.count + right.count; - result.data = cast(u8*)alloc(result.count); + result.data = cast(u8*)alloc(allocator, result.count); memcpy(result.data, left.data, left.count); memcpy(result.data+left.count, right.data, right.count); return result; } -// context.allocator ! -char *convert_to_null_terminated_string(const string s) { - char *cstring = cast(char*)alloc(s.count+1); +char *convert_to_null_terminated_string(const string s, Allocator allocator) { + char *cstring = cast(char*)alloc(allocator, s.count+1); memcpy(cstring, s.data, s.count); cstring[s.count] = 0; return cstring; } char *temp_convert_to_null_terminated_string(const string s) { - push_temp_allocator(); - char *c = convert_to_null_terminated_string(s); - pop_allocator(); + char *c = convert_to_null_terminated_string(s, temp); return c; } bool strings_match(string a, string b) { diff --git a/oogabooga/string_format.c b/oogabooga/string_format.c index 3d8fd9f..cbd917e 100644 --- a/oogabooga/string_format.c +++ b/oogabooga/string_format.c @@ -102,24 +102,24 @@ string sprint_va_list_to_buffer(const string fmt, va_list args, void* buffer, u6 char* fmt_cstring = temp_convert_to_null_terminated_string(fmt); return sprint_null_terminated_string_va_list_to_buffer(fmt_cstring, args, buffer, count); } -// context.allocator -string sprint_va_list(const string fmt, va_list args) { + +string sprint_va_list(Allocator allocator, const string fmt, va_list args) { char* fmt_cstring = temp_convert_to_null_terminated_string(fmt); u64 count = format_string_to_buffer(NULL, 0, fmt_cstring, args) + 1; char* buffer = NULL; - buffer = (char*)alloc(count); + buffer = (char*)alloc(allocator, count); return sprint_null_terminated_string_va_list_to_buffer(fmt_cstring, args, buffer, count); } -// context.allocator -string sprints(const string fmt, ...) { + +string sprints(Allocator allocator, const string fmt, ...) { va_list args = 0; va_start(args, fmt); - string s = sprint_va_list(fmt, args); + string s = sprint_va_list(allocator, fmt, args); va_end(args); return s; } @@ -128,22 +128,20 @@ string sprints(const string fmt, ...) { string tprints(const string fmt, ...) { va_list args = 0; va_start(args, fmt); - push_temp_allocator(); - string s = sprint_va_list(fmt, args); - pop_allocator(); + string s = sprint_va_list(temp, fmt, args); va_end(args); return s; } -// context.allocator -string sprintf(const char *fmt, ...) { + +string sprintf(Allocator allocator, const char *fmt, ...) { string sfmt; sfmt.data = cast(u8*)fmt; sfmt.count = strlen(fmt); va_list args; va_start(args, fmt); - string s = sprint_va_list(sfmt, args); + string s = sprint_va_list(allocator, sfmt, args); va_end(args); return s; @@ -156,22 +154,12 @@ string tprintf(const char *fmt, ...) { va_list args; va_start(args, fmt); - push_temp_allocator(); - string s = sprint_va_list(sfmt, args); - pop_allocator(); + string s = sprint_va_list(temp, sfmt, args); va_end(args); return s; } - -// context.allocator (alloc & dealloc) -void print_va_list(const string fmt, va_list args) { - string s = sprint_va_list(fmt, args); - os_write_string_to_stdout(s); - dealloc(s.data); -} - // print for 'string' and printf for 'char*' #define PRINT_BUFFER_SIZE 4096 @@ -203,14 +191,14 @@ void print_va_list_buffered(const string fmt, va_list args) { } -// context.allocator (alloc & dealloc) + void prints(const string fmt, ...) { va_list args; va_start(args, fmt); print_va_list_buffered(fmt, args); va_end(args); } -// context.allocator (alloc & dealloc) + void printf(const char* fmt, ...) { va_list args; va_start(args, fmt); diff --git a/oogabooga/tests.c b/oogabooga/tests.c index ae1f7ab..9478c27 100644 --- a/oogabooga/tests.c +++ b/oogabooga/tests.c @@ -30,10 +30,13 @@ void log_heap() { } void test_allocator(bool do_log_heap) { + + Allocator heap = get_heap_allocator(); + // Basic allocation and free - int* a = (int*)alloc(sizeof(int)); - int* b = (int*)alloc(sizeof(int)); - int* c = (int*)alloc(sizeof(int)); + int* a = (int*)alloc(heap, sizeof(int)); + int* b = (int*)alloc(heap, sizeof(int)); + int* c = (int*)alloc(heap, sizeof(int)); *a = 69; *b = 420; @@ -51,41 +54,41 @@ void test_allocator(bool do_log_heap) { assert(*c == 1337, "Test failed: Memory corrupted"); // Allocate and free large block - void* large_block = alloc(1024 * 1024 * 100); - dealloc(large_block); + void* large_block = alloc(heap, 1024 * 1024 * 100); + dealloc(heap, large_block); // Allocate multiple small blocks void* blocks[100]; for (int i = 0; i < 100; ++i) { - blocks[i] = alloc(128); + blocks[i] = alloc(heap, 128); assert(blocks[i] != NULL, "Failed to allocate small block"); } for (int i = 0; i < 100; ++i) { - dealloc(blocks[i]); + dealloc(heap, blocks[i]); } // Stress test with various sizes for (int i = 1; i <= 1000; ++i) { - void* p = alloc(i * 64); + void* p = alloc(heap, i * 64); assert(p != NULL, "Failed to allocate varying size block"); - dealloc(p); + dealloc(heap, p); } // Free in reverse order for (int i = 0; i < 100; ++i) { - blocks[i] = alloc(128); + blocks[i] = alloc(heap, 128); assert(blocks[i] != NULL, "Failed to allocate small block"); } for (int i = 99; i >= 0; --i) { - dealloc(blocks[i]); + dealloc(heap, blocks[i]); } // Test memory integrity with various allocation patterns int* nums[10]; for (int i = 0; i < 10; ++i) { - nums[i] = (int*)alloc(sizeof(int) * 10); + nums[i] = (int*)alloc(heap, sizeof(int) * 10); for (int j = 0; j < 10; ++j) { nums[i][j] = i * 10 + j; } @@ -95,19 +98,17 @@ void test_allocator(bool do_log_heap) { for (int j = 0; j < 10; ++j) { assert(nums[i][j] == i * 10 + j, "Memory corruption detected"); } - dealloc(nums[i]); + dealloc(heap, nums[i]); } reset_temporary_storage(); - - push_allocator(temp); - int* foo = (int*)alloc(72); + int* foo = (int*)alloc(temp, 72); *foo = 1337; - void* bar = alloc(69); + void* bar = alloc(temp, 69); (void)bar; - void* baz = alloc(420); + void* baz = alloc(temp, 420); (void)baz; assert(*foo == 1337, "Temp memory corruptada"); @@ -116,63 +117,61 @@ void test_allocator(bool do_log_heap) { reset_temporary_storage(); - foo = (int*)alloc(72); + foo = (int*)alloc(temp, 72); assert(old_foo == foo, "Temp allocator goof"); - pop_allocator(); - // Repeated Allocation and Free for (int i = 0; i < 10000; ++i) { - void* temp = alloc(128); + void* temp = alloc(heap, 128); assert(temp != NULL && "Repeated allocation failed"); - dealloc(temp); + dealloc(heap, temp); } // Mixed Size Allocations void* mixed_blocks[200]; for (int i = 0; i < 200; ++i) { if (i % 2 == 0) { - mixed_blocks[i] = alloc(128); + mixed_blocks[i] = alloc(heap, 128); } else { - mixed_blocks[i] = alloc(1024 * 1024); // 1MB blocks + mixed_blocks[i] = alloc(heap, 1024 * 1024); // 1MB blocks } assert(mixed_blocks[i] != NULL && "Mixed size allocation failed"); } for (int i = 0; i < 200; ++i) { if (i % 2 == 0) { - dealloc(mixed_blocks[i]); + dealloc(heap, mixed_blocks[i]); } } for (int i = 0; i < 200; ++i) { if (i % 2 != 0) { - dealloc(mixed_blocks[i]); + dealloc(heap, mixed_blocks[i]); } } // Fragmentation Stress Test for (int i = 0; i < 50; ++i) { - blocks[i] = alloc(256); + blocks[i] = alloc(heap, 256); assert(blocks[i] != NULL && "Failed to allocate small block for fragmentation test"); } for (int i = 0; i < 50; i += 2) { - dealloc(blocks[i]); + dealloc(heap, blocks[i]); } for (int i = 50; i < 100; ++i) { - blocks[i] = alloc(128); + blocks[i] = alloc(heap, 128); assert(blocks[i] != NULL && "Failed to allocate small block in fragmented heap"); } for (int i = 50; i < 100; ++i) { - dealloc(blocks[i]); + dealloc(heap, blocks[i]); } for (int i = 1; i < 50; i += 2) { - dealloc(blocks[i]); + dealloc(heap, blocks[i]); } if (do_log_heap) log_heap(); @@ -192,7 +191,8 @@ void test_thread_proc1(Thread* t) { } void test_threads() { - Thread* t = os_make_thread(test_thread_proc1); + + Thread* t = os_make_thread(test_thread_proc1, get_heap_allocator()); os_start_thread(t); os_sleep(20); printf("This should be printed in middle of thread execution\n"); @@ -205,31 +205,34 @@ void test_threads() { } void test_allocator_threaded(Thread *t) { + + Allocator heap = get_heap_allocator(); + for (int i = 0; i < 1000; ++i) { - void* temp = alloc(128); + void* temp = alloc(heap, 128); assert(temp != NULL && "Repeated allocation failed"); - dealloc(temp); + dealloc(heap, temp); } void* mixed_blocks[40]; for (int i = 0; i < 40; ++i) { if (i % 2 == 0) { - mixed_blocks[i] = alloc(128); + mixed_blocks[i] = alloc(heap, 128); } else { - mixed_blocks[i] = alloc(1024 * 1024); // 1MB blocks + mixed_blocks[i] = alloc(heap, 1024 * 1024); // 1MB blocks } assert(mixed_blocks[i] != NULL && "Mixed size allocation failed"); } for (int i = 0; i < 40; ++i) { if (i % 2 == 0) { - dealloc(mixed_blocks[i]); + dealloc(heap, mixed_blocks[i]); } } for (int i = 0; i < 40; ++i) { if (i % 2 != 0) { - dealloc(mixed_blocks[i]); + dealloc(heap, mixed_blocks[i]); } } } @@ -239,43 +242,43 @@ void test_strings() { assert(length_of_null_terminated_string("Test") == 4, "Failed: length_of_null_terminated_string"); assert(length_of_null_terminated_string("") == 0, "Failed: length_of_null_terminated_string"); + Allocator heap = get_heap_allocator(); + // Test alloc_string and dealloc_string - string alloc_str = alloc_string(10); + string alloc_str = alloc_string(heap, 10); assert(alloc_str.data != NULL, "Failed: alloc_string"); assert(alloc_str.count == 10, "Failed: alloc_string"); - dealloc_string(alloc_str); + dealloc_string(heap, alloc_str); // Test string_concat string str1 = fixed_string("Hello, "); string str2 = fixed_string("World!"); - string concat_str = string_concat(str1, str2); + string concat_str = string_concat(str1, str2, heap); assert(concat_str.count == str1.count + str2.count, "Failed: string_concat"); assert(memcmp(concat_str.data, "Hello, World!", concat_str.count) == 0, "Failed: string_concat"); - dealloc_string(concat_str); + dealloc_string(heap, concat_str); // Test convert_to_null_terminated_string - char* cstr = convert_to_null_terminated_string(str1); + char* cstr = convert_to_null_terminated_string(str1, heap); assert(strcmp(cstr, "Hello, ") == 0, "Failed: convert_to_null_terminated_string"); - dealloc(cstr); + dealloc(heap, cstr); // Test temp_convert_to_null_terminated_string cstr = temp_convert_to_null_terminated_string(str2); assert(strcmp(cstr, "World!") == 0, "Failed: temp_convert_to_null_terminated_string"); - // No need to dealloc, it's temporary storage // Test sprint string format_str = fixed_string("Number: %d"); - string formatted_str = sprint(format_str, 42); - char* formatted_cstr = convert_to_null_terminated_string(formatted_str); + string formatted_str = sprint(heap, format_str, 42); + char* formatted_cstr = convert_to_null_terminated_string(formatted_str, heap); assert(strcmp(formatted_cstr, "Number: 42") == 0, "Failed: sprint"); - dealloc(formatted_str.data); - dealloc(formatted_cstr); + dealloc(heap, formatted_str.data); + dealloc(heap, formatted_cstr); // Test tprint string temp_formatted_str = tprint(format_str, 100); formatted_cstr = temp_convert_to_null_terminated_string(temp_formatted_str); assert(strcmp(formatted_cstr, "Number: 100") == 0, "Failed: tprint"); - // No need to dealloc, it's temporary storage // Test print and printf (visual inspection) printf("Expected output: Hello, World!\n"); @@ -308,24 +311,24 @@ void test_strings() { // Test handling of empty strings string empty_str = fixed_string(""); - string concat_empty_str = string_concat(empty_str, empty_str); + string concat_empty_str = string_concat(empty_str, empty_str, heap); assert(concat_empty_str.count == 0, "Failed: string_concat with empty strings"); - dealloc_string(concat_empty_str); + dealloc_string(heap, concat_empty_str); // Test very large strings (performance test) - string large_str1 = alloc_string(1024 * 1024); - string large_str2 = alloc_string(1024 * 1024); - string large_concat_str = string_concat(large_str1, large_str2); + string large_str1 = alloc_string(heap, 1024 * 1024); + string large_str2 = alloc_string(heap, 1024 * 1024); + string large_concat_str = string_concat(large_str1, large_str2, heap); assert(large_concat_str.count == 2 * 1024 * 1024, "Failed: large string_concat"); - dealloc_string(large_str1); - dealloc_string(large_str2); - dealloc_string(large_concat_str); + dealloc_string(heap, large_str1); + dealloc_string(heap, large_str2); + dealloc_string(heap, large_concat_str); // Test string with special characters string special_char_str = fixed_string("Special chars: \n\t\r"); - cstr = convert_to_null_terminated_string(special_char_str); + cstr = convert_to_null_terminated_string(special_char_str, heap); assert(strcmp(cstr, "Special chars: \n\t\r") == 0, "Failed: special character string"); - dealloc(cstr); + dealloc(heap, cstr); string a = tprintf("Hello, %cs!\n", "balls"); string balls1 = string_view(a, 7, 5); @@ -340,17 +343,15 @@ void test_file_io() { #if TARGET_OS == WINDOWS // Test win32_fixed_utf8_to_null_terminated_wide string utf8_str = fixed_string("Test"); - u16 *wide_str = win32_fixed_utf8_to_null_terminated_wide(utf8_str); + u16 *wide_str = win32_fixed_utf8_to_null_terminated_wide(utf8_str, get_heap_allocator()); assert(wide_str != NULL, "Failed: win32_fixed_utf8_to_null_terminated_wide"); assert(wide_str[4] == 0, "Failed: win32_fixed_utf8_to_null_terminated_wide"); - dealloc(wide_str); + dealloc(get_heap_allocator(), wide_str); // Test temp_win32_fixed_utf8_to_null_terminated_wide - push_temp_allocator(); wide_str = temp_win32_fixed_utf8_to_null_terminated_wide(utf8_str); assert(wide_str != NULL, "Failed: temp_win32_fixed_utf8_to_null_terminated_wide"); assert(wide_str[4] == 0, "Failed: temp_win32_fixed_utf8_to_null_terminated_wide"); - pop_allocator(); #endif File file = OS_INVALID_FILE; @@ -391,12 +392,14 @@ void test_file_io() { bool write_entire_result = os_write_entire_file(fixed_string("entire_test.txt"), write_data); assert(write_entire_result, "Failed: os_write_entire_file"); + Allocator heap = get_heap_allocator(); + string read_data; - bool read_entire_result = os_read_entire_file(fixed_string("entire_test.txt"), &read_data); + bool read_entire_result = os_read_entire_file(fixed_string("entire_test.txt"), &read_data, heap); assert(read_entire_result, "Failed: os_read_entire_file"); assert(strings_match(read_data, write_data), "Failed: os_read_entire_file write/read mismatch"); assert(memcmp(read_data.data, write_data.data, write_data.count) == 0, "Failed: os_read_entire_file (content mismatch)"); - dealloc(read_data.data); + dealloc(heap, read_data.data); // Test fprint File balls = os_file_open(fixed_string("balls.txt"), O_WRITE | O_CREATE); @@ -404,7 +407,7 @@ void test_file_io() { fprint(balls, "Hello, %cs!", "Balls"); os_file_close(balls); string hello_balls; - read_entire_result = os_read_entire_file(fixed_string("balls.txt"), &hello_balls); + read_entire_result = os_read_entire_file(fixed_string("balls.txt"), &hello_balls, heap); assert(read_entire_result, "Failed: could not read balls.txt"); assert(strings_match(hello_balls, fixed_string("Hello, Balls!")), "Failed: balls read/write mismatch. Expected 'Hello, Balls!', got '%s'", hello_balls); @@ -419,7 +422,7 @@ void test_file_io() { assert(ok, "write integers fail"); string integers_read; - ok = os_read_entire_file(fxstr("integers"), &integers_read); + ok = os_read_entire_file(fxstr("integers"), &integers_read, heap); assert(ok, "read integers fail"); u64 *new_integers = (u64*)integers_data.data; assert(integers_read.count == integers_data.count, "Failed: big file read/write mismatch. Read was %d and written was %d", integers_read.count, integers_data.count); @@ -435,6 +438,8 @@ void test_file_io() { assert(delete_ok, "Failed: could not delete entire_test.txt"); delete_ok = os_file_delete(fixed_string("balls.txt")); assert(delete_ok, "Failed: could not delete balls.txt"); + delete_ok = os_file_delete(fixed_string("integers.txt")); + assert(delete_ok, "Failed: could not delete integers.txt"); } void oogabooga_run_tests() { @@ -453,7 +458,7 @@ void oogabooga_run_tests() { printf("Thread bombing allocator... "); Thread* threads[100]; for (int i = 0; i < 100; i++) { - threads[i] = os_make_thread(test_allocator_threaded); + threads[i] = os_make_thread(test_allocator_threaded, get_heap_allocator()); os_start_thread(threads[i]); } for (int i = 0; i < 100; i++) {