From 482f85af62d8a63db260584ca1923c460eaabdc5 Mon Sep 17 00:00:00 2001 From: SpookyDervish Date: Sat, 11 Apr 2026 16:06:34 +1000 Subject: [PATCH] core of lists done --- libs/collections/collections.c | 8 + libs/collections/list.c | 378 +++++++++++++++++++++++++++++++++ libs/collections/list.h | 11 + 3 files changed, 397 insertions(+) create mode 100644 libs/collections/collections.c create mode 100644 libs/collections/list.c create mode 100644 libs/collections/list.h diff --git a/libs/collections/collections.c b/libs/collections/collections.c new file mode 100644 index 0000000..3b04f6e --- /dev/null +++ b/libs/collections/collections.c @@ -0,0 +1,8 @@ +#include +#include + +#include "list.h" + +void ground_init(GroundScope* scope) { + groundAddValueToScope(scope, "List", createListStruct()); +} \ No newline at end of file diff --git a/libs/collections/list.c b/libs/collections/list.c new file mode 100644 index 0000000..335cd21 --- /dev/null +++ b/libs/collections/list.c @@ -0,0 +1,378 @@ +#include "list.h" +#include +#include +#include +#include +#include +#include +#include +#include + +const uint8_t STARTING_ELEMENTS = 2; + + +GroundValue appendToListStruct(GroundScope* scope, List args) { + GroundValue newValue = args.values[0]; + + // grab fields we need from struct + GroundVariable* sizeField = groundFindVariable(scope, "size"); + if (sizeField == NULL) { + ERROR("A field called \"size\" was not found", "FieldNotFound"); + } + + GroundVariable* memSizeField = groundFindVariable(scope, "memSize"); + if (memSizeField == NULL) { + ERROR("A field called \"memSize\" was not found", "FieldNotFound"); + } + + GroundVariable* ptrField = groundFindVariable(scope, "__ptr"); + if (ptrField == NULL) { + ERROR("A field called \"__ptr\" was not found", "FieldNotFound"); + } + GroundValue* items = (GroundValue*)ptrField->value.data.intVal; + + GroundVariable* capacityField = groundFindVariable(scope, "capacity"); + if (sizeField == NULL) { + ERROR("A field called \"capacity\" was not found", "FieldNotFound"); + } + int64_t capacity = capacityField->value.data.intVal; + + sizeField->value.data.intVal++; + + if (capacity <= sizeField->value.data.intVal) { + capacity *= 2; + capacityField->value.data.intVal = capacity; + + uint64_t newSize = sizeof(GroundValue) * capacity; + memSizeField->value.data.intVal = newSize; + + items = realloc(items, newSize); + if (items == NULL) { + ERROR("Failed to allocate memory when increasing list size!", "MemoryAllocationFailed"); + } + + ptrField->value.data.intVal = (uint64_t)items; + } + + items[sizeField->value.data.intVal - 1] = newValue; + + return groundCreateValue(INT, 0); +} + +GroundValue listStructAt(GroundScope* scope, List args) { + + uint64_t index = args.values[0].data.intVal; + if (index < 0) { + ERROR("Attempt to access list at negative index", "OutOfBounds"); + } + + GroundVariable* sizeField = groundFindVariable(scope, "size"); + if (sizeField == NULL) { + ERROR("A field called \"size\" was not found", "FieldNotFound"); + } + uint64_t size = (uint64_t)sizeField->value.data.intVal; + if (index >= size) { + char buffer[512]; + sprintf(buffer, "Attempt to access list at index %ld when list is of length %ld", index, size); + ERROR(buffer, "OutOfBounds"); + } + + GroundVariable* ptrField = groundFindVariable(scope, "__ptr"); + if (ptrField == NULL) { + ERROR("A field called \"__ptr\" was not found", "FieldNotFound"); + } + GroundValue* items = (GroundValue*)ptrField->value.data.intVal; + + return items[index]; +} + +GroundValue listStructToString(GroundScope* scope, List args) { + return groundCreateValue(STRING, "TODO"); +} + +GroundValue clearListStruct(GroundScope* scope, List args) { + // grab fields we need from struct + GroundVariable* sizeField = groundFindVariable(scope, "size"); + if (sizeField == NULL) { + ERROR("A field called \"size\" was not found", "FieldNotFound"); + } + + GroundVariable* memSizeField = groundFindVariable(scope, "memSize"); + if (memSizeField == NULL) { + ERROR("A field called \"memSize\" was not found", "FieldNotFound"); + } + + GroundVariable* ptrField = groundFindVariable(scope, "__ptr"); + if (ptrField == NULL) { + ERROR("A field called \"__ptr\" was not found", "FieldNotFound"); + } + + GroundVariable* capacityField = groundFindVariable(scope, "capacity"); + if (sizeField == NULL) { + ERROR("A field called \"capacity\" was not found", "FieldNotFound"); + } + + sizeField->value.data.intVal = 0; + ptrField->value.data.intVal = (uint64_t)calloc(STARTING_ELEMENTS, sizeof(GroundValue)); + capacityField->value.data.intVal = STARTING_ELEMENTS; + memSizeField->value.data.intVal = sizeof(GroundValue) * STARTING_ELEMENTS; + + return groundCreateValue(INT, 0); +} + +GroundValue insertIntoListStruct(GroundScope* scope, List args) { + GroundValue value = args.values[0]; + uint64_t index = args.values[1].data.intVal; + if (index < 0) { + ERROR("Attempt to insert element into list at negative index", "OutOfBounds"); + } + + // grab fields we need from struct + GroundVariable* sizeField = groundFindVariable(scope, "size"); + if (sizeField == NULL) { + ERROR("A field called \"size\" was not found", "FieldNotFound"); + } + + + GroundVariable* memSizeField = groundFindVariable(scope, "memSize"); + if (memSizeField == NULL) { + ERROR("A field called \"memSize\" was not found", "FieldNotFound"); + } + + GroundVariable* ptrField = groundFindVariable(scope, "__ptr"); + if (ptrField == NULL) { + ERROR("A field called \"__ptr\" was not found", "FieldNotFound"); + } + GroundValue* items = (GroundValue*)ptrField->value.data.intVal; + + GroundVariable* capacityField = groundFindVariable(scope, "capacity"); + if (sizeField == NULL) { + ERROR("A field called \"capacity\" was not found", "FieldNotFound"); + } + int64_t capacity = capacityField->value.data.intVal; + + + if (sizeField->value.data.intVal <= index) { + sizeField->value.data.intVal = index+1; + } else { + sizeField->value.data.intVal++; + } + + // check if we have enough space to insert the element + if (capacity <= sizeField->value.data.intVal+1) { + // not enough space, double size + capacity = sizeField->value.data.intVal + 1; + capacityField->value.data.intVal = capacity; + } + + // allocate new buffer + GroundValue* newBuffer = calloc(capacity, sizeof(GroundValue)); + if (newBuffer == NULL) { + ERROR("Failed to allocate memory when increasing list size!", "MemoryAllocationFailed"); + } + ptrField->value.data.intVal = (uint64_t)newBuffer; + + // copy elements from 0 to i-1 into new buffer + memcpy(newBuffer, items, sizeof(GroundValue) * index); + // insert element at i + newBuffer[index] = value; + // copy elements 0 to i+1 into new buffer + memcpy(newBuffer + (index+1), items + index, sizeof(GroundValue) * (sizeField->value.data.intVal - index)); + + // free older buffer + free(items); + + // retur null + return groundCreateValue(INT, 0); +} + +GroundValue listStructDelete(GroundScope* scope, List args) { + uint64_t index = args.values[0].data.intVal; + if (index < 0) { + ERROR("Attempt to remove element into list at negative index", "OutOfBounds"); + } + + // grab fields we need from struct + GroundVariable* sizeField = groundFindVariable(scope, "size"); + if (sizeField == NULL) { + ERROR("A field called \"size\" was not found", "FieldNotFound"); + } + + + GroundVariable* memSizeField = groundFindVariable(scope, "memSize"); + if (memSizeField == NULL) { + ERROR("A field called \"memSize\" was not found", "FieldNotFound"); + } + + GroundVariable* ptrField = groundFindVariable(scope, "__ptr"); + if (ptrField == NULL) { + ERROR("A field called \"__ptr\" was not found", "FieldNotFound"); + } + GroundValue* items = (GroundValue*)ptrField->value.data.intVal; + + GroundVariable* capacityField = groundFindVariable(scope, "capacity"); + if (sizeField == NULL) { + ERROR("A field called \"capacity\" was not found", "FieldNotFound"); + } + int64_t capacity = capacityField->value.data.intVal; + + printf("size = %ld, index = %ld\n", sizeField->value.data.intVal, index); + if (sizeField->value.data.intVal < index) { + char buffer[512]; + sprintf(buffer, "Attempt to delete element at index %ld when list is of size %ld", index, sizeField->value.data.intVal); + ERROR(buffer, "OutOfBounds"); + } else { + sizeField->value.data.intVal--; + } + + int64_t size = sizeField->value.data.intVal; + + // check if we have enough space to insert the element + if (capacity > size+1) { + // too much space, make list smaller + capacity = size + 1; + capacityField->value.data.intVal = capacity; + } + + // allocate new buffer + GroundValue* newBuffer = calloc(capacity, sizeof(GroundValue)); + if (newBuffer == NULL) { + ERROR("Failed to allocate memory when decreasing list size!", "MemoryAllocationFailed"); + } + ptrField->value.data.intVal = (uint64_t)newBuffer; + + // copy elements from 0 to i-1 into new buffer + + + if (index > 0) + memcpy(newBuffer, items, sizeof(GroundValue) * index); + // copy elements 0 to i+1 into new buffer + if (index < size) + memcpy(newBuffer + index, items + index + 1, sizeof(GroundValue) * (size - index)); + + + // free older buffer + free(items); + + // retur null + return groundCreateValue(INT, 0); +} + +GroundValue listStructSet(GroundScope* scope, List args) { + GroundValue value = args.values[0]; + uint64_t index = args.values[1].data.intVal; + if (index < 0) { + ERROR("Attempt to set element in list at negative index", "OutOfBounds"); + } + + GroundVariable* sizeField = groundFindVariable(scope, "size"); + if (sizeField == NULL) { + ERROR("A field called \"size\" was not found", "FieldNotFound"); + } + int64_t size = sizeField->value.data.intVal; + + GroundVariable* ptrField = groundFindVariable(scope, "__ptr"); + if (ptrField == NULL) { + ERROR("A field called \"__ptr\" was not found", "FieldNotFound"); + } + GroundValue* items = (GroundValue*)ptrField->value.data.intVal; + + if (index >= size) { + insertIntoListStruct(scope, args); + } else { + items[index] = value; + } + + return groundCreateValue(INT, 0); +} + +GroundValue listStructIsEmpty(GroundScope* scope, List args) { + GroundVariable* sizeField = groundFindVariable(scope, "size"); + if (sizeField == NULL) { + ERROR("A field called \"size\" was not found", "FieldNotFound"); + } + int64_t size = sizeField->value.data.intVal; + + return groundCreateValue(BOOL, size <= 0); +} + +bool areGroundValuesEqual(GroundValue a, GroundValue b) { + if (a.type != b.type) { + + if (a.type == INT && b.type == DOUBLE) { + return a.data.intVal == b.data.doubleVal; + } else if (a.type == DOUBLE && b.type == INT) { + return a.data.doubleVal == b.data.intVal; + } + + } else { + switch (a.type) { + case INT: + return a.data.intVal == b.data.intVal; + case DOUBLE: + return a.data.doubleVal == b.data.doubleVal; + case BOOL: + return a.data.boolVal == b.data.boolVal; + case CHAR: + return a.data.charVal == b.data.charVal; + case STRING: + return strcmp(a.data.stringVal, b.data.stringVal) == 0; + default: + return false; + } + } + + return false; +} + +GroundValue listStructContains(GroundScope* scope, List args) { + GroundValue targetValue = args.values[0]; + + GroundVariable* sizeField = groundFindVariable(scope, "size"); + if (sizeField == NULL) { + ERROR("A field called \"size\" was not found", "FieldNotFound"); + } + int64_t size = sizeField->value.data.intVal; + + GroundVariable* ptrField = groundFindVariable(scope, "__ptr"); + if (ptrField == NULL) { + ERROR("A field called \"__ptr\" was not found", "FieldNotFound"); + } + GroundValue* items = (GroundValue*)ptrField->value.data.intVal; + + for (uint64_t i = 0; i < size; i++) { + if (areGroundValuesEqual(items[i], targetValue)) { + return groundCreateValue(BOOL, true); + } + } + + return groundCreateValue(BOOL, false); +} + +GroundValue reverseListStruct(GroundScope* scope, List args) { + return groundCreateValue(INT, 0); +} + +GroundValue createListStruct() { + GroundStruct listStruct = groundCreateStruct(); + + GroundValue* items = calloc(STARTING_ELEMENTS, sizeof(GroundValue)); + + groundAddFieldToStruct(&listStruct, "size", groundCreateValue(INT, 0)); // number of elements + groundAddFieldToStruct(&listStruct, "memSize", groundCreateValue(INT, sizeof(GroundValue) * STARTING_ELEMENTS)); // number of bytes allocated + groundAddFieldToStruct(&listStruct, "capacity", groundCreateValue(INT, STARTING_ELEMENTS)); // number of elements that can fit in the currently allocated space + groundAddFieldToStruct(&listStruct, "__ptr", groundCreateValue(INT, items)); // pointer to internal list struct + + groundAddFunctionToStruct(&listStruct, "append", appendToListStruct, INT, 1, INT, "value"); // append item to end of list + groundAddFunctionToStruct(&listStruct, "string", listStructToString, STRING, 0); // convert list to string + groundAddFunctionToStruct(&listStruct, "insert", insertIntoListStruct, INT, 2, INT, "value", INT, "index"); // insert value at index + groundAddFunctionToStruct(&listStruct, "delete", listStructDelete, INT, 1, INT, "index"); // delete value at index + groundAddFunctionToStruct(&listStruct, "at", listStructAt, INT, 1, INT, "index"); // get value at index + groundAddFunctionToStruct(&listStruct, "clear", clearListStruct, INT, 0); // clear list + groundAddFunctionToStruct(&listStruct, "set", listStructSet, INT, 2, INT, "value", INT, "index"); // replace a value at an index + groundAddFunctionToStruct(&listStruct, "isEmpty", listStructIsEmpty, BOOL, 0); // returns true if list is empty, otherwise false + groundAddFunctionToStruct(&listStruct, "contains", listStructContains, BOOL, 1, INT, "value"); // returns true if value is in list + groundAddFunctionToStruct(&listStruct, "reverse", reverseListStruct, CUSTOM, 0); // return list struct in reverse order + + return groundCreateValue(STRUCTVAL, listStruct); +} \ No newline at end of file diff --git a/libs/collections/list.h b/libs/collections/list.h new file mode 100644 index 0000000..0b7b7d1 --- /dev/null +++ b/libs/collections/list.h @@ -0,0 +1,11 @@ +#ifndef LIST_H +#define LIST_H + +#include +#include + +extern const uint8_t STARTING_ELEMENTS; + +GroundValue createListStruct(); + +#endif \ No newline at end of file