Convert binary search to a C style impl

This commit is contained in:
2026-07-05 23:26:54 +10:00
parent ed1f4fc0cc
commit 234fd9e302
5 changed files with 692 additions and 668 deletions
+273 -204
View File
@@ -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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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<DN_U32>(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);
}
+72 -129
View File
@@ -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 <typename T>
using DN_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs);
template <typename T>
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 <typename T> bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
template <typename T> DN_BinarySearchResult DN_BinarySearch (T const *array, DN_USize array_size, T const &find, DN_BinarySearchType type = DN_BinarySearchType_Match, DN_BinarySearchLessThanProc<T> less_than = DN_BinarySearch_DefaultLessThan);
template <typename T>
bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs)
{
bool result = lhs < rhs;
return result;
}
template <typename T>
DN_BinarySearchResult DN_BinarySearch(T const *array,
DN_USize array_size,
T const &find,
DN_BinarySearchType type,
DN_BinarySearchLessThanProc<T> 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