This commit is contained in:
2025-05-31 22:14:47 -04:00
parent e678b15d11
commit 93a71dc702
2 changed files with 207 additions and 136 deletions

View File

@@ -2,9 +2,16 @@
WATL Exercise WATL Exercise
Version: 0 (From Scratch, 1-Stage Compilation, MSVC & WinAPI Only, Win CRT Multi-threaded Static Linkage) Version: 0 (From Scratch, 1-Stage Compilation, MSVC & WinAPI Only, Win CRT Multi-threaded Static Linkage)
Host: Windows 11 (x86-64) Host: Windows 11 (x86-64)
Toolchain: MSVC 19.43 Toolchain: MSVC 19.43, C-Stanard: 23
*/ */
#pragma warning(disable: 4100)
#pragma warning(disable: 4127)
#pragma warning(disable: 4201)
#pragma warning(disable: 4702)
#pragma warning(disable: 4710)
#pragma warning(disable: 5045)
#pragma region Header #pragma region Header
#pragma region DSL #pragma region DSL
@@ -23,8 +30,8 @@ typedef S8 B8;
typedef S16 B16; typedef S16 B16;
typedef S32 B32; typedef S32 B32;
enum { enum {
false, false = 0,
true, true = 1,
true_overflow, true_overflow,
}; };
#define glue_impl(A, B) A ## B #define glue_impl(A, B) A ## B
@@ -33,6 +40,7 @@ enum {
#define stringify(S) stringify_impl(S) #define stringify(S) stringify_impl(S)
#define tmpl(prefix, type) prefix ## _ ## type #define tmpl(prefix, type) prefix ## _ ## type
#define byte_pad(amount, ...) Byte glue(_PAD_, __VA_ARGS__) [amount]
#define farray_len(array) (SSIZE)sizeof(array) / size_of( typeof((array)[0])) #define farray_len(array) (SSIZE)sizeof(array) / size_of( typeof((array)[0]))
#define farray_init(type, ...) (type[]){__VA_ARGS__} #define farray_init(type, ...) (type[]){__VA_ARGS__}
#define def_farray(type, len) type A ## len ## _ ## type[len] #define def_farray(type, len) type A ## len ## _ ## type[len]
@@ -47,7 +55,8 @@ enum {
#define offset_of(type, member) cast(SSIZE, & (((type*) 0)->member)) #define offset_of(type, member) cast(SSIZE, & (((type*) 0)->member))
#define static_assert _Static_assert #define static_assert _Static_assert
#define typeof __typeof__ #define typeof __typeof__
#define typeof_ptr(ptr) __typeof__(ptr[0]) #define typeof_ptr(ptr) typeof(ptr[0])
#define typeof_same(a, b) _Generic((a), typeof((b)): 1, default: 0)
#define cast(type, data) ((type)(data)) #define cast(type, data) ((type)(data))
#define pcast(type, data) * cast(type*, & (data)) #define pcast(type, data) * cast(type*, & (data))
@@ -72,6 +81,8 @@ enum {
typedef def_range(S32); typedef def_range(S32);
typedef def_range(U32); typedef def_range(U32);
typedef def_range(SSIZE); typedef def_range(SSIZE);
typedef void fn(VoidFn) (void);
#pragma endregion DSL #pragma endregion DSL
#pragma region Debug #pragma region Debug
@@ -103,7 +114,8 @@ void assert_handler( char const* condition, char const* file, char const* functi
#pragma endregion Debug #pragma endregion Debug
#pragma region Memory #pragma region Memory
#define align_pow2(x, b) (((x) + (b) - 1) & ( ~((b) - 1))) inline SSIZE align_pow2(SSIZE x, SSIZE b);
#define align_struct(type_width) ((SSIZE)(((type_width) + 7) / 8 * 8)) #define align_struct(type_width) ((SSIZE)(((type_width) + 7) / 8 * 8))
#define assert_bounds(point, start, end) do { \ #define assert_bounds(point, start, end) do { \
@@ -129,13 +141,17 @@ def_struct(tmpl(Slice,type)) { \
typedef def_Slice(void); typedef def_Slice(void);
typedef def_Slice(Byte); typedef def_Slice(Byte);
#define slice_byte(slice) (Slice_Byte){cast(Byte*, (slice).ptr), (slice).len * size_of_slice_type(slice)} #define slice_byte(slice) ((Slice_Byte){cast(Byte*, (slice).ptr), (slice).len * size_of_slice_type(slice)})
#define slice_fmem(mem) (Slice_Byte){ mem, size_of(mem) } #define slice_fmem(mem) ((Slice_Byte){ mem, size_of(mem) })
void slice__copy(Slice_Byte dest, SSIZE dest_typewidth, Slice_Byte src, SSIZE src_typewidth); void slice__copy(Slice_Byte dest, SSIZE dest_typewidth, Slice_Byte src, SSIZE src_typewidth);
void slice__zero(Slice_Byte mem, SSIZE typewidth); void slice__zero(Slice_Byte mem, SSIZE typewidth);
#define slice_copy(dest, src) slice__copy(slice_byte(dest), size_of_slice_type(dest), slice_byte(src), size_of_slice_type(src)) #define slice_copy(dest, src) do { \
static_assert(typeof_same(dest, src)); \
slice__copy(slice_byte(dest), size_of_slice_type(dest), slice_byte(src), size_of_slice_type(src)); \
} while (0)
#define slice_zero(slice) slice__zero(slice_byte(slice), size_of_slice_type(slice)) #define slice_zero(slice) slice__zero(slice_byte(slice), size_of_slice_type(slice))
#define slice_iter(container, iter) \ #define slice_iter(container, iter) \
typeof((container).ptr) iter = (container).ptr; \ typeof((container).ptr) iter = (container).ptr; \
iter != slice_end(container); \ iter != slice_end(container); \
@@ -176,7 +192,7 @@ typedef unsigned char UTF8;
typedef def_Slice(UTF8); typedef def_Slice(UTF8);
typedef Slice_UTF8 Str8; typedef Slice_UTF8 Str8;
typedef def_Slice(Str8); typedef def_Slice(Str8);
#define lit(string_literal) (Str8){ string_literal, size_of(string_literal) - 1 } #define lit(string_literal) (Str8){ (UTF8*) string_literal, size_of(string_literal) - 1 }
#pragma endregion Strings #pragma endregion Strings
#pragma region Allocator Interface #pragma region Allocator Interface
@@ -204,18 +220,21 @@ typedef def_enum(U64, AllocatorQueryFlags) {
// Ability to rewind to a save point (ex: arenas, stack), must also be able to save such a point // Ability to rewind to a save point (ex: arenas, stack), must also be able to save such a point
AllocatorQuery_Rewind = (1 << 6), AllocatorQuery_Rewind = (1 << 6),
}; };
typedef def_struct(AllocatorSP) {
void* type_sig;
SSIZE slot;
};
typedef def_struct(AllocatorProc_In) { typedef def_struct(AllocatorProc_In) {
void* data; void* data;
AllocatorOp op;
SSIZE requested_size; SSIZE requested_size;
SSIZE alignment; SSIZE alignment;
Slice_Byte old_allocation; Slice_Byte old_allocation;
AllocatorOp op;
byte_pad(4);
}; };
typedef def_struct(AllocatorProc_Out) { typedef struct AllocatorProc_Out AllocatorProc_Out;
typedef void fn(AllocatorProc) (AllocatorProc_In In, AllocatorProc_Out* Out);
typedef def_struct(AllocatorSP) {
AllocatorProc* type_sig;
SSIZE slot;
};
struct AllocatorProc_Out {
union { union {
Slice_Byte allocation; Slice_Byte allocation;
AllocatorSP save_point; AllocatorSP save_point;
@@ -225,13 +244,12 @@ typedef def_struct(AllocatorProc_Out) {
SSIZE max_alloc; SSIZE max_alloc;
SSIZE min_alloc; SSIZE min_alloc;
B32 continuity_break; // Whether this allocation broke continuity with the previous (address space wise) B32 continuity_break; // Whether this allocation broke continuity with the previous (address space wise)
byte_pad(4);
}; };
typedef void fn(AllocatorProc) (AllocatorProc_In In, AllocatorProc_Out* Out);
typedef def_struct(AllocatorInfo) { typedef def_struct(AllocatorInfo) {
AllocatorProc* proc; AllocatorProc* proc;
void* data; void* data;
}; };
static_assert(size_of(AllocatorSP) <= size_of(Slice_Byte)); static_assert(size_of(AllocatorSP) <= size_of(Slice_Byte));
#define MEMORY_ALIGNMENT_DEFAULT (2 * size_of(void*)) #define MEMORY_ALIGNMENT_DEFAULT (2 * size_of(void*))
@@ -243,10 +261,10 @@ void mem_reset (AllocatorInfo ainfo);
void mem_rewind (AllocatorInfo ainfo, AllocatorSP save_point); void mem_rewind (AllocatorInfo ainfo, AllocatorSP save_point);
AllocatorSP mem_save_point(AllocatorInfo ainfo); AllocatorSP mem_save_point(AllocatorInfo ainfo);
typedef def_struct(Opts_mem_alloc) { SSIZE alignment; B32 no_zero; }; typedef def_struct(Opts_mem_alloc) { SSIZE alignment; B32 no_zero; byte_pad(4); };
typedef def_struct(Opts_mem_grow) { SSIZE alignment; B32 no_zero; }; typedef def_struct(Opts_mem_grow) { SSIZE alignment; B32 no_zero; byte_pad(4); };
typedef def_struct(Opts_mem_shrink) { SSIZE alignment; }; typedef def_struct(Opts_mem_shrink) { SSIZE alignment; };
typedef def_struct(Opts_mem_resize) { SSIZE alignment; B32 no_zero; }; typedef def_struct(Opts_mem_resize) { SSIZE alignment; B32 no_zero; byte_pad(4); };
Slice_Byte mem__alloc (AllocatorInfo ainfo, SSIZE size, Opts_mem_alloc* opts); Slice_Byte mem__alloc (AllocatorInfo ainfo, SSIZE size, Opts_mem_alloc* opts);
Slice_Byte mem__grow (AllocatorInfo ainfo, Slice_Byte mem, SSIZE size, Opts_mem_grow* opts); Slice_Byte mem__grow (AllocatorInfo ainfo, Slice_Byte mem, SSIZE size, Opts_mem_grow* opts);
@@ -296,9 +314,10 @@ typedef def_struct(OS_SystemInfo) {
typedef def_struct(Opts_vmem) { typedef def_struct(Opts_vmem) {
SSIZE base_addr; SSIZE base_addr;
B32 no_large_pages; B32 no_large_pages;
byte_pad(4);
}; };
void os_init(); void os_init(void);
OS_SystemInfo* os_system_info(); OS_SystemInfo* os_system_info(void);
inline B32 os__vmem_commit(void* vm, SSIZE size, Opts_vmem* opts); inline B32 os__vmem_commit(void* vm, SSIZE size, Opts_vmem* opts);
inline Byte* os__vmem_reserve(SSIZE size, Opts_vmem* opts); inline Byte* os__vmem_reserve(SSIZE size, Opts_vmem* opts);
@@ -320,12 +339,14 @@ typedef def_struct(VArena) {
SSIZE committed; SSIZE committed;
SSIZE commit_used; SSIZE commit_used;
VArenaFlags flags; VArenaFlags flags;
byte_pad(4);
}; };
typedef def_struct(Opts_varena_make) { typedef def_struct(Opts_varena_make) {
SSIZE base_addr; SSIZE base_addr;
SSIZE reserve_size; SSIZE reserve_size;
SSIZE commit_size; SSIZE commit_size;
VArenaFlags flags; VArenaFlags flags;
byte_pad(4);
}; };
VArena* varena__make(Opts_varena_make* opts); VArena* varena__make(Opts_varena_make* opts);
#define varena_make(...) varena__make(opt_args(Opts_varena_make, __VA_ARGS__)) #define varena_make(...) varena__make(opt_args(Opts_varena_make, __VA_ARGS__))
@@ -359,6 +380,7 @@ typedef def_struct(Arena) {
SSIZE base_pos; SSIZE base_pos;
SSIZE pos; SSIZE pos;
ArenaFlags flags; ArenaFlags flags;
byte_pad(4);
}; };
typedef Opts_varena_make Opts_arena_make; typedef Opts_varena_make Opts_arena_make;
Arena* arena__make (Opts_arena_make* opts); Arena* arena__make (Opts_arena_make* opts);
@@ -427,6 +449,7 @@ def_struct(tmpl(KT1CX_Slot,type)) { \
type value; \ type value; \
U64 key; \ U64 key; \
B32 occupied; \ B32 occupied; \
byte_pad(4); \
} }
#define def_KT1CX_Cell(type, depth) \ #define def_KT1CX_Cell(type, depth) \
def_struct(tmpl(KT1CX_Cell,type)) { \ def_struct(tmpl(KT1CX_Cell,type)) { \
@@ -442,6 +465,10 @@ def_struct(tmpl(KT1CX,type)) { \
typedef def_struct(KT1CX_Byte_Slot) { typedef def_struct(KT1CX_Byte_Slot) {
U64 key; U64 key;
B32 occupied; B32 occupied;
byte_pad(4);
};
typedef def_struct(KT1CX_Byte_Cell) {
Byte* next;
}; };
typedef def_struct(KT1CX_Byte) { typedef def_struct(KT1CX_Byte) {
Slice_Byte cell_pool; Slice_Byte cell_pool;
@@ -473,7 +500,13 @@ void kt1cx__init (KT1CX_Info info, KT1CX_Byte* result);
void kt1cx__clear (KT1CX_Byte kt, KT1CX_ByteMeta meta); void kt1cx__clear (KT1CX_Byte kt, KT1CX_ByteMeta meta);
U64 kt1cx__slot_id(KT1CX_Byte kt, U64 key, KT1CX_ByteMeta meta); U64 kt1cx__slot_id(KT1CX_Byte kt, U64 key, KT1CX_ByteMeta meta);
Slice_Byte kt1cx__get (KT1CX_Byte kt, U64 key, KT1CX_ByteMeta meta); Slice_Byte kt1cx__get (KT1CX_Byte kt, U64 key, KT1CX_ByteMeta meta);
Slice_Byte kt1cx__set (KT1CX_Byte* kt, U64 key, Slice_Byte value, AllocatorInfo backing_cells, KT1CX_ByteMeta meta); Slice_Byte kt1cx__set (KT1CX_Byte kt, U64 key, Slice_Byte value, AllocatorInfo backing_cells, KT1CX_ByteMeta meta);
#define kt1cx_assert(kt) do { \
slice_assert(kt.cell_pool); \
slice_assert(kt.table); \
} while(0)
#define kt1cx_byte(kt) (KT1CX_Byte){slice_byte(kt.cell_pool), { cast(Byte*, kt.table.ptr), kt.table.len } }
#pragma endregion KT1CX #pragma endregion KT1CX
#pragma region String Operations #pragma region String Operations
@@ -524,12 +557,12 @@ Str8Cache str8cache__make( Opts_str8cache_init* opts);
#define str8gen_slice_byte(gen) (Slice_Byte){ cast(Byte*, (gen).ptr), (gen).cap } #define str8gen_slice_byte(gen) (Slice_Byte){ cast(Byte*, (gen).ptr), (gen).cap }
#define str8cache_init(cache, ...) str8cache__init(cache, opt_args(Opts_str8cache_init)) #define str8cache_init(cache, ...) str8cache__init(cache, opt_args(Opts_str8cache_init, __VA_ARGS__))
#define str8cache_make(...) str8cache__make( opt_args(Opts_str8cache_init)) #define str8cache_make(...) str8cache__make( opt_args(Opts_str8cache_init, __VA_ARGS__))
void str8cache_clear(KT1CX_Str8 kt); void str8cache_clear(KT1CX_Str8 kt);
Str8 str8cache_get (KT1CX_Str8 kt, U64 key); Str8 str8cache_get (KT1CX_Str8 kt, U64 key);
Str8 str8cache_set (KT1CX_Str8* kt, U64 key, Str8 value, AllocatorInfo str_reserve, AllocatorInfo backing_cells); Str8 str8cache_set (KT1CX_Str8 kt, U64 key, Str8 value, AllocatorInfo str_reserve, AllocatorInfo backing_cells);
Str8 cache_str8(Str8Cache* cache, Str8 str); Str8 cache_str8(Str8Cache* cache, Str8 str);
@@ -557,6 +590,7 @@ typedef def_struct(FileOpInfo) {
typedef def_struct(Opts_read_file_contents) { typedef def_struct(Opts_read_file_contents) {
AllocatorInfo backing; AllocatorInfo backing;
B32 zero_backing; B32 zero_backing;
byte_pad(4);
}; };
void api_file_read_contents(FileOpInfo* result, Str8 path, Opts_read_file_contents opts); void api_file_read_contents(FileOpInfo* result, Str8 path, Opts_read_file_contents opts);
void file_write_str8 (Str8 path, Str8 content); void file_write_str8 (Str8 path, Str8 content);
@@ -578,11 +612,10 @@ typedef def_struct(WATL_Tok) {
}; };
typedef def_Slice(WATL_Tok); typedef def_Slice(WATL_Tok);
typedef def_enum(U32, WATL_LexStatus) { typedef def_enum(U32, WATL_LexStatus) {
WATL_LexStatus_MemFail_Alloc = (1 << 0), WATL_LexStatus_MemFail_SliceConstraintFail = (1 << 0),
WATL_LexStatus_MemFail_SliceConstraintFail = (1 << 1), // WATL_LexStatus_PosUntrackable = (1 << 1),
WATL_LexStatus_PosUntrackable = (1 << 2), // WATL_LexStatus_UnsupportedCodepoints = (1 << 2),
WATL_LexStatus_UnsupportedCodepoints = (1 << 3), // WATL_LexStatus_MessageOverflow = (1 << 3),
WATL_LexStatus_MessageOverflow = (1 << 4),
}; };
typedef def_struct(WATL_Pos) { typedef def_struct(WATL_Pos) {
S32 line; S32 line;
@@ -598,6 +631,7 @@ typedef def_struct(WATL_LexInfo) {
WATL_LexMsg* msgs; WATL_LexMsg* msgs;
Slice_WATL_Tok toks; Slice_WATL_Tok toks;
WATL_LexStatus signal; WATL_LexStatus signal;
byte_pad(4);
}; };
typedef def_struct(Opts_watl_lex) { typedef def_struct(Opts_watl_lex) {
AllocatorInfo ainfo_msgs; AllocatorInfo ainfo_msgs;
@@ -605,6 +639,7 @@ typedef def_struct(Opts_watl_lex) {
B8 failon_unsupported_codepoints; B8 failon_unsupported_codepoints;
B8 failon_pos_untrackable; B8 failon_pos_untrackable;
B8 failon_slice_constraint_fail; B8 failon_slice_constraint_fail;
byte_pad(5);
}; };
void api_watl_lex(WATL_LexInfo* info, Str8 source, Opts_watl_lex* opts); void api_watl_lex(WATL_LexInfo* info, Str8 source, Opts_watl_lex* opts);
WATL_LexInfo watl__lex ( Str8 source, Opts_watl_lex* opts); WATL_LexInfo watl__lex ( Str8 source, Opts_watl_lex* opts);
@@ -622,23 +657,24 @@ typedef def_struct(WATL_ParseMsg) {
WATL_Pos pos; WATL_Pos pos;
}; };
typedef def_enum(U32, WATL_ParseStatus) { typedef def_enum(U32, WATL_ParseStatus) {
WATL_ParseStatus_MemFail_Alloc = (1 << 0), WATL_ParseStatus_MemFail_SliceConstraintFail = (1 << 0),
WATL_ParseStatus_MemFail_SliceConstraintFail = (1 << 1), // WATL_ParseStatus_PosUntrackable = (1 << 1),
WATL_ParseStatus_PosUntrackable = (1 << 2), // WATL_ParseStatus_UnsupportedTokens = (1 << 2),
WATL_ParseStatus_UnsupportedTokens = (1 << 3), // WATL_ParseStatus_MessageOverflow = (1 << 3),
WATL_ParseStatus_MessageOverflow = (1 << 4),
}; };
typedef def_struct(WATL_ParseInfo) { typedef def_struct(WATL_ParseInfo) {
Slice_WATL_Line lines; Slice_WATL_Line lines;
WATL_ParseMsg* msgs; WATL_ParseMsg* msgs;
WATL_ParseStatus signal; WATL_ParseStatus signal;
byte_pad(4);
}; };
typedef def_struct(Opts_watl_parse) { typedef def_struct(Opts_watl_parse) {
AllocatorInfo ainfo_msgs; AllocatorInfo ainfo_msgs;
AllocatorInfo ainfo_nodes; AllocatorInfo ainfo_nodes;
AllocatorInfo ainfo_lines; AllocatorInfo ainfo_lines;
Str8Cache* str_cache; Str8Cache* str_cache;
B8 failon_slice_constraint_fail; B32 failon_slice_constraint_fail;
byte_pad(4);
}; };
void api_watl_parse(WATL_ParseInfo* info, Slice_WATL_Tok tokens, Opts_watl_parse* opts); void api_watl_parse(WATL_ParseInfo* info, Slice_WATL_Tok tokens, Opts_watl_parse* opts);
WATL_ParseInfo watl__parse ( Slice_WATL_Tok tokens, Opts_watl_parse* opts); WATL_ParseInfo watl__parse ( Slice_WATL_Tok tokens, Opts_watl_parse* opts);
@@ -657,23 +693,28 @@ void* __cdecl memcpy (void* _Dst, void const* _Src, USIZE _Size);
void* __cdecl memmove(void* _Dst, void const* _Src, USIZE _Size); void* __cdecl memmove(void* _Dst, void const* _Src, USIZE _Size);
void* __cdecl memset (void* _Dst, int _Val, USIZE _Size); void* __cdecl memset (void* _Dst, int _Val, USIZE _Size);
inline
SSIZE align_pow2(SSIZE x, SSIZE b) {
assert(b != 0);
assert((b & (b - 1)) == 0); // Check power of 2
return ((x + b - 1) & (~(b - 1)));
}
inline inline
void* memory_copy(void* restrict dest, void const* restrict src, USIZE length) { void* memory_copy(void* restrict dest, void const* restrict src, USIZE length) {
if (dest == nullptr || src == nullptr || length == 0) { return nullptr; } if (dest == nullptr || src == nullptr) { return nullptr; }
memcpy(dest, src, length); memcpy(dest, src, length);
return dest; return dest;
} }
inline inline
void* memory_copy_overlapping(void* restrict dest, void const* restrict src, USIZE length) { void* memory_copy_overlapping(void* restrict dest, void const* restrict src, USIZE length) {
if (dest == nullptr || src == nullptr || length == 0) { return nullptr; } if (dest == nullptr || src == nullptr) { return nullptr; }
memmove(dest, src, length); memmove(dest, src, length);
return dest; return dest;
} }
inline inline
B32 memory_zero(void* dest, USIZE length) { B32 memory_zero(void* dest, USIZE length) {
if (dest == nullptr || length <= 0) { if (dest == nullptr) return false;
return false;
}
memset((unsigned char*)dest, 0, length); memset((unsigned char*)dest, 0, length);
return true; return true;
} }
@@ -719,7 +760,7 @@ AllocatorSP mem_save_point(AllocatorInfo ainfo) {
assert(ainfo.proc != nullptr); assert(ainfo.proc != nullptr);
AllocatorProc_Out out; AllocatorProc_Out out;
ainfo.proc((AllocatorProc_In){.data = ainfo.data, .op = AllocatorOp_SavePoint}, & out); ainfo.proc((AllocatorProc_In){.data = ainfo.data, .op = AllocatorOp_SavePoint}, & out);
return * cast(AllocatorSP*, & out.allocation); return out.save_point;
} }
inline inline
@@ -812,14 +853,14 @@ Slice_Byte farena__push(FArena* arena, SSIZE amount, SSIZE type_width, Opts_fare
inline void farena_reset(FArena* arena) { arena->used = 0; } inline void farena_reset(FArena* arena) { arena->used = 0; }
inline inline
void farena_rewind(FArena* arena, AllocatorSP save_point) { void farena_rewind(FArena* arena, AllocatorSP save_point) {
assert(save_point.type_sig == farena_allocator_proc); assert(save_point.type_sig == & farena_allocator_proc);
Byte* end = cast(Byte*, cast(SSIZE, arena->start) + arena->used); Byte* end = cast(Byte*, cast(SSIZE, arena->start) + arena->used);
assert_bounds(save_point.slot, arena->start, end); assert_bounds(save_point.slot, arena->start, end);
arena->used -= save_point.slot - cast(SSIZE, arena->start); arena->used -= save_point.slot - cast(SSIZE, arena->start);
} }
inline inline
AllocatorSP farena_save (FArena arena) { AllocatorSP farena_save (FArena arena) {
AllocatorSP sp = { .type_sig = farena_allocator_proc, .slot = cast(SSIZE, arena.used) }; AllocatorSP sp = { .type_sig = & farena_allocator_proc, .slot = cast(SSIZE, arena.used) };
return sp; return sp;
} }
void farena_allocator_proc(AllocatorProc_In in, AllocatorProc_Out* out) void farena_allocator_proc(AllocatorProc_In in, AllocatorProc_Out* out)
@@ -872,6 +913,8 @@ void farena_allocator_proc(AllocatorProc_In in, AllocatorProc_Out* out)
#pragma endregion FArena #pragma endregion FArena
#pragma region OS #pragma region OS
#pragma warning(push)
#pragma warning(disable: 4820)
#pragma comment(lib, "Kernel32.lib") #pragma comment(lib, "Kernel32.lib")
#pragma comment(lib, "Advapi32.lib") #pragma comment(lib, "Advapi32.lib")
#define MS_INVALID_HANDLE_VALUE ((MS_HANDLE)(__int64)-1) #define MS_INVALID_HANDLE_VALUE ((MS_HANDLE)(__int64)-1)
@@ -919,16 +962,17 @@ __declspec(dllimport) MS_BOOL __stdcall LookupPrivilegeValueW(MS_LPWSTR lpSyst
__declspec(dllimport) MS_BOOL __stdcall OpenProcessToken(MS_HANDLE ProcessHandle, MS_DWORD DesiredAccess, MS_PHANDLE TokenHandle); __declspec(dllimport) MS_BOOL __stdcall OpenProcessToken(MS_HANDLE ProcessHandle, MS_DWORD DesiredAccess, MS_PHANDLE TokenHandle);
__declspec(dllimport) MS_LPVOID __stdcall VirtualAlloc(MS_LPVOID lpAddress, USIZE dwSize, MS_DWORD flAllocationType, MS_DWORD flProtect); __declspec(dllimport) MS_LPVOID __stdcall VirtualAlloc(MS_LPVOID lpAddress, USIZE dwSize, MS_DWORD flAllocationType, MS_DWORD flProtect);
__declspec(dllimport) MS_BOOL __stdcall VirtualFree (MS_LPVOID lpAddress, USIZE dwSize, MS_DWORD dwFreeType); __declspec(dllimport) MS_BOOL __stdcall VirtualFree (MS_LPVOID lpAddress, USIZE dwSize, MS_DWORD dwFreeType);
#pragma warning(pop)
typedef def_struct(OS_Windows_State) { typedef def_struct(OS_Windows_State) {
OS_SystemInfo system_info; OS_SystemInfo system_info;
}; };
global OS_Windows_State os__windows_info; global OS_Windows_State os__windows_info;
OS_SystemInfo* os_system_info() { OS_SystemInfo* os_system_info(void) {
return & os__windows_info.system_info; return & os__windows_info.system_info;
} }
void os__enable_large_pages() { void os__enable_large_pages(void) {
MS_HANDLE token; MS_HANDLE token;
if (OpenProcessToken(GetCurrentProcess(), MS_TOKEN_ADJUST_PRIVILEGES | MS_TOKEN_QUERY, &token)) if (OpenProcessToken(GetCurrentProcess(), MS_TOKEN_ADJUST_PRIVILEGES | MS_TOKEN_QUERY, &token))
{ {
@@ -945,7 +989,7 @@ void os__enable_large_pages() {
} }
} }
inline inline
void os_init() { void os_init(void) {
os__enable_large_pages(); os__enable_large_pages();
OS_SystemInfo* info = & os__windows_info.system_info; OS_SystemInfo* info = & os__windows_info.system_info;
info->target_page_size = (SSIZE)GetLargePageMinimum(); info->target_page_size = (SSIZE)GetLargePageMinimum();
@@ -1010,21 +1054,21 @@ Slice_Byte varena__push(VArena* vm, SSIZE amount, SSIZE type_width, Opts_varena*
if (next_commit_size) { if (next_commit_size) {
Byte* next_commit_start = cast(Byte*, cast(SSIZE, vm) + vm->committed); Byte* next_commit_start = cast(Byte*, cast(SSIZE, vm) + vm->committed);
B32 no_large_pages = (vm->flags & VArenaFlag_NoLargePages) != 0; B32 no_large_pages = (vm->flags & VArenaFlag_NoLargePages) != 0;
B32 commit_result = os_vmem_commit(next_commit_start, next_commit_size); B32 commit_result = os_vmem_commit(next_commit_start, next_commit_size, .no_large_pages = no_large_pages);
if (commit_result == false) { if (commit_result == false) {
return (Slice_Byte){0}; return (Slice_Byte){0};
} }
vm->committed += next_commit_size; vm->committed += next_commit_size;
} }
} }
vm->commit_used += to_be_used; vm->commit_used = to_be_used;
return (Slice_Byte){.ptr = cast(Byte*, current_offset), .len = requested_size}; return (Slice_Byte){.ptr = cast(Byte*, current_offset), .len = requested_size};
} }
inline void varena_release(VArena* arena) { os_vmem_release(arena, arena->reserve); } inline void varena_release(VArena* arena) { os_vmem_release(arena, arena->reserve); }
inline inline
void varena_rewind(VArena* vm, AllocatorSP sp) { void varena_rewind(VArena* vm, AllocatorSP sp) {
assert(vm != nullptr); assert(vm != nullptr);
assert(sp.type_sig == varena_allocator_proc); assert(sp.type_sig == & varena_allocator_proc);
vm->commit_used = sp.slot; vm->commit_used = sp.slot;
} }
inline AllocatorSP varena_save(VArena* vm) { return (AllocatorSP){varena_allocator_proc, vm->commit_used}; } inline AllocatorSP varena_save(VArena* vm) { return (AllocatorSP){varena_allocator_proc, vm->commit_used}; }
@@ -1048,7 +1092,10 @@ void varena_allocator_proc(AllocatorProc_In in, AllocatorProc_Out* out)
case AllocatorOp_Grow_NoZero: case AllocatorOp_Grow_NoZero:
case AllocatorOp_Grow: { case AllocatorOp_Grow: {
SSIZE grow_amount = in.requested_size - in.old_allocation.len; SSIZE grow_amount = in.requested_size - in.old_allocation.len;
assert(grow_amount >= 0); if (grow_amount == 0) {
out->allocation = in.old_allocation;
return;
}
SSIZE current_offset = vm->reserve_start + vm->commit_used; SSIZE current_offset = vm->reserve_start + vm->commit_used;
assert(in.old_allocation.ptr == cast(Byte*, current_offset)); assert(in.old_allocation.ptr == cast(Byte*, current_offset));
Slice_Byte allocation = varena_push_array(vm, Byte, grow_amount, .alignment = in.alignment); Slice_Byte allocation = varena_push_array(vm, Byte, grow_amount, .alignment = in.alignment);
@@ -1060,7 +1107,10 @@ void varena_allocator_proc(AllocatorProc_In in, AllocatorProc_Out* out)
case AllocatorOp_Shrink: { case AllocatorOp_Shrink: {
SSIZE current_offset = vm->reserve_start + vm->commit_used; SSIZE current_offset = vm->reserve_start + vm->commit_used;
SSIZE shrink_amount = in.old_allocation.len - in.requested_size; SSIZE shrink_amount = in.old_allocation.len - in.requested_size;
assert(shrink_amount >= 0); if (shrink_amount < 0) {
out->allocation = in.old_allocation;
return;
}
assert(in.old_allocation.ptr == cast(Byte*, current_offset)); assert(in.old_allocation.ptr == cast(Byte*, current_offset));
vm->commit_used -= shrink_amount; vm->commit_used -= shrink_amount;
out->allocation = (Slice_Byte){ in.old_allocation.ptr, in.requested_size }; out->allocation = (Slice_Byte){ in.old_allocation.ptr, in.requested_size };
@@ -1154,14 +1204,13 @@ void arena_rewind(Arena* arena, AllocatorSP save_point) {
assert(save_point.type_sig == arena_allocator_proc); assert(save_point.type_sig == arena_allocator_proc);
SSIZE header_size = align_pow2(size_of(Arena), MEMORY_ALIGNMENT_DEFAULT); SSIZE header_size = align_pow2(size_of(Arena), MEMORY_ALIGNMENT_DEFAULT);
Arena* curr = arena->current; Arena* curr = arena->current;
VArena* backing = arena->backing;
SSIZE big_pos = clamp_bot(header_size, save_point.slot); SSIZE big_pos = clamp_bot(header_size, save_point.slot);
for (Arena* prev = nullptr; curr->base_pos >= big_pos; curr = prev) { for (Arena* prev = nullptr; curr->base_pos >= big_pos; curr = prev) {
prev = curr->prev; prev = curr->prev;
varena_release(curr->backing); varena_release(curr->backing);
} }
arena->current = curr; arena->current = curr;
SSIZE new_pos = big_pos - curr->pos; SSIZE new_pos = big_pos - curr->base_pos;
assert(new_pos <= curr->pos); assert(new_pos <= curr->pos);
curr->pos = new_pos; curr->pos = new_pos;
varena_rewind(curr->backing, (AllocatorSP){varena_allocator_proc, curr->pos}); varena_rewind(curr->backing, (AllocatorSP){varena_allocator_proc, curr->pos});
@@ -1218,7 +1267,7 @@ SSIZE kt1l__populate_slice_a2(KT1L_Byte* kt, KT1L_Info info, Slice_Byte values,
* kt = alloc_slice(info.backing, Byte, info.slot_size * num_values ); * kt = alloc_slice(info.backing, Byte, info.slot_size * num_values );
slice_assert(* kt); slice_assert(* kt);
SSIZE num_bytes = 0; SSIZE num_bytes = 0;
for (range_iter(U32, iter, 0, <, num_values)) { for (range_iter(SSIZE, iter, 0, <, num_values)) {
SSIZE slot_offset = iter.cursor * info.slot_size; SSIZE slot_offset = iter.cursor * info.slot_size;
Byte* slot_cursor = & kt->ptr[slot_offset]; Byte* slot_cursor = & kt->ptr[slot_offset];
Byte* a2_cursor = & values.ptr[iter.cursor * info.type_width * 2]; Byte* a2_cursor = & values.ptr[iter.cursor * info.type_width * 2];
@@ -1229,7 +1278,7 @@ SSIZE kt1l__populate_slice_a2(KT1L_Byte* kt, KT1L_Info info, Slice_Byte values,
Slice_Byte a2_key = { a2_cursor, info.type_width }; Slice_Byte a2_key = { a2_cursor, info.type_width };
Slice_Byte a2_value = { a2_cursor + info.type_width, info.type_width }; Slice_Byte a2_value = { a2_cursor + info.type_width, info.type_width };
slice_copy(slot_value, a2_value); slice_copy(slot_value, a2_value);
hash64_djb8(slot_key, a2_key); * slot_key = 0; hash64_djb8(slot_key, a2_key);
num_bytes += slot_value.len; num_bytes += slot_value.len;
} }
@@ -1294,10 +1343,10 @@ Slice_Byte kt1cx__get(KT1CX_Byte kt, U64 key, KT1CX_ByteMeta m) {
return slot_value; return slot_value;
} }
} }
Byte* next = slot_cursor + m.cell_next_offset; Byte* slot_next = slot_cursor + m.cell_next_offset;
if (next != nullptr) { if (slot_next != nullptr) {
slots.ptr = next; slots.ptr = slot_next;
slot_cursor = next; slot_cursor = slot_next;
goto process_slots; goto process_slots;
} }
else { else {
@@ -1305,9 +1354,9 @@ Slice_Byte kt1cx__get(KT1CX_Byte kt, U64 key, KT1CX_ByteMeta m) {
} }
} }
} }
Slice_Byte kt1cx__set(KT1CX_Byte* kt, U64 key, Slice_Byte value, AllocatorInfo backing_cells, KT1CX_ByteMeta m) { Slice_Byte kt1cx__set(KT1CX_Byte kt, U64 key, Slice_Byte value, AllocatorInfo backing_cells, KT1CX_ByteMeta m) {
U64 hash_index = kt1cx__slot_id(* kt, key, m); U64 hash_index = kt1cx__slot_id(kt, key, m);
Slice_Byte cell = { & kt->table.ptr[hash_index], m.cell_size}; Slice_Byte cell = { & kt.table.ptr[hash_index], m.cell_size};
{ {
Slice_Byte slots = {cell.ptr, m.cell_depth * m.slot_size}; Slice_Byte slots = {cell.ptr, m.cell_depth * m.slot_size};
Byte* slot_cursor = slots.ptr; Byte* slot_cursor = slots.ptr;
@@ -1325,18 +1374,20 @@ Slice_Byte kt1cx__set(KT1CX_Byte* kt, U64 key, Slice_Byte value, AllocatorInfo b
return slot_value; return slot_value;
} }
} }
Byte* next = slot_cursor + m.cell_next_offset; KT1CX_Byte_Cell curr_cell = { slot_cursor + m.cell_next_offset };
if (next != nullptr) { if ( curr_cell.next != nullptr) {
slots.ptr = next; slots.ptr = curr_cell.next;
slot_cursor = next; slot_cursor = curr_cell.next;
cell.ptr = curr_cell.next;
goto process_slots; goto process_slots;
} }
else { else {
cell = mem_alloc(backing_cells, m.cell_size); Slice_Byte new_cell = mem_alloc(backing_cells, m.cell_size);
KT1CX_Byte_Slot* slot = cast(KT1CX_Byte_Slot*, cell.ptr + m.slot_key_offset); curr_cell.next = new_cell.ptr;
KT1CX_Byte_Slot* slot = cast(KT1CX_Byte_Slot*, new_cell.ptr + m.slot_key_offset);
slot->occupied = true; slot->occupied = true;
slot->key = key; slot->key = key;
Slice_Byte slot_value = {cell.ptr, m.type_width}; Slice_Byte slot_value = {new_cell.ptr, m.type_width};
return slot_value; return slot_value;
} }
} }
@@ -1348,10 +1399,10 @@ Slice_Byte kt1cx__set(KT1CX_Byte* kt, U64 key, Slice_Byte value, AllocatorInfo b
#pragma region String Operations #pragma region String Operations
inline inline
char* str8_to_cstr_capped(Str8 content, Slice_Byte mem) { char* str8_to_cstr_capped(Str8 content, Slice_Byte mem) {
assert(mem.len > content.len); SSIZE copy_len = min(content.len, mem.len - 1);
memory_copy(mem.ptr, content.ptr, content.len); memory_copy(mem.ptr, content.ptr, copy_len);
mem.ptr[content.len] = '\0'; mem.ptr[copy_len] = '\0';
return mem.ptr; return cast(char*, mem.ptr);
} }
Str8 str8_from_u32(AllocatorInfo ainfo, U32 num, U32 radix, U8 min_digits, U8 digit_group_separator) Str8 str8_from_u32(AllocatorInfo ainfo, U32 num, U32 radix, U8 min_digits, U8 digit_group_separator)
{ {
@@ -1402,7 +1453,7 @@ Str8 str8_from_u32(AllocatorInfo ainfo, U32 num, U32 radix, U8 min_digits, U8 di
{ {
U32 num_reduce = num; U32 num_reduce = num;
U32 digits_until_separator = digit_group_size; U32 digits_until_separator = digit_group_size;
for (U32 idx = 0; idx < result.len; idx += 1) for (SSIZE idx = 0; idx < result.len; idx += 1)
{ {
SSIZE separator_pos = result.len - idx - 1; SSIZE separator_pos = result.len - idx - 1;
if (digits_until_separator == 0 && digit_group_separator != 0) { if (digits_until_separator == 0 && digit_group_separator != 0) {
@@ -1410,7 +1461,7 @@ Str8 str8_from_u32(AllocatorInfo ainfo, U32 num, U32 radix, U8 min_digits, U8 di
digits_until_separator = digit_group_size + 1; digits_until_separator = digit_group_size + 1;
} }
else { else {
result.ptr[separator_pos] = char_to_lower(integer_symbols(num_reduce % radix)); result.ptr[separator_pos] = char_to_lower(integer_symbols(cast(U8, num_reduce % radix)));
num_reduce /= radix; num_reduce /= radix;
} }
digits_until_separator -= 1; digits_until_separator -= 1;
@@ -1455,9 +1506,15 @@ Str8 str8__fmt_kt1l(AllocatorInfo ainfo, Slice_Byte buffer, KT1L_Str8 table, Str
{ {
UTF8* cursor_potential_token = cursor_fmt + 1; UTF8* cursor_potential_token = cursor_fmt + 1;
SSIZE potential_token_length = 0; SSIZE potential_token_length = 0;
while (* (cursor_potential_token + potential_token_length) != '>') { B32 fmt_overflow = false;
for (;;) {
UTF8* cursor = cursor_potential_token + potential_token_length;
fmt_overflow = cursor >= slice_end(fmt_template);
B32 found_terminator = * (cursor_potential_token + potential_token_length) != '>';
if (fmt_overflow || found_terminator) { break; }
++ potential_token_length; ++ potential_token_length;
} }
if (fmt_overflow) continue;
// Hashing the potential token and cross checking it with our token table // Hashing the potential token and cross checking it with our token table
U64 key = 0; hash64_djb8(& key, (Slice_Byte){ cast(void*, cursor_fmt + 1), potential_token_length}); U64 key = 0; hash64_djb8(& key, (Slice_Byte){ cast(void*, cursor_fmt + 1), potential_token_length});
Str8* value = nullptr; Str8* value = nullptr;
@@ -1476,7 +1533,7 @@ Str8 str8__fmt_kt1l(AllocatorInfo ainfo, Slice_Byte buffer, KT1L_Str8 table, Str
buffer = mem_grow(ainfo, buffer, buffer.len + potential_token_length); buffer = mem_grow(ainfo, buffer, buffer.len + potential_token_length);
} }
SSIZE left = value->len; SSIZE left = value->len;
char const* cursor_value = value->ptr; U8* cursor_value = value->ptr;
while (left && buffer_remaining) { while (left && buffer_remaining) {
* cursor_buffer = * cursor_value; * cursor_buffer = * cursor_value;
@@ -1513,7 +1570,7 @@ Str8 str8__fmt_backed(AllocatorInfo tbl_backing, AllocatorInfo buf_backing, Str8
Str8 str8__fmt(Str8 fmt_template, Slice_A2_Str8* entries) { Str8 str8__fmt(Str8 fmt_template, Slice_A2_Str8* entries) {
local_persist Byte tbl_mem[kilo(32)]; FArena tbl_arena = farena_make(slice_fmem(tbl_mem)); local_persist Byte tbl_mem[kilo(32)]; FArena tbl_arena = farena_make(slice_fmem(tbl_mem));
local_persist Byte buf_mem[kilo(128)]; local_persist Byte buf_mem[kilo(128)];
KT1L_Str8 kt = {0}; SSIZE num_bytes = kt1l_populate_slice_a2(Str8, kt, ainfo_farena(tbl_arena), *entries ); KT1L_Str8 kt = {0}; kt1l_populate_slice_a2(Str8, kt, ainfo_farena(tbl_arena), *entries );
Str8 result = str8__fmt_kt1l((AllocatorInfo){0}, slice_fmem(buf_mem), kt, fmt_template); Str8 result = str8__fmt_kt1l((AllocatorInfo){0}, slice_fmem(buf_mem), kt, fmt_template);
return result; return result;
} }
@@ -1547,7 +1604,8 @@ void str8cache__init(Str8Cache* cache, Opts_str8cache_init* opts) {
inline Str8Cache str8cache__make(Opts_str8cache_init* opts) { Str8Cache cache; str8cache__init(& cache, opts); return cache; } inline Str8Cache str8cache__make(Opts_str8cache_init* opts) { Str8Cache cache; str8cache__init(& cache, opts); return cache; }
inline inline
void str8cache_clear(KT1CX_Str8 kt) { void str8cache_clear(KT1CX_Str8 kt) {
kt1cx__clear(pcast(KT1CX_Byte, kt), (KT1CX_ByteMeta){ kt1cx_assert(kt);
kt1cx__clear(kt1cx_byte(kt), (KT1CX_ByteMeta){
.slot_size = size_of(KT1CX_Slot_Str8), .slot_size = size_of(KT1CX_Slot_Str8),
.slot_key_offset = offset_of(KT1CX_Slot_Str8, key), .slot_key_offset = offset_of(KT1CX_Slot_Str8, key),
.cell_next_offset = offset_of(KT1CX_Cell_Str8, next), .cell_next_offset = offset_of(KT1CX_Cell_Str8, next),
@@ -1559,7 +1617,8 @@ void str8cache_clear(KT1CX_Str8 kt) {
} }
inline inline
Str8 str8cache_get(KT1CX_Str8 kt, U64 key) { Str8 str8cache_get(KT1CX_Str8 kt, U64 key) {
Slice_Byte result = kt1cx__get(pcast(KT1CX_Byte, kt), key kt1cx_assert(kt);
Slice_Byte result = kt1cx__get(kt1cx_byte(kt), key
, (KT1CX_ByteMeta){ , (KT1CX_ByteMeta){
.slot_size = size_of(KT1CX_Slot_Str8), .slot_size = size_of(KT1CX_Slot_Str8),
.slot_key_offset = offset_of(KT1CX_Slot_Str8, key), .slot_key_offset = offset_of(KT1CX_Slot_Str8, key),
@@ -1572,12 +1631,12 @@ Str8 str8cache_get(KT1CX_Str8 kt, U64 key) {
return pcast(Str8, result); return pcast(Str8, result);
} }
inline inline
Str8 str8cache_set(KT1CX_Str8* kt, U64 key, Str8 value, AllocatorInfo str_reserve, AllocatorInfo backing_cells) { Str8 str8cache_set(KT1CX_Str8 kt, U64 key, Str8 value, AllocatorInfo str_reserve, AllocatorInfo backing_cells) {
assert(kt != nullptr); kt1cx_assert(kt);
slice_assert(value);
assert(str_reserve.proc != nullptr); assert(str_reserve.proc != nullptr);
assert(backing_cells.proc != nullptr); assert(backing_cells.proc != nullptr);
slice_assert(value); Slice_Byte entry = kt1cx__set(kt1cx_byte(kt), key, slice_byte(value), backing_cells, (KT1CX_ByteMeta){
Slice_Byte entry = kt1cx__set(pcast(KT1CX_Byte*, kt), key, slice_byte(value), backing_cells, (KT1CX_ByteMeta){
.slot_size = size_of(KT1CX_Slot_Str8), .slot_size = size_of(KT1CX_Slot_Str8),
.slot_key_offset = offset_of(KT1CX_Slot_Str8, key), .slot_key_offset = offset_of(KT1CX_Slot_Str8, key),
.cell_next_offset = offset_of(KT1CX_Cell_Str8, next), .cell_next_offset = offset_of(KT1CX_Cell_Str8, next),
@@ -1597,8 +1656,9 @@ Str8 str8cache_set(KT1CX_Str8* kt, U64 key, Str8 value, AllocatorInfo str_reserv
} }
inline inline
Str8 cache_str8(Str8Cache* cache, Str8 str) { Str8 cache_str8(Str8Cache* cache, Str8 str) {
assert(cache != nullptr);
U64 key = 0; hash64_djb8(& key, slice_byte(str)); U64 key = 0; hash64_djb8(& key, slice_byte(str));
Str8 result = str8cache_set(& cache->kt, key, str, cache->str_reserve, cache->cell_reserve); Str8 result = str8cache_set(cache->kt, key, str, cache->str_reserve, cache->cell_reserve);
return result; return result;
} }
@@ -1618,15 +1678,18 @@ void str8gen_append_str8(Str8Gen* gen, Str8 str){
Slice_Byte result = mem_grow(gen->backing, str8gen_slice_byte(* gen), str.len + gen->len); Slice_Byte result = mem_grow(gen->backing, str8gen_slice_byte(* gen), str.len + gen->len);
slice_assert(result); slice_assert(result);
Slice_Byte to_copy = { result.ptr + gen->len, result.len - gen->len }; Slice_Byte to_copy = { result.ptr + gen->len, result.len - gen->len };
slice_copy(to_copy, str); slice_copy(to_copy, slice_byte(str));
gen->ptr = cast(UTF8*, result.ptr); gen->len = result.len; gen->ptr = cast(UTF8*, result.ptr); gen->len = result.len;
} }
void str8gen__append_fmt(Str8Gen* gen, Str8 fmt_template, Slice_A2_Str8* entries){ void str8gen__append_fmt(Str8Gen* gen, Str8 fmt_template, Slice_A2_Str8* entries){
local_persist Byte tbl_mem[kilo(32)]; FArena tbl_arena = farena_make(slice_fmem(tbl_mem)); local_persist Byte tbl_mem[kilo(32)]; FArena tbl_arena = farena_make(slice_fmem(tbl_mem));
KT1L_Str8 kt = {0}; SSIZE num_bytes = kt1l_populate_slice_a2(Str8, kt, ainfo_farena(tbl_arena), *entries ); KT1L_Str8 kt = {0}; kt1l_populate_slice_a2(Str8, kt, ainfo_farena(tbl_arena), *entries );
Slice_Byte buffer = { gen->ptr + gen->len, gen->cap - gen->len }; Slice_Byte buffer = { gen->ptr + gen->len, gen->cap - gen->len };
if (buffer.len < kilo(16)) { if (buffer.len < kilo(16)) {
Slice_Byte result = mem_grow(gen->backing, str8gen_slice_byte(* gen), kilo(16) + gen->cap ); Slice_Byte result = mem_grow(gen->backing, str8gen_slice_byte(* gen), kilo(16) + gen->cap );
slice_assert(result);
gen->ptr = result.ptr;
gen->cap = result.len;
buffer = (Slice_Byte){ cast(Byte*, gen->ptr + gen->len), gen->cap - gen->len }; buffer = (Slice_Byte){ cast(Byte*, gen->ptr + gen->len), gen->cap - gen->len };
} }
Str8 result = str8__fmt_kt1l(gen->backing, buffer, kt, fmt_template); Str8 result = str8__fmt_kt1l(gen->backing, buffer, kt, fmt_template);
@@ -1681,7 +1744,7 @@ void api_file_read_contents(FileOpInfo* result, Str8 path, Opts_read_file_conten
// Backing is required at this point // Backing is required at this point
assert(opts.backing.proc != nullptr); assert(opts.backing.proc != nullptr);
// This will limit a path for V1 to be 32kb worth of codepoints. // This will limit a path for V1 to be 32kb worth of codepoints.
local_persist U8 scratch[kilo(32)]; local_persist U8 scratch[kilo(64)];
char const* path_cstr = str8_to_cstr_capped(path, slice_fmem(scratch) ); char const* path_cstr = str8_to_cstr_capped(path, slice_fmem(scratch) );
MS_HANDLE id_file = CreateFileA( MS_HANDLE id_file = CreateFileA(
path_cstr, path_cstr,
@@ -1718,7 +1781,7 @@ void api_file_read_contents(FileOpInfo* result, Str8 path, Opts_read_file_conten
MS_BOOL read_result = ReadFile( MS_BOOL read_result = ReadFile(
id_file, id_file,
buffer.ptr, buffer.ptr,
file_size.QuadPart, cast(MS_DWORD, file_size.QuadPart),
& amount_read, & amount_read,
nullptr nullptr
); );
@@ -1736,7 +1799,7 @@ void api_file_read_contents(FileOpInfo* result, Str8 path, Opts_read_file_conten
void file_write_str8(Str8 path, Str8 content) void file_write_str8(Str8 path, Str8 content)
{ {
slice_assert(path); slice_assert(path);
Byte scratch[kilo(16)] = {0}; Byte scratch[kilo(64)] = {0};
char const* path_cstr = str8_to_cstr_capped(path, slice_fmem(scratch)); char const* path_cstr = str8_to_cstr_capped(path, slice_fmem(scratch));
MS_HANDLE id_file = CreateFileA( MS_HANDLE id_file = CreateFileA(
path_cstr, path_cstr,
@@ -1756,7 +1819,7 @@ void file_write_str8(Str8 path, Str8 content)
MS_DWORD bytes_written = 0; MS_DWORD bytes_written = 0;
B32 status = WriteFile(id_file B32 status = WriteFile(id_file
, cast(void*, content.ptr) , cast(void*, content.ptr)
, cast(USIZE, content.len) , cast(MS_DWORD, content.len)
, & bytes_written , & bytes_written
, nullptr , nullptr
); );
@@ -1825,8 +1888,8 @@ void assert_handler( char const* condition, char const* file, char const* functi
#pragma region WATL #pragma region WATL
void api_watl_lex(WATL_LexInfo* info, Str8 source, Opts_watl_lex* opts) void api_watl_lex(WATL_LexInfo* info, Str8 source, Opts_watl_lex* opts)
{ {
if (source.len == 0) { return; }
assert(info != nullptr); assert(info != nullptr);
slice_assert(source);
assert(opts != nullptr); assert(opts != nullptr);
assert(opts->ainfo_msgs.proc != nullptr); assert(opts->ainfo_msgs.proc != nullptr);
assert(opts->ainfo_toks.proc != nullptr); assert(opts->ainfo_toks.proc != nullptr);
@@ -1835,7 +1898,7 @@ void api_watl_lex(WATL_LexInfo* info, Str8 source, Opts_watl_lex* opts)
UTF8* end = source.ptr + source.len; UTF8* end = source.ptr + source.len;
UTF8* cursor = source.ptr; UTF8* cursor = source.ptr;
UTF8* prev = source.ptr; UTF8* prev = source.ptr - 1;
UTF8 code = * cursor; UTF8 code = * cursor;
B32 was_formatting = true; B32 was_formatting = true;
WATL_Tok* tok = nullptr; WATL_Tok* tok = nullptr;
@@ -1895,35 +1958,38 @@ void api_watl_lex(WATL_LexInfo* info, Str8 source, Opts_watl_lex* opts)
if (num_bytes > start_snapshot.left) { if (num_bytes > start_snapshot.left) {
info->signal |= WATL_LexStatus_MemFail_SliceConstraintFail; info->signal |= WATL_LexStatus_MemFail_SliceConstraintFail;
WATL_LexMsg* msg = alloc_type(opts->ainfo_msgs, WATL_LexMsg); WATL_LexMsg* msg = alloc_type(opts->ainfo_msgs, WATL_LexMsg);
assert(msg != nullptr);
msg->pos = (WATL_Pos){ -1, -1 }; msg->pos = (WATL_Pos){ -1, -1 };
msg->tok = tok; msg->tok = tok;
msg->content = lit("Token slice allocation was not contiguous"); msg->content = lit("Token slice allocation was not contiguous");
sll_queue_push_n(info->msgs, msg_last, msg, next); sll_queue_push_n(info->msgs, msg_last, msg, next);
assert(opts->failon_slice_constraint_fail == false); assert(opts->failon_slice_constraint_fail == false);
} }
assert(tok != nullptr);
assert(num > 0);
info->toks.ptr = tok - num; info->toks.ptr = tok - num;
info->toks.len = num; info->toks.len = num;
} }
WATL_LexInfo watl__lex(Str8 source, Opts_watl_lex* opts) { WATL_LexInfo info; api_watl_lex(& info, source, opts); return info; } WATL_LexInfo watl__lex(Str8 source, Opts_watl_lex* opts) { WATL_LexInfo info = {0}; api_watl_lex(& info, source, opts); return info; }
Str8 watl_tok_str8(Slice_WATL_Tok toks, WATL_Tok* tok) { Str8 str8_from_watl_tok(Slice_WATL_Tok toks, WATL_Tok* tok) {
WATL_Tok* next = tok + 1; SSIZE start = cast(SSIZE, toks.ptr->code);
USIZE start = cast(USIZE, toks.ptr->code); SSIZE curr = cast(SSIZE, tok->code);
USIZE curr = cast(USIZE, tok->code); SSIZE offset = curr - start;
USIZE offset = curr - start; SSIZE left = cast(SSIZE, toks.ptr + toks.len) - offset;
SSIZE left = toks.len - offset; B32 last_tok = tok == & toks.ptr[toks.len - 1]; // Check to see if this token's end is also the end of the slice:
B32 last_tok = (start + toks.len) == (curr + left);
Str8 text = {0}; Str8 text = {0};
text.ptr = tok->code; text.ptr = tok->code;
text.len = next > (toks.ptr + toks.len) ? text.len = last_tok ?
left left
// Othwerise its the last minus the curr. // Othwerise its the next minus the curr.
: cast(SSIZE, next->code - tok->code); : cast(SSIZE, (tok + 1)->code - tok->code);
return text; return text;
} }
void api_watl_parse(WATL_ParseInfo* info, Slice_WATL_Tok tokens, Opts_watl_parse* opts) void api_watl_parse(WATL_ParseInfo* info, Slice_WATL_Tok tokens, Opts_watl_parse* opts)
{ {
if (tokens.len == 0) { return; }
assert(opts != nullptr); assert(opts != nullptr);
assert(opts->ainfo_lines.proc != nullptr); assert(opts->ainfo_lines.proc != nullptr);
assert(opts->ainfo_msgs.proc != nullptr); assert(opts->ainfo_msgs.proc != nullptr);
@@ -1946,12 +2012,12 @@ void api_watl_parse(WATL_ParseInfo* info, Slice_WATL_Tok tokens, Opts_watl_parse
case WATL_Tok_LineFeed: case WATL_Tok_LineFeed:
{ {
AllocatorProc_Out end_nodes_snapshot; { opts->ainfo_nodes.proc((AllocatorProc_In){.op = AllocatorOp_Query}, & end_nodes_snapshot); } AllocatorProc_Out end_nodes_snapshot; { opts->ainfo_nodes.proc((AllocatorProc_In){.op = AllocatorOp_Query}, & end_nodes_snapshot); }
SSIZE distance_nodes = end_nodes_snapshot.left - end_nodes_snapshot.save_point.slot; SSIZE distance_nodes = end_nodes_snapshot.save_point.slot - start_nodes_snapshot.save_point.slot;
if (distance_nodes > start_lines_snapshot.left) { if (distance_nodes > start_lines_snapshot.left) {
info->signal |= WATL_ParseStatus_MemFail_SliceConstraintFail; info->signal |= WATL_ParseStatus_MemFail_SliceConstraintFail;
WATL_ParseMsg* msg = alloc_type(opts->ainfo_msgs, WATL_ParseMsg); WATL_ParseMsg* msg = alloc_type(opts->ainfo_msgs, WATL_ParseMsg);
msg->content = lit("Nodes slice allocation was not contiguous"); msg->content = lit("Nodes slice allocation was not contiguous");
msg->pos = (WATL_Pos){info->lines.len, line->len}; msg->pos = (WATL_Pos){cast(S32, info->lines.len), cast(S32, line->len)};
msg->line = line; msg->line = line;
msg->tok = token; msg->tok = token;
sll_queue_push_n(info->msgs, msg_last, msg, next); sll_queue_push_n(info->msgs, msg_last, msg, next);
@@ -1969,7 +2035,7 @@ void api_watl_parse(WATL_ParseInfo* info, Slice_WATL_Tok tokens, Opts_watl_parse
default: default:
break; break;
} }
Str8 tok_str = watl_tok_str8(tokens, token); Str8 tok_str = str8_from_watl_tok(tokens, token);
* curr = cache_str8(opts->str_cache, tok_str); * curr = cache_str8(opts->str_cache, tok_str);
curr = alloc_type(opts->ainfo_nodes, WATL_Node); curr = alloc_type(opts->ainfo_nodes, WATL_Node);
* curr = (WATL_Node){0}; * curr = (WATL_Node){0};
@@ -1978,7 +2044,7 @@ void api_watl_parse(WATL_ParseInfo* info, Slice_WATL_Tok tokens, Opts_watl_parse
} }
AllocatorProc_Out end_lines_snapshot; { opts->ainfo_lines.proc((AllocatorProc_In){.op = AllocatorOp_Query}, & end_lines_snapshot); } AllocatorProc_Out end_lines_snapshot; { opts->ainfo_lines.proc((AllocatorProc_In){.op = AllocatorOp_Query}, & end_lines_snapshot); }
SSIZE distance_lines = end_lines_snapshot.left - start_lines_snapshot.save_point.slot; SSIZE distance_lines = end_lines_snapshot.save_point.slot - start_lines_snapshot.save_point.slot;
if (distance_lines > start_lines_snapshot.left) { if (distance_lines > start_lines_snapshot.left) {
info->signal |= WATL_ParseStatus_MemFail_SliceConstraintFail; info->signal |= WATL_ParseStatus_MemFail_SliceConstraintFail;
WATL_ParseMsg* msg = alloc_type(opts->ainfo_msgs, WATL_ParseMsg); WATL_ParseMsg* msg = alloc_type(opts->ainfo_msgs, WATL_ParseMsg);
@@ -1989,7 +2055,7 @@ void api_watl_parse(WATL_ParseInfo* info, Slice_WATL_Tok tokens, Opts_watl_parse
return; return;
} }
} }
WATL_ParseInfo watl__parse(Slice_WATL_Tok tokens, Opts_watl_parse* opts) { WATL_ParseInfo info; api_watl_parse(& info, tokens, opts); return info; } WATL_ParseInfo watl__parse(Slice_WATL_Tok tokens, Opts_watl_parse* opts) { WATL_ParseInfo info = {0}; api_watl_parse(& info, tokens, opts); return info; }
Str8 watl_dump_listing(AllocatorInfo buffer, Slice_WATL_Line lines) Str8 watl_dump_listing(AllocatorInfo buffer, Slice_WATL_Line lines)
{ {
@@ -2002,7 +2068,7 @@ Str8 watl_dump_listing(AllocatorInfo buffer, Slice_WATL_Line lines)
#define fmt_entry(label, value) { lit(label), value } #define fmt_entry(label, value) { lit(label), value }
++ line_num; ++ line_num;
Str8 str_line_num = str8_from_u32(sinfo, line_num, 10, 0, 0); Str8 str_line_num = str8_from_u32(sinfo, line_num, 10, 0, 0);
Str8 str_chunk_num = str8_from_u32(sinfo, line->len, 10, 0, 0); Str8 str_chunk_num = str8_from_u32(sinfo, cast(U32, line->len), 10, 0, 0);
str8gen_append_fmt(& result, "Line <line_num> - Chunks <chunk_num>:\n" str8gen_append_fmt(& result, "Line <line_num> - Chunks <chunk_num>:\n"
, fmt_entry("line_num", str_line_num) , fmt_entry("line_num", str_line_num)
, fmt_entry("chunk_num", str_chunk_num) , fmt_entry("chunk_num", str_chunk_num)
@@ -2016,7 +2082,7 @@ Str8 watl_dump_listing(AllocatorInfo buffer, Slice_WATL_Line lines)
case WATL_Tok_Tab: id = lit("Tab"); break; case WATL_Tok_Tab: id = lit("Tab"); break;
default: id = lit("Visible"); break; default: id = lit("Visible"); break;
} }
Str8 str_chunk_len = str8_from_u32(sinfo, chunk->len, 10, 0, 0); Str8 str_chunk_len = str8_from_u32(sinfo, cast(U32, chunk->len), 10, 0, 0);
str8gen_append_fmt(& result, "\t<id>(<size>): '<chunk>'\n" str8gen_append_fmt(& result, "\t<id>(<size>): '<chunk>'\n"
, fmt_entry("id", id) , fmt_entry("id", id)
, fmt_entry("size", str_chunk_len) , fmt_entry("size", str_chunk_len)
@@ -2024,7 +2090,6 @@ Str8 watl_dump_listing(AllocatorInfo buffer, Slice_WATL_Line lines)
); );
} }
farena_reset(& sarena); farena_reset(& sarena);
#undef push_str8_u32
#undef fmt_entry_u32 #undef fmt_entry_u32
} }
return (Str8){ result.ptr, result.len }; return (Str8){ result.ptr, result.len };
@@ -2033,12 +2098,15 @@ Str8 watl_dump_listing(AllocatorInfo buffer, Slice_WATL_Line lines)
#pragma endregion Implementation #pragma endregion Implementation
int main() #pragma warning(push)
#pragma warning(disable: 4101)
int main(void)
{ {
os_init(); os_init();
VArena* vm_file = varena_make(.reserve_size = giga(4), .flags = VArenaFlag_NoLargePages); VArena* vm_file = varena_make(.reserve_size = giga(4), .flags = VArenaFlag_NoLargePages);
FileOpInfo file = file_read_contents(lit("watl.v0.msvc.c"), .backing = ainfo_varena(vm_file)); FileOpInfo file = file_read_contents(lit("watl.v0.msvc.c"), .backing = ainfo_varena(vm_file));
slice_assert(file.content);
Arena* a_msgs = arena_make(); Arena* a_msgs = arena_make();
Arena* a_toks = arena_make(); Arena* a_toks = arena_make();
@@ -2046,14 +2114,14 @@ int main()
.ainfo_msgs = ainfo_arena(a_msgs), .ainfo_msgs = ainfo_arena(a_msgs),
.ainfo_toks = ainfo_arena(a_toks), .ainfo_toks = ainfo_arena(a_toks),
); );
assert(lex_res.signal & WATL_LexStatus_MemFail_SliceConstraintFail); assert((lex_res.signal & WATL_LexStatus_MemFail_SliceConstraintFail) == 0);
Arena* str_cache_kt1_ainfo = arena_make(); Arena* str_cache_kt1_ainfo = arena_make();
Str8Cache str_cache = str8cache_make( Str8Cache str_cache = str8cache_make(
.str_reserve = ainfo_arena(arena_make()), .str_reserve = ainfo_arena(arena_make()),
.cell_reserve = ainfo_arena(str_cache_kt1_ainfo), .cell_reserve = ainfo_arena(str_cache_kt1_ainfo),
.tbl_backing = ainfo_arena(str_cache_kt1_ainfo), .tbl_backing = ainfo_arena(str_cache_kt1_ainfo),
.cell_pool_amnt = kilo(4), .cell_pool_size = kilo(4),
.table_size = kilo(32), .table_size = kilo(32),
); );
@@ -2064,10 +2132,11 @@ int main()
.ainfo_lines = ainfo_arena(a_lines), .ainfo_lines = ainfo_arena(a_lines),
.str_cache = & str_cache .str_cache = & str_cache
); );
assert(parse_res.signal & WATL_ParseStatus_MemFail_SliceConstraintFail); assert((parse_res.signal & WATL_ParseStatus_MemFail_SliceConstraintFail) == 0);
arena_reset(a_msgs); arena_reset(a_msgs);
arena_reset(a_toks); arena_reset(a_toks);
Str8 listing = watl_dump_listing(ainfo_arena(a_msgs), parse_res.lines); Str8 listing = watl_dump_listing(ainfo_arena(a_msgs), parse_res.lines);
return 0; return 0;
} }
#pragma warning(pop)

View File

@@ -11,6 +11,7 @@ if ($IsWindows) {
# https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170 # https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170
$flag_all_c = '/TC' $flag_all_c = '/TC'
$flag_c11 = '/std:c11' $flag_c11 = '/std:c11'
$flag_c23 = '/std:c23'
$flag_all_cpp = '/TP' $flag_all_cpp = '/TP'
$flag_compile = '/c' $flag_compile = '/c'
$flag_charset_utf8 = '/utf-8' $flag_charset_utf8 = '/utf-8'
@@ -84,7 +85,14 @@ $compiler_args += $flag_RTTI_disabled
$compiler_args += $flag_preprocess_conform $compiler_args += $flag_preprocess_conform
$compiler_args += $flag_sanitize_address $compiler_args += $flag_sanitize_address
$compiler_args += $flag_wall
# Set charset encoding for both execution and source to UTF-8 # Set charset encoding for both execution and source to UTF-8
$compiler_args += $flag_charset_utf8
# Specifing output pathing
$compiler_args += ( $flag_path_interm + $path_build + '\' )
$compiler_args += ( $flag_path_output + $path_build + '\' )
# Dump preprocess file # Dump preprocess file
if ($false) { if ($false) {
@@ -95,15 +103,12 @@ if ($false) {
# Diagnostic logging # Diagnostic logging
$compiler_args += $flag_full_src_path $compiler_args += $flag_full_src_path
# Specifing output pathing $compiler_args += $flag_optimize_intrinsics
$compiler_args += ( $flag_path_interm + $path_build + '\' ) # $compiler_args += $flag_no_optimization
$compiler_args += ( $flag_path_output + $path_build + '\' )
$compiler_args += $flag_no_optimization
# Debug setup # Debug setup
$compiler_args += $flag_debug
$compiler_args += ($flag_define + 'BUILD_DEBUG') $compiler_args += ($flag_define + 'BUILD_DEBUG')
$compiler_args += $flag_debug
$compiler_args += ( $flag_path_debug + $path_build + '\' ) $compiler_args += ( $flag_path_debug + $path_build + '\' )
$compiler_args += $flag_link_win_rt_static_debug $compiler_args += $flag_link_win_rt_static_debug
@@ -118,9 +123,6 @@ $compiler_args += $flag_compile, $unit
$compiler_args | ForEach-Object { Write-Host $_ } $compiler_args | ForEach-Object { Write-Host $_ }
write-host write-host
# $compiler_args += ( $flag_define + 'DEMO_STR_SLICE' )
# $compiler_args += ( $flag_define + 'DEMO__FILE_READ_CONTENTS_V1' )
# Compile the unit # Compile the unit
& $compiler $compiler_args & $compiler $compiler_args