added hashmaps and fixed some small issues with lists

This commit is contained in:
2026-04-11 19:47:12 +10:00
parent a1ad1fe139
commit 8a3093c30f
4 changed files with 184 additions and 31 deletions

View File

@@ -2,7 +2,9 @@
#include <groundvm.h>
#include "list.h"
#include "hashmap.h"
void ground_init(GroundScope* scope) {
groundAddValueToScope(scope, "List", createListStruct());
groundAddValueToScope(scope, "Hashmap", createHashmapStruct());
}

132
libs/collections/hashmap.c Normal file
View File

@@ -0,0 +1,132 @@
#include "hashmap.h"
#include <groundext.h>
#include <groundvm.h>
#include <stdlib.h>
#include <string.h>
#include <uthash.h>
#include <stdio.h>
GroundValue hashmapStructSet(GroundScope* scope, List args) {
char* key = args.values[0].data.stringVal;
GroundValue value = args.values[1];
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
HashmapItem* keys = (HashmapItem*)ptrField->value.data.intVal;
HashmapItem* newItem = malloc(sizeof(HashmapItem));
newItem->key = strdup(key);
newItem->value = value;
HASH_ADD_KEYPTR(hh, keys, newItem->key, strlen(newItem->key), newItem);
ptrField->value.data.intVal = (long long)keys;
return groundCreateValue(INT, 0);
}
GroundValue hashmapStructGet(GroundScope* scope, List args) {
char* query = args.values[0].data.stringVal;
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
HashmapItem* keys = (HashmapItem*)ptrField->value.data.intVal;
HashmapItem* out;
HASH_FIND_STR(keys, query, out);
if (out == NULL) {
ERROR("Key was not found in hashmap (tip: use hashmap.getOr if you want to specify a fallback value)", "KeyNotFound");
}
return out->value;
}
GroundValue hashmapStructGetOr(GroundScope* scope, List args) {
char* query = args.values[0].data.stringVal;
GroundValue fallback = args.values[1];
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
HashmapItem* keys = (HashmapItem*)ptrField->value.data.intVal;
HashmapItem* out;
HASH_FIND_STR(keys, query, out);
if (out == NULL)
return fallback;
return out->value;
}
GroundValue hashmapStructRemove(GroundScope* scope, List args) {
char* query = args.values[0].data.stringVal;
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
HashmapItem* keys = (HashmapItem*)ptrField->value.data.intVal;
HashmapItem* out;
HASH_FIND_STR(keys, query, out);
if (out == NULL) {
ERROR("Key was not found in hashmap (tip: use hashmap.removeIfPresent if you want to avoid errors)", "KeyNotFound");
}
HASH_DEL(keys, out);
free(out->key);
free(out);
return groundCreateValue(INT, 0);
}
GroundValue hashmapStructRemoveIfPresent(GroundScope* scope, List args) {
char* query = args.values[0].data.stringVal;
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
HashmapItem* keys = (HashmapItem*)ptrField->value.data.intVal;
HashmapItem* out;
HASH_FIND_STR(keys, query, out);
if (out == NULL) {
return groundCreateValue(BOOL, false);
}
HASH_DEL(keys, out);
free(out->key);
free(out);
return groundCreateValue(BOOL, true);
}
GroundValue createHashmapStruct() {
GroundStruct hashmapStruct = groundCreateStruct();
groundAddFieldToStruct(&hashmapStruct, "private_ptr", groundCreateValue(INT, 0));
groundAddFunctionToStruct(&hashmapStruct, "set", hashmapStructSet, INT, 2, STRING, "key", ANY, "value"); // set a key in the hashmap
groundAddFunctionToStruct(&hashmapStruct, "get", hashmapStructGet, INT, 1, STRING, "key"); // get a key in the hashmap, throws KeyNotFound if the key does not exist
groundAddFunctionToStruct(&hashmapStruct, "getOr", hashmapStructGetOr, INT, 2, STRING, "key", ANY, "default"); // get a key in the hashmap, or fallback to a default value
groundAddFunctionToStruct(&hashmapStruct, "remove", hashmapStructRemove, INT, 1, STRING, "key"); // remove a key from the hashmap, throws KeyNotFound if the key does not exist
groundAddFunctionToStruct(&hashmapStruct, "removeIfPresent", hashmapStructRemoveIfPresent, BOOL, 1, STRING, "key"); // remove a key from the hashmap, returns true if the key was removed or false if it didn't exist
return groundCreateValue(STRUCTVAL, hashmapStruct);
}

View File

@@ -0,0 +1,16 @@
#ifndef HASHMAP_H
#define HASHMAP_H
#include <groundext.h>
#include <groundvm.h>
#include <uthash.h>
typedef struct {
GroundValue value;
char* key;
UT_hash_handle hh;
} HashmapItem;
GroundValue createHashmapStruct();
#endif

View File

@@ -6,7 +6,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uthash.h>
const uint8_t STARTING_ELEMENTS = 2;
@@ -25,9 +24,9 @@ GroundValue appendToListStruct(GroundScope* scope, List args) {
ERROR("A field called \"memSize\" was not found", "FieldNotFound");
}
GroundVariable* ptrField = groundFindVariable(scope, "__ptr");
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"__ptr\" was not found", "FieldNotFound");
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
GroundValue* items = (GroundValue*)ptrField->value.data.intVal;
@@ -77,9 +76,9 @@ GroundValue listStructAt(GroundScope* scope, List args) {
ERROR(buffer, "OutOfBounds");
}
GroundVariable* ptrField = groundFindVariable(scope, "__ptr");
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"__ptr\" was not found", "FieldNotFound");
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
GroundValue* items = (GroundValue*)ptrField->value.data.intVal;
@@ -102,9 +101,9 @@ GroundValue clearListStruct(GroundScope* scope, List args) {
ERROR("A field called \"memSize\" was not found", "FieldNotFound");
}
GroundVariable* ptrField = groundFindVariable(scope, "__ptr");
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"__ptr\" was not found", "FieldNotFound");
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
GroundVariable* capacityField = groundFindVariable(scope, "capacity");
@@ -112,8 +111,13 @@ GroundValue clearListStruct(GroundScope* scope, List args) {
ERROR("A field called \"capacity\" was not found", "FieldNotFound");
}
GroundValue* newBuffer = calloc(STARTING_ELEMENTS, sizeof(GroundValue));
if (newBuffer == NULL) {
ERROR("Failed to allocate memory when clearing list!", "MemoryAllocationFailed");
}
sizeField->value.data.intVal = 0;
ptrField->value.data.intVal = (int64_t)calloc(STARTING_ELEMENTS, sizeof(GroundValue));
ptrField->value.data.intVal = (int64_t)newBuffer;
capacityField->value.data.intVal = STARTING_ELEMENTS;
memSizeField->value.data.intVal = sizeof(GroundValue) * STARTING_ELEMENTS;
@@ -138,9 +142,9 @@ GroundValue insertIntoListStruct(GroundScope* scope, List args) {
ERROR("A field called \"memSize\" was not found", "FieldNotFound");
}
GroundVariable* ptrField = groundFindVariable(scope, "__ptr");
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"__ptr\" was not found", "FieldNotFound");
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
GroundValue* items = (GroundValue*)ptrField->value.data.intVal;
@@ -204,9 +208,9 @@ GroundValue listStructDelete(GroundScope* scope, List args) {
ERROR("A field called \"memSize\" was not found", "FieldNotFound");
}
GroundVariable* ptrField = groundFindVariable(scope, "__ptr");
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"__ptr\" was not found", "FieldNotFound");
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
GroundValue* items = (GroundValue*)ptrField->value.data.intVal;
@@ -270,9 +274,9 @@ GroundValue listStructSet(GroundScope* scope, List args) {
}
int64_t size = sizeField->value.data.intVal;
GroundVariable* ptrField = groundFindVariable(scope, "__ptr");
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"__ptr\" was not found", "FieldNotFound");
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
GroundValue* items = (GroundValue*)ptrField->value.data.intVal;
@@ -333,9 +337,9 @@ GroundValue listStructContains(GroundScope* scope, List args) {
}
int64_t size = sizeField->value.data.intVal;
GroundVariable* ptrField = groundFindVariable(scope, "__ptr");
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"__ptr\" was not found", "FieldNotFound");
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
GroundValue* items = (GroundValue*)ptrField->value.data.intVal;
@@ -361,9 +365,9 @@ GroundValue reverseListStruct(GroundScope* scope, List args) {
}
int64_t capacity = capacityField->value.data.intVal;
GroundVariable* ptrField = groundFindVariable(scope, "__ptr");
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"__ptr\" was not found", "FieldNotFound");
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
GroundValue* items = (GroundValue*)ptrField->value.data.intVal;
@@ -389,9 +393,9 @@ GroundValue findListStruct(GroundScope* scope, List args) {
}
int64_t size = sizeField->value.data.intVal;
GroundVariable* ptrField = groundFindVariable(scope, "__ptr");
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"__ptr\" was not found", "FieldNotFound");
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
GroundValue* items = (GroundValue*)ptrField->value.data.intVal;
@@ -413,9 +417,9 @@ GroundValue reserveListStruct(GroundScope* scope, List args) {
}
int64_t capacity = capacityField->value.data.intVal;
GroundVariable* ptrField = groundFindVariable(scope, "__ptr");
GroundVariable* ptrField = groundFindVariable(scope, "private_ptr");
if (ptrField == NULL) {
ERROR("A field called \"__ptr\" was not found", "FieldNotFound");
ERROR("A field called \"private_ptr\" was not found", "FieldNotFound");
}
GroundValue* items = (GroundValue*)ptrField->value.data.intVal;
@@ -449,17 +453,16 @@ GroundValue createListStruct() {
groundAddFieldToStruct(&listStruct, "capacity", groundCreateValue(INT, STARTING_ELEMENTS)); // number of elements that can fit in the currently allocated space
groundAddFieldToStruct(&listStruct, "private_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, "append", appendToListStruct, INT, 1, ANY, "value"); // append item to end of list
groundAddFunctionToStruct(&listStruct, "insert", insertIntoListStruct, INT, 2, ANY, "value", INT, "index"); // insert value at index
groundAddFunctionToStruct(&listStruct, "remove", 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, "set", listStructSet, INT, 2, ANY, "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, "contains", listStructContains, BOOL, 1, ANY, "value"); // returns true if value is in list
groundAddFunctionToStruct(&listStruct, "reverse", reverseListStruct, INT, 0); // return list struct in reverse order
groundAddFunctionToStruct(&listStruct, "find", findListStruct, INT, 1, INT, "value"); // return index of value in list, if not found, returns -1
groundAddFunctionToStruct(&listStruct, "find", findListStruct, INT, 1, ANY, "value"); // return index of value in list, if not found, returns -1
groundAddFunctionToStruct(&listStruct, "reserve", reserveListStruct, BOOL, 1, INT, "amount"); // ensure list capacity >= amount. returns true if the list's capacity was expanded
return groundCreateValue(STRUCTVAL, listStruct);