summaryrefslogtreecommitdiff
path: root/src/core/allocator.c
blob: 5444b39079f35c064264558cea2893daf151ab87 (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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "allocator.h"

#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <stddef.h>

#define DEFAULT_ALIGNMENT ((size_t)_Alignof(max_align_t))

void *sand_allocate_aligned(SandAllocator *a, size_t size, size_t alignment) {
	assert(a != NULL);
	assert(size > 0);
	assert(alignment > 0);
	void *ptr = a->allocate(size, alignment, a->user_data);
	assert(ptr == NULL || sand_pointer_is_aligned(ptr, alignment));
	return ptr;
}

void *sand_allocate(SandAllocator *a, size_t size) {
	return sand_allocate_aligned(a, size, DEFAULT_ALIGNMENT);
}

void *sand_reallocate_aligned(SandAllocator *a, void *old_ptr, size_t old_size, size_t new_size, size_t alignment) {
	assert(a != NULL);
	assert(old_ptr != NULL);
	assert(old_size > 0);
	assert(new_size > 0);
	assert(alignment > 0);

	if (a->reallocate != NULL) {
		void *new_ptr = a->reallocate(old_ptr, old_size, new_size, alignment, a->user_data);
		assert(sand_pointer_is_aligned(new_ptr, alignment));
		return new_ptr;
	} else {
		void *new_ptr = a->allocate(new_size, alignment, a->user_data);
		if (new_ptr == NULL) {
			return NULL; // Note that we HAVEN'T freed `old_ptr`!
		}
		assert(sand_pointer_is_aligned(new_ptr, alignment));
		memmove(new_ptr, old_ptr, old_size); // Can't know if they overlap.
		a->deallocate(old_ptr, old_size, a->user_data);
		return new_ptr;
	}
}

void *sand_reallocate(SandAllocator *a, void *old_ptr, size_t old_size, size_t new_size) {
	return sand_reallocate_aligned(a, old_ptr, old_size, new_size, DEFAULT_ALIGNMENT);
}

void sand_deallocate(SandAllocator *a, void *old_ptr, size_t old_size) {
	assert(a != NULL);
	assert(old_ptr != NULL);
	assert(old_size > 0);

	if (old_ptr == NULL) {
		return;
	}
	a->deallocate(old_ptr, old_size, a->user_data);
}

bool sand_is_valid_alignment(size_t alignment) {
	// Only powers of two are allowed as alignments for simplicity.
	return alignment % 2 == 0;
}

void *sand_align_pointer_forward(void *ptr, size_t alignment) {
	intptr_t p = (intptr_t)ptr;
	intptr_t a = alignment;
	intptr_t ap = ((p + a - 1) & ~(a - 1));
	void *result = (void *)ap;
	assert(sand_pointer_is_aligned(result, alignment));
	return result;
}

size_t sand_align_size_forward(size_t n, size_t alignment) {
	size_t result = ((n + alignment - 1) & ~(alignment - 1));
	assert(sand_size_is_aligned(result, alignment));
	return result;
}

bool sand_pointer_is_aligned(void *pointer, size_t alignment) {
	return ((uintptr_t)pointer & (alignment - 1)) == 0;
}

bool sand_size_is_aligned(size_t n, size_t alignment) {
	return (n & (alignment - 1)) == 0;
}