Skip to content

Commit bcf085f

Browse files
AW-AlanWuicgmilk
andcommitted
Add generic dynamic array (dynarr_t)
Introduce a reusable, arena-allocated dynamic array implementation. The new 'dynarr_t' type encapsulates element size, current size, capacity, and a pointer to the arena allocator. Core operations include: - 'dynarr_init': initialize array with specified capacity. - 'dynarr_reserve': reserve given capacity. - 'dynarr_resize': adjust array size, growing if needed. - 'dynarr_push_raw/byte/word': append elements of arbitrary types. - 'dynarr_extend': bulk append buffer of elements. - 'dynarr_get_raw/byte/word': retrieve elements by index with checks. - 'dynarr_set_raw': overwrite an element at a given index. Relying on the existing arena allocator ensures proper byte alignment and eliminates failure checks. This implementation can replace the current 'strbuf_t' and most fixed-size arrays. In addition to improving consistency in memory management, the built-in boundary checks enhance safety, while the impact on performance remains within an acceptable margin. Co-authored-by: Jim Hsu <[email protected]>
1 parent 6ef2402 commit bcf085f

File tree

2 files changed

+231
-0
lines changed

2 files changed

+231
-0
lines changed

src/defs.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,23 @@ typedef struct {
351351
char *elements;
352352
} strbuf_t;
353353

354+
/* Definition of a generic dynamic array.
355+
*
356+
* size: Number of elements currently in use.
357+
* capacity: Number of elements the buffer can hold before reallocation.
358+
* elem_size: Size of each element in bytes.
359+
* elements: Pointer to the data buffer.
360+
* arena: Arena allocator used for allocations.
361+
*/
362+
typedef struct {
363+
int size;
364+
int capacity;
365+
int elem_size;
366+
void *elements;
367+
368+
arena_t *arena;
369+
} dynarr_t;
370+
354371
/* phase-2 IR definition */
355372
struct ph2_ir {
356373
opcode_t op;

src/globals.c

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,220 @@ void add_insn(block_t *block,
10091009
bb->insn_list.tail = n;
10101010
}
10111011

1012+
/**
1013+
* dynarr_reserve() - Ensure the array can hold at least new_cap elements.
1014+
* @arr: Dynamic array (must not be NULL).
1015+
* @new_cap: Desired capacity (in elements).
1016+
*
1017+
* If new_cap <= current capacity, do nothing. Otherwise, reallocate
1018+
* via arena_realloc(), preserving existing elements.
1019+
*/
1020+
void dynarr_reserve(dynarr_t *arr, int new_cap)
1021+
{
1022+
if (new_cap <= arr->capacity)
1023+
return;
1024+
int oldsz = arr->capacity * arr->elem_size;
1025+
int newsz = new_cap * arr->elem_size;
1026+
arr->elements = arena_realloc(arr->arena, arr->elements, oldsz, newsz);
1027+
arr->capacity = new_cap;
1028+
}
1029+
1030+
/**
1031+
* dynarr_init() - Initialize a new dynamic array in the given arena.
1032+
* @arena: Arena allocator (must not be NULL).
1033+
* @init_cap: Initial capacity (0 for none).
1034+
* @elem_size: Size of each element in bytes (> 0).
1035+
*
1036+
* Returns a pointer to the new dynarr_t.
1037+
*/
1038+
dynarr_t *dynarr_init(arena_t *arena, int init_cap, int elem_size)
1039+
{
1040+
if (elem_size <= 0) {
1041+
printf("dynarr_init: elem_size must be > 0\n");
1042+
abort();
1043+
}
1044+
dynarr_t *arr = arena_alloc(arena, sizeof(dynarr_t));
1045+
arr->size = 0;
1046+
arr->capacity = 0;
1047+
arr->elem_size = elem_size;
1048+
arr->elements = NULL;
1049+
arr->arena = arena;
1050+
dynarr_reserve(arr, init_cap);
1051+
return arr;
1052+
}
1053+
1054+
void _dynarr_grow(dynarr_t *arr, int need)
1055+
{
1056+
if (need <= arr->capacity)
1057+
return;
1058+
int new_cap = arr->capacity ? arr->capacity << 1 : 4;
1059+
while (need > new_cap)
1060+
new_cap <<= 1;
1061+
dynarr_reserve(arr, new_cap);
1062+
}
1063+
1064+
/**
1065+
* dynarr_resize() - Set array size, growing capacity if needed.
1066+
* @arr: Target array.
1067+
* @new_size: New size (>= 0).
1068+
*/
1069+
void dynarr_resize(dynarr_t *arr, int new_size)
1070+
{
1071+
if (new_size < 0) {
1072+
printf("dynarr_resize: new_size must be >= 0\n");
1073+
abort();
1074+
}
1075+
_dynarr_grow(arr, new_size);
1076+
arr->size = new_size;
1077+
}
1078+
1079+
/**
1080+
* dynarr_push_raw() - Append an element by copying bytes.
1081+
* @arr: Target array.
1082+
* @elem: Pointer to element (elem_size bytes).
1083+
*/
1084+
void dynarr_push_raw(dynarr_t *arr, void *elem)
1085+
{
1086+
_dynarr_grow(arr, arr->size + 1);
1087+
char *dst = arr->elements;
1088+
char *src = elem;
1089+
dst += arr->size * arr->elem_size;
1090+
memcpy(dst, src, arr->elem_size);
1091+
++arr->size;
1092+
}
1093+
1094+
/**
1095+
* dynarr_push_byte() - Append a single byte.
1096+
* @arr: Target array (elem_size must be 1).
1097+
* @elem: Byte value to append.
1098+
*/
1099+
void dynarr_push_byte(dynarr_t *arr, char elem)
1100+
{
1101+
if (arr->elem_size != sizeof(char)) {
1102+
printf("dynarr_push_byte: elem_size must be 1\n");
1103+
abort();
1104+
}
1105+
_dynarr_grow(arr, arr->size + 1);
1106+
char *ptr = arr->elements;
1107+
ptr[arr->size] = elem;
1108+
++arr->size;
1109+
}
1110+
1111+
/**
1112+
* dynarr_push_word() - Append an int value.
1113+
* @arr: Target array (elem_size must equal sizeof(int)).
1114+
* @elem: Int value to append.
1115+
*/
1116+
void dynarr_push_word(dynarr_t *arr, int elem)
1117+
{
1118+
if (arr->elem_size != sizeof(int)) {
1119+
printf("dynarr_push_word: elem_size must be sizeof(int)\n");
1120+
abort();
1121+
}
1122+
_dynarr_grow(arr, arr->size + 1);
1123+
int *ptr = arr->elements;
1124+
ptr[arr->size] = elem;
1125+
++arr->size;
1126+
}
1127+
1128+
/**
1129+
* dynarr_extend() - Append multiple elements from a buffer.
1130+
* @arr: Target array.
1131+
* @elems: Buffer of elements to copy.
1132+
* @size: Size of buffer in bytes (multiple of elem_size).
1133+
*/
1134+
void dynarr_extend(dynarr_t *arr, void *elems, int size)
1135+
{
1136+
if (size % arr->elem_size != 0) {
1137+
printf("dynarr_extend: size must be a multiple of elem_size\n");
1138+
abort();
1139+
}
1140+
int added = (size / arr->elem_size);
1141+
_dynarr_grow(arr, arr->size + added);
1142+
char *dst = arr->elements;
1143+
int offset = arr->size * arr->elem_size;
1144+
char *ptr = elems;
1145+
memcpy(dst + offset, ptr, size);
1146+
arr->size += added;
1147+
}
1148+
1149+
/**
1150+
* dynarr_get_raw() - Get pointer to element at index.
1151+
* @arr: Target array.
1152+
* @index: Element index (0-based).
1153+
*
1154+
* Returns pointer to element in internal buffer.
1155+
*/
1156+
void *dynarr_get_raw(dynarr_t *arr, int index)
1157+
{
1158+
if (index < 0 || index >= arr->size) {
1159+
printf("index %d out of bounds (size=%d)\n", index, arr->size);
1160+
return NULL;
1161+
}
1162+
char *ptr = arr->elements;
1163+
ptr += index * arr->elem_size;
1164+
return ptr;
1165+
}
1166+
1167+
/**
1168+
* dynarr_get_byte() - Fetch byte at index.
1169+
* @arr: Target array (elem_size must be 1).
1170+
* @index: Element index.
1171+
*
1172+
* Returns the byte value.
1173+
*/
1174+
char dynarr_get_byte(dynarr_t *arr, int index)
1175+
{
1176+
if (arr->elem_size != sizeof(char)) {
1177+
printf("dynarr_get_byte: elem_size must be 1\n");
1178+
abort();
1179+
}
1180+
if (index < 0 || index >= arr->size) {
1181+
printf("index %d out of bounds (size=%d)\n", index, arr->size);
1182+
return 0;
1183+
}
1184+
char *ptr = arr->elements;
1185+
return ptr[index];
1186+
}
1187+
1188+
/**
1189+
* dynarr_get_word() - Fetch int at index.
1190+
* @arr: Target array (elem_size must be sizeof(int)).
1191+
* @index: Element index.
1192+
*
1193+
* Returns the int value.
1194+
*/
1195+
int dynarr_get_word(dynarr_t *arr, int index)
1196+
{
1197+
if (arr->elem_size != sizeof(int)) {
1198+
printf("dynarr_get_word: elem_size must be sizeof(int)\n");
1199+
abort();
1200+
}
1201+
if (index < 0 || index >= arr->size) {
1202+
printf("index %d out of bounds (size=%d)\n", index, arr->size);
1203+
return 0;
1204+
}
1205+
int *ptr = arr->elements;
1206+
return ptr[index];
1207+
}
1208+
1209+
/**
1210+
* dynarr_set_raw() - Overwrite element at index with given bytes.
1211+
* @arr: Target array.
1212+
* @index: Element index to overwrite.
1213+
* @elem: Pointer to source bytes (elem_size bytes).
1214+
*/
1215+
void dynarr_set_raw(dynarr_t *arr, int index, void *elem)
1216+
{
1217+
if (index < 0 || index >= arr->size) {
1218+
printf("index %d out of bounds (size=%d)\n", index, arr->size);
1219+
return;
1220+
}
1221+
char *dst = arr->elements;
1222+
dst += index * arr->elem_size;
1223+
memcpy(dst, elem, arr->elem_size);
1224+
}
1225+
10121226
strbuf_t *strbuf_create(int init_capacity)
10131227
{
10141228
strbuf_t *array = malloc(sizeof(strbuf_t));

0 commit comments

Comments
 (0)