new repo for codebase
This commit is contained in:
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
build/
|
||||
backup
|
||||
subl.bat
|
||||
multimedia.c
|
||||
multimedia.h
|
||||
playground.py
|
||||
ui_notes.txt
|
||||
run_linux.bat
|
||||
l.log
|
||||
vendor
|
||||
|
||||
*.10x
|
||||
*.wasm
|
||||
*.o
|
||||
*sublime-project*
|
||||
*sublime-workspace*
|
||||
20
build.bat
Normal file
20
build.bat
Normal file
@@ -0,0 +1,20 @@
|
||||
@echo off
|
||||
|
||||
for %%a in (%*) do set "%%~a=1"
|
||||
|
||||
|
||||
set common=-I ../src/ -g -fdiagnostics-absolute-paths -Wno-unsequenced -Wno-single-bit-bitfield-constant-conversion -Wall -Wno-missing-braces -Wextra -Wno-missing-field-initializers
|
||||
set wasm_flags=--target=wasm32 -nostdlib -mbulk-memory -msimd128 -Wl,-export-dynamic,--allow-undefined,--import-memory,--no-entry,--initial-memory=131072000,--max-memory=4294967296
|
||||
|
||||
if not exist build (
|
||||
mkdir build
|
||||
)
|
||||
pushd build
|
||||
if "%testing%"=="1" echo [testing] && set didbuild=1 && clang ../src/testing/testing_main.c -o testing.exe %common% || exit 1 /b
|
||||
if "%scratch%"=="1" echo [scratch] && set didbuild=1 && clang ../src/scratch/scratch_main.c -o ../src/scratch/main.wasm %common% %wasm_flags% || exit 1 /b
|
||||
popd
|
||||
|
||||
if "%didbuild%"=="" (
|
||||
echo [WARNING] no valid build target specified
|
||||
exit /b 1
|
||||
)
|
||||
17
build.sh
Normal file
17
build.sh
Normal file
@@ -0,0 +1,17 @@
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
if [ ! -d build ]; then
|
||||
mkdir build
|
||||
fi
|
||||
pushd build
|
||||
clang ../src/testing/testing_main.c -g
|
||||
popd
|
||||
|
||||
# if [ ! -f build/build_tool.exe ]; then
|
||||
# echo build_tool rebuild
|
||||
# cd build
|
||||
# clang ../src/meta/build_tool.c -ldl -lbacktrace -o build_tool.exe -g -fdiagnostics-absolute-paths -Wno-single-bit-bitfield-constant-conversion -Wno-unsequenced
|
||||
# cd ..
|
||||
# fi
|
||||
|
||||
# ./build/build_tool.exe clang ../build_file.c -o build_file.exe -ldl -lm -lbacktrace -g -Wall -Wextra -Wno-missing-braces -Wno-missing-field-initializers -Wno-single-bit-bitfield-constant-conversion -fdiagnostics-absolute-paths -Wno-writable-strings -Wno-unsequenced
|
||||
15
src/core/core.c
Normal file
15
src/core/core.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "core_platform.c"
|
||||
#include "core_intrin.c"
|
||||
#include "core_unicode.c"
|
||||
#include "core_math.c"
|
||||
#include "core_arena.c"
|
||||
#include "stb_sprintf.c"
|
||||
#include "core_string.c"
|
||||
#include "core_string16.c"
|
||||
#include "core_log.c"
|
||||
#include "core_lexer.c"
|
||||
#include "core_type_info.c"
|
||||
#include "core_hash_table.c"
|
||||
#include "core_array.c"
|
||||
#include "core_math.gen.c"
|
||||
#include "core_ctx.c"
|
||||
14
src/core/core.h
Normal file
14
src/core/core.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "core_basic.h"
|
||||
#include "core_unicode.h"
|
||||
#include "core_arena.h"
|
||||
#include "core_string.h"
|
||||
#include "core_string16.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"
|
||||
#include "core_array.h"
|
||||
202
src/core/core_arena.c
Normal file
202
src/core/core_arena.c
Normal file
@@ -0,0 +1,202 @@
|
||||
#include "core_arena.h"
|
||||
#include "core_platform.h"
|
||||
#include "core_intrin.h"
|
||||
#include "core_ctx.h"
|
||||
|
||||
#if PLATFORM_ADDRESS_SANITIZER
|
||||
#include <sanitizer/asan_interface.h>
|
||||
#endif
|
||||
|
||||
#if !defined(ASAN_POISON_MEMORY_REGION)
|
||||
#define MA_ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
|
||||
#define MA_ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
|
||||
#else
|
||||
#define MA_ASAN_POISON_MEMORY_REGION(addr, size) ASAN_POISON_MEMORY_REGION(addr, size)
|
||||
#define MA_ASAN_UNPOISON_MEMORY_REGION(addr, size) ASAN_UNPOISON_MEMORY_REGION(addr, size)
|
||||
#endif
|
||||
|
||||
fn b32 is_pow2(usize x) {
|
||||
b32 result = (((x) & ((x)-1)) == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn usize get_align_offset(usize size, usize align) {
|
||||
assert(is_pow2(align));
|
||||
if (align == 0) return 0;
|
||||
|
||||
usize mask = align - 1;
|
||||
usize val = size & mask;
|
||||
if (val) {
|
||||
val = align - val;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
fn usize align_up(usize size, usize align) {
|
||||
usize result = size + get_align_offset(size, align);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn usize align_down(usize size, usize align) {
|
||||
size += 1; // Make sure when align is 8 doesn't get rounded down to 0
|
||||
usize result = size - (align - get_align_offset(size, align));
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void ma_init(ma_arena_t *arena, usize reserve) {
|
||||
reserve = align_up(reserve, ma_page_size);
|
||||
arena->align = ma_default_alignment;
|
||||
arena->data = (u8 *)os_vmem_reserve(reserve);
|
||||
if (arena->data) {
|
||||
arena->reserve = reserve;
|
||||
}
|
||||
}
|
||||
|
||||
fn ma_arena_t *ma_create(usize reserve) {
|
||||
ma_arena_t *result = NULL;
|
||||
|
||||
void *data = os_vmem_reserve(reserve);
|
||||
if (!data) return result;
|
||||
|
||||
b32 success = os_vmem_commit(data, ma_page_size);
|
||||
if (!success) {
|
||||
os_vmem_release(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = (ma_arena_t *)data;
|
||||
result->data = (u8 *)data;
|
||||
result->reserve = reserve;
|
||||
result->commit = ma_page_size;
|
||||
result->len = result->base_len = sizeof(ma_arena_t);
|
||||
result->align = ma_default_alignment;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void *ma_push_size_ex(ma_arena_t *arena, usize size) {
|
||||
// base_len is used for bootstraping arenas, it denotes the
|
||||
// space occupied by the arena. If len is smaller then base_len then
|
||||
// we start to overwrite the arena itself - pure barbarism.
|
||||
assert(arena->len >= arena->base_len);
|
||||
|
||||
usize align_offset = 0;
|
||||
if (arena->align) {
|
||||
align_offset = get_align_offset((usize)arena->data + arena->len, arena->align);
|
||||
}
|
||||
usize size_with_alignment = size + align_offset;
|
||||
usize new_len = arena->len + size_with_alignment;
|
||||
if (new_len > arena->commit) {
|
||||
if (arena->reserve == 0) {
|
||||
ma_init(arena, ma_default_reserve_size);
|
||||
}
|
||||
usize new_len_aligned_to_page_size = align_up(new_len, ma_page_size);
|
||||
usize to_commit = new_len_aligned_to_page_size - arena->commit;
|
||||
usize to_commit_clamped = CLAMP_TOP(to_commit, arena->reserve);
|
||||
if (to_commit_clamped > 0) {
|
||||
b32 success = os_vmem_commit(arena->data + arena->commit, to_commit_clamped);
|
||||
if (success) {
|
||||
MA_ASAN_UNPOISON_MEMORY_REGION(arena->data + arena->commit, to_commit_clamped);
|
||||
arena->commit += to_commit_clamped;
|
||||
}
|
||||
}
|
||||
if (new_len > arena->commit) {
|
||||
invalid_codepath;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
u8 *result = arena->data + arena->len + align_offset;
|
||||
arena->len = new_len;
|
||||
MA_ASAN_UNPOISON_MEMORY_REGION(result, size);
|
||||
return (void *)result;
|
||||
}
|
||||
|
||||
fn void *ma_push_size(ma_arena_t *arena, usize size) {
|
||||
void *result = ma_push_size_ex(arena, size);
|
||||
if (result) memory_zero(result, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void ma_push_arena_ex(ma_arena_t *allocator, ma_arena_t *result, usize size) {
|
||||
result->data = (u8 *)ma_push_size(allocator, size);
|
||||
result->reserve = size;
|
||||
result->commit = size;
|
||||
result->align = ma_default_alignment;
|
||||
}
|
||||
|
||||
fn ma_arena_t *ma_push_arena(ma_arena_t *allocator, usize size) {
|
||||
ma_arena_t *result = ma_push_type(allocator, ma_arena_t);
|
||||
ma_push_arena_ex(allocator, result, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void ma_destroy(ma_arena_t *arena) {
|
||||
if (arena == NULL || arena->data == NULL) return;
|
||||
b32 zero_memory = (u8 *)arena != arena->data;
|
||||
os_vmem_release(arena->data);
|
||||
if (zero_memory) memory_zero(arena, sizeof(ma_arena_t));
|
||||
}
|
||||
|
||||
fn void ma_set_len(ma_arena_t *arena, usize pos) {
|
||||
// base_len is used for bootstraping arenas, it denotes the
|
||||
// space occupied by the arena. If len is smaller then base_len then
|
||||
// we start to overwrite the arena itself - pure barbarism.
|
||||
assert(arena->len >= arena->base_len);
|
||||
|
||||
pos = CLAMP(pos, arena->base_len, arena->len);
|
||||
usize size = arena->len - pos;
|
||||
arena->len = pos;
|
||||
MA_ASAN_POISON_MEMORY_REGION(arena->data + arena->len, size);
|
||||
}
|
||||
|
||||
fn void ma_pop(ma_arena_t *arena, usize size) { ma_set_len(arena, arena->len - size); }
|
||||
fn ma_temp_t ma_begin_temp(ma_arena_t *arena) { return (ma_temp_t){arena, arena->len}; }
|
||||
fn void ma_end_temp(ma_temp_t temp) { ma_set_len(temp.arena, temp.len); }
|
||||
fn void ma_set0(ma_arena_t *arena) { ma_set_len(arena, 0); }
|
||||
|
||||
//
|
||||
// Scratch arena
|
||||
fn ma_temp_t ma_begin_scratch_ex(ma_arena_t **conflicts, int conflict_count) {
|
||||
ma_arena_t *unoccupied = 0;
|
||||
for (int i = 0; i < lengthof(tcx->scratch); i += 1) {
|
||||
ma_arena_t *from_pool = tcx->scratch + i;
|
||||
unoccupied = from_pool;
|
||||
for (int conflict_i = 0; conflict_i < conflict_count; conflict_i += 1) {
|
||||
ma_arena_t *from_conflict = conflicts[conflict_i];
|
||||
if (from_pool == from_conflict) {
|
||||
unoccupied = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (unoccupied) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(unoccupied); // failed to get free scratch memory, this is a fatal error, this shouldnt happen
|
||||
ma_temp_t result = ma_begin_temp(unoccupied);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn ma_temp_t ma_begin_scratch(void) {
|
||||
ma_temp_t result = ma_begin_temp(tcx->scratch + 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn ma_temp_t ma_begin_scratch1(ma_arena_t *conflict) {
|
||||
ma_arena_t *conflicts[] = {conflict};
|
||||
return ma_begin_scratch_ex(conflicts, 1);
|
||||
}
|
||||
|
||||
fn ma_temp_t ma_begin_scratch2(ma_arena_t *a, ma_arena_t *b) {
|
||||
ma_arena_t *conflicts[] = {a, b};
|
||||
return ma_begin_scratch_ex(conflicts, 2);
|
||||
}
|
||||
|
||||
fn void *ma_push__copy(ma_arena_t *arena, void *data, u64 size) {
|
||||
void *result = ma_push_size_ex(arena, size);
|
||||
if (result) {
|
||||
memory_copy(result, data, size);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
59
src/core/core_arena.h
Normal file
59
src/core/core_arena.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
|
||||
static const usize ma_page_size = 4096;
|
||||
static const usize ma_default_alignment = sizeof(void *);
|
||||
static const usize ma_default_reserve_size = mib(256);
|
||||
|
||||
typedef struct ma_arena_t ma_arena_t;
|
||||
struct ma_arena_t {
|
||||
u8 *data;
|
||||
usize len;
|
||||
usize base_len; // to prevent self deleting the arena
|
||||
usize reserve;
|
||||
usize commit;
|
||||
usize align;
|
||||
};
|
||||
|
||||
typedef struct ma_temp_t ma_temp_t;
|
||||
struct ma_temp_t {
|
||||
ma_arena_t *arena;
|
||||
usize len;
|
||||
};
|
||||
|
||||
//
|
||||
// constructors
|
||||
fn void ma_init(ma_arena_t *arena, usize reserve);
|
||||
fn ma_arena_t *ma_create(usize reserve);
|
||||
fn void ma_destroy(ma_arena_t *arena);
|
||||
|
||||
//
|
||||
// push
|
||||
fn void *ma_push_size(ma_arena_t *arena, usize size);
|
||||
fn void *ma_push_size_ex(ma_arena_t *arena, usize size);
|
||||
fn ma_arena_t *ma_push_arena(ma_arena_t *allocator, usize size);
|
||||
fn void ma_push_arena_ex(ma_arena_t *allocator, ma_arena_t *result, usize size);
|
||||
#define ma_push_type(arena, Type) (Type *)ma_push_size((arena), sizeof(Type))
|
||||
#define ma_push_array(arena, Type, count) (Type *)ma_push_size((arena), sizeof(Type) * (count))
|
||||
#define ma_push_type_copy(ma, data) ma_push__copy((ma), (data), sizeof(*(data)))
|
||||
#define ma_push_array_copy(ma, data, count) ma_push__copy((ma), (data), (count) * sizeof(*(data)))
|
||||
|
||||
//
|
||||
// pop
|
||||
fn void ma_set_len(ma_arena_t *arena, usize pos);
|
||||
fn void ma_pop(ma_arena_t *arena, usize size);
|
||||
fn void ma_set0(ma_arena_t *arena);
|
||||
|
||||
//
|
||||
// temp
|
||||
fn ma_temp_t ma_begin_temp(ma_arena_t *arena);
|
||||
fn void ma_end_temp(ma_temp_t temp);
|
||||
#define ma_temp_scope(name, InArena) for (ma_temp_t name = ma_begin_temp(InArena); name.arena; (ma_end_temp(name), name.arena = 0))
|
||||
|
||||
//
|
||||
// scratch
|
||||
fn ma_temp_t ma_begin_scratch_ex(ma_arena_t **conflicts, int conflict_count);
|
||||
fn ma_temp_t ma_begin_scratch(void);
|
||||
fn ma_temp_t ma_begin_scratch1(ma_arena_t *conflict);
|
||||
#define ma_end_scratch(x) ma_end_temp(x)
|
||||
#define ma_scratch_scope(x) for (ma_temp_t x = ma_begin_scratch(); x.arena; (ma_end_temp(x), x.arena = 0))
|
||||
122
src/core/core_array.c
Normal file
122
src/core/core_array.c
Normal file
@@ -0,0 +1,122 @@
|
||||
#include "core_array.h"
|
||||
#include "core_basic.h"
|
||||
#include "core_platform.h"
|
||||
#include "core_ctx.h"
|
||||
#include "core_intrin.h"
|
||||
|
||||
fn void array__init(alo_t alo, array_void_t *this, size_t item_size, i64 count) {
|
||||
assert_expr(this->data == NULL);
|
||||
this->data = alloc_size(alo, item_size * count);
|
||||
this->cap = count;
|
||||
this->len = 0;
|
||||
this->alo = alo;
|
||||
}
|
||||
|
||||
fn void array__copy(alo_t alo, array_void_t *dst, array_void_t *src, size_t item_size) {
|
||||
dst->data = alloc_size(alo, item_size * src->cap);
|
||||
memory_copy(dst->data, src->data, item_size * src->len);
|
||||
dst->cap = src->cap;
|
||||
dst->len = src->len;
|
||||
dst->alo = alo;
|
||||
}
|
||||
|
||||
fn void array__grow(array_void_t *this, size_t item_size, i64 item_count) {
|
||||
if (this->len + 1 > this->cap) {
|
||||
i64 new_cap = this->cap == 0 ? 16 : (this->cap + item_count - 1) * 2;
|
||||
void *new_data = alloc_size(this->alo, new_cap * item_size);
|
||||
if (this->data) {
|
||||
memory_copy(new_data, this->data, this->len*item_size);
|
||||
dealloc(this->alo, this->data);
|
||||
}
|
||||
this->data = new_data;
|
||||
this->cap = new_cap;
|
||||
}
|
||||
}
|
||||
|
||||
fn void array__del(array_void_t *this, size_t item_size, i64 idx, i64 count) {
|
||||
if (count == 0) return;
|
||||
assert(idx >= 0 && idx < this->len);
|
||||
assert((idx + count) > 0 && (idx + count) <= this->len);
|
||||
i64 right_len = this->len - idx - count;
|
||||
u8 *data = (u8 *)this->data;
|
||||
memory_move(data + idx * item_size, data + (idx + count) * item_size, right_len * item_size);
|
||||
this->len -= count;
|
||||
}
|
||||
|
||||
fn void array__insert(array_void_t *this, size_t item_size, i64 idx) {
|
||||
array__grow(this, item_size, 1);
|
||||
assert(idx >= 0);
|
||||
assert(idx <= this->len);
|
||||
assert(this->alo.object);
|
||||
|
||||
u8 *data = (u8 *)this->data;
|
||||
i64 right_len = this->len - idx;
|
||||
memory_move(data + (idx + 1) * item_size, data + idx * item_size, item_size * right_len);
|
||||
this->len += 1;
|
||||
}
|
||||
|
||||
fn_test void test_array(void) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
{
|
||||
array_i64_t arr = (array_i64_t){.alo = malot(scratch)};
|
||||
for (int i = 0; i < 512; i += 1) {
|
||||
array_add(&arr, i);
|
||||
}
|
||||
for (int i = 0; i < 512; i += 1) {
|
||||
assert(arr.data[i] == i);
|
||||
}
|
||||
assert(arr.len == 512);
|
||||
assert(arr.cap == 512);
|
||||
for (int i = 511; i >= 0; i -= 1) {
|
||||
i64 a = array_pop(&arr);
|
||||
assert(a == i);
|
||||
}
|
||||
assert(arr.len == 0);
|
||||
array_dealloc(&arr);
|
||||
}
|
||||
|
||||
{
|
||||
array_i64_t arr = (array_i64_t){.alo = malot(scratch)};
|
||||
i64 *i = array_addn(&arr, 10);
|
||||
assert(arr.len == 10 && arr.cap == 16);
|
||||
i64 *j = array_addn(&arr, 2);
|
||||
assert(i == arr.data);
|
||||
assert(j == arr.data + 10);
|
||||
array_dealloc(&arr);
|
||||
}
|
||||
|
||||
{
|
||||
array_i64_t arr = (array_i64_t){.alo = malot(scratch)};
|
||||
for (int i = 0; i < 512; i += 1) {
|
||||
array_add(&arr, i);
|
||||
}
|
||||
|
||||
array_insert(&arr, 256, 111);
|
||||
assert(arr.data[256] == 111);
|
||||
assert(arr.data[255] == 255);
|
||||
assert(arr.data[257] == 256);
|
||||
assert(arr.len == 513);
|
||||
|
||||
array_insert(&arr, 4, 222);
|
||||
assert(arr.len == 514);
|
||||
assert(arr.data[4] == 222);
|
||||
assert(arr.data[3] == 3);
|
||||
assert(arr.data[5] == 4);
|
||||
|
||||
array_swapdel(&arr, 2);
|
||||
assert(arr.len == 513);
|
||||
assert(arr.data[2] == 511);
|
||||
assert(arr.data[1] == 1);
|
||||
assert(arr.data[3] == 3);
|
||||
|
||||
array_i64_t copy = {0};
|
||||
array_copy(malot(scratch), ©, &arr);
|
||||
for (i64 i = 0; i < arr.len; i += 1) {
|
||||
assert(arr.data[i] == copy.data[i]);
|
||||
}
|
||||
assert(copy.len == arr.len);
|
||||
|
||||
}
|
||||
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
27
src/core/core_array.h
Normal file
27
src/core/core_array.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
|
||||
#define array(type) struct { alo_t alo; type *data; i64 len; i64 cap; }
|
||||
typedef array(void) array_void_t;
|
||||
typedef array(i64) array_i64_t;
|
||||
|
||||
#define arrisz(x) sizeof((x)->data[0])
|
||||
#define arrcst(x) ((array_void_t *)(x))
|
||||
#define array_init(a, this, count) (array__init((a), arrcst(this), arrisz(this), (count)))
|
||||
#define array_add(this, ...) (array__grow(arrcst(this), arrisz(this), 1), (this)->data[(this)->len++] = __VA_ARGS__)
|
||||
#define array_pop(this) (assert_expr((this)->len > 0), (this)->data[--(this)->len])
|
||||
#define array_dealloc(this) (dealloc((this)->alo, (this)->data))
|
||||
#define array_addn(this, n) (array__grow(arrcst(this), arrisz(this), (n)), (this)->len += (n), &(this)->data[(this)->len - (n)])
|
||||
#define array_insert(this, i, item) (array__insert(arrcst(this), arrisz(this), (i)), (this)->data[(i)] = (item))
|
||||
#define array_swapdel(this, i) (assert_expr((i) < (this)->len), (this)->data[(i)] = (this)->data[--(this)->len])
|
||||
#define array_del(this, i) (array__del(arrcst(this), arrisz(this), (i), 1))
|
||||
#define array_deln(this, i, count) (array__del(arrcst(this), arrisz(this), (i), (count)))
|
||||
#define array_copy(alo, dst, src) (array__copy((alo), arrcst(dst), (array_void_t *)(src), arrisz(dst)))
|
||||
#define array_last(x) ((x)->data[(x)->len - 1])
|
||||
#define array_for(type, it, array) for (type *it = (array)->data; it < (array)->data + (array)->len; it += 1)
|
||||
|
||||
fn void array__init(alo_t alo, array_void_t *, size_t item_size, i64 count);
|
||||
fn void array__copy(alo_t alo, array_void_t *dst, array_void_t *src, size_t item_size);
|
||||
fn void array__grow(array_void_t *, size_t item_size, i64 item_count);
|
||||
fn void array__del(array_void_t *, size_t item_size, i64 idx, i64 count);
|
||||
fn void array__insert(array_void_t *, size_t item_size, i64 idx);
|
||||
422
src/core/core_basic.h
Normal file
422
src/core/core_basic.h
Normal file
@@ -0,0 +1,422 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#define PLATFORM_MAC_OS 1
|
||||
#define PLATFORM_POSIX 1
|
||||
#elif defined(_WIN32)
|
||||
#define PLATFORM_WINDOWS 1
|
||||
#elif defined(__linux__)
|
||||
#define PLATFORM_POSIX 1
|
||||
#define PLATFORM_LINUX 1
|
||||
#elif defined(__wasm)
|
||||
#define PLATFORM_WASM 1
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
#define PLATFORM_CLANG 1
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#define PLATFORM_GCC 1
|
||||
#elif defined(_MSC_VER)
|
||||
#define PLATFORM_CL 1
|
||||
#elif defined(__TINYC__)
|
||||
#define PLATFORM_TCC 1
|
||||
#endif
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
#define PLATFORM_EMSCRIPTEN 1
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_EMSCRIPTEN
|
||||
#define PLATFORM_EMSCRIPTEN 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_WASM
|
||||
#define PLATFORM_WASM 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
#define PLATFORM_WINDOWS 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_LINUX
|
||||
#define PLATFORM_LINUX 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_POSIX
|
||||
#define PLATFORM_POSIX 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_MAC_OS
|
||||
#define PLATFORM_MAC_OS 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_CLANG
|
||||
#define PLATFORM_CLANG 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_GCC
|
||||
#define PLATFORM_GCC 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_CL
|
||||
#define PLATFORM_CL 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_TCC
|
||||
#define PLATFORM_TCC 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_ADDRESS_SANITIZER
|
||||
#define PLATFORM_ADDRESS_SANITIZER 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_DEBUG_ASSERT
|
||||
#define PLATFORM_DEBUG_ASSERT 1
|
||||
#endif
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#define SWITCH_PLATFORM_WINDOWS_WASM_ELSE(WINDOWS, WASM, ELSE) WINDOWS
|
||||
#elif PLATFORM_WASM
|
||||
#define SWITCH_PLATFORM_WINDOWS_WASM_ELSE(WINDOWS, WASM, ELSE) WASM
|
||||
#else
|
||||
#define SWITCH_PLATFORM_WINDOWS_WASM_ELSE(WINDOWS, WASM, ELSE) ELSE
|
||||
#endif
|
||||
|
||||
#if PLATFORM_CLANG
|
||||
#define IF_PLATFORM_CLANG_ELSE(IF, ELSE) IF
|
||||
#else
|
||||
#define IF_PLATFORM_CLANG_ELSE(IF, ELSE) ELSE
|
||||
#endif
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#define IF_PLATFORM_WINDOWS(x) x
|
||||
#else
|
||||
#define IF_PLATFORM_WINDOWS(x)
|
||||
#endif
|
||||
|
||||
#if PLATFORM_LINUX && !defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
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) ((int)(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_expr(!STACK_FULL(stack)), (stack).data[(stack).len++] = __VA_ARGS__)
|
||||
#define STACK_POP(stack) (assert_expr(!STACK_EMPTY(stack)), (stack).data[--(stack).len])
|
||||
#define STACK_TOP(stack) (assert_expr(!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 SWAP_PTR(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_WINDOWS
|
||||
int IsDebuggerPresent(void);
|
||||
#define debug__break() (IsDebuggerPresent() && (__debugbreak(), 1))
|
||||
#elif PLATFORM_UNIX
|
||||
// https://github.com/r-lyeh/tinybits/blob/master/tinyassert.c
|
||||
#include <signal.h>
|
||||
static void os_unix_sigtrap(int signum) { signal(SIGTRAP, SIG_DFL); }
|
||||
#define debug__break() (signal(SIGTRAP, os_unix_sigtrap), raise(SIGTRAP))
|
||||
#else
|
||||
#define debug__break() __builtin_trap()
|
||||
#endif
|
||||
#define debug_break() (debug__break(), 1)
|
||||
|
||||
#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_expr((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_expr((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_expr((node)->next == NULL); \
|
||||
assert_expr((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_expr((node)->next == NULL); \
|
||||
assert_expr((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_expr((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_expr((node)->next == NULL); \
|
||||
assert_expr((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)
|
||||
|
||||
typedef enum {
|
||||
alokind_alloc,
|
||||
alokind_dealloc,
|
||||
} alokind_t;
|
||||
|
||||
typedef struct alo_t alo_t;
|
||||
struct alo_t {
|
||||
void *object;
|
||||
void *(*proc)(alo_t alo, alokind_t kind, void *ptr, size_t size);
|
||||
};
|
||||
30
src/core/core_ctx.c
Normal file
30
src/core/core_ctx.c
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "core_ctx.h"
|
||||
#include "core_platform.h"
|
||||
|
||||
gb_thread thread_ctx_t *tcx;
|
||||
|
||||
fn void *ma_arena_alo_proc(alo_t alo, alokind_t kind, void *ptr, size_t size) {
|
||||
unused(ptr);
|
||||
if (kind == alokind_alloc) {
|
||||
return ma_push_size(alo.object, size);
|
||||
} else if (kind == alokind_dealloc) {
|
||||
return NULL;
|
||||
} else_is_invalid;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn alo_t malo(ma_arena_t *arena) {
|
||||
return (alo_t){arena, ma_arena_alo_proc};
|
||||
}
|
||||
|
||||
fn alo_t malot(ma_temp_t temp) {
|
||||
return malo(temp.arena);
|
||||
}
|
||||
|
||||
fn void dealloc(alo_t alo, void *ptr) {
|
||||
alo.proc(alo, alokind_dealloc, ptr, 0);
|
||||
}
|
||||
|
||||
fn void *alloc_size(alo_t alo, size_t size) {
|
||||
return alo.proc(alo, alokind_alloc, NULL, size);
|
||||
}
|
||||
34
src/core/core_ctx.h
Normal file
34
src/core/core_ctx.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include "core_arena.h"
|
||||
#include "core_log.h"
|
||||
|
||||
typedef struct thread_ctx_t thread_ctx_t;
|
||||
struct thread_ctx_t {
|
||||
ma_arena_t scratch[3];
|
||||
ma_arena_t temp; // application specific arena
|
||||
|
||||
// I probably want to discourage using it implicitly like: tcx.perm, instead just pass it around
|
||||
// to functions that allocate pernament memory. temp and scratch very nicely create reusable code
|
||||
// perm is basically gb state so it would be nice to annotate which functions are reusable
|
||||
// and which functions have state
|
||||
ma_arena_t perm;
|
||||
|
||||
void *app_ctx;
|
||||
void *rn_ctx;
|
||||
void *ui_ctx;
|
||||
void *te_ctx;
|
||||
void *user_ctx;
|
||||
|
||||
logger_t log;
|
||||
int thread_index;
|
||||
};
|
||||
|
||||
#define alloc_type(alo, type) (type *)alloc_size((aloc), sizeof(type))
|
||||
#define alloc_array(alo, type, count) (type *)alloc_size((alo), sizeof(type) * (count))
|
||||
fn alo_t malo(ma_arena_t *arena);
|
||||
fn alo_t malot(ma_temp_t temp);
|
||||
fn void dealloc(alo_t alo, void *ptr);
|
||||
fn void *alloc_size(alo_t alo, size_t size);
|
||||
fn int tcx_alloc_id(void);
|
||||
|
||||
extern gb_thread thread_ctx_t *tcx;
|
||||
217
src/core/core_hash_table.c
Normal file
217
src/core/core_hash_table.c
Normal file
@@ -0,0 +1,217 @@
|
||||
#include "core_hash_table.h"
|
||||
#include "core_platform.h"
|
||||
|
||||
// xorshift64
|
||||
fn u64 get_random_u64(random_seed_t *seed) {
|
||||
u64 x = seed->a;
|
||||
x ^= x << 13;
|
||||
x ^= x >> 7;
|
||||
x ^= x << 17;
|
||||
return seed->a = x;
|
||||
}
|
||||
|
||||
fn u64 get_random_in_range_u64(random_seed_t *seed, u64 start, u64 one_past_end) {
|
||||
u64 r = get_random_u64(seed);
|
||||
u64 diff = one_past_end - start;
|
||||
u64 rr = r % diff;
|
||||
u64 rrr = rr + start;
|
||||
return rrr;
|
||||
}
|
||||
|
||||
fn i64 get_random_in_range_i64(random_seed_t *seed, i64 start, i64 one_past_end) {
|
||||
u64 r = get_random_u64(seed);
|
||||
i64 diff = one_past_end - start;
|
||||
u64 rr = r % diff;
|
||||
i64 rrr = (i64)rr + start;
|
||||
return rrr;
|
||||
}
|
||||
|
||||
fn f64 get_random_f64(random_seed_t *seed) {
|
||||
f64 random = (f64)get_random_in_range_u64(seed, 0, UINT32_MAX);
|
||||
f64 result = random / (f64)(UINT32_MAX - 1u);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn u64 hash_data(s8_t string) {
|
||||
u8 *data = (u8 *)string.str;
|
||||
u64 hash = (u64)14695981039346656037ULL;
|
||||
for (i64 i = 0; i < string.len; i++) {
|
||||
hash = hash ^ (u64)(data[i]);
|
||||
hash = hash * (u64)1099511628211ULL;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
fn u64 hash_mix(u64 x, u64 y) {
|
||||
x ^= y;
|
||||
x *= 0xff51afd7ed558ccd;
|
||||
x ^= x >> 32;
|
||||
return x;
|
||||
}
|
||||
|
||||
fn ht_t *ht_create(ma_arena_t *arena, i32 size) {
|
||||
ht_t *result = ma_push_type(arena, ht_t);
|
||||
result->buckets = ma_push_array(arena, ht_bucket_t, size);
|
||||
result->bucket_count = size;
|
||||
result->arena = arena;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_insert_kv(ht_t *ht, u64 hash, ht_key_value_t kv) {
|
||||
ht_node_t *result = ma_push_type(ht->arena, ht_node_t);
|
||||
result->kv = kv;
|
||||
i64 idx = hash % ht->bucket_count;
|
||||
SLLQ_APPEND(ht->buckets[idx].first, ht->buckets[idx].last, result);
|
||||
ht->item_count += 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_insert_u64(ht_t *ht, u64 key, u64 value) {
|
||||
u64 hash = hash_data(s8_struct(key));
|
||||
return ht_insert_kv(ht, hash, (ht_key_value_t){.key_u64 = key, .value_u64 = value});
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_insert_ptr(ht_t *ht, void *key, void *value) {
|
||||
return ht_insert_u64(ht, (u64)key, (u64)value);
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_insert_string(ht_t *ht, s8_t key, s8_t value) {
|
||||
u64 hash = hash_data(key);
|
||||
return ht_insert_kv(ht, hash, (ht_key_value_t){.key_string = key, .value_string = value});
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_insert_string_ptr(ht_t *ht, s8_t key, void *value) {
|
||||
u64 hash = hash_data(key);
|
||||
return ht_insert_kv(ht, hash, (ht_key_value_t){.key_string = key, .value_ptr = value});
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_search_u64_ex(ht_t *ht, u64 key) {
|
||||
u64 hash = hash_data(s8_struct(key));
|
||||
i64 idx = hash % ht->bucket_count;
|
||||
ht_bucket_t *bucket = ht->buckets + idx;
|
||||
for (ht_node_t *it = bucket->first; it; it = it->next) {
|
||||
if (it->kv.key_u64 == key) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_search_ptr_ex(ht_t *ht, void *key) {
|
||||
u64 hash = hash_data(s8_struct(key));
|
||||
i64 idx = hash % ht->bucket_count;
|
||||
ht_bucket_t *bucket = ht->buckets + idx;
|
||||
for (ht_node_t *it = bucket->first; it; it = it->next) {
|
||||
if (it->kv.key_ptr == key) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_search_string_ex(ht_t *ht, s8_t key) {
|
||||
u64 hash = hash_data(key);
|
||||
i64 idx = hash % ht->bucket_count;
|
||||
ht_bucket_t *bucket = ht->buckets + idx;
|
||||
for (ht_node_t *it = bucket->first; it; it = it->next) {
|
||||
if (s8_are_equal(it->kv.key_string, key)) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn u64 *ht_search_u64(ht_t *ht, u64 key) {
|
||||
ht_node_t *node = ht_search_u64_ex(ht, key);
|
||||
if (node) return &node->kv.value_u64;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn void **ht_search_ptr(ht_t *ht, void *key) {
|
||||
ht_node_t *node = ht_search_ptr_ex(ht, key);
|
||||
if (node) return &node->kv.value_ptr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn s8_t *ht_search_string(ht_t *ht, s8_t key) {
|
||||
ht_node_t *node = ht_search_string_ex(ht, key);
|
||||
if (node) return &node->kv.value_string;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn void **ht_search_string_ptr(ht_t *ht, s8_t key) {
|
||||
ht_node_t *node = ht_search_string_ex(ht, key);
|
||||
if (node) return &node->kv.value_ptr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// string interning
|
||||
fn s8i_t *intern_string(ht_t *ht, s8_t string) {
|
||||
s8_t *item = ht_search_string(ht, string);
|
||||
if (!item) {
|
||||
string = s8_copy(ht->arena, string);
|
||||
ht_node_t *node = ht_insert_string(ht, string, string);
|
||||
item = &node->kv.value_string;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
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_expr(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("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);
|
||||
}
|
||||
73
src/core/core_hash_table.h
Normal file
73
src/core/core_hash_table.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
#include "core_arena.h"
|
||||
#include "core_string.h"
|
||||
|
||||
typedef struct ht_key_value_t ht_key_value_t;
|
||||
struct ht_key_value_t {
|
||||
union {
|
||||
s8_t key_string;
|
||||
u64 key_u64;
|
||||
void *key_ptr;
|
||||
};
|
||||
union {
|
||||
s8_t value_string;
|
||||
void *value_ptr;
|
||||
u64 value_u64;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct ht_node_t ht_node_t;
|
||||
struct ht_node_t {
|
||||
ht_node_t *next;
|
||||
ht_key_value_t kv;
|
||||
};
|
||||
|
||||
typedef struct ht_bucket_t ht_bucket_t;
|
||||
struct ht_bucket_t {
|
||||
ht_node_t *first;
|
||||
ht_node_t *last;
|
||||
};
|
||||
|
||||
typedef struct ht_t ht_t;
|
||||
struct ht_t {
|
||||
ma_arena_t *arena;
|
||||
i32 item_count;
|
||||
i32 bucket_count;
|
||||
ht_bucket_t *buckets;
|
||||
};
|
||||
|
||||
fn ht_t *ht_create (ma_arena_t *arena, i32 size);
|
||||
fn ht_node_t *ht_insert_kv (ht_t *ht, u64 hash, ht_key_value_t kv);
|
||||
fn ht_node_t *ht_insert_u64 (ht_t *ht, u64 key, u64 value);
|
||||
fn ht_node_t *ht_insert_ptr (ht_t *ht, void *key, void *value);
|
||||
fn ht_node_t *ht_insert_string (ht_t *ht, s8_t key, s8_t value);
|
||||
fn ht_node_t *ht_insert_string_ptr (ht_t *ht, s8_t key, void *value);
|
||||
fn u64 *ht_search_u64 (ht_t *ht, u64 key);
|
||||
fn void **ht_search_ptr (ht_t *ht, void *key);
|
||||
fn s8_t *ht_search_string (ht_t *ht, s8_t key);
|
||||
fn void **ht_search_string_ptr (ht_t *ht, s8_t key);
|
||||
fn ht_node_t *ht_search_u64_ex (ht_t *ht, u64 key);
|
||||
fn ht_node_t *ht_search_ptr_ex (ht_t *ht, void *key);
|
||||
fn ht_node_t *ht_search_string_ex (ht_t *ht, s8_t key);
|
||||
|
||||
///////////////////////////////
|
||||
// string interning
|
||||
#define s8i_t s8_t
|
||||
fn s8i_t *intern_string(ht_t *ht, s8_t string);
|
||||
fn s8i_t *internf(ht_t *ht, char *str, ...);
|
||||
|
||||
|
||||
///////////////////////////////
|
||||
// Hashing
|
||||
typedef struct random_seed_t random_seed_t;
|
||||
struct random_seed_t {
|
||||
u64 a;
|
||||
};
|
||||
|
||||
fn u64 get_random_u64(random_seed_t *seed);
|
||||
fn u64 get_random_in_range_u64(random_seed_t *seed, u64 start, u64 one_past_end);
|
||||
fn i64 get_random_in_range_i64(random_seed_t *seed, i64 start, i64 one_past_end);
|
||||
fn f64 get_random_f64(random_seed_t *seed);
|
||||
fn u64 hash_data(s8_t string);
|
||||
fn u64 hash_mix(u64 x, u64 y);
|
||||
242
src/core/core_intrin.c
Normal file
242
src/core/core_intrin.c
Normal file
@@ -0,0 +1,242 @@
|
||||
#include "core_intrin.h"
|
||||
#include "core_basic.h"
|
||||
#include "core_platform.h"
|
||||
|
||||
fn void memory_copy(void *dst, void *src, usize n) {
|
||||
IF_PLATFORM_CLANG_ELSE(__builtin_memcpy(dst, src, n), memcpy(dst, src, n));
|
||||
}
|
||||
|
||||
fn void memory_move(void *dest, const void *src, usize n) {
|
||||
IF_PLATFORM_CLANG_ELSE(__builtin_memmove(dest, src, n), memmove(dest, src, n));
|
||||
}
|
||||
|
||||
fn void memory_set(void *dst, i32 c, usize size) {
|
||||
IF_PLATFORM_CLANG_ELSE(__builtin_memset(dst, c, size), memset(dst, c, size));
|
||||
}
|
||||
|
||||
fn int bad_memory__compare(void *left, void *right, usize size) {
|
||||
u8 *l = left;
|
||||
u8 *r = right;
|
||||
for (usize i = 0; i < size; i += 1) {
|
||||
if (l[i] != r[i]) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn b32 memory_equal(void *left, void *right, usize size) {
|
||||
int cmp = IF_PLATFORM_CLANG_ELSE(bad_memory__compare(left, right, size), memcmp(left, right, size));
|
||||
return cmp == 0;
|
||||
}
|
||||
|
||||
fn void memory_zero(void *dst, usize size) {
|
||||
memory_set(dst, 0, size);
|
||||
}
|
||||
|
||||
fn f32 f32_sqrt(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_sqrtf(x), sqrtf(x)); }
|
||||
fn f64 f64_sqrt(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_sqrt(x), sqrt(x)); }
|
||||
fn f32 f32_ceil(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_ceilf(x), ceilf(x)); }
|
||||
fn f64 f64_ceil(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_ceil(x), ceil(x)); }
|
||||
fn f32 f32_floor(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_floorf(x), floorf(x)); }
|
||||
fn f64 f64_floor(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_floor(x), floor(x)); }
|
||||
fn f32 f32_abs(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_fabsf(x), fabsf(x)); }
|
||||
fn f64 f64_abs(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_fabs(x), fabs(x)); }
|
||||
// fn f32 f32_round(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_roundf(x), roundf(x)); }
|
||||
fn f64 f64_round(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_round(x), round(x)); }
|
||||
fn f64 f64_mod(f64 a, f64 b) { return IF_PLATFORM_CLANG_ELSE(__builtin_fmod(a, b), fmod(a, b)); }
|
||||
fn f32 f32_mod(f32 a, f32 b) { return IF_PLATFORM_CLANG_ELSE(__builtin_fmodf(a, b), fmodf(a, b)); }
|
||||
|
||||
/* https://gitlab.com/nakst/essence/-/blob/master/shared/math.cpp
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
** SOFTWARE.
|
||||
**
|
||||
*/
|
||||
|
||||
fn f64 f64_exp2(f64 x) {
|
||||
f64 a = f64_floor(x * 8);
|
||||
int64_t ai = (i64)a;
|
||||
|
||||
if (ai < -1024) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
f64 b = x - a / 8;
|
||||
|
||||
f64 y = U64_TO_F64(0x3FF0000000000000) +
|
||||
b * (U64_TO_F64(0x3FE62E42FEFA3A00) +
|
||||
b * (U64_TO_F64(0x3FCEBFBDFF829140) +
|
||||
b * (U64_TO_F64(0x3FAC6B08D73C4A40) +
|
||||
b * (U64_TO_F64(0x3F83B2AB53873280) +
|
||||
b * (U64_TO_F64(0x3F55D88F363C6C00) +
|
||||
b * (U64_TO_F64(0x3F242C003E4A2000) +
|
||||
b * U64_TO_F64(0x3EF0B291F6C00000)))))));
|
||||
|
||||
f64 m[8] = {
|
||||
U64_TO_F64(0x3FF0000000000000),
|
||||
U64_TO_F64(0x3FF172B83C7D517B),
|
||||
U64_TO_F64(0x3FF306FE0A31B715),
|
||||
U64_TO_F64(0x3FF4BFDAD5362A27),
|
||||
U64_TO_F64(0x3FF6A09E667F3BCD),
|
||||
U64_TO_F64(0x3FF8ACE5422AA0DB),
|
||||
U64_TO_F64(0x3FFAE89F995AD3AD),
|
||||
U64_TO_F64(0x3FFD5818DCFBA487),
|
||||
};
|
||||
|
||||
y *= m[ai & 7];
|
||||
|
||||
convert_f64_u64_t c;
|
||||
c.f = y;
|
||||
c.i += (ai >> 3) << 52;
|
||||
return c.f;
|
||||
}
|
||||
|
||||
fn f32 f32_exp2(f32 x) {
|
||||
f32 a = f32_floor(x);
|
||||
i32 ai = (i32)a;
|
||||
|
||||
if (ai < -128) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
f32 b = x - a;
|
||||
|
||||
f32 y = U32_TO_F32(0x3F7FFFFE) + b * (U32_TO_F32(0x3F31729A) + b * (U32_TO_F32(0x3E75E700) + b * (U32_TO_F32(0x3D64D520) + b * (U32_TO_F32(0x3C128280) + b * U32_TO_F32(0x3AF89400)))));
|
||||
|
||||
convert_f32_u32_t c;
|
||||
c.f = y;
|
||||
c.i += ai << 23;
|
||||
return c.f;
|
||||
}
|
||||
|
||||
fn f64 f64_log2(f64 x) {
|
||||
convert_f64_u64_t c;
|
||||
c.f = x;
|
||||
int64_t e = ((c.i >> 52) & 2047) - 0x3FF;
|
||||
c.i = (c.i & ~((uint64_t)0x7FF << 52)) + ((uint64_t)0x3FF << 52);
|
||||
x = c.f;
|
||||
|
||||
f64 a;
|
||||
|
||||
if (x < 1.125) {
|
||||
a = 0;
|
||||
} else if (x < 1.250) {
|
||||
x *= 1.125 / 1.250;
|
||||
a = U64_TO_F64(0xBFC374D65D9E608E);
|
||||
} else if (x < 1.375) {
|
||||
x *= 1.125 / 1.375;
|
||||
a = U64_TO_F64(0xBFD28746C334FECB);
|
||||
} else if (x < 1.500) {
|
||||
x *= 1.125 / 1.500;
|
||||
a = U64_TO_F64(0xBFDA8FF971810A5E);
|
||||
} else if (x < 1.625) {
|
||||
x *= 1.125 / 1.625;
|
||||
a = U64_TO_F64(0xBFE0F9F9FFC8932A);
|
||||
} else if (x < 1.750) {
|
||||
x *= 1.125 / 1.750;
|
||||
a = U64_TO_F64(0xBFE465D36ED11B11);
|
||||
} else if (x < 1.875) {
|
||||
x *= 1.125 / 1.875;
|
||||
a = U64_TO_F64(0xBFE79538DEA712F5);
|
||||
} else {
|
||||
x *= 1.125 / 2.000;
|
||||
a = U64_TO_F64(0xBFEA8FF971810A5E);
|
||||
}
|
||||
|
||||
f64 y = U64_TO_F64(0xC00FF8445026AD97) + x * (U64_TO_F64(0x40287A7A02D9353F) + x * (U64_TO_F64(0xC03711C58D55CEE2) + x * (U64_TO_F64(0x4040E8263C321A26) + x * (U64_TO_F64(0xC041EB22EA691BB3) + x * (U64_TO_F64(0x403B00FB376D1F10) + x * (U64_TO_F64(0xC02C416ABE857241) + x * (U64_TO_F64(0x40138BA7FAA3523A) + x * (U64_TO_F64(0xBFF019731AF80316) + x * U64_TO_F64(0x3FB7F1CD3852C200)))))))));
|
||||
|
||||
return y - a + e;
|
||||
}
|
||||
|
||||
fn f32 f32_log2(f32 x) {
|
||||
// TODO f32_log2(0.9999971379999999f) gives 0.00000143051147460938 (should be negative!!).
|
||||
|
||||
convert_f32_u32_t c;
|
||||
c.f = x;
|
||||
i32 e = ((c.i >> 23) & 255) - 0x7F;
|
||||
c.i = (c.i & ~(0xFF << 23)) + (0x7F << 23);
|
||||
x = c.f;
|
||||
|
||||
f32 y = U32_TO_F32(0xC05B5154) + x * (U32_TO_F32(0x410297C6) + x * (U32_TO_F32(0xC1205CEB) + x * (U32_TO_F32(0x4114DF63) + x * (U32_TO_F32(0xC0C0DBBB) + x * (U32_TO_F32(0x402942C6) + x * (U32_TO_F32(0xBF3FF98A) + x * (U32_TO_F32(0x3DFE1050) + x * U32_TO_F32(0xBC151480))))))));
|
||||
|
||||
return y + e;
|
||||
}
|
||||
|
||||
fn f64 f64_pow(f64 x, f64 y) {
|
||||
return f64_exp2(y * f64_log2(x));
|
||||
}
|
||||
|
||||
fn f32 f32_pow(f32 x, f32 y) {
|
||||
return f32_exp2(y * f32_log2(x));
|
||||
}
|
||||
|
||||
//
|
||||
/* https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=newlib/libm/common/s_round.c;hb=master
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
**/
|
||||
fn f32 f32_round(f32 x) {
|
||||
u32 w = F32_TO_U32(x);
|
||||
/* Most significant word, least significant word. */
|
||||
int exponent_less_127;
|
||||
|
||||
/* Extract exponent field. */
|
||||
exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
|
||||
|
||||
if (exponent_less_127 < 23) {
|
||||
if (exponent_less_127 < 0) {
|
||||
w &= 0x80000000;
|
||||
if (exponent_less_127 == -1)
|
||||
/* Result is +1.0 or -1.0. */
|
||||
w |= ((u32)127 << 23);
|
||||
} else {
|
||||
unsigned int exponent_mask = 0x007fffff >> exponent_less_127;
|
||||
if ((w & exponent_mask) == 0)
|
||||
/* x has an integral value. */
|
||||
return x;
|
||||
|
||||
w += 0x00400000 >> exponent_less_127;
|
||||
w &= ~exponent_mask;
|
||||
}
|
||||
} else {
|
||||
if (exponent_less_127 == 128)
|
||||
/* x is NaN or infinite. */
|
||||
return x + x;
|
||||
else
|
||||
return x;
|
||||
}
|
||||
x = U32_TO_F32(w);
|
||||
return x;
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// other
|
||||
fn u32 u32_safe_cast(u64 v) {
|
||||
assert_expr(v <= u32_max);
|
||||
return (u32)v;
|
||||
}
|
||||
|
||||
fn u16 u16_safe_cast(u64 v) {
|
||||
assert(v <= u16_max);
|
||||
return (u16)v;
|
||||
}
|
||||
|
||||
fn u8 u8_safe_cast(u64 v) {
|
||||
assert(v <= u8_max);
|
||||
return (u8)v;
|
||||
}
|
||||
|
||||
fn i32 i32_safe_cast(i64 v) {
|
||||
assert(v >= i32_min && v <= i32_max);
|
||||
return (i32)v;
|
||||
}
|
||||
32
src/core/core_intrin.h
Normal file
32
src/core/core_intrin.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
|
||||
fn void memory_copy(void *dst, void *src, usize n);
|
||||
fn void memory_move(void *dest, const void *src, usize n);
|
||||
fn void memory_set(void *dst, i32 c, usize size);
|
||||
fn b32 memory_equal(void *left, void *right, usize size);
|
||||
fn void memory_zero(void *dst, usize size);
|
||||
|
||||
fn f32 f32_sqrt(f32 x);
|
||||
fn f64 f64_sqrt(f64 x);
|
||||
fn f32 f32_ceil(f32 x);
|
||||
fn f64 f64_ceil(f64 x);
|
||||
fn f32 f32_floor(f32 x);
|
||||
fn f64 f64_floor(f64 x);
|
||||
fn f32 f32_abs(f32 x);
|
||||
fn f64 f64_abs(f64 x);
|
||||
fn f32 f32_round(f32 x);
|
||||
fn f64 f64_round(f64 x);
|
||||
fn f64 f64_mod(f64 a, f64 b);
|
||||
fn f32 f32_mod(f32 a, f32 b);
|
||||
fn f64 f64_exp2(f64 x);
|
||||
fn f32 f32_exp2(f32 x);
|
||||
fn f64 f64_log2(f64 x);
|
||||
fn f32 f32_log2(f32 x);
|
||||
fn f64 f64_pow(f64 x, f64 y);
|
||||
fn f32 f32_pow(f32 x, f32 y);
|
||||
fn f32 f32_round(f32 x);
|
||||
fn u32 u32_safe_cast(u64 v);
|
||||
fn u16 u16_safe_cast(u64 v);
|
||||
fn u8 u8_safe_cast(u64 v);
|
||||
fn i32 i32_safe_cast(i64 v);
|
||||
469
src/core/core_lexer.c
Normal file
469
src/core/core_lexer.c
Normal file
@@ -0,0 +1,469 @@
|
||||
#include "core_lexer.h"
|
||||
#include "core_log.h"
|
||||
#include "core_platform.h"
|
||||
#include "core_ctx.h"
|
||||
|
||||
#define lex_error(TOKEN, STRING) do {\
|
||||
errorf(STRING);\
|
||||
TOKEN->kind = lex_kind_error;\
|
||||
TOKEN->string = s8(STRING);\
|
||||
} while (0)
|
||||
|
||||
fn lexer_t lex_make(s8_t stream, char *file_name) {
|
||||
lexer_t result = {.at = stream.str, .end = stream.str + stream.len, .file = file_name};
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 lex_at_end(lexer_t *lex) {
|
||||
b32 result = lex->at >= lex->end;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void lex_advance(lexer_t *lex) {
|
||||
if (lex_at_end(lex)) return;
|
||||
if (lex->at[0] == '\n') { lex->column = 0; lex->line += 1; }
|
||||
lex->column += 1;
|
||||
lex->at += 1;
|
||||
}
|
||||
|
||||
fn b32 lex_match(lexer_t *lex, char c) {
|
||||
if (lex->at[0] == c) {
|
||||
lex_advance(lex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn void lex_eat_whitespace(lexer_t *lex) {
|
||||
for (;;) {
|
||||
if (char_is_whitespace(lex->at[0])) {
|
||||
if (lex->at[0] == '\n') lex->inside_macro = false;
|
||||
lex_advance(lex);
|
||||
} else if (lex->at[0] == '\\' && lex->at[1] == '\n') {
|
||||
lex_advance(lex); lex_advance(lex);
|
||||
} else if (lex->at[0] == '\\' && lex->at[1] == '\r' && lex->at[2] == '\n') {
|
||||
lex_advance(lex); lex_advance(lex); lex_advance(lex);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void lex_eat_macro_whitespace(lexer_t *lex) {
|
||||
while (lex->at[0] == ' ' || lex->at[0] == '\t') lex_advance(lex);
|
||||
}
|
||||
|
||||
fn void lex_suffix(lexer_t *lex, lex_t *token) {
|
||||
if (lex_match(lex, 'f')) {
|
||||
token->kind = lex_kind_real;
|
||||
token->suffix = lex_suffix_f;
|
||||
} else if (lex_match(lex, 'd')) {
|
||||
token->kind = lex_kind_real;
|
||||
token->suffix = lex_suffix_d;
|
||||
} else if (token->kind == lex_kind_integer && ((lex->at[0] == 'u' && lex->at[1] == 'l' && lex->at[2] == 'l') || (lex->at[0] == 'U' && lex->at[1] == 'L' && lex->at[2] == 'L'))) {
|
||||
token->suffix = lex_suffix_ull;
|
||||
lex_advance(lex); lex_advance(lex); lex_advance(lex);
|
||||
} else if (token->kind == lex_kind_integer && ((lex->at[0] == 'u' && lex->at[1] == 'l') || (lex->at[0] == 'U' && lex->at[1] == 'L'))) {
|
||||
token->suffix = lex_suffix_ul;
|
||||
lex_advance(lex); lex_advance(lex);
|
||||
} else if (token->kind == lex_kind_integer && (lex->at[0] == 'l' || lex->at[0] == 'L')) {
|
||||
token->suffix = lex_suffix_l;
|
||||
lex_advance(lex);
|
||||
} else if (token->kind == lex_kind_integer && ((lex->at[0] == 'l' && lex->at[1] == 'l') || (lex->at[0] == 'L' && lex->at[1] == 'L'))) {
|
||||
token->suffix = lex_suffix_ll;
|
||||
lex_advance(lex); lex_advance(lex);
|
||||
}
|
||||
}
|
||||
|
||||
fn void lex_eat_number(lexer_t *lex, lex_t *token) {
|
||||
token->kind = lex_kind_integer;
|
||||
for (;;) {
|
||||
if (char_is_digit(lex->at[0])) {
|
||||
lex_advance(lex);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lex_match(lex, '.')) {
|
||||
if (token->kind == lex_kind_real) {
|
||||
lex_error(token, "multiple '.' periods in floating point number literal");
|
||||
return;
|
||||
}
|
||||
token->kind = lex_kind_real;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
lex_suffix(lex, token);
|
||||
}
|
||||
|
||||
fn void lex_eat_until(lexer_t *lex, char c) {
|
||||
while (lex->at[0] != c && !lex_at_end(lex)) lex_advance(lex);
|
||||
}
|
||||
|
||||
fn void lex_eat_string(lexer_t *lex, lex_t *token) {
|
||||
token->kind = lex_kind_string;
|
||||
for (;;) {
|
||||
if (lex->at[0] == '\\') {
|
||||
lex_advance(lex);
|
||||
} else if (lex_match(lex, token->str[0])) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (lex->at[0] == 0) {
|
||||
lex_error(token, "unclosed string");
|
||||
return;
|
||||
}
|
||||
|
||||
lex_advance(lex);
|
||||
}
|
||||
}
|
||||
|
||||
fn b32 lex_macro(lexer_t *lex, lex_t *token) {
|
||||
lex_eat_macro_whitespace(lex);
|
||||
token->str = lex->at;
|
||||
while (char_is_alphabetic(lex->at[0])) lex_advance(lex);
|
||||
token->len = (i32)(lex->at - token->str);
|
||||
|
||||
if (s8_are_equal(token->string, s8("define"))) {
|
||||
token->kind = lex_kind_preproc_define;
|
||||
} else if (s8_are_equal(token->string, s8("ifdef"))) {
|
||||
token->kind = lex_kind_preproc_ifdef;
|
||||
} else if (s8_are_equal(token->string, s8("ifndef"))) {
|
||||
token->kind = lex_kind_preproc_ifndef;
|
||||
} else if (s8_are_equal(token->string, s8("include"))) {
|
||||
token->kind = lex_kind_preproc_include;
|
||||
lex_eat_macro_whitespace(lex);
|
||||
char end = 0;
|
||||
if (lex_match(lex, '"')) {
|
||||
end = '"';
|
||||
} else if (lex_match(lex, '<')) {
|
||||
end = '>';
|
||||
token->system_include = true;
|
||||
} else {
|
||||
lex_error(token, "invalid include directive, should be followed by string or '<'");
|
||||
return false;
|
||||
}
|
||||
|
||||
token->str = lex->at;
|
||||
while (lex->at[0] != end) {
|
||||
if (lex_at_end(lex)) {
|
||||
lex_error(token, "invalid include directive, reached end of file");
|
||||
return false;
|
||||
}
|
||||
if (lex->at[0] == '\n') {
|
||||
lex_error(token, "invalid include directive, reached end of line");
|
||||
return false;
|
||||
}
|
||||
lex_advance(lex);
|
||||
}
|
||||
lex_advance(lex);
|
||||
} else if (s8_are_equal(token->string, s8("if"))) {
|
||||
token->kind = lex_kind_preproc_if;
|
||||
} else if (s8_are_equal(token->string, s8("endif"))) {
|
||||
token->kind = lex_kind_preproc_endif;
|
||||
} else if (s8_are_equal(token->string, s8("error"))) {
|
||||
token->kind = lex_kind_preproc_error;
|
||||
lex_eat_macro_whitespace(lex);
|
||||
token->str = lex->at;
|
||||
lex_eat_until(lex, '\n');
|
||||
} else if (s8_are_equal(token->string, s8("else"))) {
|
||||
token->kind = lex_kind_preproc_else;
|
||||
} else if (s8_are_equal(token->string, s8("elif"))) {
|
||||
token->kind = lex_kind_preproc_elif;
|
||||
} else if (s8_are_equal(token->string, s8("pragma"))) {
|
||||
token->kind = lex_kind_preproc_pragma;
|
||||
} else if (s8_are_equal(token->string, s8("undef"))) {
|
||||
token->kind = lex_kind_preproc_undef;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define LEX_CASE3(C1, K1, C2, K2, C3, K3) \
|
||||
case C1: { \
|
||||
token->kind = K1; \
|
||||
if (lex_match(lex, C2)) { \
|
||||
lex_advance(lex); \
|
||||
token->kind = K2; \
|
||||
} else if (lex_match(lex, C3)) { \
|
||||
lex_advance(lex); \
|
||||
token->kind = K3; \
|
||||
} \
|
||||
} break
|
||||
|
||||
fn void lex_token_ex(lexer_t *lex, lex_t *token) {
|
||||
lex_eat_whitespace(lex);
|
||||
*token = (lex_t){.str = lex->at, .file = lex->file, .line = lex->line, .column = lex->column};
|
||||
lex_advance(lex);
|
||||
|
||||
switch (token->str[0]) {
|
||||
case '\0': token->kind = lex_kind_eof; break;
|
||||
case '{': token->kind = lex_kind_open_brace; break;
|
||||
case '}': token->kind = lex_kind_close_brace; break;
|
||||
case '(': token->kind = lex_kind_open_paren; break;
|
||||
case ')': token->kind = lex_kind_close_paren; break;
|
||||
case '[': token->kind = lex_kind_open_bracket; break;
|
||||
case ']': token->kind = lex_kind_close_bracket; break;
|
||||
case '~': token->kind = lex_kind_bit_negation; break;
|
||||
case ';': token->kind = lex_kind_semicolon; break;
|
||||
case ':': token->kind = lex_kind_colon; break;
|
||||
case ',': token->kind = lex_kind_comma; break;
|
||||
case '@': token->kind = lex_kind_tag; break;
|
||||
case '?': token->kind = lex_kind_question; break;
|
||||
case '\\': token->kind = lex_kind_escape; break;
|
||||
case '"': lex_eat_string(lex, token); break;
|
||||
case '`': lex_eat_string(lex, token); break;
|
||||
case '\'': lex_eat_string(lex, token); break;
|
||||
|
||||
LEX_CASE3('^', lex_kind_bit_xor, '=', lex_kind_bit_xor_assign, /*ignored option*/'=', lex_kind_bit_xor_assign);
|
||||
LEX_CASE3('=', lex_kind_assign, '=', lex_kind_equals, /*ignored option*/'=', lex_kind_equals);
|
||||
LEX_CASE3('!', lex_kind_negation, '=', lex_kind_not_equals, /*ignored option*/'=', lex_kind_not_equals);
|
||||
LEX_CASE3('%', lex_kind_modulo, '=', lex_kind_modulo_assign, /*ignored option*/'=', lex_kind_modulo_assign);
|
||||
LEX_CASE3('*', lex_kind_multiply, '=', lex_kind_multiply_assign, /*ignored option*/'=', lex_kind_multiply_assign);
|
||||
LEX_CASE3('+', lex_kind_plus, '+', lex_kind_increment, '=', lex_kind_plus_assign);
|
||||
LEX_CASE3('-', lex_kind_minus, '-', lex_kind_decrement, '=', lex_kind_minus_assign);
|
||||
LEX_CASE3('&', lex_kind_bit_and, '&', lex_kind_and, '=', lex_kind_bit_and_assign);
|
||||
LEX_CASE3('|', lex_kind_bit_or, '|', lex_kind_or, '=', lex_kind_bit_or_assign);
|
||||
|
||||
case '.': {
|
||||
token->kind = lex_kind_dot;
|
||||
if (lex->at[0] == '.' && lex->at[1] == '.') {
|
||||
lex_advance(lex);
|
||||
lex_advance(lex);
|
||||
token->kind = lex_kind_three_dots;
|
||||
}
|
||||
} break;
|
||||
|
||||
case '/': {
|
||||
token->kind = lex_kind_divide;
|
||||
if (lex_match(lex, '/')) {
|
||||
token->kind = lex_kind_comment;
|
||||
lex_eat_until(lex, '\n');
|
||||
} else if (lex_match(lex, '*')) {
|
||||
token->kind = lex_kind_comment;
|
||||
for (;;) {
|
||||
if (lex->at[0] == '*' && lex->at[1] == '/') {
|
||||
break;
|
||||
}
|
||||
if (lex->at[0] == 0) {
|
||||
lex_error(token, "unclosed block comment");
|
||||
return;
|
||||
}
|
||||
lex_advance(lex);
|
||||
}
|
||||
lex_advance(lex);
|
||||
lex_advance(lex);
|
||||
} else if (lex_match(lex, '=')) {
|
||||
token->kind = lex_kind_divide_assign;
|
||||
}
|
||||
} break;
|
||||
|
||||
case '>': {
|
||||
token->kind = lex_kind_greater;
|
||||
if (lex_match(lex, '=')) {
|
||||
token->kind = lex_kind_greater_or_equal;
|
||||
} else if (lex_match(lex, '>')) {
|
||||
token->kind = lex_kind_bit_right_shift;
|
||||
if (lex_match(lex, '=')) {
|
||||
token->kind = lex_kind_bit_right_shift_assign;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case '<': {
|
||||
token->kind = lex_kind_lesser;
|
||||
if (lex_match(lex, '=')) {
|
||||
token->kind = lex_kind_lesser_or_equal;
|
||||
} else if (lex_match(lex, '<')) {
|
||||
token->kind = lex_kind_bit_left_shift;
|
||||
if (lex_match(lex, '=')) {
|
||||
token->kind = lex_kind_bit_left_shift_assign;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case '#': {
|
||||
if (lex_match(lex, '#')) {
|
||||
token->kind = lex_kind_preproc_concat;
|
||||
} else {
|
||||
b32 inside_macro = lex_macro(lex, token);
|
||||
if (inside_macro) {
|
||||
lex->inside_macro = true;
|
||||
} else {
|
||||
if (!lex->inside_macro) {
|
||||
lex_error(token, "invalid preprocessor directive");
|
||||
return;
|
||||
}
|
||||
token->kind = lex_kind_preproc_stringify;
|
||||
token->str = lex->at;
|
||||
// this is slighly wrong, first letter can't be number
|
||||
while (char_is_alphanumeric(lex->at[0]) || lex->at[0] == '_') lex_advance(lex);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': {
|
||||
lex_eat_number(lex, token);
|
||||
} break;
|
||||
|
||||
case 'A': case 'a': case 'B': case 'b': case 'C': case 'c':
|
||||
case 'D': case 'd': case 'E': case 'e': case 'F': case 'f':
|
||||
case 'G': case 'g': case 'H': case 'h': case 'I': case 'i':
|
||||
case 'J': case 'j': case 'K': case 'k': case 'L': case 'l':
|
||||
case 'M': case 'm': case 'N': case 'n': case 'O': case 'o':
|
||||
case 'P': case 'p': case 'Q': case 'q': case 'R': case 'r':
|
||||
case 'S': case 's': case 'T': case 't': case 'U': case 'u':
|
||||
case 'V': case 'v': case 'W': case 'w': case 'X': case 'x':
|
||||
case 'Y': case 'y': case 'Z': case 'z': case '_': {
|
||||
token->kind = lex_kind_ident;
|
||||
while (char_is_alphanumeric(lex->at[0]) || lex->at[0] == '_') lex_advance(lex);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
lex_error(token, "found invalid character in the token stream");
|
||||
}
|
||||
}
|
||||
|
||||
token->len = (i32)(lex->at - token->str);
|
||||
|
||||
if (token->kind == lex_kind_integer) {
|
||||
s8_t string_to_lex = token->string;
|
||||
if (token->suffix != lex_suffix_none) {
|
||||
s8_t string_value = ti_enum_value_to_name(token->suffix, type(lex_suffix_t));
|
||||
s8_t prefix = s8("lex_suffix_");
|
||||
string_to_lex.len -= string_value.len - prefix.len;
|
||||
}
|
||||
token->integer = u64_from_s8(string_to_lex, 10);
|
||||
} else if (token->kind == lex_kind_real) {
|
||||
s8_t string_to_lex = token->string;
|
||||
if (token->suffix != lex_suffix_none) {
|
||||
s8_t string_value = ti_enum_value_to_name(token->suffix, type(lex_suffix_t));
|
||||
s8_t prefix = s8("lex_suffix_");
|
||||
string_to_lex.len -= string_value.len - prefix.len;
|
||||
}
|
||||
token->real = f64_from_s8(string_to_lex);
|
||||
} else if (token->kind == lex_kind_string) {
|
||||
token->str += 1;
|
||||
token->len -= 2;
|
||||
} else if (token->kind == lex_kind_preproc_include) {
|
||||
token->len -= 1;
|
||||
}
|
||||
if (lex->inside_macro) token->inside_macro = true;
|
||||
}
|
||||
|
||||
fn lex_t lex_token(lexer_t *lex) {
|
||||
lex_t result = {0};
|
||||
lex_token_ex(lex, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn lex_array_t lex_tokens(ma_arena_t *arena, char *file_name, s8_t stream) {
|
||||
usize align = arena->align;
|
||||
arena->align = 0;
|
||||
|
||||
lex_array_t token_array = {0};
|
||||
lexer_t l = lex_make(stream, file_name);
|
||||
for (;;) {
|
||||
lex_t *token = ma_push_type(arena, lex_t);
|
||||
if (token_array.data == NULL) {
|
||||
token_array.data = token;
|
||||
}
|
||||
token_array.len += 1;
|
||||
|
||||
do {
|
||||
lex_token_ex(&l, token);
|
||||
} while (token->kind == lex_kind_comment);
|
||||
if (token->kind == lex_kind_eof) break;
|
||||
}
|
||||
|
||||
arena->align = align;
|
||||
return token_array;
|
||||
}
|
||||
|
||||
gb_read_only s8_t lex_kind_simple_strings[] = {
|
||||
#define X(KIND, STR, SIMPLE) s8_const(SIMPLE),
|
||||
LEX_KIND_XLIST
|
||||
#undef X
|
||||
};
|
||||
|
||||
fn s8_t lex_kind_to_simple_s8(lex_kind_t kind) {
|
||||
assert_expr(kind >= 0 && kind < lex_kind_count);
|
||||
return lex_kind_simple_strings[kind];
|
||||
}
|
||||
|
||||
gb_read_only s8_t lex_kind_strings[] = {
|
||||
#define X(KIND, STR, SIMPLE) s8_const(STR),
|
||||
LEX_KIND_XLIST
|
||||
#undef X
|
||||
};
|
||||
|
||||
fn s8_t lex_kind_to_s8(lex_kind_t kind) {
|
||||
assert(kind >= 0 && kind < lex_kind_count);
|
||||
return lex_kind_strings[kind];
|
||||
}
|
||||
|
||||
fn lex_t *parser_next(parser_t *par) {
|
||||
lex_t *result = par->at;
|
||||
if (result->kind != lex_kind_eof) par->at += 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn lex_t *parser_match(parser_t *par, lex_kind_t kind) {
|
||||
if (par->at->kind == kind) {
|
||||
return parser_next(par);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
fn lex_t *parser_matchi(parser_t *par, s8_t str) {
|
||||
if (par->at->kind == lex_kind_ident && s8_are_equal(par->at->string, str)) {
|
||||
return parser_next(par);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
fn void parser_panicf(b32 print_only_file, lex_t *token, const char *str, ...) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
b8 p = tcx->log.print_file_and_line;
|
||||
tcx->log.print_file_and_line = false;
|
||||
|
||||
S8_FMT(scratch.arena, str, str8);
|
||||
if (print_only_file) {
|
||||
fatalf("%s: error: %S", token->file, str8);
|
||||
} else {
|
||||
fatalf("%s(%d): error: %S", token->file, token->line, str8);
|
||||
}
|
||||
|
||||
|
||||
tcx->log.print_file_and_line = p;
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
|
||||
fn lex_t *parser_expect(parser_t *par, lex_kind_t kind) {
|
||||
lex_t *token = parser_match(par, kind);
|
||||
if (!token) parser_panicf(par->print_only_file, par->at, "expected token kind: %S, got instead: %S", lex_kind_to_s8(kind), lex_kind_to_s8(par->at->kind));
|
||||
return token;
|
||||
}
|
||||
|
||||
fn lex_t *parser_expecti(parser_t *par, s8_t ident) {
|
||||
lex_t *token = parser_matchi(par, ident);
|
||||
if (!token) parser_panicf(par->print_only_file, par->at, "expected identifier: '%S'", ident);
|
||||
return token;
|
||||
}
|
||||
|
||||
fn void parser_eat_until(parser_t *par, lex_kind_t kind) {
|
||||
while (par->at->kind != kind && par->at->kind != lex_kind_eof) {
|
||||
parser_next(par);
|
||||
}
|
||||
}
|
||||
|
||||
fn void parser_eat_including(parser_t *par, lex_kind_t kind) {
|
||||
parser_eat_until(par, kind);
|
||||
parser_next(par);
|
||||
}
|
||||
182
src/core/core_lexer.h
Normal file
182
src/core/core_lexer.h
Normal file
@@ -0,0 +1,182 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
#include "core_string.h"
|
||||
#include "core_arena.h"
|
||||
#include "core_type_info.h"
|
||||
|
||||
typedef enum lex_kind_t {
|
||||
#define LEX_KIND_XLIST\
|
||||
X(lex_kind_eof , "end of file" , "---" )\
|
||||
X(lex_kind_error , "error" , "---" )\
|
||||
X(lex_kind_integer , "integer" , "---" )\
|
||||
X(lex_kind_real , "real" , "---" )\
|
||||
X(lex_kind_ident , "identifier" , "---" )\
|
||||
X(lex_kind_string , "string" , "---" )\
|
||||
X(lex_kind_comment , "comment" , "---" )\
|
||||
X(lex_kind_open_brace , "'{' open brace" , "{" )\
|
||||
X(lex_kind_close_brace , "'}' close brace" , "}" )\
|
||||
X(lex_kind_open_paren , "'(' open parenthesis" , "(" )\
|
||||
X(lex_kind_close_paren , "')' close parenthesis" , ")" )\
|
||||
X(lex_kind_open_bracket , "'[' open bracket" , "[" )\
|
||||
X(lex_kind_close_bracket , "']' close bracket" , "]" )\
|
||||
X(lex_kind_plus , "'+' plus" , "+" )\
|
||||
X(lex_kind_minus , "'-' minus" , "-" )\
|
||||
X(lex_kind_divide , "'/' division sign" , "/" )\
|
||||
X(lex_kind_multiply , "'*' multiplication sign" , "*" )\
|
||||
X(lex_kind_modulo , "'%' modulo" , "%" )\
|
||||
X(lex_kind_or , "'||' logical or" , "||" )\
|
||||
X(lex_kind_and , "'&&' logical and" , "&&" )\
|
||||
X(lex_kind_negation , "'!' logical negation" , "!" )\
|
||||
X(lex_kind_bit_negation , "'~' bit negation" , "~" )\
|
||||
X(lex_kind_bit_left_shift , "'<<' bit left shift" , "<<" )\
|
||||
X(lex_kind_bit_right_shift , "'>>' bit right shift" , ">>" )\
|
||||
X(lex_kind_bit_or , "'|' bit or" , "|" )\
|
||||
X(lex_kind_bit_and , "'&' bit and" , "&" )\
|
||||
X(lex_kind_bit_xor , "'^' bit xor" , "^" )\
|
||||
X(lex_kind_decrement , "'--' decrement" , "--" )\
|
||||
X(lex_kind_increment , "'++' increment" , "++" )\
|
||||
X(lex_kind_post_decrement , "'--' post decrement" , "--" )\
|
||||
X(lex_kind_post_increment , "'++' post increment" , "++" )\
|
||||
X(lex_kind_assign , "'=' assignment" , "=" )\
|
||||
X(lex_kind_divide_assign , "'/=' divide assignment" , "/=" )\
|
||||
X(lex_kind_multiply_assign , "'*=' multiply assignment" , "*=" )\
|
||||
X(lex_kind_plus_assign , "'+=' plus assignment" , "+=" )\
|
||||
X(lex_kind_minus_assign , "'-=' minus assignment" , "-=" )\
|
||||
X(lex_kind_modulo_assign , "'%=' modulo assignment" , "%=" )\
|
||||
X(lex_kind_bit_and_assign , "'&=' bit and assignment" , "&=" )\
|
||||
X(lex_kind_bit_or_assign , "'|=' bit or assignment" , "|=" )\
|
||||
X(lex_kind_bit_xor_assign , "'^=' bit xor assignment" , "^=" )\
|
||||
X(lex_kind_bit_left_shift_assign , "'<<=' bit left shift assignment" , "<<=" )\
|
||||
X(lex_kind_bit_right_shift_assign , "'>>=' bit right shift assignment" , ">>=" )\
|
||||
X(lex_kind_equals , "'==' equals sign" , "==" )\
|
||||
X(lex_kind_not_equals , "'!=' not equals sign" , "!=" )\
|
||||
X(lex_kind_lesser , "'<' lesser then" , "<" )\
|
||||
X(lex_kind_greater , "'>' greater then" , ">" )\
|
||||
X(lex_kind_lesser_or_equal , "'<=' lesser then or equal" , "<=" )\
|
||||
X(lex_kind_greater_or_equal , "'>=' greater then or equal" , ">=" )\
|
||||
X(lex_kind_comma , "',' comma" , "," )\
|
||||
X(lex_kind_dot , "'.' dot" , "." )\
|
||||
X(lex_kind_three_dots , "'...' three dots" , "..." )\
|
||||
X(lex_kind_semicolon , "';' semicolon" , ";" )\
|
||||
X(lex_kind_colon , "':' colon" , ":" )\
|
||||
X(lex_kind_arrow , "'->' arrow" , "->" )\
|
||||
X(lex_kind_question , "'?' question mark" , "?" )\
|
||||
X(lex_kind_tag , "'@' tag sign" , "@" )\
|
||||
X(lex_kind_escape , "'\\' escape" , "\\" )\
|
||||
X(lex_kind_preproc_null , "preproc_null" , "---" )\
|
||||
X(lex_kind_preproc_define , "preproc_define" , "---" )\
|
||||
X(lex_kind_preproc_ifdef , "preproc_ifdef" , "---" )\
|
||||
X(lex_kind_preproc_ifndef , "preproc_ifndef" , "---" )\
|
||||
X(lex_kind_preproc_include , "preproc_include" , "---" )\
|
||||
X(lex_kind_preproc_endif , "preproc_endif" , "---" )\
|
||||
X(lex_kind_preproc_if , "preproc_if" , "---" )\
|
||||
X(lex_kind_preproc_pragma , "preproc_pragma" , "---" )\
|
||||
X(lex_kind_preproc_error , "preproc_error" , "---" )\
|
||||
X(lex_kind_preproc_else , "preproc_else" , "---" )\
|
||||
X(lex_kind_preproc_elif , "preproc_elif" , "---" )\
|
||||
X(lex_kind_preproc_undef , "preproc_undef" , "---" )\
|
||||
X(lex_kind_preproc_concat , "preproc_concat" , "---" )\
|
||||
X(lex_kind_preproc_stringify , "preproc_stringify" , "---" )\
|
||||
|
||||
#define X(KIND, STR, SIMPLE) KIND,
|
||||
LEX_KIND_XLIST
|
||||
#undef X
|
||||
|
||||
lex_kind_count,
|
||||
} lex_kind_t;
|
||||
|
||||
typedef enum lex_suffix_t {
|
||||
#define LEX_SUFFIX_XLIST\
|
||||
X(lex_suffix_none) \
|
||||
X(lex_suffix_f) \
|
||||
X(lex_suffix_d) \
|
||||
X(lex_suffix_u) \
|
||||
X(lex_suffix_ul) \
|
||||
X(lex_suffix_ull) \
|
||||
X(lex_suffix_l) \
|
||||
X(lex_suffix_ll) \
|
||||
|
||||
#define X(KIND) KIND,
|
||||
LEX_SUFFIX_XLIST
|
||||
#undef X
|
||||
|
||||
lex_suffix_count,
|
||||
} lex_suffix_t;
|
||||
|
||||
typedef struct lex_t lex_t;
|
||||
struct lex_t {
|
||||
lex_kind_t kind;
|
||||
lex_suffix_t suffix;
|
||||
struct {
|
||||
b8 inside_macro: 1;
|
||||
b8 system_include: 1;
|
||||
};
|
||||
|
||||
union {
|
||||
struct {char *str; i64 len;};
|
||||
s8_t string;
|
||||
};
|
||||
|
||||
i32 line;
|
||||
i32 column;
|
||||
char *file;
|
||||
|
||||
union {
|
||||
u64 integer;
|
||||
f64 real;
|
||||
char *error;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct lexer_t lexer_t;
|
||||
struct lexer_t {
|
||||
char *at;
|
||||
char *end;
|
||||
char *file;
|
||||
i32 line;
|
||||
i32 column;
|
||||
|
||||
b8 inside_macro;
|
||||
};
|
||||
|
||||
typedef struct lex_array_t lex_array_t;
|
||||
struct lex_array_t {
|
||||
lex_t *data;
|
||||
i32 len;
|
||||
};
|
||||
|
||||
fn lex_array_t lex_tokens(ma_arena_t *arena, char *filename, s8_t stream);
|
||||
fn s8_t lex_kind_to_simple_s8(lex_kind_t kind);
|
||||
fn s8_t lex_kind_to_s8(lex_kind_t kind);
|
||||
|
||||
typedef struct parser_t parser_t;
|
||||
struct parser_t {
|
||||
ma_arena_t *arena;
|
||||
lex_t *at;
|
||||
b8 print_only_file;
|
||||
};
|
||||
|
||||
#define parser_make(ARENA, TOKEN) &(parser_t){.arena = ARENA, .at = TOKEN}
|
||||
fn lex_t *parser_next(parser_t *par);
|
||||
fn lex_t *parser_match(parser_t *par, lex_kind_t kind);
|
||||
fn lex_t *parser_matchi(parser_t *par, s8_t str);
|
||||
fn lex_t *parser_expect(parser_t *par, lex_kind_t kind);
|
||||
fn void parser_panicf(b32 print_only_file, lex_t *token, const char *str, ...);
|
||||
fn void parser_eat_until(parser_t *par, lex_kind_t kind);
|
||||
fn void parser_eat_including(parser_t *par, lex_kind_t kind);
|
||||
|
||||
static gb_read_only lex_t lex_null;
|
||||
|
||||
static gb_read_only type_member_t members__lex_kind_t[] = {
|
||||
#define X(KIND, STR, SIMPLE) {.name = s8_const("lex_kind_" #KIND), .value = KIND},
|
||||
LEX_KIND_XLIST
|
||||
#undef X
|
||||
};
|
||||
static DEFINE_ENUM(lex_kind_t);
|
||||
|
||||
static gb_read_only type_member_t members__lex_suffix_t[] = {
|
||||
#define X(KIND) {.name = s8_const(#KIND), .value = KIND},
|
||||
LEX_SUFFIX_XLIST
|
||||
#undef X
|
||||
};
|
||||
static DEFINE_ENUM(lex_suffix_t);
|
||||
42
src/core/core_log.c
Normal file
42
src/core/core_log.c
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "core_log.h"
|
||||
#include "core_ctx.h"
|
||||
#include "core_platform.h"
|
||||
|
||||
fn void log_basef(log_level_t level, s8_t file_and_line, const char *str, ...) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
S8_FMT(scratch.arena, str, string);
|
||||
tcx->log.log_proc(level, file_and_line, string);
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
|
||||
fn void default_log_proc(log_level_t level, s8_t file_and_line, s8_t string) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
|
||||
char *colon = ": ";
|
||||
if (tcx->log.print_file_and_line == false) {
|
||||
file_and_line.len = 0;
|
||||
colon = "";
|
||||
}
|
||||
|
||||
switch(level) {
|
||||
case log_level_debug:
|
||||
case log_level_info: {
|
||||
os_console_log(s8_printf(scratch.arena, "%S\n", string).str);
|
||||
} break;
|
||||
case log_level_warning: {
|
||||
os_console_log(s8_printf(scratch.arena, "%S%s%S\n", file_and_line, colon, string).str);
|
||||
if (tcx->log.break_on_warning) debug_break();
|
||||
} break;
|
||||
case log_level_error: {
|
||||
os_console_log(s8_printf(scratch.arena, "%S%s%S\n", file_and_line, colon, string).str);
|
||||
if (tcx->log.break_on_error) debug_break();
|
||||
} break;
|
||||
case log_level_fatal: {
|
||||
os_error_box(s8_printf(scratch.arena, "%S%s%S\n", file_and_line, colon, string).str);
|
||||
if (tcx->log.break_on_fatal) debug_break();
|
||||
} break;
|
||||
default_is_invalid;
|
||||
}
|
||||
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
30
src/core/core_log.h
Normal file
30
src/core/core_log.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
#include "core_string.h"
|
||||
|
||||
typedef enum {
|
||||
log_level_debug,
|
||||
log_level_info,
|
||||
log_level_warning,
|
||||
log_level_error,
|
||||
log_level_fatal,
|
||||
} log_level_t;
|
||||
|
||||
typedef struct logger_t logger_t;
|
||||
struct logger_t {
|
||||
void (*log_proc)(log_level_t level, s8_t file_and_line, s8_t string);
|
||||
void *user_data;
|
||||
b8 break_on_fatal;
|
||||
b8 break_on_error;
|
||||
b8 break_on_warning;
|
||||
b8 print_file_and_line;
|
||||
};
|
||||
|
||||
///////////////////////////////
|
||||
// main api
|
||||
#define debugf(...) log_basef(log_level_debug, S8_FILE_AND_LINE, __VA_ARGS__)
|
||||
#define errorf(...) log_basef(log_level_error, S8_FILE_AND_LINE, __VA_ARGS__)
|
||||
#define fatalf(...) (log_basef(log_level_fatal, S8_FILE_AND_LINE, __VA_ARGS__), 0)
|
||||
|
||||
fn void default_log_proc(log_level_t level, s8_t file_and_line, s8_t string);
|
||||
fn void log_basef(log_level_t level, s8_t file_and_line, const char *str, ...);
|
||||
555
src/core/core_math.c
Normal file
555
src/core/core_math.c
Normal file
@@ -0,0 +1,555 @@
|
||||
#include "core_math.h"
|
||||
#include "core_intrin.h"
|
||||
|
||||
/*
|
||||
* Converts an RGB color value to HSL. Conversion formula
|
||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||||
* also https://gist.github.com/ciembor/1494530
|
||||
* alpha is ignored
|
||||
*/
|
||||
fn v3f32_t v3f32_rgb_to_hsl(v3f32_t color) {
|
||||
v3f32_t result;
|
||||
f32 max = MAX(MAX(color.r, color.g), color.b);
|
||||
f32 min = MIN(MIN(color.r, color.g), color.b);
|
||||
|
||||
result.h = result.s = result.l = (max + min) / 2.f;
|
||||
|
||||
if (max == min) {
|
||||
result.h = result.s = 0.f; // achromatic
|
||||
} else {
|
||||
f32 d = max - min;
|
||||
result.s = (result.l > 0.5f) ? d / (2.f - max - min) : d / (max + min);
|
||||
|
||||
if (max == color.r) {
|
||||
result.h = (color.g - color.b) / d + (color.g < color.b ? 6.f : 0.f);
|
||||
} else if (max == color.g) {
|
||||
result.h = (color.b - color.r) / d + 2.f;
|
||||
} else if (max == color.b) {
|
||||
result.h = (color.r - color.g) / d + 4.f;
|
||||
}
|
||||
|
||||
result.h /= 6.f;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts an HUE to r, g or b.
|
||||
* returns f32 in the set [0, 1].
|
||||
*/
|
||||
fn f32 f32_hue_to_rgb(f32 p, f32 q, f32 t) {
|
||||
if (t < 0.f)
|
||||
t += 1.f;
|
||||
if (t > 1.f)
|
||||
t -= 1.f;
|
||||
if (t < 1.f / 6.f)
|
||||
return p + (q - p) * 6.f * t;
|
||||
if (t < 1.f / 2.f)
|
||||
return q;
|
||||
if (t < 2.f / 3.f)
|
||||
return p + (q - p) * (2.f / 3.f - t) * 6.f;
|
||||
return p;
|
||||
}
|
||||
|
||||
fn v3f32_t v3f32_hsl_to_rgb(v3f32_t color) {
|
||||
v3f32_t result;
|
||||
|
||||
if (0 == color.s) {
|
||||
result.r = result.g = result.b = color.l; // achromatic
|
||||
} else {
|
||||
f32 q = color.l < 0.5f ? color.l * (1.f + color.s)
|
||||
: color.l + color.s - color.l * color.s;
|
||||
f32 p = 2.f * color.l - q;
|
||||
result.r = f32_hue_to_rgb(p, q, color.h + 1.f / 3.f);
|
||||
result.g = f32_hue_to_rgb(p, q, color.h);
|
||||
result.b = f32_hue_to_rgb(p, q, color.h - 1.f / 3.f);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn v4f32_t v4f32_rgba_to_hsla(v4f32_t rgba) {
|
||||
v3f32_t result = v3f32_rgb_to_hsl(rgba.xyz);
|
||||
return (v4f32_t){result.r, result.g, result.b, rgba.a};
|
||||
}
|
||||
|
||||
fn v4f32_t v4f32_hsla_to_rgba(v4f32_t color) {
|
||||
v3f32_t result = v3f32_hsl_to_rgb(color.xyz);
|
||||
return (v4f32_t){result.r, result.g, result.b, color.a};
|
||||
}
|
||||
|
||||
/*
|
||||
https://git.musl-libc.org/cgit/musl/tree/src/math
|
||||
https://gitlab.com/nakst/essence/-/blob/master/shared/math.cpp
|
||||
*/
|
||||
|
||||
|
||||
fn f64 f64_clamp01(f64 a) { return CLAMP(a, 0, 1); }
|
||||
fn f64 f64_lerp(f64 a, f64 b, f64 t) { return (1 - t) * a + t * b; }
|
||||
fn f64 f64_smooth_step(f64 t) { return t*t*(3-2*t); }
|
||||
fn f64 f64_ease_in_quint(f64 x) { return x * x * x * x * x; }
|
||||
fn f64 f64_ease_in_cubic(f64 x) { return x * x * x; }
|
||||
fn f64 f64_ping_pong(f64 x) { return 1.0 - f64_abs(1.0 - f64_mod(x,2)); }
|
||||
|
||||
fn f32 f32_clamp01(f32 a) { return CLAMP(a, 0, 1); }
|
||||
fn f32 f32_lerp(f32 a, f32 b, f32 t) { return (1 - t) * a + t * b; }
|
||||
fn f32 f32_smooth_step(f32 t) { return t*t*(3-2*t); }
|
||||
fn f32 f32_ease_in_quint(f32 x) { return x * x * x * x * x; }
|
||||
fn f32 f32_ease_in_cubic(f32 x) { return x * x * x; }
|
||||
fn f32 f32_ping_pong(f32 x) { return 1.0f - f32_abs(1.0f - f32_mod(x,2)); }
|
||||
|
||||
fn v4f32_t v4f32_lerp(v4f32_t a, v4f32_t b, f32 t) {
|
||||
return (v4f32_t){f32_lerp(a.x, b.x, t), f32_lerp(a.y, b.y, t), f32_lerp(a.z, b.z, t), f32_lerp(a.w, b.w, t)};
|
||||
}
|
||||
|
||||
fn v4f32_t v4f32_lerp_noa(v4f32_t a, v4f32_t b, f32 t) {
|
||||
return (v4f32_t){f32_lerp(a.x, b.x, t), f32_lerp(a.y, b.y, t), f32_lerp(a.z, b.z, t), a.w};
|
||||
}
|
||||
|
||||
fn f64 _Sine(f64 x) {
|
||||
// Calculates sin(x) for x in [0, pi/4].
|
||||
|
||||
f64 x2 = x * x;
|
||||
|
||||
return x * (U64_TO_F64(0x3FF0000000000000) + x2 * (U64_TO_F64(0xBFC5555555555540) + x2 * (U64_TO_F64(0x3F8111111110ED80) + x2 * (U64_TO_F64(0xBF2A01A019AE6000)
|
||||
+ x2 * (U64_TO_F64(0x3EC71DE349280000) + x2 * (U64_TO_F64(0xBE5AE5DC48000000) + x2 * U64_TO_F64(0x3DE5D68200000000)))))));
|
||||
}
|
||||
|
||||
fn f32 _SineFloat(f32 x) {
|
||||
// Calculates sin(x) for x in [0, pi/4].
|
||||
|
||||
f32 x2 = x * x;
|
||||
|
||||
return x * (U32_TO_F32(0x3F800000) + x2 * (U32_TO_F32(0xBE2AAAA0) + x2 * (U32_TO_F32(0x3C0882C0) + x2 * U32_TO_F32(0xB94C6000))));
|
||||
}
|
||||
|
||||
fn f64 _ArcSine(f64 x) {
|
||||
// Calculates arcsin(x) for x in [0, 0.5].
|
||||
|
||||
f64 x2 = x * x;
|
||||
|
||||
return x * (U64_TO_F64(0x3FEFFFFFFFFFFFE6) + x2 * (U64_TO_F64(0x3FC555555555FE00) + x2 * (U64_TO_F64(0x3FB333333292DF90) + x2 * (U64_TO_F64(0x3FA6DB6DFD3693A0)
|
||||
+ x2 * (U64_TO_F64(0x3F9F1C608DE51900) + x2 * (U64_TO_F64(0x3F96EA0659B9A080) + x2 * (U64_TO_F64(0x3F91B4ABF1029100)
|
||||
+ x2 * (U64_TO_F64(0x3F8DA8DAF31ECD00) + x2 * (U64_TO_F64(0x3F81C01FD5000C00) + x2 * (U64_TO_F64(0x3F94BDA038CF6B00)
|
||||
+ x2 * (U64_TO_F64(0xBF8E849CA75B1E00) + x2 * U64_TO_F64(0x3FA146C2D37F2C60))))))))))));
|
||||
}
|
||||
|
||||
fn f32 _ArcSineFloat(f32 x) {
|
||||
// Calculates arcsin(x) for x in [0, 0.5].
|
||||
|
||||
f32 x2 = x * x;
|
||||
|
||||
return x * (U32_TO_F32(0x3F800004) + x2 * (U32_TO_F32(0x3E2AA130) + x2 * (U32_TO_F32(0x3D9B2C28) + x2 * (U32_TO_F32(0x3D1C1800) + x2 * U32_TO_F32(0x3D5A97C0)))));
|
||||
}
|
||||
|
||||
fn f64 _ArcTangent(f64 x) {
|
||||
// Calculates arctan(x) for x in [0, 0.5].
|
||||
|
||||
f64 x2 = x * x;
|
||||
|
||||
return x * (U64_TO_F64(0x3FEFFFFFFFFFFFF8) + x2 * (U64_TO_F64(0xBFD5555555553B44) + x2 * (U64_TO_F64(0x3FC9999999803988) + x2 * (U64_TO_F64(0xBFC249248C882E80)
|
||||
+ x2 * (U64_TO_F64(0x3FBC71C5A4E4C220) + x2 * (U64_TO_F64(0xBFB745B3B75243F0) + x2 * (U64_TO_F64(0x3FB3AFAE9A2939E0)
|
||||
+ x2 * (U64_TO_F64(0xBFB1030C4A4A1B90) + x2 * (U64_TO_F64(0x3FAD6F65C35579A0) + x2 * (U64_TO_F64(0xBFA805BCFDAFEDC0)
|
||||
+ x2 * (U64_TO_F64(0x3F9FC6B5E115F2C0) + x2 * U64_TO_F64(0xBF87DCA5AB25BF80))))))))))));
|
||||
}
|
||||
|
||||
fn f32 _ArcTangentFloat(f32 x) {
|
||||
// Calculates arctan(x) for x in [0, 0.5].
|
||||
|
||||
f32 x2 = x * x;
|
||||
|
||||
return x * (U32_TO_F32(0x3F7FFFF8) + x2 * (U32_TO_F32(0xBEAAA53C) + x2 * (U32_TO_F32(0x3E4BC990) + x2 * (U32_TO_F32(0xBE084A60) + x2 * U32_TO_F32(0x3D8864B0)))));
|
||||
}
|
||||
|
||||
fn f64 _Cosine(f64 x) {
|
||||
// Calculates cos(x) for x in [0, pi/4].
|
||||
|
||||
f64 x2 = x * x;
|
||||
|
||||
return U64_TO_F64(0x3FF0000000000000) + x2 * (U64_TO_F64(0xBFDFFFFFFFFFFFA0) + x2 * (U64_TO_F64(0x3FA555555554F7C0) + x2 * (U64_TO_F64(0xBF56C16C16475C00)
|
||||
+ x2 * (U64_TO_F64(0x3EFA019F87490000) + x2 * (U64_TO_F64(0xBE927DF66B000000) + x2 * U64_TO_F64(0x3E21B949E0000000))))));
|
||||
}
|
||||
|
||||
fn f32 _CosineFloat(f32 x) {
|
||||
// Calculates cos(x) for x in [0, pi/4].
|
||||
|
||||
f32 x2 = x * x;
|
||||
|
||||
return U32_TO_F32(0x3F800000) + x2 * (U32_TO_F32(0xBEFFFFDA) + x2 * (U32_TO_F32(0x3D2A9F60) + x2 * U32_TO_F32(0xBAB22C00)));
|
||||
}
|
||||
|
||||
fn f64 _Tangent(f64 x) {
|
||||
// Calculates tan(x) for x in [0, pi/4].
|
||||
|
||||
f64 x2 = x * x;
|
||||
|
||||
return x * (U64_TO_F64(0x3FEFFFFFFFFFFFE8) + x2 * (U64_TO_F64(0x3FD5555555558000) + x2 * (U64_TO_F64(0x3FC1111110FACF90) + x2 * (U64_TO_F64(0x3FABA1BA266BFD20)
|
||||
+ x2 * (U64_TO_F64(0x3F9664F30E56E580) + x2 * (U64_TO_F64(0x3F822703B08BDC00) + x2 * (U64_TO_F64(0x3F6D698D2E4A4C00)
|
||||
+ x2 * (U64_TO_F64(0x3F57FF4F23EA4400) + x2 * (U64_TO_F64(0x3F424F3BEC845800) + x2 * (U64_TO_F64(0x3F34C78CA9F61000)
|
||||
+ x2 * (U64_TO_F64(0xBF042089F8510000) + x2 * (U64_TO_F64(0x3F29D7372D3A8000) + x2 * (U64_TO_F64(0xBF19D1C5EF6F0000)
|
||||
+ x2 * (U64_TO_F64(0x3F0980BDF11E8000)))))))))))))));
|
||||
}
|
||||
|
||||
fn f32 _TangentFloat(f32 x) {
|
||||
// Calculates tan(x) for x in [0, pi/4].
|
||||
|
||||
f32 x2 = x * x;
|
||||
|
||||
return x * (U32_TO_F32(0x3F800001) + x2 * (U32_TO_F32(0x3EAAA9AA) + x2 * (U32_TO_F32(0x3E08ABA8) + x2 * (U32_TO_F32(0x3D58EC90)
|
||||
+ x2 * (U32_TO_F32(0x3CD24840) + x2 * (U32_TO_F32(0x3AC3CA00) + x2 * U32_TO_F32(0x3C272F00)))))));
|
||||
}
|
||||
|
||||
fn f64 f64_sin(f64 x) {
|
||||
b32 negate = false;
|
||||
|
||||
// x in -infty, infty
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = true;
|
||||
}
|
||||
|
||||
// x in 0, infty
|
||||
|
||||
x -= 2 * F64_PI * f64_floor(x / (2 * F64_PI));
|
||||
|
||||
// x in 0, 2*pi
|
||||
|
||||
if (x < F64_PI / 2) {
|
||||
} else if (x < F64_PI) {
|
||||
x = F64_PI - x;
|
||||
} else if (x < 3 * F64_PI / 2) {
|
||||
x = x - F64_PI;
|
||||
negate = !negate;
|
||||
} else {
|
||||
x = F64_PI * 2 - x;
|
||||
negate = !negate;
|
||||
}
|
||||
|
||||
// x in 0, pi/2
|
||||
|
||||
f64 y = x < F64_PI / 4 ? _Sine(x) : _Cosine(F64_PI / 2 - x);
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
|
||||
fn f32 f32_sin(f32 x) {
|
||||
b32 negate = false;
|
||||
|
||||
// x in -infty, infty
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = true;
|
||||
}
|
||||
|
||||
// x in 0, infty
|
||||
|
||||
x -= 2 * F32_PI * f32_floor(x / (2 * F32_PI));
|
||||
|
||||
// x in 0, 2*pi
|
||||
|
||||
if (x < F32_PI / 2) {
|
||||
} else if (x < F32_PI) {
|
||||
x = F32_PI - x;
|
||||
} else if (x < 3 * F32_PI / 2) {
|
||||
x = x - F32_PI;
|
||||
negate = !negate;
|
||||
} else {
|
||||
x = F32_PI * 2 - x;
|
||||
negate = !negate;
|
||||
}
|
||||
|
||||
// x in 0, pi/2
|
||||
|
||||
f32 y = x < F32_PI / 4 ? _SineFloat(x) : _CosineFloat(F32_PI / 2 - x);
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f64 f64_cos(f64 x) {
|
||||
b32 negate = false;
|
||||
|
||||
// x in -infty, infty
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
}
|
||||
|
||||
// x in 0, infty
|
||||
|
||||
x -= 2 * F64_PI * f64_floor(x / (2 * F64_PI));
|
||||
|
||||
// x in 0, 2*pi
|
||||
|
||||
if (x < F64_PI / 2) {
|
||||
} else if (x < F64_PI) {
|
||||
x = F64_PI - x;
|
||||
negate = !negate;
|
||||
} else if (x < 3 * F64_PI / 2) {
|
||||
x = x - F64_PI;
|
||||
negate = !negate;
|
||||
} else {
|
||||
x = F64_PI * 2 - x;
|
||||
}
|
||||
|
||||
// x in 0, pi/2
|
||||
|
||||
f64 y = x < F64_PI / 4 ? _Cosine(x) : _Sine(F64_PI / 2 - x);
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f32 f32_cos(f32 x) {
|
||||
b32 negate = false;
|
||||
|
||||
// x in -infty, infty
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
}
|
||||
|
||||
// x in 0, infty
|
||||
|
||||
x -= 2 * F32_PI * f32_floor(x / (2 * F32_PI));
|
||||
|
||||
// x in 0, 2*pi
|
||||
|
||||
if (x < F32_PI / 2) {
|
||||
} else if (x < F32_PI) {
|
||||
x = F32_PI - x;
|
||||
negate = !negate;
|
||||
} else if (x < 3 * F32_PI / 2) {
|
||||
x = x - F32_PI;
|
||||
negate = !negate;
|
||||
} else {
|
||||
x = F32_PI * 2 - x;
|
||||
}
|
||||
|
||||
// x in 0, pi/2
|
||||
|
||||
f32 y = x < F32_PI / 4 ? _CosineFloat(x) : _SineFloat(F32_PI / 2 - x);
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f64 f64_tan(f64 x) {
|
||||
b32 negate = false;
|
||||
|
||||
// x in -infty, infty
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = !negate;
|
||||
}
|
||||
|
||||
// x in 0, infty
|
||||
|
||||
x -= F64_PI * f64_floor(x / F64_PI);
|
||||
|
||||
// x in 0, pi
|
||||
|
||||
if (x > F64_PI / 2) {
|
||||
x = F64_PI - x;
|
||||
negate = !negate;
|
||||
}
|
||||
|
||||
// x in 0, pi/2
|
||||
|
||||
f64 y = x < F64_PI / 4 ? _Tangent(x) : (1.0 / _Tangent(F64_PI / 2 - x));
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f32 f32_tan(f32 x) {
|
||||
b32 negate = false;
|
||||
|
||||
// x in -infty, infty
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = !negate;
|
||||
}
|
||||
|
||||
// x in 0, infty
|
||||
|
||||
x -= F32_PI * f32_floor(x / F32_PI);
|
||||
|
||||
// x in 0, pi
|
||||
|
||||
if (x > F32_PI / 2) {
|
||||
x = F32_PI - x;
|
||||
negate = !negate;
|
||||
}
|
||||
|
||||
// x in 0, pi/2
|
||||
|
||||
f32 y = x < F32_PI / 4 ? _TangentFloat(x) : (1.0f / _TangentFloat(F32_PI / 2 - x));
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f64 f64_asin(f64 x) {
|
||||
b32 negate = false;
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = true;
|
||||
}
|
||||
|
||||
f64 y;
|
||||
|
||||
if (x < 0.5) {
|
||||
y = _ArcSine(x);
|
||||
} else {
|
||||
y = F64_PI / 2 - 2 * _ArcSine(f64_sqrt(0.5 - 0.5 * x));
|
||||
}
|
||||
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f32 f32_asin(f32 x) {
|
||||
b32 negate = false;
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = true;
|
||||
}
|
||||
|
||||
f32 y;
|
||||
|
||||
if (x < 0.5) {
|
||||
y = _ArcSineFloat(x);
|
||||
} else {
|
||||
y = F32_PI / 2 - 2 * _ArcSineFloat(f32_sqrt(0.5f - 0.5f * x));
|
||||
}
|
||||
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f64 f64_acos(f64 x) {
|
||||
return f64_asin(-x) + F64_PI / 2;
|
||||
}
|
||||
|
||||
fn f32 f32_acos(f32 x) {
|
||||
return f32_asin(-x) + F32_PI / 2;
|
||||
}
|
||||
|
||||
fn f64 f64_atan(f64 x) {
|
||||
b32 negate = false;
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = true;
|
||||
}
|
||||
|
||||
b32 reciprocalTaken = false;
|
||||
|
||||
if (x > 1) {
|
||||
x = 1 / x;
|
||||
reciprocalTaken = true;
|
||||
}
|
||||
|
||||
f64 y;
|
||||
|
||||
if (x < 0.5) {
|
||||
y = _ArcTangent(x);
|
||||
} else {
|
||||
y = 0.463647609000806116 + _ArcTangent((2 * x - 1) / (2 + x));
|
||||
}
|
||||
|
||||
if (reciprocalTaken) {
|
||||
y = F64_PI / 2 - y;
|
||||
}
|
||||
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f32 f32_atan(f32 x) {
|
||||
b32 negate = false;
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = true;
|
||||
}
|
||||
|
||||
b32 reciprocalTaken = false;
|
||||
|
||||
if (x > 1) {
|
||||
x = 1 / x;
|
||||
reciprocalTaken = true;
|
||||
}
|
||||
|
||||
f32 y;
|
||||
|
||||
if (x < 0.5f) {
|
||||
y = _ArcTangentFloat(x);
|
||||
} else {
|
||||
y = 0.463647609000806116f + _ArcTangentFloat((2 * x - 1) / (2 + x));
|
||||
}
|
||||
|
||||
if (reciprocalTaken) {
|
||||
y = F32_PI / 2 - y;
|
||||
}
|
||||
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f64 f64_atan2(f64 y, f64 x) {
|
||||
if (x == 0) return y > 0 ? F64_PI / 2 : -F64_PI / 2;
|
||||
else if (x > 0) return f64_atan(y / x);
|
||||
else if (y >= 0) return F64_PI + f64_atan(y / x);
|
||||
else return -F64_PI + f64_atan(y / x);
|
||||
}
|
||||
|
||||
fn f32 f32_atan2(f32 y, f32 x) {
|
||||
if (x == 0) return y > 0 ? F32_PI / 2 : -F32_PI / 2;
|
||||
else if (x > 0) return f32_atan(y / x);
|
||||
else if (y >= 0) return F32_PI + f32_atan(y / x);
|
||||
else return -F32_PI + f32_atan(y / x);
|
||||
}
|
||||
|
||||
fn b32 f32_are_equal(f32 a, f32 b) {
|
||||
f32 diff = f32_abs(a - b);
|
||||
b32 result = diff <= 0.00001f;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 f64_are_equal(f64 a, f64 b) {
|
||||
f64 diff = f64_abs(a - b);
|
||||
b32 result = diff <= 0.00001;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn f32 f32_ease_out_bounce(f32 x) {
|
||||
f32 n1 = 7.5625f;
|
||||
f32 d1 = 2.75f;
|
||||
|
||||
if (x < 1.f / d1) {
|
||||
return n1 * x * x;
|
||||
} else if (x < 2.f / d1) {
|
||||
return n1 * (x -= 1.5f / d1) * x + 0.75f;
|
||||
} else if (x < 2.5f / d1) {
|
||||
return n1 * (x -= 2.25f / d1) * x + 0.9375f;
|
||||
} else {
|
||||
return n1 * (x -= 2.625f / d1) * x + 0.984375f;
|
||||
}
|
||||
}
|
||||
|
||||
fn f32 f32_ease_out_elastic(f32 x) {
|
||||
f32 c4 = (2 * F32_PI) / 3;
|
||||
|
||||
return x == 0.f
|
||||
? 0
|
||||
: x == 1.f
|
||||
? 1
|
||||
: f32_pow(2.f, -10.f * x) * f32_sin((x * 10.f - 0.75f) * c4) + 1.f;
|
||||
}
|
||||
|
||||
fn f32 f32_ease_out_cubic(f32 x) {
|
||||
return 1.f - f32_pow(1.f - x, 3.f);
|
||||
}
|
||||
|
||||
fn f32 f32_ease_out_n(f32 x, f32 n) {
|
||||
return 1.f - f32_pow(1.f - x, n);
|
||||
}
|
||||
|
||||
fn r2f32_t r2f32_lerp(r2f32_t a, r2f32_t b, f32 t) {
|
||||
r2f32_t result = { .min = {f32_lerp(a.min.x, b.min.x, t), f32_lerp(a.min.y, b.min.y, t)}, .max = {f32_lerp(a.max.x, b.max.x, t), f32_lerp(a.max.y, b.max.y, t)} };
|
||||
return result;
|
||||
}
|
||||
959
src/core/core_math.gen.c
Normal file
959
src/core/core_math.gen.c
Normal file
@@ -0,0 +1,959 @@
|
||||
#include "core_math.h"
|
||||
#include "core_intrin.h"
|
||||
|
||||
fn_inline v2f32_t v2f32(f32 x, f32 y) { return (v2f32_t){ x, y }; }
|
||||
gb_read_only v2f32_t v2f32_null = {0};
|
||||
fn_inline b32 v2f32_is_null(v2f32_t a) { return memory_equal(&a, &v2f32_null, sizeof(a)); }
|
||||
fn_inline b32 v2f32_are_equal(v2f32_t a, v2f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v2f32_t v2f32_add(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x + b.x, a.y + b.y }; }
|
||||
fn_inline v2f32_t v2f32_adds(v2f32_t a, f32 b) { return (v2f32_t){ a.x + b, a.y + b }; }
|
||||
fn_inline v2f32_t v2f32_sub(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x - b.x, a.y - b.y }; }
|
||||
fn_inline v2f32_t v2f32_subs(v2f32_t a, f32 b) { return (v2f32_t){ a.x - b, a.y - b }; }
|
||||
fn_inline v2f32_t v2f32_mul(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x * b.x, a.y * b.y }; }
|
||||
fn_inline v2f32_t v2f32_muls(v2f32_t a, f32 b) { return (v2f32_t){ a.x * b, a.y * b }; }
|
||||
fn_inline v2f32_t v2f32_div(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x / b.x, a.y / b.y }; }
|
||||
fn_inline v2f32_t v2f32_divs(v2f32_t a, f32 b) { return (v2f32_t){ a.x / b, a.y / b }; }
|
||||
fn_inline v3f32_t v3f32(f32 x, f32 y, f32 z) { return (v3f32_t){ x, y, z }; }
|
||||
gb_read_only v3f32_t v3f32_null = {0};
|
||||
fn_inline b32 v3f32_is_null(v3f32_t a) { return memory_equal(&a, &v3f32_null, sizeof(a)); }
|
||||
fn_inline b32 v3f32_are_equal(v3f32_t a, v3f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v3f32_t v3f32_add(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
|
||||
fn_inline v3f32_t v3f32_adds(v3f32_t a, f32 b) { return (v3f32_t){ a.x + b, a.y + b, a.z + b }; }
|
||||
fn_inline v3f32_t v3f32_sub(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
|
||||
fn_inline v3f32_t v3f32_subs(v3f32_t a, f32 b) { return (v3f32_t){ a.x - b, a.y - b, a.z - b }; }
|
||||
fn_inline v3f32_t v3f32_mul(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
|
||||
fn_inline v3f32_t v3f32_muls(v3f32_t a, f32 b) { return (v3f32_t){ a.x * b, a.y * b, a.z * b }; }
|
||||
fn_inline v3f32_t v3f32_div(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
|
||||
fn_inline v3f32_t v3f32_divs(v3f32_t a, f32 b) { return (v3f32_t){ a.x / b, a.y / b, a.z / b }; }
|
||||
fn_inline v4f32_t v4f32(f32 x, f32 y, f32 z, f32 w) { return (v4f32_t){ x, y, z, w }; }
|
||||
gb_read_only v4f32_t v4f32_null = {0};
|
||||
fn_inline b32 v4f32_is_null(v4f32_t a) { return memory_equal(&a, &v4f32_null, sizeof(a)); }
|
||||
fn_inline b32 v4f32_are_equal(v4f32_t a, v4f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v4f32_t v4f32_add(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
|
||||
fn_inline v4f32_t v4f32_adds(v4f32_t a, f32 b) { return (v4f32_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
|
||||
fn_inline v4f32_t v4f32_sub(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
|
||||
fn_inline v4f32_t v4f32_subs(v4f32_t a, f32 b) { return (v4f32_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
|
||||
fn_inline v4f32_t v4f32_mul(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
|
||||
fn_inline v4f32_t v4f32_muls(v4f32_t a, f32 b) { return (v4f32_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
|
||||
fn_inline v4f32_t v4f32_div(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
|
||||
fn_inline v4f32_t v4f32_divs(v4f32_t a, f32 b) { return (v4f32_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
|
||||
fn_inline r2f32_t r2f32(f32 x0, f32 y0, f32 x1, f32 y1) { return (r2f32_t){ x0, y0, x1, y1 }; }
|
||||
gb_read_only r2f32_t r2f32_null = {0};
|
||||
fn_inline b32 r2f32_is_null(r2f32_t a) { return memory_equal(&a, &r2f32_null, sizeof(a)); }
|
||||
fn_inline b32 r2f32_are_equal(r2f32_t a, r2f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r2f32_t r2f32_add(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
|
||||
fn_inline r2f32_t r2f32_adds(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
|
||||
fn_inline r2f32_t r2f32_sub(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
|
||||
fn_inline r2f32_t r2f32_subs(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
|
||||
fn_inline r2f32_t r2f32_mul(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
|
||||
fn_inline r2f32_t r2f32_muls(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
|
||||
fn_inline r2f32_t r2f32_div(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
|
||||
fn_inline r2f32_t r2f32_divs(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
|
||||
fn_inline r3f32_t r3f32(f32 x0, f32 y0, f32 z0, f32 x1, f32 y1, f32 z1) { return (r3f32_t){ x0, y0, z0, x1, y1, z1 }; }
|
||||
gb_read_only r3f32_t r3f32_null = {0};
|
||||
fn_inline b32 r3f32_is_null(r3f32_t a) { return memory_equal(&a, &r3f32_null, sizeof(a)); }
|
||||
fn_inline b32 r3f32_are_equal(r3f32_t a, r3f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r3f32_t r3f32_add(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
|
||||
fn_inline r3f32_t r3f32_adds(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
|
||||
fn_inline r3f32_t r3f32_sub(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
|
||||
fn_inline r3f32_t r3f32_subs(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
|
||||
fn_inline r3f32_t r3f32_mul(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
|
||||
fn_inline r3f32_t r3f32_muls(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
|
||||
fn_inline r3f32_t r3f32_div(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
|
||||
fn_inline r3f32_t r3f32_divs(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
|
||||
fn_inline v2f64_t v2f64(f64 x, f64 y) { return (v2f64_t){ x, y }; }
|
||||
gb_read_only v2f64_t v2f64_null = {0};
|
||||
fn_inline b32 v2f64_is_null(v2f64_t a) { return memory_equal(&a, &v2f64_null, sizeof(a)); }
|
||||
fn_inline b32 v2f64_are_equal(v2f64_t a, v2f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v2f64_t v2f64_add(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x + b.x, a.y + b.y }; }
|
||||
fn_inline v2f64_t v2f64_adds(v2f64_t a, f64 b) { return (v2f64_t){ a.x + b, a.y + b }; }
|
||||
fn_inline v2f64_t v2f64_sub(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x - b.x, a.y - b.y }; }
|
||||
fn_inline v2f64_t v2f64_subs(v2f64_t a, f64 b) { return (v2f64_t){ a.x - b, a.y - b }; }
|
||||
fn_inline v2f64_t v2f64_mul(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x * b.x, a.y * b.y }; }
|
||||
fn_inline v2f64_t v2f64_muls(v2f64_t a, f64 b) { return (v2f64_t){ a.x * b, a.y * b }; }
|
||||
fn_inline v2f64_t v2f64_div(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x / b.x, a.y / b.y }; }
|
||||
fn_inline v2f64_t v2f64_divs(v2f64_t a, f64 b) { return (v2f64_t){ a.x / b, a.y / b }; }
|
||||
fn_inline v3f64_t v3f64(f64 x, f64 y, f64 z) { return (v3f64_t){ x, y, z }; }
|
||||
gb_read_only v3f64_t v3f64_null = {0};
|
||||
fn_inline b32 v3f64_is_null(v3f64_t a) { return memory_equal(&a, &v3f64_null, sizeof(a)); }
|
||||
fn_inline b32 v3f64_are_equal(v3f64_t a, v3f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v3f64_t v3f64_add(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
|
||||
fn_inline v3f64_t v3f64_adds(v3f64_t a, f64 b) { return (v3f64_t){ a.x + b, a.y + b, a.z + b }; }
|
||||
fn_inline v3f64_t v3f64_sub(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
|
||||
fn_inline v3f64_t v3f64_subs(v3f64_t a, f64 b) { return (v3f64_t){ a.x - b, a.y - b, a.z - b }; }
|
||||
fn_inline v3f64_t v3f64_mul(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
|
||||
fn_inline v3f64_t v3f64_muls(v3f64_t a, f64 b) { return (v3f64_t){ a.x * b, a.y * b, a.z * b }; }
|
||||
fn_inline v3f64_t v3f64_div(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
|
||||
fn_inline v3f64_t v3f64_divs(v3f64_t a, f64 b) { return (v3f64_t){ a.x / b, a.y / b, a.z / b }; }
|
||||
fn_inline v4f64_t v4f64(f64 x, f64 y, f64 z, f64 w) { return (v4f64_t){ x, y, z, w }; }
|
||||
gb_read_only v4f64_t v4f64_null = {0};
|
||||
fn_inline b32 v4f64_is_null(v4f64_t a) { return memory_equal(&a, &v4f64_null, sizeof(a)); }
|
||||
fn_inline b32 v4f64_are_equal(v4f64_t a, v4f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v4f64_t v4f64_add(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
|
||||
fn_inline v4f64_t v4f64_adds(v4f64_t a, f64 b) { return (v4f64_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
|
||||
fn_inline v4f64_t v4f64_sub(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
|
||||
fn_inline v4f64_t v4f64_subs(v4f64_t a, f64 b) { return (v4f64_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
|
||||
fn_inline v4f64_t v4f64_mul(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
|
||||
fn_inline v4f64_t v4f64_muls(v4f64_t a, f64 b) { return (v4f64_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
|
||||
fn_inline v4f64_t v4f64_div(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
|
||||
fn_inline v4f64_t v4f64_divs(v4f64_t a, f64 b) { return (v4f64_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
|
||||
fn_inline r2f64_t r2f64(f64 x0, f64 y0, f64 x1, f64 y1) { return (r2f64_t){ x0, y0, x1, y1 }; }
|
||||
gb_read_only r2f64_t r2f64_null = {0};
|
||||
fn_inline b32 r2f64_is_null(r2f64_t a) { return memory_equal(&a, &r2f64_null, sizeof(a)); }
|
||||
fn_inline b32 r2f64_are_equal(r2f64_t a, r2f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r2f64_t r2f64_add(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
|
||||
fn_inline r2f64_t r2f64_adds(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
|
||||
fn_inline r2f64_t r2f64_sub(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
|
||||
fn_inline r2f64_t r2f64_subs(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
|
||||
fn_inline r2f64_t r2f64_mul(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
|
||||
fn_inline r2f64_t r2f64_muls(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
|
||||
fn_inline r2f64_t r2f64_div(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
|
||||
fn_inline r2f64_t r2f64_divs(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
|
||||
fn_inline r3f64_t r3f64(f64 x0, f64 y0, f64 z0, f64 x1, f64 y1, f64 z1) { return (r3f64_t){ x0, y0, z0, x1, y1, z1 }; }
|
||||
gb_read_only r3f64_t r3f64_null = {0};
|
||||
fn_inline b32 r3f64_is_null(r3f64_t a) { return memory_equal(&a, &r3f64_null, sizeof(a)); }
|
||||
fn_inline b32 r3f64_are_equal(r3f64_t a, r3f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r3f64_t r3f64_add(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
|
||||
fn_inline r3f64_t r3f64_adds(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
|
||||
fn_inline r3f64_t r3f64_sub(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
|
||||
fn_inline r3f64_t r3f64_subs(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
|
||||
fn_inline r3f64_t r3f64_mul(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
|
||||
fn_inline r3f64_t r3f64_muls(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
|
||||
fn_inline r3f64_t r3f64_div(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
|
||||
fn_inline r3f64_t r3f64_divs(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
|
||||
fn_inline v2i32_t v2i32(i32 x, i32 y) { return (v2i32_t){ x, y }; }
|
||||
gb_read_only v2i32_t v2i32_null = {0};
|
||||
fn_inline b32 v2i32_is_null(v2i32_t a) { return memory_equal(&a, &v2i32_null, sizeof(a)); }
|
||||
fn_inline b32 v2i32_are_equal(v2i32_t a, v2i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v2i32_t v2i32_add(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x + b.x, a.y + b.y }; }
|
||||
fn_inline v2i32_t v2i32_adds(v2i32_t a, i32 b) { return (v2i32_t){ a.x + b, a.y + b }; }
|
||||
fn_inline v2i32_t v2i32_sub(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x - b.x, a.y - b.y }; }
|
||||
fn_inline v2i32_t v2i32_subs(v2i32_t a, i32 b) { return (v2i32_t){ a.x - b, a.y - b }; }
|
||||
fn_inline v2i32_t v2i32_mul(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x * b.x, a.y * b.y }; }
|
||||
fn_inline v2i32_t v2i32_muls(v2i32_t a, i32 b) { return (v2i32_t){ a.x * b, a.y * b }; }
|
||||
fn_inline v2i32_t v2i32_div(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x / b.x, a.y / b.y }; }
|
||||
fn_inline v2i32_t v2i32_divs(v2i32_t a, i32 b) { return (v2i32_t){ a.x / b, a.y / b }; }
|
||||
fn_inline v3i32_t v3i32(i32 x, i32 y, i32 z) { return (v3i32_t){ x, y, z }; }
|
||||
gb_read_only v3i32_t v3i32_null = {0};
|
||||
fn_inline b32 v3i32_is_null(v3i32_t a) { return memory_equal(&a, &v3i32_null, sizeof(a)); }
|
||||
fn_inline b32 v3i32_are_equal(v3i32_t a, v3i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v3i32_t v3i32_add(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
|
||||
fn_inline v3i32_t v3i32_adds(v3i32_t a, i32 b) { return (v3i32_t){ a.x + b, a.y + b, a.z + b }; }
|
||||
fn_inline v3i32_t v3i32_sub(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
|
||||
fn_inline v3i32_t v3i32_subs(v3i32_t a, i32 b) { return (v3i32_t){ a.x - b, a.y - b, a.z - b }; }
|
||||
fn_inline v3i32_t v3i32_mul(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
|
||||
fn_inline v3i32_t v3i32_muls(v3i32_t a, i32 b) { return (v3i32_t){ a.x * b, a.y * b, a.z * b }; }
|
||||
fn_inline v3i32_t v3i32_div(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
|
||||
fn_inline v3i32_t v3i32_divs(v3i32_t a, i32 b) { return (v3i32_t){ a.x / b, a.y / b, a.z / b }; }
|
||||
fn_inline v4i32_t v4i32(i32 x, i32 y, i32 z, i32 w) { return (v4i32_t){ x, y, z, w }; }
|
||||
gb_read_only v4i32_t v4i32_null = {0};
|
||||
fn_inline b32 v4i32_is_null(v4i32_t a) { return memory_equal(&a, &v4i32_null, sizeof(a)); }
|
||||
fn_inline b32 v4i32_are_equal(v4i32_t a, v4i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v4i32_t v4i32_add(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
|
||||
fn_inline v4i32_t v4i32_adds(v4i32_t a, i32 b) { return (v4i32_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
|
||||
fn_inline v4i32_t v4i32_sub(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
|
||||
fn_inline v4i32_t v4i32_subs(v4i32_t a, i32 b) { return (v4i32_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
|
||||
fn_inline v4i32_t v4i32_mul(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
|
||||
fn_inline v4i32_t v4i32_muls(v4i32_t a, i32 b) { return (v4i32_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
|
||||
fn_inline v4i32_t v4i32_div(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
|
||||
fn_inline v4i32_t v4i32_divs(v4i32_t a, i32 b) { return (v4i32_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
|
||||
fn_inline r2i32_t r2i32(i32 x0, i32 y0, i32 x1, i32 y1) { return (r2i32_t){ x0, y0, x1, y1 }; }
|
||||
gb_read_only r2i32_t r2i32_null = {0};
|
||||
fn_inline b32 r2i32_is_null(r2i32_t a) { return memory_equal(&a, &r2i32_null, sizeof(a)); }
|
||||
fn_inline b32 r2i32_are_equal(r2i32_t a, r2i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r2i32_t r2i32_add(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
|
||||
fn_inline r2i32_t r2i32_adds(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
|
||||
fn_inline r2i32_t r2i32_sub(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
|
||||
fn_inline r2i32_t r2i32_subs(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
|
||||
fn_inline r2i32_t r2i32_mul(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
|
||||
fn_inline r2i32_t r2i32_muls(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
|
||||
fn_inline r2i32_t r2i32_div(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
|
||||
fn_inline r2i32_t r2i32_divs(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
|
||||
fn_inline r3i32_t r3i32(i32 x0, i32 y0, i32 z0, i32 x1, i32 y1, i32 z1) { return (r3i32_t){ x0, y0, z0, x1, y1, z1 }; }
|
||||
gb_read_only r3i32_t r3i32_null = {0};
|
||||
fn_inline b32 r3i32_is_null(r3i32_t a) { return memory_equal(&a, &r3i32_null, sizeof(a)); }
|
||||
fn_inline b32 r3i32_are_equal(r3i32_t a, r3i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r3i32_t r3i32_add(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
|
||||
fn_inline r3i32_t r3i32_adds(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
|
||||
fn_inline r3i32_t r3i32_sub(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
|
||||
fn_inline r3i32_t r3i32_subs(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
|
||||
fn_inline r3i32_t r3i32_mul(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
|
||||
fn_inline r3i32_t r3i32_muls(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
|
||||
fn_inline r3i32_t r3i32_div(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
|
||||
fn_inline r3i32_t r3i32_divs(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
|
||||
fn_inline v2i64_t v2i64(i64 x, i64 y) { return (v2i64_t){ x, y }; }
|
||||
gb_read_only v2i64_t v2i64_null = {0};
|
||||
fn_inline b32 v2i64_is_null(v2i64_t a) { return memory_equal(&a, &v2i64_null, sizeof(a)); }
|
||||
fn_inline b32 v2i64_are_equal(v2i64_t a, v2i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v2i64_t v2i64_add(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x + b.x, a.y + b.y }; }
|
||||
fn_inline v2i64_t v2i64_adds(v2i64_t a, i64 b) { return (v2i64_t){ a.x + b, a.y + b }; }
|
||||
fn_inline v2i64_t v2i64_sub(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x - b.x, a.y - b.y }; }
|
||||
fn_inline v2i64_t v2i64_subs(v2i64_t a, i64 b) { return (v2i64_t){ a.x - b, a.y - b }; }
|
||||
fn_inline v2i64_t v2i64_mul(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x * b.x, a.y * b.y }; }
|
||||
fn_inline v2i64_t v2i64_muls(v2i64_t a, i64 b) { return (v2i64_t){ a.x * b, a.y * b }; }
|
||||
fn_inline v2i64_t v2i64_div(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x / b.x, a.y / b.y }; }
|
||||
fn_inline v2i64_t v2i64_divs(v2i64_t a, i64 b) { return (v2i64_t){ a.x / b, a.y / b }; }
|
||||
fn_inline v3i64_t v3i64(i64 x, i64 y, i64 z) { return (v3i64_t){ x, y, z }; }
|
||||
gb_read_only v3i64_t v3i64_null = {0};
|
||||
fn_inline b32 v3i64_is_null(v3i64_t a) { return memory_equal(&a, &v3i64_null, sizeof(a)); }
|
||||
fn_inline b32 v3i64_are_equal(v3i64_t a, v3i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v3i64_t v3i64_add(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
|
||||
fn_inline v3i64_t v3i64_adds(v3i64_t a, i64 b) { return (v3i64_t){ a.x + b, a.y + b, a.z + b }; }
|
||||
fn_inline v3i64_t v3i64_sub(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
|
||||
fn_inline v3i64_t v3i64_subs(v3i64_t a, i64 b) { return (v3i64_t){ a.x - b, a.y - b, a.z - b }; }
|
||||
fn_inline v3i64_t v3i64_mul(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
|
||||
fn_inline v3i64_t v3i64_muls(v3i64_t a, i64 b) { return (v3i64_t){ a.x * b, a.y * b, a.z * b }; }
|
||||
fn_inline v3i64_t v3i64_div(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
|
||||
fn_inline v3i64_t v3i64_divs(v3i64_t a, i64 b) { return (v3i64_t){ a.x / b, a.y / b, a.z / b }; }
|
||||
fn_inline v4i64_t v4i64(i64 x, i64 y, i64 z, i64 w) { return (v4i64_t){ x, y, z, w }; }
|
||||
gb_read_only v4i64_t v4i64_null = {0};
|
||||
fn_inline b32 v4i64_is_null(v4i64_t a) { return memory_equal(&a, &v4i64_null, sizeof(a)); }
|
||||
fn_inline b32 v4i64_are_equal(v4i64_t a, v4i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v4i64_t v4i64_add(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
|
||||
fn_inline v4i64_t v4i64_adds(v4i64_t a, i64 b) { return (v4i64_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
|
||||
fn_inline v4i64_t v4i64_sub(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
|
||||
fn_inline v4i64_t v4i64_subs(v4i64_t a, i64 b) { return (v4i64_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
|
||||
fn_inline v4i64_t v4i64_mul(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
|
||||
fn_inline v4i64_t v4i64_muls(v4i64_t a, i64 b) { return (v4i64_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
|
||||
fn_inline v4i64_t v4i64_div(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
|
||||
fn_inline v4i64_t v4i64_divs(v4i64_t a, i64 b) { return (v4i64_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
|
||||
fn_inline r2i64_t r2i64(i64 x0, i64 y0, i64 x1, i64 y1) { return (r2i64_t){ x0, y0, x1, y1 }; }
|
||||
gb_read_only r2i64_t r2i64_null = {0};
|
||||
fn_inline b32 r2i64_is_null(r2i64_t a) { return memory_equal(&a, &r2i64_null, sizeof(a)); }
|
||||
fn_inline b32 r2i64_are_equal(r2i64_t a, r2i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r2i64_t r2i64_add(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
|
||||
fn_inline r2i64_t r2i64_adds(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
|
||||
fn_inline r2i64_t r2i64_sub(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
|
||||
fn_inline r2i64_t r2i64_subs(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
|
||||
fn_inline r2i64_t r2i64_mul(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
|
||||
fn_inline r2i64_t r2i64_muls(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
|
||||
fn_inline r2i64_t r2i64_div(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
|
||||
fn_inline r2i64_t r2i64_divs(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
|
||||
fn_inline r3i64_t r3i64(i64 x0, i64 y0, i64 z0, i64 x1, i64 y1, i64 z1) { return (r3i64_t){ x0, y0, z0, x1, y1, z1 }; }
|
||||
gb_read_only r3i64_t r3i64_null = {0};
|
||||
fn_inline b32 r3i64_is_null(r3i64_t a) { return memory_equal(&a, &r3i64_null, sizeof(a)); }
|
||||
fn_inline b32 r3i64_are_equal(r3i64_t a, r3i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r3i64_t r3i64_add(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
|
||||
fn_inline r3i64_t r3i64_adds(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
|
||||
fn_inline r3i64_t r3i64_sub(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
|
||||
fn_inline r3i64_t r3i64_subs(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
|
||||
fn_inline r3i64_t r3i64_mul(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
|
||||
fn_inline r3i64_t r3i64_muls(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
|
||||
fn_inline r3i64_t r3i64_div(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
|
||||
fn_inline r3i64_t r3i64_divs(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
|
||||
fn_inline r2f32_t r2f32_min_dim(v2f32_t pos, v2f32_t size) { return (r2f32_t){ pos, v2f32_add(pos, size) }; }
|
||||
fn_inline r2f32_t r2f32_center_half_dim(v2f32_t center, v2f32_t halfdim) { return (r2f32_t){ v2f32_sub(center, halfdim), v2f32_add(center, halfdim) }; }
|
||||
fn_inline r3f32_t r3f32_min_dim(v3f32_t pos, v3f32_t size) { return (r3f32_t){ pos, v3f32_add(pos, size) }; }
|
||||
fn_inline r3f32_t r3f32_center_half_dim(v3f32_t center, v3f32_t halfdim) { return (r3f32_t){ v3f32_sub(center, halfdim), v3f32_add(center, halfdim) }; }
|
||||
fn_inline r2f64_t r2f64_min_dim(v2f64_t pos, v2f64_t size) { return (r2f64_t){ pos, v2f64_add(pos, size) }; }
|
||||
fn_inline r2f64_t r2f64_center_half_dim(v2f64_t center, v2f64_t halfdim) { return (r2f64_t){ v2f64_sub(center, halfdim), v2f64_add(center, halfdim) }; }
|
||||
fn_inline r3f64_t r3f64_min_dim(v3f64_t pos, v3f64_t size) { return (r3f64_t){ pos, v3f64_add(pos, size) }; }
|
||||
fn_inline r3f64_t r3f64_center_half_dim(v3f64_t center, v3f64_t halfdim) { return (r3f64_t){ v3f64_sub(center, halfdim), v3f64_add(center, halfdim) }; }
|
||||
fn_inline r2i32_t r2i32_min_dim(v2i32_t pos, v2i32_t size) { return (r2i32_t){ pos, v2i32_add(pos, size) }; }
|
||||
fn_inline r2i32_t r2i32_center_half_dim(v2i32_t center, v2i32_t halfdim) { return (r2i32_t){ v2i32_sub(center, halfdim), v2i32_add(center, halfdim) }; }
|
||||
fn_inline r3i32_t r3i32_min_dim(v3i32_t pos, v3i32_t size) { return (r3i32_t){ pos, v3i32_add(pos, size) }; }
|
||||
fn_inline r3i32_t r3i32_center_half_dim(v3i32_t center, v3i32_t halfdim) { return (r3i32_t){ v3i32_sub(center, halfdim), v3i32_add(center, halfdim) }; }
|
||||
fn_inline r2i64_t r2i64_min_dim(v2i64_t pos, v2i64_t size) { return (r2i64_t){ pos, v2i64_add(pos, size) }; }
|
||||
fn_inline r2i64_t r2i64_center_half_dim(v2i64_t center, v2i64_t halfdim) { return (r2i64_t){ v2i64_sub(center, halfdim), v2i64_add(center, halfdim) }; }
|
||||
fn_inline r3i64_t r3i64_min_dim(v3i64_t pos, v3i64_t size) { return (r3i64_t){ pos, v3i64_add(pos, size) }; }
|
||||
fn_inline r3i64_t r3i64_center_half_dim(v3i64_t center, v3i64_t halfdim) { return (r3i64_t){ v3i64_sub(center, halfdim), v3i64_add(center, halfdim) }; }
|
||||
fn r2f32_t r2f32_cut_left(r2f32_t *r, f32 value) {
|
||||
f32 minx = r->min.x;
|
||||
r->min.x = MIN(r->min.x + value, r->max.x);
|
||||
r2f32_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_cut_right(r2f32_t *r, f32 value) {
|
||||
f32 maxx = r->max.x;
|
||||
r->max.x = MAX(r->min.x, r->max.x - value);
|
||||
r2f32_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_cut_top(r2f32_t *r, f32 value) { /* Y is down */
|
||||
f32 miny = r->min.y;
|
||||
r->min.y = MIN(r->max.y, r->min.y + value);
|
||||
r2f32_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_cut_bottom(r2f32_t *r, f32 value) { /* Y is down */
|
||||
f32 maxy = r->max.y;
|
||||
r->max.y = MAX(r->min.y, r->max.y - value);
|
||||
r2f32_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f32_t r2f32_cut_left_no_squash(r2f32_t *r, f32 value) {
|
||||
f32 minx = r->min.x;
|
||||
r->min.x = r->min.x + value;
|
||||
r2f32_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_cut_right_no_squash(r2f32_t *r, f32 value) {
|
||||
f32 maxx = r->max.x;
|
||||
r->max.x = r->max.x - value;
|
||||
r2f32_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_cut_top_no_squash(r2f32_t *r, f32 value) { /* Y is down */
|
||||
f32 miny = r->min.y;
|
||||
r->min.y = r->min.y + value;
|
||||
r2f32_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_cut_bottom_no_squash(r2f32_t *r, f32 value) { /* Y is down */
|
||||
f32 maxy = r->max.y;
|
||||
r->max.y = r->max.y - value;
|
||||
r2f32_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f32_t r2f32_add_left(r2f32_t *r, f32 value) {
|
||||
r2f32_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
|
||||
r->min.x -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_add_right(r2f32_t *r, f32 value) {
|
||||
r2f32_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
|
||||
r->max.x += value;
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_add_top(r2f32_t *r, f32 value) {
|
||||
r2f32_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
|
||||
r->min.y -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_add_bottom(r2f32_t *r, f32 value) {
|
||||
r2f32_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
|
||||
r->max.y += value;
|
||||
return result;
|
||||
}
|
||||
|
||||
// get past left
|
||||
fn r2f32_t r2f32_getp_left(const r2f32_t *rect, f32 value) {
|
||||
r2f32_t result = r2f32(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_getp_right(const r2f32_t *rect, f32 value) {
|
||||
r2f32_t result = r2f32(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_getp_bottom(const r2f32_t *rect, f32 value) {
|
||||
r2f32_t result = r2f32(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_getp_top(const r2f32_t *rect, f32 value) {
|
||||
r2f32_t result = r2f32(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f32_t r2f32_get_left(const r2f32_t *r, f32 value) {
|
||||
f32 minx = r->min.x;
|
||||
r2f32_t result = (r2f32_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_get_right(const r2f32_t *r, f32 value) {
|
||||
f32 maxx = r->max.x;
|
||||
r2f32_t result = (r2f32_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_get_top(const r2f32_t *r, f32 value) { /* Y is down */
|
||||
f32 miny = r->min.y;
|
||||
r2f32_t result = (r2f32_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_get_bottom(const r2f32_t *r, f32 value) { /* Y is down */
|
||||
f32 maxy = r->max.y;
|
||||
r2f32_t result = (r2f32_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
fn_inline r2f32_t r2f32_expand(r2f32_t rect, v2f32_t value) { return (r2f32_t){ v2f32_sub(rect.min, value), v2f32_add(rect.max, value) }; }
|
||||
fn_inline r2f32_t r2f32_shrink(r2f32_t rect, v2f32_t value) { return (r2f32_t){ v2f32_add(rect.min, value), v2f32_sub(rect.max, value) }; }
|
||||
fn_inline r2f32_t r2f32_shrinks(r2f32_t rect, f32 value) { return (r2f32_t){ v2f32_adds(rect.min, value), v2f32_subs(rect.max, value) }; }
|
||||
fn_inline v2f32_t r2f32_size(r2f32_t r) { return (v2f32_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
|
||||
fn_inline v2f32_t r2f32_get_mid(r2f32_t r) { return v2f32_add(r.min, v2f32_divs(r2f32_size(r), 2)); }
|
||||
fn_inline b32 r2f32_contains(r2f32_t rec, v2f32_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
|
||||
fn_inline r2f32_t r2f32_intersect(r2f32_t a, r2f32_t b) { return (r2f32_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
|
||||
fn_inline r2f32_t r2f32_union(r2f32_t a, r2f32_t b) { return (r2f32_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
|
||||
|
||||
fn_inline f32 r1f32_size(r1f32_t a) { return a.max - a.min; }
|
||||
fn_inline r1f32_t r1f32(f32 min, f32 max) { return (r1f32_t){min,max}; }
|
||||
fn_inline r1f32_t r1f32_auto(f32 a, f32 b) { return (r1f32_t){MIN(a,b),MAX(a,b)}; }
|
||||
fn_inline r1f32_t r1f32s(f32 a) { return (r1f32_t){a,a}; }
|
||||
fn_inline r1f32_t r1f32_clamp(r1f32_t a, f32 min, f32 max) { return (r1f32_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
|
||||
fn_inline b32 r1f32_contains(r1f32_t rec, f32 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
|
||||
fn_inline b32 r1f32_are_equal(r1f32_t a, r1f32_t b) { return a.min == b.min && a.max == b.max; }
|
||||
gb_read_only r1f32_t r1f32_null;
|
||||
|
||||
fn b32 r1f32_overlap(r1f32_t a, r1f32_t b) {
|
||||
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
|
||||
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
|
||||
return r1 || r2;
|
||||
}
|
||||
|
||||
fn v2f32_t v2f32_clamps(v2f32_t v, f32 min, f32 max) {
|
||||
v2f32_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
|
||||
return result;
|
||||
}
|
||||
fn v2f32_t v2f32_clamp(v2f32_t v, v2f32_t min, v2f32_t max) {
|
||||
v2f32_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f32_t r2f32_fix(r2f32_t n) {
|
||||
r2f32_t result = {
|
||||
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
|
||||
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_left(r2f64_t *r, f64 value) {
|
||||
f64 minx = r->min.x;
|
||||
r->min.x = MIN(r->min.x + value, r->max.x);
|
||||
r2f64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_right(r2f64_t *r, f64 value) {
|
||||
f64 maxx = r->max.x;
|
||||
r->max.x = MAX(r->min.x, r->max.x - value);
|
||||
r2f64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_top(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 miny = r->min.y;
|
||||
r->min.y = MIN(r->max.y, r->min.y + value);
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_bottom(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 maxy = r->max.y;
|
||||
r->max.y = MAX(r->min.y, r->max.y - value);
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_cut_left_no_squash(r2f64_t *r, f64 value) {
|
||||
f64 minx = r->min.x;
|
||||
r->min.x = r->min.x + value;
|
||||
r2f64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_right_no_squash(r2f64_t *r, f64 value) {
|
||||
f64 maxx = r->max.x;
|
||||
r->max.x = r->max.x - value;
|
||||
r2f64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_top_no_squash(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 miny = r->min.y;
|
||||
r->min.y = r->min.y + value;
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_bottom_no_squash(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 maxy = r->max.y;
|
||||
r->max.y = r->max.y - value;
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_add_left(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
|
||||
r->min.x -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_add_right(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
|
||||
r->max.x += value;
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_add_top(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
|
||||
r->min.y -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_add_bottom(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
|
||||
r->max.y += value;
|
||||
return result;
|
||||
}
|
||||
|
||||
// get past left
|
||||
fn r2f64_t r2f64_getp_left(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_getp_right(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_getp_bottom(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_getp_top(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_get_left(const r2f64_t *r, f64 value) {
|
||||
f64 minx = r->min.x;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_get_right(const r2f64_t *r, f64 value) {
|
||||
f64 maxx = r->max.x;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_get_top(const r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 miny = r->min.y;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_get_bottom(const r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 maxy = r->max.y;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
fn_inline r2f64_t r2f64_expand(r2f64_t rect, v2f64_t value) { return (r2f64_t){ v2f64_sub(rect.min, value), v2f64_add(rect.max, value) }; }
|
||||
fn_inline r2f64_t r2f64_shrink(r2f64_t rect, v2f64_t value) { return (r2f64_t){ v2f64_add(rect.min, value), v2f64_sub(rect.max, value) }; }
|
||||
fn_inline r2f64_t r2f64_shrinks(r2f64_t rect, f64 value) { return (r2f64_t){ v2f64_adds(rect.min, value), v2f64_subs(rect.max, value) }; }
|
||||
fn_inline v2f64_t r2f64_size(r2f64_t r) { return (v2f64_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
|
||||
fn_inline v2f64_t r2f64_get_mid(r2f64_t r) { return v2f64_add(r.min, v2f64_divs(r2f64_size(r), 2)); }
|
||||
fn_inline b32 r2f64_contains(r2f64_t rec, v2f64_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
|
||||
fn_inline r2f64_t r2f64_intersect(r2f64_t a, r2f64_t b) { return (r2f64_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
|
||||
fn_inline r2f64_t r2f64_union(r2f64_t a, r2f64_t b) { return (r2f64_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
|
||||
|
||||
fn_inline f64 r1f64_size(r1f64_t a) { return a.max - a.min; }
|
||||
fn_inline r1f64_t r1f64(f64 min, f64 max) { return (r1f64_t){min,max}; }
|
||||
fn_inline r1f64_t r1f64_auto(f64 a, f64 b) { return (r1f64_t){MIN(a,b),MAX(a,b)}; }
|
||||
fn_inline r1f64_t r1f64s(f64 a) { return (r1f64_t){a,a}; }
|
||||
fn_inline r1f64_t r1f64_clamp(r1f64_t a, f64 min, f64 max) { return (r1f64_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
|
||||
fn_inline b32 r1f64_contains(r1f64_t rec, f64 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
|
||||
fn_inline b32 r1f64_are_equal(r1f64_t a, r1f64_t b) { return a.min == b.min && a.max == b.max; }
|
||||
gb_read_only r1f64_t r1f64_null;
|
||||
|
||||
fn b32 r1f64_overlap(r1f64_t a, r1f64_t b) {
|
||||
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
|
||||
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
|
||||
return r1 || r2;
|
||||
}
|
||||
|
||||
fn v2f64_t v2f64_clamps(v2f64_t v, f64 min, f64 max) {
|
||||
v2f64_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
|
||||
return result;
|
||||
}
|
||||
fn v2f64_t v2f64_clamp(v2f64_t v, v2f64_t min, v2f64_t max) {
|
||||
v2f64_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_fix(r2f64_t n) {
|
||||
r2f64_t result = {
|
||||
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
|
||||
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_cut_left(r2i32_t *r, i32 value) {
|
||||
i32 minx = r->min.x;
|
||||
r->min.x = MIN(r->min.x + value, r->max.x);
|
||||
r2i32_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_cut_right(r2i32_t *r, i32 value) {
|
||||
i32 maxx = r->max.x;
|
||||
r->max.x = MAX(r->min.x, r->max.x - value);
|
||||
r2i32_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_cut_top(r2i32_t *r, i32 value) { /* Y is down */
|
||||
i32 miny = r->min.y;
|
||||
r->min.y = MIN(r->max.y, r->min.y + value);
|
||||
r2i32_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_cut_bottom(r2i32_t *r, i32 value) { /* Y is down */
|
||||
i32 maxy = r->max.y;
|
||||
r->max.y = MAX(r->min.y, r->max.y - value);
|
||||
r2i32_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i32_t r2i32_cut_left_no_squash(r2i32_t *r, i32 value) {
|
||||
i32 minx = r->min.x;
|
||||
r->min.x = r->min.x + value;
|
||||
r2i32_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_cut_right_no_squash(r2i32_t *r, i32 value) {
|
||||
i32 maxx = r->max.x;
|
||||
r->max.x = r->max.x - value;
|
||||
r2i32_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_cut_top_no_squash(r2i32_t *r, i32 value) { /* Y is down */
|
||||
i32 miny = r->min.y;
|
||||
r->min.y = r->min.y + value;
|
||||
r2i32_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_cut_bottom_no_squash(r2i32_t *r, i32 value) { /* Y is down */
|
||||
i32 maxy = r->max.y;
|
||||
r->max.y = r->max.y - value;
|
||||
r2i32_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i32_t r2i32_add_left(r2i32_t *r, i32 value) {
|
||||
r2i32_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
|
||||
r->min.x -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_add_right(r2i32_t *r, i32 value) {
|
||||
r2i32_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
|
||||
r->max.x += value;
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_add_top(r2i32_t *r, i32 value) {
|
||||
r2i32_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
|
||||
r->min.y -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_add_bottom(r2i32_t *r, i32 value) {
|
||||
r2i32_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
|
||||
r->max.y += value;
|
||||
return result;
|
||||
}
|
||||
|
||||
// get past left
|
||||
fn r2i32_t r2i32_getp_left(const r2i32_t *rect, i32 value) {
|
||||
r2i32_t result = r2i32(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_getp_right(const r2i32_t *rect, i32 value) {
|
||||
r2i32_t result = r2i32(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_getp_bottom(const r2i32_t *rect, i32 value) {
|
||||
r2i32_t result = r2i32(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_getp_top(const r2i32_t *rect, i32 value) {
|
||||
r2i32_t result = r2i32(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i32_t r2i32_get_left(const r2i32_t *r, i32 value) {
|
||||
i32 minx = r->min.x;
|
||||
r2i32_t result = (r2i32_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_get_right(const r2i32_t *r, i32 value) {
|
||||
i32 maxx = r->max.x;
|
||||
r2i32_t result = (r2i32_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_get_top(const r2i32_t *r, i32 value) { /* Y is down */
|
||||
i32 miny = r->min.y;
|
||||
r2i32_t result = (r2i32_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_get_bottom(const r2i32_t *r, i32 value) { /* Y is down */
|
||||
i32 maxy = r->max.y;
|
||||
r2i32_t result = (r2i32_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
fn_inline r2i32_t r2i32_expand(r2i32_t rect, v2i32_t value) { return (r2i32_t){ v2i32_sub(rect.min, value), v2i32_add(rect.max, value) }; }
|
||||
fn_inline r2i32_t r2i32_shrink(r2i32_t rect, v2i32_t value) { return (r2i32_t){ v2i32_add(rect.min, value), v2i32_sub(rect.max, value) }; }
|
||||
fn_inline r2i32_t r2i32_shrinks(r2i32_t rect, i32 value) { return (r2i32_t){ v2i32_adds(rect.min, value), v2i32_subs(rect.max, value) }; }
|
||||
fn_inline v2i32_t r2i32_size(r2i32_t r) { return (v2i32_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
|
||||
fn_inline v2i32_t r2i32_get_mid(r2i32_t r) { return v2i32_add(r.min, v2i32_divs(r2i32_size(r), 2)); }
|
||||
fn_inline b32 r2i32_contains(r2i32_t rec, v2i32_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
|
||||
fn_inline r2i32_t r2i32_intersect(r2i32_t a, r2i32_t b) { return (r2i32_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
|
||||
fn_inline r2i32_t r2i32_union(r2i32_t a, r2i32_t b) { return (r2i32_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
|
||||
|
||||
fn_inline i32 r1i32_size(r1i32_t a) { return a.max - a.min; }
|
||||
fn_inline r1i32_t r1i32(i32 min, i32 max) { return (r1i32_t){min,max}; }
|
||||
fn_inline r1i32_t r1i32_auto(i32 a, i32 b) { return (r1i32_t){MIN(a,b),MAX(a,b)}; }
|
||||
fn_inline r1i32_t r1i32s(i32 a) { return (r1i32_t){a,a}; }
|
||||
fn_inline r1i32_t r1i32_clamp(r1i32_t a, i32 min, i32 max) { return (r1i32_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
|
||||
fn_inline b32 r1i32_contains(r1i32_t rec, i32 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
|
||||
fn_inline b32 r1i32_are_equal(r1i32_t a, r1i32_t b) { return a.min == b.min && a.max == b.max; }
|
||||
gb_read_only r1i32_t r1i32_null;
|
||||
|
||||
fn b32 r1i32_overlap(r1i32_t a, r1i32_t b) {
|
||||
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
|
||||
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
|
||||
return r1 || r2;
|
||||
}
|
||||
|
||||
fn v2i32_t v2i32_clamps(v2i32_t v, i32 min, i32 max) {
|
||||
v2i32_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
|
||||
return result;
|
||||
}
|
||||
fn v2i32_t v2i32_clamp(v2i32_t v, v2i32_t min, v2i32_t max) {
|
||||
v2i32_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i32_t r2i32_fix(r2i32_t n) {
|
||||
r2i32_t result = {
|
||||
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
|
||||
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_cut_left(r2i64_t *r, i64 value) {
|
||||
i64 minx = r->min.x;
|
||||
r->min.x = MIN(r->min.x + value, r->max.x);
|
||||
r2i64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_cut_right(r2i64_t *r, i64 value) {
|
||||
i64 maxx = r->max.x;
|
||||
r->max.x = MAX(r->min.x, r->max.x - value);
|
||||
r2i64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_cut_top(r2i64_t *r, i64 value) { /* Y is down */
|
||||
i64 miny = r->min.y;
|
||||
r->min.y = MIN(r->max.y, r->min.y + value);
|
||||
r2i64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_cut_bottom(r2i64_t *r, i64 value) { /* Y is down */
|
||||
i64 maxy = r->max.y;
|
||||
r->max.y = MAX(r->min.y, r->max.y - value);
|
||||
r2i64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i64_t r2i64_cut_left_no_squash(r2i64_t *r, i64 value) {
|
||||
i64 minx = r->min.x;
|
||||
r->min.x = r->min.x + value;
|
||||
r2i64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_cut_right_no_squash(r2i64_t *r, i64 value) {
|
||||
i64 maxx = r->max.x;
|
||||
r->max.x = r->max.x - value;
|
||||
r2i64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_cut_top_no_squash(r2i64_t *r, i64 value) { /* Y is down */
|
||||
i64 miny = r->min.y;
|
||||
r->min.y = r->min.y + value;
|
||||
r2i64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_cut_bottom_no_squash(r2i64_t *r, i64 value) { /* Y is down */
|
||||
i64 maxy = r->max.y;
|
||||
r->max.y = r->max.y - value;
|
||||
r2i64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i64_t r2i64_add_left(r2i64_t *r, i64 value) {
|
||||
r2i64_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
|
||||
r->min.x -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_add_right(r2i64_t *r, i64 value) {
|
||||
r2i64_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
|
||||
r->max.x += value;
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_add_top(r2i64_t *r, i64 value) {
|
||||
r2i64_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
|
||||
r->min.y -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_add_bottom(r2i64_t *r, i64 value) {
|
||||
r2i64_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
|
||||
r->max.y += value;
|
||||
return result;
|
||||
}
|
||||
|
||||
// get past left
|
||||
fn r2i64_t r2i64_getp_left(const r2i64_t *rect, i64 value) {
|
||||
r2i64_t result = r2i64(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_getp_right(const r2i64_t *rect, i64 value) {
|
||||
r2i64_t result = r2i64(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_getp_bottom(const r2i64_t *rect, i64 value) {
|
||||
r2i64_t result = r2i64(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_getp_top(const r2i64_t *rect, i64 value) {
|
||||
r2i64_t result = r2i64(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i64_t r2i64_get_left(const r2i64_t *r, i64 value) {
|
||||
i64 minx = r->min.x;
|
||||
r2i64_t result = (r2i64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_get_right(const r2i64_t *r, i64 value) {
|
||||
i64 maxx = r->max.x;
|
||||
r2i64_t result = (r2i64_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_get_top(const r2i64_t *r, i64 value) { /* Y is down */
|
||||
i64 miny = r->min.y;
|
||||
r2i64_t result = (r2i64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_get_bottom(const r2i64_t *r, i64 value) { /* Y is down */
|
||||
i64 maxy = r->max.y;
|
||||
r2i64_t result = (r2i64_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
fn_inline r2i64_t r2i64_expand(r2i64_t rect, v2i64_t value) { return (r2i64_t){ v2i64_sub(rect.min, value), v2i64_add(rect.max, value) }; }
|
||||
fn_inline r2i64_t r2i64_shrink(r2i64_t rect, v2i64_t value) { return (r2i64_t){ v2i64_add(rect.min, value), v2i64_sub(rect.max, value) }; }
|
||||
fn_inline r2i64_t r2i64_shrinks(r2i64_t rect, i64 value) { return (r2i64_t){ v2i64_adds(rect.min, value), v2i64_subs(rect.max, value) }; }
|
||||
fn_inline v2i64_t r2i64_size(r2i64_t r) { return (v2i64_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
|
||||
fn_inline v2i64_t r2i64_get_mid(r2i64_t r) { return v2i64_add(r.min, v2i64_divs(r2i64_size(r), 2)); }
|
||||
fn_inline b32 r2i64_contains(r2i64_t rec, v2i64_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
|
||||
fn_inline r2i64_t r2i64_intersect(r2i64_t a, r2i64_t b) { return (r2i64_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
|
||||
fn_inline r2i64_t r2i64_union(r2i64_t a, r2i64_t b) { return (r2i64_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
|
||||
|
||||
fn_inline i64 r1i64_size(r1i64_t a) { return a.max - a.min; }
|
||||
fn_inline r1i64_t r1i64(i64 min, i64 max) { return (r1i64_t){min,max}; }
|
||||
fn_inline r1i64_t r1i64_auto(i64 a, i64 b) { return (r1i64_t){MIN(a,b),MAX(a,b)}; }
|
||||
fn_inline r1i64_t r1i64s(i64 a) { return (r1i64_t){a,a}; }
|
||||
fn_inline r1i64_t r1i64_clamp(r1i64_t a, i64 min, i64 max) { return (r1i64_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
|
||||
fn_inline b32 r1i64_contains(r1i64_t rec, i64 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
|
||||
fn_inline b32 r1i64_are_equal(r1i64_t a, r1i64_t b) { return a.min == b.min && a.max == b.max; }
|
||||
gb_read_only r1i64_t r1i64_null;
|
||||
|
||||
fn b32 r1i64_overlap(r1i64_t a, r1i64_t b) {
|
||||
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
|
||||
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
|
||||
return r1 || r2;
|
||||
}
|
||||
|
||||
fn v2i64_t v2i64_clamps(v2i64_t v, i64 min, i64 max) {
|
||||
v2i64_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
|
||||
return result;
|
||||
}
|
||||
fn v2i64_t v2i64_clamp(v2i64_t v, v2i64_t min, v2i64_t max) {
|
||||
v2i64_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i64_t r2i64_fix(r2i64_t n) {
|
||||
r2i64_t result = {
|
||||
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
|
||||
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
fn_inline v2f64_t v2f32_to_v2f64(v2f32_t v) { return (v2f64_t){ (f64)v.x, (f64)v.y }; }
|
||||
fn_inline v3f64_t v3f32_to_v3f64(v3f32_t v) { return (v3f64_t){ (f64)v.x, (f64)v.y, (f64)v.z }; }
|
||||
fn_inline v4f64_t v4f32_to_v4f64(v4f32_t v) { return (v4f64_t){ (f64)v.x, (f64)v.y, (f64)v.z, (f64)v.w }; }
|
||||
fn_inline r2f64_t r2f32_to_r2f64(r2f32_t v) { return (r2f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.x1, (f64)v.y1 }; }
|
||||
fn_inline r3f64_t r3f32_to_r3f64(r3f32_t v) { return (r3f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.z0, (f64)v.x1, (f64)v.y1, (f64)v.z1 }; }
|
||||
fn_inline v2i32_t v2f32_to_v2i32(v2f32_t v) { return (v2i32_t){ (i32)v.x, (i32)v.y }; }
|
||||
fn_inline v3i32_t v3f32_to_v3i32(v3f32_t v) { return (v3i32_t){ (i32)v.x, (i32)v.y, (i32)v.z }; }
|
||||
fn_inline v4i32_t v4f32_to_v4i32(v4f32_t v) { return (v4i32_t){ (i32)v.x, (i32)v.y, (i32)v.z, (i32)v.w }; }
|
||||
fn_inline r2i32_t r2f32_to_r2i32(r2f32_t v) { return (r2i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.x1, (i32)v.y1 }; }
|
||||
fn_inline r3i32_t r3f32_to_r3i32(r3f32_t v) { return (r3i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.z0, (i32)v.x1, (i32)v.y1, (i32)v.z1 }; }
|
||||
fn_inline v2i64_t v2f32_to_v2i64(v2f32_t v) { return (v2i64_t){ (i64)v.x, (i64)v.y }; }
|
||||
fn_inline v3i64_t v3f32_to_v3i64(v3f32_t v) { return (v3i64_t){ (i64)v.x, (i64)v.y, (i64)v.z }; }
|
||||
fn_inline v4i64_t v4f32_to_v4i64(v4f32_t v) { return (v4i64_t){ (i64)v.x, (i64)v.y, (i64)v.z, (i64)v.w }; }
|
||||
fn_inline r2i64_t r2f32_to_r2i64(r2f32_t v) { return (r2i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.x1, (i64)v.y1 }; }
|
||||
fn_inline r3i64_t r3f32_to_r3i64(r3f32_t v) { return (r3i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.z0, (i64)v.x1, (i64)v.y1, (i64)v.z1 }; }
|
||||
fn_inline v2f32_t v2f64_to_v2f32(v2f64_t v) { return (v2f32_t){ (f32)v.x, (f32)v.y }; }
|
||||
fn_inline v3f32_t v3f64_to_v3f32(v3f64_t v) { return (v3f32_t){ (f32)v.x, (f32)v.y, (f32)v.z }; }
|
||||
fn_inline v4f32_t v4f64_to_v4f32(v4f64_t v) { return (v4f32_t){ (f32)v.x, (f32)v.y, (f32)v.z, (f32)v.w }; }
|
||||
fn_inline r2f32_t r2f64_to_r2f32(r2f64_t v) { return (r2f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.x1, (f32)v.y1 }; }
|
||||
fn_inline r3f32_t r3f64_to_r3f32(r3f64_t v) { return (r3f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.z0, (f32)v.x1, (f32)v.y1, (f32)v.z1 }; }
|
||||
fn_inline v2i32_t v2f64_to_v2i32(v2f64_t v) { return (v2i32_t){ (i32)v.x, (i32)v.y }; }
|
||||
fn_inline v3i32_t v3f64_to_v3i32(v3f64_t v) { return (v3i32_t){ (i32)v.x, (i32)v.y, (i32)v.z }; }
|
||||
fn_inline v4i32_t v4f64_to_v4i32(v4f64_t v) { return (v4i32_t){ (i32)v.x, (i32)v.y, (i32)v.z, (i32)v.w }; }
|
||||
fn_inline r2i32_t r2f64_to_r2i32(r2f64_t v) { return (r2i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.x1, (i32)v.y1 }; }
|
||||
fn_inline r3i32_t r3f64_to_r3i32(r3f64_t v) { return (r3i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.z0, (i32)v.x1, (i32)v.y1, (i32)v.z1 }; }
|
||||
fn_inline v2i64_t v2f64_to_v2i64(v2f64_t v) { return (v2i64_t){ (i64)v.x, (i64)v.y }; }
|
||||
fn_inline v3i64_t v3f64_to_v3i64(v3f64_t v) { return (v3i64_t){ (i64)v.x, (i64)v.y, (i64)v.z }; }
|
||||
fn_inline v4i64_t v4f64_to_v4i64(v4f64_t v) { return (v4i64_t){ (i64)v.x, (i64)v.y, (i64)v.z, (i64)v.w }; }
|
||||
fn_inline r2i64_t r2f64_to_r2i64(r2f64_t v) { return (r2i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.x1, (i64)v.y1 }; }
|
||||
fn_inline r3i64_t r3f64_to_r3i64(r3f64_t v) { return (r3i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.z0, (i64)v.x1, (i64)v.y1, (i64)v.z1 }; }
|
||||
fn_inline v2f32_t v2i32_to_v2f32(v2i32_t v) { return (v2f32_t){ (f32)v.x, (f32)v.y }; }
|
||||
fn_inline v3f32_t v3i32_to_v3f32(v3i32_t v) { return (v3f32_t){ (f32)v.x, (f32)v.y, (f32)v.z }; }
|
||||
fn_inline v4f32_t v4i32_to_v4f32(v4i32_t v) { return (v4f32_t){ (f32)v.x, (f32)v.y, (f32)v.z, (f32)v.w }; }
|
||||
fn_inline r2f32_t r2i32_to_r2f32(r2i32_t v) { return (r2f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.x1, (f32)v.y1 }; }
|
||||
fn_inline r3f32_t r3i32_to_r3f32(r3i32_t v) { return (r3f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.z0, (f32)v.x1, (f32)v.y1, (f32)v.z1 }; }
|
||||
fn_inline v2f64_t v2i32_to_v2f64(v2i32_t v) { return (v2f64_t){ (f64)v.x, (f64)v.y }; }
|
||||
fn_inline v3f64_t v3i32_to_v3f64(v3i32_t v) { return (v3f64_t){ (f64)v.x, (f64)v.y, (f64)v.z }; }
|
||||
fn_inline v4f64_t v4i32_to_v4f64(v4i32_t v) { return (v4f64_t){ (f64)v.x, (f64)v.y, (f64)v.z, (f64)v.w }; }
|
||||
fn_inline r2f64_t r2i32_to_r2f64(r2i32_t v) { return (r2f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.x1, (f64)v.y1 }; }
|
||||
fn_inline r3f64_t r3i32_to_r3f64(r3i32_t v) { return (r3f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.z0, (f64)v.x1, (f64)v.y1, (f64)v.z1 }; }
|
||||
fn_inline v2i64_t v2i32_to_v2i64(v2i32_t v) { return (v2i64_t){ (i64)v.x, (i64)v.y }; }
|
||||
fn_inline v3i64_t v3i32_to_v3i64(v3i32_t v) { return (v3i64_t){ (i64)v.x, (i64)v.y, (i64)v.z }; }
|
||||
fn_inline v4i64_t v4i32_to_v4i64(v4i32_t v) { return (v4i64_t){ (i64)v.x, (i64)v.y, (i64)v.z, (i64)v.w }; }
|
||||
fn_inline r2i64_t r2i32_to_r2i64(r2i32_t v) { return (r2i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.x1, (i64)v.y1 }; }
|
||||
fn_inline r3i64_t r3i32_to_r3i64(r3i32_t v) { return (r3i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.z0, (i64)v.x1, (i64)v.y1, (i64)v.z1 }; }
|
||||
fn_inline v2f32_t v2i64_to_v2f32(v2i64_t v) { return (v2f32_t){ (f32)v.x, (f32)v.y }; }
|
||||
fn_inline v3f32_t v3i64_to_v3f32(v3i64_t v) { return (v3f32_t){ (f32)v.x, (f32)v.y, (f32)v.z }; }
|
||||
fn_inline v4f32_t v4i64_to_v4f32(v4i64_t v) { return (v4f32_t){ (f32)v.x, (f32)v.y, (f32)v.z, (f32)v.w }; }
|
||||
fn_inline r2f32_t r2i64_to_r2f32(r2i64_t v) { return (r2f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.x1, (f32)v.y1 }; }
|
||||
fn_inline r3f32_t r3i64_to_r3f32(r3i64_t v) { return (r3f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.z0, (f32)v.x1, (f32)v.y1, (f32)v.z1 }; }
|
||||
fn_inline v2f64_t v2i64_to_v2f64(v2i64_t v) { return (v2f64_t){ (f64)v.x, (f64)v.y }; }
|
||||
fn_inline v3f64_t v3i64_to_v3f64(v3i64_t v) { return (v3f64_t){ (f64)v.x, (f64)v.y, (f64)v.z }; }
|
||||
fn_inline v4f64_t v4i64_to_v4f64(v4i64_t v) { return (v4f64_t){ (f64)v.x, (f64)v.y, (f64)v.z, (f64)v.w }; }
|
||||
fn_inline r2f64_t r2i64_to_r2f64(r2i64_t v) { return (r2f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.x1, (f64)v.y1 }; }
|
||||
fn_inline r3f64_t r3i64_to_r3f64(r3i64_t v) { return (r3f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.z0, (f64)v.x1, (f64)v.y1, (f64)v.z1 }; }
|
||||
fn_inline v2i32_t v2i64_to_v2i32(v2i64_t v) { return (v2i32_t){ (i32)v.x, (i32)v.y }; }
|
||||
fn_inline v3i32_t v3i64_to_v3i32(v3i64_t v) { return (v3i32_t){ (i32)v.x, (i32)v.y, (i32)v.z }; }
|
||||
fn_inline v4i32_t v4i64_to_v4i32(v4i64_t v) { return (v4i32_t){ (i32)v.x, (i32)v.y, (i32)v.z, (i32)v.w }; }
|
||||
fn_inline r2i32_t r2i64_to_r2i32(r2i64_t v) { return (r2i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.x1, (i32)v.y1 }; }
|
||||
fn_inline r3i32_t r3i64_to_r3i32(r3i64_t v) { return (r3i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.z0, (i32)v.x1, (i32)v.y1, (i32)v.z1 }; }
|
||||
fn_inline r2f32_t r2f32_add_v2f32(r2f32_t a, v2f32_t b) { return (r2f32_t){ v2f32_add(a.min, b), v2f32_add(a.max, b) }; }
|
||||
fn_inline r2f32_t r2f32_sub_v2f32(r2f32_t a, v2f32_t b) { return (r2f32_t){ v2f32_sub(a.min, b), v2f32_sub(a.max, b) }; }
|
||||
fn_inline r2f32_t r2f32_mul_v2f32(r2f32_t a, v2f32_t b) { return (r2f32_t){ v2f32_mul(a.min, b), v2f32_mul(a.max, b) }; }
|
||||
fn_inline r2f32_t r2f32_div_v2f32(r2f32_t a, v2f32_t b) { return (r2f32_t){ v2f32_div(a.min, b), v2f32_div(a.max, b) }; }
|
||||
fn_inline r2f64_t r2f64_add_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_add(a.min, b), v2f64_add(a.max, b) }; }
|
||||
fn_inline r2f64_t r2f64_sub_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_sub(a.min, b), v2f64_sub(a.max, b) }; }
|
||||
fn_inline r2f64_t r2f64_mul_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_mul(a.min, b), v2f64_mul(a.max, b) }; }
|
||||
fn_inline r2f64_t r2f64_div_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_div(a.min, b), v2f64_div(a.max, b) }; }
|
||||
fn_inline r2i32_t r2i32_add_v2i32(r2i32_t a, v2i32_t b) { return (r2i32_t){ v2i32_add(a.min, b), v2i32_add(a.max, b) }; }
|
||||
fn_inline r2i32_t r2i32_sub_v2i32(r2i32_t a, v2i32_t b) { return (r2i32_t){ v2i32_sub(a.min, b), v2i32_sub(a.max, b) }; }
|
||||
fn_inline r2i32_t r2i32_mul_v2i32(r2i32_t a, v2i32_t b) { return (r2i32_t){ v2i32_mul(a.min, b), v2i32_mul(a.max, b) }; }
|
||||
fn_inline r2i32_t r2i32_div_v2i32(r2i32_t a, v2i32_t b) { return (r2i32_t){ v2i32_div(a.min, b), v2i32_div(a.max, b) }; }
|
||||
fn_inline r2i64_t r2i64_add_v2i64(r2i64_t a, v2i64_t b) { return (r2i64_t){ v2i64_add(a.min, b), v2i64_add(a.max, b) }; }
|
||||
fn_inline r2i64_t r2i64_sub_v2i64(r2i64_t a, v2i64_t b) { return (r2i64_t){ v2i64_sub(a.min, b), v2i64_sub(a.max, b) }; }
|
||||
fn_inline r2i64_t r2i64_mul_v2i64(r2i64_t a, v2i64_t b) { return (r2i64_t){ v2i64_mul(a.min, b), v2i64_mul(a.max, b) }; }
|
||||
fn_inline r2i64_t r2i64_div_v2i64(r2i64_t a, v2i64_t b) { return (r2i64_t){ v2i64_div(a.min, b), v2i64_div(a.max, b) }; }
|
||||
fn f32 f32_safe_ratio(f32 a, f32 b, f32 if0) {
|
||||
f32 result = if0;
|
||||
if (b != 0.0) {
|
||||
result = a / b;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn_inline f32 f32_safe_ratio0(f32 a, f32 b) { return f32_safe_ratio(a, b, 0); }
|
||||
fn_inline f32 f32_safe_ratio1(f32 a, f32 b) { return f32_safe_ratio(a, b, 0); }
|
||||
fn f64 f64_safe_ratio(f64 a, f64 b, f64 if0) {
|
||||
f64 result = if0;
|
||||
if (b != 0.0) {
|
||||
result = a / b;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn_inline f64 f64_safe_ratio0(f64 a, f64 b) { return f64_safe_ratio(a, b, 0); }
|
||||
fn_inline f64 f64_safe_ratio1(f64 a, f64 b) { return f64_safe_ratio(a, b, 0); }
|
||||
215
src/core/core_math.h
Normal file
215
src/core/core_math.h
Normal file
@@ -0,0 +1,215 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
|
||||
typedef union v2f32_t v2f32_t;
|
||||
union v2f32_t {
|
||||
struct { f32 x, y; };
|
||||
f32 e[2];
|
||||
};
|
||||
|
||||
typedef union v3f32_t v3f32_t;
|
||||
union v3f32_t {
|
||||
struct { f32 x, y, z; };
|
||||
struct { v2f32_t xy; };
|
||||
struct { f32 _x0; v2f32_t zw; };
|
||||
struct { f32 r, g, b; };
|
||||
struct { f32 h, s, l; };
|
||||
f32 e[3];
|
||||
};
|
||||
|
||||
typedef union v4f32_t v4f32_t;
|
||||
union v4f32_t {
|
||||
struct { f32 x, y, z, w; };
|
||||
struct { v2f32_t xy; v2f32_t zw; };
|
||||
struct { v3f32_t xyz; };
|
||||
struct { f32 _x0; f32 yzw; };
|
||||
struct { f32 r, g, b, a; };
|
||||
struct { f32 h, s, l, _a; };
|
||||
f32 e[4];
|
||||
};
|
||||
|
||||
typedef union r1f32_t r1f32_t;
|
||||
union r1f32_t {
|
||||
struct { f32 min, max; };
|
||||
struct { f32 x0, x1; };
|
||||
f32 e[2];
|
||||
};
|
||||
|
||||
typedef union r2f32_t r2f32_t;
|
||||
union r2f32_t {
|
||||
struct { v2f32_t min, max; };
|
||||
struct { f32 x0, y0, x1, y1; };
|
||||
v4f32_t e4;
|
||||
f32 e[4];
|
||||
};
|
||||
|
||||
typedef union r3f32_t r3f32_t;
|
||||
union r3f32_t {
|
||||
struct { v3f32_t min, max; };
|
||||
struct { f32 x0, y0, z0, x1, y1, z1; };
|
||||
f32 e[6];
|
||||
};
|
||||
|
||||
|
||||
typedef union v2f64_t v2f64_t;
|
||||
union v2f64_t {
|
||||
struct { f64 x, y; };
|
||||
f64 e[2];
|
||||
};
|
||||
|
||||
typedef union v3f64_t v3f64_t;
|
||||
union v3f64_t {
|
||||
struct { f64 x, y, z; };
|
||||
struct { v2f64_t xy; };
|
||||
struct { f64 _x0; v2f64_t zw; };
|
||||
struct { f64 r, g, b; };
|
||||
struct { f64 h, s, l; };
|
||||
f64 e[3];
|
||||
};
|
||||
|
||||
typedef union v4f64_t v4f64_t;
|
||||
union v4f64_t {
|
||||
struct { f64 x, y, z, w; };
|
||||
struct { v2f64_t xy; v2f64_t zw; };
|
||||
struct { v3f64_t xyz; };
|
||||
struct { f64 _x0; f64 yzw; };
|
||||
struct { f64 r, g, b, a; };
|
||||
struct { f64 h, s, l, _a; };
|
||||
f64 e[4];
|
||||
};
|
||||
|
||||
typedef union r1f64_t r1f64_t;
|
||||
union r1f64_t {
|
||||
struct { f64 min, max; };
|
||||
struct { f64 x0, x1; };
|
||||
f64 e[2];
|
||||
};
|
||||
|
||||
typedef union r2f64_t r2f64_t;
|
||||
union r2f64_t {
|
||||
struct { v2f64_t min, max; };
|
||||
struct { f64 x0, y0, x1, y1; };
|
||||
v4f64_t e4;
|
||||
f64 e[4];
|
||||
};
|
||||
|
||||
typedef union r3f64_t r3f64_t;
|
||||
union r3f64_t {
|
||||
struct { v3f64_t min, max; };
|
||||
struct { f64 x0, y0, z0, x1, y1, z1; };
|
||||
f64 e[6];
|
||||
};
|
||||
|
||||
|
||||
typedef union v2i32_t v2i32_t;
|
||||
union v2i32_t {
|
||||
struct { i32 x, y; };
|
||||
i32 e[2];
|
||||
};
|
||||
|
||||
typedef union v3i32_t v3i32_t;
|
||||
union v3i32_t {
|
||||
struct { i32 x, y, z; };
|
||||
struct { v2i32_t xy; };
|
||||
struct { i32 _x0; v2i32_t zw; };
|
||||
struct { i32 r, g, b; };
|
||||
struct { i32 h, s, l; };
|
||||
i32 e[3];
|
||||
};
|
||||
|
||||
typedef union v4i32_t v4i32_t;
|
||||
union v4i32_t {
|
||||
struct { i32 x, y, z, w; };
|
||||
struct { v2i32_t xy; v2i32_t zw; };
|
||||
struct { v3i32_t xyz; };
|
||||
struct { i32 _x0; i32 yzw; };
|
||||
struct { i32 r, g, b, a; };
|
||||
struct { i32 h, s, l, _a; };
|
||||
i32 e[4];
|
||||
};
|
||||
|
||||
typedef union r1i32_t r1i32_t;
|
||||
union r1i32_t {
|
||||
struct { i32 min, max; };
|
||||
struct { i32 x0, x1; };
|
||||
i32 e[2];
|
||||
};
|
||||
|
||||
typedef union r2i32_t r2i32_t;
|
||||
union r2i32_t {
|
||||
struct { v2i32_t min, max; };
|
||||
struct { i32 x0, y0, x1, y1; };
|
||||
v4i32_t e4;
|
||||
i32 e[4];
|
||||
};
|
||||
|
||||
typedef union r3i32_t r3i32_t;
|
||||
union r3i32_t {
|
||||
struct { v3i32_t min, max; };
|
||||
struct { i32 x0, y0, z0, x1, y1, z1; };
|
||||
i32 e[6];
|
||||
};
|
||||
|
||||
|
||||
typedef union v2i64_t v2i64_t;
|
||||
union v2i64_t {
|
||||
struct { i64 x, y; };
|
||||
i64 e[2];
|
||||
};
|
||||
|
||||
typedef union v3i64_t v3i64_t;
|
||||
union v3i64_t {
|
||||
struct { i64 x, y, z; };
|
||||
struct { v2i64_t xy; };
|
||||
struct { i64 _x0; v2i64_t zw; };
|
||||
struct { i64 r, g, b; };
|
||||
struct { i64 h, s, l; };
|
||||
i64 e[3];
|
||||
};
|
||||
|
||||
typedef union v4i64_t v4i64_t;
|
||||
union v4i64_t {
|
||||
struct { i64 x, y, z, w; };
|
||||
struct { v2i64_t xy; v2i64_t zw; };
|
||||
struct { v3i64_t xyz; };
|
||||
struct { i64 _x0; i64 yzw; };
|
||||
struct { i64 r, g, b, a; };
|
||||
struct { i64 h, s, l, _a; };
|
||||
i64 e[4];
|
||||
};
|
||||
|
||||
typedef union r1i64_t r1i64_t;
|
||||
union r1i64_t {
|
||||
struct { i64 min, max; };
|
||||
struct { i64 x0, x1; };
|
||||
i64 e[2];
|
||||
};
|
||||
|
||||
typedef union r2i64_t r2i64_t;
|
||||
union r2i64_t {
|
||||
struct { v2i64_t min, max; };
|
||||
struct { i64 x0, y0, x1, y1; };
|
||||
v4i64_t e4;
|
||||
i64 e[4];
|
||||
};
|
||||
|
||||
typedef union r3i64_t r3i64_t;
|
||||
union r3i64_t {
|
||||
struct { v3i64_t min, max; };
|
||||
struct { i64 x0, y0, z0, x1, y1, z1; };
|
||||
i64 e[6];
|
||||
};
|
||||
|
||||
#define F64_PI (3.1415926535897932384626433832795028841971693994)
|
||||
#define F64_DEG2RAD (F64_PI / 180.0); // @Usage: degree * DEG2RAD = radians;
|
||||
#define F64_RAD2DEG (180.0 / F64_PI);
|
||||
#define F32_PI ((f32)F64_PI)
|
||||
|
||||
#define v4f32_const_rgba255(r, g, b, a) { (f32)(r) / 255.0f, (f32)(g) / 255.0f, (f32)(b) / 255.0f, (f32)(a) / 255.0f }
|
||||
#define v4f32_rgba255(r, g, b, a) (v4f32_t){ (f32)(r) / 255.0f, (f32)(g) / 255.0f, (f32)(b) / 255.0f, (f32)(a) / 255.0f }
|
||||
|
||||
static gb_read_only v4f32_t white_color = v4f32_const_rgba255(255, 255, 255, 255);
|
||||
static gb_read_only v4f32_t black_color = v4f32_const_rgba255(0, 0, 0, 255);
|
||||
static gb_read_only v4f32_t magenta_color = v4f32_const_rgba255(255, 0, 255, 255);
|
||||
static gb_read_only v4f32_t red_color = v4f32_const_rgba255(255, 0, 0, 255);
|
||||
static gb_read_only v4f32_t blue_color = v4f32_const_rgba255(0, 0, 255, 255);
|
||||
406
src/core/core_math_gen.py
Normal file
406
src/core/core_math_gen.py
Normal file
@@ -0,0 +1,406 @@
|
||||
import sys
|
||||
|
||||
op_idx = 0
|
||||
opname_idx = 1
|
||||
symbols = [
|
||||
["+", "add"],
|
||||
["-", "sub"],
|
||||
["*", "mul"],
|
||||
["/", "div"],
|
||||
]
|
||||
|
||||
basic_types = [
|
||||
"f32",
|
||||
"f64",
|
||||
"i32",
|
||||
"i64",
|
||||
]
|
||||
|
||||
name_idx = 0
|
||||
member_idx = 1
|
||||
|
||||
vec_types = [
|
||||
["v2", ["x", "y"]],
|
||||
["v3", ["x", "y", "z"]],
|
||||
["v4", ["x", "y", "z", "w"]],
|
||||
]
|
||||
|
||||
rect_types = [
|
||||
["r2", ["x0", "y0", "x1", "y1"]],
|
||||
["r3", ["x0", "y0", "z0", "x1", "y1", "z1"]],
|
||||
]
|
||||
|
||||
struct_types = vec_types + rect_types
|
||||
|
||||
|
||||
# fd = open("core_math.gen.h", "w")
|
||||
# sys.stdout = fd
|
||||
|
||||
# print("// auto generated using:", __file__)
|
||||
|
||||
# for bt in basic_types:
|
||||
# s = """
|
||||
# typedef union v2f64_t v2f64_t;
|
||||
# union v2f64_t {
|
||||
# struct { f64 x, y; };
|
||||
# f64 e[2];
|
||||
# };
|
||||
|
||||
# typedef union v3f64_t v3f64_t;
|
||||
# union v3f64_t {
|
||||
# struct { f64 x, y, z; };
|
||||
# struct { v2f64_t xy; };
|
||||
# struct { f64 _x0; v2f64_t zw; };
|
||||
# struct { f64 r, g, b; };
|
||||
# struct { f64 h, s, l; };
|
||||
# f64 e[3];
|
||||
# };
|
||||
|
||||
# typedef union v4f64_t v4f64_t;
|
||||
# union v4f64_t {
|
||||
# struct { f64 x, y, z, w; };
|
||||
# struct { v2f64_t xy; v2f64_t zw; };
|
||||
# struct { v3f64_t xyz; };
|
||||
# struct { f64 _x0; f64 yzw; };
|
||||
# struct { f64 r, g, b, a; };
|
||||
# struct { f64 h, s, l, _a; };
|
||||
# f64 e[4];
|
||||
# };
|
||||
|
||||
# typedef union r1f64_t r1f64_t;
|
||||
# union r1f64_t {
|
||||
# struct { f64 min, max; };
|
||||
# struct { f64 x0, x1; };
|
||||
# f64 e[2];
|
||||
# };
|
||||
|
||||
# typedef union r2f64_t r2f64_t;
|
||||
# union r2f64_t {
|
||||
# struct { v2f64_t min, max; };
|
||||
# struct { f64 x0, y0, x1, y1; };
|
||||
# v4f64_t e4;
|
||||
# f64 e[4];
|
||||
# };
|
||||
|
||||
# typedef union r3f64_t r3f64_t;
|
||||
# union r3f64_t {
|
||||
# struct { v3f64_t min, max; };
|
||||
# struct { f64 x0, y0, z0, x1, y1, z1; };
|
||||
# f64 e[6];
|
||||
# };
|
||||
#
|
||||
#
|
||||
# type_t type__v2f64_t = { type_kind_struct, s8_const("v2f64_t"), sizeof(v2f64_t), .count = 2,
|
||||
# .members = (type_member_t[]){
|
||||
# {s8_const("x"), &type__f64, .offset = offsetof(v2f64_t, x)},
|
||||
# {s8_const("y"), &type__f64, .offset = offsetof(v2f64_t, y)},
|
||||
# }
|
||||
# };
|
||||
|
||||
# type_t type__v3f64_t = { type_kind_struct, s8_const("v3f64_t"), sizeof(v3f64_t), .count = 3,
|
||||
# .members = (type_member_t[]){
|
||||
# {s8_const("x"), &type__f64, .offset = offsetof(v3f64_t, x)},
|
||||
# {s8_const("y"), &type__f64, .offset = offsetof(v3f64_t, y)},
|
||||
# {s8_const("z"), &type__f64, .offset = offsetof(v3f64_t, z)},
|
||||
# }
|
||||
# };
|
||||
|
||||
# type_t type__v4f64_t = { type_kind_struct, s8_const("v4f64_t"), sizeof(v4f64_t), .count = 4,
|
||||
# .members = (type_member_t[]){
|
||||
# {s8_const("x"), &type__f64, .offset = offsetof(v4f64_t, x)},
|
||||
# {s8_const("y"), &type__f64, .offset = offsetof(v4f64_t, y)},
|
||||
# {s8_const("z"), &type__f64, .offset = offsetof(v4f64_t, z)},
|
||||
# {s8_const("w"), &type__f64, .offset = offsetof(v4f64_t, w)},
|
||||
# }
|
||||
# };
|
||||
|
||||
# type_t type__r3f64_t = { type_kind_struct, s8_const("r3f64_t"), sizeof(r3f64_t), .count = 6,
|
||||
# .members = (type_member_t[]){
|
||||
# {s8_const("x0"), &type__f64, .offset = offsetof(r3f64_t, x0)},
|
||||
# {s8_const("y0"), &type__f64, .offset = offsetof(r3f64_t, y0)},
|
||||
# {s8_const("x0"), &type__f64, .offset = offsetof(r3f64_t, z0)},
|
||||
# {s8_const("x1"), &type__f64, .offset = offsetof(r3f64_t, x1)},
|
||||
# {s8_const("y1"), &type__f64, .offset = offsetof(r3f64_t, y1)},
|
||||
# {s8_const("x1"), &type__f64, .offset = offsetof(r3f64_t, z1)},
|
||||
# }
|
||||
# };
|
||||
|
||||
# type_member_t members__r2f64_t[] = {
|
||||
# {s8_const("x0"), &type__f64, .offset = offsetof(r2f64_t, x0)},
|
||||
# {s8_const("y0"), &type__f64, .offset = offsetof(r2f64_t, y0)},
|
||||
# {s8_const("x1"), &type__f64, .offset = offsetof(r2f64_t, x1)},
|
||||
# {s8_const("y1"), &type__f64, .offset = offsetof(r2f64_t, y1)},
|
||||
# };
|
||||
# DEFINE_STRUCT(r2f64_t);
|
||||
|
||||
# type_member_t members__r1f64_t[] = {
|
||||
# {s8_const("x0"), &type__f64, .offset = offsetof(r1f64_t, x0)},
|
||||
# {s8_const("x1"), &type__f64, .offset = offsetof(r1f64_t, x1)},
|
||||
# };
|
||||
# DEFINE_STRUCT(r1f64_t);
|
||||
# """
|
||||
# s = s.replace("f64", bt)
|
||||
# print(s)
|
||||
|
||||
|
||||
fd = open("core_math.gen.c", "w", newline = "\n", encoding = "utf-8")
|
||||
sys.stdout = fd
|
||||
|
||||
for basic_type in basic_types:
|
||||
for st in struct_types:
|
||||
type = f"{st[name_idx]}{basic_type}"
|
||||
typedef = f"{type}_t"
|
||||
members = st[member_idx]
|
||||
|
||||
def members_as_func_params(members, basic_type):
|
||||
result = ""
|
||||
for i, m in enumerate(members):
|
||||
result += f"{basic_type} {m}"
|
||||
if i != len(members) - 1:
|
||||
result += ", "
|
||||
return result
|
||||
|
||||
print(f"""fn_inline {type}_t {type}({members_as_func_params(members, basic_type)}) {{ return ({type}_t){{ {members_as_func_params(members, "")} }}; }}""")
|
||||
print(f"""gb_read_only {type}_t {type}_null = {{0}};""")
|
||||
print(f"""fn_inline b32 {type}_is_null({type}_t a) {{ return memory_equal(&a, &{type}_null, sizeof(a)); }}""")
|
||||
print(f"""fn_inline b32 {type}_are_equal({type}_t a, {type}_t b) {{ return memory_equal(&a, &b, sizeof(a)); }}""")
|
||||
|
||||
for sym in symbols:
|
||||
op = sym[op_idx]
|
||||
opname = sym[opname_idx]
|
||||
|
||||
|
||||
def op_str(members, op, skip_right = False):
|
||||
result = ""
|
||||
for i in range(len(members)):
|
||||
mem = members[i]
|
||||
if skip_right:
|
||||
result += f"a.{mem} {op} b"
|
||||
else:
|
||||
result += f"a.{mem} {op} b.{mem}"
|
||||
|
||||
if i != len(members) - 1:
|
||||
result += ", "
|
||||
return result
|
||||
|
||||
|
||||
print(f"fn_inline {type}_t {type}_{opname}({type}_t a, {type}_t b) {{ return ({type}_t){{ {op_str(members, op)} }}; }}")
|
||||
print(f"fn_inline {type}_t {type}_{opname}s({type}_t a, {basic_type} b) {{ return ({type}_t){{ {op_str(members, op, skip_right = True)} }}; }}")
|
||||
|
||||
for basic_type in basic_types:
|
||||
for i in range(len(rect_types)):
|
||||
vec_type = vec_types[i]
|
||||
rect_type = rect_types[i]
|
||||
|
||||
vec_name = vec_type[name_idx] + basic_type
|
||||
vec_members = vec_type[member_idx]
|
||||
rect_name = rect_type[name_idx] + basic_type
|
||||
rect_members = rect_type[member_idx]
|
||||
|
||||
print(f"fn_inline {rect_name}_t {rect_name}_min_dim({vec_name}_t pos, {vec_name}_t size) {{ return ({rect_name}_t){{ pos, {vec_name}_add(pos, size) }}; }}")
|
||||
print(f"fn_inline {rect_name}_t {rect_name}_center_half_dim({vec_name}_t center, {vec_name}_t halfdim) {{ return ({rect_name}_t){{ {vec_name}_sub(center, halfdim), {vec_name}_add(center, halfdim) }}; }}")
|
||||
|
||||
for basic_type in basic_types:
|
||||
s = """
|
||||
fn r2f64_t r2f64_cut_left(r2f64_t *r, f64 value) {
|
||||
f64 minx = r->min.x;
|
||||
r->min.x = MIN(r->min.x + value, r->max.x);
|
||||
r2f64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_right(r2f64_t *r, f64 value) {
|
||||
f64 maxx = r->max.x;
|
||||
r->max.x = MAX(r->min.x, r->max.x - value);
|
||||
r2f64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_top(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 miny = r->min.y;
|
||||
r->min.y = MIN(r->max.y, r->min.y + value);
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_bottom(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 maxy = r->max.y;
|
||||
r->max.y = MAX(r->min.y, r->max.y - value);
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_cut_left_no_squash(r2f64_t *r, f64 value) {
|
||||
f64 minx = r->min.x;
|
||||
r->min.x = r->min.x + value;
|
||||
r2f64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_right_no_squash(r2f64_t *r, f64 value) {
|
||||
f64 maxx = r->max.x;
|
||||
r->max.x = r->max.x - value;
|
||||
r2f64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_top_no_squash(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 miny = r->min.y;
|
||||
r->min.y = r->min.y + value;
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_bottom_no_squash(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 maxy = r->max.y;
|
||||
r->max.y = r->max.y - value;
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_add_left(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
|
||||
r->min.x -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_add_right(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
|
||||
r->max.x += value;
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_add_top(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
|
||||
r->min.y -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_add_bottom(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
|
||||
r->max.y += value;
|
||||
return result;
|
||||
}
|
||||
|
||||
// get past left
|
||||
fn r2f64_t r2f64_getp_left(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_getp_right(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_getp_bottom(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_getp_top(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_get_left(const r2f64_t *r, f64 value) {
|
||||
f64 minx = r->min.x;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_get_right(const r2f64_t *r, f64 value) {
|
||||
f64 maxx = r->max.x;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_get_top(const r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 miny = r->min.y;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_get_bottom(const r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 maxy = r->max.y;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
fn_inline r2f64_t r2f64_expand(r2f64_t rect, v2f64_t value) { return (r2f64_t){ v2f64_sub(rect.min, value), v2f64_add(rect.max, value) }; }
|
||||
fn_inline r2f64_t r2f64_shrink(r2f64_t rect, v2f64_t value) { return (r2f64_t){ v2f64_add(rect.min, value), v2f64_sub(rect.max, value) }; }
|
||||
fn_inline r2f64_t r2f64_shrinks(r2f64_t rect, f64 value) { return (r2f64_t){ v2f64_adds(rect.min, value), v2f64_subs(rect.max, value) }; }
|
||||
fn_inline v2f64_t r2f64_size(r2f64_t r) { return (v2f64_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
|
||||
fn_inline v2f64_t r2f64_get_mid(r2f64_t r) { return v2f64_add(r.min, v2f64_divs(r2f64_size(r), 2)); }
|
||||
fn_inline b32 r2f64_contains(r2f64_t rec, v2f64_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
|
||||
fn_inline r2f64_t r2f64_intersect(r2f64_t a, r2f64_t b) { return (r2f64_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
|
||||
fn_inline r2f64_t r2f64_union(r2f64_t a, r2f64_t b) { return (r2f64_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
|
||||
|
||||
fn_inline f64 r1f64_size(r1f64_t a) { return a.max - a.min; }
|
||||
fn_inline r1f64_t r1f64(f64 min, f64 max) { return (r1f64_t){min,max}; }
|
||||
fn_inline r1f64_t r1f64_auto(f64 a, f64 b) { return (r1f64_t){MIN(a,b),MAX(a,b)}; }
|
||||
fn_inline r1f64_t r1f64s(f64 a) { return (r1f64_t){a,a}; }
|
||||
fn_inline r1f64_t r1f64_clamp(r1f64_t a, f64 min, f64 max) { return (r1f64_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
|
||||
fn_inline b32 r1f64_contains(r1f64_t rec, f64 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
|
||||
fn_inline b32 r1f64_are_equal(r1f64_t a, r1f64_t b) { return a.min == b.min && a.max == b.max; }
|
||||
gb_read_only r1f64_t r1f64_null;
|
||||
|
||||
fn b32 r1f64_overlap(r1f64_t a, r1f64_t b) {
|
||||
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
|
||||
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
|
||||
return r1 || r2;
|
||||
}
|
||||
|
||||
fn v2f64_t v2f64_clamps(v2f64_t v, f64 min, f64 max) {
|
||||
v2f64_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
|
||||
return result;
|
||||
}
|
||||
fn v2f64_t v2f64_clamp(v2f64_t v, v2f64_t min, v2f64_t max) {
|
||||
v2f64_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_fix(r2f64_t n) {
|
||||
r2f64_t result = {
|
||||
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
|
||||
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
""".strip()
|
||||
s = s.replace("f64", basic_type)
|
||||
print(s)
|
||||
|
||||
for at in basic_types:
|
||||
for bt in basic_types:
|
||||
if at == bt: continue
|
||||
for st in struct_types:
|
||||
atype = f"{st[name_idx]}{at}"
|
||||
btype = f"{st[name_idx]}{bt}"
|
||||
members = st[member_idx]
|
||||
|
||||
def cast_members(members, type):
|
||||
result = ""
|
||||
for i in range(len(members)):
|
||||
result += f"({type})v.{members[i]}"
|
||||
if i != len(members) - 1:
|
||||
result += ", "
|
||||
return result
|
||||
|
||||
print(f"fn_inline {btype}_t {atype}_to_{btype}({atype}_t v) {{ return ({btype}_t){{ {cast_members(members, bt)} }}; }}")
|
||||
|
||||
|
||||
#######
|
||||
# generate r2f64_sub_v2f64 for +-*/ and types
|
||||
for bt in basic_types:
|
||||
for sym in symbols:
|
||||
word_op = sym[1]
|
||||
s = """
|
||||
fn_inline r2f64_t r2f64_sub_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_sub(a.min, b), v2f64_sub(a.max, b) }; }
|
||||
""".strip()
|
||||
s = s.replace("f64", bt)
|
||||
s = s.replace("sub", word_op)
|
||||
print(s)
|
||||
|
||||
|
||||
for bt in ["f32", "f64"]:
|
||||
s = """
|
||||
fn f64 f64_safe_ratio(f64 a, f64 b, f64 if0) {
|
||||
f64 result = if0;
|
||||
if (b != 0.0) {
|
||||
result = a / b;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn_inline f64 f64_safe_ratio0(f64 a, f64 b) { return f64_safe_ratio(a, b, 0); }
|
||||
fn_inline f64 f64_safe_ratio1(f64 a, f64 b) { return f64_safe_ratio(a, b, 0); }
|
||||
""".strip()
|
||||
s = s.replace("f64", bt)
|
||||
print(s)
|
||||
470
src/core/core_platform.c
Normal file
470
src/core/core_platform.c
Normal file
@@ -0,0 +1,470 @@
|
||||
#include "core_platform.h"
|
||||
#include "core_ctx.h"
|
||||
|
||||
#if PLATFORM_WASM && PLATFORM_EMSCRIPTEN == 0
|
||||
#define gb_wasm_export __attribute__((visibility("default")))
|
||||
#define fn_wasm_export __attribute__((visibility("default")))
|
||||
#define fn_wasm_import
|
||||
|
||||
fn_wasm_import void wasm_alert(isize ptr, i32 len);
|
||||
fn_wasm_import f64 wasm_parse_float(isize str, i32 len);
|
||||
fn_wasm_import void wasm_write_to_console(isize str, i32 len);
|
||||
|
||||
extern char __heap_base;
|
||||
|
||||
fn void *os_vmem_reserve(usize size) {
|
||||
unused(size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_commit(void *p, usize size) {
|
||||
unused(p);
|
||||
unused(size);
|
||||
return false;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_release(void *p) {
|
||||
unused(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_decommit(void *p, usize size) {
|
||||
unused(p);
|
||||
unused(size);
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void os_error_box(char *str) {
|
||||
wasm_alert((isize)str, str_len(str));
|
||||
}
|
||||
|
||||
fn void os_console_log(char *str) {
|
||||
s8_t string = s8_from_char(str);
|
||||
if (s8_ends_with(string, s8("\n"))) {
|
||||
string = s8_chop(string, 1);
|
||||
}
|
||||
wasm_write_to_console((isize)string.str, (i32)string.len);
|
||||
}
|
||||
|
||||
fn f64 os_parse_float(char *str) {
|
||||
return wasm_parse_float((isize)str, str_len((char *)str));
|
||||
}
|
||||
|
||||
fn void os_core_small_init(ma_arena_t *arena) {
|
||||
tcx = ma_push_type(arena, thread_ctx_t);
|
||||
tcx->log.break_on_error = true;
|
||||
tcx->log.break_on_fatal = true;
|
||||
tcx->log.break_on_warning = true;
|
||||
tcx->log.print_file_and_line = true;
|
||||
tcx->log.log_proc = default_log_proc;
|
||||
}
|
||||
|
||||
fn void os_core_init(void) {
|
||||
ma_arena_t perm = {0};
|
||||
isize page_size = kib(64);
|
||||
isize page_count = __builtin_wasm_memory_size(0);
|
||||
u8 *memory = (u8 *)&__heap_base;
|
||||
usize memory_size = page_count * (page_size) - (isize)memory;
|
||||
perm.data = memory;
|
||||
perm.commit = perm.reserve = memory_size;
|
||||
os_core_small_init(&perm);
|
||||
tcx->perm = perm;
|
||||
ma_push_arena_ex(&tcx->perm, &tcx->temp, mib(16));
|
||||
ma_push_arena_ex(&tcx->perm, &tcx->scratch[0], mib(2));
|
||||
ma_push_arena_ex(&tcx->perm, &tcx->scratch[1], kib(256));
|
||||
ma_push_arena_ex(&tcx->perm, &tcx->scratch[2], kib(64));
|
||||
debugf("memory size = %lld", memory_size);
|
||||
}
|
||||
#elif PLATFORM_WINDOWS
|
||||
#pragma comment(lib, "user32.lib")
|
||||
#pragma comment(lib, "DbgHelp.lib")
|
||||
#pragma comment(lib, "Shell32.lib")
|
||||
#pragma comment(lib, "Ole32.lib")
|
||||
#define NOMINMAX
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <DbgHelp.h>
|
||||
#include <TlHelp32.h>
|
||||
#include <Shlobj.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
|
||||
typedef struct b_stacktrace_tag* b_stacktrace_handle;
|
||||
|
||||
/*
|
||||
Returns a stack-trace handle from the point of view of the caller which
|
||||
can be expanded to a string via b_stacktrace_to_string.
|
||||
The handle is allocated with `malloc` and needs to be freed with `free`
|
||||
*/
|
||||
fn b_stacktrace_handle b_stacktrace_get();
|
||||
|
||||
/*
|
||||
Converts a stack-trace handle to a human-readable string.
|
||||
The string is allocated with `malloc` and needs to be freed with `free`
|
||||
*/
|
||||
fn char* b_stacktrace_to_string(b_stacktrace_handle stacktrace);
|
||||
|
||||
/*
|
||||
Returns a human-readable stack-trace string from the point of view of the
|
||||
caller.
|
||||
The string is allocated with `malloc` and needs to be freed with `free`
|
||||
*/
|
||||
fn char* b_stacktrace_get_string(void);
|
||||
|
||||
/* version */
|
||||
|
||||
typedef struct print_buf {
|
||||
char* buf;
|
||||
int pos;
|
||||
int size;
|
||||
} print_buf;
|
||||
|
||||
static print_buf buf_init(void) {
|
||||
print_buf ret = {
|
||||
(char*) malloc(1024),
|
||||
0,
|
||||
1024
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void buf_printf(print_buf* b, const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
const int len = vsnprintf(NULL, 0, fmt, args) + 1;
|
||||
va_end(args);
|
||||
|
||||
const int new_end = b->pos + len;
|
||||
|
||||
if (new_end > b->size) {
|
||||
while (new_end > b->size) b->size *= 2;
|
||||
b->buf = (char*)realloc(b->buf, b->size);
|
||||
}
|
||||
|
||||
va_start(args, fmt);
|
||||
b->pos += vsnprintf(b->buf + b->pos, len, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
char* b_stacktrace_get_string(void) {
|
||||
b_stacktrace_handle h = b_stacktrace_get();
|
||||
char* ret = b_stacktrace_to_string(h);
|
||||
free(h);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define B_STACKTRACE_MAX_DEPTH 1024
|
||||
|
||||
#define B_STACKTRACE_ERROR_FLAG ((DWORD64)1 << 63)
|
||||
|
||||
typedef struct b_stacktrace_entry {
|
||||
DWORD64 AddrPC_Offset;
|
||||
DWORD64 AddrReturn_Offset;
|
||||
} b_stacktrace_entry;
|
||||
|
||||
static int SymInitialize_called = 0;
|
||||
|
||||
b_stacktrace_handle b_stacktrace_get(void) {
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
CONTEXT context;
|
||||
STACKFRAME64 frame; /* in/out stackframe */
|
||||
DWORD imageType;
|
||||
b_stacktrace_entry* ret = (b_stacktrace_entry*)malloc(B_STACKTRACE_MAX_DEPTH * sizeof(b_stacktrace_entry));
|
||||
int i = 0;
|
||||
|
||||
if (!SymInitialize_called) {
|
||||
SymInitialize(process, NULL, TRUE);
|
||||
SymInitialize_called = 1;
|
||||
}
|
||||
|
||||
RtlCaptureContext(&context);
|
||||
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
#ifdef _M_IX86
|
||||
imageType = IMAGE_FILE_MACHINE_I386;
|
||||
frame.AddrPC.Offset = context.Eip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Ebp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Esp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#elif _M_X64
|
||||
imageType = IMAGE_FILE_MACHINE_AMD64;
|
||||
frame.AddrPC.Offset = context.Rip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Rsp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Rsp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#elif _M_IA64
|
||||
imageType = IMAGE_FILE_MACHINE_IA64;
|
||||
frame.AddrPC.Offset = context.StIIP;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.IntSp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrBStore.Offset = context.RsBSP;
|
||||
frame.AddrBStore.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.IntSp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#else
|
||||
#error "Platform not supported!"
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
b_stacktrace_entry* cur = ret + i++;
|
||||
if (i == B_STACKTRACE_MAX_DEPTH) {
|
||||
cur->AddrPC_Offset = 0;
|
||||
cur->AddrReturn_Offset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!StackWalk64(imageType, process, thread, &frame, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
|
||||
cur->AddrPC_Offset = frame.AddrPC.Offset;
|
||||
cur->AddrReturn_Offset = B_STACKTRACE_ERROR_FLAG; /* mark error */
|
||||
cur->AddrReturn_Offset |= GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
cur->AddrPC_Offset = frame.AddrPC.Offset;
|
||||
cur->AddrReturn_Offset = frame.AddrReturn.Offset;
|
||||
|
||||
if (frame.AddrReturn.Offset == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (b_stacktrace_handle)(ret);
|
||||
}
|
||||
|
||||
char* b_stacktrace_to_string(b_stacktrace_handle h) {
|
||||
const b_stacktrace_entry* entries = (b_stacktrace_entry*)h;
|
||||
int i = 0;
|
||||
HANDLE process = GetCurrentProcess();
|
||||
print_buf out = buf_init();
|
||||
IMAGEHLP_SYMBOL64* symbol = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + 1024);
|
||||
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
symbol->MaxNameLength = 1024;
|
||||
|
||||
while (1) {
|
||||
IMAGEHLP_LINE64 lineData;
|
||||
DWORD lineOffset = 0;
|
||||
DWORD64 symOffset = 0;
|
||||
const b_stacktrace_entry* cur = entries + i++;
|
||||
|
||||
if (cur->AddrReturn_Offset & B_STACKTRACE_ERROR_FLAG) {
|
||||
DWORD error = cur->AddrReturn_Offset & 0xFFFFFFFF;
|
||||
buf_printf(&out, "StackWalk64 error: %d @ %p\n", error, cur->AddrPC_Offset);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cur->AddrPC_Offset == cur->AddrReturn_Offset) {
|
||||
buf_printf(&out, "Stack overflow @ %p\n", cur->AddrPC_Offset);
|
||||
break;
|
||||
}
|
||||
|
||||
SymGetLineFromAddr64(process, cur->AddrPC_Offset, &lineOffset, &lineData);
|
||||
buf_printf(&out, "%s(%d): ", lineData.FileName, lineData.LineNumber);
|
||||
|
||||
if (SymGetSymFromAddr64(process, cur->AddrPC_Offset, &symOffset, symbol)) {
|
||||
buf_printf(&out, "%s\n", symbol->Name);
|
||||
}
|
||||
else {
|
||||
buf_printf(&out, " Unkown symbol @ %p\n", cur->AddrPC_Offset);
|
||||
}
|
||||
|
||||
if (cur->AddrReturn_Offset == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(symbol);
|
||||
return out.buf;
|
||||
}
|
||||
|
||||
fn void *os_vmem_reserve(usize size) {
|
||||
void *result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_commit(void *p, usize size) {
|
||||
void *result = VirtualAlloc(p, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
return result ? true : false;
|
||||
}
|
||||
fn b32 os_vmem_release(void *p) {
|
||||
BOOL result = VirtualFree(p, 0, MEM_RELEASE);
|
||||
return result ? true : false;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_decommit(void *p, usize size) {
|
||||
BOOL result = VirtualFree(p, size, MEM_DECOMMIT);
|
||||
return result ? true : false;
|
||||
}
|
||||
|
||||
fn void os_error_box(char *str) {
|
||||
OutputDebugStringA(str);
|
||||
fprintf(stderr, "%s", str);
|
||||
fflush(stderr);
|
||||
MessageBoxA(NULL, str, "fatal error", MB_OK);
|
||||
}
|
||||
|
||||
fn void os_console_log(char *str) {
|
||||
OutputDebugStringA(str);
|
||||
fputs(str, stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
fn f64 os_parse_float(char *str) {
|
||||
return strtod(str, NULL);
|
||||
}
|
||||
|
||||
fn void os_win32_crash_handler(int signal) {
|
||||
printf("signal: %d\n", signal);
|
||||
puts(b_stacktrace_get_string());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fn void os_win32_register_crash_handler() {
|
||||
signal(SIGSEGV, os_win32_crash_handler);
|
||||
signal(SIGABRT, os_win32_crash_handler);
|
||||
}
|
||||
|
||||
fn void os_core_small_init(ma_arena_t *arena) {
|
||||
tcx = ma_push_type(arena, thread_ctx_t);
|
||||
tcx->log.break_on_error = true;
|
||||
tcx->log.break_on_fatal = true;
|
||||
tcx->log.break_on_warning = true;
|
||||
tcx->log.print_file_and_line = true;
|
||||
tcx->log.log_proc = default_log_proc;
|
||||
os_win32_register_crash_handler();
|
||||
}
|
||||
|
||||
fn void os_core_init(void) {
|
||||
ma_arena_t perm = {0};
|
||||
os_core_small_init(&perm);
|
||||
tcx->perm = perm;
|
||||
}
|
||||
#elif PLATFORM_POSIX
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <signal.h>
|
||||
#include <ucontext.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#if !PLATFORM_EMSCRIPTEN
|
||||
#include <execinfo.h>
|
||||
#include <backtrace.h>
|
||||
#endif
|
||||
fn void *os_vmem_reserve(usize size) {
|
||||
void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
return result == MAP_FAILED ? NULL : result;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_commit(void *ptr, usize size) {
|
||||
mprotect(ptr, size, PROT_READ|PROT_WRITE);
|
||||
return true;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_release(void *ptr) {
|
||||
int result = munmap(ptr, 0);
|
||||
return result == 0 ? true : false;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_decommit(void *ptr, usize size) {
|
||||
madvise(ptr, size, MADV_DONTNEED);
|
||||
mprotect(ptr, size, PROT_NONE);
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void os_error_box(char *str) {
|
||||
fprintf(stderr, "%s", str);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
fn void os_console_log(char *str) {
|
||||
fputs(str, stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
fn f64 os_parse_float(char *str) {
|
||||
return strtod(str, NULL);
|
||||
}
|
||||
|
||||
gb struct backtrace_state *backtrace_state = NULL;
|
||||
|
||||
fn void os_core_backtrace_error_callback(void *data, const char *msg, int errnum) {
|
||||
unused(data);
|
||||
errorf("libbacktrace error: %s (errnum: %d)\n", msg, errnum);
|
||||
}
|
||||
|
||||
fn int os_core_backtrace_print_callback(void *data, uintptr_t pc, const char *filename, int lineno, const char *function) {
|
||||
unused(data);
|
||||
unused(pc);
|
||||
b32 printed = false;
|
||||
if (filename != NULL) {
|
||||
char buffer[512];
|
||||
char *f = realpath(filename, buffer);
|
||||
printf("%s:%d:1: ", f, lineno);
|
||||
printed = true;
|
||||
}
|
||||
if (function != NULL) {
|
||||
printf("%s", function);
|
||||
printed = true;
|
||||
}
|
||||
if (printed) {
|
||||
printf("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !PLATFORM_EMSCRIPTEN
|
||||
fn void os_unix_crash_handler(int signal, siginfo_t* info, void* context) {
|
||||
unused(context);
|
||||
unused(signal);
|
||||
unused(info);
|
||||
backtrace_full(backtrace_state, 2, os_core_backtrace_print_callback, os_core_backtrace_error_callback, NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fn void os_unix_register_crash_handler() {
|
||||
backtrace_state = backtrace_create_state(NULL, 1, os_core_backtrace_error_callback, NULL);
|
||||
|
||||
struct sigaction sa;
|
||||
sa.sa_sigaction = os_unix_crash_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
sigaction(SIGABRT, &sa, NULL);
|
||||
sigaction(SIGBUS, &sa, NULL);
|
||||
sigaction(SIGILL, &sa, NULL);
|
||||
sigaction(SIGFPE, &sa, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
fn void os_core_small_init(ma_arena_t *arena) {
|
||||
tcx = ma_push_type(arena, thread_ctx_t);
|
||||
tcx->log.break_on_error = true;
|
||||
tcx->log.break_on_fatal = true;
|
||||
tcx->log.break_on_warning = true;
|
||||
tcx->log.print_file_and_line = true;
|
||||
tcx->log.log_proc = default_log_proc;
|
||||
#if !PLATFORM_EMSCRIPTEN
|
||||
os_unix_register_crash_handler();
|
||||
#endif
|
||||
}
|
||||
|
||||
fn void os_core_init(void) {
|
||||
ma_arena_t perm = {0};
|
||||
os_core_small_init(&perm);
|
||||
tcx->perm = perm;
|
||||
}
|
||||
#endif
|
||||
30
src/core/core_platform.h
Normal file
30
src/core/core_platform.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
#include "core_arena.h"
|
||||
|
||||
fn void os_error_box(char *str);
|
||||
fn void os_console_log(char *str);
|
||||
|
||||
fn void *os_vmem_reserve(usize size);
|
||||
fn b32 os_vmem_commit(void *p, usize size);
|
||||
fn b32 os_vmem_release(void *p);
|
||||
fn b32 os_vmem_decommit(void *p, usize size);
|
||||
|
||||
fn void os_core_init(void);
|
||||
fn void os_core_small_init(ma_arena_t *arena);
|
||||
fn f64 os_parse_float(char *str);
|
||||
|
||||
|
||||
#if PLATFORM_DEBUG_ASSERT
|
||||
#define assert_expr(x) (!(x) && (os_error_box(FILE_AND_LINE ": assertion failed: " #x "\n"), debug_break()))
|
||||
#define assert(x) do { assert_expr(x); } while(0)
|
||||
#define assert_ex(x, msg) (!(x) && (os_error_box(FILE_AND_LINE ": assertion failed: " #x " :: " #msg "\n"), debug_break()))
|
||||
#else
|
||||
#define assert_expr(x) (void)(x)
|
||||
#define assert(x) do { (void)(x); } while(0)
|
||||
#define assert_ex(x, msg) do { (void)(x); } while(0)
|
||||
#endif
|
||||
#define not_implemented assert(!"not implemented!")
|
||||
#define invalid_codepath assert(!"invalid code path!")
|
||||
#define default_is_invalid default: assert(!"invalid default case")
|
||||
#define else_is_invalid else { assert(!"else was not expected to be executed!"); }
|
||||
559
src/core/core_string.c
Normal file
559
src/core/core_string.c
Normal file
@@ -0,0 +1,559 @@
|
||||
#include "core_string.h"
|
||||
#include "core_intrin.h"
|
||||
#include "core_platform.h"
|
||||
#include "stb_sprintf.h"
|
||||
|
||||
#define s8_vsnprintf stbsp_vsnprintf
|
||||
|
||||
fn i32 str_len(char *str) {
|
||||
i32 i = 0;
|
||||
while (str[i]) i += 1;
|
||||
return i;
|
||||
}
|
||||
|
||||
fn b32 str_eq(char *a, char *b) {
|
||||
return s8_are_equal(s8_from_char(a), s8_from_char(b));
|
||||
}
|
||||
|
||||
fn char char_to_lower_case(char a) {
|
||||
if (a >= 'A' && a <= 'Z') a += 32;
|
||||
return a;
|
||||
}
|
||||
|
||||
fn char char_to_upper_case(char a) {
|
||||
if (a >= 'a' && a <= 'z') a -= 32;
|
||||
return a;
|
||||
}
|
||||
|
||||
fn b32 char_is_whitespace(char w) {
|
||||
b32 result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r';
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char_is_alphabetic(char a) {
|
||||
b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char_is_ident(char a) {
|
||||
b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z') || a == '_';
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char_is_digit(char a) {
|
||||
b32 result = a >= '0' && a <= '9';
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char_is_alphanumeric(char a) {
|
||||
b32 result = char_is_digit(a) || char_is_alphabetic(a);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char_is_symbol(char w) {
|
||||
b32 result = (w >= '!' && w <= '/') || (w >= ':' && w <= '@') || (w >= '[' && w <= '`') || (w >= '{' && w <= '~');
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char_is_non_word(char w) {
|
||||
b32 result = w != '_' && (char_is_symbol(w) || char_is_whitespace(w));
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char_is_word(char w) {
|
||||
b32 result = !char_is_non_word(w);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_from_range(char *begin, char *end) {
|
||||
assert(end >= begin);
|
||||
intptr_t size = (intptr_t)end - (intptr_t)begin;
|
||||
s8_t result = {begin, size};
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_from_char(char *string) {
|
||||
s8_t result;
|
||||
result.str = (char *)string;
|
||||
result.len = str_len(string);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_copy(ma_arena_t *ma, s8_t string) {
|
||||
char *copy = (char *)ma_push_size(ma, sizeof(char) * (string.len + 1));
|
||||
memory_copy(copy, string.str, string.len);
|
||||
copy[string.len] = 0;
|
||||
s8_t result = s8_make(copy, string.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_copy_char(ma_arena_t *ma, char *s) {
|
||||
int64_t len = str_len(s);
|
||||
char *copy = (char *)ma_push_size(ma, sizeof(char) * (len + 1));
|
||||
memory_copy(copy, s, len);
|
||||
copy[len] = 0;
|
||||
s8_t result = s8_make(copy, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s8_are_equal_ex(s8_t a, s8_t b, b32 ignore_case) {
|
||||
if (a.len != b.len) return false;
|
||||
for (int64_t i = 0; i < a.len; i++) {
|
||||
char A = a.str[i];
|
||||
char B = b.str[i];
|
||||
if (ignore_case) {
|
||||
A = char_to_lower_case(A);
|
||||
B = char_to_lower_case(B);
|
||||
}
|
||||
if (A != B)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn b32 s8_are_equal(s8_t a, s8_t b) {
|
||||
return s8_are_equal_ex(a, b, false);
|
||||
}
|
||||
|
||||
fn s8_t s8_get_postfix(s8_t string, int64_t len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
int64_t remain_len = string.len - len;
|
||||
s8_t result = s8_make(string.str + remain_len, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_get_prefix(s8_t string, int64_t len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
s8_t result = s8_make(string.str, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_chop(s8_t string, int64_t len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
s8_t result = s8_make(string.str, string.len - len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_skip(s8_t string, int64_t len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
int64_t remain = string.len - len;
|
||||
s8_t result = s8_make(string.str + len, remain);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s8_ends_with_ex(s8_t a, s8_t end, b32 ignore_case) {
|
||||
s8_t a_end = s8_get_postfix(a, end.len);
|
||||
b32 result = s8_are_equal_ex(end, a_end, ignore_case);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s8_starts_with_ex(s8_t a, s8_t start, b32 ignore_case) {
|
||||
s8_t a_start = s8_get_prefix(a, start.len);
|
||||
b32 result = s8_are_equal_ex(start, a_start, ignore_case);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s8_ends_with(s8_t a, s8_t end) {
|
||||
return s8_ends_with_ex(a, end, false);
|
||||
}
|
||||
|
||||
fn b32 s8_starts_with(s8_t a, s8_t start) {
|
||||
return s8_starts_with_ex(a, start, false);
|
||||
}
|
||||
|
||||
fn void s8_normalize_path_unsafe(s8_t s) {
|
||||
for (int64_t i = 0; i < s.len; i++) {
|
||||
if (s.str[i] == '\\')
|
||||
s.str[i] = '/';
|
||||
}
|
||||
}
|
||||
|
||||
fn b32 s8_is_pointer_inside(s8_t string, char *p) {
|
||||
uintptr_t pointer = (uintptr_t)p;
|
||||
uintptr_t start = (uintptr_t)string.str;
|
||||
uintptr_t stop = start + (uintptr_t)string.len;
|
||||
b32 result = pointer >= start && pointer < stop;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_cut_start(s8_t *in, i64 size) {
|
||||
s8_t result = s8_get_prefix(*in, size);
|
||||
*in = s8_skip(*in, result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_cut_end(s8_t *in, i64 size) {
|
||||
s8_t result = s8_get_postfix(*in, size);
|
||||
*in = s8_chop(*in, result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if 0
|
||||
s8_t s8_skip_to_p(s8_t string, char *p) {
|
||||
if (s8_is_pointer_inside(string, p)) {
|
||||
s8_t result = s8_make(p, p - string.str);
|
||||
return result;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
s8_t s8_skip_past(s8_t string, s8_t a) {
|
||||
if (s8_is_pointer_inside(string, a.str)) {
|
||||
s8_t on_p = s8_make(a.str, a.str - string.str);
|
||||
s8_t result = s8_skip(on_p, a.len);
|
||||
return result;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
#endif
|
||||
|
||||
fn s8_t s8_slice(s8_t string, int64_t first_index, int64_t one_past_last_index) {
|
||||
if (one_past_last_index < 0) one_past_last_index = string.len + one_past_last_index + 1;
|
||||
if (first_index < 0) first_index = string.len + first_index;
|
||||
assert(first_index < one_past_last_index);
|
||||
assert(string.len > 0);
|
||||
s8_t result = string;
|
||||
if (string.len > 0) {
|
||||
if (one_past_last_index > first_index) {
|
||||
first_index = CLAMP_TOP(first_index, string.len - 1);
|
||||
one_past_last_index = CLAMP_TOP(one_past_last_index, string.len);
|
||||
result.str += first_index;
|
||||
result.len = one_past_last_index - first_index;
|
||||
}
|
||||
else {
|
||||
result.len = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_trim(s8_t string) {
|
||||
if (string.len == 0)
|
||||
return string;
|
||||
|
||||
int64_t whitespace_begin = 0;
|
||||
for (; whitespace_begin < string.len; whitespace_begin++) {
|
||||
if (!char_is_whitespace(string.str[whitespace_begin])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t whitespace_end = string.len;
|
||||
for (; whitespace_end != whitespace_begin; whitespace_end--) {
|
||||
if (!char_is_whitespace(string.str[whitespace_end - 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (whitespace_begin == whitespace_end) {
|
||||
string.len = 0;
|
||||
}
|
||||
else {
|
||||
string = s8_slice(string, whitespace_begin, whitespace_end);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
fn s8_t s8_trim_end(s8_t string) {
|
||||
int64_t whitespace_end = string.len;
|
||||
for (; whitespace_end != 0; whitespace_end--) {
|
||||
if (!char_is_whitespace(string.str[whitespace_end - 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s8_t result = s8_get_prefix(string, whitespace_end);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s8_seek(s8_t string, s8_t find, s8_seek_t flags, int64_t *index_out) {
|
||||
b32 ignore_case = flags & s8_seek_ignore_case ? true : false;
|
||||
b32 result = false;
|
||||
if (flags & s8_seek_match_find_last) {
|
||||
for (int64_t i = string.len; i != 0; i--) {
|
||||
int64_t index = i - 1;
|
||||
s8_t substring = s8_slice(string, index, index + find.len);
|
||||
if (s8_are_equal_ex(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = index;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int64_t i = 0; i < string.len; i++) {
|
||||
s8_t substring = s8_slice(string, i, i + find.len);
|
||||
if (s8_are_equal_ex(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = i;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn int64_t s8_find(s8_t string, s8_t find, s8_seek_t flag) {
|
||||
int64_t result = -1;
|
||||
s8_seek(string, find, flag, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_chop_last_char(s8_t s, s8_t ch) {
|
||||
s8_t result = s;
|
||||
s8_seek(s, ch, s8_seek_match_find_last, &result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_chop_last_slash(s8_t s) {
|
||||
return s8_chop_last_char(s, s8("/"));
|
||||
}
|
||||
|
||||
fn s8_t s8_chop_last_period(s8_t s) {
|
||||
return s8_chop_last_char(s, s8("."));
|
||||
}
|
||||
|
||||
fn s8_t s8_skip_to_last_char(s8_t s, s8_t ch) {
|
||||
int64_t pos;
|
||||
s8_t result = s;
|
||||
if (s8_seek(s, ch, s8_seek_match_find_last, &pos)) {
|
||||
result = s8_skip(result, pos + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_skip_to_last_slash(s8_t s) {
|
||||
return s8_skip_to_last_char(s, s8("/"));
|
||||
}
|
||||
|
||||
fn s8_t s8_skip_to_last_period(s8_t s) {
|
||||
return s8_skip_to_last_char(s, s8("."));
|
||||
}
|
||||
|
||||
fn s8_t s8_get_name_no_ext(s8_t s) {
|
||||
return s8_skip_to_last_slash(s8_chop_last_period(s));
|
||||
}
|
||||
|
||||
fn s8_t s8_normalize_path(ma_arena_t *ma, s8_t s) {
|
||||
s8_t copy = s8_copy(ma, s);
|
||||
s8_normalize_path_unsafe(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn s8_t s8_to_lower_case(ma_arena_t *ma, s8_t s) {
|
||||
s8_t copy = s8_copy(ma, s);
|
||||
for (int64_t i = 0; i < copy.len; i++) {
|
||||
copy.str[i] = char_to_lower_case(copy.str[i]);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn s8_t s8_to_upper_case(ma_arena_t *ma, s8_t s) {
|
||||
s8_t copy = s8_copy(ma, s);
|
||||
for (int64_t i = 0; i < copy.len; i++) {
|
||||
copy.str[i] = char_to_upper_case(copy.str[i]);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn s8_t s8_vfmt(ma_arena_t *ma, const char *str, va_list args1) {
|
||||
va_list args2;
|
||||
va_copy(args2, args1);
|
||||
int64_t len = s8_vsnprintf(0, 0, str, args2);
|
||||
va_end(args2);
|
||||
|
||||
char *result = (char *)ma_push_size(ma, sizeof(char) * (len + 1));
|
||||
s8_vsnprintf(result, (i32)(len + 1), str, args1);
|
||||
s8_t res = s8_make(result, len);
|
||||
return res;
|
||||
}
|
||||
|
||||
fn s8_t s8_printf(ma_arena_t *ma, const char *str, ...) {
|
||||
S8_FMT(ma, str, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn sb8_node_t *sb8_create_node(ma_arena_t *ma, s8_t str) {
|
||||
sb8_node_t *node = ma_push_type(ma, sb8_node_t);
|
||||
node->string = str;
|
||||
return node;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
fn s8_t sb8_printf(sb8_t *sb, const char *str, ...) {
|
||||
S8_FMT(sb->arena, str, result);
|
||||
sb8_append(sb, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void sb8_indent(sb8_t *sb) {
|
||||
sb8_printf(sb, "\n%.*s", sb->indent*4, " ");
|
||||
}
|
||||
|
||||
fn s8_t sb8_stmtf(sb8_t *sb, const char *str, ...) {
|
||||
S8_FMT(sb->arena, str, result);
|
||||
sb8_indent(sb);
|
||||
sb8_append(sb, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn int64_t sb8_char_size(sb8_t *sb) {
|
||||
int64_t result = 0;
|
||||
for (sb8_node_t *it = sb->first; it; it = it->next) {
|
||||
result += it->len;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t sb8_merge(ma_arena_t *arena, sb8_t *sb) {
|
||||
int64_t size = sb8_char_size(sb) + 1;
|
||||
char *str = ma_push_size(arena, size);
|
||||
s8_t result = {str, 0};
|
||||
for (sb8_node_t *it = sb->first; it; it = it->next) {
|
||||
memory_copy(result.str + result.len, it->str, it->len);
|
||||
result.len += it->len;
|
||||
}
|
||||
result.str[result.len] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn sb8_t s8_split(ma_arena_t *ma, s8_t string, s8_t find, s8_split_t flags) {
|
||||
sb8_t result = (sb8_t){ma};
|
||||
int64_t index = 0;
|
||||
|
||||
s8_seek_t find_flag = flags & s8_split_ignore_case ? s8_seek_ignore_case : s8_seek_none;
|
||||
while (s8_seek(string, find, find_flag, &index)) {
|
||||
s8_t before_match = s8_make(string.str, index);
|
||||
if (flags & s8_split_cleanup) {
|
||||
before_match = s8_trim(before_match);
|
||||
if (before_match.len) {
|
||||
sb8_append(&result, before_match);
|
||||
}
|
||||
} else {
|
||||
sb8_append(&result, before_match);
|
||||
}
|
||||
if (flags & s8_split_inclusive) {
|
||||
s8_t match = s8_make(string.str + index, find.len);
|
||||
sb8_append(&result, match);
|
||||
}
|
||||
string = s8_skip(string, index + find.len);
|
||||
}
|
||||
if (string.len) sb8_append(&result, string);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn u64 u64_from_hexchar(char c) {
|
||||
switch (c) {
|
||||
case '0': return 0; break;
|
||||
case '1': return 1; break;
|
||||
case '2': return 2; break;
|
||||
case '3': return 3; break;
|
||||
case '4': return 4; break;
|
||||
case '5': return 5; break;
|
||||
case '6': return 6; break;
|
||||
case '7': return 7; break;
|
||||
case '8': return 8; break;
|
||||
case '9': return 9; break;
|
||||
case 'a':
|
||||
case 'A': return 10; break;
|
||||
case 'b':
|
||||
case 'B': return 11; break;
|
||||
case 'c':
|
||||
case 'C': return 12; break;
|
||||
case 'd':
|
||||
case 'D': return 13; break;
|
||||
case 'e':
|
||||
case 'E': return 14; break;
|
||||
case 'f':
|
||||
case 'F': return 15; break;
|
||||
default: return 255;
|
||||
}
|
||||
}
|
||||
|
||||
fn u64 u64_from_s8(s8_t s, u64 base) {
|
||||
assert(base >= 2 && base <= 16);
|
||||
u64 acc = 0;
|
||||
for (i64 i = 0; i < s.len; i++) {
|
||||
u64 num = u64_from_hexchar(s.str[i]);
|
||||
assert(num < base);
|
||||
acc *= base;
|
||||
acc += num;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
fn u64 u64_from_s8_loose(s8_t s, u64 base) {
|
||||
assert(base >= 2 && base <= 16);
|
||||
u64 acc = 0;
|
||||
for (i64 i = 0; i < s.len; i++) {
|
||||
u64 num = u64_from_hexchar(s.str[i]);
|
||||
if (num >= base) {
|
||||
break;
|
||||
}
|
||||
acc *= base;
|
||||
acc += num;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
fn f64 f64_from_s8(s8_t string) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s8_t num_string = s8_copy(scratch.arena, string);
|
||||
f64 result = os_parse_float(num_string.str);
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
gb_read_only i64 s8_fuzzy_closer_word_begin = 5;
|
||||
gb_read_only i64 s8_fuzzy_consecutive_multiplier = 3;
|
||||
fn i64 s8_fuzzy_rate_string(s8_t string, s8_t with) {
|
||||
if (with.len == 0) return 0;
|
||||
|
||||
i64 points = 0;
|
||||
i64 consecutive = 0;
|
||||
i64 with_i = 0;
|
||||
for (i64 i = 0; i < string.len; i++) {
|
||||
if (string.str[i] == with.str[with_i]) {
|
||||
i64 closer_begin = CLAMP_BOT((i64)0, s8_fuzzy_closer_word_begin - i);
|
||||
points += closer_begin;
|
||||
consecutive++;
|
||||
with_i += 1;
|
||||
} else {
|
||||
points += consecutive * s8_fuzzy_consecutive_multiplier;
|
||||
consecutive = 0;
|
||||
with_i = 0;
|
||||
}
|
||||
|
||||
if (with_i >= with.len) with_i = 0;
|
||||
}
|
||||
points += consecutive * s8_fuzzy_consecutive_multiplier;
|
||||
return points;
|
||||
}
|
||||
|
||||
fn fuzzy_pair_t *s8_fuzzy_rate_array(ma_arena_t *arena, s8_t needle, s8_t *array, i32 len) {
|
||||
fuzzy_pair_t *pairs = ma_push_array(arena, fuzzy_pair_t, len);
|
||||
for (i32 i = 0; i < len; i += 1) {
|
||||
pairs[i].rating = s8_fuzzy_rate_string(array[i], needle);
|
||||
pairs[i].index = i;
|
||||
}
|
||||
|
||||
for (i32 i = 0; i < len - 1; i++) {
|
||||
for (i32 j = 0; j < len - 1; j++) {
|
||||
if (pairs[j].rating < pairs[j + 1].rating) {
|
||||
SWAP(fuzzy_pair_t, pairs[j], pairs[j + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
174
src/core/core_string.h
Normal file
174
src/core/core_string.h
Normal file
@@ -0,0 +1,174 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
#include "core_arena.h"
|
||||
|
||||
typedef struct s8_t s8_t;
|
||||
struct s8_t {
|
||||
char *str;
|
||||
int64_t len;
|
||||
};
|
||||
|
||||
typedef struct sb8_node_t sb8_node_t;
|
||||
struct sb8_node_t {
|
||||
sb8_node_t *next;
|
||||
union {
|
||||
struct { char *str; int64_t len; };
|
||||
s8_t string;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct sb8_t sb8_t;
|
||||
struct sb8_t {
|
||||
ma_arena_t *arena;
|
||||
sb8_node_t *first;
|
||||
sb8_node_t *last;
|
||||
|
||||
// WARNING: remember to update typeinfo after editing this
|
||||
i32 indent;
|
||||
};
|
||||
|
||||
typedef i32 s8_seek_t;
|
||||
enum {
|
||||
s8_seek_none = 0,
|
||||
s8_seek_ignore_case = 1,
|
||||
s8_seek_match_find_last = 2,
|
||||
};
|
||||
|
||||
typedef i32 s8_split_t;
|
||||
enum {
|
||||
s8_split_none = 0,
|
||||
s8_split_ignore_case = 1,
|
||||
s8_split_inclusive = 2,
|
||||
s8_split_cleanup = 4,
|
||||
};
|
||||
|
||||
enum { s8_ignore_case = 1 };
|
||||
|
||||
//
|
||||
// char and char string operations
|
||||
fn i32 str_len(char *str);
|
||||
fn b32 str_eq(char *a, char *b);
|
||||
fn char char_to_lower_case(char a);
|
||||
fn char char_to_upper_case(char a);
|
||||
fn b32 char_is_whitespace(char w);
|
||||
fn b32 char_is_alphabetic(char a);
|
||||
fn b32 char_is_ident(char a);
|
||||
fn b32 char_is_digit(char a);
|
||||
fn b32 char_is_alphanumeric(char a);
|
||||
|
||||
fn u64 u64_from_hexchar(char c);
|
||||
fn u64 u64_from_s8(s8_t s, u64 base);
|
||||
fn f64 f64_from_s8(s8_t string);
|
||||
|
||||
//
|
||||
// string8 constructors
|
||||
#define s8_make(str,len) (s8_t){str, len}
|
||||
#define s8_null (s8_t){0}
|
||||
#define s8_invalid s8("<INVALID>")
|
||||
#define s8(string) (s8_t){(char *)string, sizeof(string) - 1}
|
||||
#define s8_const(string) { string, sizeof(string) - 1 }
|
||||
#define s8_struct(DATA) (s8_t){.str = (char *)&(DATA), .len = sizeof(DATA)}
|
||||
#define s8_array(DATA) (s8_t){.str = (char *)(DATA), .len = lengthof(DATA)}
|
||||
#define s8_array_lit(DATA) {.str = (char *)(DATA), .len = lengthof(DATA)}
|
||||
fn s8_t s8_from_range(char *begin, char *end);
|
||||
fn s8_t s8_from_char(char *string);
|
||||
fn s8_t s8_copy(ma_arena_t *ma, s8_t string);
|
||||
|
||||
//
|
||||
// conditional
|
||||
fn b32 s8_are_equal_ex(s8_t a, s8_t b, b32 ignore_case);
|
||||
fn b32 s8_are_equal(s8_t a, s8_t b);
|
||||
fn b32 s8_ends_with_ex(s8_t a, s8_t end, b32 ignore_case);
|
||||
fn b32 s8_starts_with_ex(s8_t a, s8_t start, b32 ignore_case);
|
||||
fn b32 s8_ends_with(s8_t a, s8_t end);
|
||||
fn b32 s8_starts_with(s8_t a, s8_t start);
|
||||
fn b32 s8_is_pointer_inside(s8_t string, char *p);// @todo: maybe more general?
|
||||
|
||||
//
|
||||
// search
|
||||
fn b32 s8_seek(s8_t string, s8_t find, s8_seek_t flags, int64_t *index_out);
|
||||
fn int64_t s8_find(s8_t string, s8_t find, s8_seek_t flag);
|
||||
fn sb8_t s8_split(ma_arena_t *ma, s8_t string, s8_t find, s8_split_t flags);
|
||||
|
||||
//
|
||||
// string view transforms
|
||||
fn s8_t s8_slice(s8_t string, int64_t first_index, int64_t one_past_last_index);
|
||||
fn s8_t s8_get_postfix(s8_t string, int64_t len);
|
||||
fn s8_t s8_get_prefix(s8_t string, int64_t len);
|
||||
fn s8_t s8_chop(s8_t string, int64_t len);
|
||||
fn s8_t s8_skip(s8_t string, int64_t len);
|
||||
fn s8_t s8_chop_last_slash(s8_t s);
|
||||
fn s8_t s8_chop_last_period(s8_t s);
|
||||
fn s8_t s8_skip_to_last_slash(s8_t s);
|
||||
fn s8_t s8_skip_to_last_period(s8_t s);
|
||||
fn s8_t s8_get_name_no_ext(s8_t s);
|
||||
fn s8_t s8_trim(s8_t string);
|
||||
fn s8_t s8_trim_end(s8_t string);
|
||||
fn s8_t s8_cut_start(s8_t *in, i64 size);
|
||||
fn s8_t s8_cut_end(s8_t *in, i64 size);
|
||||
//
|
||||
// formatting
|
||||
fn void s8_normalize_path_unsafe(s8_t s);
|
||||
fn s8_t s8_normalize_path(ma_arena_t *ma, s8_t s);
|
||||
fn s8_t s8_to_lower_case(ma_arena_t *ma, s8_t s);
|
||||
fn s8_t s8_to_upper_case(ma_arena_t *ma, s8_t s);
|
||||
fn s8_t s8_vfmt(ma_arena_t *ma, const char *str, va_list args1);
|
||||
fn s8_t s8_printf(ma_arena_t *ma, const char *str, ...);
|
||||
|
||||
//
|
||||
// string builder
|
||||
#define sb8(ARENA) &(sb8_t){.arena = arena}
|
||||
#define sb8_serial_begin(ARENA) &(sb8_t){.arena = ARENA}
|
||||
#define sb8_serial_end(ARENA, SB) sb8_merge(ARENA, SB)
|
||||
|
||||
fn s8_t sb8_printf(sb8_t *sb, const char *str, ...);
|
||||
fn sb8_node_t *sb8_append(sb8_t *list, s8_t string);
|
||||
fn sb8_node_t *sb8_create_node(ma_arena_t *ma, s8_t str);
|
||||
|
||||
fn s8_t sb8_merge(ma_arena_t *arena, sb8_t *sb);
|
||||
fn void sb8_indent(sb8_t *sb);
|
||||
fn s8_t sb8_stmtf(sb8_t *sb, const char *str, ...);
|
||||
fn int64_t sb8_char_size(sb8_t *sb);
|
||||
|
||||
#if 0
|
||||
sb8_t *sbin_write_begin(ma_arena_t *arena);
|
||||
s8_t sbin_write_end(sb8_t *sb);
|
||||
|
||||
void *sbin_write_data(sb8_t *sb, void *p, i64 size);
|
||||
void *sbin_write_size(sb8_t *sb, i64 size);
|
||||
void *sbin_write_u64(sb8_t *sb, u64 value);
|
||||
void *sbin_write_u32(sb8_t *sb, u32 value);
|
||||
void *sbin_write_u16(sb8_t *sb, u16 value);
|
||||
void *sbin_write_u8(sb8_t *sb, u8 value);
|
||||
s8_t *sbin_write_s8(sb8_t *sb, s8_t string);
|
||||
char *sbin_write_str(sb8_t *sb, char *string);
|
||||
|
||||
stream_t sbin_read_begin(void *p, i64 size);
|
||||
void sbin_read_end(stream_t *stream);
|
||||
void *sbin_read_data(stream_t *stream, i64 size);
|
||||
#endif
|
||||
|
||||
//
|
||||
// other
|
||||
#define s8_fmtspec(string) (int)(string).len, (string).str
|
||||
#define S8_CODE(...) s8(#__VA_ARGS__)
|
||||
#define S8_FILE s8(__FILE__)
|
||||
#define S8_FILE_AND_LINE s8(FILE_AND_LINE)
|
||||
|
||||
#define S8_FMT(ma, str, result) \
|
||||
va_list args1; \
|
||||
va_start(args1, str); \
|
||||
s8_t result = s8_vfmt(ma, str, args1); \
|
||||
va_end(args1)
|
||||
|
||||
#define STR_FMT(buff, str) \
|
||||
va_list args1; \
|
||||
va_start(args1, str); \
|
||||
i32 len = stbsp_vsnprintf(buff, sizeof(buff), str, args1); \
|
||||
va_end(args1)
|
||||
|
||||
typedef struct fuzzy_pair_t fuzzy_pair_t;
|
||||
struct fuzzy_pair_t {
|
||||
i64 index;
|
||||
i64 rating;
|
||||
};
|
||||
619
src/core/core_string16.c
Normal file
619
src/core/core_string16.c
Normal file
@@ -0,0 +1,619 @@
|
||||
#include "core_string16.h"
|
||||
#include "core_platform.h"
|
||||
#include "core_intrin.h"
|
||||
#include "core_unicode.h"
|
||||
#include "core_ctx.h"
|
||||
|
||||
fn i64 str16_len(u16 *string) {
|
||||
i64 len = 0;
|
||||
while (*string++ != 0)
|
||||
len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
fn u16 char16_to_lower_case(u16 a) {
|
||||
if (a >= 'A' && a <= 'Z') a += 32;
|
||||
return a;
|
||||
}
|
||||
|
||||
fn u16 char16_to_upper_case(u16 a) {
|
||||
if (a >= 'a' && a <= 'z') a -= 32;
|
||||
return a;
|
||||
}
|
||||
|
||||
fn b32 char16_is_whitespace(u16 w) {
|
||||
b32 result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r';
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char16_is_alphabetic(u16 a) {
|
||||
b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char16_is_ident(u16 a) {
|
||||
b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z') || a == '_';
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char16_is_digit(u16 a) {
|
||||
b32 result = a >= '0' && a <= '9';
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char16_is_symbol(u16 w) {
|
||||
b32 result = (w >= '!' && w <= '/') || (w >= ':' && w <= '@') || (w >= '[' && w <= '`') || (w >= '{' && w <= '~');
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char16_is_non_word(u16 w) {
|
||||
b32 result = w != '_' && (char16_is_symbol(w) || char16_is_whitespace(w));
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char16_is_word(u16 w) {
|
||||
b32 result = !char16_is_non_word(w);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char16_is_alphanumeric(u16 a) {
|
||||
b32 result = char16_is_digit(a) || char16_is_alphabetic(a);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_from_range(u16 *begin, u16 *end) {
|
||||
assert_expr(end >= begin);
|
||||
intptr_t size = (intptr_t)end - (intptr_t)begin;
|
||||
s16_t result = {begin, size / 2};
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_from_str16(u16 *string) {
|
||||
s16_t result;
|
||||
result.str = string;
|
||||
result.len = str16_len(string);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_copy(ma_arena_t *ma, s16_t string) {
|
||||
i64 byte_size = sizeof(u16) * string.len;
|
||||
u16 *copy = (u16 *)ma_push_size(ma, byte_size + sizeof(u16));
|
||||
memory_copy(copy, string.str, byte_size);
|
||||
copy[string.len] = 0;
|
||||
s16_t result = s16_make(copy, string.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_copy_str16(ma_arena_t *ma, u16 *s) {
|
||||
return s16_copy(ma, s16_make(s, str16_len(s)));
|
||||
}
|
||||
|
||||
fn b32 s16_are_equal_ex(s16_t a, s16_t b, b32 ignore_case) {
|
||||
if (a.len != b.len) return false;
|
||||
for (i64 i = 0; i < a.len; i++) {
|
||||
u16 A = a.str[i];
|
||||
u16 B = b.str[i];
|
||||
if (ignore_case) {
|
||||
A = char16_to_lower_case(A);
|
||||
B = char16_to_lower_case(B);
|
||||
}
|
||||
if (A != B)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn b32 s16_are_equal(s16_t a, s16_t b) {
|
||||
return s16_are_equal_ex(a, b, false);
|
||||
}
|
||||
|
||||
fn s16_t s16_from_s8(ma_arena_t *ma, s8_t string) {
|
||||
u16 *buffer = ma_push_array(ma, u16, string.len + 1);
|
||||
i64 len = wstr_from_str(buffer, string.len + 1, string.str, string.len);
|
||||
assert(len <= string.len); // @todo: verify
|
||||
return (s16_t){buffer, len};
|
||||
}
|
||||
|
||||
fn s8_t s8_from_s16(ma_arena_t *ma, s16_t string) {
|
||||
i64 buffer_size = (string.len + 1) * 2;
|
||||
char *buffer = ma_push_array(ma, char, buffer_size);
|
||||
i64 len = str_from_wstr(buffer, buffer_size, string.str, string.len);
|
||||
assert(len < buffer_size);
|
||||
return (s8_t){buffer, len};
|
||||
}
|
||||
|
||||
fn s16_t s16_get_postfix(s16_t string, i64 len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
i64 remain_len = string.len - len;
|
||||
s16_t result = s16_make(string.str + remain_len, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_get_prefix(s16_t string, i64 len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
s16_t result = s16_make(string.str, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_chop(s16_t string, i64 len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
s16_t result = s16_make(string.str, string.len - len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_skip(s16_t string, i64 len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
i64 remain = string.len - len;
|
||||
s16_t result = s16_make(string.str + len, remain);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s16_ends_with_ex(s16_t a, s16_t end, b32 ignore_case) {
|
||||
s16_t a_end = s16_get_postfix(a, end.len);
|
||||
b32 result = s16_are_equal_ex(end, a_end, ignore_case);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s16_starts_with_ex(s16_t a, s16_t start, b32 ignore_case) {
|
||||
s16_t a_start = s16_get_prefix(a, start.len);
|
||||
b32 result = s16_are_equal_ex(start, a_start, ignore_case);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s16_ends_with(s16_t a, s16_t end) {
|
||||
return s16_ends_with_ex(a, end, false);
|
||||
}
|
||||
|
||||
fn b32 s16_starts_with(s16_t a, s16_t start) {
|
||||
return s16_ends_with_ex(a, start, false);
|
||||
}
|
||||
|
||||
fn void s16_normalize_path_unsafe(s16_t s) {
|
||||
for (i64 i = 0; i < s.len; i++) {
|
||||
if (s.str[i] == '\\')
|
||||
s.str[i] = '/';
|
||||
}
|
||||
}
|
||||
|
||||
fn s16_t s16_normalize_path(ma_arena_t *ma, s16_t s) {
|
||||
s16_t copy = s16_copy(ma, s);
|
||||
s16_normalize_path_unsafe(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn b32 s16_is_pointer_inside(s16_t string, u16 *p) {
|
||||
uintptr_t pointer = (uintptr_t)p;
|
||||
uintptr_t start = (uintptr_t)string.str;
|
||||
uintptr_t stop = start + (uintptr_t)string.len * sizeof(u16);
|
||||
b32 result = pointer >= start && pointer < stop;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_cut_start(s16_t *in, i64 size) {
|
||||
s16_t result = s16_get_prefix(*in, size);
|
||||
*in = s16_skip(*in, result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_cut_end(s16_t *in, i64 size) {
|
||||
s16_t result = s16_get_postfix(*in, size);
|
||||
*in = s16_chop(*in, result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_slice(s16_t string, i64 first_index, i64 one_past_last_index) {
|
||||
if (one_past_last_index < 0) one_past_last_index = string.len + one_past_last_index + 1;
|
||||
if (first_index < 0) first_index = string.len + first_index;
|
||||
assert(first_index < one_past_last_index);
|
||||
assert(string.len > 0);
|
||||
s16_t result = string;
|
||||
if (string.len > 0) {
|
||||
if (one_past_last_index > first_index) {
|
||||
first_index = CLAMP_TOP(first_index, string.len - 1);
|
||||
one_past_last_index = CLAMP_TOP(one_past_last_index, string.len);
|
||||
result.str += first_index;
|
||||
result.len = one_past_last_index - first_index;
|
||||
}
|
||||
else {
|
||||
result.len = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_trim(s16_t string) {
|
||||
if (string.len == 0)
|
||||
return string;
|
||||
|
||||
i64 whitespace_begin = 0;
|
||||
for (; whitespace_begin < string.len; whitespace_begin++) {
|
||||
if (!char16_is_whitespace(string.str[whitespace_begin])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i64 whitespace_end = string.len;
|
||||
for (; whitespace_end != whitespace_begin; whitespace_end--) {
|
||||
if (!char16_is_whitespace(string.str[whitespace_end - 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (whitespace_begin == whitespace_end) {
|
||||
string.len = 0;
|
||||
}
|
||||
else {
|
||||
string = s16_slice(string, whitespace_begin, whitespace_end);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
fn s16_t s16_trim_end(s16_t string) {
|
||||
i64 whitespace_end = string.len;
|
||||
for (; whitespace_end != 0; whitespace_end--) {
|
||||
if (!char16_is_whitespace(string.str[whitespace_end - 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s16_t result = s16_get_prefix(string, whitespace_end);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s16_seek(s16_t string, s16_t find, s16_seek_t flags, int64_t *index_out) {
|
||||
b32 ignore_case = flags & s16_seek_ignore_case ? true : false;
|
||||
b32 result = false;
|
||||
if (flags & s16_seek_match_find_last) {
|
||||
for (int64_t i = string.len; i != 0; i--) {
|
||||
int64_t index = i - 1;
|
||||
s16_t substring = s16_slice(string, index, index + find.len);
|
||||
if (s16_are_equal_ex(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = index;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int64_t i = 0; i < string.len; i++) {
|
||||
s16_t substring = s16_slice(string, i, i + find.len);
|
||||
if (s16_are_equal_ex(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = i;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn int64_t s16_find(s16_t string, s16_t find, s16_seek_t flag) {
|
||||
int64_t result = -1;
|
||||
s16_seek(string, find, flag, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_chop_last_char(s16_t s, s16_t ch) {
|
||||
s16_t result = s;
|
||||
s16_seek(s, ch, s16_seek_match_find_last, &result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_chop_last_slash(s16_t s) {
|
||||
return s16_chop_last_char(s, s16("/"));
|
||||
}
|
||||
|
||||
fn s16_t s16_chop_last_period(s16_t s) {
|
||||
return s16_chop_last_char(s, s16("."));
|
||||
}
|
||||
|
||||
fn s16_t s16_skip_to_last_char(s16_t s, s16_t ch) {
|
||||
int64_t pos;
|
||||
s16_t result = s;
|
||||
if (s16_seek(s, ch, s16_seek_match_find_last, &pos)) {
|
||||
result = s16_skip(result, pos + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_skip_to_last_slash(s16_t s) {
|
||||
return s16_skip_to_last_char(s, s16("/"));
|
||||
}
|
||||
|
||||
fn s16_t s16_skip_to_last_period(s16_t s) {
|
||||
return s16_skip_to_last_char(s, s16("."));
|
||||
}
|
||||
|
||||
fn s16_t s16_get_name_no_ext(s16_t s) {
|
||||
return s16_skip_to_last_slash(s16_chop_last_period(s));
|
||||
}
|
||||
|
||||
fn s16_t s16_to_lower_case(ma_arena_t *ma, s16_t s) {
|
||||
s16_t copy = s16_copy(ma, s);
|
||||
for (int64_t i = 0; i < copy.len; i++) {
|
||||
copy.str[i] = char16_to_lower_case(copy.str[i]);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn s16_t s16_to_upper_case(ma_arena_t *ma, s16_t s) {
|
||||
s16_t copy = s16_copy(ma, s);
|
||||
for (int64_t i = 0; i < copy.len; i++) {
|
||||
copy.str[i] = char16_to_upper_case(copy.str[i]);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn s16_t s16_printf(ma_arena_t *ma, const char *str, ...) {
|
||||
ma_temp_t scratch = ma_begin_scratch1(ma);
|
||||
S8_FMT(scratch.arena, str, result);
|
||||
s16_t result16 = s16_from_s8(ma, result);
|
||||
ma_end_scratch(scratch);
|
||||
return result16;
|
||||
}
|
||||
|
||||
fn u64 u64_from_s16(s16_t s, u64 base) {
|
||||
assert(base >= 2 && base <= 16);
|
||||
u64 acc = 0;
|
||||
for (i64 i = 0; i < s.len; i++) {
|
||||
u64 num = u64_from_hexchar((char)s.str[i]);
|
||||
assert(num < base);
|
||||
acc *= base;
|
||||
acc += num;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
fn f64 f64_from_s16(s16_t string) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s8_t num_string = s8_from_s16(scratch.arena, string);
|
||||
f64 result = os_parse_float(num_string.str);
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
gb_read_only i64 s16_fuzzy_closer_word_begin = 5;
|
||||
gb_read_only i64 s16_fuzzy_consecutive_multiplier = 3;
|
||||
fn i64 s16_fuzzy_rate(s16_t string, s16_t with) {
|
||||
if (with.len == 0) return 0;
|
||||
|
||||
i64 points = 0;
|
||||
i64 consecutive = 0;
|
||||
i64 with_i = 0;
|
||||
for (i64 i = 0; i < string.len; i++) {
|
||||
if (string.str[i] == with.str[with_i]) {
|
||||
i64 closer_begin = CLAMP_BOT((i64)0, s16_fuzzy_closer_word_begin - i);
|
||||
points += closer_begin;
|
||||
consecutive++;
|
||||
with_i += 1;
|
||||
} else {
|
||||
points += consecutive * s16_fuzzy_consecutive_multiplier;
|
||||
consecutive = 0;
|
||||
with_i = 0;
|
||||
}
|
||||
|
||||
if (with_i >= with.len) with_i = 0;
|
||||
}
|
||||
points += consecutive * s16_fuzzy_consecutive_multiplier;
|
||||
return points;
|
||||
}
|
||||
|
||||
fn fuzzy_pair_t *s16_fuzzy_rate_array(ma_arena_t *arena, s16_t needle, s16_t *array, i32 len) {
|
||||
fuzzy_pair_t *pairs = ma_push_array(arena, fuzzy_pair_t, len);
|
||||
for (i32 i = 0; i < len; i += 1) {
|
||||
pairs[i].rating = s16_fuzzy_rate(array[i], needle);
|
||||
pairs[i].index = i;
|
||||
}
|
||||
|
||||
for (i32 i = 0; i < len - 1; i++) {
|
||||
for (i32 j = 0; j < len - 1; j++) {
|
||||
if (pairs[j].rating < pairs[j + 1].rating) {
|
||||
SWAP(fuzzy_pair_t, pairs[j], pairs[j + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
|
||||
fn sb16_node_t *sb16_create_node(ma_arena_t *ma, s16_t str) {
|
||||
sb16_node_t *node = ma_push_type(ma, sb16_node_t);
|
||||
node->string = str;
|
||||
return node;
|
||||
}
|
||||
|
||||
fn sb16_node_t *sb16_append(sb16_t *list, s16_t string) {
|
||||
assert(list->arena != NULL);
|
||||
sb16_node_t *node = sb16_create_node(list->arena, string);
|
||||
SLLQ_APPEND(list->first, list->last, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
fn s16_t sb16_printf(sb16_t *sb, const char *str, ...) {
|
||||
ma_temp_t scratch = ma_begin_scratch1(sb->arena);
|
||||
S8_FMT(scratch.arena, str, result);
|
||||
s16_t result16 = s16_from_s8(sb->arena, result);
|
||||
sb16_append(sb, result16);
|
||||
ma_end_scratch(scratch);
|
||||
return result16;
|
||||
}
|
||||
|
||||
fn void sb16_indent(sb16_t *sb) {
|
||||
sb16_printf(sb, "\n%.*s", sb->indent*4, " ");
|
||||
}
|
||||
|
||||
fn s16_t sb16_stmtf(sb16_t *sb, const char *str, ...) {
|
||||
ma_temp_t scratch = ma_begin_scratch1(sb->arena);
|
||||
S8_FMT(scratch.arena, str, result);
|
||||
s16_t result16 = s16_from_s8(sb->arena, result);
|
||||
sb16_indent(sb);
|
||||
sb16_append(sb, result16);
|
||||
ma_end_scratch(scratch);
|
||||
return result16;
|
||||
}
|
||||
|
||||
fn int64_t sb16_char_size(sb16_t *sb) {
|
||||
int64_t result = 0;
|
||||
for (sb16_node_t *it = sb->first; it; it = it->next) {
|
||||
result += it->len;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t sb16_merge(ma_arena_t *arena, sb16_t *sb) {
|
||||
int64_t size = sb16_char_size(sb) + 1;
|
||||
i64 byte_size = size * sizeof(u16);
|
||||
u16 *str = ma_push_size(arena, byte_size);
|
||||
s16_t result = {str, 0};
|
||||
for (sb16_node_t *it = sb->first; it; it = it->next) {
|
||||
memory_copy(result.str + result.len, it->str, it->len * sizeof(u16));
|
||||
result.len += it->len;
|
||||
}
|
||||
result.str[result.len] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn sb16_t s16_split(ma_arena_t *ma, s16_t string, s16_t find, s16_split_t flags) {
|
||||
sb16_t result = (sb16_t){ma};
|
||||
int64_t index = 0;
|
||||
|
||||
s16_seek_t find_flag = flags & s16_split_ignore_case ? s16_seek_ignore_case : s16_seek_none;
|
||||
while (s16_seek(string, find, find_flag, &index)) {
|
||||
s16_t before_match = s16_make(string.str, index);
|
||||
sb16_append(&result, before_match);
|
||||
if (flags & s16_split_inclusive) {
|
||||
s16_t match = s16_make(string.str + index, find.len);
|
||||
sb16_append(&result, match);
|
||||
}
|
||||
string = s16_skip(string, index + find.len);
|
||||
}
|
||||
if (string.len) sb16_append(&result, string);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_copy_ex(alo_t ma, s16_t string) {
|
||||
i64 byte_size = sizeof(u16) * string.len;
|
||||
u16 *copy = (u16 *)alloc_size(ma, byte_size + sizeof(u16));
|
||||
memory_copy(copy, string.str, byte_size);
|
||||
copy[string.len] = 0;
|
||||
s16_t result = s16_make(copy, string.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn_test void test_string16(void) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
|
||||
// string16 lit basic tests
|
||||
{
|
||||
s16_t a = s16("memes");
|
||||
assert(a.len == 5);
|
||||
assert(a.str[0] == char16('m'));
|
||||
assert(a.str[4] == char16('s'));
|
||||
s16_t b = s16("not memes");
|
||||
s16_t c = s16("MEMES");
|
||||
assert(s16_are_equal(a, b) == false);
|
||||
assert(s16_are_equal(a, a) == true);
|
||||
assert(s16_are_equal_ex(a, c, true) == true);
|
||||
}
|
||||
|
||||
{
|
||||
assert(char16_to_upper_case('a') == char16('A'));
|
||||
assert(char16_to_upper_case('a') == 'A');
|
||||
assert(char16_to_upper_case(char16('a')) == 'A');
|
||||
assert(char16_is_digit('3'));
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16_from_str16(str16("memes"));
|
||||
assert(a.len == 5);
|
||||
assert(s16_are_equal(a, s16("memes")) == true);
|
||||
|
||||
s16_t b = s16_copy(scratch.arena, a);
|
||||
assert(a.str != b.str);
|
||||
assert(b.len == a.len);
|
||||
assert(s16_are_equal(a, b));
|
||||
|
||||
s16_t c = s16_from_range(a.str, a.str + a.len);
|
||||
assert(s16_are_equal(a, c));
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16("thing itself");
|
||||
assert(s16_starts_with_ex(a, s16("thing"), false));
|
||||
assert(!s16_starts_with_ex(a, s16("thing itself and"), false));
|
||||
assert(!s16_starts_with_ex(a, s16("thing itself "), false));
|
||||
assert(s16_starts_with_ex(a, s16("THING"), true));
|
||||
assert(!s16_starts_with_ex(a, s16("a"), false));
|
||||
|
||||
assert(s16_ends_with_ex(a, s16("itself"), false));
|
||||
assert(s16_ends_with_ex(a, s16("thing itself"), false));
|
||||
assert(!s16_ends_with_ex(a, s16("thing itselfa"), false));
|
||||
|
||||
s16_t b = s16("memes");
|
||||
assert(s16_is_pointer_inside(b, b.str));
|
||||
assert(s16_is_pointer_inside(b, b.str + 4));
|
||||
assert(!s16_is_pointer_inside(b, b.str + 5));
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16("C:\\Program Files\\Memes");
|
||||
u16 memes[256] = {0};
|
||||
memory_copy(memes, a.str, a.len * 2 + 2);
|
||||
s16_t b = s16_make(memes, a.len);
|
||||
|
||||
s16_normalize_path_unsafe(b);
|
||||
assert(b.str[2] == '/');
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16(" thing ");
|
||||
s16_t b = s16_trim(a);
|
||||
assert(s16_are_equal(b, s16("thing")));
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16_printf(scratch.arena, "%d", 432);
|
||||
assert(s16_are_equal(a, s16("432")));
|
||||
assert(f64_from_s16(s16("432.0")) == 432.0);
|
||||
assert(u64_from_s16(s16("432"), 10) == 432);
|
||||
}
|
||||
|
||||
{
|
||||
sb16_t *list = sb16_serial_begin(scratch.arena);
|
||||
sb16_printf(list, "%d ", 987);
|
||||
sb16_printf(list, "ter ");
|
||||
sb16_printf(list, "|");
|
||||
s16_t string = sb16_serial_end(scratch.arena, list);
|
||||
assert(s16_are_equal(string, s16("987 ter |")));
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16("A|B|dek|mek|vek|");
|
||||
sb16_t b = s16_split(scratch.arena, a, s16("|"), s16_split_none);
|
||||
assert(s16_are_equal(b.first->string, s16("A")));
|
||||
assert(s16_are_equal(b.first->next->string, s16("B")));
|
||||
assert(s16_are_equal(b.first->next->next->string, s16("dek")));
|
||||
assert(s16_are_equal(b.first->next->next->next->string, s16("mek")));
|
||||
assert(s16_are_equal(b.first->next->next->next->next->string, s16("vek")));
|
||||
assert(b.first->next->next->next->next->next == NULL);
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16_to_upper_case(scratch.arena, s16("thing Meme"));
|
||||
assert(s16_are_equal(a, s16("THING MEME")));
|
||||
|
||||
a = s16_to_lower_case(scratch.arena, s16("THING Meme"));
|
||||
assert(s16_are_equal(a, s16("thing meme")));
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16("C:/thing/itself");
|
||||
assert(s16_are_equal(s16_chop_last_slash(a), s16("C:/thing")));
|
||||
}
|
||||
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
128
src/core/core_string16.h
Normal file
128
src/core/core_string16.h
Normal file
@@ -0,0 +1,128 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
#include "core_arena.h"
|
||||
#include "core_string.h"
|
||||
|
||||
typedef struct s16_t s16_t;
|
||||
struct s16_t {
|
||||
u16 *str;
|
||||
i64 len;
|
||||
};
|
||||
|
||||
typedef struct sb16_node_t sb16_node_t;
|
||||
struct sb16_node_t {
|
||||
sb16_node_t *next;
|
||||
union {
|
||||
struct { u16 *str; int64_t len; };
|
||||
s16_t string;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct sb16_t sb16_t;
|
||||
struct sb16_t {
|
||||
ma_arena_t *arena;
|
||||
sb16_node_t *first;
|
||||
sb16_node_t *last;
|
||||
|
||||
// WARNING: remember to update typeinfo after editing this
|
||||
i32 indent;
|
||||
};
|
||||
|
||||
typedef i32 s16_seek_t;
|
||||
enum {
|
||||
s16_seek_none = 0,
|
||||
s16_seek_ignore_case = 1,
|
||||
s16_seek_match_find_last = 2,
|
||||
};
|
||||
|
||||
typedef i32 s16_split_t;
|
||||
enum {
|
||||
s16_split_none = 0,
|
||||
s16_split_ignore_case = 1,
|
||||
s16_split_inclusive = 2,
|
||||
};
|
||||
|
||||
enum { s16_ignore_case = 1 };
|
||||
|
||||
|
||||
typedef struct s32_t s32_t;
|
||||
struct s32_t {
|
||||
u32 *str;
|
||||
i64 len;
|
||||
};
|
||||
|
||||
#define s16_make(str,len) (s16_t){str, len}
|
||||
|
||||
#define s16(str) (s16_t){(u16 *)u##str, lengthof(str) - 1}
|
||||
#define s16_const(string) { (u16 *)u##string, lengthof(string) - 1 }
|
||||
#define s16_invalid s16_lit("<INVALID>")
|
||||
#define s16_null (s16_t){0}
|
||||
|
||||
#define str16(str) ((u16 *)u##str)
|
||||
#define char16(str) ((u16)u##str)
|
||||
|
||||
#define sb16(ARENA) &(sb16_t){.arena = arena}
|
||||
#define sb16_serial_begin(ARENA) &(sb16_t){.arena = ARENA}
|
||||
#define sb16_serial_end(ARENA, SB) sb16_merge(ARENA, SB)
|
||||
|
||||
fn i64 str16_len(u16 *string);
|
||||
fn u16 char16_to_lower_case(u16 a);
|
||||
fn u16 char16_to_upper_case(u16 a);
|
||||
fn b32 char16_is_whitespace(u16 w);
|
||||
fn b32 char16_is_alphabetic(u16 a);
|
||||
fn b32 char16_is_ident(u16 a);
|
||||
fn b32 char16_is_digit(u16 a);
|
||||
fn b32 char16_is_symbol(u16 w);
|
||||
fn b32 char16_is_non_word(u16 w);
|
||||
fn b32 char16_is_word(u16 w);
|
||||
fn b32 char16_is_alphanumeric(u16 a);
|
||||
fn s16_t s16_from_range(u16 *begin, u16 *end);
|
||||
fn s16_t s16_from_str16(u16 *string);
|
||||
fn s16_t s16_copy(ma_arena_t *ma, s16_t string);
|
||||
fn s16_t s16_copy_str16(ma_arena_t *ma, u16 *s);
|
||||
fn b32 s16_are_equal_ex(s16_t a, s16_t b, b32 ignore_case);
|
||||
fn b32 s16_are_equal(s16_t a, s16_t b);
|
||||
fn s16_t s16_from_s8(ma_arena_t *ma, s8_t string);
|
||||
fn s8_t s8_from_s16(ma_arena_t *ma, s16_t string);
|
||||
fn s16_t s16_get_postfix(s16_t string, i64 len);
|
||||
fn s16_t s16_get_prefix(s16_t string, i64 len);
|
||||
fn s16_t s16_chop(s16_t string, i64 len);
|
||||
fn s16_t s16_skip(s16_t string, i64 len);
|
||||
fn b32 s16_ends_with_ex(s16_t a, s16_t end, b32 ignore_case);
|
||||
fn b32 s16_starts_with_ex(s16_t a, s16_t start, b32 ignore_case);
|
||||
fn b32 s16_ends_with(s16_t a, s16_t end);
|
||||
fn b32 s16_starts_with(s16_t a, s16_t start);
|
||||
fn void s16_normalize_path_unsafe(s16_t s);
|
||||
fn s16_t s16_normalize_path(ma_arena_t *ma, s16_t s);
|
||||
fn b32 s16_is_pointer_inside(s16_t string, u16 *p);
|
||||
fn s16_t s16_cut_start(s16_t *in, i64 size);
|
||||
fn s16_t s16_cut_end(s16_t *in, i64 size);
|
||||
fn s16_t s16_slice(s16_t string, i64 first_index, i64 one_past_last_index);
|
||||
fn s16_t s16_trim(s16_t string);
|
||||
fn s16_t s16_trim_end(s16_t string);
|
||||
fn b32 s16_seek(s16_t string, s16_t find, s16_seek_t flags, int64_t *index_out);
|
||||
fn int64_t s16_find(s16_t string, s16_t find, s16_seek_t flag);
|
||||
fn s16_t s16_chop_last_char(s16_t s, s16_t ch);
|
||||
fn s16_t s16_chop_last_slash(s16_t s);
|
||||
fn s16_t s16_chop_last_period(s16_t s);
|
||||
fn s16_t s16_skip_to_last_char(s16_t s, s16_t ch);
|
||||
fn s16_t s16_skip_to_last_slash(s16_t s);
|
||||
fn s16_t s16_skip_to_last_period(s16_t s);
|
||||
fn s16_t s16_get_name_no_ext(s16_t s);
|
||||
fn s16_t s16_to_lower_case(ma_arena_t *ma, s16_t s);
|
||||
fn s16_t s16_to_upper_case(ma_arena_t *ma, s16_t s);
|
||||
fn s16_t s16_printf(ma_arena_t *ma, const char *str, ...);
|
||||
fn u64 u64_from_s16(s16_t s, u64 base);
|
||||
fn f64 f64_from_s16(s16_t string);
|
||||
fn i64 s16_fuzzy_rate(s16_t string, s16_t with);
|
||||
fn fuzzy_pair_t *s16_fuzzy_rate_array(ma_arena_t *arena, s16_t needle, s16_t *array, i32 len);
|
||||
fn sb16_node_t *sb16_create_node(ma_arena_t *ma, s16_t str);
|
||||
fn sb16_node_t *sb16_append(sb16_t *list, s16_t string);
|
||||
fn s16_t sb16_printf(sb16_t *sb, const char *str, ...);
|
||||
fn void sb16_indent(sb16_t *sb);
|
||||
fn s16_t sb16_stmtf(sb16_t *sb, const char *str, ...);
|
||||
fn int64_t sb16_char_size(sb16_t *sb);
|
||||
fn s16_t sb16_merge(ma_arena_t *arena, sb16_t *sb);
|
||||
fn sb16_t s16_split(ma_arena_t *ma, s16_t string, s16_t find, s16_split_t flags);
|
||||
fn s16_t s16_copy_ex(alo_t ma, s16_t string);
|
||||
fn_test void test_string16(void);
|
||||
466
src/core/core_type_info.c
Normal file
466
src/core/core_type_info.c
Normal file
@@ -0,0 +1,466 @@
|
||||
#include "core_type_info.h"
|
||||
#include "core_platform.h"
|
||||
#include "core_log.h"
|
||||
#include "core_lexer.h"
|
||||
|
||||
fn s8_t ti_enum_value_to_name(i64 value, type_t *type) {
|
||||
assert(type->kind == type_kind_enum);
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
type_member_t *it = type->members + i;
|
||||
if (value == it->value) {
|
||||
return it->name;
|
||||
}
|
||||
}
|
||||
return s8("invalid");
|
||||
}
|
||||
|
||||
fn i64 ti_enum_name_to_value(s8_t name, type_t *type) {
|
||||
assert(type->kind == type_kind_enum);
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
type_member_t *it = type->members + i;
|
||||
if (s8_are_equal(it->name, name)) {
|
||||
return it->value;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
fn i64 ti_enum_read_value(void *p, type_t *type) {
|
||||
assert(type->kind == type_kind_enum);
|
||||
i64 value = 0;
|
||||
if (type->size == 1) {
|
||||
value = *(i8 *)p;
|
||||
} else if (type->size == 2) {
|
||||
value = *(i16 *)p;
|
||||
} else if (type->size == 4) {
|
||||
value = *(i32 *)p;
|
||||
} else if (type->size == 8) {
|
||||
value = *(i64 *)p;
|
||||
} else {
|
||||
fatalf("invalid size of enum: %d", type->size);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
fn void ti_enum_write_value(void *p, i64 value, type_t *type) {
|
||||
assert(type->kind == type_kind_enum);
|
||||
if (type->size == 1) {
|
||||
*(i8 *)p = (i8)value;
|
||||
} else if (type->size == 2) {
|
||||
*(i16 *)p = (i16)value;
|
||||
} else if (type->size == 4) {
|
||||
*(i32 *)p = (i32)value;
|
||||
} else if (type->size == 8) {
|
||||
*(i64 *)p = (i64)value;
|
||||
} else {
|
||||
fatalf("invalid size of enum: %d", type->size);
|
||||
}
|
||||
}
|
||||
|
||||
fn i64 ti_enum_next_value(i64 value, type_t *type) {
|
||||
assert(type->kind == type_kind_enum);
|
||||
i32 next_i = 0;
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
type_member_t *it = type->members + i;
|
||||
if (value == it->value) {
|
||||
if (i + 1 < type->count) {
|
||||
next_i = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type_member_t *tm = type->members + next_i;
|
||||
return tm->value;
|
||||
}
|
||||
|
||||
fn type_member_t *ti_get_member(s8_t name, type_t *type) {
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
type_member_t *it = type->members + i;
|
||||
if (s8_are_equal(it->name, name)) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn void *ti_extract_member(void *p, type_member_t *tm) {
|
||||
u8 *p8 = (u8 *)p;
|
||||
u8 *result = p8 + tm->offset;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void *ti_extract_array_idx(void *p, type_t *type, i32 idx) {
|
||||
assert(idx < type->count);
|
||||
|
||||
u8 *p8 = (u8 *)p;
|
||||
u8 *result = p8 + type->base->size * idx;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void ti__serial_data_ex(sb8_t *sb, void *p, type_t *type) {
|
||||
assert(type->kind != type_kind_invalid);
|
||||
|
||||
switch(type->kind) {
|
||||
case type_kind_i8: {
|
||||
i8 n = *(i8 *)p;
|
||||
sb8_printf(sb, "%d", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_i16: {
|
||||
i16 n = *(i16 *)p;
|
||||
sb8_printf(sb, "%d", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_i32: {
|
||||
i32 n = *(i32 *)p;
|
||||
sb8_printf(sb, "%d", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_i64: {
|
||||
i64 n = *(i64 *)p;
|
||||
sb8_printf(sb, "%lld", (long long)n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u8: {
|
||||
u8 n = *(u8 *)p;
|
||||
sb8_printf(sb, "%u", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u16: {
|
||||
u16 n = *(u16 *)p;
|
||||
sb8_printf(sb, "%u", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u32: {
|
||||
u32 n = *(u32 *)p;
|
||||
sb8_printf(sb, "%u", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u64: {
|
||||
u64 n = *(u64 *)p;
|
||||
sb8_printf(sb, "%llu", (unsigned long long)n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b8: {
|
||||
b8 n = *(b8 *)p;
|
||||
sb8_printf(sb, "%d", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b16: {
|
||||
b16 n = *(b16 *)p;
|
||||
sb8_printf(sb, "%d", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b32: {
|
||||
b32 n = *(b32 *)p;
|
||||
sb8_printf(sb, "%d", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b64: {
|
||||
b64 n = *(b64 *)p;
|
||||
sb8_printf(sb, "%lld", (long long)n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_f32: {
|
||||
f32 n = *(f32 *)p;
|
||||
sb8_printf(sb, "%f", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_f64: {
|
||||
f64 n = *(f64 *)p;
|
||||
sb8_printf(sb, "%f", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_isize: {
|
||||
isize n = *(isize *)p;
|
||||
sb8_printf(sb, "%lld", (long long)n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_usize: {
|
||||
usize n = *(usize *)p;
|
||||
sb8_printf(sb, "%llu", (unsigned long long)n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_int: {
|
||||
int n = *(int *)p;
|
||||
sb8_printf(sb, "%d", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_char: {
|
||||
char n = *(char *)p;
|
||||
sb8_printf(sb, "%c", n);
|
||||
return;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (type == &type__s8_t) {
|
||||
s8_t n = *(s8_t *)p;
|
||||
sb8_printf(sb, "\"%S\"", n);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (type->kind == type_kind_pointer) {
|
||||
sb8_printf(sb, "0x%x", p);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type->kind == type_kind_enum) {
|
||||
i64 value = ti_enum_read_value(p, type);
|
||||
s8_t s = ti_enum_value_to_name(value, type);
|
||||
sb8_append(sb, s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type->kind == type_kind_array) {
|
||||
sb8_printf(sb, "{");
|
||||
sb->indent += 1;
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
void *mem_p = ti_extract_array_idx(p, type, i);
|
||||
sb8_indent(sb);
|
||||
ti__serial_data_ex(sb, mem_p, type->base);
|
||||
sb8_printf(sb, ",");
|
||||
}
|
||||
sb->indent -= 1;
|
||||
sb8_stmtf(sb, "}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (type->kind == type_kind_struct) {
|
||||
sb8_printf(sb, "{");
|
||||
sb->indent += 1;
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
type_member_t *mem = type->members + i;
|
||||
void *mem_p = ti_extract_member(p, mem);
|
||||
sb8_indent(sb);
|
||||
sb8_printf(sb, "%S: ", mem->name);
|
||||
ti__serial_data_ex(sb, mem_p, mem->type);
|
||||
sb8_printf(sb, ",");
|
||||
}
|
||||
sb->indent -= 1;
|
||||
sb8_stmtf(sb, "}");
|
||||
return;
|
||||
}
|
||||
|
||||
fatalf("can't serialize: unhandled type");
|
||||
}
|
||||
|
||||
fn s8_t ti__serial_data(ma_arena_t *arena, void *p, type_t *type) {
|
||||
ma_temp_t scratch = ma_begin_scratch1(arena);
|
||||
sb8_t *sb = sb8_serial_begin(scratch.arena);
|
||||
ti__serial_data_ex(sb, p, type);
|
||||
s8_t string = sb8_serial_end(arena, sb);
|
||||
ma_end_scratch(scratch);
|
||||
return string;
|
||||
}
|
||||
|
||||
fn i64 ti__parser_match_i64(parser_t *par) {
|
||||
i64 minus = 1;
|
||||
if (parser_match(par, lex_kind_minus)) {
|
||||
minus = -1;
|
||||
}
|
||||
lex_t *token = parser_expect(par, lex_kind_integer);
|
||||
i64 result = (i64)token->integer * minus;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void ti__deserial_data_ex(ma_arena_t *arena, parser_t *par, void *p, type_t *type) {
|
||||
switch(type->kind) {
|
||||
case type_kind_i8: {
|
||||
i8 *n = (i8 *)p;
|
||||
n[0] = (i8)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_i16: {
|
||||
i16 *n = (i16 *)p;
|
||||
n[0] = (i16)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_i32: {
|
||||
i32 *n = (i32 *)p;
|
||||
n[0] = (i32)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_i64: {
|
||||
i64 *n = (i64 *)p;
|
||||
n[0] = (i64)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b8: {
|
||||
b8 *n = (b8 *)p;
|
||||
n[0] = (b8)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b16: {
|
||||
b16 *n = (b16 *)p;
|
||||
n[0] = (b16)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b32: {
|
||||
b32 *n = (b32 *)p;
|
||||
n[0] = (b32)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b64: {
|
||||
b64 *n = (b64 *)p;
|
||||
n[0] = (b64)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u8: {
|
||||
lex_t *token = parser_expect(par, lex_kind_integer);
|
||||
u8 *n = (u8 *)p;
|
||||
n[0] = (u8)token->integer;
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u16: {
|
||||
lex_t *token = parser_expect(par, lex_kind_integer);
|
||||
u16 *n = (u16 *)p;
|
||||
n[0] = (u16)token->integer;
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u32: {
|
||||
lex_t *token = parser_expect(par, lex_kind_integer);
|
||||
u32 *n = (u32 *)p;
|
||||
n[0] = (u32)token->integer;
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u64: {
|
||||
lex_t *token = parser_expect(par, lex_kind_integer);
|
||||
u64 *n = (u64 *)p;
|
||||
n[0] = (u64)token->integer;
|
||||
return;
|
||||
} break;
|
||||
case type_kind_f32: {
|
||||
lex_t *token = parser_expect(par, lex_kind_real);
|
||||
f32 *n = (f32 *)p;
|
||||
n[0] = (f32)token->real;
|
||||
return;
|
||||
} break;
|
||||
case type_kind_f64: {
|
||||
lex_t *token = parser_expect(par, lex_kind_real);
|
||||
f64 *n = (f64 *)p;
|
||||
n[0] = token->real;
|
||||
return;
|
||||
} break;
|
||||
case type_kind_isize: {
|
||||
isize *n = (isize *)p;
|
||||
n[0] = (isize)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_usize: {
|
||||
lex_t *token = parser_expect(par, lex_kind_integer);
|
||||
usize *n = (usize *)p;
|
||||
n[0] = (usize)token->integer;
|
||||
return;
|
||||
} break;
|
||||
case type_kind_int: {
|
||||
int *n = (int *)p;
|
||||
n[0] = (int)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_char: {
|
||||
char *n = (char *)p;
|
||||
n[0] = (char)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (type == &type__s8_t) {
|
||||
lex_t *token = parser_expect(par, lex_kind_string);
|
||||
s8_t *n = (s8_t *)p;
|
||||
n[0] = s8_copy(arena, token->string);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type->kind == type_kind_enum) {
|
||||
lex_t *token = parser_expect(par, lex_kind_ident);
|
||||
i64 value = ti_enum_name_to_value(token->string, type);
|
||||
if (value == -1) {
|
||||
fatalf("invalid enum value: %S", token->string);
|
||||
}
|
||||
|
||||
ti_enum_write_value(p, value, type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type->kind == type_kind_struct) {
|
||||
#if 0
|
||||
parser_expect(par, lex_kind_open_brace);
|
||||
while (!parser_match(par, lex_kind_close_brace)) {
|
||||
lex_t *ident = parser_expect(par, lex_kind_ident);
|
||||
parser_expect(par, lex_kind_colon);
|
||||
|
||||
type_member_t *mem = ti_get_member(type, ident->string);
|
||||
if (mem) {
|
||||
u8 *mem_p = p8 + mem->offset;
|
||||
ti__deserial_data_ex(arena, par, mem_p, mem->type);
|
||||
} else {
|
||||
debugf("deserial - skipping field: %S", ident->string);
|
||||
parser_eat_until(par, lex_kind_comma);
|
||||
}
|
||||
|
||||
parser_expect(par, lex_kind_comma);
|
||||
}
|
||||
|
||||
#else // strict
|
||||
parser_expect(par, lex_kind_open_brace);
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
type_member_t *mem = type->members + i;
|
||||
void *memp = ti_extract_member(p, mem);
|
||||
|
||||
lex_t *ident = parser_expect(par, lex_kind_ident);
|
||||
parser_expect(par, lex_kind_colon);
|
||||
|
||||
expect (s8_are_equal(ident->string, mem->name)) fatalf("expected identifier: %S, got instead %S", mem->name, ident->string);
|
||||
|
||||
ti__deserial_data_ex(arena, par, memp, mem->type);
|
||||
parser_expect(par, lex_kind_comma);
|
||||
}
|
||||
parser_expect(par, lex_kind_close_brace);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (type->kind == type_kind_array) {
|
||||
parser_expect(par, lex_kind_open_brace);
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
void *memp = ti_extract_array_idx(p, type, i);
|
||||
ti__deserial_data_ex(arena, par, memp, type->base);
|
||||
parser_expect(par, lex_kind_comma);
|
||||
}
|
||||
parser_expect(par, lex_kind_close_brace);
|
||||
}
|
||||
}
|
||||
|
||||
fn void *ti__deserial_data(ma_arena_t *arena, s8_t data, type_t *type) {
|
||||
void *p = ma_push_size(arena, type->size);
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
lex_array_t tokens = lex_tokens(scratch.arena, "data serializing", data);
|
||||
parser_t *par = parser_make(scratch.arena, tokens.data);
|
||||
ti__deserial_data_ex(arena, par, p, type);
|
||||
ma_end_scratch(scratch);
|
||||
return p;
|
||||
}
|
||||
|
||||
fn b32 ti_is_basic(type_t *type) {
|
||||
b32 result = type->kind >= type_kind_first_basic && type->kind <= type_kind_last_basic;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 ti_has_type_name(type_t *type) {
|
||||
b32 result = ti_is_basic(type) || type->kind == type_kind_struct || type->kind == type_kind_enum || type->kind == type_kind_union;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t ti_serial_type(ma_arena_t *arena, type_t *type) {
|
||||
if (ti_has_type_name(type)) {
|
||||
return type->name;
|
||||
} else if (type->kind == type_kind_pointer) {
|
||||
s8_t name = ti_serial_type(arena, type->base);
|
||||
return s8_printf(arena, "%S*", name);
|
||||
} else if (type->kind == type_kind_array) {
|
||||
s8_t name = ti_serial_type(arena, type->base);
|
||||
return s8_printf(arena, "%S[%d]", name, type->count);
|
||||
} else_is_invalid;
|
||||
return s8_invalid;
|
||||
}
|
||||
364
src/core/core_type_info.h
Normal file
364
src/core/core_type_info.h
Normal file
@@ -0,0 +1,364 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
#include "core_arena.h"
|
||||
#include "core_string.h"
|
||||
#include "core_string16.h"
|
||||
#include "core_math.h"
|
||||
|
||||
typedef int type_kind_t;
|
||||
enum {
|
||||
type_kind_invalid,
|
||||
|
||||
type_kind_i8,
|
||||
type_kind_i16,
|
||||
type_kind_i32,
|
||||
type_kind_i64,
|
||||
type_kind_b8,
|
||||
type_kind_b16,
|
||||
type_kind_b32,
|
||||
type_kind_b64,
|
||||
type_kind_u8,
|
||||
type_kind_u16,
|
||||
type_kind_u32,
|
||||
type_kind_u64,
|
||||
type_kind_f32,
|
||||
type_kind_f64,
|
||||
type_kind_isize,
|
||||
type_kind_usize,
|
||||
type_kind_int,
|
||||
type_kind_char,
|
||||
type_kind_void,
|
||||
|
||||
type_kind_pointer,
|
||||
type_kind_array,
|
||||
type_kind_struct,
|
||||
type_kind_union,
|
||||
type_kind_enum,
|
||||
|
||||
type_kind_first_basic = type_kind_i8,
|
||||
type_kind_last_basic = type_kind_void,
|
||||
};
|
||||
|
||||
typedef struct type_t type_t;
|
||||
struct type_t {
|
||||
type_kind_t kind;
|
||||
s8_t name;
|
||||
i32 size;
|
||||
i32 count;
|
||||
struct type_member_t *members;
|
||||
type_t *base;
|
||||
};
|
||||
|
||||
typedef struct type_member_t type_member_t;
|
||||
struct type_member_t {
|
||||
s8_t name;
|
||||
type_t *type;
|
||||
i64 value;
|
||||
u64 offset;
|
||||
b8 dont_serialize;
|
||||
};
|
||||
|
||||
typedef struct mt_tweak_t mt_tweak_t;
|
||||
struct mt_tweak_t {
|
||||
type_t *type;
|
||||
s8_t name;
|
||||
void *ptr;
|
||||
f32 min, max;
|
||||
};
|
||||
#define mt_embed_file(name, path)
|
||||
#define mt_tweak_f32(name, default, min, max)
|
||||
#define mt_tweak_color(name, ...)
|
||||
#define mt_tweak_b32(name, default)
|
||||
|
||||
//
|
||||
// serialization to string
|
||||
#define ti_deserial_data(ARENA, DATA, TYPE) (TYPE *)ti__deserial_data(ARENA, DATA, type(TYPE))
|
||||
#define ti_serial_data(ARENA, DATA, TYPE) ti__serial_data(ARENA, DATA, type(TYPE))
|
||||
|
||||
fn void *ti__deserial_data(ma_arena_t *arena, s8_t data, type_t *type);
|
||||
fn s8_t ti__serial_data(ma_arena_t *arena, void *p, type_t *type);
|
||||
|
||||
//
|
||||
// utilities
|
||||
fn s8_t ti_enum_value_to_name(i64 value, type_t *type);
|
||||
fn i64 ti_enum_name_to_value(s8_t name, type_t *type);
|
||||
fn type_member_t *ti_get_member(s8_t name, type_t *type);
|
||||
|
||||
//
|
||||
// core type info data
|
||||
#define type(X) (&type__##X)
|
||||
#define DEFINE_ENUM(x) type_t type__##x = {type_kind_enum, s8_const(#x), sizeof(x), .members = members__##x, .count = lengthof(members__##x)}
|
||||
#define DEFINE_STRUCT(x) type_t type__##x = {type_kind_struct, s8_const(#x), sizeof(x), .members = members__##x, .count = lengthof(members__##x)}
|
||||
#define POINTER(x) (type_t){type_kind_pointer, s8_const(#x "*"), sizeof(void *), .base = &type__##x}
|
||||
|
||||
static gb_read_only type_t type__i8 = {type_kind_i8, s8_const("i8"), sizeof(i8)};
|
||||
static gb_read_only type_t type__i16 = {type_kind_i16, s8_const("i16"), sizeof(i16)};
|
||||
static gb_read_only type_t type__i32 = {type_kind_i32, s8_const("i32"), sizeof(i32)};
|
||||
static gb_read_only type_t type__i64 = {type_kind_i64, s8_const("i64"), sizeof(i64)};
|
||||
static gb_read_only type_t type__u8 = {type_kind_u8, s8_const("u8"), sizeof(u8)};
|
||||
static gb_read_only type_t type__u16 = {type_kind_u16, s8_const("u16"), sizeof(u16)};
|
||||
static gb_read_only type_t type__u32 = {type_kind_u32, s8_const("u32"), sizeof(u32)};
|
||||
static gb_read_only type_t type__u64 = {type_kind_u64, s8_const("u64"), sizeof(u64)};
|
||||
static gb_read_only type_t type__b8 = {type_kind_b8, s8_const("b8"), sizeof(b8)};
|
||||
static gb_read_only type_t type__b16 = {type_kind_b16, s8_const("b16"), sizeof(b16)};
|
||||
static gb_read_only type_t type__b32 = {type_kind_b32, s8_const("b32"), sizeof(b32)};
|
||||
static gb_read_only type_t type__b64 = {type_kind_b64, s8_const("b64"), sizeof(b64)};
|
||||
static gb_read_only type_t type__f32 = {type_kind_f32, s8_const("f32"), sizeof(f32)};
|
||||
static gb_read_only type_t type__f64 = {type_kind_f64, s8_const("f64"), sizeof(f64)};
|
||||
static gb_read_only type_t type__isize = {type_kind_isize, s8_const("isize"), sizeof(isize)};
|
||||
static gb_read_only type_t type__usize = {type_kind_usize, s8_const("usize"), sizeof(usize)};
|
||||
static gb_read_only type_t type__int = {type_kind_int, s8_const("int"), sizeof(int)};
|
||||
static gb_read_only type_t type__char = {type_kind_char, s8_const("char"), sizeof(char)};
|
||||
static gb_read_only type_t type__void = {type_kind_void, s8_const("void")};
|
||||
|
||||
static gb_read_only type_t type__s8_t = { type_kind_struct, s8_const("s8_t"), sizeof(s8_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("str"), &POINTER(char), .offset = offsetof(s8_t, str)},
|
||||
{s8_const("len"), &type__i64, .offset = offsetof(s8_t, len)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__s16_t = { type_kind_struct, s8_const("s16_t"), sizeof(s16_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("str"), &POINTER(u16), .offset = offsetof(s16_t, str)},
|
||||
{s8_const("len"), &type__i64, .offset = offsetof(s16_t, len)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__s32_t = { type_kind_struct, s8_const("s32_t"), sizeof(s32_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("str"), &POINTER(u32), .offset = offsetof(s32_t, str)},
|
||||
{s8_const("len"), &type__i64, .offset = offsetof(s32_t, len)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__ma_arena_t = { type_kind_struct, s8_const("ma_arena_t"), sizeof(ma_arena_t), .count = 6,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("data"), &POINTER(u8), .offset = offsetof(ma_arena_t, data)},
|
||||
{s8_const("len"), &type__usize, .offset = offsetof(ma_arena_t, len)},
|
||||
{s8_const("base_len"), &type__usize, .offset = offsetof(ma_arena_t, base_len)},
|
||||
{s8_const("reserve"), &type__usize, .offset = offsetof(ma_arena_t, reserve)},
|
||||
{s8_const("commit"), &type__usize, .offset = offsetof(ma_arena_t, commit)},
|
||||
{s8_const("align"), &type__usize, .offset = offsetof(ma_arena_t, align)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__sb8_node_t = {type_kind_struct, s8_const("sb8_node_t"), sizeof(sb8_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("next"), &POINTER(sb8_node_t), .offset = offsetof(sb8_node_t, next)},
|
||||
{s8_const("string"), &type__s8_t, .offset = offsetof(sb8_node_t, string)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__sb8_t = { type_kind_struct, s8_const("sb8_t"), sizeof(sb8_t), .count = 4,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("arena"), &POINTER(ma_arena_t), .offset = offsetof(sb8_t, arena)},
|
||||
{s8_const("first"), &POINTER(sb8_node_t), .offset = offsetof(sb8_t, first)},
|
||||
{s8_const("last"), &POINTER(sb8_node_t), .offset = offsetof(sb8_t, last)},
|
||||
{s8_const("indent"), &type__i32, .offset = offsetof(sb8_t, indent)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__ma_temp_t = { type_kind_struct, s8_const("ma_temp_t"), sizeof(ma_temp_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("arena"), &POINTER(ma_arena_t), .offset = offsetof(ma_temp_t, arena)},
|
||||
{s8_const("len"), &type__usize, .offset = offsetof(ma_temp_t, len)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v2f32_t = { type_kind_struct, s8_const("v2f32_t"), sizeof(v2f32_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__f32, .offset = offsetof(v2f32_t, x)},
|
||||
{s8_const("y"), &type__f32, .offset = offsetof(v2f32_t, y)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v3f32_t = { type_kind_struct, s8_const("v3f32_t"), sizeof(v3f32_t), .count = 3,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__f32, .offset = offsetof(v3f32_t, x)},
|
||||
{s8_const("y"), &type__f32, .offset = offsetof(v3f32_t, y)},
|
||||
{s8_const("z"), &type__f32, .offset = offsetof(v3f32_t, z)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v4f32_t = { type_kind_struct, s8_const("v4f32_t"), sizeof(v4f32_t), .count = 4,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__f32, .offset = offsetof(v4f32_t, x)},
|
||||
{s8_const("y"), &type__f32, .offset = offsetof(v4f32_t, y)},
|
||||
{s8_const("z"), &type__f32, .offset = offsetof(v4f32_t, z)},
|
||||
{s8_const("w"), &type__f32, .offset = offsetof(v4f32_t, w)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__r3f32_t = { type_kind_struct, s8_const("r3f32_t"), sizeof(r3f32_t), .count = 6,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x0"), &type__f32, .offset = offsetof(r3f32_t, x0)},
|
||||
{s8_const("y0"), &type__f32, .offset = offsetof(r3f32_t, y0)},
|
||||
{s8_const("x0"), &type__f32, .offset = offsetof(r3f32_t, z0)},
|
||||
{s8_const("x1"), &type__f32, .offset = offsetof(r3f32_t, x1)},
|
||||
{s8_const("y1"), &type__f32, .offset = offsetof(r3f32_t, y1)},
|
||||
{s8_const("x1"), &type__f32, .offset = offsetof(r3f32_t, z1)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_member_t members__r2f32_t[] = {
|
||||
{s8_const("x0"), &type__f32, .offset = offsetof(r2f32_t, x0)},
|
||||
{s8_const("y0"), &type__f32, .offset = offsetof(r2f32_t, y0)},
|
||||
{s8_const("x1"), &type__f32, .offset = offsetof(r2f32_t, x1)},
|
||||
{s8_const("y1"), &type__f32, .offset = offsetof(r2f32_t, y1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r2f32_t);
|
||||
|
||||
static gb_read_only type_member_t members__r1f32_t[] = {
|
||||
{s8_const("x0"), &type__f32, .offset = offsetof(r1f32_t, x0)},
|
||||
{s8_const("x1"), &type__f32, .offset = offsetof(r1f32_t, x1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r1f32_t);
|
||||
|
||||
static gb_read_only type_t type__v2f64_t = { type_kind_struct, s8_const("v2f64_t"), sizeof(v2f64_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__f64, .offset = offsetof(v2f64_t, x)},
|
||||
{s8_const("y"), &type__f64, .offset = offsetof(v2f64_t, y)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v3f64_t = { type_kind_struct, s8_const("v3f64_t"), sizeof(v3f64_t), .count = 3,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__f64, .offset = offsetof(v3f64_t, x)},
|
||||
{s8_const("y"), &type__f64, .offset = offsetof(v3f64_t, y)},
|
||||
{s8_const("z"), &type__f64, .offset = offsetof(v3f64_t, z)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v4f64_t = { type_kind_struct, s8_const("v4f64_t"), sizeof(v4f64_t), .count = 4,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__f64, .offset = offsetof(v4f64_t, x)},
|
||||
{s8_const("y"), &type__f64, .offset = offsetof(v4f64_t, y)},
|
||||
{s8_const("z"), &type__f64, .offset = offsetof(v4f64_t, z)},
|
||||
{s8_const("w"), &type__f64, .offset = offsetof(v4f64_t, w)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__r3f64_t = { type_kind_struct, s8_const("r3f64_t"), sizeof(r3f64_t), .count = 6,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x0"), &type__f64, .offset = offsetof(r3f64_t, x0)},
|
||||
{s8_const("y0"), &type__f64, .offset = offsetof(r3f64_t, y0)},
|
||||
{s8_const("x0"), &type__f64, .offset = offsetof(r3f64_t, z0)},
|
||||
{s8_const("x1"), &type__f64, .offset = offsetof(r3f64_t, x1)},
|
||||
{s8_const("y1"), &type__f64, .offset = offsetof(r3f64_t, y1)},
|
||||
{s8_const("x1"), &type__f64, .offset = offsetof(r3f64_t, z1)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_member_t members__r2f64_t[] = {
|
||||
{s8_const("x0"), &type__f64, .offset = offsetof(r2f64_t, x0)},
|
||||
{s8_const("y0"), &type__f64, .offset = offsetof(r2f64_t, y0)},
|
||||
{s8_const("x1"), &type__f64, .offset = offsetof(r2f64_t, x1)},
|
||||
{s8_const("y1"), &type__f64, .offset = offsetof(r2f64_t, y1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r2f64_t);
|
||||
|
||||
static gb_read_only type_member_t members__r1f64_t[] = {
|
||||
{s8_const("x0"), &type__f64, .offset = offsetof(r1f64_t, x0)},
|
||||
{s8_const("x1"), &type__f64, .offset = offsetof(r1f64_t, x1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r1f64_t);
|
||||
|
||||
static gb_read_only type_t type__v2i32_t = { type_kind_struct, s8_const("v2i32_t"), sizeof(v2i32_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__i32, .offset = offsetof(v2i32_t, x)},
|
||||
{s8_const("y"), &type__i32, .offset = offsetof(v2i32_t, y)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v3i32_t = { type_kind_struct, s8_const("v3i32_t"), sizeof(v3i32_t), .count = 3,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__i32, .offset = offsetof(v3i32_t, x)},
|
||||
{s8_const("y"), &type__i32, .offset = offsetof(v3i32_t, y)},
|
||||
{s8_const("z"), &type__i32, .offset = offsetof(v3i32_t, z)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v4i32_t = { type_kind_struct, s8_const("v4i32_t"), sizeof(v4i32_t), .count = 4,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__i32, .offset = offsetof(v4i32_t, x)},
|
||||
{s8_const("y"), &type__i32, .offset = offsetof(v4i32_t, y)},
|
||||
{s8_const("z"), &type__i32, .offset = offsetof(v4i32_t, z)},
|
||||
{s8_const("w"), &type__i32, .offset = offsetof(v4i32_t, w)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__r3i32_t = { type_kind_struct, s8_const("r3i32_t"), sizeof(r3i32_t), .count = 6,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x0"), &type__i32, .offset = offsetof(r3i32_t, x0)},
|
||||
{s8_const("y0"), &type__i32, .offset = offsetof(r3i32_t, y0)},
|
||||
{s8_const("x0"), &type__i32, .offset = offsetof(r3i32_t, z0)},
|
||||
{s8_const("x1"), &type__i32, .offset = offsetof(r3i32_t, x1)},
|
||||
{s8_const("y1"), &type__i32, .offset = offsetof(r3i32_t, y1)},
|
||||
{s8_const("x1"), &type__i32, .offset = offsetof(r3i32_t, z1)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_member_t members__r2i32_t[] = {
|
||||
{s8_const("x0"), &type__i32, .offset = offsetof(r2i32_t, x0)},
|
||||
{s8_const("y0"), &type__i32, .offset = offsetof(r2i32_t, y0)},
|
||||
{s8_const("x1"), &type__i32, .offset = offsetof(r2i32_t, x1)},
|
||||
{s8_const("y1"), &type__i32, .offset = offsetof(r2i32_t, y1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r2i32_t);
|
||||
|
||||
static gb_read_only type_member_t members__r1i32_t[] = {
|
||||
{s8_const("x0"), &type__i32, .offset = offsetof(r1i32_t, x0)},
|
||||
{s8_const("x1"), &type__i32, .offset = offsetof(r1i32_t, x1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r1i32_t);
|
||||
|
||||
|
||||
static gb_read_only type_t type__v2i64_t = { type_kind_struct, s8_const("v2i64_t"), sizeof(v2i64_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__i64, .offset = offsetof(v2i64_t, x)},
|
||||
{s8_const("y"), &type__i64, .offset = offsetof(v2i64_t, y)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v3i64_t = { type_kind_struct, s8_const("v3i64_t"), sizeof(v3i64_t), .count = 3,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__i64, .offset = offsetof(v3i64_t, x)},
|
||||
{s8_const("y"), &type__i64, .offset = offsetof(v3i64_t, y)},
|
||||
{s8_const("z"), &type__i64, .offset = offsetof(v3i64_t, z)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v4i64_t = { type_kind_struct, s8_const("v4i64_t"), sizeof(v4i64_t), .count = 4,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__i64, .offset = offsetof(v4i64_t, x)},
|
||||
{s8_const("y"), &type__i64, .offset = offsetof(v4i64_t, y)},
|
||||
{s8_const("z"), &type__i64, .offset = offsetof(v4i64_t, z)},
|
||||
{s8_const("w"), &type__i64, .offset = offsetof(v4i64_t, w)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__r3i64_t = { type_kind_struct, s8_const("r3i64_t"), sizeof(r3i64_t), .count = 6,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x0"), &type__i64, .offset = offsetof(r3i64_t, x0)},
|
||||
{s8_const("y0"), &type__i64, .offset = offsetof(r3i64_t, y0)},
|
||||
{s8_const("x0"), &type__i64, .offset = offsetof(r3i64_t, z0)},
|
||||
{s8_const("x1"), &type__i64, .offset = offsetof(r3i64_t, x1)},
|
||||
{s8_const("y1"), &type__i64, .offset = offsetof(r3i64_t, y1)},
|
||||
{s8_const("x1"), &type__i64, .offset = offsetof(r3i64_t, z1)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_member_t members__r2i64_t[] = {
|
||||
{s8_const("x0"), &type__i64, .offset = offsetof(r2i64_t, x0)},
|
||||
{s8_const("y0"), &type__i64, .offset = offsetof(r2i64_t, y0)},
|
||||
{s8_const("x1"), &type__i64, .offset = offsetof(r2i64_t, x1)},
|
||||
{s8_const("y1"), &type__i64, .offset = offsetof(r2i64_t, y1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r2i64_t);
|
||||
|
||||
static gb_read_only type_member_t members__r1i64_t[] = {
|
||||
{s8_const("x0"), &type__i64, .offset = offsetof(r1i64_t, x0)},
|
||||
{s8_const("x1"), &type__i64, .offset = offsetof(r1i64_t, x1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r1i64_t);
|
||||
199
src/core/core_unicode.c
Normal file
199
src/core/core_unicode.c
Normal file
@@ -0,0 +1,199 @@
|
||||
#include "core_unicode.h"
|
||||
|
||||
fn utf32_result_t utf16_to_utf32(uint16_t *c, int max_advance) {
|
||||
utf32_result_t result = {0};
|
||||
if (max_advance >= 1) {
|
||||
result.advance = 1;
|
||||
result.out_str = c[0];
|
||||
if (c[0] >= 0xD800 && c[0] <= 0xDBFF && c[1] >= 0xDC00 && c[1] <= 0xDFFF) {
|
||||
if (max_advance >= 2) {
|
||||
result.out_str = 0x10000;
|
||||
result.out_str += (uint32_t)(c[0] & 0x03FF) << 10u | (c[1] & 0x03FF);
|
||||
result.advance = 2;
|
||||
} else {
|
||||
result.error = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.error = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn utf8_result_t utf32_to_utf8(uint32_t codepoint) {
|
||||
utf8_result_t result = {0};
|
||||
|
||||
if (codepoint <= 0x7F) {
|
||||
result.len = 1;
|
||||
result.out_str[0] = (char)codepoint;
|
||||
}
|
||||
else if (codepoint <= 0x7FF) {
|
||||
result.len = 2;
|
||||
result.out_str[0] = 0xc0 | (0x1f & (codepoint >> 6));
|
||||
result.out_str[1] = 0x80 | (0x3f & codepoint);
|
||||
}
|
||||
else if (codepoint <= 0xFFFF) { // 16 bit word
|
||||
result.len = 3;
|
||||
result.out_str[0] = 0xe0 | (0xf & (codepoint >> 12)); // 4 bits
|
||||
result.out_str[1] = 0x80 | (0x3f & (codepoint >> 6)); // 6 bits
|
||||
result.out_str[2] = 0x80 | (0x3f & codepoint); // 6 bits
|
||||
}
|
||||
else if (codepoint <= 0x10FFFF) { // 21 bit word
|
||||
result.len = 4;
|
||||
result.out_str[0] = 0xf0 | (0x7 & (codepoint >> 18)); // 3 bits
|
||||
result.out_str[1] = 0x80 | (0x3f & (codepoint >> 12)); // 6 bits
|
||||
result.out_str[2] = 0x80 | (0x3f & (codepoint >> 6)); // 6 bits
|
||||
result.out_str[3] = 0x80 | (0x3f & codepoint); // 6 bits
|
||||
}
|
||||
else {
|
||||
result.error = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn utf32_result_t utf8_to_utf32(char *c, int max_advance) {
|
||||
utf32_result_t result = {0};
|
||||
|
||||
if ((c[0] & 0x80) == 0) { // Check if leftmost zero of first byte is unset
|
||||
if (max_advance >= 1) {
|
||||
result.out_str = c[0];
|
||||
result.advance = 1;
|
||||
}
|
||||
else result.error = 1;
|
||||
}
|
||||
|
||||
else if ((c[0] & 0xe0) == 0xc0) {
|
||||
if ((c[1] & 0xc0) == 0x80) { // Continuation byte required
|
||||
if (max_advance >= 2) {
|
||||
result.out_str = (uint32_t)(c[0] & 0x1f) << 6u | (c[1] & 0x3f);
|
||||
result.advance = 2;
|
||||
}
|
||||
else result.error = 2;
|
||||
}
|
||||
else result.error = 2;
|
||||
}
|
||||
|
||||
else if ((c[0] & 0xf0) == 0xe0) {
|
||||
if ((c[1] & 0xc0) == 0x80 && (c[2] & 0xc0) == 0x80) { // Two continuation bytes required
|
||||
if (max_advance >= 3) {
|
||||
result.out_str = (uint32_t)(c[0] & 0xf) << 12u | (uint32_t)(c[1] & 0x3f) << 6u | (c[2] & 0x3f);
|
||||
result.advance = 3;
|
||||
}
|
||||
else result.error = 3;
|
||||
}
|
||||
else result.error = 3;
|
||||
}
|
||||
|
||||
else if ((c[0] & 0xf8) == 0xf0) {
|
||||
if ((c[1] & 0xc0) == 0x80 && (c[2] & 0xc0) == 0x80 && (c[3] & 0xc0) == 0x80) { // Three continuation bytes required
|
||||
if (max_advance >= 4) {
|
||||
result.out_str = (uint32_t)(c[0] & 0xf) << 18u | (uint32_t)(c[1] & 0x3f) << 12u | (uint32_t)(c[2] & 0x3f) << 6u | (uint32_t)(c[3] & 0x3f);
|
||||
result.advance = 4;
|
||||
}
|
||||
else result.error = 4;
|
||||
}
|
||||
else result.error = 4;
|
||||
}
|
||||
else result.error = 4;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn utf16_result_t utf32_to_utf16(uint32_t codepoint) {
|
||||
utf16_result_t result = {0};
|
||||
if (codepoint < 0x10000) {
|
||||
result.out_str[0] = (uint16_t)codepoint;
|
||||
result.out_str[1] = 0;
|
||||
result.len = 1;
|
||||
}
|
||||
else if (codepoint <= 0x10FFFF) {
|
||||
uint32_t code = (codepoint - 0x10000);
|
||||
result.out_str[0] = (uint16_t)(0xD800 | (code >> 10));
|
||||
result.out_str[1] = (uint16_t)(0xDC00 | (code & 0x3FF));
|
||||
result.len = 2;
|
||||
}
|
||||
else {
|
||||
result.error = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define UTF__HANDLE_DECODE_ERROR(question_mark) \
|
||||
{ \
|
||||
if (outlen < buffer_size - 1) buffer[outlen++] = (question_mark); \
|
||||
break; \
|
||||
}
|
||||
|
||||
fn int64_t str_from_wstr(char *buffer, int64_t buffer_size, uint16_t *in, int64_t inlen) {
|
||||
int64_t outlen = 0;
|
||||
for (int64_t i = 0; i < inlen && in[i];) {
|
||||
utf32_result_t decode = utf16_to_utf32((uint16_t *)(in + i), (int)(inlen - i));
|
||||
if (!decode.error) {
|
||||
i += decode.advance;
|
||||
utf8_result_t encode = utf32_to_utf8(decode.out_str);
|
||||
if (!encode.error) {
|
||||
for (int64_t j = 0; j < encode.len; j++) {
|
||||
if (outlen < buffer_size - 1) {
|
||||
buffer[outlen++] = encode.out_str[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
else UTF__HANDLE_DECODE_ERROR('?');
|
||||
}
|
||||
else UTF__HANDLE_DECODE_ERROR('?');
|
||||
}
|
||||
|
||||
buffer[outlen] = 0;
|
||||
return outlen;
|
||||
}
|
||||
|
||||
fn int64_t wstr_from_str(uint16_t *buffer, int64_t buffer_size, char *in, int64_t inlen) {
|
||||
int64_t outlen = 0;
|
||||
for (int64_t i = 0; i < inlen;) {
|
||||
utf32_result_t decode = utf8_to_utf32(in + i, (int)(inlen - i));
|
||||
if (!decode.error) {
|
||||
i += decode.advance;
|
||||
utf16_result_t encode = utf32_to_utf16(decode.out_str);
|
||||
if (!encode.error) {
|
||||
for (int64_t j = 0; j < encode.len; j++) {
|
||||
if (outlen < buffer_size - 1) {
|
||||
buffer[outlen++] = encode.out_str[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
else UTF__HANDLE_DECODE_ERROR(0x003f);
|
||||
}
|
||||
else UTF__HANDLE_DECODE_ERROR(0x003f);
|
||||
}
|
||||
|
||||
buffer[outlen] = 0;
|
||||
return outlen;
|
||||
}
|
||||
|
||||
fn void utf8_advance(utf8_iter_t *iter) {
|
||||
iter->i += iter->utf8_codepoint_byte_size;
|
||||
utf32_result_t r = utf8_to_utf32(iter->str + iter->i, iter->len - iter->i);
|
||||
if (r.error) {
|
||||
iter->item = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
iter->utf8_codepoint_byte_size = r.advance;
|
||||
iter->item = r.out_str;
|
||||
}
|
||||
|
||||
// @todo: s8_t, change name
|
||||
fn utf8_iter_t utf8_iterate_ex(char *str, int len) {
|
||||
utf8_iter_t result = {str, len};
|
||||
if (len) utf8_advance(&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn utf8_iter_t utf8_iterate(char *str) {
|
||||
int length = 0;
|
||||
while (str[length]) length += 1;
|
||||
return utf8_iterate_ex(str, length);
|
||||
}
|
||||
56
src/core/core_unicode.h
Normal file
56
src/core/core_unicode.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
|
||||
typedef struct utf32_result_t utf32_result_t;
|
||||
struct utf32_result_t {
|
||||
uint32_t out_str;
|
||||
int advance;
|
||||
int error;
|
||||
};
|
||||
|
||||
typedef struct utf16_result_t utf16_result_t;
|
||||
struct utf16_result_t {
|
||||
uint16_t out_str[2];
|
||||
int len;
|
||||
int error;
|
||||
};
|
||||
|
||||
typedef struct utf8_result_t utf8_result_t;
|
||||
struct utf8_result_t {
|
||||
uint8_t out_str[4];
|
||||
int len;
|
||||
int error;
|
||||
};
|
||||
|
||||
typedef struct utf8_iter_t utf8_iter_t;
|
||||
struct utf8_iter_t {
|
||||
char *str;
|
||||
int len;
|
||||
int utf8_codepoint_byte_size;
|
||||
int i;
|
||||
uint32_t item;
|
||||
};
|
||||
|
||||
//
|
||||
// codepoint conversions
|
||||
fn utf32_result_t utf16_to_utf32(uint16_t *c, int max_advance);
|
||||
fn utf8_result_t utf32_to_utf8(uint32_t codepoint);
|
||||
fn utf32_result_t utf8_to_utf32(char *c, int max_advance);
|
||||
fn utf16_result_t utf32_to_utf16(uint32_t codepoint);
|
||||
|
||||
//
|
||||
// widestring / string conversions
|
||||
fn int64_t str_from_wstr(char *buffer, int64_t buffer_size, uint16_t *in, int64_t inlen);
|
||||
fn int64_t wstr_from_str(uint16_t *buffer, int64_t buffer_size, char *in, int64_t inlen);
|
||||
|
||||
//
|
||||
// codepoint iterator
|
||||
fn utf8_iter_t utf8_iterate(char *str);
|
||||
fn utf8_iter_t utf8_iterate_ex(char *str, int len);
|
||||
fn void utf8_advance(utf8_iter_t *iter);
|
||||
/* example:
|
||||
for (utf8_iter_t iter = utf8_iterate(string); iter.item; utf8_advance(&iter)) {
|
||||
u32 codepoint = iter.item;
|
||||
}
|
||||
|
||||
*/
|
||||
3
src/core/stb_sprintf.c
Normal file
3
src/core/stb_sprintf.c
Normal file
@@ -0,0 +1,3 @@
|
||||
#define STB_SPRINTF_IMPLEMENTATION
|
||||
#include "stb_sprintf.h"
|
||||
#undef STB_SPRINTF_IMPLEMENTATION
|
||||
1962
src/core/stb_sprintf.h
Normal file
1962
src/core/stb_sprintf.h
Normal file
File diff suppressed because it is too large
Load Diff
654
src/os/os.c
Normal file
654
src/os/os.c
Normal file
@@ -0,0 +1,654 @@
|
||||
#include "os.h"
|
||||
#include "core/core_string16.h"
|
||||
#include "core/core_platform.h"
|
||||
#include "core/core_log.h"
|
||||
|
||||
///////////////////////////////////
|
||||
#if PLATFORM_WINDOWS
|
||||
#define NOMINMAX
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <DbgHelp.h>
|
||||
#include <TlHelp32.h>
|
||||
#include <Shlobj.h>
|
||||
///////////////////////////////
|
||||
fn os_date_t os_local_time(void) {
|
||||
SYSTEMTIME lt;
|
||||
GetLocalTime(<);
|
||||
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 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;
|
||||
}
|
||||
|
||||
static int64_t win32_counts_per_second;
|
||||
fn f64 os_seconds(void) {
|
||||
if (win32_counts_per_second == 0) {
|
||||
LARGE_INTEGER freq;
|
||||
QueryPerformanceFrequency(&freq);
|
||||
win32_counts_per_second = freq.QuadPart;
|
||||
}
|
||||
|
||||
LARGE_INTEGER time;
|
||||
QueryPerformanceCounter(&time);
|
||||
f64 result = (f64)time.QuadPart / (f64)win32_counts_per_second;
|
||||
return result;
|
||||
}
|
||||
|
||||
// @todo: revise these conversions
|
||||
fn f64 os_get_microseconds(void) {
|
||||
f64 secs = os_seconds();
|
||||
f64 result = secs * 1000000.0;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn f64 os_milliseconds(void) {
|
||||
f64 secs = os_seconds();
|
||||
f64 result = secs * 1000.0;
|
||||
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_expr(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;
|
||||
}
|
||||
|
||||
// @todo: improve to return error codes
|
||||
fn s8_t os_read(ma_arena_t *arena, s8_t path) {
|
||||
s8_t result = {0};
|
||||
ma_temp_t scratch = ma_begin_scratch1(arena);
|
||||
s16_t path16 = s16_from_s8(scratch.arena, path);
|
||||
HANDLE handle = CreateFileW(path16.str, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
LARGE_INTEGER file_size;
|
||||
if (GetFileSizeEx(handle, &file_size)) {
|
||||
if (file_size.QuadPart != 0) {
|
||||
result.len = file_size.QuadPart;
|
||||
result.str = ma_push_array(arena, char, result.len + 1);
|
||||
assert(result.len == (i64)(DWORD)result.len);
|
||||
DWORD read;
|
||||
if (ReadFile(handle, result.str, (DWORD)result.len, &read, NULL)) { // @todo: can only read 32 byte size files?
|
||||
if (read == result.len) {
|
||||
result.str[result.len] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
CloseHandle(handle);
|
||||
}
|
||||
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_make(data->cFileName, str16_len(data->cFileName)));
|
||||
|
||||
char *separator = it->path.str[it->path.len - 1] == '/' ? "" : "/";
|
||||
it->rel = s8_printf(it->arena, "%S%s%S", it->path, separator, it->name);
|
||||
it->abs = os_abs(it->arena, it->rel);
|
||||
it->is_valid = true;
|
||||
s8_normalize_path_unsafe(it->rel);
|
||||
s8_normalize_path_unsafe(it->abs);
|
||||
|
||||
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_make(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_make(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_make(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, (LPTHREAD_START_ROUTINE)func, user_data, creation_flags, &thread_id);
|
||||
if (thread_handle == NULL) {
|
||||
debugf("%s.CreatedThread failed: %d", __FUNCTION__, 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_thread_join(os_thread_t *thread) {
|
||||
DWORD return_value_indicates_event = WaitForSingleObject(thread->w32->handle, INFINITE);
|
||||
if (return_value_indicates_event != WAIT_OBJECT_0) {
|
||||
debugf("%s.WaitForSingleObject failed: %d", __FUNCTION__, GetLastError());
|
||||
}
|
||||
|
||||
DWORD exit_code = 0;
|
||||
BOOL if_fails_then_zero = GetExitCodeThread(thread->w32->handle, &exit_code);
|
||||
if (if_fails_then_zero == 0) {
|
||||
debugf("%s.GetExitCodeThread failed: %d", __FUNCTION__, 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) {
|
||||
// os_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_thread_join(&threads[i]);
|
||||
// }
|
||||
// ma_end_scratch(scratch);
|
||||
// }
|
||||
|
||||
fn s8_t os_appdata(ma_arena_t *arena, s8_t name) {
|
||||
assert(name.len != 0);
|
||||
assert(name.str);
|
||||
assert(arena);
|
||||
|
||||
wchar_t *out_path = NULL;
|
||||
HRESULT hr = SHGetKnownFolderPath(&FOLDERID_RoamingAppData, KF_FLAG_CREATE, NULL, &out_path);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
debugf("%s.SHGetKnownFolderPath failed with hr: %d", __FUNCTION__, hr);
|
||||
return s8_null;
|
||||
}
|
||||
|
||||
s16_t appdata_path = s16_from_str16((u16 *)out_path);
|
||||
|
||||
ma_temp_t scratch = ma_begin_scratch1(arena);
|
||||
s8_t tmp = s8_from_s16(scratch.arena, appdata_path);
|
||||
s8_normalize_path_unsafe(tmp);
|
||||
s8_t path = s8_printf(arena, "%S/%S", tmp, name);
|
||||
os_mkdir_t mkdir_status = os_mkdir(path);
|
||||
if (mkdir_status != os_mkdir_success && mkdir_status != os_mkdir_file_exists) {
|
||||
debugf("%s.os_mkdir failed with status: %d, for: %S", __FUNCTION__, mkdir_status, path);
|
||||
path = s8_null;
|
||||
}
|
||||
|
||||
CoTaskMemFree(out_path);
|
||||
ma_end_scratch(scratch);
|
||||
return path;
|
||||
}
|
||||
|
||||
///////////////////////////////////
|
||||
#elif PLATFORM_POSIX
|
||||
///////////////////////////////////
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
fn os_date_t os_local_time(void) {
|
||||
os_date_t result = {0};
|
||||
time_t t = time(NULL);
|
||||
struct tm *lt = localtime(&t);
|
||||
result.sec = lt->tm_sec;
|
||||
result.min = lt->tm_min;
|
||||
result.hour = lt->tm_hour;
|
||||
result.day = lt->tm_mday;
|
||||
result.month = lt->tm_mon;
|
||||
result.year = lt->tm_year;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn os_date_t os_universal_time(void) {
|
||||
os_date_t result = {0};
|
||||
time_t t = time(NULL);
|
||||
struct tm u = {0};
|
||||
gmtime_r(&t, &u);
|
||||
result.sec = u.tm_sec;
|
||||
result.min = u.tm_min;
|
||||
result.hour = u.tm_hour;
|
||||
result.day = u.tm_mday;
|
||||
result.month = u.tm_mon;
|
||||
result.year = u.tm_year;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn f64 os_get_microseconds(void) {
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
u64 result = t.tv_sec*million(1) + (t.tv_nsec/thousand(1));
|
||||
return (f64)result;
|
||||
}
|
||||
|
||||
fn f64 os_get_milliseconds(void) {
|
||||
u64 micros = os_get_microseconds();
|
||||
f64 result = (f64)micros / 1000.0;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t os_exe(ma_arena_t *arena) {
|
||||
const i32 buffer_size = 2048;
|
||||
ma_temp_t temp = ma_begin_scratch1(arena);
|
||||
char *buffer = ma_push_array(arena, char, buffer_size);
|
||||
ssize_t size = readlink("/proc/self/exe", buffer, buffer_size);
|
||||
assert(size < buffer_size); // @todo:?
|
||||
assert(size != -1);
|
||||
s8_t string = s8_copy(arena, s8_make(buffer, size));
|
||||
ma_end_scratch(temp);
|
||||
return string;
|
||||
}
|
||||
|
||||
fn s8_t os_exe_dir(ma_arena_t *arena) {
|
||||
ma_temp_t temp = ma_begin_scratch1(arena);
|
||||
s8_t exe = os_exe(temp.arena);
|
||||
s8_t dir = s8_chop_last_slash(exe);
|
||||
s8_t result = s8_copy(arena, dir);
|
||||
ma_end_scratch(temp);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t os_cwd(ma_arena_t *arena) {
|
||||
const i32 buffer_size = 2048;
|
||||
ma_temp_t temp = ma_begin_scratch1(arena);
|
||||
char *buffer = ma_push_array(arena, char, buffer_size);
|
||||
char *ok = getcwd(buffer, buffer_size);
|
||||
assert(ok);
|
||||
s8_t result = s8_copy(arena, s8_from_char(buffer));
|
||||
ma_end_scratch(temp);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void os_set_cwd(s8_t path) {
|
||||
ma_temp_t temp = ma_begin_scratch();
|
||||
chdir(s8_copy(temp.arena, path).str);
|
||||
ma_end_scratch(temp);
|
||||
}
|
||||
|
||||
fn b32 os_exists(s8_t path) {
|
||||
ma_temp_t temp = ma_begin_scratch();
|
||||
s8_t copy = s8_copy(temp.arena, path);
|
||||
int ok = access(copy.str, F_OK);
|
||||
ma_end_scratch(temp);
|
||||
return ok == 0 ? true : false;
|
||||
}
|
||||
|
||||
fn b32 os_is_dir(s8_t path) {
|
||||
b32 result = false;
|
||||
ma_temp_t temp = ma_begin_scratch();
|
||||
s8_t copy = s8_copy(temp.arena, path);
|
||||
DIR *dir = opendir(copy.str);
|
||||
if (dir) {
|
||||
result = true;
|
||||
closedir(dir);
|
||||
}
|
||||
ma_end_scratch(temp);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 os_is_file(s8_t path) {
|
||||
ma_temp_t temp = ma_begin_scratch();
|
||||
s8_t copy = s8_copy(temp.arena, path);
|
||||
struct stat path_stat;
|
||||
stat(copy.str, &path_stat);
|
||||
ma_end_scratch(temp);
|
||||
b32 result = S_ISREG(path_stat.st_mode);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 os_is_abs(s8_t path) {
|
||||
b32 result = path.len && path.str[0] == '/';
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t os_abs(ma_arena_t *arena, s8_t path) {
|
||||
ma_temp_t temp = ma_begin_scratch1(arena);
|
||||
s8_t null_term_path = s8_copy(temp.arena, path);
|
||||
char buffer[PATH_MAX];
|
||||
char *resolved_path = realpath(null_term_path.str, buffer);
|
||||
s8_t result = s8_copy(arena, s8_from_char(resolved_path));
|
||||
ma_end_scratch(temp);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t os_read(ma_arena_t *arena, s8_t path) {
|
||||
s8_t result = {0};
|
||||
ma_temp_t temp = ma_begin_scratch1(arena);
|
||||
s8_t copy_path = s8_copy(temp.arena, path);
|
||||
FILE *fd = fopen(copy_path.str, "rb");
|
||||
if (fd) {
|
||||
fseek(fd, 0, SEEK_END);
|
||||
long size = ftell(fd);
|
||||
fseek(fd, 0, SEEK_SET);
|
||||
char *string = malloc(size + 1);
|
||||
fread(string, size, 1, fd);
|
||||
fclose(fd);
|
||||
|
||||
result = s8_make(string, size);
|
||||
result.str[result.len] = 0;
|
||||
}
|
||||
ma_end_scratch(temp);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn os_write_t os_write(s8_t path, s8_t content) {
|
||||
os_write_t result = os_write_path_not_found;
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s8_t copy_path = s8_copy(scratch.arena, path);
|
||||
FILE *fd = fopen(copy_path.str, "w");
|
||||
if (fd) {
|
||||
size_t size_written = fwrite(content.str, 1, content.len, fd);
|
||||
assert((int64_t)size_written == content.len);
|
||||
fclose(fd);
|
||||
result = os_write_success;
|
||||
}
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 os_copy(s8_t src_path, s8_t dst_path, b32 overwrite) {
|
||||
if (overwrite == false && os_exists(dst_path)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ma_temp_t temp = ma_begin_scratch();
|
||||
s8_t src_data = os_read(temp.arena, src_path);
|
||||
os_write_t write_result = os_write(dst_path, src_data);
|
||||
b32 result = write_result == os_write_success;
|
||||
ma_end_scratch(temp);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 os_delete(s8_t path) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s8_t copy_path = s8_copy(scratch.arena, path);
|
||||
int rc = unlink(copy_path.str);
|
||||
ma_end_scratch(scratch);
|
||||
return (b32)(rc == 0);
|
||||
}
|
||||
|
||||
fn void os_advance(os_iter_t *it) {
|
||||
struct dirent *file = NULL;
|
||||
while ((file = readdir((DIR *)it->unix_dir)) != NULL) {
|
||||
if (file->d_name[0] == '.' && file->d_name[1] == '.' && file->d_name[2] == 0) {
|
||||
continue;
|
||||
}
|
||||
if (file->d_name[0] == '.' && file->d_name[1] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
it->is_directory = file->d_type == DT_DIR;
|
||||
it->name = s8_copy(it->arena, s8_from_char(file->d_name));
|
||||
|
||||
const char *separator = it->path.str[it->path.len - 1] == '/' ? "" : "/";
|
||||
it->rel = s8_printf(it->arena, "%S%s%s", it->path, separator, file->d_name);
|
||||
it->abs = os_abs(it->arena, it->rel);
|
||||
it->is_valid = true;
|
||||
return;
|
||||
}
|
||||
|
||||
it->is_valid = false;
|
||||
closedir((DIR *)it->unix_dir);
|
||||
}
|
||||
|
||||
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->arena = arena;
|
||||
it->path = s8_copy(arena, path);
|
||||
it->unix_dir = opendir(s8_copy(arena, it->path).str);
|
||||
if (it->unix_dir) {
|
||||
it->is_valid = true;
|
||||
os_advance(it);
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
///////////////////////////////////
|
||||
#endif // PLATFORM_POSIX
|
||||
///////////////////////////////////
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#if PLATFORM_WINDOWS || PLATFORM_POSIX
|
||||
fn int os_systemf(const char *string, ...) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
S8_FMT(scratch.arena, string, result);
|
||||
int error_code = system(result.str);
|
||||
ma_end_scratch(scratch);
|
||||
return error_code;
|
||||
}
|
||||
#endif
|
||||
90
src/os/os.h
Normal file
90
src/os/os.h
Normal file
@@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
#include "core/core_basic.h"
|
||||
#include "core/core_string.h"
|
||||
|
||||
typedef struct os_date_t os_date_t;
|
||||
struct os_date_t {
|
||||
u16 ms;
|
||||
u16 sec;
|
||||
u16 min;
|
||||
u16 hour;
|
||||
u16 day;
|
||||
u16 month;
|
||||
u16 year;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
s8_t path;
|
||||
ma_arena_t *arena;
|
||||
|
||||
union {
|
||||
struct w32_file_iter_t *w32;
|
||||
void *platform;
|
||||
void *unix_dir;
|
||||
};
|
||||
};
|
||||
|
||||
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 f64 os_get_microseconds(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 s8_t os_read(ma_arena_t *arena, s8_t path);
|
||||
|
||||
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_appdata(ma_arena_t *arena, s8_t name);
|
||||
|
||||
|
||||
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 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);
|
||||
BIN
src/scratch/FiraCode-Regular.ttf
Normal file
BIN
src/scratch/FiraCode-Regular.ttf
Normal file
Binary file not shown.
2950
src/scratch/fira_code.c
Normal file
2950
src/scratch/fira_code.c
Normal file
File diff suppressed because it is too large
Load Diff
255
src/scratch/scratch.html
Normal file
255
src/scratch/scratch.html
Normal file
@@ -0,0 +1,255 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Canvas</title>
|
||||
<style>
|
||||
html,body{margin:0;height:100%;overflow:hidden;padding:0;font-size: 100px;font-family: FiraCode;}
|
||||
canvas{display:block;width:100%;height:250px;border-bottom: dotted;}
|
||||
|
||||
@font-face {
|
||||
font-family: 'FiraCode';
|
||||
src: url('./FiraCode-Regular.ttf');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
div{
|
||||
position:relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
|
||||
text-align: center;
|
||||
border-bottom: dotted;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="glcanvas"></canvas>
|
||||
<div>
|
||||
<p>Hello world (html)</p>
|
||||
</div>
|
||||
<canvas id="2dcanvas"></canvas>
|
||||
<script>
|
||||
function createShader(gl, type, src) {
|
||||
const sh = gl.createShader(type);
|
||||
gl.shaderSource(sh, src);
|
||||
gl.compileShader(sh);
|
||||
if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
|
||||
console.error('Shader compile error:', gl.getShaderInfoLog(sh));
|
||||
gl.deleteShader(sh);
|
||||
return null;
|
||||
}
|
||||
return sh;
|
||||
}
|
||||
|
||||
function createProgram(gl, vs, fs) {
|
||||
const prg = gl.createProgram();
|
||||
gl.attachShader(prg, vs);
|
||||
gl.attachShader(prg, fs);
|
||||
gl.linkProgram(prg);
|
||||
if (!gl.getProgramParameter(prg, gl.LINK_STATUS)) {
|
||||
console.error('Program link error:', gl.getProgramInfoLog(prg));
|
||||
gl.deleteProgram(prg);
|
||||
return null;
|
||||
}
|
||||
return prg;
|
||||
}
|
||||
|
||||
class WASMMemory {
|
||||
constructor(wasm_memory) {
|
||||
this.mem = wasm_memory;
|
||||
this.u8 = new Uint8Array(this.mem.buffer);
|
||||
this.data_view = new DataView(this.mem.buffer);
|
||||
this.utf8decoder = new TextDecoder("utf-8");
|
||||
this.utf8encoder = new TextEncoder("utf-8");
|
||||
this.exports = null;
|
||||
}
|
||||
|
||||
readString(str, len) {
|
||||
const arr = this.u8.subarray(str, str+len);
|
||||
const text = this.utf8decoder.decode(arr);
|
||||
return text;
|
||||
}
|
||||
|
||||
readUint8(p, len) {
|
||||
const arr = this.u8.subarray(p, p+len);
|
||||
return arr;
|
||||
}
|
||||
|
||||
writeString(ptr, ptr_len, string) {
|
||||
const bytes = this.utf8encoder.encode(string);
|
||||
let i = 0;
|
||||
for (; i < bytes.length && i < (ptr_len-1); i += 1) {
|
||||
this.u8[ptr + i] = bytes[i];
|
||||
}
|
||||
this.u8[ptr + i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
async function WASMInit(name) {
|
||||
const request = await fetch(name);
|
||||
const mem = new WASMMemory(new WebAssembly['Memory']({ initial: 2000, maximum: 65536 }));
|
||||
const binary = await request.arrayBuffer();
|
||||
const import_table = {
|
||||
memory: mem.mem,
|
||||
wasm_parse_float: (str, len) => { return parseFloat(mem.readString(str, len)); },
|
||||
wasm_alert: (str, len) => { alert(mem.readString(str,len)); },
|
||||
wasm_trap: () => { throw new Error(); },
|
||||
wasm_write_to_console: (str, len) => { console.log(mem.readString(str, len)); },
|
||||
};
|
||||
const program = await WebAssembly['instantiate'](binary, { "env": import_table });
|
||||
const instance = program['instance'];
|
||||
const export_table = instance['exports'];
|
||||
mem.exports = export_table;
|
||||
return mem;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const wasm = await WASMInit("main.wasm");
|
||||
wasm.exports.init();
|
||||
|
||||
|
||||
const VERTEX_SRC = `#version 300 es
|
||||
precision mediump float;
|
||||
in vec2 a_position;
|
||||
out vec2 v_texCoord;
|
||||
void main() {
|
||||
v_texCoord = (a_position + 1.0) * 0.5; // [0,1]
|
||||
v_texCoord.y = (1.0 - v_texCoord.y); // Flip the Y to get the standard memory behavior
|
||||
gl_Position = vec4(a_position, 0.0, 1.0);
|
||||
}`;
|
||||
|
||||
const FRAGMENT_SRC = `#version 300 es
|
||||
precision mediump float;
|
||||
in vec2 v_texCoord;
|
||||
uniform sampler2D u_texture;
|
||||
out vec4 outColor;
|
||||
void main() {
|
||||
outColor = texture(u_texture, v_texCoord);
|
||||
}`;
|
||||
|
||||
/* ---------- WebGL setup ---------- */
|
||||
const canvas = document.getElementById('glcanvas');
|
||||
const gl = canvas.getContext('webgl2');
|
||||
if (!gl) { alert('WebGL 2 not supported'); return; }
|
||||
|
||||
const vs = createShader(gl, gl.VERTEX_SHADER, VERTEX_SRC);
|
||||
const fs = createShader(gl, gl.FRAGMENT_SHADER, FRAGMENT_SRC);
|
||||
const program = createProgram(gl, vs, fs);
|
||||
|
||||
const posLoc = gl.getAttribLocation(program, 'a_position');
|
||||
const texLoc = gl.getUniformLocation(program, 'u_texture');
|
||||
|
||||
// Fullscreen quad
|
||||
const quad = new Float32Array([
|
||||
-1, -1, // bottom left
|
||||
1, -1, // bottom right
|
||||
-1, 1, // top left
|
||||
-1, 1, // top left
|
||||
1, -1, // bottom right
|
||||
1, 1 // top right
|
||||
]);
|
||||
|
||||
const vao = gl.createVertexArray();
|
||||
gl.bindVertexArray(vao);
|
||||
const vbo = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, quad, gl.STATIC_DRAW);
|
||||
gl.enableVertexAttribArray(posLoc);
|
||||
gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
|
||||
/* ---------- Dynamic texture handling ---------- */
|
||||
let texture = null;
|
||||
let texWidth = 0, texHeight = 0;
|
||||
let pixels = null;
|
||||
|
||||
function createTexture(w, h) {
|
||||
const tex = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||
// Allocate an empty texture of the canvas size
|
||||
gl.texImage2D(
|
||||
gl.TEXTURE_2D, 0, gl.RGBA8,
|
||||
w, h, 0,
|
||||
gl.RGBA, gl.UNSIGNED_BYTE, null
|
||||
);
|
||||
// Set parameters – no filtering needed for empty data
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
return tex;
|
||||
}
|
||||
|
||||
function updateTextureSize() {
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
const w = Math.floor(canvas.clientWidth * dpr);
|
||||
const h = Math.floor(canvas.clientHeight * dpr);
|
||||
if (w !== texWidth || h !== texHeight) {
|
||||
texWidth = w; texHeight = h;
|
||||
if (texture) gl.deleteTexture(texture);
|
||||
texture = createTexture(w, h);
|
||||
|
||||
let rawPtr = wasm.exports.update(texWidth, texHeight, window.devicePixelRatio || 1.0);
|
||||
pixels = wasm.readUint8(rawPtr, texWidth*texHeight*4);
|
||||
|
||||
{
|
||||
const canvas = document.getElementById('2dcanvas');
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
const w = Math.floor(canvas.clientWidth * dpr);
|
||||
const h = Math.floor(canvas.clientHeight * dpr);
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
const ctx = canvas.getContext('2d');
|
||||
let size = 100*dpr;
|
||||
ctx.font = `${size}px FiraCode`;
|
||||
const text = 'Hello world (canvas)';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
const centerX = canvas.width / 2;
|
||||
const centerY = canvas.height / 2;
|
||||
ctx.fillStyle = '#000';
|
||||
ctx.fillText(text, centerX, centerY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- Canvas resize routine ---------- */
|
||||
function resizeCanvasToDisplaySize() {
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
const w = Math.floor(canvas.clientWidth * dpr);
|
||||
const h = Math.floor(canvas.clientHeight * dpr);
|
||||
if (canvas.width !== w || canvas.height !== h) {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
gl.viewport(0, 0, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- Render loop ---------- */
|
||||
function render() {
|
||||
resizeCanvasToDisplaySize();
|
||||
updateTextureSize();
|
||||
|
||||
|
||||
gl.useProgram(program);
|
||||
gl.bindVertexArray(vao);
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, texWidth, texHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
||||
gl.uniform1i(texLoc, 0);
|
||||
|
||||
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||
|
||||
requestAnimationFrame(render);
|
||||
}
|
||||
|
||||
requestAnimationFrame(render);
|
||||
|
||||
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
112
src/scratch/scratch_main.c
Normal file
112
src/scratch/scratch_main.c
Normal file
@@ -0,0 +1,112 @@
|
||||
#include "core/core.h"
|
||||
#include "core/core.c"
|
||||
|
||||
#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_fmod(x,y) (f64_mod(x,y))
|
||||
#define STBTT_pow(x,y) (f64_pow(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_malloc(x,u) ((void)u,ma_push_size(&tcx->temp,x))
|
||||
#define STBTT_free(x,u) ((void)x,(void)u)
|
||||
#define STBTT_assert(x) assert(x)
|
||||
#define STBTT_strlen(x) str_len(x)
|
||||
#define STBTT_memcpy memory_copy
|
||||
#define STBTT_memset memory_set
|
||||
|
||||
#include "vendor/stb/stb_truetype.h"
|
||||
#include "fira_code.c"
|
||||
|
||||
typedef struct glyph_t glyph_t;
|
||||
struct glyph_t {
|
||||
u8 *data;
|
||||
i32 width, height;
|
||||
i32 xoff, yoff;
|
||||
i32 left_side_bearing, xadvance;
|
||||
};
|
||||
|
||||
typedef struct font_t font_t;
|
||||
struct font_t {
|
||||
glyph_t glyphs[96];
|
||||
i32 ascent, descent, line_gap, size;
|
||||
f32 scale;
|
||||
};
|
||||
|
||||
typedef struct bitmap_t bitmap_t;
|
||||
struct bitmap_t {
|
||||
u32 *data;
|
||||
i32 x, y;
|
||||
};
|
||||
|
||||
fn_wasm_export void init(void) {
|
||||
os_core_init();
|
||||
}
|
||||
|
||||
fn v2i32_t draw_string(bitmap_t *canvas, font_t *font, int ix, int iy, b32 draw, char *string) {
|
||||
i32 xiter = 0;
|
||||
v2i32_t R = {0};
|
||||
for (char *it = string; *it; it += 1) {
|
||||
glyph_t *g = font->glyphs + (*it - ' ');
|
||||
|
||||
i32 curr_xiter = xiter;
|
||||
xiter += g->xadvance * font->scale;
|
||||
|
||||
i32 x0 = curr_xiter + g->xoff + ix;
|
||||
i32 y0 = g->yoff + font->ascent*font->scale + iy;
|
||||
i32 x1 = g->width + x0;
|
||||
i32 y1 = g->height + y0;
|
||||
|
||||
i32 cx0 = CLAMP(x0, 0, canvas->x);
|
||||
i32 cy0 = CLAMP(y0, 0, canvas->y);
|
||||
i32 cx1 = CLAMP(x1, 0, canvas->x);
|
||||
i32 cy1 = CLAMP(y1, 0, canvas->y);
|
||||
|
||||
R.x = xiter;
|
||||
R.y = MAX(R.y, g->height);
|
||||
|
||||
if (!draw || (cx0 >= cx1 || cy0 >= cy1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
i32 sx_off = cx0 - x0;
|
||||
i32 sy_off = cy0 - y0;
|
||||
|
||||
i32 sy = sy_off;
|
||||
for (i32 y = cy0; y < cy1; y += 1) {
|
||||
i32 sx = sx_off;
|
||||
for (i32 x = cx0; x < cx1; x += 1) {
|
||||
canvas->data[x + y * canvas->x] = g->data[sx + sy * g->width] << 24;
|
||||
sx += 1;
|
||||
}
|
||||
sy += 1;
|
||||
}
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
fn_wasm_export u32 *update(i32 width, i32 height, f32 dpr) {
|
||||
gb font_t font = {0};
|
||||
font.size = (i32)(130.f * dpr);
|
||||
stbtt_fontinfo stb_font;
|
||||
int rc = stbtt_InitFont(&stb_font, main_font_data, stbtt_GetFontOffsetForIndex(main_font_data,0));
|
||||
assert_expr(rc != 0);
|
||||
|
||||
font.scale = stbtt_ScaleForPixelHeight(&stb_font, (f32)font.size);
|
||||
stbtt_GetFontVMetrics(&stb_font, &font.ascent, &font.descent, &font.line_gap);
|
||||
for (int c = ' '; c < '~'; c += 1) {
|
||||
glyph_t *glyph = font.glyphs + (c - ' ');
|
||||
u8 *temp_data = (u8 *)stbtt_GetCodepointBitmap(&stb_font, 0, font.scale, c, &glyph->width, &glyph->height, &glyph->xoff, &glyph->yoff);
|
||||
glyph->data = ma_push_array_copy(&tcx->perm, temp_data, glyph->width*glyph->height);
|
||||
stbtt_GetCodepointHMetrics(&stb_font, c, &glyph->xadvance, &glyph->left_side_bearing);
|
||||
}
|
||||
|
||||
ma_set0(&tcx->temp);
|
||||
u32 *pixels = ma_push_array(&tcx->temp, u32, width * height);
|
||||
bitmap_t canvas = {pixels, width, height};
|
||||
v2i32_t size = draw_string(&canvas, &font, 200, 500, false, "Hello world (stb)");
|
||||
draw_string(&canvas, &font, (width-size.x)/2, height - size.y*2, true, "Hello world (stb)");
|
||||
return pixels;
|
||||
}
|
||||
181
src/testing/testing_main.c
Normal file
181
src/testing/testing_main.c
Normal file
@@ -0,0 +1,181 @@
|
||||
#include "core/core.h"
|
||||
#include "os/os.h"
|
||||
|
||||
#include "core/core.c"
|
||||
#include "os/os.c"
|
||||
|
||||
fn void os_test(void) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
|
||||
os_date_t local_time = os_local_time();
|
||||
os_date_t universal_time = os_universal_time();
|
||||
unused(universal_time); unused(local_time);
|
||||
// debugf("OS 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(cwd.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("../path/")));
|
||||
|
||||
s8_t file = os_read(&tcx->temp, s8("../.gitignore"));
|
||||
assert(file.str != 0);
|
||||
assert(file.len != 0);
|
||||
|
||||
// TEST os_copy
|
||||
{
|
||||
b32 a = os_copy(s8("../.gitignore"), s8(".gitignore_copy_test"), true);
|
||||
assert(a);
|
||||
|
||||
s8_t gitignore_copy = os_read(scratch.arena, s8(".gitignore_copy_test"));
|
||||
s8_t gitignore = os_read(scratch.arena, s8("../.gitignore"));
|
||||
assert(s8_are_equal(gitignore, gitignore_copy));
|
||||
os_delete(s8(".gitignore_copy_test"));
|
||||
}
|
||||
|
||||
// TEST os_iter
|
||||
{
|
||||
b32 found_gitignore = false;
|
||||
b32 found_src = false;
|
||||
for (os_iter_t *iter = os_iter(scratch.arena, s8("../")); iter->is_valid; os_advance(iter)) {
|
||||
assert(os_is_abs(iter->abs));
|
||||
assert(!os_is_abs(iter->rel));
|
||||
if (s8_ends_with(iter->rel, s8(".gitignore"))) {
|
||||
found_gitignore = true;
|
||||
assert(os_is_file(iter->rel));
|
||||
}
|
||||
if (s8_ends_with(iter->rel, s8("src"))) {
|
||||
found_src = true;
|
||||
assert(os_is_dir(iter->rel));
|
||||
}
|
||||
|
||||
if (os_is_dir(iter->abs)) {
|
||||
assert(iter->abs.str[iter->abs.len - 1] != '/');
|
||||
}
|
||||
}
|
||||
assert(found_src);
|
||||
assert(found_gitignore);
|
||||
}
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
s8_t path = os_appdata(scratch.arena, s8("testing"));
|
||||
assert(path.str[path.len - 1] != '/');
|
||||
assert(s8_starts_with(path, s8("C:/")));
|
||||
assert(s8_ends_with(path, s8("/testing")));
|
||||
#endif
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
|
||||
fn 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("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("things are going fine"));
|
||||
s8_t string = sb8_merge(temp.arena, sb);
|
||||
assert(s8_are_equal(string, s8("memesthings are going fine")));
|
||||
|
||||
ma_end_temp(temp);
|
||||
}
|
||||
|
||||
{
|
||||
s8_t str = s8("thing|another|");
|
||||
sb8_t sb = s8_split(arena, str, s8("|"), s8_split_none);
|
||||
|
||||
assert(s8_are_equal(sb.first->string, s8("thing")));
|
||||
assert(s8_are_equal(sb.first->next->string, s8("another")));
|
||||
assert(sb.first->next->next == NULL);
|
||||
}
|
||||
|
||||
{
|
||||
s8_t str = s8("thing|another|");
|
||||
sb8_t sb = s8_split(arena, str, s8("|"), s8_split_inclusive);
|
||||
|
||||
assert(s8_are_equal(sb.first->string, s8("thing")));
|
||||
assert(s8_are_equal(sb.first->next->string, s8("|")));
|
||||
assert(s8_are_equal(sb.first->next->next->string, s8("another")));
|
||||
assert(s8_are_equal(sb.first->next->next->next->string, s8("|")));
|
||||
assert(sb.first->next->next->next->next == NULL);
|
||||
}
|
||||
|
||||
{
|
||||
s8_t str = s8("aabaaBaa");
|
||||
sb8_t sb = s8_split(arena, str, s8("b"), s8_split_inclusive | s8_split_ignore_case);
|
||||
|
||||
assert(s8_are_equal(sb.first->string, s8("aa")));
|
||||
assert(s8_are_equal(sb.first->next->string, s8("b")));
|
||||
assert(s8_are_equal(sb.first->next->next->string, s8("aa")));
|
||||
assert(s8_are_equal(sb.first->next->next->next->string, s8("B")));
|
||||
assert(s8_are_equal(sb.first->next->next->next->next->string, s8("aa")));
|
||||
assert(sb.first->next->next->next->next->next == NULL);
|
||||
}
|
||||
|
||||
{
|
||||
s8_t str = s8("aabaaBaa");
|
||||
sb8_t sb = s8_split(arena, str, s8("b"), s8_split_inclusive);
|
||||
|
||||
assert(s8_are_equal(sb.first->string, s8("aa")));
|
||||
assert(s8_are_equal(sb.first->next->string, s8("b")));
|
||||
assert(s8_are_equal(sb.first->next->next->string, s8("aaBaa")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s = s8("0123456789");
|
||||
assert(s8_are_equal(s8_slice(s, 0, 4), s8("0123")));
|
||||
assert(s8_are_equal(s8_slice(s, -2, -1), s8("89")));
|
||||
assert(s8_are_equal(s8_slice(s, -2, 10), s8("89")));
|
||||
assert(s8_are_equal(s8_slice(s, 8, 10), s8("89")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s = s8(" a \n");
|
||||
s = s8_trim(s);
|
||||
assert(s8_are_equal(s, s8("a")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s = s8("C:/memes/the_thing.c");
|
||||
s8_t ss = s8_get_name_no_ext(s);
|
||||
assert(s8_are_equal(ss, s8("the_thing")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s = s8_printf(arena, "%d%Sv%s", 32, s8("|"), ">");
|
||||
assert(s8_are_equal(s, s8("32|v>")));
|
||||
}
|
||||
|
||||
{
|
||||
s8_t s0 = s8("0123456789");
|
||||
s8_t s1 = s8_cut_start(&s0, 2);
|
||||
assert(s8_are_equal(s0, s8("23456789")));
|
||||
assert(s8_are_equal(s1, s8("01")));
|
||||
}
|
||||
|
||||
ma_destroy(arena);
|
||||
}
|
||||
|
||||
int main() {
|
||||
os_core_init();
|
||||
test_s8();
|
||||
os_test();
|
||||
debugf("Testing OK");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user