summaryrefslogtreecommitdiff
path: root/src/core/allocator.h
blob: e67a08bf14f157dced6787ebff3e49f0556f63a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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