feat: hectic C: debug constructor wroks!!!
This commit is contained in:
@@ -64,8 +64,8 @@ void set_output_color_mode(ColorMode mode) {
|
|||||||
|
|
||||||
#define POSITION_INFO_DECLARATION const char *file, const char *func, int line
|
#define POSITION_INFO_DECLARATION const char *file, const char *func, int line
|
||||||
#define POSITION_INFO file, func, line
|
#define POSITION_INFO file, func, line
|
||||||
#define COLORING_DECLARATION POSITION_INFO_DECLARATION Arena *arena
|
#define CTX_DECLARATION POSITION_INFO_DECLARATION, Arena *arena
|
||||||
|
#define CTX(lifetimed_arena) POSITION_INFO, arena = (lifetimed_arena)
|
||||||
|
|
||||||
// ------------
|
// ------------
|
||||||
// -- Logger --
|
// -- Logger --
|
||||||
@@ -198,6 +198,88 @@ char* raise_message(
|
|||||||
// -- debug --
|
// -- debug --
|
||||||
// -----------
|
// -----------
|
||||||
|
|
||||||
|
PtrSet *ptrset_init(Arena *arena) {
|
||||||
|
PtrSet *set = arena_alloc(arena, sizeof(PtrSet));
|
||||||
|
set->data = arena_alloc(arena, 4 * sizeof(void*));
|
||||||
|
set->size = 0;
|
||||||
|
set->capacity = 4;
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool debug_ptrset_contains__(PtrSet *set, void *ptr) {
|
||||||
|
for (size_t i = 0; i < set->size; i++) {
|
||||||
|
if (set->data[i] == ptr)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_ptrset_add__(CTX_DECLARATION, PtrSet *set, void *ptr) {
|
||||||
|
if (set->size == set->capacity) {
|
||||||
|
set->capacity = set->capacity ? set->capacity * 2 : 4;
|
||||||
|
set->data = arena_realloc__(CTX(arena), set->data, set->capacity, set->capacity * sizeof(void*));
|
||||||
|
}
|
||||||
|
set->data[set->size++] = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *string_to_debug_str__(CTX_DECLARATION, const char *name, const char *string) {
|
||||||
|
return arena_strdup_fmt__(CTX(arena), "%s = %p \"%s\"", name, string, string);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *number_to_debug_str__(CTX_DECLARATION, const char *name, int number) {
|
||||||
|
return arena_strdup_fmt__(CTX(arena), "%s = %d", name, number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Private function */
|
||||||
|
char *debug_join_debug_strings_v(CTX_DECLARATION, int count, va_list args) {
|
||||||
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG JOIN: Joining %d strings", count);
|
||||||
|
int total_len = 1;
|
||||||
|
|
||||||
|
va_list args_copy;
|
||||||
|
va_copy(args_copy, args);
|
||||||
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG JOIN: Starting first pass");
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "iter1");
|
||||||
|
char *s = va_arg(args_copy, char*);
|
||||||
|
int len = strlen(s);
|
||||||
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG JOIN: String %d: [%s] %p len: %d", i, s, s, len);
|
||||||
|
total_len += len;
|
||||||
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "iter2");
|
||||||
|
}
|
||||||
|
va_end(args_copy);
|
||||||
|
|
||||||
|
char *joined = arena_alloc__(CTX(arena), total_len);
|
||||||
|
joined[0] = '\0';
|
||||||
|
|
||||||
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG JOIN: concatenating strings");
|
||||||
|
va_copy(args_copy, args);
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
char *s = va_arg(args_copy, char*);
|
||||||
|
strcat(joined, s);
|
||||||
|
if (i < count - 1) {
|
||||||
|
strcat(joined, ", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(args_copy);
|
||||||
|
|
||||||
|
return joined;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *struct_to_debug_str__(CTX_DECLARATION, const char *type, const char *name, void *ptr, int count, ...) {
|
||||||
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG STR: type: %s, name: %s, ptr: %p, count: %d", type, name, ptr, count);
|
||||||
|
char *result;
|
||||||
|
if ((ptr) == NULL) {
|
||||||
|
result = arena_strdup_fmt__(CTX(arena), "%s %s = NULL", type, name);
|
||||||
|
} else {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, count);
|
||||||
|
char *joined = debug_join_debug_strings_v(CTX(arena), count, args);
|
||||||
|
va_end(args);
|
||||||
|
result = arena_strdup_fmt__(CTX(arena), "%s %s = {%s} %p", type, name, joined, ptr);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------
|
// ------------
|
||||||
// -- arena --
|
// -- arena --
|
||||||
// ------------
|
// ------------
|
||||||
@@ -287,7 +369,7 @@ void* arena_alloc__(POSITION_INFO_DECLARATION, Arena *arena, size_t size) {
|
|||||||
raise_message(LOG_LEVEL_DEBUG, POSITION_INFO,
|
raise_message(LOG_LEVEL_DEBUG, POSITION_INFO,
|
||||||
"ARENA ALLOC: Allocating memory (arena: %p, size: %zu bytes)", arena, size);
|
"ARENA ALLOC: Allocating memory (arena: %p, size: %zu bytes)", arena, size);
|
||||||
|
|
||||||
void *mem = arena_alloc_or_null__(POSITION_INFO, arena, size, true);
|
void *mem = arena_alloc_or_null__(POSITION_INFO, arena, size, false);
|
||||||
if (!mem) {
|
if (!mem) {
|
||||||
raise_message(LOG_LEVEL_DEBUG, POSITION_INFO,
|
raise_message(LOG_LEVEL_DEBUG, POSITION_INFO,
|
||||||
"ARENA ALLOC: Allocation failed (arena: %p, requested: %zu bytes)", arena, size);
|
"ARENA ALLOC: Allocation failed (arena: %p, requested: %zu bytes)", arena, size);
|
||||||
@@ -302,6 +384,26 @@ void* arena_alloc__(POSITION_INFO_DECLARATION, Arena *arena, size_t size) {
|
|||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reallocates a memory block and copies the contents of the old block to the new one.
|
||||||
|
* NOTE(yukkop): We need to provide the old size to avoid copying more than needed.
|
||||||
|
*/
|
||||||
|
void* arena_realloc__(POSITION_INFO_DECLARATION, Arena *arena,
|
||||||
|
void *ptr, size_t size, size_t new_size) {
|
||||||
|
void *new_ptr = NULL;
|
||||||
|
if (ptr == NULL) {
|
||||||
|
new_ptr = arena_alloc__(POSITION_INFO, arena, new_size);
|
||||||
|
} else if (new_size <= size) {
|
||||||
|
new_ptr = ptr;
|
||||||
|
} else {
|
||||||
|
// FIXME(yukkop): Must tries to expand the arena before allocating new memory
|
||||||
|
new_ptr = arena_alloc_or_null__(POSITION_INFO, arena, new_size, false);
|
||||||
|
if (new_ptr)
|
||||||
|
memcpy(new_ptr, ptr, size);
|
||||||
|
}
|
||||||
|
return new_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
void arena_reset__(POSITION_INFO_DECLARATION, Arena *arena) {
|
void arena_reset__(POSITION_INFO_DECLARATION, Arena *arena) {
|
||||||
// Function entry logging
|
// Function entry logging
|
||||||
raise_message(LOG_LEVEL_DEBUG, POSITION_INFO,
|
raise_message(LOG_LEVEL_DEBUG, POSITION_INFO,
|
||||||
@@ -503,22 +605,6 @@ char* arena_repstr__(POSITION_INFO_DECLARATION, Arena *arena,
|
|||||||
return new_str;
|
return new_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(yukkop): this is who
|
|
||||||
void* arena_realloc_copy__(POSITION_INFO_DECLARATION, Arena *arena,
|
|
||||||
void *old_ptr, size_t old_size, size_t new_size) {
|
|
||||||
void *new_ptr = NULL;
|
|
||||||
if (old_ptr == NULL) {
|
|
||||||
new_ptr = arena_alloc__(POSITION_INFO, arena, new_size);
|
|
||||||
} else if (new_size <= old_size) {
|
|
||||||
new_ptr = old_ptr;
|
|
||||||
} else {
|
|
||||||
new_ptr = arena_alloc_or_null__(POSITION_INFO, arena, new_size, true);
|
|
||||||
if (new_ptr)
|
|
||||||
memcpy(new_ptr, old_ptr, old_size);
|
|
||||||
}
|
|
||||||
return new_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// -- misc --
|
// -- misc --
|
||||||
// ----------
|
// ----------
|
||||||
|
|||||||
@@ -290,8 +290,8 @@ char* arena_strdup_fmt__(const char *file, const char *func, int line, Arena *ar
|
|||||||
char* arena_repstr__(const char *file, const char *func, int line, Arena *arena,
|
char* arena_repstr__(const char *file, const char *func, int line, Arena *arena,
|
||||||
const char *src, size_t start, size_t len, const char *rep);
|
const char *src, size_t start, size_t len, const char *rep);
|
||||||
|
|
||||||
void* arena_realloc_copy__(const char *file, const char *func, int line, Arena *arena,
|
void* arena_realloc__(const char *file, const char *func, int line, Arena *arena,
|
||||||
void *old_ptr, size_t old_size, size_t new_size);
|
void *ptr, size_t size, size_t new_size);
|
||||||
|
|
||||||
char* arena_strncpy__(const char *file, const char *func, int line, Arena *arena, const char *start, size_t len);
|
char* arena_strncpy__(const char *file, const char *func, int line, Arena *arena, const char *start, size_t len);
|
||||||
|
|
||||||
@@ -321,8 +321,8 @@ char* arena_strncpy__(const char *file, const char *func, int line, Arena *arena
|
|||||||
#define arena_repstr(arena, src, start, len, rep) \
|
#define arena_repstr(arena, src, start, len, rep) \
|
||||||
arena_repstr__(__FILE__, __func__, __LINE__, arena, src, start, len, rep)
|
arena_repstr__(__FILE__, __func__, __LINE__, arena, src, start, len, rep)
|
||||||
|
|
||||||
#define arena_realloc_copy(arena, old_ptr, old_size, new_size) \
|
#define arena_realloc(arena, ptr, size, new_size) \
|
||||||
arena_realloc_copy__(__FILE__, __func__, __LINE__, arena, old_ptr, old_size, new_size)
|
arena_realloc__(__FILE__, __func__, __LINE__, arena, ptr, size, new_size)
|
||||||
|
|
||||||
#define arena_strncpy(arena, src, len) \
|
#define arena_strncpy(arena, src, len) \
|
||||||
arena_strncpy__(__FILE__, __func__, __LINE__, arena, src, len)
|
arena_strncpy__(__FILE__, __func__, __LINE__, arena, src, len)
|
||||||
@@ -342,6 +342,20 @@ static Arena disposable_arena __attribute__((unused)) = {0};
|
|||||||
// -- Debug --
|
// -- Debug --
|
||||||
// ------------
|
// ------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set of pointers to track visited objects
|
||||||
|
* Used to detect cycles in debug strings
|
||||||
|
*/
|
||||||
|
typedef struct PtrSet {
|
||||||
|
void **data;
|
||||||
|
size_t size;
|
||||||
|
size_t capacity;
|
||||||
|
} PtrSet;
|
||||||
|
|
||||||
|
PtrSet *ptrset_init(Arena *arena);
|
||||||
|
bool debug_ptrset_contains__(PtrSet *set, void *ptr);
|
||||||
|
void debug_ptrset_add__(const char *file, const char *func, int line, Arena *arena, PtrSet *set, void *ptr);
|
||||||
|
|
||||||
#define DEBUGSTR(arena, type, value) DEBUGSTR_##type(arena, value)
|
#define DEBUGSTR(arena, type, value) DEBUGSTR_##type(arena, value)
|
||||||
|
|
||||||
#define DEBUGSTR_Slice(arena, value) slice_to_debug_str(arena, value)
|
#define DEBUGSTR_Slice(arena, value) slice_to_debug_str(arena, value)
|
||||||
@@ -360,6 +374,31 @@ void logger_print_rules();
|
|||||||
*/
|
*/
|
||||||
char* logger_rules_to_string(Arena *arena);
|
char* logger_rules_to_string(Arena *arena);
|
||||||
|
|
||||||
|
char *string_to_debug_str__(const char *file, const char *func, int line, Arena *arena, const char *name, const char *string);
|
||||||
|
|
||||||
|
char *number_to_debug_str__(const char *file, const char *func, int line, Arena *arena, const char *name, int number);
|
||||||
|
|
||||||
|
char *struct_to_debug_str__(const char *file, const char *func, int line, Arena *arena, const char *type, const char *name, void *ptr, int count, ...);
|
||||||
|
|
||||||
|
#define STRING_TO_DEBUG_STR(arena, name, string) \
|
||||||
|
string_to_debug_str__(__FILE__, __func__, __LINE__, arena, name, string)
|
||||||
|
#define NUMBER_TO_DEBUG_STR(arena, name, number) \
|
||||||
|
number_to_debug_str__(__FILE__, __func__, __LINE__, arena, name, number)
|
||||||
|
#define STRUCT_TO_DEBUG_STR(arena, type, name, self, count, ...) \
|
||||||
|
struct_to_debug_str__(__FILE__, __func__, __LINE__, arena, #type, name, self, count, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
bool debug_ptrset_contains(PtrSet *set, void *ptr);
|
||||||
|
|
||||||
|
#define debug_check_cycle__(file, func, line, arena, type, name, self, visited) __extension__ ({ \
|
||||||
|
if (debug_ptrset_contains__(visited, self)) \
|
||||||
|
return struct_to_debug_str__(file, func, line, arena, \
|
||||||
|
#type, name, self, 1, "cycle detected"); \
|
||||||
|
debug_ptrset_add__(file, func, line, arena, visited, self); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define DEBUG_CHECK_CYCLE(arena, type, name, self, visited) \
|
||||||
|
debug_check_cycle__(__FILE__, __func__, __LINE__, arena, type, name, self, visited)
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// -- Json --
|
// -- Json --
|
||||||
// ----------
|
// ----------
|
||||||
|
|||||||
@@ -19,58 +19,19 @@ struct TestStruct2 {
|
|||||||
TestStruct *other;
|
TestStruct *other;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define test_struct_to_debug_str(arena, name, self) test_struct_to_debug_str__(arena, name, self, ptrset_init(arena))
|
||||||
|
|
||||||
typedef struct PtrSet {
|
char *test_struct_to_debug_str__(Arena *arena, char *name, TestStruct *self, PtrSet *visited) {
|
||||||
void **data;
|
|
||||||
size_t size;
|
|
||||||
size_t capacity;
|
|
||||||
} PtrSet;
|
|
||||||
|
|
||||||
static bool debug_ptrset_contains(PtrSet *set, void *ptr) {
|
|
||||||
for (size_t i = 0; i < set->size; i++) {
|
|
||||||
if (set->data[i] == ptr)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void debug_ptrset_add(PtrSet *set, void *ptr) {
|
|
||||||
if (set->size == set->capacity) {
|
|
||||||
set->capacity = set->capacity ? set->capacity * 2 : 4;
|
|
||||||
set->data = realloc(set->data, set->capacity * sizeof(void*));
|
|
||||||
}
|
|
||||||
set->data[set->size++] = ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define STRING_TO_DEBUG_STR(arena, name, string) \
|
|
||||||
arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%s = %p \"%s\"", name, string, string)
|
|
||||||
|
|
||||||
#define NUMBER_TO_DEBUG_STR(arena, name, number) \
|
|
||||||
arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%s = %d", name, number)
|
|
||||||
|
|
||||||
#define STRUCT_TO_DEBUG_STR(arena, type, name, ptr, ...) __extension__ ({ \
|
|
||||||
char *result; \
|
|
||||||
if ((ptr) == NULL) { \
|
|
||||||
result = arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%s %s = NULL", #type, name); \
|
|
||||||
} else { \
|
|
||||||
char* fields = arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%s, %s, %s", __VA_ARGS__); \
|
|
||||||
result = arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%s %s = {%s} %p", #type, name, fields, ptr); \
|
|
||||||
} \
|
|
||||||
result; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define test_struct_to_debug_str(arena, name, self) test_struct_to_debug_str__(arena, name, self)
|
|
||||||
|
|
||||||
char *test_struct_to_debug_str__(Arena *arena, char *name, TestStruct *self) {
|
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
name = "$1";
|
name = "$1";
|
||||||
}
|
}
|
||||||
|
|
||||||
char *result = STRUCT_TO_DEBUG_STR(arena, TestStruct, name, self,
|
DEBUG_CHECK_CYCLE(arena, TestStruct, name, self, visited);
|
||||||
|
|
||||||
|
char *result = STRUCT_TO_DEBUG_STR(arena, TestStruct, name, self, 3,
|
||||||
NUMBER_TO_DEBUG_STR(arena, "a", self->a),
|
NUMBER_TO_DEBUG_STR(arena, "a", self->a),
|
||||||
NUMBER_TO_DEBUG_STR(arena, "b", self->b),
|
NUMBER_TO_DEBUG_STR(arena, "b", self->b),
|
||||||
test_struct_to_debug_str__(arena, "next", self->next)
|
test_struct_to_debug_str__(arena, "next", self->next, visited)
|
||||||
);
|
);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -91,6 +52,7 @@ int main(void) {
|
|||||||
init_logger();
|
init_logger();
|
||||||
|
|
||||||
TestStruct test_struct = {.a = 1, .b = 2, .next = NULL};
|
TestStruct test_struct = {.a = 1, .b = 2, .next = NULL};
|
||||||
|
test_struct.next = &test_struct;
|
||||||
raise_notice("%s", test_struct_to_debug_str(DISPOSABLE_ARENA, "test_struct", &test_struct));
|
raise_notice("%s", test_struct_to_debug_str(DISPOSABLE_ARENA, "test_struct", &test_struct));
|
||||||
|
|
||||||
printf("%sAll tests passed %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
printf("%sAll tests passed %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
||||||
|
|||||||
Reference in New Issue
Block a user