Custom allocators and memory functions
A simple arena-style allocator
Represents an arena allocator. ArenaAllocator holds its own buffer, but managing its size is left to the user. Like most structs in libflint, it must be malloc’d first before being passed to arena_init().
typedef struct { unsigned char* buf; size_t buf_sz; size_t offset_cur; size_t offset_prev; } ArenaAllocator;
Initializes the ArenaAllocator. The struct must first be created by the user using malloc(), see the example below. buf_sz is the size of the underlying buffer in bytes.
void arena_init(ArenaAllocator *allocator, size_t buf_sz); /* Usage */ ArenaAllocator *a = malloc(sizeof(ArenaAllocator)); arena_init(a, 1024);
Frees allocator and its underlying buffer. Users should set allocator to NULL after calling arena_free().
void arena_free(ArenaAllocator *allocator); /* Usage */ arena_free(allocator); allocator = NULL;
Resets the offset markers of the arena to 0, but does not wipe the underlying buffer. Technically, any assigned pointers will still work and
void arena_clear(ArenaAllocator *allocator);
Request memory of size bytes in length from the arena. Returns NULL if the assignment failed.
void *arena_malloc(ArenaAllocator* allocator, size_t size);
Reallocates the underlying buffer in the arena to new_sz. You can grow or shrink the arena using this function. Any pointers allocated out of the arena are invalid after using this function.
void arena_resize_buf(ArenaAllocator *allocator, size_t new_sz);
Resize an allocated pointer from the arena. See the example below for a simple use case
void *arena_resize(ArenaAllocator *allocator, void *mem, size_t old_sz, size_t new_sz); /* Usage */ int *i = arena_malloc(a, sizeof(int)); *i = 1; long *l = arena_resize(a, i1, sizeof(int), sizeof(long)); assert(*l == 1);
Convenience macro for getting the size of the arena’s buffer
#define arena_sz(a) (a)->buf_sz
A pool-based allocator for chunks of the same size. Useful for quickly allocating and using memory of the same size without worrying about order; most operations are O(1)
Represents a pool allocator. PoolAllocator holds its own buffer, but managing its size is left to the user. Like most structs in libflint, it must be malloc’d first before being passed to pool_init().
typedef struct { unsigned char *buf; size_t buf_sz; size_t chunk_size; List *free_list; } PoolAllocator;
Initializes the PoolAllocator. The struct must first be created by the user using malloc(), see the example below.
buf_sz: Size of the underlying buffer in byteschunk_sz: Size of each chunk in byteschunk_align: The alignment of the chunks. TheLF_DEFAULT_ALIGNMENT macro is available as a good default for basic typesvoid pool_init(PoolAllocator *allocator, size_t buf_sz, size_t chunk_sz, size_t chunk_align); /* Usage */ PoolAllocator *pool = malloc(sizeof(PoolAllocator)); pool_init(pool, 64, 16, LF_DEFAULT_ALIGNMENT);
Return a single chunk back to the pool. ptr is a pointer to the allocated chunk.
void pool_free(PoolAllocator *allocator, void *ptr);
Returns all chunks back to the pool. Any pointers received before this call are now invalid and must be reasigned with pool_alloc or set to NULL.
void pool_free_all(PoolAllocator *allocator);
Allocate a chunk from the pool. Returns NULL on failure.
void *pool_alloc(PoolAllocator *allocator);
Destroys the underlying buffer and List in allocator, then frees it. User is responsible for setting allocator to NULL afterwards.
void pool_destroy(PoolAllocator *allocator);
Returns the amount of chunks left available in the pool
#define pool_count_available(x) (x)->free_list->size
The default alignment for allocators. Use this as a simple default (defaults to 16 bytes on amd64 systems) when storing basic types
#ifndef DEFAULT_ALIGNMENT #define LF_DEFAULT_ALIGNMENT (2*sizeof(void*)) #endif // DEFAULT_ALIGNMENT