win32: Fix error messages for WinINet, add DSMap
This commit is contained in:
parent
8d9ee115e1
commit
0ae5331d21
568
Code/Dqn.h
568
Code/Dqn.h
@ -186,11 +186,19 @@
|
|||||||
b = tmp; \
|
b = tmp; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define DQN_LEN_AND_STR(string) Dqn_CharCount(str), string
|
// NOTE: Prefer the templated Dqn_CharCount function for type-safety. I prefer
|
||||||
#define DQN_STR_AND_LEN(string) string, Dqn_CharCount(string)
|
// the macro version for embedding within macros for debuggers. When we step
|
||||||
#define DQN_STR_AND_LEN_I(string) string, (int)Dqn_CharCount(string)
|
// into a function call using the macro like, DQN_STRING("...") which is very
|
||||||
|
// common, the debugger jumps into the templated functions which is a waste of
|
||||||
|
// time (they're bug free by virtue of templatizing).
|
||||||
|
#define DQN_CHAR_COUNT(string) (sizeof(string) - 1)
|
||||||
|
|
||||||
|
#define DQN_LEN_AND_STR(string) DQN_CHAR_COUNT(str), string
|
||||||
|
#define DQN_STR_AND_LEN(string) string, DQN_CHAR_COUNT(string)
|
||||||
|
#define DQN_STR_AND_LEN_I(string) string, (int)DQN_CHAR_COUNT(string)
|
||||||
#define DQN_FOR_EACH(i, limit) for (Dqn_isize i = 0; i < (Dqn_isize)(limit); ++i)
|
#define DQN_FOR_EACH(i, limit) for (Dqn_isize i = 0; i < (Dqn_isize)(limit); ++i)
|
||||||
|
|
||||||
|
|
||||||
#define DQN_BYTES(val) (val)
|
#define DQN_BYTES(val) (val)
|
||||||
#define DQN_KILOBYTES(val) (1024ULL * DQN_BYTES(val))
|
#define DQN_KILOBYTES(val) (1024ULL * DQN_BYTES(val))
|
||||||
#define DQN_MEGABYTES(val) (1024ULL * DQN_KILOBYTES(val))
|
#define DQN_MEGABYTES(val) (1024ULL * DQN_KILOBYTES(val))
|
||||||
@ -277,8 +285,11 @@
|
|||||||
#define DQN_ASSERT_MSG(expr, fmt, ...) DQN_HARD_ASSERT_MSG(expr, fmt, ##__VA_ARGS__)
|
#define DQN_ASSERT_MSG(expr, fmt, ...) DQN_HARD_ASSERT_MSG(expr, fmt, ##__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DQN_INVALID_CODE_PATH DQN_ASSERT(0)
|
#define DQN_INVALID_CODE_PATH_MSG(fmt, ...) DQN_ASSERT_MSG(0, fmt, ##__VA_ARGS__)
|
||||||
#define DQN_HARD_INVALID_CODE_PATH DQN_HARD_ASSERT(0 && "Invalid Code Path")
|
#define DQN_INVALID_CODE_PATH DQN_INVALID_CODE_PATH_MSG("Invalid code path triggered")
|
||||||
|
|
||||||
|
#define DQN_HARD_INVALID_CODE_PATH_MSG(fmt, ...) DQN_HARD_ASSERT_MSG(0, fmt, ##__VA_ARGS__)
|
||||||
|
#define DQN_HARD_INVALID_CODE_PATH DQN_HARD_INVALID_CODE_PATH_MSG("Invalid code path triggered")
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// NOTE: Typedefs
|
// NOTE: Typedefs
|
||||||
@ -927,6 +938,106 @@ DQN_API void Dqn_CRTAllocator_Free (Dqn_CRTAllocator *alloc
|
|||||||
DQN_API void *Dqn_CRTAllocator__Malloc (Dqn_CRTAllocator *allocator, Dqn_usize size DQN_CALL_SITE_ARGS);
|
DQN_API void *Dqn_CRTAllocator__Malloc (Dqn_CRTAllocator *allocator, Dqn_usize size DQN_CALL_SITE_ARGS);
|
||||||
DQN_API void *Dqn_CRTAllocator__Realloc (Dqn_CRTAllocator *allocator, void *ptr, Dqn_usize size DQN_CALL_SITE_ARGS);
|
DQN_API void *Dqn_CRTAllocator__Realloc (Dqn_CRTAllocator *allocator, void *ptr, Dqn_usize size DQN_CALL_SITE_ARGS);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
// NOTE: Dqn_ArenaAllocator
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
struct Dqn_ArenaAllocatorBlock
|
||||||
|
{
|
||||||
|
Dqn_AllocationTracer *tracer;
|
||||||
|
void *memory;
|
||||||
|
Dqn_isize size;
|
||||||
|
Dqn_isize used;
|
||||||
|
Dqn_ArenaAllocatorBlock *prev;
|
||||||
|
Dqn_ArenaAllocatorBlock *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum struct Dqn_ArenaAllocatorMemProvider
|
||||||
|
{
|
||||||
|
CRT,
|
||||||
|
Virtual,
|
||||||
|
UserMemory,
|
||||||
|
};
|
||||||
|
|
||||||
|
Dqn_usize const DQN_MEM_ARENA_DEFAULT_MIN_BLOCK_SIZE = DQN_KILOBYTES(4);
|
||||||
|
struct Dqn_ArenaAllocator
|
||||||
|
{
|
||||||
|
Dqn_ArenaAllocatorMemProvider mem_provider;
|
||||||
|
|
||||||
|
// NOTE: Read/Write
|
||||||
|
Dqn_isize min_block_size; // (Optional): When 0, DQN_MEM_ARENA_DEFAULT_MIN_BLOCK_SIZE is used. Otherwise every new block will at minimum be sized to this value.
|
||||||
|
|
||||||
|
// The following fields are should be set once after zero initialisation
|
||||||
|
Dqn_AllocationTracer *tracer;
|
||||||
|
|
||||||
|
// NOTE: Read Only
|
||||||
|
Dqn_ArenaAllocatorBlock *curr_mem_block;
|
||||||
|
Dqn_ArenaAllocatorBlock *top_mem_block;
|
||||||
|
Dqn_isize highest_used_mark; // TODO(dqn): This is not implemented yet
|
||||||
|
int total_allocated_mem_blocks; // Total throughout the life-time of the arena
|
||||||
|
Dqn_isize usage_before_last_reset;
|
||||||
|
Dqn_isize wastage_before_last_reset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Dqn_ArenaAllocatorRegion
|
||||||
|
{
|
||||||
|
Dqn_ArenaAllocator *arena;
|
||||||
|
Dqn_ArenaAllocatorBlock *curr_mem_block;
|
||||||
|
Dqn_isize curr_mem_block_used;
|
||||||
|
Dqn_ArenaAllocatorBlock *top_mem_block;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Dqn_ArenaAllocatorAutoRegion
|
||||||
|
{
|
||||||
|
Dqn_ArenaAllocatorAutoRegion(Dqn_ArenaAllocator *arena);
|
||||||
|
~Dqn_ArenaAllocatorAutoRegion();
|
||||||
|
Dqn_ArenaAllocatorRegion region;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Dqn_ArenaAllocatorStats
|
||||||
|
{
|
||||||
|
Dqn_isize total_used;
|
||||||
|
Dqn_isize total_allocated;
|
||||||
|
Dqn_isize total_wasted;
|
||||||
|
Dqn_isize total_blocks;
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE: Dqn_ArenaAllocator can also be zero initialised and will default to the heap allocator with 0 size.
|
||||||
|
DQN_API Dqn_ArenaAllocator Dqn_ArenaAllocator_InitWithMemory(void *memory, Dqn_isize size);
|
||||||
|
DQN_API Dqn_ArenaAllocator Dqn_ArenaAllocator_InitWithCRT (Dqn_isize size DQN_CALL_SITE_ARGS);
|
||||||
|
DQN_API void Dqn_ArenaAllocator_Free (Dqn_ArenaAllocator *arena);
|
||||||
|
DQN_API Dqn_b32 Dqn_ArenaAllocator_Reserve (Dqn_ArenaAllocator *arena, Dqn_isize size DQN_CALL_SITE_ARGS);
|
||||||
|
DQN_API void Dqn_ArenaAllocator_ResetUsage (Dqn_ArenaAllocator *arena, Dqn_ZeroMem zero_mem);
|
||||||
|
DQN_API Dqn_ArenaAllocatorRegion Dqn_ArenaAllocator_BeginRegion (Dqn_ArenaAllocator *arena);
|
||||||
|
DQN_API void Dqn_ArenaAllocator_EndRegion (Dqn_ArenaAllocatorRegion region);
|
||||||
|
DQN_API Dqn_ArenaAllocatorAutoRegion Dqn_ArenaAllocator_AutoRegion (Dqn_ArenaAllocator *arena);
|
||||||
|
|
||||||
|
#define Dqn_ArenaAllocator_TaggedAllocate(arena, size, alignment, zero_mem, tag) Dqn_ArenaAllocator__Allocate(arena, size, alignment, zero_mem DQN_CALL_SITE(tag))
|
||||||
|
#define Dqn_ArenaAllocator_Allocate(arena, size, alignment, zero_mem) Dqn_ArenaAllocator__Allocate(arena, size, alignment, zero_mem DQN_CALL_SITE(""))
|
||||||
|
|
||||||
|
#define Dqn_ArenaAllocator_TaggedNew(arena, Type, zero_mem, tag) (Type *)Dqn_ArenaAllocator__Allocate(arena, sizeof(Type), alignof(Type), zero_mem DQN_CALL_SITE(tag))
|
||||||
|
#define Dqn_ArenaAllocator_New(arena, Type, zero_mem) (Type *)Dqn_ArenaAllocator__Allocate(arena, sizeof(Type), alignof(Type), zero_mem DQN_CALL_SITE(""))
|
||||||
|
|
||||||
|
#define Dqn_ArenaAllocator_TaggedNewArray(arena, Type, count, zero_mem, tag) (Type *)Dqn_ArenaAllocator__Allocate(arena, sizeof(Type) * count, alignof(Type), zero_mem DQN_CALL_SITE(tag))
|
||||||
|
#define Dqn_ArenaAllocator_NewArray(arena, Type, count, zero_mem) (Type *)Dqn_ArenaAllocator__Allocate(arena, sizeof(Type) * count, alignof(Type), zero_mem DQN_CALL_SITE(""))
|
||||||
|
|
||||||
|
#define Dqn_ArenaAllocator_TaggedCopyNullTerminate(arena, Type, src, count, tag) (Type *)Dqn_ArenaAllocator__CopyNullTerminate(arena, src, sizeof(*src) * count, alignof(Type) DQN_CALL_SITE(tag))
|
||||||
|
#define Dqn_ArenaAllocator_CopyNullTerminate(arena, Type, src, count) (Type *)Dqn_ArenaAllocator__CopyNullTerminate(arena, src, sizeof(*src) * count, alignof(Type) DQN_CALL_SITE(""))
|
||||||
|
|
||||||
|
#define Dqn_ArenaAllocator_TaggedCopy(arena, Type, src, count, tag) (Type *)Dqn_ArenaAllocator__Copy(arena, src, sizeof(*src) * count, alignof(Type) DQN_CALL_SITE(tag))
|
||||||
|
#define Dqn_ArenaAllocator_Copy(arena, Type, src, count) (Type *)Dqn_ArenaAllocator__Copy(arena, src, sizeof(*src) * count, alignof(Type) DQN_CALL_SITE(""))
|
||||||
|
DQN_API void *Dqn_ArenaAllocator__Copy (Dqn_ArenaAllocator *arena, void *src, Dqn_isize size, Dqn_u8 alignment DQN_CALL_SITE_ARGS);
|
||||||
|
DQN_API void *Dqn_ArenaAllocator__CopyNullTerminate (Dqn_ArenaAllocator *arena, void *src, Dqn_isize size, Dqn_u8 alignment DQN_CALL_SITE_ARGS);
|
||||||
|
DQN_API void *Dqn_ArenaAllocator__Allocate (Dqn_ArenaAllocator *arena, Dqn_isize size, Dqn_u8 alignment, Dqn_ZeroMem zero_mem DQN_CALL_SITE_ARGS);
|
||||||
|
|
||||||
|
DQN_API Dqn_ArenaAllocatorStats Dqn_ArenaAllocator_GetStats (Dqn_ArenaAllocator const *arena);
|
||||||
|
DQN_API void Dqn_ArenaAllocator_DumpStatsToLog (Dqn_ArenaAllocator const *arena, char const *label);
|
||||||
|
|
||||||
|
// Macros to print the string, i.e.
|
||||||
|
// fprintf(stdout, "Arena Dump - " DQN_ARENA_ALLOCATOR_FMT_STRING, DQN_ARENA_ALLOCATOR_FMT(stats, "Global Arena"));
|
||||||
|
#define DQN_ARENA_ALLOCATOR_FMT_STRING "%s: %$$.3d/%$$.3d (wasted %$$.3d - %d blks)"
|
||||||
|
#define DQN_ARENA_ALLOCATOR_FMT(stats, arena_label) arena_label, stats.total_used, stats.total_allocated, stats.total_wasted, stats.total_blocks
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
// NOTE: Dqn_Map
|
// NOTE: Dqn_Map
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
@ -944,8 +1055,8 @@ template <typename T>
|
|||||||
struct Dqn_Map
|
struct Dqn_Map
|
||||||
{
|
{
|
||||||
Dqn_ArenaAllocator *arena;
|
Dqn_ArenaAllocator *arena;
|
||||||
Dqn_MapEntry<T> **values;
|
Dqn_MapEntry<T> **slots;
|
||||||
Dqn_isize size; // The size of the 'values' list
|
Dqn_isize size; // The number of slots
|
||||||
|
|
||||||
// NOTE: Sum count and chain_count for total items in the list.
|
// NOTE: Sum count and chain_count for total items in the list.
|
||||||
Dqn_isize count; // The total number of top-level slots in the 'values' list occupied
|
Dqn_isize count; // The total number of top-level slots in the 'values' list occupied
|
||||||
@ -967,6 +1078,42 @@ template <typename T> Dqn_MapEntry<T> *Dqn_Map_AddCopy (Dqn_Map<T> *map, Dq
|
|||||||
template <typename T> Dqn_MapEntry<T> *Dqn_Map_Get (Dqn_Map<T> *map, Dqn_u64 hash);
|
template <typename T> Dqn_MapEntry<T> *Dqn_Map_Get (Dqn_Map<T> *map, Dqn_u64 hash);
|
||||||
template <typename T> void Dqn_Map_Erase (Dqn_Map<T> *map, Dqn_u64 hash, Dqn_ZeroMem zero_mem);
|
template <typename T> void Dqn_Map_Erase (Dqn_Map<T> *map, Dqn_u64 hash, Dqn_ZeroMem zero_mem);
|
||||||
|
|
||||||
|
// Demitri Spanos (HMN) Hash Table
|
||||||
|
// 70% Max Load, PoT size, Linear Probing, Tombstoneless Deletes
|
||||||
|
|
||||||
|
#if !defined(DQN_DS_MAP_MIN_SIZE)
|
||||||
|
#define DQN_DS_MAP_MIN_SIZE 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct Dqn_DSMapEntry
|
||||||
|
{
|
||||||
|
Dqn_u64 hash;
|
||||||
|
T value;
|
||||||
|
Dqn_u8 occupied;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct Dqn_DSMap
|
||||||
|
{
|
||||||
|
Dqn_ArenaAllocator arena;
|
||||||
|
Dqn_DSMapEntry<T> *slots;
|
||||||
|
Dqn_isize size; // The number of slots
|
||||||
|
Dqn_isize count; // The number of slots occupied in the list
|
||||||
|
};
|
||||||
|
|
||||||
|
// (Optional) DSMap can be zero initialised, it will default to a size of
|
||||||
|
// DQN_DS_MAP_MIN_SIZE elements, but if an initial size use the init function.
|
||||||
|
// size: A power of 2 size.
|
||||||
|
template <typename T> Dqn_DSMap<T> Dqn_DSMap_Init (Dqn_isize size);
|
||||||
|
template <typename T> void Dqn_DSMap_Free (Dqn_DSMap<T> *map);
|
||||||
|
|
||||||
|
template <typename T> Dqn_DSMapEntry<T> *Dqn_DSMap_FindOrAdd(Dqn_DSMap<T> *map, Dqn_u64 hash, Dqn_b32 find_only);
|
||||||
|
template <typename T> Dqn_DSMapEntry<T> *Dqn_DSMap_Add (Dqn_DSMap<T> *map, Dqn_u64 hash, T &value);
|
||||||
|
template <typename T> Dqn_DSMapEntry<T> *Dqn_DSMap_AddCopy (Dqn_DSMap<T> *map, Dqn_u64 hash, T const &value);
|
||||||
|
template <typename T> Dqn_DSMapEntry<T> *Dqn_DSMap_Get (Dqn_DSMap<T> *map, Dqn_u64 hash);
|
||||||
|
template <typename T> void Dqn_DSMap_Erase (Dqn_DSMap<T> *map, Dqn_u64 hash, Dqn_ZeroMem zero_mem);
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
// NOTE: Dqn_Array
|
// NOTE: Dqn_Array
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
@ -1006,7 +1153,7 @@ template <typename T> DQN_API T * Dqn_Array_Peek (Dqn
|
|||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
// NOTE: Dqn_String
|
// NOTE: Dqn_String
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
#define DQN_STRING(string) Dqn_String_Init(string, Dqn_CharCountI(string))
|
#define DQN_STRING(string) Dqn_String{(char *)string, (Dqn_isize)DQN_CHAR_COUNT(string), (Dqn_isize)DQN_CHAR_COUNT(string)}
|
||||||
#define DQN_STRING_FMT(string) (int)((string).size), (string).str
|
#define DQN_STRING_FMT(string) (int)((string).size), (string).str
|
||||||
struct Dqn_String
|
struct Dqn_String
|
||||||
{
|
{
|
||||||
@ -1047,12 +1194,16 @@ DQN_API Dqn_String Dqn_String_InitMemory(char *buf, Dqn_isize capacity);
|
|||||||
#define Dqn_String_TaggedAllocate(arena, size, zero_mem, tag) Dqn_String__Allocate(arena, size, zero_mem DQN_CALL_SITE(tag));
|
#define Dqn_String_TaggedAllocate(arena, size, zero_mem, tag) Dqn_String__Allocate(arena, size, zero_mem DQN_CALL_SITE(tag));
|
||||||
#define Dqn_String_Allocate(arena, size, zero_mem) Dqn_String__Allocate(arena, size, zero_mem DQN_CALL_SITE(""));
|
#define Dqn_String_Allocate(arena, size, zero_mem) Dqn_String__Allocate(arena, size, zero_mem DQN_CALL_SITE(""));
|
||||||
|
|
||||||
|
#define Dqn_String_TaggedCopyCString(src, size, arena, tag) Dqn_String__CopyCString(src, size, arena DQN_CALL_SITE(tag))
|
||||||
|
#define Dqn_String_CopyCString(src, size, arena) Dqn_String__CopyCString(src, size, arena DQN_CALL_SITE(""))
|
||||||
|
|
||||||
#define Dqn_String_TaggedCopy(src, arena, tag) Dqn_String__Copy(src, arena DQN_CALL_SITE(tag))
|
#define Dqn_String_TaggedCopy(src, arena, tag) Dqn_String__Copy(src, arena DQN_CALL_SITE(tag))
|
||||||
#define Dqn_String_Copy(src, arena) Dqn_String__Copy(src, arena DQN_CALL_SITE(""))
|
#define Dqn_String_Copy(src, arena) Dqn_String__Copy(src, arena DQN_CALL_SITE(""))
|
||||||
|
|
||||||
DQN_API Dqn_String Dqn_String__Fmt(Dqn_ArenaAllocator *arena DQN_CALL_SITE_ARGS, char const *fmt, ...);
|
DQN_API Dqn_String Dqn_String__Fmt(Dqn_ArenaAllocator *arena DQN_CALL_SITE_ARGS, char const *fmt, ...);
|
||||||
DQN_API Dqn_String Dqn_String__FmtV(Dqn_ArenaAllocator *arena, char const *fmt, va_list va DQN_CALL_SITE_ARGS);
|
DQN_API Dqn_String Dqn_String__FmtV(Dqn_ArenaAllocator *arena, char const *fmt, va_list va DQN_CALL_SITE_ARGS);
|
||||||
DQN_API Dqn_String Dqn_String__Allocate(Dqn_ArenaAllocator *arena, Dqn_isize size, Dqn_ZeroMem zero_mem);
|
DQN_API Dqn_String Dqn_String__Allocate(Dqn_ArenaAllocator *arena, Dqn_isize size, Dqn_ZeroMem zero_mem);
|
||||||
|
DQN_API Dqn_String Dqn_String__CopyCString(char const *string, Dqn_isize size, Dqn_ArenaAllocator *arena DQN_CALL_SITE_ARGS);
|
||||||
DQN_API Dqn_String Dqn_String__Copy(Dqn_String const src, Dqn_ArenaAllocator *arena DQN_CALL_SITE_ARGS);
|
DQN_API Dqn_String Dqn_String__Copy(Dqn_String const src, Dqn_ArenaAllocator *arena DQN_CALL_SITE_ARGS);
|
||||||
|
|
||||||
DQN_API Dqn_String Dqn_String_TrimWhitespaceAround(Dqn_String src);
|
DQN_API Dqn_String Dqn_String_TrimWhitespaceAround(Dqn_String src);
|
||||||
@ -1077,7 +1228,6 @@ DQN_API Dqn_Array<Dqn_String> Dqn_String_Split (Dqn_String src, D
|
|||||||
DQN_API Dqn_u64 Dqn_String_ToU64 (Dqn_String str);
|
DQN_API Dqn_u64 Dqn_String_ToU64 (Dqn_String str);
|
||||||
DQN_API Dqn_i64 Dqn_String_ToI64 (Dqn_String str);
|
DQN_API Dqn_i64 Dqn_String_ToI64 (Dqn_String str);
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
// NOTE: Dqn_FixedString
|
// NOTE: Dqn_FixedString
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
@ -1327,100 +1477,6 @@ DQN_API Dqn_V2I Dqn_RectI32_Size (Dqn_RectI32 rect);
|
|||||||
DQN_API Dqn_V2 Dqn_LerpV2 (Dqn_V2 a, Dqn_f32 t, Dqn_V2 b);
|
DQN_API Dqn_V2 Dqn_LerpV2 (Dqn_V2 a, Dqn_f32 t, Dqn_V2 b);
|
||||||
DQN_API Dqn_f32 Dqn_LerpF32(Dqn_f32 a, Dqn_f32 t, Dqn_f32 b);
|
DQN_API Dqn_f32 Dqn_LerpF32(Dqn_f32 a, Dqn_f32 t, Dqn_f32 b);
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
|
||||||
// NOTE: Dqn_ArenaAllocator
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
|
||||||
struct Dqn_ArenaAllocatorBlock
|
|
||||||
{
|
|
||||||
Dqn_AllocationTracer *tracer;
|
|
||||||
void *memory;
|
|
||||||
Dqn_isize size;
|
|
||||||
Dqn_isize used;
|
|
||||||
Dqn_ArenaAllocatorBlock *prev;
|
|
||||||
Dqn_ArenaAllocatorBlock *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum struct Dqn_ArenaAllocatorMemProvider
|
|
||||||
{
|
|
||||||
CRT,
|
|
||||||
Virtual,
|
|
||||||
UserMemory,
|
|
||||||
};
|
|
||||||
|
|
||||||
Dqn_usize const DQN_MEM_ARENA_DEFAULT_MIN_BLOCK_SIZE = DQN_KILOBYTES(4);
|
|
||||||
struct Dqn_ArenaAllocator
|
|
||||||
{
|
|
||||||
Dqn_ArenaAllocatorMemProvider mem_provider;
|
|
||||||
|
|
||||||
// NOTE: Read/Write
|
|
||||||
Dqn_isize min_block_size; // (Optional): When 0, DQN_MEM_ARENA_DEFAULT_MIN_BLOCK_SIZE is used. Otherwise every new block will at minimum be sized to this value.
|
|
||||||
|
|
||||||
// The following fields are should be set once after zero initialisation
|
|
||||||
Dqn_AllocationTracer *tracer;
|
|
||||||
|
|
||||||
// NOTE: Read Only
|
|
||||||
Dqn_ArenaAllocatorBlock *curr_mem_block;
|
|
||||||
Dqn_ArenaAllocatorBlock *top_mem_block;
|
|
||||||
Dqn_isize highest_used_mark; // TODO(dqn): This is not implemented yet
|
|
||||||
int total_allocated_mem_blocks; // Total throughout the life-time of the arena
|
|
||||||
Dqn_isize usage_before_last_reset;
|
|
||||||
Dqn_isize wastage_before_last_reset;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Dqn_ArenaAllocatorRegion
|
|
||||||
{
|
|
||||||
Dqn_ArenaAllocator *arena;
|
|
||||||
Dqn_ArenaAllocatorBlock *curr_mem_block;
|
|
||||||
Dqn_isize curr_mem_block_used;
|
|
||||||
Dqn_ArenaAllocatorBlock *top_mem_block;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Dqn_ArenaAllocatorAutoRegion
|
|
||||||
{
|
|
||||||
Dqn_ArenaAllocatorAutoRegion(Dqn_ArenaAllocator *arena);
|
|
||||||
~Dqn_ArenaAllocatorAutoRegion();
|
|
||||||
Dqn_ArenaAllocatorRegion region;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Dqn_ArenaAllocatorStats
|
|
||||||
{
|
|
||||||
Dqn_isize total_used;
|
|
||||||
Dqn_isize total_allocated;
|
|
||||||
Dqn_isize total_wasted;
|
|
||||||
Dqn_isize total_blocks;
|
|
||||||
};
|
|
||||||
|
|
||||||
// NOTE: Dqn_ArenaAllocator can also be zero initialised and will default to the heap allocator with 0 size.
|
|
||||||
DQN_API Dqn_ArenaAllocator Dqn_ArenaAllocator_InitWithMemory(void *memory, Dqn_isize size);
|
|
||||||
DQN_API Dqn_ArenaAllocator Dqn_ArenaAllocator_InitWithCRT (Dqn_isize size DQN_CALL_SITE_ARGS);
|
|
||||||
DQN_API void Dqn_ArenaAllocator_Free (Dqn_ArenaAllocator *arena);
|
|
||||||
DQN_API Dqn_b32 Dqn_ArenaAllocator_Reserve (Dqn_ArenaAllocator *arena, Dqn_isize size DQN_CALL_SITE_ARGS);
|
|
||||||
DQN_API void Dqn_ArenaAllocator_ResetUsage (Dqn_ArenaAllocator *arena, Dqn_ZeroMem zero_mem);
|
|
||||||
DQN_API Dqn_ArenaAllocatorRegion Dqn_ArenaAllocator_BeginRegion (Dqn_ArenaAllocator *arena);
|
|
||||||
DQN_API void Dqn_ArenaAllocator_EndRegion (Dqn_ArenaAllocatorRegion region);
|
|
||||||
DQN_API Dqn_ArenaAllocatorAutoRegion Dqn_ArenaAllocator_AutoRegion (Dqn_ArenaAllocator *arena);
|
|
||||||
|
|
||||||
#define Dqn_ArenaAllocator_TaggedAllocate(arena, size, alignment, zero_mem, tag) Dqn_ArenaAllocator__Allocate(arena, size, alignment, zero_mem DQN_CALL_SITE(tag))
|
|
||||||
#define Dqn_ArenaAllocator_Allocate(arena, size, alignment, zero_mem) Dqn_ArenaAllocator__Allocate(arena, size, alignment, zero_mem DQN_CALL_SITE(""))
|
|
||||||
|
|
||||||
#define Dqn_ArenaAllocator_TaggedNew(arena, Type, zero_mem, tag) (Type *)Dqn_ArenaAllocator__Allocate(arena, sizeof(Type), alignof(Type), zero_mem DQN_CALL_SITE(tag))
|
|
||||||
#define Dqn_ArenaAllocator_New(arena, Type, zero_mem) (Type *)Dqn_ArenaAllocator__Allocate(arena, sizeof(Type), alignof(Type), zero_mem DQN_CALL_SITE(""))
|
|
||||||
|
|
||||||
#define Dqn_ArenaAllocator_TaggedNewArray(arena, Type, count, zero_mem, tag) (Type *)Dqn_ArenaAllocator__Allocate(arena, sizeof(Type) * count, alignof(Type), zero_mem DQN_CALL_SITE(tag))
|
|
||||||
#define Dqn_ArenaAllocator_NewArray(arena, Type, count, zero_mem) (Type *)Dqn_ArenaAllocator__Allocate(arena, sizeof(Type) * count, alignof(Type), zero_mem DQN_CALL_SITE(""))
|
|
||||||
|
|
||||||
#define Dqn_ArenaAllocator_TaggedCopyNullTerminate(arena, Type, src, count, tag) (Type *)Dqn_ArenaAllocator__CopyNullTerminate(arena, src, sizeof(*src) * count, alignof(Type) DQN_CALL_SITE(tag))
|
|
||||||
#define Dqn_ArenaAllocator_CopyNullTerminate(arena, Type, src, count) (Type *)Dqn_ArenaAllocator__CopyNullTerminate(arena, src, sizeof(*src) * count, alignof(Type) DQN_CALL_SITE(""))
|
|
||||||
|
|
||||||
#define Dqn_ArenaAllocator_TaggedCopy(arena, Type, src, count, tag) (Type *)Dqn_ArenaAllocator__Copy(arena, src, sizeof(*src) * count, alignof(Type) DQN_CALL_SITE(tag))
|
|
||||||
#define Dqn_ArenaAllocator_Copy(arena, Type, src, count) (Type *)Dqn_ArenaAllocator__Copy(arena, src, sizeof(*src) * count, alignof(Type) DQN_CALL_SITE(""))
|
|
||||||
DQN_API void *Dqn_ArenaAllocator__Copy (Dqn_ArenaAllocator *arena, void *src, Dqn_isize size, Dqn_u8 alignment DQN_CALL_SITE_ARGS);
|
|
||||||
DQN_API void *Dqn_ArenaAllocator__CopyNullTerminate (Dqn_ArenaAllocator *arena, void *src, Dqn_isize size, Dqn_u8 alignment DQN_CALL_SITE_ARGS);
|
|
||||||
DQN_API void *Dqn_ArenaAllocator__Allocate (Dqn_ArenaAllocator *arena, Dqn_isize size, Dqn_u8 alignment, Dqn_ZeroMem zero_mem DQN_CALL_SITE_ARGS);
|
|
||||||
DQN_API Dqn_ArenaAllocatorStats Dqn_ArenaAllocator_GetStats (Dqn_ArenaAllocator const *arena);
|
|
||||||
DQN_API void Dqn_ArenaAllocator_DumpStatsToLog (Dqn_ArenaAllocator const *arena, char const *label);
|
|
||||||
DQN_API Dqn_FixedString<512> Dqn_ArenaAllocator_StatsString (Dqn_ArenaAllocator const *arena, char const *label);
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
// NOTE: Dqn_Bit
|
// NOTE: Dqn_Bit
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
@ -1478,6 +1534,9 @@ DQN_API Dqn_u8 *Dqn_Hex_CStringToU8BytesUnchecked(char const *hex, Dq
|
|||||||
DQN_API Dqn_Array<Dqn_u8> Dqn_Hex_CStringToU8ArrayUnchecked(char const *hex, Dqn_isize size, Dqn_ArenaAllocator *arena);
|
DQN_API Dqn_Array<Dqn_u8> Dqn_Hex_CStringToU8ArrayUnchecked(char const *hex, Dqn_isize size, Dqn_ArenaAllocator *arena);
|
||||||
DQN_API Dqn_Array<Dqn_u8> Dqn_Hex_StringToU8ArrayUnchecked (Dqn_String const hex, Dqn_ArenaAllocator *arena);
|
DQN_API Dqn_Array<Dqn_u8> Dqn_Hex_StringToU8ArrayUnchecked (Dqn_String const hex, Dqn_ArenaAllocator *arena);
|
||||||
|
|
||||||
|
DQN_API Dqn_u64 Dqn_Hex_CStringToU64(char const *hex, Dqn_isize size);
|
||||||
|
DQN_API Dqn_u64 Dqn_Hex_StringToU64(Dqn_String hex);
|
||||||
|
|
||||||
// Convert a series of bytes into a string
|
// Convert a series of bytes into a string
|
||||||
DQN_API char *Dqn_Hex_U8BytesToCString(char const *bytes, Dqn_isize size, Dqn_ArenaAllocator *arena);
|
DQN_API char *Dqn_Hex_U8BytesToCString(char const *bytes, Dqn_isize size, Dqn_ArenaAllocator *arena);
|
||||||
DQN_API Dqn_String Dqn_Hex_U8ArrayToString (Dqn_Array<Dqn_u8> const bytes, Dqn_ArenaAllocator *arena);
|
DQN_API Dqn_String Dqn_Hex_U8ArrayToString (Dqn_Array<Dqn_u8> const bytes, Dqn_ArenaAllocator *arena);
|
||||||
@ -1586,9 +1645,15 @@ DQN_API char *Dqn_U64ToTempStr (Dqn_u64 val, Dqn_b32 comma_sep = true);
|
|||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
// NOTE: Dqn_Win
|
// NOTE: Dqn_Win
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
// last_error: (Optional) The error code associated with the last error will be written into this value
|
struct Dqn_WinErrorMsg
|
||||||
DQN_API Dqn_String Dqn_Win_LastError (Dqn_ArenaAllocator *arena, int *last_error);
|
{
|
||||||
DQN_API void Dqn_Win_DumpLastError(Dqn_ArenaAllocator *tmp_arena, Dqn_String prefix);
|
DWORD code;
|
||||||
|
char str[DQN_KILOBYTES(64) - 1]; // Maximum error size
|
||||||
|
DWORD size;
|
||||||
|
};
|
||||||
|
DQN_API Dqn_WinErrorMsg Dqn_Win_LastError ();
|
||||||
|
DQN_API void Dqn_Win_DumpLastError(Dqn_String prefix); // Automatically dumps to DQN_LOG_E
|
||||||
|
|
||||||
DQN_API Dqn_StringW Dqn_Win_UTF8ToWChar (Dqn_String src, Dqn_ArenaAllocator *arena);
|
DQN_API Dqn_StringW Dqn_Win_UTF8ToWChar (Dqn_String src, Dqn_ArenaAllocator *arena);
|
||||||
DQN_API Dqn_String Dqn_Win_WCharToUTF8 (Dqn_StringW src, Dqn_ArenaAllocator *arena);
|
DQN_API Dqn_String Dqn_Win_WCharToUTF8 (Dqn_StringW src, Dqn_ArenaAllocator *arena);
|
||||||
|
|
||||||
@ -1847,8 +1912,8 @@ Dqn_Map<T> Dqn_Map_InitWithArena(Dqn_ArenaAllocator *arena, Dqn_isize size)
|
|||||||
result.arena = arena;
|
result.arena = arena;
|
||||||
|
|
||||||
Dqn_isize final_size = size == 0 ? 4096 : size;
|
Dqn_isize final_size = size == 0 ? 4096 : size;
|
||||||
result.values = Dqn_ArenaAllocator_NewArray(arena, Dqn_MapEntry<T> *, final_size, Dqn_ZeroMem::Yes);
|
result.slots = Dqn_ArenaAllocator_NewArray(arena, Dqn_MapEntry<T> *, final_size, Dqn_ZeroMem::Yes);
|
||||||
if (result.values) result.size = final_size;
|
if (result.slots) result.size = final_size;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1856,7 +1921,7 @@ template <typename T>
|
|||||||
Dqn_MapEntry<T> *Dqn_Map_FindOrAdd(Dqn_Map<T> *map, Dqn_u64 hash, Dqn_MapCollideRule rule)
|
Dqn_MapEntry<T> *Dqn_Map_FindOrAdd(Dqn_Map<T> *map, Dqn_u64 hash, Dqn_MapCollideRule rule)
|
||||||
{
|
{
|
||||||
Dqn_isize index = hash % map->size;
|
Dqn_isize index = hash % map->size;
|
||||||
Dqn_MapEntry<T> *result = map->values[index];
|
Dqn_MapEntry<T> *result = map->slots[index];
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
@ -1884,7 +1949,7 @@ Dqn_MapEntry<T> *Dqn_Map_FindOrAdd(Dqn_Map<T> *map, Dqn_u64 hash, Dqn_MapCollide
|
|||||||
{
|
{
|
||||||
result = Dqn_ArenaAllocator_New(map->arena, Dqn_MapEntry<T>, Dqn_ZeroMem::Yes);
|
result = Dqn_ArenaAllocator_New(map->arena, Dqn_MapEntry<T>, Dqn_ZeroMem::Yes);
|
||||||
map->count++;
|
map->count++;
|
||||||
map->values[index] = result;
|
map->slots[index] = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
@ -1919,7 +1984,7 @@ Dqn_MapEntry<T> *Dqn_Map_Get(Dqn_Map<T> *map, Dqn_u64 hash)
|
|||||||
Dqn_isize index = hash % map->size;
|
Dqn_isize index = hash % map->size;
|
||||||
Dqn_MapEntry<T> *result = nullptr;
|
Dqn_MapEntry<T> *result = nullptr;
|
||||||
|
|
||||||
for (Dqn_MapEntry<T> *entry = map->values[index]; entry; entry = entry->next)
|
for (Dqn_MapEntry<T> *entry = map->slots[index]; entry; entry = entry->next)
|
||||||
{
|
{
|
||||||
if (entry->hash == hash)
|
if (entry->hash == hash)
|
||||||
{
|
{
|
||||||
@ -1935,7 +2000,7 @@ template <typename T>
|
|||||||
void Dqn_Map_Erase(Dqn_Map<T> *map, Dqn_u64 hash, Dqn_ZeroMem zero_mem)
|
void Dqn_Map_Erase(Dqn_Map<T> *map, Dqn_u64 hash, Dqn_ZeroMem zero_mem)
|
||||||
{
|
{
|
||||||
Dqn_isize index = hash % map->size;
|
Dqn_isize index = hash % map->size;
|
||||||
Dqn_MapEntry<T> **entry = &(map->values[index]);
|
Dqn_MapEntry<T> **entry = &(map->slots[index]);
|
||||||
Dqn_b32 is_chain_entry = *entry && (*entry)->next;
|
Dqn_b32 is_chain_entry = *entry && (*entry)->next;
|
||||||
|
|
||||||
while ((*entry) && (*entry)->hash != hash)
|
while ((*entry) && (*entry)->hash != hash)
|
||||||
@ -1956,6 +2021,143 @@ void Dqn_Map_Erase(Dqn_Map<T> *map, Dqn_u64 hash, Dqn_ZeroMem zero_mem)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
// NOTE: Dqn_DSMap Template Implementation
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
Dqn_DSMap<T> Dqn_DSMap_Init(Dqn_isize size)
|
||||||
|
{
|
||||||
|
DQN_ASSERT_MSG(((size & (size - 1)) == 0), "Require non-zero power of 2 table size");
|
||||||
|
Dqn_DSMap<T> result = {};
|
||||||
|
result.slots = Dqn_ArenaAllocator_NewArray(&result.arena, Dqn_DSMapEntry<T>, size, Dqn_ZeroMem::Yes);
|
||||||
|
if (result.slots) result.size = size;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void Dqn_DSMap_Free(Dqn_DSMap<T> *map)
|
||||||
|
{
|
||||||
|
Dqn_ArenaAllocator_Free(&map->arena);
|
||||||
|
*map = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Dqn_DSMapEntry<T> *Dqn_DSMap_FindOrAdd(Dqn_DSMap<T> *map, Dqn_u64 hash, Dqn_b32 find_only)
|
||||||
|
{
|
||||||
|
if (!map->slots)
|
||||||
|
{
|
||||||
|
if (!find_only) *map = Dqn_DSMap_Init<T>(DQN_DS_MAP_MIN_SIZE);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dqn_isize index = hash % map->size;
|
||||||
|
Dqn_DSMapEntry<T> *result = map->slots + index;
|
||||||
|
while (result->occupied && result->hash != hash)
|
||||||
|
{
|
||||||
|
Dqn_isize next_index = (index + 1) % map->size;
|
||||||
|
result = map->slots + next_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result->occupied)
|
||||||
|
{
|
||||||
|
DQN_ASSERT_MSG(result->hash == hash,
|
||||||
|
"We have a max load factor of 70%% so we should never get an occupied slot that doesn't match "
|
||||||
|
"the hash we were searching for");
|
||||||
|
}
|
||||||
|
else if (find_only)
|
||||||
|
{
|
||||||
|
result = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result->hash = hash;
|
||||||
|
result->occupied = true;
|
||||||
|
|
||||||
|
Dqn_f32 load_factor = ++map->count / DQN_CAST(Dqn_f32)map->size;
|
||||||
|
if (load_factor >= 0.7f)
|
||||||
|
{
|
||||||
|
auto new_map = Dqn_DSMap_Init<T>(map->size << 1);
|
||||||
|
for (Dqn_isize map_index = 0; map_index < map->size; map_index++)
|
||||||
|
{
|
||||||
|
Dqn_DSMapEntry<T> *entry = map->slots + map_index;
|
||||||
|
if (entry->occupied)
|
||||||
|
{
|
||||||
|
Dqn_DSMapEntry<T> *new_entry = Dqn_DSMap_AddCopy(&new_map, entry->hash, entry->value);
|
||||||
|
if (new_entry->hash == hash)
|
||||||
|
result = new_entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dqn_DSMap_Free(map);
|
||||||
|
*map = new_map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Dqn_DSMapEntry<T> *Dqn_DSMap_Add(Dqn_DSMap<T> *map, Dqn_u64 hash, T &value)
|
||||||
|
{
|
||||||
|
Dqn_DSMapEntry<T> *result = Dqn_DSMap_FindOrAdd(map, hash, false /*find_only*/);
|
||||||
|
if (result)
|
||||||
|
result->value = value;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Dqn_DSMapEntry<T> *Dqn_DSMap_AddCopy(Dqn_DSMap<T> *map, Dqn_u64 hash, T const &value)
|
||||||
|
{
|
||||||
|
Dqn_DSMapEntry<T> *result = Dqn_DSMap_FindOrAdd(map, hash, false /*find_only*/);
|
||||||
|
if (result)
|
||||||
|
result->value = value;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Dqn_DSMapEntry<T> *Dqn_DSMap_Get(Dqn_DSMap<T> *map, Dqn_u64 hash)
|
||||||
|
{
|
||||||
|
Dqn_DSMapEntry<T> *result = Dqn_DSMap_FindOrAdd(map, hash, true /*find_only*/);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void Dqn_DSMap_Erase(Dqn_DSMap<T> *map, Dqn_u64 hash, Dqn_ZeroMem zero_mem)
|
||||||
|
{
|
||||||
|
Dqn_isize index = hash % map->size;
|
||||||
|
Dqn_DSMapEntry<T> *result = map->slots + index;
|
||||||
|
if (!result || !result->occupied)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Dqn_isize start_index = index;
|
||||||
|
Dqn_isize probe_index = index;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
probe_index = (probe_index + 1) % map->size;
|
||||||
|
Dqn_DSMapEntry<T> *probe = map->slots + probe_index;
|
||||||
|
if (!probe->occupied) break;
|
||||||
|
|
||||||
|
Dqn_isize desired_index = probe->hash % map->size;
|
||||||
|
if (desired_index != probe_index)
|
||||||
|
{
|
||||||
|
map->slots[start_index] = map->slots[probe_index];
|
||||||
|
start_index = probe_index;
|
||||||
|
DQN_ASSERT(map->slots[start_index].occupied);
|
||||||
|
DQN_ASSERT(map->slots[probe_index].occupied);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DQN_ASSERT(map->slots[start_index].occupied);
|
||||||
|
map->slots[start_index].occupied = false;
|
||||||
|
map->count -= 1;
|
||||||
|
|
||||||
|
Dqn__ZeroMemBytes(map->slots + start_index,
|
||||||
|
sizeof(map->slots[start_index]),
|
||||||
|
zero_mem);
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
// NOTE: Dqn_FixedString Template Implementation
|
// NOTE: Dqn_FixedString Template Implementation
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
@ -2596,6 +2798,7 @@ Dqn_b32 Dqn_List_Iterate(Dqn_List<T> *list, Dqn_ListIterator<T> *iterator)
|
|||||||
// NOTE: FormatMessageA
|
// NOTE: FormatMessageA
|
||||||
#define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000
|
#define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000
|
||||||
#define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200
|
#define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200
|
||||||
|
#define FORMAT_MESSAGE_FROM_HMODULE 0x00000800
|
||||||
#define MAKELANGID(p, s) ((((unsigned short )(s)) << 10) | (unsigned short )(p))
|
#define MAKELANGID(p, s) ((((unsigned short )(s)) << 10) | (unsigned short )(p))
|
||||||
#define SUBLANG_DEFAULT 0x01 // user default
|
#define SUBLANG_DEFAULT 0x01 // user default
|
||||||
#define LANG_NEUTRAL 0x00
|
#define LANG_NEUTRAL 0x00
|
||||||
@ -2740,6 +2943,8 @@ Dqn_b32 Dqn_List_Iterate(Dqn_List<T> *list, Dqn_ListIterator<T> *iterator)
|
|||||||
BOOL FreeLibrary (void *lib_module);
|
BOOL FreeLibrary (void *lib_module);
|
||||||
void *GetProcAddress (void *hmodule, char const *proc_name);
|
void *GetProcAddress (void *hmodule, char const *proc_name);
|
||||||
unsigned int GetWindowModuleFileNameA (void *hwnd, char *file_name, unsigned int file_name_max);
|
unsigned int GetWindowModuleFileNameA (void *hwnd, char *file_name, unsigned int file_name_max);
|
||||||
|
HMODULE GetModuleHandleA (char const *lpModuleName);
|
||||||
|
|
||||||
DWORD WaitForSingleObject (HANDLE handle, DWORD milliseconds);
|
DWORD WaitForSingleObject (HANDLE handle, DWORD milliseconds);
|
||||||
|
|
||||||
BOOL QueryPerformanceCounter (LARGE_INTEGER *performance_count);
|
BOOL QueryPerformanceCounter (LARGE_INTEGER *performance_count);
|
||||||
@ -3212,13 +3417,26 @@ DQN_API Dqn_String Dqn_String__Allocate(Dqn_ArenaAllocator *arena, Dqn_isize siz
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DQN_API Dqn_String Dqn_String__CopyCString(char const *string, Dqn_isize size, Dqn_ArenaAllocator *arena DQN_CALL_SITE_ARGS)
|
||||||
|
{
|
||||||
|
Dqn_String result = {};
|
||||||
|
if (size < 0 || !string || !arena)
|
||||||
|
{
|
||||||
|
DQN_INVALID_CODE_PATH;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *copy = DQN_CAST(char *)Dqn_ArenaAllocator__Allocate(arena, size + 1, alignof(char), Dqn_ZeroMem::No DQN_CALL_SITE_ARGS_INPUT);
|
||||||
|
DQN_MEMCOPY(copy, string, DQN_CAST(size_t)size);
|
||||||
|
copy[size] = 0;
|
||||||
|
|
||||||
|
result = Dqn_String_Init(copy, size);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
DQN_API Dqn_String Dqn_String__Copy(Dqn_String const src, Dqn_ArenaAllocator *arena DQN_CALL_SITE_ARGS)
|
DQN_API Dqn_String Dqn_String__Copy(Dqn_String const src, Dqn_ArenaAllocator *arena DQN_CALL_SITE_ARGS)
|
||||||
{
|
{
|
||||||
Dqn_String result = src;
|
Dqn_String result = Dqn_String__CopyCString(src.str, src.size, arena DQN_CALL_SITE_ARGS_INPUT);
|
||||||
result.str = DQN_CAST(char *)Dqn_ArenaAllocator__Allocate(arena, result.size + 1, alignof(char), Dqn_ZeroMem::No DQN_CALL_SITE_ARGS_INPUT);
|
|
||||||
result.cap = result.size;
|
|
||||||
DQN_MEMCOPY(result.str, src.str, DQN_CAST(size_t)result.size);
|
|
||||||
result.str[result.size] = 0;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3293,7 +3511,7 @@ DQN_API Dqn_b32 Dqn_String_StartsWith(Dqn_String string, Dqn_String prefix, Dqn_
|
|||||||
if (prefix.size > string.size)
|
if (prefix.size > string.size)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
Dqn_String substring = {string.str, prefix.size};
|
Dqn_String substring = Dqn_String{string.str, prefix.size, prefix.size};
|
||||||
result = Dqn_String_Eq(substring, prefix, eq_case);
|
result = Dqn_String_Eq(substring, prefix, eq_case);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -3617,28 +3835,10 @@ DQN_API Dqn_ArenaAllocatorStats Dqn_ArenaAllocator_GetStats(Dqn_ArenaAllocator c
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dqn_String const DQN_ARENA_ALLOCATOR__STATS_FMT = DQN_STRING("%s: %$$.3d/%$$.3d (wasted %$$.3d - %d blks)");
|
|
||||||
DQN_API void Dqn_ArenaAllocator_DumpStatsToLog(Dqn_ArenaAllocator const *arena, char const *label)
|
DQN_API void Dqn_ArenaAllocator_DumpStatsToLog(Dqn_ArenaAllocator const *arena, char const *label)
|
||||||
{
|
{
|
||||||
Dqn_ArenaAllocatorStats stats = Dqn_ArenaAllocator_GetStats(arena);
|
Dqn_ArenaAllocatorStats stats = Dqn_ArenaAllocator_GetStats(arena);
|
||||||
DQN_LOG_M(DQN_ARENA_ALLOCATOR__STATS_FMT.str,
|
DQN_LOG_M(DQN_ARENA_ALLOCATOR_FMT_STRING, DQN_ARENA_ALLOCATOR_FMT(stats, label));
|
||||||
label,
|
|
||||||
stats.total_used,
|
|
||||||
stats.total_allocated,
|
|
||||||
stats.total_wasted,
|
|
||||||
stats.total_blocks);
|
|
||||||
}
|
|
||||||
|
|
||||||
DQN_API Dqn_FixedString<512> Dqn_ArenaAllocator_StatsString(Dqn_ArenaAllocator const *arena, char const *label)
|
|
||||||
{
|
|
||||||
Dqn_ArenaAllocatorStats stats = Dqn_ArenaAllocator_GetStats(arena);
|
|
||||||
auto result = Dqn_FixedString_Fmt<512>(DQN_ARENA_ALLOCATOR__STATS_FMT.str,
|
|
||||||
label,
|
|
||||||
stats.total_used,
|
|
||||||
stats.total_allocated,
|
|
||||||
stats.total_wasted,
|
|
||||||
stats.total_blocks);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
@ -4285,7 +4485,7 @@ DQN_API Dqn_b32 Dqn_Char_IsWhitespace(char ch)
|
|||||||
|
|
||||||
DQN_API Dqn_b32 Dqn_Char_IsHex(char ch)
|
DQN_API Dqn_b32 Dqn_Char_IsHex(char ch)
|
||||||
{
|
{
|
||||||
Dqn_b32 result = ((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') || (ch >= '0' || ch <= '9'));
|
Dqn_b32 result = ((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') || (ch >= '0' && ch <= '9'));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4394,6 +4594,42 @@ DQN_API Dqn_Array<Dqn_u8> Dqn_Hex_StringToU8ArrayUnchecked(Dqn_String const hex,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DQN_API Dqn_u64 Dqn_Hex_CStringToU64(char const *hex, Dqn_isize size)
|
||||||
|
{
|
||||||
|
Dqn_isize trim_size = size;
|
||||||
|
char const *trim_hex = hex;
|
||||||
|
if (trim_size >= 2)
|
||||||
|
{
|
||||||
|
if (trim_hex[0] == '0' && (trim_hex[1] == 'x' || trim_hex[1] == 'X'))
|
||||||
|
{
|
||||||
|
trim_size -= 2;
|
||||||
|
trim_hex += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DQN_ASSERT(DQN_CAST(Dqn_usize)(trim_size * 4 / 8) /*maximum amount of bytes represented in the hex string*/ <= sizeof(Dqn_u64));
|
||||||
|
|
||||||
|
Dqn_u64 result = 0;
|
||||||
|
Dqn_usize bits_written = 0;
|
||||||
|
for (Dqn_isize hex_index = 0; hex_index < size; hex_index++, bits_written += 4)
|
||||||
|
{
|
||||||
|
char ch = trim_hex[hex_index];
|
||||||
|
if (!Dqn_Char_IsHex(ch)) break;
|
||||||
|
Dqn_u8 val = Dqn_Char_HexToU8(ch);
|
||||||
|
Dqn_usize bit_shift = 60 - bits_written;
|
||||||
|
result |= (DQN_CAST(Dqn_u64)val << bit_shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
result >>= (64 - bits_written); // Shift the remainder digits to the end.
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DQN_API Dqn_u64 Dqn_Hex_StringToU64(Dqn_String hex)
|
||||||
|
{
|
||||||
|
Dqn_u64 result = Dqn_Hex_CStringToU64(hex.str, hex.size);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
DQN_API char *Dqn_Hex_U8BytesToCString(char const *bytes, Dqn_isize size, Dqn_ArenaAllocator *arena)
|
DQN_API char *Dqn_Hex_U8BytesToCString(char const *bytes, Dqn_isize size, Dqn_ArenaAllocator *arena)
|
||||||
{
|
{
|
||||||
char *result = size > 0 ? Dqn_ArenaAllocator_NewArray(arena, char, size * 2, Dqn_ZeroMem::No) : nullptr;
|
char *result = size > 0 ? Dqn_ArenaAllocator_NewArray(arena, char, size * 2, Dqn_ZeroMem::No) : nullptr;
|
||||||
@ -5032,37 +5268,40 @@ DQN_API char *Dqn_U64ToTempStr(Dqn_u64 val, Dqn_b32 comma_sep)
|
|||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
// NOTE: Dqn_Win Implementation
|
// NOTE: Dqn_Win Implementation
|
||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
DQN_API Dqn_String Dqn_Win_LastError(Dqn_ArenaAllocator *arena, int *last_error)
|
DQN_API Dqn_WinErrorMsg Dqn_Win_LastError()
|
||||||
{
|
{
|
||||||
DWORD error = GetLastError();
|
Dqn_WinErrorMsg result;
|
||||||
int const MSG_SIZE_BYTES = DQN_KILOBYTES(64) - 1; // Maximum error size
|
result.code = GetLastError();
|
||||||
int const MSG_SIZE = MSG_SIZE_BYTES / sizeof(char);
|
result.str[0] = 0;
|
||||||
auto * msg = DQN_CAST(char *) Dqn_ArenaAllocator_NewArray(arena, char, MSG_SIZE_BYTES, Dqn_ZeroMem::No);
|
|
||||||
|
|
||||||
DWORD msg_length = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, // DWORD dwFlags,
|
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||||
nullptr, // LPCVOID lpSource,
|
HMODULE module_to_get_errors_from = nullptr;
|
||||||
error, // DWORD dwMessageId,
|
|
||||||
|
if (result.code >= 12000 && result.code <= 12175) // WinINET Errors
|
||||||
|
{
|
||||||
|
flags |= FORMAT_MESSAGE_FROM_HMODULE;
|
||||||
|
module_to_get_errors_from = GetModuleHandleA("wininet.dll");
|
||||||
|
}
|
||||||
|
|
||||||
|
result.size = FormatMessageA(flags,
|
||||||
|
module_to_get_errors_from, // LPCVOID lpSource,
|
||||||
|
result.code, // DWORD dwMessageId,
|
||||||
0, // DWORD dwLanguageId,
|
0, // DWORD dwLanguageId,
|
||||||
msg, // LPSTR lpBuffer,
|
result.str, // LPSTR lpBuffer,
|
||||||
MSG_SIZE, // DWORD nSize,
|
DQN_CAST(DWORD) Dqn_ArrayCountI(result.str), // DWORD nSize,
|
||||||
nullptr // va_list * Arguments);
|
nullptr // va_list * Arguments);
|
||||||
);
|
);
|
||||||
|
|
||||||
Dqn_String result = Dqn_String_Init(msg, msg_length);
|
|
||||||
if (last_error) *last_error = error;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_API void Dqn_Win_DumpLastError(Dqn_ArenaAllocator *tmp_arena, Dqn_String prefix)
|
DQN_API void Dqn_Win_DumpLastError(Dqn_String prefix)
|
||||||
{
|
{
|
||||||
Dqn_ArenaAllocatorAutoRegion mem_region = Dqn_ArenaAllocator_AutoRegion(tmp_arena);
|
Dqn_WinErrorMsg msg = Dqn_Win_LastError();
|
||||||
int last_error = 0;
|
|
||||||
Dqn_String msg = Dqn_Win_LastError(tmp_arena, &last_error);
|
|
||||||
|
|
||||||
if (msg.size)
|
if (msg.size)
|
||||||
DQN_LOG_E("%.*s. Error: %.*s", DQN_STRING_FMT(prefix), DQN_STRING_FMT(msg));
|
DQN_LOG_E("%.*s. Error: %.*s", DQN_STRING_FMT(prefix), msg.size, msg.str);
|
||||||
else
|
else
|
||||||
DQN_LOG_E("%.*s. FormatMessage failed on error: %d with error code: %d\n", DQN_STRING_FMT(prefix), last_error, GetLastError());
|
DQN_LOG_E("%.*s. FormatMessage error: %d. No error message for: %d\n", DQN_STRING_FMT(prefix), GetLastError(), msg.code);
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_API Dqn_StringW Dqn_Win_UTF8ToWChar(Dqn_String src, Dqn_ArenaAllocator *arena)
|
DQN_API Dqn_StringW Dqn_Win_UTF8ToWChar(Dqn_String src, Dqn_ArenaAllocator *arena)
|
||||||
@ -5075,11 +5314,10 @@ DQN_API Dqn_StringW Dqn_Win_UTF8ToWChar(Dqn_String src, Dqn_ArenaAllocator *aren
|
|||||||
int required = MultiByteToWideChar(CP_UTF8, 0 /*dwFlags*/, src.str, size_int, nullptr, 0);
|
int required = MultiByteToWideChar(CP_UTF8, 0 /*dwFlags*/, src.str, size_int, nullptr, 0);
|
||||||
if (required == 0)
|
if (required == 0)
|
||||||
{
|
{
|
||||||
Dqn_ArenaAllocatorAutoRegion mem_region = Dqn_ArenaAllocator_AutoRegion(arena);
|
Dqn_WinErrorMsg error = Dqn_Win_LastError();
|
||||||
Dqn_String error = Dqn_Win_LastError(arena, nullptr);
|
|
||||||
DQN_LOG_W("Failed to convert string '%.*s' to wide string: %.*s",
|
DQN_LOG_W("Failed to convert string '%.*s' to wide string: %.*s",
|
||||||
DQN_STRING_FMT(src),
|
DQN_STRING_FMT(src),
|
||||||
DQN_STRING_FMT(error));
|
error.size, error.str);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5096,7 +5334,7 @@ DQN_API Dqn_StringW Dqn_Win_UTF8ToWChar(Dqn_String src, Dqn_ArenaAllocator *aren
|
|||||||
"the character before is not a null character.");
|
"the character before is not a null character.");
|
||||||
}
|
}
|
||||||
|
|
||||||
result = {string, string_size};
|
result = Dqn_StringW{string, string_size, string_size};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5111,10 +5349,10 @@ DQN_API Dqn_String Dqn_Win_WCharToUTF8(Dqn_StringW src, Dqn_ArenaAllocator *aren
|
|||||||
if (required == 0)
|
if (required == 0)
|
||||||
{
|
{
|
||||||
Dqn_ArenaAllocatorAutoRegion mem_region = Dqn_ArenaAllocator_AutoRegion(arena);
|
Dqn_ArenaAllocatorAutoRegion mem_region = Dqn_ArenaAllocator_AutoRegion(arena);
|
||||||
Dqn_String error = Dqn_Win_LastError(arena, nullptr);
|
Dqn_WinErrorMsg error = Dqn_Win_LastError();
|
||||||
DQN_LOG_W("Failed to convert wide string '%.*s' to UTF8 string: %.*s",
|
DQN_LOG_W("Failed to convert wide string '%.*s' to UTF8 string: %.*s",
|
||||||
DQN_STRING_FMT(src),
|
DQN_STRING_FMT(src),
|
||||||
DQN_STRING_FMT(error));
|
error.size, error.str);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5155,7 +5393,7 @@ DQN_API Dqn_StringW Dqn_Win_CurrentDirW(Dqn_ArenaAllocator *arena, Dqn_StringW s
|
|||||||
|
|
||||||
wchar_t *w_path = Dqn_ArenaAllocator_NewArray(arena, wchar_t, desired_size, Dqn_ZeroMem::No);
|
wchar_t *w_path = Dqn_ArenaAllocator_NewArray(arena, wchar_t, desired_size, Dqn_ZeroMem::No);
|
||||||
if (!w_path)
|
if (!w_path)
|
||||||
result;
|
return result;
|
||||||
|
|
||||||
DWORD bytes_written_wo_null_terminator = GetCurrentDirectoryW(desired_size, w_path);
|
DWORD bytes_written_wo_null_terminator = GetCurrentDirectoryW(desired_size, w_path);
|
||||||
if ((bytes_written_wo_null_terminator + 1) != required_size)
|
if ((bytes_written_wo_null_terminator + 1) != required_size)
|
||||||
@ -5171,7 +5409,7 @@ DQN_API Dqn_StringW Dqn_Win_CurrentDirW(Dqn_ArenaAllocator *arena, Dqn_StringW s
|
|||||||
w_path[desired_size] = 0;
|
w_path[desired_size] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = {w_path, desired_size - 1};
|
result = Dqn_StringW{w_path, desired_size - 1, desired_size - 1};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,8 @@ struct Dqn_CurlProcs
|
|||||||
};
|
};
|
||||||
|
|
||||||
Dqn_CurlProcs Dqn_CurlProcs_Init();
|
Dqn_CurlProcs Dqn_CurlProcs_Init();
|
||||||
|
void Dqn_Curl_SetPostData(CURL *curl, char const *post_data, int post_size);
|
||||||
|
|
||||||
#endif // DQN_CURL_H
|
#endif // DQN_CURL_H
|
||||||
|
|
||||||
#if defined(DQN_CURL_IMPLEMENTATION)
|
#if defined(DQN_CURL_IMPLEMENTATION)
|
||||||
@ -77,4 +79,11 @@ Dqn_CurlProcs Dqn_CurlProcs_Init()
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Dqn_Curl_SetPostData(CURL *curl, char const *post_data, int post_size)
|
||||||
|
{
|
||||||
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, post_size);
|
||||||
|
}
|
||||||
#endif // DQN_CURL_IMPLEMENTATION
|
#endif // DQN_CURL_IMPLEMENTATION
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -131,109 +131,6 @@ void Dqn_TestState_PrintResult(Dqn_TestState const *result)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dqn_Test_Allocator()
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
Dqn_TestingState testing_state = {};
|
|
||||||
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Allocator");
|
|
||||||
|
|
||||||
// NOTE: Various allocator test
|
|
||||||
{
|
|
||||||
{
|
|
||||||
DQN_TEST_START_SCOPE(testing_state, "HeapAllocator - Allocate Small");
|
|
||||||
Dqn_Allocator allocator = Dqn_Allocator_InitWithHeap();
|
|
||||||
char const EXPECT[] = "hello_world";
|
|
||||||
char *buf = DQN_CAST(char *)Dqn_Allocator_Allocate(&allocator, Dqn_ArrayCount(EXPECT), alignof(char), Dqn_ZeroMem::Yes);
|
|
||||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, buf); };
|
|
||||||
memcpy(buf, EXPECT, Dqn_ArrayCount(EXPECT));
|
|
||||||
DQN_TEST_EXPECT_MSG(testing_state, memcmp(EXPECT, buf, Dqn_ArrayCount(EXPECT)) == 0, "buf: %s, expect: %s", buf, EXPECT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
DQN_TEST_START_SCOPE(testing_state, "XHeapAllocator - Allocate Small");
|
|
||||||
Dqn_Allocator allocator = Dqn_Allocator_InitWithXHeap();
|
|
||||||
char const EXPECT[] = "hello_world";
|
|
||||||
char *buf = DQN_CAST(char *)Dqn_Allocator_Allocate(&allocator, Dqn_ArrayCount(EXPECT), alignof(char), Dqn_ZeroMem::Yes);
|
|
||||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, buf); };
|
|
||||||
memcpy(buf, EXPECT, Dqn_ArrayCount(EXPECT));
|
|
||||||
DQN_TEST_EXPECT_MSG(testing_state, memcmp(EXPECT, buf, Dqn_ArrayCount(EXPECT)) == 0, "buf: %s, expect: %s", buf, EXPECT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
DQN_TEST_START_SCOPE(testing_state, "ArenaAllocator - Allocate Small");
|
|
||||||
Dqn_ArenaAllocator arena = Dqn_ArenaAllocator_InitWithNewAllocator(Dqn_Allocator_InitWithHeap(), 0, nullptr);
|
|
||||||
Dqn_Allocator allocator = Dqn_Allocator_InitWithArena(&arena);
|
|
||||||
char const EXPECT[] = "hello_world";
|
|
||||||
char *buf = DQN_CAST(char *)Dqn_Allocator_Allocate(&allocator, Dqn_ArrayCount(EXPECT), alignof(char), Dqn_ZeroMem::Yes);
|
|
||||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, buf); };
|
|
||||||
memcpy(buf, EXPECT, Dqn_ArrayCount(EXPECT));
|
|
||||||
DQN_TEST_EXPECT_MSG(testing_state, memcmp(EXPECT, buf, Dqn_ArrayCount(EXPECT)) == 0, "buf: %s, expect: %s", buf, EXPECT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Alignment Test
|
|
||||||
{
|
|
||||||
Dqn_u8 const ALIGNMENT3 = 4;
|
|
||||||
Dqn_u8 const NUM_BYTES = sizeof(Dqn_u32);
|
|
||||||
{
|
|
||||||
DQN_TEST_START_SCOPE(testing_state, "HeapAllocator - Align to 32 bytes");
|
|
||||||
Dqn_Allocator allocator = Dqn_Allocator_InitWithHeap();
|
|
||||||
auto *buf = DQN_CAST(Dqn_u32 *)Dqn_Allocator_Allocate(&allocator, NUM_BYTES, ALIGNMENT3, Dqn_ZeroMem::Yes);
|
|
||||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, buf); };
|
|
||||||
int buf_mod_alignment = DQN_CAST(int)(DQN_CAST(uintptr_t)buf % ALIGNMENT3);
|
|
||||||
DQN_TEST_EXPECT_MSG(testing_state, buf_mod_alignment == 0, "buf_mod_alignment: %d", buf_mod_alignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
DQN_TEST_START_SCOPE(testing_state, "XHeapAllocator - Align to 32 bytes");
|
|
||||||
Dqn_Allocator allocator = Dqn_Allocator_InitWithXHeap();
|
|
||||||
auto *buf = DQN_CAST(Dqn_u32 *)Dqn_Allocator_Allocate(&allocator, NUM_BYTES, ALIGNMENT3, Dqn_ZeroMem::Yes);
|
|
||||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, buf); };
|
|
||||||
int buf_mod_alignment = DQN_CAST(int)(DQN_CAST(uintptr_t)buf % ALIGNMENT3);
|
|
||||||
DQN_TEST_EXPECT_MSG(testing_state, buf_mod_alignment == 0, "buf_mod_alignment: %d", buf_mod_alignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
DQN_TEST_START_SCOPE(testing_state, "ArenaAllocator - Align to 32 bytes");
|
|
||||||
Dqn_ArenaAllocator arena = {};
|
|
||||||
if (arena.backup_allocator.type == Dqn_AllocatorType::Null)
|
|
||||||
arena.backup_allocator = Dqn_Allocator_InitWithHeap();
|
|
||||||
|
|
||||||
Dqn_Allocator allocator = Dqn_Allocator_InitWithArena(&arena);
|
|
||||||
auto *buf = DQN_CAST(Dqn_u32 *)Dqn_Allocator_Allocate(&allocator, NUM_BYTES, ALIGNMENT3, Dqn_ZeroMem::Yes);
|
|
||||||
int buf_mod_alignment = DQN_CAST(int)(DQN_CAST(uintptr_t)buf % ALIGNMENT3);
|
|
||||||
DQN_TEST_EXPECT_MSG(testing_state, buf_mod_alignment == 0, "buf_mod_alignment: %d", buf_mod_alignment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Dqn_PointerMetadata tests
|
|
||||||
{
|
|
||||||
Dqn_u8 const ALIGNMENT3 = 4;
|
|
||||||
Dqn_u8 const NUM_BYTES = 4;
|
|
||||||
Dqn_u8 const MAX_OFFSET = (ALIGNMENT3 - 1) + sizeof(Dqn_PointerMetadata);
|
|
||||||
{
|
|
||||||
DQN_TEST_START_SCOPE(testing_state, "HeapAllocator - Allocation metadata initialised");
|
|
||||||
Dqn_Allocator allocator = Dqn_Allocator_InitWithHeap();
|
|
||||||
char *buf = DQN_CAST(char *)Dqn_Allocator_Allocate(&allocator, NUM_BYTES, ALIGNMENT3, Dqn_ZeroMem::Yes);
|
|
||||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, buf); };
|
|
||||||
Dqn_PointerMetadata metadata = Dqn_PointerMetadata_Get(buf);
|
|
||||||
DQN_TEST_EXPECT_MSG(testing_state, metadata.alignment == ALIGNMENT3, "metadata.alignment: %u, ALIGNMENT3: %u", metadata.alignment, ALIGNMENT3);
|
|
||||||
DQN_TEST_EXPECT_MSG(testing_state, metadata.offset <= MAX_OFFSET, "metadata.offset: %u, MAX_OFFSET: %u", metadata.offset, MAX_OFFSET);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
DQN_TEST_START_SCOPE(testing_state, "XHeapAllocator - Allocation metadata initialised");
|
|
||||||
Dqn_Allocator allocator = Dqn_Allocator_InitWithXHeap();
|
|
||||||
char *buf = DQN_CAST(char *)Dqn_Allocator_Allocate(&allocator, NUM_BYTES, ALIGNMENT3, Dqn_ZeroMem::Yes);
|
|
||||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, buf); };
|
|
||||||
Dqn_PointerMetadata metadata = Dqn_PointerMetadata_Get(buf);
|
|
||||||
DQN_TEST_EXPECT_MSG(testing_state, metadata.alignment == ALIGNMENT3, "metadata.alignment: %u, ALIGNMENT3: %u", metadata.alignment, ALIGNMENT3);
|
|
||||||
DQN_TEST_EXPECT_MSG(testing_state, metadata.offset <= MAX_OFFSET, "metadata.offset: %u, MAX_OFFSET: %u", metadata.offset, MAX_OFFSET);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dqn_Test_Array()
|
void Dqn_Test_Array()
|
||||||
{
|
{
|
||||||
Dqn_TestingState testing_state = {};
|
Dqn_TestingState testing_state = {};
|
||||||
@ -431,6 +328,77 @@ void Dqn_Test_FixedString()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Dqn_Test_Hex()
|
||||||
|
{
|
||||||
|
Dqn_TestingState testing_state = {};
|
||||||
|
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Hex");
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Convert 0x123");
|
||||||
|
Dqn_u64 result = Dqn_Hex_StringToU64(DQN_STRING("0x123"));
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, result == 0x123, "result: %I64u", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Convert 0xFFFF");
|
||||||
|
Dqn_u64 result = Dqn_Hex_StringToU64(DQN_STRING("0xFFFF"));
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, result == 0xFFFF, "result: %I64u", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Convert FFFF");
|
||||||
|
Dqn_u64 result = Dqn_Hex_StringToU64(DQN_STRING("FFFF"));
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, result == 0xFFFF, "result: %I64u", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Convert abCD");
|
||||||
|
Dqn_u64 result = Dqn_Hex_StringToU64(DQN_STRING("abCD"));
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, result == 0xabCD, "result: %I64u", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Convert 0xabCD");
|
||||||
|
Dqn_u64 result = Dqn_Hex_StringToU64(DQN_STRING("0xabCD"));
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, result == 0xabCD, "result: %I64u", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Convert 0x");
|
||||||
|
Dqn_u64 result = Dqn_Hex_StringToU64(DQN_STRING("0x"));
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, result == 0x0, "result: %I64u", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Convert 0X");
|
||||||
|
Dqn_u64 result = Dqn_Hex_StringToU64(DQN_STRING("0X"));
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, result == 0x0, "result: %I64u", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Convert 3");
|
||||||
|
Dqn_u64 result = Dqn_Hex_StringToU64(DQN_STRING("3"));
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, result == 3, "result: %I64u", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Convert f");
|
||||||
|
Dqn_u64 result = Dqn_Hex_StringToU64(DQN_STRING("f"));
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, result == 0xf, "result: %I64u", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Convert g");
|
||||||
|
Dqn_u64 result = Dqn_Hex_StringToU64(DQN_STRING("g"));
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, result == 0, "result: %I64u", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Convert -0x3");
|
||||||
|
Dqn_u64 result = Dqn_Hex_StringToU64(DQN_STRING("-0x3"));
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, result == 0, "result: %I64u", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Dqn_Test_M4()
|
void Dqn_Test_M4()
|
||||||
{
|
{
|
||||||
Dqn_TestingState testing_state = {};
|
Dqn_TestingState testing_state = {};
|
||||||
@ -456,6 +424,99 @@ void Dqn_Test_M4()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Dqn_Test_DSMap()
|
||||||
|
{
|
||||||
|
Dqn_TestingState testing_state = {};
|
||||||
|
DQN_TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_DSMap");
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Add r-value item to map");
|
||||||
|
Dqn_DSMap<int> map = Dqn_DSMap_Init<int>(128);
|
||||||
|
Dqn_DSMapEntry<int> *entry = Dqn_DSMap_AddCopy(&map, 3 /*hash*/, 5 /*value*/);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, map.size == 128, "size: %I64d", map.size);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, map.count == 1, "count: %I64u", map.count);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, entry->hash == 3, "hash: %I64u", entry->hash);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, entry->value == 5, "value: %d", entry->value);
|
||||||
|
Dqn_DSMap_Free(&map);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Add l-value item to map");
|
||||||
|
Dqn_DSMap<int> map = Dqn_DSMap_Init<int>(128);
|
||||||
|
int value = 5;
|
||||||
|
Dqn_DSMapEntry<int> *entry = Dqn_DSMap_Add(&map, 3 /*hash*/, value);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, map.size == 128, "size: %I64d", map.size);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, map.count == 1, "count: %I64u", map.count);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, entry->hash == 3, "hash: %I64u", entry->hash);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, entry->value == 5, "value: %d", entry->value);
|
||||||
|
Dqn_DSMap_Free(&map);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Get item from map");
|
||||||
|
Dqn_DSMap<int> map = Dqn_DSMap_Init<int>(128);
|
||||||
|
Dqn_DSMapEntry<int> *entry = Dqn_DSMap_AddCopy(&map, 3 /*hash*/, 5 /*value*/);
|
||||||
|
Dqn_DSMapEntry<int> *get_entry = Dqn_DSMap_Get(&map, 3 /*hash*/);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, get_entry == entry, "get_entry: %p, entry: %p", get_entry, entry);
|
||||||
|
Dqn_DSMap_Free(&map);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Get non-existent item from map");
|
||||||
|
Dqn_DSMap<int> map = Dqn_DSMap_Init<int>(128);
|
||||||
|
Dqn_DSMapEntry<int> *entry = Dqn_DSMap_Get(&map, 3 /*hash*/);
|
||||||
|
DQN_TEST_EXPECT(testing_state, entry == nullptr);
|
||||||
|
Dqn_DSMap_Free(&map);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Erase item from map");
|
||||||
|
Dqn_DSMap<int> map = Dqn_DSMap_Init<int>(128);
|
||||||
|
Dqn_DSMap_AddCopy(&map, 3 /*hash*/, 5 /*value*/);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, map.count == 1, "count: %I64d", map.count);
|
||||||
|
Dqn_DSMap_Erase(&map, 3 /*hash*/, Dqn_ZeroMem::No);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, map.count == 0, "count: %I64d", map.count);
|
||||||
|
Dqn_DSMap_Free(&map);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Erase non-existent item from map");
|
||||||
|
Dqn_DSMap<int> map = Dqn_DSMap_Init<int>(128);
|
||||||
|
Dqn_DSMap_Erase(&map, 3 /*hash*/, Dqn_ZeroMem::No);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, map.count == 0, "count: %I64d", map.count);
|
||||||
|
Dqn_DSMap_Free(&map);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DQN_TEST_START_SCOPE(testing_state, "Test resize on maximum load");
|
||||||
|
const Dqn_isize INIT_SIZE = 4;
|
||||||
|
Dqn_DSMap<int> map = Dqn_DSMap_Init<int>(INIT_SIZE);
|
||||||
|
Dqn_DSMap_AddCopy(&map, 0 /*hash*/, 5 /*value*/);
|
||||||
|
Dqn_DSMap_AddCopy(&map, 1 /*hash*/, 5 /*value*/);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, map.count == 2, "count: %I64d", map.count);
|
||||||
|
|
||||||
|
// This *should* cause a resize because 3/4 slots filled is 75% load
|
||||||
|
Dqn_DSMap_AddCopy(&map, 6 /*hash*/, 5 /*value*/);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, map.count == 3, "count: %I64d", map.count);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, map.size == INIT_SIZE * 2, "size: %I64d", map.size);
|
||||||
|
|
||||||
|
// Check that the elements are rehashed where we expected them to be
|
||||||
|
DQN_TEST_EXPECT (testing_state, map.slots[0].occupied == DQN_CAST(Dqn_u8)true);
|
||||||
|
DQN_TEST_EXPECT (testing_state, map.slots[1].occupied == DQN_CAST(Dqn_u8)true);
|
||||||
|
DQN_TEST_EXPECT (testing_state, map.slots[2].occupied == DQN_CAST(Dqn_u8)false);
|
||||||
|
DQN_TEST_EXPECT (testing_state, map.slots[3].occupied == DQN_CAST(Dqn_u8)false);
|
||||||
|
DQN_TEST_EXPECT (testing_state, map.slots[4].occupied == DQN_CAST(Dqn_u8)false);
|
||||||
|
DQN_TEST_EXPECT (testing_state, map.slots[5].occupied == DQN_CAST(Dqn_u8)false);
|
||||||
|
DQN_TEST_EXPECT (testing_state, map.slots[6].occupied == DQN_CAST(Dqn_u8)true);
|
||||||
|
DQN_TEST_EXPECT (testing_state, map.slots[7].occupied == DQN_CAST(Dqn_u8)false);
|
||||||
|
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, map.slots[0].value == 5, "value: %d", map.slots[0].value);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, map.slots[1].value == 5, "value: %d", map.slots[1].value);
|
||||||
|
DQN_TEST_EXPECT_MSG(testing_state, map.slots[6].value == 5, "value: %d", map.slots[6].value);
|
||||||
|
|
||||||
|
Dqn_DSMap_Free(&map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Dqn_Test_Map()
|
void Dqn_Test_Map()
|
||||||
{
|
{
|
||||||
Dqn_TestingState testing_state = {};
|
Dqn_TestingState testing_state = {};
|
||||||
@ -1182,18 +1243,20 @@ void Dqn_Test_TicketMutex()
|
|||||||
|
|
||||||
void Dqn_Test_RunSuite()
|
void Dqn_Test_RunSuite()
|
||||||
{
|
{
|
||||||
Dqn_Test_Allocator();
|
|
||||||
Dqn_Test_Array();
|
Dqn_Test_Array();
|
||||||
Dqn_Test_FixedArray();
|
Dqn_Test_FixedArray();
|
||||||
Dqn_Test_FixedString();
|
Dqn_Test_FixedString();
|
||||||
|
Dqn_Test_Hex();
|
||||||
Dqn_Test_Intrinsics();
|
Dqn_Test_Intrinsics();
|
||||||
Dqn_Test_M4();
|
Dqn_Test_M4();
|
||||||
|
Dqn_Test_DSMap();
|
||||||
Dqn_Test_Map();
|
Dqn_Test_Map();
|
||||||
Dqn_Test_Rect();
|
Dqn_Test_Rect();
|
||||||
Dqn_Test_Str();
|
Dqn_Test_Str();
|
||||||
Dqn_Test_String();
|
Dqn_Test_String();
|
||||||
Dqn_Test_StringBuilder();
|
Dqn_Test_StringBuilder();
|
||||||
Dqn_Test_TicketMutex();
|
Dqn_Test_TicketMutex();
|
||||||
|
|
||||||
fprintf(stdout, "Summary: %d/%d tests succeeded\n", g_dqn_test_total_good_tests, g_dqn_test_total_tests);
|
fprintf(stdout, "Summary: %d/%d tests succeeded\n", g_dqn_test_total_good_tests, g_dqn_test_total_tests);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user