Derive-C
Loading...
Searching...
No Matches
template.h
Go to the documentation of this file.
1
2
4#if !defined(SKIP_INCLUDES)
5 #include "includes.h"
6#endif
7
10
11#if !defined BLOCK_SIZE
12 #if !defined DC_PLACEHOLDERS
13TEMPLATE_ERROR("No BLOCK_SIZE")
14 #endif
15 #define BLOCK_SIZE 64
16#endif
17
18#if !defined SLAB_SIZE
19 #if !defined DC_PLACEHOLDERS
20TEMPLATE_ERROR("No SLAB_SIZE")
21 #endif
22 #define SLAB_SIZE 4096
23#endif
24
25DC_STATIC_ASSERT(BLOCK_SIZE > 0, "Block size must be larger than zero");
26DC_STATIC_ASSERT(SLAB_SIZE >= BLOCK_SIZE, "Slab size must be at least block size");
28 "Block size must be at least pointer size for freelist");
29
30#define SLAB_VECTOR NS(NAME, slab_vector)
31
32#pragma push_macro("ALLOC")
33
34typedef struct {
35 void* ptr;
36} NS(NAME, slab_info);
37
38static NS(NAME, slab_info) NS(NAME, slab_info_clone)(NS(NAME, slab_info) const* self) {
39 return *self;
40}
41static void NS(NAME, slab_info_delete)(NS(NAME, slab_info) * /* self */) {}
42static void NS(NAME, slab_info_debug)(NS(NAME, slab_info) const* /* self */, dc_debug_fmt /* fmt */,
43 FILE* /* stream */) {}
44
45#define ITEM NS(NAME, slab_info) // [DERIVE-C] for template
46#define ITEM_CLONE NS(NAME, slab_info_clone) // [DERIVE-C] for template
47#define ITEM_DELETE NS(NAME, slab_info_delete) // [DERIVE-C] for template
48#define ITEM_DEBUG NS(NAME, slab_info_debug) // [DERIVE-C] for template
49#define INTERNAL_NAME SLAB_VECTOR // [DERIVE-C] for template
51
52#pragma pop_macro("ALLOC")
53
54typedef struct {
57 NS(ALLOC, ref) alloc_ref;
58 dc_gdb_marker derive_c_slaballoc;
59} SELF;
60
61DC_PUBLIC static SELF NS(SELF, new)(NS(ALLOC, ref) alloc_ref) {
62 return (SELF){
63 .slabs = NS(SLAB_VECTOR, new)(alloc_ref),
64 .free_list_head = NULL,
65 .alloc_ref = alloc_ref,
66 .derive_c_slaballoc = {},
67 };
68}
69
71 DC_ASSUME(self);
72
73 size_t blocks_per_slab = SLAB_SIZE / BLOCK_SIZE;
74 void* slab_ptr = NS(ALLOC, allocate_uninit)(self->alloc_ref, SLAB_SIZE);
75
76 NS(NAME, slab_info) info = {.ptr = slab_ptr};
77 NS(SLAB_VECTOR, push)(&self->slabs, info);
78
79 for (size_t i = 0; i < blocks_per_slab; i++) {
80 void* block_ptr = (char*)slab_ptr + (i * BLOCK_SIZE);
81 // Temporarily unpoison to write the freelist pointer
83 block_ptr, sizeof(void*));
84 *(void**)block_ptr = self->free_list_head;
85 self->free_list_head = block_ptr;
86 // Mark the entire block as inaccessible (NONE) - including the freelist pointer
89 }
90}
91
92DC_PUBLIC static void* NS(SELF, allocate_uninit)(SELF* self, size_t size) {
93 DC_ASSUME(self);
94 DC_ASSERT(size > 0, "Cannot allocate zero sized");
95
96 if (size > BLOCK_SIZE) {
97 return NS(ALLOC, allocate_uninit)(self->alloc_ref, size);
98 }
99
100 if (self->free_list_head == NULL) {
101 PRIV(NS(SELF, allocate_new_slab))(self);
102 }
103
104 void* block = self->free_list_head;
105
106 // Temporarily mark as READ_WRITE to read the freelist pointer
108 sizeof(void*));
109 void* next = *(void**)block;
110 self->free_list_head = next;
111
112 // Mark the allocated region as writable but uninitialized (WRITE)
114 // Mark any remaining space in the block as inaccessible
115 if (size < BLOCK_SIZE) {
117 (char*)block + size, BLOCK_SIZE - size);
118 }
119
120 return block;
121}
122
123DC_PUBLIC static void* NS(SELF, allocate_zeroed)(SELF* self, size_t size) {
124 DC_ASSUME(self);
125 DC_ASSERT(size > 0, "Cannot allocate zero sized");
126
127 void* ptr = NS(SELF, allocate_uninit)(self, size);
128 memset(ptr, 0, size);
130 return ptr;
131}
132
133DC_PUBLIC static void NS(SELF, deallocate)(SELF* self, void* ptr, size_t size) {
134 DC_ASSUME(self);
135 DC_ASSUME(ptr);
136 DC_ASSERT(size > 0, "Cannot deallocate zero sized");
137
138 if (size > BLOCK_SIZE) {
139 NS(ALLOC, deallocate)(self->alloc_ref, ptr, size);
140 return;
141 }
142
143 // Temporarily unpoison to write the freelist pointer
145 sizeof(void*));
146 *(void**)ptr = self->free_list_head;
147 self->free_list_head = ptr;
148
149 // Mark the entire block as inaccessible (NONE) - including the freelist pointer
151}
152
153DC_PUBLIC static void* NS(SELF, reallocate)(SELF* self, void* ptr, size_t old_size,
154 size_t new_size) {
155 DC_ASSUME(self);
156 DC_ASSUME(ptr);
157 DC_ASSERT(old_size > 0, "Cannot reallocate zero sized");
158 DC_ASSERT(new_size > 0, "Cannot allocate zero sized");
159
160 if (old_size > BLOCK_SIZE && new_size > BLOCK_SIZE) {
161 return NS(ALLOC, reallocate)(self->alloc_ref, ptr, old_size, new_size);
162 }
163
164 void* new_ptr = NS(SELF, allocate_uninit)(self, new_size);
165
166 size_t copy_size = (old_size < new_size) ? old_size : new_size;
167 memcpy(new_ptr, ptr, copy_size);
168
169 if (new_size <= old_size) {
171 new_ptr, new_size);
172 } else {
174 new_ptr, copy_size);
175 }
176
177 NS(SELF, deallocate)(self, ptr, old_size);
178
179 return new_ptr;
180}
181
182DC_PUBLIC static void NS(SELF, reset)(SELF* self) {
183 DC_ASSUME(self);
184
185 size_t num_slabs = NS(SLAB_VECTOR, size)(&self->slabs);
186 for (size_t i = 0; i < num_slabs; i++) {
187 NS(NAME, slab_info) const* info = NS(SLAB_VECTOR, read)(&self->slabs, i);
189 SLAB_SIZE);
190 NS(ALLOC, deallocate)(self->alloc_ref, info->ptr, SLAB_SIZE);
191 }
192
193 NS(SLAB_VECTOR, remove_at)(&self->slabs, 0, num_slabs);
194 self->free_list_head = NULL;
195}
196
197DC_PUBLIC static void NS(SELF, delete)(SELF* self) {
198 DC_ASSUME(self);
199
200 NS(SELF, reset)(self);
201 NS(SLAB_VECTOR, delete)(&self->slabs);
202}
203
204DC_PUBLIC static void NS(SELF, debug)(SELF const* self, dc_debug_fmt fmt, FILE* stream) {
205 DC_ASSUME(self);
206 fprintf(stream, DC_EXPAND_STRING(SELF) "@%p {\n", (void*)self);
207 fmt = dc_debug_fmt_scope_begin(fmt);
208
209 dc_debug_fmt_print(fmt, stream, "block_size: %zu,\n", (size_t)BLOCK_SIZE);
210 dc_debug_fmt_print(fmt, stream, "slab_size: %zu,\n", (size_t)SLAB_SIZE);
211 dc_debug_fmt_print(fmt, stream, "blocks_per_slab: %zu,\n", (size_t)(SLAB_SIZE / BLOCK_SIZE));
212 dc_debug_fmt_print(fmt, stream, "num_slabs: %zu,\n", NS(SLAB_VECTOR, size)(&self->slabs));
213
214 dc_debug_fmt_print(fmt, stream, "alloc: ");
215 NS(ALLOC, debug)(NS(NS(ALLOC, ref), deref)(self->alloc_ref), fmt, stream);
216 fprintf(stream, "\n");
217
218 fmt = dc_debug_fmt_scope_end(fmt);
219 dc_debug_fmt_print(fmt, stream, "}");
220}
221
222#undef SLAB_VECTOR
223#undef SLAB_SIZE
224#undef BLOCK_SIZE
225
227
229
static DC_PUBLIC void deallocate(SELF *self, void *ptr, size_t size)
Definition template.h:127
static DC_PUBLIC void debug(SELF const *self, dc_debug_fmt fmt, FILE *stream)
Definition template.h:212
static DC_PUBLIC void * allocate_zeroed(SELF *self, size_t size)
Definition template.h:117
static DC_PUBLIC void reset(SELF *self)
Definition template.h:186
#define BLOCK_SIZE
A chunked bump allocator that allocates memory in fixed-size blocks.
Definition template.h:15
static DC_PUBLIC void * allocate_uninit(SELF *self, size_t size)
Definition template.h:92
static DC_PUBLIC void * reallocate(SELF *self, void *ptr, size_t old_size, size_t new_size)
Definition template.h:137
static void slab_info_debug(slab_info const *, dc_debug_fmt, FILE *)
Definition template.h:42
#define SLAB_SIZE
Definition template.h:22
static void slab_info_delete(slab_info *)
Definition template.h:41
#define SLAB_VECTOR
Definition template.h:30
static slab_info slab_info_clone(slab_info const *self)
Definition template.h:38
static DC_INTERNAL void PRIV allocate_new_slab(SELF *self)
Definition template.h:70
#define ALLOC
Definition template.h:31
#define DC_TRAIT_ALLOC(SELF)
Definition trait.h:18
static DC_PUBLIC IV_PAIR next(ITER *iter)
Definition template.h:355
static DC_PUBLIC VALUE const * read(SELF const *self, INDEX index)
Definition template.h:199
static DC_PUBLIC size_t size(SELF const *self)
Definition template.h:252
static DC_PUBLIC void remove_at(SELF *self, size_t at, size_t count)
Definition template.h:211
static DC_PUBLIC ITEM * push(SELF *self, ITEM item)
Definition template.h:263
#define TEMPLATE_ERROR(...)
With the user provided name, even in nested templates.
Definition def.h:56
#define NAME
Supporting templates that internally invoke new templates.
Definition def.h:51
#define SELF
Definition def.h:52
static DC_PUBLIC void dc_debug_fmt_print(dc_debug_fmt fmt, FILE *stream, const char *format,...)
Definition fmt.h:32
static DC_PUBLIC dc_debug_fmt dc_debug_fmt_scope_end(dc_debug_fmt fmt)
Definition fmt.h:57
static DC_PUBLIC dc_debug_fmt dc_debug_fmt_scope_begin(dc_debug_fmt fmt)
Definition fmt.h:50
static DC_PUBLIC void dc_memory_tracker_set(dc_memory_tracker_level level, dc_memory_tracker_capability cap, const volatile void *addr, size_t size)
@ DC_MEMORY_TRACKER_LVL_ALLOC
@ DC_MEMORY_TRACKER_CAP_WRITE
@ DC_MEMORY_TRACKER_CAP_NONE
@ DC_MEMORY_TRACKER_CAP_READ_WRITE
#define DC_PUBLIC
Definition namespace.h:25
#define NS(pre, post)
Definition namespace.h:14
#define DC_EXPAND_STRING(NAME)
Definition namespace.h:6
#define PRIV(name)
Definition namespace.h:20
#define DC_INTERNAL
Definition namespace.h:30
#define DC_ASSERT(expr,...)
Definition panic.h:37
#define DC_STATIC_ASSERT
Definition panic.h:22
#define DC_ASSUME(expr,...)
Definition panic.h:57
#define DC_TRAIT_REFERENCABLE_BY_PTR(SELF)
Definition ref.h:19
void * free_list_head
Definition template.h:56
dc_gdb_marker derive_c_slaballoc
Definition template.h:58
ref alloc_ref
Definition template.h:49
SLAB_VECTOR slabs
Definition template.h:55
Debug format helpers for debug printin data structures.
Definition fmt.h:11
void * ptr
Definition template.h:35
static DC_PUBLIC FILE * stream(SELF *self)
Definition template.h:108