Skip to content

Commit 9575ef2

Browse files
committed
Add arena helper functions and improve block insertion
- Add `arena_memdup` to duplicate a block of memory into the arena. - Add `arena_strdup` to copy null-terminated strings into the arena. - Add `arena_realloc` to resize arena-managed allocations. - Refactor `arena_alloc` to insert new blocks at the head of the arena list.
1 parent 7163605 commit 9575ef2

File tree

1 file changed

+94
-35
lines changed

1 file changed

+94
-35
lines changed

src/globals.c

Lines changed: 94 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,14 @@ arena_block_t *arena_block_create(int capacity)
9999
arena_block_t *block = malloc(sizeof(arena_block_t));
100100

101101
if (!block) {
102-
printf("Failed to allocate memory for arena block\n");
102+
printf("Failed to allocate memory for arena block structure\n");
103103
exit(1);
104104
}
105105

106-
block->memory = calloc(capacity, sizeof(char));
106+
block->memory = malloc(capacity * sizeof(char));
107107

108108
if (!block->memory) {
109-
printf("Failed to allocate memory for arena block\n");
109+
printf("Failed to allocate memory for arena block buffer\n");
110110
free(block);
111111
exit(1);
112112
}
@@ -117,6 +117,16 @@ arena_block_t *arena_block_create(int capacity)
117117
return block;
118118
}
119119

120+
/**
121+
* arena_block_free() - Free a single arena block and its memory buffer.
122+
* @block: Pointer to the arena_block_t to free. Must not be NULL.
123+
*/
124+
void arena_block_free(arena_block_t *block)
125+
{
126+
free(block->memory);
127+
free(block);
128+
}
129+
120130
/**
121131
* arena_init() - Initializes the given arena with initial capacity.
122132
* @initial_capacity: The initial capacity of the arena. Must be positive.
@@ -126,6 +136,10 @@ arena_block_t *arena_block_create(int capacity)
126136
arena_t *arena_init(int initial_capacity)
127137
{
128138
arena_t *arena = malloc(sizeof(arena_t));
139+
if (!arena) {
140+
printf("Failed to allocate memory for arena structure\n");
141+
exit(1);
142+
}
129143
arena->head = arena_block_create(initial_capacity);
130144
return arena;
131145
}
@@ -141,47 +155,93 @@ arena_t *arena_init(int initial_capacity)
141155
*/
142156
void *arena_alloc(arena_t *arena, int size)
143157
{
144-
char *ptr;
145-
arena_block_t *block = arena->head;
146-
147-
while (block) {
148-
if (block->offset + size <= block->capacity) {
149-
ptr = block->memory + block->offset;
150-
block->offset += size;
151-
return ptr;
152-
}
153-
if (!block->next)
154-
break;
155-
block = block->next;
158+
if (size <= 0) {
159+
printf("arena_alloc: size must be positive");
160+
exit(1);
156161
}
157162

158-
/* If no space is available, create a new block
159-
* Allocate at least 256 KiB or the requested size
160-
*/
161-
int new_capacity = size > DEFAULT_ARENA_SIZE ? size : DEFAULT_ARENA_SIZE;
162-
arena_block_t *new_block = arena_block_create(new_capacity);
163+
/* Align to 4 bytes */
164+
size = (size + 4 - 1) & ~(4 - 1);
163165

164-
if (!new_block)
165-
return NULL;
166+
if (!arena->head || arena->head->offset + size > arena->head->capacity) {
167+
/* Need a new block: choose capacity = max(DEFAULT_ARENA_SIZE, size) */
168+
int new_capacity =
169+
(size > DEFAULT_ARENA_SIZE ? size : DEFAULT_ARENA_SIZE);
170+
arena_block_t *new_block = arena_block_create(new_capacity);
171+
new_block->next = arena->head;
172+
arena->head = new_block;
173+
}
166174

167-
block->next = new_block;
168-
ptr = new_block->memory + new_block->offset;
169-
new_block->offset += size;
175+
void *ptr = arena->head->memory + arena->head->offset;
176+
arena->head->offset += size;
170177
return ptr;
171178
}
172179

173180
/**
174-
* arena_reset() - Resets the given arena by resetting all blocks' offset to 0.
175-
* @arena: The arena to reset. Must not be NULL.
181+
* arena_realloc() - Reallocate a previously allocated region within the arena
182+
* to a different size.
183+
*
184+
* If existing region is the most recent allocation in the current block
185+
* and there is enough space to expand in place, simply extend the offset.
186+
* Otherwise, allocate a new region of the requested size and copy the old data.
187+
*
188+
* @arena: Pointer to the arena. Must not be NULL.
189+
* @oldptr: Pointer to the previously allocated memory in the arena.
190+
* @oldsz: Original size (in bytes) of that allocation.
191+
* @newsz: New desired size (in bytes).
192+
*
193+
* Return: Pointer to the reallocated (resized) memory region.
194+
*/
195+
void *arena_realloc(arena_t *arena, char *oldptr, int oldsz, int newsz)
196+
{
197+
/* No need to grow; existing pointer is sufficient. */
198+
if (newsz <= oldsz)
199+
return oldptr;
200+
201+
/* Check if oldptr is at the end of the current block's allocations */
202+
if (oldptr + oldsz == arena->head->memory + arena->head->offset &&
203+
arena->head->offset + (newsz - oldsz) <= arena->head->capacity) {
204+
/* Grow in place */
205+
arena->head->offset += (newsz - oldsz);
206+
return oldptr;
207+
}
208+
209+
/* Otherwise, allocate new region and copy */
210+
void *newptr = arena_alloc(arena, newsz);
211+
memcpy(newptr, oldptr, oldsz);
212+
return newptr;
213+
}
214+
215+
/**
216+
* arena_strdup() - Duplicate a NUL-terminated string into the arena.
217+
*
218+
* @arena: a Pointer to the arena. Must not be NULL.
219+
* @str: NUL-terminated input string to duplicate. Must not be NULL.
220+
*
221+
* Return: Pointer to the duplicated string stored in the arena.
176222
*/
177-
void arena_reset(arena_t *arena)
223+
char *arena_strdup(arena_t *arena, char *str)
178224
{
179-
arena_block_t *block = arena->head;
225+
int n = strlen(str);
226+
char *dup = arena_alloc(arena, n + 1);
227+
memcpy(dup, str, n);
228+
dup[n] = '\0';
229+
return dup;
230+
}
180231

181-
while (block) {
182-
block->offset = 0;
183-
block = block->next;
184-
}
232+
/**
233+
* arena_memdup() - Duplicate a block of memory into the arena.
234+
* Allocates size bytes within the arena and copies data from the input pointer.
235+
*
236+
* @arena: a Pointer to the arena. Must not be NULL.
237+
* @data: data Pointer to the source memory. Must not be NULL.
238+
* @size: size Number of bytes to copy. Must be non-negative.
239+
*
240+
* Return: The pointer to the duplicated memory stored in the arena.
241+
*/
242+
void *arena_memdup(arena_t *arena, void *data, int size)
243+
{
244+
return memcpy(arena_alloc(arena, size), data, size);
185245
}
186246

187247
/**
@@ -194,8 +254,7 @@ void arena_free(arena_t *arena)
194254

195255
while (block) {
196256
next = block->next;
197-
free(block->memory);
198-
free(block);
257+
arena_block_free(block);
199258
block = next;
200259
}
201260

0 commit comments

Comments
 (0)