Files
ground/libs/allocator/allocator.c
2026-05-19 20:33:52 +10:00

203 lines
7.4 KiB
C

// allocator.c - library to safely, dynamically allocate memory inside of Ground
#include <groundext.h>
#include <groundvm.h>
#include <stdbool.h>
#include <uthash.h>
GroundStruct allocatorStruct;
// callmethod &allocator !allocate $size &
GroundValue groundAllocatorAllocate(GroundScope* scope, List args) {
int64_t size = args.values[0].data.intVal;
if (size < 1) {
ERROR("Cannot allocate with size of < 1", "AllocSizeError");
}
GroundValue* ptr = malloc(sizeof(GroundValue) * size);
if (ptr == NULL) {
ERROR("Failed to allocate memory", "AllocError");
}
GroundVariable* ptrField = groundFindVariable(scope, "ptr");
if (ptrField == NULL) {
ERROR("Failed to find field for pointer", "ValueError");
}
ptrField->value.type = INT;
ptrField->value.data.intVal = (int64_t)ptr;
GroundVariable* capacityField = groundFindVariable(scope, "capacity");
if (capacityField == NULL) {
ERROR("Failed to find field for capacity", "ValueError");
}
capacityField->value.type = INT;
capacityField->value.data.intVal = size;
return groundCreateValue(INT, 0);
}
// callmethod &allocator !addCapacity $addedCapacity &
GroundValue groundAllocatorAddCapacity(GroundScope* scope, List args) {
int64_t addedCapacity = args.values[0].data.intVal;
if (addedCapacity < 0) {
ERROR("Cannot shrink capacity", "AllocSizeError");
}
GroundVariable* currentCapacity = groundFindVariable(scope, "capacity");
if (currentCapacity == NULL) {
ERROR("Failed to find field for capacity", "ValueError");
}
if (currentCapacity->value.data.intVal < 1) {
return groundAllocatorAllocate(scope, args);
}
currentCapacity->value.data.intVal += addedCapacity;
GroundVariable* ptrField = groundFindVariable(scope, "ptr");
if (ptrField == NULL) {
ERROR("Failed to find field for pointer", "ValueError");
}
GroundValue* ptr = (GroundValue*)ptrField->value.data.intVal;
if (ptr == NULL) {
return groundAllocatorAllocate(scope, args);
}
GroundValue* newPtr = realloc(ptr, sizeof(GroundValue) * currentCapacity->value.data.intVal);
if (newPtr == NULL) {
ERROR("Failed to allocate more memory for pointer", "AllocError");
}
ptrField->value.data.intVal = (int64_t)newPtr;
return groundCreateValue(INT, 0);
}
// callmethod &allocator !getAtOffset $offset &
GroundValue groundAllocatorGetAtOffset(GroundScope* scope, List args) {
int64_t offset = args.values[0].data.intVal;
GroundVariable* currentCapacity = groundFindVariable(scope, "capacity");
if (currentCapacity == NULL) {
ERROR("Failed to find field for capacity", "ValueError");
}
if (offset >= currentCapacity->value.data.intVal || offset < 0) {
ERROR("Offset is out of bounds for current capacity", "OutOfBounds");
}
GroundVariable* ptrField = groundFindVariable(scope, "ptr");
if (ptrField == NULL) {
ERROR("Failed to find field for pointer", "ValueError");
}
GroundValue* ptr = (GroundValue*)ptrField->value.data.intVal;
if (ptr == NULL) {
ERROR("Cannot get offset of null pointer", "NullPointerError");
}
return ptr[offset];
}
GroundValue copyGroundValue(const GroundValue* gv);
// callmethod &allocator !setAtOffset $offset $value &
GroundValue groundAllocatorSetAtOffset(GroundScope* scope, List args) {
int64_t offset = args.values[0].data.intVal;
GroundValue value = copyGroundValue(&args.values[1]);
GroundVariable* currentCapacity = groundFindVariable(scope, "capacity");
if (currentCapacity == NULL) {
ERROR("Failed to find field for capacity", "ValueError");
}
if (offset >= currentCapacity->value.data.intVal || offset < 0) {
ERROR("Offset is out of bounds for current capacity", "OutOfBounds");
}
GroundVariable* ptrField = groundFindVariable(scope, "ptr");
if (ptrField == NULL) {
ERROR("Failed to find field for pointer", "ValueError");
}
GroundValue* ptr = (GroundValue*)ptrField->value.data.intVal;
if (ptr == NULL) {
ERROR("Cannot set offset of null pointer", "NullPointerError");
}
ptr[offset] = value;
return groundCreateValue(INT, 0);
}
GroundValue groundAllocatorDestructor(GroundScope* scope, List args) {
GroundVariable* ptrField = groundFindVariable(scope, "ptr");
if (ptrField == NULL) {
ERROR("Failed to find field for pointer", "ValueError");
}
GroundValue* ptr = (GroundValue*)ptrField->value.data.intVal;
if (ptr == NULL) {
ERROR("Cannot set offset of null pointer", "NullPointerError");
}
free(ptr);
ptrField->value.data.intVal = 0;
GroundVariable* currentCapacity = groundFindVariable(scope, "capacity");
if (currentCapacity == NULL) {
ERROR("Failed to find field for capacity", "ValueError");
}
currentCapacity->value.data.intVal = 0;
return groundCreateValue(INT, 0);
}
GroundValue groundAllocatorDuplicator(GroundScope* scope, List args) {
GroundVariable* ptrField = groundFindVariable(scope, "ptr");
if (ptrField == NULL) {
ERROR("Failed to find field for pointer", "ValueError");
}
GroundValue* ptr = (GroundValue*)ptrField->value.data.intVal;
GroundVariable* currentCapacity = groundFindVariable(scope, "capacity");
if (currentCapacity == NULL) {
ERROR("Failed to find field for capacity", "ValueError");
}
GroundValue newAllocator = groundCreateValue(CUSTOM, &allocatorStruct);
GroundObjectField* newPtrField = groundFindField(*newAllocator.data.customVal, "ptr");
if (newPtrField == NULL) {
ERROR("Failed to find field for pointer", "ValueError");
}
GroundValue* newPtr;
if (ptr == NULL) {
newPtr = NULL;
} else {
newPtr = malloc(sizeof(GroundValue) * currentCapacity->value.data.intVal);
if (newPtr == NULL) {
ERROR("Failed to allocate new pointer in duplicator", "AllocError");
}
memcpy(newPtr, ptr, sizeof(GroundValue) * currentCapacity->value.data.intVal);
}
newPtrField->value.data.intVal = (int64_t)newPtr;
GroundObjectField* newCapacity = groundFindField(*newAllocator.data.customVal, "capacity");
if (newCapacity == NULL) {
ERROR("Failed to find field for capacity", "ValueError");
}
newCapacity->value.data.intVal = currentCapacity->value.data.intVal;
return newAllocator;
}
void ground_init(GroundScope* scope) {
allocatorStruct = groundCreateStruct();
groundAddFieldToStruct(&allocatorStruct, "ptr", groundCreateValue(INT, 0)); // private
groundAddFieldToStruct(&allocatorStruct, "capacity", groundCreateValue(INT, 0)); // protected
groundAddFunctionToStruct(&allocatorStruct, "allocate", groundAllocatorAllocate, ANY, 1, INT, "amount");
groundAddFunctionToStruct(&allocatorStruct, "addCapacity", groundAllocatorAddCapacity, ANY, 1, INT, "amount");
groundAddFunctionToStruct(&allocatorStruct, "getAtOffset", groundAllocatorGetAtOffset, ANY, 1, INT, "offset");
groundAddFunctionToStruct(&allocatorStruct, "setAtOffset", groundAllocatorSetAtOffset, ANY, 2, INT, "offset", ANY, "value");
groundAddFunctionToStruct(&allocatorStruct, "destructor", groundAllocatorDestructor, INT, 0);
groundAddFunctionToStruct(&allocatorStruct, "duplicator", groundAllocatorDuplicator, CUSTOM, 1, CUSTOM, "self");
GroundValue structVal = groundCreateValue(STRUCTVAL, allocatorStruct);
groundAddValueToScope(scope, "Allocator", structVal);
}