Skip to content

Commit 8485f58

Browse files
committed
Add arena helper functions and improve block insertion
- Add `arena_calloc` to allocate zero‑initialization memory - 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 8485f58

File tree

1 file changed

+123
-35
lines changed

1 file changed

+123
-35
lines changed

src/globals.c

Lines changed: 123 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ int elf_data_start;
8989

9090
/**
9191
* arena_block_create() - Creates a new arena block with given capacity.
92-
* The created arena block is guaranteed to be zero-initialized.
9392
* @capacity: The capacity of the arena block. Must be positive.
9493
*
9594
* Return: The pointer of created arena block. NULL if failed to allocate.
@@ -99,14 +98,14 @@ arena_block_t *arena_block_create(int capacity)
9998
arena_block_t *block = malloc(sizeof(arena_block_t));
10099

101100
if (!block) {
102-
printf("Failed to allocate memory for arena block\n");
101+
printf("Failed to allocate memory for arena block structure\n");
103102
exit(1);
104103
}
105104

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

108107
if (!block->memory) {
109-
printf("Failed to allocate memory for arena block\n");
108+
printf("Failed to allocate memory for arena block buffer\n");
110109
free(block);
111110
exit(1);
112111
}
@@ -117,6 +116,16 @@ arena_block_t *arena_block_create(int capacity)
117116
return block;
118117
}
119118

119+
/**
120+
* arena_block_free() - Free a single arena block and its memory buffer.
121+
* @block: Pointer to the arena_block_t to free. Must not be NULL.
122+
*/
123+
void arena_block_free(arena_block_t *block)
124+
{
125+
free(block->memory);
126+
free(block);
127+
}
128+
120129
/**
121130
* arena_init() - Initializes the given arena with initial capacity.
122131
* @initial_capacity: The initial capacity of the arena. Must be positive.
@@ -126,6 +135,10 @@ arena_block_t *arena_block_create(int capacity)
126135
arena_t *arena_init(int initial_capacity)
127136
{
128137
arena_t *arena = malloc(sizeof(arena_t));
138+
if (!arena) {
139+
printf("Failed to allocate memory for arena structure\n");
140+
exit(1);
141+
}
129142
arena->head = arena_block_create(initial_capacity);
130143
return arena;
131144
}
@@ -141,47 +154,123 @@ arena_t *arena_init(int initial_capacity)
141154
*/
142155
void *arena_alloc(arena_t *arena, int size)
143156
{
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;
157+
if (size <= 0) {
158+
printf("arena_alloc: size must be positive");
159+
exit(1);
156160
}
157161

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);
162+
/* Align to PTR_SIZE bytes */
163+
size = (size + PTR_SIZE - 1) & ~(PTR_SIZE - 1);
163164

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

167-
block->next = new_block;
168-
ptr = new_block->memory + new_block->offset;
169-
new_block->offset += size;
174+
void *ptr = arena->head->memory + arena->head->offset;
175+
arena->head->offset += size;
170176
return ptr;
171177
}
172178

173179
/**
174-
* arena_reset() - Resets the given arena by resetting all blocks' offset to 0.
175-
* @arena: The arena to reset. Must not be NULL.
180+
* arena_calloc() - arena_alloc() plus explicit zero‑initialization.
181+
* @arena: The arena to allocate memory from. Must not be NULL.
182+
* @n: Number of elements.
183+
* @size: Size of each element in bytes.
184+
*
185+
* Internally calls arena_alloc(n * size) and then fills the entire region
186+
* with zero bytes.
187+
*
188+
* Return: Pointer to zero-initialized memory.
176189
*/
177-
void arena_reset(arena_t *arena)
190+
void *arena_calloc(arena_t *arena, int n, int size)
178191
{
179-
arena_block_t *block = arena->head;
192+
int total = n * size;
193+
void *ptr = arena_alloc(arena, total);
180194

181-
while (block) {
182-
block->offset = 0;
183-
block = block->next;
195+
int *w_ptr = ptr;
196+
int w_count = total >> 2;
197+
int b_index = w_count << 2;
198+
199+
for (int i = 0; i < w_count; ++i)
200+
w_ptr[i] = 0;
201+
202+
char *b_ptr = ptr;
203+
while (b_index < total)
204+
b_ptr[b_index++] = 0;
205+
206+
return ptr;
207+
}
208+
209+
/**
210+
* arena_realloc() - Reallocate a previously allocated region within the arena
211+
* to a different size.
212+
*
213+
* If existing region is the most recent allocation in the current block
214+
* and there is enough space to expand in place, simply extend the offset.
215+
* Otherwise, allocate a new region of the requested size and copy the old data.
216+
*
217+
* @arena: Pointer to the arena. Must not be NULL.
218+
* @oldptr: Pointer to the previously allocated memory in the arena.
219+
* @oldsz: Original size (in bytes) of that allocation.
220+
* @newsz: New desired size (in bytes).
221+
*
222+
* Return: Pointer to the reallocated (resized) memory region.
223+
*/
224+
void *arena_realloc(arena_t *arena, char *oldptr, int oldsz, int newsz)
225+
{
226+
/* No need to grow; existing pointer is sufficient. */
227+
if (newsz <= oldsz)
228+
return oldptr;
229+
230+
/* Check if oldptr is at the end of the current block's allocations */
231+
if (oldptr + oldsz == arena->head->memory + arena->head->offset &&
232+
arena->head->offset + (newsz - oldsz) <= arena->head->capacity) {
233+
/* Grow in place */
234+
arena->head->offset += (newsz - oldsz);
235+
return oldptr;
184236
}
237+
238+
/* Otherwise, allocate new region and copy */
239+
void *newptr = arena_alloc(arena, newsz);
240+
memcpy(newptr, oldptr, oldsz);
241+
return newptr;
242+
}
243+
244+
/**
245+
* arena_strdup() - Duplicate a NULL-terminated string into the arena.
246+
*
247+
* @arena: a Pointer to the arena. Must not be NULL.
248+
* @str: NULL-terminated input string to duplicate. Must not be NULL.
249+
*
250+
* Return: Pointer to the duplicated string stored in the arena.
251+
*/
252+
char *arena_strdup(arena_t *arena, char *str)
253+
{
254+
int n = strlen(str);
255+
char *dup = arena_alloc(arena, n + 1);
256+
memcpy(dup, str, n);
257+
dup[n] = '\0';
258+
return dup;
259+
}
260+
261+
/**
262+
* arena_memdup() - Duplicate a block of memory into the arena.
263+
* Allocates size bytes within the arena and copies data from the input pointer.
264+
*
265+
* @arena: a Pointer to the arena. Must not be NULL.
266+
* @data: data Pointer to the source memory. Must not be NULL.
267+
* @size: size Number of bytes to copy. Must be non-negative.
268+
*
269+
* Return: The pointer to the duplicated memory stored in the arena.
270+
*/
271+
void *arena_memdup(arena_t *arena, void *data, int size)
272+
{
273+
return memcpy(arena_alloc(arena, size), data, size);
185274
}
186275

187276
/**
@@ -194,8 +283,7 @@ void arena_free(arena_t *arena)
194283

195284
while (block) {
196285
next = block->next;
197-
free(block->memory);
198-
free(block);
286+
arena_block_free(block);
199287
block = next;
200288
}
201289

0 commit comments

Comments
 (0)