Add guf_alloc_tracker

This commit is contained in:
jun 2025-05-14 14:45:30 +02:00
parent 6ffb79f7a0
commit 37f9011166
12 changed files with 303 additions and 163 deletions

View File

@ -27,10 +27,10 @@ else ()
set(DBG_FLAGS /fsanitize=address)
endif ()
add_executable(libguf_example src/test/example.c src/test/impls/str_impl.c src/test/impls/dict_impl.c src/test/impls/linalg_impl.c)
add_executable(libguf_example src/test/example.c src/test/impls/str_impl.c src/test/impls/dict_impl.c src/test/impls/linalg_impl.c src/test/impls/alloc_tracker_impl.c)
target_include_directories(libguf_example PRIVATE src src/test)
add_executable(libguf_test src/test/test.cpp src/test/test_dbuf.cpp src/test/test_dict.cpp src/test/test_str.cpp src/test/test_ckdint.cpp src/test/test_utf8.cpp src/test/impls/init_impl.c src/test/impls/dbuf_impl.c src/test/impls/str_impl.c src/test/impls/dict_impl.c src/test/impls/rand_impl.c src/test/impls/sort_impl.c src/test/impls/linalg_impl.c src/test/impls/ckdint_impl.c)
add_executable(libguf_test src/test/test.cpp src/test/test_dbuf.cpp src/test/test_dict.cpp src/test/test_str.cpp src/test/test_ckdint.cpp src/test/test_utf8.cpp src/test/impls/init_impl.c src/test/impls/dbuf_impl.c src/test/impls/str_impl.c src/test/impls/dict_impl.c src/test/impls/rand_impl.c src/test/impls/sort_impl.c src/test/impls/linalg_impl.c src/test/impls/ckdint_impl.c src/test/impls/alloc_tracker_impl.c)
target_include_directories(libguf_test PRIVATE src src/test)
set_target_properties(libguf_example libguf_test PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})

View File

@ -15,17 +15,11 @@ typedef struct guf_allocator {
void *ctx;
} guf_allocator;
typedef struct guf_alloc_meta {
size_t alloc_count, realloc_count, free_count;
ptrdiff_t allocated_bytes;
uint32_t alloc_id;
} guf_alloc_meta;
typedef enum guf_alloc_fn_type {
GUF_ALLOC_FN_TYPE_ALLOC,
GUF_ALLOC_FN_TYPE_REALLOC,
GUF_ALLOC_FN_TYPE_FREE,
} guf_alloc_fn_type;
// typedef enum guf_alloc_fn_type {
// GUF_ALLOC_FN_TYPE_ALLOC,
// GUF_ALLOC_FN_TYPE_REALLOC,
// GUF_ALLOC_FN_TYPE_FREE,
// } guf_alloc_fn_type;
/*
GUF_ALLOC_MAX_BYTES: Largest number of bytes an allocated buffer of elements of TYPE can have.

View File

@ -6,10 +6,11 @@
#define GUF_ALLOC_LIBC_H
#include <memory.h>
#include "guf_alloc.h"
#define GUF_ALLOC_TRACKER_IMPL_STATIC
#include "guf_alloc_tracker.h"
typedef struct guf_libc_alloc_ctx {
guf_alloc_meta meta;
bool track_allocs;
guf_alloc_tracker tracker;
bool zero_init;
} guf_libc_alloc_ctx;
@ -17,13 +18,22 @@ static inline void *guf_libc_alloc(ptrdiff_t size, void *ctx)
{
GUF_ASSERT_RELEASE(size >= 0);
guf_libc_alloc_ctx *alloc_ctx = (guf_libc_alloc_ctx*)ctx;
void *res = NULL;
if (size == 0) {
return NULL;
res = NULL;
} else if (alloc_ctx && alloc_ctx->zero_init) {
return calloc(size, 1);
res = calloc(size, 1);
} else {
return malloc(size);
res = malloc(size);
}
if (alloc_ctx && alloc_ctx->tracker.enabled) {
const bool succ = guf_track_alloc(&alloc_ctx->tracker, size);
GUF_ASSERT(succ);
}
return res;
}
static inline void *guf_libc_realloc(void *ptr, ptrdiff_t old_size, ptrdiff_t new_size, void *ctx)
@ -37,21 +47,41 @@ static inline void *guf_libc_realloc(void *ptr, ptrdiff_t old_size, ptrdiff_t ne
void *new_ptr = realloc(ptr, new_size);
if (!new_ptr || new_size == 0) {
return NULL;
new_ptr = NULL;
} else if (alloc_ctx && alloc_ctx->zero_init && new_size > old_size) {
ptrdiff_t len = new_size - old_size;
const ptrdiff_t len = new_size - old_size;
GUF_ASSERT(len > 0);
GUF_ASSERT(old_size + len == new_size);
memset((char*)ptr + old_size, 0, len); // TODO: sketchy
}
if (alloc_ctx && alloc_ctx->tracker.enabled) {
const bool succ = guf_track_realloc(&alloc_ctx->tracker, old_size, new_size);
GUF_ASSERT(succ);
}
return new_ptr;
}
static inline void guf_libc_free(void *ptr, ptrdiff_t size, void *ctx)
{
(void)ctx;
(void)size;
free(ptr);
guf_libc_alloc_ctx *alloc_ctx = (guf_libc_alloc_ctx*)ctx;
if (alloc_ctx && alloc_ctx->tracker.enabled) {
const bool succ = guf_track_free(&alloc_ctx->tracker, size);
GUF_ASSERT(succ);
}
}
static inline guf_allocator *guf_libc_allocator_init(guf_allocator *a, guf_libc_alloc_ctx *ctx)
{
GUF_ASSERT_RELEASE(a);
a->alloc = guf_libc_alloc;
a->realloc = guf_libc_realloc;
a->free = guf_libc_free;
a->ctx = ctx;
return a;
}
static guf_allocator guf_allocator_libc = {

View File

@ -1,117 +0,0 @@
#include "guf_common.h"
#include "guf_alloc.h"
#include "math.h"
typedef struct guf_alloc_tracker {
FILE *log, *err_log;
size_t alloc_count, realloc_count, free_count;
ptrdiff_t allocated_bytes;
uint32_t id;
} guf_alloc_tracker;
static bool guf_track_alloc(guf_alloc_tracker *t, ptrdiff_t size)
{
GUF_ASSERT(t);
GUF_ASSERT(size >= 0);
bool success = true;
if (t->err_log && t->alloc_count == SIZE_MAX) {
fprintf(t->err_log, "guf_alloc_track (id %" PRIu32 ") WARNING: alloc_count overflow\n", t->id);
//success = false;
}
t->alloc_count = guf_add_saturated_size_t(t->alloc_count, 1);
if (guf_add_is_overflow_ptrdiff(t->allocated_bytes, size)) {
if (t->err_log) {
fprintf(t->err_log, "guf_alloc_track (id %" PRIu32 ") ERROR: allocated_byte overflow\n", t->id);
}
success = false;
}
t->allocated_bytes = guf_add_saturated_ptrdiff(t->allocated_bytes, size);
if (t->allocated_bytes < 0) {
if (t->err_log) {
fprintf(t->err_log, "guf_alloc_track (id %" PRIu32 ") ERROR: allocated_bytes < 0\n", t->id);
}
success = false;
}
if (t->log) {
fprintf(t->log, "guf_alloc_track (id %" PRIu32 "): alloc (%td bytes) %s\n", t->id, size, success ? "SUCCESS" : "FAILURE");
}
return success;
}
static bool guf_track_realloc(guf_alloc_tracker *t, ptrdiff_t old_size, ptrdiff_t new_size)
{
GUF_ASSERT(t);
GUF_ASSERT(old_size >= 0 && new_size >= 0);
bool success = true;
if (t->err_log && t->realloc_count == SIZE_MAX) {
fprintf(t->err_log, "guf_realloc_track (id %" PRIu32 ") WARNING: realloc_count overflow\n");
//success = false;
}
t->realloc_count = guf_add_saturated_size_t(t->realloc_count, 1);
if (old_size < 0 || new_size < 0) {
if (t->err_log) {
fprintf(t->err_log, "guf_realloc_track (id %" PRIu32 ") ERROR: old_size < 0 or new_size < 0\n");
}
success = false;
}
t->allocated_bytes = guf_sub_saturated_ptrdiff(t->allocated_bytes, old_size);
if (t->allocated_bytes < 0) {
success = false;
fprintf(t->err_log, "guf_realloc_track (id %" PRIu32 ") ERROR: allocated_bytes < 0 after subtracting old_size\n", t->id);
}
if (guf_add_is_overflow_ptrdiff(t->allocated_bytes, new_size)) {
success = false;
if (t->err_log) {
fprintf(t->err_log, "guf_realloc_track (id %" PRIu32 ") ERROR: allocated_bytes overflow \n");
}
}
t->allocated_bytes = guf_add_saturated_ptrdiff(t->allocated_bytes, new_size);
if (t->allocated_bytes < 0) {
success = false;
fprintf(t->err_log, "guf_realloc_track (id %" PRIu32 ") ERROR: allocated_bytes < 0 after adding new_size\n", t->id);
}
if (t->log) {
fprintf(t->log, "guf_realloc_track (id %" PRIu32 "): realloc (from %td to %td bytes) %s", t->id, old_size, new_size, (success ? "SUCCESS" : "FAILURE"));
}
return success;
}
static bool guf_track_free(guf_alloc_tracker *t, ptrdiff_t size)
{
GUF_ASSERT(t);
GUF_ASSERT(size >= 0);
if (t->err_log && t->free_count == SIZE_MAX) {
fprintf(t->err_log, "guf_track_free (id %" PRIu32 ") WARNING: free_count overflow\n");
}
bool success = true;
if (size < 0) {
success = false;
if (t->err_log) {
fprintf(t->err_log, "guf_track_free (id %" PRIu32 ") ERROR: size < 0\n");
}
}
if (t->allocated_bytes < size) {
success = false;
if (t->err_log) {
fprintf(t->err_log, "guf_track_free (id %" PRIu32 ") ERROR: freed more bytes than allocated\n");
}
}
t->allocated_bytes = guf_sub_saturated_ptrdiff(t->allocated_bytes, size);
return success;
}

200
src/guf_alloc_tracker.h Normal file
View File

@ -0,0 +1,200 @@
#if defined(GUF_ALLOC_TRACKER_IMPL_STATIC)
#define GUF_ALLOC_TRACKER_KWRDS static inline
#else
#define GUF_ALLOC_TRACKER_KWRDS
#endif
#ifndef GUF_ALLOC_TRACKER_H
#define GUF_ALLOC_TRACKER_H
#include <stdio.h>
#include "guf_common.h"
typedef struct guf_alloc_tracker {
FILE *log, *err_log;
size_t alloc_count, realloc_count, free_count;
ptrdiff_t allocated_bytes;
uint32_t id;
bool enabled;
} guf_alloc_tracker;
#if !defined(GUF_ALLOC_TRACKER_IMPL_STATIC) && !defined(GUF_ALLOC_TRACKER_IMPL)
GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker *guf_alloc_tracker_init(guf_alloc_tracker *t, uint32_t id, FILE *log, FILE *err_log);
GUF_ALLOC_TRACKER_KWRDS void guf_alloc_tracker_print(const guf_alloc_tracker *t, FILE *f);
GUF_ALLOC_TRACKER_KWRDS bool guf_alloc_tracker_found_leak(guf_alloc_tracker *t);
GUF_ALLOC_TRACKER_KWRDS bool guf_track_alloc(guf_alloc_tracker *t, ptrdiff_t size);
GUF_ALLOC_TRACKER_KWRDS bool guf_track_realloc(guf_alloc_tracker *t, ptrdiff_t old_size, ptrdiff_t new_size);
GUF_ALLOC_TRACKER_KWRDS bool guf_track_free(guf_alloc_tracker *t, ptrdiff_t size);
#endif
#if defined(GUF_ALLOC_TRACKER_IMPL_STATIC) || defined(GUF_ALLOC_TRACKER_IMPL)
#include "guf_alloc.h"
#define GUF_MATH_CKDINT_IMPL_STATIC
#include "guf_math_ckdint.h"
GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker *guf_alloc_tracker_init(guf_alloc_tracker *t, uint32_t id, FILE *log, FILE *err_log)
{
GUF_ASSERT_RELEASE(t);
t->log = log;
t->err_log = err_log;
t->alloc_count = t->realloc_count = t->free_count = 0;
t->allocated_bytes = 0;
t->id = id;
t->enabled = true;
return t;
}
GUF_ALLOC_TRACKER_KWRDS bool guf_alloc_tracker_found_leak(guf_alloc_tracker *t)
{
GUF_ASSERT_RELEASE(t);
return (t->allocated_bytes != 0) || (t->alloc_count != t->free_count);
}
GUF_ALLOC_TRACKER_KWRDS void guf_alloc_tracker_print(const guf_alloc_tracker *t, FILE *f)
{
GUF_ASSERT(t);
if (!f) {
f = stdout;
}
if (!t) {
fprintf(f, "guf_alloc_tracker_fprint: guf_alloc_tracker is NULL");
return;
}
fprintf(f,
"guf_alloc_tracker (id = %" PRIu32 "):\n"
"allocated_bytes: %td\n"
"alloc_count: %zu\n"
"realloc_count: %zu\n"
"free_count: %zu\n",
t->id, t->allocated_bytes, t->alloc_count, t->realloc_count, t->free_count
);
}
GUF_ALLOC_TRACKER_KWRDS bool guf_track_alloc(guf_alloc_tracker *t, ptrdiff_t size)
{
GUF_ASSERT(t);
GUF_ASSERT(size >= 0);
bool success = true;
if (guf_saturating_add_size_t(t->alloc_count, 1, &t->alloc_count) != GUF_MATH_CKD_SUCCESS && t->err_log) {
fprintf(t->err_log, "WARNING in guf_track_alloc (id %" PRIu32 "): alloc_count reached SIZE_MAX\n", t->id);
}
if (guf_saturating_add_ptrdiff_t(t->allocated_bytes, size, &t->allocated_bytes) != GUF_MATH_CKD_SUCCESS) {
if (t->err_log) {
fprintf(t->err_log, "ERROR in guf_track_alloc (id %" PRIu32 "): allocated_byte overflow\n", t->id);
}
success = false;
}
if (t->allocated_bytes < 0) {
if (t->err_log) {
fprintf(t->err_log, "ERROR in guf_track_alloc (id %" PRIu32 "): allocated_bytes < 0\n", t->id);
}
success = false;
}
if (t->log) {
fprintf(t->log, "guf_alloc_tracker (id %" PRIu32 "): alloc (%td bytes) %s\n", t->id, size, success ? "SUCCESS" : "FAILURE");
}
return success;
}
GUF_ALLOC_TRACKER_KWRDS bool guf_track_realloc(guf_alloc_tracker *t, ptrdiff_t old_size, ptrdiff_t new_size)
{
GUF_ASSERT(t);
GUF_ASSERT(old_size >= 0 && new_size >= 0);
bool success = true;
if (guf_saturating_add_size_t(t->realloc_count, 1, &t->realloc_count) && t->err_log) {
fprintf(t->err_log, "WARNING in guf_track_realloc (id %" PRIu32 "): realloc_count reached SIZE_MAX\n", t->id);
}
if (old_size < 0 || new_size < 0) {
success = false;
if (t->err_log) {
fprintf(t->err_log, "ERROR in guf_track_realloc (id %" PRIu32 "): old_size < 0 or new_size < 0\n", t->id);
}
}
if (guf_saturating_sub_ptrdiff_t(t->allocated_bytes, old_size, &t->allocated_bytes)) {
success = false;
if (t->err_log) {
fprintf(t->err_log, "ERROR in guf_track_realloc (id %" PRIu32 "): allocated_bytes - old_size under/overflows\n", t->id);
}
}
if (t->allocated_bytes < 0) {
success = false;
fprintf(t->err_log, "ERROR in guf_track_realloc (id %" PRIu32 "): allocated_bytes < 0 after subtracting old_size\n", t->id);
}
if (guf_saturating_add_ptrdiff_t(t->allocated_bytes, new_size, &t->allocated_bytes)) {
success = false;
if (t->err_log) {
fprintf(t->err_log, "ERROR in guf_track_realloc (id %" PRIu32 "): allocated_bytes overflow \n", t->id);
}
}
if (t->allocated_bytes < 0) {
success = false;
fprintf(t->err_log, "ERROR in guf_track_realloc (id %" PRIu32 "): allocated_bytes < 0 after adding new_size\n", t->id);
}
if (t->log) {
fprintf(t->log, "guf_alloc_tracker (id %" PRIu32 "): realloc (from %td to %td bytes) %s\n", t->id, old_size, new_size, (success ? "SUCCESS" : "FAILURE"));
}
return success;
}
GUF_ALLOC_TRACKER_KWRDS bool guf_track_free(guf_alloc_tracker *t, ptrdiff_t size)
{
GUF_ASSERT(t);
GUF_ASSERT(size >= 0);
bool success = true;
if (guf_saturating_add_size_t(t->free_count, 1, &t->free_count) && t->err_log) {
fprintf(t->err_log, "WARNING in guf_track_free (id %" PRIu32 "): free_count reached SIZE_MAX\n", t->id);
}
if (size < 0) {
success = false;
if (t->err_log) {
fprintf(t->err_log, "ERROR in guf_track_free (id %" PRIu32 "): size < 0\n", t->id);
}
}
if (t->allocated_bytes < size) {
success = false;
if (t->err_log) {
fprintf(t->err_log, "ERROR in guf_track_free (id %" PRIu32 "): freed more bytes than allocated\n", t->id);
}
}
if (guf_saturating_sub_ptrdiff_t(t->allocated_bytes, size, &t->allocated_bytes)) {
success = false;
if (t->err_log) {
fprintf(t->err_log, "ERROR in guf_track_free (id %" PRIu32 "): allocated_bytes - size under/overflows\n", t->id);
}
}
if (t->log) {
fprintf(t->log, "guf_alloc_tracker (id %" PRIu32 "): free (%td bytes) %s\n", t->id, size, (success ? "SUCCESS" : "FAILURE"));
}
return success;
}
#endif /* End impl */
#endif /* End header-guard */
#undef GUF_ALLOC_TRACKER_KWRDS
#undef GUF_ALLOC_TRACKER_IMPL
#undef GUF_ALLOC_TRACKER_IMPL_STATIC

View File

@ -1,11 +1,6 @@
/*
is parametrized: no
*/
#if defined(GUF_MATH_CKDINT_IMPL_STATIC)
#define GUF_MATH_CKDINT_KWRDS static inline
#else
#define GUF_MATH_CKDINT_KWRDS
#endif
/*
// Functions for safely checking for over- and underflow of arithmetic operations
@ -85,6 +80,8 @@
typedef enum guf_math_ckd_result {GUF_MATH_CKD_SUCCESS = 0, GUF_MATH_CKD_OVERFLOW, GUF_MATH_CKD_UNDERFLOW} guf_math_ckd_result;
#if !defined(GUF_MATH_CKDINT_IMPL_STATIC) && !defined(GUF_MATH_CKDINT_IMPL)
// Signed integer arithmetic checks (generated with libguf/tools/ckdint-gen.py)
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_int(int a, int b);
@ -262,6 +259,7 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_size_t(size_t a, size
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_size_t(size_t a, size_t b, size_t *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_size_t(size_t a, size_t b, size_t *result);
#endif
#if defined(GUF_MATH_CKDINT_IMPL) || defined(GUF_MATH_CKDINT_IMPL_STATIC)
#include "guf_assert.h"
@ -2063,3 +2061,4 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_size_t(size_t a, size
#undef GUF_MATH_CKDINT_IMPL
#undef GUF_MATH_CKDINT_IMPL_STATIC
#undef GUF_MATH_CKDINT_KWRDS

View File

@ -59,7 +59,7 @@ int main(void)
guf_platform_assert_native_word_bits();
guf_allocator test_allocator = guf_allocator_libc;
guf_libc_alloc_ctx test_allocator_ctx = {.zero_init = true, .track_allocs = false};
guf_libc_alloc_ctx test_allocator_ctx = {.zero_init = true, .tracker = (guf_alloc_tracker){.enabled = false}};
test_allocator.ctx = &test_allocator_ctx;
dict_cstr_int ht;

View File

@ -0,0 +1,2 @@
#define GUF_ALLOC_TRACKER_IMPL
#include "guf_alloc_tracker.h"

View File

@ -16,8 +16,11 @@ void DbufIntTest::run()
return;
}
// allocator_ctx.tracker.log = fopen("alloc_log.txt", "w");
// allocator_ctx.tracker.err_log = fopen("alloc_err_log.txt", "w");
dbuf_int dbuf {};
dbuf_int_init(&dbuf, 0, &guf_allocator_libc);
dbuf_int_init(&dbuf, 0, &allocator);
push_check_name("test_push");
@ -29,7 +32,7 @@ void DbufIntTest::run()
dbuf_int_free(&dbuf, NULL);
TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 0 && dbuf.data == NULL);
dbuf_int_init(&dbuf, 24, &guf_allocator_libc);
dbuf_int_init(&dbuf, 24, &allocator);
TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 24 && dbuf.data);
test_push(&dbuf, 365);
@ -57,6 +60,12 @@ void DbufIntTest::run()
test_insert_remove(2049);
pop_check_name();
TEST_CHECK(!guf_alloc_tracker_found_leak(&allocator_ctx.tracker));
// guf_alloc_tracker_print(&allocator_ctx.tracker, stdout);
// puts("");
// fclose(allocator_ctx.tracker.log);
// fclose(allocator_ctx.tracker.err_log);
}
std::vector<int> DbufIntTest::dbuf_to_vec(dbuf_int *dbuf)
@ -97,7 +106,7 @@ void DbufIntTest::test_push(dbuf_int *dbuf, int n)
void DbufIntTest::test_insert_remove(int n)
{
dbuf_int dbuf = {};
dbuf_int_init(&dbuf, 0, &guf_allocator_libc);
dbuf_int_init(&dbuf, 0, &allocator);
std::vector<int> vec = dbuf_to_vec(&dbuf);
guf_err err = GUF_ERR_NONE;
@ -222,6 +231,9 @@ void DbufCstringTest::run()
return;
}
// allocator_ctx.tracker.log = fopen("alloc_log.txt", "w");
// allocator_ctx.tracker.err_log = fopen("alloc_err_log.txt", "w");
push_check_name("push_insert_erase");
for (int i = 1; i <= 32; ++i) {
@ -235,7 +247,7 @@ void DbufCstringTest::run()
test_push_insert_erase(2048, 11);
dbuf_heap_cstr str_dbuf = {};
dbuf_heap_cstr_init(&str_dbuf, 0, &guf_allocator_libc);
dbuf_heap_cstr_init(&str_dbuf, 0, &allocator);
std::vector<std::string> str_vec {};
for (int i = 0; i < 512; ++i) {
@ -261,6 +273,12 @@ void DbufCstringTest::run()
test_find(42);
test_find(129);
pop_check_name();
TEST_CHECK(!guf_alloc_tracker_found_leak(&allocator_ctx.tracker));
// guf_alloc_tracker_print(&allocator_ctx.tracker, stdout);
// puts("");
// fclose(allocator_ctx.tracker.log);
// fclose(allocator_ctx.tracker.err_log);
}
void DbufCstringTest::test_iter(std::vector<std::string>& str_vec, dbuf_heap_cstr *str_dbuf, int step)
@ -324,7 +342,7 @@ void DbufCstringTest::test_push_insert_erase(int n, ptrdiff_t start_cap)
{
std::vector<std::string> str_vec;
dbuf_heap_cstr str_dbuf {};
dbuf_heap_cstr_init(&str_dbuf, start_cap, &guf_allocator_libc);
dbuf_heap_cstr_init(&str_dbuf, start_cap, &allocator);
for (int i = 0; i < n; ++i) {
constexpr int BUF_SZ = 128;
@ -449,7 +467,7 @@ void DbufCstringTest::test_find(int n)
std::vector<std::string> str_vec {};
dbuf_heap_cstr str_dbuf = {};
dbuf_heap_cstr_init(&str_dbuf, 0, &guf_allocator_libc);
dbuf_heap_cstr_init(&str_dbuf, 0, &allocator);
for (int i = 0; i < n; ++i) {
constexpr int BUF_SZ = 128;

View File

@ -6,14 +6,24 @@ extern "C"
{
#include "guf_alloc_libc.h"
#include "impls/dbuf_impl.h"
#include "guf_alloc_libc.h"
}
struct DbufIntTest : public Test
{
DbufIntTest(const std::string& name) : Test(name) {};
DbufIntTest(const std::string& name) : Test(name)
{
allocator_ctx.zero_init = false;
guf_alloc_tracker_init(&allocator_ctx.tracker, 1, NULL, NULL);
guf_libc_allocator_init(&allocator, &allocator_ctx);
}
void run() override;
private:
guf_allocator allocator;
guf_libc_alloc_ctx allocator_ctx;
std::vector<int> dbuf_to_vec(dbuf_int *dbuf);
void test_push(dbuf_int *dbuf, int n);
void test_insert_remove(int n);
@ -22,10 +32,19 @@ private:
struct DbufCstringTest : public Test
{
DbufCstringTest(std::string name) : Test(name) {};
DbufCstringTest(std::string name) : Test(name)
{
allocator_ctx.zero_init = false;
guf_alloc_tracker_init(&allocator_ctx.tracker, 2, NULL, NULL);
guf_libc_allocator_init(&allocator, &allocator_ctx);
}
void run() override;
private:
guf_allocator allocator;
guf_libc_alloc_ctx allocator_ctx;
void test_iter(std::vector<std::string>& str_vec, dbuf_heap_cstr *str_dbuf, int step = 1);
void test_push_insert_erase(int n, ptrdiff_t start_cap = 0);
void test_find(int n = 32);

View File

@ -1,11 +1,7 @@
- guf_wrapping_mul_TYPE: Don't rely on implementation defined behaviour
- header guards for optional int64_t types maybe...
- guf_wrapping_mul_TYPE: Not 100 % sure if it does not depend on implementation defined behaviour, but it shouldn't
- sort: add cpp #ifdef to remove restrict from declaration
- separate impl and headers from tests (for compile perf)
- tests for guf_dict with GUF_DICT_64_BIT_IDX (and also hash32/hash64); maybe pass kv_type to insert to avoid copy
- dict elems shrink to fit; allow to pass GUF_DBUF_USE_GROWTH_FAC_ONE_POINT_FIVE; start capacity (for elems and kv_indices?)
- dict: if load factor is high due to mostly tombstones, just try rehashing without resizing first?
@ -15,11 +11,6 @@
- guf_stack, guf_queue, guf_dqueue, guf_prio_queue (using a heap), guf_ringbuf
- track allocs for test (implement alloc tracker):
- each thread needs its own alloc and alloc_ctx; don't track granular, give each allocator it's unique id maybe?
- potential idea for alloc: instead of using a pointer (8 or 4 bytes), use a 2 byte id to save space (and avoid dangling pointers):
- no guf_init.h
- unicode normalisation

View File

@ -408,7 +408,10 @@ if __name__ == "__main__":
"""))
print("#if !defined(GUF_MATH_CKDINT_IMPL_STATIC) && !defined(GUF_MATH_CKDINT_IMPL)")
print(code_header)
print("#endif")
print("#if defined(GUF_MATH_CKDINT_IMPL) || defined(GUF_MATH_CKDINT_IMPL_STATIC)")
print('#include "guf_assert.h"')
@ -417,5 +420,6 @@ if __name__ == "__main__":
print("#endif")
print("#undef GUF_MATH_CKDINT_KWRDS")
print("#undef GUF_MATH_CKDINT_IMPL")
print("#undef GUF_MATH_CKDINT_IMPL_STATIC\n")