arena fixes
This commit is contained in:
+8
-8
@@ -57,14 +57,14 @@ static void *arena_resize(arena_allocator_t *this, void *old_ptr, size_t bytes)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sizeof not necessary but ill do it anyways.
|
// Calculate how many bytes from old_ptr to the end of currently used arena space
|
||||||
size_t old_index = ((size_t)old_ptr - (size_t)this->data) / sizeof(*this->data);
|
size_t old_offset = old_ptr_b - this->data;
|
||||||
size_t bytes_til_buffer_end = old_index + this->size;
|
size_t bytes_from_old_to_end = this->size - old_offset;
|
||||||
size_t max_bytes_to_copy = bytes < bytes_til_buffer_end
|
// Copy the smaller of: new allocation size or remaining old data
|
||||||
? bytes
|
size_t bytes_to_copy = bytes < bytes_from_old_to_end ? bytes : bytes_from_old_to_end;
|
||||||
: bytes_til_buffer_end;
|
|
||||||
for (size_t i = old_index; i < old_index + max_bytes_to_copy; i++) {
|
for (size_t i = 0; i < bytes_to_copy; i++) {
|
||||||
new_ptr_b[i] = this->data[i];
|
new_ptr_b[i] = old_ptr_b[i];
|
||||||
}
|
}
|
||||||
return new_ptr_b;
|
return new_ptr_b;
|
||||||
}
|
}
|
||||||
|
|||||||
+245
-1
@@ -1,8 +1,9 @@
|
|||||||
#include <criterion/criterion.h>
|
#include <criterion/criterion.h>
|
||||||
#include <criterion/internal/assert.h>
|
#include <criterion/internal/assert.h>
|
||||||
|
#include <string.h>
|
||||||
#include "cig.h"
|
#include "cig.h"
|
||||||
|
|
||||||
Test(arena_allocator, test) {
|
Test(arena_allocator, basic_allocation) {
|
||||||
with_borrow(backing) {
|
with_borrow(backing) {
|
||||||
allocator_t arena = arena_allocator_create(backing, 4 * MB);
|
allocator_t arena = arena_allocator_create(backing, 4 * MB);
|
||||||
for ( size_t i = 0; i < 1000; i++ ) {
|
for ( size_t i = 0; i < 1000; i++ ) {
|
||||||
@@ -77,3 +78,246 @@ Test(arena_allocator, test) {
|
|||||||
cr_assert_eq(concrete_arena->capacity, expected_capacity);
|
cr_assert_eq(concrete_arena->capacity, expected_capacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Test(arena_allocator, resize_preserves_data) {
|
||||||
|
with_borrow(backing) {
|
||||||
|
allocator_t arena = arena_allocator_create(backing, 1 * KB);
|
||||||
|
allocator_reset(arena);
|
||||||
|
|
||||||
|
// Allocate a buffer and fill it with data
|
||||||
|
int *data = allocator_alloc(arena, sizeof(int) * 10);
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
data[i] = i * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize to larger size - should preserve existing data
|
||||||
|
int *resized = allocator_resize(arena, data, sizeof(int) * 20);
|
||||||
|
|
||||||
|
// Verify old data is preserved
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
cr_assert_eq(resized[i], i * 100, "Expected resized[%d] = %d, got %d", i, i * 100, resized[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the new space
|
||||||
|
for (int i = 10; i < 20; i++) {
|
||||||
|
resized[i] = i * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all data
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
cr_assert_eq(resized[i], i * 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(arena_allocator, resize_smaller_preserves_partial_data) {
|
||||||
|
with_borrow(backing) {
|
||||||
|
allocator_t arena = arena_allocator_create(backing, 1 * KB);
|
||||||
|
allocator_reset(arena);
|
||||||
|
|
||||||
|
// Allocate a buffer and fill it with data
|
||||||
|
int *data = allocator_alloc(arena, sizeof(int) * 20);
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
data[i] = i * 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize to smaller size - should preserve first N elements
|
||||||
|
int *resized = allocator_resize(arena, data, sizeof(int) * 10);
|
||||||
|
|
||||||
|
// Verify first 10 elements are preserved
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
cr_assert_eq(resized[i], i * 7, "Expected resized[%d] = %d, got %d", i, i * 7, resized[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(arena_allocator, resize_with_zero_capacity) {
|
||||||
|
with_borrow(backing) {
|
||||||
|
allocator_t arena = arena_allocator_create(backing, 1 * KB);
|
||||||
|
allocator_reset(arena);
|
||||||
|
|
||||||
|
// Simulate dyn_array with capacity 0 behavior
|
||||||
|
typedef struct {
|
||||||
|
size_t size;
|
||||||
|
size_t capacity;
|
||||||
|
size_t itemsize;
|
||||||
|
allocator_t allocator;
|
||||||
|
uint8_t bytes[];
|
||||||
|
} test_header_t;
|
||||||
|
|
||||||
|
// Allocate just the header (capacity = 0)
|
||||||
|
test_header_t *header = allocator_alloc(arena, sizeof(test_header_t));
|
||||||
|
header->size = 0;
|
||||||
|
header->capacity = 0;
|
||||||
|
header->itemsize = sizeof(int);
|
||||||
|
|
||||||
|
// Resize to add space for 1 element
|
||||||
|
header = allocator_resize(arena, header, sizeof(test_header_t) + sizeof(int) * 1);
|
||||||
|
cr_assert_neq(header, NULL);
|
||||||
|
header->capacity = 1;
|
||||||
|
|
||||||
|
// Add an element
|
||||||
|
int *data = (int*)header->bytes;
|
||||||
|
data[0] = 42;
|
||||||
|
header->size = 1;
|
||||||
|
|
||||||
|
// Resize again to capacity 2
|
||||||
|
header = allocator_resize(arena, header, sizeof(test_header_t) + sizeof(int) * 2);
|
||||||
|
cr_assert_neq(header, NULL);
|
||||||
|
header->capacity = 2;
|
||||||
|
|
||||||
|
// Verify first element is preserved
|
||||||
|
data = (int*)header->bytes;
|
||||||
|
cr_assert_eq(data[0], 42);
|
||||||
|
|
||||||
|
// Add second element
|
||||||
|
data[1] = 99;
|
||||||
|
header->size = 2;
|
||||||
|
|
||||||
|
// Verify both elements
|
||||||
|
cr_assert_eq(data[0], 42);
|
||||||
|
cr_assert_eq(data[1], 99);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(arena_allocator, dyn_array_resize_pattern) {
|
||||||
|
// Test the actual pattern used by dynamic arrays
|
||||||
|
with_borrow(backing) {
|
||||||
|
allocator_t arena = arena_allocator_create(backing, 10 * KB);
|
||||||
|
allocator_reset(arena);
|
||||||
|
|
||||||
|
int *arr = dyn_array_create(arena, int);
|
||||||
|
|
||||||
|
// Add 100 elements, forcing multiple resizes
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
dyn_array_append(arr, i * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all elements
|
||||||
|
cr_assert_eq(dyn_array_length(arr), 100);
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
cr_assert_eq(arr[i], i * 3, "Expected arr[%d] = %d, got %d", i, i * 3, arr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(arena_allocator, multiple_arrays_resize) {
|
||||||
|
// Test multiple dynamic arrays resizing independently
|
||||||
|
with_borrow(backing) {
|
||||||
|
allocator_t arena = arena_allocator_create(backing, 20 * KB);
|
||||||
|
allocator_reset(arena);
|
||||||
|
|
||||||
|
int *arr1 = dyn_array_create(arena, int);
|
||||||
|
int *arr2 = dyn_array_create(arena, int);
|
||||||
|
|
||||||
|
// Add to arr1
|
||||||
|
for (int i = 0; i < 50; i++) {
|
||||||
|
dyn_array_append(arr1, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to arr2
|
||||||
|
for (int i = 0; i < 30; i++) {
|
||||||
|
dyn_array_append(arr2, i * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add more to arr1
|
||||||
|
for (int i = 50; i < 100; i++) {
|
||||||
|
dyn_array_append(arr1, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify arr1
|
||||||
|
cr_assert_eq(dyn_array_length(arr1), 100);
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
cr_assert_eq(arr1[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify arr2
|
||||||
|
cr_assert_eq(dyn_array_length(arr2), 30);
|
||||||
|
for (int i = 0; i < 30; i++) {
|
||||||
|
cr_assert_eq(arr2[i], i * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(arena_allocator, resize_with_string_data) {
|
||||||
|
with_borrow(backing) {
|
||||||
|
allocator_t arena = arena_allocator_create(backing, 1 * KB);
|
||||||
|
allocator_reset(arena);
|
||||||
|
|
||||||
|
// Allocate and fill with string data
|
||||||
|
char *str = allocator_alloc(arena, 10);
|
||||||
|
strcpy(str, "Hello");
|
||||||
|
|
||||||
|
// Resize to larger
|
||||||
|
str = allocator_resize(arena, str, 20);
|
||||||
|
|
||||||
|
// Verify string is preserved
|
||||||
|
cr_assert_str_eq(str, "Hello");
|
||||||
|
|
||||||
|
// Append more
|
||||||
|
strcat(str, " World!");
|
||||||
|
cr_assert_str_eq(str, "Hello World!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(arena_allocator, nested_structures_with_resize) {
|
||||||
|
// Test resizing with nested pointer structures (like 2D arrays)
|
||||||
|
with_borrow(backing) {
|
||||||
|
allocator_t arena = arena_allocator_create(backing, 10 * KB);
|
||||||
|
allocator_reset(arena);
|
||||||
|
|
||||||
|
// Create array of int pointers (like dyn_array of dyn_arrays)
|
||||||
|
int **rows = dyn_array_create(arena, int*);
|
||||||
|
|
||||||
|
// Add 5 rows
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
int *row = dyn_array_create(arena, int);
|
||||||
|
for (int j = 0; j < 10; j++) {
|
||||||
|
dyn_array_append(row, i * 10 + j);
|
||||||
|
}
|
||||||
|
dyn_array_append(rows, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify data
|
||||||
|
cr_assert_eq(dyn_array_length(rows), 5);
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
cr_assert_eq(dyn_array_length(rows[i]), 10);
|
||||||
|
for (int j = 0; j < 10; j++) {
|
||||||
|
cr_assert_eq(rows[i][j], i * 10 + j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(arena_allocator, large_resize_chain) {
|
||||||
|
// Test many consecutive resizes
|
||||||
|
with_borrow(backing) {
|
||||||
|
allocator_t arena = arena_allocator_create(backing, 50 * KB);
|
||||||
|
allocator_reset(arena);
|
||||||
|
|
||||||
|
int *data = allocator_alloc(arena, sizeof(int) * 1);
|
||||||
|
data[0] = 123;
|
||||||
|
|
||||||
|
// Resize many times, each time doubling
|
||||||
|
for (int iteration = 0; iteration < 10; iteration++) {
|
||||||
|
size_t old_size = 1 << iteration;
|
||||||
|
size_t new_size = 1 << (iteration + 1);
|
||||||
|
|
||||||
|
data = allocator_resize(arena, data, sizeof(int) * new_size);
|
||||||
|
|
||||||
|
// Verify first element is still preserved
|
||||||
|
cr_assert_eq(data[0], 123);
|
||||||
|
|
||||||
|
// Fill new elements
|
||||||
|
for (size_t i = old_size; i < new_size; i++) {
|
||||||
|
data[i] = (int)i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final size should be 1024
|
||||||
|
cr_assert_eq(data[0], 123);
|
||||||
|
for (int i = 1; i < 1024; i++) {
|
||||||
|
cr_assert_eq(data[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user