port os functions, add testing module
This commit is contained in:
16
build_file.c
16
build_file.c
@@ -1,7 +1,7 @@
|
||||
// don't ever include stuff that build_file will generate code for!
|
||||
#define DONT_INCLUDE_GENERATED_MATH
|
||||
#include "src/core/core_inc.h"
|
||||
#include "src/core/core_inc.c"
|
||||
#include "src/core/core.h"
|
||||
#include "src/core/core.c"
|
||||
|
||||
#define BUILD_TOOL_LIB
|
||||
#define S8_String s8_t
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "src/ui/ui.meta.c"
|
||||
#include "src/render/render.meta.c"
|
||||
#include "src/wasm_app/wasm_app.meta.c"
|
||||
#include "src/testing/testing.meta.c"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
core_init();
|
||||
@@ -34,10 +35,11 @@ int main(int argc, char **argv) {
|
||||
mt_app(tcx->temp);
|
||||
mt_wasm_app(tcx->temp);
|
||||
mt_render(tcx->temp);
|
||||
mt_testing(tcx->temp);
|
||||
|
||||
b32 run_server = false;
|
||||
b32 core_test_target = true;
|
||||
b32 win32_target = true;
|
||||
b32 win32_target = false;
|
||||
b32 standalone_w32_target = false;
|
||||
b32 wasm_target = false;
|
||||
|
||||
@@ -77,10 +79,10 @@ int main(int argc, char **argv) {
|
||||
);
|
||||
}
|
||||
|
||||
if (core_test_target && cache_code_modified(s8_lit("../src/core/core_test_entry.c"), s8_lit("core_test.exe"))) {
|
||||
os_delete_file(s8_lit("core_test.pdb"));
|
||||
if (core_test_target && cache_code_modified(s8_lit("../src/testing/testing_main.c"), s8_lit("testing.exe"))) {
|
||||
os_delete_file(s8_lit("testing.pdb"));
|
||||
ok = os_systemf(
|
||||
"cl ../src/core/core_test_entry.c -Fe:core_test.exe -Fd:core_test.pdb"
|
||||
"cl ../src/testing/testing_main.c -Fe:testing.exe -Fd:testing.pdb"
|
||||
" -I ../src"
|
||||
" /Zi /FC /nologo /Oi"
|
||||
" /WX /W3 /wd4200 /diagnostics:column"
|
||||
@@ -88,7 +90,7 @@ int main(int argc, char **argv) {
|
||||
);
|
||||
if (ok != 0) return ok;
|
||||
|
||||
ok = os_systemf("core_test.exe");
|
||||
ok = os_systemf("testing.exe");
|
||||
if (ok != 0) return ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -281,36 +281,6 @@ struct w32_library_t {
|
||||
app_update_t *update_fn;
|
||||
};
|
||||
|
||||
fn b32 os_copy(s8_t from, s8_t to, b32 overwrite) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s16_t from16 = s16_from_s8(scratch.arena, from);
|
||||
s16_t to16 = s16_from_s8(scratch.arena, to);
|
||||
|
||||
BOOL fail_if_exists = !overwrite;
|
||||
BOOL success = CopyFileW(from16.str, to16.str, fail_if_exists);
|
||||
b32 result = success ? true : false;
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn i64 os_get_file_mod_time(s8_t file) {
|
||||
FILETIME time = {0};
|
||||
WIN32_FIND_DATAW data;
|
||||
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s16_t wpath = s16_from_s8(scratch.arena, file);
|
||||
HANDLE handle = FindFirstFileW(wpath.str, &data);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
FindClose(handle);
|
||||
time = data.ftLastWriteTime;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
i64 result = (i64)time.dwHighDateTime << 32 | time.dwLowDateTime;
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void w32_set_event(app_frame_t *frame, app_event_t ev) {
|
||||
frame->first_event = frame->last_event = NULL;
|
||||
frame->event_count = 0;
|
||||
@@ -370,137 +340,6 @@ fn void w32_try_reloading_library(w32_library_t *lib, app_frame_t frame) {
|
||||
end_of_lib_load:;
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// file ops
|
||||
fn s8_t os_abs(ma_arena_t *arena, s8_t rel) {
|
||||
const int buffer_size = 2048;
|
||||
ma_temp_t scratch = ma_begin_scratch1(arena);
|
||||
s16_t rel16 = s16_from_s8(scratch.arena, rel);
|
||||
wchar_t *buffer = ma_push_array(scratch.arena, wchar_t, buffer_size);
|
||||
DWORD written = GetFullPathNameW(rel16.str, buffer_size, buffer, 0);
|
||||
assert(written != 0);
|
||||
assert((i64)written < (i64)buffer_size);
|
||||
s8_t result = s8_from_s16(arena, s16(buffer, written));
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t os_exe(ma_arena_t *arena) {
|
||||
const int buffer_size = 2048;
|
||||
ma_temp_t scratch = ma_begin_scratch1(arena);
|
||||
wchar_t *buffer = ma_push_array(scratch.arena, wchar_t, buffer_size);
|
||||
DWORD wsize = GetModuleFileNameW(0, buffer, buffer_size);
|
||||
assert(wsize != 0);
|
||||
s8_t result = s8_from_s16(arena, s16(buffer, wsize));
|
||||
s8_normalize_path_unsafe(result);
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t os_exe_dir(ma_arena_t *arena) {
|
||||
ma_temp_t scratch = ma_begin_scratch1(arena);
|
||||
s8_t exe = os_exe(scratch.arena);
|
||||
s8_t path = s8_chop_last_slash(exe);
|
||||
s8_t result = s8_copy(arena, path);
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 os_delete(s8_t path) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s16_t path16 = s16_from_s8(scratch.arena, path);
|
||||
BOOL success = DeleteFileW(path16.str);
|
||||
b32 result = true;
|
||||
if (success == 0) {
|
||||
result = false; // path not found
|
||||
}
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// file iter
|
||||
typedef struct w32_file_iter_t w32_file_iter_t;
|
||||
struct w32_file_iter_t {
|
||||
HANDLE handle;
|
||||
WIN32_FIND_DATAW data;
|
||||
};
|
||||
|
||||
typedef struct os_file_iter_t os_file_iter_t;
|
||||
struct os_file_iter_t {
|
||||
s8_t abs;
|
||||
s8_t rel;
|
||||
s8_t name;
|
||||
b8 is_directory;
|
||||
b8 is_valid;
|
||||
|
||||
s8_t path;
|
||||
ma_arena_t *arena;
|
||||
|
||||
union {
|
||||
w32_file_iter_t *w32;
|
||||
void *platform;
|
||||
};
|
||||
};
|
||||
|
||||
fn void os_advance(os_file_iter_t *it) {
|
||||
while (FindNextFileW(it->w32->handle, &it->w32->data) != 0) {
|
||||
WIN32_FIND_DATAW *data = &it->w32->data;
|
||||
|
||||
// Skip '.' and '..'
|
||||
if (data->cFileName[0] == '.' && data->cFileName[1] == '.' && data->cFileName[2] == 0) continue;
|
||||
if (data->cFileName[0] == '.' && data->cFileName[1] == 0) continue;
|
||||
|
||||
it->is_directory = data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
it->name = s8_from_s16(it->arena, s16(data->cFileName, wstr_len(data->cFileName)));
|
||||
|
||||
const char *is_dir = it->is_directory ? "/" : "";
|
||||
const char *separator = it->path.str[it->path.len - 1] == '/' ? "" : "/";
|
||||
|
||||
it->rel = s8_printf(it->arena, "%S%s%S%s", it->path, separator, it->name, is_dir);
|
||||
it->abs = os_abs(it->arena, it->rel);
|
||||
it->is_valid = true;
|
||||
|
||||
if (it->is_directory) {
|
||||
assert(it->rel.str[it->rel.len - 1] == '/');
|
||||
assert(it->abs.str[it->abs.len - 1] == '/');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
it->is_valid = false;
|
||||
DWORD error = GetLastError();
|
||||
assert(error == ERROR_NO_MORE_FILES);
|
||||
FindClose(it->w32->handle);
|
||||
}
|
||||
|
||||
fn os_file_iter_t *os_iterate_files(ma_arena_t *arena, s8_t path) {
|
||||
os_file_iter_t *it = ma_push_type(arena, os_file_iter_t);
|
||||
it->w32 = ma_push_type(arena, w32_file_iter_t);
|
||||
it->arena = arena;
|
||||
it->path = path;
|
||||
it->is_valid = true;
|
||||
|
||||
ma_temp_t scratch = ma_begin_scratch1(arena);
|
||||
s8_t mod_path = s8_printf(scratch.arena, "%S\\*", path);
|
||||
s16_t mod_path16 = s16_from_s8(scratch.arena, mod_path);
|
||||
|
||||
it->w32->handle = FindFirstFileW(mod_path16.str, &it->w32->data);
|
||||
if (it->w32->handle == INVALID_HANDLE_VALUE) {
|
||||
it->is_valid = false;
|
||||
}
|
||||
|
||||
if (it->is_valid) {
|
||||
assert(it->w32->data.cFileName[0] == '.' && it->w32->data.cFileName[1] == 0);
|
||||
os_advance(it);
|
||||
}
|
||||
|
||||
ma_end_scratch(scratch);
|
||||
return it;
|
||||
}
|
||||
|
||||
|
||||
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
|
||||
core_init();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#define APP_HOT_RELOAD
|
||||
|
||||
#include "core/core_inc.h"
|
||||
#include "core/core.h"
|
||||
#include "app/app.h"
|
||||
|
||||
#include "core/core_inc.c"
|
||||
#include "core/core.c"
|
||||
#include "app/app.c"
|
||||
|
||||
313
src/core/core.h
313
src/core/core.h
@@ -1,297 +1,16 @@
|
||||
typedef uintptr_t usize;
|
||||
typedef uint64_t u64;
|
||||
typedef uint32_t u32;
|
||||
typedef uint16_t u16;
|
||||
typedef uint8_t u8;
|
||||
|
||||
typedef intptr_t isize;
|
||||
typedef int64_t i64;
|
||||
typedef int32_t i32;
|
||||
typedef int16_t i16;
|
||||
typedef int8_t i8;
|
||||
|
||||
typedef int64_t b64;
|
||||
typedef int32_t b32;
|
||||
typedef int16_t b16;
|
||||
typedef int8_t b8;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
#define f32_max FLT_MAX
|
||||
#define f32_min FLT_MIN
|
||||
#define f64_max DBL_MAX
|
||||
#define f64_min DBL_MIN
|
||||
|
||||
#define i8_max INT8_MAX
|
||||
#define i8_min INT8_MIN
|
||||
#define i16_max INT16_MAX
|
||||
#define i16_min INT16_MIN
|
||||
#define i32_max INT32_MAX
|
||||
#define i32_min INT32_MIN
|
||||
#define i64_max INT64_MAX
|
||||
#define i64_min INT64_MIN
|
||||
|
||||
#define u8_max UINT8_MAX
|
||||
#define u8_min 0
|
||||
#define u16_max UINT16_MAX
|
||||
#define u16_min 0
|
||||
#define u32_max UINT32_MAX
|
||||
#define u32_min 0
|
||||
#define u64_max UINT64_MAX
|
||||
#define u64_min 0
|
||||
|
||||
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
|
||||
#define fn
|
||||
#define fn_test
|
||||
#define gb
|
||||
#define locl static
|
||||
|
||||
typedef union convert_f64_u64_t convert_f64_u64_t;
|
||||
union convert_f64_u64_t { f64 f; u64 i; };
|
||||
typedef union convert_f64_i64_t convert_f64_i64_t;
|
||||
union convert_f64_i64_t { f64 f; i64 i; };
|
||||
typedef union convert_f32_u32_t convert_f32_u32_t;
|
||||
union convert_f32_u32_t { f32 f; u32 i; };
|
||||
typedef union convert_f32_i32_t convert_f32_i32_t;
|
||||
union convert_f32_i32_t { f32 f; i32 i; };
|
||||
|
||||
|
||||
#define U64_TO_F64(x) (((convert_f64_u64_t) { .i = (x) }).f)
|
||||
#define U32_TO_F32(x) (((convert_f32_u32_t) { .i = (x) }).f)
|
||||
#define F64_TO_U64(x) (((convert_f64_u64_t) { .f = (x) }).i)
|
||||
#define F32_TO_U32(x) (((convert_f32_u32_t) { .f = (x) }).i)
|
||||
|
||||
#define I64_TO_F64(x) (((convert_f64_i64_t) { .i = (x) }).f)
|
||||
#define I32_TO_F32(x) (((convert_f32_i32_t) { .i = (x) }).f)
|
||||
#define F64_TO_I64(x) (((convert_f64_i64_t) { .f = (x) }).i)
|
||||
#define F32_TO_I32(x) (((convert_f32_i32_t) { .f = (x) }).i)
|
||||
|
||||
#define MIN(x,y) ((x) > (y) ? (y) : (x))
|
||||
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
#define CLAMP_TOP(A,X) MIN(A,X)
|
||||
#define CLAMP_BOT(X,B) MAX(X,B)
|
||||
#define CLAMP(x,a,b) (((x)<(a))?(a):((x)>(b))?(b):(x))
|
||||
|
||||
#define set_bit(x) (1ULL << (x))
|
||||
#define lengthof(x) (sizeof((x))/sizeof((x)[0]))
|
||||
#ifndef offsetof
|
||||
#define offsetof(st, m) ((usize)&(((st *)0)->m))
|
||||
#endif
|
||||
#define expect(x) if (!(x))
|
||||
#define unused(x) (void)(x)
|
||||
|
||||
#define kib(x) (1024ULL * (x##ULL))
|
||||
#define mib(x) (1024ULL * kib(x))
|
||||
#define gib(x) (1024ULL * mib(x))
|
||||
#define thousand(n) ((n)*1000)
|
||||
#define million(n) ((n)*1000000)
|
||||
#define billion(n) ((n)*1000000000)
|
||||
|
||||
#define zero_struct(x) memory_zero((x), sizeof(*(x)))
|
||||
|
||||
|
||||
#define defer_if(begin, cond_end) for (b32 PASTE(_i_, __LINE__) = !!begin; PASTE(_i_, __LINE__); PASTE(_i_, __LINE__) = (cond_end, 0))
|
||||
#define defer_block(begin, end) for (i32 PASTE(_i_, __LINE__) = (begin, 0); !PASTE(_i_, __LINE__); PASTE(_i_, __LINE__) += (end, 1))
|
||||
|
||||
#define stack_t(type, size) struct { type data[size]; i32 len; }
|
||||
#define STACK_CAP(stack) (lengthof((stack).data))
|
||||
#define STACK_EMPTY(stack) ((stack).len == 0)
|
||||
#define STACK_FULL(stack) ((stack).len == STACK_CAP(stack))
|
||||
#define STACK_PUSH(stack, ...) (assert(!STACK_FULL(stack)), (stack).data[(stack).len++] = __VA_ARGS__)
|
||||
#define STACK_POP(stack) (assert(!STACK_EMPTY(stack)), (stack).data[--(stack).len])
|
||||
#define STACK_TOP(stack) (assert(!STACK_EMPTY(stack)), (stack).data[((stack).len-1)])
|
||||
|
||||
#define STRINGIFY_(S) #S
|
||||
#define STRINGIFY(S) STRINGIFY_(S)
|
||||
#define PASTE_(a, b) a##b
|
||||
#define PASTE(a, b) PASTE_(a, b)
|
||||
#define SWAP(t, a, b) do { t PASTE(temp__, __LINE__) = a; a = b; b = PASTE(temp__, __LINE__); } while(0)
|
||||
#define CODE(...) #__VA_ARGS__
|
||||
|
||||
#if PLATFORM_CL || (PLATFORM_CLANG && PLATFORM_WINDOWS)
|
||||
#pragma section(".rdata$", read)
|
||||
#define gb_read_only __declspec(allocate(".rdata$"))
|
||||
#elif PLATFORM_CLANG && PLATFORM_LINUX
|
||||
#define gb_read_only __attribute__((section(".rodata")))
|
||||
#else
|
||||
#define gb_read_only
|
||||
#endif
|
||||
|
||||
#if PLATFORM_CL
|
||||
#define fn_inline __forceinline
|
||||
#elif PLATFORM_CLANG || PLATFORM_GCC
|
||||
#define fn_inline __attribute__((always_inline))
|
||||
#else
|
||||
#define fn_inline
|
||||
#endif
|
||||
|
||||
#ifndef FILE_AND_LINE_GCC_FORMAT
|
||||
#define FILE_AND_LINE __FILE__"("STRINGIFY(__LINE__)")"
|
||||
#else
|
||||
#define FILE_AND_LINE __FILE__":"STRINGIFY(__LINE__)
|
||||
#endif
|
||||
|
||||
#if PLATFORM_CL
|
||||
#define debug__break() __debugbreak()
|
||||
#else
|
||||
#define debug__break() __builtin_trap()
|
||||
#endif
|
||||
#define debug_break() (debug__break(), 0)
|
||||
|
||||
#if PLATFORM_WASM
|
||||
#define gb_thread
|
||||
#elif PLATFORM_GCC | PLATFORM_CLANG
|
||||
#define gb_thread __thread
|
||||
#elif PLATFORM_CL
|
||||
#define gb_thread __declspec(thread)
|
||||
#else
|
||||
#define gb_thread _Thread_local
|
||||
#endif
|
||||
|
||||
#if PLATFORM_CL
|
||||
#pragma warning(disable: 4116)
|
||||
#endif
|
||||
|
||||
// Single linked list Queue
|
||||
#define SLLQ_APPEND_EX(f, l, n, next) \
|
||||
do { \
|
||||
assert((n)->next == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (n); \
|
||||
} else { \
|
||||
(l) = (l)->next = (n); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SLLQ_APPEND(f, l, n) SLLQ_APPEND_EX(f, l, n, next)
|
||||
|
||||
#define SLLQ_PREPEND_EX(f, l, n, next) \
|
||||
do { \
|
||||
assert((n)->next == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (n); \
|
||||
} else { \
|
||||
(n)->next = (f); \
|
||||
(f) = (n); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SLLQ_PREPEND(f, l, n) SLLQ_PREPEND_EX(f, l, n, next)
|
||||
|
||||
#define SLLQ_REMOVE_FIRST_EX(f, l, next) \
|
||||
do { \
|
||||
if ((f) == (l)) { \
|
||||
(f) = (l) = 0; \
|
||||
} else { \
|
||||
(f) = (f)->next; \
|
||||
} \
|
||||
} while (0)
|
||||
#define SLLQ_REMOVE_FIRST(f, l) SLLQ_REMOVE_FIRST_EX(f, l, next)
|
||||
|
||||
// Singly linked list stack
|
||||
#define SLLS_PUSH_EX(stack_base, new_stack_base, next) \
|
||||
do { \
|
||||
(new_stack_base)->next = (stack_base); \
|
||||
(stack_base) = (new_stack_base); \
|
||||
} while (0)
|
||||
#define SLLS_PUSH(stack_base, new_stack_base) \
|
||||
SLLS_PUSH_EX(stack_base, new_stack_base, next)
|
||||
|
||||
#define SLLS_POP(stack_base) ((stack_base) = (stack_base)->next)
|
||||
#define SLLS_POP_AND_STORE(stack_base, out_node) \
|
||||
do { \
|
||||
if (stack_base) { \
|
||||
(out_node) = (stack_base); \
|
||||
(stack_base) = (stack_base)->next; \
|
||||
(out_node)->next = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Doubly linked list Queue
|
||||
#define DLLQ_APPEND_EX(f, l, node, next, prev) \
|
||||
do { \
|
||||
assert((node)->next == NULL); \
|
||||
assert((node)->prev == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (node); \
|
||||
} else { \
|
||||
(l)->next = (node); \
|
||||
(node)->prev = (l); \
|
||||
(l) = (node); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLLQ_APPEND(f, l, node) DLLQ_APPEND_EX(f, l, node, next, prev)
|
||||
|
||||
#define DLLQ_PREPEND_EX(f, l, node, next, prev) \
|
||||
do { \
|
||||
assert((node)->next == NULL); \
|
||||
assert((node)->prev == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (node); \
|
||||
} else { \
|
||||
(node)->next = (f); \
|
||||
(f)->prev = (node); \
|
||||
(f) = (node); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLLQ_PREPEND(f, l, node) DLLQ_PREPEND_EX(f, l, node, next, prev)
|
||||
|
||||
#define DLLQ_CONTAINS(f, l, n, next, prev) for (
|
||||
|
||||
#define DLLQ_REMOVE_EX(first, last, node, next, prev) \
|
||||
do { \
|
||||
if ((first) == (last)) { \
|
||||
assert((node) == (first)); \
|
||||
(first) = (last) = 0; \
|
||||
} else if ((last) == (node)) { \
|
||||
(last) = (last)->prev; \
|
||||
(last)->next = 0; \
|
||||
} else if ((first) == (node)) { \
|
||||
(first) = (first)->next; \
|
||||
(first)->prev = 0; \
|
||||
} else { \
|
||||
(node)->prev->next = (node)->next; \
|
||||
(node)->next->prev = (node)->prev; \
|
||||
} \
|
||||
if (node) { \
|
||||
(node)->prev = 0; \
|
||||
(node)->next = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLLQ_REMOVE(first, last, node) DLLQ_REMOVE_EX(first, last, node, next, prev)
|
||||
|
||||
// Doubly linked list Stack
|
||||
#define DLLS_PUSH_EX(first, node, next, prev) \
|
||||
do { \
|
||||
assert((node)->next == NULL); \
|
||||
assert((node)->prev == NULL); \
|
||||
(node)->next = (first); \
|
||||
if ((first)) \
|
||||
(first)->prev = (node); \
|
||||
(first) = (node); \
|
||||
} while (0)
|
||||
#define DLLS_PUSH(first, node) DLLS_PUSH_EX(first, node, next, prev)
|
||||
#define DLLS_REMOVE_EX(first, node, next, prev) \
|
||||
do { \
|
||||
if ((node) == (first)) { \
|
||||
(first) = (first)->next; \
|
||||
if ((first)) \
|
||||
(first)->prev = 0; \
|
||||
} else { \
|
||||
(node)->prev->next = (node)->next; \
|
||||
if ((node)->next) \
|
||||
(node)->next->prev = (node)->prev; \
|
||||
} \
|
||||
if (node) { \
|
||||
(node)->prev = 0; \
|
||||
(node)->next = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLLS_REMOVE(first, node) DLLS_REMOVE_EX(first, node, next, prev)
|
||||
#include "core_platform_defines.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include "core_basic.h"
|
||||
#include "core_unicode.h"
|
||||
#include "core_arena.h"
|
||||
#include "core_string.h"
|
||||
#include "core_math.h"
|
||||
#include "core_type_info.h"
|
||||
#include "core_lexer.h"
|
||||
#include "core_log.h"
|
||||
#include "core_intrin.h"
|
||||
#include "core_platform.h"
|
||||
#include "core_hash_table.h"
|
||||
#include "core_ctx.h"
|
||||
297
src/core/core_basic.h
Normal file
297
src/core/core_basic.h
Normal file
@@ -0,0 +1,297 @@
|
||||
typedef uintptr_t usize;
|
||||
typedef uint64_t u64;
|
||||
typedef uint32_t u32;
|
||||
typedef uint16_t u16;
|
||||
typedef uint8_t u8;
|
||||
|
||||
typedef intptr_t isize;
|
||||
typedef int64_t i64;
|
||||
typedef int32_t i32;
|
||||
typedef int16_t i16;
|
||||
typedef int8_t i8;
|
||||
|
||||
typedef int64_t b64;
|
||||
typedef int32_t b32;
|
||||
typedef int16_t b16;
|
||||
typedef int8_t b8;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
#define f32_max FLT_MAX
|
||||
#define f32_min FLT_MIN
|
||||
#define f64_max DBL_MAX
|
||||
#define f64_min DBL_MIN
|
||||
|
||||
#define i8_max INT8_MAX
|
||||
#define i8_min INT8_MIN
|
||||
#define i16_max INT16_MAX
|
||||
#define i16_min INT16_MIN
|
||||
#define i32_max INT32_MAX
|
||||
#define i32_min INT32_MIN
|
||||
#define i64_max INT64_MAX
|
||||
#define i64_min INT64_MIN
|
||||
|
||||
#define u8_max UINT8_MAX
|
||||
#define u8_min 0
|
||||
#define u16_max UINT16_MAX
|
||||
#define u16_min 0
|
||||
#define u32_max UINT32_MAX
|
||||
#define u32_min 0
|
||||
#define u64_max UINT64_MAX
|
||||
#define u64_min 0
|
||||
|
||||
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
|
||||
#define fn
|
||||
#define fn_test
|
||||
#define gb
|
||||
#define locl static
|
||||
|
||||
typedef union convert_f64_u64_t convert_f64_u64_t;
|
||||
union convert_f64_u64_t { f64 f; u64 i; };
|
||||
typedef union convert_f64_i64_t convert_f64_i64_t;
|
||||
union convert_f64_i64_t { f64 f; i64 i; };
|
||||
typedef union convert_f32_u32_t convert_f32_u32_t;
|
||||
union convert_f32_u32_t { f32 f; u32 i; };
|
||||
typedef union convert_f32_i32_t convert_f32_i32_t;
|
||||
union convert_f32_i32_t { f32 f; i32 i; };
|
||||
|
||||
|
||||
#define U64_TO_F64(x) (((convert_f64_u64_t) { .i = (x) }).f)
|
||||
#define U32_TO_F32(x) (((convert_f32_u32_t) { .i = (x) }).f)
|
||||
#define F64_TO_U64(x) (((convert_f64_u64_t) { .f = (x) }).i)
|
||||
#define F32_TO_U32(x) (((convert_f32_u32_t) { .f = (x) }).i)
|
||||
|
||||
#define I64_TO_F64(x) (((convert_f64_i64_t) { .i = (x) }).f)
|
||||
#define I32_TO_F32(x) (((convert_f32_i32_t) { .i = (x) }).f)
|
||||
#define F64_TO_I64(x) (((convert_f64_i64_t) { .f = (x) }).i)
|
||||
#define F32_TO_I32(x) (((convert_f32_i32_t) { .f = (x) }).i)
|
||||
|
||||
#define MIN(x,y) ((x) > (y) ? (y) : (x))
|
||||
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
#define CLAMP_TOP(A,X) MIN(A,X)
|
||||
#define CLAMP_BOT(X,B) MAX(X,B)
|
||||
#define CLAMP(x,a,b) (((x)<(a))?(a):((x)>(b))?(b):(x))
|
||||
|
||||
#define set_bit(x) (1ULL << (x))
|
||||
#define lengthof(x) (sizeof((x))/sizeof((x)[0]))
|
||||
#ifndef offsetof
|
||||
#define offsetof(st, m) ((usize)&(((st *)0)->m))
|
||||
#endif
|
||||
#define expect(x) if (!(x))
|
||||
#define unused(x) (void)(x)
|
||||
|
||||
#define kib(x) (1024ULL * (x##ULL))
|
||||
#define mib(x) (1024ULL * kib(x))
|
||||
#define gib(x) (1024ULL * mib(x))
|
||||
#define thousand(n) ((n)*1000)
|
||||
#define million(n) ((n)*1000000)
|
||||
#define billion(n) ((n)*1000000000)
|
||||
|
||||
#define zero_struct(x) memory_zero((x), sizeof(*(x)))
|
||||
|
||||
|
||||
#define defer_if(begin, cond_end) for (b32 PASTE(_i_, __LINE__) = !!begin; PASTE(_i_, __LINE__); PASTE(_i_, __LINE__) = (cond_end, 0))
|
||||
#define defer_block(begin, end) for (i32 PASTE(_i_, __LINE__) = (begin, 0); !PASTE(_i_, __LINE__); PASTE(_i_, __LINE__) += (end, 1))
|
||||
|
||||
#define stack_t(type, size) struct { type data[size]; i32 len; }
|
||||
#define STACK_CAP(stack) (lengthof((stack).data))
|
||||
#define STACK_EMPTY(stack) ((stack).len == 0)
|
||||
#define STACK_FULL(stack) ((stack).len == STACK_CAP(stack))
|
||||
#define STACK_PUSH(stack, ...) (assert(!STACK_FULL(stack)), (stack).data[(stack).len++] = __VA_ARGS__)
|
||||
#define STACK_POP(stack) (assert(!STACK_EMPTY(stack)), (stack).data[--(stack).len])
|
||||
#define STACK_TOP(stack) (assert(!STACK_EMPTY(stack)), (stack).data[((stack).len-1)])
|
||||
|
||||
#define STRINGIFY_(S) #S
|
||||
#define STRINGIFY(S) STRINGIFY_(S)
|
||||
#define PASTE_(a, b) a##b
|
||||
#define PASTE(a, b) PASTE_(a, b)
|
||||
#define SWAP(t, a, b) do { t PASTE(temp__, __LINE__) = a; a = b; b = PASTE(temp__, __LINE__); } while(0)
|
||||
#define CODE(...) #__VA_ARGS__
|
||||
|
||||
#if PLATFORM_CL || (PLATFORM_CLANG && PLATFORM_WINDOWS)
|
||||
#pragma section(".rdata$", read)
|
||||
#define gb_read_only __declspec(allocate(".rdata$"))
|
||||
#elif PLATFORM_CLANG && PLATFORM_LINUX
|
||||
#define gb_read_only __attribute__((section(".rodata")))
|
||||
#else
|
||||
#define gb_read_only
|
||||
#endif
|
||||
|
||||
#if PLATFORM_CL
|
||||
#define fn_inline __forceinline
|
||||
#elif PLATFORM_CLANG || PLATFORM_GCC
|
||||
#define fn_inline __attribute__((always_inline))
|
||||
#else
|
||||
#define fn_inline
|
||||
#endif
|
||||
|
||||
#ifndef FILE_AND_LINE_GCC_FORMAT
|
||||
#define FILE_AND_LINE __FILE__"("STRINGIFY(__LINE__)")"
|
||||
#else
|
||||
#define FILE_AND_LINE __FILE__":"STRINGIFY(__LINE__)
|
||||
#endif
|
||||
|
||||
#if PLATFORM_CL
|
||||
#define debug__break() __debugbreak()
|
||||
#else
|
||||
#define debug__break() __builtin_trap()
|
||||
#endif
|
||||
#define debug_break() (debug__break(), 0)
|
||||
|
||||
#if PLATFORM_WASM
|
||||
#define gb_thread
|
||||
#elif PLATFORM_GCC | PLATFORM_CLANG
|
||||
#define gb_thread __thread
|
||||
#elif PLATFORM_CL
|
||||
#define gb_thread __declspec(thread)
|
||||
#else
|
||||
#define gb_thread _Thread_local
|
||||
#endif
|
||||
|
||||
#if PLATFORM_CL
|
||||
#pragma warning(disable: 4116)
|
||||
#endif
|
||||
|
||||
// Single linked list Queue
|
||||
#define SLLQ_APPEND_EX(f, l, n, next) \
|
||||
do { \
|
||||
assert((n)->next == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (n); \
|
||||
} else { \
|
||||
(l) = (l)->next = (n); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SLLQ_APPEND(f, l, n) SLLQ_APPEND_EX(f, l, n, next)
|
||||
|
||||
#define SLLQ_PREPEND_EX(f, l, n, next) \
|
||||
do { \
|
||||
assert((n)->next == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (n); \
|
||||
} else { \
|
||||
(n)->next = (f); \
|
||||
(f) = (n); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SLLQ_PREPEND(f, l, n) SLLQ_PREPEND_EX(f, l, n, next)
|
||||
|
||||
#define SLLQ_REMOVE_FIRST_EX(f, l, next) \
|
||||
do { \
|
||||
if ((f) == (l)) { \
|
||||
(f) = (l) = 0; \
|
||||
} else { \
|
||||
(f) = (f)->next; \
|
||||
} \
|
||||
} while (0)
|
||||
#define SLLQ_REMOVE_FIRST(f, l) SLLQ_REMOVE_FIRST_EX(f, l, next)
|
||||
|
||||
// Singly linked list stack
|
||||
#define SLLS_PUSH_EX(stack_base, new_stack_base, next) \
|
||||
do { \
|
||||
(new_stack_base)->next = (stack_base); \
|
||||
(stack_base) = (new_stack_base); \
|
||||
} while (0)
|
||||
#define SLLS_PUSH(stack_base, new_stack_base) \
|
||||
SLLS_PUSH_EX(stack_base, new_stack_base, next)
|
||||
|
||||
#define SLLS_POP(stack_base) ((stack_base) = (stack_base)->next)
|
||||
#define SLLS_POP_AND_STORE(stack_base, out_node) \
|
||||
do { \
|
||||
if (stack_base) { \
|
||||
(out_node) = (stack_base); \
|
||||
(stack_base) = (stack_base)->next; \
|
||||
(out_node)->next = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Doubly linked list Queue
|
||||
#define DLLQ_APPEND_EX(f, l, node, next, prev) \
|
||||
do { \
|
||||
assert((node)->next == NULL); \
|
||||
assert((node)->prev == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (node); \
|
||||
} else { \
|
||||
(l)->next = (node); \
|
||||
(node)->prev = (l); \
|
||||
(l) = (node); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLLQ_APPEND(f, l, node) DLLQ_APPEND_EX(f, l, node, next, prev)
|
||||
|
||||
#define DLLQ_PREPEND_EX(f, l, node, next, prev) \
|
||||
do { \
|
||||
assert((node)->next == NULL); \
|
||||
assert((node)->prev == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (node); \
|
||||
} else { \
|
||||
(node)->next = (f); \
|
||||
(f)->prev = (node); \
|
||||
(f) = (node); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLLQ_PREPEND(f, l, node) DLLQ_PREPEND_EX(f, l, node, next, prev)
|
||||
|
||||
#define DLLQ_CONTAINS(f, l, n, next, prev) for (
|
||||
|
||||
#define DLLQ_REMOVE_EX(first, last, node, next, prev) \
|
||||
do { \
|
||||
if ((first) == (last)) { \
|
||||
assert((node) == (first)); \
|
||||
(first) = (last) = 0; \
|
||||
} else if ((last) == (node)) { \
|
||||
(last) = (last)->prev; \
|
||||
(last)->next = 0; \
|
||||
} else if ((first) == (node)) { \
|
||||
(first) = (first)->next; \
|
||||
(first)->prev = 0; \
|
||||
} else { \
|
||||
(node)->prev->next = (node)->next; \
|
||||
(node)->next->prev = (node)->prev; \
|
||||
} \
|
||||
if (node) { \
|
||||
(node)->prev = 0; \
|
||||
(node)->next = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLLQ_REMOVE(first, last, node) DLLQ_REMOVE_EX(first, last, node, next, prev)
|
||||
|
||||
// Doubly linked list Stack
|
||||
#define DLLS_PUSH_EX(first, node, next, prev) \
|
||||
do { \
|
||||
assert((node)->next == NULL); \
|
||||
assert((node)->prev == NULL); \
|
||||
(node)->next = (first); \
|
||||
if ((first)) \
|
||||
(first)->prev = (node); \
|
||||
(first) = (node); \
|
||||
} while (0)
|
||||
#define DLLS_PUSH(first, node) DLLS_PUSH_EX(first, node, next, prev)
|
||||
#define DLLS_REMOVE_EX(first, node, next, prev) \
|
||||
do { \
|
||||
if ((node) == (first)) { \
|
||||
(first) = (first)->next; \
|
||||
if ((first)) \
|
||||
(first)->prev = 0; \
|
||||
} else { \
|
||||
(node)->prev->next = (node)->next; \
|
||||
if ((node)->next) \
|
||||
(node)->next->prev = (node)->prev; \
|
||||
} \
|
||||
if (node) { \
|
||||
(node)->prev = 0; \
|
||||
(node)->next = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLLS_REMOVE(first, node) DLLS_REMOVE_EX(first, node, next, prev)
|
||||
@@ -110,3 +110,57 @@ fn s8i_t *internf(ht_t *ht, char *str, ...) {
|
||||
S8_FMT(ht->arena, str, string);
|
||||
return intern_string(ht, string);
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// testing
|
||||
|
||||
fn_test void test_hash_table(void) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
{
|
||||
ht_t *ht = ht_create(scratch.arena, 16);
|
||||
|
||||
for (u64 i = 0; i < 128; i += 1) {
|
||||
ht_insert_u64(ht, i, i);
|
||||
ht_node_t *node = ht_search_u64_ex(ht, i);
|
||||
assert(node->kv.value_u64 == i);
|
||||
assert(node->kv.key_u64 == i);
|
||||
}
|
||||
for (u64 i = 0; i < 128; i += 1) {
|
||||
ht_node_t *node = ht_search_u64_ex(ht, i);
|
||||
assert(node->kv.value_u64 == i);
|
||||
assert(node->kv.key_u64 == i);
|
||||
}
|
||||
|
||||
ht_node_t *node = ht_search_u64_ex(ht, 1111);
|
||||
assert(node == NULL);
|
||||
}
|
||||
{
|
||||
ht_t *ht = ht_create(scratch.arena, 16);
|
||||
|
||||
for (i32 i = 0; i < 128; i += 1) {
|
||||
s8_t s = s8_printf(scratch.arena, "%d", i);
|
||||
ht_insert_string(ht, s, s);
|
||||
ht_node_t *node = ht_search_string_ex(ht, s);
|
||||
assert(s8_are_equal(node->kv.value_string, s));
|
||||
assert(s8_are_equal(node->kv.key_string, s));
|
||||
}
|
||||
|
||||
ht_node_t *node = ht_search_string_ex(ht, s8_lit("memes"));
|
||||
assert(node == NULL);
|
||||
}
|
||||
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
|
||||
fn_test void test_intern_table(void) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
ht_t *ht = ht_create(scratch.arena, 4);
|
||||
assert(internf(ht, "asd") == internf(ht, "asd"));
|
||||
assert(internf(ht, "asdf") != internf(ht, "asd"));
|
||||
assert(internf(ht, "asdf") == internf(ht, "asdf"));
|
||||
assert(internf(ht, "123asdf") == internf(ht, "123asdf"));
|
||||
assert(internf(ht, "123asdf") != internf(ht, "133asdf"));
|
||||
assert(internf(ht, "") == internf(ht, ""));
|
||||
assert(internf(ht, "") != internf(ht, "a"));
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#include "core_platform_defines.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include "core.h"
|
||||
#include "core_unicode.h"
|
||||
#include "core_arena.h"
|
||||
#include "core_string.h"
|
||||
#include "core_math.h"
|
||||
#include "core_type_info.h"
|
||||
#include "core_lexer.h"
|
||||
#include "core_log.h"
|
||||
#include "core_intrin.h"
|
||||
#include "core_platform.h"
|
||||
#include "core_hash_table.h"
|
||||
#include "core_ctx.h"
|
||||
@@ -380,6 +380,7 @@ fn sb8_node_t *sb8_create_node(ma_arena_t *ma, s8_t str) {
|
||||
}
|
||||
|
||||
fn sb8_node_t *sb8_append(sb8_t *list, s8_t string) {
|
||||
assert(list->arena != NULL);
|
||||
sb8_node_t *node = sb8_create_node(list->arena, string);
|
||||
SLLQ_APPEND(list->first, list->last, node);
|
||||
return node;
|
||||
@@ -530,4 +531,99 @@ fn fuzzy_pair_t *fuzzy_rate_array(ma_arena_t *arena, s8_t needle, s8_t *array, i
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
}
|
||||
|
||||
fn_test void test_s8(void) {
|
||||
ma_arena_t *arena = ma_create(ma_default_reserve_size);
|
||||
|
||||
{
|
||||
ma_temp_t temp = ma_begin_temp(arena);
|
||||
sb8_t *sb = &(sb8_t){arena};
|
||||
|
||||
s8_t memes = s8_lit("memes");
|
||||
sb8_printf(sb, "%S", memes);
|
||||
assert(sb->first == sb->last);
|
||||
assert(sb->first->len == 5);
|
||||
assert(s8_are_equal(sb->first->string, memes));
|
||||
|
||||
sb8_printf(sb, "%S", s8_lit("things are going fine"));
|
||||
s8_t string = sb8_merge(temp.arena, sb);
|
||||
assert(s8_are_equal(string, s8_lit("memesthings are going fine")));
|
||||
|
||||
ma_end_temp(temp);
|
||||
}
|
||||
|
||||
{
|
||||
s8_t str = s8_lit("thing|another|");
|
||||
sb8_t sb = s8_split(arena, str, s8_lit("|"), s8_split_none);
|
||||
|
||||
assert(s8_are_equal(sb.first->string, s8_lit("thing")));
|
||||
assert(s8_are_equal(sb.first->next->string, s8_lit("another")));
|
||||
assert(sb.first->next->next == NULL);
|
||||
}
|
||||
|
||||
{
|
||||
s8_t str = s8_lit("thing|another|");
|
||||
sb8_t sb = s8_split(arena, str, s8_lit("|"), s8_split_inclusive);
|
||||
|
||||
assert(s8_are_equal(sb.first->string, s8_lit("thing")));
|
||||
assert(s8_are_equal(sb.first->next->string, s8_lit("|")));
|
||||
assert(s8_are_equal(sb.first->next->next->string, s8_lit("another")));
|
||||
assert(s8_are_equal(sb.first->next->next->next->string, s8_lit("|")));
|
||||
assert(sb.first->next->next->next->next == NULL);
|
||||
}
|
||||
|
||||
{
|
||||
s8_t str = s8_lit("aabaaBaa");
|
||||
sb8_t sb = s8_split(arena, str, s8_lit("b"), s8_split_inclusive | s8_split_ignore_case);
|
||||
|
||||
assert(s8_are_equal(sb.first->string, s8_lit("aa")));
|
||||
assert(s8_are_equal(sb.first->next->string, s8_lit("b")));
|
||||
assert(s8_are_equal(sb.first->next->next->string, s8_lit("aa")));
|
||||
assert(s8_are_equal(sb.first->next->next->next->string, s8_lit("B")));
|
||||
assert(s8_are_equal(sb.first->next->next->next->next->string, s8_lit("aa")));
|
||||
assert(sb.first->next->next->next->next->next == NULL);
|
||||
}
|
||||
|
||||
{
|
||||
s8_t str = s8_lit("aabaaBaa");
|
||||
sb8_t sb = s8_split(arena, str, s8_lit("b"), s8_split_inclusive);
|
||||
|
||||
assert(s8_are_equal(sb.first->string, s8_lit("aa")));
|
||||
assert(s8_are_equal(sb.first->next->string, s8_lit("b")));
|
||||
assert(s8_are_equal(sb.first->next->next->string, s8_lit("aaBaa")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s = s8_lit("0123456789");
|
||||
assert(s8_are_equal(s8_slice(s, 0, 4), s8_lit("0123")));
|
||||
assert(s8_are_equal(s8_slice(s, -2, -1), s8_lit("89")));
|
||||
assert(s8_are_equal(s8_slice(s, -2, 10), s8_lit("89")));
|
||||
assert(s8_are_equal(s8_slice(s, 8, 10), s8_lit("89")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s = s8_lit(" a \n");
|
||||
s = s8_trim(s);
|
||||
assert(s8_are_equal(s, s8_lit("a")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s = s8_lit("C:/memes/the_thing.c");
|
||||
s8_t ss = s8_get_name_no_ext(s);
|
||||
assert(s8_are_equal(ss, s8_lit("the_thing")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s = s8_printf(arena, "%d%Sv%s", 32, s8_lit("|"), ">");
|
||||
assert(s8_are_equal(s, s8_lit("32|v>")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s0 = s8_lit("0123456789");
|
||||
s8_t s1 = s8_cut_start(&s0, 2);
|
||||
assert(s8_are_equal(s0, s8_lit("23456789")));
|
||||
assert(s8_are_equal(s1, s8_lit("01")));
|
||||
}
|
||||
ma_destroy(arena);
|
||||
}
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
#include "core/core_inc.h"
|
||||
#include "core/core_inc.c"
|
||||
|
||||
void test_s8(void) {
|
||||
ma_arena_t *arena = ma_create(ma_default_reserve_size);
|
||||
|
||||
{
|
||||
ma_temp_t temp = ma_begin_temp(arena);
|
||||
sb8_t *sb = &(sb8_t){arena};
|
||||
|
||||
s8_t memes = s8_lit("memes");
|
||||
sb8_printf(sb, "%S", memes);
|
||||
assert(sb->first == sb->last);
|
||||
assert(sb->first->len == 5);
|
||||
assert(s8_are_equal(sb->first->string, memes));
|
||||
|
||||
sb8_printf(sb, "%S", s8_lit("things are going fine"));
|
||||
s8_t string = sb8_merge(temp.arena, sb);
|
||||
assert(s8_are_equal(string, s8_lit("memesthings are going fine")));
|
||||
|
||||
ma_end_temp(temp);
|
||||
}
|
||||
|
||||
{
|
||||
s8_t str = s8_lit("thing|another|");
|
||||
sb8_t sb = s8_split(arena, str, s8_lit("|"), s8_split_none);
|
||||
|
||||
assert(s8_are_equal(sb.first->string, s8_lit("thing")));
|
||||
assert(s8_are_equal(sb.first->next->string, s8_lit("another")));
|
||||
assert(sb.first->next->next == NULL);
|
||||
}
|
||||
|
||||
{
|
||||
s8_t str = s8_lit("thing|another|");
|
||||
sb8_t sb = s8_split(arena, str, s8_lit("|"), s8_split_inclusive);
|
||||
|
||||
assert(s8_are_equal(sb.first->string, s8_lit("thing")));
|
||||
assert(s8_are_equal(sb.first->next->string, s8_lit("|")));
|
||||
assert(s8_are_equal(sb.first->next->next->string, s8_lit("another")));
|
||||
assert(s8_are_equal(sb.first->next->next->next->string, s8_lit("|")));
|
||||
assert(sb.first->next->next->next->next == NULL);
|
||||
}
|
||||
|
||||
{
|
||||
s8_t str = s8_lit("aabaaBaa");
|
||||
sb8_t sb = s8_split(arena, str, s8_lit("b"), s8_split_inclusive | s8_split_ignore_case);
|
||||
|
||||
assert(s8_are_equal(sb.first->string, s8_lit("aa")));
|
||||
assert(s8_are_equal(sb.first->next->string, s8_lit("b")));
|
||||
assert(s8_are_equal(sb.first->next->next->string, s8_lit("aa")));
|
||||
assert(s8_are_equal(sb.first->next->next->next->string, s8_lit("B")));
|
||||
assert(s8_are_equal(sb.first->next->next->next->next->string, s8_lit("aa")));
|
||||
assert(sb.first->next->next->next->next->next == NULL);
|
||||
}
|
||||
|
||||
{
|
||||
s8_t str = s8_lit("aabaaBaa");
|
||||
sb8_t sb = s8_split(arena, str, s8_lit("b"), s8_split_inclusive);
|
||||
|
||||
assert(s8_are_equal(sb.first->string, s8_lit("aa")));
|
||||
assert(s8_are_equal(sb.first->next->string, s8_lit("b")));
|
||||
assert(s8_are_equal(sb.first->next->next->string, s8_lit("aaBaa")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s = s8_lit("0123456789");
|
||||
assert(s8_are_equal(s8_slice(s, 0, 4), s8_lit("0123")));
|
||||
assert(s8_are_equal(s8_slice(s, -2, -1), s8_lit("89")));
|
||||
assert(s8_are_equal(s8_slice(s, -2, 10), s8_lit("89")));
|
||||
assert(s8_are_equal(s8_slice(s, 8, 10), s8_lit("89")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s = s8_lit(" a \n");
|
||||
s = s8_trim(s);
|
||||
assert(s8_are_equal(s, s8_lit("a")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s = s8_lit("C:/memes/the_thing.c");
|
||||
s8_t ss = s8_get_name_no_ext(s);
|
||||
assert(s8_are_equal(ss, s8_lit("the_thing")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s = s8_printf(arena, "%d%Sv%s", 32, s8_lit("|"), ">");
|
||||
assert(s8_are_equal(s, s8_lit("32|v>")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s0 = s8_lit("0123456789");
|
||||
s8_t s1 = s8_cut_start(&s0, 2);
|
||||
assert(s8_are_equal(s0, s8_lit("23456789")));
|
||||
assert(s8_are_equal(s1, s8_lit("01")));
|
||||
}
|
||||
ma_destroy(arena);
|
||||
}
|
||||
|
||||
void test_hash_table(void) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
{
|
||||
ht_t *ht = ht_create(scratch.arena, 16);
|
||||
|
||||
for (u64 i = 0; i < 128; i += 1) {
|
||||
ht_insert_u64(ht, i, i);
|
||||
ht_node_t *node = ht_search_u64_ex(ht, i);
|
||||
assert(node->kv.value_u64 == i);
|
||||
assert(node->kv.key_u64 == i);
|
||||
}
|
||||
for (u64 i = 0; i < 128; i += 1) {
|
||||
ht_node_t *node = ht_search_u64_ex(ht, i);
|
||||
assert(node->kv.value_u64 == i);
|
||||
assert(node->kv.key_u64 == i);
|
||||
}
|
||||
|
||||
ht_node_t *node = ht_search_u64_ex(ht, 1111);
|
||||
assert(node == NULL);
|
||||
}
|
||||
{
|
||||
ht_t *ht = ht_create(scratch.arena, 16);
|
||||
|
||||
for (i32 i = 0; i < 128; i += 1) {
|
||||
s8_t s = s8_printf(scratch.arena, "%d", i);
|
||||
ht_insert_string(ht, s, s);
|
||||
ht_node_t *node = ht_search_string_ex(ht, s);
|
||||
assert(s8_are_equal(node->kv.value_string, s));
|
||||
assert(s8_are_equal(node->kv.key_string, s));
|
||||
}
|
||||
|
||||
ht_node_t *node = ht_search_string_ex(ht, s8_lit("memes"));
|
||||
assert(node == NULL);
|
||||
}
|
||||
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
|
||||
void test_intern_table(void) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
ht_t *ht = ht_create(scratch.arena, 4);
|
||||
assert(internf(ht, "asd") == internf(ht, "asd"));
|
||||
assert(internf(ht, "asdf") != internf(ht, "asd"));
|
||||
assert(internf(ht, "asdf") == internf(ht, "asdf"));
|
||||
assert(internf(ht, "123asdf") == internf(ht, "123asdf"));
|
||||
assert(internf(ht, "123asdf") != internf(ht, "133asdf"));
|
||||
assert(internf(ht, "") == internf(ht, ""));
|
||||
assert(internf(ht, "") != internf(ht, "a"));
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
core_init();
|
||||
printf("PLATFORM_WASM = %d\n", PLATFORM_WASM);
|
||||
printf("PLATFORM_WINDOWS = %d\n", PLATFORM_WINDOWS);
|
||||
printf("PLATFORM_LINUX = %d\n", PLATFORM_LINUX);
|
||||
printf("PLATFORM_POSIX = %d\n", PLATFORM_POSIX);
|
||||
printf("PLATFORM_MAC_OS = %d\n", PLATFORM_MAC_OS);
|
||||
printf("PLATFORM_CLANG = %d\n", PLATFORM_CLANG);
|
||||
printf("PLATFORM_GCC = %d\n", PLATFORM_GCC);
|
||||
printf("PLATFORM_CL = %d\n", PLATFORM_CL);
|
||||
printf("PLATFORM_TCC = %d\n", PLATFORM_TCC);
|
||||
|
||||
|
||||
test_s8();
|
||||
test_hash_table();
|
||||
test_intern_table();
|
||||
|
||||
printf("all done!\n");
|
||||
}
|
||||
@@ -116,10 +116,24 @@ fn s8_t mt_serial_to_cbyte_array(ma_arena_t *arena, s8_t file, s8_t var_name) {
|
||||
return result;
|
||||
}
|
||||
|
||||
#define mt_cpath(arena) mt_gen_filename(arena, s8_lit(__FILE__), s8_lit("c"))
|
||||
#define mt_hpath(arena) mt_gen_filename(arena, s8_lit(__FILE__), s8_lit("h"))
|
||||
#define mt_cpath(arena) mt_gen_filename(arena, S8_FILE, s8_lit("c"))
|
||||
#define mt_hpath(arena) mt_gen_filename(arena, S8_FILE, s8_lit("h"))
|
||||
fn s8_t mt_gen_filename(ma_arena_t *arena, s8_t lit_file, s8_t ext) {
|
||||
s8_t file_noext = s8_chop_last_period(s8_chop_last_period(lit_file));
|
||||
s8_t file = s8_printf(arena, "%S.gen.%S", file_noext, ext);
|
||||
return file;
|
||||
}
|
||||
|
||||
#define mt_main_path(arena) mt__main_path(arena, S8_FILE)
|
||||
fn s8_t mt__main_path(ma_arena_t *arena, s8_t file) {
|
||||
s8_t file_noext = s8_chop_last_period(s8_chop_last_period(file));
|
||||
s8_t path = s8_printf(arena, "%S_main.c", file_noext);
|
||||
return path;
|
||||
}
|
||||
|
||||
fn sb8_t *mt_get_include_paths(ma_arena_t *arena) {
|
||||
sb8_t *result = ma_push_type(arena, sb8_t);
|
||||
result->arena = arena;
|
||||
sb8_append(result, OS_GetAbsolutePath(&Perm, s8_lit("../src")));
|
||||
return result;
|
||||
}
|
||||
26
src/os/os.c
26
src/os/os.c
@@ -4,4 +4,28 @@
|
||||
#include "os_win32.c"
|
||||
#else
|
||||
#include "os_unix.c"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
fn_test void os_test(void) {
|
||||
os_date_t local_time = os_local_time();
|
||||
os_date_t universal_time = os_universal_time();
|
||||
debugf("local_time = %S | universal_time = %S", os_format_date(tcx->temp, local_time), os_format_date(tcx->temp, universal_time));
|
||||
|
||||
s8_t exe_dir = os_exe_dir(tcx->temp);
|
||||
assert(exe_dir.str[exe_dir.len - 1] == '/');
|
||||
s8_t exe = os_exe(tcx->temp);
|
||||
s8_t cwd = os_cwd(tcx->temp);
|
||||
assert(exe_dir.str[cwd.len - 1] == '/');
|
||||
assert(os_is_dir(exe_dir));
|
||||
assert(os_is_file(exe));
|
||||
assert(os_is_dir(cwd));
|
||||
assert(os_exists(exe_dir));
|
||||
assert(os_exists(exe));
|
||||
assert(os_exists(cwd));
|
||||
assert(os_is_abs(exe_dir));
|
||||
assert(os_is_abs(exe));
|
||||
assert(os_is_abs(cwd));
|
||||
assert(!os_is_abs(s8_lit("../path/")));
|
||||
debugf("%S %S %S", exe_dir, exe, cwd);
|
||||
}
|
||||
|
||||
97
src/os/os.h
97
src/os/os.h
@@ -9,42 +9,73 @@ struct os_date_t {
|
||||
u16 year;
|
||||
};
|
||||
|
||||
fn os_date_t os_local_time_now(void);
|
||||
fn os_date_t os_universal_time_now(void);
|
||||
fn f64 os_milliseconds_now(void);
|
||||
typedef struct os_iter_t os_iter_t;
|
||||
struct os_iter_t {
|
||||
s8_t abs;
|
||||
s8_t rel;
|
||||
s8_t name;
|
||||
b8 is_directory;
|
||||
b8 is_valid;
|
||||
|
||||
#if 0
|
||||
fn u64 os_microseconds_now();
|
||||
fn f64 os_seconds_now();
|
||||
fn u32 os_unix_time_now();
|
||||
s8_t path;
|
||||
ma_arena_t *arena;
|
||||
|
||||
fn os_date_t os_local_time_to_universal_time();
|
||||
fn os_date_t os_universal_time_to_local_time();
|
||||
union {
|
||||
struct w32_file_iter_t *w32;
|
||||
void *platform;
|
||||
};
|
||||
};
|
||||
|
||||
fn void os_sleep_milliseconds();
|
||||
typedef enum {
|
||||
os_mkdir_success,
|
||||
os_mkdir_file_exists,
|
||||
os_mkdir_path_not_found,
|
||||
os_mkdir_other_error,
|
||||
} os_mkdir_t;
|
||||
|
||||
typedef enum {
|
||||
os_write_success,
|
||||
os_write_path_not_found,
|
||||
os_write_other_error,
|
||||
} os_write_t;
|
||||
|
||||
fn os_date_t os_local_time(void);
|
||||
fn os_date_t os_universal_time(void);
|
||||
fn s8_t os_format_date(ma_arena_t *arena, os_date_t date);
|
||||
fn f64 os_seconds(void);
|
||||
fn f64 os_milliseconds(void);
|
||||
|
||||
fn b32 os_copy(s8_t from, s8_t to, b32 overwrite);
|
||||
fn b32 os_delete(s8_t path);
|
||||
fn os_mkdir_t os_mkdir(s8_t path);
|
||||
fn os_write_t os_write(s8_t path, s8_t content);
|
||||
|
||||
fn void os_advance(os_iter_t *it);
|
||||
fn os_iter_t *os_iter(ma_arena_t *arena, s8_t path);
|
||||
|
||||
fn i64 os_mod_time(s8_t file);
|
||||
fn s8_t os_abs(ma_arena_t *arena, s8_t rel);
|
||||
fn s8_t os_exe(ma_arena_t *arena);
|
||||
fn s8_t os_exe_dir(ma_arena_t *arena);
|
||||
fn b32 os_is_dir(s8_t path);
|
||||
fn b32 os_is_file(s8_t path);
|
||||
fn b32 os_is_abs(s8_t path);
|
||||
fn b32 os_exists(s8_t path);
|
||||
|
||||
fn s8_t os_cwd(ma_arena_t *arena);
|
||||
fn void os_set_cwd(s8_t new_cwd);
|
||||
|
||||
|
||||
fn s8_t os_list_files(arena, path, recursive);
|
||||
fn os_file_iter_t os_iterate_files();
|
||||
fn void os_advance()
|
||||
fn b32 os_is_valid();
|
||||
typedef i32 os_thread_fn_t(void *user_data);
|
||||
typedef struct os_thread_t os_thread_t;
|
||||
struct os_thread_t {
|
||||
b32 exited;
|
||||
i32 exit_code;
|
||||
union {
|
||||
struct w32_thread_t *w32;
|
||||
void *ptr;
|
||||
};
|
||||
};
|
||||
|
||||
fn s8_t os_read_file(ma_arena_t *arena, s8_t path);
|
||||
fn void os_write_file(s8_t path, s8_t content);
|
||||
fn void os_make_dir(s8_t path);
|
||||
fn os_result_t os_copy_file(s8_t from, s8_t to, b32 overwrite);
|
||||
fn os_result_t os_delete_file(s8_t path);
|
||||
fn i64 os_get_file_mod_time(s8_t path);
|
||||
|
||||
fn b32 os_path_exists(s8_t path);
|
||||
fn b32 os_path_is_dir(s8_t path);
|
||||
fn b32 os_path_is_file(s8_t path);
|
||||
fn b32 os_path_is_abs(s8_t path);
|
||||
fn b32 os_path_is_rel(s8_t path);
|
||||
fn s8_t os_path_to_abs(ma_arena_t *arena, s8_t path);
|
||||
|
||||
fn s8_t os_path_exe(ma_arena_t *arena);
|
||||
fn s8_t os_path_exe_dir(ma_arena_t *arena);
|
||||
fn s8_t os_path_cwd(ma_arena_t *arena);
|
||||
fn void os_path_set_cwd(s8_t path);
|
||||
#endif
|
||||
fn os_thread_t os_thread_create(ma_arena_t *arena, os_thread_fn_t *func, void *user_data);
|
||||
fn i32 os_thread_wait_for_exit(os_thread_t *thread);
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
fn_wasm_import void wasm_local_time_now(void *buff, i32 size);
|
||||
fn_wasm_import void wasm_universal_time_now(void *buff, i32 size);
|
||||
fn_wasm_import f64 wasm_milliseconds_now(void);
|
||||
|
||||
fn os_date_t os_local_time_now(void) {
|
||||
os_date_t result = {0};
|
||||
wasm_local_time_now(&result, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
fn os_date_t os_universal_time_now(void) {
|
||||
os_date_t result = {0};
|
||||
wasm_universal_time_now(&result, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
fn f64 os_milliseconds_now(void) {
|
||||
return wasm_milliseconds_now();
|
||||
}
|
||||
|
||||
@@ -1,18 +1,39 @@
|
||||
fn os_date_t os_local_time_now(void) {
|
||||
os_date_t result = {0};
|
||||
///////////////////////////////
|
||||
// time
|
||||
fn os_date_t os_local_time(void) {
|
||||
SYSTEMTIME lt;
|
||||
GetLocalTime(<);
|
||||
result.ms = lt.wMilliseconds;
|
||||
result.sec = lt.wSecond;
|
||||
result.min = lt.wMinute;
|
||||
result.hour = lt.wHour;
|
||||
result.day = lt.wDay;
|
||||
result.month = lt.wMonth;
|
||||
result.year = lt.wYear;
|
||||
os_date_t result = {0};
|
||||
result.ms = lt.wMilliseconds;
|
||||
result.sec = lt.wSecond;
|
||||
result.min = lt.wMinute;
|
||||
result.hour = lt.wHour;
|
||||
result.day = lt.wDay;
|
||||
result.month = lt.wMonth;
|
||||
result.year = lt.wYear;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn f64 os_seconds_now(void) {
|
||||
fn os_date_t os_universal_time(void) {
|
||||
SYSTEMTIME lt;
|
||||
GetSystemTime(<);
|
||||
os_date_t result = {0};
|
||||
result.ms = lt.wMilliseconds;
|
||||
result.sec = lt.wSecond;
|
||||
result.min = lt.wMinute;
|
||||
result.hour = lt.wHour;
|
||||
result.day = lt.wDay;
|
||||
result.month = lt.wMonth;
|
||||
result.year = lt.wYear;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t os_format_date(ma_arena_t *arena, os_date_t date) {
|
||||
s8_t result = s8_printf(arena, "%04u-%02u-%02u %02u:%02u:%02u.%03u", date.year, date.month, date.day, date.hour, date.min, date.sec, date.ms);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn f64 os_seconds(void) {
|
||||
static int64_t counts_per_second;
|
||||
if (counts_per_second == 0) {
|
||||
LARGE_INTEGER freq;
|
||||
@@ -26,9 +47,297 @@ fn f64 os_seconds_now(void) {
|
||||
return result;
|
||||
}
|
||||
|
||||
fn f64 os_get_milliseconds(void) {
|
||||
f64 secs = os_seconds_now();
|
||||
fn f64 os_milliseconds(void) {
|
||||
f64 secs = os_seconds();
|
||||
f64 result = secs * 1000;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void os_sleep(u32 milliseconds) {
|
||||
Sleep(milliseconds);
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// files
|
||||
fn b32 os_copy(s8_t from, s8_t to, b32 overwrite) {
|
||||
BOOL fail_if_exists = true;
|
||||
if (overwrite) fail_if_exists = false;
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s16_t from16 = s16_from_s8(scratch.arena, from);
|
||||
s16_t to16 = s16_from_s8(scratch.arena, to);
|
||||
BOOL success = CopyFileW(from16.str, to16.str, fail_if_exists);
|
||||
ma_end_scratch(scratch);
|
||||
return success ? true : false;
|
||||
}
|
||||
|
||||
fn b32 os_delete(s8_t path) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s16_t path16 = s16_from_s8(scratch.arena, path);
|
||||
BOOL success = DeleteFileW(path16.str);
|
||||
ma_end_scratch(scratch);
|
||||
return success ? true : false;
|
||||
}
|
||||
|
||||
fn os_mkdir_t os_mkdir(s8_t path) {
|
||||
os_mkdir_t result = os_mkdir_success;
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s16_t path16 = s16_from_s8(scratch.arena, path);
|
||||
BOOL success = CreateDirectoryW(path16.str, NULL);
|
||||
if (success == 0) {
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_ALREADY_EXISTS) result = os_mkdir_file_exists;
|
||||
else if (error == ERROR_PATH_NOT_FOUND) result = os_mkdir_path_not_found;
|
||||
else result = os_mkdir_other_error;
|
||||
}
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn os_write_t os_write(s8_t path, s8_t content) {
|
||||
os_write_t result = os_write_other_error;
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s16_t path16 = s16_from_s8(scratch.arena, path);
|
||||
HANDLE handle = CreateFileW(path16.str, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
assert(content.len == (DWORD)content.len);
|
||||
DWORD bytes_written = 0;
|
||||
BOOL error = WriteFile(handle, content.str, (DWORD)content.len, &bytes_written, NULL);
|
||||
if (error == TRUE) {
|
||||
if (bytes_written == content.len) {
|
||||
result = os_write_success;
|
||||
}
|
||||
}
|
||||
CloseHandle(handle);
|
||||
} else result = os_write_path_not_found;
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct w32_file_iter_t w32_file_iter_t;
|
||||
struct w32_file_iter_t {
|
||||
HANDLE handle;
|
||||
WIN32_FIND_DATAW data;
|
||||
};
|
||||
|
||||
fn void os_advance(os_iter_t *it) {
|
||||
while (FindNextFileW(it->w32->handle, &it->w32->data) != 0) {
|
||||
WIN32_FIND_DATAW *data = &it->w32->data;
|
||||
|
||||
// Skip '.' and '..'
|
||||
if (data->cFileName[0] == '.' && data->cFileName[1] == '.' && data->cFileName[2] == 0) continue;
|
||||
if (data->cFileName[0] == '.' && data->cFileName[1] == 0) continue;
|
||||
|
||||
it->is_directory = data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
it->name = s8_from_s16(it->arena, s16(data->cFileName, wstr_len(data->cFileName)));
|
||||
char *is_dir = it->is_directory ? "/" : "";
|
||||
char *separator = it->path.str[it->path.len - 1] == '/' ? "" : "/";
|
||||
it->rel = s8_printf(it->arena, "%S%s%S%s", it->path, separator, it->name, is_dir);
|
||||
it->abs = os_abs(it->arena, it->rel);
|
||||
it->is_valid = true;
|
||||
|
||||
if (it->is_directory) {
|
||||
assert(it->rel.str[it->rel.len - 1] == '/');
|
||||
assert(it->abs.str[it->abs.len - 1] == '/');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
it->is_valid = false;
|
||||
DWORD error = GetLastError();
|
||||
assert(error == ERROR_NO_MORE_FILES);
|
||||
FindClose(it->w32->handle);
|
||||
}
|
||||
|
||||
fn os_iter_t *os_iter(ma_arena_t *arena, s8_t path) {
|
||||
os_iter_t *it = ma_push_type(arena, os_iter_t);
|
||||
it->w32 = ma_push_type(arena, w32_file_iter_t);
|
||||
it->arena = arena;
|
||||
it->path = path;
|
||||
it->is_valid = true;
|
||||
|
||||
ma_temp_t scratch = ma_begin_scratch1(arena);
|
||||
s8_t mod_path = s8_printf(scratch.arena, "%S\\*", path);
|
||||
s16_t mod_path16 = s16_from_s8(scratch.arena, mod_path);
|
||||
|
||||
it->w32->handle = FindFirstFileW(mod_path16.str, &it->w32->data);
|
||||
if (it->w32->handle == INVALID_HANDLE_VALUE) {
|
||||
it->is_valid = false;
|
||||
}
|
||||
|
||||
if (it->is_valid) {
|
||||
assert(it->w32->data.cFileName[0] == '.' && it->w32->data.cFileName[1] == 0);
|
||||
os_advance(it);
|
||||
}
|
||||
|
||||
ma_end_scratch(scratch);
|
||||
return it;
|
||||
}
|
||||
|
||||
fn i64 os_mod_time(s8_t file) {
|
||||
WIN32_FIND_DATAW data;
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s16_t wpath = s16_from_s8(scratch.arena, file);
|
||||
HANDLE handle = FindFirstFileW(wpath.str, &data);
|
||||
i64 result = -1;
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
FindClose(handle);
|
||||
FILETIME time = data.ftLastWriteTime;
|
||||
result = (i64)time.dwHighDateTime << 32 | time.dwLowDateTime;
|
||||
}
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t os_abs(ma_arena_t *arena, s8_t rel) {
|
||||
const int buffer_size = 2048;
|
||||
ma_temp_t scratch = ma_begin_scratch1(arena);
|
||||
s16_t rel16 = s16_from_s8(scratch.arena, rel);
|
||||
wchar_t *buffer = ma_push_array(scratch.arena, wchar_t, buffer_size);
|
||||
DWORD written = GetFullPathNameW(rel16.str, buffer_size, buffer, 0);
|
||||
assert(written != 0);
|
||||
assert((i64)written < (i64)buffer_size);
|
||||
s8_t result = s8_from_s16(arena, s16(buffer, written));
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t os_exe(ma_arena_t *arena) {
|
||||
const int buffer_size = 2048;
|
||||
ma_temp_t scratch = ma_begin_scratch1(arena);
|
||||
wchar_t *buffer = ma_push_array(scratch.arena, wchar_t, buffer_size);
|
||||
DWORD wsize = GetModuleFileNameW(0, buffer, buffer_size);
|
||||
assert(wsize != 0);
|
||||
s8_t result = s8_from_s16(arena, s16(buffer, wsize));
|
||||
s8_normalize_path_unsafe(result);
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t os_exe_dir(ma_arena_t *arena) {
|
||||
ma_temp_t scratch = ma_begin_scratch1(arena);
|
||||
s8_t exe = os_exe(scratch.arena);
|
||||
s8_t path = s8_chop_last_slash(exe);
|
||||
s8_t result = s8_printf(arena, "%S/", path);
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 os_is_dir(s8_t path) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s16_t path16 = s16_from_s8(scratch.arena, path);
|
||||
DWORD dwAttrib = GetFileAttributesW(path16.str);
|
||||
ma_end_scratch(scratch);
|
||||
return dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
fn b32 os_is_file(s8_t path) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s16_t path16 = s16_from_s8(scratch.arena, path);
|
||||
DWORD dwAttrib = GetFileAttributesW(path16.str);
|
||||
ma_end_scratch(scratch);
|
||||
b32 is_file = (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||
return dwAttrib != INVALID_FILE_ATTRIBUTES && is_file;
|
||||
}
|
||||
|
||||
fn b32 os_is_abs(s8_t path) {
|
||||
b32 result = path.len > 3 && char_is_alphabetic(path.str[0]) && path.str[1] == ':' && path.str[2] == '/';
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 os_exists(s8_t path) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s16_t path16 = s16_from_s8(scratch.arena, path);
|
||||
DWORD attribs = GetFileAttributesW(path16.str);
|
||||
ma_end_scratch(scratch);
|
||||
return attribs == INVALID_FILE_ATTRIBUTES ? false : true;
|
||||
}
|
||||
|
||||
fn s8_t os_cwd(ma_arena_t *arena) {
|
||||
ma_temp_t scratch = ma_begin_scratch1(arena);
|
||||
const u32 buffer_size = 1024;
|
||||
wchar_t *buffer = ma_push_array(scratch.arena, wchar_t, buffer_size);
|
||||
DWORD wsize = GetCurrentDirectoryW(buffer_size, buffer);
|
||||
assert(wsize != 0);
|
||||
assert(wsize <= buffer_size);
|
||||
s8_t path = s8_from_s16(scratch.arena, s16(buffer, wsize));
|
||||
s8_normalize_path_unsafe(path);
|
||||
s8_t result = s8_printf(arena, "%S/", path);
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void os_set_cwd(s8_t path) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s16_t path16 = s16_from_s8(scratch.arena, path);
|
||||
SetCurrentDirectoryW(path16.str);
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// threading
|
||||
|
||||
typedef struct w32_thread_t w32_thread_t;
|
||||
struct w32_thread_t {
|
||||
HANDLE handle;
|
||||
DWORD id;
|
||||
};
|
||||
|
||||
fn os_thread_t os_thread_create(ma_arena_t *arena, os_thread_fn_t *func, void *user_data) {
|
||||
assert(func);
|
||||
|
||||
LPSECURITY_ATTRIBUTES security_attribs = NULL;
|
||||
SIZE_T stack_size = 0;
|
||||
DWORD creation_flags = 0;
|
||||
DWORD thread_id = 0;
|
||||
HANDLE thread_handle = CreateThread(security_attribs, stack_size, func, user_data, creation_flags, &thread_id);
|
||||
if (thread_handle == NULL) {
|
||||
debugf(__FUNCTION__"CreatedThread failed: %d", GetLastError());
|
||||
return (os_thread_t){.exited = true};
|
||||
}
|
||||
|
||||
os_thread_t result = {0};
|
||||
result.w32 = ma_push_type(arena, w32_thread_t);
|
||||
result.w32->handle = thread_handle;
|
||||
result.w32->id = thread_id;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn i32 os_join(os_thread_t *thread) {
|
||||
DWORD return_value_indicates_event = WaitForSingleObject(thread->w32->handle, INFINITE);
|
||||
if (return_value_indicates_event != WAIT_OBJECT_0) {
|
||||
debugf(__FUNCTION__".WaitForSingleObject failed: %d", GetLastError());
|
||||
}
|
||||
|
||||
DWORD exit_code = 0;
|
||||
BOOL if_fails_then_zero = GetExitCodeThread(thread->w32->handle, &exit_code);
|
||||
if (if_fails_then_zero == 0) {
|
||||
debugf(__FUNCTION__".GetExitCodeThread failed: %d", GetLastError());
|
||||
} else {
|
||||
thread->exit_code = exit_code;
|
||||
}
|
||||
|
||||
CloseHandle(thread->w32->handle);
|
||||
thread->exited = true;
|
||||
return thread->exit_code;
|
||||
}
|
||||
|
||||
// @todo:
|
||||
// This will probably create 16 arenas or more XD
|
||||
// fn i32 os__thread_log(void *data) {
|
||||
// core_init();
|
||||
// debugf("testing");
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// fn void os_test_threads(void) {
|
||||
// os_thread_t threads[16];
|
||||
// ma_temp_t scratch = ma_begin_scratch();
|
||||
// for (int i = 0; i < lengthof(threads); i += 1) {
|
||||
// threads[i] = os_thread_create(scratch.arena, os__thread_log, NULL);
|
||||
// }
|
||||
// for (int i = 0; i < lengthof(threads); i += 1) {
|
||||
// os_join(&threads[i]);
|
||||
// }
|
||||
// ma_end_scratch(scratch);
|
||||
// }
|
||||
@@ -1,129 +1,30 @@
|
||||
fn rn_cmd_t *rn_get_cmd(rn_cmd_kind_t kind) {
|
||||
b32 alloc_new = false;
|
||||
if (rn->last_cmd == NULL) {
|
||||
alloc_new = true;
|
||||
} else if (rn->last_cmd->kind != kind) {
|
||||
alloc_new = true;
|
||||
}
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "render.h"
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#define STBTT_ifloor(x) ((int)f64_floor(x))
|
||||
#define STBTT_iceil(x) ((int)f64_ceil(x))
|
||||
#define STBTT_sqrt(x) (f64_sqrt(x))
|
||||
#define STBTT_pow(x,y) (f64_pow(x,y))
|
||||
#define STBTT_fmod(x,y) (f64_mod(x,y))
|
||||
#define STBTT_cos(x) (f64_cos(x))
|
||||
#define STBTT_acos(x) (f64_acos(x))
|
||||
#define STBTT_fabs(x) (f64_abs(x))
|
||||
#define STBTT_assert(x) (assert(x))
|
||||
#define STBTT_malloc(x,u) (ma_push_size(tcx->temp, x))
|
||||
#define STBTT_free(x,u)
|
||||
#define STBTT_strlen(x) (str_len(x))
|
||||
#define STBTT_memcpy memory_copy
|
||||
#define STBTT_memset memory_set
|
||||
#include "stb_truetype.h"
|
||||
|
||||
rn_cmd_t *result = rn->last_cmd;
|
||||
if (alloc_new) {
|
||||
result = ma_push_type(tcx->temp, rn_cmd_t);
|
||||
result->kind = kind;
|
||||
SLLQ_APPEND(rn->first_cmd, rn->last_cmd, result);
|
||||
#include <windows.h>
|
||||
#include "glad/glad.h"
|
||||
#include "glad/glad.c"
|
||||
|
||||
if (rn_cmd_kind_quad) {
|
||||
result->vertex = rn->vertices + rn->len;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn rn_vertex_t *rn_push_vertex(rn_cmd_t *cmd, u32 count) {
|
||||
rn_vertex_t *result = cmd->vertex + cmd->len;
|
||||
assert(rn->cap >= rn->len + count);
|
||||
rn->len += count;
|
||||
|
||||
cmd->len += count;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void rn_push_quad(r2f32_t rect, r2f32_t tex, v4f32_t color) {
|
||||
rn_cmd_t *cmd = rn_get_cmd(rn_cmd_kind_quad);
|
||||
rn_vertex_t *v = rn_push_vertex(cmd, 6);
|
||||
v[0] = (rn_vertex_t){
|
||||
{rect.min.x, rect.max.y},
|
||||
{ tex.min.x, tex.max.y},
|
||||
color
|
||||
};
|
||||
v[1] = (rn_vertex_t){
|
||||
{rect.max.x, rect.max.y},
|
||||
{ tex.max.x, tex.max.y},
|
||||
color
|
||||
};
|
||||
v[2] = (rn_vertex_t){
|
||||
{rect.min.x, rect.min.y},
|
||||
{ tex.min.x, tex.min.y},
|
||||
color
|
||||
};
|
||||
v[3] = (rn_vertex_t){
|
||||
{rect.min.x, rect.min.y},
|
||||
{ tex.min.x, tex.min.y},
|
||||
color
|
||||
};
|
||||
v[4] = (rn_vertex_t){
|
||||
{rect.max.x, rect.max.y},
|
||||
{ tex.max.x, tex.max.y},
|
||||
color
|
||||
};
|
||||
v[5] = (rn_vertex_t){
|
||||
{rect.max.x, rect.min.y},
|
||||
{ tex.max.x, tex.min.y},
|
||||
color
|
||||
};
|
||||
}
|
||||
|
||||
fn void rn_draw_rect(r2f32_t rect, v4f32_t color) {
|
||||
rn_push_quad(rect, rn->main_font->white_texture_bounding_box, color);
|
||||
}
|
||||
|
||||
fn void rn_draw_rect_border(r2f32_t rect, v4f32_t color, f32 border_thickness) {
|
||||
r2f32_t left = r2f32_cut_left(&rect, border_thickness);
|
||||
r2f32_t right = r2f32_cut_right(&rect, border_thickness);
|
||||
r2f32_t top = r2f32_cut_top(&rect, border_thickness);
|
||||
r2f32_t bottom = r2f32_cut_bottom(&rect, border_thickness);
|
||||
rn_push_quad(left, rn->main_font->white_texture_bounding_box, color);
|
||||
rn_push_quad(right, rn->main_font->white_texture_bounding_box, color);
|
||||
rn_push_quad(top, rn->main_font->white_texture_bounding_box, color);
|
||||
rn_push_quad(bottom, rn->main_font->white_texture_bounding_box, color);
|
||||
}
|
||||
|
||||
fn i64 rn_get_char_spacing(rn_font_t *font, u32 codepoint) {
|
||||
rn_glyph_t *g = rn_get_glyph(font, codepoint);
|
||||
if (g->xadvance) return (i64)g->xadvance;
|
||||
return (i64)g->size.x;
|
||||
}
|
||||
|
||||
fn i64 rn_get_line_spacing(rn_font_t *font) {
|
||||
i64 result = (i64)(font->ascent - font->descent + font->line_gap);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn v2f32_t rn_base_draw_string(rn_font_t *font, s8_t string, v2f32_t pos, v4f32_t color, b32 draw) {
|
||||
// old formula :: pos.y += rn_get_line_spacing(font) + font->descent;
|
||||
pos.y += font->ascent;
|
||||
v2f32_t original_pos = pos;
|
||||
|
||||
for (utf8_iter_t iter = utf8_iterate_ex(string.str, (int)string.len); iter.item; utf8_advance(&iter)) {
|
||||
u32 codepoint = iter.item;
|
||||
rn_glyph_t *g = rn_get_glyph(font, codepoint);
|
||||
r2f32_t rect = r2f32_min_dim(v2f32_add(pos, g->offset), g->size);
|
||||
if (draw && codepoint != '\n' && codepoint != ' ' && codepoint != '\t') {
|
||||
rn_push_quad(rect, g->atlas_bounding_box, color);
|
||||
}
|
||||
pos.x += g->xadvance;
|
||||
}
|
||||
|
||||
|
||||
v2f32_t result = {pos.x - original_pos.x, font->size};
|
||||
return result;
|
||||
}
|
||||
|
||||
fn v2f32_t rn_draw_string(rn_font_t *font, v2f32_t pos, v4f32_t color, s8_t string) {
|
||||
return rn_base_draw_string(font, string, pos, color, true);
|
||||
}
|
||||
|
||||
fn v2f32_t rn_draw_stringf(rn_font_t *font, v2f32_t pos, v4f32_t color, char *str, ...) {
|
||||
S8_FMT(tcx->temp, str, result);
|
||||
return rn_draw_string(font, pos, color, result);
|
||||
}
|
||||
|
||||
fn v2f32_t rn_measure_string(rn_font_t *font, s8_t string) {
|
||||
return rn_base_draw_string(font, string, v2f32(0,0), v4f32(0,0,0,0), false);
|
||||
}
|
||||
|
||||
fn void rn_set_clip(r2f32_t rect) {
|
||||
rn_cmd_t *cmd = rn_get_cmd(rn_cmd_kind_set_clip);
|
||||
cmd->rect = rect;
|
||||
}
|
||||
#include "render_font.c"
|
||||
#include "render_basic.c"
|
||||
#include "render.gen.c"
|
||||
#include "render_opengl.c"
|
||||
#else
|
||||
#include "render_wasm_canvas.c"
|
||||
#endif
|
||||
129
src/render/render_basic.c
Normal file
129
src/render/render_basic.c
Normal file
@@ -0,0 +1,129 @@
|
||||
fn rn_cmd_t *rn_get_cmd(rn_cmd_kind_t kind) {
|
||||
b32 alloc_new = false;
|
||||
if (rn->last_cmd == NULL) {
|
||||
alloc_new = true;
|
||||
} else if (rn->last_cmd->kind != kind) {
|
||||
alloc_new = true;
|
||||
}
|
||||
|
||||
rn_cmd_t *result = rn->last_cmd;
|
||||
if (alloc_new) {
|
||||
result = ma_push_type(tcx->temp, rn_cmd_t);
|
||||
result->kind = kind;
|
||||
SLLQ_APPEND(rn->first_cmd, rn->last_cmd, result);
|
||||
|
||||
if (rn_cmd_kind_quad) {
|
||||
result->vertex = rn->vertices + rn->len;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn rn_vertex_t *rn_push_vertex(rn_cmd_t *cmd, u32 count) {
|
||||
rn_vertex_t *result = cmd->vertex + cmd->len;
|
||||
assert(rn->cap >= rn->len + count);
|
||||
rn->len += count;
|
||||
|
||||
cmd->len += count;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void rn_push_quad(r2f32_t rect, r2f32_t tex, v4f32_t color) {
|
||||
rn_cmd_t *cmd = rn_get_cmd(rn_cmd_kind_quad);
|
||||
rn_vertex_t *v = rn_push_vertex(cmd, 6);
|
||||
v[0] = (rn_vertex_t){
|
||||
{rect.min.x, rect.max.y},
|
||||
{ tex.min.x, tex.max.y},
|
||||
color
|
||||
};
|
||||
v[1] = (rn_vertex_t){
|
||||
{rect.max.x, rect.max.y},
|
||||
{ tex.max.x, tex.max.y},
|
||||
color
|
||||
};
|
||||
v[2] = (rn_vertex_t){
|
||||
{rect.min.x, rect.min.y},
|
||||
{ tex.min.x, tex.min.y},
|
||||
color
|
||||
};
|
||||
v[3] = (rn_vertex_t){
|
||||
{rect.min.x, rect.min.y},
|
||||
{ tex.min.x, tex.min.y},
|
||||
color
|
||||
};
|
||||
v[4] = (rn_vertex_t){
|
||||
{rect.max.x, rect.max.y},
|
||||
{ tex.max.x, tex.max.y},
|
||||
color
|
||||
};
|
||||
v[5] = (rn_vertex_t){
|
||||
{rect.max.x, rect.min.y},
|
||||
{ tex.max.x, tex.min.y},
|
||||
color
|
||||
};
|
||||
}
|
||||
|
||||
fn void rn_draw_rect(r2f32_t rect, v4f32_t color) {
|
||||
rn_push_quad(rect, rn->main_font->white_texture_bounding_box, color);
|
||||
}
|
||||
|
||||
fn void rn_draw_rect_border(r2f32_t rect, v4f32_t color, f32 border_thickness) {
|
||||
r2f32_t left = r2f32_cut_left(&rect, border_thickness);
|
||||
r2f32_t right = r2f32_cut_right(&rect, border_thickness);
|
||||
r2f32_t top = r2f32_cut_top(&rect, border_thickness);
|
||||
r2f32_t bottom = r2f32_cut_bottom(&rect, border_thickness);
|
||||
rn_push_quad(left, rn->main_font->white_texture_bounding_box, color);
|
||||
rn_push_quad(right, rn->main_font->white_texture_bounding_box, color);
|
||||
rn_push_quad(top, rn->main_font->white_texture_bounding_box, color);
|
||||
rn_push_quad(bottom, rn->main_font->white_texture_bounding_box, color);
|
||||
}
|
||||
|
||||
fn i64 rn_get_char_spacing(rn_font_t *font, u32 codepoint) {
|
||||
rn_glyph_t *g = rn_get_glyph(font, codepoint);
|
||||
if (g->xadvance) return (i64)g->xadvance;
|
||||
return (i64)g->size.x;
|
||||
}
|
||||
|
||||
fn i64 rn_get_line_spacing(rn_font_t *font) {
|
||||
i64 result = (i64)(font->ascent - font->descent + font->line_gap);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn v2f32_t rn_base_draw_string(rn_font_t *font, s8_t string, v2f32_t pos, v4f32_t color, b32 draw) {
|
||||
// old formula :: pos.y += rn_get_line_spacing(font) + font->descent;
|
||||
pos.y += font->ascent;
|
||||
v2f32_t original_pos = pos;
|
||||
|
||||
for (utf8_iter_t iter = utf8_iterate_ex(string.str, (int)string.len); iter.item; utf8_advance(&iter)) {
|
||||
u32 codepoint = iter.item;
|
||||
rn_glyph_t *g = rn_get_glyph(font, codepoint);
|
||||
r2f32_t rect = r2f32_min_dim(v2f32_add(pos, g->offset), g->size);
|
||||
if (draw && codepoint != '\n' && codepoint != ' ' && codepoint != '\t') {
|
||||
rn_push_quad(rect, g->atlas_bounding_box, color);
|
||||
}
|
||||
pos.x += g->xadvance;
|
||||
}
|
||||
|
||||
|
||||
v2f32_t result = {pos.x - original_pos.x, font->size};
|
||||
return result;
|
||||
}
|
||||
|
||||
fn v2f32_t rn_draw_string(rn_font_t *font, v2f32_t pos, v4f32_t color, s8_t string) {
|
||||
return rn_base_draw_string(font, string, pos, color, true);
|
||||
}
|
||||
|
||||
fn v2f32_t rn_draw_stringf(rn_font_t *font, v2f32_t pos, v4f32_t color, char *str, ...) {
|
||||
S8_FMT(tcx->temp, str, result);
|
||||
return rn_draw_string(font, pos, color, result);
|
||||
}
|
||||
|
||||
fn v2f32_t rn_measure_string(rn_font_t *font, s8_t string) {
|
||||
return rn_base_draw_string(font, string, v2f32(0,0), v4f32(0,0,0,0), false);
|
||||
}
|
||||
|
||||
fn void rn_set_clip(r2f32_t rect) {
|
||||
rn_cmd_t *cmd = rn_get_cmd(rn_cmd_kind_set_clip);
|
||||
cmd->rect = rect;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "render.h"
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#define STBTT_ifloor(x) ((int)f64_floor(x))
|
||||
#define STBTT_iceil(x) ((int)f64_ceil(x))
|
||||
#define STBTT_sqrt(x) (f64_sqrt(x))
|
||||
#define STBTT_pow(x,y) (f64_pow(x,y))
|
||||
#define STBTT_fmod(x,y) (f64_mod(x,y))
|
||||
#define STBTT_cos(x) (f64_cos(x))
|
||||
#define STBTT_acos(x) (f64_acos(x))
|
||||
#define STBTT_fabs(x) (f64_abs(x))
|
||||
#define STBTT_assert(x) (assert(x))
|
||||
#define STBTT_malloc(x,u) (ma_push_size(tcx->temp, x))
|
||||
#define STBTT_free(x,u)
|
||||
#define STBTT_strlen(x) (str_len(x))
|
||||
#define STBTT_memcpy memory_copy
|
||||
#define STBTT_memset memory_set
|
||||
#include "stb_truetype.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include "glad/glad.h"
|
||||
#include "glad/glad.c"
|
||||
|
||||
#include "render_font.c"
|
||||
#include "render.c"
|
||||
#include "render.gen.c"
|
||||
#include "render_opengl.c"
|
||||
#else
|
||||
#include "render_wasm_canvas.c"
|
||||
#endif
|
||||
6
src/testing/testing.gen.c
Normal file
6
src/testing/testing.gen.c
Normal file
@@ -0,0 +1,6 @@
|
||||
fn void run_tests(void) {
|
||||
test_s8();
|
||||
test_hash_table();
|
||||
test_intern_table();
|
||||
os_test();
|
||||
}
|
||||
32
src/testing/testing.meta.c
Normal file
32
src/testing/testing.meta.c
Normal file
@@ -0,0 +1,32 @@
|
||||
void mt_testing(ma_arena_t *arena) {
|
||||
mt_files_t files = mt_lex_files(arena, mt_main_path(arena), mt_get_include_paths(arena));
|
||||
sb8_t *tests = sb8_serial_begin(arena);
|
||||
|
||||
for (mt_file_t *it = files.first; it; it = it->next) {
|
||||
parser_t *par = parser_make(arena, it->tokens.data);
|
||||
for (;par->at->kind != lex_kind_eof;) {
|
||||
b32 matched = false;
|
||||
|
||||
if (par->at->inside_macro == false && parser_matchi(par, s8_lit("fn_test"))) {
|
||||
parser_expecti(par, s8_lit("void"));
|
||||
lex_t *ident = parser_match(par, lex_kind_ident);
|
||||
sb8_append(tests, ident->string);
|
||||
matched = true;
|
||||
}
|
||||
|
||||
if (!matched) {
|
||||
parser_next(par);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sb8_t *c = sb8_serial_begin(arena);
|
||||
sb8_printf(c, "fn void run_tests(void) {\n");
|
||||
for (sb8_node_t *it = tests->first; it; it = it->next) {
|
||||
sb8_printf(c, " %S();\n", it->string);
|
||||
}
|
||||
sb8_printf(c, "}\n");
|
||||
|
||||
s8_t result = sb8_serial_end(arena, c);
|
||||
os_write_file(mt_cpath(arena), result);
|
||||
}
|
||||
12
src/testing/testing_main.c
Normal file
12
src/testing/testing_main.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "core/core.h"
|
||||
#include "os/os.h"
|
||||
#include "core/core.c"
|
||||
#include "os/os.c"
|
||||
|
||||
#include "testing.gen.c"
|
||||
|
||||
int main() {
|
||||
core_init();
|
||||
run_tests();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
#include "ui.gen.c"
|
||||
|
||||
fn ui_caret_t ui_caret_clamp(ui_caret_t c, i32 min, i32 max) {
|
||||
return (ui_caret_t){CLAMP(c.e[0],min,max), CLAMP(c.e[1],min,max), c.ifront};
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "ui.gen.c"
|
||||
#include "ui.c"
|
||||
@@ -1 +0,0 @@
|
||||
#include "ui.h"
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "core/core_inc.h"
|
||||
#include "core/core.h"
|
||||
#include "app/app.h"
|
||||
#include "ui/ui_inc.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
#include "core/core_inc.c"
|
||||
#include "core/core.c"
|
||||
#include "app/app.c"
|
||||
#include "render/render_inc.c"
|
||||
#include "ui/ui_inc.c"
|
||||
#include "render/render.c"
|
||||
#include "ui/ui.c"
|
||||
|
||||
#include "wasm_app.gen.c"
|
||||
|
||||
|
||||
@@ -7,5 +7,8 @@ gb_read_only mt_tweak_t tweak_table[] = {
|
||||
|
||||
};
|
||||
void run_all_tests(void) {
|
||||
test_s8();
|
||||
test_hash_table();
|
||||
test_intern_table();
|
||||
ui_test_text_replace();
|
||||
}// run_all_tests()
|
||||
|
||||
Reference in New Issue
Block a user