diff --git a/dqn.h b/dqn.h index b367873..57fcaab 100644 --- a/dqn.h +++ b/dqn.h @@ -1,3 +1,49 @@ +// NOTE: [$CFGM] Config macros ===================================================================== +// +// #define DQN_IMPLEMENTATION +// Define this in one and only one C++ file to enable the implementation +// code of the header file +// +// #define DQN_NO_ASSERT +// Turn all assertion macros to no-ops +// +// #define DQN_NO_CHECK_BREAK +// Disable debug break when a check macro's expression fails. Instead only +// the error will be logged. +// +// #define DQN_NO_WIN32_MIN_HEADER +// Define this to stop this library from defining a minimal subset of Win32 +// prototypes and definitions in this file. Useful for stopping redefinition +// of symbols if another library includes "Windows.h" +// +// #define DQN_STATIC_API +// Apply static to all function definitions and disable external linkage to +// other translation units. +// +// #define DQN_STB_SPRINTF_HEADER_ONLY +// Define this to stop this library from defining +// STB_SPRINTF_IMPLEMENTATION. Useful if another library uses and includes +// "stb_sprintf.h" +// +// #define DQN_MEMSET_BYTE 0 +// Change the byte that DQN_MEMSET will clear memory with. By default this +// is set to 0. Some of this library API accepts are clear memory parameter +// to scrub memory after certain operations. +// +// #define DQN_LEAK_TRACING +// When defined to some allocating calls in the library will automatically +// get passed in the file name, function name, line number and an optional +// leak_msg. + +#if defined(DQN_LEAK_TRACING) +#error Leak tracing not supported because we enter an infinite leak tracing loop tracing our own allocations made to tracks leaks in the internal leak table. +#endif + +// +// #define DQN_DEBUG_THREAD_CONTEXT +// Define this macro to record allocation stats for arenas used in the +// thread context. The thread context arena stats can be printed by using +// Dqn_Library_DumpThreadContextArenaStat. #if !defined(DQN_H) #define DQN_H #include // va_list diff --git a/dqn_core.h b/dqn_core.h index d089969..e95cc6d 100644 --- a/dqn_core.h +++ b/dqn_core.h @@ -1,7 +1,6 @@ // NOTE: Table Of Contents ========================================================================= // Index | Disable #define | Description // ================================================================================================= -// [$CFGM] Config macros | | Compile time customisation of library // [$CMAC] Compiler macros | | Macros for the compiler // [$MACR] Macros | | Define macros used in the library // [$TYPE] Typedefs | | Typedefs used in the library @@ -11,52 +10,6 @@ // [$CALL] Dqn_CallSite | | Source code location/tracing // ===================+=================+=========================================================== -// NOTE: [$CFGM] Config macros ===================================================================== -// #define DQN_IMPLEMENTATION -// Define this in one and only one C++ file to enable the implementation -// code of the header file -// -// #define DQN_NO_ASSERT -// Turn all assertion macros to no-ops -// -// #define DQN_NO_CHECK_BREAK -// Disable debug break when a check macro's expression fails. Instead only -// the error will be logged. -// -// #define DQN_NO_WIN32_MINIMAL_HEADER -// Define this to stop this library from defining a minimal subset of Win32 -// prototypes and definitions in this file. Useful for stopping redefinition -// of symbols if another library includes "Windows.h" -// -// #define DQN_STATIC_API -// Apply static to all function definitions and disable external linkage to -// other translation units. -// -// #define DQN_STB_SPRINTF_HEADER_ONLY -// Define this to stop this library from defining -// STB_SPRINTF_IMPLEMENTATION. Useful if another library uses and includes -// "stb_sprintf.h" -// -// #define DQN_MEMSET_BYTE 0 -// Change the byte that DQN_MEMSET will clear memory with. By default this -// is set to 0. Some of this library API accepts are clear memory parameter -// to scrub memory after certain operations. -// -// #define DQN_LEAK_TRACING -// When defined to some allocating calls in the library will automatically -// get passed in the file name, function name, line number and an optional -// leak_msg. - -#if defined(DQN_LEAK_TRACING) -#error Leak tracing not supported because we enter an infinite leak tracing loop tracing our own allocations made to tracks leaks in the internal leak table. -#endif - -// -// #define DQN_DEBUG_THREAD_CONTEXT -// Define this macro to record allocation stats for arenas used in the -// thread context. The thread context arena stats can be printed by using -// Dqn_Library_DumpThreadContextArenaStat. -// // NOTE: [$CMAC] Compiler macros =================================================================== // NOTE: Warning! Order is important here, clang-cl on Windows defines _MSC_VER #if defined(_MSC_VER) @@ -191,7 +144,7 @@ #define DQN_GIGABYTES(val) (1024ULL * DQN_MEGABYTES(val)) // NOTE: Time Macros =============================================================================== -#define DQN_SECONDS_TO_MS(val) ((val) * 1000.0f) +#define DQN_SECONDS_TO_MS(val) ((val) * 1000) #define DQN_MINS_TO_S(val) ((val) * 60ULL) #define DQN_HOURS_TO_S(val) (DQN_MINS_TO_S(val) * 60ULL) #define DQN_DAYS_TO_S(val) (DQN_HOURS_TO_S(val) * 24ULL) @@ -237,7 +190,27 @@ } #endif +#define DQN_INVALID_CODE_PATHF(fmt, ...) DQN_ASSERTF(0, fmt, ##__VA_ARGS__) +#define DQN_INVALID_CODE_PATH DQN_INVALID_CODE_PATHF("Invalid code path triggered") + +// NOTE: Check macro =============================================================================== +// Assert the expression given in debug, whilst in release- assertion is +// removed and the expression is evaluated and returned. +// +// This function provides dual logic which allows handling of the condition +// gracefully in release mode, but asserting in debug mode. This is an internal +// function, prefer the @see DQN_CHECK macros. +// +// Returns true if the expression evaluated to true, false otherwise. +// +#if 0 + bool flag = true; + if (!DQN_CHECKF(flag, "Flag was false!")) { + // This branch will execute! + } +#endif #define DQN_CHECK(expr) DQN_CHECKF(expr, "") + #if defined(DQN_NO_CHECK_BREAK) #define DQN_CHECKF(expr, fmt, ...) \ ((expr) ? true : (Dqn_Log_TypeFCallSite(Dqn_LogType_Warning, DQN_CALL_SITE, fmt, ## __VA_ARGS__), false)) @@ -246,30 +219,13 @@ ((expr) ? true : (Dqn_Log_TypeFCallSite(Dqn_LogType_Error, DQN_CALL_SITE, fmt, ## __VA_ARGS__), DQN_DEBUG_BREAK, false)) #endif -#if 0 -DQN_API bool DQN_CHECKF_(bool assertion_expr, Dqn_CallSite call_site, char const *fmt, ...) -{ - bool result = assertion_expr; - if (!result) { - va_list args; - va_start(args, fmt); - Dqn_Log_TypeFVCallSite(Dqn_LogType_Error, call_site, fmt, args); - va_end(args); - DQN_DEBUG_BREAK; - } - return result; -} -#endif - +// NOTE: Zero initialisation macro ================================================================= #if defined(__cplusplus) #define DQN_ZERO_INIT {} #else #define DQN_ZERO_INIT {0} #endif -#define DQN_INVALID_CODE_PATHF(fmt, ...) DQN_ASSERTF(0, fmt, ##__VA_ARGS__) -#define DQN_INVALID_CODE_PATH DQN_INVALID_CODE_PATHF("Invalid code path triggered") - // NOTE: Defer Macro =============================================================================== #if 0 #include diff --git a/dqn_misc.h b/dqn_misc.h index e158c68..49ee967 100644 --- a/dqn_misc.h +++ b/dqn_misc.h @@ -78,264 +78,157 @@ DQN_API void Dqn_Library_LeakTraceMarkFree (Dqn_CallSite call_site, void // NOTE: [$BITS] Dqn_Bit =========================================================================== DQN_API void Dqn_Bit_UnsetInplace(uint32_t *flags, uint32_t bitfield); -DQN_API void Dqn_Bit_SetInplace(uint32_t *flags, uint32_t bitfield); -DQN_API bool Dqn_Bit_IsSet(uint32_t bits, uint32_t bits_to_set); -DQN_API bool Dqn_Bit_IsNotSet(uint32_t bits, uint32_t bits_to_check); +DQN_API void Dqn_Bit_SetInplace (uint32_t *flags, uint32_t bitfield); +DQN_API bool Dqn_Bit_IsSet (uint32_t bits, uint32_t bits_to_set); +DQN_API bool Dqn_Bit_IsNotSet (uint32_t bits, uint32_t bits_to_check); // NOTE: [$SAFE] Dqn_Safe ========================================================================== -// Assert the expression given in debug, whilst in release- assertion is -// removed and the expression is evaluated and returned. +// @proc Dqn_Safe_AddI64, Dqn_Safe_MulI64 +// @desc Add/multiply 2 I64's together, safe asserting that the operation does +// not overflow. +// @return The result of operation, INT64_MAX if it overflowed. + +// @proc Dqn_Safe_AddU64, Dqn_Safe_MulU64 +// @desc Add/multiply 2 U64's together, safe asserting that the operation does +// not overflow. +// @return The result of operation, UINT64_MAX if it overflowed. + +// @proc Dqn_Safe_SubU64, Dqn_Safe_SubU32 +// @desc Subtract 2xU64 or 2xU32's together, safe asserting that the operation +// does not overflow. +// @return The result of operation, 0 if it overflowed. + +// @proc Dqn_Safe_SaturateCastUSizeToInt, +// Dqn_Safe_SaturateCastUSizeToI8, +// Dqn_Safe_SaturateCastUSizeToI16, +// Dqn_Safe_SaturateCastUSizeToI32, +// Dqn_Safe_SaturateCastUSizeToI64 // -// This function provides dual logic which allows handling of the condition -// gracefully in release mode, but asserting in debug mode. This is an internal -// function, prefer the @see DQN_CHECK macros. +// Dqn_Safe_SaturateCastU64ToUInt, +// Dqn_Safe_SaturateCastU64ToU8, +// Dqn_Safe_SaturateCastU64ToU16, +// Dqn_Safe_SaturateCastU64ToU32, // -// @param assertion_expr[in] Expressin to assert on -// @param fmt[in] Format string for providing a message on assertion -// @return True if the expression evaluated to true, false otherwise. -DQN_API bool DQN_CHECKF_(bool assertion_expr, Dqn_CallSite call_site, char const *fmt, ...); +// Dqn_Safe_SaturateCastUSizeToU8, +// Dqn_Safe_SaturateCastUSizeToU16, +// Dqn_Safe_SaturateCastUSizeToU32, +// Dqn_Safe_SaturateCastUSizeToU64 +// +// Dqn_Safe_SaturateCastISizeToInt, +// Dqn_Safe_SaturateCastISizeToI8, +// Dqn_Safe_SaturateCastISizeToI16, +// Dqn_Safe_SaturateCastISizeToI32, +// Dqn_Safe_SaturateCastISizeToI64, +// +// int Dqn_Safe_SaturateCastISizeToUInt, +// Dqn_Safe_SaturateCastISizeToU8, +// Dqn_Safe_SaturateCastISizeToU16, +// Dqn_Safe_SaturateCastISizeToU32, +// Dqn_Safe_SaturateCastISizeToU64, +// +// Dqn_Safe_SaturateCastI64ToISize, +// Dqn_Safe_SaturateCastI64ToI8, +// Dqn_Safe_SaturateCastI64ToI16, +// Dqn_Safe_SaturateCastI64ToI32, +// +// Dqn_Safe_SaturateCastIntToI8, +// Dqn_Safe_SaturateCastIntToU8, +// Dqn_Safe_SaturateCastIntToU16, +// Dqn_Safe_SaturateCastIntToU32, +// Dqn_Safe_SaturateCastIntToU64, +// +// @desc Truncate the lhs operand to the right clamping the result to the max +// value of the desired data type. Safe asserts if clamping occurs. +// +// The following sentinel values are returned when saturated, +// USize -> Int: INT_MAX +// USize -> I8: INT8_MAX +// USize -> I16: INT16_MAX +// USize -> I32: INT32_MAX +// USize -> I64: INT64_MAX +// +// U64 -> UInt: UINT_MAX +// U64 -> U8: UINT8_MAX +// U64 -> U16: UINT16_MAX +// U64 -> U32: UINT32_MAX +// +// USize -> U8: UINT8_MAX +// USize -> U16: UINT16_MAX +// USize -> U32: UINT32_MAX +// USize -> U64: UINT64_MAX +// +// ISize -> Int: INT_MIN or INT_MAX +// ISize -> I8: INT8_MIN or INT8_MAX +// ISize -> I16: INT16_MIN or INT16_MAX +// ISize -> I32: INT32_MIN or INT32_MAX +// ISize -> I64: INT64_MIN or INT64_MAX +// +// ISize -> UInt: 0 or UINT_MAX +// ISize -> U8: 0 or UINT8_MAX +// ISize -> U16: 0 or UINT16_MAX +// ISize -> U32: 0 or UINT32_MAX +// ISize -> U64: 0 or UINT64_MAX +// +// I64 -> ISize: DQN_ISIZE_MIN or DQN_ISIZE_MAX +// I64 -> I8: INT8_MIN or INT8_MAX +// I64 -> I16: INT16_MIN or INT16_MAX +// I64 -> I32: INT32_MIN or INT32_MAX +// +// Int -> I8: INT8_MIN or INT8_MAX +// Int -> I16: INT16_MIN or INT16_MAX +// Int -> U8: 0 or UINT8_MAX +// Int -> U16: 0 or UINT16_MAX +// Int -> U32: 0 or UINT32_MAX +// Int -> U64: 0 or UINT64_MAX -// NOTE: Dqn_Safe Arithmetic -// ----------------------------------------------------------------------------- -/// Add 2 I64's together, safe asserting that the operation does not overflow. -/// @return The result of operation, INT64_MAX if it overflowed. -DQN_API int64_t Dqn_Safe_AddI64(int64_t a, int64_t b); +DQN_API int64_t Dqn_Safe_AddI64 (int64_t a, int64_t b); +DQN_API int64_t Dqn_Safe_MulI64 (int64_t a, int64_t b); -/// Multiply 2 I64's together, safe asserting that the operation does not -/// overflow. -/// @return The result of operation, IINT64_MAX if it overflowed. -DQN_API int64_t Dqn_Safe_MulI64(int64_t a, int64_t b); +DQN_API uint64_t Dqn_Safe_AddU64 (uint64_t a, uint64_t b); +DQN_API uint64_t Dqn_Safe_MulU64 (uint64_t a, uint64_t b); -/// Add 2 U64's together, safe asserting that the operation does not overflow. -/// @return The result of operation, UINT64_MAX if it overflowed. -DQN_API uint64_t Dqn_Safe_AddU64(uint64_t a, uint64_t b); +DQN_API uint64_t Dqn_Safe_SubU64 (uint64_t a, uint64_t b); +DQN_API uint32_t Dqn_Safe_SubU32 (uint32_t a, uint32_t b); -/// Subtract 2 U64's together, safe asserting that the operation does not -/// overflow. -/// @return The result of operation, 0 if it overflowed. -DQN_API uint64_t Dqn_Safe_SubU64(uint64_t a, uint64_t b); +DQN_API int Dqn_Safe_SaturateCastUSizeToInt (Dqn_usize val); +DQN_API int8_t Dqn_Safe_SaturateCastUSizeToI8 (Dqn_usize val); +DQN_API int16_t Dqn_Safe_SaturateCastUSizeToI16 (Dqn_usize val); +DQN_API int32_t Dqn_Safe_SaturateCastUSizeToI32 (Dqn_usize val); +DQN_API int64_t Dqn_Safe_SaturateCastUSizeToI64 (Dqn_usize val); -/// Multiple 2 U64's together, safe asserting that the operation does not -/// overflow. -/// @return The result of operation, UINT64_MAX if it overflowed. -DQN_API uint64_t Dqn_Safe_MulU64(uint64_t a, uint64_t b); +DQN_API unsigned int Dqn_Safe_SaturateCastU64ToUInt (uint64_t val); +DQN_API uint8_t Dqn_Safe_SaturateCastU64ToU8 (uint64_t val); +DQN_API uint16_t Dqn_Safe_SaturateCastU64ToU16 (uint64_t val); +DQN_API uint32_t Dqn_Safe_SaturateCastU64ToU32 (uint64_t val); -/// Subtract 2 U32's together, safe asserting that the operation does not -/// overflow. -/// @return The result of operation, 0 if it overflowed. -DQN_API uint32_t Dqn_Safe_SubU32(uint32_t a, uint32_t b); +DQN_API uint8_t Dqn_Safe_SaturateCastUSizeToU8 (Dqn_usize val); +DQN_API uint16_t Dqn_Safe_SaturateCastUSizeToU16 (Dqn_usize val); +DQN_API uint32_t Dqn_Safe_SaturateCastUSizeToU32 (Dqn_usize val); +DQN_API uint64_t Dqn_Safe_SaturateCastUSizeToU64 (Dqn_usize val); -// NOTE: Dqn_Safe_SaturateCastUSizeToI* -// ----------------------------------------------------------------------------- -/// Truncate a usize to int clamping the result to the max value of the desired -/// data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT_MAX if the value would go out of the -/// valid range when casted. -DQN_API int Dqn_Safe_SaturateCastUSizeToInt(Dqn_usize val); +DQN_API int Dqn_Safe_SaturateCastISizeToInt (Dqn_isize val); +DQN_API int8_t Dqn_Safe_SaturateCastISizeToI8 (Dqn_isize val); +DQN_API int16_t Dqn_Safe_SaturateCastISizeToI16 (Dqn_isize val); +DQN_API int32_t Dqn_Safe_SaturateCastISizeToI32 (Dqn_isize val); +DQN_API int64_t Dqn_Safe_SaturateCastISizeToI64 (Dqn_isize val); -/// Truncate a usize to I8 clamping the result to the max value of the desired -/// data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT8_MAX if the value would go out of the -/// valid range when casted. -DQN_API int8_t Dqn_Safe_SaturateCastUSizeToI8(Dqn_usize val); - -/// Truncate a usize to I16 clamping the result to the max value of the desired -/// data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT16_MAX if the value would go out of the -/// valid range when casted. -DQN_API int16_t Dqn_Safe_SaturateCastUSizeToI16(Dqn_usize val); - -/// Truncate a usize to I32 clamping the result to the max value of the desired -/// data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT32_MAX if the value would go out of the -/// valid range when casted. -DQN_API int32_t Dqn_Safe_SaturateCastUSizeToI32(Dqn_usize val); - -/// Truncate a usize to I64 clamping the result to the max value of the desired -/// data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT64_MAX if the value would go out of the -/// valid range when casted. -DQN_API int64_t Dqn_Safe_SaturateCastUSizeToI64(Dqn_usize val); - -// NOTE: Dqn_Safe_SaturateCastU64ToU* -// ----------------------------------------------------------------------------- -/// Truncate a u64 to uint clamping the result to the max value of the desired -/// data type. Safe asserts if clamping occurs. -/// @return The truncated value or UINT_MAX if the value would go out of the -/// valid range when casted. -DQN_API unsigned int Dqn_Safe_SaturateCastU64ToUInt(uint64_t val); - -/// Truncate a u64 to u8 clamping the result to the max value of the desired -/// data type. Safe asserts if clamping occurs. -/// @return The truncated value or UINT8_MAX if the value would go out of the -/// valid range when casted. -DQN_API uint8_t Dqn_Safe_SaturateCastU64ToU8(uint64_t val); - -/// Truncate a u64 to u16 clamping the result to the max value of the desired -/// data type. Safe asserts if clamping occurs. -/// @return The truncated value or UINT16_MAX if the value would go out of the -/// valid range when casted. -DQN_API uint16_t Dqn_Safe_SaturateCastU64ToU16(uint64_t val); - -/// Truncate a u64 to u32 clamping the result to the max value of the desired -/// data type. Safe asserts if clamping occurs. -/// @return The truncated value or UINT32_MAX if the value would go out of the -/// valid range when casted. -DQN_API uint32_t Dqn_Safe_SaturateCastU64ToU32(uint64_t val); - -// NOTE: Dqn_Safe_SaturateCastUSizeToU* -// ----------------------------------------------------------------------------- -/// Truncate a usize to U8 clamping the result to the max value of the desired -/// data type. Safe asserts if clamping occurs. -/// @return The truncated value or UINT8_MAX if the value would go out of the -/// valid range when casted. -DQN_API uint8_t Dqn_Safe_SaturateCastUSizeToU8(Dqn_usize val); - -/// Truncate a usize to U16 clamping the result to the max value of the desired -/// data type. Safe asserts if clamping occurs. -/// @return The truncated value or UINT16_MAX if the value would go out of the -/// valid range when casted. -DQN_API uint16_t Dqn_Safe_SaturateCastUSizeToU16(Dqn_usize val); - -/// Truncate a usize to U32 clamping the result to the max value of the desired -/// data type. Safe asserts if clamping occurs. -/// @return The truncated value or UINT32_MAX if the value would go out of the -/// valid range when casted. -DQN_API uint32_t Dqn_Safe_SaturateCastUSizeToU32(Dqn_usize val); - -/// Truncate a usize to U64 clamping the result to the max value of the desired -/// data type. Safe asserts if clamping occurs. -/// @return The truncated value or UINT64_MAX if the value would go out of the -/// valid range when casted. -DQN_API uint64_t Dqn_Safe_SaturateCastUSizeToU64(Dqn_usize val); - -// NOTE: Dqn_Safe_SaturateCastISizeToI* -// ----------------------------------------------------------------------------- -/// Truncate an isize to int clamping the result to the min and max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT_MIN or INT_MAX if the value would go -/// out of the valid range when casted. -DQN_API int Dqn_Safe_SaturateCastISizeToInt(Dqn_isize val); - -/// Truncate an isize to I8 clamping the result to the min and max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT8_MIN or INT8_MAX if the value would go -/// out of the valid range when casted. -DQN_API int8_t Dqn_Safe_SaturateCastISizeToI8(Dqn_isize val); - -/// Truncate an isize to I16 clamping the result to the min and max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT16_MIN or INT16_MAX if the value would go -/// out of the valid range when casted. -DQN_API int16_t Dqn_Safe_SaturateCastISizeToI16(Dqn_isize val); - -/// Truncate an isize to I32 clamping the result to the min and max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT32_MIN or INT32_MAX if the value would go -/// out of the valid range when casted. -DQN_API int32_t Dqn_Safe_SaturateCastISizeToI32(Dqn_isize val); - -/// Truncate an isize to I64 clamping the result to the min and max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT64_MIN or INT64_MAX if the value would go -/// out of the valid range when casted. -DQN_API int64_t Dqn_Safe_SaturateCastISizeToI64(Dqn_isize val); - -// NOTE: Dqn_Safe_SaturateCastISizeToU* -// ----------------------------------------------------------------------------- -/// Truncate an isize to uint clamping the result to 0 and the max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or 0 or UINT_MAX if the value would go -/// out of the valid range when casted. DQN_API unsigned int Dqn_Safe_SaturateCastISizeToUInt(Dqn_isize val); +DQN_API uint8_t Dqn_Safe_SaturateCastISizeToU8 (Dqn_isize val); +DQN_API uint16_t Dqn_Safe_SaturateCastISizeToU16 (Dqn_isize val); +DQN_API uint32_t Dqn_Safe_SaturateCastISizeToU32 (Dqn_isize val); +DQN_API uint64_t Dqn_Safe_SaturateCastISizeToU64 (Dqn_isize val); -/// Truncate an isize to U8 clamping the result to 0 and the max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or 0 or UINT8_MAX if the value would go -/// out of the valid range when casted. -DQN_API uint8_t Dqn_Safe_SaturateCastISizeToU8(Dqn_isize val); +DQN_API Dqn_isize Dqn_Safe_SaturateCastI64ToISize (int64_t val); +DQN_API int8_t Dqn_Safe_SaturateCastI64ToI8 (int64_t val); +DQN_API int16_t Dqn_Safe_SaturateCastI64ToI16 (int64_t val); +DQN_API int32_t Dqn_Safe_SaturateCastI64ToI32 (int64_t val); -/// Truncate an isize to U16 clamping the result to 0 and the max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or 0 or UINT16_MAX if the value would go -/// out of the valid range when casted. -DQN_API uint16_t Dqn_Safe_SaturateCastISizeToU16(Dqn_isize val); - -/// Truncate an isize to U32 clamping the result to 0 and the max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or 0 or UINT32_MAX if the value would go -/// out of the valid range when casted. -DQN_API uint32_t Dqn_Safe_SaturateCastISizeToU32(Dqn_isize val); - -/// Truncate an isize to U64 clamping the result to 0 and the max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or 0 or UINT64_MAX if the value would go -/// out of the valid range when casted. -DQN_API uint64_t Dqn_Safe_SaturateCastISizeToU64(Dqn_isize val); - -// NOTE: Dqn_Safe_SaturateCastI64To* -// ----------------------------------------------------------------------------- -/// Truncate an I64 to isize clamping the result to the min and max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or DQN_ISIZE_MIN or DQN_ISIZE_MAX if the value -/// would go out of the valid range when casted. -DQN_API Dqn_isize Dqn_Safe_SaturateCastI64ToISize(Dqn_isize val); - -/// Truncate an I64 to I8 clamping the result to the min and max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT8_MIN or INT8_MAX if the value would go -/// out of the valid range when casted. -DQN_API int8_t Dqn_Safe_SaturateCastI64ToI8(int64_t val); - -/// Truncate an I64 to I16 clamping the result to the min and max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT16_MIN or INT16_MAX if the value would go -/// out of the valid range when casted. -DQN_API int16_t Dqn_Safe_SaturateCastI64ToI16(int64_t val); - -/// Truncate an I64 to I32 clamping the result to the min and max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT32_MIN or INT32_MAX if the value would go -/// out of the valid range when casted. -DQN_API int32_t Dqn_Safe_SaturateCastI64ToI32(int64_t val); - -// NOTE: Dqn_Safe_SaturateCastIntTo* -// ----------------------------------------------------------------------------- -/// Truncate an int to I8 clamping the result to the min and max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT8_MIN or INT8_MAX if the value -/// would go out of the valid range when casted. -DQN_API int8_t Dqn_Safe_SaturateCastIntToI8(int val); - -/// Truncate an int to I16 clamping the result to the min and max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or INT16_MIN or INT16_MAX if the value -/// would go out of the valid range when casted. -DQN_API int16_t Dqn_Safe_SaturateCastIntToI16(int val); - -/// Truncate an int to U8 clamping the result to 0 and the max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or 0 or UINT8_MAX if the value would go -/// out of the valid range when casted. -DQN_API uint8_t Dqn_Safe_SaturateCastIntToU8(int val); - -/// Truncate an int to U16 clamping the result to 0 and the max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or 0 or UINT16_MAX if the value would go -/// out of the valid range when casted. -DQN_API uint16_t Dqn_Safe_SaturateCastIntToU16(int val); - -/// Truncate an int to U32 clamping the result to 0 and the max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or 0 or UINT32_MAX if the value would go -/// out of the valid range when casted. -DQN_API uint32_t Dqn_Safe_SaturateCastIntToU32(int val); - -/// Truncate an int to U64 clamping the result to 0 and the max value of the -/// desired data type. Safe asserts if clamping occurs. -/// @return The truncated value or 0 or UINT64_MAX if the value would go -/// out of the valid range when casted. -DQN_API uint64_t Dqn_Safe_SaturateCastIntToU64(int val); +DQN_API int8_t Dqn_Safe_SaturateCastIntToI8 (int val); +DQN_API int16_t Dqn_Safe_SaturateCastIntToI16 (int val); +DQN_API uint8_t Dqn_Safe_SaturateCastIntToU8 (int val); +DQN_API uint16_t Dqn_Safe_SaturateCastIntToU16 (int val); +DQN_API uint32_t Dqn_Safe_SaturateCastIntToU32 (int val); +DQN_API uint64_t Dqn_Safe_SaturateCastIntToU64 (int val); // NOTE: [$TCTX] Dqn_ThreadContext ================================================================= // Each thread is assigned in their thread-local storage (TLS) scratch and diff --git a/dqn_platform.cpp b/dqn_platform.cpp index 78ddaec..2392924 100644 --- a/dqn_platform.cpp +++ b/dqn_platform.cpp @@ -924,16 +924,16 @@ DQN_API Dqn_FsFile Dqn_Fs_OpenFile(Dqn_String8 path, Dqn_FsFileOpen open_mode, u if (handle == INVALID_HANDLE_VALUE) { Dqn_WinErrorMsg msg = Dqn_Win_LastError(); result.error_size = - DQN_CAST(uint16_t) Dqn_SNPrintF2DotsOnOverflow(result.error, - DQN_ARRAY_UCOUNT(result.error), - "Open file failed: %.*s for \"%.*s\"", - DQN_STRING_FMT(msg), - DQN_STRING_FMT(path)); + DQN_CAST(uint16_t) Dqn_SNPrintFDotTruncate(result.error, + DQN_ARRAY_UCOUNT(result.error), + "Open file failed: %.*s for \"%.*s\"", + DQN_STRING_FMT(msg), + DQN_STRING_FMT(path)); return result; } #else if (access & Dqn_FsFileAccess_Execute) { - result.error_size = DQN_CAST(uint16_t) Dqn_SNPrintF2DotsOnOverflow( + result.error_size = DQN_CAST(uint16_t) Dqn_SNPrintFDotTruncate( result.error, DQN_ARRAY_UCOUNT(result.error), "Open file failed: execute access not supported for \"%.*s\"", @@ -1008,10 +1008,10 @@ DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, char const *buffer, Dqn_usize si if (!result) { Dqn_WinErrorMsg msg = Dqn_Win_LastError(); file->error_size = - DQN_CAST(uint16_t) Dqn_SNPrintF2DotsOnOverflow(file->error, - DQN_ARRAY_UCOUNT(file->error), - "Write file failed: %.*s for %.*s", - DQN_STRING_FMT(msg)); + DQN_CAST(uint16_t) Dqn_SNPrintFDotTruncate(file->error, + DQN_ARRAY_UCOUNT(file->error), + "Write file failed: %.*s for %.*s", + DQN_STRING_FMT(msg)); } #else result = fwrite(buffer, DQN_CAST(Dqn_usize)size, 1 /*count*/, file->handle) == 1 /*count*/; diff --git a/dqn_platform.h b/dqn_platform.h index a9cbc53..fcf3d65 100644 --- a/dqn_platform.h +++ b/dqn_platform.h @@ -10,6 +10,15 @@ // ================================================================================================= // NOTE: [$FSYS] Dqn_Fs ============================================================================ +// NOTE: FS Manipulation ======================================================= +// TODO(dqn): We should have a Dqn_String8 interface and a CString interface +// +// NOTE: API =================================================================== +// @proc Dqn_FsDelete +// @desc Delete the item specified at the path. This function *CAN* not delete directories unless +// the directory is empty. +// @return True if deletion was successful, false otherwise + enum Dqn_FsInfoType { Dqn_FsInfoType_Unknown, @@ -27,45 +36,43 @@ struct Dqn_FsInfo uint64_t size; }; -// NOTE: File System API -// ============================================================================= -// TODO(dqn): We should have a Dqn_String8 interface and a CString interface -DQN_API bool Dqn_Fs_Exists(Dqn_String8 path); -DQN_API bool Dqn_Fs_DirExists(Dqn_String8 path); -DQN_API Dqn_FsInfo Dqn_Fs_GetInfo(Dqn_String8 path); -DQN_API bool Dqn_Fs_Copy(Dqn_String8 src, Dqn_String8 dest, bool overwrite); +DQN_API bool Dqn_Fs_Exists (Dqn_String8 path); +DQN_API bool Dqn_Fs_DirExists(Dqn_String8 path); +DQN_API Dqn_FsInfo Dqn_Fs_GetInfo (Dqn_String8 path); +DQN_API bool Dqn_Fs_Copy (Dqn_String8 src, Dqn_String8 dest, bool overwrite); +DQN_API bool Dqn_Fs_MakeDir (Dqn_String8 path); +DQN_API bool Dqn_Fs_Move (Dqn_String8 src, Dqn_String8 dest, bool overwrite); +DQN_API bool Dqn_Fs_Delete (Dqn_String8 path); -DQN_API bool Dqn_Fs_MakeDir(Dqn_String8 path); -DQN_API bool Dqn_Fs_Move(Dqn_String8 src, Dqn_String8 dest, bool overwrite); +// NOTE: R/W Entire File =========================================================================== +// NOTE: API ======================================================================================= +// @proc Dqn_Fs_WriteString8, Dqn_Fs_WriteCString8 +// @desc Write the string to a file at the path overwriting if necessary. -// TODO(dqn): This doesn't work on directories unless you delete the files -// in that directory first. -DQN_API bool Dqn_Fs_Delete(Dqn_String8 path); +// @proc Dqn_Fs_ReadString8, Dqn_Fs_ReadCString8 +// @desc Read the file at the path to a string. -// NOTE: Read/Write Entire File API -// ============================================================================= -// file_size: (Optional) The size of the file in bytes, the allocated buffer is (file_size + 1 [null terminator]) in bytes. -DQN_API bool Dqn_Fs_WriteCString8(char const *file_path, Dqn_usize file_path_size, char const *buffer, Dqn_usize buffer_size); -DQN_API bool Dqn_Fs_WriteString8(Dqn_String8 file_path, Dqn_String8 buffer); - -/// Read a file at the specified path into memory. -/// @param[in] path Path to the file to read -/// @param[in] path_size The string size of the file path -/// @param[out] file_size (Optional) Pass a pointer to receive the number of bytes read -/// @param[in] allocator Allocator used to read the file to memory with -/// @return A cstring with the read file, null pointer on failure. #define Dqn_Fs_ReadCString8(path, path_size, file_size, allocator) Dqn_Fs_ReadCString8_(DQN_LEAK_TRACE path, path_size, file_size, allocator) -DQN_API char *Dqn_Fs_ReadCString8_(DQN_LEAK_TRACE_FUNCTION char const *path, Dqn_usize path_size, Dqn_usize *file_size, Dqn_Allocator allocator); - -/// Read a file at the specified path into memory. -/// @param[in] file_path Path to the file to read -/// @param[in] allocator Allocator used to read the file to memory with -/// @return A string with the read file, invalid string on failure. #define Dqn_Fs_ReadString8(path, allocator) Dqn_Fs_ReadString8_(DQN_LEAK_TRACE path, allocator) -DQN_API Dqn_String8 Dqn_Fs_ReadString8_(DQN_LEAK_TRACE_FUNCTION Dqn_String8 path, Dqn_Allocator allocator); -// NOTE: Read/Write File Stream API -// ============================================================================= +DQN_API bool Dqn_Fs_WriteCString8(char const *file_path, Dqn_usize file_path_size, char const *buffer, Dqn_usize buffer_size); +DQN_API bool Dqn_Fs_WriteString8 (Dqn_String8 file_path, Dqn_String8 buffer); + +// NOTE: Internal ================================================================================== +DQN_API char *Dqn_Fs_ReadCString8_(DQN_LEAK_TRACE_FUNCTION char const *path, Dqn_usize path_size, Dqn_usize *file_size, Dqn_Allocator allocator); +DQN_API Dqn_String8 Dqn_Fs_ReadString8_ (DQN_LEAK_TRACE_FUNCTION Dqn_String8 path, Dqn_Allocator allocator); + +// NOTE: R/W Stream API ============================================================================ +// NOTE: API ======================================================================================= +// @proc Dqn_Fs_OpenFile +// @desc Open a handle to the file + +// @proc Dqn_Fs_WriteFile +// @desc Append to the file specified by the handle with the given buffer. + +// @proc Dqn_Fs_CloseFile +// @desc Close the file at specified by the handle + struct Dqn_FsFile { void *handle; @@ -90,12 +97,35 @@ enum Dqn_FsFileAccess Dqn_FsFileAccess_All = Dqn_FsFileAccess_ReadWrite | Dqn_FsFileAccess_Execute, }; -DQN_API Dqn_FsFile Dqn_Fs_OpenFile(Dqn_String8 path, Dqn_FsFileOpen open_mode, uint32_t access); -DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, char const *buffer, Dqn_usize size); -DQN_API void Dqn_Fs_CloseFile(Dqn_FsFile *file); +DQN_API Dqn_FsFile Dqn_Fs_OpenFile (Dqn_String8 path, Dqn_FsFileOpen open_mode, uint32_t access); +DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, char const *buffer, Dqn_usize size); +DQN_API void Dqn_Fs_CloseFile(Dqn_FsFile *file); + +// NOTE: File system paths ========================================================================= +// Helper data structure for building paths suitable for OS consumption. +// +// NOTE: API ======================================================================================= +// @proc Dqn_FsPath_AddRef, Dqn_FsPath_Add +// @desc Append a path to the file path. The passed in path can be specify +// both a single level or multiple directories with different path separators. +// The path will be decomposed into individual sections in the function. +// +// For example passing +// - "path/to/your/desired/folder" is valid +// - "path" is valid +// - "path/to\your/desired\folder" is valid + +// @proc Dqn_FsPath_Pop +// @desc Remove the last appended path level from the current path stored in +// the FsPath. +// +// For example "path/to/your/desired/folder" popped produces +// "path/to/your/desired" + +// @proc Dqn_FsPath_ConvertString8 +// @desc Convert the path specified in the string to the OS native separated +// path. -// NOTE: Filesystem paths -// ============================================================================= #if !defined(Dqn_FsPathOSSeperator) #if defined(DQN_OS_WIN32) #define Dqn_FsPathOSSeperator "\\" @@ -125,7 +155,6 @@ DQN_API bool Dqn_FsPath_Add (Dqn_Arena *arena, Dqn_FsPath * DQN_API bool Dqn_FsPath_Pop (Dqn_FsPath *fs_path); DQN_API Dqn_String8 Dqn_FsPath_BuildWithSeparator(Dqn_Arena *arena, Dqn_FsPath const *fs_path, Dqn_String8 path_separator); DQN_API Dqn_String8 Dqn_FsPath_ConvertString8 (Dqn_Arena *arena, Dqn_String8 path); - #define Dqn_FsPath_BuildFwdSlash(arena, fs_path) Dqn_FsPath_BuildWithSeparator(arena, fs_path, DQN_STRING8("/")) #define Dqn_FsPath_BuildBackSlash(arena, fs_path) Dqn_FsPath_BuildWithSeparator(arena, fs_path, DQN_STRING8("\\")) @@ -138,6 +167,11 @@ DQN_API Dqn_String8 Dqn_FsPath_ConvertString8 (Dqn_Arena *arena, Dqn_String8 #endif // NOTE: [$DATE] Dqn_Date ========================================================================== +// NOTE: API ======================================================================================= +// @proc Dqn_Date_EpochTime +// @desc Produce the time elapsed since the Unix epoch +// (e.g. 1970-01-01T00:00:00Z) in seconds + struct Dqn_DateHMSTimeString { char date[DQN_ARRAY_UCOUNT("YYYY-MM-SS")]; @@ -158,13 +192,10 @@ struct Dqn_DateHMSTime uint8_t seconds; }; -// @return The current time at the point of invocation -DQN_API Dqn_DateHMSTime Dqn_Date_HMSLocalTimeNow(); +DQN_API Dqn_DateHMSTime Dqn_Date_HMSLocalTimeNow (); DQN_API Dqn_DateHMSTimeString Dqn_Date_HMSLocalTimeStringNow(char date_separator = '-', char hms_separator = ':'); -DQN_API Dqn_DateHMSTimeString Dqn_Date_HMSLocalTimeString(Dqn_DateHMSTime time, char date_separator = '-', char hms_separator = ':'); - -// return: The time elapsed since Unix epoch (1970-01-01T00:00:00Z) in seconds -DQN_API uint64_t Dqn_Date_EpochTime(); +DQN_API Dqn_DateHMSTimeString Dqn_Date_HMSLocalTimeString (Dqn_DateHMSTime time, char date_separator = '-', char hms_separator = ':'); +DQN_API uint64_t Dqn_Date_EpochTime (); // NOTE: [$W32H] Win32 Min Header ================================================================== #if defined(DQN_OS_WIN32) @@ -192,71 +223,70 @@ DQN_API uint64_t Dqn_Date_EpochTime(); #endif // !defined(DQN_NO_WIN32_MIN_HEADER) && !defined(_INC_WINDOWS) // NOTE: [$WIND] Dqn_Win =========================================================================== +// NOTE: API ======================================================================================= +// @proc Dqn_Win_LastErrorToBuffer, Dqn_Win_LastError +// @desc Retrieve the latest error code and message Windows produced for the +// most recent Win32 API call. + +// @proc Dqn_Win_MakeProcessDPIAware +// @desc Call once at application start-up to ensure that the application is +// DPI aware on Windows and ensure that application UI is scaled up +// appropriately for the monitor. + struct Dqn_WinErrorMsg { unsigned long code; char data[DQN_KILOBYTES(64) - 1]; // Maximum error size unsigned long size; }; -DQN_API void Dqn_Win_LastErrorToBuffer(Dqn_WinErrorMsg *msg); +DQN_API void Dqn_Win_LastErrorToBuffer(Dqn_WinErrorMsg *msg); DQN_API Dqn_WinErrorMsg Dqn_Win_LastError(); +DQN_API void Dqn_Win_MakeProcessDPIAware(); -/// Call once at application start-up to ensure that the application is DPI -/// aware on Windows and ensure that application UI is scaled up appropriately -/// for the monitor. -DQN_API void Dqn_Win_MakeProcessDPIAware(); +// NOTE: Windows String8 <-> String16 =========================================== +// Convert a UTF8 <-> UTF16 string. +// +// The exact size buffer required for this function can be determined by +// calling this function with the 'dest' set to null and 'dest_size' set to 0, +// the return size is the size required for conversion not-including space for +// the null-terminator. This function *always* null-terminates the input +// buffer. +// +// Returns the number of u8's (for UTF16->8) OR u16's (for UTF8->16) +// written/required for conversion. 0 if there was a conversion error and can be +// queried using 'Dqn_Win_LastError' -// NOTE: Windows String8 To String16 -// ----------------------------------------------------------------------------- -/// Convert a UTF8 to UTF16 string. -/// -/// The exact size buffer required for this function can be determined by -/// calling this function with the 'dest' set to null and 'dest_size' set to 0, -/// the return size is the size required for conversion not-including space for -/// the null-terminator. This function *always* null-terminates the input -/// buffer. -/// -/// @return The number of u16's written/required for conversion. 0 if there was -/// a conversion error and can be queried using 'Dqn_Win_LastError' -DQN_API int Dqn_Win_CString8ToCString16(const char *src, int src_size, wchar_t *dest, int dest_size); -DQN_API int Dqn_Win_String8ToCString16(Dqn_String8 src, wchar_t *dest, int dest_size); -DQN_API Dqn_String16 Dqn_Win_String8ToString16Allocator(Dqn_String8 src, Dqn_Allocator allocator); +DQN_API int Dqn_Win_CString8ToCString16 (char const *src, int src_size, wchar_t *dest, int dest_size); +DQN_API int Dqn_Win_String8ToCString16 (Dqn_String8 src, wchar_t *dest, int dest_size); +DQN_API Dqn_String16 Dqn_Win_String8ToString16Allocator (Dqn_String8 src, Dqn_Allocator allocator); -// NOTE: Windows String16 To String8 -// ----------------------------------------------------------------------------- -/// Convert a UTF16 to UTF8 string. -/// -/// The exact size buffer required for this function can be determined by -/// calling this function with the 'dest' set to null and 'dest_size' set to 0, -/// the return size is the size required for conversion not-including space for -/// the null-terminator. This function *always* null-terminates the input -/// buffer. -/// -/// @return The number of u8's written/required for conversion. 0 if there was -/// a conversion error and can be queried using 'Dqn_Win_LastError' -DQN_API int Dqn_Win_CString16ToCString8(const wchar_t *src, int src_size, char *dest, int dest_size); -DQN_API Dqn_String8 Dqn_Win_CString16ToString8Allocator(const wchar_t *src, int src_size, Dqn_Allocator allocator); -DQN_API int Dqn_Win_String16ToCString8(Dqn_String16 src, char *dest, int dest_size); -DQN_API Dqn_String8 Dqn_Win_String16ToString8Allocator(Dqn_String16 src, Dqn_Allocator allocator); +DQN_API int Dqn_Win_CString16ToCString8 (wchar_t const *src, int src_size, char *dest, int dest_size); +DQN_API Dqn_String8 Dqn_Win_CString16ToString8Allocator(wchar_t const *src, int src_size, Dqn_Allocator allocator); +DQN_API int Dqn_Win_String16ToCString8 (Dqn_String16 src, char *dest, int dest_size); +DQN_API Dqn_String8 Dqn_Win_String16ToString8Allocator (Dqn_String16 src, Dqn_Allocator allocator); -// NOTE: Windows Executable Directory -// ----------------------------------------------------------------------------- -/// Evaluate the current executable's directory that is running when this -/// function is called. -/// @param[out] buffer The buffer to write the executable directory into. Set -/// this to null to calculate the required buffer size for the directory. -/// @param[in] size The size of the buffer given. Set this to 0 to calculate the -/// required buffer size for the directory. -/// @return The length of the executable directory string. If this return value -/// exceeds the capacity of the 'buffer', the 'buffer' is untouched. -DQN_API Dqn_usize Dqn_Win_EXEDirW(wchar_t *buffer, Dqn_usize size); -DQN_API Dqn_String16 Dqn_Win_EXEDirWArena(Dqn_Arena *arena); +// NOTE: Path navigatoin =========================================================================== +// NOTE: API ======================================================================================= +// @proc Dqn_Win_EXEDirW, Dqn_Win_EXEDirWArena +// @desc Evaluate the current executable's directory that is running when this +// function is called. +// @param[out] buffer The buffer to write the executable directory into. Set +// this to null to calculate the required buffer size for the directory. +// @param[in] size The size of the buffer given. Set this to 0 to calculate the +// required buffer size for the directory. +// @return The length of the executable directory string. If this return value +// exceeds the capacity of the 'buffer', the 'buffer' is untouched. -// @param[in] size (Optional) The size of the current directory string returned -// @param[in] suffix (Optional) A suffix to append to the current working directory -// @param[in] suffix_size (Optional) The size of the suffix to append -DQN_API Dqn_String8 Dqn_Win_WorkingDir(Dqn_Allocator allocator, Dqn_String8 suffix); -DQN_API Dqn_String16 Dqn_Win_WorkingDirW(Dqn_Allocator allocator, Dqn_String16 suffix); +// @proc Dqn_Win_WorkingDir, Dqn_Win_WorkingDirW +// @param[in] suffix (Optional) A suffix to append to the current working directory + +// @proc Dqn_Win_FolderIterate, Dqn_Win_FolderWIterate +// @desc Iterate the files in the specified folder at the path +#if 0 + for (Dqn_WinFolderIterator it = {}; Dqn_Win_FolderIterate("C:/your/path/", &it); ) { + printf("%.*s\n", DQN_STRING_FMT(it.file_name)); + } +#endif struct Dqn_Win_FolderIteratorW { @@ -272,11 +302,36 @@ struct Dqn_Win_FolderIterator char file_name_buf[512]; }; -DQN_API bool Dqn_Win_FolderIterate(Dqn_String8 path, Dqn_Win_FolderIterator *it); -DQN_API bool Dqn_Win_FolderWIterate(Dqn_String16 path, Dqn_Win_FolderIteratorW *it); +DQN_API Dqn_usize Dqn_Win_EXEDirW (wchar_t *buffer, Dqn_usize size); +DQN_API Dqn_String16 Dqn_Win_EXEDirWArena (Dqn_Arena *arena); +DQN_API Dqn_String8 Dqn_Win_WorkingDir (Dqn_Allocator allocator, Dqn_String8 suffix); +DQN_API Dqn_String16 Dqn_Win_WorkingDirW (Dqn_Allocator allocator, Dqn_String16 suffix); +DQN_API bool Dqn_Win_FolderIterate (Dqn_String8 path, Dqn_Win_FolderIterator *it); +DQN_API bool Dqn_Win_FolderWIterate(Dqn_String16 path, Dqn_Win_FolderIteratorW *it); #if !defined(DQN_NO_WINNET) // NOTE: [$WINN] Dqn_WinNet ======================================================================== +// TODO(dqn): Useful options to expose in the handle +// https://docs.microsoft.com/en-us/windows/win32/wininet/option-flags +// INTERNET_OPTION_CONNECT_RETRIES -- default is 5 retries +// INTERNET_OPTION_CONNECT_TIMEOUT -- milliseconds +// INTERNET_OPTION_RECEIVE_TIMEOUT +// INTERNET_OPTION_SEND_TIMEOUT +// +// NOTE: API ======================================================================================= +// @proc Dqn_Win_NetHandleInitHTTPMethod, Dqn_Win_NetHandleInitHTTPMethodCString +// @desc Setup a handle to the URL with the given HTTP verb. +// +// This function is the same as calling Dqn_Win_NetHandleInit() followed by +// Dqn_Win_NetHandleSetHTTPMethod(). +// +// @param http_method The HTTP request type, e.g. "GET" or "POST" e.t.c + +// @proc Dqn_Win_NetHandleSetHTTPMethod +// @desc Set the HTTP request method for the given handle. This function can +// be used on a pre-existing valid handle that has at the minimum been +// initialised. + enum Dqn_WinNetHandleState { Dqn_WinNetHandleState_Invalid, @@ -324,34 +379,6 @@ struct Dqn_WinNetHandle Dqn_WinNetHandleState state; }; -// TODO(dqn): Useful options to expose in the handle -// https://docs.microsoft.com/en-us/windows/win32/wininet/option-flags -// INTERNET_OPTION_CONNECT_RETRIES -- default is 5 retries -// INTERNET_OPTION_CONNECT_TIMEOUT -- milliseconds -// INTERNET_OPTION_RECEIVE_TIMEOUT -// INTERNET_OPTION_SEND_TIMEOUT - -// Setup a handle to the URL with the given HTTP verb. -DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitCString(char const *url, int url_size); -DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInit(Dqn_String8 url); - -// Setup a handle to the URL with the given HTTP verb. -// -// This function is the same as calling Dqn_Win_NetHandleInit() followed by -// Dqn_Win_NetHandleSetHTTPMethod(). -// -// @param http_method The HTTP request type, e.g. "GET" or "POST" e.t.c -DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitHTTPMethodCString(char const *url, int url_size, char const *http_method); -DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitHTTPMethod(Dqn_String8 url, Dqn_String8 http_method); - -DQN_API void Dqn_Win_NetHandleClose(Dqn_WinNetHandle *handle); -DQN_API bool Dqn_Win_NetHandleIsValid(Dqn_WinNetHandle const *handle); -DQN_API void Dqn_Win_NetHandleSetUserAgentCString(Dqn_WinNetHandle *handle, char const *user_agent, int user_agent_size); - -// Set the HTTP request method for the given handle. This function can be used -// on a pre-existing valid handle that has at the minimum been initialised. -DQN_API bool Dqn_Win_NetHandleSetHTTPMethod(Dqn_WinNetHandle *handle, char const *method); - enum Dqn_WinNetHandleRequestHeaderFlag { Dqn_WinNetHandleRequestHeaderFlag_Add, @@ -360,9 +387,6 @@ enum Dqn_WinNetHandleRequestHeaderFlag Dqn_WinNetHandleRequestHeaderFlag_Count, }; -DQN_API bool Dqn_Win_NetHandleSetRequestHeaderCString8(Dqn_WinNetHandle *handle, char const *header, int header_size, uint32_t mode); -DQN_API bool Dqn_Win_NetHandleSetRequestHeaderString8(Dqn_WinNetHandle *handle, Dqn_String8 header, uint32_t mode); - struct Dqn_WinNetHandleResponse { Dqn_String8 raw_headers; @@ -373,33 +397,35 @@ struct Dqn_WinNetHandleResponse uint64_t content_length; Dqn_String8 content_type; }; -DQN_API Dqn_WinNetHandleResponse Dqn_Win_NetHandleSendRequest(Dqn_WinNetHandle *handle, Dqn_Allocator allocator, char const *post_data, unsigned long post_data_size); -DQN_API bool Dqn_Win_NetHandlePump(Dqn_WinNetHandle *handle, char *dest, int dest_size, size_t *download_size); -DQN_API char * Dqn_Win_NetHandlePumpCString8(Dqn_WinNetHandle *handle, Dqn_Arena *arena, size_t *download_size); -DQN_API Dqn_String8 Dqn_Win_NetHandlePumpString8(Dqn_WinNetHandle *handle, Dqn_Arena *arena); - -DQN_API void Dqn_Win_NetHandlePumpToCRTFile(Dqn_WinNetHandle *handle, FILE *file); -DQN_API char *Dqn_Win_NetHandlePumpToAllocCString(Dqn_WinNetHandle *handle, size_t *download_size); -DQN_API Dqn_String8 Dqn_Win_NetHandlePumpToAllocString(Dqn_WinNetHandle *handle); +DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitCString (char const *url, int url_size); +DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInit (Dqn_String8 url); +DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitHTTPMethodCString (char const *url, int url_size, char const *http_method); +DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitHTTPMethod (Dqn_String8 url, Dqn_String8 http_method); +DQN_API void Dqn_Win_NetHandleClose (Dqn_WinNetHandle *handle); +DQN_API bool Dqn_Win_NetHandleIsValid (Dqn_WinNetHandle const *handle); +DQN_API void Dqn_Win_NetHandleSetUserAgentCString (Dqn_WinNetHandle *handle, char const *user_agent, int user_agent_size); +DQN_API bool Dqn_Win_NetHandleSetHTTPMethod (Dqn_WinNetHandle *handle, char const *method); +DQN_API bool Dqn_Win_NetHandleSetRequestHeaderCString8(Dqn_WinNetHandle *handle, char const *header, int header_size, uint32_t mode); +DQN_API bool Dqn_Win_NetHandleSetRequestHeaderString8 (Dqn_WinNetHandle *handle, Dqn_String8 header, uint32_t mode); +DQN_API Dqn_WinNetHandleResponse Dqn_Win_NetHandleSendRequest (Dqn_WinNetHandle *handle, Dqn_Allocator allocator, char const *post_data, unsigned long post_data_size); +DQN_API bool Dqn_Win_NetHandlePump (Dqn_WinNetHandle *handle, char *dest, int dest_size, size_t *download_size); +DQN_API char * Dqn_Win_NetHandlePumpCString8 (Dqn_WinNetHandle *handle, Dqn_Arena *arena, size_t *download_size); +DQN_API Dqn_String8 Dqn_Win_NetHandlePumpString8 (Dqn_WinNetHandle *handle, Dqn_Arena *arena); +DQN_API void Dqn_Win_NetHandlePumpToCRTFile (Dqn_WinNetHandle *handle, FILE *file); +DQN_API char * Dqn_Win_NetHandlePumpToAllocCString (Dqn_WinNetHandle *handle, size_t *download_size); +DQN_API Dqn_String8 Dqn_Win_NetHandlePumpToAllocString (Dqn_WinNetHandle *handle); #endif // !defined(DQN_NO_WINNET) #endif // defined(DQN_OS_WIN32) // NOTE: [$OSYS] Dqn_OS ============================================================================ -/// Generate cryptographically secure bytes -DQN_API bool Dqn_OS_SecureRNGBytes(void *buffer, uint32_t size); +// NOTE: API ======================================================================================= +// @proc Dqn_OS_SecureRNGBytes +// @desc Generate cryptographically secure bytes -// return: The directory without the trailing '/' or ('\' for windows). Empty -// string with a nullptr if it fails. -DQN_API Dqn_String8 Dqn_OS_EXEDir(Dqn_Allocator allocator); - -DQN_API void Dqn_OS_SleepMs(Dqn_uint milliseconds); - -DQN_API uint64_t Dqn_OS_PerfCounterNow (); -DQN_API Dqn_f64 Dqn_OS_PerfCounterS (uint64_t begin, uint64_t end); -DQN_API Dqn_f64 Dqn_OS_PerfCounterMs (uint64_t begin, uint64_t end); -DQN_API Dqn_f64 Dqn_OS_PerfCounterMicroS(uint64_t begin, uint64_t end); -DQN_API Dqn_f64 Dqn_OS_PerfCounterNs (uint64_t begin, uint64_t end); +// @proc Dqn_OS_EXEDir +// @desc Retrieve the executable directory without the trailing '/' or +// ('\' for windows). If this fails an empty string is returned. /// Record time between two time-points using the OS's performance counter. struct Dqn_OSTimer @@ -408,12 +434,20 @@ struct Dqn_OSTimer uint64_t end; }; -DQN_API Dqn_OSTimer Dqn_OS_TimerBegin(); -DQN_API void Dqn_OS_TimerEnd (Dqn_OSTimer *timer); -DQN_API Dqn_f64 Dqn_OS_TimerS (Dqn_OSTimer timer); -DQN_API Dqn_f64 Dqn_OS_TimerMs (Dqn_OSTimer timer); -DQN_API Dqn_f64 Dqn_OS_TimerMicroS (Dqn_OSTimer timer); -DQN_API Dqn_f64 Dqn_OS_TimerNs (Dqn_OSTimer timer); +DQN_API bool Dqn_OS_SecureRNGBytes (void *buffer, uint32_t size); +DQN_API Dqn_String8 Dqn_OS_EXEDir (Dqn_Allocator allocator); +DQN_API void Dqn_OS_SleepMs (Dqn_uint milliseconds); +DQN_API uint64_t Dqn_OS_PerfCounterNow (); +DQN_API Dqn_f64 Dqn_OS_PerfCounterS (uint64_t begin, uint64_t end); +DQN_API Dqn_f64 Dqn_OS_PerfCounterMs (uint64_t begin, uint64_t end); +DQN_API Dqn_f64 Dqn_OS_PerfCounterMicroS(uint64_t begin, uint64_t end); +DQN_API Dqn_f64 Dqn_OS_PerfCounterNs (uint64_t begin, uint64_t end); +DQN_API Dqn_OSTimer Dqn_OS_TimerBegin (); +DQN_API void Dqn_OS_TimerEnd (Dqn_OSTimer *timer); +DQN_API Dqn_f64 Dqn_OS_TimerS (Dqn_OSTimer timer); +DQN_API Dqn_f64 Dqn_OS_TimerMs (Dqn_OSTimer timer); +DQN_API Dqn_f64 Dqn_OS_TimerMicroS (Dqn_OSTimer timer); +DQN_API Dqn_f64 Dqn_OS_TimerNs (Dqn_OSTimer timer); // OS_TimedBlock provides a extremely primitive way of measuring the duration of // code blocks, by sprinkling DQN_OS_TIMED_BLOCK_RECORD("record label"), you can diff --git a/dqn_strings.cpp b/dqn_strings.cpp index d7390db..a0c7d9c 100644 --- a/dqn_strings.cpp +++ b/dqn_strings.cpp @@ -589,7 +589,7 @@ DQN_API Dqn_String8 Dqn_String8_Copy_(DQN_LEAK_TRACE_FUNCTION Dqn_Allocator allo } // NOTE: [$STRB] Dqn_String8Builder ================================================================ -bool Dqn_String8Builder_AppendRef(Dqn_String8Builder *builder, Dqn_String8 string) +DQN_API bool Dqn_String8Builder_AppendRef(Dqn_String8Builder *builder, Dqn_String8 string) { if (!builder || !string.data || string.size <= 0) return false; @@ -612,14 +612,14 @@ bool Dqn_String8Builder_AppendRef(Dqn_String8Builder *builder, Dqn_String8 strin return true; } -bool Dqn_String8Builder_AppendCopy(Dqn_String8Builder *builder, Dqn_String8 string) +DQN_API bool Dqn_String8Builder_AppendCopy(Dqn_String8Builder *builder, Dqn_String8 string) { Dqn_String8 copy = Dqn_String8_Copy(builder->allocator, string); bool result = Dqn_String8Builder_AppendRef(builder, copy); return result; } -bool Dqn_String8Builder_AppendFV_(DQN_LEAK_TRACE_FUNCTION Dqn_String8Builder *builder, char const *fmt, va_list args) +DQN_API bool Dqn_String8Builder_AppendFV_(DQN_LEAK_TRACE_FUNCTION Dqn_String8Builder *builder, char const *fmt, va_list args) { Dqn_String8 string = Dqn_String8_InitFV(builder->allocator, fmt, args); if (string.size == 0) @@ -631,7 +631,7 @@ bool Dqn_String8Builder_AppendFV_(DQN_LEAK_TRACE_FUNCTION Dqn_String8Builder *bu return result; } -bool Dqn_String8Builder_AppendF(Dqn_String8Builder *builder, char const *fmt, ...) +DQN_API bool Dqn_String8Builder_AppendF(Dqn_String8Builder *builder, char const *fmt, ...) { va_list args; va_start(args, fmt); @@ -640,7 +640,7 @@ bool Dqn_String8Builder_AppendF(Dqn_String8Builder *builder, char const *fmt, .. return result; } -Dqn_String8 Dqn_String8Builder_Build(Dqn_String8Builder const *builder, Dqn_Allocator allocator) +DQN_API Dqn_String8 Dqn_String8Builder_Build(Dqn_String8Builder const *builder, Dqn_Allocator allocator) { Dqn_String8 result = DQN_ZERO_INIT; if (!builder || builder->string_size <= 0 || builder->count <= 0) @@ -662,7 +662,7 @@ Dqn_String8 Dqn_String8Builder_Build(Dqn_String8Builder const *builder, Dqn_Allo #if !defined(DQN_NO_JSON_BUILDER) // NOTE: [$JSON] Dqn_JSONBuilder =================================================================== -Dqn_JSONBuilder Dqn_JSONBuilder_Init(Dqn_Allocator allocator, int spaces_per_indent) +DQN_API Dqn_JSONBuilder Dqn_JSONBuilder_Init(Dqn_Allocator allocator, int spaces_per_indent) { Dqn_JSONBuilder result = {}; result.spaces_per_indent = spaces_per_indent; @@ -670,13 +670,13 @@ Dqn_JSONBuilder Dqn_JSONBuilder_Init(Dqn_Allocator allocator, int spaces_per_ind return result; } -Dqn_String8 Dqn_JSONBuilder_Build(Dqn_JSONBuilder const *builder, Dqn_Allocator allocator) +DQN_API Dqn_String8 Dqn_JSONBuilder_Build(Dqn_JSONBuilder const *builder, Dqn_Allocator allocator) { Dqn_String8 result = Dqn_String8Builder_Build(&builder->string_builder, allocator); return result; } -void Dqn_JSONBuilder_KeyValue(Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value) +DQN_API void Dqn_JSONBuilder_KeyValue(Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value) { if (key.size == 0 && value.size == 0) return; @@ -729,14 +729,14 @@ void Dqn_JSONBuilder_KeyValue(Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_Str builder->last_item = item; } -void Dqn_JSONBuilder_KeyValueFV(Dqn_JSONBuilder *builder, Dqn_String8 key, char const *value_fmt, va_list args) +DQN_API void Dqn_JSONBuilder_KeyValueFV(Dqn_JSONBuilder *builder, Dqn_String8 key, char const *value_fmt, va_list args) { Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(builder->string_builder.allocator.user_context); Dqn_String8 value = Dqn_String8_InitFV(scratch.allocator, value_fmt, args); Dqn_JSONBuilder_KeyValue(builder, key, value); } -void Dqn_JSONBuilder_KeyValueF(Dqn_JSONBuilder *builder, Dqn_String8 key, char const *value_fmt, ...) +DQN_API void Dqn_JSONBuilder_KeyValueF(Dqn_JSONBuilder *builder, Dqn_String8 key, char const *value_fmt, ...) { va_list args; va_start(args, value_fmt); @@ -744,47 +744,47 @@ void Dqn_JSONBuilder_KeyValueF(Dqn_JSONBuilder *builder, Dqn_String8 key, char c va_end(args); } -void Dqn_JSONBuilder_ObjectBeginNamed(Dqn_JSONBuilder *builder, Dqn_String8 name) +DQN_API void Dqn_JSONBuilder_ObjectBeginNamed(Dqn_JSONBuilder *builder, Dqn_String8 name) { Dqn_JSONBuilder_KeyValue(builder, name, DQN_STRING8("{")); } -void Dqn_JSONBuilder_ObjectEnd(Dqn_JSONBuilder *builder) +DQN_API void Dqn_JSONBuilder_ObjectEnd(Dqn_JSONBuilder *builder) { Dqn_JSONBuilder_KeyValue(builder, DQN_STRING8(""), DQN_STRING8("}")); } -void Dqn_JSONBuilder_ArrayBeginNamed(Dqn_JSONBuilder *builder, Dqn_String8 name) +DQN_API void Dqn_JSONBuilder_ArrayBeginNamed(Dqn_JSONBuilder *builder, Dqn_String8 name) { Dqn_JSONBuilder_KeyValue(builder, name, DQN_STRING8("[")); } -void Dqn_JSONBuilder_ArrayEnd(Dqn_JSONBuilder *builder) +DQN_API void Dqn_JSONBuilder_ArrayEnd(Dqn_JSONBuilder *builder) { Dqn_JSONBuilder_KeyValue(builder, DQN_STRING8(""), DQN_STRING8("]")); } -void Dqn_JSONBuilder_StringNamed(Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value) +DQN_API void Dqn_JSONBuilder_StringNamed(Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value) { Dqn_JSONBuilder_KeyValueF(builder, key, "\"%.*s\"", value.size, value.data); } -void Dqn_JSONBuilder_LiteralNamed(Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value) +DQN_API void Dqn_JSONBuilder_LiteralNamed(Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value) { Dqn_JSONBuilder_KeyValueF(builder, key, "%.*s", value.size, value.data); } -void Dqn_JSONBuilder_U64Named(Dqn_JSONBuilder *builder, Dqn_String8 key, uint64_t value) +DQN_API void Dqn_JSONBuilder_U64Named(Dqn_JSONBuilder *builder, Dqn_String8 key, uint64_t value) { Dqn_JSONBuilder_KeyValueF(builder, key, "%I64u", value); } -void Dqn_JSONBuilder_I64Named(Dqn_JSONBuilder *builder, Dqn_String8 key, int64_t value) +DQN_API void Dqn_JSONBuilder_I64Named(Dqn_JSONBuilder *builder, Dqn_String8 key, int64_t value) { Dqn_JSONBuilder_KeyValueF(builder, key, "%I64d", value); } -void Dqn_JSONBuilder_F64Named(Dqn_JSONBuilder *builder, Dqn_String8 key, double value, int decimal_places) +DQN_API void Dqn_JSONBuilder_F64Named(Dqn_JSONBuilder *builder, Dqn_String8 key, double value, int decimal_places) { if (!builder) return; @@ -797,22 +797,22 @@ void Dqn_JSONBuilder_F64Named(Dqn_JSONBuilder *builder, Dqn_String8 key, double char float_fmt[16]; if (decimal_places > 0) { // NOTE: Emit the format string "%.f" i.e. %.1f - snprintf(float_fmt, sizeof(float_fmt), "%%.%df", decimal_places); + STB_SPRINTF_DECORATE(snprintf)(float_fmt, sizeof(float_fmt), "%%.%df", decimal_places); } else { // NOTE: Emit the format string "%f" - snprintf(float_fmt, sizeof(float_fmt), "%%f"); + STB_SPRINTF_DECORATE(snprintf)(float_fmt, sizeof(float_fmt), "%%f"); } char fmt[32]; if (key.size) - snprintf(fmt, sizeof(fmt), "\"%%.*s\": %s", float_fmt); + STB_SPRINTF_DECORATE(snprintf)(fmt, sizeof(fmt), "\"%%.*s\": %s", float_fmt); else - snprintf(fmt, sizeof(fmt), "%s", float_fmt); + STB_SPRINTF_DECORATE(snprintf)(fmt, sizeof(fmt), "%s", float_fmt); Dqn_JSONBuilder_KeyValueF(builder, key, fmt, value); } -void Dqn_JSONBuilder_BoolNamed(Dqn_JSONBuilder *builder, Dqn_String8 key, bool value) +DQN_API void Dqn_JSONBuilder_BoolNamed(Dqn_JSONBuilder *builder, Dqn_String8 key, bool value) { Dqn_String8 value_string = value ? DQN_STRING8("true") : DQN_STRING8("false"); Dqn_JSONBuilder_KeyValueF(builder, key, "%.*s", value_string.size, value_string.data); @@ -1193,7 +1193,8 @@ DQN_API Dqn_String8 Dqn_Bin_HexToBytesArena(Dqn_Arena *arena, Dqn_String8 hex) } #endif // !defined(DQN_NO_HEX) -DQN_API int Dqn_SNPrintF2DotsOnOverflow(char *buffer, int size, char const *fmt, ...) +// NOTE: Other ===================================================================================== +DQN_API int Dqn_SNPrintFDotTruncate(char *buffer, int size, char const *fmt, ...) { va_list args; va_start(args, fmt); diff --git a/dqn_strings.h b/dqn_strings.h index 664100d..3de6ff1 100644 --- a/dqn_strings.h +++ b/dqn_strings.h @@ -17,13 +17,13 @@ // @desc Calculate the size of a cstring literal/array at compile time // @param literal The cstring literal/array to calculate the size for // @return The size of the cstring not including the null-terminating byte -// + // @proc Dqn_CString8_FSize, Dqn_CString8_FVSize // Calculate the required size to format the given format cstring. // @param[in] fmt The format string to calculate the size for // @return The size required to format the string, not including the null // terminator. -// + // @proc Dqn_CString8_Size // @desc Calculate the string length of the null-terminated string. // @param[in] a The string whose length is to be determined @@ -369,32 +369,31 @@ DQN_API Dqn_String8 Dqn_String8_Copy_ (DQN_LEAK_TRACE_FUNCTION Dq #if !defined(DQN_NO_FSTRING8) // NOTE: [$FSTR] Dqn_FString8 ====================================================================== -// NOTE: API -// +// NOTE: API ======================================================================================= // @proc Dqn_FString8_InitF // @desc Create a fixed string from the format string. The result string is // null-terminated. // @param fmt[in] Format string specifier to create the fixed string from // @return The created string, truncated if there was insufficient space -// + // @proc Dqn_FString8_Max // @desc @param string[in] The string to query the maximum capacity of // @return Maximum capacity of the fixed string -// + // @proc Dqn_FString8_Clear // @desc Reset the characters in the string // @param string[in] The string to clear -// + // @proc Dqn_FString8_AppendFV // @desc Append a format string to the fixed string. On failure the string is // appended to but truncated ensuring null-termination. // @param string[in] The string to append to // @param fmt[in] Format string to append to the fixed string // @return True if append was successful, false otherwise. -// + // @proc Dqn_FString8_AppendF // @desc @copydocs Dqn_FString8_AppendF -// + // @proc Dqn_FString8_AppendCString8 // @desc Append a cstring to the fixed string. On failure the string is // appended to but truncated ensuring null-termination. @@ -402,7 +401,7 @@ DQN_API Dqn_String8 Dqn_String8_Copy_ (DQN_LEAK_TRACE_FUNCTION Dq // @param value[in] Cstring to append to the fixed string // @param size[in] Size of the cstring // @return True if append was successful, false otherwise. -// + // @proc Dqn_FString8_Append // @desc Append a string to the fixed string. On failure the string is // appended to but truncated ensuring null-termination. @@ -410,23 +409,23 @@ DQN_API Dqn_String8 Dqn_String8_Copy_ (DQN_LEAK_TRACE_FUNCTION Dq // @param value[in] String to append to the fixed string // determined before appending. // @return True if append was successful, false otherwise. -// + // @proc Dqn_FString8_ToString8 // @desc Convert a fixed string to a string. The string holds a reference to the // fixed string and is invalidated once fixed string is deleted. // @param string[in] The fixed string to create a string from // @return String referencing the contents of `string` -// + // @proc Dqn_FString8_Eq // @desc @see Dqn_String8_Eq -// + // @proc Dqn_FString8_EqString8 // @desc @see Dqn_String8_Eq -// + // @proc Dqn_FString8_EqInsensitive // @desc Compare a string for equality, case insensitive // @see Dqn_String8_Eq -// + // @proc Dqn_FString8_EqString8Insensitive // @desc Compare a string for equality, case insensitive // @see Dqn_String8_Eq @@ -467,6 +466,31 @@ template bool Dqn_FString8_EqFString8Insen #endif // !defined(DQN_NO_FSTRING8) // NOTE: [$STRB] Dqn_String8Builder ================================================================ +// NOTE: API ======================================================================================= +// @proc Dqn_String8Builder_AppendRef, Dqn_String8_AppendCopy, +// Dqn_String8_AppendFV, Dqn_String8_AppendF +// @desc Append a string to the list of strings in the builder. +// +// The string is appended to the builder as follows +// - AppendRef: By reference +// - AppendCopy: By copy using the builder's allocator to copy the string +// - AppendFV, AppendF: Using a format string, allocated using the builder's +// allocator +// +// The string's data must persist whilst the string builder is being used. +// @param builder The builder to append the string to +// @param string The string to append to the builder +// @return True if append was successful, false if parameters are invalid +// or memory allocation failure. + +// @proc Dqn_String8Builder_Build +// @desc Build the list of strings into the final composite string from the +// string builder +// @param builder The string builder to build the string from +// @param allocator The allocator to use to build the string +// @return The string if build was successful, empty string if parameters are +// invalid or memory allocation failure. + struct Dqn_String8Builder { Dqn_Allocator allocator; ///< Allocator to use to back the string list @@ -476,45 +500,50 @@ struct Dqn_String8Builder Dqn_usize count; ///< The number of links in the linked list of strings }; -/// Append a string to the list of strings in the builder by reference. -/// The string's data must persist whilst the string builder is being used. -/// @param builder The builder to append the string to -/// @param string The string to append to the builder -/// @return True if append was successful, false if parameters are invalid -/// or memory allocation failure. -bool Dqn_String8Builder_AppendRef(Dqn_String8Builder *builder, Dqn_String8 string); +#define Dqn_String8Builder_AppendFV(builder, fmt, args) Dqn_String8Builder_AppendFV_(DQN_LEAK_TRACE builder, fmt, args) +DQN_API bool Dqn_String8Builder_AppendF (Dqn_String8Builder *builder, char const *fmt, ...); +DQN_API bool Dqn_String8Builder_AppendRef (Dqn_String8Builder *builder, Dqn_String8 string); +DQN_API bool Dqn_String8Builder_AppendCopy(Dqn_String8Builder *builder, Dqn_String8 string); +DQN_API Dqn_String8 Dqn_String8Builder_Build (Dqn_String8Builder const *builder, Dqn_Allocator allocator); -/// Append a string to the list of strings in the builder by copy. -/// The string is copied using the builder's allocator before appending. -/// @param builder The builder to append the string to -/// @param string The string to append to the builder -/// @return True if append was successful, false if parameters are invalid -/// or memory allocation failure. -bool Dqn_String8Builder_AppendCopy(Dqn_String8Builder *builder, Dqn_String8 string); - -/// @copydoc Dqn_String8Builder_AppendF -/// @param args The variable argument list to use in the format string -#define Dqn_String8Builder_AppendFV(builder, fmt, args) Dqn_String8Builder_AppendFV_(DQN_LEAK_TRACE builder, fmt, args) -bool Dqn_String8Builder_AppendFV_(DQN_LEAK_TRACE_FUNCTION Dqn_String8Builder *builder, char const *fmt, va_list args); - -/// Append a printf-style format string to the list of strings in the builder. -/// @param builder The builder to append the string to -/// @param fmt The format string to use -/// @return True if append was successful, false if parameters are invalid -/// or memory allocation failure. -bool Dqn_String8Builder_AppendF(Dqn_String8Builder *builder, char const *fmt, ...); - -/// Build the list of strings into the final composite string from the string -/// builder -/// @param builder The string builder to build the string from -/// @param allocator The allocator to use to build the string -/// @return The string if build was successful, empty string if parameters are -/// invalid or memory allocation failure. -Dqn_String8 Dqn_String8Builder_Build(Dqn_String8Builder const *builder, Dqn_Allocator allocator); +// NOTE: Internal ================================================================================== +DQN_API bool Dqn_String8Builder_AppendFV_ (DQN_LEAK_TRACE_FUNCTION Dqn_String8Builder *builder, char const *fmt, va_list args); #if !defined(DQN_NO_JSON_BUILDER) // NOTE: [$JSON] Dqn_JSONBuilder =================================================================== +// Basic helper class to construct JSON output to a string // TODO(dqn): We need to write tests for this +// +// NOTE: API ======================================================================================= +// @proc Dqn_JSONBuilder_Build +// @desc Convert the internal JSON buffer in the builder into a string. +// @param[in] arena The allocator to use to build the string + +// @proc Dqn_JSONBuilder_KeyValue, Dqn_JSONBuilder_KeyValueF +// @desc Add a JSON key value pair untyped. The value is emitted directly +// without checking the contents of value. +// +// All other functions internally call into this function which is the main +// workhorse of the builder. + +// @proc Dqn_JSON_Builder_ObjectEnd +// @desc End a JSON object in the builder, generates internally a '}' string + +// @proc Dqn_JSON_Builder_ArrayEnd +// @desc End a JSON array in the builder, generates internally a ']' string + +// @proc Dqn_JSONBuilder_LiteralNamed +// @desc Add a named JSON key-value object whose value is directly written to +// the following '"": ' (e.g. useful for emitting the 'null' +// value) + +// @proc Dqn_JSONBuilder_U64Named, Dqn_JSONBuilder_U64, +// Dqn_JSONBuilder_I64Named, Dqn_JSONBuilder_I64, +// Dqn_JSONBuilder_F64Named, Dqn_JSONBuilder_F64, +// Dqn_JSONBuilder_BoolNamed, Dqn_JSONBuilder_Bool, +// @desc Add the named JSON data type as a key-value object. Generates +// internally the string '"": ' + enum Dqn_JSONBuilderItem { Dqn_JSONBuilderItem_Empty, Dqn_JSONBuilderItem_OpenContainer, @@ -522,7 +551,6 @@ enum Dqn_JSONBuilderItem { Dqn_JSONBuilderItem_KeyValue, }; -/// Basic helper class to construct JSON string output struct Dqn_JSONBuilder { bool use_stdout; ///< When set, ignore the string builder and dump immediately to stdout Dqn_String8Builder string_builder; ///< (Internal) @@ -548,82 +576,29 @@ struct Dqn_JSONBuilder { Dqn_JSONBuilder_ArrayEnd(builder)) -/// Initialise a JSON builder -Dqn_JSONBuilder Dqn_JSONBuilder_Init(Dqn_Allocator allocator, int spaces_per_indent); +DQN_API Dqn_JSONBuilder Dqn_JSONBuilder_Init (Dqn_Allocator allocator, int spaces_per_indent); +DQN_API Dqn_String8 Dqn_JSONBuilder_Build (Dqn_JSONBuilder const *builder, Dqn_Allocator allocator); +DQN_API void Dqn_JSONBuilder_KeyValue (Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value); +DQN_API void Dqn_JSONBuilder_KeyValueF (Dqn_JSONBuilder *builder, Dqn_String8 key, char const *value_fmt, ...); +DQN_API void Dqn_JSONBuilder_ObjectBeginNamed(Dqn_JSONBuilder *builder, Dqn_String8 name); +DQN_API void Dqn_JSONBuilder_ObjectEnd (Dqn_JSONBuilder *builder); +DQN_API void Dqn_JSONBuilder_ArrayBeginNamed (Dqn_JSONBuilder *builder, Dqn_String8 name); +DQN_API void Dqn_JSONBuilder_ArrayEnd (Dqn_JSONBuilder *builder); +DQN_API void Dqn_JSONBuilder_StringNamed (Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value); +DQN_API void Dqn_JSONBuilder_LiteralNamed (Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value); +DQN_API void Dqn_JSONBuilder_U64Named (Dqn_JSONBuilder *builder, Dqn_String8 key, uint64_t value); +DQN_API void Dqn_JSONBuilder_I64Named (Dqn_JSONBuilder *builder, Dqn_String8 key, int64_t value); +DQN_API void Dqn_JSONBuilder_F64Named (Dqn_JSONBuilder *builder, Dqn_String8 key, double value, int decimal_places); +DQN_API void Dqn_JSONBuilder_BoolNamed (Dqn_JSONBuilder *builder, Dqn_String8 key, bool value); -/// Convert the internal JSON buffer in the builder into a string. -/// -/// @param[in] arena The allocator to use to build the string -Dqn_String8 Dqn_JSONBuilder_Build(Dqn_JSONBuilder const *builder, Dqn_Allocator allocator); - -/// Add a JSON key value pair untyped. The value is emitted directly without -/// checking the contents of value. -/// -/// All other functions internally call into this function which is the main -/// workhorse of the builder. -void Dqn_JSONBuilder_KeyValue(Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value); - -void Dqn_JSONBuilder_KeyValueF(Dqn_JSONBuilder *builder, Dqn_String8 key, char const *value_fmt, ...); - -/// Begin a named JSON object for writing into in the builder -/// -/// Generates internally a string like '"": {' -void Dqn_JSONBuilder_ObjectBeginNamed(Dqn_JSONBuilder *builder, Dqn_String8 name); -#define Dqn_JSONBuilder_ObjectBegin(builder) Dqn_JSONBuilder_ObjectBeginNamed(builder, DQN_STRING8("")) - -/// End a JSON object for writing into in the builder -/// -/// Generates internally a string like '}' -void Dqn_JSONBuilder_ObjectEnd(Dqn_JSONBuilder *builder); - -/// Begin a named JSON array for writing into in the builder -/// -/// Generates internally a string like '"": [' -void Dqn_JSONBuilder_ArrayBeginNamed(Dqn_JSONBuilder *builder, Dqn_String8 name); -#define Dqn_JSONBuilder_ArrayBegin(builder) Dqn_JSONBuilder_ArrayBeginNamed(builder, DQN_STRING8("")) - -/// Begin a named JSON array for writing into in the builder -/// -/// Generates internally a string like ']' -void Dqn_JSONBuilder_ArrayEnd(Dqn_JSONBuilder *builder); - -/// Add a named JSON string key-value object -/// -/// Generates internally a string like '"": ""' -void Dqn_JSONBuilder_StringNamed(Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value); -#define Dqn_JSONBuilder_String(builder, value) Dqn_JSONBuilder_StringNamed(builder, DQN_STRING8(""), value) - -/// Add a named JSON key-value object whose value is directly written -/// -/// Generates internally a string like '"": ' (e.g. useful for -/// emitting the 'null' value) -void Dqn_JSONBuilder_LiteralNamed(Dqn_JSONBuilder *builder, Dqn_String8 key, Dqn_String8 value); -#define Dqn_JSONBuilder_Literal(builder, value) Dqn_JSONBuilder_LiteralNamed(builder, DQN_STRING8(""), value) - -/// Add a named JSON u64 key-value object -/// -/// Generates internally a string like '"": ' -void Dqn_JSONBuilder_U64Named(Dqn_JSONBuilder *builder, Dqn_String8 key, uint64_t value); -#define Dqn_JSONBuilder_U64(builder, value) Dqn_JSONBuilder_U64Named(builder, DQN_STRING8(""), value) - -/// Add a JSON i64 key-value object -/// -/// Generates internally a string like '"": ' -void Dqn_JSONBuilder_I64Named(Dqn_JSONBuilder *builder, Dqn_String8 key, int64_t value); -#define Dqn_JSONBuilder_I64(builder, value) Dqn_JSONBuilder_I64Named(builder, DQN_STRING8(""), value) - -/// Add a JSON f64 key-value object -/// -/// Generates internally a string like '"": ' -/// @param[in] decimal_places The number of decimal places to preserve. Maximum 16 -void Dqn_JSONBuilder_F64Named(Dqn_JSONBuilder *builder, Dqn_String8 key, double value, int decimal_places); -#define Dqn_JSONBuilder_F64(builder, value) Dqn_JSONBuilder_F64Named(builder, DQN_STRING8(""), value) - -/// Add a JSON bool key-value object -/// -/// Generates internally a string like '"": ' -void Dqn_JSONBuilder_BoolNamed(Dqn_JSONBuilder *builder, Dqn_String8 key, bool value); -#define Dqn_JSONBuilder_Bool(builder, value) Dqn_JSONBuilder_BoolNamed(builder, DQN_STRING8(""), value) +#define Dqn_JSONBuilder_ObjectBegin(builder) Dqn_JSONBuilder_ObjectBeginNamed(builder, DQN_STRING8("")) +#define Dqn_JSONBuilder_ArrayBegin(builder) Dqn_JSONBuilder_ArrayBeginNamed(builder, DQN_STRING8("")) +#define Dqn_JSONBuilder_String(builder, value) Dqn_JSONBuilder_StringNamed(builder, DQN_STRING8(""), value) +#define Dqn_JSONBuilder_Literal(builder, value) Dqn_JSONBuilder_LiteralNamed(builder, DQN_STRING8(""), value) +#define Dqn_JSONBuilder_U64(builder, value) Dqn_JSONBuilder_U64Named(builder, DQN_STRING8(""), value) +#define Dqn_JSONBuilder_I64(builder, value) Dqn_JSONBuilder_I64Named(builder, DQN_STRING8(""), value) +#define Dqn_JSONBuilder_F64(builder, value) Dqn_JSONBuilder_F64Named(builder, DQN_STRING8(""), value) +#define Dqn_JSONBuilder_Bool(builder, value) Dqn_JSONBuilder_BoolNamed(builder, DQN_STRING8(""), value) #endif // !defined(DQN_NO_JSON_BUIDLER) // NOTE: [$CHAR] Dqn_Char ========================================================================== @@ -643,9 +618,7 @@ DQN_API int Dqn_UTF16_EncodeCodepoint(uint16_t utf16[2], uint32_t codepoint); #if !defined(DQN_NO_HEX) // NOTE: [$BHEX] Dqn_Bin =========================================================================== -// -// NOTE: API -// +// NOTE: API ======================================================================================= // @proc Dqn_Bin_U64ToHexU64String // @desc Convert a 64 bit number to a hex string // @param[in] number Number to convert to hexadecimal representation @@ -653,21 +626,21 @@ DQN_API int Dqn_UTF16_EncodeCodepoint(uint16_t utf16[2], uint32_t codepoint); // output of the hexadecimal string. // @return The hexadecimal representation of the number. This string is always // null-terminated. -// + // @proc Dqn_Bin_U64ToHex // @copybrief Dqn_Bin_U64ToHexU64String -// + // @param[in] allocator The memory allocator to use for the memory of the // hexadecimal string. // @copyparams Dqn_Bin_U64ToHexU64String -// + // @proc Dqn_Bin_HexBufferToU64 // @desc Convert a hexadecimal string a 64 bit value. // Asserts if the hex string is too big to be converted into a 64 bit number. -// + // @proc Dqn_Bin_HexToU64 // @copydoc Dqn_Bin_HexToU64 -// + // @proc Dqn_Bin_BytesToHexBuffer // @desc Convert a binary buffer into its hex representation into dest. // @@ -676,15 +649,15 @@ DQN_API int Dqn_UTF16_EncodeCodepoint(uint16_t utf16[2], uint32_t codepoint); // // @return True if the conversion into the dest buffer was successful, false // otherwise (e.g. invalid arguments). -// + // @proc Dqn_Bin_BytesToHexBufferArena // @desc Convert a series of bytes into a string // @return A null-terminated hex string, null pointer if allocation failed -// + // @proc Dqn_Bin_BytesToHexArena // @copydoc Dqn_Bin_BytesToHexBufferArena // @return A hex string, the string is invalid if conversion failed. -// + // @proc Dqn_Bin_HexBufferToBytes // @desc Convert a hex string into binary at `dest`. // @@ -700,20 +673,20 @@ DQN_API int Dqn_UTF16_EncodeCodepoint(uint16_t utf16[2], uint32_t codepoint); // // @return The number of bytes written to `dest_size`, this value will *never* // be greater than `dest_size`. -// + // @proc Dqn_Bin_HexToBytes // @desc String8 variant of @see Dqn_Bin_HexBufferToBytes -// + // @proc Dqn_Bin_StringHexBufferToBytesUnchecked // @desc Unchecked variant of @see Dqn_Bin_HexBufferToBytes // // This function skips some string checks, it assumes the hex is a valid hex // stream and that the arguments are valid e.g. no trimming or 0x prefix // stripping is performed -// + // @proc Dqn_Bin_String // @desc String8 variant of @see Dqn_Bin_HexBufferToBytesUnchecked -// + // @proc Dqn_Bin_HexBufferToBytesArena // Dynamic allocating variant of @see Dqn_Bin_HexBufferToBytesUnchecked // @@ -723,7 +696,7 @@ DQN_API int Dqn_UTF16_EncodeCodepoint(uint16_t utf16[2], uint32_t codepoint); // @param[out] real_size The size of the buffer returned by the function // // @return The byte representation of the hex string. -// + // @proc Dqn_Bin_HexToBytesArena // @copybrief Dqn_Bin_HexBufferToBytesArena // @@ -731,6 +704,7 @@ DQN_API int Dqn_UTF16_EncodeCodepoint(uint16_t utf16[2], uint32_t codepoint); // @param[in] hex Hex string to convert into bytes // // @return The byte representation of the hex string. + struct Dqn_BinHexU64String { char data[2 /*0x*/ + 16 /*hex*/ + 1 /*null-terminator*/]; @@ -765,12 +739,20 @@ DQN_API Dqn_usize Dqn_Bin_HexToBytes (Dqn_String8 hex, DQN_API Dqn_String8 Dqn_Bin_HexToBytesArena (Dqn_Arena *arena, Dqn_String8 hex); #endif // !defined(DQN_NO_HEX) -/// Write the format string to the buffer truncating with a trailing ".." if -/// there is insufficient space in the buffer followed by null-terminating the -/// buffer (uses stb_sprintf underneath). -/// @return The size of the string written to the buffer *not* including the -/// null-terminator. -DQN_API int Dqn_SNPrintF2DotsOnOverflow(char *buffer, int size, char const *fmt, ...); +// NOTE: Other ===================================================================================== +// NOTE: API ======================================================================================= +// @proc Dqn_SNPrintFDotTruncate +// @desc Write the format string to the buffer truncating with a trailing ".." +// if there is insufficient space in the buffer followed by null-terminating +// the buffer (uses stb_sprintf underneath). +// @return The size of the string written to the buffer *not* including the +// null-terminator. +// +// @proc Dqn_U64ToString +// @desc Convert a 64 bit unsigned value to its string representation. +// @param[in] val Value to convert into a string +// @param[in] separator The separator to insert every 3 digits. Set this to +// 0 if no separator is desired. struct Dqn_U64String { @@ -778,11 +760,8 @@ struct Dqn_U64String uint8_t size; }; -/// Convert a 64 bit unsigned value to its string representation. -/// @param[in] val Value to convert into a string -/// @param[in] separator The separator to insert every 3 digits. Set this to -/// 0 if no separator is desired. -DQN_API Dqn_U64String Dqn_U64ToString(uint64_t val, char separator); +DQN_API int Dqn_SNPrintFDotTruncate(char *buffer, int size, char const *fmt, ...); +DQN_API Dqn_U64String Dqn_U64ToString (uint64_t val, char separator); // NOTE: [$STBS] stb_sprintf ======================================================================= // stb_sprintf - v1.10 - public domain snprintf() implementation