-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patharena.h
122 lines (101 loc) · 3.09 KB
/
arena.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
114
115
116
117
118
119
120
121
122
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
// This arena is laid out in memory
// with data immediately after each Arena Header
// ----------------------------------------------
// struct Arena {
// ....
// tail -----------|
// next -------| |
// } | |
// ...<data> | |
// | |
// struct Arena {<-| |
// .... |
// tail ---------| |
// next -------| | |
// } | | |
// ...<data> | | |
// | | |
// struct Arena { <----|
// ^ ....
// |--- tail
// next = NULL
// }
// ...<data>
typedef struct Arena {
uint64_t current;
uint64_t capacity;
uint64_t total_size;
uint64_t total_capacity;
struct Arena *tail;
struct Arena *next;
} Arena;
// We're going to grab and align to at least a whole page
// No sense being super stingy, we are the allocator after all
#define PAGE_SIZE 4096
#define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
#define PAGE_ROUND_UP(x) (PAGE_SIZE * DIV_ROUND_UP((x), PAGE_SIZE))
Arena *arena_init(void) {
uint64_t chunk_size = PAGE_ROUND_UP(sizeof(Arena) + PAGE_SIZE);
Arena *a = (Arena *)malloc(chunk_size);
a->capacity = chunk_size - sizeof(Arena);
a->total_capacity = a->capacity;
a->current = 0;
a->total_size = 0;
// Being a little tricky here.
// If your tail points at yourself, when you get your tail's next,
// it's also your next, which means the append logic is simpler
a->next = NULL;
a->tail = a;
return a;
}
void arena_grow(Arena *arena_head, uint64_t size) {
uint64_t chunk_size = PAGE_ROUND_UP(sizeof(Arena) + size);
Arena *new_arena = (Arena *)malloc(chunk_size);
new_arena->capacity = chunk_size - sizeof(Arena);
new_arena->current = 0;
new_arena->next = NULL;
arena_head->total_capacity += new_arena->capacity;
// Time to slap this new arena on the tail, and patch up our previous tail
Arena *tmp = arena_head->tail;
arena_head->tail = new_arena;
tmp->next = new_arena;
}
void *arena_alloc(Arena *arena_head, uint64_t size) {
Arena *cur_arena = arena_head->tail;
uint64_t aligned_size = sizeof(uint64_t) * DIV_ROUND_UP(size, sizeof(uint64_t));
if ((cur_arena->current + aligned_size) > cur_arena->capacity) {
arena_grow(arena_head, aligned_size);
cur_arena = arena_head->tail;
}
char *cur_arena_bytes = (char *)cur_arena;
void *new_buffer = (void *)((cur_arena_bytes + sizeof(Arena)) + cur_arena->current);
cur_arena->current += aligned_size;
arena_head->total_size += aligned_size;
return new_buffer;
}
void *arena_realloc(Arena *arena_head, void *buffer, uint64_t old_size, uint64_t new_size) {
void *new_buffer = arena_alloc(arena_head, new_size);
memcpy(new_buffer, buffer, old_size);
return new_buffer;
}
void arena_clear(Arena *arena_head) {
Arena *cur = arena_head->next;
while (cur != NULL) {
Arena *tmp = cur;
cur = cur->next;
arena_head->total_capacity -= tmp->capacity;
free(tmp);
}
arena_head->current = 0;
arena_head->tail = arena_head;
arena_head->next = NULL;
arena_head->total_size = 0;
}
void arena_free(Arena *arena_head) {
arena_clear(arena_head);
free(arena_head);
}