2024-04-18 12:59:11 +00:00
|
|
|
#pragma once
|
|
|
|
#include "dqn.h"
|
|
|
|
|
2024-03-25 05:11:57 +00:00
|
|
|
/*
|
2024-01-31 12:49:23 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\
|
|
|
|
// $$ | $$ |$$ _____|$$ | $$ __$$\ $$ _____|$$ __$$\ $$ __$$\
|
|
|
|
// $$ | $$ |$$ | $$ | $$ | $$ |$$ | $$ | $$ |$$ / \__|
|
|
|
|
// $$$$$$$$ |$$$$$\ $$ | $$$$$$$ |$$$$$\ $$$$$$$ |\$$$$$$\
|
|
|
|
// $$ __$$ |$$ __| $$ | $$ ____/ $$ __| $$ __$$< \____$$\
|
|
|
|
// $$ | $$ |$$ | $$ | $$ | $$ | $$ | $$ |$$\ $$ |
|
|
|
|
// $$ | $$ |$$$$$$$$\ $$$$$$$$\ $$ | $$$$$$$$\ $$ | $$ |\$$$$$$ |
|
|
|
|
// \__| \__|\________|\________|\__| \________|\__| \__| \______/
|
|
|
|
//
|
|
|
|
// dqn_helpers.cpp
|
|
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
2024-03-25 05:11:57 +00:00
|
|
|
*/
|
2024-01-31 12:49:23 +00:00
|
|
|
|
|
|
|
// NOTE: [$PCGX] Dqn_PCG32 /////////////////////////////////////////////////////////////////////////
|
2023-10-24 13:11:48 +00:00
|
|
|
#define DQN_PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL
|
|
|
|
#define DQN_PCG_DEFAULT_INCREMENT_64 1442695040888963407ULL
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_API Dqn_PCG32 Dqn_PCG32_Init(uint64_t seed)
|
|
|
|
{
|
|
|
|
Dqn_PCG32 result = {};
|
|
|
|
Dqn_PCG32_Next(&result);
|
|
|
|
result.state += seed;
|
|
|
|
Dqn_PCG32_Next(&result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API uint32_t Dqn_PCG32_Next(Dqn_PCG32 *rng)
|
|
|
|
{
|
|
|
|
uint64_t state = rng->state;
|
|
|
|
rng->state = state * DQN_PCG_DEFAULT_MULTIPLIER_64 + DQN_PCG_DEFAULT_INCREMENT_64;
|
|
|
|
|
|
|
|
// XSH-RR
|
|
|
|
uint32_t value = (uint32_t)((state ^ (state >> 18)) >> 27);
|
|
|
|
int rot = state >> 59;
|
|
|
|
return rot ? (value >> rot) | (value << (32 - rot)) : value;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint64_t Dqn_PCG32_Next64(Dqn_PCG32 *rng)
|
|
|
|
{
|
|
|
|
uint64_t value = Dqn_PCG32_Next(rng);
|
|
|
|
value <<= 32;
|
|
|
|
value |= Dqn_PCG32_Next(rng);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint32_t Dqn_PCG32_Range(Dqn_PCG32 *rng, uint32_t low, uint32_t high)
|
|
|
|
{
|
|
|
|
uint32_t bound = high - low;
|
|
|
|
uint32_t threshold = -(int32_t)bound % bound;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
uint32_t r = Dqn_PCG32_Next(rng);
|
|
|
|
if (r >= threshold)
|
|
|
|
return low + (r % bound);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API float Dqn_PCG32_NextF32(Dqn_PCG32 *rng)
|
|
|
|
{
|
|
|
|
uint32_t x = Dqn_PCG32_Next(rng);
|
|
|
|
return (float)(int32_t)(x >> 8) * 0x1.0p-24f;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API double Dqn_PCG32_NextF64(Dqn_PCG32 *rng)
|
|
|
|
{
|
|
|
|
uint64_t x = Dqn_PCG32_Next64(rng);
|
|
|
|
return (double)(int64_t)(x >> 11) * 0x1.0p-53;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API void Dqn_PCG32_Advance(Dqn_PCG32 *rng, uint64_t delta)
|
|
|
|
{
|
|
|
|
uint64_t cur_mult = DQN_PCG_DEFAULT_MULTIPLIER_64;
|
|
|
|
uint64_t cur_plus = DQN_PCG_DEFAULT_INCREMENT_64;
|
|
|
|
|
|
|
|
uint64_t acc_mult = 1;
|
|
|
|
uint64_t acc_plus = 0;
|
|
|
|
|
|
|
|
while (delta != 0) {
|
|
|
|
if (delta & 1) {
|
|
|
|
acc_mult *= cur_mult;
|
|
|
|
acc_plus = acc_plus * cur_mult + cur_plus;
|
|
|
|
}
|
|
|
|
cur_plus = (cur_mult + 1) * cur_plus;
|
|
|
|
cur_mult *= cur_mult;
|
|
|
|
delta >>= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rng->state = acc_mult * rng->state + acc_plus;
|
|
|
|
}
|
|
|
|
|
2023-08-16 11:59:38 +00:00
|
|
|
#if !defined(DQN_NO_JSON_BUILDER)
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: [$JSON] Dqn_JSONBuilder ///////////////////////////////////////////////////////////////////
|
|
|
|
DQN_API Dqn_JSONBuilder Dqn_JSONBuilder_Init(Dqn_Arena *arena, int spaces_per_indent)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_JSONBuilder result = {};
|
|
|
|
result.spaces_per_indent = spaces_per_indent;
|
|
|
|
result.string_builder.arena = arena;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_API Dqn_Str8 Dqn_JSONBuilder_Build(Dqn_JSONBuilder const *builder, Dqn_Arena *arena)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_Str8 result = Dqn_Str8Builder_Build(&builder->string_builder, arena);
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_JSONBuilder_KeyValue(Dqn_JSONBuilder *builder, Dqn_Str8 key, Dqn_Str8 value)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
|
|
|
if (key.size == 0 && value.size == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Dqn_JSONBuilderItem item = Dqn_JSONBuilderItem_KeyValue;
|
|
|
|
if (value.size == 1) {
|
2024-01-31 12:49:23 +00:00
|
|
|
if (value.data[0] == '{' || value.data[0] == '[')
|
2023-08-16 11:59:38 +00:00
|
|
|
item = Dqn_JSONBuilderItem_OpenContainer;
|
2024-01-31 12:49:23 +00:00
|
|
|
else if (value.data[0] == '}' || value.data[0] == ']')
|
2023-08-16 11:59:38 +00:00
|
|
|
item = Dqn_JSONBuilderItem_CloseContainer;
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
bool adding_to_container_with_items =
|
|
|
|
item != Dqn_JSONBuilderItem_CloseContainer && (builder->last_item == Dqn_JSONBuilderItem_KeyValue ||
|
|
|
|
builder->last_item == Dqn_JSONBuilderItem_CloseContainer);
|
2023-08-16 11:59:38 +00:00
|
|
|
|
|
|
|
uint8_t prefix_size = 0;
|
2024-01-31 12:49:23 +00:00
|
|
|
char prefix[2] = {0};
|
2023-08-16 11:59:38 +00:00
|
|
|
if (adding_to_container_with_items)
|
|
|
|
prefix[prefix_size++] = ',';
|
|
|
|
|
|
|
|
if (builder->last_item != Dqn_JSONBuilderItem_Empty)
|
|
|
|
prefix[prefix_size++] = '\n';
|
|
|
|
|
|
|
|
if (item == Dqn_JSONBuilderItem_CloseContainer)
|
|
|
|
builder->indent_level--;
|
|
|
|
|
|
|
|
int spaces_per_indent = builder->spaces_per_indent ? builder->spaces_per_indent : 2;
|
|
|
|
int spaces = builder->indent_level * spaces_per_indent;
|
|
|
|
|
|
|
|
if (key.size) {
|
2024-08-01 03:34:36 +00:00
|
|
|
Dqn_Str8Builder_AddF(&builder->string_builder,
|
|
|
|
"%.*s%*c\"%.*s\": %.*s",
|
|
|
|
prefix_size,
|
|
|
|
prefix,
|
|
|
|
spaces,
|
|
|
|
' ',
|
|
|
|
DQN_STR_FMT(key),
|
|
|
|
DQN_STR_FMT(value));
|
2023-08-16 11:59:38 +00:00
|
|
|
} else {
|
2024-08-01 03:34:36 +00:00
|
|
|
Dqn_Str8Builder_AddF(&builder->string_builder, "%.*s%*c%.*s", prefix_size, prefix, spaces, ' ', DQN_STR_FMT(value));
|
2023-08-16 11:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (item == Dqn_JSONBuilderItem_OpenContainer)
|
|
|
|
builder->indent_level++;
|
|
|
|
|
|
|
|
builder->last_item = item;
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_JSONBuilder_KeyValueFV(Dqn_JSONBuilder *builder, Dqn_Str8 key, char const *value_fmt, va_list args)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
2024-08-01 03:34:36 +00:00
|
|
|
Dqn_TLSTMem tmem = Dqn_TLS_TMem(builder->string_builder.arena);
|
|
|
|
Dqn_Str8 value = Dqn_Str8_InitFV(tmem.arena, value_fmt, args);
|
2023-08-16 11:59:38 +00:00
|
|
|
Dqn_JSONBuilder_KeyValue(builder, key, value);
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_JSONBuilder_KeyValueF(Dqn_JSONBuilder *builder, Dqn_Str8 key, char const *value_fmt, ...)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, value_fmt);
|
|
|
|
Dqn_JSONBuilder_KeyValueFV(builder, key, value_fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_JSONBuilder_ObjectBeginNamed(Dqn_JSONBuilder *builder, Dqn_Str8 name)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_JSONBuilder_KeyValue(builder, name, DQN_STR8("{"));
|
2023-08-16 11:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API void Dqn_JSONBuilder_ObjectEnd(Dqn_JSONBuilder *builder)
|
|
|
|
{
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_JSONBuilder_KeyValue(builder, DQN_STR8(""), DQN_STR8("}"));
|
2023-08-16 11:59:38 +00:00
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_JSONBuilder_ArrayBeginNamed(Dqn_JSONBuilder *builder, Dqn_Str8 name)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_JSONBuilder_KeyValue(builder, name, DQN_STR8("["));
|
2023-08-16 11:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API void Dqn_JSONBuilder_ArrayEnd(Dqn_JSONBuilder *builder)
|
|
|
|
{
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_JSONBuilder_KeyValue(builder, DQN_STR8(""), DQN_STR8("]"));
|
2023-08-16 11:59:38 +00:00
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_JSONBuilder_StrNamed(Dqn_JSONBuilder *builder, Dqn_Str8 key, Dqn_Str8 value)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
|
|
|
Dqn_JSONBuilder_KeyValueF(builder, key, "\"%.*s\"", value.size, value.data);
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_JSONBuilder_LiteralNamed(Dqn_JSONBuilder *builder, Dqn_Str8 key, Dqn_Str8 value)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
|
|
|
Dqn_JSONBuilder_KeyValueF(builder, key, "%.*s", value.size, value.data);
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_JSONBuilder_U64Named(Dqn_JSONBuilder *builder, Dqn_Str8 key, uint64_t value)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
|
|
|
Dqn_JSONBuilder_KeyValueF(builder, key, "%I64u", value);
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_JSONBuilder_I64Named(Dqn_JSONBuilder *builder, Dqn_Str8 key, int64_t value)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
|
|
|
Dqn_JSONBuilder_KeyValueF(builder, key, "%I64d", value);
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_JSONBuilder_F64Named(Dqn_JSONBuilder *builder, Dqn_Str8 key, double value, int decimal_places)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
|
|
|
if (!builder)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (decimal_places >= 16)
|
|
|
|
decimal_places = 16;
|
|
|
|
|
|
|
|
// NOTE: Generate the format string for the float, depending on how many
|
|
|
|
// decimals places it wants.
|
|
|
|
char float_fmt[16];
|
|
|
|
if (decimal_places > 0) {
|
|
|
|
// NOTE: Emit the format string "%.<decimal_places>f" i.e. %.1f
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_SNPRINTF(float_fmt, sizeof(float_fmt), "%%.%df", decimal_places);
|
2023-08-16 11:59:38 +00:00
|
|
|
} else {
|
|
|
|
// NOTE: Emit the format string "%f"
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_SNPRINTF(float_fmt, sizeof(float_fmt), "%%f");
|
2023-08-16 11:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
char fmt[32];
|
|
|
|
if (key.size)
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_SNPRINTF(fmt, sizeof(fmt), "\"%%.*s\": %s", float_fmt);
|
2023-08-16 11:59:38 +00:00
|
|
|
else
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_SNPRINTF(fmt, sizeof(fmt), "%s", float_fmt);
|
2023-08-16 11:59:38 +00:00
|
|
|
|
|
|
|
Dqn_JSONBuilder_KeyValueF(builder, key, fmt, value);
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_JSONBuilder_BoolNamed(Dqn_JSONBuilder *builder, Dqn_Str8 key, bool value)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Str8 value_string = value ? DQN_STR8("true") : DQN_STR8("false");
|
2023-08-16 11:59:38 +00:00
|
|
|
Dqn_JSONBuilder_KeyValueF(builder, key, "%.*s", value_string.size, value_string.data);
|
|
|
|
}
|
|
|
|
#endif // !defined(DQN_NO_JSON_BUILDER)
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: [$BITS] Dqn_Bit ///////////////////////////////////////////////////////////////////////////
|
|
|
|
DQN_API void Dqn_Bit_UnsetInplace(Dqn_usize *flags, Dqn_usize bitfield)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
|
|
|
*flags = (*flags & ~bitfield);
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_API void Dqn_Bit_SetInplace(Dqn_usize *flags, Dqn_usize bitfield)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
|
|
|
*flags = (*flags | bitfield);
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_API bool Dqn_Bit_IsSet(Dqn_usize bits, Dqn_usize bits_to_set)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
|
|
|
auto result = DQN_CAST(bool)((bits & bits_to_set) == bits_to_set);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_API bool Dqn_Bit_IsNotSet(Dqn_usize bits, Dqn_usize bits_to_check)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
|
|
|
auto result = !Dqn_Bit_IsSet(bits, bits_to_check);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: [$SAFE] Dqn_Safe //////////////////////////////////////////////////////////////////////////
|
2023-08-16 11:59:38 +00:00
|
|
|
DQN_API int64_t Dqn_Safe_AddI64(int64_t a, int64_t b)
|
|
|
|
{
|
|
|
|
int64_t result = DQN_CHECKF(a <= INT64_MAX - b, "a=%zd, b=%zd", a, b) ? (a + b) : INT64_MAX;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API int64_t Dqn_Safe_MulI64(int64_t a, int64_t b)
|
|
|
|
{
|
|
|
|
int64_t result = DQN_CHECKF(a <= INT64_MAX / b, "a=%zd, b=%zd", a, b) ? (a * b) : INT64_MAX;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint64_t Dqn_Safe_AddU64(uint64_t a, uint64_t b)
|
|
|
|
{
|
|
|
|
uint64_t result = DQN_CHECKF(a <= UINT64_MAX - b, "a=%zu, b=%zu", a, b) ? (a + b) : UINT64_MAX;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint64_t Dqn_Safe_SubU64(uint64_t a, uint64_t b)
|
|
|
|
{
|
|
|
|
uint64_t result = DQN_CHECKF(a >= b, "a=%zu, b=%zu", a, b) ? (a - b) : 0;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint64_t Dqn_Safe_MulU64(uint64_t a, uint64_t b)
|
|
|
|
{
|
|
|
|
uint64_t result = DQN_CHECKF(a <= UINT64_MAX / b, "a=%zu, b=%zu", a, b) ? (a * b) : UINT64_MAX;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint32_t Dqn_Safe_SubU32(uint32_t a, uint32_t b)
|
|
|
|
{
|
|
|
|
uint32_t result = DQN_CHECKF(a >= b, "a=%u, b=%u", a, b) ? (a - b) : 0;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-03-19 12:11:00 +00:00
|
|
|
// NOTE: Dqn_Safe_SaturateCastUSizeToI* ////////////////////////////////////////////////////////////
|
2023-08-16 11:59:38 +00:00
|
|
|
// INT*_MAX literals will be promoted to the type of uintmax_t as uintmax_t is
|
|
|
|
// the highest possible rank (unsigned > signed).
|
|
|
|
DQN_API int Dqn_Safe_SaturateCastUSizeToInt(Dqn_usize val)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
int result = DQN_CHECK(DQN_CAST(uintmax_t) val <= INT_MAX) ? DQN_CAST(int) val : INT_MAX;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API int8_t Dqn_Safe_SaturateCastUSizeToI8(Dqn_usize val)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
int8_t result = DQN_CHECK(DQN_CAST(uintmax_t) val <= INT8_MAX) ? DQN_CAST(int8_t) val : INT8_MAX;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API int16_t Dqn_Safe_SaturateCastUSizeToI16(Dqn_usize val)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
int16_t result = DQN_CHECK(DQN_CAST(uintmax_t) val <= INT16_MAX) ? DQN_CAST(int16_t) val : INT16_MAX;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API int32_t Dqn_Safe_SaturateCastUSizeToI32(Dqn_usize val)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
int32_t result = DQN_CHECK(DQN_CAST(uintmax_t) val <= INT32_MAX) ? DQN_CAST(int32_t) val : INT32_MAX;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API int64_t Dqn_Safe_SaturateCastUSizeToI64(Dqn_usize val)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
int64_t result = DQN_CHECK(DQN_CAST(uintmax_t) val <= INT64_MAX) ? DQN_CAST(int64_t) val : INT64_MAX;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-03-19 12:11:00 +00:00
|
|
|
// NOTE: Dqn_Safe_SaturateCastUSizeToU* ////////////////////////////////////////////////////////////
|
2023-08-16 11:59:38 +00:00
|
|
|
// Both operands are unsigned and the lowest rank operand will be promoted to
|
|
|
|
// match the highest rank operand.
|
|
|
|
DQN_API uint8_t Dqn_Safe_SaturateCastUSizeToU8(Dqn_usize val)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
uint8_t result = DQN_CHECK(val <= UINT8_MAX) ? DQN_CAST(uint8_t) val : UINT8_MAX;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint16_t Dqn_Safe_SaturateCastUSizeToU16(Dqn_usize val)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
uint16_t result = DQN_CHECK(val <= UINT16_MAX) ? DQN_CAST(uint16_t) val : UINT16_MAX;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint32_t Dqn_Safe_SaturateCastUSizeToU32(Dqn_usize val)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
uint32_t result = DQN_CHECK(val <= UINT32_MAX) ? DQN_CAST(uint32_t) val : UINT32_MAX;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint64_t Dqn_Safe_SaturateCastUSizeToU64(Dqn_usize val)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
uint64_t result = DQN_CHECK(DQN_CAST(uint64_t) val <= UINT64_MAX) ? DQN_CAST(uint64_t) val : UINT64_MAX;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-02-01 13:08:31 +00:00
|
|
|
// NOTE: Dqn_Safe_SaturateCastU64To* ///////////////////////////////////////////////////////////////
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_API int Dqn_Safe_SaturateCastU64ToInt(uint64_t val)
|
|
|
|
{
|
|
|
|
int result = DQN_CHECK(val <= INT_MAX) ? DQN_CAST(int)val : INT_MAX;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-02-01 13:08:31 +00:00
|
|
|
DQN_API int64_t Dqn_Safe_SaturateCastU64ToI64(uint64_t val)
|
|
|
|
{
|
|
|
|
int64_t result = DQN_CHECK(val <= INT64_MAX) ? DQN_CAST(int64_t)val : INT64_MAX;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-08-16 11:59:38 +00:00
|
|
|
// Both operands are unsigned and the lowest rank operand will be promoted to
|
|
|
|
// match the highest rank operand.
|
|
|
|
DQN_API unsigned int Dqn_Safe_SaturateCastU64ToUInt(uint64_t val)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
unsigned int result = DQN_CHECK(val <= UINT8_MAX) ? DQN_CAST(unsigned int) val : UINT_MAX;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint8_t Dqn_Safe_SaturateCastU64ToU8(uint64_t val)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
uint8_t result = DQN_CHECK(val <= UINT8_MAX) ? DQN_CAST(uint8_t) val : UINT8_MAX;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint16_t Dqn_Safe_SaturateCastU64ToU16(uint64_t val)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
uint16_t result = DQN_CHECK(val <= UINT16_MAX) ? DQN_CAST(uint16_t) val : UINT16_MAX;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint32_t Dqn_Safe_SaturateCastU64ToU32(uint64_t val)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
uint32_t result = DQN_CHECK(val <= UINT32_MAX) ? DQN_CAST(uint32_t) val : UINT32_MAX;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-03-19 12:11:00 +00:00
|
|
|
// NOTE: Dqn_Safe_SaturateCastISizeToI* ////////////////////////////////////////////////////////////
|
2023-08-16 11:59:38 +00:00
|
|
|
// Both operands are signed so the lowest rank operand will be promoted to
|
|
|
|
// match the highest rank operand.
|
|
|
|
DQN_API int Dqn_Safe_SaturateCastISizeToInt(Dqn_isize val)
|
|
|
|
{
|
|
|
|
DQN_ASSERT(val >= INT_MIN && val <= INT_MAX);
|
2024-01-31 12:49:23 +00:00
|
|
|
int result = DQN_CAST(int) DQN_CLAMP(val, INT_MIN, INT_MAX);
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API int8_t Dqn_Safe_SaturateCastISizeToI8(Dqn_isize val)
|
|
|
|
{
|
|
|
|
DQN_ASSERT(val >= INT8_MIN && val <= INT8_MAX);
|
2024-01-31 12:49:23 +00:00
|
|
|
int8_t result = DQN_CAST(int8_t) DQN_CLAMP(val, INT8_MIN, INT8_MAX);
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API int16_t Dqn_Safe_SaturateCastISizeToI16(Dqn_isize val)
|
|
|
|
{
|
|
|
|
DQN_ASSERT(val >= INT16_MIN && val <= INT16_MAX);
|
2024-01-31 12:49:23 +00:00
|
|
|
int16_t result = DQN_CAST(int16_t) DQN_CLAMP(val, INT16_MIN, INT16_MAX);
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API int32_t Dqn_Safe_SaturateCastISizeToI32(Dqn_isize val)
|
|
|
|
{
|
|
|
|
DQN_ASSERT(val >= INT32_MIN && val <= INT32_MAX);
|
2024-01-31 12:49:23 +00:00
|
|
|
int32_t result = DQN_CAST(int32_t) DQN_CLAMP(val, INT32_MIN, INT32_MAX);
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API int64_t Dqn_Safe_SaturateCastISizeToI64(Dqn_isize val)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_ASSERT(DQN_CAST(int64_t) val >= INT64_MIN && DQN_CAST(int64_t) val <= INT64_MAX);
|
|
|
|
int64_t result = DQN_CAST(int64_t) DQN_CLAMP(DQN_CAST(int64_t) val, INT64_MIN, INT64_MAX);
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-03-19 12:11:00 +00:00
|
|
|
// NOTE: Dqn_Safe_SaturateCastISizeToU* ////////////////////////////////////////////////////////////
|
2023-08-16 11:59:38 +00:00
|
|
|
// If the value is a negative integer, we clamp to 0. Otherwise, we know that
|
|
|
|
// the value is >=0, we can upcast safely to bounds check against the maximum
|
|
|
|
// allowed value.
|
|
|
|
DQN_API unsigned int Dqn_Safe_SaturateCastISizeToUInt(Dqn_isize val)
|
|
|
|
{
|
|
|
|
unsigned int result = 0;
|
2024-01-31 12:49:23 +00:00
|
|
|
if (DQN_CHECK(val >= DQN_CAST(Dqn_isize) 0)) {
|
|
|
|
if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT_MAX))
|
|
|
|
result = DQN_CAST(unsigned int) val;
|
2023-08-16 11:59:38 +00:00
|
|
|
else
|
|
|
|
result = UINT_MAX;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint8_t Dqn_Safe_SaturateCastISizeToU8(Dqn_isize val)
|
|
|
|
{
|
|
|
|
uint8_t result = 0;
|
2024-01-31 12:49:23 +00:00
|
|
|
if (DQN_CHECK(val >= DQN_CAST(Dqn_isize) 0)) {
|
|
|
|
if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT8_MAX))
|
|
|
|
result = DQN_CAST(uint8_t) val;
|
2023-08-16 11:59:38 +00:00
|
|
|
else
|
|
|
|
result = UINT8_MAX;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint16_t Dqn_Safe_SaturateCastISizeToU16(Dqn_isize val)
|
|
|
|
{
|
|
|
|
uint16_t result = 0;
|
2024-01-31 12:49:23 +00:00
|
|
|
if (DQN_CHECK(val >= DQN_CAST(Dqn_isize) 0)) {
|
|
|
|
if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT16_MAX))
|
|
|
|
result = DQN_CAST(uint16_t) val;
|
2023-08-16 11:59:38 +00:00
|
|
|
else
|
|
|
|
result = UINT16_MAX;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint32_t Dqn_Safe_SaturateCastISizeToU32(Dqn_isize val)
|
|
|
|
{
|
|
|
|
uint32_t result = 0;
|
2024-01-31 12:49:23 +00:00
|
|
|
if (DQN_CHECK(val >= DQN_CAST(Dqn_isize) 0)) {
|
|
|
|
if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT32_MAX))
|
|
|
|
result = DQN_CAST(uint32_t) val;
|
2023-08-16 11:59:38 +00:00
|
|
|
else
|
|
|
|
result = UINT32_MAX;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint64_t Dqn_Safe_SaturateCastISizeToU64(Dqn_isize val)
|
|
|
|
{
|
|
|
|
uint64_t result = 0;
|
2024-01-31 12:49:23 +00:00
|
|
|
if (DQN_CHECK(val >= DQN_CAST(Dqn_isize) 0)) {
|
|
|
|
if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT64_MAX))
|
|
|
|
result = DQN_CAST(uint64_t) val;
|
2023-08-16 11:59:38 +00:00
|
|
|
else
|
|
|
|
result = UINT64_MAX;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-03-19 12:11:00 +00:00
|
|
|
// NOTE: Dqn_Safe_SaturateCastI64To* ///////////////////////////////////////////////////////////////
|
2023-08-16 11:59:38 +00:00
|
|
|
// Both operands are signed so the lowest rank operand will be promoted to
|
|
|
|
// match the highest rank operand.
|
|
|
|
DQN_API Dqn_isize Dqn_Safe_SaturateCastI64ToISize(int64_t val)
|
|
|
|
{
|
|
|
|
DQN_CHECK(val >= DQN_ISIZE_MIN && val <= DQN_ISIZE_MAX);
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_isize result = DQN_CAST(int64_t) DQN_CLAMP(val, DQN_ISIZE_MIN, DQN_ISIZE_MAX);
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API int8_t Dqn_Safe_SaturateCastI64ToI8(int64_t val)
|
|
|
|
{
|
|
|
|
DQN_CHECK(val >= INT8_MIN && val <= INT8_MAX);
|
2024-01-31 12:49:23 +00:00
|
|
|
int8_t result = DQN_CAST(int8_t) DQN_CLAMP(val, INT8_MIN, INT8_MAX);
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API int16_t Dqn_Safe_SaturateCastI64ToI16(int64_t val)
|
|
|
|
{
|
|
|
|
DQN_CHECK(val >= INT16_MIN && val <= INT16_MAX);
|
2024-01-31 12:49:23 +00:00
|
|
|
int16_t result = DQN_CAST(int16_t) DQN_CLAMP(val, INT16_MIN, INT16_MAX);
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API int32_t Dqn_Safe_SaturateCastI64ToI32(int64_t val)
|
|
|
|
{
|
|
|
|
DQN_CHECK(val >= INT32_MIN && val <= INT32_MAX);
|
2024-01-31 12:49:23 +00:00
|
|
|
int32_t result = DQN_CAST(int32_t) DQN_CLAMP(val, INT32_MIN, INT32_MAX);
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-03-19 12:11:00 +00:00
|
|
|
DQN_API unsigned int Dqn_Safe_SaturateCastI64ToUInt(int64_t val)
|
|
|
|
{
|
|
|
|
unsigned int result = 0;
|
|
|
|
if (DQN_CHECK(val >= DQN_CAST(int64_t) 0)) {
|
|
|
|
if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT_MAX))
|
|
|
|
result = DQN_CAST(unsigned int) val;
|
|
|
|
else
|
|
|
|
result = UINT_MAX;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API Dqn_isize Dqn_Safe_SaturateCastI64ToUSize(int64_t val)
|
|
|
|
{
|
|
|
|
Dqn_usize result = 0;
|
|
|
|
if (DQN_CHECK(val >= DQN_CAST(int64_t) 0)) {
|
|
|
|
if (DQN_CHECK(DQN_CAST(uintmax_t) val <= DQN_USIZE_MAX))
|
|
|
|
result = DQN_CAST(Dqn_usize) val;
|
|
|
|
else
|
|
|
|
result = DQN_USIZE_MAX;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint8_t Dqn_Safe_SaturateCastI64ToU8(int64_t val)
|
|
|
|
{
|
|
|
|
uint8_t result = 0;
|
|
|
|
if (DQN_CHECK(val >= DQN_CAST(int64_t) 0)) {
|
|
|
|
if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT8_MAX))
|
|
|
|
result = DQN_CAST(uint8_t) val;
|
|
|
|
else
|
|
|
|
result = UINT8_MAX;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint16_t Dqn_Safe_SaturateCastI64ToU16(int64_t val)
|
|
|
|
{
|
|
|
|
uint16_t result = 0;
|
|
|
|
if (DQN_CHECK(val >= DQN_CAST(int64_t) 0)) {
|
|
|
|
if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT16_MAX))
|
|
|
|
result = DQN_CAST(uint16_t) val;
|
|
|
|
else
|
|
|
|
result = UINT16_MAX;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint32_t Dqn_Safe_SaturateCastI64ToU32(int64_t val)
|
|
|
|
{
|
|
|
|
uint32_t result = 0;
|
|
|
|
if (DQN_CHECK(val >= DQN_CAST(int64_t) 0)) {
|
|
|
|
if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT32_MAX))
|
|
|
|
result = DQN_CAST(uint32_t) val;
|
|
|
|
else
|
|
|
|
result = UINT32_MAX;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint64_t Dqn_Safe_SaturateCastI64ToU64(int64_t val)
|
|
|
|
{
|
|
|
|
uint64_t result = 0;
|
|
|
|
if (DQN_CHECK(val >= DQN_CAST(int64_t) 0)) {
|
|
|
|
if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT64_MAX))
|
|
|
|
result = DQN_CAST(uint64_t) val;
|
|
|
|
else
|
|
|
|
result = UINT64_MAX;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: Dqn_Safe_SaturateCastIntTo* ///////////////////////////////////////////////////////////////
|
2023-08-16 11:59:38 +00:00
|
|
|
DQN_API int8_t Dqn_Safe_SaturateCastIntToI8(int val)
|
|
|
|
{
|
|
|
|
DQN_CHECK(val >= INT8_MIN && val <= INT8_MAX);
|
2024-01-31 12:49:23 +00:00
|
|
|
int8_t result = DQN_CAST(int8_t) DQN_CLAMP(val, INT8_MIN, INT8_MAX);
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API int16_t Dqn_Safe_SaturateCastIntToI16(int val)
|
|
|
|
{
|
|
|
|
DQN_CHECK(val >= INT16_MIN && val <= INT16_MAX);
|
2024-01-31 12:49:23 +00:00
|
|
|
int16_t result = DQN_CAST(int16_t) DQN_CLAMP(val, INT16_MIN, INT16_MAX);
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint8_t Dqn_Safe_SaturateCastIntToU8(int val)
|
|
|
|
{
|
|
|
|
uint8_t result = 0;
|
2024-01-31 12:49:23 +00:00
|
|
|
if (DQN_CHECK(val >= DQN_CAST(Dqn_isize) 0)) {
|
|
|
|
if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT8_MAX))
|
|
|
|
result = DQN_CAST(uint8_t) val;
|
2023-08-16 11:59:38 +00:00
|
|
|
else
|
|
|
|
result = UINT8_MAX;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint16_t Dqn_Safe_SaturateCastIntToU16(int val)
|
|
|
|
{
|
|
|
|
uint16_t result = 0;
|
2024-01-31 12:49:23 +00:00
|
|
|
if (DQN_CHECK(val >= DQN_CAST(Dqn_isize) 0)) {
|
|
|
|
if (DQN_CHECK(DQN_CAST(uintmax_t) val <= UINT16_MAX))
|
|
|
|
result = DQN_CAST(uint16_t) val;
|
2023-08-16 11:59:38 +00:00
|
|
|
else
|
|
|
|
result = UINT16_MAX;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint32_t Dqn_Safe_SaturateCastIntToU32(int val)
|
|
|
|
{
|
|
|
|
static_assert(sizeof(val) <= sizeof(uint32_t), "Sanity check to allow simplifying of casting");
|
|
|
|
uint32_t result = 0;
|
|
|
|
if (DQN_CHECK(val >= 0))
|
2024-01-31 12:49:23 +00:00
|
|
|
result = DQN_CAST(uint32_t) val;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API uint64_t Dqn_Safe_SaturateCastIntToU64(int val)
|
|
|
|
{
|
|
|
|
static_assert(sizeof(val) <= sizeof(uint64_t), "Sanity check to allow simplifying of casting");
|
|
|
|
uint64_t result = 0;
|
|
|
|
if (DQN_CHECK(val >= 0))
|
2024-01-31 12:49:23 +00:00
|
|
|
result = DQN_CAST(uint64_t) val;
|
2023-08-16 11:59:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: [$MISC] Misc //////////////////////////////////////////////////////////////////////////////
|
|
|
|
DQN_API int Dqn_FmtBuffer3DotTruncate(char *buffer, int size, DQN_FMT_ATTRIB char const *fmt, ...)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2024-01-31 12:49:23 +00:00
|
|
|
int size_required = DQN_VSNPRINTF(buffer, size, fmt, args);
|
2023-08-16 11:59:38 +00:00
|
|
|
int result = DQN_MAX(DQN_MIN(size_required, size - 1), 0);
|
|
|
|
if (result == size - 1) {
|
|
|
|
buffer[size - 2] = '.';
|
|
|
|
buffer[size - 3] = '.';
|
|
|
|
}
|
|
|
|
va_end(args);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API Dqn_U64Str8 Dqn_U64ToStr8(uint64_t val, char separator)
|
2023-08-16 11:59:38 +00:00
|
|
|
{
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_U64Str8 result = {};
|
2023-08-16 11:59:38 +00:00
|
|
|
if (val == 0) {
|
|
|
|
result.data[result.size++] = '0';
|
|
|
|
} else {
|
|
|
|
// NOTE: The number is written in reverse because we form the string by
|
|
|
|
// dividing by 10, so we write it in, then reverse it out after all is
|
|
|
|
// done.
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_U64Str8 temp = {};
|
2023-08-25 13:42:09 +00:00
|
|
|
for (Dqn_usize digit_count = 0; val > 0; digit_count++) {
|
|
|
|
if (separator && (digit_count != 0) && (digit_count % 3 == 0))
|
2023-08-16 11:59:38 +00:00
|
|
|
temp.data[temp.size++] = separator;
|
|
|
|
|
|
|
|
auto digit = DQN_CAST(char)(val % 10);
|
|
|
|
temp.data[temp.size++] = '0' + digit;
|
|
|
|
val /= 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: Reverse the string
|
2023-08-25 13:42:09 +00:00
|
|
|
DQN_MSVC_WARNING_PUSH
|
|
|
|
DQN_MSVC_WARNING_DISABLE(6293) // Ill-defined for-loop
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_MSVC_WARNING_DISABLE(
|
|
|
|
6385) // Reading invalid data from 'temp.data' NOTE(doyle): Unsigned overflow is valid for loop termination
|
2023-08-25 13:42:09 +00:00
|
|
|
for (Dqn_usize temp_index = temp.size - 1; temp_index < temp.size; temp_index--) {
|
2024-01-31 12:49:23 +00:00
|
|
|
char ch = temp.data[temp_index];
|
2023-08-16 11:59:38 +00:00
|
|
|
result.data[result.size++] = ch;
|
|
|
|
}
|
2023-08-25 13:42:09 +00:00
|
|
|
DQN_MSVC_WARNING_POP
|
2023-08-16 11:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_API Dqn_U64ByteSize Dqn_U64ToByteSize(uint64_t bytes, Dqn_U64ByteSizeType desired_type)
|
|
|
|
{
|
|
|
|
Dqn_U64ByteSize result = {};
|
|
|
|
result.bytes = DQN_CAST(Dqn_f64)bytes;
|
|
|
|
if (!DQN_CHECK(desired_type != Dqn_U64ByteSizeType_Count)) {
|
|
|
|
result.suffix = Dqn_U64ByteSizeTypeString(result.type);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (desired_type == Dqn_U64ByteSizeType_Auto) {
|
|
|
|
for (; result.type < Dqn_U64ByteSizeType_Count && result.bytes >= 1024.0; result.type = DQN_CAST(Dqn_U64ByteSizeType)(DQN_CAST(Dqn_usize)result.type + 1))
|
|
|
|
result.bytes /= 1024.0;
|
|
|
|
} else {
|
|
|
|
for (; result.type < desired_type; result.type = DQN_CAST(Dqn_U64ByteSizeType)(DQN_CAST(Dqn_usize)result.type + 1))
|
|
|
|
result.bytes /= 1024.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
result.suffix = Dqn_U64ByteSizeTypeString(result.type);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API Dqn_Str8 Dqn_U64ToByteSizeStr8(Dqn_Arena *arena, uint64_t bytes, Dqn_U64ByteSizeType desired_type)
|
|
|
|
{
|
|
|
|
Dqn_U64ByteSize byte_size = Dqn_U64ToByteSize(bytes, desired_type);
|
|
|
|
Dqn_Str8 result = Dqn_Str8_InitF(arena, "%.2f%.*s", byte_size.bytes, DQN_STR_FMT(byte_size.suffix));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API Dqn_Str8 Dqn_U64ByteSizeTypeString(Dqn_U64ByteSizeType type)
|
|
|
|
{
|
|
|
|
Dqn_Str8 result = DQN_STR8("");
|
|
|
|
switch (type) {
|
|
|
|
case Dqn_U64ByteSizeType_B: result = DQN_STR8("B"); break;
|
|
|
|
case Dqn_U64ByteSizeType_KiB: result = DQN_STR8("KiB"); break;
|
|
|
|
case Dqn_U64ByteSizeType_MiB: result = DQN_STR8("MiB"); break;
|
|
|
|
case Dqn_U64ByteSizeType_GiB: result = DQN_STR8("GiB"); break;
|
|
|
|
case Dqn_U64ByteSizeType_TiB: result = DQN_STR8("TiB"); break;
|
|
|
|
case Dqn_U64ByteSizeType_Count: result = DQN_STR8(""); break;
|
|
|
|
case Dqn_U64ByteSizeType_Auto: result = DQN_STR8(""); break;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-08-01 03:34:36 +00:00
|
|
|
DQN_API Dqn_Str8 Dqn_U64ToAge(Dqn_Arena *arena, uint64_t age_s, Dqn_U64AgeUnit unit)
|
2024-01-31 12:49:23 +00:00
|
|
|
{
|
|
|
|
Dqn_Str8 result = {};
|
|
|
|
if (!arena)
|
|
|
|
return result;
|
|
|
|
|
2024-08-01 03:34:36 +00:00
|
|
|
Dqn_TLSTMem tmem = Dqn_TLS_TMem(arena);
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_Str8Builder builder = {};
|
|
|
|
builder.arena = arena;
|
|
|
|
uint64_t remainder = age_s;
|
|
|
|
|
2024-08-01 03:34:36 +00:00
|
|
|
if (unit & Dqn_U64AgeUnit_Year) {
|
|
|
|
Dqn_usize value = remainder / DQN_YEARS_TO_S(1);
|
|
|
|
remainder -= DQN_YEARS_TO_S(value);
|
|
|
|
if (value)
|
|
|
|
Dqn_Str8Builder_AddF(&builder, "%s%I64uyr", builder.string_size ? " " : "", value);
|
2024-01-31 12:49:23 +00:00
|
|
|
}
|
|
|
|
|
2024-08-01 03:34:36 +00:00
|
|
|
if (unit & Dqn_U64AgeUnit_Week) {
|
|
|
|
Dqn_usize value = remainder / DQN_WEEKS_TO_S(1);
|
|
|
|
remainder -= DQN_WEEKS_TO_S(value);
|
|
|
|
if (value)
|
|
|
|
Dqn_Str8Builder_AddF(&builder, "%s%I64uw", builder.string_size ? " " : "", value);
|
2024-01-31 12:49:23 +00:00
|
|
|
}
|
|
|
|
|
2024-08-01 03:34:36 +00:00
|
|
|
if (unit & Dqn_U64AgeUnit_Day) {
|
|
|
|
Dqn_usize value = remainder / DQN_DAYS_TO_S(1);
|
|
|
|
remainder -= DQN_DAYS_TO_S(value);
|
|
|
|
if (value)
|
|
|
|
Dqn_Str8Builder_AddF(&builder, "%s%I64ud", builder.string_size ? " " : "", value);
|
2024-01-31 12:49:23 +00:00
|
|
|
}
|
|
|
|
|
2024-08-01 03:34:36 +00:00
|
|
|
if (unit & Dqn_U64AgeUnit_Hr) {
|
|
|
|
Dqn_usize value = remainder / DQN_HOURS_TO_S(1);
|
|
|
|
remainder -= DQN_HOURS_TO_S(value);
|
|
|
|
if (value)
|
|
|
|
Dqn_Str8Builder_AddF(&builder, "%s%I64uh", builder.string_size ? " " : "", value);
|
2024-01-31 12:49:23 +00:00
|
|
|
}
|
|
|
|
|
2024-08-01 03:34:36 +00:00
|
|
|
if (unit & Dqn_U64AgeUnit_Min) {
|
|
|
|
Dqn_usize value = remainder / DQN_MINS_TO_S(1);
|
|
|
|
remainder -= DQN_MINS_TO_S(value);
|
|
|
|
if (value)
|
|
|
|
Dqn_Str8Builder_AddF(&builder, "%s%I64um", builder.string_size ? " " : "", value);
|
2024-01-31 12:49:23 +00:00
|
|
|
}
|
|
|
|
|
2024-08-01 03:34:36 +00:00
|
|
|
if (unit & Dqn_U64AgeUnit_Sec) {
|
|
|
|
Dqn_usize value = remainder;
|
|
|
|
Dqn_Str8Builder_AddF(&builder, "%s%I64us", builder.string_size ? " " : "", value);
|
2024-01-31 12:49:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
result = Dqn_Str8Builder_Build(&builder, arena);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-04-18 12:59:11 +00:00
|
|
|
DQN_API uint64_t Dqn_HexToU64(Dqn_Str8 hex)
|
|
|
|
{
|
|
|
|
Dqn_Str8 real_hex = Dqn_Str8_TrimPrefix(Dqn_Str8_TrimPrefix(hex, DQN_STR8("0x")), DQN_STR8("0X"));
|
|
|
|
Dqn_usize max_hex_size = sizeof(uint64_t) * 2 /*hex chars per byte*/;
|
|
|
|
DQN_ASSERT(real_hex.size <= max_hex_size);
|
|
|
|
|
|
|
|
Dqn_usize size = DQN_MIN(max_hex_size, real_hex.size);
|
|
|
|
uint64_t result = 0;
|
|
|
|
for (Dqn_usize index = 0; index < size; index++) {
|
|
|
|
char ch = real_hex.data[index];
|
|
|
|
Dqn_CharHexToU8 val = Dqn_Char_HexToU8(ch);
|
|
|
|
if (!val.success)
|
|
|
|
break;
|
|
|
|
result = (result << 4) | val.value;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API Dqn_Str8 Dqn_U64ToHex(Dqn_Arena *arena, uint64_t number, uint32_t flags)
|
|
|
|
{
|
|
|
|
Dqn_Str8 prefix = {};
|
2024-08-01 03:34:36 +00:00
|
|
|
if ((flags & Dqn_HexU64Str8Flags_0xPrefix))
|
2024-04-18 12:59:11 +00:00
|
|
|
prefix = DQN_STR8("0x");
|
|
|
|
|
2024-08-01 03:34:36 +00:00
|
|
|
char const *fmt = (flags & Dqn_HexU64Str8Flags_UppercaseHex) ? "%I64X" : "%I64x";
|
2024-04-18 12:59:11 +00:00
|
|
|
Dqn_usize required_size = Dqn_CStr8_FSize(fmt, number) + prefix.size;
|
|
|
|
Dqn_Str8 result = Dqn_Str8_Alloc(arena, required_size, Dqn_ZeroMem_No);
|
|
|
|
|
|
|
|
if (Dqn_Str8_HasData(result)) {
|
|
|
|
DQN_MEMCPY(result.data, prefix.data, prefix.size);
|
|
|
|
int space = DQN_CAST(int) DQN_MAX((result.size - prefix.size) + 1, 0); /*null-terminator*/
|
|
|
|
DQN_SNPRINTF(result.data + prefix.size, space, fmt, number);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API Dqn_U64HexStr8 Dqn_U64ToHexStr8(uint64_t number, uint32_t flags)
|
|
|
|
{
|
|
|
|
Dqn_Str8 prefix = {};
|
2024-08-01 03:34:36 +00:00
|
|
|
if (flags & Dqn_HexU64Str8Flags_0xPrefix)
|
2024-04-18 12:59:11 +00:00
|
|
|
prefix = DQN_STR8("0x");
|
|
|
|
|
|
|
|
Dqn_U64HexStr8 result = {};
|
|
|
|
DQN_MEMCPY(result.data, prefix.data, prefix.size);
|
|
|
|
result.size += DQN_CAST(int8_t) prefix.size;
|
|
|
|
|
2024-08-01 03:34:36 +00:00
|
|
|
char const *fmt = (flags & Dqn_HexU64Str8Flags_UppercaseHex) ? "%I64X" : "%I64x";
|
2024-04-18 12:59:11 +00:00
|
|
|
int size = DQN_SNPRINTF(result.data + result.size, DQN_ARRAY_UCOUNT(result.data) - result.size, fmt, number);
|
|
|
|
result.size += DQN_CAST(uint8_t) size;
|
|
|
|
DQN_ASSERT(result.size < DQN_ARRAY_UCOUNT(result.data));
|
|
|
|
|
|
|
|
// NOTE: snprintf returns the required size of the format string
|
|
|
|
// irrespective of if there's space or not, but, always null terminates so
|
|
|
|
// the last byte is wasted.
|
|
|
|
result.size = DQN_MIN(result.size, DQN_ARRAY_UCOUNT(result.data) - 1);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API bool Dqn_BytesToHexPtr(void const *src, Dqn_usize src_size, char *dest, Dqn_usize dest_size)
|
|
|
|
{
|
|
|
|
if (!src || !dest)
|
|
|
|
return false;
|
|