Pull in changes from internal project
This commit is contained in:
parent
765b8255f7
commit
6b403eae71
@ -1,3 +1,4 @@
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$$$$$\ $$$$$$$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$\ $$$$$$$$\
|
||||
@ -12,6 +13,7 @@
|
||||
// dqn_cpp_file.h -- Functions to emit C++ formatted code
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
#if !defined(DQN_CPP_FILE_H)
|
||||
#define DQN_CPP_FILE_H
|
||||
|
||||
|
@ -13,7 +13,7 @@ pushd Build
|
||||
REM O2 Optimisation Level 2
|
||||
REM Oi Use CPU Intrinsics
|
||||
REM Z7 Combine multi-debug files to one debug file
|
||||
set common_flags=-D DQN_WITH_UNIT_TESTS -D DQN_UNIT_TESTS_WITH_MAIN -D DQN_UNIT_TESTS_WITH_KECCAK -D DQN_USE_STD_PRINTF %script_dir%\dqn.cpp
|
||||
set common_flags=-D DQN_UNIT_TESTS_WITH_MAIN -D DQN_UNIT_TESTS_WITH_KECCAK -D DQN_USE_STD_PRINTF /Tp %script_dir%\dqn.cpp
|
||||
|
||||
set msvc_driver_flags=%common_flags% -MT -EHa -GR- -Od -Oi -Z7 -wd4201 -W4 -nologo
|
||||
|
||||
|
14
dqn.cpp
14
dqn.cpp
@ -21,7 +21,17 @@
|
||||
#if !defined(DQN_NO_METADESK)
|
||||
DQN_MSVC_WARNING_PUSH
|
||||
DQN_MSVC_WARNING_DISABLE(4505) // warning C4505: '<function>': unreferenced function with internal linkage has been removed
|
||||
|
||||
DQN_GCC_WARNING_PUSH
|
||||
DQN_GCC_WARNING_DISABLE(-Wwrite-strings)
|
||||
DQN_GCC_WARNING_DISABLE(-Wunused-but-set-variable)
|
||||
DQN_GCC_WARNING_DISABLE(-Wsign-compare)
|
||||
DQN_GCC_WARNING_DISABLE(-Wunused-function)
|
||||
DQN_GCC_WARNING_DISABLE(-Wunused-result)
|
||||
|
||||
#include "External/metadesk/md.c"
|
||||
|
||||
DQN_GCC_WARNING_POP
|
||||
DQN_MSVC_WARNING_POP
|
||||
#endif
|
||||
#define DQN_CPP_FILE_IMPLEMENTATION
|
||||
@ -34,13 +44,13 @@
|
||||
#endif
|
||||
|
||||
#include "dqn_base.cpp"
|
||||
#include "dqn_thread_context.cpp"
|
||||
#include "dqn_external.cpp"
|
||||
#include "dqn_allocator.cpp"
|
||||
#include "dqn_debug.cpp"
|
||||
#include "dqn_string.cpp"
|
||||
#include "dqn_containers.cpp"
|
||||
#include "dqn_type_info.cpp"
|
||||
#include "dqn_os.cpp"
|
||||
|
||||
#if defined(DQN_PLATFORM_EMSCRIPTEN) || defined(DQN_PLATFORM_POSIX) || defined(DQN_PLATFORM_ARM64)
|
||||
#include "dqn_os_posix.cpp"
|
||||
@ -50,7 +60,7 @@
|
||||
#error Please define a platform e.g. 'DQN_PLATFORM_WIN32' to enable the correct implementation for platform APIs
|
||||
#endif
|
||||
|
||||
#include "dqn_os.cpp"
|
||||
#include "dqn_tls.cpp"
|
||||
#include "dqn_math.cpp"
|
||||
#include "dqn_hash.cpp"
|
||||
#include "dqn_helpers.cpp"
|
||||
|
11
dqn.h
11
dqn.h
@ -126,7 +126,7 @@
|
||||
//
|
||||
// Allocations are stored in a global hash-table and their respective stack
|
||||
// traces for the allocation location. Memory leaks can be dumped at the end
|
||||
// of the program or some epoch by calling Dqn_Library_DumpLeaks()
|
||||
// of the program or some epoch by calling Dqn_Debug_DumpLeaks()
|
||||
//
|
||||
// #define DQN_LEAK_TRACKING
|
||||
//
|
||||
@ -300,17 +300,14 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define DQN_UNDO_CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#define MD_DEFAULT_SPRINTF 0
|
||||
#define MD_IMPL_Vsnprintf DQN_VSNPRINTF
|
||||
#include "External/metadesk/md.h"
|
||||
#if defined(DQN_UNDO_CRT_SECURE_NO_WARNINGS)
|
||||
#undef _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Metadesk includes 'stb_sprintf.h' already
|
||||
#if !defined(DQN_STB_SPRINTF_HEADER_ONLY)
|
||||
#define DQN_STB_SPRINTF_HEADER_ONLY
|
||||
#endif
|
||||
|
||||
// Metadesk includes Windows.h
|
||||
#define DQN_NO_WIN32_MIN_HEADER
|
||||
#endif
|
||||
@ -321,7 +318,7 @@
|
||||
#include "dqn_win32.h"
|
||||
#endif
|
||||
#include "dqn_allocator.h"
|
||||
#include "dqn_thread_context.h"
|
||||
#include "dqn_tls.h"
|
||||
#include "dqn_debug.h"
|
||||
#include "dqn_string.h"
|
||||
#include "dqn_containers.h"
|
||||
|
@ -56,11 +56,28 @@ DQN_API Dqn_ArenaBlock *Dqn_Arena_BlockInitFlags(uint64_t reserve, uint64_t comm
|
||||
return result;
|
||||
}
|
||||
|
||||
static void Dqn_Arena_UpdateStatsOnNewBlock_(Dqn_Arena *arena, Dqn_ArenaBlock const *block)
|
||||
{
|
||||
DQN_ASSERT(arena);
|
||||
if (block) {
|
||||
arena->stats.info.used += block->used;
|
||||
arena->stats.info.commit += block->commit;
|
||||
arena->stats.info.reserve += block->reserve;
|
||||
arena->stats.info.blocks += 1;
|
||||
|
||||
arena->stats.hwm.used = DQN_MAX(arena->stats.hwm.used, arena->stats.info.used);
|
||||
arena->stats.hwm.commit = DQN_MAX(arena->stats.hwm.commit, arena->stats.info.commit);
|
||||
arena->stats.hwm.reserve = DQN_MAX(arena->stats.hwm.reserve, arena->stats.info.reserve);
|
||||
arena->stats.hwm.blocks = DQN_MAX(arena->stats.hwm.blocks, arena->stats.info.blocks);
|
||||
}
|
||||
}
|
||||
|
||||
DQN_API Dqn_Arena Dqn_Arena_InitSize(uint64_t reserve, uint64_t commit, uint8_t flags)
|
||||
{
|
||||
Dqn_Arena result = {};
|
||||
result.flags = flags;
|
||||
result.curr = Dqn_Arena_BlockInitFlags(reserve, commit, flags);
|
||||
Dqn_Arena_UpdateStatsOnNewBlock_(&result, result.curr);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -123,8 +140,10 @@ DQN_API void *Dqn_Arena_Alloc(Dqn_Arena *arena, uint64_t size, uint8_t align, Dq
|
||||
if (!arena)
|
||||
return nullptr;
|
||||
|
||||
if (!arena->curr)
|
||||
if (!arena->curr) {
|
||||
arena->curr = Dqn_Arena_BlockInitFlags(DQN_ARENA_RESERVE_SIZE, DQN_ARENA_COMMIT_SIZE, arena->flags);
|
||||
Dqn_Arena_UpdateStatsOnNewBlock_(arena, arena->curr);
|
||||
}
|
||||
|
||||
if (!arena->curr)
|
||||
return nullptr;
|
||||
@ -147,6 +166,7 @@ DQN_API void *Dqn_Arena_Alloc(Dqn_Arena *arena, uint64_t size, uint8_t align, Dq
|
||||
new_block->prev = arena->curr;
|
||||
arena->curr = new_block;
|
||||
new_block->reserve_sum = new_block->prev->reserve_sum + new_block->prev->reserve;
|
||||
Dqn_Arena_UpdateStatsOnNewBlock_(arena, arena->curr);
|
||||
goto try_alloc_again;
|
||||
}
|
||||
|
||||
@ -159,11 +179,16 @@ DQN_API void *Dqn_Arena_Alloc(Dqn_Arena *arena, uint64_t size, uint8_t align, Dq
|
||||
return nullptr;
|
||||
if (poison)
|
||||
Dqn_ASAN_PoisonMemoryRegion(commit_ptr, commit_size);
|
||||
curr->commit = end_commit;
|
||||
curr->commit = end_commit;
|
||||
arena->stats.info.commit += commit_size;
|
||||
arena->stats.hwm.commit = DQN_MAX(arena->stats.hwm.commit, arena->stats.info.commit);
|
||||
}
|
||||
|
||||
void *result = DQN_CAST(char *) curr + offset_pos;
|
||||
curr->used = end_pos;
|
||||
void *result = DQN_CAST(char *) curr + offset_pos;
|
||||
Dqn_usize alloc_size = end_pos - curr->used;
|
||||
curr->used += alloc_size;
|
||||
arena->stats.info.used += alloc_size;
|
||||
arena->stats.hwm.used = DQN_MAX(arena->stats.hwm.used, arena->stats.info.used);
|
||||
Dqn_ASAN_UnpoisonMemoryRegion(result, size);
|
||||
|
||||
if (zero_mem == Dqn_ZeroMem_Yes) {
|
||||
@ -171,6 +196,10 @@ DQN_API void *Dqn_Arena_Alloc(Dqn_Arena *arena, uint64_t size, uint8_t align, Dq
|
||||
DQN_MEMSET(result, 0, reused_bytes);
|
||||
}
|
||||
|
||||
DQN_ASSERT(arena->stats.hwm.used >= arena->stats.info.used);
|
||||
DQN_ASSERT(arena->stats.hwm.commit >= arena->stats.info.commit);
|
||||
DQN_ASSERT(arena->stats.hwm.reserve >= arena->stats.info.reserve);
|
||||
DQN_ASSERT(arena->stats.hwm.blocks >= arena->stats.info.blocks);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -195,21 +224,27 @@ DQN_API void *Dqn_Arena_Copy(Dqn_Arena *arena, void const *data, uint64_t size,
|
||||
|
||||
DQN_API void Dqn_Arena_PopTo(Dqn_Arena *arena, uint64_t init_used)
|
||||
{
|
||||
if (!arena)
|
||||
if (!arena || !arena->curr)
|
||||
return;
|
||||
uint64_t used = DQN_MAX(DQN_ARENA_HEADER_SIZE, init_used);
|
||||
Dqn_ArenaBlock *curr = arena->curr;
|
||||
while (curr->reserve_sum >= used) {
|
||||
Dqn_ArenaBlock *block_to_free = curr;
|
||||
arena->stats.info.used -= block_to_free->used;
|
||||
arena->stats.info.commit -= block_to_free->commit;
|
||||
arena->stats.info.reserve -= block_to_free->reserve;
|
||||
arena->stats.info.blocks -= 1;
|
||||
curr = curr->prev;
|
||||
Dqn_Arena_BlockDeinit_(arena, block_to_free);
|
||||
}
|
||||
|
||||
arena->curr = curr;
|
||||
curr->used = used - curr->reserve_sum;
|
||||
char *poison_ptr = (char *)curr + Dqn_AlignUpPowerOfTwo(curr->used, DQN_ASAN_POISON_ALIGNMENT);
|
||||
Dqn_usize poison_size = ((char *)curr + curr->commit) - poison_ptr;
|
||||
arena->stats.info.used -= curr->used;
|
||||
arena->curr = curr;
|
||||
curr->used = used - curr->reserve_sum;
|
||||
char *poison_ptr = (char *)curr + Dqn_AlignUpPowerOfTwo(curr->used, DQN_ASAN_POISON_ALIGNMENT);
|
||||
Dqn_usize poison_size = ((char *)curr + curr->commit) - poison_ptr;
|
||||
Dqn_ASAN_PoisonMemoryRegion(poison_ptr, poison_size);
|
||||
arena->stats.info.used += curr->used;
|
||||
}
|
||||
|
||||
DQN_API void Dqn_Arena_Pop(Dqn_Arena *arena, uint64_t amount)
|
||||
@ -237,7 +272,7 @@ DQN_API bool Dqn_Arena_OwnsPtr(Dqn_Arena const *arena, void *ptr)
|
||||
{
|
||||
bool result = false;
|
||||
uintptr_t uint_ptr = DQN_CAST(uintptr_t)ptr;
|
||||
for (Dqn_ArenaBlock const *block = arena ? arena->curr : nullptr; !result && block; ) {
|
||||
for (Dqn_ArenaBlock const *block = arena ? arena->curr : nullptr; !result && block; block = block->prev) {
|
||||
uintptr_t begin = DQN_CAST(uintptr_t) block + DQN_ARENA_HEADER_SIZE;
|
||||
uintptr_t end = begin + block->reserve;
|
||||
result = uint_ptr >= begin && uint_ptr <= end;
|
||||
@ -245,6 +280,42 @@ DQN_API bool Dqn_Arena_OwnsPtr(Dqn_Arena const *arena, void *ptr)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DQN_API Dqn_ArenaStats Dqn_Arena_SumStatsArray(Dqn_ArenaStats const *array, Dqn_usize size)
|
||||
{
|
||||
Dqn_ArenaStats result = {};
|
||||
DQN_FOR_UINDEX(index, size) {
|
||||
Dqn_ArenaStats stats = array[index];
|
||||
result.info.used += stats.info.used;
|
||||
result.info.commit += stats.info.commit;
|
||||
result.info.reserve += stats.info.reserve;
|
||||
result.info.blocks += stats.info.blocks;
|
||||
|
||||
result.hwm.used = DQN_MAX(result.hwm.used, result.info.used);
|
||||
result.hwm.commit = DQN_MAX(result.hwm.commit, result.info.commit);
|
||||
result.hwm.reserve = DQN_MAX(result.hwm.reserve, result.info.reserve);
|
||||
result.hwm.blocks = DQN_MAX(result.hwm.blocks, result.info.blocks);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_ArenaStats Dqn_Arena_SumStats(Dqn_ArenaStats lhs, Dqn_ArenaStats rhs)
|
||||
{
|
||||
Dqn_ArenaStats array[] = {lhs, rhs};
|
||||
Dqn_ArenaStats result = Dqn_Arena_SumStatsArray(array, DQN_ARRAY_UCOUNT(array));
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_ArenaStats Dqn_Arena_SumArenaArrayToStats(Dqn_Arena const *array, Dqn_usize size)
|
||||
{
|
||||
Dqn_ArenaStats result = {};
|
||||
for (Dqn_usize index = 0; index < size; index++) {
|
||||
Dqn_Arena const *arena = array + index;
|
||||
result = Dqn_Arena_SumStats(result, arena->stats);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_ArenaTempMem Dqn_Arena_TempMemBegin(Dqn_Arena *arena)
|
||||
{
|
||||
Dqn_ArenaTempMem result = {};
|
||||
@ -299,13 +370,8 @@ DQN_API void *Dqn_ChunkPool_Alloc(Dqn_ChunkPool *pool, Dqn_usize size)
|
||||
Dqn_usize const size_to_slot_offset = 5; // __lzcnt64(32) e.g. Dqn_ChunkPoolSlotSize_32B
|
||||
Dqn_usize slot_index = 0;
|
||||
if (required_size > 32) {
|
||||
#if defined(DQN_OS_WIN32)
|
||||
Dqn_usize dist_to_next_msb = __lzcnt64(required_size) + 1;
|
||||
#else
|
||||
Dqn_usize dist_to_next_msb = __builtin_clzll(required_size) + 1;
|
||||
#endif
|
||||
|
||||
// NOTE: Round up if not PoT as the low bits are set.
|
||||
Dqn_usize dist_to_next_msb = Dqn_CountLeadingZerosU64(required_size) + 1;
|
||||
dist_to_next_msb -= DQN_CAST(Dqn_usize)(!Dqn_IsPowerOfTwo(required_size));
|
||||
|
||||
Dqn_usize const register_size = sizeof(Dqn_usize) * 8;
|
||||
@ -401,14 +467,17 @@ DQN_API Dqn_Str8 Dqn_ChunkPool_AllocStr8Copy(Dqn_ChunkPool *pool, Dqn_Str8 strin
|
||||
|
||||
DQN_API void Dqn_ChunkPool_Dealloc(Dqn_ChunkPool *pool, void *ptr)
|
||||
{
|
||||
if (!Dqn_ChunkPool_IsValid(pool))
|
||||
if (!Dqn_ChunkPool_IsValid(pool) || !ptr)
|
||||
return;
|
||||
|
||||
Dqn_usize offset_to_original_ptr = 0;
|
||||
DQN_MEMCPY(&offset_to_original_ptr, &(DQN_CAST(char *)ptr)[-1], 1);
|
||||
DQN_ASSERT(Dqn_Arena_OwnsPtr(pool->arena, ptr));
|
||||
|
||||
char const *one_byte_behind_ptr = DQN_CAST(char *) ptr - 1;
|
||||
Dqn_usize offset_to_original_ptr = 0;
|
||||
DQN_MEMCPY(&offset_to_original_ptr, one_byte_behind_ptr, 1);
|
||||
DQN_ASSERT(offset_to_original_ptr <= sizeof(Dqn_ChunkPoolSlot) + pool->align);
|
||||
|
||||
char *original_ptr = DQN_CAST(char *)ptr - offset_to_original_ptr;
|
||||
char *original_ptr = DQN_CAST(char *)ptr - offset_to_original_ptr;
|
||||
Dqn_ChunkPoolSlot *slot = DQN_CAST(Dqn_ChunkPoolSlot *)original_ptr;
|
||||
Dqn_ChunkPoolSlotSize slot_index = DQN_CAST(Dqn_ChunkPoolSlotSize)(DQN_CAST(uintptr_t)slot->next);
|
||||
DQN_ASSERT(slot_index < Dqn_ChunkPoolSlotSize_Count);
|
||||
@ -417,6 +486,20 @@ DQN_API void Dqn_ChunkPool_Dealloc(Dqn_ChunkPool *pool, void *ptr)
|
||||
pool->slots[slot_index] = slot;
|
||||
}
|
||||
|
||||
DQN_API void *Dqn_ChunkPool_Copy(Dqn_ChunkPool *pool, void const *data, uint64_t size, uint8_t align)
|
||||
{
|
||||
if (!pool || !data || size == 0)
|
||||
return nullptr;
|
||||
|
||||
// TODO: Hmm should align be part of the alloc interface in general? I'm not going to worry
|
||||
// about this until we crash because of misalignment.
|
||||
DQN_ASSERT(pool->align >= align);
|
||||
|
||||
void *result = Dqn_ChunkPool_Alloc(pool, size);
|
||||
if (result)
|
||||
DQN_MEMCPY(result, data, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: [$ACAT] Dqn_ArenaCatalog //////////////////////////////////////////////////////////////////
|
||||
DQN_API void Dqn_ArenaCatalog_Init(Dqn_ArenaCatalog *catalog, Dqn_ChunkPool *pool)
|
||||
@ -440,7 +523,7 @@ DQN_API Dqn_ArenaCatalogItem *Dqn_ArenaCatalog_Find(Dqn_ArenaCatalog *catalog, D
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API void Dqn_ArenaCatalog_AddLabelRef(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, Dqn_Str8 label)
|
||||
static void Dqn_ArenaCatalog_AddInternal_(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, Dqn_Str8 label, bool arena_pool_allocated)
|
||||
{
|
||||
// NOTE: We could use an atomic for appending to the sentinel but it is such
|
||||
// a rare operation to append to the catalog that we don't bother.
|
||||
@ -451,6 +534,7 @@ DQN_API void Dqn_ArenaCatalog_AddLabelRef(Dqn_ArenaCatalog *catalog, Dqn_Arena *
|
||||
if (result) {
|
||||
result->arena = arena;
|
||||
result->label = label;
|
||||
result->arena_pool_allocated = arena_pool_allocated;
|
||||
|
||||
// NOTE: Add to the catalog (linked list)
|
||||
Dqn_ArenaCatalogItem *sentinel = &catalog->sentinel;
|
||||
@ -463,14 +547,6 @@ DQN_API void Dqn_ArenaCatalog_AddLabelRef(Dqn_ArenaCatalog *catalog, Dqn_Arena *
|
||||
Dqn_TicketMutex_End(&catalog->ticket_mutex);
|
||||
}
|
||||
|
||||
DQN_API void Dqn_ArenaCatalog_AddLabelCopy(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, Dqn_Str8 label)
|
||||
{
|
||||
Dqn_TicketMutex_Begin(&catalog->ticket_mutex);
|
||||
Dqn_Str8 label_copy = Dqn_ChunkPool_AllocStr8Copy(catalog->pool, label);
|
||||
Dqn_TicketMutex_End(&catalog->ticket_mutex);
|
||||
Dqn_ArenaCatalog_AddLabelRef(catalog, arena, label_copy);
|
||||
}
|
||||
|
||||
DQN_API void Dqn_ArenaCatalog_AddF(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, DQN_FMT_ATTRIB char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
@ -479,7 +555,7 @@ DQN_API void Dqn_ArenaCatalog_AddF(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena,
|
||||
Dqn_Str8 label = Dqn_ChunkPool_AllocStr8FV(catalog->pool, fmt, args);
|
||||
Dqn_TicketMutex_End(&catalog->ticket_mutex);
|
||||
va_end(args);
|
||||
Dqn_ArenaCatalog_AddLabelRef(catalog, arena, label);
|
||||
Dqn_ArenaCatalog_AddInternal_(catalog, arena, label, false /*arena_pool_allocated*/);
|
||||
}
|
||||
|
||||
DQN_API void Dqn_ArenaCatalog_AddFV(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, DQN_FMT_ATTRIB char const *fmt, va_list args)
|
||||
@ -487,35 +563,18 @@ DQN_API void Dqn_ArenaCatalog_AddFV(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena,
|
||||
Dqn_TicketMutex_Begin(&catalog->ticket_mutex);
|
||||
Dqn_Str8 label = Dqn_ChunkPool_AllocStr8FV(catalog->pool, fmt, args);
|
||||
Dqn_TicketMutex_End(&catalog->ticket_mutex);
|
||||
Dqn_ArenaCatalog_AddLabelRef(catalog, arena, label);
|
||||
}
|
||||
|
||||
DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocLabelRef(Dqn_ArenaCatalog *catalog, Dqn_usize reserve, Dqn_usize commit, uint8_t arena_flags, Dqn_Str8 label)
|
||||
{
|
||||
Dqn_TicketMutex_Begin(&catalog->ticket_mutex);
|
||||
Dqn_Arena *result = Dqn_ChunkPool_New(catalog->pool, Dqn_Arena);
|
||||
Dqn_TicketMutex_End(&catalog->ticket_mutex);
|
||||
|
||||
*result = Dqn_Arena_InitSize(reserve, commit, arena_flags);
|
||||
Dqn_ArenaCatalog_AddLabelRef(catalog, result, label);
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocLabelCopy(Dqn_ArenaCatalog *catalog, Dqn_usize reserve, Dqn_usize commit, uint8_t arena_flags, Dqn_Str8 label)
|
||||
{
|
||||
Dqn_TicketMutex_Begin(&catalog->ticket_mutex);
|
||||
Dqn_Str8 label_copy = Dqn_ChunkPool_AllocStr8Copy(catalog->pool, label);
|
||||
Dqn_TicketMutex_End(&catalog->ticket_mutex);
|
||||
Dqn_Arena *result = Dqn_ArenaCatalog_AllocLabelRef(catalog, reserve, commit, arena_flags, label_copy);
|
||||
return result;
|
||||
Dqn_ArenaCatalog_AddInternal_(catalog, arena, label, false /*arena_pool_allocated*/);
|
||||
}
|
||||
|
||||
DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocFV(Dqn_ArenaCatalog *catalog, Dqn_usize reserve, Dqn_usize commit, uint8_t arena_flags, DQN_FMT_ATTRIB char const *fmt, va_list args)
|
||||
{
|
||||
Dqn_TicketMutex_Begin(&catalog->ticket_mutex);
|
||||
Dqn_Str8 label = Dqn_ChunkPool_AllocStr8FV(catalog->pool, fmt, args);
|
||||
Dqn_Arena *result = Dqn_ChunkPool_New(catalog->pool, Dqn_Arena);
|
||||
Dqn_TicketMutex_End(&catalog->ticket_mutex);
|
||||
Dqn_Arena *result = Dqn_ArenaCatalog_AllocLabelRef(catalog, reserve, commit, arena_flags, label);
|
||||
|
||||
*result = Dqn_Arena_InitSize(reserve, commit, arena_flags);
|
||||
Dqn_ArenaCatalog_AddInternal_(catalog, result, label, true /*arena_pool_allocated*/);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -525,8 +584,34 @@ DQN_API Dqn_Arena *Dqn_ArenaCatalog_AllocF(Dqn_ArenaCatalog *catalog, Dqn_usize
|
||||
va_start(args, fmt);
|
||||
Dqn_TicketMutex_Begin(&catalog->ticket_mutex);
|
||||
Dqn_Str8 label = Dqn_ChunkPool_AllocStr8FV(catalog->pool, fmt, args);
|
||||
Dqn_Arena *result = Dqn_ChunkPool_New(catalog->pool, Dqn_Arena);
|
||||
Dqn_TicketMutex_End(&catalog->ticket_mutex);
|
||||
Dqn_Arena *result = Dqn_ArenaCatalog_AllocLabelRef(catalog, reserve, commit, arena_flags, label);
|
||||
va_end(args);
|
||||
|
||||
*result = Dqn_Arena_InitSize(reserve, commit, arena_flags);
|
||||
Dqn_ArenaCatalog_AddInternal_(catalog, result, label, true /*arena_pool_allocated*/);
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API bool Dqn_ArenaCatalog_Erase(Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, Dqn_ArenaCatalogFreeArena free_arena)
|
||||
{
|
||||
bool result = false;
|
||||
Dqn_TicketMutex_Begin(&catalog->ticket_mutex);
|
||||
for (Dqn_ArenaCatalogItem *item = catalog->sentinel.next; item != &catalog->sentinel; item = item->next) {
|
||||
if (item->arena == arena) {
|
||||
item->next->prev = item->prev;
|
||||
item->prev->next = item->next;
|
||||
if (item->arena_pool_allocated) {
|
||||
if (free_arena == Dqn_ArenaCatalogFreeArena_Yes)
|
||||
Dqn_Arena_Deinit(item->arena);
|
||||
Dqn_ChunkPool_Dealloc(catalog->pool, item->arena);
|
||||
}
|
||||
Dqn_ChunkPool_Dealloc(catalog->pool, item->label.data);
|
||||
Dqn_ChunkPool_Dealloc(catalog->pool, item);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Dqn_TicketMutex_End(&catalog->ticket_mutex);
|
||||
return result;
|
||||
}
|
||||
|
@ -50,11 +50,26 @@ enum Dqn_ArenaFlag
|
||||
Dqn_ArenaFlag_AllocCanLeak = 1 << 3,
|
||||
};
|
||||
|
||||
struct Dqn_ArenaInfo
|
||||
{
|
||||
uint64_t used;
|
||||
uint64_t commit;
|
||||
uint64_t reserve;
|
||||
uint64_t blocks;
|
||||
};
|
||||
|
||||
struct Dqn_ArenaStats
|
||||
{
|
||||
Dqn_ArenaInfo info;
|
||||
Dqn_ArenaInfo hwm;
|
||||
};
|
||||
|
||||
struct Dqn_Arena
|
||||
{
|
||||
Dqn_ArenaBlock *curr;
|
||||
uint8_t flags;
|
||||
Dqn_ArenaStats stats;
|
||||
Dqn_TicketMutex mutex; // For user code to lock the arena, the arena itself does not use.
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
struct Dqn_ArenaTempMem
|
||||
@ -131,6 +146,7 @@ struct Dqn_ArenaCatalogItem
|
||||
{
|
||||
Dqn_Arena *arena;
|
||||
Dqn_Str8 label;
|
||||
bool arena_pool_allocated;
|
||||
Dqn_ArenaCatalogItem *next;
|
||||
Dqn_ArenaCatalogItem *prev;
|
||||
};
|
||||
@ -143,6 +159,12 @@ struct Dqn_ArenaCatalog
|
||||
uint16_t arena_count;
|
||||
};
|
||||
|
||||
enum Dqn_ArenaCatalogFreeArena
|
||||
{
|
||||
Dqn_ArenaCatalogFreeArena_No,
|
||||
Dqn_ArenaCatalogFreeArena_Yes,
|
||||
};
|
||||
|
||||
// NOTE: [$AREN] Dqn_Arena /////////////////////////////////////////////////////////////////////////
|
||||
DQN_API Dqn_Arena Dqn_Arena_InitSize (uint64_t reserve, uint64_t commit, uint8_t flags);
|
||||
DQN_API void Dqn_Arena_Deinit (Dqn_Arena *arena);
|
||||
@ -156,6 +178,9 @@ DQN_API void Dqn_Arena_Pop (Dqn_Arena *arena,
|
||||
DQN_API uint64_t Dqn_Arena_Pos (Dqn_Arena const *arena);
|
||||
DQN_API void Dqn_Arena_Clear (Dqn_Arena *arena);
|
||||
DQN_API bool Dqn_Arena_OwnsPtr (Dqn_Arena const *arena, void *ptr);
|
||||
DQN_API Dqn_ArenaStats Dqn_Arena_SumStatsArray (Dqn_ArenaStats const *array, Dqn_usize size);
|
||||
DQN_API Dqn_ArenaStats Dqn_Arena_SumStats (Dqn_ArenaStats lhs, Dqn_ArenaStats rhs);
|
||||
DQN_API Dqn_ArenaStats Dqn_Arena_SumArenaArrayToStats (Dqn_Arena const *array, Dqn_usize size);
|
||||
DQN_API Dqn_ArenaTempMem Dqn_Arena_TempMemBegin (Dqn_Arena *arena);
|
||||
DQN_API void Dqn_Arena_TempMemEnd (Dqn_ArenaTempMem mem);
|
||||
#define Dqn_Arena_New(arena, T, zero_mem) (T *)Dqn_Arena_Alloc(arena, sizeof(T), alignof(T), zero_mem)
|
||||
@ -164,7 +189,6 @@ DQN_API void Dqn_Arena_TempMemEnd (Dqn_ArenaTempMem m
|
||||
#define Dqn_Arena_NewArrayCopy(arena, T, src, count) (T *)Dqn_Arena_Copy (arena, (src), sizeof(T) * (count), alignof(T))
|
||||
|
||||
// NOTE: [$CHUN] Dqn_ChunkPool /////////////////////////////////////////////////////////////////////
|
||||
#define Dqn_ChunkPool_New(pool, T) (T *)Dqn_ChunkPool_Alloc(pool, sizeof(T))
|
||||
DQN_API Dqn_ChunkPool Dqn_ChunkPool_Init (Dqn_Arena *arena, uint8_t align);
|
||||
DQN_API bool Dqn_ChunkPool_IsValid (Dqn_ChunkPool const *pool);
|
||||
DQN_API void * Dqn_ChunkPool_Alloc (Dqn_ChunkPool *pool, Dqn_usize size);
|
||||
@ -172,15 +196,18 @@ DQN_API Dqn_Str8 Dqn_ChunkPool_AllocStr8FV (Dqn_ChunkPool *poo
|
||||
DQN_API Dqn_Str8 Dqn_ChunkPool_AllocStr8F (Dqn_ChunkPool *pool, DQN_FMT_ATTRIB char const *fmt, ...);
|
||||
DQN_API Dqn_Str8 Dqn_ChunkPool_AllocStr8Copy (Dqn_ChunkPool *pool, Dqn_Str8 string);
|
||||
DQN_API void Dqn_ChunkPool_Dealloc (Dqn_ChunkPool *pool, void *ptr);
|
||||
DQN_API void * Dqn_ChunkPool_Copy (Dqn_ChunkPool *pool, void const *data, uint64_t size, uint8_t align);
|
||||
|
||||
#define Dqn_ChunkPool_New(pool, T) (T *)Dqn_ChunkPool_Alloc(pool, sizeof(T))
|
||||
#define Dqn_ChunkPool_NewArray(pool, T, count) (T *)Dqn_ChunkPool_Alloc(pool, count * sizeof(T))
|
||||
#define Dqn_ChunkPool_NewCopy(arena, T, src) (T *)Dqn_ChunkPool_Copy (arena, (src), sizeof(T), alignof(T))
|
||||
#define Dqn_ChunkPool_NewArrayCopy(arena, T, src, count) (T *)Dqn_ChunkPool_Copy (arena, (src), sizeof(T) * (count), alignof(T))
|
||||
|
||||
// NOTE: [$ACAT] Dqn_ArenaCatalog //////////////////////////////////////////////////////////////////
|
||||
DQN_API void Dqn_ArenaCatalog_Init (Dqn_ArenaCatalog *catalog, Dqn_ChunkPool *pool);
|
||||
DQN_API Dqn_ArenaCatalogItem *Dqn_ArenaCatalog_Find (Dqn_ArenaCatalog *catalog, Dqn_Str8 label);
|
||||
DQN_API void Dqn_ArenaCatalog_AddLabelRef (Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, Dqn_Str8 label);
|
||||
DQN_API void Dqn_ArenaCatalog_AddLabelCopy (Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, Dqn_Str8 label);
|
||||
DQN_API void Dqn_ArenaCatalog_AddF (Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, DQN_FMT_ATTRIB char const *fmt, ...);
|
||||
DQN_API void Dqn_ArenaCatalog_AddFV (Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, DQN_FMT_ATTRIB char const *fmt, va_list args);
|
||||
DQN_API Dqn_Arena * Dqn_ArenaCatalog_AllocLabelRef (Dqn_ArenaCatalog *catalog, Dqn_usize reserve, Dqn_usize commit, uint8_t arena_flags, Dqn_Str8 label);
|
||||
DQN_API Dqn_Arena * Dqn_ArenaCatalog_AllocLabelCopy(Dqn_ArenaCatalog *catalog, Dqn_usize reserve, Dqn_usize commit, uint8_t arena_flags, Dqn_Str8 label);
|
||||
DQN_API Dqn_Arena * Dqn_ArenaCatalog_AllocFV (Dqn_ArenaCatalog *catalog, Dqn_usize reserve, Dqn_usize commit, uint8_t arena_flags, DQN_FMT_ATTRIB char const *fmt, va_list args);
|
||||
DQN_API Dqn_Arena * Dqn_ArenaCatalog_AllocF (Dqn_ArenaCatalog *catalog, Dqn_usize reserve, Dqn_usize commit, uint8_t arena_flags, DQN_FMT_ATTRIB char const *fmt, ...);
|
||||
DQN_API void Dqn_ArenaCatalog_Init (Dqn_ArenaCatalog *catalog, Dqn_ChunkPool *pool);
|
||||
DQN_API Dqn_ArenaCatalogItem *Dqn_ArenaCatalog_Find (Dqn_ArenaCatalog *catalog, Dqn_Str8 label);
|
||||
DQN_API void Dqn_ArenaCatalog_AddF (Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, DQN_FMT_ATTRIB char const *fmt, ...);
|
||||
DQN_API void Dqn_ArenaCatalog_AddFV (Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, DQN_FMT_ATTRIB char const *fmt, va_list args);
|
||||
DQN_API Dqn_Arena * Dqn_ArenaCatalog_AllocFV (Dqn_ArenaCatalog *catalog, Dqn_usize reserve, Dqn_usize commit, uint8_t arena_flags, DQN_FMT_ATTRIB char const *fmt, va_list args);
|
||||
DQN_API Dqn_Arena * Dqn_ArenaCatalog_AllocF (Dqn_ArenaCatalog *catalog, Dqn_usize reserve, Dqn_usize commit, uint8_t arena_flags, DQN_FMT_ATTRIB char const *fmt, ...);
|
||||
DQN_API bool Dqn_ArenaCatalog_Erase (Dqn_ArenaCatalog *catalog, Dqn_Arena *arena, Dqn_ArenaCatalogFreeArena free_arena);
|
||||
|
49
dqn_base.cpp
49
dqn_base.cpp
@ -77,8 +77,8 @@ DQN_API void Dqn_CPU_SetFeature(Dqn_CPUReport *report, Dqn_CPUFeature feature)
|
||||
DQN_API Dqn_CPUReport Dqn_CPU_Report()
|
||||
{
|
||||
Dqn_CPUReport result = {};
|
||||
Dqn_CPUIDResult fn_0000_[16] = {};
|
||||
Dqn_CPUIDResult fn_8000_[64] = {};
|
||||
Dqn_CPUIDResult fn_0000_[512] = {};
|
||||
Dqn_CPUIDResult fn_8000_[512] = {};
|
||||
int const EXTENDED_FUNC_BASE_EAX = 0x8000'0000;
|
||||
int const REGISTER_SIZE = sizeof(fn_0000_[0].reg.eax);
|
||||
|
||||
@ -102,8 +102,10 @@ DQN_API Dqn_CPUReport Dqn_CPU_Report()
|
||||
|
||||
// NOTE: Enumerate all CPUID results for the known function counts /////////////////////////////
|
||||
{
|
||||
DQN_ASSERT((STANDARD_FUNC_MAX_EAX + 1) <= DQN_ARRAY_ICOUNT(fn_0000_));
|
||||
DQN_ASSERT((DQN_CAST(Dqn_isize)EXTENDED_FUNC_MAX_EAX - EXTENDED_FUNC_BASE_EAX + 1) <= DQN_ARRAY_ICOUNT(fn_8000_));
|
||||
DQN_ASSERTF((STANDARD_FUNC_MAX_EAX + 1) <= DQN_ARRAY_ICOUNT(fn_0000_),
|
||||
"Max standard count is %zu", STANDARD_FUNC_MAX_EAX + 1);
|
||||
DQN_ASSERTF((DQN_CAST(Dqn_isize)EXTENDED_FUNC_MAX_EAX - EXTENDED_FUNC_BASE_EAX + 1) <= DQN_ARRAY_ICOUNT(fn_8000_),
|
||||
"Max extended count is %zu", DQN_CAST(Dqn_isize)EXTENDED_FUNC_MAX_EAX - EXTENDED_FUNC_BASE_EAX + 1);
|
||||
|
||||
for (int eax = 1; eax <= STANDARD_FUNC_MAX_EAX; eax++) {
|
||||
Dqn_CPUIDArgs args = {};
|
||||
@ -535,15 +537,15 @@ DQN_FILE_SCOPE void Dqn_Log_FVDefault_(Dqn_Str8 type, int log_type, void *user_d
|
||||
// NOTE: Open log file for appending if requested //////////////////////////
|
||||
Dqn_TicketMutex_Begin(&lib->log_file_mutex);
|
||||
if (lib->log_to_file && !lib->log_file.handle && !lib->log_file.error) {
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8 log_path = Dqn_OS_PathConvertF(scratch.arena, "%.*s/dqn.log", DQN_STR_FMT(lib->exe_dir));
|
||||
lib->log_file = Dqn_OS_FileOpen(log_path, Dqn_OSFileOpen_CreateAlways, Dqn_OSFileAccess_AppendOnly, nullptr);
|
||||
Dqn_TLSTMem t_mem = Dqn_TLS_TMem(nullptr);
|
||||
Dqn_Str8 log_path = Dqn_OS_PathF(t_mem.arena, "%.*s/dqn.log", DQN_STR_FMT(lib->exe_dir));
|
||||
lib->log_file = Dqn_OS_FileOpen(log_path, Dqn_OSFileOpen_CreateAlways, Dqn_OSFileAccess_AppendOnly, nullptr);
|
||||
}
|
||||
Dqn_TicketMutex_End(&lib->log_file_mutex);
|
||||
|
||||
// NOTE: Generate the log header ///////////////////////////////////////////
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8 log_line = Dqn_Log_MakeStr8(scratch.arena, !lib->log_no_colour, type, log_type, call_site, fmt, args);
|
||||
Dqn_TLSTMem t_mem = Dqn_TLS_TMem(nullptr);
|
||||
Dqn_Str8 log_line = Dqn_Log_MakeStr8(t_mem.arena, !lib->log_no_colour, type, log_type, call_site, fmt, args);
|
||||
|
||||
// NOTE: Print log /////////////////////////////////////////////////////////
|
||||
Dqn_Print_StdLn(Dqn_PrintStd_Out, log_line);
|
||||
@ -597,13 +599,14 @@ DQN_API void Dqn_Log_TypeFCallSite(Dqn_LogType type, Dqn_CallSite call_site, DQN
|
||||
// NOTE: [$ERRS] Dqn_ErrorSink /////////////////////////////////////////////////////////////////////
|
||||
DQN_API Dqn_ErrorSink *Dqn_ErrorSink_Begin(Dqn_ErrorSinkMode mode)
|
||||
{
|
||||
Dqn_ThreadContext *thread_context = Dqn_ThreadContext_Get();
|
||||
Dqn_ErrorSink *result = &thread_context->error_sink;
|
||||
Dqn_ErrorSinkNode *node = Dqn_Arena_New(result->arena, Dqn_ErrorSinkNode, Dqn_ZeroMem_Yes);
|
||||
node->next = result->stack;
|
||||
node->arena_pos = Dqn_Arena_Pos(result->arena);
|
||||
node->mode = mode;
|
||||
result->stack = node;
|
||||
Dqn_TLS *tls = Dqn_TLS_Get();
|
||||
Dqn_ErrorSink *result = &tls->error_sink;
|
||||
Dqn_usize arena_pos = Dqn_Arena_Pos(result->arena);
|
||||
Dqn_ErrorSinkNode *node = Dqn_Arena_New(result->arena, Dqn_ErrorSinkNode, Dqn_ZeroMem_Yes);
|
||||
node->next = result->stack;
|
||||
node->arena_pos = arena_pos;
|
||||
node->mode = mode;
|
||||
result->stack = node;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -640,8 +643,8 @@ DQN_API void Dqn_ErrorSink_EndAndIgnore(Dqn_ErrorSink *error)
|
||||
|
||||
DQN_API bool Dqn_ErrorSink_EndAndLogError(Dqn_ErrorSink *error, Dqn_Str8 error_msg)
|
||||
{
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_ErrorSinkNode node = Dqn_ErrorSink_End(scratch.arena, error);
|
||||
Dqn_TLSTMem t_mem = Dqn_TLS_TMem(nullptr);
|
||||
Dqn_ErrorSinkNode node = Dqn_ErrorSink_End(t_mem.arena, error);
|
||||
if (node.error) {
|
||||
if (Dqn_Str8_HasData(error_msg)) {
|
||||
Dqn_Log_TypeFCallSite(Dqn_LogType_Error, node.call_site, "%.*s: %.*s", DQN_STR_FMT(error_msg), DQN_STR_FMT(node.msg));
|
||||
@ -655,8 +658,8 @@ DQN_API bool Dqn_ErrorSink_EndAndLogError(Dqn_ErrorSink *error, Dqn_Str8 error_m
|
||||
|
||||
DQN_API bool Dqn_ErrorSink_EndAndLogErrorFV(Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, va_list args)
|
||||
{
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8 log = Dqn_Str8_InitFV(scratch.arena, fmt, args);
|
||||
Dqn_TLSTMem t_mem = Dqn_TLS_TMem(nullptr);
|
||||
Dqn_Str8 log = Dqn_Str8_InitFV(t_mem.arena, fmt, args);
|
||||
bool result = Dqn_ErrorSink_EndAndLogError(error, log);
|
||||
return result;
|
||||
}
|
||||
@ -665,8 +668,8 @@ DQN_API bool Dqn_ErrorSink_EndAndLogErrorF(Dqn_ErrorSink *error, DQN_FMT_ATTRIB
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8 log = Dqn_Str8_InitFV(scratch.arena, fmt, args);
|
||||
Dqn_TLSTMem t_mem = Dqn_TLS_TMem(nullptr);
|
||||
Dqn_Str8 log = Dqn_Str8_InitFV(t_mem.arena, fmt, args);
|
||||
bool result = Dqn_ErrorSink_EndAndLogError(error, log);
|
||||
va_end(args);
|
||||
return result;
|
||||
@ -699,7 +702,7 @@ DQN_API void Dqn_ErrorSink_MakeFV_(Dqn_ErrorSink *error, uint32_t error_code, DQ
|
||||
node->msg = Dqn_Str8_InitFV(error->arena, fmt, args);
|
||||
node->error_code = error_code;
|
||||
node->error = true;
|
||||
node->call_site = Dqn_ThreadContext_Get()->call_site;
|
||||
node->call_site = Dqn_TLS_Get()->call_site;
|
||||
if (node->mode == Dqn_ErrorSinkMode_ExitOnError)
|
||||
Dqn_ErrorSink_EndAndExitIfErrorF(error, error_code, "Fatal error %u", error_code);
|
||||
}
|
||||
|
17
dqn_base.h
17
dqn_base.h
@ -145,16 +145,16 @@
|
||||
#if !defined(DQN_MEMCPY) || !defined(DQN_MEMSET) || !defined(DQN_MEMCMP) || !defined(DQN_MEMMOVE)
|
||||
#include <string.h>
|
||||
#if !defined(DQN_MEMCPY)
|
||||
#define DQN_MEMCPY(dest, src, count) memcpy(dest, src, count)
|
||||
#define DQN_MEMCPY(dest, src, count) memcpy((dest), (src), (count))
|
||||
#endif
|
||||
#if !defined(DQN_MEMSET)
|
||||
#define DQN_MEMSET(dest, value, count) memset(dest, value, count)
|
||||
#define DQN_MEMSET(dest, value, count) memset((dest), (value), (count))
|
||||
#endif
|
||||
#if !defined(DQN_MEMCMP)
|
||||
#define DQN_MEMCMP(lhs, rhs, count) memcmp(lhs, rhs, count)
|
||||
#define DQN_MEMCMP(lhs, rhs, count) memcmp((lhs), (rhs), (count))
|
||||
#endif
|
||||
#if !defined(DQN_MEMMOVE)
|
||||
#define DQN_MEMMOVE(dest, src, count) memmove(dest, src, count)
|
||||
#define DQN_MEMMOVE(dest, src, count) memmove((dest), (src), (count))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -424,6 +424,9 @@ struct Dqn_ErrorSink
|
||||
#define Dqn_Atomic_AddU64(target, value) _InterlockedExchangeAdd64((__int64 volatile *)target, value)
|
||||
#define Dqn_Atomic_SubU32(target, value) Dqn_Atomic_AddU32(DQN_CAST(long volatile *)target, (long)-value)
|
||||
#define Dqn_Atomic_SubU64(target, value) Dqn_Atomic_AddU64(target, (uint64_t)-value)
|
||||
|
||||
#define Dqn_CountLeadingZerosU64(value) __lzcnt64(value)
|
||||
|
||||
#define Dqn_CPU_TSC() __rdtsc()
|
||||
#define Dqn_CompilerReadBarrierAndCPUReadFence _ReadBarrier(); _mm_lfence()
|
||||
#define Dqn_CompilerWriteBarrierAndCPUWriteFence _WriteBarrier(); _mm_sfence()
|
||||
@ -439,6 +442,8 @@ struct Dqn_ErrorSink
|
||||
#define Dqn_Atomic_AddU64(target, value) __atomic_fetch_add(target, value, __ATOMIC_ACQ_REL)
|
||||
#define Dqn_Atomic_SubU32(target, value) __atomic_fetch_sub(target, value, __ATOMIC_ACQ_REL)
|
||||
#define Dqn_Atomic_SubU64(target, value) __atomic_fetch_sub(target, value, __ATOMIC_ACQ_REL)
|
||||
|
||||
#define Dqn_CountLeadingZerosU64(value) __builtin_clzll(value)
|
||||
#if defined(DQN_COMPILER_GCC)
|
||||
#define Dqn_CPU_TSC() __rdtsc()
|
||||
#else
|
||||
@ -752,8 +757,8 @@ DQN_API bool Dqn_ErrorSink_EndAndLogErrorF
|
||||
DQN_API void Dqn_ErrorSink_EndAndExitIfErrorF (Dqn_ErrorSink *error, uint32_t exit_code, DQN_FMT_ATTRIB char const *fmt, ...);
|
||||
DQN_API void Dqn_ErrorSink_EndAndExitIfErrorFV (Dqn_ErrorSink *error, uint32_t exit_code, DQN_FMT_ATTRIB char const *fmt, va_list args);
|
||||
|
||||
#define Dqn_ErrorSink_MakeFV(error, error_code, fmt, args) do { Dqn_ThreadContext_SaveCallSite; Dqn_ErrorSink_MakeFV_(error, error_code, fmt, args); } while (0)
|
||||
#define Dqn_ErrorSink_MakeF(error, error_code, fmt, ...) do { Dqn_ThreadContext_SaveCallSite; Dqn_ErrorSink_MakeF_(error, error_code, fmt, ## __VA_ARGS__); } while (0)
|
||||
#define Dqn_ErrorSink_MakeFV(error, error_code, fmt, args) do { Dqn_TLS_SaveCallSite; Dqn_ErrorSink_MakeFV_(error, error_code, fmt, args); } while (0)
|
||||
#define Dqn_ErrorSink_MakeF(error, error_code, fmt, ...) do { Dqn_TLS_SaveCallSite; Dqn_ErrorSink_MakeF_(error, error_code, fmt, ## __VA_ARGS__); } while (0)
|
||||
DQN_API void Dqn_ErrorSink_MakeFV_ (Dqn_ErrorSink *error, uint32_t error_code, DQN_FMT_ATTRIB char const *fmt, va_list args);
|
||||
DQN_API void Dqn_ErrorSink_MakeF_ (Dqn_ErrorSink *error, uint32_t error_code, DQN_FMT_ATTRIB char const *fmt, ...);
|
||||
|
||||
|
517
dqn_cgen.cpp
517
dqn_cgen.cpp
@ -1,3 +1,4 @@
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// $$$$$$\ $$$$$$\ $$$$$$$$\ $$\ $$\
|
||||
@ -12,6 +13,7 @@
|
||||
// dqn_cgen.cpp
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
Dqn_CGenMapNodeToEnum const DQN_CGEN_TABLE_KEY_LIST[] =
|
||||
{
|
||||
@ -48,6 +50,7 @@ Dqn_CGenTableHeaderType const DQN_CGEN_TABLE_CODE_GEN_STRUCT_HEADER_LIST[] =
|
||||
Dqn_CGenTableHeaderType_CppOpEquals,
|
||||
Dqn_CGenTableHeaderType_CppArraySize,
|
||||
Dqn_CGenTableHeaderType_CppArraySizeField,
|
||||
Dqn_CGenTableHeaderType_CppLabel,
|
||||
Dqn_CGenTableHeaderType_GenTypeInfo,
|
||||
};
|
||||
|
||||
@ -57,6 +60,7 @@ Dqn_CGenTableHeaderType const DQN_CGEN_TABLE_CODE_GEN_ENUM_HEADER_LIST[] =
|
||||
Dqn_CGenTableHeaderType_Table,
|
||||
Dqn_CGenTableHeaderType_CppName,
|
||||
Dqn_CGenTableHeaderType_CppValue,
|
||||
Dqn_CGenTableHeaderType_CppLabel,
|
||||
Dqn_CGenTableHeaderType_GenTypeInfo,
|
||||
Dqn_CGenTableHeaderType_GenEnumCount,
|
||||
};
|
||||
@ -159,6 +163,7 @@ static bool Dqn_CGen_GatherTables_(Dqn_CGen *cgen, Dqn_ErrorSink *error)
|
||||
// NOTE: Validate table headers ////////////////////////////////////////////////////////////
|
||||
switch (table->type) {
|
||||
case Dqn_CGenTableType_Nil: DQN_INVALID_CODE_PATH;
|
||||
case Dqn_CGenTableType_Count: DQN_INVALID_CODE_PATH;
|
||||
|
||||
case Dqn_CGenTableType_Data: {
|
||||
} break;
|
||||
@ -299,7 +304,6 @@ DQN_API Dqn_CGen Dqn_CGen_InitFilesArgV(int argc, char const **argv, Dqn_ErrorSi
|
||||
MD_String8 file_name = MD_S8CString(DQN_CAST(char *)argv[arg_index]);
|
||||
MD_ParseResult parse_result = MD_ParseWholeFile(result.arena, file_name);
|
||||
for (MD_Message *message = parse_result.errors.first; message != 0; message = message->next) {
|
||||
MD_CodeLoc code_loc = MD_CodeLocFromNode(message->node);
|
||||
has_error = true;
|
||||
Dqn_CGen_LogF(message->kind, message->node, error, "%.*s", MD_S8VArg(message->string));
|
||||
}
|
||||
@ -324,6 +328,7 @@ DQN_API Dqn_Str8 Dqn_CGen_TableHeaderTypeToDeclStr8(Dqn_CGenTableHeaderType type
|
||||
case Dqn_CGenTableHeaderType_CppOpEquals: result = DQN_STR8("cpp_op_equals"); break;
|
||||
case Dqn_CGenTableHeaderType_CppArraySize: result = DQN_STR8("cpp_array_size"); break;
|
||||
case Dqn_CGenTableHeaderType_CppArraySizeField: result = DQN_STR8("cpp_array_size_field"); break;
|
||||
case Dqn_CGenTableHeaderType_CppLabel: result = DQN_STR8("cpp_label"); break;
|
||||
case Dqn_CGenTableHeaderType_GenTypeInfo: result = DQN_STR8("gen_type_info"); break;
|
||||
case Dqn_CGenTableHeaderType_GenEnumCount: result = DQN_STR8("gen_enum_count"); break;
|
||||
case Dqn_CGenTableHeaderType_Count: result = DQN_STR8("XX BAD ENUM VALUE XX"); break;
|
||||
@ -345,56 +350,63 @@ DQN_API Dqn_CGenMapNodeToEnum Dqn_CGen_MapNodeToEnumOrExit(MD_Node const *node,
|
||||
|
||||
if (result.enum_val == 0) {
|
||||
MD_CodeLoc loc = MD_CodeLocFromNode(DQN_CAST(MD_Node *)node);
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_TLSTMem tmem = Dqn_TLS_TMem(nullptr);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Dqn_Str8 user_msg = Dqn_Str8_InitFV(scratch.arena, fmt, args);
|
||||
Dqn_Str8 user_msg = Dqn_Str8_InitFV(tmem.arena, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
Dqn_Str8Builder builder = {};
|
||||
builder.arena = scratch.arena;
|
||||
builder.arena = tmem.arena;
|
||||
|
||||
Dqn_Str8Builder_AppendF(&builder, "%.*s: '%.*s' is not recognised, the supported values are ", DQN_STR_FMT(user_msg), MD_S8VArg(node->string));
|
||||
Dqn_Str8Builder_AddF(&builder, "%.*s: '%.*s' is not recognised, the supported values are ", DQN_STR_FMT(user_msg), MD_S8VArg(node->string));
|
||||
for (Dqn_usize index = 0; index < valid_keys_size; index++) {
|
||||
Dqn_CGenMapNodeToEnum const *validator = valid_keys + index;
|
||||
Dqn_Str8Builder_AppendF(&builder, DQN_CAST(char *)"%s'%.*s'", index ? ", " : "", DQN_STR_FMT(validator->node_string));
|
||||
Dqn_Str8Builder_AddF(&builder, DQN_CAST(char *)"%s'%.*s'", index ? ", " : "", DQN_STR_FMT(validator->node_string));
|
||||
}
|
||||
|
||||
Dqn_Str8 error_msg = Dqn_Str8Builder_Build(&builder, scratch.arena);
|
||||
Dqn_Str8 error_msg = Dqn_Str8Builder_Build(&builder, tmem.arena);
|
||||
MD_PrintMessageFmt(stderr, loc, MD_MessageKind_Error, DQN_CAST(char *) "%.*s", DQN_STR_FMT(error_msg));
|
||||
Dqn_OS_Exit(DQN_CAST(uint32_t)-1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_usize Dqn_CGen_NodeChildrenCount(MD_Node const *node)
|
||||
{
|
||||
Dqn_usize result = 0;
|
||||
for (MD_EachNode(item, node->first_child))
|
||||
result++;
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API void Dqn_CGen_LogF(MD_MessageKind kind, MD_Node *node, Dqn_ErrorSink *error, char const *fmt, ...)
|
||||
{
|
||||
if (!error)
|
||||
return;
|
||||
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8Builder builder = {};
|
||||
builder.arena = scratch.arena;
|
||||
Dqn_TLSTMem tmem = Dqn_TLS_PushTMem(nullptr);
|
||||
Dqn_Str8Builder builder = Dqn_Str8Builder_Init_TLS();
|
||||
|
||||
MD_String8 kind_string = MD_StringFromMessageKind(kind);
|
||||
MD_CodeLoc loc = MD_CodeLocFromNode(node);
|
||||
Dqn_Str8Builder_AppendF(&builder, "" MD_FmtCodeLoc " %.*s: ", MD_CodeLocVArg(loc), MD_S8VArg(kind_string));
|
||||
Dqn_Str8Builder_AddF(&builder, "" MD_FmtCodeLoc " %.*s: ", MD_CodeLocVArg(loc), MD_S8VArg(kind_string));
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Dqn_Str8Builder_AppendFV(&builder, fmt, args);
|
||||
Dqn_Str8Builder_AddFV(&builder, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
Dqn_Str8 msg = Dqn_Str8Builder_Build(&builder, scratch.arena);
|
||||
Dqn_Str8 msg = Dqn_Str8Builder_Build(&builder, tmem.arena);
|
||||
Dqn_ErrorSink_MakeF(error, DQN_CAST(uint32_t)-1, "%.*s", DQN_STR_FMT(msg));
|
||||
}
|
||||
|
||||
DQN_API bool Dqn_CGen_TableHasHeaders(Dqn_CGenTable const *table, Dqn_Str8 const *headers, Dqn_usize header_count, Dqn_ErrorSink *error)
|
||||
{
|
||||
bool result = true;
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_TLSTMem tmem = Dqn_TLS_TMem(nullptr);
|
||||
Dqn_Str8Builder builder = {};
|
||||
builder.arena = scratch.arena;
|
||||
builder.arena = tmem.arena;
|
||||
|
||||
for (Dqn_usize index = 0; index < header_count; index++) {
|
||||
Dqn_Str8 header = headers[index];
|
||||
@ -402,12 +414,12 @@ DQN_API bool Dqn_CGen_TableHasHeaders(Dqn_CGenTable const *table, Dqn_Str8 const
|
||||
MD_MapSlot *slot = MD_MapLookup(DQN_CAST(MD_Map *)&table->headers_map, MD_MapKeyStr(header_md));
|
||||
if (!slot) {
|
||||
result = false;
|
||||
Dqn_Str8Builder_AppendF(&builder, "%s%.*s", builder.count ? ", " : "", DQN_STR_FMT(header));
|
||||
Dqn_Str8Builder_AddF(&builder, "%s%.*s", builder.count ? ", " : "", DQN_STR_FMT(header));
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
Dqn_Str8 missing_headers = Dqn_Str8Builder_Build(&builder, scratch.arena);
|
||||
Dqn_Str8 missing_headers = Dqn_Str8Builder_Build(&builder, tmem.arena);
|
||||
Dqn_CGen_LogF(MD_MessageKind_Error,
|
||||
table->headers_node,
|
||||
error,
|
||||
@ -482,6 +494,26 @@ DQN_API bool Dqn_CGen_LookupNextTableInCodeGenTable(Dqn_CGen *cgen, Dqn_CGenTabl
|
||||
return true;
|
||||
}
|
||||
|
||||
DQN_API bool Dqn_CGen_WillCodeGenTypeName(Dqn_CGen const *cgen, Dqn_Str8 name)
|
||||
{
|
||||
if (!Dqn_Str8_HasData(name))
|
||||
return false;
|
||||
|
||||
for (Dqn_CGenTable *table = cgen->first_table; table != 0; table = table->next) {
|
||||
if (table->type != Dqn_CGenTableType_CodeGenStruct && table->type != Dqn_CGenTableType_CodeGenEnum)
|
||||
continue;
|
||||
|
||||
for (Dqn_usize row_index = 0; row_index < table->row_count; row_index++) {
|
||||
Dqn_CGenTableRow const *row = table->rows + row_index;
|
||||
Dqn_CGenTableColumn const *column = row->columns + table->column_indexes[Dqn_CGenTableHeaderType_Name];
|
||||
if (column->string == name)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Dqn_CGen_EmitRowWhitespace_(Dqn_CGenTableRow const *row, Dqn_CppFile *cpp)
|
||||
{
|
||||
for (Dqn_CGenTableRowTag *tag = row->first_tag; tag; tag = tag->next) {
|
||||
@ -492,8 +524,8 @@ static void Dqn_CGen_EmitRowWhitespace_(Dqn_CGenTableRow const *row, Dqn_CppFile
|
||||
if (tag->comment.size <= 0)
|
||||
break;
|
||||
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8 prefix = Dqn_Str8_InitF(scratch.arena, "// NOTE: %.*s ", MD_S8VArg(tag->comment));
|
||||
Dqn_TLSTMem tmem = Dqn_TLS_TMem(nullptr);
|
||||
Dqn_Str8 prefix = Dqn_Str8_InitF(tmem.arena, "// NOTE: %.*s ", MD_S8VArg(tag->comment));
|
||||
int line_padding = DQN_MAX(100 - (DQN_CAST(int) prefix.size + (Dqn_CppSpacePerIndent(cpp) * cpp->indent)), 0);
|
||||
Dqn_CppPrint(cpp, "%.*s", DQN_STR_FMT(prefix));
|
||||
for (int index = 0; index < line_padding; index++)
|
||||
@ -508,62 +540,105 @@ static void Dqn_CGen_EmitRowWhitespace_(Dqn_CGenTableRow const *row, Dqn_CppFile
|
||||
}
|
||||
}
|
||||
|
||||
Dqn_Str8 Dqn_CGen_StripQualifiersOnCppType_(Dqn_Arena *arena, Dqn_Str8 type)
|
||||
{
|
||||
Dqn_TLSTMem tmem = Dqn_TLS_TMem(arena);
|
||||
Dqn_Str8 result = Dqn_Str8_TrimWhitespaceAround(type);
|
||||
result = Dqn_Str8_Replace(result, /*find*/ DQN_STR8("*"), /*replace*/ DQN_STR8(""), /*start_index*/ 0, tmem.arena, Dqn_Str8EqCase_Sensitive);
|
||||
result = Dqn_Str8_Replace(result, /*find*/ DQN_STR8("constexpr"), /*replace*/ DQN_STR8(""), /*start_index*/ 0, tmem.arena, Dqn_Str8EqCase_Sensitive);
|
||||
result = Dqn_Str8_Replace(result, /*find*/ DQN_STR8("const"), /*replace*/ DQN_STR8(""), /*start_index*/ 0, tmem.arena, Dqn_Str8EqCase_Sensitive);
|
||||
result = Dqn_Str8_Replace(result, /*find*/ DQN_STR8("static"), /*replace*/ DQN_STR8(""), /*start_index*/ 0, tmem.arena, Dqn_Str8EqCase_Sensitive);
|
||||
result = Dqn_Str8_Replace(result, /*find*/ DQN_STR8(" "), /*replace*/ DQN_STR8(""), /*start_index*/ 0, arena, Dqn_Str8EqCase_Sensitive);
|
||||
result = Dqn_Str8_TrimWhitespaceAround(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API void Dqn_CGen_EmitCodeForTables(Dqn_CGen *cgen, Dqn_CGenEmit emit, Dqn_CppFile *cpp, Dqn_Str8 emit_prefix)
|
||||
{
|
||||
DQN_ASSERT(Dqn_Str8_HasData(emit_prefix));
|
||||
|
||||
if (emit & Dqn_CGenEmit_Prototypes) {
|
||||
// NOTE: Generate type info enums //////////////////////////////////////////////////////////
|
||||
Dqn_CppEnumBlock(cpp, "%.*s_Type", DQN_STR_FMT(emit_prefix)) {
|
||||
Dqn_CppLine(cpp, "%.*s_Type_Nil,", DQN_STR_FMT(emit_prefix));
|
||||
Dqn_CppEnumBlock(cpp, "%.*sType", DQN_STR_FMT(emit_prefix)) {
|
||||
Dqn_CppLine(cpp, "%.*sType_Nil,", DQN_STR_FMT(emit_prefix));
|
||||
for (Dqn_CGenTable *table = cgen->first_table; table != 0; table = table->next) {
|
||||
for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it);)
|
||||
Dqn_CppLine(cpp, "%.*s_Type_%.*s,", DQN_STR_FMT(emit_prefix), DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string));
|
||||
Dqn_CppLine(cpp, "%.*sType_%.*s,", DQN_STR_FMT(emit_prefix), DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string));
|
||||
}
|
||||
Dqn_CppLine(cpp, "%.*s_Type_Count,", DQN_STR_FMT(emit_prefix));
|
||||
Dqn_CppLine(cpp, "%.*sType_Count,", DQN_STR_FMT(emit_prefix));
|
||||
}
|
||||
Dqn_CppNewLine(cpp);
|
||||
|
||||
// NOTE: Generate structs + enums //////////////////////////////////////////////////////////////
|
||||
for (Dqn_CGenTable *table = cgen->first_table; table != 0; table = table->next) {
|
||||
switch (table->type) {
|
||||
case Dqn_CGenTableType_Nil: DQN_INVALID_CODE_PATH;
|
||||
case Dqn_CGenTableType_Data: continue;
|
||||
case Dqn_CGenTableType_Nil: DQN_INVALID_CODE_PATH;
|
||||
case Dqn_CGenTableType_Count: DQN_INVALID_CODE_PATH;
|
||||
case Dqn_CGenTableType_CodeGenBuiltinTypes: continue;
|
||||
case Dqn_CGenTableType_Data: continue;
|
||||
|
||||
case Dqn_CGenTableType_CodeGenStruct: {
|
||||
|
||||
for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it); ) {
|
||||
// TODO(doyle): Verify the codegen table has the headers from the table it references
|
||||
Dqn_CppStructBlock(cpp, "%.*s", DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string)) {
|
||||
int longest_type_name = 0;
|
||||
for (Dqn_usize row_index = 0; row_index < it.table->row_count; row_index++) {
|
||||
Dqn_TLSTMem tmem = Dqn_TLS_TMem(nullptr);
|
||||
Dqn_CGenTableRow const *row = it.table->rows + row_index;
|
||||
Dqn_CGenLookupColumnAtHeader cpp_type = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppType].string, row);
|
||||
|
||||
Dqn_usize length = cpp_type.column.string.size;
|
||||
Dqn_Str8 find_name = Dqn_CGen_StripQualifiersOnCppType_(tmem.arena, cpp_type.column.string);
|
||||
if (Dqn_CGen_WillCodeGenTypeName(cgen, find_name))
|
||||
length += emit_prefix.size;
|
||||
|
||||
longest_type_name = DQN_MAX(longest_type_name, DQN_CAST(int)length);
|
||||
}
|
||||
|
||||
Dqn_CppStructBlock(cpp, "%.*s%.*s", DQN_STR_FMT(emit_prefix), DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string)) {
|
||||
for (Dqn_usize row_index = 0; row_index < it.table->row_count; row_index++) {
|
||||
Dqn_CGenTableRow const *row = it.table->rows + row_index;
|
||||
Dqn_CGenLookupColumnAtHeader cpp_name = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppName].string, row);
|
||||
Dqn_CGenLookupColumnAtHeader cpp_type = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppType].string, row);
|
||||
Dqn_CGenLookupColumnAtHeader cpp_array_size = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppArraySize].string, row);
|
||||
int name_to_type_padding = 1 + it.table->headers[cpp_type.index].longest_string - DQN_CAST(int) cpp_type.column.string.size;
|
||||
if (cpp_name.column.string.size <= 0 || cpp_type.column.string.size <= 0)
|
||||
continue;
|
||||
Dqn_CGen_EmitRowWhitespace_(row, cpp);
|
||||
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
// NOTE: Generate cpp array size ///////////////////////////////////
|
||||
Dqn_TLSTMem tmem = Dqn_TLS_TMem(nullptr);
|
||||
Dqn_Str8 array_size = {};
|
||||
if (cpp_array_size.column.string.size)
|
||||
array_size = Dqn_Str8_InitF(scratch.arena, "[%.*s]", DQN_STR_FMT(cpp_array_size.column.string));
|
||||
array_size = Dqn_Str8_InitF(tmem.arena, "[%.*s]", DQN_STR_FMT(cpp_array_size.column.string));
|
||||
|
||||
// NOTE: Check if we're referencing a code generated type. If we
|
||||
// are, append the `emit_prefix`
|
||||
Dqn_Str8 emit_cpp_type = cpp_type.column.string;
|
||||
{
|
||||
Dqn_Str8 find_name = Dqn_CGen_StripQualifiersOnCppType_(tmem.arena, emit_cpp_type);
|
||||
if (Dqn_CGen_WillCodeGenTypeName(cgen, find_name))
|
||||
emit_cpp_type = Dqn_Str8_InitF(tmem.arena, "%.*s%.*s", DQN_STR_FMT(emit_prefix), DQN_STR_FMT(cpp_type.column.string));
|
||||
}
|
||||
|
||||
int name_to_type_padding = 1 + longest_type_name - DQN_CAST(int) emit_cpp_type.size;
|
||||
|
||||
// NOTE: Emit decl /////////////////////////////////////////////////
|
||||
Dqn_CGen_EmitRowWhitespace_(row, cpp);
|
||||
Dqn_CppLine(cpp,
|
||||
"%.*s%*s%.*s%.*s;",
|
||||
DQN_STR_FMT(cpp_type.column.string),
|
||||
DQN_STR_FMT(emit_cpp_type),
|
||||
name_to_type_padding,
|
||||
"",
|
||||
DQN_STR_FMT(cpp_name.column.string),
|
||||
DQN_STR_FMT(array_size));
|
||||
}
|
||||
}
|
||||
Dqn_CppNewLine(cpp);
|
||||
Dqn_CppNewLine(cpp);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case Dqn_CGenTableType_CodeGenEnum: {
|
||||
for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it); ) {
|
||||
Dqn_CppEnumBlock(cpp, "%.*s", DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string)) {
|
||||
Dqn_CppEnumBlock(cpp, "%.*s%.*s", DQN_STR_FMT(emit_prefix), DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string)) {
|
||||
Dqn_usize enum_count = 0;
|
||||
for (Dqn_usize row_index = 0; row_index < it.table->row_count; row_index++) {
|
||||
Dqn_CGenTableRow const *row = it.table->rows + row_index;
|
||||
@ -576,13 +651,15 @@ DQN_API void Dqn_CGen_EmitCodeForTables(Dqn_CGen *cgen, Dqn_CGenEmit emit, Dqn_C
|
||||
Dqn_CGen_EmitRowWhitespace_(row, cpp);
|
||||
if (cpp_value.column.string.size) {
|
||||
Dqn_CppLine(cpp,
|
||||
"%.*s_%.*s = %.*s,",
|
||||
"%.*s%.*s_%.*s = %.*s,",
|
||||
DQN_STR_FMT(emit_prefix),
|
||||
DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string),
|
||||
DQN_STR_FMT(cpp_name.column.string),
|
||||
DQN_STR_FMT(cpp_value.column.string));
|
||||
} else {
|
||||
Dqn_CppLine(cpp,
|
||||
"%.*s_%.*s = %zu,",
|
||||
"%.*s%.*s_%.*s = %zu,",
|
||||
DQN_STR_FMT(emit_prefix),
|
||||
DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string),
|
||||
DQN_STR_FMT(cpp_name.column.string),
|
||||
row_index);
|
||||
@ -593,11 +670,13 @@ DQN_API void Dqn_CGen_EmitCodeForTables(Dqn_CGen *cgen, Dqn_CGenEmit emit, Dqn_C
|
||||
Dqn_CGenTableColumn gen_enum_count_column = it.cgen_table_column[Dqn_CGenTableHeaderType_GenEnumCount];
|
||||
if (gen_enum_count_column.string.size)
|
||||
Dqn_CppLine(cpp,
|
||||
"%.*s_%.*s = %zu,",
|
||||
"%.*s%.*s_%.*s = %zu,",
|
||||
DQN_STR_FMT(emit_prefix),
|
||||
DQN_STR_FMT(it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string),
|
||||
DQN_STR_FMT(gen_enum_count_column.string),
|
||||
enum_count);
|
||||
}
|
||||
Dqn_CppNewLine(cpp);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
@ -606,24 +685,27 @@ DQN_API void Dqn_CGen_EmitCodeForTables(Dqn_CGen *cgen, Dqn_CGenEmit emit, Dqn_C
|
||||
// NOTE: Generate enums for struct fields //////////////////////////////////////////////////
|
||||
for (Dqn_CGenTable *table = cgen->first_table; table != 0; table = table->next) {
|
||||
switch (table->type) {
|
||||
case Dqn_CGenTableType_Nil: DQN_INVALID_CODE_PATH;
|
||||
case Dqn_CGenTableType_Data: continue;
|
||||
case Dqn_CGenTableType_CodeGenEnum: continue;
|
||||
case Dqn_CGenTableType_Nil: DQN_INVALID_CODE_PATH;
|
||||
case Dqn_CGenTableType_Count: DQN_INVALID_CODE_PATH;
|
||||
case Dqn_CGenTableType_Data: continue;
|
||||
case Dqn_CGenTableType_CodeGenBuiltinTypes: continue;
|
||||
case Dqn_CGenTableType_CodeGenEnum: continue;
|
||||
|
||||
case Dqn_CGenTableType_CodeGenStruct: {
|
||||
for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it); ) {
|
||||
Dqn_Str8 struct_name = it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string;
|
||||
Dqn_CppEnumBlock(cpp, "%.*sTypeField", DQN_STR_FMT(struct_name)) {
|
||||
Dqn_CppEnumBlock(cpp, "%.*s%.*sTypeField", DQN_STR_FMT(emit_prefix), DQN_STR_FMT(struct_name)) {
|
||||
for (Dqn_usize row_index = 0; row_index < it.table->row_count; row_index++) {
|
||||
Dqn_CGenTableRow const *row = it.table->rows + row_index;
|
||||
Dqn_CGenLookupColumnAtHeader cpp_name = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppName].string, row);
|
||||
if (cpp_name.column.string.size <= 0)
|
||||
continue;
|
||||
Dqn_CGen_EmitRowWhitespace_(row, cpp);
|
||||
Dqn_CppLine(cpp, "%.*sTypeField_%.*s,", DQN_STR_FMT(struct_name), DQN_STR_FMT(cpp_name.column.string));
|
||||
Dqn_CppLine(cpp, "%.*s%.*sTypeField_%.*s,", DQN_STR_FMT(emit_prefix), DQN_STR_FMT(struct_name), DQN_STR_FMT(cpp_name.column.string));
|
||||
}
|
||||
Dqn_CppLine(cpp, "%.*sTypeField_Count,", DQN_STR_FMT(struct_name));
|
||||
Dqn_CppLine(cpp, "%.*s%.*sTypeField_Count,", DQN_STR_FMT(emit_prefix), DQN_STR_FMT(struct_name));
|
||||
}
|
||||
Dqn_CppNewLine(cpp);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
@ -636,10 +718,11 @@ DQN_API void Dqn_CGen_EmitCodeForTables(Dqn_CGen *cgen, Dqn_CGenEmit emit, Dqn_C
|
||||
|
||||
for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it);) {
|
||||
Dqn_Str8 type_name = it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string;
|
||||
Dqn_CppStructBlock(cpp, "%.*sStr8ToEnumResult", DQN_STR_FMT(type_name)) {
|
||||
Dqn_CppStructBlock(cpp, "%.*s%.*sStr8ToEnumResult", DQN_STR_FMT(emit_prefix), DQN_STR_FMT(type_name)) {
|
||||
Dqn_CppLine(cpp, "bool success;");
|
||||
Dqn_CppLine(cpp, "%.*s value;", DQN_STR_FMT(type_name));
|
||||
Dqn_CppLine(cpp, "%.*s%.*s value;", DQN_STR_FMT(emit_prefix), DQN_STR_FMT(type_name));
|
||||
}
|
||||
Dqn_CppNewLine(cpp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -649,7 +732,12 @@ DQN_API void Dqn_CGen_EmitCodeForTables(Dqn_CGen *cgen, Dqn_CGenEmit emit, Dqn_C
|
||||
|
||||
for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it);) {
|
||||
Dqn_Str8 type_name = it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string;
|
||||
Dqn_CppLine(cpp, "%.*sStr8ToEnumResult %.*s_Str8ToEnum(Dqn_Str8 string);", DQN_STR_FMT(type_name), DQN_STR_FMT(type_name));
|
||||
Dqn_CppLine(cpp,
|
||||
"%.*s%.*sStr8ToEnumResult %.*s%.*s_Str8ToEnum(Dqn_Str8 string);",
|
||||
DQN_STR_FMT(emit_prefix),
|
||||
DQN_STR_FMT(type_name),
|
||||
DQN_STR_FMT(emit_prefix),
|
||||
DQN_STR_FMT(type_name));
|
||||
}
|
||||
}
|
||||
|
||||
@ -664,8 +752,18 @@ DQN_API void Dqn_CGen_EmitCodeForTables(Dqn_CGen *cgen, Dqn_CGenEmit emit, Dqn_C
|
||||
continue;
|
||||
|
||||
Dqn_Str8 type_name = it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string;
|
||||
Dqn_CppLine(cpp, "bool operator==(%.*s const &lhs, %.*s const &rhs);", DQN_STR_FMT(type_name), DQN_STR_FMT(type_name));
|
||||
Dqn_CppLine(cpp, "bool operator!=(%.*s const &lhs, %.*s const &rhs);", DQN_STR_FMT(type_name), DQN_STR_FMT(type_name));
|
||||
Dqn_CppLine(cpp,
|
||||
"bool operator==(%.*s%.*s const &lhs, %.*s%.*s const &rhs);",
|
||||
DQN_STR_FMT(emit_prefix),
|
||||
DQN_STR_FMT(type_name),
|
||||
DQN_STR_FMT(emit_prefix),
|
||||
DQN_STR_FMT(type_name));
|
||||
Dqn_CppLine(cpp,
|
||||
"bool operator!=(%.*s%.*s const &lhs, %.*s%.*s const &rhs);",
|
||||
DQN_STR_FMT(emit_prefix),
|
||||
DQN_STR_FMT(type_name),
|
||||
DQN_STR_FMT(emit_prefix),
|
||||
DQN_STR_FMT(type_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -679,8 +777,29 @@ DQN_API void Dqn_CGen_EmitCodeForTables(Dqn_CGen *cgen, Dqn_CGenEmit emit, Dqn_C
|
||||
continue;
|
||||
|
||||
Dqn_Str8 struct_or_enum_name = it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string;
|
||||
Dqn_CppBlock(cpp, ";\n\n", "Dqn_TypeField const g_%.*s_type_fields[] =", DQN_STR_FMT(struct_or_enum_name)) {
|
||||
Dqn_CppBlock(cpp, ";\n\n", "Dqn_TypeField const g_%.*s%.*s_type_fields[] =", DQN_STR_FMT(emit_prefix), DQN_STR_FMT(struct_or_enum_name)) {
|
||||
if (table->type == Dqn_CGenTableType_CodeGenStruct) {
|
||||
|
||||
// NOTE: Construct the cpp type string first. We will prepend `emit_prefix`
|
||||
// for types that are declared in the same mdesk file. We will also
|
||||
// calculate the longest type name that we will generate for whitespace
|
||||
// padding purposes.
|
||||
Dqn_TLSTMem tmem = Dqn_TLS_PushTMem(nullptr);
|
||||
Dqn_usize longest_cpp_type_name = 0;
|
||||
auto cpp_type_list = Dqn_SArray_Init<Dqn_Str8>(tmem.arena, it.table->row_count, Dqn_ZeroMem_Yes);
|
||||
|
||||
for (Dqn_usize row_index = 0; row_index < it.table->row_count; row_index++) {
|
||||
Dqn_CGenTableRow const *row = it.table->rows + row_index;
|
||||
Dqn_CGenLookupColumnAtHeader cpp_type = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppType].string, row);
|
||||
Dqn_Str8 cpp_type_name = Dqn_CGen_StripQualifiersOnCppType_(tmem.arena, cpp_type.column.string);
|
||||
if (Dqn_CGen_WillCodeGenTypeName(cgen, cpp_type_name))
|
||||
cpp_type_name = Dqn_Str8_InitF_TLS("%.*s%.*s", DQN_STR_FMT(emit_prefix), DQN_STR_FMT(cpp_type_name));
|
||||
|
||||
longest_cpp_type_name = DQN_MAX(longest_cpp_type_name, cpp_type_name.size);
|
||||
Dqn_SArray_Add(&cpp_type_list, cpp_type_name);
|
||||
}
|
||||
|
||||
// NOTE: Iterate each row and emit the C++ declarations ////////////////////
|
||||
for (Dqn_usize row_index = 0; row_index < it.table->row_count; row_index++) {
|
||||
Dqn_CGenTableRow const *row = it.table->rows + row_index;
|
||||
Dqn_CGenLookupColumnAtHeader cpp_name = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppName].string, row);
|
||||
@ -688,12 +807,12 @@ DQN_API void Dqn_CGen_EmitCodeForTables(Dqn_CGen *cgen, Dqn_CGenEmit emit, Dqn_C
|
||||
Dqn_CGenLookupColumnAtHeader cpp_is_ptr = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppIsPtr].string, row);
|
||||
Dqn_CGenLookupColumnAtHeader cpp_array_size = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppArraySize].string, row);
|
||||
Dqn_CGenLookupColumnAtHeader cpp_array_size_field = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppArraySizeField].string, row);
|
||||
Dqn_CGenLookupColumnAtHeader cpp_label = Dqn_CGen_LookupColumnAtHeader(it.table, it.cgen_table_column[Dqn_CGenTableHeaderType_CppLabel].string, row);
|
||||
|
||||
bool cpp_is_ptr_b32 = cpp_is_ptr.column.string == DQN_STR8("true");
|
||||
Dqn_Str8 cpp_array_size_str8 = Dqn_Str8_HasData(cpp_array_size.column.string) ? cpp_array_size.column.string : DQN_STR8("0");
|
||||
|
||||
Dqn_CGenTableColumn struct_name = it.cgen_table_row->columns[table->column_indexes[Dqn_CGenTableHeaderType_Name]];
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8 cpp_array_size_field_str8 = DQN_STR8("NULL");
|
||||
if (cpp_array_size_field.column.string.size) {
|
||||
|
||||
@ -707,57 +826,100 @@ DQN_API void Dqn_CGen_EmitCodeForTables(Dqn_CGen *cgen, Dqn_CGenEmit emit, Dqn_C
|
||||
if (sub_cpp_name.string == cpp_array_size_field.column.string)
|
||||
index_the_field_references = sub_row_index;
|
||||
}
|
||||
cpp_array_size_field_str8 = Dqn_Str8_InitF(scratch.arena,
|
||||
"&g_%.*s_type_fields[%zu]",
|
||||
DQN_STR_FMT(struct_name.string),
|
||||
index_the_field_references);
|
||||
cpp_array_size_field_str8 =
|
||||
Dqn_Str8_InitF_TLS("&g_%.*s%.*s_type_fields[%zu]",
|
||||
DQN_STR_FMT(emit_prefix),
|
||||
DQN_STR_FMT(struct_name.string),
|
||||
index_the_field_references);
|
||||
}
|
||||
|
||||
Dqn_Str8 orig_cpp_type_info = Dqn_Str8_InitF(scratch.arena, "%.*s", DQN_STR_FMT(cpp_type.column.string));
|
||||
Dqn_Str8 cpp_type_info = orig_cpp_type_info;
|
||||
cpp_type_info = Dqn_Str8_Replace(cpp_type_info, /*find*/ DQN_STR8("*"), /*replace*/ DQN_STR8(""), /*start_index*/ 0, scratch.arena, Dqn_Str8EqCase_Sensitive);
|
||||
cpp_type_info = Dqn_Str8_Replace(cpp_type_info, /*find*/ DQN_STR8("constexpr"), /*replace*/ DQN_STR8(""), /*start_index*/ 0, scratch.arena, Dqn_Str8EqCase_Sensitive);
|
||||
cpp_type_info = Dqn_Str8_Replace(cpp_type_info, /*find*/ DQN_STR8("const"), /*replace*/ DQN_STR8(""), /*start_index*/ 0, scratch.arena, Dqn_Str8EqCase_Sensitive);
|
||||
cpp_type_info = Dqn_Str8_Replace(cpp_type_info, /*find*/ DQN_STR8("static"), /*replace*/ DQN_STR8(""), /*start_index*/ 0, scratch.arena, Dqn_Str8EqCase_Sensitive);
|
||||
cpp_type_info = |