Add Allocator stats, StringBuilder len doesn't include null terminator
This commit is contained in:
parent
65cbe4b493
commit
2f7ce338a8
48
Code/Dqn.h
48
Code/Dqn.h
@ -613,6 +613,12 @@ struct Dqn_Allocator
|
||||
Dqn_Allocator_Type type;
|
||||
void *data;
|
||||
|
||||
isize bytes_allocated;
|
||||
isize total_bytes_allocated;
|
||||
|
||||
isize allocations;
|
||||
isize total_allocations;
|
||||
|
||||
// NOTE: Only required if type == Dqn_Allocator_Type::Custom
|
||||
Dqn_Allocator_AllocateProc *allocate;
|
||||
Dqn_Allocator_ReallocProc *realloc;
|
||||
@ -718,7 +724,13 @@ DQN_HEADER_COPY_PROTOTYPE(Dqn_Allocator, inline Dqn_Allocator_Arena(Dqn_MemArena
|
||||
DQN_HEADER_COPY_BEGIN
|
||||
struct Dqn_String
|
||||
{
|
||||
char *str;
|
||||
union {
|
||||
// NOTE: To appease GCC, Clang can't assign C string literal to char *
|
||||
// Only UB if you try modify a string originally declared const
|
||||
char const *str_;
|
||||
char *str;
|
||||
};
|
||||
|
||||
Dqn_isize len;
|
||||
char const *begin() const { return str; }
|
||||
char const *end () const { return str + len; }
|
||||
@ -855,7 +867,7 @@ DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> char *, Dqn_StringBuilder_Build
|
||||
{
|
||||
Dqn_isize len_w_null_terminator = Dqn_StringBuilder_BuildLen(builder);
|
||||
auto *result = DQN_CAST(char *)Dqn_Allocator_Allocate(allocator, sizeof(char) * len_w_null_terminator);
|
||||
if (len) *len = len_w_null_terminator;
|
||||
if (len) *len = (len_w_null_terminator - 1);
|
||||
Dqn_StringBuilder__BuildOutput(builder, result, len_w_null_terminator);
|
||||
return result;
|
||||
}
|
||||
@ -863,7 +875,7 @@ DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> char *, Dqn_StringBuilder_Build
|
||||
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> Dqn_String, Dqn_StringBuilder_BuildString(Dqn_StringBuilder<N> *builder, Dqn_Allocator *allocator))
|
||||
{
|
||||
Dqn_String result = {};
|
||||
result.str = Dqn_StringBuilder_Build(builder, allocator, &result.len);
|
||||
result.str = Dqn_StringBuilder_Build(builder, allocator, &result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -888,6 +900,8 @@ DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> void, Dqn_StringBuilder_Append(
|
||||
{
|
||||
if (!str) return;
|
||||
if (len == -1) len = DQN_CAST(Dqn_isize)strlen(str);
|
||||
if (len == 0) return;
|
||||
|
||||
Dqn_isize len_w_null_terminator = len + 1;
|
||||
char *buf = Dqn_StringBuilder__GetWriteBufferAndUpdateUsage(builder, len_w_null_terminator);
|
||||
memcpy(buf, str, len);
|
||||
@ -895,6 +909,16 @@ DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> void, Dqn_StringBuilder_Append(
|
||||
buf[len] = 0;
|
||||
}
|
||||
|
||||
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> void, Dqn_StringBuilder_AppendString(Dqn_StringBuilder<N> *builder, Dqn_String const string))
|
||||
{
|
||||
if (!string.str || string.len == 0) return;
|
||||
Dqn_isize len_w_null_terminator = string.len + 1;
|
||||
char *buf = Dqn_StringBuilder__GetWriteBufferAndUpdateUsage(builder, len_w_null_terminator);
|
||||
memcpy(buf, string.str, string.len);
|
||||
builder->string_len += string.len;
|
||||
buf[string.len] = 0;
|
||||
}
|
||||
|
||||
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_usize N> void, Dqn_StringBuilder_AppendChar(Dqn_StringBuilder<N> *builder, char ch))
|
||||
{
|
||||
char *buf = Dqn_StringBuilder__GetWriteBufferAndUpdateUsage(builder, 1 + 1 /*null terminator*/);
|
||||
@ -1459,6 +1483,11 @@ DQN_HEADER_COPY_PROTOTYPE(void *, Dqn_Allocator_Allocate(Dqn_Allocator *allocato
|
||||
break;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
allocator->allocations++;
|
||||
allocator->total_bytes_allocated += size;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1466,6 +1495,7 @@ DQN_HEADER_COPY_PROTOTYPE(void *, Dqn_Allocator_Realloc(Dqn_Allocator *allocator
|
||||
{
|
||||
DQN_IF_ASSERT(old_size >= 0) old_size = 0;
|
||||
DQN_IF_ASSERT(new_size >= 0) new_size = 0;
|
||||
DQN_ASSERT(new_size > old_size);
|
||||
|
||||
void *result = nullptr;
|
||||
switch (allocator->type)
|
||||
@ -1503,6 +1533,11 @@ DQN_HEADER_COPY_PROTOTYPE(void *, Dqn_Allocator_Realloc(Dqn_Allocator *allocator
|
||||
break;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
allocator->total_bytes_allocated += new_size;
|
||||
allocator->total_allocations++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1529,6 +1564,13 @@ DQN_HEADER_COPY_PROTOTYPE(void, Dqn_Allocator_Free(Dqn_Allocator *allocator, voi
|
||||
case Dqn_Allocator_Type::Arena:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
allocator->total_allocations++;
|
||||
allocator->allocations--;
|
||||
DQN_ASSERT(allocator->allocations >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
// @ -------------------------------------------------------------------------------------------------
|
||||
|
@ -4,19 +4,20 @@
|
||||
|
||||
struct TestState
|
||||
{
|
||||
Dqn_MemArena arena;
|
||||
int indent_level;
|
||||
Dqn_Slice<char> name;
|
||||
Dqn_Slice<char> fail_expr;
|
||||
Dqn_Slice<char> fail_msg;
|
||||
bool scope_started;
|
||||
int indent_level;
|
||||
Dqn_String name;
|
||||
Dqn_String fail_expr;
|
||||
Dqn_String fail_msg;
|
||||
bool scope_started;
|
||||
};
|
||||
|
||||
struct TestingState
|
||||
{
|
||||
int num_tests_in_group;
|
||||
int num_tests_ok_in_group;
|
||||
TestState test;
|
||||
int num_tests_in_group;
|
||||
int num_tests_ok_in_group;
|
||||
TestState test;
|
||||
Dqn_MemArena arena_;
|
||||
Dqn_Allocator allocator;
|
||||
};
|
||||
|
||||
#define ANSI_COLOR_RED "\x1b[31m"
|
||||
@ -32,9 +33,11 @@ struct TestingState
|
||||
{ \
|
||||
if (testing_state.test.fail_expr.len == 0) testing_state.num_tests_ok_in_group++; \
|
||||
TestState_PrintResult(&testing_state.test); \
|
||||
testing_state.test = {}; \
|
||||
Dqn_MemArena_ResetUsage(&testing_state.arena_, Dqn_ZeroMem::No); \
|
||||
testing_state.allocator = Dqn_Allocator_Arena(&testing_state.arena_); \
|
||||
testing_state.test = {}; \
|
||||
}; \
|
||||
testing_state.test.name = Dqn_AsprintfSlice(&testing_state.test.arena, test_name); \
|
||||
testing_state.test.name = Dqn_Asprintf(&testing_state.allocator, test_name); \
|
||||
testing_state.test.scope_started = true; \
|
||||
testing_state.num_tests_in_group++
|
||||
|
||||
@ -50,8 +53,8 @@ struct TestingState
|
||||
DQN_ASSERT(testing_state.test.scope_started); \
|
||||
if (!(expr)) \
|
||||
{ \
|
||||
testing_state.test.fail_expr = Dqn_AsprintfSlice(&testing_state.test.arena, #expr); \
|
||||
testing_state.test.fail_msg = Dqn_AsprintfSlice(&testing_state.test.arena, msg, ##__VA_ARGS__); \
|
||||
testing_state.test.fail_expr = Dqn_Asprintf(&testing_state.allocator, #expr); \
|
||||
testing_state.test.fail_msg = Dqn_Asprintf(&testing_state.allocator, msg, ##__VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define TEST_EXPECT(testing_state, expr) TEST_EXPECT_MSG(testing_state, expr, "")
|
||||
@ -115,7 +118,7 @@ FILE_SCOPE void UnitTests()
|
||||
TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_Allocator");
|
||||
{
|
||||
TEST_START_SCOPE(testing_state, "HeapAllocator - Allocate Small");
|
||||
Dqn_Allocator allocator = Dqn_Allocator_HeapAllocator();
|
||||
Dqn_Allocator allocator = Dqn_Allocator_Heap();
|
||||
char constexpr EXPECT[] = "hello_world";
|
||||
char *buf = DQN_CAST(char *)Dqn_Allocator_Allocate(&allocator, Dqn_ArrayCount(EXPECT));
|
||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, buf); };
|
||||
@ -125,7 +128,7 @@ FILE_SCOPE void UnitTests()
|
||||
|
||||
{
|
||||
TEST_START_SCOPE(testing_state, "XHeapAllocator - Allocate Small");
|
||||
Dqn_Allocator allocator = Dqn_Allocator_XHeapAllocator();
|
||||
Dqn_Allocator allocator = Dqn_Allocator_XHeap();
|
||||
char constexpr EXPECT[] = "hello_world";
|
||||
char *buf = DQN_CAST(char *)Dqn_Allocator_Allocate(&allocator, Dqn_ArrayCount(EXPECT));
|
||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, buf); };
|
||||
@ -136,7 +139,7 @@ FILE_SCOPE void UnitTests()
|
||||
{
|
||||
TEST_START_SCOPE(testing_state, "ArenaAllocator - Allocate Small");
|
||||
Dqn_MemArena arena = {};
|
||||
Dqn_Allocator allocator = Dqn_Allocator_ArenaAllocator(&arena);
|
||||
Dqn_Allocator allocator = Dqn_Allocator_Arena(&arena);
|
||||
char constexpr EXPECT[] = "hello_world";
|
||||
char *buf = DQN_CAST(char *)Dqn_Allocator_Allocate(&allocator, Dqn_ArrayCount(EXPECT));
|
||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, buf); };
|
||||
@ -412,120 +415,121 @@ FILE_SCOPE void UnitTests()
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
{
|
||||
TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_StringBuilder");
|
||||
Dqn_Allocator allocator = Dqn_Allocator_Heap();
|
||||
// NOTE: Dqn_StringBuilder_Append
|
||||
{
|
||||
{
|
||||
TEST_START_SCOPE(testing_state, "Append variable length strings and build using malloc");
|
||||
TEST_START_SCOPE(testing_state, "Append variable length strings and build using heap allocator");
|
||||
Dqn_StringBuilder<> builder = {};
|
||||
Dqn_StringBuilder_Append(&builder, "Abc", 1);
|
||||
Dqn_StringBuilder_Append(&builder, "cd");
|
||||
isize len = 0;
|
||||
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||
DQN_DEFER { free(result); };
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &allocator, &len);
|
||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, result); };
|
||||
|
||||
char constexpr EXPECT_STR[] = "Acd";
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR) + 1 /*null terminator*/, "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR), "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
||||
}
|
||||
|
||||
{
|
||||
TEST_START_SCOPE(testing_state, "Append empty string and build using malloc");
|
||||
TEST_START_SCOPE(testing_state, "Append empty string and build using heap allocator");
|
||||
Dqn_StringBuilder<> builder = {};
|
||||
Dqn_StringBuilder_Append(&builder, "");
|
||||
Dqn_StringBuilder_Append(&builder, "");
|
||||
isize len = 0;
|
||||
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||
DQN_DEFER { free(result); };
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &allocator, &len);
|
||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, result); };
|
||||
|
||||
char constexpr EXPECT_STR[] = "";
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR) + 1 /*null terminator*/, "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR), "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
||||
}
|
||||
|
||||
{
|
||||
TEST_START_SCOPE(testing_state, "Append empty string onto string and build using malloc");
|
||||
TEST_START_SCOPE(testing_state, "Append empty string onto string and build using heap allocator");
|
||||
Dqn_StringBuilder<> builder = {};
|
||||
Dqn_StringBuilder_Append(&builder, "Acd");
|
||||
Dqn_StringBuilder_Append(&builder, "");
|
||||
isize len = 0;
|
||||
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||
DQN_DEFER { free(result); };
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &allocator, &len);
|
||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, result); };
|
||||
|
||||
char constexpr EXPECT_STR[] = "Acd";
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR) + 1 /*null terminator*/, "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR), "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
||||
}
|
||||
|
||||
{
|
||||
TEST_START_SCOPE(testing_state, "Append nullptr and build using malloc");
|
||||
TEST_START_SCOPE(testing_state, "Append nullptr and build using heap allocator");
|
||||
Dqn_StringBuilder<> builder = {};
|
||||
Dqn_StringBuilder_Append(&builder, nullptr, 5);
|
||||
isize len = 0;
|
||||
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||
DQN_DEFER { free(result); };
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &allocator, &len);
|
||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, result); };
|
||||
|
||||
char constexpr EXPECT_STR[] = "";
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR) + 1 /*null terminator*/, "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR), "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
||||
}
|
||||
|
||||
{
|
||||
TEST_START_SCOPE(testing_state, "Append and require new linked buffer and build using malloc");
|
||||
TEST_START_SCOPE(testing_state, "Append and require new linked buffer and build using heap allocator");
|
||||
Dqn_StringBuilder<2> builder = {};
|
||||
Dqn_StringBuilder_Append(&builder, "A");
|
||||
Dqn_StringBuilder_Append(&builder, "z"); // Should force a new memory block
|
||||
Dqn_StringBuilder_Append(&builder, "tec");
|
||||
isize len = 0;
|
||||
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||
DQN_DEFER { free(result); };
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &allocator, &len);
|
||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, result); };
|
||||
|
||||
char constexpr EXPECT_STR[] = "Aztec";
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR) + 1 /*null terminator*/, "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR), "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Dqn_StringBuilder_AppendChar
|
||||
{
|
||||
TEST_START_SCOPE(testing_state, "Append char and build using malloc");
|
||||
TEST_START_SCOPE(testing_state, "Append char and build using heap allocator");
|
||||
Dqn_StringBuilder<> builder = {};
|
||||
Dqn_StringBuilder_AppendChar(&builder, 'a');
|
||||
Dqn_StringBuilder_AppendChar(&builder, 'b');
|
||||
isize len = 0;
|
||||
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||
DQN_DEFER { free(result); };
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &allocator, &len);
|
||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, result); };
|
||||
|
||||
char constexpr EXPECT_STR[] = "ab";
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR) + 1 /*null terminator*/, "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR), "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
||||
}
|
||||
|
||||
// NOTE: Dqn_StringBuilder_FmtAppend
|
||||
{
|
||||
{
|
||||
TEST_START_SCOPE(testing_state, "Append format string and build using malloc");
|
||||
TEST_START_SCOPE(testing_state, "Append format string and build using heap allocator");
|
||||
Dqn_StringBuilder<> builder = {};
|
||||
Dqn_StringBuilder_FmtAppend(&builder, "Number: %d, String: %s, ", 4, "Hello Sailor");
|
||||
Dqn_StringBuilder_FmtAppend(&builder, "Extra Stuff");
|
||||
isize len = 0;
|
||||
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||
DQN_DEFER { free(result); };
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &allocator, &len);
|
||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, result); };
|
||||
|
||||
char constexpr EXPECT_STR[] = "Number: 4, String: Hello Sailor, Extra Stuff";
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR) + 1 /*null terminator*/, "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR), "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
||||
}
|
||||
|
||||
{
|
||||
TEST_START_SCOPE(testing_state, "Append nullptr format string and build using malloc");
|
||||
TEST_START_SCOPE(testing_state, "Append nullptr format string and build using heap allocator");
|
||||
Dqn_StringBuilder<> builder = {};
|
||||
Dqn_StringBuilder_FmtAppend(&builder, nullptr);
|
||||
isize len = 0;
|
||||
char *result = Dqn_StringBuilder_BuildFromMalloc(&builder, &len);
|
||||
DQN_DEFER { free(result); };
|
||||
char *result = Dqn_StringBuilder_Build(&builder, &allocator, &len);
|
||||
DQN_DEFER { Dqn_Allocator_Free(&allocator, result); };
|
||||
|
||||
char constexpr EXPECT_STR[] = "";
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR) + 1 /*null terminator*/, "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, len == Dqn_CharCountI(EXPECT_STR), "len: %zd", len);
|
||||
TEST_EXPECT_MSG(testing_state, strncmp(result, EXPECT_STR, len) == 0, "result: %s", result);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user