diff options
Diffstat (limited to 'src/core/allocator.h')
-rw-r--r-- | src/core/allocator.h | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/src/core/allocator.h b/src/core/allocator.h new file mode 100644 index 0000000..e67a08b --- /dev/null +++ b/src/core/allocator.h @@ -0,0 +1,69 @@ +#ifndef SAND_ALLOCATOR_H +#define SAND_ALLOCATOR_H + +// This module defines a generic allocator interface. All allocations in this +// family of programs happen through this allocation interface. +// +// As references to `SandAllocator`s are passed all around the program, the +// convention adopted here is to allow single-variable (mainly `a`) names for +// these. + +#include <stddef.h> +#include <stdbool.h> + +typedef struct { + // Shall return a new piece of writable and readable memory of size `size` and with alignment `alignment`. + // This function may return `NULL` to indicate out-of-memory. + // Caller promises to call `deallocate` or `reallocate` on the returned pointer. + void *(* allocate)(size_t size, size_t alignment, void *user_data); + + // Shall the allocation made at `old_ptr`. + // Unlike with `realloc(3)`, `old_ptr` is not nullable. + // This operation is assumed to be infallible, as there is no reasonable way to recover. + // FIXME: This should take alignment as well. + void (* deallocate)(void *old_ptr, size_t old_size, void *user_data); + + // Resize the allocation at `old_ptr` from `old_size` to `new_size`. + // `alignment` is guaranteed to be the same as passed to the original call to `allocate`. + // `old_ptr` and `old_size` are guaranteed to be from the last successful invocation of `allocate` or `reallocate`. + // This function may return `NULL` to indicate out-of-memory, however `old_ptr` should still remain valid in that case. + // The struct member itself may be `NULL`, in which case a default implementation is used. + void *(* reallocate)(void *old_ptr, size_t old_size, size_t new_size, size_t alignment, void *user_data); + + // Custom data which is passed to every function in the interface. The + // allocator can use this for extra metadata it needs to keep. + void *user_data; +} SandAllocator; + + +// Allocates a chunk of memory with the given size and alignment. +// Returns `NULL` on failure. +// Caller assumes ownership of returned pointer, must free with `sand_deallocate`. +void *sand_allocate_aligned(SandAllocator *, size_t size, size_t alignment); + +// Same as `sand_allocate_aligned` but with default alignment. +void *sand_allocate(SandAllocator *, size_t size); + +// Resize the allocation at `old_ptr` from `old_size` to `new_size`. +// `alignment` is guaranteed to be the same as passed to the original call to `allocate`. +// Returns a new pointer or `NULL` if reallocation fails. +// If `NULL` is returned, `old_ptr` remains valid. +// Caller assumes ownership of returned pointer (or retains ownership of old pointer). +void *sand_reallocate_aligned(SandAllocator *, void *old_ptr, size_t old_size, size_t new_size, size_t alignment); + +// Same as `sand_reallocate_aligned` but with default alignment. +void *sand_reallocate(SandAllocator *, void *old_ptr, size_t old_size, size_t new_size); + +// Frees `old_ptr`. +// `old_ptr` is nullable, in which case `old_size` is ignored. +// `old_size` must match the size passed to last call to `sand_allocate` or `sand_reallocate`. +void sand_deallocate(SandAllocator *, void *old_ptr, size_t old_size); + +// The following are only intended to be used by allocator implementations. +bool sand_is_valid_alignment(size_t alignment); +bool sand_pointer_is_aligned(void *pointer, size_t alignment); +void *sand_align_pointer_forward(void *ptr, size_t alignment); +bool sand_size_is_aligned(size_t n, size_t alignment); +size_t sand_align_size_forward(size_t n, size_t alignment); + +#endif |