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 65536
16#endif
17
18DC_STATIC_ASSERT(BLOCK_SIZE > 0, "Block size must be larger than zero");
19
20#define BLOCK_VECTOR NS(NAME, block_vector)
21
22#pragma push_macro("ALLOC")
23
24typedef struct {
25 void* ptr;
26 size_t num_blocks;
28
30 return *self;
31}
32static void NS(NAME, block_info_delete)(NS(NAME, block_info) * /* self */) {}
33static void NS(NAME, block_info_debug)(NS(NAME, block_info) const* /* self */,
34 dc_debug_fmt /* fmt */, FILE* /* stream */) {}
35
36#define ITEM NS(NAME, block_info) // [DERIVE-C] for template
37#define ITEM_CLONE NS(NAME, block_info_clone) // [DERIVE-C] for template
38#define ITEM_DELETE NS(NAME, block_info_delete) // [DERIVE-C] for template
39#define ITEM_DEBUG NS(NAME, block_info_debug) // [DERIVE-C] for template
40#define INTERNAL_NAME BLOCK_VECTOR // [DERIVE-C] for template
42
43#pragma pop_macro("ALLOC")
44
52
53DC_PUBLIC static SELF NS(SELF, new)(NS(ALLOC, ref) alloc_ref) {
54 return (SELF){
55 .blocks = NS(BLOCK_VECTOR, new)(alloc_ref),
56 .current_block_idx = 0,
57 .current_block_offset = 0,
58 .alloc_ref = alloc_ref,
59 .derive_c_chunkedbumpalloc = {},
60 };
61}
62
63DC_INTERNAL static void* PRIV(NS(SELF, allocate_new_blocks))(SELF* self, size_t size) {
64 DC_ASSUME(self);
65 DC_ASSERT(size > 0);
66
67 size_t num_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
68 size_t total_size = num_blocks * BLOCK_SIZE;
69
70 void* base_ptr = NS(ALLOC, allocate_uninit)(self->alloc_ref, total_size);
71
72 for (size_t i = 0; i < num_blocks; i++) {
73 void* block_ptr = (char*)base_ptr + (i * BLOCK_SIZE);
74 size_t block_count = (i == 0) ? num_blocks : 0;
75
76 NS(NAME, block_info) info = {.ptr = block_ptr, .num_blocks = block_count};
77 NS(BLOCK_VECTOR, push)(&self->blocks, info);
78 }
79
80 self->current_block_idx = NS(BLOCK_VECTOR, size)(&self->blocks) - 1;
81 self->current_block_offset = size % BLOCK_SIZE;
82
83 if (self->current_block_offset == 0 && size > 0) {
84 self->current_block_offset = BLOCK_SIZE;
85 }
86
88
89 return base_ptr;
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 size_t num_blocks = NS(BLOCK_VECTOR, size)(&self->blocks);
97 if (num_blocks > 0) {
98 size_t remaining = BLOCK_SIZE - self->current_block_offset;
99
100 if (remaining >= size) {
102 const* current_info = NS(BLOCK_VECTOR, read)(&self->blocks, self->current_block_idx);
103 void* allocation_ptr = (char*)current_info->ptr + self->current_block_offset;
104
105 self->current_block_offset += size;
106
108 allocation_ptr, size);
109
110 return allocation_ptr;
111 }
112 }
113
114 return PRIV(NS(SELF, allocate_new_blocks))(self, size);
115}
116
117DC_PUBLIC static void* NS(SELF, allocate_zeroed)(SELF* self, size_t size) {
118 DC_ASSUME(self);
119 DC_ASSERT(size > 0, "Cannot allocate zero sized");
120
121 void* ptr = NS(SELF, allocate_uninit)(self, size);
122 memset(ptr, 0, size);
124 return ptr;
125}
126
127DC_PUBLIC static void NS(SELF, deallocate)(SELF* self, void* ptr, size_t size) {
128 DC_ASSUME(self);
129 DC_ASSUME(ptr); // deallocate requires non-null pointer
130 DC_ASSERT(size > 0, "Cannot deallocate zero sized");
131
132 // Bump allocators don't free individual items, but we poison the memory
133 // to catch use-after-free bugs
135}
136
137DC_PUBLIC static void* NS(SELF, reallocate)(SELF* self, void* ptr, size_t old_size,
138 size_t new_size) {
139 DC_ASSUME(self);
140 DC_ASSUME(ptr);
141 DC_ASSERT(old_size > 0, "Cannot reallocate zero sized");
142 DC_ASSERT(new_size > 0, "Cannot allocate zero sized");
143
144 // Check if this is the last allocation and can be extended in place
145 size_t num_blocks = NS(BLOCK_VECTOR, size)(&self->blocks);
146 if (num_blocks > 0 && new_size > old_size) {
148 const* current_info = NS(BLOCK_VECTOR, read)(&self->blocks, self->current_block_idx);
149 char* expected_last_alloc =
150 (char*)current_info->ptr + self->current_block_offset - old_size;
151
152 if ((char*)ptr == expected_last_alloc) {
153 // This is the last allocation - check if we can extend in place
154 size_t extension = new_size - old_size;
155 size_t remaining = BLOCK_SIZE - self->current_block_offset;
156
157 if (extension <= remaining) {
158 // Can extend in place!
160 (char*)ptr + old_size, extension);
161 self->current_block_offset += extension;
162 return ptr;
163 }
164 }
165 }
166
167 // Can't extend in place, allocate new memory and copy
168 void* new_ptr = NS(SELF, allocate_uninit)(self, new_size);
169
170 size_t copy_size = (old_size < new_size) ? old_size : new_size;
171 memcpy(new_ptr, ptr, copy_size);
172
173 if (new_size <= old_size) {
175 new_ptr, new_size);
176 } else {
178 new_ptr, copy_size);
179 }
180
182
183 return new_ptr;
184}
185
186DC_PUBLIC static void NS(SELF, reset)(SELF* self) {
187 DC_ASSUME(self);
188
189 size_t num_blocks = NS(BLOCK_VECTOR, size)(&self->blocks);
190 for (size_t i = 0; i < num_blocks; i++) {
191 NS(NAME, block_info) const* info = NS(BLOCK_VECTOR, read)(&self->blocks, i);
192 if (info->num_blocks > 0) {
193 size_t total_size = info->num_blocks * BLOCK_SIZE;
195 info->ptr, total_size);
196 NS(ALLOC, deallocate)(self->alloc_ref, info->ptr, total_size);
197 }
198 }
199
200 NS(BLOCK_VECTOR, remove_at)(&self->blocks, 0, num_blocks);
201 self->current_block_idx = 0;
202 self->current_block_offset = 0;
203}
204
205DC_PUBLIC static void NS(SELF, delete)(SELF* self) {
206 DC_ASSUME(self);
207
208 NS(SELF, reset)(self);
209 NS(BLOCK_VECTOR, delete)(&self->blocks);
210}
211
212DC_PUBLIC static void NS(SELF, debug)(SELF const* self, dc_debug_fmt fmt, FILE* stream) {
213 DC_ASSUME(self);
214 fprintf(stream, DC_EXPAND_STRING(SELF) "@%p {\n", (void*)self);
215 fmt = dc_debug_fmt_scope_begin(fmt);
216
217 dc_debug_fmt_print(fmt, stream, "block_size: %zu,\n", (size_t)BLOCK_SIZE);
218 dc_debug_fmt_print(fmt, stream, "num_blocks: %zu,\n", NS(BLOCK_VECTOR, size)(&self->blocks));
219 dc_debug_fmt_print(fmt, stream, "current_block_idx: %zu,\n", self->current_block_idx);
220 dc_debug_fmt_print(fmt, stream, "current_block_offset: %zu,\n", self->current_block_offset);
221
222 size_t total_allocated = 0;
223 size_t num_blocks = NS(BLOCK_VECTOR, size)(&self->blocks);
224 for (size_t i = 0; i < num_blocks; i++) {
225 NS(NAME, block_info) const* info = NS(BLOCK_VECTOR, read)(&self->blocks, i);
226 if (info->num_blocks > 0) {
227 total_allocated += info->num_blocks * BLOCK_SIZE;
228 }
229 }
230 dc_debug_fmt_print(fmt, stream, "total_allocated: %zu,\n", total_allocated);
231
232 dc_debug_fmt_print(fmt, stream, "alloc: ");
233 NS(ALLOC, debug)(NS(NS(ALLOC, ref), deref)(self->alloc_ref), fmt, stream);
234 fprintf(stream, "\n");
235
236 fmt = dc_debug_fmt_scope_end(fmt);
237 dc_debug_fmt_print(fmt, stream, "}");
238}
239
240#undef BLOCK_VECTOR
241#undef BLOCK_SIZE
242
244
246
#define BLOCK_VECTOR
Definition template.h:20
static void block_info_debug(block_info const *, dc_debug_fmt, FILE *)
Definition template.h:33
static DC_PUBLIC void deallocate(SELF *self, void *ptr, size_t size)
Definition template.h:127
static DC_INTERNAL void *PRIV allocate_new_blocks(SELF *self, size_t size)
Definition template.h:63
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 void block_info_delete(block_info *)
Definition template.h:32
static DC_PUBLIC void reset(SELF *self)
Definition template.h:186
static block_info block_info_clone(block_info const *self)
Definition template.h:29
#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
#define ALLOC
Definition template.h:31
#define DC_TRAIT_ALLOC(SELF)
Definition trait.h:18
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
BLOCK_VECTOR blocks
Definition template.h:46
size_t current_block_idx
Definition template.h:47
dc_gdb_marker derive_c_chunkedbumpalloc
Definition template.h:50
size_t current_block_offset
Definition template.h:48
ref alloc_ref
Definition template.h:49
void * ptr
Definition template.h:25
size_t num_blocks
Definition template.h:26
Debug format helpers for debug printin data structures.
Definition fmt.h:11
static DC_PUBLIC FILE * stream(SELF *self)
Definition template.h:108