203 lines
7.4 KiB
C
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);
|
|
}
|