From 158d058d5d563ddb9ccf74b87b686d621ef2cadd Mon Sep 17 00:00:00 2001 From: doylet Date: Tue, 19 Mar 2024 23:11:00 +1100 Subject: [PATCH] Import latest revision of dqn lib from CSIGHT --- Standalone/dqn_cpp_file.h | 2 +- dqn_allocator.cpp | 14 ++- dqn_allocator.h | 3 +- dqn_base.cpp | 14 ++- dqn_base.h | 5 +- dqn_cgen.cpp | 37 ++++++- dqn_cgen.h | 3 + dqn_containers.h | 12 +-- dqn_helpers.cpp | 200 ++++++++++++++++++++++++++++---------- dqn_helpers.h | 25 ++++- dqn_os.h | 3 +- dqn_os_posix.cpp | 4 +- dqn_os_win32.cpp | 4 +- dqn_string.cpp | 22 +++++ dqn_string.h | 2 + dqn_type_info.h | 1 + 16 files changed, 270 insertions(+), 81 deletions(-) diff --git a/Standalone/dqn_cpp_file.h b/Standalone/dqn_cpp_file.h index 6e4590e..6f67354 100644 --- a/Standalone/dqn_cpp_file.h +++ b/Standalone/dqn_cpp_file.h @@ -71,7 +71,7 @@ void Dqn_CppPrint(Dqn_CppFile *cpp, char const *fmt, ...); #define Dqn_CppForBlock(cpp, fmt, ...) \ for (bool DQN_CPP_TOKEN_PASTE_(once_, __LINE__) = \ - (Dqn_CppBeginForBLock(cpp, fmt, ##__VA_ARGS__), true); \ + (Dqn_CppBeginForBlock(cpp, fmt, ##__VA_ARGS__), true); \ DQN_CPP_TOKEN_PASTE_(once_, __LINE__); \ DQN_CPP_TOKEN_PASTE_(once_, __LINE__) = (Dqn_CppEndForBlock(cpp), false)) diff --git a/dqn_allocator.cpp b/dqn_allocator.cpp index 9b05744..ca4e810 100644 --- a/dqn_allocator.cpp +++ b/dqn_allocator.cpp @@ -220,7 +220,7 @@ DQN_API void Dqn_Arena_Pop(Dqn_Arena *arena, uint64_t amount) Dqn_Arena_PopTo(arena, pop_to); } -DQN_API uint64_t Dqn_Arena_Pos(Dqn_Arena *arena) +DQN_API uint64_t Dqn_Arena_Pos(Dqn_Arena const *arena) { uint64_t result = (arena && arena->curr) ? arena->curr->reserve_sum + arena->curr->used : 0; return result; @@ -231,6 +231,18 @@ DQN_API void Dqn_Arena_Clear(Dqn_Arena *arena) Dqn_Arena_PopTo(arena, 0); } +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; ) { + 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; + } + return result; +} + DQN_API Dqn_ArenaTempMem Dqn_Arena_TempMemBegin(Dqn_Arena *arena) { Dqn_ArenaTempMem result = {}; diff --git a/dqn_allocator.h b/dqn_allocator.h index 5c30951..ec1c2bb 100644 --- a/dqn_allocator.h +++ b/dqn_allocator.h @@ -145,8 +145,9 @@ DQN_API void * Dqn_Arena_AllocContiguous (Dqn_Arena *arena, DQN_API void * Dqn_Arena_Copy (Dqn_Arena *arena, void const *data, uint64_t size, uint8_t align); DQN_API void Dqn_Arena_PopTo (Dqn_Arena *arena, uint64_t init_used); DQN_API void Dqn_Arena_Pop (Dqn_Arena *arena, uint64_t amount); -DQN_API uint64_t Dqn_Arena_Pos (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_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) diff --git a/dqn_base.cpp b/dqn_base.cpp index 5c845f4..31043e3 100644 --- a/dqn_base.cpp +++ b/dqn_base.cpp @@ -419,6 +419,12 @@ DQN_API Dqn_ErrorSink *Dqn_ErrorSink_Begin(Dqn_ErrorSinkMode mode) return result; } +DQN_API bool Dqn_ErrorSink_HasError(Dqn_ErrorSink *error) +{ + bool result = error && error->stack->error; + return result; +} + DQN_API Dqn_ErrorSinkNode Dqn_ErrorSink_End(Dqn_Arena *arena, Dqn_ErrorSink *error) { Dqn_ErrorSinkNode result = {}; @@ -445,7 +451,7 @@ DQN_API bool Dqn_ErrorSink_EndAndLogError(Dqn_ErrorSink *error, Dqn_Str8 error_m Dqn_ErrorSinkNode node = Dqn_ErrorSink_End(scratch.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)); + Dqn_Log_TypeFCallSite(Dqn_LogType_Error, node.call_site, "%.*s: %.*s", DQN_STR_FMT(error_msg), DQN_STR_FMT(node.msg)); } else { Dqn_Log_TypeFCallSite(Dqn_LogType_Error, node.call_site, "%.*s", DQN_STR_FMT(node.msg)); } @@ -475,8 +481,10 @@ DQN_API bool Dqn_ErrorSink_EndAndLogErrorF(Dqn_ErrorSink *error, DQN_FMT_ATTRIB DQN_API void Dqn_ErrorSink_EndAndExitIfErrorFV(Dqn_ErrorSink *error, uint32_t exit_code, DQN_FMT_ATTRIB char const *fmt, va_list args) { - if (Dqn_ErrorSink_EndAndLogErrorFV(error, fmt, args)) + if (Dqn_ErrorSink_EndAndLogErrorFV(error, fmt, args)) { + DQN_DEBUG_BREAK; Dqn_OS_Exit(exit_code); + } } DQN_API void Dqn_ErrorSink_EndAndExitIfErrorF(Dqn_ErrorSink *error, uint32_t exit_code, DQN_FMT_ATTRIB char const *fmt, ...) @@ -500,7 +508,7 @@ DQN_API void Dqn_ErrorSink_MakeFV_(Dqn_ErrorSink *error, uint32_t error_code, DQ node->error = true; node->call_site = Dqn_ThreadContext_Get()->call_site; if (node->mode == Dqn_ErrorSinkMode_ExitOnError) - Dqn_ErrorSink_EndAndExitIfErrorF(error, error_code, "Fatal error encountered: (%u) %.*s", error_code, DQN_STR_FMT(node->msg)); + Dqn_ErrorSink_EndAndExitIfErrorF(error, error_code, "Fatal error %u", error_code); } } diff --git a/dqn_base.h b/dqn_base.h index 77144d2..bf9f15b 100644 --- a/dqn_base.h +++ b/dqn_base.h @@ -285,8 +285,8 @@ } while (0) #endif -#define DQN_INVALID_CODE_PATHF(fmt, ...) DQN_ASSERTF(0, fmt, ##__VA_ARGS__) -#define DQN_INVALID_CODE_PATH DQN_INVALID_CODE_PATHF("Invalid code path triggered") +#define DQN_INVALID_CODE_PATHF(fmt, ...) DQN_HARD_ASSERTF(0, fmt, ##__VA_ARGS__) +#define DQN_INVALID_CODE_PATH DQN_INVALID_CODE_PATHF("Invalid code path triggered") // NOTE: Check macro /////////////////////////////////////////////////////////////////////////////// #define DQN_CHECK(expr) DQN_CHECKF(expr, "") @@ -621,6 +621,7 @@ DQN_API void Dqn_Log_FCallSite // NOTE: [$ERRS] Dqn_ErrorSink ///////////////////////////////////////////////////////////////////// DQN_API Dqn_ErrorSink * Dqn_ErrorSink_Begin (Dqn_ErrorSinkMode mode); +DQN_API bool Dqn_ErrorSink_HasError (Dqn_ErrorSink *error); DQN_API Dqn_ErrorSinkNode Dqn_ErrorSink_End (Dqn_Arena *arena, Dqn_ErrorSink *error); DQN_API bool Dqn_ErrorSink_EndAndLogError (Dqn_ErrorSink *error, Dqn_Str8 error_msg); DQN_API bool Dqn_ErrorSink_EndAndLogErrorFV (Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, va_list args); diff --git a/dqn_cgen.cpp b/dqn_cgen.cpp index 0b50fca..8a8df0c 100644 --- a/dqn_cgen.cpp +++ b/dqn_cgen.cpp @@ -105,6 +105,9 @@ static bool Dqn_CGen_GatherTables_(Dqn_CGen *cgen, Dqn_ErrorSink *error) DQN_ARRAY_UCOUNT(DQN_CGEN_TABLE_TYPE_LIST), "Table 'type' specified invalid value"); table->type = DQN_CAST(Dqn_CGenTableType) table_type_validator.enum_val; + + DQN_ASSERT(table->type <= Dqn_CGenTableType_Count); + cgen->table_counts[table->type]++; } break; } } @@ -454,6 +457,7 @@ DQN_API bool Dqn_CGen_LookupNextTableInCodeGenTable(Dqn_CGen *cgen, Dqn_CGenTabl // NOTE: Lookup the table in this row that we will code generate from. Not // applicable when we are doing builtin types as the types are just put // in-line into the code generation table itself. + it->cgen_table = cgen_table; it->cgen_table_row = cgen_table->rows + it->row_index++; if (cgen_table->type != Dqn_CGenTableType_CodeGenBuiltinTypes) { Dqn_CGenTableColumn cgen_table_column = it->cgen_table_row->columns[cgen_table->column_indexes[Dqn_CGenTableHeaderType_Table]]; @@ -752,7 +756,7 @@ DQN_API void Dqn_CGen_EmitCodeForTables(Dqn_CGen *cgen, Dqn_CGenEmit emit, Dqn_C } Dqn_CppBlock(cpp, ";\n\n", "Dqn_TypeInfo const g_%.*s_types[] =", DQN_STR_FMT(emit_prefix)) { - Dqn_CppLine(cpp, "{DQN_STR8(\"\"),%*sDqn_TypeKind_Nil, /*fields*/ NULL, /*count*/ 0},", 1 + longest_name_across_all_tables, ""); + Dqn_CppLine(cpp, "{DQN_STR8(\"\"),%*sDqn_TypeKind_Nil, 0, /*fields*/ NULL, /*count*/ 0},", 1 + longest_name_across_all_tables, ""); for (Dqn_CGenTable *table = cgen->first_table; table != 0; table = table->next) { for (Dqn_CGenLookupTableIterator it = {}; Dqn_CGen_LookupNextTableInCodeGenTable(cgen, table, &it);) { Dqn_Str8 type_name = it.cgen_table_column[Dqn_CGenTableHeaderType_Name].string; @@ -794,16 +798,45 @@ DQN_API void Dqn_CGen_EmitCodeForTables(Dqn_CGen *cgen, Dqn_CGenEmit emit, Dqn_C } Dqn_CppLine(cpp, - "{DQN_STR8(\"%.*s\"),%*s%.*s, %s/*fields*/ %.*s,%*s/*count*/ %.*s},", + "{DQN_STR8(\"%.*s\"),%*s%.*s, %ssizeof(%.*s),%*s/*fields*/ %.*s,%*s/*count*/ %.*s},", DQN_STR_FMT(type_name), name_padding, "", DQN_STR_FMT(type_info_kind), type_info_kind_padding, + DQN_STR_FMT(type_name), + name_padding, "", DQN_STR_FMT(fields), fields_padding, "", DQN_STR_FMT(fields_count)); } } } + + for (Dqn_CGenTable *table = cgen->first_table; table != 0; table = table->next) { + if (table->type != Dqn_CGenTableType_CodeGenEnum) + continue; + + 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_CppLine(cpp, "bool success;"); + Dqn_CppLine(cpp, "%.*s value;", DQN_STR_FMT(type_name)); + } + + Dqn_CppFuncBlock(cpp, "%.*sStr8ToEnumResult %.*s_Str8ToEnum(Dqn_Str8 string)", DQN_STR_FMT(type_name), DQN_STR_FMT(type_name)) { + Dqn_CppLine(cpp, "%.*sStr8ToEnumResult result = {};", DQN_STR_FMT(type_name)); + Dqn_CppForBlock(cpp, "Dqn_usize index = 0; !result.success && index < DQN_ARRAY_UCOUNT(g_%.*s_type_fields); index++", DQN_STR_FMT(type_name)) { + Dqn_CppIfChain(cpp) { + Dqn_CppLine(cpp, "Dqn_TypeField field = g_%.*s_type_fields[index];", DQN_STR_FMT(type_name)); + Dqn_CppIfOrElseIfBlock(cpp, "string == field.name") { + Dqn_CppLine(cpp, "result.success = true;"); + Dqn_CppLine(cpp, "result.value = (%.*s)index;", DQN_STR_FMT(type_name)); + } + } + } + Dqn_CppLine(cpp, "return result;"); + } + } + } } } diff --git a/dqn_cgen.h b/dqn_cgen.h index 08ed922..9471619 100644 --- a/dqn_cgen.h +++ b/dqn_cgen.h @@ -43,6 +43,7 @@ enum Dqn_CGenTableType Dqn_CGenTableType_CodeGenBuiltinTypes, Dqn_CGenTableType_CodeGenStruct, Dqn_CGenTableType_CodeGenEnum, + Dqn_CGenTableType_Count, }; enum Dqn_CGenTableRowTagType @@ -123,6 +124,7 @@ struct Dqn_CGen MD_Map table_map; Dqn_CGenTable *first_table; Dqn_CGenTable *last_table; + Dqn_usize table_counts[Dqn_CGenTableType_Count]; }; struct Dqn_CGenMapNodeToEnum @@ -133,6 +135,7 @@ struct Dqn_CGenMapNodeToEnum struct Dqn_CGenLookupTableIterator { + Dqn_CGenTable *cgen_table; Dqn_CGenTableRow *cgen_table_row; Dqn_CGenTableColumn cgen_table_column[Dqn_CGenTableHeaderType_Count]; Dqn_CGenTable *table; diff --git a/dqn_containers.h b/dqn_containers.h index bd45f16..3cd73ba 100644 --- a/dqn_containers.h +++ b/dqn_containers.h @@ -400,11 +400,11 @@ template T *Dqn_CArray_InsertArray(T *data, Dqn_usize *size, Dqn_us Dqn_usize clamped_index = DQN_MIN(index, *size); if (clamped_index != *size) { - char const *src = DQN_CAST(char *)(data + clamped_index); - char const *dest = DQN_CAST(char *)(data + (clamped_index + count)); - char const *end = DQN_CAST(char *)(data + (*size)); - Dqn_usize bytes_to_move = end - src; - DQN_MEMMOVE(DQN_CAST(void *)dest, src, bytes_to_move); + char const *src = DQN_CAST(char *)(data + clamped_index); + char const *dest = DQN_CAST(char *)(data + (clamped_index + count)); + char const *end = DQN_CAST(char *)(data + (*size)); + Dqn_usize bytes_to_move = end - src; + DQN_MEMMOVE(DQN_CAST(void *) dest, src, bytes_to_move); } result = data + clamped_index; @@ -561,7 +561,7 @@ template T *Dqn_VArray_InsertArray(Dqn_VArray *array, Dqn_usize T *result = nullptr; if (!Dqn_VArray_IsValid(array)) return result; - if (Dqn_VArray_Reserve(array, count)) + if (Dqn_VArray_Reserve(array, array->size + count)) result = Dqn_CArray_InsertArray(array->data, &array->size, array->max, index, items, count); return result; } diff --git a/dqn_helpers.cpp b/dqn_helpers.cpp index d9d923f..c0a2ab6 100644 --- a/dqn_helpers.cpp +++ b/dqn_helpers.cpp @@ -523,8 +523,7 @@ DQN_API uint32_t Dqn_Safe_SubU32(uint32_t a, uint32_t b) return result; } -// NOTE: Dqn_Safe_SaturateCastUSizeToI* -// ----------------------------------------------------------------------------- +// NOTE: Dqn_Safe_SaturateCastUSizeToI* //////////////////////////////////////////////////////////// // INT*_MAX literals will be promoted to the type of uintmax_t as uintmax_t is // the highest possible rank (unsigned > signed). DQN_API int Dqn_Safe_SaturateCastUSizeToInt(Dqn_usize val) @@ -557,8 +556,7 @@ DQN_API int64_t Dqn_Safe_SaturateCastUSizeToI64(Dqn_usize val) return result; } -// NOTE: Dqn_Safe_SaturateCastUSizeToU* -// ----------------------------------------------------------------------------- +// NOTE: Dqn_Safe_SaturateCastUSizeToU* //////////////////////////////////////////////////////////// // Both operands are unsigned and the lowest rank operand will be promoted to // match the highest rank operand. DQN_API uint8_t Dqn_Safe_SaturateCastUSizeToU8(Dqn_usize val) @@ -624,8 +622,7 @@ DQN_API uint32_t Dqn_Safe_SaturateCastU64ToU32(uint64_t val) return result; } -// NOTE: Dqn_Safe_SaturateCastISizeToI* -// ----------------------------------------------------------------------------- +// NOTE: Dqn_Safe_SaturateCastISizeToI* //////////////////////////////////////////////////////////// // Both operands are signed so the lowest rank operand will be promoted to // match the highest rank operand. DQN_API int Dqn_Safe_SaturateCastISizeToInt(Dqn_isize val) @@ -663,8 +660,7 @@ DQN_API int64_t Dqn_Safe_SaturateCastISizeToI64(Dqn_isize val) return result; } -// NOTE: Dqn_Safe_SaturateCastISizeToU* -// ----------------------------------------------------------------------------- +// NOTE: Dqn_Safe_SaturateCastISizeToU* //////////////////////////////////////////////////////////// // If the value is a negative integer, we clamp to 0. Otherwise, we know that // the value is >=0, we can upcast safely to bounds check against the maximum // allowed value. @@ -728,8 +724,7 @@ DQN_API uint64_t Dqn_Safe_SaturateCastISizeToU64(Dqn_isize val) return result; } -// NOTE: Dqn_Safe_SaturateCastI64To* -// ----------------------------------------------------------------------------- +// NOTE: Dqn_Safe_SaturateCastI64To* /////////////////////////////////////////////////////////////// // Both operands are signed so the lowest rank operand will be promoted to // match the highest rank operand. DQN_API Dqn_isize Dqn_Safe_SaturateCastI64ToISize(int64_t val) @@ -760,8 +755,79 @@ DQN_API int32_t Dqn_Safe_SaturateCastI64ToI32(int64_t val) return result; } -// NOTE: Dqn_Safe_SaturateCastIntTo* -// ----------------------------------------------------------------------------- +DQN_API unsigned int Dqn_Safe_SaturateCastI64ToUInt(int64_t val) +{ + unsigned int result = 0; + if (DQN_CHECK(val >= DQN_CAST(int64_t) 0)) { + if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT_MAX)) + result = DQN_CAST(unsigned int) val; + else + result = UINT_MAX; + } + return result; +} + +DQN_API Dqn_isize Dqn_Safe_SaturateCastI64ToUSize(int64_t val) +{ + Dqn_usize result = 0; + if (DQN_CHECK(val >= DQN_CAST(int64_t) 0)) { + if (DQN_CHECK(DQN_CAST(uintmax_t) val <= DQN_USIZE_MAX)) + result = DQN_CAST(Dqn_usize) val; + else + result = DQN_USIZE_MAX; + } + return result; +} + +DQN_API uint8_t Dqn_Safe_SaturateCastI64ToU8(int64_t val) +{ + uint8_t result = 0; + if (DQN_CHECK(val >= DQN_CAST(int64_t) 0)) { + if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT8_MAX)) + result = DQN_CAST(uint8_t) val; + else + result = UINT8_MAX; + } + return result; +} + +DQN_API uint16_t Dqn_Safe_SaturateCastI64ToU16(int64_t val) +{ + uint16_t result = 0; + if (DQN_CHECK(val >= DQN_CAST(int64_t) 0)) { + if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT16_MAX)) + result = DQN_CAST(uint16_t) val; + else + result = UINT16_MAX; + } + return result; +} + +DQN_API uint32_t Dqn_Safe_SaturateCastI64ToU32(int64_t val) +{ + uint32_t result = 0; + if (DQN_CHECK(val >= DQN_CAST(int64_t) 0)) { + if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT32_MAX)) + result = DQN_CAST(uint32_t) val; + else + result = UINT32_MAX; + } + return result; +} + +DQN_API uint64_t Dqn_Safe_SaturateCastI64ToU64(int64_t val) +{ + uint64_t result = 0; + if (DQN_CHECK(val >= DQN_CAST(int64_t) 0)) { + if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT64_MAX)) + result = DQN_CAST(uint64_t) val; + else + result = UINT64_MAX; + } + return result; +} + +// NOTE: Dqn_Safe_SaturateCastIntTo* /////////////////////////////////////////////////////////////// DQN_API int8_t Dqn_Safe_SaturateCastIntToI8(int val) { DQN_CHECK(val >= INT8_MIN && val <= INT8_MAX); @@ -1260,87 +1326,113 @@ void Dqn_Profiler_Dump(uint64_t tsc_per_second) // NOTE: [$JOBQ] Dqn_JobQueue /////////////////////////////////////////////////////////////////////// DQN_API Dqn_JobQueueSPMC Dqn_OS_JobQueueSPMCInit() { - Dqn_JobQueueSPMC result = {}; - result.thread_wait_for_job_semaphore = Dqn_OS_SemaphoreInit(0 /*initial_count*/); - result.wait_for_completion_semaphore = Dqn_OS_SemaphoreInit(0 /*initial_count*/); - result.mutex = Dqn_OS_MutexInit(); + Dqn_JobQueueSPMC result = {}; + result.thread_wait_for_job_semaphore = Dqn_OS_SemaphoreInit(0 /*initial_count*/); + result.wait_for_completion_semaphore = Dqn_OS_SemaphoreInit(0 /*initial_count*/); + result.complete_queue_write_semaphore = Dqn_OS_SemaphoreInit(DQN_ARRAY_UCOUNT(result.complete_queue)); + result.mutex = Dqn_OS_MutexInit(); return result; } -DQN_API bool Dqn_OS_JobQueueSPMCAddArray(Dqn_JobQueueSPMC *job_queue, Dqn_Job *jobs, uint32_t count) +DQN_API bool Dqn_OS_JobQueueSPMCAddArray(Dqn_JobQueueSPMC *queue, Dqn_Job *jobs, uint32_t count) { - if (!job_queue) + if (!queue) return false; - uint32_t const pot_mask = DQN_ARRAY_UCOUNT(job_queue->jobs) - 1; - uint32_t read_index = job_queue->read_index; - uint32_t write_index = job_queue->write_index; + uint32_t const pot_mask = DQN_ARRAY_UCOUNT(queue->jobs) - 1; + uint32_t read_index = queue->read_index; + uint32_t write_index = queue->write_index; uint32_t size = write_index - read_index; - if ((size + count) > DQN_ARRAY_UCOUNT(job_queue->jobs)) + if ((size + count) > DQN_ARRAY_UCOUNT(queue->jobs)) return false; for (size_t offset = 0; offset < count; offset++) { uint32_t wrapped_write_index = (write_index + offset) & pot_mask; - job_queue->jobs[wrapped_write_index] = jobs[offset]; + queue->jobs[wrapped_write_index] = jobs[offset]; } - Dqn_OS_MutexLock(&job_queue->mutex); - job_queue->write_index += count; - Dqn_OS_SemaphoreIncrement(&job_queue->thread_wait_for_job_semaphore, count); - Dqn_OS_MutexUnlock(&job_queue->mutex); + Dqn_OS_MutexLock(&queue->mutex); + queue->write_index += count; + Dqn_OS_SemaphoreIncrement(&queue->thread_wait_for_job_semaphore, count); + Dqn_OS_MutexUnlock(&queue->mutex); return true; } -DQN_API bool Dqn_OS_JobQueueSPMCAdd(Dqn_JobQueueSPMC *job_queue, Dqn_Job job) +DQN_API bool Dqn_OS_JobQueueSPMCAdd(Dqn_JobQueueSPMC *queue, Dqn_Job job) { - bool result = Dqn_OS_JobQueueSPMCAddArray(job_queue, &job, 1); + bool result = Dqn_OS_JobQueueSPMCAddArray(queue, &job, 1); return result; } DQN_API int32_t Dqn_OS_JobQueueSPMCThread(Dqn_OSThread *thread) { - Dqn_JobQueueSPMC *job_queue = DQN_CAST(Dqn_JobQueueSPMC *) thread->user_context; - uint32_t const pot_mask = DQN_ARRAY_UCOUNT(job_queue->jobs) - 1; + Dqn_JobQueueSPMC *queue = DQN_CAST(Dqn_JobQueueSPMC *) thread->user_context; + uint32_t const pot_mask = DQN_ARRAY_UCOUNT(queue->jobs) - 1; + static_assert(DQN_ARRAY_UCOUNT(queue->jobs) == DQN_ARRAY_UCOUNT(queue->complete_queue), "PoT mask is used to mask access to both arrays"); for (;;) { - Dqn_OS_SemaphoreWait(&job_queue->thread_wait_for_job_semaphore, DQN_OS_SEMAPHORE_INFINITE_TIMEOUT); - if (job_queue->quit) + Dqn_OS_SemaphoreWait(&queue->thread_wait_for_job_semaphore, DQN_OS_SEMAPHORE_INFINITE_TIMEOUT); + if (queue->quit) break; - DQN_ASSERT(job_queue->read_index != job_queue->write_index); + DQN_ASSERT(queue->read_index != queue->write_index); - Dqn_OS_MutexLock(&job_queue->mutex); - uint32_t wrapped_read_index = job_queue->read_index & pot_mask; - Dqn_Job job = job_queue->jobs[wrapped_read_index]; - job_queue->read_index += 1; - Dqn_OS_MutexUnlock(&job_queue->mutex); + Dqn_OS_MutexLock(&queue->mutex); + uint32_t wrapped_read_index = queue->read_index & pot_mask; + Dqn_Job job = queue->jobs[wrapped_read_index]; + queue->read_index += 1; + Dqn_OS_MutexUnlock(&queue->mutex); job.func(job.user_context); Dqn_Arena_Deinit(job.arena); - Dqn_OS_MutexLock(&job_queue->mutex); - job_queue->complete_index += 1; - if (job_queue->complete_index == job_queue->write_index && job_queue->threads_waiting_for_completion) { - Dqn_OS_SemaphoreIncrement(&job_queue->wait_for_completion_semaphore, - job_queue->threads_waiting_for_completion); - job_queue->threads_waiting_for_completion = 0; + if (job.add_to_completion_queue) { + Dqn_OS_SemaphoreWait(&queue->complete_queue_write_semaphore, DQN_OS_SEMAPHORE_INFINITE_TIMEOUT); + Dqn_OS_MutexLock(&queue->mutex); + queue->complete_queue[(queue->complete_write_index++ & pot_mask)] = job; + Dqn_OS_MutexUnlock(&queue->mutex); + Dqn_OS_SemaphoreIncrement(&queue->complete_queue_write_semaphore, 1); } - Dqn_OS_MutexUnlock(&job_queue->mutex); + + Dqn_OS_MutexLock(&queue->mutex); + queue->finish_index += 1; + if (queue->finish_index == queue->write_index && queue->threads_waiting_for_completion) { + Dqn_OS_SemaphoreIncrement(&queue->wait_for_completion_semaphore, + queue->threads_waiting_for_completion); + queue->threads_waiting_for_completion = 0; + } + Dqn_OS_MutexUnlock(&queue->mutex); } - return job_queue->quit_exit_code; + return queue->quit_exit_code; } -DQN_API void Dqn_OS_JobQueueSPMCWaitForCompletion(Dqn_JobQueueSPMC *job_queue) +DQN_API void Dqn_OS_JobQueueSPMCWaitForCompletion(Dqn_JobQueueSPMC *queue) { - Dqn_OS_MutexLock(&job_queue->mutex); - if (job_queue->read_index == job_queue->write_index) { - Dqn_OS_MutexUnlock(&job_queue->mutex); + Dqn_OS_MutexLock(&queue->mutex); + if (queue->read_index == queue->write_index) { + Dqn_OS_MutexUnlock(&queue->mutex); return; } - job_queue->threads_waiting_for_completion++; - Dqn_OS_MutexUnlock(&job_queue->mutex); + queue->threads_waiting_for_completion++; + Dqn_OS_MutexUnlock(&queue->mutex); - Dqn_OS_SemaphoreWait(&job_queue->wait_for_completion_semaphore, DQN_OS_SEMAPHORE_INFINITE_TIMEOUT); + Dqn_OS_SemaphoreWait(&queue->wait_for_completion_semaphore, DQN_OS_SEMAPHORE_INFINITE_TIMEOUT); +} + +DQN_API Dqn_usize Dqn_OS_JobQueueSPMCGetFinishedJobs(Dqn_JobQueueSPMC *queue, Dqn_Job *jobs, Dqn_usize jobs_size) +{ + Dqn_usize result = 0; + if (!queue || !jobs || jobs_size <= 0) + return result; + + uint32_t const pot_mask = DQN_ARRAY_UCOUNT(queue->jobs) - 1; + Dqn_OS_MutexLock(&queue->mutex); + while (queue->complete_read_index < queue->complete_write_index && result < jobs_size) { + jobs[result++] = queue->complete_queue[(queue->complete_read_index++ & pot_mask)]; + } + Dqn_OS_MutexUnlock(&queue->mutex); + + return result; } diff --git a/dqn_helpers.h b/dqn_helpers.h index f9303fb..b48a451 100644 --- a/dqn_helpers.h +++ b/dqn_helpers.h @@ -202,8 +202,10 @@ struct Dqn_Profiler typedef void (Dqn_JobQueueFunc)(void *user_context); struct Dqn_Job { + bool add_to_completion_queue; Dqn_Arena *arena; Dqn_JobQueueFunc *func; + uint32_t user_tag; void *user_context; }; @@ -214,12 +216,17 @@ struct Dqn_JobQueueSPMC Dqn_OSSemaphore wait_for_completion_semaphore; uint32_t threads_waiting_for_completion; - Dqn_Job jobs[32]; + Dqn_Job jobs[64]; Dqn_b32 quit; uint32_t quit_exit_code; uint32_t volatile read_index; - uint32_t volatile complete_index; + uint32_t volatile finish_index; uint32_t volatile write_index; + + Dqn_OSSemaphore complete_queue_write_semaphore; + Dqn_Job complete_queue[64]; + uint32_t volatile complete_read_index; + uint32_t volatile complete_write_index; }; // NOTE: [$DLIB] Dqn_Library /////////////////////////////////////////////////////////////////////// @@ -408,6 +415,13 @@ DQN_API int8_t Dqn_Safe_SaturateCastI64ToI8 (int64_t va DQN_API int16_t Dqn_Safe_SaturateCastI64ToI16 (int64_t val); DQN_API int32_t Dqn_Safe_SaturateCastI64ToI32 (int64_t val); +DQN_API unsigned int Dqn_Safe_SaturateCastI64ToUInt (int64_t val); +DQN_API Dqn_isize Dqn_Safe_SaturateCastI64ToUSize (int64_t val); +DQN_API uint8_t Dqn_Safe_SaturateCastI64ToU8 (int64_t val); +DQN_API uint16_t Dqn_Safe_SaturateCastI64ToU16 (int64_t val); +DQN_API uint32_t Dqn_Safe_SaturateCastI64ToU32 (int64_t val); +DQN_API uint64_t Dqn_Safe_SaturateCastI64ToU64 (int64_t val); + DQN_API int8_t Dqn_Safe_SaturateCastIntToI8 (int val); DQN_API int16_t Dqn_Safe_SaturateCastIntToI16 (int val); DQN_API uint8_t Dqn_Safe_SaturateCastIntToU8 (int val); @@ -433,10 +447,11 @@ DQN_API void Dqn_Profiler_Dump (uint64_t t // NOTE: [$JOBQ] Dqn_JobQueue /////////////////////////////////////////////////////////////////////// DQN_API Dqn_JobQueueSPMC Dqn_OS_JobQueueSPMCInit (); -DQN_API bool Dqn_OS_JobQueueSPMCAddArray (Dqn_JobQueueSPMC *job_queue, Dqn_Job *jobs, uint32_t count); -DQN_API bool Dqn_OS_JobQueueSPMCAdd (Dqn_JobQueueSPMC *job_queue, Dqn_Job job); -DQN_API void Dqn_OS_JobQueueSPMCWaitForCompletion (Dqn_JobQueueSPMC *job_queue); +DQN_API bool Dqn_OS_JobQueueSPMCAddArray (Dqn_JobQueueSPMC *queue, Dqn_Job *jobs, uint32_t count); +DQN_API bool Dqn_OS_JobQueueSPMCAdd (Dqn_JobQueueSPMC *queue, Dqn_Job job); +DQN_API void Dqn_OS_JobQueueSPMCWaitForCompletion (Dqn_JobQueueSPMC *queue); DQN_API int32_t Dqn_OS_JobQueueSPMCThread (Dqn_OSThread *thread); +DQN_API Dqn_usize Dqn_OS_JobQueueSPMCGetFinishedJobs (Dqn_JobQueueSPMC *queue, Dqn_Job *jobs, Dqn_usize jobs_size); // NOTE: Dqn_Library /////////////////////////////////////////////////////////////////////////////// DQN_API Dqn_Library * Dqn_Library_Init (Dqn_LibraryOnInit on_init); diff --git a/dqn_os.h b/dqn_os.h index 69acd99..5af51ec 100644 --- a/dqn_os.h +++ b/dqn_os.h @@ -285,7 +285,6 @@ DQN_API bool Dqn_OS_SecureRNGBytes (void *buffer, uint DQN_API Dqn_Str8 Dqn_OS_EXEPath (Dqn_Arena *arena); DQN_API Dqn_Str8 Dqn_OS_EXEDir (Dqn_Arena *arena); DQN_API void Dqn_OS_SleepMs (Dqn_uint milliseconds); - // NOTE: Counters ////////////////////////////////////////////////////////////////////////////////// DQN_API uint64_t Dqn_OS_PerfCounterNow (); DQN_API uint64_t Dqn_OS_PerfCounterFrequency(); @@ -345,7 +344,7 @@ DQN_API Dqn_Str8 Dqn_OS_PathConvertF (Dqn_Arena *arena #define Dqn_OS_PathBuild(allocator, fs_path) Dqn_OS_PathBuildWithSeparator(allocator, fs_path, Dqn_OSPathSeparatorString) // NOTE: [$EXEC] Dqn_OSExec //////////////////////////////////////////////////////////////////////// -DQN_API void Dqn_OS_Exit (uint32_t exit_code); +DQN_API void Dqn_OS_Exit (int32_t exit_code); DQN_API Dqn_OSExecResult Dqn_OS_ExecWait (Dqn_OSExecAsyncHandle handle); DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync (Dqn_Slice cmd_line, Dqn_Str8 working_dir); DQN_API Dqn_OSExecResult Dqn_OS_Exec (Dqn_Slice cmd_line, Dqn_Str8 working_dir); diff --git a/dqn_os_posix.cpp b/dqn_os_posix.cpp index 112e7c7..c14635b 100644 --- a/dqn_os_posix.cpp +++ b/dqn_os_posix.cpp @@ -526,9 +526,9 @@ DQN_API void Dqn_OS_FileClose(Dqn_OSFile *file) #endif // !defined(DQN_NO_OS_FILE_API) // NOTE: [$EXEC] Dqn_OSExec //////////////////////////////////////////////////////////////////////// -DQN_API void Dqn_OS_Exit(uint32_t exit_code) +DQN_API void Dqn_OS_Exit(int32_t exit_code) { - exit(exit_code); + exit(DQN_CAST(int)exit_code); } DQN_API Dqn_OSExecResult Dqn_OS_ExecWait(Dqn_OSExecAsyncHandle handle) diff --git a/dqn_os_win32.cpp b/dqn_os_win32.cpp index d741142..9c45997 100644 --- a/dqn_os_win32.cpp +++ b/dqn_os_win32.cpp @@ -545,9 +545,9 @@ DQN_API void Dqn_OS_FileClose(Dqn_OSFile *file) #endif // !defined(DQN_NO_OS_FILE_API) // NOTE: [$EXEC] Dqn_OSExec //////////////////////////////////////////////////////////////////////// -DQN_API void Dqn_OS_Exit(uint32_t exit_code) +DQN_API void Dqn_OS_Exit(int32_t exit_code) { - ExitProcess(exit_code); + ExitProcess(DQN_CAST(UINT)exit_code); } DQN_API Dqn_OSExecResult Dqn_OS_ExecWait(Dqn_OSExecAsyncHandle handle) diff --git a/dqn_string.cpp b/dqn_string.cpp index 190c71c..6cbcb00 100644 --- a/dqn_string.cpp +++ b/dqn_string.cpp @@ -119,6 +119,12 @@ DQN_API Dqn_Str8 Dqn_Str8_Advance(Dqn_Str8 string, Dqn_usize amount) return result; } +DQN_API Dqn_Str8 Dqn_Str8_NextLine(Dqn_Str8 string) +{ + Dqn_Str8 result = Dqn_Str8_BinarySplit(string, DQN_STR8("\n")).rhs; + return result; +} + DQN_API Dqn_Str8BinarySplitResult Dqn_Str8_BinarySplitArray(Dqn_Str8 string, Dqn_Str8 const *find, Dqn_usize find_size) { Dqn_Str8BinarySplitResult result = {}; @@ -839,6 +845,22 @@ DQN_API Dqn_Slice Dqn_Str8Builder_BuildSlice(Dqn_Str8Builder const *bu return result; } +DQN_API void Dqn_Str8Builder_PrintF(Dqn_Str8Builder const *builder) +{ + for (Dqn_Str8Link *link = builder ? builder->head : nullptr; link; link = link->next) + Dqn_Print(link->string); +} + +DQN_API void Dqn_Str8Builder_PrintLnF(Dqn_Str8Builder const *builder) +{ + for (Dqn_Str8Link *link = builder ? builder->head : nullptr; link; link = link->next) { + if (link->next) { + Dqn_Print(link->string); + } else { + Dqn_Print_Ln(link->string); + } + } +} // NOTE: [$CHAR] Dqn_Char ////////////////////////////////////////////////////////////////////////// DQN_API bool Dqn_Char_IsAlphabet(char ch) diff --git a/dqn_string.h b/dqn_string.h index b58f20e..d36bbaa 100644 --- a/dqn_string.h +++ b/dqn_string.h @@ -152,6 +152,7 @@ DQN_API Dqn_Str8 Dqn_Str8_Copy DQN_API Dqn_Str8 Dqn_Str8_Slice (Dqn_Str8 string, Dqn_usize offset, Dqn_usize size); DQN_API Dqn_Str8 Dqn_Str8_Advance (Dqn_Str8 string, Dqn_usize amount); +DQN_API Dqn_Str8 Dqn_Str8_NextLine (Dqn_Str8 string); DQN_API Dqn_Str8BinarySplitResult Dqn_Str8_BinarySplitArray (Dqn_Str8 string, Dqn_Str8 const *find, Dqn_usize find_size); DQN_API Dqn_Str8BinarySplitResult Dqn_Str8_BinarySplit (Dqn_Str8 string, Dqn_Str8 find); DQN_API Dqn_Str8BinarySplitResult Dqn_Str8_BinarySplitReverseArray(Dqn_Str8 string, Dqn_Str8 const *find, Dqn_usize find_size); @@ -206,6 +207,7 @@ DQN_API bool Dqn_Str8Builder_Ap DQN_API Dqn_Str8 Dqn_Str8Builder_Build (Dqn_Str8Builder const *builder, Dqn_Arena *arena); DQN_API Dqn_Str8 Dqn_Str8Builder_BuildCRT (Dqn_Str8Builder const *builder); DQN_API Dqn_Slice Dqn_Str8Builder_BuildSlice (Dqn_Str8Builder const *builder, Dqn_Arena *arena); +DQN_API void Dqn_Str8Builder_PrintF (Dqn_Str8Builder const *builder); // NOTE: [$FSTR] Dqn_FStr8 ////////////////////////////////////////////////////////////////////// #if !defined(DQN_NO_FSTR8) diff --git a/dqn_type_info.h b/dqn_type_info.h index e2f4b4a..2514977 100644 --- a/dqn_type_info.h +++ b/dqn_type_info.h @@ -39,6 +39,7 @@ struct Dqn_TypeInfo { Dqn_Str8 name; Dqn_TypeKind kind; + Dqn_usize size_of; Dqn_TypeField const *fields; uint16_t fields_count; };