2026-04-11 19:47:12 +10:00
# include "hashmap.h"
# include <groundext.h>
# include <groundvm.h>
2026-04-17 10:09:40 +10:00
# include <stdint.h>
2026-04-11 19:47:12 +10:00
# include <stdlib.h>
# include <string.h>
# include <uthash.h>
# include <stdio.h>
2026-04-12 09:47:27 +10:00
GroundStruct hashmapStruct = { } ;
2026-04-11 19:47:12 +10:00
GroundValue hashmapStructSet ( GroundScope * scope , List args ) {
char * key = args . values [ 0 ] . data . stringVal ;
GroundValue value = args . values [ 1 ] ;
2026-04-13 12:09:49 +10:00
GroundVariable * ptrField = groundFindVariable ( scope , " ptr " ) ;
2026-04-11 19:47:12 +10:00
if ( ptrField = = NULL ) {
2026-04-13 12:09:49 +10:00
ERROR ( " A field called \" ptr \" was not found " , " FieldNotFound " ) ;
2026-04-11 19:47:12 +10:00
}
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 ;
2026-04-13 12:09:49 +10:00
GroundVariable * ptrField = groundFindVariable ( scope , " ptr " ) ;
2026-04-11 19:47:12 +10:00
if ( ptrField = = NULL ) {
2026-04-13 12:09:49 +10:00
ERROR ( " A field called \" ptr \" was not found " , " FieldNotFound " ) ;
2026-04-11 19:47:12 +10:00
}
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 ] ;
2026-04-13 12:09:49 +10:00
GroundVariable * ptrField = groundFindVariable ( scope , " ptr " ) ;
2026-04-11 19:47:12 +10:00
if ( ptrField = = NULL ) {
2026-04-13 12:09:49 +10:00
ERROR ( " A field called \" ptr \" was not found " , " FieldNotFound " ) ;
2026-04-11 19:47:12 +10:00
}
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 ;
2026-04-13 12:09:49 +10:00
GroundVariable * ptrField = groundFindVariable ( scope , " ptr " ) ;
2026-04-11 19:47:12 +10:00
if ( ptrField = = NULL ) {
2026-04-13 12:09:49 +10:00
ERROR ( " A field called \" ptr \" was not found " , " FieldNotFound " ) ;
2026-04-11 19:47:12 +10:00
}
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 ;
2026-04-13 12:09:49 +10:00
GroundVariable * ptrField = groundFindVariable ( scope , " ptr " ) ;
2026-04-11 19:47:12 +10:00
if ( ptrField = = NULL ) {
2026-04-13 12:09:49 +10:00
ERROR ( " A field called \" ptr \" was not found " , " FieldNotFound " ) ;
2026-04-11 19:47:12 +10:00
}
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 ) ;
}
2026-04-12 09:47:27 +10:00
GroundValue hashmapStructConstructor ( GroundScope * scope , List args ) {
GroundValue value = groundCreateValue ( CUSTOM , & hashmapStruct ) ;
value . type = CUSTOM ;
return value ;
}
2026-04-13 12:09:49 +10:00
GroundValue destroyHashmapStruct ( GroundScope * scope , List args ) {
GroundVariable * ptrField = groundFindVariable ( scope , " ptr " ) ;
if ( ptrField = = NULL ) {
ERROR ( " A field called \" ptr \" was not found " , " FieldNotFound " ) ;
}
HashmapItem * keys = ( HashmapItem * ) ptrField - > value . data . intVal ;
HashmapItem * current , * temp ;
HASH_ITER ( hh , keys , current , temp ) {
HASH_DEL ( keys , current ) ;
free ( current - > key ) ;
free ( current ) ;
}
return groundCreateValue ( NONE ) ;
}
2026-04-17 10:09:40 +10:00
GroundValue duplicateHashmapStruct ( GroundScope * scope , List args ) {
GroundObject * self = args . values [ 0 ] . data . customVal ;
GroundValue newSelf = groundCreateValue ( CUSTOM , & hashmapStruct ) ;
HashmapItem * src , * dst = NULL , * item , * tmp ;
HASH_ITER ( hh , src , item , tmp ) {
HashmapItem * copy = malloc ( sizeof ( HashmapItem ) ) ;
* copy = * item ;
HASH_ADD_KEYPTR ( hh , dst , copy - > key , strlen ( copy - > key ) , copy ) ;
}
GroundVariable * ptrField = groundFindVariable ( scope , " ptr " ) ;
if ( ptrField = = NULL ) {
ERROR ( " A field called \" ptr \" was not found " , " FieldNotFound " ) ;
}
ptrField - > value . data . intVal = ( int64_t ) src ;
return newSelf ;
}
2026-04-12 09:47:27 +10:00
void initHashmaps ( GroundScope * scope ) {
hashmapStruct = groundCreateStruct ( ) ;
2026-04-11 19:47:12 +10:00
2026-04-13 12:09:49 +10:00
groundAddFieldToStruct ( & hashmapStruct , " ptr " , groundCreateValue ( INT , 0 ) ) ;
2026-04-11 19:47:12 +10:00
groundAddFunctionToStruct ( & hashmapStruct , " set " , hashmapStructSet , INT , 2 , STRING , " key " , ANY , " value " ) ; // set a key in the hashmap
2026-04-11 19:57:35 +10:00
groundAddFunctionToStruct ( & hashmapStruct , " get " , hashmapStructGet , ANY , 1 , STRING , " key " ) ; // get a key in the hashmap, throws KeyNotFound if the key does not exist
groundAddFunctionToStruct ( & hashmapStruct , " getOr " , hashmapStructGetOr , ANY , 2 , STRING , " key " , ANY , " default " ) ; // get a key in the hashmap, or fallback to a default value
2026-04-11 19:47:12 +10:00
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
2026-04-13 12:09:49 +10:00
groundAddFunctionToStruct ( & hashmapStruct , " destructor " , destroyHashmapStruct , ANY , 0 ) ;
2026-04-17 10:09:40 +10:00
groundAddFunctionToStruct ( & hashmapStruct , " duplicator " , duplicateHashmapStruct , ANY , 1 , CUSTOM ) ;
2026-04-12 09:47:27 +10:00
groundAddNativeFunction ( scope , " newHashmap " , hashmapStructConstructor , CUSTOM , 0 ) ;
groundAddNativeFunction ( scope , " Hashmap_SOLS_CONSTRUCTOR " , hashmapStructConstructor , CUSTOM , 0 ) ;
2026-04-11 19:47:12 +10:00
}