From 234fd9e3028e51524785449f49a0a90e7e8a4649 Mon Sep 17 00:00:00 2001 From: doylet Date: Sun, 5 Jul 2026 23:26:54 +1000 Subject: [PATCH] Convert binary search to a C style impl --- Single-Header/dn_single_header.cpp | 477 +++++++++++++++++------------ Single-Header/dn_single_header.h | 201 +++++------- Source/Standalone/dn_sha3.h | 8 +- Source/dn.cpp | 475 ++++++++++++++++------------ Source/dn.h | 199 +++++------- 5 files changed, 692 insertions(+), 668 deletions(-) diff --git a/Single-Header/dn_single_header.cpp b/Single-Header/dn_single_header.cpp index 6cf20d0..c83e61b 100644 --- a/Single-Header/dn_single_header.cpp +++ b/Single-Header/dn_single_header.cpp @@ -1,4 +1,4 @@ -// Generated by the DN single header generator 2026-07-05 12:47:32 +// Generated by the DN single header generator 2026-07-05 23:26:32 // DN: Single header generator commented out => #if defined(_CLANGD) // #define DN_WITH_TESTS 1 @@ -2679,14 +2679,14 @@ DN_API DN_U8x32 DN_U8x32FromHexUnsafe(DN_Str8 hex_32b) DN_U8x32 result = {}; hex_32b = DN_Str8TrimHexPrefix(hex_32b); DN_Assert(hex_32b.count <= sizeof(result.data) * 2); - DN_BytesFromHexPtr(hex_32b.data, hex_32b.count, result.data, sizeof(result.data)); + DN_PtrBytesFromPtrHex(hex_32b.data, hex_32b.count, result.data, sizeof(result.data)); return result; } DN_API DN_U8x32FromResult DN_U8x32FromHex(DN_Str8 hex_32b) { DN_U8x32FromResult result = {}; - DN_USize bytes_written = DN_BytesFromHexPtr(hex_32b.data, hex_32b.count, result.value.data, sizeof(result.value.data)); + DN_USize bytes_written = DN_PtrBytesFromPtrHex(hex_32b.data, hex_32b.count, result.value.data, sizeof(result.value.data)); if (bytes_written == sizeof(result.value.data)) result.success = true; return result; @@ -4986,7 +4986,7 @@ DN_API DN_NibbleFromU8Result DN_NibbleFromU8(DN_U8 u8) return result; } -DN_API DN_USize DN_BytesFromHex(DN_Str8 hex, void *dest, DN_USize dest_count) +DN_API DN_USize DN_PtrBytesFromStr8Hex(DN_Str8 hex, void *dest, DN_USize dest_count) { DN_Str8 hex_trimmed = DN_Str8TrimHexPrefix(hex); DN_USize result = 0; @@ -5019,65 +5019,65 @@ DN_API DN_USize DN_BytesFromHex(DN_Str8 hex, void *dest, DN_USize dest_count) return result; } -DN_API DN_Str8 DN_BytesFromHexArena(DN_Str8 hex, DN_Arena *arena) +DN_API DN_USize DN_PtrBytesFromPtrHex(char const *hex, DN_USize hex_count, void *dest, DN_USize dest_count) { - DN_Str8 result = DN_BytesFromHexPtrArena(hex.data, hex.count, arena); + DN_USize result = DN_PtrBytesFromStr8Hex(DN_Str8FromPtr(hex, hex_count), dest, dest_count); return result; } -DN_API DN_USize DN_BytesFromHexPtr(char const *hex, DN_USize hex_count, void *dest, DN_USize dest_count) +DN_API DN_Str8 DN_Str8BytesFromStr8HexArena(DN_Str8 hex, DN_Arena *arena) { - DN_USize result = DN_BytesFromHex(DN_Str8FromPtr(hex, hex_count), dest, dest_count); + DN_Str8 result = DN_Str8BytesFromPtrHexArena(hex.data, hex.count, arena); return result; } -DN_API DN_Str8 DN_BytesFromHexPtrArena(char const *hex, DN_USize hex_count, DN_Arena *arena) +DN_API DN_Str8 DN_Str8BytesFromPtrHexArena(char const *hex, DN_USize hex_count, DN_Arena *arena) { DN_Str8 hex_trimmed = DN_Str8TrimHexPrefix(DN_Str8FromPtr(hex, hex_count)); DN_Assert(hex_trimmed.count % 2 == 0); DN_Str8 result = {}; result.data = DN_ArenaNewArray(arena, char, hex_trimmed.count / 2, DN_ZMem_No); if (result.data) - result.count = DN_BytesFromHex(hex_trimmed, result.data, hex_trimmed.count / 2); + result.count = DN_PtrBytesFromStr8Hex(hex_trimmed, result.data, hex_trimmed.count / 2); return result; } -DN_API DN_Str8 DN_BytesFromHexPtrPool(char const *hex, DN_USize hex_count, DN_Pool *pool) +DN_API DN_Str8 DN_Str8BytesFromPtrHexPool(char const *hex, DN_USize hex_count, DN_Pool *pool) { DN_Str8 hex_trimmed = DN_Str8TrimHexPrefix(DN_Str8FromPtr(hex, hex_count)); DN_Assert(hex_trimmed.count % 2 == 0); DN_Str8 result = {}; result.data = DN_PoolNewArray(pool, char, hex_trimmed.count / 2); if (result.data) - result.count = DN_BytesFromHex(hex_trimmed, result.data, hex_trimmed.count / 2); + result.count = DN_PtrBytesFromStr8Hex(hex_trimmed, result.data, hex_trimmed.count / 2); return result; } -DN_API DN_U8x16 DN_BytesFromHex32Ptr(char const *hex, DN_USize hex_count) +DN_API DN_U8x16 DN_U8x16FromPtrHex32(char const *hex, DN_USize hex_count) { DN_U8x16 result = {}; DN_Str8 hex_trimmed = DN_Str8TrimHexPrefix(DN_Str8FromPtr(hex, hex_count)); DN_Assert(hex_trimmed.count / 2 == sizeof result.data); - DN_USize bytes_written = DN_BytesFromHex(hex_trimmed, result.data, sizeof result.data); + DN_USize bytes_written = DN_PtrBytesFromStr8Hex(hex_trimmed, result.data, sizeof result.data); DN_Assert(bytes_written == sizeof result.data); return result; } -DN_API DN_U8x32 DN_BytesFromHex64Ptr(char const *hex, DN_USize hex_count) +DN_API DN_U8x32 DN_U8x32FromPtrHex64(char const *hex, DN_USize hex_count) { DN_U8x32 result = {}; DN_Str8 hex_trimmed = DN_Str8TrimHexPrefix(DN_Str8FromPtr(hex, hex_count)); DN_Assert(hex_trimmed.count / 2 == sizeof result.data); - DN_USize bytes_written = DN_BytesFromHex(hex_trimmed, result.data, sizeof result.data); + DN_USize bytes_written = DN_PtrBytesFromStr8Hex(hex_trimmed, result.data, sizeof result.data); DN_Assert(bytes_written == sizeof result.data); return result; } -DN_API DN_HexU64 DN_HexFromU64(DN_U64 value, DN_HexFromU64Type type) +DN_API DN_HexU64 DN_HexU64FromU64(DN_U64 value, DN_HexFromU64Type type) { DN_HexU64 result = {}; - DN_USize count = DN_HexFromPtrBytes(&value, sizeof(value), result.data, sizeof(result.data), DN_TrimLeadingZero_No); + DN_USize count = DN_PtrHexFromPtrBytes(&value, sizeof(value), result.data, sizeof(result.data), DN_TrimLeadingZero_No); result.count = DN_SaturateCastUSizeToU8(count); if (type == DN_HexFromU64Type_Uppercase) { for (DN_USize index = 0; index < result.count; index++) @@ -5086,7 +5086,7 @@ DN_API DN_HexU64 DN_HexFromU64(DN_U64 value, DN_HexFromU64Type type) return result; } -DN_API DN_USize DN_HexFromPtrBytes(void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z) +DN_API DN_USize DN_PtrHexFromPtrBytes(void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z) { DN_USize result = 0; if ((bytes_count * 2) > hex_count) @@ -5118,57 +5118,57 @@ DN_API DN_USize DN_HexFromPtrBytes(void const *bytes, DN_USize bytes_count, void return result; } -DN_API DN_Str8 DN_HexFromPtrBytesArena(void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z) +DN_API DN_Str8 DN_Str8HexFromPtrBytesArena(void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z) { DN_Str8 result = {}; if (bytes_count) { result.data = DN_ArenaNewArray(arena, char, bytes_count * 2, DN_ZMem_No); if (result.data) - result.count = DN_HexFromPtrBytes(bytes, bytes_count, result.data, bytes_count * 2, trim_leading_z); + result.count = DN_PtrHexFromPtrBytes(bytes, bytes_count, result.data, bytes_count * 2, trim_leading_z); } return result; } -DN_API DN_USize DN_HexFromStr8Bytes(DN_Str8 bytes, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z) +DN_API DN_USize DN_PtrHexFromStr8Bytes(DN_Str8 bytes, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z) { - DN_USize result = DN_HexFromPtrBytes(bytes.data, bytes.count, hex, hex_count, trim_leading_z); + DN_USize result = DN_PtrHexFromPtrBytes(bytes.data, bytes.count, hex, hex_count, trim_leading_z); return result; } -DN_API DN_Str8 DN_HexFromStr8BytesArena(DN_Str8 bytes, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z) +DN_API DN_Str8 DN_Str8HexFromStr8BytesArena(DN_Str8 bytes, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z) { DN_Str8 result = {}; if (bytes.count) { result.data = DN_ArenaNewArray(arena, char, bytes.count * 2, DN_ZMem_No); if (result.data) - result.count = DN_HexFromStr8Bytes(bytes, result.data, bytes.count * 2, trim_leading_z); + result.count = DN_PtrHexFromStr8Bytes(bytes, result.data, bytes.count * 2, trim_leading_z); } return result; } -DN_API DN_Hex32 DN_Hex32FromPtr16b(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) +DN_API DN_Hex32 DN_Hex32FromPtrBytes16(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) { DN_Hex32 result = {}; DN_Assert(bytes_count * 2 == sizeof result.data - 1); - result.count = DN_HexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); + result.count = DN_PtrHexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); DN_Assert(result.count <= sizeof result.data - 1); return result; } -DN_API DN_Hex64 DN_Hex64FromPtr32b(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) +DN_API DN_Hex64 DN_Hex64FromPtrBytes32(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) { DN_Hex64 result = {}; DN_Assert(bytes_count * 2 == sizeof result.data - 1); - result.count = DN_HexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); + result.count = DN_PtrHexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); DN_Assert(result.count <= sizeof result.data - 1); return result; } -DN_API DN_Hex128 DN_Hex128FromPtr64b(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) +DN_API DN_Hex128 DN_Hex128FromPtrBytes64(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) { DN_Hex128 result = {}; DN_Assert(bytes_count * 2 == sizeof result.data - 1); - result.count = DN_HexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); + result.count = DN_PtrHexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); DN_Assert(result.count <= sizeof result.data - 1); return result; } @@ -5748,7 +5748,7 @@ DN_API bool DN_QSortCompareStr8LexicographicDesc(void const* lhs, void const *rh DN_API bool DN_QSortCompareBytesLT(void const* lhs, void const *rhs, void *user_context) { DN_USize elem_size = *DN_Cast(DN_USize *)user_context; - bool result = DN_Memcmp(lhs, rhs, elem_size) < 0; + bool result = DN_Memcmp(lhs, rhs, elem_size) < 0; return result; } @@ -5789,6 +5789,75 @@ DN_API void DN_QSortStr8LexicographicDesc(DN_Str8 *array, DN_USize array_size, D DN_QSort(array, array_size, sizeof(*array), /*user_context=*/ &eq_case, DN_QSortCompareStr8LexicographicDesc); } +DN_API bool DN_BSearchLessThanBytes(void const *lhs, void const *rhs, void *user_context) +{ + DN_USize elem_size = *DN_Cast(DN_USize *)user_context; + bool result = DN_Memcmp(lhs, rhs, elem_size) < 0; + return result; +} + +DN_API DN_BSearchResult DN_BSearch(void const *array, DN_USize count, DN_USize elem_size, void const *find, DN_BSearchType type, void *user_context, DN_BSearchLessThanFunc *less_than) +{ + DN_BSearchResult result = {}; + if (!array || count <= 0 || !less_than || !find) + return result; + + void const *end = DN_Cast(char *)array + (count * elem_size); + void const *first = array; + void const *last = end; + while (first != last) { + DN_USize dist = (DN_Cast(char *)last - DN_Cast(char *)first) / elem_size; + void const *it = DN_Cast(char *)first + ((dist / 2) * elem_size); + bool advance_first = false; + if (type == DN_BSearchType_UpperBound) + advance_first = !less_than(find, it, user_context); + else + advance_first = less_than(it, find, user_context); + + if (advance_first) + first = DN_Cast(char *)it + (1 * elem_size); + else + last = it; + } + + switch (type) { + case DN_BSearchType_Match: { + result.found = first != end && !less_than(find, first, user_context); + } break; + + case DN_BSearchType_LowerBound: /*FALLTHRU*/ + case DN_BSearchType_UpperBound: { + result.found = first != end; + } break; + } + + result.index = (DN_Cast(char *)first - DN_Cast(char *)array) / elem_size; + return result; +} + +DN_API DN_BSearchResult DN_BSearchBytes(void const *array, DN_USize count, DN_USize elem_size, void const *find, DN_BSearchType type) +{ + DN_BSearchResult result = DN_BSearch(array, count, elem_size, find, type, &elem_size, DN_BSearchLessThanBytes); + return result; +} + +DN_API DN_BSearchResult DN_BSearchUSize(DN_USize const *array, DN_USize count, DN_USize find, DN_BSearchType type) +{ + DN_BSearchResult result = DN_BSearchBytes(array, count, sizeof(*array), &find, type); + return result; +} + +DN_API DN_BSearchResult DN_BSearchU64(DN_U64 const *array, DN_USize count, DN_U64 find, DN_BSearchType type) +{ + DN_BSearchResult result = DN_BSearchBytes(array, count, sizeof(*array), &find, type); + return result; +} + +DN_API DN_BSearchResult DN_BSearchU32(DN_U32 const *array, DN_USize count, DN_U32 find, DN_BSearchType type) +{ + DN_BSearchResult result = DN_BSearchBytes(array, count, sizeof(*array), &find, type); + return result; +} #define DN_PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL #define DN_PCG_DEFAULT_INCREMENT_64 1442695040888963407ULL @@ -9303,6 +9372,109 @@ DN_API void DN_TestEnd(DN_TestCore *test) group->curr_entry = nullptr; } +DN_API DN_Str8 DN_Str8FromTestCore(DN_TestCore const *test, DN_Arena *arena, DN_Str8FromTestCoreFlags flags) +{ + DN_TCScratch scratch = DN_TCScratchBeginArena(&arena, 1); + DN_USize padding_count = 100; + DN_Str8 padding_line = DN_Str8FillF(&scratch.arena, padding_count, "."); + if (flags & DN_Str8FromTestCoreFlags_Colour) + padding_line = DN_Str8FromFmtANSIColourU8RGBArena(DN_ANSIColourMode_Fg, 64, 64, 64, &scratch.arena, "%.*s", DN_Str8PrintFmt(padding_line)); + + DN_V3F32 const good_colour = DN_V3F32From3N(0, 255, 0); + DN_V3F32 const bad_colour = DN_V3F32From3N(255, 0, 0); + DN_Str8Builder builder = DN_Str8BuilderFromArena(arena); + for (DN_ForItSize(group_it, DN_TestGroup const, test->groups, test->groups_count)) { + DN_TestGroup const* group = group_it.data; + DN_USize group_successes = 0; + DN_USize group_failures = 0; + DN_MSVC_WARNING_PUSH + DN_MSVC_WARNING_DISABLE(6067) // _Param_(5) in call to 'DN_Str8BuilderAppendF' must be the address of a string. Actual type: 'const unsigned __int64'. + DN_MSVC_WARNING_DISABLE(6271) // Extra argument passed to 'DN_Str8BuilderAppendF'. + DN_Str8BuilderAppendF(&builder, "[%.*s] (%'zu test%s)\n", DN_Str8PrintFmt(group->name), group->entries_count, (group->entries_count > 1) ? "s" : ""); + DN_MSVC_WARNING_POP + for (DN_ForItSize(entry_it, DN_TestEntry const, group->entries, group->entries_count)) { + DN_TestEntry const* entry = entry_it.data; + if (entry->failed) + group_failures++; + else + group_successes++; + + // NOTE: Extract the test name and pad the line with dots (.) + DN_Str8 test_prefix = DN_Str8FromFmtArena(&scratch.arena, " [%zu/%zu] %.*s ", entry_it.index + 1, group->entries_count, DN_Str8PrintFmt(entry->name)); + if (test_prefix.count < padding_line.count) { + DN_USize remaining = padding_line.count - test_prefix.count; + DN_Str8 padder = DN_Str8Subset(padding_line, 0, remaining); + test_prefix = DN_Str8AppendF(&scratch.arena, test_prefix, "%.*s", DN_Str8PrintFmt(padder)); + } + + // NOTE: Construct the test line + DN_Str8 outcome_str8 = entry->failed ? DN_Str8Lit("FAILED") : DN_Str8Lit("OK"); + if (flags & DN_Str8FromTestCoreFlags_Colour) { + if (entry->failed) + outcome_str8 = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, bad_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(outcome_str8)); + else + outcome_str8 = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, good_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(outcome_str8)); + } + + DN_F64 elapsed_ms = DN_OS_PerfCounterMs(entry->ts_begin, entry->ts_end); + DN_Str8BuilderAppendF(&builder, "%.*s %.*s (%.3fms)\n", DN_Str8PrintFmt(test_prefix), DN_Str8PrintFmt(outcome_str8), elapsed_ms); + + // NOTE: Output the test diagnostics, populated on failure + if (entry->failed) { + for (DN_ForItSize(row_it, DN_TestDiagnosticRow, entry->diagnostics, entry->diagnostics_count)) { + DN_USize row_count = 1; + DN_Str8TableFlags table_flags = DN_Str8TableFlags_None; + if (row_it.index == 0) { + row_count++; // Header + table_flags |= DN_Str8TableFlags_HasHeader; + } + + DN_USize col_count = 3; // Expression, Eval, Call site + DN_USize row_index = 0; + DN_Str8 *rows_str8 = DN_ArenaNewArrayZ(&scratch.arena, DN_Str8, row_count * col_count); + if (row_it.index == 0) { + rows_str8[row_index++] = DN_Str8Lit("Expr."); + rows_str8[row_index++] = DN_Str8Lit("Eval."); + rows_str8[row_index++] = DN_Str8Lit("Location"); + } + + DN_TestDiagnosticRow *row = row_it.data; + DN_Str8 file_name = DN_Str8FileNameFromPath(row->call_site.file); + rows_str8[row_index++] = row->expr; + rows_str8[row_index++] = row->invariant; + rows_str8[row_index++] = DN_Str8FromFmtArena(&scratch.arena, "%.*s:%u", DN_Str8PrintFmt(file_name), row->call_site.line); + + DN_Str8 table = DN_Str8Table(rows_str8, row_count, col_count, table_flags, &scratch.arena); + table = DN_Str8PadNewLinesArena(table, DN_Str8Lit(" "), &scratch.arena); + DN_Str8BuilderAppendF(&builder, " %.*s\n", DN_Str8PrintFmt(table)); + if (row->message.count) { + DN_Str8 line_break = DN_Str8LineBreakArena(row->message, 100, DN_Str8Lit("\n "), DN_Str8LineBreakMode_AtWord, &scratch.arena); + DN_Str8BuilderAppendF(&builder, " User Message: %.*s\n", DN_Str8PrintFmt(line_break)); + } + } + DN_Str8BuilderAppendF(&builder, "\n"); + } + } + + DN_F64 elapsed_ms = DN_OS_PerfCounterMs(group->ts_begin, group->ts_end); + DN_MSVC_WARNING_PUSH + DN_MSVC_WARNING_DISABLE(6067) // _Param_(3) in call to 'DN_Str8BuilderAppendF' must be the address of a string. Actual type: 'const unsigned __int64'. + DN_MSVC_WARNING_DISABLE(6271) // Extra argument passed to 'DN_Str8BuilderAppendF'. + DN_Str8 group_prefix = DN_Str8FromFmtArena(&scratch.arena, "%'zu/%'zu test%s", group_successes, group->entries_count, group_successes > 1 ? "s" :""); + DN_MSVC_WARNING_POP + if (flags & DN_Str8FromTestCoreFlags_Colour) { + if (group_failures == 0) + group_prefix = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, good_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(group_prefix)); + else + group_prefix = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, bad_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(group_prefix)); + } + DN_Str8BuilderAppendF(&builder, "\n %.*s passed in [%.*s] %.3fms (%zu failed)\n", DN_Str8PrintFmt(group_prefix), DN_Str8PrintFmt(group->name), elapsed_ms, group_failures); + } + + DN_Str8 result = DN_Str8FromStr8BuilderArena(&builder, arena); + return result; +} + DN_API DN_TestDiagnosticRow *DN_TestVerifySetupFmtV(DN_TestCore *test, DN_CallSite call_site, DN_Str8 expr, bool verify_failed, char const *fmt, va_list args) { DN_AssertF(test->curr_group, "Test group must be started before attempting to verify a test invariant"); @@ -9444,8 +9616,8 @@ DN_API void DN_TestVerifyBytesF(DN_TestCore *test, DN_CallSite call_site, DN_Str DN_TestDiagnosticRow *row = DN_TestVerifySetupFmtV(test, call_site, expr, verify_failed, fmt, args); va_end(args); if (row) { - DN_Str8 bytes_hex = DN_HexFromStr8BytesArena(bytes, test->arena, DN_TrimLeadingZero_No); - DN_Str8 expect_hex = DN_HexFromStr8BytesArena(expect, test->arena, DN_TrimLeadingZero_No); + DN_Str8 bytes_hex = DN_Str8HexFromStr8BytesArena(bytes, test->arena, DN_TrimLeadingZero_No); + DN_Str8 expect_hex = DN_Str8HexFromStr8BytesArena(expect, test->arena, DN_TrimLeadingZero_No); if (expect_eq) row->invariant = DN_Str8FromFmtArena(test->arena, "\"%.*s\" != \"%.*s\"", DN_Str8PrintFmt(bytes_hex), DN_Str8PrintFmt(expect_hex)); else @@ -9453,109 +9625,6 @@ DN_API void DN_TestVerifyBytesF(DN_TestCore *test, DN_CallSite call_site, DN_Str } } -DN_API DN_Str8 DN_Str8FromTestCore(DN_TestCore const *test, DN_Arena *arena, DN_Str8FromTestCoreFlags flags) -{ - DN_TCScratch scratch = DN_TCScratchBeginArena(&arena, 1); - DN_USize padding_count = 100; - DN_Str8 padding_line = DN_Str8FillF(&scratch.arena, padding_count, "."); - if (flags & DN_Str8FromTestCoreFlags_Colour) - padding_line = DN_Str8FromFmtANSIColourU8RGBArena(DN_ANSIColourMode_Fg, 64, 64, 64, &scratch.arena, "%.*s", DN_Str8PrintFmt(padding_line)); - - DN_V3F32 const good_colour = DN_V3F32From3N(0, 255, 0); - DN_V3F32 const bad_colour = DN_V3F32From3N(255, 0, 0); - DN_Str8Builder builder = DN_Str8BuilderFromArena(arena); - for (DN_ForItSize(group_it, DN_TestGroup const, test->groups, test->groups_count)) { - DN_TestGroup const* group = group_it.data; - DN_USize group_successes = 0; - DN_USize group_failures = 0; - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6067) // _Param_(5) in call to 'DN_Str8BuilderAppendF' must be the address of a string. Actual type: 'const unsigned __int64'. - DN_MSVC_WARNING_DISABLE(6271) // Extra argument passed to 'DN_Str8BuilderAppendF'. - DN_Str8BuilderAppendF(&builder, "[%.*s] (%'zu test%s)\n", DN_Str8PrintFmt(group->name), group->entries_count, (group->entries_count > 1) ? "s" : ""); - DN_MSVC_WARNING_POP - for (DN_ForItSize(entry_it, DN_TestEntry const, group->entries, group->entries_count)) { - DN_TestEntry const* entry = entry_it.data; - if (entry->failed) - group_failures++; - else - group_successes++; - - // NOTE: Extract the test name and pad the line with dots (.) - DN_Str8 test_prefix = DN_Str8FromFmtArena(&scratch.arena, " [%zu/%zu] %.*s ", entry_it.index + 1, group->entries_count, DN_Str8PrintFmt(entry->name)); - if (test_prefix.count < padding_line.count) { - DN_USize remaining = padding_line.count - test_prefix.count; - DN_Str8 padder = DN_Str8Subset(padding_line, 0, remaining); - test_prefix = DN_Str8AppendF(&scratch.arena, test_prefix, "%.*s", DN_Str8PrintFmt(padder)); - } - - // NOTE: Construct the test line - DN_Str8 outcome_str8 = entry->failed ? DN_Str8Lit("FAILED") : DN_Str8Lit("OK"); - if (flags & DN_Str8FromTestCoreFlags_Colour) { - if (entry->failed) - outcome_str8 = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, bad_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(outcome_str8)); - else - outcome_str8 = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, good_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(outcome_str8)); - } - - DN_F64 elapsed_ms = DN_OS_PerfCounterMs(entry->ts_begin, entry->ts_end); - DN_Str8BuilderAppendF(&builder, "%.*s %.*s (%.3fms)\n", DN_Str8PrintFmt(test_prefix), DN_Str8PrintFmt(outcome_str8), elapsed_ms); - - // NOTE: Output the test diagnostics, populated on failure - if (entry->failed) { - for (DN_ForItSize(row_it, DN_TestDiagnosticRow, entry->diagnostics, entry->diagnostics_count)) { - DN_USize row_count = 1; - DN_Str8TableFlags table_flags = DN_Str8TableFlags_None; - if (row_it.index == 0) { - row_count++; // Header - table_flags |= DN_Str8TableFlags_HasHeader; - } - - DN_USize col_count = 3; // Expression, Eval, Call site - DN_USize row_index = 0; - DN_Str8 *rows_str8 = DN_ArenaNewArrayZ(&scratch.arena, DN_Str8, row_count * col_count); - if (row_it.index == 0) { - rows_str8[row_index++] = DN_Str8Lit("Expr."); - rows_str8[row_index++] = DN_Str8Lit("Eval."); - rows_str8[row_index++] = DN_Str8Lit("Location"); - } - - DN_TestDiagnosticRow *row = row_it.data; - DN_Str8 file_name = DN_Str8FileNameFromPath(row->call_site.file); - rows_str8[row_index++] = row->expr; - rows_str8[row_index++] = row->invariant; - rows_str8[row_index++] = DN_Str8FromFmtArena(&scratch.arena, "%.*s:%u", DN_Str8PrintFmt(file_name), row->call_site.line); - - DN_Str8 table = DN_Str8Table(rows_str8, row_count, col_count, table_flags, &scratch.arena); - table = DN_Str8PadNewLinesArena(table, DN_Str8Lit(" "), &scratch.arena); - DN_Str8BuilderAppendF(&builder, " %.*s\n", DN_Str8PrintFmt(table)); - if (row->message.count) { - DN_Str8 line_break = DN_Str8LineBreakArena(row->message, 100, DN_Str8Lit("\n "), DN_Str8LineBreakMode_AtWord, &scratch.arena); - DN_Str8BuilderAppendF(&builder, " User Message: %.*s\n", DN_Str8PrintFmt(line_break)); - } - } - DN_Str8BuilderAppendF(&builder, "\n"); - } - } - - DN_F64 elapsed_ms = DN_OS_PerfCounterMs(group->ts_begin, group->ts_end); - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6067) // _Param_(3) in call to 'DN_Str8BuilderAppendF' must be the address of a string. Actual type: 'const unsigned __int64'. - DN_MSVC_WARNING_DISABLE(6271) // Extra argument passed to 'DN_Str8BuilderAppendF'. - DN_Str8 group_prefix = DN_Str8FromFmtArena(&scratch.arena, "%'zu/%'zu test%s", group_successes, group->entries_count, group_successes > 1 ? "s" :""); - DN_MSVC_WARNING_POP - if (flags & DN_Str8FromTestCoreFlags_Colour) { - if (group_failures == 0) - group_prefix = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, good_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(group_prefix)); - else - group_prefix = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, bad_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(group_prefix)); - } - DN_Str8BuilderAppendF(&builder, "\n %.*s passed in [%.*s] %.3fms (%zu failed)\n", DN_Str8PrintFmt(group_prefix), DN_Str8PrintFmt(group->name), elapsed_ms, group_failures); - } - - DN_Str8 result = DN_Str8FromStr8BuilderArena(&builder, arena); - return result; -} - #if DN_WITH_TESTS #if defined(DN_PLATFORM_WIN32) && defined(DN_COMPILER_MSVC) // NOTE: Taken from MSDN __cpuid example implementation @@ -10001,261 +10070,261 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) } } - // NOTE: BytesHex + // NOTE: Hex/Bytes { DN_TCScratch scratch = DN_TCScratchBeginArena(&arena_, 1); DN_DEFER { DN_TCScratchEnd(&scratch); }; - for (DN_TestScopeF(&result, "[BytesHex] Convert 0x123")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert 0x123")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("0x123")); DN_TestVerifyExprF(&result, val == 0x123, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert 0xFFFF")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert 0xFFFF")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("0xFFFF")); DN_TestVerifyExprF(&result, val == 0xFFFF, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert FFFF")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert FFFF")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("FFFF")); DN_TestVerifyExprF(&result, val == 0xFFFF, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert abCD")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert abCD")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("abCD")); DN_TestVerifyExprF(&result, val == 0xabCD, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert 0xabCD")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert 0xabCD")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("0xabCD")); DN_TestVerifyExprF(&result, val == 0xabCD, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert 0x")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert 0x")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("0x")); DN_TestVerifyExprF(&result, val == 0x0, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert 0X")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert 0X")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("0X")); DN_TestVerifyExprF(&result, val == 0x0, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert 3")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert 3")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("3")); DN_TestVerifyExprF(&result, val == 3, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert f")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert f")) { DN_U64FromResult res = DN_U64FromHexStr8(DN_Str8Lit("f")); DN_TestVerifyExpr(&result, res.success); DN_TestVerifyExpr(&result, res.value == 0xf); } - for (DN_TestScopeF(&result, "[BytesHex] Convert g")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert g")) { DN_U64FromResult res = DN_U64FromHexStr8(DN_Str8Lit("g")); DN_TestVerifyExpr(&result, !res.success); } - for (DN_TestScopeF(&result, "[BytesHex] Convert -0x3")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert -0x3")) { DN_U64FromResult res = DN_U64FromHexStr8(DN_Str8Lit("-0x3")); DN_TestVerifyExpr(&result, !res.success); } DN_U32 number = 0xd095f6; - for (DN_TestScopeF(&result, "[BytesHex] Convert %x to string", number)) { - DN_Str8 number_hex = DN_HexFromPtrBytesArena(&number, sizeof(number), &scratch.arena, DN_TrimLeadingZero_No); + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert %x to string", number)) { + DN_Str8 number_hex = DN_Str8HexFromPtrBytesArena(&number, sizeof(number), &scratch.arena, DN_TrimLeadingZero_No); DN_TestVerifyStr8EqF(&result, number_hex, DN_Str8Lit("f695d000"), "number_hex=%.*s", DN_Str8PrintFmt(number_hex)); } number = 0xf6ed00; - for (DN_TestScopeF(&result, "[BytesHex] Convert %x to string", number)) { - DN_Str8 number_hex = DN_HexFromPtrBytesArena(&number, sizeof(number), &scratch.arena, DN_TrimLeadingZero_No); + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert %x to string", number)) { + DN_Str8 number_hex = DN_Str8HexFromPtrBytesArena(&number, sizeof(number), &scratch.arena, DN_TrimLeadingZero_No); DN_TestVerifyStr8EqF(&result, number_hex, DN_Str8Lit("00edf600"), "number_hex=%.*s", DN_Str8PrintFmt(number_hex)); } DN_Str8 hex = DN_Str8Lit("0xf6ed00"); - for (DN_TestScopeF(&result, "[BytesHex] Convert %.*s to bytes", DN_Str8PrintFmt(hex))) { - DN_Str8 bytes = DN_BytesFromHexArena(hex, &scratch.arena); + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert %.*s to bytes", DN_Str8PrintFmt(hex))) { + DN_Str8 bytes = DN_Str8BytesFromStr8HexArena(hex, &scratch.arena); DN_TestVerifyStr8EqF(&result, bytes, DN_Str8Lit("\xf6\xed\x00"), "number_hex=%.*s", - DN_Str8PrintFmt(DN_HexFromPtrBytesArena(bytes.data, bytes.count, &scratch.arena, DN_TrimLeadingZero_No))); + DN_Str8PrintFmt(DN_Str8HexFromPtrBytesArena(bytes.data, bytes.count, &scratch.arena, DN_TrimLeadingZero_No))); } - for (DN_TestScopeF(&result, "[BytesHex] Convert empty bytes to string")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert empty bytes to string")) { DN_Str8 bytes = DN_Str8Lit(""); - DN_Str8 as_hex = DN_HexFromPtrBytesArena(bytes.data, bytes.count, &scratch.arena, DN_TrimLeadingZero_No); + DN_Str8 as_hex = DN_Str8HexFromPtrBytesArena(bytes.data, bytes.count, &scratch.arena, DN_TrimLeadingZero_No); DN_TestVerifyStr8EqF(&result, as_hex, DN_Str8Lit(""), "as_hex=%.*s", DN_Str8PrintFmt(as_hex)); } } - // NOTE: BinarySearch + // NOTE: BSearch { - for (DN_TestScopeF(&result, "[BinarySearch] Search array of 1 item")) { - DN_U32 array[] = {1}; - DN_BinarySearchResult search = {}; + for (DN_TestScopeF(&result, "[BSearch] Search array of 1 item")) { + DN_U32 array[] = {1}; + DN_BSearchResult search = {}; - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 1); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 1); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 1); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 1); } - for (DN_TestScopeF(&result, "[BinarySearch] Search array of 3 items")) { + for (DN_TestScopeF(&result, "[BSearch] Search array of 3 items")) { DN_U32 array[] = {1, 2, 3}; - DN_BinarySearchResult search = {}; + DN_BSearchResult search = {}; - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 1); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 3U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 3U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 2); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 4U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 4U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 3); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 1); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 3U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 3U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 2); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 4U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 4U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 3); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 1); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 2); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 3U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 3U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 3); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 4U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 4U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 3); } - for (DN_TestScopeF(&result, "[BinarySearch] Search array with duplicate items")) { + for (DN_TestScopeF(&result, "[BSearch] Search array with duplicate items")) { DN_U32 array[] = {1, 1, 2, 2, 3}; - DN_BinarySearchResult search = {}; + DN_BSearchResult search = {}; - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 2); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 3U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 3U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 4); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 4U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 4U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 5); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 2); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 3U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 3U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 4); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 4U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 4U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 5); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 2); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 4); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 3U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 3U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 5); } diff --git a/Single-Header/dn_single_header.h b/Single-Header/dn_single_header.h index 7e3646e..8b65d88 100644 --- a/Single-Header/dn_single_header.h +++ b/Single-Header/dn_single_header.h @@ -1,4 +1,4 @@ -// Generated by the DN single header generator 2026-07-05 12:47:31 +// Generated by the DN single header generator 2026-07-05 23:26:32 #if !defined(DN_H) #define DN_H @@ -1542,7 +1542,42 @@ struct DN_Profiler DN_F64 frame_avg_tsc; }; -typedef bool (DN_QSortCompareFunc)(void const *a, void const *b, void *user_context); +typedef bool (DN_QSortCompareFunc) (void const *lhs, void const *rhs, void *user_context); +typedef bool (DN_BSearchLessThanFunc)(void const *lhs, void const *rhs, void *user_context); +enum DN_BSearchType +{ + // NOTE: Index of the match. If no match is found, found is set to false and the + // index is set to the index where the match should be inserted/exist, if + // it were in the array + DN_BSearchType_Match, + + // NOTE: Index of the first element in the array that is `element >= find`. If no such + // item is found or the array is empty, then, the index is set to the array + // size and found is set to `false`. + // + // For example: + // int array[] = {0, 1, 2, 3, 4, 5}; + // DN_BSearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BSearchType_LowerBound); + // printf("%zu\n", result.index); // Prints index '4' + DN_BSearchType_LowerBound, + + // NOTE: Index of the first element in the array that is `element > find`. If no such + // item is found or the array is empty, then, the index is set to the array + // size and found is set to `false`. + // + // For example: + // int array[] = {0, 1, 2, 3, 4, 5}; + // DN_BSearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BSearchType_UpperBound); + // printf("%zu\n", result.index); // Prints index '5' + DN_BSearchType_UpperBound, +}; + +struct DN_BSearchResult +{ + bool found; + DN_USize index; +}; + enum DN_ErrSinkMode { DN_ErrSinkMode_Nil, // Default behaviour to accumulate errors into the sink @@ -4953,22 +4988,22 @@ DN_API DN_USize DN_USizeCodepointCountFromUTF8 DN_API DN_U8 DN_U8FromHexNibble (char hex); DN_API DN_NibbleFromU8Result DN_NibbleFromU8 (DN_U8 u8); -DN_API DN_USize DN_BytesFromHex (DN_Str8 hex, void *dest, DN_USize dest_count); -DN_API DN_Str8 DN_BytesFromHexArena (DN_Str8 hex, DN_Arena *arena); -DN_API DN_USize DN_BytesFromHexPtr (char const *hex, DN_USize hex_count, void *dest, DN_USize dest_count); -DN_API DN_Str8 DN_BytesFromHexPtrArena (char const *hex, DN_USize hex_count, DN_Arena *arena); -DN_API DN_Str8 DN_BytesFromHexPtrPool (char const *hex, DN_USize hex_count, DN_Pool *pool); -DN_API DN_U8x16 DN_BytesFromHex32Ptr (char const *hex, DN_USize hex_count); -DN_API DN_U8x32 DN_BytesFromHex64Ptr (char const *hex, DN_USize hex_count); +DN_API DN_USize DN_PtrBytesFromStr8Hex (DN_Str8 hex, void *dest, DN_USize dest_count); +DN_API DN_USize DN_PtrBytesFromPtrHex (char const *hex, DN_USize hex_count, void *dest, DN_USize dest_count); +DN_API DN_Str8 DN_Str8BytesFromStr8HexArena (DN_Str8 hex, DN_Arena *arena); +DN_API DN_Str8 DN_Str8BytesFromPtrHexArena (char const *hex, DN_USize hex_count, DN_Arena *arena); +DN_API DN_Str8 DN_Str8BytesFromPtrHexPool (char const *hex, DN_USize hex_count, DN_Pool *pool); +DN_API DN_U8x16 DN_U8x16FromPtrHex32 (char const *hex, DN_USize hex_count); +DN_API DN_U8x32 DN_U8x32FromPtrHex64 (char const *hex, DN_USize hex_count); -DN_API DN_HexU64 DN_HexFromU64 (DN_U64 value, DN_HexFromU64Type type); -DN_API DN_USize DN_HexFromPtrBytes (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Str8 DN_HexFromPtrBytesArena (void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); -DN_API DN_USize DN_HexFromStr8Bytes (DN_Str8 bytes, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Str8 DN_HexFromStr8BytesArena (DN_Str8 bytes, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Hex32 DN_Hex32FromPtr16b (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Hex64 DN_Hex64FromPtr32b (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Hex128 DN_Hex128FromPtr64b (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_HexU64 DN_HexU64FromU64 (DN_U64 value, DN_HexFromU64Type type); +DN_API DN_USize DN_PtrHexFromPtrBytes (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_USize DN_PtrHexFromStr8Bytes (DN_Str8 bytes, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Str8 DN_Str8HexFromPtrBytesArena (void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Str8 DN_Str8HexFromStr8BytesArena (DN_Str8 bytes, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex32 DN_Hex32FromPtrBytes16 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex64 DN_Hex64FromPtrBytes32 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex128 DN_Hex128FromPtrBytes64 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); DN_API DN_Str8x128 DN_AgeStr8FromMsU64 (DN_U64 duration_ms, DN_AgeUnit units); DN_API DN_Str8x128 DN_AgeStr8FromSecU64 (DN_U64 duration_ms, DN_AgeUnit units); @@ -5060,6 +5095,13 @@ DN_API void DN_QSortStr8NaturalDesc DN_API void DN_QSortStr8LexicographicAsc (DN_Str8 *array, DN_USize array_size, DN_Str8EqCase eq_case); DN_API void DN_QSortStr8LexicographicDesc (DN_Str8 *array, DN_USize array_size, DN_Str8EqCase eq_case); +DN_API bool DN_BSearchLessThanBytes (void const *lhs, void const *rhs, void *user_context); +DN_API DN_BSearchResult DN_BSearch (void const *array, DN_USize count, DN_USize elem_size, void const *find, DN_BSearchType type, void *user_context, DN_BSearchLessThanFunc *less_than); +DN_API DN_BSearchResult DN_BSearchBytes (void const *array, DN_USize count, DN_USize elem_size, void const *find, DN_BSearchType type); +DN_API DN_BSearchResult DN_BSearchUSize (DN_USize const *array, DN_USize count, DN_USize find, DN_BSearchType type); +DN_API DN_BSearchResult DN_BSearchU64 (DN_U64 const *array, DN_USize count, DN_U64 find, DN_BSearchType type); +DN_API DN_BSearchResult DN_BSearchU32 (DN_U32 const *array, DN_USize count, DN_U32 find, DN_BSearchType type); + DN_API DN_PCG32 DN_PCG32Init (DN_U64 seed); DN_API DN_U32 DN_PCG32Next (DN_PCG32 *rng); DN_API DN_U64 DN_PCG32Next64 (DN_PCG32 *rng); @@ -6073,6 +6115,7 @@ DN_API void DN_TestGroupEnd DN_API void DN_TestBeginF (DN_TestCore *test, char const *fmt, ...); DN_API void DN_TestEnd (DN_TestCore *test); #define DN_TestScopeF(test_ptr, fmt, ...) bool test_once_ = (DN_TestBeginF(test_ptr, fmt, ##__VA_ARGS__), false); !test_once_; DN_TestEnd(test_ptr), test_once_ = true +DN_API DN_Str8 DN_Str8FromTestCore (DN_TestCore const *test, DN_Arena *arena, DN_Str8FromTestCoreFlags flags); DN_API void DN_TestVerifyExprF_ (DN_TestCore *test, DN_CallSite call_site, DN_Str8 expr, bool expr_result, char const *fmt, ...); #define DN_TestVerifyExprF(test_ptr, expr, fmt, ...) DN_TestVerifyExprF_(test_ptr, DN_CallSiteNow, DN_Str8Lit(#expr), (expr), fmt, ##__VA_ARGS__) @@ -6132,128 +6175,28 @@ DN_API void DN_TestVerifyBytesF #define DN_TestVerifyBytesNotEqF(test_ptr, bytes, expect, fmt, ...) DN_TestVerifyBytesF(test_ptr, DN_CallSiteNow, DN_Str8Lit(#bytes " != " #expect), (bytes), (expect), /*expect_eq=*/ false, fmt, ##__VA_ARGS__) #define DN_TestVerifyBytesNotEq(test_ptr, bytes, expect) DN_TestVerifyBytesF(test_ptr, DN_CallSiteNow, DN_Str8Lit(#bytes " != " #expect), (bytes), (expect), /*expect_eq=*/ false, "") -DN_API DN_Str8 DN_Str8FromTestCore (DN_TestCore const *test, DN_Arena *arena, DN_Str8FromTestCoreFlags flags); - #if DN_WITH_TESTS DN_API DN_TestCore DN_TestSuite (DN_Arena *arena_); #endif -// TODO: Replace with a C implementation -template -using DN_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs); - -template -bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs); - -enum DN_BinarySearchType -{ - // Index of the match. If no match is found, found is set to false and the - // index is set to the index where the match should be inserted/exist, if - // it were in the array - DN_BinarySearchType_Match, - - // Index of the first element in the array that is `element >= find`. If no such - // item is found or the array is empty, then, the index is set to the array - // size and found is set to `false`. - // - // For example: - // int array[] = {0, 1, 2, 3, 4, 5}; - // DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_LowerBound); - // printf("%zu\n", result.index); // Prints index '4' - - DN_BinarySearchType_LowerBound, - - // Index of the first element in the array that is `element > find`. If no such - // item is found or the array is empty, then, the index is set to the array - // size and found is set to `false`. - // - // For example: - // int array[] = {0, 1, 2, 3, 4, 5}; - // DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_UpperBound); - // printf("%zu\n", result.index); // Prints index '5' - - DN_BinarySearchType_UpperBound, -}; - -struct DN_BinarySearchResult -{ - bool found; - DN_USize index; -}; - -template bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs); -template DN_BinarySearchResult DN_BinarySearch (T const *array, DN_USize array_size, T const &find, DN_BinarySearchType type = DN_BinarySearchType_Match, DN_BinarySearchLessThanProc less_than = DN_BinarySearch_DefaultLessThan); - -template -bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs) -{ - bool result = lhs < rhs; - return result; -} - -template -DN_BinarySearchResult DN_BinarySearch(T const *array, - DN_USize array_size, - T const &find, - DN_BinarySearchType type, - DN_BinarySearchLessThanProc less_than) -{ - DN_BinarySearchResult result = {}; - if (!array || array_size <= 0 || !less_than) - return result; - - T const *end = array + array_size; - T const *first = array; - T const *last = end; - while (first != last) { - DN_USize count = last - first; - T const *it = first + (count / 2); - - bool advance_first = false; - if (type == DN_BinarySearchType_UpperBound) - advance_first = !less_than(find, it[0]); - else - advance_first = less_than(it[0], find); - - if (advance_first) - first = it + 1; - else - last = it; - } - - switch (type) { - case DN_BinarySearchType_Match: { - result.found = first != end && !less_than(find, *first); - } break; - - case DN_BinarySearchType_LowerBound: /*FALLTHRU*/ - case DN_BinarySearchType_UpperBound: { - result.found = first != end; - } break; - } - - result.index = first - array; - return result; -} - -DN_API void DN_LeakTrackAlloc_ (DN_LeakTracker *leak, void *ptr, DN_USize size, bool alloc_can_leak); -DN_API void DN_LeakTrackDealloc_(DN_LeakTracker *leak, void *ptr); -DN_API void DN_LeakDump_ (DN_LeakTracker *leak); +DN_API void DN_LeakTrackAlloc_ (DN_LeakTracker *leak, void *ptr, DN_USize size, bool alloc_can_leak); +DN_API void DN_LeakTrackDealloc_ (DN_LeakTracker *leak, void *ptr); +DN_API void DN_LeakDump_ (DN_LeakTracker *leak); #if defined(DN_LEAK_TRACKING) -#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) DN_LeakTrackAlloc_(leak, ptr, size, alloc_can_leak) -#define DN_LeakTrackDealloc(leak, ptr) DN_LeakTrackDealloc_(leak, ptr) -#define DN_LeakDump(leak) DN_LeakDump_(leak) +#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) DN_LeakTrackAlloc_(leak, ptr, size, alloc_can_leak) +#define DN_LeakTrackDealloc(leak, ptr) DN_LeakTrackDealloc_(leak, ptr) +#define DN_LeakDump(leak) DN_LeakDump_(leak) #else -#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0) -#define DN_LeakTrackDealloc(leak, ptr) do { (void)ptr; } while (0) -#define DN_LeakDump(leak) do { } while (0) +#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0) +#define DN_LeakTrackDealloc(leak, ptr) do { (void)ptr; } while (0) +#define DN_LeakDump(leak) do { } while (0) #endif #if DN_WITH_OS -DN_API DN_Str8 DN_OS_Str8FromStr8BuilderHeap (DN_Str8Builder const *builder); -DN_API void DN_OS_LogPrint (DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_OS_SetLogPrintFuncToOS (); +DN_API DN_Str8 DN_OS_Str8FromStr8BuilderHeap (DN_Str8Builder const *builder); +DN_API void DN_OS_LogPrint (DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_OS_SetLogPrintFuncToOS (); // NOTE: Heap // Overview diff --git a/Source/Standalone/dn_sha3.h b/Source/Standalone/dn_sha3.h index 8221205..f5ccc4a 100644 --- a/Source/Standalone/dn_sha3.h +++ b/Source/Standalone/dn_sha3.h @@ -679,10 +679,10 @@ enum DN_SHA3TestHash DN_SHA3TestHash_Count, }; -static void DN_SHA3TestHashDispatch_(DN_TestCore *test, DN_SHA3TestHash hash_type, DN_Str8 input) +static void DN_SHA3_TestHashDispatch_(DN_TestCore *test, DN_SHA3TestHash hash_type, DN_Str8 input) { DN_TCScratch scratch = DN_TCScratchBeginArena(&test->arena, 1); - DN_Str8 input_hex = DN_HexFromPtrBytesArena(input.data, input.count, &scratch.arena, DN_TrimLeadingZero_No); + DN_Str8 input_hex = DN_Str8HexFromPtrBytesArena(input.data, input.count, &scratch.arena, DN_TrimLeadingZero_No); switch (hash_type) { case DN_SHA3TestHash_Count: DN_AssertInvalidCodePath; break; case DN_SHA3TestHash_224: { @@ -774,7 +774,7 @@ DN_TestCore DN_SHA3_TestSuite(DN_Arena *arena) for (DN_ForItCArray(it, DN_Str8 const, INPUTS)) { for (DN_TestScopeF(&result, "[%.*s] %.*s", DN_Str8PrintFmt(hash_name), DN_Str8PrintFmt(*it.data))) - DN_SHA3TestHashDispatch_(&result, DN_Cast(DN_SHA3TestHash)hash_type, *it.data); + DN_SHA3_TestHashDispatch_(&result, DN_Cast(DN_SHA3TestHash)hash_type, *it.data); } } @@ -790,7 +790,7 @@ DN_TestCore DN_SHA3_TestSuite(DN_Arena *arena) // NOTE: Do the hashing DN_Str8 input = DN_Str8FromPtr(src, src_size); - DN_SHA3TestHashDispatch_(&result, DN_Cast(DN_SHA3TestHash)hash_type, input); + DN_SHA3_TestHashDispatch_(&result, DN_Cast(DN_SHA3TestHash)hash_type, input); } } } diff --git a/Source/dn.cpp b/Source/dn.cpp index 68b2c8a..250f68f 100644 --- a/Source/dn.cpp +++ b/Source/dn.cpp @@ -2677,14 +2677,14 @@ DN_API DN_U8x32 DN_U8x32FromHexUnsafe(DN_Str8 hex_32b) DN_U8x32 result = {}; hex_32b = DN_Str8TrimHexPrefix(hex_32b); DN_Assert(hex_32b.count <= sizeof(result.data) * 2); - DN_BytesFromHexPtr(hex_32b.data, hex_32b.count, result.data, sizeof(result.data)); + DN_PtrBytesFromPtrHex(hex_32b.data, hex_32b.count, result.data, sizeof(result.data)); return result; } DN_API DN_U8x32FromResult DN_U8x32FromHex(DN_Str8 hex_32b) { DN_U8x32FromResult result = {}; - DN_USize bytes_written = DN_BytesFromHexPtr(hex_32b.data, hex_32b.count, result.value.data, sizeof(result.value.data)); + DN_USize bytes_written = DN_PtrBytesFromPtrHex(hex_32b.data, hex_32b.count, result.value.data, sizeof(result.value.data)); if (bytes_written == sizeof(result.value.data)) result.success = true; return result; @@ -4984,7 +4984,7 @@ DN_API DN_NibbleFromU8Result DN_NibbleFromU8(DN_U8 u8) return result; } -DN_API DN_USize DN_BytesFromHex(DN_Str8 hex, void *dest, DN_USize dest_count) +DN_API DN_USize DN_PtrBytesFromStr8Hex(DN_Str8 hex, void *dest, DN_USize dest_count) { DN_Str8 hex_trimmed = DN_Str8TrimHexPrefix(hex); DN_USize result = 0; @@ -5017,65 +5017,65 @@ DN_API DN_USize DN_BytesFromHex(DN_Str8 hex, void *dest, DN_USize dest_count) return result; } -DN_API DN_Str8 DN_BytesFromHexArena(DN_Str8 hex, DN_Arena *arena) +DN_API DN_USize DN_PtrBytesFromPtrHex(char const *hex, DN_USize hex_count, void *dest, DN_USize dest_count) { - DN_Str8 result = DN_BytesFromHexPtrArena(hex.data, hex.count, arena); + DN_USize result = DN_PtrBytesFromStr8Hex(DN_Str8FromPtr(hex, hex_count), dest, dest_count); return result; } -DN_API DN_USize DN_BytesFromHexPtr(char const *hex, DN_USize hex_count, void *dest, DN_USize dest_count) +DN_API DN_Str8 DN_Str8BytesFromStr8HexArena(DN_Str8 hex, DN_Arena *arena) { - DN_USize result = DN_BytesFromHex(DN_Str8FromPtr(hex, hex_count), dest, dest_count); + DN_Str8 result = DN_Str8BytesFromPtrHexArena(hex.data, hex.count, arena); return result; } -DN_API DN_Str8 DN_BytesFromHexPtrArena(char const *hex, DN_USize hex_count, DN_Arena *arena) +DN_API DN_Str8 DN_Str8BytesFromPtrHexArena(char const *hex, DN_USize hex_count, DN_Arena *arena) { DN_Str8 hex_trimmed = DN_Str8TrimHexPrefix(DN_Str8FromPtr(hex, hex_count)); DN_Assert(hex_trimmed.count % 2 == 0); DN_Str8 result = {}; result.data = DN_ArenaNewArray(arena, char, hex_trimmed.count / 2, DN_ZMem_No); if (result.data) - result.count = DN_BytesFromHex(hex_trimmed, result.data, hex_trimmed.count / 2); + result.count = DN_PtrBytesFromStr8Hex(hex_trimmed, result.data, hex_trimmed.count / 2); return result; } -DN_API DN_Str8 DN_BytesFromHexPtrPool(char const *hex, DN_USize hex_count, DN_Pool *pool) +DN_API DN_Str8 DN_Str8BytesFromPtrHexPool(char const *hex, DN_USize hex_count, DN_Pool *pool) { DN_Str8 hex_trimmed = DN_Str8TrimHexPrefix(DN_Str8FromPtr(hex, hex_count)); DN_Assert(hex_trimmed.count % 2 == 0); DN_Str8 result = {}; result.data = DN_PoolNewArray(pool, char, hex_trimmed.count / 2); if (result.data) - result.count = DN_BytesFromHex(hex_trimmed, result.data, hex_trimmed.count / 2); + result.count = DN_PtrBytesFromStr8Hex(hex_trimmed, result.data, hex_trimmed.count / 2); return result; } -DN_API DN_U8x16 DN_BytesFromHex32Ptr(char const *hex, DN_USize hex_count) +DN_API DN_U8x16 DN_U8x16FromPtrHex32(char const *hex, DN_USize hex_count) { DN_U8x16 result = {}; DN_Str8 hex_trimmed = DN_Str8TrimHexPrefix(DN_Str8FromPtr(hex, hex_count)); DN_Assert(hex_trimmed.count / 2 == sizeof result.data); - DN_USize bytes_written = DN_BytesFromHex(hex_trimmed, result.data, sizeof result.data); + DN_USize bytes_written = DN_PtrBytesFromStr8Hex(hex_trimmed, result.data, sizeof result.data); DN_Assert(bytes_written == sizeof result.data); return result; } -DN_API DN_U8x32 DN_BytesFromHex64Ptr(char const *hex, DN_USize hex_count) +DN_API DN_U8x32 DN_U8x32FromPtrHex64(char const *hex, DN_USize hex_count) { DN_U8x32 result = {}; DN_Str8 hex_trimmed = DN_Str8TrimHexPrefix(DN_Str8FromPtr(hex, hex_count)); DN_Assert(hex_trimmed.count / 2 == sizeof result.data); - DN_USize bytes_written = DN_BytesFromHex(hex_trimmed, result.data, sizeof result.data); + DN_USize bytes_written = DN_PtrBytesFromStr8Hex(hex_trimmed, result.data, sizeof result.data); DN_Assert(bytes_written == sizeof result.data); return result; } -DN_API DN_HexU64 DN_HexFromU64(DN_U64 value, DN_HexFromU64Type type) +DN_API DN_HexU64 DN_HexU64FromU64(DN_U64 value, DN_HexFromU64Type type) { DN_HexU64 result = {}; - DN_USize count = DN_HexFromPtrBytes(&value, sizeof(value), result.data, sizeof(result.data), DN_TrimLeadingZero_No); + DN_USize count = DN_PtrHexFromPtrBytes(&value, sizeof(value), result.data, sizeof(result.data), DN_TrimLeadingZero_No); result.count = DN_SaturateCastUSizeToU8(count); if (type == DN_HexFromU64Type_Uppercase) { for (DN_USize index = 0; index < result.count; index++) @@ -5084,7 +5084,7 @@ DN_API DN_HexU64 DN_HexFromU64(DN_U64 value, DN_HexFromU64Type type) return result; } -DN_API DN_USize DN_HexFromPtrBytes(void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z) +DN_API DN_USize DN_PtrHexFromPtrBytes(void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z) { DN_USize result = 0; if ((bytes_count * 2) > hex_count) @@ -5116,57 +5116,57 @@ DN_API DN_USize DN_HexFromPtrBytes(void const *bytes, DN_USize bytes_count, void return result; } -DN_API DN_Str8 DN_HexFromPtrBytesArena(void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z) +DN_API DN_Str8 DN_Str8HexFromPtrBytesArena(void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z) { DN_Str8 result = {}; if (bytes_count) { result.data = DN_ArenaNewArray(arena, char, bytes_count * 2, DN_ZMem_No); if (result.data) - result.count = DN_HexFromPtrBytes(bytes, bytes_count, result.data, bytes_count * 2, trim_leading_z); + result.count = DN_PtrHexFromPtrBytes(bytes, bytes_count, result.data, bytes_count * 2, trim_leading_z); } return result; } -DN_API DN_USize DN_HexFromStr8Bytes(DN_Str8 bytes, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z) +DN_API DN_USize DN_PtrHexFromStr8Bytes(DN_Str8 bytes, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z) { - DN_USize result = DN_HexFromPtrBytes(bytes.data, bytes.count, hex, hex_count, trim_leading_z); + DN_USize result = DN_PtrHexFromPtrBytes(bytes.data, bytes.count, hex, hex_count, trim_leading_z); return result; } -DN_API DN_Str8 DN_HexFromStr8BytesArena(DN_Str8 bytes, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z) +DN_API DN_Str8 DN_Str8HexFromStr8BytesArena(DN_Str8 bytes, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z) { DN_Str8 result = {}; if (bytes.count) { result.data = DN_ArenaNewArray(arena, char, bytes.count * 2, DN_ZMem_No); if (result.data) - result.count = DN_HexFromStr8Bytes(bytes, result.data, bytes.count * 2, trim_leading_z); + result.count = DN_PtrHexFromStr8Bytes(bytes, result.data, bytes.count * 2, trim_leading_z); } return result; } -DN_API DN_Hex32 DN_Hex32FromPtr16b(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) +DN_API DN_Hex32 DN_Hex32FromPtrBytes16(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) { DN_Hex32 result = {}; DN_Assert(bytes_count * 2 == sizeof result.data - 1); - result.count = DN_HexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); + result.count = DN_PtrHexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); DN_Assert(result.count <= sizeof result.data - 1); return result; } -DN_API DN_Hex64 DN_Hex64FromPtr32b(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) +DN_API DN_Hex64 DN_Hex64FromPtrBytes32(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) { DN_Hex64 result = {}; DN_Assert(bytes_count * 2 == sizeof result.data - 1); - result.count = DN_HexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); + result.count = DN_PtrHexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); DN_Assert(result.count <= sizeof result.data - 1); return result; } -DN_API DN_Hex128 DN_Hex128FromPtr64b(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) +DN_API DN_Hex128 DN_Hex128FromPtrBytes64(void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z) { DN_Hex128 result = {}; DN_Assert(bytes_count * 2 == sizeof result.data - 1); - result.count = DN_HexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); + result.count = DN_PtrHexFromPtrBytes(bytes, bytes_count, result.data, sizeof result.data, trim_leading_z); DN_Assert(result.count <= sizeof result.data - 1); return result; } @@ -5746,7 +5746,7 @@ DN_API bool DN_QSortCompareStr8LexicographicDesc(void const* lhs, void const *rh DN_API bool DN_QSortCompareBytesLT(void const* lhs, void const *rhs, void *user_context) { DN_USize elem_size = *DN_Cast(DN_USize *)user_context; - bool result = DN_Memcmp(lhs, rhs, elem_size) < 0; + bool result = DN_Memcmp(lhs, rhs, elem_size) < 0; return result; } @@ -5787,6 +5787,75 @@ DN_API void DN_QSortStr8LexicographicDesc(DN_Str8 *array, DN_USize array_size, D DN_QSort(array, array_size, sizeof(*array), /*user_context=*/ &eq_case, DN_QSortCompareStr8LexicographicDesc); } +DN_API bool DN_BSearchLessThanBytes(void const *lhs, void const *rhs, void *user_context) +{ + DN_USize elem_size = *DN_Cast(DN_USize *)user_context; + bool result = DN_Memcmp(lhs, rhs, elem_size) < 0; + return result; +} + +DN_API DN_BSearchResult DN_BSearch(void const *array, DN_USize count, DN_USize elem_size, void const *find, DN_BSearchType type, void *user_context, DN_BSearchLessThanFunc *less_than) +{ + DN_BSearchResult result = {}; + if (!array || count <= 0 || !less_than || !find) + return result; + + void const *end = DN_Cast(char *)array + (count * elem_size); + void const *first = array; + void const *last = end; + while (first != last) { + DN_USize dist = (DN_Cast(char *)last - DN_Cast(char *)first) / elem_size; + void const *it = DN_Cast(char *)first + ((dist / 2) * elem_size); + bool advance_first = false; + if (type == DN_BSearchType_UpperBound) + advance_first = !less_than(find, it, user_context); + else + advance_first = less_than(it, find, user_context); + + if (advance_first) + first = DN_Cast(char *)it + (1 * elem_size); + else + last = it; + } + + switch (type) { + case DN_BSearchType_Match: { + result.found = first != end && !less_than(find, first, user_context); + } break; + + case DN_BSearchType_LowerBound: /*FALLTHRU*/ + case DN_BSearchType_UpperBound: { + result.found = first != end; + } break; + } + + result.index = (DN_Cast(char *)first - DN_Cast(char *)array) / elem_size; + return result; +} + +DN_API DN_BSearchResult DN_BSearchBytes(void const *array, DN_USize count, DN_USize elem_size, void const *find, DN_BSearchType type) +{ + DN_BSearchResult result = DN_BSearch(array, count, elem_size, find, type, &elem_size, DN_BSearchLessThanBytes); + return result; +} + +DN_API DN_BSearchResult DN_BSearchUSize(DN_USize const *array, DN_USize count, DN_USize find, DN_BSearchType type) +{ + DN_BSearchResult result = DN_BSearchBytes(array, count, sizeof(*array), &find, type); + return result; +} + +DN_API DN_BSearchResult DN_BSearchU64(DN_U64 const *array, DN_USize count, DN_U64 find, DN_BSearchType type) +{ + DN_BSearchResult result = DN_BSearchBytes(array, count, sizeof(*array), &find, type); + return result; +} + +DN_API DN_BSearchResult DN_BSearchU32(DN_U32 const *array, DN_USize count, DN_U32 find, DN_BSearchType type) +{ + DN_BSearchResult result = DN_BSearchBytes(array, count, sizeof(*array), &find, type); + return result; +} #define DN_PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL #define DN_PCG_DEFAULT_INCREMENT_64 1442695040888963407ULL @@ -9301,6 +9370,109 @@ DN_API void DN_TestEnd(DN_TestCore *test) group->curr_entry = nullptr; } +DN_API DN_Str8 DN_Str8FromTestCore(DN_TestCore const *test, DN_Arena *arena, DN_Str8FromTestCoreFlags flags) +{ + DN_TCScratch scratch = DN_TCScratchBeginArena(&arena, 1); + DN_USize padding_count = 100; + DN_Str8 padding_line = DN_Str8FillF(&scratch.arena, padding_count, "."); + if (flags & DN_Str8FromTestCoreFlags_Colour) + padding_line = DN_Str8FromFmtANSIColourU8RGBArena(DN_ANSIColourMode_Fg, 64, 64, 64, &scratch.arena, "%.*s", DN_Str8PrintFmt(padding_line)); + + DN_V3F32 const good_colour = DN_V3F32From3N(0, 255, 0); + DN_V3F32 const bad_colour = DN_V3F32From3N(255, 0, 0); + DN_Str8Builder builder = DN_Str8BuilderFromArena(arena); + for (DN_ForItSize(group_it, DN_TestGroup const, test->groups, test->groups_count)) { + DN_TestGroup const* group = group_it.data; + DN_USize group_successes = 0; + DN_USize group_failures = 0; + DN_MSVC_WARNING_PUSH + DN_MSVC_WARNING_DISABLE(6067) // _Param_(5) in call to 'DN_Str8BuilderAppendF' must be the address of a string. Actual type: 'const unsigned __int64'. + DN_MSVC_WARNING_DISABLE(6271) // Extra argument passed to 'DN_Str8BuilderAppendF'. + DN_Str8BuilderAppendF(&builder, "[%.*s] (%'zu test%s)\n", DN_Str8PrintFmt(group->name), group->entries_count, (group->entries_count > 1) ? "s" : ""); + DN_MSVC_WARNING_POP + for (DN_ForItSize(entry_it, DN_TestEntry const, group->entries, group->entries_count)) { + DN_TestEntry const* entry = entry_it.data; + if (entry->failed) + group_failures++; + else + group_successes++; + + // NOTE: Extract the test name and pad the line with dots (.) + DN_Str8 test_prefix = DN_Str8FromFmtArena(&scratch.arena, " [%zu/%zu] %.*s ", entry_it.index + 1, group->entries_count, DN_Str8PrintFmt(entry->name)); + if (test_prefix.count < padding_line.count) { + DN_USize remaining = padding_line.count - test_prefix.count; + DN_Str8 padder = DN_Str8Subset(padding_line, 0, remaining); + test_prefix = DN_Str8AppendF(&scratch.arena, test_prefix, "%.*s", DN_Str8PrintFmt(padder)); + } + + // NOTE: Construct the test line + DN_Str8 outcome_str8 = entry->failed ? DN_Str8Lit("FAILED") : DN_Str8Lit("OK"); + if (flags & DN_Str8FromTestCoreFlags_Colour) { + if (entry->failed) + outcome_str8 = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, bad_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(outcome_str8)); + else + outcome_str8 = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, good_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(outcome_str8)); + } + + DN_F64 elapsed_ms = DN_OS_PerfCounterMs(entry->ts_begin, entry->ts_end); + DN_Str8BuilderAppendF(&builder, "%.*s %.*s (%.3fms)\n", DN_Str8PrintFmt(test_prefix), DN_Str8PrintFmt(outcome_str8), elapsed_ms); + + // NOTE: Output the test diagnostics, populated on failure + if (entry->failed) { + for (DN_ForItSize(row_it, DN_TestDiagnosticRow, entry->diagnostics, entry->diagnostics_count)) { + DN_USize row_count = 1; + DN_Str8TableFlags table_flags = DN_Str8TableFlags_None; + if (row_it.index == 0) { + row_count++; // Header + table_flags |= DN_Str8TableFlags_HasHeader; + } + + DN_USize col_count = 3; // Expression, Eval, Call site + DN_USize row_index = 0; + DN_Str8 *rows_str8 = DN_ArenaNewArrayZ(&scratch.arena, DN_Str8, row_count * col_count); + if (row_it.index == 0) { + rows_str8[row_index++] = DN_Str8Lit("Expr."); + rows_str8[row_index++] = DN_Str8Lit("Eval."); + rows_str8[row_index++] = DN_Str8Lit("Location"); + } + + DN_TestDiagnosticRow *row = row_it.data; + DN_Str8 file_name = DN_Str8FileNameFromPath(row->call_site.file); + rows_str8[row_index++] = row->expr; + rows_str8[row_index++] = row->invariant; + rows_str8[row_index++] = DN_Str8FromFmtArena(&scratch.arena, "%.*s:%u", DN_Str8PrintFmt(file_name), row->call_site.line); + + DN_Str8 table = DN_Str8Table(rows_str8, row_count, col_count, table_flags, &scratch.arena); + table = DN_Str8PadNewLinesArena(table, DN_Str8Lit(" "), &scratch.arena); + DN_Str8BuilderAppendF(&builder, " %.*s\n", DN_Str8PrintFmt(table)); + if (row->message.count) { + DN_Str8 line_break = DN_Str8LineBreakArena(row->message, 100, DN_Str8Lit("\n "), DN_Str8LineBreakMode_AtWord, &scratch.arena); + DN_Str8BuilderAppendF(&builder, " User Message: %.*s\n", DN_Str8PrintFmt(line_break)); + } + } + DN_Str8BuilderAppendF(&builder, "\n"); + } + } + + DN_F64 elapsed_ms = DN_OS_PerfCounterMs(group->ts_begin, group->ts_end); + DN_MSVC_WARNING_PUSH + DN_MSVC_WARNING_DISABLE(6067) // _Param_(3) in call to 'DN_Str8BuilderAppendF' must be the address of a string. Actual type: 'const unsigned __int64'. + DN_MSVC_WARNING_DISABLE(6271) // Extra argument passed to 'DN_Str8BuilderAppendF'. + DN_Str8 group_prefix = DN_Str8FromFmtArena(&scratch.arena, "%'zu/%'zu test%s", group_successes, group->entries_count, group_successes > 1 ? "s" :""); + DN_MSVC_WARNING_POP + if (flags & DN_Str8FromTestCoreFlags_Colour) { + if (group_failures == 0) + group_prefix = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, good_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(group_prefix)); + else + group_prefix = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, bad_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(group_prefix)); + } + DN_Str8BuilderAppendF(&builder, "\n %.*s passed in [%.*s] %.3fms (%zu failed)\n", DN_Str8PrintFmt(group_prefix), DN_Str8PrintFmt(group->name), elapsed_ms, group_failures); + } + + DN_Str8 result = DN_Str8FromStr8BuilderArena(&builder, arena); + return result; +} + DN_API DN_TestDiagnosticRow *DN_TestVerifySetupFmtV(DN_TestCore *test, DN_CallSite call_site, DN_Str8 expr, bool verify_failed, char const *fmt, va_list args) { DN_AssertF(test->curr_group, "Test group must be started before attempting to verify a test invariant"); @@ -9442,8 +9614,8 @@ DN_API void DN_TestVerifyBytesF(DN_TestCore *test, DN_CallSite call_site, DN_Str DN_TestDiagnosticRow *row = DN_TestVerifySetupFmtV(test, call_site, expr, verify_failed, fmt, args); va_end(args); if (row) { - DN_Str8 bytes_hex = DN_HexFromStr8BytesArena(bytes, test->arena, DN_TrimLeadingZero_No); - DN_Str8 expect_hex = DN_HexFromStr8BytesArena(expect, test->arena, DN_TrimLeadingZero_No); + DN_Str8 bytes_hex = DN_Str8HexFromStr8BytesArena(bytes, test->arena, DN_TrimLeadingZero_No); + DN_Str8 expect_hex = DN_Str8HexFromStr8BytesArena(expect, test->arena, DN_TrimLeadingZero_No); if (expect_eq) row->invariant = DN_Str8FromFmtArena(test->arena, "\"%.*s\" != \"%.*s\"", DN_Str8PrintFmt(bytes_hex), DN_Str8PrintFmt(expect_hex)); else @@ -9451,109 +9623,6 @@ DN_API void DN_TestVerifyBytesF(DN_TestCore *test, DN_CallSite call_site, DN_Str } } -DN_API DN_Str8 DN_Str8FromTestCore(DN_TestCore const *test, DN_Arena *arena, DN_Str8FromTestCoreFlags flags) -{ - DN_TCScratch scratch = DN_TCScratchBeginArena(&arena, 1); - DN_USize padding_count = 100; - DN_Str8 padding_line = DN_Str8FillF(&scratch.arena, padding_count, "."); - if (flags & DN_Str8FromTestCoreFlags_Colour) - padding_line = DN_Str8FromFmtANSIColourU8RGBArena(DN_ANSIColourMode_Fg, 64, 64, 64, &scratch.arena, "%.*s", DN_Str8PrintFmt(padding_line)); - - DN_V3F32 const good_colour = DN_V3F32From3N(0, 255, 0); - DN_V3F32 const bad_colour = DN_V3F32From3N(255, 0, 0); - DN_Str8Builder builder = DN_Str8BuilderFromArena(arena); - for (DN_ForItSize(group_it, DN_TestGroup const, test->groups, test->groups_count)) { - DN_TestGroup const* group = group_it.data; - DN_USize group_successes = 0; - DN_USize group_failures = 0; - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6067) // _Param_(5) in call to 'DN_Str8BuilderAppendF' must be the address of a string. Actual type: 'const unsigned __int64'. - DN_MSVC_WARNING_DISABLE(6271) // Extra argument passed to 'DN_Str8BuilderAppendF'. - DN_Str8BuilderAppendF(&builder, "[%.*s] (%'zu test%s)\n", DN_Str8PrintFmt(group->name), group->entries_count, (group->entries_count > 1) ? "s" : ""); - DN_MSVC_WARNING_POP - for (DN_ForItSize(entry_it, DN_TestEntry const, group->entries, group->entries_count)) { - DN_TestEntry const* entry = entry_it.data; - if (entry->failed) - group_failures++; - else - group_successes++; - - // NOTE: Extract the test name and pad the line with dots (.) - DN_Str8 test_prefix = DN_Str8FromFmtArena(&scratch.arena, " [%zu/%zu] %.*s ", entry_it.index + 1, group->entries_count, DN_Str8PrintFmt(entry->name)); - if (test_prefix.count < padding_line.count) { - DN_USize remaining = padding_line.count - test_prefix.count; - DN_Str8 padder = DN_Str8Subset(padding_line, 0, remaining); - test_prefix = DN_Str8AppendF(&scratch.arena, test_prefix, "%.*s", DN_Str8PrintFmt(padder)); - } - - // NOTE: Construct the test line - DN_Str8 outcome_str8 = entry->failed ? DN_Str8Lit("FAILED") : DN_Str8Lit("OK"); - if (flags & DN_Str8FromTestCoreFlags_Colour) { - if (entry->failed) - outcome_str8 = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, bad_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(outcome_str8)); - else - outcome_str8 = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, good_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(outcome_str8)); - } - - DN_F64 elapsed_ms = DN_OS_PerfCounterMs(entry->ts_begin, entry->ts_end); - DN_Str8BuilderAppendF(&builder, "%.*s %.*s (%.3fms)\n", DN_Str8PrintFmt(test_prefix), DN_Str8PrintFmt(outcome_str8), elapsed_ms); - - // NOTE: Output the test diagnostics, populated on failure - if (entry->failed) { - for (DN_ForItSize(row_it, DN_TestDiagnosticRow, entry->diagnostics, entry->diagnostics_count)) { - DN_USize row_count = 1; - DN_Str8TableFlags table_flags = DN_Str8TableFlags_None; - if (row_it.index == 0) { - row_count++; // Header - table_flags |= DN_Str8TableFlags_HasHeader; - } - - DN_USize col_count = 3; // Expression, Eval, Call site - DN_USize row_index = 0; - DN_Str8 *rows_str8 = DN_ArenaNewArrayZ(&scratch.arena, DN_Str8, row_count * col_count); - if (row_it.index == 0) { - rows_str8[row_index++] = DN_Str8Lit("Expr."); - rows_str8[row_index++] = DN_Str8Lit("Eval."); - rows_str8[row_index++] = DN_Str8Lit("Location"); - } - - DN_TestDiagnosticRow *row = row_it.data; - DN_Str8 file_name = DN_Str8FileNameFromPath(row->call_site.file); - rows_str8[row_index++] = row->expr; - rows_str8[row_index++] = row->invariant; - rows_str8[row_index++] = DN_Str8FromFmtArena(&scratch.arena, "%.*s:%u", DN_Str8PrintFmt(file_name), row->call_site.line); - - DN_Str8 table = DN_Str8Table(rows_str8, row_count, col_count, table_flags, &scratch.arena); - table = DN_Str8PadNewLinesArena(table, DN_Str8Lit(" "), &scratch.arena); - DN_Str8BuilderAppendF(&builder, " %.*s\n", DN_Str8PrintFmt(table)); - if (row->message.count) { - DN_Str8 line_break = DN_Str8LineBreakArena(row->message, 100, DN_Str8Lit("\n "), DN_Str8LineBreakMode_AtWord, &scratch.arena); - DN_Str8BuilderAppendF(&builder, " User Message: %.*s\n", DN_Str8PrintFmt(line_break)); - } - } - DN_Str8BuilderAppendF(&builder, "\n"); - } - } - - DN_F64 elapsed_ms = DN_OS_PerfCounterMs(group->ts_begin, group->ts_end); - DN_MSVC_WARNING_PUSH - DN_MSVC_WARNING_DISABLE(6067) // _Param_(3) in call to 'DN_Str8BuilderAppendF' must be the address of a string. Actual type: 'const unsigned __int64'. - DN_MSVC_WARNING_DISABLE(6271) // Extra argument passed to 'DN_Str8BuilderAppendF'. - DN_Str8 group_prefix = DN_Str8FromFmtArena(&scratch.arena, "%'zu/%'zu test%s", group_successes, group->entries_count, group_successes > 1 ? "s" :""); - DN_MSVC_WARNING_POP - if (flags & DN_Str8FromTestCoreFlags_Colour) { - if (group_failures == 0) - group_prefix = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, good_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(group_prefix)); - else - group_prefix = DN_Str8FromFmtANSIColourV3F32RGB255Arena(DN_ANSIColourMode_Fg, bad_colour, &scratch.arena, "%.*s", DN_Str8PrintFmt(group_prefix)); - } - DN_Str8BuilderAppendF(&builder, "\n %.*s passed in [%.*s] %.3fms (%zu failed)\n", DN_Str8PrintFmt(group_prefix), DN_Str8PrintFmt(group->name), elapsed_ms, group_failures); - } - - DN_Str8 result = DN_Str8FromStr8BuilderArena(&builder, arena); - return result; -} - #if DN_WITH_TESTS #if defined(DN_PLATFORM_WIN32) && defined(DN_COMPILER_MSVC) // NOTE: Taken from MSDN __cpuid example implementation @@ -9999,261 +10068,261 @@ DN_API DN_TestCore DN_TestSuite(DN_Arena *arena_) } } - // NOTE: BytesHex + // NOTE: Hex/Bytes { DN_TCScratch scratch = DN_TCScratchBeginArena(&arena_, 1); DN_DEFER { DN_TCScratchEnd(&scratch); }; - for (DN_TestScopeF(&result, "[BytesHex] Convert 0x123")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert 0x123")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("0x123")); DN_TestVerifyExprF(&result, val == 0x123, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert 0xFFFF")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert 0xFFFF")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("0xFFFF")); DN_TestVerifyExprF(&result, val == 0xFFFF, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert FFFF")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert FFFF")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("FFFF")); DN_TestVerifyExprF(&result, val == 0xFFFF, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert abCD")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert abCD")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("abCD")); DN_TestVerifyExprF(&result, val == 0xabCD, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert 0xabCD")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert 0xabCD")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("0xabCD")); DN_TestVerifyExprF(&result, val == 0xabCD, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert 0x")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert 0x")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("0x")); DN_TestVerifyExprF(&result, val == 0x0, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert 0X")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert 0X")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("0X")); DN_TestVerifyExprF(&result, val == 0x0, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert 3")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert 3")) { uint64_t val = DN_U64FromHexStr8Unsafe(DN_Str8Lit("3")); DN_TestVerifyExprF(&result, val == 3, "val: %" PRIu64, val); } - for (DN_TestScopeF(&result, "[BytesHex] Convert f")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert f")) { DN_U64FromResult res = DN_U64FromHexStr8(DN_Str8Lit("f")); DN_TestVerifyExpr(&result, res.success); DN_TestVerifyExpr(&result, res.value == 0xf); } - for (DN_TestScopeF(&result, "[BytesHex] Convert g")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert g")) { DN_U64FromResult res = DN_U64FromHexStr8(DN_Str8Lit("g")); DN_TestVerifyExpr(&result, !res.success); } - for (DN_TestScopeF(&result, "[BytesHex] Convert -0x3")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert -0x3")) { DN_U64FromResult res = DN_U64FromHexStr8(DN_Str8Lit("-0x3")); DN_TestVerifyExpr(&result, !res.success); } DN_U32 number = 0xd095f6; - for (DN_TestScopeF(&result, "[BytesHex] Convert %x to string", number)) { - DN_Str8 number_hex = DN_HexFromPtrBytesArena(&number, sizeof(number), &scratch.arena, DN_TrimLeadingZero_No); + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert %x to string", number)) { + DN_Str8 number_hex = DN_Str8HexFromPtrBytesArena(&number, sizeof(number), &scratch.arena, DN_TrimLeadingZero_No); DN_TestVerifyStr8EqF(&result, number_hex, DN_Str8Lit("f695d000"), "number_hex=%.*s", DN_Str8PrintFmt(number_hex)); } number = 0xf6ed00; - for (DN_TestScopeF(&result, "[BytesHex] Convert %x to string", number)) { - DN_Str8 number_hex = DN_HexFromPtrBytesArena(&number, sizeof(number), &scratch.arena, DN_TrimLeadingZero_No); + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert %x to string", number)) { + DN_Str8 number_hex = DN_Str8HexFromPtrBytesArena(&number, sizeof(number), &scratch.arena, DN_TrimLeadingZero_No); DN_TestVerifyStr8EqF(&result, number_hex, DN_Str8Lit("00edf600"), "number_hex=%.*s", DN_Str8PrintFmt(number_hex)); } DN_Str8 hex = DN_Str8Lit("0xf6ed00"); - for (DN_TestScopeF(&result, "[BytesHex] Convert %.*s to bytes", DN_Str8PrintFmt(hex))) { - DN_Str8 bytes = DN_BytesFromHexArena(hex, &scratch.arena); + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert %.*s to bytes", DN_Str8PrintFmt(hex))) { + DN_Str8 bytes = DN_Str8BytesFromStr8HexArena(hex, &scratch.arena); DN_TestVerifyStr8EqF(&result, bytes, DN_Str8Lit("\xf6\xed\x00"), "number_hex=%.*s", - DN_Str8PrintFmt(DN_HexFromPtrBytesArena(bytes.data, bytes.count, &scratch.arena, DN_TrimLeadingZero_No))); + DN_Str8PrintFmt(DN_Str8HexFromPtrBytesArena(bytes.data, bytes.count, &scratch.arena, DN_TrimLeadingZero_No))); } - for (DN_TestScopeF(&result, "[BytesHex] Convert empty bytes to string")) { + for (DN_TestScopeF(&result, "[Hex/Bytes] Convert empty bytes to string")) { DN_Str8 bytes = DN_Str8Lit(""); - DN_Str8 as_hex = DN_HexFromPtrBytesArena(bytes.data, bytes.count, &scratch.arena, DN_TrimLeadingZero_No); + DN_Str8 as_hex = DN_Str8HexFromPtrBytesArena(bytes.data, bytes.count, &scratch.arena, DN_TrimLeadingZero_No); DN_TestVerifyStr8EqF(&result, as_hex, DN_Str8Lit(""), "as_hex=%.*s", DN_Str8PrintFmt(as_hex)); } } - // NOTE: BinarySearch + // NOTE: BSearch { - for (DN_TestScopeF(&result, "[BinarySearch] Search array of 1 item")) { - DN_U32 array[] = {1}; - DN_BinarySearchResult search = {}; + for (DN_TestScopeF(&result, "[BSearch] Search array of 1 item")) { + DN_U32 array[] = {1}; + DN_BSearchResult search = {}; - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 1); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 1); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 1); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 1); } - for (DN_TestScopeF(&result, "[BinarySearch] Search array of 3 items")) { + for (DN_TestScopeF(&result, "[BSearch] Search array of 3 items")) { DN_U32 array[] = {1, 2, 3}; - DN_BinarySearchResult search = {}; + DN_BSearchResult search = {}; - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 1); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 3U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 3U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 2); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 4U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 4U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 3); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 1); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 3U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 3U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 2); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 4U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 4U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 3); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 1); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 2); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 3U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 3U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 3); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 4U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 4U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 3); } - for (DN_TestScopeF(&result, "[BinarySearch] Search array with duplicate items")) { + for (DN_TestScopeF(&result, "[BSearch] Search array with duplicate items")) { DN_U32 array[] = {1, 1, 2, 2, 3}; - DN_BinarySearchResult search = {}; + DN_BSearchResult search = {}; - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 2); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 3U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 3U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 4); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 4U, DN_BinarySearchType_Match); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 4U, DN_BSearchType_Match); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 5); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 2); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 3U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 3U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 4); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 4U, DN_BinarySearchType_LowerBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 4U, DN_BSearchType_LowerBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 5); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 0U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 0U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 0); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 1U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 1U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 2); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 2U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 2U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, search.found); DN_TestVerifyUSizeEq(&result, search.index, 4); - search = DN_BinarySearch(array, DN_ArrayCountU(array), 3U, DN_BinarySearchType_UpperBound); + search = DN_BSearchU32(array, DN_ArrayCountU(array), 3U, DN_BSearchType_UpperBound); DN_TestVerifyExpr(&result, !search.found); DN_TestVerifyUSizeEq(&result, search.index, 5); } diff --git a/Source/dn.h b/Source/dn.h index 8243d14..d197666 100644 --- a/Source/dn.h +++ b/Source/dn.h @@ -1540,7 +1540,42 @@ struct DN_Profiler DN_F64 frame_avg_tsc; }; -typedef bool (DN_QSortCompareFunc)(void const *a, void const *b, void *user_context); +typedef bool (DN_QSortCompareFunc) (void const *lhs, void const *rhs, void *user_context); +typedef bool (DN_BSearchLessThanFunc)(void const *lhs, void const *rhs, void *user_context); +enum DN_BSearchType +{ + // NOTE: Index of the match. If no match is found, found is set to false and the + // index is set to the index where the match should be inserted/exist, if + // it were in the array + DN_BSearchType_Match, + + // NOTE: Index of the first element in the array that is `element >= find`. If no such + // item is found or the array is empty, then, the index is set to the array + // size and found is set to `false`. + // + // For example: + // int array[] = {0, 1, 2, 3, 4, 5}; + // DN_BSearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BSearchType_LowerBound); + // printf("%zu\n", result.index); // Prints index '4' + DN_BSearchType_LowerBound, + + // NOTE: Index of the first element in the array that is `element > find`. If no such + // item is found or the array is empty, then, the index is set to the array + // size and found is set to `false`. + // + // For example: + // int array[] = {0, 1, 2, 3, 4, 5}; + // DN_BSearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BSearchType_UpperBound); + // printf("%zu\n", result.index); // Prints index '5' + DN_BSearchType_UpperBound, +}; + +struct DN_BSearchResult +{ + bool found; + DN_USize index; +}; + enum DN_ErrSinkMode { DN_ErrSinkMode_Nil, // Default behaviour to accumulate errors into the sink @@ -3023,22 +3058,22 @@ DN_API DN_USize DN_USizeCodepointCountFromUTF8 DN_API DN_U8 DN_U8FromHexNibble (char hex); DN_API DN_NibbleFromU8Result DN_NibbleFromU8 (DN_U8 u8); -DN_API DN_USize DN_BytesFromHex (DN_Str8 hex, void *dest, DN_USize dest_count); -DN_API DN_Str8 DN_BytesFromHexArena (DN_Str8 hex, DN_Arena *arena); -DN_API DN_USize DN_BytesFromHexPtr (char const *hex, DN_USize hex_count, void *dest, DN_USize dest_count); -DN_API DN_Str8 DN_BytesFromHexPtrArena (char const *hex, DN_USize hex_count, DN_Arena *arena); -DN_API DN_Str8 DN_BytesFromHexPtrPool (char const *hex, DN_USize hex_count, DN_Pool *pool); -DN_API DN_U8x16 DN_BytesFromHex32Ptr (char const *hex, DN_USize hex_count); -DN_API DN_U8x32 DN_BytesFromHex64Ptr (char const *hex, DN_USize hex_count); +DN_API DN_USize DN_PtrBytesFromStr8Hex (DN_Str8 hex, void *dest, DN_USize dest_count); +DN_API DN_USize DN_PtrBytesFromPtrHex (char const *hex, DN_USize hex_count, void *dest, DN_USize dest_count); +DN_API DN_Str8 DN_Str8BytesFromStr8HexArena (DN_Str8 hex, DN_Arena *arena); +DN_API DN_Str8 DN_Str8BytesFromPtrHexArena (char const *hex, DN_USize hex_count, DN_Arena *arena); +DN_API DN_Str8 DN_Str8BytesFromPtrHexPool (char const *hex, DN_USize hex_count, DN_Pool *pool); +DN_API DN_U8x16 DN_U8x16FromPtrHex32 (char const *hex, DN_USize hex_count); +DN_API DN_U8x32 DN_U8x32FromPtrHex64 (char const *hex, DN_USize hex_count); -DN_API DN_HexU64 DN_HexFromU64 (DN_U64 value, DN_HexFromU64Type type); -DN_API DN_USize DN_HexFromPtrBytes (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Str8 DN_HexFromPtrBytesArena (void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); -DN_API DN_USize DN_HexFromStr8Bytes (DN_Str8 bytes, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Str8 DN_HexFromStr8BytesArena (DN_Str8 bytes, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Hex32 DN_Hex32FromPtr16b (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Hex64 DN_Hex64FromPtr32b (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); -DN_API DN_Hex128 DN_Hex128FromPtr64b (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_HexU64 DN_HexU64FromU64 (DN_U64 value, DN_HexFromU64Type type); +DN_API DN_USize DN_PtrHexFromPtrBytes (void const *bytes, DN_USize bytes_count, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_USize DN_PtrHexFromStr8Bytes (DN_Str8 bytes, void *hex, DN_USize hex_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Str8 DN_Str8HexFromPtrBytesArena (void const *bytes, DN_USize bytes_count, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Str8 DN_Str8HexFromStr8BytesArena (DN_Str8 bytes, DN_Arena *arena, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex32 DN_Hex32FromPtrBytes16 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex64 DN_Hex64FromPtrBytes32 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); +DN_API DN_Hex128 DN_Hex128FromPtrBytes64 (void const *bytes, DN_USize bytes_count, DN_TrimLeadingZero trim_leading_z); DN_API DN_Str8x128 DN_AgeStr8FromMsU64 (DN_U64 duration_ms, DN_AgeUnit units); DN_API DN_Str8x128 DN_AgeStr8FromSecU64 (DN_U64 duration_ms, DN_AgeUnit units); @@ -3130,6 +3165,13 @@ DN_API void DN_QSortStr8NaturalDesc DN_API void DN_QSortStr8LexicographicAsc (DN_Str8 *array, DN_USize array_size, DN_Str8EqCase eq_case); DN_API void DN_QSortStr8LexicographicDesc (DN_Str8 *array, DN_USize array_size, DN_Str8EqCase eq_case); +DN_API bool DN_BSearchLessThanBytes (void const *lhs, void const *rhs, void *user_context); +DN_API DN_BSearchResult DN_BSearch (void const *array, DN_USize count, DN_USize elem_size, void const *find, DN_BSearchType type, void *user_context, DN_BSearchLessThanFunc *less_than); +DN_API DN_BSearchResult DN_BSearchBytes (void const *array, DN_USize count, DN_USize elem_size, void const *find, DN_BSearchType type); +DN_API DN_BSearchResult DN_BSearchUSize (DN_USize const *array, DN_USize count, DN_USize find, DN_BSearchType type); +DN_API DN_BSearchResult DN_BSearchU64 (DN_U64 const *array, DN_USize count, DN_U64 find, DN_BSearchType type); +DN_API DN_BSearchResult DN_BSearchU32 (DN_U32 const *array, DN_USize count, DN_U32 find, DN_BSearchType type); + DN_API DN_PCG32 DN_PCG32Init (DN_U64 seed); DN_API DN_U32 DN_PCG32Next (DN_PCG32 *rng); DN_API DN_U64 DN_PCG32Next64 (DN_PCG32 *rng); @@ -4143,6 +4185,7 @@ DN_API void DN_TestGroupEnd DN_API void DN_TestBeginF (DN_TestCore *test, char const *fmt, ...); DN_API void DN_TestEnd (DN_TestCore *test); #define DN_TestScopeF(test_ptr, fmt, ...) bool test_once_ = (DN_TestBeginF(test_ptr, fmt, ##__VA_ARGS__), false); !test_once_; DN_TestEnd(test_ptr), test_once_ = true +DN_API DN_Str8 DN_Str8FromTestCore (DN_TestCore const *test, DN_Arena *arena, DN_Str8FromTestCoreFlags flags); DN_API void DN_TestVerifyExprF_ (DN_TestCore *test, DN_CallSite call_site, DN_Str8 expr, bool expr_result, char const *fmt, ...); #define DN_TestVerifyExprF(test_ptr, expr, fmt, ...) DN_TestVerifyExprF_(test_ptr, DN_CallSiteNow, DN_Str8Lit(#expr), (expr), fmt, ##__VA_ARGS__) @@ -4202,128 +4245,28 @@ DN_API void DN_TestVerifyBytesF #define DN_TestVerifyBytesNotEqF(test_ptr, bytes, expect, fmt, ...) DN_TestVerifyBytesF(test_ptr, DN_CallSiteNow, DN_Str8Lit(#bytes " != " #expect), (bytes), (expect), /*expect_eq=*/ false, fmt, ##__VA_ARGS__) #define DN_TestVerifyBytesNotEq(test_ptr, bytes, expect) DN_TestVerifyBytesF(test_ptr, DN_CallSiteNow, DN_Str8Lit(#bytes " != " #expect), (bytes), (expect), /*expect_eq=*/ false, "") -DN_API DN_Str8 DN_Str8FromTestCore (DN_TestCore const *test, DN_Arena *arena, DN_Str8FromTestCoreFlags flags); - #if DN_WITH_TESTS DN_API DN_TestCore DN_TestSuite (DN_Arena *arena_); #endif -// TODO: Replace with a C implementation -template -using DN_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs); - -template -bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs); - -enum DN_BinarySearchType -{ - // Index of the match. If no match is found, found is set to false and the - // index is set to the index where the match should be inserted/exist, if - // it were in the array - DN_BinarySearchType_Match, - - // Index of the first element in the array that is `element >= find`. If no such - // item is found or the array is empty, then, the index is set to the array - // size and found is set to `false`. - // - // For example: - // int array[] = {0, 1, 2, 3, 4, 5}; - // DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_LowerBound); - // printf("%zu\n", result.index); // Prints index '4' - - DN_BinarySearchType_LowerBound, - - // Index of the first element in the array that is `element > find`. If no such - // item is found or the array is empty, then, the index is set to the array - // size and found is set to `false`. - // - // For example: - // int array[] = {0, 1, 2, 3, 4, 5}; - // DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_UpperBound); - // printf("%zu\n", result.index); // Prints index '5' - - DN_BinarySearchType_UpperBound, -}; - -struct DN_BinarySearchResult -{ - bool found; - DN_USize index; -}; - -template bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs); -template DN_BinarySearchResult DN_BinarySearch (T const *array, DN_USize array_size, T const &find, DN_BinarySearchType type = DN_BinarySearchType_Match, DN_BinarySearchLessThanProc less_than = DN_BinarySearch_DefaultLessThan); - -template -bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs) -{ - bool result = lhs < rhs; - return result; -} - -template -DN_BinarySearchResult DN_BinarySearch(T const *array, - DN_USize array_size, - T const &find, - DN_BinarySearchType type, - DN_BinarySearchLessThanProc less_than) -{ - DN_BinarySearchResult result = {}; - if (!array || array_size <= 0 || !less_than) - return result; - - T const *end = array + array_size; - T const *first = array; - T const *last = end; - while (first != last) { - DN_USize count = last - first; - T const *it = first + (count / 2); - - bool advance_first = false; - if (type == DN_BinarySearchType_UpperBound) - advance_first = !less_than(find, it[0]); - else - advance_first = less_than(it[0], find); - - if (advance_first) - first = it + 1; - else - last = it; - } - - switch (type) { - case DN_BinarySearchType_Match: { - result.found = first != end && !less_than(find, *first); - } break; - - case DN_BinarySearchType_LowerBound: /*FALLTHRU*/ - case DN_BinarySearchType_UpperBound: { - result.found = first != end; - } break; - } - - result.index = first - array; - return result; -} - -DN_API void DN_LeakTrackAlloc_ (DN_LeakTracker *leak, void *ptr, DN_USize size, bool alloc_can_leak); -DN_API void DN_LeakTrackDealloc_(DN_LeakTracker *leak, void *ptr); -DN_API void DN_LeakDump_ (DN_LeakTracker *leak); +DN_API void DN_LeakTrackAlloc_ (DN_LeakTracker *leak, void *ptr, DN_USize size, bool alloc_can_leak); +DN_API void DN_LeakTrackDealloc_ (DN_LeakTracker *leak, void *ptr); +DN_API void DN_LeakDump_ (DN_LeakTracker *leak); #if defined(DN_LEAK_TRACKING) -#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) DN_LeakTrackAlloc_(leak, ptr, size, alloc_can_leak) -#define DN_LeakTrackDealloc(leak, ptr) DN_LeakTrackDealloc_(leak, ptr) -#define DN_LeakDump(leak) DN_LeakDump_(leak) +#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) DN_LeakTrackAlloc_(leak, ptr, size, alloc_can_leak) +#define DN_LeakTrackDealloc(leak, ptr) DN_LeakTrackDealloc_(leak, ptr) +#define DN_LeakDump(leak) DN_LeakDump_(leak) #else -#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0) -#define DN_LeakTrackDealloc(leak, ptr) do { (void)ptr; } while (0) -#define DN_LeakDump(leak) do { } while (0) +#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0) +#define DN_LeakTrackDealloc(leak, ptr) do { (void)ptr; } while (0) +#define DN_LeakDump(leak) do { } while (0) #endif #if DN_WITH_OS -DN_API DN_Str8 DN_OS_Str8FromStr8BuilderHeap (DN_Str8Builder const *builder); -DN_API void DN_OS_LogPrint (DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); -DN_API void DN_OS_SetLogPrintFuncToOS (); +DN_API DN_Str8 DN_OS_Str8FromStr8BuilderHeap (DN_Str8Builder const *builder); +DN_API void DN_OS_LogPrint (DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args); +DN_API void DN_OS_SetLogPrintFuncToOS (); // NOTE: Heap // Overview