#ifndef __NICKEL_ALLOC_H #define __NICKEL_ALLOC_H #include #include #include #ifdef __cplusplus extern "C" { #endif /* Nickel Allocator API (explicit; does NOT replace libc malloc unless you opt-in). Design goal: easy to use in tools, easy to test, portable across Linux/macOS. */ typedef struct ni_alloc_stats { /* current usage */ size_t bytes_in_use; /* user-visible allocated bytes (approx if desired) */ size_t bytes_reserved; /* backing store reserved from VM */ size_t bytes_peak; /* peak in-use */ size_t bytes_reserved_peak; /* counters */ uint64_t alloc_calls; uint64_t free_calls; uint64_t realloc_calls; uint64_t calloc_calls; uint64_t memalign_calls; /* failures */ uint64_t oom_count; } ni_alloc_stats; /* Allocator configuration knobs (keep minimal at first; extend later). */ typedef struct ni_alloc_config { /* If true, ni_free(NULL) is allowed and a no-op (recommended true). */ bool free_null_is_noop; /* If true, ni_realloc(p,0) behaves like free(p) and returns NULL. */ bool realloc_zero_frees; /* If true, scribble freed blocks with a pattern (debug build feature). */ bool scribble_free; /* If true, scribble newly allocated blocks with a pattern (debug). */ bool scribble_alloc; /* Optional alignment for default allocations (usually alignof(max_align_t)). */ size_t default_alignment; /* Optional: maximum small-bin size, arena chunk size, etc. */ size_t arena_chunk_bytes; } ni_alloc_config; /* Opaque allocator instance. You can use the global allocator, or create a private allocator instance (handy for tests / subsystems). */ typedef struct ni_allocator ni_allocator; /* -------- Global allocator API -------- */ /* Initialize/shutdown global allocator (optional; can be lazy). Returns false if initialization fails. */ bool ni_alloc_global_init(const ni_alloc_config* cfg); void ni_alloc_global_shutdown(void); /* Allocation functions using the global allocator. */ void* ni_malloc(size_t size); void ni_free(void* ptr); void* ni_realloc(void* ptr, size_t new_size); void* ni_calloc(size_t count, size_t elem_size); /* Alignment: - alignment must be power of two and >= sizeof(void*) - returns NULL on failure */ void* ni_memalign(size_t alignment, size_t size); /* Equivalent of C11 aligned_alloc semantics: - alignment must be power of two - size must be a multiple of alignment */ void* ni_aligned_alloc(size_t alignment, size_t size); /* Query/reset stats for global allocator. */ void ni_alloc_get_stats(ni_alloc_stats* out_stats); void ni_alloc_reset_stats(void); /* -------- Instance allocator API -------- */ ni_allocator* ni_allocator_create(const ni_alloc_config* cfg); void ni_allocator_destroy(ni_allocator* a); void* ni_allocator_malloc(ni_allocator* a, size_t size); void ni_allocator_free(ni_allocator* a, void* ptr); void* ni_allocator_realloc(ni_allocator* a, void* ptr, size_t new_size); void* ni_allocator_calloc(ni_allocator* a, size_t count, size_t elem_size); void* ni_allocator_memalign(ni_allocator* a, size_t alignment, size_t size); void ni_allocator_get_stats(ni_allocator* a, ni_alloc_stats* out_stats); void ni_allocator_reset_stats(ni_allocator* a); /* -------- Utilities / validation -------- */ /* Returns true if n is a power of two (and nonzero). */ bool ni_is_pow2_size(size_t n); /* Round up x to next multiple of align (align must be power of two). */ size_t ni_align_up(size_t x, size_t align); /* Optional: verify internal invariants in debug builds. - returns false if corruption detected */ bool ni_alloc_validate(void); #ifdef __cplusplus } #endif #endif /* __NICKEL_ALLOC_H */