From 8f8c9549987158e97a6e598b638dcee5214a24f6 Mon Sep 17 00:00:00 2001 From: doyle Date: Tue, 23 Feb 2021 20:49:43 +1100 Subject: [PATCH] Add some string split functions, fix warnings --- Code/Dqn.h | 347 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 211 insertions(+), 136 deletions(-) diff --git a/Code/Dqn.h b/Code/Dqn.h index e46bd98..55ae300 100644 --- a/Code/Dqn.h +++ b/Code/Dqn.h @@ -1104,7 +1104,7 @@ struct Dqn_ArenaAllocator // NOTE: Read Only Dqn_ArenaAllocatorBlock *curr_mem_block; Dqn_ArenaAllocatorBlock *top_mem_block; - Dqn_isize highest_used_mark; + Dqn_isize highest_used_mark; // TODO(doyle): This is not implemented yet int total_allocated_mem_blocks; Dqn_isize usage_before_last_reset; Dqn_isize wastage_before_last_reset; @@ -1145,6 +1145,45 @@ DQN_API Dqn_ArenaAllocatorScopedRegion Dqn_ArenaAllocator_MakeScopedRegion (D #define Dqn_ArenaAllocator_NewArray( arena, Type, count, zero_mem) (Type *)Dqn_ArenaAllocator__Allocate(arena, sizeof(Type) * count, alignof(Type), zero_mem DQN_CALL_SITE("")) 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 void Dqn_ArenaAllocator_DumpStatsToLog (Dqn_ArenaAllocator const *arena, char const *label); +// ------------------------------------------------------------------------------------------------- +// +// NOTE: Dqn_Slices +// +// ------------------------------------------------------------------------------------------------- +#define DQN_SLICE_FMT(slice) (slice).size, (slice).data +template +struct Dqn_Slice +{ + T *data; + Dqn_isize size; + + T const &operator[] (Dqn_isize i) const { DQN_ASSERT_MSG(i >= 0 && i < size, "%d >= 0 && %d < %d", i, size); return data[i]; } + T &operator[] (Dqn_isize i) { DQN_ASSERT_MSG(i >= 0 && i < size, "%d >= 0 && %d < %d", i, size); return data[i]; } + T const *begin () const { return data; } + T const *end () const { return data + size; } + T *begin () { return data; } + T *end () { return data + size; } + T const *operator+ (Dqn_isize i) const { DQN_ASSERT_MSG(i >= 0 && i < size, "%d >= 0 && %d < %d", i, size); return data + i; } + T *operator+ (Dqn_isize i) { DQN_ASSERT_MSG(i >= 0 && i < size, "%d >= 0 && %d < %d", i, size); return data + i; } +}; + +template DQN_API Dqn_Slice Dqn_Slice_Init (T *data, Dqn_isize size); +template DQN_API Dqn_Slice Dqn_Slice_InitWithArray (T (&array)[N]); + +#define Dqn_Slice_TaggedAllocate( allocator, Type, size, zero_mem, tag) Dqn_Slice__Allocate(allocator, size, zero_mem DQN_CALL_SITE(tag)) +#define Dqn_Slice_Allocate( allocator, Type, size, zero_mem) Dqn_Slice__Allocate(allocator, size, zero_mem DQN_CALL_SITE("")) + +// Allocate and copy the bytes/slice into a new slice. The null terminated variants are for byte +// arrays and allocate an extra byte to ensure that the last byte is 0. +template DQN_API Dqn_Slice Dqn_Slice_CopyNullTerminated(Dqn_Allocator *allocator, T const *src, Dqn_isize size); +template DQN_API Dqn_Slice Dqn_Slice_CopyNullTerminated(Dqn_Allocator *allocator, Dqn_Slice const src); +template DQN_API Dqn_Slice Dqn_Slice_Copy (Dqn_Allocator *allocator, T const *src, Dqn_isize size); +template DQN_API Dqn_Slice Dqn_Slice_Copy (Dqn_Allocator *allocator, Dqn_Slice const src); + +// Check equality of two slices using memcmp, operator== checks slice equality if size and pointers are the same +template DQN_API Dqn_b32 Dqn_Slice_Memcmp (Dqn_Slice const a, Dqn_Slice const b); +template DQN_API Dqn_b32 operator== (Dqn_Slice const &lhs, Dqn_Slice const &rhs); // ------------------------------------------------------------------------------------------------- // @@ -1235,8 +1274,9 @@ DQN_API Dqn_String Dqn_String__Fmt (Dqn_Allocator *allocator DQ // Free a string allocated with `Dqn_String_Copy`, `Dqn_String_FmtV` `Dqn_String_Fmt` // allocator: The same allocator specified when `Dqn_String_Copy` was called. -DQN_API void Dqn_String_Free (Dqn_String *string, Dqn_Allocator *allocator); -DQN_API Dqn_b32 Dqn_String_StartsWith (Dqn_String string, Dqn_String prefix); +DQN_API void Dqn_String_Free (Dqn_String *string, Dqn_Allocator *allocator); +DQN_API Dqn_b32 Dqn_String_StartsWith(Dqn_String string, Dqn_String prefix); +DQN_API Dqn_Slice Dqn_String_Split (Dqn_String src, Dqn_Allocator *allocator); // ------------------------------------------------------------------------------------------------- // @@ -1343,48 +1383,8 @@ template DQN_API void Dqn_StringBuilder_AppendFmt template DQN_API void Dqn_StringBuilder_Append (Dqn_StringBuilder *builder, char const *str, Dqn_isize len = -1); template DQN_API void Dqn_StringBuilder_AppendString (Dqn_StringBuilder *builder, Dqn_String const string); template DQN_API void Dqn_StringBuilder_AppendChar (Dqn_StringBuilder *builder, char ch); - template DQN_API void Dqn_StringBuilder_Free (Dqn_StringBuilder *builder); -// ------------------------------------------------------------------------------------------------- -// -// NOTE: Dqn_Slices -// -// ------------------------------------------------------------------------------------------------- -#define DQN_SLICE_FMT(slice) (slice).size, (slice).data -template -struct Dqn_Slice -{ - T *data; - Dqn_isize size; - - T const &operator[] (Dqn_isize i) const { DQN_ASSERT_MSG(i >= 0 && i < size, "%d >= 0 && %d < %d", i, size); return data[i]; } - T &operator[] (Dqn_isize i) { DQN_ASSERT_MSG(i >= 0 && i < size, "%d >= 0 && %d < %d", i, size); return data[i]; } - T const *begin () const { return data; } - T const *end () const { return data + size; } - T *begin () { return data; } - T *end () { return data + size; } - T const *operator+ (Dqn_isize i) const { DQN_ASSERT_MSG(i >= 0 && i < size, "%d >= 0 && %d < %d", i, size); return data + i; } - T *operator+ (Dqn_isize i) { DQN_ASSERT_MSG(i >= 0 && i < size, "%d >= 0 && %d < %d", i, size); return data + i; } -}; - -template DQN_API Dqn_Slice Dqn_Slice_Init (T *data, Dqn_isize size); -template DQN_API Dqn_Slice Dqn_Slice_InitWithArray (T (&array)[N]); - -#define Dqn_Slice_TaggedAllocate( allocator, Type, size, zero_mem, tag) Dqn_Slice__Allocate(allocator, size, zero_mem DQN_CALL_SITE(tag)) -#define Dqn_Slice_Allocate( allocator, Type, size, zero_mem) Dqn_Slice__Allocate(allocator, size, zero_mem DQN_CALL_SITE("")) - -// Allocate and copy the bytes/slice into a new slice. The null terminated variants are for byte -// arrays and allocate an extra byte to ensure that the last byte is 0. -template DQN_API Dqn_Slice Dqn_Slice_CopyNullTerminated(Dqn_Allocator *allocator, T const *src, Dqn_isize size); -template DQN_API Dqn_Slice Dqn_Slice_CopyNullTerminated(Dqn_Allocator *allocator, Dqn_Slice const src); -template DQN_API Dqn_Slice Dqn_Slice_Copy (Dqn_Allocator *allocator, T const *src, Dqn_isize size); -template DQN_API Dqn_Slice Dqn_Slice_Copy (Dqn_Allocator *allocator, Dqn_Slice const src); - -// Check equality of two slices using memcmp, operator== checks slice equality if size and pointers are the same -template DQN_API Dqn_b32 Dqn_Slice_Memcmp (Dqn_Slice const a, Dqn_Slice const b); -template DQN_API Dqn_b32 operator== (Dqn_Slice const &lhs, Dqn_Slice const &rhs); - // ------------------------------------------------------------------------------------------------- // // NOTE: Dqn_FixedArray @@ -1600,6 +1600,89 @@ DQN_API Dqn_MurmurHash3_128 Dqn_MurmurHash3_x64_128(void const *key, int len, Dq // NOTE: Template Implementation // // ------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- +// +// NOTE: Dqn_Slice Template Implementation +// +// ------------------------------------------------------------------------------------------------- +template +DQN_API Dqn_Slice Dqn_Slice_Init(T *data, Dqn_isize size) +{ + Dqn_Slice result = {}; + result.data = data; + result.size = size; + return result; +} + +template +DQN_API Dqn_Slice Dqn_Slice_InitWithArray(T (&array)[N]) +{ + Dqn_Slice result = {}; + result.size = N; + result.data = array; + return result; +} + +template +DQN_API Dqn_Slice Dqn_Slice__Allocate(Dqn_Allocator *allocator, Dqn_isize size, Dqn_ZeroMem zero_mem DQN_CALL_SITE_ARGS) +{ + Dqn_Slice result = {}; + result.size = size; + result.data = DQN_CAST(T *) Dqn_Allocator__Allocate(allocator, (sizeof(T) * size), alignof(T), zero_mem DQN_CALL_SITE_ARGS_INPUT); + return result; +} + +template +DQN_API Dqn_Slice Dqn_Slice_CopyNullTerminated(Dqn_Allocator *allocator, T const *src, Dqn_isize size) +{ + Dqn_Slice result = {}; + result.size = size; + result.data = DQN_CAST(T *) Dqn_Allocator_Allocate(allocator, (sizeof(T) * size) + 1, alignof(T), Dqn_ZeroMem::No); + DQN_MEMCOPY(result.data, src, size * sizeof(T)); + result.buf[size] = 0; + return result; +} + +template +DQN_API Dqn_Slice Dqn_Slice_CopyNullTerminated(Dqn_Allocator *allocator, Dqn_Slice const src) +{ + Dqn_Slice result = Dqn_Slice_CopyNullTerminated(allocator, src.data, src.size); + return result; +} + +template +DQN_API Dqn_Slice Dqn_Slice_Copy(Dqn_Allocator *allocator, T const *src, Dqn_isize size) +{ + Dqn_Slice result = {}; + result.size = size; + result.data = DQN_CAST(T *) Dqn_Allocator_Allocate(allocator, sizeof(T) * size, alignof(T), Dqn_ZeroMem::No); + DQN_MEMCOPY(result.dat, src, size * sizeof(T)); + return result; +} + +template +DQN_API Dqn_Slice Dqn_Slice_Copy(Dqn_Allocator *allocator, Dqn_Slice const src) +{ + Dqn_Slice result = Dqn_Slice_Copy(allocator, src.data, src.size); + return result; +} + +template +DQN_API Dqn_b32 Dqn_Slice_Memcmp(Dqn_Slice const a, Dqn_Slice const b) +{ + Dqn_b32 result = false; + if (a.size != b.size) return result; + result = (memcmp(a.data, b.data, a.size) == 0); + return result; +} + +template +DQN_API Dqn_b32 operator==(Dqn_Slice const &lhs, Dqn_Slice const &rhs) +{ + Dqn_b32 result = lhs.size == rhs.size && lhs.data == rhs.data; + return result; +} + // ------------------------------------------------------------------------------------------------- // // NOTE: Dqn_HashTable Template Implementation @@ -1660,7 +1743,6 @@ Dqn_HashTable Dqn_HashTable_InitWithMemory(void *mem, Dqn_isize mem_size) // NOTE: Generate the table // Dqn_isize bytes_required = bytes_for_values + bytes_for_usage_bitset; - (void)bytes_required; DQN_ASSERT_MSG(bytes_required <= mem_size, "(bytes_for_values = %Id, bytes_for_usage_bitset = %Id, mem_size = %Id)", bytes_for_values, bytes_for_usage_bitset, mem_size); @@ -1933,89 +2015,6 @@ DQN_API void Dqn_StringBuilder_Free(Dqn_StringBuilder *builder) Dqn_StringBuilder__LazyInitialise(builder); } -// ------------------------------------------------------------------------------------------------- -// -// NOTE: Dqn_Slice Template Implementation -// -// ------------------------------------------------------------------------------------------------- -template -DQN_API Dqn_Slice Dqn_Slice_Init(T *data, Dqn_isize size) -{ - Dqn_Slice result = {}; - result.data = data; - result.size = size; - return result; -} - -template -DQN_API Dqn_Slice Dqn_Slice_InitWithArray(T (&array)[N]) -{ - Dqn_Slice result = {}; - result.size = N; - result.data = array; - return result; -} - -template -DQN_API Dqn_Slice Dqn_Slice__Allocate(Dqn_Allocator *allocator, Dqn_isize size, Dqn_ZeroMem zero_mem DQN_CALL_SITE_ARGS) -{ - Dqn_Slice result = {}; - result.size = size; - result.data = DQN_CAST(T *) Dqn_Allocator__Allocate(allocator, (sizeof(T) * size), alignof(T), zero_mem DQN_CALL_SITE_ARGS_INPUT); - return result; -} - -template -DQN_API Dqn_Slice Dqn_Slice_CopyNullTerminated(Dqn_Allocator *allocator, T const *src, Dqn_isize size) -{ - Dqn_Slice result = {}; - result.size = size; - result.data = DQN_CAST(T *) Dqn_Allocator_Allocate(allocator, (sizeof(T) * size) + 1, alignof(T), Dqn_ZeroMem::No); - DQN_MEMCOPY(result.data, src, size * sizeof(T)); - result.buf[size] = 0; - return result; -} - -template -DQN_API Dqn_Slice Dqn_Slice_CopyNullTerminated(Dqn_Allocator *allocator, Dqn_Slice const src) -{ - Dqn_Slice result = Dqn_Slice_CopyNullTerminated(allocator, src.data, src.size); - return result; -} - -template -DQN_API Dqn_Slice Dqn_Slice_Copy(Dqn_Allocator *allocator, T const *src, Dqn_isize size) -{ - Dqn_Slice result = {}; - result.size = size; - result.data = DQN_CAST(T *) Dqn_Allocator_Allocate(allocator, sizeof(T) * size, alignof(T), Dqn_ZeroMem::No); - DQN_MEMCOPY(result.dat, src, size * sizeof(T)); - return result; -} - -template -DQN_API Dqn_Slice Dqn_Slice_Copy(Dqn_Allocator *allocator, Dqn_Slice const src) -{ - Dqn_Slice result = Dqn_Slice_Copy(allocator, src.data, src.size); - return result; -} - -template -DQN_API Dqn_b32 Dqn_Slice_Memcmp(Dqn_Slice const a, Dqn_Slice const b) -{ - Dqn_b32 result = false; - if (a.size != b.size) return result; - result = (memcmp(a.data, b.data, a.size) == 0); - return result; -} - -template -DQN_API Dqn_b32 operator==(Dqn_Slice const &lhs, Dqn_Slice const &rhs) -{ - Dqn_b32 result = lhs.size == rhs.size && lhs.data == rhs.data; - return result; -} - // ------------------------------------------------------------------------------------------------- // // NOTE: Dqn_FixedArray Template Implementation @@ -2543,16 +2542,23 @@ DQN_API void Dqn_LogV(Dqn_LogType type, char const *file, Dqn_usize file_len, ch FILE *handle = (type == Dqn_LogType::Error) ? stderr : stdout; fprintf(handle, - "%s %.*s %05zu %.*s ", + "[%s:%.*s:%05zu:%.*s] ", Dqn_LogTypeString[DQN_CAST(int) type], (int)file_ptr_len, file_ptr, line, (int)func_len, - func - ); + func); - vfprintf(handle, fmt, va); + // NOTE: Use the callback version of stb_sprintf to allow us to chunk logs and print arbitrary + // sized format strings without needing to size it up first. + auto stb_vsprintf_callback = [](char *buf, void *user, int len) -> char * { + fprintf(DQN_CAST(FILE *)user, "%.*s", len, buf); + return buf; + }; + + char stb_buffer[STB_SPRINTF_MIN * 2] = {}; + stbsp_vsprintfcb(stb_vsprintf_callback, handle, stb_buffer, fmt, va); fputc('\n', handle); } @@ -2863,7 +2869,7 @@ DQN_API Dqn_f32 Dqn_LerpF32(Dqn_f32 a, Dqn_f32 t, Dqn_f32 b) Dqn_AllocationTracer Dqn_AllocationTracer_InitWithMemory(void *mem, Dqn_usize mem_size) { Dqn_AllocationTracer result = {}; - result.table = Dqn_HashTable_InitWithMemory(mem, mem_size); + result.table = Dqn_HashTable_InitWithMemory(mem, mem_size); return result; } @@ -3314,6 +3320,27 @@ DQN_API void *Dqn_ArenaAllocator__Allocate(Dqn_ArenaAllocator *arena, Dqn_isize return result; } +DQN_API void Dqn_ArenaAllocator_DumpStatsToLog(Dqn_ArenaAllocator const *arena, char const *label) +{ + Dqn_isize total_used = 0; + Dqn_isize total_allocated = 0; + Dqn_isize total_wasted = 0; + for (Dqn_ArenaAllocatorBlock const *block = arena->top_mem_block; block; block = block->prev) + { + total_allocated += block->size; + total_used += block->used; + if (block != arena->top_mem_block) + total_wasted += block->size - block->used; + } + + DQN_LOG_M("%s: %$$.3d/%$$.3d (wasted %$$.3d - %d blks)", + label, + total_used, + total_allocated, + total_wasted, + arena->total_allocated_mem_blocks); +} + // ------------------------------------------------------------------------------------------------- // // NOTE: Dqn_Bit @@ -3494,13 +3521,13 @@ char constexpr DQN_HEX_LUT[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9' DQN_API char Dqn_Char_ToHex(char ch) { char result = DQN_CAST(char)-1; - if (ch <= 16) result = DQN_HEX_LUT[ch]; + if (ch <= 16) result = DQN_HEX_LUT[DQN_CAST(unsigned)ch]; return result; } DQN_API char Dqn_Char_ToHexUnchecked(char ch) { - char result = DQN_HEX_LUT[ch]; + char result = DQN_HEX_LUT[DQN_CAST(unsigned)ch]; return result; } @@ -3508,9 +3535,7 @@ DQN_API char Dqn_Char_ToLower(char ch) { char result = ch; if (result >= 'A' && result <= 'Z') - { result += 'a' - 'A'; - } return result; } @@ -3617,6 +3642,56 @@ DQN_API Dqn_b32 Dqn_String_StartsWith(Dqn_String string, Dqn_String prefix) return result; } +DQN_API Dqn_Slice Dqn_String_Split(Dqn_String src, Dqn_Allocator *allocator) +{ + enum StringSplitStage + { + StringSplitStage_Enumerate, + StringSplitStage_Write, + StringSplitStage_Count, + }; + + Dqn_Slice result = {}; + int split_index = 0; + int split_count = 0; + + for (int stage = StringSplitStage_Enumerate; + stage < StringSplitStage_Count; + stage++) + { + char const *begin = src.str; + char const *end = src.str; + + if (stage == StringSplitStage_Write) + result = Dqn_Slice_Allocate(allocator, Dqn_String, split_count, Dqn_ZeroMem::No); + + for (;;) + { + while (end[0] != '\r' && end[0] != '\n' && end[0] != 0) + end++; + + if (end[0] == 0) + break; + + auto split = Dqn_String_Init(begin, end - begin); + begin = end + 1; + end = begin; + + if (split.size == 0) + continue; + else + { + if (stage == StringSplitStage_Enumerate) split_count++; + else result[split_index++] = split; + } + } + } + + DQN_ASSERT(split_count == split_index); + return result; +} + + // ------------------------------------------------------------------------------------------------- // // NOTE: Dqn_Str