forked from ground/ground
core of lists done
This commit is contained in:
8
libs/collections/collections.c
Normal file
8
libs/collections/collections.c
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include <groundext.h>
|
||||||
|
#include <groundvm.h>
|
||||||
|
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
void ground_init(GroundScope* scope) {
|
||||||
|
groundAddValueToScope(scope, "List", createListStruct());
|
||||||
|
}
|
||||||
378
libs/collections/list.c
Normal file
378
libs/collections/list.c
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
#include "list.h"
|
||||||
|
#include <groundext.h>
|
||||||
|
#include <groundvm.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <uthash.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
11
libs/collections/list.h
Normal file
11
libs/collections/list.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef LIST_H
|
||||||
|
#define LIST_H
|
||||||
|
|
||||||
|
#include <groundext.h>
|
||||||
|
#include <groundvm.h>
|
||||||
|
|
||||||
|
extern const uint8_t STARTING_ELEMENTS;
|
||||||
|
|
||||||
|
GroundValue createListStruct();
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user