Simplify, simplify, simplify. Kill code that was unloved and unused

This commit is contained in:
2026-06-18 22:11:30 +10:00
parent b813543659
commit ab4eaa5bb3
32 changed files with 3637 additions and 9925 deletions
File diff suppressed because it is too large Load Diff
+310 -513
View File
@@ -1,4 +1,4 @@
// Generated by the DN single header generator 2026-06-18 18:20:05 // Generated by the DN single header generator 2026-06-18 22:11:00
#if !defined(DN_H) #if !defined(DN_H)
#define DN_H #define DN_H
@@ -143,17 +143,23 @@
// Tracing incurs an additional much heavier performance penalty than the UAF guard due to // Tracing incurs an additional much heavier performance penalty than the UAF guard due to
// the stacktrace that is stored per region to report to the user when a UAF guard violation // the stacktrace that is stored per region to report to the user when a UAF guard violation
// occurs. // occurs.
//
// Str8 AVX512F variants
// We have some AVX512 string functions that can be enabled by defining the following
//
// #define DN_STR8_AVX512F 1
// DN: Single header generator commented out => #include "Base/dn_base.h" // DN: Single header generator commented out => #include "Base/dn_base.h"
#if !defined(DN_BASE_H) #if !defined(DN_BASE_H)
#define DN_BASE_H #define DN_BASE_H
// DN: Single header generator commented out => #if defined(_CLANGD) // DN: Single header generator commented out => #if defined(_CLANGD)
// #define DN_STR8_AVX512F 1
// #include "../dn.h" // #include "../dn.h"
// #endif // #endif
// NOTE: Compiler identification // NOTE: Compiler identification
// Warning! Order is important here, clang-cl on Windows defines _MSC_VER // NOTE: Warning! Order is important here, clang-cl on Windows defines _MSC_VER
#if defined(_MSC_VER) #if defined(_MSC_VER)
#if defined(__clang__) #if defined(__clang__)
#define DN_COMPILER_CLANG_CL #define DN_COMPILER_CLANG_CL
@@ -168,7 +174,8 @@
#endif #endif
// NOTE: __has_feature // NOTE: __has_feature
// MSVC for example does not support the feature detection macro for instance so we compile it out // NOTE: MSVC for example does not support the feature detection macro for instance so we compile it
// out
#if defined(__has_feature) #if defined(__has_feature)
#define DN_HAS_FEATURE(expr) __has_feature(expr) #define DN_HAS_FEATURE(expr) __has_feature(expr)
#else #else
@@ -176,7 +183,7 @@
#endif #endif
// NOTE: __has_builtin // NOTE: __has_builtin
// MSVC for example does not support the feature detection macro for instance so we compile it out // NOTE: MSVC for example does not support the feature detection macro for instance so we compile it out
#if defined(__has_builtin) #if defined(__has_builtin)
#define DN_HAS_BUILTIN(expr) __has_builtin(expr) #define DN_HAS_BUILTIN(expr) __has_builtin(expr)
#else #else
@@ -391,15 +398,6 @@
typedef char DN_TokenCombine(static_assert_dummy__, __LINE__)[(expr) ? 1 : -1]; \ typedef char DN_TokenCombine(static_assert_dummy__, __LINE__)[(expr) ? 1 : -1]; \
DN_GCC_WARNING_POP DN_GCC_WARNING_POP
#define DN_Check(expr) DN_CheckF(expr, "")
#if defined(DN_NO_CHECK_BREAK)
#define DN_CheckF(expr, fmt, ...) \
((expr) ? true : (DN_LogWarningF(fmt, ##__VA_ARGS__), false))
#else
#define DN_CheckF(expr, fmt, ...) \
((expr) ? true : (DN_LogErrorF(fmt, ##__VA_ARGS__), DN_StackTracePrint(128 /*limit*/), DN_DebugBreak, false))
#endif
#if defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) #if defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64)
#define DN_64_BIT #define DN_64_BIT
#else #else
@@ -3835,7 +3833,7 @@ DN_API DN_I16 DN_SaturateCastI64ToI16
DN_API DN_I32 DN_SaturateCastI64ToI32 (DN_I64 val); DN_API DN_I32 DN_SaturateCastI64ToI32 (DN_I64 val);
DN_API DN_UInt DN_SaturateCastI64ToUInt (DN_I64 val); DN_API DN_UInt DN_SaturateCastI64ToUInt (DN_I64 val);
DN_API DN_ISize DN_SaturateCastI64ToUSize (DN_I64 val); DN_API DN_USize DN_SaturateCastI64ToUSize (DN_I64 val);
DN_API DN_U8 DN_SaturateCastI64ToU8 (DN_I64 val); DN_API DN_U8 DN_SaturateCastI64ToU8 (DN_I64 val);
DN_API DN_U16 DN_SaturateCastI64ToU16 (DN_I64 val); DN_API DN_U16 DN_SaturateCastI64ToU16 (DN_I64 val);
DN_API DN_U32 DN_SaturateCastI64ToU32 (DN_I64 val); DN_API DN_U32 DN_SaturateCastI64ToU32 (DN_I64 val);
@@ -4044,12 +4042,14 @@ DN_API DN_USize DN_CStr16Size
#define DN_Str8Lit(c_str) DN_Literal(DN_Str8){(char *)(c_str), sizeof(c_str) - 1} #define DN_Str8Lit(c_str) DN_Literal(DN_Str8){(char *)(c_str), sizeof(c_str) - 1}
#define DN_Str8PrintFmt(string) (int)((string).size), (string).data #define DN_Str8PrintFmt(string) (int)((string).size), (string).data
#define DN_Str8FromPtr(data, size) DN_Literal(DN_Str8){(char *)(data), (DN_USize)(size)} #define DN_Str8FromPtr(data, size) DN_Literal(DN_Str8){(char *)(data), (DN_USize)(size)}
#define DN_Str8FromStruct(ptr) DN_Str8FromPtr((ptr)->data, (ptr)->size) #define DN_Str8FromStruct(ptr) DN_Str8FromPtr((ptr)->data, (ptr)->size)
#define DN_Str8FromLitArray(c_array) DN_Str8FromPtr(c_array, DN_ArrayCountU(c_array)) #define DN_Str8FromLitArray(c_array) DN_Str8FromPtr(c_array, DN_ArrayCountU(c_array))
DN_API DN_Str8 DN_Str8AllocAllocator (DN_USize size, DN_ZMem z_mem, DN_Allocator allocator); DN_API DN_Str8 DN_Str8AllocAllocator (DN_USize size, DN_ZMem z_mem, DN_Allocator allocator);
DN_API DN_Str8 DN_Str8AllocArena (DN_USize size, DN_ZMem z_mem, DN_Arena *arena); DN_API DN_Str8 DN_Str8AllocArena (DN_USize size, DN_ZMem z_mem, DN_Arena *arena);
DN_API DN_Str8 DN_Str8AllocPool (DN_USize size, DN_Pool *pool); DN_API DN_Str8 DN_Str8AllocPool (DN_USize size, DN_Pool *pool);
DN_API DN_Str8 DN_Str8FromCStr8 (char const *src); DN_API DN_Str8 DN_Str8FromCStr8 (char const *src);
DN_API DN_Str8 DN_Str8FromCStr8Arena (char const *src, DN_Arena *arena); DN_API DN_Str8 DN_Str8FromCStr8Arena (char const *src, DN_Arena *arena);
DN_API DN_Str8 DN_Str8FromPtrArena (void const *data, DN_USize size, DN_Arena *arena); DN_API DN_Str8 DN_Str8FromPtrArena (void const *data, DN_USize size, DN_Arena *arena);
@@ -4063,6 +4063,7 @@ DN_API DN_Str8 DN_Str8FromFmtAllocator
DN_API DN_Str8 DN_Str8FromFmtArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_Str8 DN_Str8FromFmtArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...);
DN_API DN_Str8 DN_Str8FromFmtVPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args); DN_API DN_Str8 DN_Str8FromFmtVPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args);
DN_API DN_Str8 DN_Str8FromFmtPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_Str8 DN_Str8FromFmtPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...);
DN_API DN_Str8x16 DN_Str8x16FromFmt (DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_Str8x16 DN_Str8x16FromFmt (DN_FMT_ATTRIB char const *fmt, ...);
DN_API DN_Str8x16 DN_Str8x16FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); DN_API DN_Str8x16 DN_Str8x16FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args);
DN_API DN_Str8x32 DN_Str8x32FromFmt (DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_Str8x32 DN_Str8x32FromFmt (DN_FMT_ATTRIB char const *fmt, ...);
@@ -4091,6 +4092,7 @@ DN_API void DN_Str8x512AppendFmt
DN_API void DN_Str8x512AppendFmtV (DN_Str8x512 *str, DN_FMT_ATTRIB char const *fmt, va_list args); DN_API void DN_Str8x512AppendFmtV (DN_Str8x512 *str, DN_FMT_ATTRIB char const *fmt, va_list args);
DN_API void DN_Str8x1024AppendFmt (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, ...); DN_API void DN_Str8x1024AppendFmt (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, ...);
DN_API void DN_Str8x1024AppendFmtV (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, va_list args); DN_API void DN_Str8x1024AppendFmtV (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, va_list args);
DN_API DN_Str8x32 DN_Str8x32FromU64 (DN_U64 val, char separator); DN_API DN_Str8x32 DN_Str8x32FromU64 (DN_U64 val, char separator);
DN_API bool DN_Str8IsAll (DN_Str8 string, DN_Str8IsAllType is_all); DN_API bool DN_Str8IsAll (DN_Str8 string, DN_Str8IsAllType is_all);
DN_API char * DN_Str8End (DN_Str8 string); DN_API char * DN_Str8End (DN_Str8 string);
@@ -4115,6 +4117,7 @@ DN_API bool DN_Str8StartsWithInsensitive
DN_API bool DN_Str8EndsWith (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive); DN_API bool DN_Str8EndsWith (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive);
DN_API bool DN_Str8EndsWithInsensitive (DN_Str8 string, DN_Str8 prefix); DN_API bool DN_Str8EndsWithInsensitive (DN_Str8 string, DN_Str8 prefix);
DN_API bool DN_Str8HasChar (DN_Str8 string, char ch); DN_API bool DN_Str8HasChar (DN_Str8 string, char ch);
DN_API DN_Str8 DN_Str8TrimPrefix (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive); DN_API DN_Str8 DN_Str8TrimPrefix (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive);
DN_API DN_Str8 DN_Str8TrimHexPrefix (DN_Str8 string); DN_API DN_Str8 DN_Str8TrimHexPrefix (DN_Str8 string);
DN_API DN_Str8 DN_Str8TrimSuffix (DN_Str8 string, DN_Str8 suffix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive); DN_API DN_Str8 DN_Str8TrimSuffix (DN_Str8 string, DN_Str8 suffix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive);
@@ -4123,6 +4126,7 @@ DN_API DN_Str8 DN_Str8TrimHeadWhitespace
DN_API DN_Str8 DN_Str8TrimTailWhitespace (DN_Str8 string); DN_API DN_Str8 DN_Str8TrimTailWhitespace (DN_Str8 string);
DN_API DN_Str8 DN_Str8TrimWhitespaceAround (DN_Str8 string); DN_API DN_Str8 DN_Str8TrimWhitespaceAround (DN_Str8 string);
DN_API DN_Str8 DN_Str8TrimByteOrderMark (DN_Str8 string); DN_API DN_Str8 DN_Str8TrimByteOrderMark (DN_Str8 string);
DN_API DN_Str8 DN_Str8FileNameFromPath (DN_Str8 path); DN_API DN_Str8 DN_Str8FileNameFromPath (DN_Str8 path);
DN_API DN_Str8 DN_Str8FileNameNoExtension (DN_Str8 path); DN_API DN_Str8 DN_Str8FileNameNoExtension (DN_Str8 path);
DN_API DN_Str8 DN_Str8FilePathNoExtension (DN_Str8 path); DN_API DN_Str8 DN_Str8FilePathNoExtension (DN_Str8 path);
@@ -4146,6 +4150,15 @@ DN_API DN_Str8 DN_Str8LineBreakAllocator
DN_API DN_Str8 DN_Str8LineBreakArena (DN_Str8 src, DN_USize desired_width, DN_Str8 delimiter, DN_Str8LineBreakMode mode, DN_Arena *arena); DN_API DN_Str8 DN_Str8LineBreakArena (DN_Str8 src, DN_USize desired_width, DN_Str8 delimiter, DN_Str8LineBreakMode mode, DN_Arena *arena);
DN_API DN_Str8 DN_Str8Table (DN_Str8 const* rows, DN_USize num_rows, DN_USize num_cols, DN_Str8TableFlags flags, DN_Arena *arena); DN_API DN_Str8 DN_Str8Table (DN_Str8 const* rows, DN_USize num_rows, DN_USize num_cols, DN_Str8TableFlags flags, DN_Arena *arena);
#if DN_STR8_AVX512F
DN_API DN_Str8FindResult DN_Str8FindStr8AVX512F (DN_Str8 string, DN_Str8 find);
DN_API DN_Str8FindResult DN_Str8FindLastStr8AVX512F (DN_Str8 string, DN_Str8 find);
DN_API DN_Str8BSplitResult DN_Str8BSplitAVX512F (DN_Str8 string, DN_Str8 find);
DN_API DN_Str8BSplitResult DN_Str8BSplitLastAVX512F (DN_Str8 string, DN_Str8 find);
DN_API DN_USize DN_Str8SplitAVX512F (DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitFlags flags);
DN_API DN_Str8Slice DN_Str8SplitAllocAVX512F (DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitFlags flags);
#endif
DN_API DN_Str8 DN_Str8SliceRender (DN_Str8Slice array, DN_Str8 separator, DN_Arena *arena); DN_API DN_Str8 DN_Str8SliceRender (DN_Str8Slice array, DN_Str8 separator, DN_Arena *arena);
DN_API DN_Str8 DN_Str8RenderSpaceSep (DN_Str8Slice array, DN_Arena *arena); DN_API DN_Str8 DN_Str8RenderSpaceSep (DN_Str8Slice array, DN_Arena *arena);
DN_API int DN_Str8CompareNatural (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); DN_API int DN_Str8CompareNatural (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case);
@@ -4627,8 +4640,8 @@ DN_API DN_M4 DN_M4MulF
DN_API DN_M4 DN_M4DivF (DN_M4 lhs, DN_F32 rhs); DN_API DN_M4 DN_M4DivF (DN_M4 lhs, DN_F32 rhs);
DN_API DN_Str8x256 DN_M4ColumnMajorString (DN_M4 mat); DN_API DN_Str8x256 DN_M4ColumnMajorString (DN_M4 mat);
DN_API bool operator== (DN_M2x3 const &lhs, DN_M2x3 const &rhs); DN_API bool DN_M2x3Eq (DN_M2x3 const *lhs, DN_M2x3 const *rhs);
DN_API bool operator!= (DN_M2x3 const &lhs, DN_M2x3 const &rhs); DN_API bool DN_M2x3NotEq (DN_M2x3 const *lhs, DN_M2x3 const *rhs);
DN_API DN_M2x3 DN_M2x3Identity (); DN_API DN_M2x3 DN_M2x3Identity ();
DN_API DN_M2x3 DN_M2x3Translate (DN_V2F32 offset); DN_API DN_M2x3 DN_M2x3Translate (DN_V2F32 offset);
DN_API DN_V2F32 DN_M2x3ScaleGet (DN_M2x3 m2x3); DN_API DN_V2F32 DN_M2x3ScaleGet (DN_M2x3 m2x3);
@@ -4648,7 +4661,6 @@ DN_API DN_Rect DN_M2x3MulRect
#define DN_RectFrom4N(x, y, w, h) DN_Literal(DN_Rect){DN_Literal(DN_V2F32){{x, y}}, DN_Literal(DN_V2F32){{w, h}}} #define DN_RectFrom4N(x, y, w, h) DN_Literal(DN_Rect){DN_Literal(DN_V2F32){{x, y}}, DN_Literal(DN_V2F32){{w, h}}}
#define DN_RectZero DN_RectFrom4N(0, 0, 0, 0) #define DN_RectZero DN_RectFrom4N(0, 0, 0, 0)
DN_API bool operator== (const DN_Rect& lhs, const DN_Rect& rhs);
DN_API DN_V2F32 DN_RectCenter (DN_Rect rect); DN_API DN_V2F32 DN_RectCenter (DN_Rect rect);
DN_API bool DN_RectContainsPoint (DN_Rect rect, DN_V2F32 p); DN_API bool DN_RectContainsPoint (DN_Rect rect, DN_V2F32 p);
DN_API bool DN_RectContainsRect (DN_Rect a, DN_Rect b); DN_API bool DN_RectContainsRect (DN_Rect a, DN_Rect b);
@@ -5115,9 +5127,10 @@ DN_API void DN_RingWrite (DN_Rin
DN_API void DN_RingRead (DN_Ring *ring, void *dest, DN_U64 dest_size); DN_API void DN_RingRead (DN_Ring *ring, void *dest, DN_U64 dest_size);
#define DN_RingReadStruct(ring, dest) DN_RingRead((ring), (dest), sizeof(*(dest))) #define DN_RingReadStruct(ring, dest) DN_RingRead((ring), (dest), sizeof(*(dest)))
// TODO: Replace with a C-style hash table
#if defined(__cplusplus)
DN_U32 const DN_DS_MAP_DEFAULT_HASH_SEED = 0x8a1ced49; DN_U32 const DN_DS_MAP_DEFAULT_HASH_SEED = 0x8a1ced49;
DN_U32 const DN_DS_MAP_SENTINEL_SLOT = 0; DN_U32 const DN_DS_MAP_SENTINEL_SLOT = 0;
template <typename T> DN_DSMap<T> DN_DSMapInit (DN_Arena *arena, DN_U32 size, DN_DSMapFlags flags); template <typename T> DN_DSMap<T> DN_DSMapInit (DN_Arena *arena, DN_U32 size, DN_DSMapFlags flags);
template <typename T> void DN_DSMapDeinit (DN_DSMap<T> *map, DN_ZMem z_mem); template <typename T> void DN_DSMapDeinit (DN_DSMap<T> *map, DN_ZMem z_mem);
template <typename T> bool DN_DSMapIsValid (DN_DSMap<T> const *map); template <typename T> bool DN_DSMapIsValid (DN_DSMap<T> const *map);
@@ -5144,7 +5157,240 @@ template <typename T> DN_DSMapKey DN_DSMapKeyStr8 (DN_DSMap
DN_API DN_DSMapKey DN_DSMapKeyU64NoHash (DN_U64 u64); DN_API DN_DSMapKey DN_DSMapKeyU64NoHash (DN_U64 u64);
DN_API bool DN_DSMapKeyEquals (DN_DSMapKey lhs, DN_DSMapKey rhs); DN_API bool DN_DSMapKeyEquals (DN_DSMapKey lhs, DN_DSMapKey rhs);
DN_API bool operator== (DN_DSMapKey lhs, DN_DSMapKey rhs); DN_API bool operator== (DN_DSMapKey lhs, DN_DSMapKey rhs);
#endif
enum DN_BinPackMode
{
DN_BinPackMode_Serialise,
DN_BinPackMode_Deserialise,
};
struct DN_BinPack
{
DN_Str8Builder writer;
DN_Str8 read;
DN_USize read_index;
};
DN_API bool DN_BinPackIsEndOfReadStream(DN_BinPack const *pack);
DN_API void DN_BinPackUSize (DN_BinPack *pack, DN_BinPackMode mode, DN_USize *item);
DN_API void DN_BinPackU64 (DN_BinPack *pack, DN_BinPackMode mode, DN_U64 *item);
DN_API void DN_BinPackU32 (DN_BinPack *pack, DN_BinPackMode mode, DN_U32 *item);
DN_API void DN_BinPackU16 (DN_BinPack *pack, DN_BinPackMode mode, DN_U16 *item);
DN_API void DN_BinPackU8 (DN_BinPack *pack, DN_BinPackMode mode, DN_U8 *item);
DN_API void DN_BinPackI64 (DN_BinPack *pack, DN_BinPackMode mode, DN_I64 *item);
DN_API void DN_BinPackI32 (DN_BinPack *pack, DN_BinPackMode mode, DN_I32 *item);
DN_API void DN_BinPackI16 (DN_BinPack *pack, DN_BinPackMode mode, DN_I16 *item);
DN_API void DN_BinPackI8 (DN_BinPack *pack, DN_BinPackMode mode, DN_I8 *item);
DN_API void DN_BinPackF64 (DN_BinPack *pack, DN_BinPackMode mode, DN_F64 *item);
DN_API void DN_BinPackF32 (DN_BinPack *pack, DN_BinPackMode mode, DN_F32 *item);
DN_API void DN_BinPackV2 (DN_BinPack *pack, DN_BinPackMode mode, DN_V2F32 *item);
DN_API void DN_BinPackV4 (DN_BinPack *pack, DN_BinPackMode mode, DN_V4F32 *item);
DN_API void DN_BinPackBool (DN_BinPack *pack, DN_BinPackMode mode, bool *item);
DN_API void DN_BinPackStr8FromArena (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, DN_Str8 *string);
DN_API void DN_BinPackStr8FromPool (DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, DN_Str8 *string);
DN_API DN_Str8 DN_BinPackStr8FromBuffer (DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max);
DN_API void DN_BinPackBytesFromArena (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, void **ptr, DN_USize *size);
DN_API void DN_BinPackBytesFromPool (DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, void **ptr, DN_USize *size);
DN_API void DN_BinPackCArray (DN_BinPack *pack, DN_BinPackMode mode, void *ptr, DN_USize size);
DN_API void DN_BinPackCBuffer (DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max);
DN_API DN_Str8 DN_BinPackBuild (DN_BinPack const *pack, DN_Arena *arena);
enum DN_CSVSerialise
{
DN_CSVSerialise_Read,
DN_CSVSerialise_Write,
};
struct DN_CSVTokeniser
{
bool bad;
DN_Str8 string;
char delimiter;
char const *it;
bool end_of_line;
};
struct DN_CSVPack
{
DN_Str8Builder write_builder;
DN_USize write_column;
DN_CSVTokeniser read_tokeniser;
};
// NOTE: Data structures to create and parse CSV files, supports Python style escaped quotes (e.g.
// Using "" to escape quotes inside a quoted string).
//
// API
// DN_CSVTokeniserNextN: Reads the next N consecutive fields from the parser. If `column_iterator`
// is `false` then the read of the N consecutive fields does not proceed past the end of the
// current CSV row. If `true` then it reads the next N fields even if reading would progress onto
// the next row.
DN_API DN_CSVTokeniser DN_CSVTokeniserInit (DN_Str8 string, char delimiter);
DN_API bool DN_CSVTokeniserValid (DN_CSVTokeniser *tokeniser);
DN_API bool DN_CSVTokeniserNextRow (DN_CSVTokeniser *tokeniser);
DN_API DN_Str8 DN_CSVTokeniserNextField (DN_CSVTokeniser *tokeniser);
DN_API DN_Str8 DN_CSVTokeniserNextColumn (DN_CSVTokeniser *tokeniser);
DN_API void DN_CSVTokeniserSkipLine (DN_CSVTokeniser *tokeniser);
DN_API int DN_CSVTokeniserNextN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size, bool column_iterator);
DN_API int DN_CSVTokeniserNextColumnN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size);
DN_API int DN_CSVTokeniserNextFieldN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size);
DN_API void DN_CSVTokeniserSkipLineN (DN_CSVTokeniser *tokeniser, int count);
DN_API void DN_CSVPackU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 *value);
DN_API void DN_CSVPackI64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 *value);
DN_API void DN_CSVPackI32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 *value);
DN_API void DN_CSVPackI16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 *value);
DN_API void DN_CSVPackI8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *value);
DN_API void DN_CSVPackU32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 *value);
DN_API void DN_CSVPackU16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 *value);
DN_API void DN_CSVPackBoolAsU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, bool *value);
DN_API void DN_CSVPackStr8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_Str8 *str8, DN_Arena *arena);
DN_API void DN_CSVPackBuffer (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size);
DN_API void DN_CSVPackBufferWithMax (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size, size_t max);
DN_API bool DN_CSVPackNewLine (DN_CSVPack *pack, DN_CSVSerialise serialise);
// TODO: Replace with a C implementation
template <typename T>
using DN_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs);
template <typename T>
bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
enum DN_BinarySearchType
{
// Index of the match. If no match is found, found is set to false and the
// index is set to the index where the match should be inserted/exist, if
// it were in the array
DN_BinarySearchType_Match,
// Index of the first element in the array that is `element >= find`. If no such
// item is found or the array is empty, then, the index is set to the array
// size and found is set to `false`.
//
// For example:
// int array[] = {0, 1, 2, 3, 4, 5};
// DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_LowerBound);
// printf("%zu\n", result.index); // Prints index '4'
DN_BinarySearchType_LowerBound,
// Index of the first element in the array that is `element > find`. If no such
// item is found or the array is empty, then, the index is set to the array
// size and found is set to `false`.
//
// For example:
// int array[] = {0, 1, 2, 3, 4, 5};
// DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_UpperBound);
// printf("%zu\n", result.index); // Prints index '5'
DN_BinarySearchType_UpperBound,
};
struct DN_BinarySearchResult
{
bool found;
DN_USize index;
};
template <typename T> bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
template <typename T> DN_BinarySearchResult DN_BinarySearch (T const *array, DN_USize array_size, T const &find, DN_BinarySearchType type = DN_BinarySearchType_Match, DN_BinarySearchLessThanProc<T> less_than = DN_BinarySearch_DefaultLessThan);
template <typename T>
bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs)
{
bool result = lhs < rhs;
return result;
}
template <typename T>
DN_BinarySearchResult DN_BinarySearch(T const *array,
DN_USize array_size,
T const &find,
DN_BinarySearchType type,
DN_BinarySearchLessThanProc<T> less_than)
{
DN_BinarySearchResult result = {};
if (!array || array_size <= 0 || !less_than)
return result;
T const *end = array + array_size;
T const *first = array;
T const *last = end;
while (first != last) {
DN_USize count = last - first;
T const *it = first + (count / 2);
bool advance_first = false;
if (type == DN_BinarySearchType_UpperBound)
advance_first = !less_than(find, it[0]);
else
advance_first = less_than(it[0], find);
if (advance_first)
first = it + 1;
else
last = it;
}
switch (type) {
case DN_BinarySearchType_Match: {
result.found = first != end && !less_than(find, *first);
} break;
case DN_BinarySearchType_LowerBound: /*FALLTHRU*/
case DN_BinarySearchType_UpperBound: {
result.found = first != end;
} break;
}
result.index = first - array;
return result;
}
enum DN_LeakAllocFlag
{
DN_LeakAllocFlag_Freed = 1 << 0,
DN_LeakAllocFlag_LeakPermitted = 1 << 1,
};
struct DN_LeakAlloc
{
void *ptr; // 8 Pointer to the allocation being tracked
DN_USize size; // 16 Size of the allocation
DN_USize freed_size; // 24 Store the size of the allocation when it is freed
DN_Str8 stack_trace; // 40 Stack trace at the point of allocation
DN_Str8 freed_stack_trace; // 56 Stack trace of where the allocation was freed
DN_U16 flags; // 72 Bit flags from `DN_LeakAllocFlag`
};
// NOTE: We aim to keep the allocation record as light as possible as memory tracking can get
// expensive. Enforce that there is no unexpected padding.
DN_StaticAssert(sizeof(DN_LeakAlloc) == 64 || sizeof(DN_LeakAlloc) == 32); // NOTE: 64 bit vs 32 bit pointers respectively
struct DN_LeakTracker
{
DN_DSMap<DN_LeakAlloc> alloc_table;
DN_TicketMutex alloc_table_mutex;
DN_MemList alloc_table_mem;
DN_Arena alloc_table_arena;
DN_U64 alloc_table_bytes_allocated_for_stack_traces;
};
DN_API void DN_LeakTrackAlloc_ (DN_LeakTracker *leak, void *ptr, DN_USize size, bool alloc_can_leak);
DN_API void DN_LeakTrackDealloc_(DN_LeakTracker *leak, void *ptr);
DN_API void DN_LeakDump_ (DN_LeakTracker *leak);
#if defined(DN_LEAK_TRACKING)
#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) DN_LeakTrackAlloc_(leak, ptr, size, alloc_can_leak)
#define DN_LeakTrackDealloc(leak, ptr) DN_LeakTrackDealloc_(leak, ptr)
#define DN_LeakDump(leak) DN_LeakDump_(leak)
#else
#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0)
#define DN_LeakTrackDealloc(leak, ptr) do { (void)ptr; } while (0)
#define DN_LeakDump(leak) do { } while (0)
#endif
// NOTE: Template implementations
#if defined(__cplusplus) #if defined(__cplusplus)
template <typename T> T *DN_TMemCopyObj(T *dest, T const *src, DN_USize count) template <typename T> T *DN_TMemCopyObj(T *dest, T const *src, DN_USize count)
{ {
@@ -5280,57 +5526,6 @@ bool DN_TArrayGrowIfNeededFromArena(T **data, DN_USize size, DN_USize *max, DN_A
} }
#endif // defined(__cplusplus) #endif // defined(__cplusplus)
#endif // !defined(DN_BASE_H) #endif // !defined(DN_BASE_H)
// DN: Single header generator commented out => #include "Base/dn_base_leak.h"
#if !defined(DN_BASE_LEAK_H)
#define DN_BASE_LEAK_H
// DN: Single header generator commented out => #if defined(_CLANGD)
// #include "../dn.h"
// #endif
enum DN_LeakAllocFlag
{
DN_LeakAllocFlag_Freed = 1 << 0,
DN_LeakAllocFlag_LeakPermitted = 1 << 1,
};
struct DN_LeakAlloc
{
void *ptr; // 8 Pointer to the allocation being tracked
DN_USize size; // 16 Size of the allocation
DN_USize freed_size; // 24 Store the size of the allocation when it is freed
DN_Str8 stack_trace; // 40 Stack trace at the point of allocation
DN_Str8 freed_stack_trace; // 56 Stack trace of where the allocation was freed
DN_U16 flags; // 72 Bit flags from `DN_LeakAllocFlag`
};
// NOTE: We aim to keep the allocation record as light as possible as memory tracking can get
// expensive. Enforce that there is no unexpected padding.
DN_StaticAssert(sizeof(DN_LeakAlloc) == 64 || sizeof(DN_LeakAlloc) == 32); // NOTE: 64 bit vs 32 bit pointers respectively
struct DN_LeakTracker
{
DN_DSMap<DN_LeakAlloc> alloc_table;
DN_TicketMutex alloc_table_mutex;
DN_MemList alloc_table_mem;
DN_Arena alloc_table_arena;
DN_U64 alloc_table_bytes_allocated_for_stack_traces;
};
DN_API void DN_LeakTrackAlloc_ (DN_LeakTracker *leak, void *ptr, DN_USize size, bool alloc_can_leak);
DN_API void DN_LeakTrackDealloc_(DN_LeakTracker *leak, void *ptr);
DN_API void DN_LeakDump_ (DN_LeakTracker *leak);
#if defined(DN_LEAK_TRACKING)
#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) DN_LeakTrackAlloc_(leak, ptr, size, alloc_can_leak)
#define DN_LeakTrackDealloc(leak, ptr) DN_LeakTrackDealloc_(leak, ptr)
#define DN_LeakDump(leak) DN_LeakDump_(leak)
#else
#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0)
#define DN_LeakTrackDealloc(leak, ptr) do { (void)ptr; } while (0)
#define DN_LeakDump(leak) do { } while (0)
#endif
#endif // DN_BASE_LEAK_H
#if DN_H_WITH_OS #if DN_H_WITH_OS
#if defined(DN_PLATFORM_WIN32) #if defined(DN_PLATFORM_WIN32)
@@ -6884,10 +7079,6 @@ DN_API DN_OSPosixProcSelfStatus DN_OS_PosixProcSelfStatus();
#endif #endif
#endif #endif
#if defined(DN_PLATFORM_EMSCRIPTEN)
#include <emscripten/fetch.h> // emscripten_fetch (for DN_OSHttpResponse)
#endif
extern DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count]; extern DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count];
struct DN_OSTimer /// Record time between two time-points using the OS's performance counter. struct DN_OSTimer /// Record time between two time-points using the OS's performance counter.
@@ -7082,42 +7273,6 @@ struct DN_OSThread
DN_TCInitArgs tc_init_args; DN_TCInitArgs tc_init_args;
}; };
// NOTE: DN_OSHttp
enum DN_OSHttpRequestSecure
{
DN_OSHttpRequestSecure_No,
DN_OSHttpRequestSecure_Yes,
};
struct DN_OSHttpResponse
{
// NOTE: Response data
DN_U32 error_code;
DN_Str8 error_msg;
DN_U16 http_status;
DN_Str8 body;
DN_B32 done;
// NOTE: Book-keeping
DN_Arena *arena; // Allocates memory for the response
// NOTE: Async book-keeping
// Synchronous HTTP response uses the TLS scratch arena whereas async
// calls use their own dedicated arena.
DN_Arena tmp_arena;
DN_Arena scratch_arena;
DN_Str8Builder builder;
DN_OSSemaphore on_complete_semaphore;
#if defined(DN_PLATFORM_EMSCRIPTEN)
emscripten_fetch_t *em_handle;
#elif defined(DN_PLATFORM_WIN32)
HINTERNET w32_request_session;
HINTERNET w32_request_connection;
HINTERNET w32_request_handle;
#endif
};
struct DN_OSCore struct DN_OSCore
{ {
DN_CPUReport cpu_report; DN_CPUReport cpu_report;
@@ -7362,10 +7517,52 @@ DN_API DN_OSThreadLane* DN_OS_TCThreadLane ()
DN_API void DN_OS_TCThreadLaneSync (void **ptr_to_share); DN_API void DN_OS_TCThreadLaneSync (void **ptr_to_share);
DN_API DN_OSThreadLane DN_OS_TCThreadLaneEquip (DN_OSThreadLane lane); DN_API DN_OSThreadLane DN_OS_TCThreadLaneEquip (DN_OSThreadLane lane);
DN_API void DN_OS_HttpRequestAsync (DN_OSHttpResponse *response, DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers); enum DN_OSAsyncPriority
DN_API void DN_OS_HttpRequestWait (DN_OSHttpResponse *response); {
DN_API void DN_OS_HttpRequestFree (DN_OSHttpResponse *response); DN_OSAsyncPriority_Low,
DN_API DN_OSHttpResponse DN_OS_HttpRequest (DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers); DN_OSAsyncPriority_High,
DN_OSAsyncPriority_Count,
};
struct DN_OSAsyncCore
{
DN_OSMutex ring_mutex;
DN_OSConditionVariable ring_write_cv;
DN_OSSemaphore worker_sem;
DN_Ring ring;
DN_OSThread *threads;
DN_U32 thread_count;
DN_U32 busy_threads;
DN_U32 join_threads;
};
struct DN_OSAsyncWorkArgs
{
DN_OSThread *thread;
void *input;
};
typedef void(DN_OSAsyncWorkFunc)(DN_OSAsyncWorkArgs work_args);
struct DN_OSAsyncWork
{
DN_OSAsyncWorkFunc *func;
void *input;
void *output;
};
struct DN_OSAsyncTask
{
bool queued;
DN_OSAsyncWork work;
DN_OSSemaphore completion_sem;
};
DN_API void DN_OS_AsyncInit (DN_OSAsyncCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size);
DN_API void DN_OS_AsyncDeinit (DN_OSAsyncCore *async);
DN_API bool DN_OS_AsyncQueueWork(DN_OSAsyncCore *async, DN_OSAsyncWorkFunc *func, void *input, DN_U64 wait_time_ms);
DN_API DN_OSAsyncTask DN_OS_AsyncQueueTask(DN_OSAsyncCore *async, DN_OSAsyncWorkFunc *func, void *input, DN_U64 wait_time_ms);
DN_API bool DN_OS_AsyncWaitTask (DN_OSAsyncTask *task, DN_U32 timeout_ms);
// NOTE: DN_OSPrint // NOTE: DN_OSPrint
enum DN_OSPrintDest enum DN_OSPrintDest
@@ -7423,48 +7620,6 @@ DN_API void DN_OS_PrintLnFV (DN_OSPrintDest dest, DN_FMT_ATTRIB char
DN_API void DN_OS_PrintLnStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_Str8 string); DN_API void DN_OS_PrintLnStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_Str8 string);
DN_API void DN_OS_PrintLnFStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, ...); DN_API void DN_OS_PrintLnFStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, ...);
DN_API void DN_OS_PrintLnFVStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, va_list args); DN_API void DN_OS_PrintLnFVStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, va_list args);
// NOTE: DN_VArray
// TODO(doyle): Add an API for shrinking the array by decomitting pages back to the OS.
template <typename T> struct DN_VArray
{
T *data; // Pointer to the start of the array items in the block of memory
DN_USize size; // Number of items currently in the array
DN_USize max; // Maximum number of items this array can store
DN_USize commit; // Bytes committed
T *begin() { return data; }
T *end () { return data + size; }
T const *begin() const { return data; }
T const *end () const { return data + size; }
};
template <typename T> DN_VArray<T> DN_OS_VArrayInitByteSize (DN_USize byte_size);
template <typename T> DN_VArray<T> DN_OS_VArrayInit (DN_USize max);
template <typename T, DN_USize N> DN_VArray<T> DN_OS_VArrayInitCArray (T const (&items)[N], DN_USize max);
template <typename T> void DN_OS_VArrayDeinit (DN_VArray<T> *array);
template <typename T> bool DN_OS_VArrayIsValid (DN_VArray<T> const *array);
template <typename T> bool DN_OS_VArrayReserve (DN_VArray<T> *array, DN_USize count);
template <typename T> T * DN_OS_VArrayAddArray (DN_VArray<T> *array, T const *items, DN_USize count);
template <typename T, DN_USize N> T * DN_OS_VArrayAddCArray (DN_VArray<T> *array, T const (&items)[N]);
template <typename T> T * DN_OS_VArrayAdd (DN_VArray<T> *array, T const &item);
#define DN_OS_VArrayAddArrayAssert(...) DN_HardAssert(DN_OS_VArrayAddArray(__VA_ARGS__))
#define DN_OS_VArrayAddCArrayAssert(...) DN_HardAssert(DN_OS_VArrayAddCArray(__VA_ARGS__))
#define DN_OS_VArrayAddAssert(...) DN_HardAssert(DN_OS_VArrayAdd(__VA_ARGS__))
template <typename T> T * DN_OS_VArrayMakeArray (DN_VArray<T> *array, DN_USize count, DN_ZMem z_mem);
template <typename T> T * DN_OS_VArrayMake (DN_VArray<T> *array, DN_ZMem z_mem);
#define DN_OS_VArrayMakeArrayAssert(...) DN_HardAssert(DN_OS_VArrayMakeArray(__VA_ARGS__))
#define DN_OS_VArrayMakeAssert(...) DN_HardAssert(DN_OS_VArrayMake(__VA_ARGS__))
template <typename T> T * DN_OS_VArrayInsertArray (DN_VArray<T> *array, DN_USize index, T const *items, DN_USize count);
template <typename T, DN_USize N> T * DN_OS_VArrayInsertCArray (DN_VArray<T> *array, DN_USize index, T const (&items)[N]);
template <typename T> T * DN_OS_VArrayInsert (DN_VArray<T> *array, DN_USize index, T const &item);
#define DN_OS_VArrayInsertArrayAssert(...) DN_HardAssert(DN_OS_VArrayInsertArray(__VA_ARGS__))
#define DN_OS_VArrayInsertCArrayAssert(...) DN_HardAssert(DN_OS_VArrayInsertCArray(__VA_ARGS__))
#define DN_OS_VArrayInsertAssert(...) DN_HardAssert(DN_OS_VArrayInsert(__VA_ARGS__))
template <typename T> T DN_OS_VArrayPopFront (DN_VArray<T> *array, DN_USize count);
template <typename T> T DN_OS_VArrayPopBack (DN_VArray<T> *array, DN_USize count);
template <typename T> DN_ArrayEraseResult DN_OS_VArrayEraseRange (DN_VArray<T> *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase);
template <typename T> void DN_OS_VArrayClear (DN_VArray<T> *array, DN_ZMem z_mem);
#endif // !defined(DN_OS_H) #endif // !defined(DN_OS_H)
#endif #endif
@@ -7502,255 +7657,6 @@ DN_API void DN_Set (DN_Core *dn);
DN_API DN_Core *DN_Get (); DN_API DN_Core *DN_Get ();
DN_API void DN_BeginFrame(); DN_API void DN_BeginFrame();
#if DN_H_WITH_HELPERS
// DN: Single header generator commented out => #include "Extra/dn_helpers.h"
#if !defined(DN_HELPERS_H)
#define DN_HELPERS_H
// DN: Single header generator commented out => #if defined(_CLANGD)
// #include "../dn.h"
// #endif
/*
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\
// $$ | $$ |$$ _____|$$ | $$ __$$\ $$ _____|$$ __$$\ $$ __$$\
// $$ | $$ |$$ | $$ | $$ | $$ |$$ | $$ | $$ |$$ / \__|
// $$$$$$$$ |$$$$$\ $$ | $$$$$$$ |$$$$$\ $$$$$$$ |\$$$$$$\
// $$ __$$ |$$ __| $$ | $$ ____/ $$ __| $$ __$$< \____$$\
// $$ | $$ |$$ | $$ | $$ | $$ | $$ | $$ |$$\ $$ |
// $$ | $$ |$$$$$$$$\ $$$$$$$$\ $$ | $$$$$$$$\ $$ | $$ |\$$$$$$ |
// \__| \__|\________|\________|\__| \________|\__| \__| \______/
//
// dn_helpers.h -- Helper functions/data structures
//
////////////////////////////////////////////////////////////////////////////////////////////////////
*/
#if !defined(DN_NO_JSON_BUILDER)
enum DN_JSONBuilderItem
{
DN_JSONBuilderItem_Empty,
DN_JSONBuilderItem_OpenContainer,
DN_JSONBuilderItem_CloseContainer,
DN_JSONBuilderItem_KeyValue,
};
struct DN_JSONBuilder
{
bool use_stdout; // When set, ignore the string builder and dump immediately to stdout
DN_Str8Builder string_builder; // (Internal)
int indent_level; // (Internal)
int spaces_per_indent; // The number of spaces per indent level
DN_JSONBuilderItem last_item;
};
#endif // !defined(DN_NO_JSON_BUIDLER)
template <typename T>
using DN_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs);
template <typename T>
bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
enum DN_BinarySearchType
{
// Index of the match. If no match is found, found is set to false and the
// index is set to the index where the match should be inserted/exist, if
// it were in the array
DN_BinarySearchType_Match,
// Index of the first element in the array that is `element >= find`. If no such
// item is found or the array is empty, then, the index is set to the array
// size and found is set to `false`.
//
// For example:
// int array[] = {0, 1, 2, 3, 4, 5};
// DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_LowerBound);
// printf("%zu\n", result.index); // Prints index '4'
DN_BinarySearchType_LowerBound,
// Index of the first element in the array that is `element > find`. If no such
// item is found or the array is empty, then, the index is set to the array
// size and found is set to `false`.
//
// For example:
// int array[] = {0, 1, 2, 3, 4, 5};
// DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_UpperBound);
// printf("%zu\n", result.index); // Prints index '5'
DN_BinarySearchType_UpperBound,
};
struct DN_BinarySearchResult
{
bool found;
DN_USize index;
};
#if !defined(DN_NO_JSON_BUILDER)
// NOTE: DN_JSONBuilder
#define DN_JSONBuilder_Object(builder) \
DN_DeferLoop(DN_JSONBuilder_ObjectBegin(builder), \
DN_JSONBuilder_ObjectEnd(builder))
#define DN_JSONBuilder_ObjectNamed(builder, name) \
DN_DeferLoop(DN_JSONBuilder_ObjectBeginNamed(builder, name), \
DN_JSONBuilder_ObjectEnd(builder))
#define DN_JSONBuilder_Array(builder) \
DN_DeferLoop(DN_JSONBuilder_ArrayBegin(builder), \
DN_JSONBuilder_ArrayEnd(builder))
#define DN_JSONBuilder_ArrayNamed(builder, name) \
DN_DeferLoop(DN_JSONBuilder_ArrayBeginNamed(builder, name), \
DN_JSONBuilder_ArrayEnd(builder))
DN_API DN_JSONBuilder DN_JSONBuilder_Init (DN_Arena *arena, int spaces_per_indent);
DN_API DN_Str8 DN_JSONBuilder_Build (DN_JSONBuilder const *builder, DN_Arena *arena);
DN_API void DN_JSONBuilder_KeyValue (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value);
DN_API void DN_JSONBuilder_KeyValueF (DN_JSONBuilder *builder, DN_Str8 key, char const *value_fmt, ...);
DN_API void DN_JSONBuilder_ObjectBeginNamed (DN_JSONBuilder *builder, DN_Str8 name);
DN_API void DN_JSONBuilder_ObjectEnd (DN_JSONBuilder *builder);
DN_API void DN_JSONBuilder_ArrayBeginNamed (DN_JSONBuilder *builder, DN_Str8 name);
DN_API void DN_JSONBuilder_ArrayEnd (DN_JSONBuilder *builder);
DN_API void DN_JSONBuilder_Str8Named (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value);
DN_API void DN_JSONBuilder_LiteralNamed (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value);
DN_API void DN_JSONBuilder_U64Named (DN_JSONBuilder *builder, DN_Str8 key, uint64_t value);
DN_API void DN_JSONBuilder_I64Named (DN_JSONBuilder *builder, DN_Str8 key, int64_t value);
DN_API void DN_JSONBuilder_F64Named (DN_JSONBuilder *builder, DN_Str8 key, double value, int decimal_places);
DN_API void DN_JSONBuilder_BoolNamed (DN_JSONBuilder *builder, DN_Str8 key, bool value);
#define DN_JSONBuilder_ObjectBegin(builder) DN_JSONBuilder_ObjectBeginNamed(builder, DN_Str8Lit(""))
#define DN_JSONBuilder_ArrayBegin(builder) DN_JSONBuilder_ArrayBeginNamed(builder, DN_Str8Lit(""))
#define DN_JSONBuilder_Str8(builder, value) DN_JSONBuilder_Str8Named(builder, DN_Str8Lit(""), value)
#define DN_JSONBuilder_Literal(builder, value) DN_JSONBuilder_LiteralNamed(builder, DN_Str8Lit(""), value)
#define DN_JSONBuilder_U64(builder, value) DN_JSONBuilder_U64Named(builder, DN_Str8Lit(""), value)
#define DN_JSONBuilder_I64(builder, value) DN_JSONBuilder_I64Named(builder, DN_Str8Lit(""), value)
#define DN_JSONBuilder_F64(builder, value) DN_JSONBuilder_F64Named(builder, DN_Str8Lit(""), value)
#define DN_JSONBuilder_Bool(builder, value) DN_JSONBuilder_BoolNamed(builder, DN_Str8Lit(""), value)
#endif // !defined(DN_NO_JSON_BUILDER)
// NOTE: DN_BinarySearch
template <typename T> bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
template <typename T> DN_BinarySearchResult DN_BinarySearch (T const *array, DN_USize array_size, T const &find, DN_BinarySearchType type = DN_BinarySearchType_Match, DN_BinarySearchLessThanProc<T> less_than = DN_BinarySearch_DefaultLessThan);
// NOTE: DN_BinarySearch
template <typename T>
bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs)
{
bool result = lhs < rhs;
return result;
}
template <typename T>
DN_BinarySearchResult DN_BinarySearch(T const *array,
DN_USize array_size,
T const &find,
DN_BinarySearchType type,
DN_BinarySearchLessThanProc<T> less_than)
{
DN_BinarySearchResult result = {};
if (!array || array_size <= 0 || !less_than)
return result;
T const *end = array + array_size;
T const *first = array;
T const *last = end;
while (first != last) {
DN_USize count = last - first;
T const *it = first + (count / 2);
bool advance_first = false;
if (type == DN_BinarySearchType_UpperBound)
advance_first = !less_than(find, it[0]);
else
advance_first = less_than(it[0], find);
if (advance_first)
first = it + 1;
else
last = it;
}
switch (type) {
case DN_BinarySearchType_Match: {
result.found = first != end && !less_than(find, *first);
} break;
case DN_BinarySearchType_LowerBound: /*FALLTHRU*/
case DN_BinarySearchType_UpperBound: {
result.found = first != end;
} break;
}
result.index = first - array;
return result;
}
#endif // !defined(DN_HELPERS_H)
#endif
#if DN_H_WITH_ASYNC
// DN: Single header generator commented out => #include "Extra/dn_async.h"
#if !defined(DN_ASYNC_H)
#define DN_ASYNC_H
// DN: Single header generator commented out => #if defined(_CLANGD)
// #define DN_H_WITH_OS 1
// #include "../dn.h"
// #endif
enum DN_ASYNCPriority
{
DN_ASYNCPriority_Low,
DN_ASYNCPriority_High,
DN_ASYNCPriority_Count,
};
struct DN_ASYNCCore
{
DN_OSMutex ring_mutex;
DN_OSConditionVariable ring_write_cv;
DN_OSSemaphore worker_sem;
DN_Ring ring;
DN_OSThread *threads;
DN_U32 thread_count;
DN_U32 busy_threads;
DN_U32 join_threads;
};
struct DN_ASYNCWorkArgs
{
DN_OSThread *thread;
void *input;
};
typedef void(DN_ASYNCWorkFunc)(DN_ASYNCWorkArgs work_args);
struct DN_ASYNCWork
{
DN_ASYNCWorkFunc *func;
void *input;
void *output;
};
struct DN_ASYNCTask
{
bool queued;
DN_ASYNCWork work;
DN_OSSemaphore completion_sem;
};
DN_API void DN_ASYNC_Init (DN_ASYNCCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size);
DN_API void DN_ASYNC_Deinit (DN_ASYNCCore *async);
DN_API bool DN_ASYNC_QueueWork(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms);
DN_API DN_ASYNCTask DN_ASYNC_QueueTask(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms);
DN_API void DN_ASYNC_WaitTask (DN_OSSemaphore *sem, DN_U32 timeout_ms);
#endif // DN_ASYNC_H
#endif
#if DN_H_WITH_NET #if DN_H_WITH_NET
// DN: Single header generator commented out => #include "Extra/dn_net.h" // DN: Single header generator commented out => #include "Extra/dn_net.h"
#if !defined(DN_NET_H) #if !defined(DN_NET_H)
@@ -7889,112 +7795,3 @@ void DN_NET_EndFinishedRequest (DN_NETRequest *request);
#endif // DN_NET_H #endif // DN_NET_H
#endif #endif
#endif // !defined(DN_H) #endif // !defined(DN_H)
#if !defined(DN_BIN_PACK_H)
#define DN_BIN_PACK_H
// DN: Single header generator commented out => #if defined(_CLANGD)
// #include "../dn.h"
// #endif
enum DN_BinPackMode
{
DN_BinPackMode_Serialise,
DN_BinPackMode_Deserialise,
};
struct DN_BinPack
{
DN_Str8Builder writer;
DN_Str8 read;
DN_USize read_index;
};
DN_API bool DN_BinPackIsEndOfReadStream(DN_BinPack const *pack);
DN_API void DN_BinPackUSize (DN_BinPack *pack, DN_BinPackMode mode, DN_USize *item);
DN_API void DN_BinPackU64 (DN_BinPack *pack, DN_BinPackMode mode, DN_U64 *item);
DN_API void DN_BinPackU32 (DN_BinPack *pack, DN_BinPackMode mode, DN_U32 *item);
DN_API void DN_BinPackU16 (DN_BinPack *pack, DN_BinPackMode mode, DN_U16 *item);
DN_API void DN_BinPackU8 (DN_BinPack *pack, DN_BinPackMode mode, DN_U8 *item);
DN_API void DN_BinPackI64 (DN_BinPack *pack, DN_BinPackMode mode, DN_I64 *item);
DN_API void DN_BinPackI32 (DN_BinPack *pack, DN_BinPackMode mode, DN_I32 *item);
DN_API void DN_BinPackI16 (DN_BinPack *pack, DN_BinPackMode mode, DN_I16 *item);
DN_API void DN_BinPackI8 (DN_BinPack *pack, DN_BinPackMode mode, DN_I8 *item);
DN_API void DN_BinPackF64 (DN_BinPack *pack, DN_BinPackMode mode, DN_F64 *item);
DN_API void DN_BinPackF32 (DN_BinPack *pack, DN_BinPackMode mode, DN_F32 *item);
#if defined (DN_MATH_H)
DN_API void DN_BinPackV2 (DN_BinPack *pack, DN_BinPackMode mode, DN_V2F32 *item);
DN_API void DN_BinPackV4 (DN_BinPack *pack, DN_BinPackMode mode, DN_V4F32 *item);
#endif
DN_API void DN_BinPackBool (DN_BinPack *pack, DN_BinPackMode mode, bool *item);
DN_API void DN_BinPackStr8FromArena (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, DN_Str8 *string);
DN_API void DN_BinPackStr8FromPool (DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, DN_Str8 *string);
DN_API DN_Str8 DN_BinPackStr8FromBuffer (DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max);
DN_API void DN_BinPackBytesFromArena (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, void **ptr, DN_USize *size);
DN_API void DN_BinPackBytesFromPool (DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, void **ptr, DN_USize *size);
DN_API void DN_BinPackCArray (DN_BinPack *pack, DN_BinPackMode mode, void *ptr, DN_USize size);
DN_API void DN_BinPackCBuffer (DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max);
DN_API DN_Str8 DN_BinPackBuild (DN_BinPack const *pack, DN_Arena *arena);
#endif // !defined(DN_BIN_PACK_H)
#if !defined(DN_CSV_H)
#define DN_CSV_H
// NOTE: Data structures to create and parse CSV files, supports Python style escaped quotes (e.g.
// Using "" to escape quotes inside a quoted string).
//
// API
// DN_CSV_TokeniserNextN: Reads the next N consecutive fields from the parser. If `column_iterator`
// is `false` then the read of the N consecutive fields does not proceed past the end of the
// current CSV row. If `true` then it reads the next N fields even if reading would progress onto
// the next row.
// DN: Single header generator commented out => #if defined(_CLANGD)
// #include "../dn.h"
// #endif
enum DN_CSVSerialise
{
DN_CSVSerialise_Read,
DN_CSVSerialise_Write,
};
struct DN_CSVTokeniser
{
bool bad;
DN_Str8 string;
char delimiter;
char const *it;
bool end_of_line;
};
struct DN_CSVPack
{
DN_Str8Builder write_builder;
DN_USize write_column;
DN_CSVTokeniser read_tokeniser;
};
DN_CSVTokeniser DN_CSV_TokeniserInit (DN_Str8 string, char delimiter);
bool DN_CSV_TokeniserValid (DN_CSVTokeniser *tokeniser);
bool DN_CSV_TokeniserNextRow (DN_CSVTokeniser *tokeniser);
DN_Str8 DN_CSV_TokeniserNextField (DN_CSVTokeniser *tokeniser);
DN_Str8 DN_CSV_TokeniserNextColumn (DN_CSVTokeniser *tokeniser);
void DN_CSV_TokeniserSkipLine (DN_CSVTokeniser *tokeniser);
int DN_CSV_TokeniserNextN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size, bool column_iterator);
int DN_CSV_TokeniserNextColumnN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size);
int DN_CSV_TokeniserNextFieldN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size);
void DN_CSV_TokeniserSkipLineN (DN_CSVTokeniser *tokeniser, int count);
void DN_CSV_PackU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 *value);
void DN_CSV_PackI64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 *value);
void DN_CSV_PackI32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 *value);
void DN_CSV_PackI16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 *value);
void DN_CSV_PackI8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *value);
void DN_CSV_PackU32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 *value);
void DN_CSV_PackU16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 *value);
void DN_CSV_PackBoolAsU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, bool *value);
void DN_CSV_PackStr8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_Str8 *str8, DN_Arena *arena);
void DN_CSV_PackBuffer (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size);
void DN_CSV_PackBufferWithMax (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size, size_t max);
bool DN_CSV_PackNewLine (DN_CSVPack *pack, DN_CSVSerialise serialise);
#endif // !defined(DN_CSV_H)
+1860 -165
View File
File diff suppressed because it is too large Load Diff
+258 -17
View File
@@ -2,11 +2,12 @@
#define DN_BASE_H #define DN_BASE_H
#if defined(_CLANGD) #if defined(_CLANGD)
#define DN_STR8_AVX512F 1
#include "../dn.h" #include "../dn.h"
#endif #endif
// NOTE: Compiler identification // NOTE: Compiler identification
// Warning! Order is important here, clang-cl on Windows defines _MSC_VER // NOTE: Warning! Order is important here, clang-cl on Windows defines _MSC_VER
#if defined(_MSC_VER) #if defined(_MSC_VER)
#if defined(__clang__) #if defined(__clang__)
#define DN_COMPILER_CLANG_CL #define DN_COMPILER_CLANG_CL
@@ -21,7 +22,8 @@
#endif #endif
// NOTE: __has_feature // NOTE: __has_feature
// MSVC for example does not support the feature detection macro for instance so we compile it out // NOTE: MSVC for example does not support the feature detection macro for instance so we compile it
// out
#if defined(__has_feature) #if defined(__has_feature)
#define DN_HAS_FEATURE(expr) __has_feature(expr) #define DN_HAS_FEATURE(expr) __has_feature(expr)
#else #else
@@ -29,7 +31,7 @@
#endif #endif
// NOTE: __has_builtin // NOTE: __has_builtin
// MSVC for example does not support the feature detection macro for instance so we compile it out // NOTE: MSVC for example does not support the feature detection macro for instance so we compile it out
#if defined(__has_builtin) #if defined(__has_builtin)
#define DN_HAS_BUILTIN(expr) __has_builtin(expr) #define DN_HAS_BUILTIN(expr) __has_builtin(expr)
#else #else
@@ -244,15 +246,6 @@
typedef char DN_TokenCombine(static_assert_dummy__, __LINE__)[(expr) ? 1 : -1]; \ typedef char DN_TokenCombine(static_assert_dummy__, __LINE__)[(expr) ? 1 : -1]; \
DN_GCC_WARNING_POP DN_GCC_WARNING_POP
#define DN_Check(expr) DN_CheckF(expr, "")
#if defined(DN_NO_CHECK_BREAK)
#define DN_CheckF(expr, fmt, ...) \
((expr) ? true : (DN_LogWarningF(fmt, ##__VA_ARGS__), false))
#else
#define DN_CheckF(expr, fmt, ...) \
((expr) ? true : (DN_LogErrorF(fmt, ##__VA_ARGS__), DN_StackTracePrint(128 /*limit*/), DN_DebugBreak, false))
#endif
#if defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) #if defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64)
#define DN_64_BIT #define DN_64_BIT
#else #else
@@ -1760,7 +1753,7 @@ DN_API DN_I16 DN_SaturateCastI64ToI16
DN_API DN_I32 DN_SaturateCastI64ToI32 (DN_I64 val); DN_API DN_I32 DN_SaturateCastI64ToI32 (DN_I64 val);
DN_API DN_UInt DN_SaturateCastI64ToUInt (DN_I64 val); DN_API DN_UInt DN_SaturateCastI64ToUInt (DN_I64 val);
DN_API DN_ISize DN_SaturateCastI64ToUSize (DN_I64 val); DN_API DN_USize DN_SaturateCastI64ToUSize (DN_I64 val);
DN_API DN_U8 DN_SaturateCastI64ToU8 (DN_I64 val); DN_API DN_U8 DN_SaturateCastI64ToU8 (DN_I64 val);
DN_API DN_U16 DN_SaturateCastI64ToU16 (DN_I64 val); DN_API DN_U16 DN_SaturateCastI64ToU16 (DN_I64 val);
DN_API DN_U32 DN_SaturateCastI64ToU32 (DN_I64 val); DN_API DN_U32 DN_SaturateCastI64ToU32 (DN_I64 val);
@@ -1969,12 +1962,14 @@ DN_API DN_USize DN_CStr16Size
#define DN_Str8Lit(c_str) DN_Literal(DN_Str8){(char *)(c_str), sizeof(c_str) - 1} #define DN_Str8Lit(c_str) DN_Literal(DN_Str8){(char *)(c_str), sizeof(c_str) - 1}
#define DN_Str8PrintFmt(string) (int)((string).size), (string).data #define DN_Str8PrintFmt(string) (int)((string).size), (string).data
#define DN_Str8FromPtr(data, size) DN_Literal(DN_Str8){(char *)(data), (DN_USize)(size)} #define DN_Str8FromPtr(data, size) DN_Literal(DN_Str8){(char *)(data), (DN_USize)(size)}
#define DN_Str8FromStruct(ptr) DN_Str8FromPtr((ptr)->data, (ptr)->size) #define DN_Str8FromStruct(ptr) DN_Str8FromPtr((ptr)->data, (ptr)->size)
#define DN_Str8FromLitArray(c_array) DN_Str8FromPtr(c_array, DN_ArrayCountU(c_array)) #define DN_Str8FromLitArray(c_array) DN_Str8FromPtr(c_array, DN_ArrayCountU(c_array))
DN_API DN_Str8 DN_Str8AllocAllocator (DN_USize size, DN_ZMem z_mem, DN_Allocator allocator); DN_API DN_Str8 DN_Str8AllocAllocator (DN_USize size, DN_ZMem z_mem, DN_Allocator allocator);
DN_API DN_Str8 DN_Str8AllocArena (DN_USize size, DN_ZMem z_mem, DN_Arena *arena); DN_API DN_Str8 DN_Str8AllocArena (DN_USize size, DN_ZMem z_mem, DN_Arena *arena);
DN_API DN_Str8 DN_Str8AllocPool (DN_USize size, DN_Pool *pool); DN_API DN_Str8 DN_Str8AllocPool (DN_USize size, DN_Pool *pool);
DN_API DN_Str8 DN_Str8FromCStr8 (char const *src); DN_API DN_Str8 DN_Str8FromCStr8 (char const *src);
DN_API DN_Str8 DN_Str8FromCStr8Arena (char const *src, DN_Arena *arena); DN_API DN_Str8 DN_Str8FromCStr8Arena (char const *src, DN_Arena *arena);
DN_API DN_Str8 DN_Str8FromPtrArena (void const *data, DN_USize size, DN_Arena *arena); DN_API DN_Str8 DN_Str8FromPtrArena (void const *data, DN_USize size, DN_Arena *arena);
@@ -1988,6 +1983,7 @@ DN_API DN_Str8 DN_Str8FromFmtAllocator
DN_API DN_Str8 DN_Str8FromFmtArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_Str8 DN_Str8FromFmtArena (DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...);
DN_API DN_Str8 DN_Str8FromFmtVPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args); DN_API DN_Str8 DN_Str8FromFmtVPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, va_list args);
DN_API DN_Str8 DN_Str8FromFmtPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_Str8 DN_Str8FromFmtPool (DN_Pool *pool, DN_FMT_ATTRIB char const *fmt, ...);
DN_API DN_Str8x16 DN_Str8x16FromFmt (DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_Str8x16 DN_Str8x16FromFmt (DN_FMT_ATTRIB char const *fmt, ...);
DN_API DN_Str8x16 DN_Str8x16FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args); DN_API DN_Str8x16 DN_Str8x16FromFmtV (DN_FMT_ATTRIB char const *fmt, va_list args);
DN_API DN_Str8x32 DN_Str8x32FromFmt (DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_Str8x32 DN_Str8x32FromFmt (DN_FMT_ATTRIB char const *fmt, ...);
@@ -2016,6 +2012,7 @@ DN_API void DN_Str8x512AppendFmt
DN_API void DN_Str8x512AppendFmtV (DN_Str8x512 *str, DN_FMT_ATTRIB char const *fmt, va_list args); DN_API void DN_Str8x512AppendFmtV (DN_Str8x512 *str, DN_FMT_ATTRIB char const *fmt, va_list args);
DN_API void DN_Str8x1024AppendFmt (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, ...); DN_API void DN_Str8x1024AppendFmt (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, ...);
DN_API void DN_Str8x1024AppendFmtV (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, va_list args); DN_API void DN_Str8x1024AppendFmtV (DN_Str8x1024 *str, DN_FMT_ATTRIB char const *fmt, va_list args);
DN_API DN_Str8x32 DN_Str8x32FromU64 (DN_U64 val, char separator); DN_API DN_Str8x32 DN_Str8x32FromU64 (DN_U64 val, char separator);
DN_API bool DN_Str8IsAll (DN_Str8 string, DN_Str8IsAllType is_all); DN_API bool DN_Str8IsAll (DN_Str8 string, DN_Str8IsAllType is_all);
DN_API char * DN_Str8End (DN_Str8 string); DN_API char * DN_Str8End (DN_Str8 string);
@@ -2040,6 +2037,7 @@ DN_API bool DN_Str8StartsWithInsensitive
DN_API bool DN_Str8EndsWith (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive); DN_API bool DN_Str8EndsWith (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive);
DN_API bool DN_Str8EndsWithInsensitive (DN_Str8 string, DN_Str8 prefix); DN_API bool DN_Str8EndsWithInsensitive (DN_Str8 string, DN_Str8 prefix);
DN_API bool DN_Str8HasChar (DN_Str8 string, char ch); DN_API bool DN_Str8HasChar (DN_Str8 string, char ch);
DN_API DN_Str8 DN_Str8TrimPrefix (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive); DN_API DN_Str8 DN_Str8TrimPrefix (DN_Str8 string, DN_Str8 prefix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive);
DN_API DN_Str8 DN_Str8TrimHexPrefix (DN_Str8 string); DN_API DN_Str8 DN_Str8TrimHexPrefix (DN_Str8 string);
DN_API DN_Str8 DN_Str8TrimSuffix (DN_Str8 string, DN_Str8 suffix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive); DN_API DN_Str8 DN_Str8TrimSuffix (DN_Str8 string, DN_Str8 suffix, DN_Str8EqCase eq_case = DN_Str8EqCase_Sensitive);
@@ -2048,6 +2046,7 @@ DN_API DN_Str8 DN_Str8TrimHeadWhitespace
DN_API DN_Str8 DN_Str8TrimTailWhitespace (DN_Str8 string); DN_API DN_Str8 DN_Str8TrimTailWhitespace (DN_Str8 string);
DN_API DN_Str8 DN_Str8TrimWhitespaceAround (DN_Str8 string); DN_API DN_Str8 DN_Str8TrimWhitespaceAround (DN_Str8 string);
DN_API DN_Str8 DN_Str8TrimByteOrderMark (DN_Str8 string); DN_API DN_Str8 DN_Str8TrimByteOrderMark (DN_Str8 string);
DN_API DN_Str8 DN_Str8FileNameFromPath (DN_Str8 path); DN_API DN_Str8 DN_Str8FileNameFromPath (DN_Str8 path);
DN_API DN_Str8 DN_Str8FileNameNoExtension (DN_Str8 path); DN_API DN_Str8 DN_Str8FileNameNoExtension (DN_Str8 path);
DN_API DN_Str8 DN_Str8FilePathNoExtension (DN_Str8 path); DN_API DN_Str8 DN_Str8FilePathNoExtension (DN_Str8 path);
@@ -2071,6 +2070,15 @@ DN_API DN_Str8 DN_Str8LineBreakAllocator
DN_API DN_Str8 DN_Str8LineBreakArena (DN_Str8 src, DN_USize desired_width, DN_Str8 delimiter, DN_Str8LineBreakMode mode, DN_Arena *arena); DN_API DN_Str8 DN_Str8LineBreakArena (DN_Str8 src, DN_USize desired_width, DN_Str8 delimiter, DN_Str8LineBreakMode mode, DN_Arena *arena);
DN_API DN_Str8 DN_Str8Table (DN_Str8 const* rows, DN_USize num_rows, DN_USize num_cols, DN_Str8TableFlags flags, DN_Arena *arena); DN_API DN_Str8 DN_Str8Table (DN_Str8 const* rows, DN_USize num_rows, DN_USize num_cols, DN_Str8TableFlags flags, DN_Arena *arena);
#if DN_STR8_AVX512F
DN_API DN_Str8FindResult DN_Str8FindStr8AVX512F (DN_Str8 string, DN_Str8 find);
DN_API DN_Str8FindResult DN_Str8FindLastStr8AVX512F (DN_Str8 string, DN_Str8 find);
DN_API DN_Str8BSplitResult DN_Str8BSplitAVX512F (DN_Str8 string, DN_Str8 find);
DN_API DN_Str8BSplitResult DN_Str8BSplitLastAVX512F (DN_Str8 string, DN_Str8 find);
DN_API DN_USize DN_Str8SplitAVX512F (DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitFlags flags);
DN_API DN_Str8Slice DN_Str8SplitAllocAVX512F (DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitFlags flags);
#endif
DN_API DN_Str8 DN_Str8SliceRender (DN_Str8Slice array, DN_Str8 separator, DN_Arena *arena); DN_API DN_Str8 DN_Str8SliceRender (DN_Str8Slice array, DN_Str8 separator, DN_Arena *arena);
DN_API DN_Str8 DN_Str8RenderSpaceSep (DN_Str8Slice array, DN_Arena *arena); DN_API DN_Str8 DN_Str8RenderSpaceSep (DN_Str8Slice array, DN_Arena *arena);
DN_API int DN_Str8CompareNatural (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case); DN_API int DN_Str8CompareNatural (DN_Str8 lhs, DN_Str8 rhs, DN_Str8EqCase eq_case);
@@ -2552,8 +2560,8 @@ DN_API DN_M4 DN_M4MulF
DN_API DN_M4 DN_M4DivF (DN_M4 lhs, DN_F32 rhs); DN_API DN_M4 DN_M4DivF (DN_M4 lhs, DN_F32 rhs);
DN_API DN_Str8x256 DN_M4ColumnMajorString (DN_M4 mat); DN_API DN_Str8x256 DN_M4ColumnMajorString (DN_M4 mat);
DN_API bool operator== (DN_M2x3 const &lhs, DN_M2x3 const &rhs); DN_API bool DN_M2x3Eq (DN_M2x3 const *lhs, DN_M2x3 const *rhs);
DN_API bool operator!= (DN_M2x3 const &lhs, DN_M2x3 const &rhs); DN_API bool DN_M2x3NotEq (DN_M2x3 const *lhs, DN_M2x3 const *rhs);
DN_API DN_M2x3 DN_M2x3Identity (); DN_API DN_M2x3 DN_M2x3Identity ();
DN_API DN_M2x3 DN_M2x3Translate (DN_V2F32 offset); DN_API DN_M2x3 DN_M2x3Translate (DN_V2F32 offset);
DN_API DN_V2F32 DN_M2x3ScaleGet (DN_M2x3 m2x3); DN_API DN_V2F32 DN_M2x3ScaleGet (DN_M2x3 m2x3);
@@ -2573,7 +2581,6 @@ DN_API DN_Rect DN_M2x3MulRect
#define DN_RectFrom4N(x, y, w, h) DN_Literal(DN_Rect){DN_Literal(DN_V2F32){{x, y}}, DN_Literal(DN_V2F32){{w, h}}} #define DN_RectFrom4N(x, y, w, h) DN_Literal(DN_Rect){DN_Literal(DN_V2F32){{x, y}}, DN_Literal(DN_V2F32){{w, h}}}
#define DN_RectZero DN_RectFrom4N(0, 0, 0, 0) #define DN_RectZero DN_RectFrom4N(0, 0, 0, 0)
DN_API bool operator== (const DN_Rect& lhs, const DN_Rect& rhs);
DN_API DN_V2F32 DN_RectCenter (DN_Rect rect); DN_API DN_V2F32 DN_RectCenter (DN_Rect rect);
DN_API bool DN_RectContainsPoint (DN_Rect rect, DN_V2F32 p); DN_API bool DN_RectContainsPoint (DN_Rect rect, DN_V2F32 p);
DN_API bool DN_RectContainsRect (DN_Rect a, DN_Rect b); DN_API bool DN_RectContainsRect (DN_Rect a, DN_Rect b);
@@ -3040,9 +3047,10 @@ DN_API void DN_RingWrite (DN_Rin
DN_API void DN_RingRead (DN_Ring *ring, void *dest, DN_U64 dest_size); DN_API void DN_RingRead (DN_Ring *ring, void *dest, DN_U64 dest_size);
#define DN_RingReadStruct(ring, dest) DN_RingRead((ring), (dest), sizeof(*(dest))) #define DN_RingReadStruct(ring, dest) DN_RingRead((ring), (dest), sizeof(*(dest)))
// TODO: Replace with a C-style hash table
#if defined(__cplusplus)
DN_U32 const DN_DS_MAP_DEFAULT_HASH_SEED = 0x8a1ced49; DN_U32 const DN_DS_MAP_DEFAULT_HASH_SEED = 0x8a1ced49;
DN_U32 const DN_DS_MAP_SENTINEL_SLOT = 0; DN_U32 const DN_DS_MAP_SENTINEL_SLOT = 0;
template <typename T> DN_DSMap<T> DN_DSMapInit (DN_Arena *arena, DN_U32 size, DN_DSMapFlags flags); template <typename T> DN_DSMap<T> DN_DSMapInit (DN_Arena *arena, DN_U32 size, DN_DSMapFlags flags);
template <typename T> void DN_DSMapDeinit (DN_DSMap<T> *map, DN_ZMem z_mem); template <typename T> void DN_DSMapDeinit (DN_DSMap<T> *map, DN_ZMem z_mem);
template <typename T> bool DN_DSMapIsValid (DN_DSMap<T> const *map); template <typename T> bool DN_DSMapIsValid (DN_DSMap<T> const *map);
@@ -3069,7 +3077,240 @@ template <typename T> DN_DSMapKey DN_DSMapKeyStr8 (DN_DSMap
DN_API DN_DSMapKey DN_DSMapKeyU64NoHash (DN_U64 u64); DN_API DN_DSMapKey DN_DSMapKeyU64NoHash (DN_U64 u64);
DN_API bool DN_DSMapKeyEquals (DN_DSMapKey lhs, DN_DSMapKey rhs); DN_API bool DN_DSMapKeyEquals (DN_DSMapKey lhs, DN_DSMapKey rhs);
DN_API bool operator== (DN_DSMapKey lhs, DN_DSMapKey rhs); DN_API bool operator== (DN_DSMapKey lhs, DN_DSMapKey rhs);
#endif
enum DN_BinPackMode
{
DN_BinPackMode_Serialise,
DN_BinPackMode_Deserialise,
};
struct DN_BinPack
{
DN_Str8Builder writer;
DN_Str8 read;
DN_USize read_index;
};
DN_API bool DN_BinPackIsEndOfReadStream(DN_BinPack const *pack);
DN_API void DN_BinPackUSize (DN_BinPack *pack, DN_BinPackMode mode, DN_USize *item);
DN_API void DN_BinPackU64 (DN_BinPack *pack, DN_BinPackMode mode, DN_U64 *item);
DN_API void DN_BinPackU32 (DN_BinPack *pack, DN_BinPackMode mode, DN_U32 *item);
DN_API void DN_BinPackU16 (DN_BinPack *pack, DN_BinPackMode mode, DN_U16 *item);
DN_API void DN_BinPackU8 (DN_BinPack *pack, DN_BinPackMode mode, DN_U8 *item);
DN_API void DN_BinPackI64 (DN_BinPack *pack, DN_BinPackMode mode, DN_I64 *item);
DN_API void DN_BinPackI32 (DN_BinPack *pack, DN_BinPackMode mode, DN_I32 *item);
DN_API void DN_BinPackI16 (DN_BinPack *pack, DN_BinPackMode mode, DN_I16 *item);
DN_API void DN_BinPackI8 (DN_BinPack *pack, DN_BinPackMode mode, DN_I8 *item);
DN_API void DN_BinPackF64 (DN_BinPack *pack, DN_BinPackMode mode, DN_F64 *item);
DN_API void DN_BinPackF32 (DN_BinPack *pack, DN_BinPackMode mode, DN_F32 *item);
DN_API void DN_BinPackV2 (DN_BinPack *pack, DN_BinPackMode mode, DN_V2F32 *item);
DN_API void DN_BinPackV4 (DN_BinPack *pack, DN_BinPackMode mode, DN_V4F32 *item);
DN_API void DN_BinPackBool (DN_BinPack *pack, DN_BinPackMode mode, bool *item);
DN_API void DN_BinPackStr8FromArena (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, DN_Str8 *string);
DN_API void DN_BinPackStr8FromPool (DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, DN_Str8 *string);
DN_API DN_Str8 DN_BinPackStr8FromBuffer (DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max);
DN_API void DN_BinPackBytesFromArena (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, void **ptr, DN_USize *size);
DN_API void DN_BinPackBytesFromPool (DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, void **ptr, DN_USize *size);
DN_API void DN_BinPackCArray (DN_BinPack *pack, DN_BinPackMode mode, void *ptr, DN_USize size);
DN_API void DN_BinPackCBuffer (DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max);
DN_API DN_Str8 DN_BinPackBuild (DN_BinPack const *pack, DN_Arena *arena);
enum DN_CSVSerialise
{
DN_CSVSerialise_Read,
DN_CSVSerialise_Write,
};
struct DN_CSVTokeniser
{
bool bad;
DN_Str8 string;
char delimiter;
char const *it;
bool end_of_line;
};
struct DN_CSVPack
{
DN_Str8Builder write_builder;
DN_USize write_column;
DN_CSVTokeniser read_tokeniser;
};
// NOTE: Data structures to create and parse CSV files, supports Python style escaped quotes (e.g.
// Using "" to escape quotes inside a quoted string).
//
// API
// DN_CSVTokeniserNextN: Reads the next N consecutive fields from the parser. If `column_iterator`
// is `false` then the read of the N consecutive fields does not proceed past the end of the
// current CSV row. If `true` then it reads the next N fields even if reading would progress onto
// the next row.
DN_API DN_CSVTokeniser DN_CSVTokeniserInit (DN_Str8 string, char delimiter);
DN_API bool DN_CSVTokeniserValid (DN_CSVTokeniser *tokeniser);
DN_API bool DN_CSVTokeniserNextRow (DN_CSVTokeniser *tokeniser);
DN_API DN_Str8 DN_CSVTokeniserNextField (DN_CSVTokeniser *tokeniser);
DN_API DN_Str8 DN_CSVTokeniserNextColumn (DN_CSVTokeniser *tokeniser);
DN_API void DN_CSVTokeniserSkipLine (DN_CSVTokeniser *tokeniser);
DN_API int DN_CSVTokeniserNextN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size, bool column_iterator);
DN_API int DN_CSVTokeniserNextColumnN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size);
DN_API int DN_CSVTokeniserNextFieldN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size);
DN_API void DN_CSVTokeniserSkipLineN (DN_CSVTokeniser *tokeniser, int count);
DN_API void DN_CSVPackU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 *value);
DN_API void DN_CSVPackI64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 *value);
DN_API void DN_CSVPackI32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 *value);
DN_API void DN_CSVPackI16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 *value);
DN_API void DN_CSVPackI8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *value);
DN_API void DN_CSVPackU32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 *value);
DN_API void DN_CSVPackU16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 *value);
DN_API void DN_CSVPackBoolAsU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, bool *value);
DN_API void DN_CSVPackStr8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_Str8 *str8, DN_Arena *arena);
DN_API void DN_CSVPackBuffer (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size);
DN_API void DN_CSVPackBufferWithMax (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size, size_t max);
DN_API bool DN_CSVPackNewLine (DN_CSVPack *pack, DN_CSVSerialise serialise);
// TODO: Replace with a C implementation
template <typename T>
using DN_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs);
template <typename T>
bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
enum DN_BinarySearchType
{
// Index of the match. If no match is found, found is set to false and the
// index is set to the index where the match should be inserted/exist, if
// it were in the array
DN_BinarySearchType_Match,
// Index of the first element in the array that is `element >= find`. If no such
// item is found or the array is empty, then, the index is set to the array
// size and found is set to `false`.
//
// For example:
// int array[] = {0, 1, 2, 3, 4, 5};
// DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_LowerBound);
// printf("%zu\n", result.index); // Prints index '4'
DN_BinarySearchType_LowerBound,
// Index of the first element in the array that is `element > find`. If no such
// item is found or the array is empty, then, the index is set to the array
// size and found is set to `false`.
//
// For example:
// int array[] = {0, 1, 2, 3, 4, 5};
// DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_UpperBound);
// printf("%zu\n", result.index); // Prints index '5'
DN_BinarySearchType_UpperBound,
};
struct DN_BinarySearchResult
{
bool found;
DN_USize index;
};
template <typename T> bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
template <typename T> DN_BinarySearchResult DN_BinarySearch (T const *array, DN_USize array_size, T const &find, DN_BinarySearchType type = DN_BinarySearchType_Match, DN_BinarySearchLessThanProc<T> less_than = DN_BinarySearch_DefaultLessThan);
template <typename T>
bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs)
{
bool result = lhs < rhs;
return result;
}
template <typename T>
DN_BinarySearchResult DN_BinarySearch(T const *array,
DN_USize array_size,
T const &find,
DN_BinarySearchType type,
DN_BinarySearchLessThanProc<T> less_than)
{
DN_BinarySearchResult result = {};
if (!array || array_size <= 0 || !less_than)
return result;
T const *end = array + array_size;
T const *first = array;
T const *last = end;
while (first != last) {
DN_USize count = last - first;
T const *it = first + (count / 2);
bool advance_first = false;
if (type == DN_BinarySearchType_UpperBound)
advance_first = !less_than(find, it[0]);
else
advance_first = less_than(it[0], find);
if (advance_first)
first = it + 1;
else
last = it;
}
switch (type) {
case DN_BinarySearchType_Match: {
result.found = first != end && !less_than(find, *first);
} break;
case DN_BinarySearchType_LowerBound: /*FALLTHRU*/
case DN_BinarySearchType_UpperBound: {
result.found = first != end;
} break;
}
result.index = first - array;
return result;
}
enum DN_LeakAllocFlag
{
DN_LeakAllocFlag_Freed = 1 << 0,
DN_LeakAllocFlag_LeakPermitted = 1 << 1,
};
struct DN_LeakAlloc
{
void *ptr; // 8 Pointer to the allocation being tracked
DN_USize size; // 16 Size of the allocation
DN_USize freed_size; // 24 Store the size of the allocation when it is freed
DN_Str8 stack_trace; // 40 Stack trace at the point of allocation
DN_Str8 freed_stack_trace; // 56 Stack trace of where the allocation was freed
DN_U16 flags; // 72 Bit flags from `DN_LeakAllocFlag`
};
// NOTE: We aim to keep the allocation record as light as possible as memory tracking can get
// expensive. Enforce that there is no unexpected padding.
DN_StaticAssert(sizeof(DN_LeakAlloc) == 64 || sizeof(DN_LeakAlloc) == 32); // NOTE: 64 bit vs 32 bit pointers respectively
struct DN_LeakTracker
{
DN_DSMap<DN_LeakAlloc> alloc_table;
DN_TicketMutex alloc_table_mutex;
DN_MemList alloc_table_mem;
DN_Arena alloc_table_arena;
DN_U64 alloc_table_bytes_allocated_for_stack_traces;
};
DN_API void DN_LeakTrackAlloc_ (DN_LeakTracker *leak, void *ptr, DN_USize size, bool alloc_can_leak);
DN_API void DN_LeakTrackDealloc_(DN_LeakTracker *leak, void *ptr);
DN_API void DN_LeakDump_ (DN_LeakTracker *leak);
#if defined(DN_LEAK_TRACKING)
#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) DN_LeakTrackAlloc_(leak, ptr, size, alloc_can_leak)
#define DN_LeakTrackDealloc(leak, ptr) DN_LeakTrackDealloc_(leak, ptr)
#define DN_LeakDump(leak) DN_LeakDump_(leak)
#else
#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0)
#define DN_LeakTrackDealloc(leak, ptr) do { (void)ptr; } while (0)
#define DN_LeakDump(leak) do { } while (0)
#endif
// NOTE: Template implementations
#if defined(__cplusplus) #if defined(__cplusplus)
template <typename T> T *DN_TMemCopyObj(T *dest, T const *src, DN_USize count) template <typename T> T *DN_TMemCopyObj(T *dest, T const *src, DN_USize count)
{ {
-821
View File
@@ -1,821 +0,0 @@
#if defined(_CLANGD)
#include "../dn.h"
#endif
struct DN_ArrayFindEqMemcmpContext_
{
DN_USize elem_size;
void const *find;
};
DN_API void *DN_SliceAllocArena(void **data, DN_USize *slice_size_field, DN_USize size, DN_USize elem_size, DN_U8 align, DN_ZMem zmem, DN_Arena *arena)
{
void *result = *data;
*data = DN_ArenaAlloc(arena, size * elem_size, align, zmem);
if (*data)
*slice_size_field = size;
return result;
}
DN_API DN_ArrayFindResult DN_ArrayFind(void *data, DN_USize size, DN_USize elem_size, void const *find, DN_ArrayFindEqFunc *eq_func)
{
DN_ArrayFindResult result = {};
DN_Assert(data);
DN_Assert(elem_size);
if (find) {
for (DN_ForIndexU(index, size)) {
DN_U8 *it = DN_Cast(DN_U8 *) data + (index * elem_size);
if (eq_func(it, find)) {
result.index = index;
result.value = it;
result.success = true;
break;
}
}
}
return result;
}
static bool DN_ArrayFindEqMemEqUnsafe_(void const *lhs, void const *find)
{
DN_ArrayFindEqMemcmpContext_ *context = DN_Cast(DN_ArrayFindEqMemcmpContext_ *) find;
bool result = DN_MemEqUnsafe(lhs, context->find, context->elem_size);
return result;
}
DN_API DN_ArrayFindResult DN_ArrayFindMemEq(void *data, DN_USize size, DN_USize elem_size, void const *find)
{
DN_ArrayFindEqMemcmpContext_ context = {};
context.elem_size = elem_size;
context.find = find;
DN_ArrayFindResult result = DN_ArrayFind(data, size, elem_size, &context, DN_ArrayFindEqMemEqUnsafe_);
return result;
}
DN_API void *DN_ArrayInsertArray(void *data, DN_USize *size, DN_USize max, DN_USize elem_size, DN_USize index, void const *items, DN_USize count)
{
void *result = nullptr;
if (!data || !size || !items || count <= 0 || ((*size + count) > max))
return result;
DN_USize clamped_index = DN_Min(index, *size);
if (clamped_index != *size) {
char const *src = DN_Cast(char *)data + (clamped_index * elem_size);
char const *dest = DN_Cast(char *)data + ((clamped_index + count) * elem_size);
char const *end = DN_Cast(char *)data + (size[0] * elem_size);
DN_USize bytes_to_move = end - src;
DN_Memmove(DN_Cast(void *) dest, src, bytes_to_move);
}
result = DN_Cast(char *)data + (clamped_index * elem_size);
DN_Memcpy(result, items, elem_size * count);
*size += count;
return result;
}
DN_API void *DN_ArrayPopFront(void *data, DN_USize *size, DN_USize elem_size, DN_USize count)
{
if (!data || !size || *size == 0 || count == 0)
return nullptr;
DN_USize pop_count = DN_Min(count, *size);
void *result = data;
if (pop_count < *size) {
char *src = DN_Cast(char *)data + (pop_count * elem_size);
char *dest = DN_Cast(char *)data;
DN_USize bytes_to_move = (*size - pop_count) * elem_size;
DN_Memmove(dest, src, bytes_to_move);
}
*size -= pop_count;
return result;
}
DN_API void *DN_ArrayPopBack(void *data, DN_USize *size, DN_USize elem_size, DN_USize count)
{
if (!data || !size || *size == 0 || count == 0)
return nullptr;
DN_USize pop_count = DN_Min(count, *size);
*size -= pop_count;
return DN_Cast(char *)data + (*size * elem_size);
}
DN_API DN_ArrayEraseResult DN_ArrayEraseRange(void *data, DN_USize *size, DN_USize elem_size, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase)
{
DN_ArrayEraseResult result = {};
result.it_index = begin_index;
if (!data || !size || *size == 0 || count == 0)
return result;
// Compute the range to erase
DN_USize start = 0, end = 0;
if (count < 0) {
// Erase backwards from begin_index, not inclusive of begin_index
// Range: [begin_index + count, begin_index)
// Which is: [begin_index - abs(count), begin_index)
DN_USize abs_count = DN_Abs(count);
start = (begin_index > abs_count) ? (begin_index - abs_count) : 0;
end = begin_index;
} else {
start = begin_index;
end = begin_index + count;
}
// Clamp indices to valid bounds
start = DN_Min(start, *size);
end = DN_Min(end, *size);
// Erase the range [start, end)
DN_USize erase_count = end > start ? end - start : 0;
if (erase_count) {
char *dest = (char *)data + (elem_size * start);
char *array_end = (char *)data + (elem_size * *size);
char *src = dest + (elem_size * erase_count);
if (erase == DN_ArrayErase_Stable) {
DN_USize move_size = array_end - src;
DN_Memmove(dest, src, move_size);
} else {
char *unstable_src = array_end - (elem_size * erase_count);
DN_USize move_size = array_end - unstable_src;
DN_Memcpy(dest, unstable_src, move_size);
}
*size -= erase_count;
}
result.items_erased = erase_count;
// NOTE: If we are erasing from the current index of the iterator to the end of the array then
// there's no more elements in the array to iterate. So the returned index should b
// one-past-last index
if (begin_index == start && end >= *size) {
result.it_index = *size;
} else {
result.it_index = start ? start - 1 : 0;
}
return result;
}
DN_API void *DN_ArrayMakeArray(void *data, DN_USize *size, DN_USize max, DN_USize elem_size, DN_USize make_count, DN_ZMem z_mem)
{
void *result = nullptr;
DN_USize new_size = *size + make_count;
if (new_size <= max) {
result = DN_Cast(char *) data + (elem_size * size[0]);
*size = new_size;
if (z_mem == DN_ZMem_Yes)
DN_Memset(result, 0, elem_size * make_count);
}
return result;
}
DN_API void *DN_ArrayMakeArrayAssert(void *data, DN_USize *size, DN_USize max, DN_USize elem_size, DN_USize make_count, DN_ZMem z_mem, DN_CallSite call_site)
{
void *result = DN_ArrayMakeArray(data, size, max, elem_size, make_count, z_mem);
DN_AssertArgsF(result, call_site, "array=%p size=%zu max=%zu", data, *size, max);
return result;
}
DN_API void *DN_ArrayAddArray(void *data, DN_USize *size, DN_USize max, DN_USize elem_size, void const *elems, DN_USize elems_count, DN_ArrayAdd add)
{
void *result = DN_ArrayMakeArray(data, size, max, elem_size, elems_count, DN_ZMem_No);
if (result) {
if (add == DN_ArrayAdd_Append) {
DN_Memcpy(result, elems, elems_count * elem_size);
} else {
char *move_dest = DN_Cast(char *)data + (elems_count * elem_size); // Shift elements forward
char *move_src = DN_Cast(char *)data;
DN_Memmove(move_dest, move_src, elem_size * size[0]);
DN_Memcpy(data, elems, elem_size * elems_count);
}
}
return result;
}
DN_API void *DN_ArrayAddArrayAssert(void *data, DN_USize *size, DN_USize max, DN_USize elem_size, void const *elems, DN_USize elems_count, DN_ArrayAdd add, DN_CallSite call_site)
{
void *result = DN_ArrayAddArray(data, size, max, elem_size, elems, elems_count, add);
DN_AssertArgsF(result, call_site, "array=%p size=%zu max=%zu", data, *size, max);
return result;
}
DN_API bool DN_ArrayResizeFromArena(void **data, DN_USize *size, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize new_max)
{
bool result = true;
if (new_max != *max) {
DN_USize bytes_to_alloc = elem_size * new_max;
void *buffer = DN_PoolNewArray(pool, DN_U8, bytes_to_alloc);
if (buffer) {
DN_USize bytes_to_copy = elem_size * DN_Min(*size, new_max);
DN_Memcpy(buffer, *data, bytes_to_copy);
DN_PoolDealloc(pool, *data);
*data = buffer;
*max = new_max;
*size = DN_Min(*size, new_max);
} else {
result = false;
}
}
return result;
}
DN_API bool DN_ArrayResizeFromPool(void **data, DN_USize *size, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize new_max)
{
bool result = true;
if (new_max != *max) {
DN_USize bytes_to_alloc = elem_size * new_max;
void *buffer = DN_PoolNewArray(pool, DN_U8, bytes_to_alloc);
if (buffer) {
DN_USize bytes_to_copy = elem_size * DN_Min(*size, new_max);
DN_Memcpy(buffer, *data, bytes_to_copy);
DN_PoolDealloc(pool, *data);
*data = buffer;
*max = new_max;
*size = DN_Min(*size, new_max);
} else {
result = false;
}
}
return result;
}
DN_API bool DN_ArrayResizeFromArena(void **data, DN_USize *size, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize new_max)
{
bool result = true;
if (new_max != *max) {
DN_USize bytes_to_alloc = elem_size * new_max;
void *buffer = DN_ArenaNewArray(arena, DN_U8, bytes_to_alloc, DN_ZMem_No);
if (buffer) {
DN_USize bytes_to_copy = elem_size * DN_Min(*size, new_max);
DN_Memcpy(buffer, *data, bytes_to_copy);
*data = buffer;
*max = new_max;
*size = DN_Min(*size, new_max);
} else {
result = false;
}
}
return result;
}
DN_API bool DN_ArrayGrowFromPool(void **data, DN_USize size, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize new_max)
{
bool result = true;
if (new_max > *max)
result = DN_ArrayResizeFromPool(data, &size, max, elem_size, pool, new_max);
return result;
}
DN_API bool DN_ArrayGrowFromArena(void **data, DN_USize size, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize new_max)
{
bool result = true;
if (new_max > *max)
result = DN_ArrayResizeFromArena(data, &size, max, elem_size, arena, new_max);
return result;
}
DN_API bool DN_ArrayGrowIfNeededFromPool(void **data, DN_USize size, DN_USize *max, DN_USize elem_size, DN_Pool *pool, DN_USize add_count)
{
bool result = true;
DN_USize new_size = size + add_count;
if (new_size > *max) {
DN_USize new_max = DN_Max(DN_Max(*max * 2, new_size), 8);
result = DN_ArrayResizeFromPool(data, &size, max, elem_size, pool, new_max);
}
return result;
}
DN_API bool DN_ArrayGrowIfNeededFromArena(void **data, DN_USize size, DN_USize *max, DN_USize elem_size, DN_Arena *arena, DN_USize add_count)
{
bool result = true;
DN_USize new_size = size + add_count;
if (new_size > *max) {
DN_USize new_max = DN_Max(DN_Max(*max * 2, new_size), 8);
result = DN_ArrayResizeFromArena(data, &size, max, elem_size, arena, new_max);
}
return result;
}
DN_API void *DN_SinglyLLDetach(void **link, void **next)
{
void *result = *link;
if (*link) {
*link = *next;
*next = nullptr;
}
return result;
}
DN_API bool DN_RingHasSpace(DN_Ring const *ring, DN_U64 size)
{
DN_U64 avail = ring->write_pos - ring->read_pos;
DN_U64 space = ring->size - avail;
bool result = space >= size;
return result;
}
DN_API bool DN_RingHasData(DN_Ring const *ring, DN_U64 size)
{
DN_U64 data = ring->write_pos - ring->read_pos;
bool result = data >= size;
return result;
}
DN_API void DN_RingWrite(DN_Ring *ring, void const *src, DN_U64 src_size)
{
DN_Assert(src_size <= ring->size);
DN_U64 offset = ring->write_pos % ring->size;
DN_U64 bytes_before_split = ring->size - offset;
DN_U64 pre_split_bytes = DN_Min(bytes_before_split, src_size);
DN_U64 post_split_bytes = src_size - pre_split_bytes;
void const *pre_split_data = src;
void const *post_split_data = ((char *)src + pre_split_bytes);
DN_Memcpy(ring->base + offset, pre_split_data, pre_split_bytes);
DN_Memcpy(ring->base, post_split_data, post_split_bytes);
ring->write_pos += src_size;
}
DN_API void DN_RingRead(DN_Ring *ring, void *dest, DN_U64 dest_size)
{
DN_Assert(dest_size <= ring->size);
DN_U64 offset = ring->read_pos % ring->size;
DN_U64 bytes_before_split = ring->size - offset;
DN_U64 pre_split_bytes = DN_Min(bytes_before_split, dest_size);
DN_U64 post_split_bytes = dest_size - pre_split_bytes;
DN_Memcpy(dest, ring->base + offset, pre_split_bytes);
DN_Memcpy((char *)dest + pre_split_bytes, ring->base, post_split_bytes);
ring->read_pos += dest_size;
}
template <typename T>
DN_DSMap<T> DN_DSMapInit(DN_Arena *arena, DN_U32 size, DN_DSMapFlags flags)
{
DN_DSMap<T> result = {};
if (!DN_CheckF(DN_IsPowerOfTwo(size), "Power-of-two size required, given size was '%u'", size))
return result;
if (size <= 0)
return result;
if (!DN_Check(arena))
return result;
result.arena = arena;
result.pool = DN_PoolFromArena(arena, DN_POOL_DEFAULT_ALIGN);
result.hash_to_slot = DN_ArenaNewArray(result.arena, DN_U32, size, DN_ZMem_Yes);
result.slots = DN_ArenaNewArray(result.arena, DN_DSMapSlot<T>, size, DN_ZMem_Yes);
result.occupied = 1; // For sentinel
result.size = size;
result.initial_size = size;
result.flags = flags;
DN_AssertF(result.hash_to_slot && result.slots, "We pre-allocated a block of memory sufficient in size for the 2 arrays. Maybe the pointers needed extra space because of natural alignment?");
return result;
}
template <typename T>
void DN_DSMapDeinit(DN_DSMap<T> *map, DN_ZMem z_mem)
{
if (!map)
return;
// TODO(doyle): Use z_mem
(void)z_mem;
DN_MemListDeinit(map->arena->mem);
*map = {};
}
template <typename T>
bool DN_DSMapIsValid(DN_DSMap<T> const *map)
{
bool result = map &&
map->arena &&
map->hash_to_slot && // Hash to slot mapping array must be allocated
map->slots && // Slots array must be allocated
(map->size & (map->size - 1)) == 0 && // Must be power of two size
map->occupied >= 1; // DN_DS_MAP_SENTINEL_SLOT takes up one slot
return result;
}
template <typename T>
DN_U32 DN_DSMapHash(DN_DSMap<T> const *map, DN_DSMapKey key)
{
DN_U32 result = 0;
if (!map)
return result;
if (key.type == DN_DSMapKeyType_U64NoHash) {
result = DN_Cast(DN_U32) key.u64;
return result;
}
if (key.type == DN_DSMapKeyType_BufferAsU64NoHash) {
result = key.hash;
return result;
}
DN_U32 seed = map->hash_seed ? map->hash_seed : DN_DS_MAP_DEFAULT_HASH_SEED;
if (map->hash_function) {
map->hash_function(key, seed);
} else {
// NOTE: Courtesy of Demetri Spanos (which this hash table was inspired
// from), the following is a hashing function snippet provided for
// reliable, quick and simple quality hashing functions for hash table
// use.
// Source: https://github.com/demetri/scribbles/blob/c475464756c104c91bab83ed4e14badefef12ab5/hashing/ub_aware_hash_functions.c
char const *key_ptr = nullptr;
DN_U32 len = 0;
DN_U32 h = seed;
switch (key.type) {
case DN_DSMapKeyType_BufferAsU64NoHash: /*FALLTHRU*/
case DN_DSMapKeyType_U64NoHash: DN_InvalidCodePath; /*FALLTHRU*/
case DN_DSMapKeyType_Invalid: break;
case DN_DSMapKeyType_Buffer:
key_ptr = DN_Cast(char const *) key.buffer_data;
len = key.buffer_size;
break;
case DN_DSMapKeyType_U64:
key_ptr = DN_Cast(char const *) & key.u64;
len = sizeof(key.u64);
break;
}
// Murmur3 32-bit without UB unaligned accesses
// DN_U32 mur3_32_no_UB(const void *key, int len, DN_U32 h)
// main body, work on 32-bit blocks at a time
for (DN_U32 i = 0; i < len / 4; i++) {
DN_U32 k;
memcpy(&k, &key_ptr[i * 4], sizeof(k));
k *= 0xcc9e2d51;
k = ((k << 15) | (k >> 17)) * 0x1b873593;
h = (((h ^ k) << 13) | ((h ^ k) >> 19)) * 5 + 0xe6546b64;
}
// load/mix up to 3 remaining tail bytes into a tail block
DN_U32 t = 0;
uint8_t *tail = ((uint8_t *)key_ptr) + 4 * (len / 4);
switch (len & 3) {
case 3: t ^= tail[2] << 16;
case 2: t ^= tail[1] << 8;
case 1: {
t ^= tail[0] << 0;
h ^= ((0xcc9e2d51 * t << 15) | (0xcc9e2d51 * t >> 17)) * 0x1b873593;
}
}
// finalization mix, including key length
h = ((h ^ len) ^ ((h ^ len) >> 16)) * 0x85ebca6b;
h = (h ^ (h >> 13)) * 0xc2b2ae35;
result = h ^ (h >> 16);
}
return result;
}
template <typename T>
DN_U32 DN_DSMapHashToSlotIndex(DN_DSMap<T> const *map, DN_DSMapKey key)
{
DN_Assert(key.type != DN_DSMapKeyType_Invalid);
DN_U32 result = DN_DS_MAP_SENTINEL_SLOT;
if (!DN_DSMapIsValid(map))
return result;
result = key.hash & (map->size - 1);
for (;;) {
if (result == DN_DS_MAP_SENTINEL_SLOT) // Sentinel is reserved
result++;
if (map->hash_to_slot[result] == DN_DS_MAP_SENTINEL_SLOT) // Slot is vacant, can use
return result;
DN_DSMapSlot<T> *slot = map->slots + map->hash_to_slot[result];
if (slot->key.type == DN_DSMapKeyType_Invalid || (slot->key.hash == key.hash && slot->key == key))
return result;
result = (result + 1) & (map->size - 1);
}
}
template <typename T>
DN_DSMapResult<T> DN_DSMapFind(DN_DSMap<T> const *map, DN_DSMapKey key)
{
DN_DSMapResult<T> result = {};
if (DN_DSMapIsValid(map)) {
DN_U32 index = DN_DSMapHashToSlotIndex(map, key);
if (index != DN_DS_MAP_SENTINEL_SLOT && map->hash_to_slot[index] == DN_DS_MAP_SENTINEL_SLOT) {
result.slot = map->slots; // NOTE: Set to sentinel value
} else {
result.slot = map->slots + map->hash_to_slot[index];
result.found = true;
}
result.value = &result.slot->value;
}
return result;
}
template <typename T>
DN_DSMapResult<T> DN_DSMapMake(DN_DSMap<T> *map, DN_DSMapKey key)
{
DN_DSMapResult<T> result = {};
if (!DN_DSMapIsValid(map))
return result;
DN_U32 index = DN_DSMapHashToSlotIndex(map, key);
if (map->hash_to_slot[index] == DN_DS_MAP_SENTINEL_SLOT) {
// NOTE: Create the slot
if (index != DN_DS_MAP_SENTINEL_SLOT)
map->hash_to_slot[index] = map->occupied++;
// NOTE: Check if resize is required
bool map_is_75pct_full = (map->occupied * 4) > (map->size * 3);
if (map_is_75pct_full) {
if (!DN_DSMapResize(map, map->size * 2))
return result;
result = DN_DSMapMake(map, key);
} else {
result.slot = map->slots + map->hash_to_slot[index];
result.slot->key = key; // NOTE: Assign key to new slot
if ((key.type == DN_DSMapKeyType_Buffer ||
key.type == DN_DSMapKeyType_BufferAsU64NoHash) &&
!key.no_copy_buffer)
result.slot->key.buffer_data = DN_PoolNewArrayCopy(&map->pool, char, key.buffer_data, key.buffer_size);
}
} else {
result.slot = map->slots + map->hash_to_slot[index];
result.found = true;
}
result.value = &result.slot->value;
DN_Assert(result.slot->key.type != DN_DSMapKeyType_Invalid);
return result;
}
template <typename T>
DN_DSMapResult<T> DN_DSMapSet(DN_DSMap<T> *map, DN_DSMapKey key, T const &value)
{
DN_DSMapResult<T> result = {};
if (!DN_DSMapIsValid(map))
return result;
result = DN_DSMapMake(map, key);
result.slot->value = value;
return result;
}
template <typename T>
DN_DSMapResult<T> DN_DSMapFindKeyU64(DN_DSMap<T> const *map, DN_U64 key)
{
DN_DSMapKey map_key = DN_DSMapKeyU64(map, key);
DN_DSMapResult<T> result = DN_DSMapFind(map, map_key);
return result;
}
template <typename T>
DN_DSMapResult<T> DN_DSMapMakeKeyU64(DN_DSMap<T> *map, DN_U64 key)
{
DN_DSMapKey map_key = DN_DSMapKeyU64(map, key);
DN_DSMapResult<T> result = DN_DSMapMake(map, map_key);
return result;
}
template <typename T>
DN_DSMapResult<T> DN_DSMapSetKeyU64(DN_DSMap<T> *map, DN_U64 key, T const &value)
{
DN_DSMapKey map_key = DN_DSMapKeyU64(map, key);
DN_DSMapResult<T> result = DN_DSMapSet(map, map_key, value);
return result;
}
template <typename T>
DN_DSMapResult<T> DN_DSMapFindKeyStr8(DN_DSMap<T> const *map, DN_Str8 key)
{
DN_DSMapKey map_key = DN_DSMapKeyStr8(map, key);
DN_DSMapResult<T> result = DN_DSMapFind(map, map_key);
return result;
}
template <typename T>
DN_DSMapResult<T> DN_DSMapMakeKeyStr8(DN_DSMap<T> *map, DN_Str8 key)
{
DN_DSMapKey map_key = DN_DSMapKeyStr8(map, key);
DN_DSMapResult<T> result = DN_DSMapMake(map, map_key);
return result;
}
template <typename T>
DN_DSMapResult<T> DN_DSMapSetKeyStr8(DN_DSMap<T> *map, DN_Str8 key, T const &value)
{
DN_DSMapKey map_key = DN_DSMapKeyStr8(map, key);
DN_DSMapResult<T> result = DN_DSMapSet(map, map_key);
return result;
}
template <typename T>
bool DN_DSMapResize(DN_DSMap<T> *map, DN_U32 size)
{
if (!DN_DSMapIsValid(map) || size < map->occupied || size < map->initial_size)
return false;
DN_Arena *prev_arena = map->arena;
DN_MemList *new_mem = prev_arena->mem;
DN_MemList prev_mem = *prev_arena->mem;
prev_arena->mem = &prev_mem;
*new_mem = {};
new_mem->funcs = prev_mem.funcs;
new_mem->flags = prev_mem.flags;
DN_Arena new_arena = {};
new_arena.mem = new_mem;
DN_DSMap<T> new_map = DN_DSMapInit<T>(&new_arena, size, map->flags);
if (!DN_DSMapIsValid(&new_map))
return false;
new_map.initial_size = map->initial_size;
for (DN_U32 old_index = 1 /*Sentinel*/; old_index < map->occupied; old_index++) {
DN_DSMapSlot<T> *old_slot = map->slots + old_index;
DN_DSMapKey old_key = old_slot->key;
if (old_key.type == DN_DSMapKeyType_Invalid)
continue;
DN_DSMapSet(&new_map, old_key, old_slot->value);
}
if ((map->flags & DN_DSMapFlags_DontFreeArenaOnResize) == 0)
DN_DSMapDeinit(map, DN_ZMem_No);
*map = new_map; // Update the map inplace
map->arena = prev_arena; // Restore the previous arena pointer, it's been de-init-ed
*map->arena = new_arena; // Re-init the old arena with the new data
map->pool.arena = map->arena;
return true;
}
template <typename T>
bool DN_DSMapErase(DN_DSMap<T> *map, DN_DSMapKey key)
{
if (!DN_DSMapIsValid(map))
return false;
DN_U32 index = DN_DSMapHashToSlotIndex(map, key);
if (index == 0)
return true;
DN_U32 slot_index = map->hash_to_slot[index];
if (slot_index == DN_DS_MAP_SENTINEL_SLOT)
return false;
// NOTE: Mark the slot as unoccupied
map->hash_to_slot[index] = DN_DS_MAP_SENTINEL_SLOT;
DN_DSMapSlot<T> *slot = map->slots + slot_index;
if (!slot->key.no_copy_buffer)
DN_PoolDealloc(&map->pool, DN_Cast(void *) slot->key.buffer_data);
*slot = {}; // TODO: Optional?
if (map->occupied > 1 /*Sentinel*/) {
// NOTE: Repair the hash chain, e.g. rehash all the items after the removed
// element and reposition them if necessary.
for (DN_U32 probe_index = index;;) {
probe_index = (probe_index + 1) & (map->size - 1);
if (map->hash_to_slot[probe_index] == DN_DS_MAP_SENTINEL_SLOT)
break;
DN_DSMapSlot<T> *probe = map->slots + map->hash_to_slot[probe_index];
DN_U32 new_index = probe->key.hash & (map->size - 1);
if (index <= probe_index) {
if (index < new_index && new_index <= probe_index)
continue;
} else {
if (index < new_index || new_index <= probe_index)
continue;
}
map->hash_to_slot[index] = map->hash_to_slot[probe_index];
map->hash_to_slot[probe_index] = DN_DS_MAP_SENTINEL_SLOT;
index = probe_index;
}
// NOTE: We have erased a slot from the hash table, this leaves a gap
// in our contiguous array. After repairing the chain, the hash mapping
// is correct.
// We will now fill in the vacant spot that we erased using the last
// element in the slot list.
if (map->occupied >= 3 /*Ignoring sentinel, at least 2 other elements to unstable erase*/) {
DN_U32 last_index = map->occupied - 1;
if (last_index != slot_index) {
// NOTE: Copy in last slot to the erase slot
DN_DSMapSlot<T> *last_slot = map->slots + last_index;
map->slots[slot_index] = *last_slot;
// NOTE: Update the hash-to-slot mapping for the value that was copied in
DN_U32 hash_to_slot_index = DN_DSMapHashToSlotIndex(map, last_slot->key);
map->hash_to_slot[hash_to_slot_index] = slot_index;
*last_slot = {}; // TODO: Optional?
}
}
}
map->occupied--;
bool map_is_below_25pct_full = (map->occupied * 4) < (map->size * 1);
if (map_is_below_25pct_full && (map->size / 2) >= map->initial_size)
DN_DSMapResize(map, map->size / 2);
return true;
}
template <typename T>
bool DN_DSMapEraseKeyU64(DN_DSMap<T> *map, DN_U64 key)
{
DN_DSMapKey map_key = DN_DSMapKeyU64(map, key);
bool result = DN_DSMapErase(map, map_key);
return result;
}
template <typename T>
bool DN_DSMapEraseKeyStr8(DN_DSMap<T> *map, DN_Str8 key)
{
DN_DSMapKey map_key = DN_DSMapKeyStr8(map, key);
bool result = DN_DSMapErase(map, map_key);
return result;
}
template <typename T>
DN_DSMapKey DN_DSMapKeyBuffer(DN_DSMap<T> const *map, void const *data, DN_USize size)
{
DN_Assert(size > 0 && size <= UINT32_MAX);
DN_DSMapKey result = {};
result.type = DN_DSMapKeyType_Buffer;
result.buffer_data = data;
result.buffer_size = DN_Cast(DN_U32) size;
result.hash = DN_DSMapHash(map, result);
return result;
}
template <typename T>
DN_DSMapKey DN_DSMapKeyBufferAsU64NoHash(DN_DSMap<T> const *map, void const *data, DN_USize size)
{
DN_DSMapKey result = {};
result.type = DN_DSMapKeyType_BufferAsU64NoHash;
result.buffer_data = data;
result.buffer_size = DN_Cast(DN_U32) size;
DN_Assert(size >= sizeof(result.hash));
DN_Memcpy(&result.hash, data, sizeof(result.hash));
return result;
}
template <typename T>
DN_DSMapKey DN_DSMapKeyU64(DN_DSMap<T> const *map, DN_U64 u64)
{
DN_DSMapKey result = {};
result.type = DN_DSMapKeyType_U64;
result.u64 = u64;
result.hash = DN_DSMapHash(map, result);
return result;
}
template <typename T>
DN_DSMapKey DN_DSMapKeyStr8(DN_DSMap<T> const *map, DN_Str8 string)
{
DN_DSMapKey result = DN_DSMapKeyBuffer(map, string.data, string.size);
return result;
}
// NOTE: DN_DSMap
DN_API DN_DSMapKey DN_DSMapKeyU64NoHash(DN_U64 u64)
{
DN_DSMapKey result = {};
result.type = DN_DSMapKeyType_U64NoHash;
result.u64 = u64;
result.hash = DN_Cast(DN_U32) u64;
return result;
}
DN_API bool DN_DSMapKeyEquals(DN_DSMapKey lhs, DN_DSMapKey rhs)
{
bool result = false;
if (lhs.type == rhs.type && lhs.hash == rhs.hash) {
switch (lhs.type) {
case DN_DSMapKeyType_Invalid: result = true; break;
case DN_DSMapKeyType_U64NoHash: result = true; break;
case DN_DSMapKeyType_U64: result = lhs.u64 == rhs.u64; break;
case DN_DSMapKeyType_BufferAsU64NoHash: /*FALLTHRU*/
case DN_DSMapKeyType_Buffer: {
if (lhs.buffer_size == rhs.buffer_size)
result = DN_Memcmp(lhs.buffer_data, rhs.buffer_data, lhs.buffer_size) == 0;
} break;
}
}
return result;
}
DN_API bool operator==(DN_DSMapKey lhs, DN_DSMapKey rhs)
{
bool result = DN_DSMapKeyEquals(lhs, rhs);
return result;
}
-135
View File
@@ -1,135 +0,0 @@
#define DN_BASE_LEAK_CPP
#if defined(_CLANGD)
#include "../dn.h"
#endif
DN_API void DN_LeakTrackAlloc_(DN_LeakTracker *leak, void *ptr, DN_USize size, bool leak_permitted)
{
if (!ptr)
return;
DN_TicketMutex_Begin(&leak->alloc_table_mutex);
DN_Str8 stack_trace = DN_Str8FromStackTraceNowHeap(128, 3 /*skip*/);
DN_DSMap<DN_LeakAlloc> *alloc_table = &leak->alloc_table;
DN_DSMapResult<DN_LeakAlloc> alloc_entry = DN_DSMapMakeKeyU64(alloc_table, DN_Cast(DN_U64) ptr);
DN_LeakAlloc *alloc = alloc_entry.value;
if (alloc_entry.found) {
if ((alloc->flags & DN_LeakAllocFlag_Freed) == 0) {
DN_Str8x32 alloc_size = DN_Str8x32FromByteCountU64Auto(alloc->size);
DN_Str8x32 new_alloc_size = DN_Str8x32FromByteCountU64Auto(size);
DN_HardAssertF(
alloc->flags & DN_LeakAllocFlag_Freed,
"This pointer is already in the leak tracker, however it has not been freed yet. This "
"same pointer is being ask to be tracked twice in the allocation table, e.g. one if its "
"previous free calls has not being marked freed with an equivalent call to "
"DN_LeakTrackDealloc()\n"
"\n"
"The pointer (0x%p) originally allocated %.*s at:\n"
"\n"
"%.*s\n"
"\n"
"The pointer is allocating %.*s again at:\n"
"\n"
"%.*s\n",
ptr,
DN_Str8PrintFmt(alloc_size),
DN_Str8PrintFmt(alloc->stack_trace),
DN_Str8PrintFmt(new_alloc_size),
DN_Str8PrintFmt(stack_trace));
}
// NOTE: Pointer was reused, clean up the prior entry
leak->alloc_table_bytes_allocated_for_stack_traces -= alloc->stack_trace.size;
leak->alloc_table_bytes_allocated_for_stack_traces -= alloc->freed_stack_trace.size;
DN_OS_MemDealloc(alloc->stack_trace.data);
DN_OS_MemDealloc(alloc->freed_stack_trace.data);
*alloc = {};
}
alloc->ptr = ptr;
alloc->size = size;
alloc->stack_trace = stack_trace;
alloc->flags |= leak_permitted ? DN_LeakAllocFlag_LeakPermitted : 0;
leak->alloc_table_bytes_allocated_for_stack_traces += alloc->stack_trace.size;
DN_TicketMutex_End(&leak->alloc_table_mutex);
}
DN_API void DN_LeakTrackDealloc_(DN_LeakTracker *leak, void *ptr)
{
if (!ptr)
return;
DN_TicketMutex_Begin(&leak->alloc_table_mutex);
DN_Str8 stack_trace = DN_Str8FromStackTraceNowHeap(128, 3 /*skip*/);
DN_DSMap<DN_LeakAlloc> *alloc_table = &leak->alloc_table;
DN_DSMapResult<DN_LeakAlloc> alloc_entry = DN_DSMapFindKeyU64(alloc_table, DN_Cast(uintptr_t) ptr);
DN_HardAssertF(alloc_entry.found,
"Allocated pointer can not be removed as it does not exist in the "
"allocation table. When this memory was allocated, the pointer was "
"not added to the allocation table [ptr=%p]",
ptr);
DN_LeakAlloc *alloc = alloc_entry.value;
if (alloc->flags & DN_LeakAllocFlag_Freed) {
DN_Str8x32 freed_size = DN_Str8x32FromByteCountU64Auto(alloc->freed_size);
DN_HardAssertF((alloc->flags & DN_LeakAllocFlag_Freed) == 0,
"Double free detected, pointer to free was already marked "
"as freed. Either the pointer was reallocated but not "
"traced, or, the pointer was freed twice.\n"
"\n"
"The pointer (0x%p) originally allocated %.*s at:\n"
"\n"
"%.*s\n"
"\n"
"The pointer was freed at:\n"
"\n"
"%.*s\n"
"\n"
"The pointer is being freed again at:\n"
"\n"
"%.*s\n",
ptr,
DN_Str8PrintFmt(freed_size),
DN_Str8PrintFmt(alloc->stack_trace),
DN_Str8PrintFmt(alloc->freed_stack_trace),
DN_Str8PrintFmt(stack_trace));
}
DN_Assert(alloc->freed_stack_trace.size == 0);
alloc->flags |= DN_LeakAllocFlag_Freed;
alloc->freed_stack_trace = stack_trace;
leak->alloc_table_bytes_allocated_for_stack_traces += alloc->freed_stack_trace.size;
DN_TicketMutex_End(&leak->alloc_table_mutex);
}
DN_API void DN_LeakDump_(DN_LeakTracker *leak)
{
DN_U64 leak_count = 0;
DN_U64 leaked_bytes = 0;
for (DN_USize index = 1; index < leak->alloc_table.occupied; index++) {
DN_DSMapSlot<DN_LeakAlloc> *slot = leak->alloc_table.slots + index;
DN_LeakAlloc *alloc = &slot->value;
bool alloc_leaked = (alloc->flags & DN_LeakAllocFlag_Freed) == 0;
bool leak_permitted = (alloc->flags & DN_LeakAllocFlag_LeakPermitted);
if (alloc_leaked && !leak_permitted) {
leaked_bytes += alloc->size;
leak_count++;
DN_Str8x32 alloc_size = DN_Str8x32FromByteCountU64Auto(alloc->size);
DN_LogWarningF(
"Pointer (0x%p) leaked %.*s at:\n"
"%.*s",
alloc->ptr,
DN_Str8PrintFmt(alloc_size),
DN_Str8PrintFmt(alloc->stack_trace));
}
}
if (leak_count) {
DN_Str8x32 leak_size = DN_Str8x32FromByteCountU64Auto(leaked_bytes);
DN_LogWarningF("There were %I64u leaked allocations totalling %.*s", leak_count, DN_Str8PrintFmt(leak_size));
}
}
-50
View File
@@ -1,50 +0,0 @@
#if !defined(DN_BASE_LEAK_H)
#define DN_BASE_LEAK_H
#if defined(_CLANGD)
#include "../dn.h"
#endif
enum DN_LeakAllocFlag
{
DN_LeakAllocFlag_Freed = 1 << 0,
DN_LeakAllocFlag_LeakPermitted = 1 << 1,
};
struct DN_LeakAlloc
{
void *ptr; // 8 Pointer to the allocation being tracked
DN_USize size; // 16 Size of the allocation
DN_USize freed_size; // 24 Store the size of the allocation when it is freed
DN_Str8 stack_trace; // 40 Stack trace at the point of allocation
DN_Str8 freed_stack_trace; // 56 Stack trace of where the allocation was freed
DN_U16 flags; // 72 Bit flags from `DN_LeakAllocFlag`
};
// NOTE: We aim to keep the allocation record as light as possible as memory tracking can get
// expensive. Enforce that there is no unexpected padding.
DN_StaticAssert(sizeof(DN_LeakAlloc) == 64 || sizeof(DN_LeakAlloc) == 32); // NOTE: 64 bit vs 32 bit pointers respectively
struct DN_LeakTracker
{
DN_DSMap<DN_LeakAlloc> alloc_table;
DN_TicketMutex alloc_table_mutex;
DN_MemList alloc_table_mem;
DN_Arena alloc_table_arena;
DN_U64 alloc_table_bytes_allocated_for_stack_traces;
};
DN_API void DN_LeakTrackAlloc_ (DN_LeakTracker *leak, void *ptr, DN_USize size, bool alloc_can_leak);
DN_API void DN_LeakTrackDealloc_(DN_LeakTracker *leak, void *ptr);
DN_API void DN_LeakDump_ (DN_LeakTracker *leak);
#if defined(DN_LEAK_TRACKING)
#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) DN_LeakTrackAlloc_(leak, ptr, size, alloc_can_leak)
#define DN_LeakTrackDealloc(leak, ptr) DN_LeakTrackDealloc_(leak, ptr)
#define DN_LeakDump(leak) DN_LeakDump_(leak)
#else
#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0)
#define DN_LeakTrackDealloc(leak, ptr) do { (void)ptr; } while (0)
#define DN_LeakDump(leak) do { } while (0)
#endif
#endif // DN_BASE_LEAK_H
-124
View File
@@ -1,124 +0,0 @@
#define DN_ASYNC_CPP
#if defined(_CLANGD)
#define DN_H_WITH_OS 1
#include "../dn.h"
#include "dn_async.h"
#endif
static DN_I32 DN_ASYNC_ThreadEntryPoint_(DN_OSThread *thread)
{
DN_OS_ThreadSetNameFmt("%.*s", DN_Str8PrintFmt(thread->name));
DN_ASYNCCore *async = DN_Cast(DN_ASYNCCore *) thread->user_context;
DN_Ring *ring = &async->ring;
for (;;) {
DN_OS_SemaphoreWait(&async->worker_sem, UINT32_MAX);
if (async->join_threads)
break;
DN_ASYNCTask task = {};
for (DN_OS_MutexScope(&async->ring_mutex)) {
if (DN_RingHasData(ring, sizeof(task)))
DN_RingRead(ring, &task, sizeof(task));
}
if (task.work.func) {
DN_OS_ConditionVariableBroadcast(&async->ring_write_cv); // Resume any blocked ring write(s)
DN_ASYNCWorkArgs args = {};
args.input = task.work.input;
args.thread = thread;
DN_AtomicAddU32(&async->busy_threads, 1);
task.work.func(args);
DN_AtomicSubU32(&async->busy_threads, 1);
if (task.completion_sem.handle != 0)
DN_OS_SemaphoreIncrement(&task.completion_sem, 1);
}
}
return 0;
}
DN_API void DN_ASYNC_Init(DN_ASYNCCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size)
{
DN_Assert(async);
async->ring.size = base_size;
async->ring.base = base;
async->ring_mutex = DN_OS_MutexInit();
async->ring_write_cv = DN_OS_ConditionVariableInit();
async->worker_sem = DN_OS_SemaphoreInit(0);
async->thread_count = threads_size;
async->threads = threads;
for (DN_ForIndexU(index, async->thread_count)) {
DN_OSThread *thread = async->threads + index;
DN_OS_ThreadInit(thread, DN_ASYNC_ThreadEntryPoint_, /*lane=*/ nullptr, DN_TCInitArgsDefault(), async);
}
}
DN_API void DN_ASYNC_Deinit(DN_ASYNCCore *async)
{
DN_Assert(async);
DN_AtomicSetValue32(&async->join_threads, true);
DN_OS_SemaphoreIncrement(&async->worker_sem, async->thread_count);
for (DN_ForItSize(it, DN_OSThread, async->threads, async->thread_count))
DN_OS_ThreadJoin(it.data, DN_TCDeinitArenas_Yes);
}
static bool DN_ASYNC_QueueTask_(DN_ASYNCCore *async, DN_ASYNCTask const *task, DN_U64 wait_time_ms) {
DN_U64 end_time_ms = DN_OS_DateUnixTimeMs() + wait_time_ms;
bool result = false;
for (DN_OS_MutexScope(&async->ring_mutex)) {
for (;;) {
if (DN_RingHasSpace(&async->ring, sizeof(*task))) {
DN_RingWriteStruct(&async->ring, task);
result = true;
break;
}
DN_OS_ConditionVariableWaitUntil(&async->ring_write_cv, &async->ring_mutex, end_time_ms);
if (DN_OS_DateUnixTimeMs() >= end_time_ms)
break;
}
}
if (result)
DN_OS_SemaphoreIncrement(&async->worker_sem, 1); // Flag that a job is available
return result;
}
DN_API bool DN_ASYNC_QueueWork(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms)
{
DN_ASYNCTask task = {};
task.work.func = func;
task.work.input = input;
bool result = DN_ASYNC_QueueTask_(async, &task, wait_time_ms);
return result;
}
DN_API DN_ASYNCTask DN_ASYNC_QueueTask(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms)
{
DN_ASYNCTask result = {};
result.work.func = func;
result.work.input = input;
result.completion_sem = DN_OS_SemaphoreInit(0);
result.queued = DN_ASYNC_QueueTask_(async, &result, wait_time_ms);
if (!result.queued)
DN_OS_SemaphoreDeinit(&result.completion_sem);
return result;
}
DN_API bool DN_ASYNC_WaitTask(DN_ASYNCTask *task, DN_U32 timeout_ms)
{
bool result = true;
if (!task->queued)
return result;
DN_OSSemaphoreWaitResult wait = DN_OS_SemaphoreWait(&task->completion_sem, timeout_ms);
result = wait == DN_OSSemaphoreWaitResult_Success;
if (result)
DN_OS_SemaphoreDeinit(&task->completion_sem);
return result;
}
-56
View File
@@ -1,56 +0,0 @@
#if !defined(DN_ASYNC_H)
#define DN_ASYNC_H
#if defined(_CLANGD)
#define DN_H_WITH_OS 1
#include "../dn.h"
#endif
enum DN_ASYNCPriority
{
DN_ASYNCPriority_Low,
DN_ASYNCPriority_High,
DN_ASYNCPriority_Count,
};
struct DN_ASYNCCore
{
DN_OSMutex ring_mutex;
DN_OSConditionVariable ring_write_cv;
DN_OSSemaphore worker_sem;
DN_Ring ring;
DN_OSThread *threads;
DN_U32 thread_count;
DN_U32 busy_threads;
DN_U32 join_threads;
};
struct DN_ASYNCWorkArgs
{
DN_OSThread *thread;
void *input;
};
typedef void(DN_ASYNCWorkFunc)(DN_ASYNCWorkArgs work_args);
struct DN_ASYNCWork
{
DN_ASYNCWorkFunc *func;
void *input;
void *output;
};
struct DN_ASYNCTask
{
bool queued;
DN_ASYNCWork work;
DN_OSSemaphore completion_sem;
};
DN_API void DN_ASYNC_Init (DN_ASYNCCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size);
DN_API void DN_ASYNC_Deinit (DN_ASYNCCore *async);
DN_API bool DN_ASYNC_QueueWork(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms);
DN_API DN_ASYNCTask DN_ASYNC_QueueTask(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms);
DN_API void DN_ASYNC_WaitTask (DN_OSSemaphore *sem, DN_U32 timeout_ms);
#endif // DN_ASYNC_H
-206
View File
@@ -1,206 +0,0 @@
#define DN_BIN_PACK_CPP
#if defined(_CLANGD)
#include "dn_bin_pack.h"
#endif
DN_API void DN_BinPackU64(DN_BinPack *pack, DN_BinPackMode mode, DN_U64 *item)
{
DN_U64 const VALUE_MASK = 0b0111'1111;
DN_U8 const CONTINUE_BIT = 0b1000'0000;
if (mode == DN_BinPackMode_Serialise) {
DN_U64 it = *item;
do {
DN_U8 write_value = DN_Cast(DN_U8)(it & VALUE_MASK);
it >>= 7;
if (it)
write_value |= CONTINUE_BIT;
DN_Str8BuilderAppendBytesCopy(&pack->writer, &write_value, sizeof(write_value));
} while (it);
} else {
*item = 0;
DN_USize bits_read = 0;
for (DN_U8 src = CONTINUE_BIT; (src & CONTINUE_BIT) && bits_read < 64; bits_read += 7) {
src = pack->read.data[pack->read_index++];
DN_U8 masked_src = src & VALUE_MASK;
*item |= (DN_Cast(DN_U64) masked_src << bits_read);
}
}
}
DN_API void DN_BinPackVarInt_(DN_BinPack *pack, DN_BinPackMode mode, void *item, DN_USize size)
{
DN_U64 value = 0;
DN_AssertF(size <= sizeof(value),
"An item larger than 64 bits (%zu) is trying to be packed as a variable integer which is not supported",
size * 8);
if (mode == DN_BinPackMode_Serialise) // Read `item` into U64 `value`
DN_Memcpy(&value, item, size);
DN_BinPackU64(pack, mode, &value);
if (mode == DN_BinPackMode_Deserialise) // Write U64 `value` into `item`
DN_Memcpy(item, &value, size);
}
DN_API bool DN_BinPackIsEndOfReadStream(DN_BinPack const *pack)
{
bool result = pack->read_index == pack->read.size;
return result;
}
DN_API void DN_BinPackUSize(DN_BinPack *pack, DN_BinPackMode mode, DN_USize *item)
{
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
}
DN_API void DN_BinPackU32(DN_BinPack *pack, DN_BinPackMode mode, DN_U32 *item)
{
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
}
DN_API void DN_BinPackU16(DN_BinPack *pack, DN_BinPackMode mode, DN_U16 *item)
{
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
}
DN_API void DN_BinPackU8(DN_BinPack *pack, DN_BinPackMode mode, DN_U8 *item)
{
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
}
DN_API void DN_BinPackI64(DN_BinPack *pack, DN_BinPackMode mode, DN_I64 *item)
{
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
}
DN_API void DN_BinPackI32(DN_BinPack *pack, DN_BinPackMode mode, DN_I32 *item)
{
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
}
DN_API void DN_BinPackI16(DN_BinPack *pack, DN_BinPackMode mode, DN_I16 *item)
{
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
}
DN_API void DN_BinPackI8(DN_BinPack *pack, DN_BinPackMode mode, DN_I8 *item)
{
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
}
DN_API void DN_BinPackF64(DN_BinPack *pack, DN_BinPackMode mode, DN_F64 *item)
{
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
}
DN_API void DN_BinPackF32(DN_BinPack *pack, DN_BinPackMode mode, DN_F32 *item)
{
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
}
#if defined(DN_MATH_H)
DN_API void DN_BinPackV2(DN_BinPack *pack, DN_BinPackMode mode, DN_V2F32 *item)
{
DN_BinPackF32(pack, mode, &item->x);
DN_BinPackF32(pack, mode, &item->y);
}
DN_API void DN_BinPackV4(DN_BinPack *pack, DN_BinPackMode mode, DN_V4F32 *item)
{
DN_BinPackF32(pack, mode, &item->x);
DN_BinPackF32(pack, mode, &item->y);
DN_BinPackF32(pack, mode, &item->z);
DN_BinPackF32(pack, mode, &item->w);
}
#endif
DN_API void DN_BinPackBool(DN_BinPack *pack, DN_BinPackMode mode, bool *item)
{
DN_BinPackVarInt_(pack, mode, item, sizeof(*item));
}
DN_API void DN_BinPackStr8FromArena(DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, DN_Str8 *string)
{
DN_BinPackVarInt_(pack, mode, &string->size, sizeof(string->size));
if (mode == DN_BinPackMode_Serialise) {
DN_Str8BuilderAppendBytesCopy(&pack->writer, string->data, string->size);
} else {
DN_Str8 src = DN_Str8Subset(pack->read, pack->read_index, string->size);
*string = DN_Str8FromStr8Arena(src, arena);
pack->read_index += src.size;
}
}
DN_API void DN_BinPackStr8FromPool(DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, DN_Str8 *string)
{
DN_BinPackVarInt_(pack, mode, &string->size, sizeof(string->size));
if (mode == DN_BinPackMode_Serialise) {
DN_Str8BuilderAppendBytesCopy(&pack->writer, string->data, string->size);
} else {
DN_Str8 src = DN_Str8Subset(pack->read, pack->read_index, string->size);
*string = DN_Str8FromStr8Pool(src, pool);
pack->read_index += src.size;
}
}
DN_API DN_Str8 DN_BinPackStr8FromBuffer(DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max)
{
DN_BinPackCBuffer(pack, mode, ptr, size, max);
DN_Str8 result = DN_Str8FromPtr(ptr, *size);
return result;
}
DN_API void DN_BinPackBytesFromArena(DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, void **ptr, DN_USize *size)
{
DN_Str8 string = DN_Str8FromPtr(*ptr, *size);
DN_BinPackStr8FromArena(pack, arena, mode, &string);
*ptr = string.data;
*size = string.size;
}
DN_API void DN_BinPackBytesFromPool(DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, void **ptr, DN_USize *size)
{
DN_Str8 string = DN_Str8FromPtr(*ptr, *size);
DN_BinPackStr8FromPool(pack, pool, mode, &string);
*ptr = string.data;
*size = string.size;
}
DN_API void DN_BinPackCArray(DN_BinPack *pack, DN_BinPackMode mode, void *ptr, DN_USize size)
{
DN_BinPackVarInt_(pack, mode, &size, sizeof(size));
if (mode == DN_BinPackMode_Serialise) {
DN_Str8BuilderAppendBytesCopy(&pack->writer, ptr, size);
} else {
DN_Str8 src = DN_Str8Subset(pack->read, pack->read_index, size);
DN_Assert(src.size == size);
DN_Memcpy(ptr, src.data, DN_Min(src.size, size));
pack->read_index += src.size;
}
}
DN_API void DN_BinPackCBuffer(DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max)
{
if (mode == DN_BinPackMode_Serialise) {
DN_BinPackUSize(pack, mode, size);
DN_Str8BuilderAppendBytesCopy(&pack->writer, ptr, *size);
} else {
DN_U64 size_u64 = 0;
DN_BinPackU64(pack, mode, &size_u64);
DN_Assert(size_u64 < DN_USIZE_MAX);
DN_Assert(size_u64 <= max);
*size = DN_Min(size_u64, max);
DN_Memcpy(ptr, pack->read.data + pack->read_index, *size);
pack->read_index += size_u64;
}
}
DN_API DN_Str8 DN_BinPackBuild(DN_BinPack const *pack, DN_Arena *arena)
{
DN_Str8 result = DN_Str8FromStr8BuilderArena(&pack->writer, arena);
return result;
}
-47
View File
@@ -1,47 +0,0 @@
#if !defined(DN_BIN_PACK_H)
#define DN_BIN_PACK_H
#if defined(_CLANGD)
#include "../dn.h"
#endif
enum DN_BinPackMode
{
DN_BinPackMode_Serialise,
DN_BinPackMode_Deserialise,
};
struct DN_BinPack
{
DN_Str8Builder writer;
DN_Str8 read;
DN_USize read_index;
};
DN_API bool DN_BinPackIsEndOfReadStream(DN_BinPack const *pack);
DN_API void DN_BinPackUSize (DN_BinPack *pack, DN_BinPackMode mode, DN_USize *item);
DN_API void DN_BinPackU64 (DN_BinPack *pack, DN_BinPackMode mode, DN_U64 *item);
DN_API void DN_BinPackU32 (DN_BinPack *pack, DN_BinPackMode mode, DN_U32 *item);
DN_API void DN_BinPackU16 (DN_BinPack *pack, DN_BinPackMode mode, DN_U16 *item);
DN_API void DN_BinPackU8 (DN_BinPack *pack, DN_BinPackMode mode, DN_U8 *item);
DN_API void DN_BinPackI64 (DN_BinPack *pack, DN_BinPackMode mode, DN_I64 *item);
DN_API void DN_BinPackI32 (DN_BinPack *pack, DN_BinPackMode mode, DN_I32 *item);
DN_API void DN_BinPackI16 (DN_BinPack *pack, DN_BinPackMode mode, DN_I16 *item);
DN_API void DN_BinPackI8 (DN_BinPack *pack, DN_BinPackMode mode, DN_I8 *item);
DN_API void DN_BinPackF64 (DN_BinPack *pack, DN_BinPackMode mode, DN_F64 *item);
DN_API void DN_BinPackF32 (DN_BinPack *pack, DN_BinPackMode mode, DN_F32 *item);
#if defined (DN_MATH_H)
DN_API void DN_BinPackV2 (DN_BinPack *pack, DN_BinPackMode mode, DN_V2F32 *item);
DN_API void DN_BinPackV4 (DN_BinPack *pack, DN_BinPackMode mode, DN_V4F32 *item);
#endif
DN_API void DN_BinPackBool (DN_BinPack *pack, DN_BinPackMode mode, bool *item);
DN_API void DN_BinPackStr8FromArena (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, DN_Str8 *string);
DN_API void DN_BinPackStr8FromPool (DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, DN_Str8 *string);
DN_API DN_Str8 DN_BinPackStr8FromBuffer (DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max);
DN_API void DN_BinPackBytesFromArena (DN_BinPack *pack, DN_Arena *arena, DN_BinPackMode mode, void **ptr, DN_USize *size);
DN_API void DN_BinPackBytesFromPool (DN_BinPack *pack, DN_Pool *pool, DN_BinPackMode mode, void **ptr, DN_USize *size);
DN_API void DN_BinPackCArray (DN_BinPack *pack, DN_BinPackMode mode, void *ptr, DN_USize size);
DN_API void DN_BinPackCBuffer (DN_BinPack *pack, DN_BinPackMode mode, char *ptr, DN_USize *size, DN_USize max);
DN_API DN_Str8 DN_BinPackBuild (DN_BinPack const *pack, DN_Arena *arena);
#endif // !defined(DN_BIN_PACK_H)
File diff suppressed because it is too large Load Diff
-185
View File
@@ -1,185 +0,0 @@
#if !defined(DN_CGEN_H)
#define DN_CGEN_H
#if defined(_CLANGD)
#define DN_H_WITH_OS 1
#include "../dn.h"
#include "../Standalone/dn_cpp_file.h"
#endif
#if !defined(DN_NO_METADESK)
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#define DN_UNDO_CRT_SECURE_NO_WARNINGS
#endif
// NOTE: Metadesk does not have the header for 'size_t'
#if defined(DN_COMPILER_GCC)
#include <stdint.h>
#endif
#define MD_DEFAULT_SPRINTF 0
#define MD_IMPL_Vsnprintf DN_VSNPrintF
#include "../External/metadesk/md.h"
#if defined(DN_UNDO_CRT_SECURE_NO_WARNINGS)
#undef _CRT_SECURE_NO_WARNINGS
#endif
#endif
#if !defined(DN_CPP_FILE_H)
#error dn_cpp_file.h must be included before this
#endif
#if defined(DN_PLATFORM_WINDOWS) && !defined(DN_NO_WINDOWS_H_REPLACEMENT_HEADER)
#error DN <Windows.h> replacement header must be disabled with DN_NO_WINDOWS_H_REPLACEMENT_HEADER since Metadesk includes <Windows.h>
#endif
#if !defined(MD_H)
#error Metadesk 'md.h' must be included before 'dn_cgen.h'
#endif
enum DN_CGenTableKeyType
{
DN_CGenTableKeyType_Nil,
DN_CGenTableKeyType_Name,
DN_CGenTableKeyType_Type,
};
enum DN_CGenTableType
{
DN_CGenTableType_Nil,
DN_CGenTableType_Data,
DN_CGenTableType_CodeGenBuiltinTypes,
DN_CGenTableType_CodeGenStruct,
DN_CGenTableType_CodeGenEnum,
DN_CGenTableType_Count,
};
enum DN_CGenTableRowTagType
{
DN_CGenTableRowTagType_Nil,
DN_CGenTableRowTagType_CommentDivider,
DN_CGenTableRowTagType_EmptyLine,
};
enum DN_CGenTableRowTagCommentDivider
{
DN_CGenTableRowTagCommentDivider_Nil,
DN_CGenTableRowTagCommentDivider_Label,
};
enum DN_CGenTableHeaderType
{
DN_CGenTableHeaderType_Name,
DN_CGenTableHeaderType_Table,
DN_CGenTableHeaderType_CppType,
DN_CGenTableHeaderType_CppName,
DN_CGenTableHeaderType_CppValue,
DN_CGenTableHeaderType_CppIsPtr,
DN_CGenTableHeaderType_CppOpEquals,
DN_CGenTableHeaderType_CppArraySize,
DN_CGenTableHeaderType_CppArraySizeField,
DN_CGenTableHeaderType_CppLabel,
DN_CGenTableHeaderType_GenTypeInfo,
DN_CGenTableHeaderType_GenEnumCount,
DN_CGenTableHeaderType_Count,
};
struct DN_CGenTableHeader
{
MD_String8 name;
int longest_string;
};
struct DN_CGenTableRowTag
{
DN_CGenTableRowTagType type;
MD_String8 comment;
DN_CGenTableRowTag *next;
};
struct DN_CGenTableColumn
{
MD_Node *node;
DN_Str8 string;
};
struct DN_CGenTableRow
{
DN_CGenTableRowTag *first_tag;
DN_CGenTableRowTag *last_tag;
DN_CGenTableColumn *columns;
};
struct DN_CGenTable
{
DN_CGenTableType type;
DN_Str8 name;
MD_Map headers_map;
DN_CGenTableHeader *headers;
DN_CGenTableRow *rows;
size_t column_count;
size_t row_count;
MD_Node *node;
MD_Node *headers_node;
DN_USize column_indexes[DN_CGenTableHeaderType_Count];
DN_CGenTable *next;
};
struct DN_CGen
{
MD_Arena *arena;
MD_Node *file_list;
MD_Map table_map;
DN_CGenTable *first_table;
DN_CGenTable *last_table;
DN_USize table_counts[DN_CGenTableType_Count];
};
struct DN_CGenMapNodeToEnum
{
uint32_t enum_val;
DN_Str8 node_string;
};
struct DN_CGenLookupTableIterator
{
DN_CGenTable *cgen_table;
DN_CGenTableRow *cgen_table_row;
DN_CGenTableColumn cgen_table_column[DN_CGenTableHeaderType_Count];
DN_CGenTable *table;
DN_USize row_index;
};
struct DN_CGenLookupColumnAtHeader
{
DN_USize index;
DN_CGenTableHeader header;
DN_CGenTableColumn column;
};
enum DN_CGenEmit
{
DN_CGenEmit_Prototypes = 1 << 0,
DN_CGenEmit_Implementation = 1 << 1,
};
#define DN_CGen_MDToDNStr8(str8) DN_Str8FromPtr((str8).str, (str8).size)
#define DN_CGen_DNToMDStr8(str8) \
{ \
DN_Cast(MD_u8 *) \
(str8).data, \
(str8).size \
}
DN_API DN_CGen DN_CGen_InitFilesArgV(int argc, char const **argv, DN_ErrSink *err);
DN_API DN_Str8 DN_CGen_TableHeaderTypeToDeclStr8(DN_CGenTableHeaderType type);
DN_API DN_CGenMapNodeToEnum DN_CGen_MapNodeToEnumOrExit(MD_Node const *node, DN_CGenMapNodeToEnum const *valid_keys, DN_USize valid_keys_size, char const *fmt, ...);
DN_API DN_USize DN_CGen_NodeChildrenCount(MD_Node const *node);
DN_API void DN_CGen_LogF(MD_MessageKind kind, MD_Node *node, DN_ErrSink *err, char const *fmt, ...);
DN_API bool DN_CGen_TableHasHeaders(DN_CGenTable const *table, DN_Str8 const *headers, DN_USize header_count, DN_ErrSink *err);
DN_API DN_CGenLookupColumnAtHeader DN_CGen_LookupColumnAtHeader(DN_CGenTable *table, DN_Str8 header, DN_CGenTableRow const *row);
DN_API bool DN_CGen_LookupNextTableInCodeGenTable(DN_CGen *cgen, DN_CGenTable *cgen_table, DN_CGenLookupTableIterator *it);
DN_API void DN_CGen_EmitCodeForTables(DN_CGen *cgen, DN_CGenEmit emit, DN_CppFile *cpp, DN_Str8 emit_prefix);
#endif // DN_CGEN_H
-290
View File
@@ -1,290 +0,0 @@
#define DN_CSV_CPP
#include "dn_csv.h"
DN_CSVTokeniser DN_CSV_TokeniserInit(DN_Str8 string, char delimiter)
{
DN_CSVTokeniser result = {};
result.string = string;
result.delimiter = delimiter;
return result;
}
bool DN_CSV_TokeniserValid(DN_CSVTokeniser *tokeniser)
{
bool result = tokeniser && !tokeniser->bad;
return result;
}
static void DN_CSV_TokeniserEatNewLines_(DN_CSVTokeniser *tokeniser)
{
char const *end = tokeniser->string.data + tokeniser->string.size;
while (tokeniser->it[0] == '\n' || tokeniser->it[0] == '\r')
if (++tokeniser->it == end)
break;
}
bool DN_CSV_TokeniserNextRow(DN_CSVTokeniser *tokeniser)
{
bool result = false;
if (DN_CSV_TokeniserValid(tokeniser) && tokeniser->string.size) {
// NOTE: First time querying row iterator is nil, let tokeniser advance
if (tokeniser->it) {
// NOTE: Only advance the tokeniser if we're at the end of the line and
// there's more to tokenise.
char const *end = tokeniser->string.data + tokeniser->string.size;
if (tokeniser->it != end && tokeniser->end_of_line) {
tokeniser->end_of_line = false;
result = true;
}
}
}
return result;
}
DN_Str8 DN_CSV_TokeniserNextField(DN_CSVTokeniser *tokeniser)
{
DN_Str8 result = {};
if (!DN_CSV_TokeniserValid(tokeniser))
return result;
if (tokeniser->string.size == 0) {
tokeniser->bad = true;
return result;
}
// NOTE: First time tokeniser is invoked with a string, set up initial state.
char const *string_end = tokeniser->string.data + tokeniser->string.size;
if (!tokeniser->it) {
tokeniser->it = tokeniser->string.data;
DN_CSV_TokeniserEatNewLines_(tokeniser); // NOTE: Skip any leading new lines
}
// NOTE: Tokeniser pointing at end, no more valid data to parse.
if (tokeniser->it == string_end)
return result;
// NOTE: Scan forward until the next control character.
// 1. '"' Double quoted field, extract everything between the quotes.
// 2. tokeniser->delimiter End of the field, extract everything leading up to the delimiter.
// 3. '\n' Last field in record, extract everything leading up the the new line.
char const *begin = tokeniser->it;
while (tokeniser->it != string_end && (tokeniser->it[0] != '"' &&
tokeniser->it[0] != tokeniser->delimiter &&
tokeniser->it[0] != '\n'))
tokeniser->it++;
bool quoted_field = (tokeniser->it != string_end) && tokeniser->it[0] == '"';
if (quoted_field) {
begin = ++tokeniser->it; // Begin after the quote
// NOTE: Scan forward until the next '"' which marks the end
// of the field unless it is escaped by another '"'.
find_next_quote:
while (tokeniser->it != string_end && tokeniser->it[0] != '"')
tokeniser->it++;
// NOTE: If we encounter a '"' right after, the quotes were escaped
// and we need to skip to the next instance of a '"'.
if (tokeniser->it != string_end && tokeniser->it + 1 != string_end && tokeniser->it[1] == '"') {
tokeniser->it += 2;
goto find_next_quote;
}
}
// NOTE: Mark the end of the field
char const *end = tokeniser->it;
tokeniser->end_of_line = tokeniser->it == string_end || end[0] == '\n';
// NOTE: In files with \r\n style new lines ensure that we don't include
// the \r byte in the CSV field we produce.
if (end != string_end && end[0] == '\n') {
DN_Assert((uintptr_t)(end - 1) > (uintptr_t)tokeniser->string.data &&
"Internal error: The string iterator is pointing behind the start of the string we're reading");
if (end[-1] == '\r')
end = end - 1;
}
// NOTE: Quoted fields may have whitespace after the closing quote, we skip
// until we reach the field terminator.
if (quoted_field)
while (tokeniser->it != string_end && (tokeniser->it[0] != tokeniser->delimiter && tokeniser->it[0] != '\n'))
tokeniser->it++;
// NOTE: Advance the tokeniser past the field terminator.
if (tokeniser->it != string_end)
tokeniser->it++;
// NOTE: Generate the record
result.data = DN_Cast(char *) begin;
result.size = DN_Cast(int)(end - begin);
return result;
}
DN_Str8 DN_CSV_TokeniserNextColumn(DN_CSVTokeniser *tokeniser)
{
DN_Str8 result = {};
if (!DN_CSV_TokeniserValid(tokeniser))
return result;
// NOTE: End of line, the user must explicitly advance to the next row
if (tokeniser->end_of_line)
return result;
// NOTE: Advance tokeniser to the next field in the row
result = DN_CSV_TokeniserNextField(tokeniser);
return result;
}
void DN_CSV_TokeniserSkipLine(DN_CSVTokeniser *tokeniser)
{
while (DN_CSV_TokeniserValid(tokeniser) && !tokeniser->end_of_line)
DN_CSV_TokeniserNextColumn(tokeniser);
DN_CSV_TokeniserNextRow(tokeniser);
}
int DN_CSV_TokeniserNextN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size, bool column_iterator)
{
if (!DN_CSV_TokeniserValid(tokeniser) || !fields || fields_size <= 0)
return 0;
int result = 0;
for (; result < fields_size; result++) {
fields[result] = column_iterator ? DN_CSV_TokeniserNextColumn(tokeniser) : DN_CSV_TokeniserNextField(tokeniser);
if (!DN_CSV_TokeniserValid(tokeniser) || !fields[result].data)
break;
}
return result;
}
int DN_CSV_TokeniserNextColumnN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size)
{
int result = DN_CSV_TokeniserNextN(tokeniser, fields, fields_size, true /*column_iterator*/);
return result;
}
int DN_CSV_TokeniserNextFieldN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size)
{
int result = DN_CSV_TokeniserNextN(tokeniser, fields, fields_size, false /*column_iterator*/);
return result;
}
void DN_CSV_TokeniserSkipLineN(DN_CSVTokeniser *tokeniser, int count)
{
for (int i = 0; i < count && DN_CSV_TokeniserValid(tokeniser); i++)
DN_CSV_TokeniserSkipLine(tokeniser);
}
void DN_CSV_PackU64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 *value)
{
if (serialise == DN_CSVSerialise_Read) {
DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser);
DN_U64FromResult to_u64 = DN_U64FromStr8(csv_value, 0);
DN_Assert(to_u64.success);
*value = to_u64.value;
} else {
DN_Str8BuilderAppendF(&pack->write_builder, "%s%" PRIu64, pack->write_column++ ? "," : "", *value);
}
}
void DN_CSV_PackI64(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 *value)
{
if (serialise == DN_CSVSerialise_Read) {
DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser);
DN_I64FromResult to_i64 = DN_I64FromStr8(csv_value, 0);
DN_Assert(to_i64.success);
*value = to_i64.value;
} else {
DN_Str8BuilderAppendF(&pack->write_builder, "%s%" PRIu64, pack->write_column++ ? "," : "", *value);
}
}
void DN_CSV_PackI32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 *value)
{
DN_I64 u64 = *value;
DN_CSV_PackI64(pack, serialise, &u64);
if (serialise == DN_CSVSerialise_Read)
*value = DN_SaturateCastI64ToI32(u64);
}
void DN_CSV_PackI16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 *value)
{
DN_I64 u64 = *value;
DN_CSV_PackI64(pack, serialise, &u64);
if (serialise == DN_CSVSerialise_Read)
*value = DN_SaturateCastI64ToI16(u64);
}
void DN_CSV_PackI8(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *value)
{
DN_I64 u64 = *value;
DN_CSV_PackI64(pack, serialise, &u64);
if (serialise == DN_CSVSerialise_Read)
*value = DN_SaturateCastI64ToI8(u64);
}
void DN_CSV_PackU32(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 *value)
{
DN_U64 u64 = *value;
DN_CSV_PackU64(pack, serialise, &u64);
if (serialise == DN_CSVSerialise_Read)
*value = DN_SaturateCastU64ToU32(u64);
}
void DN_CSV_PackU16(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 *value)
{
DN_U64 u64 = *value;
DN_CSV_PackU64(pack, serialise, &u64);
if (serialise == DN_CSVSerialise_Read)
*value = DN_SaturateCastU64ToU16(u64);
}
void DN_CSV_PackBoolAsU64(DN_CSVPack *pack, DN_CSVSerialise serialise, bool *value)
{
DN_U64 u64 = *value;
DN_CSV_PackU64(pack, serialise, &u64);
if (serialise == DN_CSVSerialise_Read)
*value = u64 ? 1 : 0;
}
void DN_CSV_PackStr8(DN_CSVPack *pack, DN_CSVSerialise serialise, DN_Str8 *str8, DN_Arena *arena)
{
if (serialise == DN_CSVSerialise_Read) {
DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser);
*str8 = DN_Str8FromStr8Arena(csv_value, arena);
} else {
DN_Str8BuilderAppendF(&pack->write_builder, "%s%.*s", pack->write_column++ ? "," : "", DN_Str8PrintFmt(*str8));
}
}
void DN_CSV_PackBuffer(DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size)
{
if (serialise == DN_CSVSerialise_Read) {
DN_Str8 csv_value = DN_CSV_TokeniserNextColumn(&pack->read_tokeniser);
*size = DN_Min(*size, csv_value.size);
DN_Memcpy(dest, csv_value.data, *size);
} else {
DN_Str8BuilderAppendF(&pack->write_builder, "%s%.*s", pack->write_column++ ? "," : "", DN_Cast(int)(*size), dest);
}
}
void DN_CSV_PackBufferWithMax(DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size, size_t max)
{
if (serialise == DN_CSVSerialise_Read)
*size = max;
DN_CSV_PackBuffer(pack, serialise, dest, size);
}
bool DN_CSV_PackNewLine(DN_CSVPack *pack, DN_CSVSerialise serialise)
{
bool result = true;
if (serialise == DN_CSVSerialise_Read) {
result = DN_CSV_TokeniserNextRow(&pack->read_tokeniser);
} else {
pack->write_column = 0;
result = DN_Str8BuilderAppendRef(&pack->write_builder, DN_Str8Lit("\n"));
}
return result;
}
-62
View File
@@ -1,62 +0,0 @@
#if !defined(DN_CSV_H)
#define DN_CSV_H
// NOTE: Data structures to create and parse CSV files, supports Python style escaped quotes (e.g.
// Using "" to escape quotes inside a quoted string).
//
// API
// DN_CSV_TokeniserNextN: Reads the next N consecutive fields from the parser. If `column_iterator`
// is `false` then the read of the N consecutive fields does not proceed past the end of the
// current CSV row. If `true` then it reads the next N fields even if reading would progress onto
// the next row.
#if defined(_CLANGD)
#include "../dn.h"
#endif
enum DN_CSVSerialise
{
DN_CSVSerialise_Read,
DN_CSVSerialise_Write,
};
struct DN_CSVTokeniser
{
bool bad;
DN_Str8 string;
char delimiter;
char const *it;
bool end_of_line;
};
struct DN_CSVPack
{
DN_Str8Builder write_builder;
DN_USize write_column;
DN_CSVTokeniser read_tokeniser;
};
DN_CSVTokeniser DN_CSV_TokeniserInit (DN_Str8 string, char delimiter);
bool DN_CSV_TokeniserValid (DN_CSVTokeniser *tokeniser);
bool DN_CSV_TokeniserNextRow (DN_CSVTokeniser *tokeniser);
DN_Str8 DN_CSV_TokeniserNextField (DN_CSVTokeniser *tokeniser);
DN_Str8 DN_CSV_TokeniserNextColumn (DN_CSVTokeniser *tokeniser);
void DN_CSV_TokeniserSkipLine (DN_CSVTokeniser *tokeniser);
int DN_CSV_TokeniserNextN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size, bool column_iterator);
int DN_CSV_TokeniserNextColumnN(DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size);
int DN_CSV_TokeniserNextFieldN (DN_CSVTokeniser *tokeniser, DN_Str8 *fields, int fields_size);
void DN_CSV_TokeniserSkipLineN (DN_CSVTokeniser *tokeniser, int count);
void DN_CSV_PackU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U64 *value);
void DN_CSV_PackI64 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I64 *value);
void DN_CSV_PackI32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I32 *value);
void DN_CSV_PackI16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I16 *value);
void DN_CSV_PackI8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_I8 *value);
void DN_CSV_PackU32 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U32 *value);
void DN_CSV_PackU16 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_U16 *value);
void DN_CSV_PackBoolAsU64 (DN_CSVPack *pack, DN_CSVSerialise serialise, bool *value);
void DN_CSV_PackStr8 (DN_CSVPack *pack, DN_CSVSerialise serialise, DN_Str8 *str8, DN_Arena *arena);
void DN_CSV_PackBuffer (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size);
void DN_CSV_PackBufferWithMax (DN_CSVPack *pack, DN_CSVSerialise serialise, void *dest, size_t *size, size_t max);
bool DN_CSV_PackNewLine (DN_CSVPack *pack, DN_CSVSerialise serialise);
#endif // !defined(DN_CSV_H)
File diff suppressed because it is too large Load Diff
-153
View File
@@ -1,153 +0,0 @@
#define DN_HELPERS_CPP
#if defined(_CLANGD)
#include "dn_helpers.h"
#endif
DN_API DN_JSONBuilder DN_JSONBuilder_Init(DN_Arena *arena, int spaces_per_indent)
{
DN_JSONBuilder result = {};
result.spaces_per_indent = spaces_per_indent;
result.string_builder.arena = arena;
return result;
}
DN_API DN_Str8 DN_JSONBuilder_Build(DN_JSONBuilder const *builder, DN_Arena *arena)
{
DN_Str8 result = DN_Str8FromStr8BuilderArena(&builder->string_builder, arena);
return result;
}
DN_API void DN_JSONBuilder_KeyValue(DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value)
{
if (key.size == 0 && value.size == 0)
return;
DN_JSONBuilderItem item = DN_JSONBuilderItem_KeyValue;
if (value.size >= 1) {
if (value.data[0] == '{' || value.data[0] == '[')
item = DN_JSONBuilderItem_OpenContainer;
else if (value.data[0] == '}' || value.data[0] == ']')
item = DN_JSONBuilderItem_CloseContainer;
}
bool adding_to_container_with_items =
item != DN_JSONBuilderItem_CloseContainer && (builder->last_item == DN_JSONBuilderItem_KeyValue ||
builder->last_item == DN_JSONBuilderItem_CloseContainer);
uint8_t prefix_size = 0;
char prefix[2] = {0};
if (adding_to_container_with_items)
prefix[prefix_size++] = ',';
if (builder->last_item != DN_JSONBuilderItem_Empty)
prefix[prefix_size++] = '\n';
if (item == DN_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)
DN_Str8BuilderAppendF(&builder->string_builder,
"%.*s%*c\"%.*s\": %.*s",
prefix_size,
prefix,
spaces,
' ',
DN_Str8PrintFmt(key),
DN_Str8PrintFmt(value));
else if (spaces == 0)
DN_Str8BuilderAppendF(&builder->string_builder, "%.*s%.*s", prefix_size, prefix, DN_Str8PrintFmt(value));
else
DN_Str8BuilderAppendF(&builder->string_builder, "%.*s%*c%.*s", prefix_size, prefix, spaces, ' ', DN_Str8PrintFmt(value));
if (item == DN_JSONBuilderItem_OpenContainer)
builder->indent_level++;
builder->last_item = item;
}
DN_API void DN_JSONBuilder_KeyValueFV(DN_JSONBuilder *builder, DN_Str8 key, char const *value_fmt, va_list args)
{
DN_TCScratch scratch = DN_TCScratchBeginArena(&builder->string_builder.arena, 1);
DN_Str8 value = DN_Str8FromFmtVArena(&scratch.arena, value_fmt, args);
DN_JSONBuilder_KeyValue(builder, key, value);
DN_TCScratchEnd(&scratch);
}
DN_API void DN_JSONBuilder_KeyValueF(DN_JSONBuilder *builder, DN_Str8 key, char const *value_fmt, ...)
{
va_list args;
va_start(args, value_fmt);
DN_JSONBuilder_KeyValueFV(builder, key, value_fmt, args);
va_end(args);
}
DN_API void DN_JSONBuilder_ObjectBeginNamed(DN_JSONBuilder *builder, DN_Str8 name)
{
DN_JSONBuilder_KeyValue(builder, name, DN_Str8Lit("{"));
}
DN_API void DN_JSONBuilder_ObjectEnd(DN_JSONBuilder *builder)
{
DN_JSONBuilder_KeyValue(builder, DN_Str8Lit(""), DN_Str8Lit("}"));
}
DN_API void DN_JSONBuilder_ArrayBeginNamed(DN_JSONBuilder *builder, DN_Str8 name)
{
DN_JSONBuilder_KeyValue(builder, name, DN_Str8Lit("["));
}
DN_API void DN_JSONBuilder_ArrayEnd(DN_JSONBuilder *builder)
{
DN_JSONBuilder_KeyValue(builder, DN_Str8Lit(""), DN_Str8Lit("]"));
}
DN_API void DN_JSONBuilder_Str8Named(DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value)
{
DN_JSONBuilder_KeyValueF(builder, key, "\"%.*s\"", value.size, value.data);
}
DN_API void DN_JSONBuilder_LiteralNamed(DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value)
{
DN_JSONBuilder_KeyValueF(builder, key, "%.*s", value.size, value.data);
}
DN_API void DN_JSONBuilder_U64Named(DN_JSONBuilder *builder, DN_Str8 key, uint64_t value)
{
DN_JSONBuilder_KeyValueF(builder, key, "%I64u", value);
}
DN_API void DN_JSONBuilder_I64Named(DN_JSONBuilder *builder, DN_Str8 key, int64_t value)
{
DN_JSONBuilder_KeyValueF(builder, key, "%I64d", value);
}
DN_API void DN_JSONBuilder_F64Named(DN_JSONBuilder *builder, DN_Str8 key, double value, int decimal_places)
{
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
DN_SNPrintF(float_fmt, sizeof(float_fmt), "%%.%df", decimal_places);
} else {
// NOTE: Emit the format string "%f"
DN_SNPrintF(float_fmt, sizeof(float_fmt), "%%f");
}
DN_JSONBuilder_KeyValueF(builder, key, float_fmt, value);
}
DN_API void DN_JSONBuilder_BoolNamed(DN_JSONBuilder *builder, DN_Str8 key, bool value)
{
DN_Str8 value_string = value ? DN_Str8Lit("true") : DN_Str8Lit("false");
DN_JSONBuilder_KeyValueF(builder, key, "%.*s", value_string.size, value_string.data);
}
-185
View File
@@ -1,185 +0,0 @@
#if !defined(DN_HELPERS_H)
#define DN_HELPERS_H
#if defined(_CLANGD)
#include "../dn.h"
#endif
/*
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\
// $$ | $$ |$$ _____|$$ | $$ __$$\ $$ _____|$$ __$$\ $$ __$$\
// $$ | $$ |$$ | $$ | $$ | $$ |$$ | $$ | $$ |$$ / \__|
// $$$$$$$$ |$$$$$\ $$ | $$$$$$$ |$$$$$\ $$$$$$$ |\$$$$$$\
// $$ __$$ |$$ __| $$ | $$ ____/ $$ __| $$ __$$< \____$$\
// $$ | $$ |$$ | $$ | $$ | $$ | $$ | $$ |$$\ $$ |
// $$ | $$ |$$$$$$$$\ $$$$$$$$\ $$ | $$$$$$$$\ $$ | $$ |\$$$$$$ |
// \__| \__|\________|\________|\__| \________|\__| \__| \______/
//
// dn_helpers.h -- Helper functions/data structures
//
////////////////////////////////////////////////////////////////////////////////////////////////////
*/
#if !defined(DN_NO_JSON_BUILDER)
enum DN_JSONBuilderItem
{
DN_JSONBuilderItem_Empty,
DN_JSONBuilderItem_OpenContainer,
DN_JSONBuilderItem_CloseContainer,
DN_JSONBuilderItem_KeyValue,
};
struct DN_JSONBuilder
{
bool use_stdout; // When set, ignore the string builder and dump immediately to stdout
DN_Str8Builder string_builder; // (Internal)
int indent_level; // (Internal)
int spaces_per_indent; // The number of spaces per indent level
DN_JSONBuilderItem last_item;
};
#endif // !defined(DN_NO_JSON_BUIDLER)
template <typename T>
using DN_BinarySearchLessThanProc = bool(T const &lhs, T const &rhs);
template <typename T>
bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
enum DN_BinarySearchType
{
// Index of the match. If no match is found, found is set to false and the
// index is set to the index where the match should be inserted/exist, if
// it were in the array
DN_BinarySearchType_Match,
// Index of the first element in the array that is `element >= find`. If no such
// item is found or the array is empty, then, the index is set to the array
// size and found is set to `false`.
//
// For example:
// int array[] = {0, 1, 2, 3, 4, 5};
// DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_LowerBound);
// printf("%zu\n", result.index); // Prints index '4'
DN_BinarySearchType_LowerBound,
// Index of the first element in the array that is `element > find`. If no such
// item is found or the array is empty, then, the index is set to the array
// size and found is set to `false`.
//
// For example:
// int array[] = {0, 1, 2, 3, 4, 5};
// DN_BinarySearchResult result = DN_BinarySearch(array, DN_ArrayCountU(array), 4, DN_BinarySearchType_UpperBound);
// printf("%zu\n", result.index); // Prints index '5'
DN_BinarySearchType_UpperBound,
};
struct DN_BinarySearchResult
{
bool found;
DN_USize index;
};
#if !defined(DN_NO_JSON_BUILDER)
// NOTE: DN_JSONBuilder
#define DN_JSONBuilder_Object(builder) \
DN_DeferLoop(DN_JSONBuilder_ObjectBegin(builder), \
DN_JSONBuilder_ObjectEnd(builder))
#define DN_JSONBuilder_ObjectNamed(builder, name) \
DN_DeferLoop(DN_JSONBuilder_ObjectBeginNamed(builder, name), \
DN_JSONBuilder_ObjectEnd(builder))
#define DN_JSONBuilder_Array(builder) \
DN_DeferLoop(DN_JSONBuilder_ArrayBegin(builder), \
DN_JSONBuilder_ArrayEnd(builder))
#define DN_JSONBuilder_ArrayNamed(builder, name) \
DN_DeferLoop(DN_JSONBuilder_ArrayBeginNamed(builder, name), \
DN_JSONBuilder_ArrayEnd(builder))
DN_API DN_JSONBuilder DN_JSONBuilder_Init (DN_Arena *arena, int spaces_per_indent);
DN_API DN_Str8 DN_JSONBuilder_Build (DN_JSONBuilder const *builder, DN_Arena *arena);
DN_API void DN_JSONBuilder_KeyValue (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value);
DN_API void DN_JSONBuilder_KeyValueF (DN_JSONBuilder *builder, DN_Str8 key, char const *value_fmt, ...);
DN_API void DN_JSONBuilder_ObjectBeginNamed (DN_JSONBuilder *builder, DN_Str8 name);
DN_API void DN_JSONBuilder_ObjectEnd (DN_JSONBuilder *builder);
DN_API void DN_JSONBuilder_ArrayBeginNamed (DN_JSONBuilder *builder, DN_Str8 name);
DN_API void DN_JSONBuilder_ArrayEnd (DN_JSONBuilder *builder);
DN_API void DN_JSONBuilder_Str8Named (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value);
DN_API void DN_JSONBuilder_LiteralNamed (DN_JSONBuilder *builder, DN_Str8 key, DN_Str8 value);
DN_API void DN_JSONBuilder_U64Named (DN_JSONBuilder *builder, DN_Str8 key, uint64_t value);
DN_API void DN_JSONBuilder_I64Named (DN_JSONBuilder *builder, DN_Str8 key, int64_t value);
DN_API void DN_JSONBuilder_F64Named (DN_JSONBuilder *builder, DN_Str8 key, double value, int decimal_places);
DN_API void DN_JSONBuilder_BoolNamed (DN_JSONBuilder *builder, DN_Str8 key, bool value);
#define DN_JSONBuilder_ObjectBegin(builder) DN_JSONBuilder_ObjectBeginNamed(builder, DN_Str8Lit(""))
#define DN_JSONBuilder_ArrayBegin(builder) DN_JSONBuilder_ArrayBeginNamed(builder, DN_Str8Lit(""))
#define DN_JSONBuilder_Str8(builder, value) DN_JSONBuilder_Str8Named(builder, DN_Str8Lit(""), value)
#define DN_JSONBuilder_Literal(builder, value) DN_JSONBuilder_LiteralNamed(builder, DN_Str8Lit(""), value)
#define DN_JSONBuilder_U64(builder, value) DN_JSONBuilder_U64Named(builder, DN_Str8Lit(""), value)
#define DN_JSONBuilder_I64(builder, value) DN_JSONBuilder_I64Named(builder, DN_Str8Lit(""), value)
#define DN_JSONBuilder_F64(builder, value) DN_JSONBuilder_F64Named(builder, DN_Str8Lit(""), value)
#define DN_JSONBuilder_Bool(builder, value) DN_JSONBuilder_BoolNamed(builder, DN_Str8Lit(""), value)
#endif // !defined(DN_NO_JSON_BUILDER)
// NOTE: DN_BinarySearch
template <typename T> bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs);
template <typename T> DN_BinarySearchResult DN_BinarySearch (T const *array, DN_USize array_size, T const &find, DN_BinarySearchType type = DN_BinarySearchType_Match, DN_BinarySearchLessThanProc<T> less_than = DN_BinarySearch_DefaultLessThan);
// NOTE: DN_BinarySearch
template <typename T>
bool DN_BinarySearch_DefaultLessThan(T const &lhs, T const &rhs)
{
bool result = lhs < rhs;
return result;
}
template <typename T>
DN_BinarySearchResult DN_BinarySearch(T const *array,
DN_USize array_size,
T const &find,
DN_BinarySearchType type,
DN_BinarySearchLessThanProc<T> less_than)
{
DN_BinarySearchResult result = {};
if (!array || array_size <= 0 || !less_than)
return result;
T const *end = array + array_size;
T const *first = array;
T const *last = end;
while (first != last) {
DN_USize count = last - first;
T const *it = first + (count / 2);
bool advance_first = false;
if (type == DN_BinarySearchType_UpperBound)
advance_first = !less_than(find, it[0]);
else
advance_first = less_than(it[0], find);
if (advance_first)
first = it + 1;
else
last = it;
}
switch (type) {
case DN_BinarySearchType_Match: {
result.found = first != end && !less_than(find, *first);
} break;
case DN_BinarySearchType_LowerBound: /*FALLTHRU*/
case DN_BinarySearchType_UpperBound: {
result.found = first != end;
} break;
}
result.index = first - array;
return result;
}
#endif // !defined(DN_HELPERS_H)
-428
View File
@@ -1,428 +0,0 @@
#define DN_JSON_CPP
// NOTE: DN_JSON //////////////////////////////////////////////////////////////////////////////////
void *DN_JSON_ArenaAllocFunc(void *user_data, size_t count)
{
void *result = NULL;
if (!user_data)
return result;
DN_Arena *arena = DN_Cast(DN_Arena*)user_data;
result = DN_ArenaAlloc(arena, count, alignof(json_value_s), DN_ZMem_No);
return result;
}
char const *DN_JSON_TypeEnumCString(json_type_e type, size_t *size)
{
switch (type) {
case json_type_string: { if (size) { *size = sizeof("string") - 1; } return "string"; }
case json_type_number: { if (size) { *size = sizeof("number") - 1; } return "number"; }
case json_type_object: { if (size) { *size = sizeof("object") - 1; } return "object"; }
case json_type_array: { if (size) { *size = sizeof("array") - 1; } return "array"; }
case json_type_true: { if (size) { *size = sizeof("true (boolean)") - 1; } return "true (boolean)"; }
case json_type_false: { if (size) { *size = sizeof("false (boolean)") - 1; } return "false (boolean)"; }
default: /*FALLTHRU*/
case json_type_null: { if (size) { *size = sizeof("(null)") - 1; } return "(null)"; }
}
}
bool DN_JSON_String8Cmp(json_string_s const *lhs, DN_Str8 key)
{
bool result = false;
if (lhs && key.size) {
DN_Str8 lhs_string = DN_Str8FromPtr(lhs->string, lhs->string_size);
result = DN_Str8Eq(lhs_string, key);
}
return result;
}
// NOTE: DN_JSON_It ///////////////////////////////////////////////////////////////////////////////
DN_JSONIt DN_JSON_LoadFileToIt(DN_Arena *arena, DN_Str8 json)
{
json_parse_result_s parse_result = {};
json_value_ex_s *ex_value =
DN_Cast(json_value_ex_s *) json_parse_ex(json.data,
json.size,
json_parse_flags_allow_location_information,
DN_JSON_ArenaAllocFunc,
arena,
&parse_result);
DN_JSONIt result = {};
DN_JSON_ItPushValue(&result, &ex_value->value);
return result;
}
// NOTE: DN_JSON_ItPush/Pop ///////////////////////////////////////////////////////////////////////
bool DN_JSON_ItPushObjElement(DN_JSONIt *it, json_object_element_s *element)
{
if (!it || !element)
return false;
DN_Assert(it->stack_count < DN_ArrayCountI(it->stack));
it->stack[it->stack_count++] = {DN_JSON_ItEntryTypeObjElement, element};
return true;
}
bool DN_JSON_ItPushObj(DN_JSONIt *it, json_object_s *obj)
{
if (!it || !obj)
return false;
DN_Assert(it->stack_count < DN_ArrayCountI(it->stack));
it->stack[it->stack_count++] = {DN_JSON_ItEntryTypeObj, obj};
return true;
}
bool DN_JSON_ItPushArrayElement(DN_JSONIt *it, json_array_element_s *element)
{
if (!it || !element)
return false;
DN_Assert(it->stack_count < DN_ArrayCountI(it->stack));
it->stack[it->stack_count++] = {DN_JSON_ItEntryTypeArrayElement, element};
return true;
}
bool DN_JSON_ItPushArray(DN_JSONIt *it, json_value_s *value)
{
if (!it || !value || json_value_as_array(value) == nullptr)
return false;
DN_Assert(it->stack_count < DN_ArrayCountI(it->stack));
it->stack[it->stack_count++] = {DN_JSON_ItEntryTypeArray, value};
return true;
}
bool DN_JSON_ItPushValue(DN_JSONIt *it, json_value_s *value)
{
bool result = false;
if (!it || !value)
return result;
if (value->type == json_type_object) {
result = DN_JSON_ItPushObj(it, json_value_as_object(value));
} else if (value->type == json_type_array) {
result = DN_JSON_ItPushArray(it, value);
}
return result;
}
void DN_JSON_ItPop(DN_JSONIt *it)
{
if (!it)
return;
DN_Assert(it->stack_count > 0);
if (it->stack_count > 0)
it->stack_count--;
}
// NOTE: DN_JSON_It JSON tree navigation //////////////////////////////////////////////////////////
json_value_s *DN_JSON_ItPushCurrValue(DN_JSONIt *it)
{
json_value_s *result = nullptr;
DN_JSONItEntry *curr = DN_JSON_ItCurr(it);
if (!curr)
return result;
if (curr->type == DN_JSON_ItEntryTypeObjElement) {
json_object_element_s *element = DN_Cast(json_object_element_s *) curr->value;
result = element->value;
} else if (curr->type == DN_JSON_ItEntryTypeArrayElement) {
json_array_element_s *element = DN_Cast(json_array_element_s *) curr->value;
result = element->value;
} else {
result = DN_Cast(json_value_s *) curr->value;
}
if (result->type == json_type_array) {
json_array_s *array = json_value_as_array(result);
DN_Assert(array);
DN_JSON_ItPushArray(it, result);
} else if (result->type == json_type_object) {
json_object_s *obj = json_value_as_object(result);
DN_Assert(obj);
DN_JSON_ItPushObj(it, obj);
}
return result;
}
bool DN_JSON_ItNext(DN_JSONIt *it)
{
DN_JSONItEntry *curr = DN_JSON_ItCurr(it);
if (!curr)
return false;
json_object_element_s *obj_element = nullptr;
json_array_element_s *array_element = nullptr;
if (curr->type == DN_JSON_ItEntryTypeObj) {
auto *obj = DN_Cast(json_object_s *) curr->value;
obj_element = obj->start;
} else if (curr->type == DN_JSON_ItEntryTypeObjElement) {
auto *element = DN_Cast(json_object_element_s *) curr->value;
obj_element = element->next;
DN_JSON_ItPop(it);
} else if (curr->type == DN_JSON_ItEntryTypeArray) {
auto *value = DN_Cast(json_value_s *) curr->value;
auto *array = json_value_as_array(value);
array_element = array->start;
} else if (curr->type == DN_JSON_ItEntryTypeArrayElement) {
auto *element = DN_Cast(json_array_element_s *) curr->value;
array_element = element->next;
DN_JSON_ItPop(it);
} else {
DN_JSON_ItPop(it);
}
if (obj_element)
DN_JSON_ItPushObjElement(it, obj_element);
else if (array_element)
DN_JSON_ItPushArrayElement(it, array_element);
bool result = obj_element || array_element;
return result;
}
// NOTE: DN_JSON_ItCurr ///////////////////////////////////////////////////////////////////////////
DN_JSONItEntry *DN_JSON_ItCurr(DN_JSONIt *it)
{
DN_JSONItEntry *result = nullptr;
if (!it || it->stack_count <= 0)
return result;
result = &it->stack[it->stack_count - 1];
return result;
}
json_value_s *DN_JSON_ItCurrValue(DN_JSONIt *it)
{
json_value_s *result = nullptr;
DN_JSONItEntry *curr = DN_JSON_ItCurr(it);
if (!curr)
return result;
if (curr->type == DN_JSON_ItEntryTypeObjElement) {
auto *element = DN_Cast(json_object_element_s *)curr->value;
result = element->value;
} else if (curr->type == DN_JSON_ItEntryTypeArrayElement) {
auto *element = DN_Cast(json_array_element_s *)curr->value;
result = element->value;
} else if (curr->type == DN_JSON_ItEntryTypeString ||
curr->type == DN_JSON_ItEntryTypeNumber ||
curr->type == DN_JSON_ItEntryTypeObj ||
curr->type == DN_JSON_ItEntryTypeArray)
{
result = DN_Cast(json_value_s *)curr->value;
}
return result;
}
json_object_element_s *DN_JSON_ItCurrObjElement(DN_JSONIt *it)
{
DN_JSONItEntry *curr = DN_JSON_ItCurr(it);
auto *result = (curr && curr->type == DN_JSON_ItEntryTypeObjElement)
? DN_Cast(json_object_element_s *) curr->value
: nullptr;
return result;
}
// NOTE: DN_JSON_ItValueIs ////////////////////////////////////////////////////////////////////////
json_value_s *DN_JSON_ItValueIs(DN_JSONIt *it, json_type_e type)
{
json_value_s *curr = DN_JSON_ItCurrValue(it);
json_value_s *result = (curr && type == curr->type) ? curr : nullptr;
return result;
}
json_object_s *DN_JSON_ItValueIsObj(DN_JSONIt *it)
{
json_value_s *curr = DN_JSON_ItCurrValue(it);
json_object_s *result = curr ? json_value_as_object(curr) : nullptr;
return result;
}
json_array_s *DN_JSON_ItValueIsArray(DN_JSONIt *it)
{
json_value_s *curr = DN_JSON_ItCurrValue(it);
json_array_s *result = curr ? json_value_as_array(curr) : nullptr;
return result;
}
json_string_s *DN_JSON_ItValueIsString(DN_JSONIt *it)
{
json_value_s *curr = DN_JSON_ItCurrValue(it);
json_string_s *result = curr ? json_value_as_string(curr) : nullptr;
return result;
}
json_number_s *DN_JSON_ItValueIsNumber(DN_JSONIt *it)
{
json_value_s *curr = DN_JSON_ItCurrValue(it);
json_number_s *result = curr ? json_value_as_number(curr) : nullptr;
return result;
}
json_value_s *DN_JSON_ItValueIsBool(DN_JSONIt *it)
{
json_value_s *curr = DN_JSON_ItCurrValue(it);
json_value_s *result = (curr && (curr->type == json_type_true || curr->type == json_type_false)) ? curr : nullptr;
return result;
}
json_value_s *DN_JSON_ItValueIsNull(DN_JSONIt *it)
{
json_value_s *curr = DN_JSON_ItCurrValue(it);
json_value_s *result = (curr && (curr->type == json_type_null)) ? curr : nullptr;
return result;
}
size_t DN_JSON_ItValueArraySize(DN_JSONIt *it)
{
size_t result = 0;
if (json_array_s *curr = DN_JSON_ItValueIsArray(it))
result = curr->length;
return result;
}
// NOTE: DN_JSON_ItKeyValueIs /////////////////////////////////////////////////////////////////////
DN_Str8 DN_JSON_ItKey(DN_JSONIt *it)
{
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
DN_Str8 result = {};
if (curr) {
result.data = DN_Cast(char *)curr->name->string;
result.size = curr->name->string_size;
}
return result;
}
bool DN_JSON_ItKeyIs(DN_JSONIt *it, DN_Str8 key)
{
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
bool result = DN_JSON_String8Cmp(curr->name, key);
return result;
}
json_object_s *DN_JSON_ItKeyValueIsObj(DN_JSONIt *it, DN_Str8 key)
{
json_object_s *result = nullptr;
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
if (curr && DN_JSON_String8Cmp(curr->name, key))
result = json_value_as_object(curr->value);
return result;
}
json_array_s *DN_JSON_ItKeyValueIsArray(DN_JSONIt *it, DN_Str8 key)
{
json_array_s *result = nullptr;
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
if (curr && DN_JSON_String8Cmp(curr->name, key))
result = json_value_as_array(curr->value);
return result;
}
json_string_s *DN_JSON_ItKeyValueIsString(DN_JSONIt *it, DN_Str8 key)
{
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
json_string_s *result = nullptr;
if (curr && DN_JSON_String8Cmp(curr->name, key))
result = json_value_as_string(curr->value);
return result;
}
json_number_s *DN_JSON_ItKeyValueIsNumber(DN_JSONIt *it, DN_Str8 key)
{
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
json_number_s *result = nullptr;
if (curr && DN_JSON_String8Cmp(curr->name, key))
result = json_value_as_number(curr->value);
return result;
}
json_value_s *DN_JSON_ItKeyValueIsBool(DN_JSONIt *it, DN_Str8 key)
{
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
json_value_s *result = nullptr;
if (curr && DN_JSON_String8Cmp(curr->name, key))
result = curr->value->type == json_type_true || curr->value->type == json_type_false ? curr->value : nullptr;
return result;
}
json_value_s *DN_JSON_ItKeyValueIsNull(DN_JSONIt *it, DN_Str8 key)
{
json_object_element_s *curr = DN_JSON_ItCurrObjElement(it);
json_value_s *result = nullptr;
if (curr && DN_JSON_String8Cmp(curr->name, key))
result = curr->value->type == json_type_null ? curr->value : nullptr;
return result;
}
// NOTE: DN_JSON_ItValueTo ////////////////////////////////////////////////////////////////////////
DN_Str8 DN_JSON_ItValueToString(DN_JSONIt *it)
{
DN_Str8 result = {};
if (json_string_s *curr = DN_JSON_ItValueIsString(it))
result = DN_Str8FromPtr(curr->string, curr->string_size);
return result;
}
int64_t DN_JSON_ItValueToI64(DN_JSONIt *it)
{
int64_t result = {};
if (json_number_s *curr = DN_JSON_ItValueIsNumber(it))
result = DN_I64FromStr8(DN_Str8FromPtr(curr->number, curr->number_size), 0 /*separator*/).value;
return result;
}
uint64_t DN_JSON_ItValueToU64(DN_JSONIt *it)
{
uint64_t result = {};
if (json_number_s *curr = DN_JSON_ItValueIsNumber(it))
result = DN_U64FromStr8(DN_Str8FromPtr(curr->number, curr->number_size), 0 /*separator*/).value;
return result;
}
bool DN_JSON_ItValueToBool(DN_JSONIt *it)
{
bool result = {};
if (json_value_s *curr = DN_JSON_ItValueIsBool(it))
result = curr->type == json_type_true;
return result;
}
void DN_JSON_ItErrorUnknownKeyValue_(DN_JSONIt *it, DN_CallSite call_site)
{
if (!it)
return;
json_object_element_s const *curr = DN_JSON_ItCurrObjElement(it);
if (!curr)
return;
size_t value_type_size = 0;
char const *value_type = DN_JSON_TypeEnumCString(DN_Cast(json_type_e)curr->value->type, &value_type_size);
json_string_s const *key = curr->name;
if (it->flags & json_parse_flags_allow_location_information) {
json_string_ex_s const *info = DN_Cast(json_string_ex_s const *)key;
DN_LogEmitFromType(DN_LogMakeU32LogTypeParam(DN_LogType_Warning),
call_site,
"Unknown key-value pair in object [loc=%zu:%zu, key=%.*s, value=%.*s]",
info->line_no,
info->row_no,
DN_Cast(int) key->string_size,
key->string,
DN_Cast(int) value_type_size,
value_type);
} else {
DN_LogEmitFromType(DN_LogMakeU32LogTypeParam(DN_LogType_Warning),
call_site,
"Unknown key-value pair in object [key=%.*s, value=%.*s]",
DN_Cast(int) key->string_size,
key->string,
DN_Cast(int) value_type_size,
value_type);
}
}
-96
View File
@@ -1,96 +0,0 @@
#if !defined(DN_JSON_H)
#define DN_JSON_H
#if defined(_CLANGD)
#include "../dn.h"
#include "../External/json.h"
#endif
#if !defined(SHEREDOM_JSON_H_INCLUDED)
#error Sheredom json.h (github.com/sheredom/json.h) must be included before this file
#endif
// NOTE: DN_JSON
void *DN_JSON_ArenaAllocFunc (void *user_data, size_t count);
char const *DN_JSON_TypeEnumCString(json_type_e type, size_t *size);
bool DN_JSON_String8Cmp (json_string_s const *lhs, DN_Str8 rhs);
// NOTE: DN_JSON_It
enum DN_JSONItEntryType
{
DN_JSON_ItEntryTypeObjElement,
DN_JSON_ItEntryTypeObj,
DN_JSON_ItEntryTypeArrayElement,
DN_JSON_ItEntryTypeArray,
DN_JSON_ItEntryTypeString,
DN_JSON_ItEntryTypeNumber,
};
struct DN_JSONItEntry
{
DN_JSONItEntryType type;
void *value;
};
struct DN_JSONIt
{
DN_JSONItEntry stack[128];
int stack_count;
size_t flags;
};
DN_JSONIt DN_JSON_LoadFileToIt(DN_Arena *arena, DN_Str8 json);
// NOTE: DN_JSON_ItPush/Pop
bool DN_JSON_ItPushObjElement (DN_JSONIt *it, json_object_element_s *element);
bool DN_JSON_ItPushObj (DN_JSONIt *it, json_object_s *obj);
bool DN_JSON_ItPushArrayElement(DN_JSONIt *it, json_array_element_s *element);
bool DN_JSON_ItPushArray (DN_JSONIt *it, json_value_s *value);
bool DN_JSON_ItPushValue (DN_JSONIt *it, json_value_s *value);
void DN_JSON_ItPop (DN_JSONIt *it);
// NOTE: DN_JSON_It tree navigation
json_value_s *DN_JSON_ItPushCurrValue(DN_JSONIt *it);
bool DN_JSON_ItNext(DN_JSONIt *it);
#define DN_JSON_ItPushCurrValueIterateThenPop(it) \
for(void *DN_UniqueName(ptr) = DN_JSON_ItPushCurrValue(it); DN_UniqueName(ptr); DN_JSON_ItPop(it), DN_UniqueName(ptr) = nullptr) \
while (DN_JSON_ItNext(it))
// NOTE: DN_JSON_ItCurr
DN_JSONItEntry *DN_JSON_ItCurr(DN_JSONIt *it);
json_value_s *DN_JSON_ItCurrValue(DN_JSONIt *it);
json_object_element_s *DN_JSON_ItCurrObjElement(DN_JSONIt *it);
// NOTE: DN_JSON_ItValueIs
json_value_s *DN_JSON_ItValueIs(DN_JSONIt *it, json_type_e type);
json_object_s *DN_JSON_ItValueIsObj(DN_JSONIt *it);
json_array_s *DN_JSON_ItValueIsArray(DN_JSONIt *it);
json_string_s *DN_JSON_ItValueIsString(DN_JSONIt *it);
json_number_s *DN_JSON_ItValueIsNumber(DN_JSONIt *it);
json_value_s *DN_JSON_ItValueIsBool(DN_JSONIt *it);
json_value_s *DN_JSON_ItValueIsNull(DN_JSONIt *it);
size_t DN_JSON_ItValueArraySize(DN_JSONIt *it);
// NOTE: DN_JSON_ItKeyValueIs
DN_Str8 DN_JSON_ItKey(DN_JSONIt *it);
bool DN_JSON_ItKeyIs(DN_JSONIt *it, DN_Str8 key);
json_object_s *DN_JSON_ItKeyValueIsObj(DN_JSONIt *it, DN_Str8 key);
json_array_s *DN_JSON_ItKeyValueIsArray(DN_JSONIt *it, DN_Str8 key);
json_string_s *DN_JSON_ItKeyValueIsString(DN_JSONIt *it, DN_Str8 key);
json_number_s *DN_JSON_ItKeyValueIsNumber(DN_JSONIt *it, DN_Str8 key);
json_value_s *DN_JSON_ItKeyValueIsBool(DN_JSONIt *it, DN_Str8 key);
json_value_s *DN_JSON_ItKeyValueIsNull(DN_JSONIt *it, DN_Str8 key);
// NOTE: DN_JSON_ItValueTo
DN_Str8 DN_JSON_ItValueToString(DN_JSONIt *it);
int64_t DN_JSON_ItValueToI64(DN_JSONIt *it);
uint64_t DN_JSON_ItValueToU64(DN_JSONIt *it);
bool DN_JSON_ItValueToBool(DN_JSONIt *it);
#define DN_JSON_ItErrorUnknownKeyValue(it) DN_JSON_ItErrorUnknownKeyValue_(it, DN_CALL_SITE)
void DN_JSON_ItErrorUnknownKeyValue_(DN_JSONIt *it, DN_CallSite call_site);
#endif // !defined(DN_JSON_H)
-85
View File
@@ -1342,90 +1342,6 @@ static DN_UTCore DN_TST_BaseArray()
return result; return result;
} }
static DN_UTCore DN_TST_BaseVArray()
{
DN_UTCore result = DN_UT_Init();
DN_UT_LogF(&result, "DN_VArray\n");
{
{
DN_VArray<DN_U32> array = DN_OS_VArrayInitByteSize<DN_U32>(DN_Kilobytes(64));
DN_DEFER
{
DN_OS_VArrayDeinit(&array);
};
for (DN_UT_Test(&result, "Test adding an array of items to the array")) {
DN_U32 array_literal[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
DN_OS_VArrayAddArray<DN_U32>(&array, array_literal, DN_ArrayCountU(array_literal));
DN_UT_Assert(&result, array.size == DN_ArrayCountU(array_literal));
DN_UT_Assert(&result, DN_Memcmp(array.data, array_literal, DN_ArrayCountU(array_literal) * sizeof(array_literal[0])) == 0);
}
for (DN_UT_Test(&result, "Test adding an array of items")) {
DN_U32 array_literal[] = {0, 1, 2, 3};
DN_OS_VArrayAddArray<DN_U32>(&array, array_literal, DN_ArrayCountU(array_literal));
DN_U32 expected_literal[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3};
DN_UT_Assert(&result, array.size == DN_ArrayCountU(expected_literal));
DN_UT_Assert(&result, DN_Memcmp(array.data, expected_literal, DN_ArrayCountU(expected_literal) * sizeof(expected_literal[0])) == 0);
}
}
for (DN_UT_Test(&result, "Array of unaligned objects are contiguously laid out in memory")) {
// NOTE: Since we allocate from a virtual memory block, each time
// we request memory from the block we can demand some alignment
// on the returned pointer from the memory block. If there's
// additional alignment done in that function then we can no
// longer access the items in the array contiguously leading to
// confusing memory "corruption" errors.
//
// This result makes sure that the unaligned objects are allocated
// from the memory block (and hence the array) contiguously
// when the size of the object is not aligned with the required
// alignment of the object.
DN_MSVC_WARNING_PUSH
DN_MSVC_WARNING_DISABLE(4324) // warning C4324: 'TestVArray::UnalignedObject': structure was padded due to alignment specifier
struct alignas(8) UnalignedObject
{
char data[511];
};
DN_MSVC_WARNING_POP
DN_VArray<UnalignedObject> array = DN_OS_VArrayInitByteSize<UnalignedObject>(DN_Kilobytes(64));
DN_DEFER
{
DN_OS_VArrayDeinit(&array);
};
// NOTE: Verify that the items returned from the data array are
// contiguous in memory.
UnalignedObject *make_item_a = DN_OS_VArrayMakeArray(&array, 1, DN_ZMem_Yes);
UnalignedObject *make_item_b = DN_OS_VArrayMakeArray(&array, 1, DN_ZMem_Yes);
DN_Memset(make_item_a->data, 'a', sizeof(make_item_a->data));
DN_Memset(make_item_b->data, 'b', sizeof(make_item_b->data));
DN_UT_Assert(&result, (uintptr_t)make_item_b == (uintptr_t)(make_item_a + 1));
// NOTE: Verify that accessing the items from the data array yield
// the same object.
DN_UT_Assert(&result, array.size == 2);
UnalignedObject *data_item_a = array.data + 0;
UnalignedObject *data_item_b = array.data + 1;
DN_UT_Assert(&result, (uintptr_t)data_item_b == (uintptr_t)(data_item_a + 1));
DN_UT_Assert(&result, (uintptr_t)data_item_b == (uintptr_t)(make_item_a + 1));
DN_UT_Assert(&result, (uintptr_t)data_item_b == (uintptr_t)make_item_b);
for (DN_USize i = 0; i < sizeof(data_item_a->data); i++)
DN_UT_Assert(&result, data_item_a->data[i] == 'a');
for (DN_USize i = 0; i < sizeof(data_item_b->data); i++)
DN_UT_Assert(&result, data_item_b->data[i] == 'b');
}
}
return result;
}
#if defined(DN_UNIT_TESTS_WITH_KECCAK) #if defined(DN_UNIT_TESTS_WITH_KECCAK)
DN_GCC_WARNING_PUSH DN_GCC_WARNING_PUSH
DN_GCC_WARNING_DISABLE(-Wunused-parameter) DN_GCC_WARNING_DISABLE(-Wunused-parameter)
@@ -2695,7 +2611,6 @@ DN_TSTResult DN_TST_RunSuite(DN_TSTPrint print)
DN_TST_BaseDSMap(), DN_TST_BaseDSMap(),
DN_TST_BaseIArray(), DN_TST_BaseIArray(),
DN_TST_BaseArray(), DN_TST_BaseArray(),
DN_TST_BaseVArray(),
DN_TST_Keccak(), DN_TST_Keccak(),
DN_TST_M4(), DN_TST_M4(),
DN_TST_OS(), DN_TST_OS(),
-37
View File
@@ -1,37 +0,0 @@
#define DN_TYPE_INFO_CPP
#if defined(_CLANGD)
#include "dn_type_info.h"
#endif
/*
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\
// \__$$ __|\$$\ $$ |$$ __$$\ $$ _____| \_$$ _|$$$\ $$ |$$ _____|$$ __$$\
// $$ | \$$\ $$ / $$ | $$ |$$ | $$ | $$$$\ $$ |$$ | $$ / $$ |
// $$ | \$$$$ / $$$$$$$ |$$$$$\ $$ | $$ $$\$$ |$$$$$\ $$ | $$ |
// $$ | \$$ / $$ ____/ $$ __| $$ | $$ \$$$$ |$$ __| $$ | $$ |
// $$ | $$ | $$ | $$ | $$ | $$ |\$$$ |$$ | $$ | $$ |
// $$ | $$ | $$ | $$$$$$$$\ $$$$$$\ $$ | \$$ |$$ | $$$$$$ |
// \__| \__| \__| \________| \______|\__| \__|\__| \______/
//
// dn_type_info.cpp
//
////////////////////////////////////////////////////////////////////////////////////////////////////
*/
DN_TypeGetField DN_Type_GetField(DN_TypeInfo const *type_info, DN_Str8 name)
{
DN_TypeGetField result = {};
for (DN_USize index = 0; index < type_info->fields_count; index++) {
DN_TypeField const *type_field = type_info->fields + index;
if (DN_Str8Eq(type_field->name, name)) {
result.success = true;
result.index = index;
result.field = DN_Cast(DN_TypeField *)type_field;
break;
}
}
return result;
}
-68
View File
@@ -1,68 +0,0 @@
#if !defined(DN_TYPE_INFO_H)
#define DN_TYPE_INFO_H
#if defined(_CLANGD)
#include "../dn.h"
#endif
/*
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\
// \__$$ __|\$$\ $$ |$$ __$$\ $$ _____| \_$$ _|$$$\ $$ |$$ _____|$$ __$$\
// $$ | \$$\ $$ / $$ | $$ |$$ | $$ | $$$$\ $$ |$$ | $$ / $$ |
// $$ | \$$$$ / $$$$$$$ |$$$$$\ $$ | $$ $$\$$ |$$$$$\ $$ | $$ |
// $$ | \$$ / $$ ____/ $$ __| $$ | $$ \$$$$ |$$ __| $$ | $$ |
// $$ | $$ | $$ | $$ | $$ | $$ |\$$$ |$$ | $$ | $$ |
// $$ | $$ | $$ | $$$$$$$$\ $$$$$$\ $$ | \$$ |$$ | $$$$$$ |
// \__| \__| \__| \________| \______|\__| \__|\__| \______/
//
// dn_type_info.h -- C++ type introspection
//
////////////////////////////////////////////////////////////////////////////////////////////////////
*/
enum DN_TypeKind
{
DN_TypeKind_Nil,
DN_TypeKind_Basic,
DN_TypeKind_Enum,
DN_TypeKind_Struct,
};
struct DN_TypeField
{
uint16_t index;
DN_Str8 name;
DN_Str8 label;
DN_ISize value;
DN_USize offset_of;
DN_USize size_of;
DN_USize align_of;
DN_Str8 type_decl;
uint32_t type_enum;
bool is_pointer;
uint16_t array_size;
DN_TypeField const *array_size_field;
};
struct DN_TypeInfo
{
DN_Str8 name;
DN_TypeKind kind;
DN_USize size_of;
DN_TypeField const *fields;
uint16_t fields_count;
};
struct DN_TypeGetField
{
bool success;
DN_USize index;
DN_TypeField *field;
};
DN_TypeGetField DN_Type_GetField(DN_TypeInfo const *type_info, DN_Str8 name);
#endif // !defined(DN_TYPE_INFO_H)
+108 -180
View File
@@ -883,27 +883,122 @@ DN_API DN_OSThreadLane DN_OS_TCThreadLaneEquip(DN_OSThreadLane lane)
return result; return result;
} }
// NOTE: DN_OSHttp static DN_I32 DN_OS_AsyncThreadEntryPoint_(DN_OSThread *thread)
DN_API void DN_OS_HttpRequestWait(DN_OSHttpResponse *response)
{ {
if (response && response->on_complete_semaphore.handle != 0) DN_OS_ThreadSetNameFmt("%.*s", DN_Str8PrintFmt(thread->name));
DN_OS_SemaphoreWait(&response->on_complete_semaphore, DN_OS_SEMAPHORE_INFINITE_TIMEOUT); DN_OSAsyncCore *async = DN_Cast(DN_OSAsyncCore *) thread->user_context;
DN_Ring *ring = &async->ring;
for (;;) {
DN_OS_SemaphoreWait(&async->worker_sem, UINT32_MAX);
if (async->join_threads)
break;
DN_OSAsyncTask task = {};
for (DN_OS_MutexScope(&async->ring_mutex)) {
if (DN_RingHasData(ring, sizeof(task)))
DN_RingRead(ring, &task, sizeof(task));
}
if (task.work.func) {
DN_OS_ConditionVariableBroadcast(&async->ring_write_cv); // Resume any blocked ring write(s)
DN_OSAsyncWorkArgs args = {};
args.input = task.work.input;
args.thread = thread;
DN_AtomicAddU32(&async->busy_threads, 1);
task.work.func(args);
DN_AtomicSubU32(&async->busy_threads, 1);
if (task.completion_sem.handle != 0)
DN_OS_SemaphoreIncrement(&task.completion_sem, 1);
}
}
return 0;
} }
DN_API DN_OSHttpResponse DN_OS_HttpRequest(DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers) DN_API void DN_OS_AsyncInit(DN_OSAsyncCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size)
{ {
// TODO(doyle): Revise the memory allocation and its lifetime DN_Assert(async);
DN_OSHttpResponse result = {}; async->ring.size = base_size;
DN_TCScratch scratch = DN_TCScratchBeginArena(&arena, 1); async->ring.base = base;
result.scratch_arena = scratch.arena; async->ring_mutex = DN_OS_MutexInit();
async->ring_write_cv = DN_OS_ConditionVariableInit();
async->worker_sem = DN_OS_SemaphoreInit(0);
async->thread_count = threads_size;
async->threads = threads;
for (DN_ForIndexU(index, async->thread_count)) {
DN_OSThread *thread = async->threads + index;
DN_OS_ThreadInit(thread, DN_OS_AsyncThreadEntryPoint_, /*lane=*/ nullptr, DN_TCInitArgsDefault(), async);
}
}
DN_API void DN_OS_AsyncDeinit(DN_OSAsyncCore *async)
{
DN_Assert(async);
DN_AtomicSetValue32(&async->join_threads, true);
DN_OS_SemaphoreIncrement(&async->worker_sem, async->thread_count);
for (DN_ForItSize(it, DN_OSThread, async->threads, async->thread_count))
DN_OS_ThreadJoin(it.data, DN_TCDeinitArenas_Yes);
}
static bool DN_OS_AsyncQueueTask_(DN_OSAsyncCore *async, DN_OSAsyncTask const *task, DN_U64 wait_time_ms) {
DN_U64 end_time_ms = DN_OS_DateUnixTimeMs() + wait_time_ms;
bool result = false;
for (DN_OS_MutexScope(&async->ring_mutex)) {
for (;;) {
if (DN_RingHasSpace(&async->ring, sizeof(*task))) {
DN_RingWriteStruct(&async->ring, task);
result = true;
break;
}
DN_OS_ConditionVariableWaitUntil(&async->ring_write_cv, &async->ring_mutex, end_time_ms);
if (DN_OS_DateUnixTimeMs() >= end_time_ms)
break;
}
}
if (result)
DN_OS_SemaphoreIncrement(&async->worker_sem, 1); // Flag that a job is available
DN_OS_HttpRequestAsync(&result, arena, host, path, secure, method, body, headers);
DN_OS_HttpRequestWait(&result);
DN_TCScratchEnd(&scratch);
return result; return result;
} }
// NOTE: DN_OSPrint DN_API bool DN_OS_AsyncQueueWork(DN_OSAsyncCore *async, DN_OSAsyncWorkFunc *func, void *input, DN_U64 wait_time_ms)
{
DN_OSAsyncTask task = {};
task.work.func = func;
task.work.input = input;
bool result = DN_OS_AsyncQueueTask_(async, &task, wait_time_ms);
return result;
}
DN_API DN_OSAsyncTask DN_OS_AsyncQueueTask(DN_OSAsyncCore *async, DN_OSAsyncWorkFunc *func, void *input, DN_U64 wait_time_ms)
{
DN_OSAsyncTask result = {};
result.work.func = func;
result.work.input = input;
result.completion_sem = DN_OS_SemaphoreInit(0);
result.queued = DN_OS_AsyncQueueTask_(async, &result, wait_time_ms);
if (!result.queued)
DN_OS_SemaphoreDeinit(&result.completion_sem);
return result;
}
DN_API bool DN_OS_AsyncWaitTask(DN_OSAsyncTask *task, DN_U32 timeout_ms)
{
bool result = true;
if (!task->queued)
return result;
DN_OSSemaphoreWaitResult wait = DN_OS_SemaphoreWait(&task->completion_sem, timeout_ms);
result = wait == DN_OSSemaphoreWaitResult_Success;
if (result)
DN_OS_SemaphoreDeinit(&task->completion_sem);
return result;
}
DN_API DN_LogStyle DN_OS_PrintStyleColour(uint8_t r, uint8_t g, uint8_t b, DN_LogBold bold) DN_API DN_LogStyle DN_OS_PrintStyleColour(uint8_t r, uint8_t g, uint8_t b, DN_LogBold bold)
{ {
DN_LogStyle result = {}; DN_LogStyle result = {};
@@ -1077,173 +1172,6 @@ DN_API void DN_OS_PrintLnFVStyle(DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_
DN_OS_Print(dest, DN_Str8Lit("\n")); DN_OS_Print(dest, DN_Str8Lit("\n"));
} }
// NOTE: DN_VArray
template <typename T>
DN_VArray<T> DN_OS_VArrayInitByteSize(DN_USize byte_size)
{
DN_VArray<T> result = {};
result.data = DN_Cast(T *) DN_OS_MemReserve(byte_size, DN_MemCommit_No, DN_MemPage_ReadWrite);
if (result.data)
result.max = byte_size / sizeof(T);
return result;
}
template <typename T>
DN_VArray<T> DN_OS_VArrayInit(DN_USize max)
{
DN_VArray<T> result = DN_OS_VArrayInitByteSize<T>(max * sizeof(T));
DN_Assert(result.max >= max);
return result;
}
template <typename T, DN_USize N>
DN_VArray<T> DN_OS_VArrayInitCArray(T const (&items)[N], DN_USize max)
{
DN_USize real_max = DN_Max(N, max);
DN_VArray<T> result = DN_OS_VArrayInit<T>(real_max);
if (DN_OS_VArrayIsValid(&result))
DN_OS_VArrayAddArray(&result, items, N);
return result;
}
template <typename T>
void DN_OS_VArrayDeinit(DN_VArray<T> *array)
{
DN_OS_MemRelease(array->data, array->max * sizeof(T));
*array = {};
}
template <typename T>
bool DN_OS_VArrayIsValid(DN_VArray<T> const *array)
{
bool result = array->data && array->size <= array->max;
return result;
}
template <typename T>
T *DN_OS_VArrayAddArray(DN_VArray<T> *array, T const *items, DN_USize count)
{
T *result = DN_OS_VArrayMakeArray(array, count, DN_ZMem_No);
if (result)
DN_Memcpy(result, items, count * sizeof(T));
return result;
}
template <typename T, DN_USize N>
T *DN_OS_VArrayAddCArray(DN_VArray<T> *array, T const (&items)[N])
{
T *result = DN_OS_VArrayAddArray(array, items, N);
return result;
}
template <typename T>
T *DN_OS_VArrayAdd(DN_VArray<T> *array, T const &item)
{
T *result = DN_OS_VArrayAddArray(array, &item, 1);
return result;
}
template <typename T>
T *DN_OS_VArrayMakeArray(DN_VArray<T> *array, DN_USize count, DN_ZMem z_mem)
{
if (!DN_OS_VArrayIsValid(array))
return nullptr;
if (!DN_CheckF((array->size + count) < array->max, "Array is out of space (user requested +%zu items, array has %zu/%zu items)", count, array->size, array->max))
return nullptr;
if (!DN_OS_VArrayReserve(array, count))
return nullptr;
// TODO: Use placement new
T *result = array->data + array->size;
array->size += count;
if (z_mem == DN_ZMem_Yes)
DN_Memset(result, 0, count * sizeof(T));
return result;
}
template <typename T>
T *DN_OS_VArrayMake(DN_VArray<T> *array, DN_ZMem z_mem)
{
T *result = DN_OS_VArrayMakeArray(array, 1, z_mem);
return result;
}
template <typename T>
T *DN_OS_VArrayInsertArray(DN_VArray<T> *array, DN_USize index, T const *items, DN_USize count)
{
T *result = nullptr;
if (!DN_OS_VArrayIsValid(array))
return result;
if (DN_OS_VArrayReserve(array, array->size + count))
result = DN_ArrayInsertArray(array->data, &array->size, array->max, index, items, count);
return result;
}
template <typename T, DN_USize N>
T *DN_OS_VArrayInsertCArray(DN_VArray<T> *array, DN_USize index, T const (&items)[N])
{
T *result = DN_OS_VArrayInsertArray(array, index, items, N);
return result;
}
template <typename T>
T *DN_OS_VArrayInsert(DN_VArray<T> *array, DN_USize index, T const &item)
{
T *result = DN_OS_VArrayInsertArray(array, index, &item, 1);
return result;
}
template <typename T>
T *DN_OS_VArrayPopFront(DN_VArray<T> *array, DN_USize count)
{
T *result = DN_Cast(T *)DN_ArrayPopFront(array->data, &array->size, sizeof(T), count);
return result;
}
template <typename T>
T *DN_OS_VArrayPopBack(DN_VArray<T> *array, DN_USize count)
{
T *result = DN_Cast(T *)DN_ArrayPopBack(array->data, &array->size, sizeof(T), count);
return result;
}
template <typename T>
DN_ArrayEraseResult DN_OS_VArrayEraseRange(DN_VArray<T> *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase)
{
DN_ArrayEraseResult result = {};
if (!DN_OS_VArrayIsValid(array))
return result;
result = DN_ArrayEraseRange(array->data, &array->size, sizeof(T), begin_index, count, erase);
return result;
}
template <typename T>
void DN_OS_VArrayClear(DN_VArray<T> *array, DN_ZMem z_mem)
{
if (array) {
if (z_mem == DN_ZMem_Yes)
DN_Memset(array->data, 0, array->size * sizeof(T));
array->size = 0;
}
}
template <typename T>
bool DN_OS_VArrayReserve(DN_VArray<T> *array, DN_USize count)
{
if (!DN_OS_VArrayIsValid(array) || count == 0)
return false;
DN_USize real_commit = (array->size + count) * sizeof(T);
DN_USize aligned_commit = DN_AlignUpPowerOfTwo(real_commit, DN_Get()->os.page_size);
if (array->commit >= aligned_commit)
return true;
bool result = DN_OS_MemCommit(array->data, aligned_commit, DN_MemPage_ReadWrite);
array->commit = aligned_commit;
return result;
}
DN_API DN_StackTrace DN_StackTraceFromAllocator(DN_Allocator allocator, DN_U16 limit) DN_API DN_StackTrace DN_StackTraceFromAllocator(DN_Allocator allocator, DN_U16 limit)
{ {
DN_StackTrace result = {}; DN_StackTrace result = {};
+46 -86
View File
@@ -31,10 +31,6 @@
#endif #endif
#endif #endif
#if defined(DN_PLATFORM_EMSCRIPTEN)
#include <emscripten/fetch.h> // emscripten_fetch (for DN_OSHttpResponse)
#endif
extern DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count]; extern DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count];
struct DN_OSTimer /// Record time between two time-points using the OS's performance counter. struct DN_OSTimer /// Record time between two time-points using the OS's performance counter.
@@ -229,42 +225,6 @@ struct DN_OSThread
DN_TCInitArgs tc_init_args; DN_TCInitArgs tc_init_args;
}; };
// NOTE: DN_OSHttp
enum DN_OSHttpRequestSecure
{
DN_OSHttpRequestSecure_No,
DN_OSHttpRequestSecure_Yes,
};
struct DN_OSHttpResponse
{
// NOTE: Response data
DN_U32 error_code;
DN_Str8 error_msg;
DN_U16 http_status;
DN_Str8 body;
DN_B32 done;
// NOTE: Book-keeping
DN_Arena *arena; // Allocates memory for the response
// NOTE: Async book-keeping
// Synchronous HTTP response uses the TLS scratch arena whereas async
// calls use their own dedicated arena.
DN_Arena tmp_arena;
DN_Arena scratch_arena;
DN_Str8Builder builder;
DN_OSSemaphore on_complete_semaphore;
#if defined(DN_PLATFORM_EMSCRIPTEN)
emscripten_fetch_t *em_handle;
#elif defined(DN_PLATFORM_WIN32)
HINTERNET w32_request_session;
HINTERNET w32_request_connection;
HINTERNET w32_request_handle;
#endif
};
struct DN_OSCore struct DN_OSCore
{ {
DN_CPUReport cpu_report; DN_CPUReport cpu_report;
@@ -509,10 +469,52 @@ DN_API DN_OSThreadLane* DN_OS_TCThreadLane ()
DN_API void DN_OS_TCThreadLaneSync (void **ptr_to_share); DN_API void DN_OS_TCThreadLaneSync (void **ptr_to_share);
DN_API DN_OSThreadLane DN_OS_TCThreadLaneEquip (DN_OSThreadLane lane); DN_API DN_OSThreadLane DN_OS_TCThreadLaneEquip (DN_OSThreadLane lane);
DN_API void DN_OS_HttpRequestAsync (DN_OSHttpResponse *response, DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers); enum DN_OSAsyncPriority
DN_API void DN_OS_HttpRequestWait (DN_OSHttpResponse *response); {
DN_API void DN_OS_HttpRequestFree (DN_OSHttpResponse *response); DN_OSAsyncPriority_Low,
DN_API DN_OSHttpResponse DN_OS_HttpRequest (DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers); DN_OSAsyncPriority_High,
DN_OSAsyncPriority_Count,
};
struct DN_OSAsyncCore
{
DN_OSMutex ring_mutex;
DN_OSConditionVariable ring_write_cv;
DN_OSSemaphore worker_sem;
DN_Ring ring;
DN_OSThread *threads;
DN_U32 thread_count;
DN_U32 busy_threads;
DN_U32 join_threads;
};
struct DN_OSAsyncWorkArgs
{
DN_OSThread *thread;
void *input;
};
typedef void(DN_OSAsyncWorkFunc)(DN_OSAsyncWorkArgs work_args);
struct DN_OSAsyncWork
{
DN_OSAsyncWorkFunc *func;
void *input;
void *output;
};
struct DN_OSAsyncTask
{
bool queued;
DN_OSAsyncWork work;
DN_OSSemaphore completion_sem;
};
DN_API void DN_OS_AsyncInit (DN_OSAsyncCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size);
DN_API void DN_OS_AsyncDeinit (DN_OSAsyncCore *async);
DN_API bool DN_OS_AsyncQueueWork(DN_OSAsyncCore *async, DN_OSAsyncWorkFunc *func, void *input, DN_U64 wait_time_ms);
DN_API DN_OSAsyncTask DN_OS_AsyncQueueTask(DN_OSAsyncCore *async, DN_OSAsyncWorkFunc *func, void *input, DN_U64 wait_time_ms);
DN_API bool DN_OS_AsyncWaitTask (DN_OSAsyncTask *task, DN_U32 timeout_ms);
// NOTE: DN_OSPrint // NOTE: DN_OSPrint
enum DN_OSPrintDest enum DN_OSPrintDest
@@ -570,46 +572,4 @@ DN_API void DN_OS_PrintLnFV (DN_OSPrintDest dest, DN_FMT_ATTRIB char
DN_API void DN_OS_PrintLnStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_Str8 string); DN_API void DN_OS_PrintLnStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_Str8 string);
DN_API void DN_OS_PrintLnFStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, ...); DN_API void DN_OS_PrintLnFStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, ...);
DN_API void DN_OS_PrintLnFVStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, va_list args); DN_API void DN_OS_PrintLnFVStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, va_list args);
// NOTE: DN_VArray
// TODO(doyle): Add an API for shrinking the array by decomitting pages back to the OS.
template <typename T> struct DN_VArray
{
T *data; // Pointer to the start of the array items in the block of memory
DN_USize size; // Number of items currently in the array
DN_USize max; // Maximum number of items this array can store
DN_USize commit; // Bytes committed
T *begin() { return data; }
T *end () { return data + size; }
T const *begin() const { return data; }
T const *end () const { return data + size; }
};
template <typename T> DN_VArray<T> DN_OS_VArrayInitByteSize (DN_USize byte_size);
template <typename T> DN_VArray<T> DN_OS_VArrayInit (DN_USize max);
template <typename T, DN_USize N> DN_VArray<T> DN_OS_VArrayInitCArray (T const (&items)[N], DN_USize max);
template <typename T> void DN_OS_VArrayDeinit (DN_VArray<T> *array);
template <typename T> bool DN_OS_VArrayIsValid (DN_VArray<T> const *array);
template <typename T> bool DN_OS_VArrayReserve (DN_VArray<T> *array, DN_USize count);
template <typename T> T * DN_OS_VArrayAddArray (DN_VArray<T> *array, T const *items, DN_USize count);
template <typename T, DN_USize N> T * DN_OS_VArrayAddCArray (DN_VArray<T> *array, T const (&items)[N]);
template <typename T> T * DN_OS_VArrayAdd (DN_VArray<T> *array, T const &item);
#define DN_OS_VArrayAddArrayAssert(...) DN_HardAssert(DN_OS_VArrayAddArray(__VA_ARGS__))
#define DN_OS_VArrayAddCArrayAssert(...) DN_HardAssert(DN_OS_VArrayAddCArray(__VA_ARGS__))
#define DN_OS_VArrayAddAssert(...) DN_HardAssert(DN_OS_VArrayAdd(__VA_ARGS__))
template <typename T> T * DN_OS_VArrayMakeArray (DN_VArray<T> *array, DN_USize count, DN_ZMem z_mem);
template <typename T> T * DN_OS_VArrayMake (DN_VArray<T> *array, DN_ZMem z_mem);
#define DN_OS_VArrayMakeArrayAssert(...) DN_HardAssert(DN_OS_VArrayMakeArray(__VA_ARGS__))
#define DN_OS_VArrayMakeAssert(...) DN_HardAssert(DN_OS_VArrayMake(__VA_ARGS__))
template <typename T> T * DN_OS_VArrayInsertArray (DN_VArray<T> *array, DN_USize index, T const *items, DN_USize count);
template <typename T, DN_USize N> T * DN_OS_VArrayInsertCArray (DN_VArray<T> *array, DN_USize index, T const (&items)[N]);
template <typename T> T * DN_OS_VArrayInsert (DN_VArray<T> *array, DN_USize index, T const &item);
#define DN_OS_VArrayInsertArrayAssert(...) DN_HardAssert(DN_OS_VArrayInsertArray(__VA_ARGS__))
#define DN_OS_VArrayInsertCArrayAssert(...) DN_HardAssert(DN_OS_VArrayInsertCArray(__VA_ARGS__))
#define DN_OS_VArrayInsertAssert(...) DN_HardAssert(DN_OS_VArrayInsert(__VA_ARGS__))
template <typename T> T DN_OS_VArrayPopFront (DN_VArray<T> *array, DN_USize count);
template <typename T> T DN_OS_VArrayPopBack (DN_VArray<T> *array, DN_USize count);
template <typename T> DN_ArrayEraseResult DN_OS_VArrayEraseRange (DN_VArray<T> *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase);
template <typename T> void DN_OS_VArrayClear (DN_VArray<T> *array, DN_ZMem z_mem);
#endif // !defined(DN_OS_H) #endif // !defined(DN_OS_H)
-151
View File
@@ -1444,154 +1444,3 @@ DN_API DN_OSPosixProcSelfStatus DN_OS_PosixProcSelfStatus()
DN_OS_FileClose(&file); DN_OS_FileClose(&file);
return result; return result;
} }
// NOTE: DN_OSHttp /////////////////////////////////////////////////////////////////////////////////
#if 0 // TODO(doyle): Implement websockets for Windows and Emscripten
static EM_BOOL EMWebSocketOnOpenCallback(int type, const EmscriptenWebSocketOpenEvent *event, void *user_context)
{
(void)user_context;
(void)type;
(void)event;
// EMSCRIPTEN_RESULT result = emscripten_websocket_send_utf8_text(event->socket, R"({"jsonrpc":"2.0","id":1,"method": "eth_subscribe","params":["newHeads"]})");
// if (result)
// DN_LogInfoF("Failed to emscripten_websocket_send_utf8_text(): %d\n", result);
return EM_TRUE;
}
static EM_BOOL EMWebSocketOnMsgCallback(int type, const EmscriptenWebSocketMessageEvent *event __attribute__((nonnull)), void *user_context)
{
(void)type;
(void)user_context;
(void)event;
if (event->isText) {
DN_LogInfoF("Received: %.*s", event->numBytes, event->data);
} else {
DN_LogInfoF("Received: %d bytes", event->numBytes);
}
return EM_TRUE;
}
static EM_BOOL EMWebSocketOnErrorCallback(int type, const EmscriptenWebSocketErrorEvent *event, void *user_context)
{
(void)user_context;
(void)type;
(void)event;
return EM_TRUE;
}
static EM_BOOL EMWebSocketOnCloseCallback(int type, const EmscriptenWebSocketCloseEvent *event, void *user_context)
{
(void)user_context;
(void)type;
(void)event;
return EM_TRUE;
}
#endif
#if defined(DN_PLATFORM_EMSCRIPTEN)
static void DN_OS_HttpRequestEMFetchOnSuccessCallback(emscripten_fetch_t *fetch)
{
DN_OSHttpResponse *response = DN_Cast(DN_OSHttpResponse *) fetch->userData;
if (!DN_Check(response))
return;
response->http_status = DN_Cast(DN_U32) fetch->status;
response->body = DN_Str8AllocArena(fetch->numBytes, DN_ZMem_No, response->arena);
if (response->body.data)
DN_Memcpy(response->body.data, fetch->data, fetch->numBytes);
DN_OS_SemaphoreIncrement(&response->on_complete_semaphore, 1);
DN_AtomicAddU32(&response->done, 1);
}
static void DN_OS_HttpRequestEMFetchOnErrorCallback(emscripten_fetch_t *fetch)
{
DN_OSHttpResponse *response = DN_Cast(DN_OSHttpResponse *) fetch->userData;
if (!DN_Check(response))
return;
response->http_status = DN_Cast(DN_U32) fetch->status;
response->body = DN_Str8AllocArena(fetch->numBytes, DN_ZMem_No, response->arena);
if (response->body.size)
DN_Memcpy(response->body.data, fetch->data, fetch->numBytes);
DN_OS_SemaphoreIncrement(&response->on_complete_semaphore, 1);
DN_AtomicAddU32(&response->done, 1);
}
#endif
DN_API void DN_OS_HttpRequestAsync(DN_OSHttpResponse *response,
DN_Arena *arena,
DN_Str8 host,
DN_Str8 path,
DN_OSHttpRequestSecure secure,
DN_Str8 method,
DN_Str8 body,
DN_Str8 headers)
{
if (!response || !arena)
return;
response->arena = arena;
response->builder.arena = response->scratch_arena.mem ? &response->scratch_arena : &response->tmp_arena;
DN_Arena *scratch = &response->scratch_arena;
DN_TCScratch scratch_ = DN_TCScratchBeginArena(&arena, 1);
DN_DEFER { DN_TCScratchEnd(&scratch_); };
if (!scratch)
scratch = &scratch_.arena;
#if defined(DN_PLATFORM_EMSCRIPTEN)
emscripten_fetch_attr_t fetch_attribs = {};
emscripten_fetch_attr_init(&fetch_attribs);
if (method.size >= sizeof(fetch_attribs.requestMethod)) {
response->error_msg =
DN_Str8FromFmtArena(arena,
"Request method in EM has a size limit of 31 characters, method was "
"'%.*s' which is %zu characters long",
DN_Str8PrintFmt(method),
method.size);
DN_CheckF(method.size < sizeof(fetch_attribs.requestMethod),
"%.*s",
DN_Str8PrintFmt(response->error_msg));
response->error_code = DN_Cast(DN_U32) - 1;
DN_AtomicAddU32(&response->done, 1);
return;
}
DN_Memcpy(fetch_attribs.requestMethod, method.data, method.size);
fetch_attribs.requestData = body.data;
fetch_attribs.requestDataSize = body.size;
fetch_attribs.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
fetch_attribs.onsuccess = DN_OS_HttpRequestEMFetchOnSuccessCallback;
fetch_attribs.onerror = DN_OS_HttpRequestEMFetchOnErrorCallback;
fetch_attribs.userData = response;
DN_Str8 url = DN_Str8FromFmtArena(scratch, "%.*s%.*s", DN_Str8PrintFmt(host), DN_Str8PrintFmt(path));
DN_LogInfoF("Initiating HTTP '%s' request to '%.*s' with payload '%.*s'",
fetch_attribs.requestMethod,
DN_Str8PrintFmt(url),
DN_Str8PrintFmt(body));
response->on_complete_semaphore = DN_OS_SemaphoreInit(0);
response->em_handle = emscripten_fetch(&fetch_attribs, url.data);
#else // #elif defined(DN_OS_WIN32)
DN_InvalidCodePathF("Unimplemented function");
#endif
}
DN_API void DN_OS_HttpRequestFree(DN_OSHttpResponse *response)
{
// NOTE: Cleanup
#if defined(DN_PLATFORM_EMSCRIPTEN)
if (response->em_handle) {
emscripten_fetch_close(response->em_handle);
response->em_handle = nullptr;
}
#endif // #elif defined(DN_OS_WIN32)
DN_MemListDeinit(response->tmp_arena.mem);
DN_OS_SemaphoreDeinit(&response->on_complete_semaphore);
*response = {};
}
+12 -212
View File
@@ -395,15 +395,9 @@ DN_API DN_OSFileRead DN_OS_FileRead(DN_OSFile *file, void *buffer, DN_USize size
if (!file || !file->handle || file->error || !buffer || size <= 0) if (!file || !file->handle || file->error || !buffer || size <= 0)
return result; return result;
DN_TCScratch scratch = DN_TCScratchBeginArena(nullptr, 0); if (size > ULONG_MAX) {
if (!DN_Check(size <= (unsigned long)-1)) { DN_Str8x32 desc = DN_Str8x32FromByteCountU64Auto(size);
DN_Str8x32 buffer_size_str8 = DN_Str8x32FromByteCountU64Auto(size); DN_ErrSinkAppendF(err, 1 /*error_code*/, "Current implementation doesn't support reading >4GiB file (requested %.*s), implement Win32 overlapped IO", DN_Str8PrintFmt(desc));
DN_ErrSinkAppendF(
err,
1 /*error_code*/,
"Current implementation doesn't support reading >4GiB file (requested %.*s), implement Win32 overlapped IO",
DN_Str8PrintFmt(buffer_size_str8));
DN_TCScratchEnd(&scratch);
return result; return result;
} }
@@ -414,6 +408,7 @@ DN_API DN_OSFileRead DN_OS_FileRead(DN_OSFile *file, void *buffer, DN_USize size
/*LPDWORD lpNumberOfByesRead*/ &bytes_read, /*LPDWORD lpNumberOfByesRead*/ &bytes_read,
/*LPOVERLAPPED lpOverlapped*/ nullptr); /*LPOVERLAPPED lpOverlapped*/ nullptr);
if (read_result == 0) { if (read_result == 0) {
DN_TCScratch scratch = DN_TCScratchBeginArena(nullptr, 0);
DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena);
DN_ErrSinkAppendF(err, win_error.code, "Failed to read data from file: (%u) %.*s", win_error.code, DN_Str8PrintFmt(win_error.msg)); DN_ErrSinkAppendF(err, win_error.code, "Failed to read data from file: (%u) %.*s", win_error.code, DN_Str8PrintFmt(win_error.msg));
DN_TCScratchEnd(&scratch); DN_TCScratchEnd(&scratch);
@@ -421,6 +416,7 @@ DN_API DN_OSFileRead DN_OS_FileRead(DN_OSFile *file, void *buffer, DN_USize size
} }
if (bytes_read != size) { if (bytes_read != size) {
DN_TCScratch scratch = DN_TCScratchBeginArena(nullptr, 0);
DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena); DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena);
DN_ErrSinkAppendF( DN_ErrSinkAppendF(
err, err,
@@ -436,7 +432,6 @@ DN_API DN_OSFileRead DN_OS_FileRead(DN_OSFile *file, void *buffer, DN_USize size
result.bytes_read = bytes_read; result.bytes_read = bytes_read;
result.success = true; result.success = true;
DN_TCScratchEnd(&scratch);
return result; return result;
} }
@@ -732,7 +727,7 @@ DN_API DN_OSExecResult DN_OS_ExecPump(DN_OSExecAsyncHandle handle,
DN_ErrSinkAppendF(err, result.os_error_code, "Executed command failed to terminate: %.*s", DN_Str8PrintFmt(win_error.msg)); DN_ErrSinkAppendF(err, result.os_error_code, "Executed command failed to terminate: %.*s", DN_Str8PrintFmt(win_error.msg));
DN_TCScratchEnd(&scratch); DN_TCScratchEnd(&scratch);
return result; return result;
} else if (DN_Check(exec_result == WAIT_TIMEOUT || exec_result == WAIT_OBJECT_0)) { } else if (exec_result == WAIT_TIMEOUT || exec_result == WAIT_OBJECT_0) {
// NOTE: Read stdout from process // NOTE: Read stdout from process
// If the pipes are full, the process will block. We periodically // If the pipes are full, the process will block. We periodically
// flush the pipes to make sure this doesn't happen // flush the pipes to make sure this doesn't happen
@@ -1341,204 +1336,6 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name)
DN_TCScratchEnd(&scratch); DN_TCScratchEnd(&scratch);
} }
void DN_OS_HttpRequestWin32Callback(HINTERNET session, DWORD *dwContext, DWORD dwInternetStatus, VOID *lpvStatusInformation, DWORD dwStatusInformationLength)
{
(void)session;
(void)dwStatusInformationLength;
DN_OSHttpResponse *response = DN_Cast(DN_OSHttpResponse *) dwContext;
HINTERNET request = DN_Cast(HINTERNET) response->w32_request_handle;
DN_OSW32Error error = {};
DWORD const READ_BUFFER_SIZE = DN_Megabytes(1);
if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_RESOLVING_NAME) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_NAME_RESOLVED) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SENDING_REQUEST) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_REQUEST_SENT) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CREATED) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_DETECTING_PROXY) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_REDIRECT) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE) {
DWORD status = 0;
DWORD status_size = sizeof(status_size);
if (WinHttpQueryHeaders(request,
WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
WINHTTP_HEADER_NAME_BY_INDEX,
&status,
&status_size,
WINHTTP_NO_HEADER_INDEX)) {
response->http_status = DN_Cast(uint16_t) status;
// NOTE: You can normally call into WinHttpQueryDataAvailable which means the kernel
// will buffer the response into a single buffer and return us the full size of the
// request.
//
// or
//
// You may call WinHttpReadData directly to write the memory into our buffer directly.
// This is advantageous to avoid a copy from the kernel buffer into our buffer. If the
// end user application knows the typical payload size then they can optimise for this
// to prevent unnecessary allocation on the user side.
void *buffer = DN_ArenaAlloc(response->builder.arena, READ_BUFFER_SIZE, 1 /*align*/, DN_ZMem_No);
if (!WinHttpReadData(request, buffer, READ_BUFFER_SIZE, nullptr))
error = DN_OS_W32LastError(&response->tmp_arena);
} else {
error = DN_OS_W32LastError(&response->tmp_arena);
}
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_READ_COMPLETE) {
DWORD bytes_read = dwStatusInformationLength;
if (bytes_read) {
DN_Str8 prev_buffer = DN_Str8FromPtr(DN_Cast(char *) lpvStatusInformation, bytes_read);
DN_Str8BuilderAppendRef(&response->builder, prev_buffer);
void *buffer = DN_ArenaAlloc(response->builder.arena, READ_BUFFER_SIZE, 1 /*align*/, DN_ZMem_No);
if (!WinHttpReadData(request, buffer, READ_BUFFER_SIZE, nullptr))
error = DN_OS_W32LastError(&response->tmp_arena);
}
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE) {
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_REQUEST_ERROR) {
WINHTTP_ASYNC_RESULT *async_result = DN_Cast(WINHTTP_ASYNC_RESULT *) lpvStatusInformation;
error = DN_OS_W32ErrorCodeToMsg(&response->tmp_arena, DN_Cast(DN_U32) async_result->dwError);
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE) {
if (!WinHttpReceiveResponse(request, 0))
error = DN_OS_W32LastError(&response->tmp_arena);
}
// NOTE: If the request handle is missing, then, the response has been freed.
// MSDN says that this callback can still be called after closing the handle
// and trigger the WINHTTP_CALLBACK_STATUS_REQUEST_ERROR.
if (request) {
bool read_complete = dwInternetStatus == WINHTTP_CALLBACK_STATUS_READ_COMPLETE && dwStatusInformationLength == 0;
if (read_complete)
response->body = DN_Str8FromStr8BuilderArena(&response->builder, response->arena);
if (read_complete || dwInternetStatus == WINHTTP_CALLBACK_STATUS_REQUEST_ERROR || error.code) {
DN_OS_SemaphoreIncrement(&response->on_complete_semaphore, 1);
DN_AtomicAddU32(&response->done, 1);
}
if (error.code) {
response->error_code = error.code;
response->error_msg = error.msg;
}
}
}
DN_API void DN_OS_HttpRequestAsync(DN_OSHttpResponse *response,
DN_Arena *arena,
DN_Str8 host,
DN_Str8 path,
DN_OSHttpRequestSecure secure,
DN_Str8 method,
DN_Str8 body,
DN_Str8 headers)
{
if (!response || !arena)
return;
response->arena = arena;
response->builder = DN_Str8BuilderFromArena(response->scratch_arena.mem ? &response->scratch_arena : &response->tmp_arena);
DN_TCScratch scratch_ = DN_TCScratchBeginArena(&arena, 1);
if (!response->scratch_arena.mem)
response->scratch_arena = scratch_.arena;
DN_OSW32Error error = {};
DN_DEFER
{
response->error_msg = error.msg;
response->error_code = error.code;
if (error.code) {
// NOTE: 'Wait' handles failures gracefully, skipping the wait and
// cleans up the request
DN_OS_HttpRequestWait(response);
DN_AtomicAddU32(&response->done, 1);
}
DN_TCScratchEnd(&scratch_);
};
response->w32_request_session = WinHttpOpen(nullptr /*user agent*/, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC);
if (!response->w32_request_session) {
error = DN_OS_W32LastError(&response->tmp_arena);
return;
}
DWORD callback_flags = WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE |
WINHTTP_CALLBACK_STATUS_READ_COMPLETE |
WINHTTP_CALLBACK_STATUS_REQUEST_ERROR |
WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE;
if (WinHttpSetStatusCallback(response->w32_request_session,
DN_Cast(WINHTTP_STATUS_CALLBACK) DN_OS_HttpRequestWin32Callback,
callback_flags,
DN_Cast(DWORD_PTR) nullptr /*dwReserved*/) == WINHTTP_INVALID_STATUS_CALLBACK) {
error = DN_OS_W32LastError(&response->tmp_arena);
return;
}
DN_Str16 host16 = DN_OS_W32Str8ToStr16(&response->scratch_arena, host);
response->w32_request_connection = WinHttpConnect(response->w32_request_session, host16.data, secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, 0 /*reserved*/);
if (!response->w32_request_connection) {
error = DN_OS_W32LastError(&response->tmp_arena);
return;
}
DN_Str16 method16 = DN_OS_W32Str8ToStr16(&response->scratch_arena, method);
DN_Str16 path16 = DN_OS_W32Str8ToStr16(&response->scratch_arena, path);
response->w32_request_handle = WinHttpOpenRequest(response->w32_request_connection,
method16.data,
path16.data,
nullptr /*version*/,
nullptr /*referrer*/,
nullptr /*accept types*/,
secure ? WINHTTP_FLAG_SECURE : 0);
if (!response->w32_request_handle) {
error = DN_OS_W32LastError(&response->tmp_arena);
return;
}
DN_Str16 headers16 = DN_OS_W32Str8ToStr16(&response->scratch_arena, headers);
response->on_complete_semaphore = DN_OS_SemaphoreInit(0);
if (!WinHttpSendRequest(response->w32_request_handle,
headers16.data,
DN_Cast(DWORD) headers16.size,
body.data /*optional data*/,
DN_Cast(DWORD) body.size /*optional length*/,
DN_Cast(DWORD) body.size /*total content length*/,
DN_Cast(DWORD_PTR) response)) {
error = DN_OS_W32LastError(&response->tmp_arena);
return;
}
}
DN_API void DN_OS_HttpRequestFree(DN_OSHttpResponse *response)
{
// NOTE: Cleanup
// NOTE: These calls are synchronous even when the HTTP request is async.
WinHttpCloseHandle(response->w32_request_handle);
WinHttpCloseHandle(response->w32_request_connection);
WinHttpCloseHandle(response->w32_request_session);
response->w32_request_session = nullptr;
response->w32_request_connection = nullptr;
response->w32_request_handle = nullptr;
DN_MemListDeinit(response->tmp_arena.mem);
DN_OS_SemaphoreDeinit(&response->on_complete_semaphore);
*response = {};
}
// NOTE: DN_OS_W32
DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc(DN_U32 error_code) DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc(DN_U32 error_code)
{ {
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
@@ -1638,7 +1435,8 @@ DN_API DN_Str16 DN_OS_W32Str8ToStr16(DN_Arena *arena, DN_Str8 src)
return result; return result;
int chars_written = MultiByteToWideChar(CP_UTF8, 0 /*dwFlags*/, src.data, DN_Cast(int) src.size, buffer, required_size); int chars_written = MultiByteToWideChar(CP_UTF8, 0 /*dwFlags*/, src.data, DN_Cast(int) src.size, buffer, required_size);
if (DN_Check(chars_written == required_size)) { DN_Assert(chars_written == required_size);
if (chars_written == required_size) {
result.data = buffer; result.data = buffer;
result.size = chars_written; result.size = chars_written;
result.data[result.size] = 0; result.data[result.size] = 0;
@@ -1700,7 +1498,8 @@ DN_API DN_Str8 DN_OS_W32Str16ToStr8(DN_Arena *arena, DN_Str16 src)
DN_Str8 buffer = DN_Str8AllocArena(required_size, DN_ZMem_No, &temp); DN_Str8 buffer = DN_Str8AllocArena(required_size, DN_ZMem_No, &temp);
if (buffer.size) { if (buffer.size) {
int chars_written = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, buffer.data, DN_Cast(int) buffer.size, nullptr, nullptr); int chars_written = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, buffer.data, DN_Cast(int) buffer.size, nullptr, nullptr);
if (DN_Check(chars_written == required_size)) { DN_Assert(chars_written == required_size);
if (chars_written == required_size) {
result = buffer; result = buffer;
result.data[result.size] = 0; result.data[result.size] = 0;
} }
@@ -1730,7 +1529,8 @@ DN_API DN_Str8 DN_OS_W32Str16ToStr8FromHeap(DN_Str16 src)
return result; return result;
int chars_written = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, buffer.data, DN_Cast(int) buffer.size, nullptr, nullptr); int chars_written = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, buffer.data, DN_Cast(int) buffer.size, nullptr, nullptr);
if (DN_Check(chars_written == required_size)) { DN_Assert(chars_written == required_size);
if (chars_written == required_size) {
result = buffer; result = buffer;
result.data[result.size] = 0; result.data[result.size] = 0;
} else { } else {
-271
View File
@@ -1,271 +0,0 @@
#define DN_SIMD_AVX512F_CPP
#include <immintrin.h>
DN_API DN_Str8FindResult DN_SIMD_Str8FindAVX512F(DN_Str8 string, DN_Str8 find)
{
// NOTE: Algorithm as described in http://0x80.pl/articles/simd-strfind.html
DN_Str8FindResult result = {};
if (string.size == 0 || find.size == 0 || find.size > string.size)
return result;
__m512i const find_first_ch = _mm512_set1_epi8(find.data[0]);
__m512i const find_last_ch = _mm512_set1_epi8(find.data[find.size - 1]);
DN_USize const search_size = string.size - find.size;
DN_USize simd_iterations = search_size / sizeof(__m512i);
char const *ptr = string.data;
while (simd_iterations--) {
__m512i find_first_ch_block = _mm512_loadu_si512(ptr);
__m512i find_last_ch_block = _mm512_loadu_si512(ptr + find.size - 1);
// NOTE: AVX512F does not have a cmpeq so we use XOR to place a 0 bit
// where matches are found.
__m512i first_ch_matches = _mm512_xor_si512(find_first_ch_block, find_first_ch);
// NOTE: We can combine the 2nd XOR and merge the 2 XOR results into one
// operation using the ternarylogic intrinsic.
//
// A = first_ch_matches (find_first_ch_block ^ find_first_ch)
// B = find_last_ch_block
// C = find_last_ch
//
// ternarylogic op => A | (B ^ C) => 0b1111'0110 => 0xf6
//
// / A / B / C / B ^ C / A | (B ^ C) /
// | 0 | 0 | 0 | 0 | 0 |
// | 0 | 0 | 1 | 1 | 1 |
// | 0 | 1 | 0 | 1 | 1 |
// | 0 | 1 | 1 | 0 | 0 |
// | 1 | 0 | 0 | 0 | 1 |
// | 1 | 0 | 1 | 1 | 1 |
// | 1 | 1 | 0 | 1 | 1 |
// | 1 | 1 | 1 | 0 | 1 |
__m512i ch_matches = _mm512_ternarylogic_epi32(first_ch_matches, find_last_ch_block, find_last_ch, 0xf6);
// NOTE: Matches were XOR-ed and are hence indicated as zero so we mask
// out which 32 bit elements in the vector had zero bytes. This uses a
// bit twiddling trick
// https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
__mmask16 zero_byte_mask = {};
{
const __m512i v01 = _mm512_set1_epi32(0x01010101u);
const __m512i v80 = _mm512_set1_epi32(0x80808080u);
const __m512i v1 = _mm512_sub_epi32(ch_matches, v01);
const __m512i tmp1 = _mm512_ternarylogic_epi32(v1, ch_matches, v80, 0x20);
zero_byte_mask = _mm512_test_epi32_mask(tmp1, tmp1);
}
while (zero_byte_mask) {
uint64_t const lsb_zero_pos = _tzcnt_u64(zero_byte_mask);
char const *base_ptr = ptr + (4 * lsb_zero_pos);
if (DN_MEMCMP(base_ptr + 0, find.data, find.size) == 0) {
result.found = true;
result.index = base_ptr - string.data;
} else if (DN_MEMCMP(base_ptr + 1, find.data, find.size) == 0) {
result.found = true;
result.index = base_ptr - string.data + 1;
} else if (DN_MEMCMP(base_ptr + 2, find.data, find.size) == 0) {
result.found = true;
result.index = base_ptr - string.data + 2;
} else if (DN_MEMCMP(base_ptr + 3, find.data, find.size) == 0) {
result.found = true;
result.index = base_ptr - string.data + 3;
}
if (result.found) {
result.start_to_before_match = DN_Str8FromPtr(string.data, result.index);
result.match = DN_Str8FromPtr(string.data + result.index, find.size);
result.match_to_end_of_buffer = DN_Str8FromPtr(result.match.data, string.size - result.index);
result.after_match_to_end_of_buffer = DN_Str8Advance(result.match_to_end_of_buffer, find.size);
return result;
}
zero_byte_mask = DN_Bit_ClearNextLSB(zero_byte_mask);
}
ptr += sizeof(__m512i);
}
for (DN_USize index = ptr - string.data; index < string.size; index++) {
DN_Str8 string_slice = DN_Str8Slice(string, index, find.size);
if (DN_Str8Eq(string_slice, find)) {
result.found = true;
result.index = index;
result.start_to_before_match = DN_Str8FromPtr(string.data, index);
result.match = DN_Str8FromPtr(string.data + index, find.size);
result.match_to_end_of_buffer = DN_Str8FromPtr(result.match.data, string.size - index);
result.after_match_to_end_of_buffer = DN_Str8Advance(result.match_to_end_of_buffer, find.size);
return result;
}
}
return result;
}
DN_API DN_Str8FindResult DN_SIMD_Str8FindLastAVX512F(DN_Str8 string, DN_Str8 find)
{
// NOTE: Algorithm as described in http://0x80.pl/articles/simd-strfind.html
DN_Str8FindResult result = {};
if (string.size == 0 || find.size == 0 || find.size > string.size)
return result;
__m512i const find_first_ch = _mm512_set1_epi8(find.data[0]);
__m512i const find_last_ch = _mm512_set1_epi8(find.data[find.size - 1]);
DN_USize const search_size = string.size - find.size;
DN_USize simd_iterations = search_size / sizeof(__m512i);
char const *ptr = string.data + search_size + 1;
while (simd_iterations--) {
ptr -= sizeof(__m512i);
__m512i find_first_ch_block = _mm512_loadu_si512(ptr);
__m512i find_last_ch_block = _mm512_loadu_si512(ptr + find.size - 1);
// NOTE: AVX512F does not have a cmpeq so we use XOR to place a 0 bit
// where matches are found.
__m512i first_ch_matches = _mm512_xor_si512(find_first_ch_block, find_first_ch);
// NOTE: We can combine the 2nd XOR and merge the 2 XOR results into one
// operation using the ternarylogic intrinsic.
//
// A = first_ch_matches (find_first_ch_block ^ find_first_ch)
// B = find_last_ch_block
// C = find_last_ch
//
// ternarylogic op => A | (B ^ C) => 0b1111'0110 => 0xf6
//
// / A / B / C / B ^ C / A | (B ^ C) /
// | 0 | 0 | 0 | 0 | 0 |
// | 0 | 0 | 1 | 1 | 1 |
// | 0 | 1 | 0 | 1 | 1 |
// | 0 | 1 | 1 | 0 | 0 |
// | 1 | 0 | 0 | 0 | 1 |
// | 1 | 0 | 1 | 1 | 1 |
// | 1 | 1 | 0 | 1 | 1 |
// | 1 | 1 | 1 | 0 | 1 |
__m512i ch_matches = _mm512_ternarylogic_epi32(first_ch_matches, find_last_ch_block, find_last_ch, 0xf6);
// NOTE: Matches were XOR-ed and are hence indicated as zero so we mask
// out which 32 bit elements in the vector had zero bytes. This uses a
// bit twiddling trick
// https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
__mmask16 zero_byte_mask = {};
{
const __m512i v01 = _mm512_set1_epi32(0x01010101u);
const __m512i v80 = _mm512_set1_epi32(0x80808080u);
const __m512i v1 = _mm512_sub_epi32(ch_matches, v01);
const __m512i tmp1 = _mm512_ternarylogic_epi32(v1, ch_matches, v80, 0x20);
zero_byte_mask = _mm512_test_epi32_mask(tmp1, tmp1);
}
while (zero_byte_mask) {
uint64_t const lsb_zero_pos = _tzcnt_u64(zero_byte_mask);
char const *base_ptr = ptr + (4 * lsb_zero_pos);
if (DN_MEMCMP(base_ptr + 0, find.data, find.size) == 0) {
result.found = true;
result.index = base_ptr - string.data;
} else if (DN_MEMCMP(base_ptr + 1, find.data, find.size) == 0) {
result.found = true;
result.index = base_ptr - string.data + 1;
} else if (DN_MEMCMP(base_ptr + 2, find.data, find.size) == 0) {
result.found = true;
result.index = base_ptr - string.data + 2;
} else if (DN_MEMCMP(base_ptr + 3, find.data, find.size) == 0) {
result.found = true;
result.index = base_ptr - string.data + 3;
}
if (result.found) {
result.start_to_before_match = DN_Str8FromPtr(string.data, result.index);
result.match = DN_Str8FromPtr(string.data + result.index, find.size);
result.match_to_end_of_buffer = DN_Str8FromPtr(result.match.data, string.size - result.index);
return result;
}
zero_byte_mask = DN_Bit_ClearNextLSB(zero_byte_mask);
}
}
for (DN_USize index = ptr - string.data - 1; index < string.size; index--) {
DN_Str8 string_slice = DN_Str8Slice(string, index, find.size);
if (DN_Str8Eq(string_slice, find)) {
result.found = true;
result.index = index;
result.start_to_before_match = DN_Str8FromPtr(string.data, index);
result.match = DN_Str8FromPtr(string.data + index, find.size);
result.match_to_end_of_buffer = DN_Str8FromPtr(result.match.data, string.size - index);
return result;
}
}
return result;
}
DN_API DN_Str8BSplitResult DN_SIMD_Str8BSplitAVX512F(DN_Str8 string, DN_Str8 find)
{
DN_Str8BSplitResult result = {};
DN_Str8FindResult find_result = DN_SIMD_Str8FindAVX512F(string, find);
if (find_result.found) {
result.lhs.data = string.data;
result.lhs.size = find_result.index;
result.rhs = DN_Str8Advance(find_result.match_to_end_of_buffer, find.size);
} else {
result.lhs = string;
}
return result;
}
DN_API DN_Str8BSplitResult DN_SIMD_Str8BSplitLastAVX512F(DN_Str8 string, DN_Str8 find)
{
DN_Str8BSplitResult result = {};
DN_Str8FindResult find_result = DN_SIMD_Str8FindLastAVX512F(string, find);
if (find_result.found) {
result.lhs.data = string.data;
result.lhs.size = find_result.index;
result.rhs = DN_Str8Advance(find_result.match_to_end_of_buffer, find.size);
} else {
result.lhs = string;
}
return result;
}
DN_API DN_USize DN_SIMD_Str8SplitAVX512F(DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitIncludeEmptyStrings mode)
{
DN_USize result = 0; // The number of splits in the actual string.
if (string.size == 0 || delimiter.size == 0 || delimiter.size <= 0)
return result;
DN_Str8BSplitResult split = {};
DN_Str8 first = string;
do {
split = DN_SIMD_Str8BSplitAVX512F(first, delimiter);
if (split.lhs.size || mode == DN_Str8SplitIncludeEmptyStrings_Yes) {
if (splits && result < splits_count)
splits[result] = split.lhs;
result++;
}
first = split.rhs;
} while (first.size);
return result;
}
DN_API DN_Slice<DN_Str8> DN_SIMD_Str8SplitAllocAVX512F(DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode)
{
DN_Slice<DN_Str8> result = {};
DN_USize splits_required = DN_SIMD_Str8SplitAVX512F(string, delimiter, /*splits*/ nullptr, /*count*/ 0, mode);
result.data = DN_ArenaNewArray(arena, DN_Str8, splits_required, DN_ZMem_No);
if (result.data) {
result.size = DN_SIMD_Str8SplitAVX512F(string, delimiter, result.data, splits_required, mode);
DN_Assert(splits_required == result.size);
}
return result;
}
-28
View File
@@ -1,28 +0,0 @@
#if !defined(DN_SIMD_AVX512F_H)
#define DN_SIMD_AVX512F_H
/*
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// $$$$$$\ $$\ $$\ $$\ $$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$$\
// $$ __$$\ $$ | $$ |$$ | $$ | $$ ____| $$$$ | $$ __$$\ $$ _____|
// $$ / $$ |$$ | $$ |\$$\ $$ | $$ | \_$$ | \__/ $$ |$$ |
// $$$$$$$$ |\$$\ $$ | \$$$$ /$$$$$$\ $$$$$$$\ $$ | $$$$$$ |$$$$$\
// $$ __$$ | \$$\$$ / $$ $$< \______|\_____$$\ $$ | $$ ____/ $$ __|
// $$ | $$ | \$$$ / $$ /\$$\ $$\ $$ | $$ | $$ | $$ |
// $$ | $$ | \$ / $$ / $$ | \$$$$$$ |$$$$$$\ $$$$$$$$\ $$ |
// \__| \__| \_/ \__| \__| \______/ \______|\________|\__|
//
// dn_avx512f.h -- Functions implemented w/ AVX512
//
////////////////////////////////////////////////////////////////////////////////////////////////////
*/
DN_API DN_Str8FindResult DN_Str8FindStr8AVX512F (DN_Str8 string, DN_Str8 find);
DN_API DN_Str8FindResult DN_Str8FindLastStr8AVX512F (DN_Str8 string, DN_Str8 find);
DN_API DN_Str8BSplitResult DN_Str8BSplitAVX512F (DN_Str8 string, DN_Str8 find);
DN_API DN_Str8BSplitResult DN_Str8BSplitLastAVX512F(DN_Str8 string, DN_Str8 find);
DN_API DN_USize DN_Str8SplitAVX512F (DN_Str8 string, DN_Str8 delimiter, DN_Str8 *splits, DN_USize splits_count, DN_Str8SplitIncludeEmptyStrings mode);
DN_API DN_Slice<DN_Str8> DN_Str8SplitAllocAVX512F (DN_Arena *arena, DN_Str8 string, DN_Str8 delimiter, DN_Str8SplitIncludeEmptyStrings mode);
#endif // DN_SIMD_AVX512F_H
-15
View File
@@ -4,8 +4,6 @@
#endif #endif
#include "Base/dn_base.cpp" #include "Base/dn_base.cpp"
#include "Base/dn_base_containers.cpp"
#include "Base/dn_base_leak.cpp"
DN_Core *g_dn_; DN_Core *g_dn_;
@@ -224,14 +222,6 @@ DN_API void DN_BeginFrame()
#endif #endif
} }
#if DN_H_WITH_HELPERS
#include "Extra/dn_helpers.cpp"
#endif
#if DN_H_WITH_ASYNC
#include "Extra/dn_async.cpp"
#endif
#if DN_H_WITH_NET #if DN_H_WITH_NET
#include "Extra/dn_net.cpp" #include "Extra/dn_net.cpp"
#endif #endif
@@ -239,8 +229,3 @@ DN_API void DN_BeginFrame()
#if DN_CPP_WITH_TESTS #if DN_CPP_WITH_TESTS
#include "Extra/dn_tests.cpp" #include "Extra/dn_tests.cpp"
#endif #endif
#if DN_CPP_WITH_DEMO
#include "Extra/dn_demo.cpp"
#endif
+5 -9
View File
@@ -141,9 +141,13 @@
// Tracing incurs an additional much heavier performance penalty than the UAF guard due to // Tracing incurs an additional much heavier performance penalty than the UAF guard due to
// the stacktrace that is stored per region to report to the user when a UAF guard violation // the stacktrace that is stored per region to report to the user when a UAF guard violation
// occurs. // occurs.
//
// Str8 AVX512F variants
// We have some AVX512 string functions that can be enabled by defining the following
//
// #define DN_STR8_AVX512F 1
#include "Base/dn_base.h" #include "Base/dn_base.h"
#include "Base/dn_base_leak.h"
#if DN_H_WITH_OS #if DN_H_WITH_OS
#if defined(DN_PLATFORM_WIN32) #if defined(DN_PLATFORM_WIN32)
@@ -191,14 +195,6 @@ DN_API void DN_Set (DN_Core *dn);
DN_API DN_Core *DN_Get (); DN_API DN_Core *DN_Get ();
DN_API void DN_BeginFrame(); DN_API void DN_BeginFrame();
#if DN_H_WITH_HELPERS
#include "Extra/dn_helpers.h"
#endif
#if DN_H_WITH_ASYNC
#include "Extra/dn_async.h"
#endif
#if DN_H_WITH_NET #if DN_H_WITH_NET
#include "Extra/dn_net.h" #include "Extra/dn_net.h"
#endif #endif
-2
View File
@@ -109,8 +109,6 @@ int main(int argc, char **argv)
DN_Str8 const REL_FILE_PATHS[] = { DN_Str8 const REL_FILE_PATHS[] = {
DN_Str8Lit("dn"), DN_Str8Lit("dn"),
DN_Str8Lit("Extra/dn_bin_pack"),
DN_Str8Lit("Extra/dn_csv"),
}; };
for (DN_ForIndexU(type, FileType_Count)) { for (DN_ForIndexU(type, FileType_Count)) {