Skip to content

Commit ffa0bc2

Browse files
buddy_krealloc, needed for arrays
1 parent 7ab71da commit ffa0bc2

3 files changed

Lines changed: 69 additions & 7 deletions

File tree

include/buddy_allocator.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ typedef struct buddy_allocator {
9494
* automatically on the first call to @ref buddy_malloc, or may be added
9595
* eagerly by growing manually.
9696
*/
97-
void buddy_init(buddy_allocator_t *alloc, int min_order, int max_order, int grow_order);
97+
void buddy_init(buddy_allocator_t* alloc, int min_order, int max_order, int grow_order);
9898

9999
/**
100100
* @brief Allocate a block of memory from the buddy allocator.
@@ -107,7 +107,7 @@ void buddy_init(buddy_allocator_t *alloc, int min_order, int max_order, int grow
107107
* automatically allocated of size (1 << grow_order). Returned blocks
108108
* are aligned to their block size (power of two).
109109
*/
110-
void *buddy_malloc(buddy_allocator_t *alloc, size_t size);
110+
void* buddy_malloc(buddy_allocator_t* alloc, size_t size);
111111

112112
/**
113113
* @brief Free a previously allocated block.
@@ -119,7 +119,7 @@ void *buddy_malloc(buddy_allocator_t *alloc, size_t size);
119119
* is also free, the two are merged into a larger block. The owning region
120120
* is identified via a back-pointer stored in the block header.
121121
*/
122-
void buddy_free(buddy_allocator_t *alloc, const void *ptr);
122+
void buddy_free(buddy_allocator_t* alloc, const void *ptr);
123123

124124
/**
125125
* @brief Destroy a buddy allocator and free all regions.
@@ -141,4 +141,17 @@ void buddy_destroy(buddy_allocator_t *alloc);
141141
* The returned string is allocated from the buddy allocator's
142142
* private heap and must be freed with @ref buddy_free.
143143
*/
144-
char* buddy_strdup(buddy_allocator_t *alloc, const char *s);
144+
char* buddy_strdup(buddy_allocator_t* alloc, const char *s);
145+
146+
/**
147+
* @brief Reallocate a block within a buddy allocator.
148+
*
149+
* Works like krealloc(): if ptr is NULL, behaves like buddy_malloc().
150+
* If size == 0, frees the block and returns NULL.
151+
*
152+
* @param alloc Buddy allocator to allocate from.
153+
* @param ptr Pointer previously returned by buddy_malloc().
154+
* @param size New desired size in bytes.
155+
* @return Pointer to resized block, or NULL on OOM.
156+
*/
157+
void* buddy_realloc(buddy_allocator_t* alloc, void *ptr, size_t size);

src/basic/array.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ bool basic_redim_int_array(const char* var, int64_t size, struct basic_ctx* ctx)
222222
if ((uint64_t)size == cur->itemcount) {
223223
return true;
224224
}
225-
cur->values = krealloc(cur->values, sizeof(int64_t) * size);
225+
cur->values = buddy_realloc(ctx->allocator, cur->values, sizeof(int64_t) * size);
226226
if ((uint64_t)size > cur->itemcount) {
227227
/* If array is being expanded, zero the new entries */
228228
for (int64_t i = cur->itemcount; i < size; ++i) {
@@ -255,7 +255,7 @@ bool basic_redim_string_array(const char* var, int64_t size, struct basic_ctx* c
255255
buddy_free(ctx->allocator, cur->values[x]);
256256
}
257257
}
258-
cur->values = krealloc(cur->values, sizeof(char*) * size);
258+
cur->values = buddy_realloc(ctx->allocator, cur->values, sizeof(char*) * size);
259259
if ((uint64_t)size > cur->itemcount) {
260260
/* If array is being expanded, zero the new entries */
261261
for (int64_t i = cur->itemcount; i < size; ++i) {
@@ -282,7 +282,7 @@ bool basic_redim_double_array(const char* var, int64_t size, struct basic_ctx* c
282282
if ((uint64_t)size == cur->itemcount) {
283283
return true;
284284
}
285-
cur->values = krealloc(cur->values, sizeof(double) * size);
285+
cur->values = buddy_realloc(ctx->allocator, cur->values, sizeof(double) * size);
286286
if ((uint64_t)size > cur->itemcount) {
287287
/* If array is being expanded, zero the new entries */
288288
for (int64_t i = cur->itemcount; i < size; ++i) {

src/buddy_allocator.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,52 @@ char *buddy_strdup(buddy_allocator_t *alloc, const char *s) {
212212
memcpy(copy, s, len);
213213
return copy;
214214
}
215+
216+
void *buddy_realloc(buddy_allocator_t *alloc, void *ptr, size_t size) {
217+
if (!ptr) {
218+
// realloc(NULL, size): malloc
219+
return buddy_malloc(alloc, size);
220+
}
221+
if (size == 0) {
222+
// realloc(ptr, 0): free
223+
buddy_free(alloc, ptr);
224+
return NULL;
225+
}
226+
227+
// Find old size from header
228+
buddy_header_t *header = (buddy_header_t *)ptr - 1;
229+
int old_order = header->order;
230+
size_t old_total = order_size(old_order);
231+
size_t old_payload = old_total - sizeof(buddy_header_t);
232+
233+
// Required order for new size
234+
int new_order = size_to_order(header->region, size + sizeof(buddy_header_t));
235+
236+
if (new_order == old_order) {
237+
// Same block size: no change
238+
return ptr;
239+
} else if (new_order < old_order) {
240+
// Shrinking: split block and free remainder
241+
header->order = new_order;
242+
// Carve off the extra as a buddy block
243+
int cur = old_order;
244+
// repeatedly split until the leftover is the right order
245+
while (cur > new_order) {
246+
cur--;
247+
buddy_block_t *buddy = (buddy_block_t *)((uint8_t *)header + order_size(cur));
248+
buddy->next = header->region->free_lists[cur];
249+
header->region->free_lists[cur] = buddy;
250+
}
251+
252+
return ptr;
253+
} else {
254+
// Growing: allocate + copy + free
255+
void *new_ptr = buddy_malloc(alloc, size);
256+
if (!new_ptr) {
257+
return NULL; // OOM
258+
}
259+
memcpy(new_ptr, ptr, old_payload);
260+
buddy_free(alloc, ptr);
261+
return new_ptr;
262+
}
263+
}

0 commit comments

Comments
 (0)