From 68d1efb759cf2d9a616554f5ec7a354d9fb6ed44 Mon Sep 17 00:00:00 2001 From: Charlie <66182434+asbott@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:07:02 +0200 Subject: [PATCH] - Start work on string library - Dyamically load minimum crt symbols in os backend so we don't need to #include c headers - Some more os calls: - write to stdout (with our string type) - macros for variadic argument lists - Dynamic library loading --- build.c | 2 +- oogabooga/base.c | 40 ++++++++++++-- oogabooga/memory.c | 13 ++++- oogabooga/oogabooga.c | 8 +-- oogabooga/os_impl_windows.c | 33 +++++++++++ oogabooga/os_interface.c | 106 ++++++++++++++++++++++++++++++++++-- oogabooga/string.c | 45 +++++++++++++++ oogabooga/tests.c | 9 +++ 8 files changed, 238 insertions(+), 18 deletions(-) create mode 100644 oogabooga/string.c diff --git a/build.c b/build.c index 90aa346..7b3254c 100644 --- a/build.c +++ b/build.c @@ -2,7 +2,7 @@ /// // Build config stuff #define VERY_DEBUG 0 -#define RUN_TESTS 0 +#define RUN_TESTS 1 typedef struct Context_Extra { int monkee; diff --git a/oogabooga/base.c b/oogabooga/base.c index 05773c2..8536f3b 100644 --- a/oogabooga/base.c +++ b/oogabooga/base.c @@ -29,13 +29,43 @@ typedef u8 bool; #define assert(cond, ...) if (!(cond)) { printf("Assertion failed for condition: " #cond ". Message: " __VA_ARGS__); os_debug_break(); } -#ifndef max - #define max(a, b) ((a) > (b) ? (a) : (b)) - #define min(a, b) ((a) < (b) ? (a) : (b)) -#endif - #define cast(t) (t) +/// +// inline +// (Credit to chatgpt, so it might not be 100% correct) +#ifdef _MSC_VER + // Microsoft Visual C++ + #define inline __forceinline +#elif defined(__GNUC__) || defined(__GNUG__) + // GNU GCC/G++ + #define inline __attribute__((always_inline)) inline +#elif defined(__clang__) + // Clang/LLVM + #define inline __attribute__((always_inline)) inline +#elif defined(__INTEL_COMPILER) || defined(__ICC) + // Intel C++ Compiler + #define inline __forceinline +#elif defined(__BORLANDC__) + // Borland C++ + #define inline __inline +#elif defined(__MINGW32__) || defined(__MINGW64__) + // MinGW (Minimalist GNU for Windows) + #define inline __attribute__((always_inline)) inline +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) + // Oracle Solaris Studio + #define inline inline __attribute__((always_inline)) +#elif defined(__IBMC__) || defined(__IBMCPP__) + // IBM XL C/C++ Compiler + #define inline __attribute__((always_inline)) inline +#elif defined(__PGI) + // Portland Group Compiler + #define inline inline __attribute__((always_inline)) +#else + // Fallback for unknown compilers + #define inline inline +#endif + typedef struct Nothing {int nothing;} Nothing; #ifndef CONTEXT_EXTRA diff --git a/oogabooga/memory.c b/oogabooga/memory.c index f4ad2cf..984e23c 100644 --- a/oogabooga/memory.c +++ b/oogabooga/memory.c @@ -164,10 +164,11 @@ void heap_init() { } void *heap_alloc(u64 size) { - // #Sync #Speed oof - os_lock_mutex(heap_mutex); if (!heap_initted) heap_init(); + + // #Sync #Speed oof + os_lock_mutex(heap_mutex); size += sizeof(Heap_Allocation_Metadata); @@ -262,9 +263,10 @@ void *heap_alloc(u64 size) { } void heap_dealloc(void *p) { // #Sync #Speed oof - os_lock_mutex(heap_mutex); if (!heap_initted) heap_init(); + + os_lock_mutex(heap_mutex); assert(is_pointer_in_program_memory(p), "Garbage pointer; out of program memory bounds!"); p = (u8*)p-sizeof(Heap_Allocation_Metadata); @@ -431,3 +433,8 @@ 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); +} diff --git a/oogabooga/oogabooga.c b/oogabooga/oogabooga.c index 6d4d5b2..12ffe2f 100644 --- a/oogabooga/oogabooga.c +++ b/oogabooga/oogabooga.c @@ -1,16 +1,14 @@ -#include // #Cleanup just using this for printf -#include - #include "base.c" +#include "string.c" + #include "os_interface.c" #include "memory.c" - #ifdef OS_WINDOWS #include "os_impl_windows.c" #elif defined (OS_LINUX) @@ -24,6 +22,6 @@ void oogabooga_init(u64 program_memory_size) { os_init(program_memory_size); - heap_init(); + heap_init(); temporary_storage_init(); } \ No newline at end of file diff --git a/oogabooga/os_impl_windows.c b/oogabooga/os_impl_windows.c index 62b44fb..c5727db 100644 --- a/oogabooga/os_impl_windows.c +++ b/oogabooga/os_impl_windows.c @@ -37,6 +37,20 @@ void os_init(u64 program_memory_size) { context.allocator = 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"); + os.crt_vprintf = (Crt_Vprintf_Proc)os_dynamic_library_load_symbol(os.crt, const_string("vprintf")); + assert(os.crt_vprintf, "Missing vprintf in crt"); + os.crt_printf = (Crt_Printf_Proc)os_dynamic_library_load_symbol(os.crt, const_string("printf")); + assert(os.crt_printf, "Missing printf in crt"); + os.crt_vsnprintf = (Crt_Vsnprintf_Proc)os_dynamic_library_load_symbol(os.crt, const_string("vsnprintf")); + assert(os.crt_vsnprintf, "Missing vsnprintf in crt"); + os.crt_memcpy = (Crt_Memcpy_Proc)os_dynamic_library_load_symbol(os.crt, const_string("memcpy")); + assert(os.crt_memcpy, "Missing memcpy in crt"); + os.crt_memcmp = (Crt_Memcmp_Proc)os_dynamic_library_load_symbol(os.crt, const_string("memcmp")); + assert(os.crt_memcmp, "Missing crt_memcmp in crt"); + os.crt_memset = (Crt_Memset_Proc)os_dynamic_library_load_symbol(os.crt, const_string("memset")); + assert(os.crt_memset, "Missing memset in crt"); } bool os_grow_program_memory(u64 new_size) { @@ -171,4 +185,23 @@ float64 os_get_current_time_in_seconds() { return -1.0; } return (double)counter.QuadPart / (double)frequency.QuadPart; +} + + +Dynamic_Library_Handle os_load_dynamic_library(string path) { + return LoadLibraryA(temp_convert_to_null_terminated_string(path)); +} +void *os_dynamic_library_load_symbol(Dynamic_Library_Handle l, string identifier) { + return GetProcAddress(l, temp_convert_to_null_terminated_string(identifier)); +} +void os_unload_dynamic_library(Dynamic_Library_Handle l) { + FreeLibrary(l); +} + + +void os_write_string_to_stdout(string s) { + HANDLE win32_stdout = GetStdHandle(STD_OUTPUT_HANDLE); + if (win32_stdout == INVALID_HANDLE_VALUE) return; + + WriteFile(win32_stdout, s.data, s.count, 0, NULL); } \ No newline at end of file diff --git a/oogabooga/os_interface.c b/oogabooga/os_interface.c index 4d69c87..c6e855d 100644 --- a/oogabooga/os_interface.c +++ b/oogabooga/os_interface.c @@ -6,32 +6,111 @@ typedef HANDLE Mutex_Handle; typedef HANDLE Thread_Handle; + typedef HMODULE Dynamic_Library_Handle; #elif defined(__linux__) // Include whatever #Incomplete #Portability #define OS_LINUX - typedef SOMETHING Mutex_Handle; typedef SOMETHING Thread_Handle; + typedef SOMETHING Dynamic_Library_Handle; + #error "Linux is not supported yet"; #elif defined(__APPLE__) && defined(__MACH__) // Include whatever #Incomplete #Portability #define OS_MAC - typedef SOMETHING Mutex_Handle; typedef SOMETHING Thread_Handle; + typedef SOMETHING Dynamic_Library_Handle; + #error "Mac is not supported yet"; #else #error "Current OS not supported!"; #endif +#ifndef max + #define max(a, b) ((a) > (b) ? (a) : (b)) + #define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1)) + +#define oogabooga_va_start(ap, v) (ap = (va_list)&v + _INTSIZEOF(v)) +#define oogabooga_va_arg(ap, t) (*(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))) +#define oogabooga_va_end(ap) (ap = (va_list)0) + +typedef void* (__cdecl *Crt_Memcpy_Proc) (void*, const void*, size_t); +typedef int (__cdecl *Crt_Memcmp_Proc) (const void*, const void*, size_t); +typedef void* (__cdecl *Crt_Memset_Proc) (void*, int, size_t); +typedef int (__cdecl *Crt_Printf_Proc) (const char*, ...); +typedef int (__cdecl *Crt_Vprintf_Proc) (const char*, va_list); +typedef int (__cdecl *Crt_Vsnprintf_Proc) (char*, size_t, const char*, va_list); + typedef struct Os_Info { u64 page_size; u64 granularity; + + Dynamic_Library_Handle crt; + + Crt_Memcpy_Proc crt_memcpy; + Crt_Memcmp_Proc crt_memcmp; + Crt_Memset_Proc crt_memset; + Crt_Printf_Proc crt_printf; // #Cleanup remove after we have our own print + Crt_Vprintf_Proc crt_vprintf; // #Cleanup remove after we have our own print + Crt_Vsnprintf_Proc crt_vsnprintf; + } Os_Info; Os_Info os; +inline void* naive_memcpy(void* dest, const void* source, size_t size) { + for (u64 i = 0; i < (u64)size; i++) ((u8*)dest)[i] = ((u8*)source)[i]; + return dest; +} +inline void* memcpy(void* dest, const void* source, size_t size) { + if (!os.crt_memcpy) return naive_memcpy(dest, source, size); + return os.crt_memcpy(dest, source, size); +} +inline int naive_memcmp(const void* a, const void* b, size_t amount) { + // I don't understand the return value of memcmp but I also dont care + for (u64 i = 0; i < (u64)amount; i++) { + if (((u8*)a)[i] != ((u8*)b)[i]) return -1; + } + return 0; +} +inline int memcmp(const void* a, const void* b, size_t amount) { + if (!os.crt_memcmp) return naive_memcmp(a, b, amount); + return os.crt_memcmp(a, b, amount); +} +inline void* naive_memset(void* dest, int value, size_t amount) { + for (u64 i = 0; i < (u64)amount; i++) ((u8*)dest)[i] = (u8)value; + return dest; +} +inline void* memset(void* dest, int value, size_t amount) { + if (!os.crt_memset) return naive_memset(dest, value, amount); + return os.crt_memset(dest, value, amount); +} +inline int printf(const char* fmt, ...) { + char fast_buffer[8196]; + char *large_buffer = 0; - + va_list args; + oogabooga_va_start(args, fmt); + int r = vprintf(fmt, args); + oogabooga_va_end(args); + + return r; +} +void os_write_string_to_stdout(string s); +inline int vprintf(const char* fmt, va_list args) { + if (os.crt_vprintf) return os.crt_vprintf(fmt, args); + else { + os_write_string_to_stdout(cstr(fmt)); + os_write_string_to_stdout(cstr(" ")); + return 0; + } +} +inline int vsnprintf(char* buffer, size_t n, const char* fmt, va_list args) { + os.crt_vsnprintf(buffer, n, fmt, args); +} void* program_memory = 0; u64 program_memory_size = 0; @@ -80,4 +159,23 @@ void os_unlock_mutex(Mutex_Handle m); /// u64 os_get_current_cycle_count(); -float64 os_get_current_time_in_seconds(); \ No newline at end of file +float64 os_get_current_time_in_seconds(); + + +/// +/// +// Dynamic Libraries +/// + +Dynamic_Library_Handle os_load_dynamic_library(string path); +void *os_dynamic_library_load_symbol(Dynamic_Library_Handle l, string identifier); +void os_unload_dynamic_library(Dynamic_Library_Handle l); + + + +/// +/// +// IO +/// + +void os_write_string_to_stdout(string s); \ No newline at end of file diff --git a/oogabooga/string.c b/oogabooga/string.c new file mode 100644 index 0000000..670376a --- /dev/null +++ b/oogabooga/string.c @@ -0,0 +1,45 @@ + +void * memcpy (void *,const void *,size_t); + +typedef struct string { + u8 *data; + u64 count; +} string; + +void push_temp_allocator(); + +#define cstr const_string +#define const_string(s) (string){ (u8*)s, length_of_null_terminated_string(s) } + +inline u64 length_of_null_terminated_string(const char* cstring) { + u64 len = 0; + while (*cstring != 0) { + len += 1; + cstring += 1; + } + return len; +} + +// context.allocator ! +string string_concat(string left, string right) { + string result; + result.count = left.count + right.count; + result.data = cast(u8*)alloc(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(string s) { + char *cstring = cast(char*)alloc(s.count+1); + memcpy(cstring, s.data, s.count); + cstring[s.count] = 0; + return cstring; +} + +char *temp_convert_to_null_terminated_string(string s) { + push_temp_allocator(); + char *c = convert_to_null_terminated_string(s); + pop_allocator(); + return c; +} \ No newline at end of file diff --git a/oogabooga/tests.c b/oogabooga/tests.c index 1ba3594..641d662 100644 --- a/oogabooga/tests.c +++ b/oogabooga/tests.c @@ -221,6 +221,11 @@ void test_allocator_threaded(Thread *t) { } } +void test_strings() { + string s = (string){ (u8*)"Ooga booga", length_of_null_terminated_string("Ooga booga") }; + string a = const_string("Ooga booga"); +} + void oogabooga_run_tests() { printf("Testing allocator...\n"); test_allocator(true); @@ -229,6 +234,10 @@ void oogabooga_run_tests() { printf("Testing threads...\n"); test_threads(); printf("OK!\n"); + + printf("Testing strings...\n"); + test_strings(); + printf("OK!\n"); printf("Thread bombing allocator...\n"); Thread* threads[100];