Explicit allocators
This commit is contained in:
parent
bf32265517
commit
ea37ceb3bd
12 changed files with 172 additions and 221 deletions
9
entry.c
9
entry.c
|
@ -18,9 +18,9 @@ int start(int argc, char **argv) {
|
||||||
|
|
||||||
window.clear_color = hex_to_rgba(0x2a2d3aff);
|
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");
|
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");
|
assert(hammer_image, "Failed loading hammer.png");
|
||||||
|
|
||||||
seed_for_random = os_get_current_cycle_count();
|
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();
|
float64 last_time = os_get_current_time_in_seconds();
|
||||||
while (!window.should_close) {
|
while (!window.should_close) {
|
||||||
reset_temporary_storage();
|
reset_temporary_storage();
|
||||||
context.allocator = temp;
|
|
||||||
|
|
||||||
float64 now = os_get_current_time_in_seconds();
|
float64 now = os_get_current_time_in_seconds();
|
||||||
float64 delta = now - last_time;
|
float64 delta = now - last_time;
|
||||||
|
@ -58,11 +57,9 @@ int start(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_key_just_released('Q')) {
|
if (is_key_just_released('Q')) {
|
||||||
push_allocator(get_heap_allocator());
|
|
||||||
delete_image(bush_image);
|
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");
|
assert(bush_image, "Failed loading berry_bush.png");
|
||||||
pop_allocator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const float32 cam_move_speed = 4.0;
|
const float32 cam_move_speed = 4.0;
|
||||||
|
|
|
@ -101,11 +101,12 @@ void printf(const char* fmt, ...);
|
||||||
|
|
||||||
|
|
||||||
#define FIRST_ARG(arg1, ...) arg1
|
#define FIRST_ARG(arg1, ...) arg1
|
||||||
|
#define SECOND_ARG(arg1, arg2, ...) arg2
|
||||||
#define print(...) _Generic((FIRST_ARG(__VA_ARGS__)), \
|
#define print(...) _Generic((FIRST_ARG(__VA_ARGS__)), \
|
||||||
string: prints, \
|
string: prints, \
|
||||||
default: printf \
|
default: printf \
|
||||||
)(__VA_ARGS__)
|
)(__VA_ARGS__)
|
||||||
#define sprint(...) _Generic((FIRST_ARG(__VA_ARGS__)), \
|
#define sprint(...) _Generic((SECOND_ARG(__VA_ARGS__)), \
|
||||||
string: sprints, \
|
string: sprints, \
|
||||||
default: sprintf \
|
default: sprintf \
|
||||||
)(__VA_ARGS__)
|
)(__VA_ARGS__)
|
||||||
|
@ -125,7 +126,7 @@ typedef enum Allocator_Message {
|
||||||
ALLOCATOR_DEALLOCATE,
|
ALLOCATOR_DEALLOCATE,
|
||||||
ALLOCATOR_REALLOCATE,
|
ALLOCATOR_REALLOCATE,
|
||||||
} Allocator_Message;
|
} Allocator_Message;
|
||||||
typedef void*(*Allocator_Proc)(u64, void*, Allocator_Message);
|
typedef void*(*Allocator_Proc)(u64, void*, Allocator_Message, void*);
|
||||||
|
|
||||||
typedef enum Log_Level {
|
typedef enum Log_Level {
|
||||||
LOG_ERROR,
|
LOG_ERROR,
|
||||||
|
@ -142,7 +143,6 @@ typedef struct Allocator {
|
||||||
} Allocator;
|
} Allocator;
|
||||||
|
|
||||||
typedef struct Context {
|
typedef struct Context {
|
||||||
Allocator allocator;
|
|
||||||
void *logger; // void(*Logger_Proc)(Log_Level level, string fmt, ...)
|
void *logger; // void(*Logger_Proc)(Log_Level level, string fmt, ...)
|
||||||
|
|
||||||
CONTEXT_EXTRA extra;
|
CONTEXT_EXTRA extra;
|
||||||
|
@ -154,8 +154,14 @@ thread_local Context context;
|
||||||
thread_local Context context_stack[CONTEXT_STACK_MAX];
|
thread_local Context context_stack[CONTEXT_STACK_MAX];
|
||||||
thread_local u64 num_contexts = 0;
|
thread_local u64 num_contexts = 0;
|
||||||
|
|
||||||
void* alloc(u64 size) { return context.allocator.proc(size, NULL, ALLOCATOR_ALLOCATE); }
|
forward_global thread_local Allocator temp;
|
||||||
void dealloc(void *p) { context.allocator.proc(0, p, ALLOCATOR_DEALLOCATE); }
|
|
||||||
|
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) {
|
void push_context(Context c) {
|
||||||
assert(num_contexts < CONTEXT_STACK_MAX, "Context stack overflow");
|
assert(num_contexts < CONTEXT_STACK_MAX, "Context stack overflow");
|
||||||
|
@ -170,11 +176,4 @@ void pop_context() {
|
||||||
context = context_stack[num_contexts];
|
context = context_stack[num_contexts];
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_allocator(Allocator a) {
|
|
||||||
Context c = context;
|
|
||||||
c.allocator = a;
|
|
||||||
push_context(c);
|
|
||||||
}
|
|
||||||
void pop_allocator() { pop_context(); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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_WHITE ((Vector4){1.0, 1.0, 1.0, 1.0})
|
||||||
#define COLOR_BLACK ((Vector4){0.0, 0.0, 0.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, Allocator allocator) {
|
||||||
Gfx_Image *load_image_from_disk(string path) {
|
|
||||||
string png;
|
string png;
|
||||||
bool ok = os_read_entire_file(path, &png);
|
bool ok = os_read_entire_file(path, &png, allocator);
|
||||||
if (!ok) return 0;
|
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
|
// This is fucking terrible I gotta write my own decoder
|
||||||
|
|
||||||
|
lodepng_allocator = allocator;
|
||||||
|
|
||||||
LodePNGState state;
|
LodePNGState state;
|
||||||
lodepng_state_init(&state);
|
lodepng_state_init(&state);
|
||||||
u32 error = lodepng_inspect(&image->width, &image->height, &state, png.data, png.count);
|
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);
|
lodepng_state_cleanup(&state);
|
||||||
|
|
||||||
dealloc_string(png);
|
dealloc_string(allocator, png);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -222,7 +223,7 @@ Gfx_Image *load_image_from_disk(string path) {
|
||||||
|
|
||||||
// We need to flip the image
|
// We need to flip the image
|
||||||
u32 row_bytes = image->width * 4; // #Magicvalue assuming 4 bytes
|
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++) {
|
for (u32 i = 0; i < image->height / 2; i++) {
|
||||||
u8* top_row = image->data + i * row_bytes;
|
u8* top_row = image->data + i * row_bytes;
|
||||||
u8* bottom_row = image->data + (image->height - i - 1) * 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(top_row, bottom_row, row_bytes);
|
||||||
memcpy(bottom_row, temp_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->gfx_handle = GFX_INVALID_HANDLE; // This is handled in gfx
|
||||||
|
|
||||||
|
image->allocator = allocator;
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
void delete_image(Gfx_Image *image) {
|
void delete_image(Gfx_Image *image) {
|
||||||
dealloc(image->data);
|
dealloc(image->allocator, image->data);
|
||||||
image->width = 0;
|
image->width = 0;
|
||||||
image->height = 0;
|
image->height = 0;
|
||||||
draw_frame.garbage_stack[draw_frame.garbage_stack_count] = image->gfx_handle;
|
draw_frame.garbage_stack[draw_frame.garbage_stack_count] = image->gfx_handle;
|
||||||
draw_frame.garbage_stack_count += 1;
|
draw_frame.garbage_stack_count += 1;
|
||||||
dealloc(image);
|
dealloc(image->allocator, image);
|
||||||
}
|
}
|
|
@ -313,7 +313,7 @@ void gfx_init() {
|
||||||
#if OOGABOOGA_DEV
|
#if OOGABOOGA_DEV
|
||||||
|
|
||||||
string source;
|
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");
|
assert(source_ok, "Could not open d3d11_image_shader source");
|
||||||
|
|
||||||
// Compile vertex shader
|
// Compile vertex shader
|
||||||
|
|
|
@ -33,5 +33,6 @@ typedef struct Gfx_Image {
|
||||||
u32 width, height;
|
u32 width, height;
|
||||||
u8 *data;
|
u8 *data;
|
||||||
Gfx_Handle gfx_handle;
|
Gfx_Handle gfx_handle;
|
||||||
|
Allocator allocator;
|
||||||
} Gfx_Image;
|
} Gfx_Image;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ u64 program_memory_size = 0;
|
||||||
u8 init_memory_arena[INIT_MEMORY_SIZE];
|
u8 init_memory_arena[INIT_MEMORY_SIZE];
|
||||||
u8 *init_memory_head = init_memory_arena;
|
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) {
|
switch (message) {
|
||||||
case ALLOCATOR_ALLOCATE: {
|
case ALLOCATOR_ALLOCATE: {
|
||||||
p = init_memory_head;
|
p = init_memory_head;
|
||||||
|
@ -35,6 +35,12 @@ void* initialization_allocator_proc(u64 size, void *p, Allocator_Message message
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Allocator get_initialization_allocator() {
|
||||||
|
Allocator a;
|
||||||
|
a.proc = initialization_allocator_proc;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
// Basic general heap allocator, free list
|
// Basic general heap allocator, free list
|
||||||
|
@ -206,7 +212,7 @@ void heap_init() {
|
||||||
if (heap_initted) return;
|
if (heap_initted) return;
|
||||||
heap_initted = true;
|
heap_initted = true;
|
||||||
heap_head = make_heap_block(0, DEFAULT_HEAP_BLOCK_SIZE);
|
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) {
|
void *heap_alloc(u64 size) {
|
||||||
|
@ -376,7 +382,7 @@ void heap_dealloc(void *p) {
|
||||||
os_spinlock_unlock(heap_lock);
|
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) {
|
switch (message) {
|
||||||
case ALLOCATOR_ALLOCATE: {
|
case ALLOCATOR_ALLOCATE: {
|
||||||
return heap_alloc(size);
|
return heap_alloc(size);
|
||||||
|
@ -421,7 +427,7 @@ Allocator get_heap_allocator() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void* talloc(u64);
|
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 void * temporary_storage = 0;
|
||||||
thread_local bool temporary_storage_initted = false;
|
thread_local bool temporary_storage_initted = false;
|
||||||
|
@ -430,7 +436,7 @@ thread_local bool has_warned_temporary_storage_overflow = false;
|
||||||
thread_local Allocator temp;
|
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) {
|
switch (message) {
|
||||||
case ALLOCATOR_ALLOCATE: {
|
case ALLOCATOR_ALLOCATE: {
|
||||||
return talloc(size);
|
return talloc(size);
|
||||||
|
@ -457,6 +463,8 @@ void temporary_storage_init() {
|
||||||
temp.data = 0;
|
temp.data = 0;
|
||||||
|
|
||||||
temporary_storage_initted = true;
|
temporary_storage_initted = true;
|
||||||
|
|
||||||
|
temp.proc = temp_allocator_proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* talloc(u64 size) {
|
void* talloc(u64 size) {
|
||||||
|
@ -487,8 +495,3 @@ void reset_temporary_storage() {
|
||||||
has_warned_temporary_storage_overflow = true;
|
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);
|
|
||||||
}
|
|
|
@ -32,16 +32,22 @@
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
Allocator get_heap_allocator();
|
||||||
|
|
||||||
// Custom allocators for lodepng
|
// Custom allocators for lodepng
|
||||||
|
Allocator lodepng_allocator = {0};
|
||||||
void* lodepng_malloc(size_t size) {
|
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) {
|
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) {
|
void lodepng_free(void* ptr) {
|
||||||
if (!ptr) return;
|
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_ALLOCATORS
|
||||||
//#define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
|
//#define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
|
||||||
|
@ -161,10 +167,11 @@ void lodepng_free(void* ptr) {
|
||||||
|
|
||||||
void oogabooga_init(u64 program_memory_size) {
|
void oogabooga_init(u64 program_memory_size) {
|
||||||
context.logger = default_logger;
|
context.logger = default_logger;
|
||||||
|
temp = get_initialization_allocator();
|
||||||
os_init(program_memory_size);
|
os_init(program_memory_size);
|
||||||
gfx_init();
|
|
||||||
heap_init();
|
heap_init();
|
||||||
temporary_storage_init();
|
temporary_storage_init();
|
||||||
|
gfx_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef INITIAL_PROGRAM_MEMORY_SIZE
|
#ifndef INITIAL_PROGRAM_MEMORY_SIZE
|
||||||
|
@ -178,7 +185,6 @@ void oogabooga_init(u64 program_memory_size) {
|
||||||
int ENTRY_PROC(int argc, char **argv);
|
int ENTRY_PROC(int argc, char **argv);
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
context.allocator.proc = initialization_allocator_proc;
|
|
||||||
oogabooga_init(INITIAL_PROGRAM_MEMORY_SIZE);
|
oogabooga_init(INITIAL_PROGRAM_MEMORY_SIZE);
|
||||||
printf("Ooga booga program started\n");
|
printf("Ooga booga program started\n");
|
||||||
|
|
||||||
|
|
|
@ -162,7 +162,6 @@ void os_init(u64 program_memory_size) {
|
||||||
|
|
||||||
|
|
||||||
heap_init();
|
heap_init();
|
||||||
context.allocator = get_heap_allocator();
|
|
||||||
|
|
||||||
os.crt = os_load_dynamic_library(const_string("msvcrt.dll"));
|
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");
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread* os_make_thread(Thread_Proc proc) {
|
Thread* os_make_thread(Thread_Proc proc, Allocator allocator) {
|
||||||
Thread *t = (Thread*)alloc(sizeof(Thread));
|
Thread *t = (Thread*)alloc(allocator, sizeof(Thread));
|
||||||
t->id = 0; // This is set when we start it
|
t->id = 0; // This is set when we start it
|
||||||
t->proc = proc;
|
t->proc = proc;
|
||||||
t->initial_context = context;
|
t->initial_context = context;
|
||||||
|
@ -365,8 +364,9 @@ void os_unlock_mutex(Mutex_Handle m) {
|
||||||
///
|
///
|
||||||
// Spinlock "primitive"
|
// Spinlock "primitive"
|
||||||
|
|
||||||
Spinlock *os_make_spinlock() {
|
Spinlock *os_make_spinlock(Allocator allocator) {
|
||||||
Spinlock *l = cast(Spinlock*)alloc(sizeof(Spinlock));
|
// #Memory #Cleanup do we need to heap allocate this ?
|
||||||
|
Spinlock *l = cast(Spinlock*)alloc(allocator, sizeof(Spinlock));
|
||||||
l->locked = false;
|
l->locked = false;
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
@ -490,15 +490,14 @@ void os_write_string_to_stdout(string s) {
|
||||||
WriteFile(win32_stdout, s.data, s.count, 0, NULL);
|
WriteFile(win32_stdout, s.data, s.count, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// context.allocator
|
u16 *win32_fixed_utf8_to_null_terminated_wide(string utf8, Allocator allocator) {
|
||||||
u16 *win32_fixed_utf8_to_null_terminated_wide(string utf8) {
|
|
||||||
u64 utf16_length = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)utf8.data, (int)utf8.count, 0, 0);
|
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);
|
int result = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)utf8.data, (int)utf8.count, utf16_str, utf16_length);
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
dealloc(utf16_str);
|
dealloc(allocator, utf16_str);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,19 +506,16 @@ u16 *win32_fixed_utf8_to_null_terminated_wide(string utf8) {
|
||||||
return utf16_str;
|
return utf16_str;
|
||||||
}
|
}
|
||||||
u16 *temp_win32_fixed_utf8_to_null_terminated_wide(string utf8) {
|
u16 *temp_win32_fixed_utf8_to_null_terminated_wide(string utf8) {
|
||||||
push_temp_allocator();
|
return win32_fixed_utf8_to_null_terminated_wide(utf8, temp);
|
||||||
u16 *result = win32_fixed_utf8_to_null_terminated_wide(utf8);
|
|
||||||
pop_allocator();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
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);
|
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);
|
int result = WideCharToMultiByte(CP_UTF8, 0, (LPCWCH)utf16, -1, (LPSTR)utf8_str, (int)utf8_length, 0, 0);
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
dealloc(utf8_str);
|
dealloc(allocator, utf8_str);
|
||||||
return (string){0, 0};
|
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) {
|
string temp_win32_null_terminated_wide_to_fixed_utf8(const u16 *utf16) {
|
||||||
push_temp_allocator();
|
return win32_null_terminated_wide_to_fixed_utf8(utf16, temp);
|
||||||
string result = win32_null_terminated_wide_to_fixed_utf8(utf16);
|
|
||||||
pop_allocator();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -600,19 +593,19 @@ bool os_write_entire_file(string path, string data) {
|
||||||
return result;
|
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;
|
LARGE_INTEGER file_size;
|
||||||
if (!GetFileSizeEx(f, &file_size)) {
|
if (!GetFileSizeEx(f, &file_size)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 actual_read = 0;
|
u64 actual_read = 0;
|
||||||
result->data = (u8*)alloc(file_size.QuadPart);
|
result->data = (u8*)alloc(allocator, file_size.QuadPart);
|
||||||
result->count = file_size.QuadPart;
|
result->count = file_size.QuadPart;
|
||||||
|
|
||||||
bool ok = os_file_read(f, result->data, file_size.QuadPart, &actual_read);
|
bool ok = os_file_read(f, result->data, file_size.QuadPart, &actual_read);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
dealloc(result->data);
|
dealloc(allocator, result->data);
|
||||||
result->data = 0;
|
result->data = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -620,12 +613,12 @@ bool os_read_entire_file_handle(File f, string *result) {
|
||||||
return actual_read == file_size.QuadPart;
|
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);
|
File file = os_file_open(path, O_READ);
|
||||||
if (file == OS_INVALID_FILE) {
|
if (file == OS_INVALID_FILE) {
|
||||||
return false;
|
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);
|
os_file_close(file);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@ typedef struct Thread {
|
||||||
|
|
||||||
///
|
///
|
||||||
// Thread primitive
|
// 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_start_thread(Thread* t);
|
||||||
void os_join_thread(Thread* t);
|
void os_join_thread(Thread* t);
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ void os_unlock_mutex(Mutex_Handle m);
|
||||||
typedef struct Spinlock {
|
typedef struct Spinlock {
|
||||||
bool locked;
|
bool locked;
|
||||||
} Spinlock;
|
} Spinlock;
|
||||||
Spinlock *os_make_spinlock();
|
Spinlock *os_make_spinlock(Allocator allocator);
|
||||||
void os_spinlock_lock(Spinlock* l);
|
void os_spinlock_lock(Spinlock* l);
|
||||||
void os_spinlock_unlock(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_handle(File f, string data);
|
||||||
bool os_write_entire_file(string path, 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_handle(File f, string *result, Allocator allocator);
|
||||||
bool os_read_entire_file(string path, string *result);
|
bool os_read_entire_file(string path, string *result, Allocator allocator);
|
||||||
|
|
||||||
bool os_is_file(string path);
|
bool os_is_file(string path);
|
||||||
bool os_is_directory(string path);
|
bool os_is_directory(string path);
|
||||||
|
|
|
@ -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;
|
u8 *data;
|
||||||
} string;
|
} string;
|
||||||
|
|
||||||
void push_temp_allocator();
|
|
||||||
|
|
||||||
// Not sure what to call this lol
|
// Not sure what to call this lol
|
||||||
#define fxstr fixed_string
|
#define fxstr fixed_string
|
||||||
#define fixed_string const_string
|
#define fixed_string const_string
|
||||||
|
@ -65,43 +28,37 @@ inline u64 length_of_null_terminated_string(const char* cstring) {
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
string alloc_string(u64 count) {
|
string alloc_string(Allocator allocator, u64 count) {
|
||||||
string s;
|
string s;
|
||||||
s.count = count;
|
s.count = count;
|
||||||
s.data = cast(u8*)alloc(count);
|
s.data = cast(u8*)alloc(allocator, count);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
void dealloc_string(string s) {
|
void dealloc_string(Allocator allocator, string s) {
|
||||||
dealloc(s.data);
|
dealloc(allocator, s.data);
|
||||||
}
|
}
|
||||||
string talloc_string(u64 count) {
|
string talloc_string(u64 count) {
|
||||||
push_temp_allocator();
|
string s = alloc_string(temp, count);
|
||||||
string s = alloc_string(count);
|
|
||||||
pop_allocator();
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// context.allocator !
|
string string_concat(const string left, const string right, Allocator allocator) {
|
||||||
string string_concat(const string left, const string right) {
|
|
||||||
string result;
|
string result;
|
||||||
result.count = left.count + right.count;
|
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.data, left.count);
|
||||||
memcpy(result.data+left.count, right.data, right.count);
|
memcpy(result.data+left.count, right.data, right.count);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
// context.allocator !
|
char *convert_to_null_terminated_string(const string s, Allocator allocator) {
|
||||||
char *convert_to_null_terminated_string(const string s) {
|
char *cstring = cast(char*)alloc(allocator, s.count+1);
|
||||||
char *cstring = cast(char*)alloc(s.count+1);
|
|
||||||
memcpy(cstring, s.data, s.count);
|
memcpy(cstring, s.data, s.count);
|
||||||
cstring[s.count] = 0;
|
cstring[s.count] = 0;
|
||||||
return cstring;
|
return cstring;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *temp_convert_to_null_terminated_string(const string s) {
|
char *temp_convert_to_null_terminated_string(const string s) {
|
||||||
push_temp_allocator();
|
char *c = convert_to_null_terminated_string(s, temp);
|
||||||
char *c = convert_to_null_terminated_string(s);
|
|
||||||
pop_allocator();
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
bool strings_match(string a, string b) {
|
bool strings_match(string a, string b) {
|
||||||
|
|
|
@ -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);
|
char* fmt_cstring = temp_convert_to_null_terminated_string(fmt);
|
||||||
return sprint_null_terminated_string_va_list_to_buffer(fmt_cstring, args, buffer, count);
|
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);
|
char* fmt_cstring = temp_convert_to_null_terminated_string(fmt);
|
||||||
u64 count = format_string_to_buffer(NULL, 0, fmt_cstring, args) + 1;
|
u64 count = format_string_to_buffer(NULL, 0, fmt_cstring, args) + 1;
|
||||||
|
|
||||||
char* buffer = NULL;
|
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);
|
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_list args = 0;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
string s = sprint_va_list(fmt, args);
|
string s = sprint_va_list(allocator, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
@ -128,22 +128,20 @@ string sprints(const string fmt, ...) {
|
||||||
string tprints(const string fmt, ...) {
|
string tprints(const string fmt, ...) {
|
||||||
va_list args = 0;
|
va_list args = 0;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
push_temp_allocator();
|
string s = sprint_va_list(temp, fmt, args);
|
||||||
string s = sprint_va_list(fmt, args);
|
|
||||||
pop_allocator();
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// context.allocator
|
|
||||||
string sprintf(const char *fmt, ...) {
|
string sprintf(Allocator allocator, const char *fmt, ...) {
|
||||||
string sfmt;
|
string sfmt;
|
||||||
sfmt.data = cast(u8*)fmt;
|
sfmt.data = cast(u8*)fmt;
|
||||||
sfmt.count = strlen(fmt);
|
sfmt.count = strlen(fmt);
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
string s = sprint_va_list(sfmt, args);
|
string s = sprint_va_list(allocator, sfmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
@ -156,22 +154,12 @@ string tprintf(const char *fmt, ...) {
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
push_temp_allocator();
|
string s = sprint_va_list(temp, sfmt, args);
|
||||||
string s = sprint_va_list(sfmt, args);
|
|
||||||
pop_allocator();
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
return s;
|
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*'
|
// print for 'string' and printf for 'char*'
|
||||||
|
|
||||||
#define PRINT_BUFFER_SIZE 4096
|
#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, ...) {
|
void prints(const string fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
print_va_list_buffered(fmt, args);
|
print_va_list_buffered(fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
// context.allocator (alloc & dealloc)
|
|
||||||
void printf(const char* fmt, ...) {
|
void printf(const char* fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
|
|
|
@ -30,10 +30,13 @@ void log_heap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_allocator(bool do_log_heap) {
|
void test_allocator(bool do_log_heap) {
|
||||||
|
|
||||||
|
Allocator heap = get_heap_allocator();
|
||||||
|
|
||||||
// Basic allocation and free
|
// Basic allocation and free
|
||||||
int* a = (int*)alloc(sizeof(int));
|
int* a = (int*)alloc(heap, sizeof(int));
|
||||||
int* b = (int*)alloc(sizeof(int));
|
int* b = (int*)alloc(heap, sizeof(int));
|
||||||
int* c = (int*)alloc(sizeof(int));
|
int* c = (int*)alloc(heap, sizeof(int));
|
||||||
|
|
||||||
*a = 69;
|
*a = 69;
|
||||||
*b = 420;
|
*b = 420;
|
||||||
|
@ -51,41 +54,41 @@ void test_allocator(bool do_log_heap) {
|
||||||
assert(*c == 1337, "Test failed: Memory corrupted");
|
assert(*c == 1337, "Test failed: Memory corrupted");
|
||||||
|
|
||||||
// Allocate and free large block
|
// Allocate and free large block
|
||||||
void* large_block = alloc(1024 * 1024 * 100);
|
void* large_block = alloc(heap, 1024 * 1024 * 100);
|
||||||
dealloc(large_block);
|
dealloc(heap, large_block);
|
||||||
|
|
||||||
// Allocate multiple small blocks
|
// Allocate multiple small blocks
|
||||||
void* blocks[100];
|
void* blocks[100];
|
||||||
for (int i = 0; i < 100; ++i) {
|
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");
|
assert(blocks[i] != NULL, "Failed to allocate small block");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 100; ++i) {
|
for (int i = 0; i < 100; ++i) {
|
||||||
dealloc(blocks[i]);
|
dealloc(heap, blocks[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stress test with various sizes
|
// Stress test with various sizes
|
||||||
for (int i = 1; i <= 1000; ++i) {
|
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");
|
assert(p != NULL, "Failed to allocate varying size block");
|
||||||
dealloc(p);
|
dealloc(heap, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free in reverse order
|
// Free in reverse order
|
||||||
for (int i = 0; i < 100; ++i) {
|
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");
|
assert(blocks[i] != NULL, "Failed to allocate small block");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 99; i >= 0; --i) {
|
for (int i = 99; i >= 0; --i) {
|
||||||
dealloc(blocks[i]);
|
dealloc(heap, blocks[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test memory integrity with various allocation patterns
|
// Test memory integrity with various allocation patterns
|
||||||
int* nums[10];
|
int* nums[10];
|
||||||
for (int i = 0; i < 10; ++i) {
|
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) {
|
for (int j = 0; j < 10; ++j) {
|
||||||
nums[i][j] = i * 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) {
|
for (int j = 0; j < 10; ++j) {
|
||||||
assert(nums[i][j] == i * 10 + j, "Memory corruption detected");
|
assert(nums[i][j] == i * 10 + j, "Memory corruption detected");
|
||||||
}
|
}
|
||||||
dealloc(nums[i]);
|
dealloc(heap, nums[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
reset_temporary_storage();
|
reset_temporary_storage();
|
||||||
|
|
||||||
push_allocator(temp);
|
int* foo = (int*)alloc(temp, 72);
|
||||||
|
|
||||||
int* foo = (int*)alloc(72);
|
|
||||||
*foo = 1337;
|
*foo = 1337;
|
||||||
void* bar = alloc(69);
|
void* bar = alloc(temp, 69);
|
||||||
(void)bar;
|
(void)bar;
|
||||||
void* baz = alloc(420);
|
void* baz = alloc(temp, 420);
|
||||||
(void)baz;
|
(void)baz;
|
||||||
|
|
||||||
assert(*foo == 1337, "Temp memory corruptada");
|
assert(*foo == 1337, "Temp memory corruptada");
|
||||||
|
@ -116,63 +117,61 @@ void test_allocator(bool do_log_heap) {
|
||||||
|
|
||||||
reset_temporary_storage();
|
reset_temporary_storage();
|
||||||
|
|
||||||
foo = (int*)alloc(72);
|
foo = (int*)alloc(temp, 72);
|
||||||
|
|
||||||
assert(old_foo == foo, "Temp allocator goof");
|
assert(old_foo == foo, "Temp allocator goof");
|
||||||
|
|
||||||
pop_allocator();
|
|
||||||
|
|
||||||
// Repeated Allocation and Free
|
// Repeated Allocation and Free
|
||||||
for (int i = 0; i < 10000; ++i) {
|
for (int i = 0; i < 10000; ++i) {
|
||||||
void* temp = alloc(128);
|
void* temp = alloc(heap, 128);
|
||||||
assert(temp != NULL && "Repeated allocation failed");
|
assert(temp != NULL && "Repeated allocation failed");
|
||||||
dealloc(temp);
|
dealloc(heap, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mixed Size Allocations
|
// Mixed Size Allocations
|
||||||
void* mixed_blocks[200];
|
void* mixed_blocks[200];
|
||||||
for (int i = 0; i < 200; ++i) {
|
for (int i = 0; i < 200; ++i) {
|
||||||
if (i % 2 == 0) {
|
if (i % 2 == 0) {
|
||||||
mixed_blocks[i] = alloc(128);
|
mixed_blocks[i] = alloc(heap, 128);
|
||||||
} else {
|
} 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");
|
assert(mixed_blocks[i] != NULL && "Mixed size allocation failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 200; ++i) {
|
for (int i = 0; i < 200; ++i) {
|
||||||
if (i % 2 == 0) {
|
if (i % 2 == 0) {
|
||||||
dealloc(mixed_blocks[i]);
|
dealloc(heap, mixed_blocks[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 200; ++i) {
|
for (int i = 0; i < 200; ++i) {
|
||||||
if (i % 2 != 0) {
|
if (i % 2 != 0) {
|
||||||
dealloc(mixed_blocks[i]);
|
dealloc(heap, mixed_blocks[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fragmentation Stress Test
|
// Fragmentation Stress Test
|
||||||
for (int i = 0; i < 50; ++i) {
|
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");
|
assert(blocks[i] != NULL && "Failed to allocate small block for fragmentation test");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 50; i += 2) {
|
for (int i = 0; i < 50; i += 2) {
|
||||||
dealloc(blocks[i]);
|
dealloc(heap, blocks[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 50; i < 100; ++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");
|
assert(blocks[i] != NULL && "Failed to allocate small block in fragmented heap");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 50; i < 100; ++i) {
|
for (int i = 50; i < 100; ++i) {
|
||||||
dealloc(blocks[i]);
|
dealloc(heap, blocks[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i < 50; i += 2) {
|
for (int i = 1; i < 50; i += 2) {
|
||||||
dealloc(blocks[i]);
|
dealloc(heap, blocks[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_log_heap) log_heap();
|
if (do_log_heap) log_heap();
|
||||||
|
@ -192,7 +191,8 @@ void test_thread_proc1(Thread* t) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_threads() {
|
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_start_thread(t);
|
||||||
os_sleep(20);
|
os_sleep(20);
|
||||||
printf("This should be printed in middle of thread execution\n");
|
printf("This should be printed in middle of thread execution\n");
|
||||||
|
@ -205,31 +205,34 @@ void test_threads() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_allocator_threaded(Thread *t) {
|
void test_allocator_threaded(Thread *t) {
|
||||||
|
|
||||||
|
Allocator heap = get_heap_allocator();
|
||||||
|
|
||||||
for (int i = 0; i < 1000; ++i) {
|
for (int i = 0; i < 1000; ++i) {
|
||||||
void* temp = alloc(128);
|
void* temp = alloc(heap, 128);
|
||||||
assert(temp != NULL && "Repeated allocation failed");
|
assert(temp != NULL && "Repeated allocation failed");
|
||||||
dealloc(temp);
|
dealloc(heap, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* mixed_blocks[40];
|
void* mixed_blocks[40];
|
||||||
for (int i = 0; i < 40; ++i) {
|
for (int i = 0; i < 40; ++i) {
|
||||||
if (i % 2 == 0) {
|
if (i % 2 == 0) {
|
||||||
mixed_blocks[i] = alloc(128);
|
mixed_blocks[i] = alloc(heap, 128);
|
||||||
} else {
|
} 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");
|
assert(mixed_blocks[i] != NULL && "Mixed size allocation failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 40; ++i) {
|
for (int i = 0; i < 40; ++i) {
|
||||||
if (i % 2 == 0) {
|
if (i % 2 == 0) {
|
||||||
dealloc(mixed_blocks[i]);
|
dealloc(heap, mixed_blocks[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 40; ++i) {
|
for (int i = 0; i < 40; ++i) {
|
||||||
if (i % 2 != 0) {
|
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("Test") == 4, "Failed: length_of_null_terminated_string");
|
||||||
assert(length_of_null_terminated_string("") == 0, "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
|
// 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.data != NULL, "Failed: alloc_string");
|
||||||
assert(alloc_str.count == 10, "Failed: alloc_string");
|
assert(alloc_str.count == 10, "Failed: alloc_string");
|
||||||
dealloc_string(alloc_str);
|
dealloc_string(heap, alloc_str);
|
||||||
|
|
||||||
// Test string_concat
|
// Test string_concat
|
||||||
string str1 = fixed_string("Hello, ");
|
string str1 = fixed_string("Hello, ");
|
||||||
string str2 = fixed_string("World!");
|
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(concat_str.count == str1.count + str2.count, "Failed: string_concat");
|
||||||
assert(memcmp(concat_str.data, "Hello, World!", concat_str.count) == 0, "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
|
// 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");
|
assert(strcmp(cstr, "Hello, ") == 0, "Failed: convert_to_null_terminated_string");
|
||||||
dealloc(cstr);
|
dealloc(heap, cstr);
|
||||||
|
|
||||||
// Test temp_convert_to_null_terminated_string
|
// Test temp_convert_to_null_terminated_string
|
||||||
cstr = temp_convert_to_null_terminated_string(str2);
|
cstr = temp_convert_to_null_terminated_string(str2);
|
||||||
assert(strcmp(cstr, "World!") == 0, "Failed: temp_convert_to_null_terminated_string");
|
assert(strcmp(cstr, "World!") == 0, "Failed: temp_convert_to_null_terminated_string");
|
||||||
// No need to dealloc, it's temporary storage
|
|
||||||
|
|
||||||
// Test sprint
|
// Test sprint
|
||||||
string format_str = fixed_string("Number: %d");
|
string format_str = fixed_string("Number: %d");
|
||||||
string formatted_str = sprint(format_str, 42);
|
string formatted_str = sprint(heap, format_str, 42);
|
||||||
char* formatted_cstr = convert_to_null_terminated_string(formatted_str);
|
char* formatted_cstr = convert_to_null_terminated_string(formatted_str, heap);
|
||||||
assert(strcmp(formatted_cstr, "Number: 42") == 0, "Failed: sprint");
|
assert(strcmp(formatted_cstr, "Number: 42") == 0, "Failed: sprint");
|
||||||
dealloc(formatted_str.data);
|
dealloc(heap, formatted_str.data);
|
||||||
dealloc(formatted_cstr);
|
dealloc(heap, formatted_cstr);
|
||||||
|
|
||||||
// Test tprint
|
// Test tprint
|
||||||
string temp_formatted_str = tprint(format_str, 100);
|
string temp_formatted_str = tprint(format_str, 100);
|
||||||
formatted_cstr = temp_convert_to_null_terminated_string(temp_formatted_str);
|
formatted_cstr = temp_convert_to_null_terminated_string(temp_formatted_str);
|
||||||
assert(strcmp(formatted_cstr, "Number: 100") == 0, "Failed: tprint");
|
assert(strcmp(formatted_cstr, "Number: 100") == 0, "Failed: tprint");
|
||||||
// No need to dealloc, it's temporary storage
|
|
||||||
|
|
||||||
// Test print and printf (visual inspection)
|
// Test print and printf (visual inspection)
|
||||||
printf("Expected output: Hello, World!\n");
|
printf("Expected output: Hello, World!\n");
|
||||||
|
@ -308,24 +311,24 @@ void test_strings() {
|
||||||
|
|
||||||
// Test handling of empty strings
|
// Test handling of empty strings
|
||||||
string empty_str = fixed_string("");
|
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");
|
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)
|
// Test very large strings (performance test)
|
||||||
string large_str1 = alloc_string(1024 * 1024);
|
string large_str1 = alloc_string(heap, 1024 * 1024);
|
||||||
string large_str2 = alloc_string(1024 * 1024);
|
string large_str2 = alloc_string(heap, 1024 * 1024);
|
||||||
string large_concat_str = string_concat(large_str1, large_str2);
|
string large_concat_str = string_concat(large_str1, large_str2, heap);
|
||||||
assert(large_concat_str.count == 2 * 1024 * 1024, "Failed: large string_concat");
|
assert(large_concat_str.count == 2 * 1024 * 1024, "Failed: large string_concat");
|
||||||
dealloc_string(large_str1);
|
dealloc_string(heap, large_str1);
|
||||||
dealloc_string(large_str2);
|
dealloc_string(heap, large_str2);
|
||||||
dealloc_string(large_concat_str);
|
dealloc_string(heap, large_concat_str);
|
||||||
|
|
||||||
// Test string with special characters
|
// Test string with special characters
|
||||||
string special_char_str = fixed_string("Special chars: \n\t\r");
|
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");
|
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 a = tprintf("Hello, %cs!\n", "balls");
|
||||||
string balls1 = string_view(a, 7, 5);
|
string balls1 = string_view(a, 7, 5);
|
||||||
|
@ -340,17 +343,15 @@ void test_file_io() {
|
||||||
#if TARGET_OS == WINDOWS
|
#if TARGET_OS == WINDOWS
|
||||||
// Test win32_fixed_utf8_to_null_terminated_wide
|
// Test win32_fixed_utf8_to_null_terminated_wide
|
||||||
string utf8_str = fixed_string("Test");
|
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 != NULL, "Failed: win32_fixed_utf8_to_null_terminated_wide");
|
||||||
assert(wide_str[4] == 0, "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
|
// Test temp_win32_fixed_utf8_to_null_terminated_wide
|
||||||
push_temp_allocator();
|
|
||||||
wide_str = temp_win32_fixed_utf8_to_null_terminated_wide(utf8_str);
|
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 != NULL, "Failed: temp_win32_fixed_utf8_to_null_terminated_wide");
|
||||||
assert(wide_str[4] == 0, "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
|
#endif
|
||||||
|
|
||||||
File file = OS_INVALID_FILE;
|
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);
|
bool write_entire_result = os_write_entire_file(fixed_string("entire_test.txt"), write_data);
|
||||||
assert(write_entire_result, "Failed: os_write_entire_file");
|
assert(write_entire_result, "Failed: os_write_entire_file");
|
||||||
|
|
||||||
|
Allocator heap = get_heap_allocator();
|
||||||
|
|
||||||
string read_data;
|
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(read_entire_result, "Failed: os_read_entire_file");
|
||||||
assert(strings_match(read_data, write_data), "Failed: os_read_entire_file write/read mismatch");
|
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)");
|
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
|
// Test fprint
|
||||||
File balls = os_file_open(fixed_string("balls.txt"), O_WRITE | O_CREATE);
|
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");
|
fprint(balls, "Hello, %cs!", "Balls");
|
||||||
os_file_close(balls);
|
os_file_close(balls);
|
||||||
string hello_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(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);
|
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");
|
assert(ok, "write integers fail");
|
||||||
|
|
||||||
string integers_read;
|
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");
|
assert(ok, "read integers fail");
|
||||||
u64 *new_integers = (u64*)integers_data.data;
|
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);
|
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");
|
assert(delete_ok, "Failed: could not delete entire_test.txt");
|
||||||
delete_ok = os_file_delete(fixed_string("balls.txt"));
|
delete_ok = os_file_delete(fixed_string("balls.txt"));
|
||||||
assert(delete_ok, "Failed: could not delete 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() {
|
void oogabooga_run_tests() {
|
||||||
|
@ -453,7 +458,7 @@ void oogabooga_run_tests() {
|
||||||
printf("Thread bombing allocator... ");
|
printf("Thread bombing allocator... ");
|
||||||
Thread* threads[100];
|
Thread* threads[100];
|
||||||
for (int i = 0; i < 100; i++) {
|
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]);
|
os_start_thread(threads[i]);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 100; i++) {
|
for (int i = 0; i < 100; i++) {
|
||||||
|
|
Reference in a new issue