mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2026-04-27 04:21:42 +00:00
memory.c cleanup and optimisation
This commit is contained in:
parent
fb8fbd1136
commit
db34bd9e2d
2 changed files with 74 additions and 39 deletions
|
|
@ -5,7 +5,8 @@
|
|||
#include "print.h"
|
||||
#include "pc/debuglog.h"
|
||||
|
||||
#define ALIGN16(val) (((val) + 0xF) & ~0xF)
|
||||
// Alignment to a data size
|
||||
#define ALIGN_UP(val, align) (((val) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
//////////////////
|
||||
// dynamic pool //
|
||||
|
|
@ -14,7 +15,8 @@
|
|||
struct DynamicPool *gLevelPool = NULL;
|
||||
|
||||
struct DynamicPool* dynamic_pool_init(void) {
|
||||
struct DynamicPool* pool = calloc(1, sizeof(struct DynamicPool));
|
||||
struct DynamicPool* pool = malloc(sizeof(struct DynamicPool));
|
||||
if (!pool) { return NULL; }
|
||||
pool->usedSpace = 0;
|
||||
pool->tail = NULL;
|
||||
pool->nextFree = NULL;
|
||||
|
|
@ -24,14 +26,17 @@ struct DynamicPool* dynamic_pool_init(void) {
|
|||
void* dynamic_pool_alloc(struct DynamicPool *pool, u32 size) {
|
||||
if (!pool) { return NULL; }
|
||||
|
||||
struct DynamicPoolNode* node = calloc(1, sizeof(struct DynamicPoolNode));
|
||||
node->ptr = calloc(1, size);
|
||||
size_t header = ALIGN_UP(sizeof(struct DynamicPoolNode), sizeof(void*));
|
||||
struct DynamicPoolNode* node = malloc(header + size);
|
||||
if (!node) { return NULL; }
|
||||
node->ptr = (u8*)node + header;
|
||||
node->prev = pool->tail;
|
||||
node->size = size;
|
||||
|
||||
pool->tail = node;
|
||||
pool->usedSpace += size;
|
||||
|
||||
memset(node->ptr, 0, size);
|
||||
return node->ptr;
|
||||
}
|
||||
|
||||
|
|
@ -50,8 +55,7 @@ void dynamic_pool_free(struct DynamicPool *pool, void* ptr) {
|
|||
next->prev = prev;
|
||||
}
|
||||
pool->usedSpace -= node->size;
|
||||
free(node->ptr);
|
||||
free(node);
|
||||
free(node); // node->ptr is freed here too; it's part of the same allocation
|
||||
return;
|
||||
}
|
||||
next = node;
|
||||
|
|
@ -81,8 +85,7 @@ void dynamic_pool_free_pool(struct DynamicPool *pool) {
|
|||
struct DynamicPoolNode* node = pool->nextFree;
|
||||
while (node) {
|
||||
struct DynamicPoolNode* prev = node->prev;
|
||||
free(node->ptr);
|
||||
free(node);
|
||||
free(node); // node->ptr is freed here too; it's part of the same allocation
|
||||
node = prev;
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +110,8 @@ struct GrowingPool* growing_pool_init(struct GrowingPool* pool, u32 nodeSize) {
|
|||
pool->usedSpace = 0;
|
||||
} else {
|
||||
// allocate a new pool
|
||||
pool = calloc(1, sizeof(struct GrowingPool));
|
||||
pool = malloc(sizeof(struct GrowingPool));
|
||||
if (!pool) { return NULL; }
|
||||
pool->usedSpace = 0;
|
||||
pool->nodeSize = nodeSize;
|
||||
pool->tail = NULL;
|
||||
|
|
@ -119,19 +123,22 @@ void* growing_pool_alloc(struct GrowingPool *pool, u32 size) {
|
|||
if (!pool) { return NULL; }
|
||||
|
||||
// maintain alignment
|
||||
size = ALIGN16(size);
|
||||
size = ALIGN_UP(size, sizeof(void*));
|
||||
|
||||
// check if it's too big for a node
|
||||
if (size >= pool->nodeSize) {
|
||||
// create a node just for this
|
||||
struct GrowingPoolNode* node = calloc(1, sizeof(struct GrowingPoolNode));
|
||||
node->ptr = calloc(1, size);
|
||||
size_t header = ALIGN_UP(sizeof(struct GrowingPoolNode), sizeof(void*));
|
||||
struct GrowingPoolNode* node = malloc(header + size);
|
||||
if (!node) { return NULL; }
|
||||
node->ptr = (u8*) node + header;
|
||||
node->prev = pool->tail;
|
||||
node->usedSpace = size;
|
||||
|
||||
pool->tail = node;
|
||||
pool->usedSpace += size;
|
||||
|
||||
memset(node->ptr, 0, size);
|
||||
return node->ptr;
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +150,7 @@ void* growing_pool_alloc(struct GrowingPool *pool, u32 size) {
|
|||
while (node && depth < 128) {
|
||||
depth++;
|
||||
s64 freeSpace = (s64)pool->nodeSize - (s64)node->usedSpace;
|
||||
if (freeSpace > size) { break; }
|
||||
if (freeSpace >= (s64) size) { break; }
|
||||
node = node->prev;
|
||||
}
|
||||
if (depth >= 128) {
|
||||
|
|
@ -153,9 +160,11 @@ void* growing_pool_alloc(struct GrowingPool *pool, u32 size) {
|
|||
|
||||
// allocate new node
|
||||
if (!node) {
|
||||
node = calloc(1, sizeof(struct GrowingPoolNode));
|
||||
size_t header = ALIGN_UP(sizeof(struct GrowingPoolNode), sizeof(void*));
|
||||
node = malloc(header + pool->nodeSize);
|
||||
if (!node) { return NULL; }
|
||||
node->usedSpace = 0;
|
||||
node->ptr = calloc(1, pool->nodeSize);
|
||||
node->ptr = (u8*) node + header;
|
||||
node->prev = pool->tail;
|
||||
pool->tail = node;
|
||||
}
|
||||
|
|
@ -174,8 +183,7 @@ void growing_pool_free_pool(struct GrowingPool *pool) {
|
|||
struct GrowingPoolNode* node = pool->tail;
|
||||
while (node) {
|
||||
struct GrowingPoolNode* prev = node->prev;
|
||||
free(node->ptr);
|
||||
free(node);
|
||||
free(node); // node->ptr is freed here too; it's part of the same allocation
|
||||
node = prev;
|
||||
}
|
||||
free(pool);
|
||||
|
|
@ -187,8 +195,13 @@ void growing_pool_free_pool(struct GrowingPool *pool) {
|
|||
|
||||
struct GrowingArray *growing_array_init(struct GrowingArray *array, u32 capacity, GrowingArrayAllocFunc alloc, GrowingArrayFreeFunc free) {
|
||||
growing_array_free(&array);
|
||||
array = calloc(1, sizeof(struct GrowingArray));
|
||||
array = malloc(sizeof(struct GrowingArray));
|
||||
if (!array) { return NULL; }
|
||||
array->buffer = calloc(capacity, sizeof(void *));
|
||||
if (!array->buffer) {
|
||||
free(array);
|
||||
return NULL;
|
||||
}
|
||||
array->capacity = capacity;
|
||||
array->count = 0;
|
||||
array->alloc = alloc;
|
||||
|
|
@ -200,11 +213,11 @@ void *growing_array_alloc(struct GrowingArray *array, u32 size) {
|
|||
if (array && array->buffer) {
|
||||
|
||||
// Increase capacity if needed
|
||||
while (array->count >= array->capacity) {
|
||||
if (array->count >= array->capacity) {
|
||||
u32 newCapacity = array->capacity * 2;
|
||||
void **newBuffer = calloc(newCapacity, sizeof(void *));
|
||||
memcpy(newBuffer, array->buffer, array->capacity * sizeof(void *));
|
||||
free(array->buffer);
|
||||
void **newBuffer = realloc(array->buffer, newCapacity * sizeof(void *));
|
||||
if (!newBuffer) { return NULL; }
|
||||
memset(newBuffer + array->capacity, 0, (newCapacity - array->capacity) * sizeof(void *));
|
||||
array->buffer = newBuffer;
|
||||
array->capacity = newCapacity;
|
||||
}
|
||||
|
|
@ -220,30 +233,52 @@ void *growing_array_alloc(struct GrowingArray *array, u32 size) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void growing_array_move(struct GrowingArray *array, u32 from, u32 to, u32 count) {
|
||||
if (array && array->buffer && count > 0 &&
|
||||
(to < from || to > from + count) &&
|
||||
(from + count) <= array->count && to <= array->count) {
|
||||
// This function can move elements to an overlapping region
|
||||
// `to` is the destination index in the array before any operations
|
||||
// Does not expand the array if `to + count` exceeds capacity
|
||||
bool growing_array_move(struct GrowingArray *array, u32 from, u32 to, u32 count) {
|
||||
if (!array || !array->buffer) { return false; }
|
||||
if (count == 0) { return true; }
|
||||
if (from >= array->count) { return false; }
|
||||
if (from + count > array->count) { return false; }
|
||||
if (to > array->count) { return false; }
|
||||
if (to + count > array->count) { return false; }
|
||||
if (from == to) { return true; }
|
||||
|
||||
void **temp = malloc(sizeof(void *) * count);
|
||||
if (!temp) { return; }
|
||||
// Use stack memory for small moves (faster)
|
||||
// Use heap memory for large moves (dynamic size)
|
||||
void **temp;
|
||||
void *stackTemp[64];
|
||||
if (count <= 64) {
|
||||
temp = stackTemp;
|
||||
} else {
|
||||
temp = (void **) malloc(sizeof(void *) * count);
|
||||
if (!temp) { return false; }
|
||||
}
|
||||
|
||||
// Copy elements to move to temporary buffer
|
||||
memcpy(temp, array->buffer + from, sizeof(void *) * count);
|
||||
// Copy elements to move to temporary buffer
|
||||
memcpy(temp, array->buffer + from, sizeof(void *) * count);
|
||||
|
||||
// Remove copied elements from the array
|
||||
memmove(array->buffer + from, array->buffer + (from + count), sizeof(void *) * (array->count - (from + count)));
|
||||
// Remove copied elements from the array
|
||||
u32 tailCount = array->count - (from + count);
|
||||
if (tailCount > 0) {
|
||||
memmove(array->buffer + from, array->buffer + from + count, sizeof(void *) * tailCount);
|
||||
}
|
||||
|
||||
// Make place for the copied elements
|
||||
// If moving left to right, account for the removed elements
|
||||
if (to > from) { to -= count; }
|
||||
memmove(array->buffer + (to + count), array->buffer + to, sizeof(void *) * (array->count - (to + count)));
|
||||
// Make place for the copied elements
|
||||
u32 numToShift = (array->count - count) - to;
|
||||
if (numToShift > 0) {
|
||||
memmove(array->buffer + to + count, array->buffer + to, sizeof(void *) * numToShift);
|
||||
}
|
||||
|
||||
// Insert copied elements
|
||||
memcpy(array->buffer + to, temp, sizeof(void *) * count);
|
||||
// Insert copied elements
|
||||
memcpy(array->buffer + to, temp, sizeof(void *) * count);
|
||||
|
||||
if (count > 64) {
|
||||
free(temp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void growing_array_free(struct GrowingArray **array) {
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ void growing_pool_free_pool(struct GrowingPool *pool);
|
|||
|
||||
struct GrowingArray *growing_array_init(struct GrowingArray *array, u32 capacity, GrowingArrayAllocFunc alloc, GrowingArrayFreeFunc free);
|
||||
void *growing_array_alloc(struct GrowingArray *array, u32 size);
|
||||
void growing_array_move(struct GrowingArray *array, u32 from, u32 to, u32 count);
|
||||
bool growing_array_move(struct GrowingArray *array, u32 from, u32 to, u32 count);
|
||||
void growing_array_free(struct GrowingArray **array);
|
||||
void growing_array_debug_print(struct GrowingArray *array, const char *name, s32 x, s32 y);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue