libclod
C library for interacting with NBTs, region files, LOD data and other things.
Loading...
Searching...
No Matches
allocator.h
1#ifndef LIBCLOD_ALLOCATOR_H
2#define LIBCLOD_ALLOCATOR_H
3
4#include "clod_config.h"
5#include <clod/memory.h>
6#include <clod/hash.h>
7
8#include "clod/debug.h"
9
10#define BLOCK_SIZE 256
11#define TREE_ORDER 31
12#define TREE_MAX_DEPTH 5
13
14struct node;
15struct branch;
16
18
19typedef uint32_t block_ptr;
20
21#define IS_BLOCK_ALIGNED(n) ((uintptr_t)(n) % BLOCK_SIZE == 0)
22#define BLOCK_PTR_NULL ((block_ptr)0)
23
24#define TYPE_NODE 1
25#define TYPE_SPAN 2
26#define TYPE_SLAB 3
27#define TYPE_BRANCH 4
28
29#define SLAB_1 0
30#define SLAB_2 1
31#define SLAB_4 2
32#define SLAB_8 3
33#define SLAB_12_4 4
34#define SLAB_16 5
35#define SLAB_24_8 6
36#define SLAB_32 7
37#define SLAB_48_16 8
38#define SLAB_64 9
39#define SLAB_96_32 10
40#define SLAB_128 11
41#define SLAB_192_64 12
42#define SLAB_CLASS_COUNT 13
43
44static block_ptr node_ptr(clod_allocator *head, struct node *node) {
45 #if CLOD_MEMORY_DEBUG
46 if ((char*)node < (char*)head) return BLOCK_PTR_NULL;
47 if (!IS_BLOCK_ALIGNED(head) || !IS_BLOCK_ALIGNED(node)) return BLOCK_PTR_NULL;
48 #endif
49 return (block_ptr)((char*)node - (char*)head) + TYPE_NODE;
50}
51static block_ptr span_ptr(clod_allocator *head, char *span) {
52 #if CLOD_MEMORY_DEBUG
53 if ((char*)span < (char*)head) return BLOCK_PTR_NULL;
54 if (!IS_BLOCK_ALIGNED(head) || !IS_BLOCK_ALIGNED(span)) return BLOCK_PTR_NULL;
55 #endif
56 return (block_ptr)((char*)span - (char*)head) + TYPE_SPAN;
57}
58static block_ptr slab_ptr(clod_allocator *head, char *slab, const int slab_class) {
59 #if CLOD_MEMORY_DEBUG
60 if (1 > slab_class || slab_class > 13) return BLOCK_PTR_NULL;
61 if ((char*)slab < (char*)head) return BLOCK_PTR_NULL;
62 if (!IS_BLOCK_ALIGNED(head) || !IS_BLOCK_ALIGNED(slab)) return BLOCK_PTR_NULL;
63 #endif
64 return (block_ptr)((char*)slab - (char*)head + TYPE_SLAB + (slab_class << 4));
65}
66static block_ptr branch_ptr(clod_allocator *head, struct node *node, const int index) {
67 #if CLOD_MEMORY_DEBUG
68 if ((char*)node < (char*)head) return BLOCK_PTR_NULL;
69 if (!IS_BLOCK_ALIGNED(node) || !IS_BLOCK_ALIGNED(head)) return BLOCK_PTR_NULL;
70 if (0 > index || index >= TREE_ORDER) return BLOCK_PTR_NULL;
71 #endif
72 return (block_ptr)((char*)node - (char*)head) + TYPE_BRANCH + ((block_ptr)index << 3);
73}
74
75static int ptr_type(const block_ptr bptr) {
76 if ((bptr & 0xFF) == TYPE_NODE) return TYPE_NODE;
77 if ((bptr & 0xFF) == TYPE_SPAN) return TYPE_SPAN;
78 if ((bptr & 0x0F) == TYPE_SLAB) return TYPE_SLAB;
79 if ((bptr & 0x07) == TYPE_BRANCH) return TYPE_BRANCH;
80 return 0;
81}
82static uint32_t block_offset(const block_ptr bptr) { return bptr & 0xFFFFFF00; }
83
84static struct node *node_get(clod_allocator *head, const block_ptr bptr) {
85 if ((bptr & 0xFF) != TYPE_NODE && (bptr & 0x7) != TYPE_BRANCH) return nullptr;
86 return (struct node*)((char*)head + block_offset(bptr));
87}
88static char *span_get(clod_allocator *head, const block_ptr bptr) {
89 if ((bptr & 0xFF) != TYPE_SPAN) return nullptr;
90 return (char*)head + block_offset(bptr);
91}
92static char *slab_get(clod_allocator *head, const block_ptr bptr) {
93 if ((bptr & 0xF) != TYPE_SLAB) return nullptr;
94 return (char*)head + block_offset(bptr);
95}
96static int slab_type_get(const block_ptr bptr) {
97 if ((bptr & 0xF) != TYPE_SLAB) return 0;
98 int type = (bptr & 0xF0) >> 4;
99 #if CLOD_MEMORY_DEBUG
100 if (1 > type || type > 13) return 0;
101 #endif
102 return type;
103}
104static int branch_index_get(const block_ptr bptr) {
105 if ((bptr & 0x7) != TYPE_BRANCH) return 0;
106 return (bptr & 0xF8) >> 3;
107}
108
109struct branch {
111 block_ptr ptr;
112
127 uint32_t data;
128};
129
132struct node {
134 uint32_t checksum;
135
136 alignas(8) struct branch branches[TREE_ORDER];
137};
138
139static_assert(sizeof(struct node) <= 256);
140
141typedef struct branch **path;
142#define PATH_NEW (&(struct branch*[TREE_MAX_DEPTH + 1]){nullptr}[1])
143static void path_push(path *path, struct branch *branch) { *++*path = branch; }
144static struct branch *path_pop(path *path) { return **path == nullptr ? nullptr : *--*path; }
145static struct branch *path_get(const path path, const int parent) {
146 for (int i = 0; i < parent; i++)
147 if (path[-i] == nullptr) return nullptr;
148 return path[-parent];
149}
150
151bool tree_next(clod_allocator *head, path *path);
152bool tree_prev(clod_allocator *head, path *path);
153static bool tree_iter(clod_allocator *head, struct node *root_node, path *path) {
154 if (path_get(*path, 0) == nullptr) {
155 path_push(path, root_node->branches);
156 }
157
158 return tree_next(head, path);
159}
160
161void tree_search(clod_allocator *head, struct node *root_node, block_ptr key, path *path);
162struct branch *tree_add(clod_allocator *head, struct node *root_node, struct branch branch, path *path);
163void free_tree_add(clod_allocator *head, struct node *root_node, struct branch branch);
164void used_tree_add(clod_allocator *head, struct node *root_node, struct branch branch);
165
167
168struct clod_allocator {
170 uint32_t checksum;
171
173 uint32_t size;
174
178
186 block_ptr last_slab_branch[SLAB_CLASS_COUNT];
187
188 alignas(BLOCK_SIZE) struct node free;
189 alignas(BLOCK_SIZE) struct node used;
190};
191
193
194#define METADATA_CRC_INIT UINT32_C(0xAE11F296)
195static void crc_check(void *block) {
196 #if CLOD_MEMORY_DEBUG
197 uint32_t crc = clod_crc32_add(METADATA_CRC_INIT, (char*)block + sizeof(uint32_t), BLOCK_SIZE - sizeof(uint32_t));
198 crc = clod_crc32_add(crc, &block, sizeof(block));
199 #else
200 uint32_t crc = (uint32_t)block;
201 #endif
202
203 if (*(uint32_t*)block != crc) {
204 fatal_old(CLOD_MEMORY_DEBUG, "Allocator metadata is corrupted.");
205 }
206}
207static void crc_update(void *block) {
208 #if CLOD_MEMORY_DEBUG
209 uint32_t crc = clod_crc32_add(METADATA_CRC_INIT, (char*)block + sizeof(uint32_t), BLOCK_SIZE - sizeof(uint32_t));
210 crc = clod_crc32_add(crc, &block, sizeof(block));
211 #else
212 uint32_t crc = (uint32_t)block;
213 #endif
214
215 *(uint32_t*)block = crc;
216}
217
218#endif
uint32_t clod_crc32_add(uint32_t crc, const void *data, size_t data_len)
Memory allocation methods.
uint32_t data
Definition allocator.h:127
block_ptr ptr
Either the next node in the tree or the block value.
Definition allocator.h:111
Allocator.
Definition memory.h:16
uint32_t checksum
Checksum.
Definition allocator.h:170
clod_allocator * next
Definition allocator.h:177
block_ptr last_slab_branch[13]
Definition allocator.h:186
void(* free)(void *ptr, void *self)
Definition memory.h:33
uint32_t size
Size of backing memory.
Definition allocator.h:173
uint32_t checksum
Checksum.
Definition allocator.h:134