-
Notifications
You must be signed in to change notification settings - Fork 0
/
allocator.h
113 lines (86 loc) · 2.92 KB
/
allocator.h
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
#ifndef ALLOCATOR_H
#define ALLOCATOR_H
#include <stdio.h>
#ifdef ALLOCATOR_IMPLEMENTATION
// linked list style
struct Block {
size_t len;
struct Block *previous, *next;
} Block;
// this aligns the memory size by pointer size
// this is something like if ((n % pointer size) == 0) aligned_address == address else aligned_address == address + adjustment (16 - offset)
#define ALIGN(n) ((n + sizeof(void *) - 1) & ~(sizeof(void *) - 1))
#define BLOCK_LEN (ALIGN(sizeof(Block)))
static struct Block *memory = NULL;
// "block" is our heap, which we will allocate from
int mem_init(void *block, size_t len) {
if (block == NULL || len < BLOCK_LEN) {
// not enough size to store a single block
return 1;
}
memory = (struct Block *)block;
// the size of the block, subtracting the header
memory->len = len - BLOCK_LEN;
memory->previous = NULL;
memory->next = NULL;
return 0;
}
void *mem_alloc(size_t len) {
if (memory == NULL) {
// no more heap!
return NULL;
}
size_t adjusted_len = ALIGN(len + BLOCK_LEN);
struct Block *next = memory->next;
struct Block *previous = memory;
struct Block *current = NULL;
char *pos = (char *)memory + BLOCK_LEN;
while (1) {
if (next != NULL) {
// the size between both of these blocks in bytes
size_t size_between = (char *)next - pos;
if (size_between >= adjusted_len) {
// we've found our header
current = (struct Block *)pos;
break;
}
pos = (char *)next + next->len;
previous = next;
next = next->next;
} else {
// the size between both of these blocks in bytes
size_t size_between = (char *)memory + memory->len - pos;
if (size_between < adjusted_len) {
// not enough space!
return NULL;
}
current = (struct Block *)pos;
break;
}
}
current->len = adjusted_len;
current->previous = previous;
current->next = next;
// if there is a block found after our newly allocated one, assign it as the previous block of the block found after the recently allocated block
if (current->next != NULL) {
current->next->previous = current;
}
previous->next = current;
return (void *)pos + BLOCK_LEN;
}
void mem_free(void *ptr) {
if (ptr == NULL) {
return;
}
// get start of block
struct Block *block = (struct Block *)((char *)ptr - BLOCK_LEN);
block->previous->next = block->next;
if (block->previous->next != NULL) {
block->next->previous = block->previous;
}
}
#endif
#endif // ALLOCATOR_H