Login
7 branches 0 tags
Benjamin Vincent Schulenburg Moved array code/definitions into the separate array.[ch] file 82ea821 4 years ago 14 Commits
nujel / lib / array.c
/*
 * Wolkenwelten - Copyright (C) 2020-2021 - Benjamin Vincent Schulenburg
 *
 * This project uses the MIT license, a copy should be included under /LICENSE
 */
#include "array.h"

#include "casting.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

lArray   lArrayList[ARR_MAX];
uint     lArrayActive = 0;
uint     lArrayMax    = 1;
uint     lArrayFFree  = 0;

void lInitArray(){
	lArrayActive    = 0;
	lArrayMax       = 1;
}

u32 lArrayAlloc(){
	lArray *ret;
	if(lArrayFFree == 0){
		if(lArrayMax >= ARR_MAX-1){
			lPrintError("lArray OOM ");
			return 0;
		}
		ret = &lArrayList[lArrayMax++];
	}else{
		ret = &lArrayList[lArrayFFree & ARR_MASK];;
		lArrayFFree = ret->nextFree;
	}
	lArrayActive++;
	*ret = (lArray){0};
	return ret - lArrayList;
}

void lArrayFree(u32 v){
	v = v & ARR_MASK;
	if((v == 0) || (v >= lArrayMax)){return;}
	lArrayActive--;
	free(lArrayList[v].data);
	lArrayList[v].data = NULL;
	lArrayList[v].nextFree = lArrayFFree;
	lArrayFFree = v;
}

lVal *lnfArrLength(lClosure *c, lVal *v){
	lVal *arr = lEval(c,lCar(v));
	if((arr == NULL) || (arr->type != ltArray)){return lValInt(0);}
	return lValInt(lArrLength(arr));
}

lVal *lnfArrRef(lClosure *c, lVal *v){
	lVal *arr = lEval(c,lCar(v));
	if((arr == NULL) || (arr->type != ltArray) || (v == NULL)){return NULL;}
	v = lCdr(v);
	lVal *t = lEval(c, lCar(v));
	if(t == NULL){return arr;}
	if((t->type != ltInt) && (t->type != ltFloat)){return NULL;}
	const lVal *lkey = lnfInt(c,t);
	if(lkey == NULL){return NULL;}
	const int key = lkey->vInt;
	if((key < 0) || (key >= lArrLength(arr))){return NULL;}
	const int val = lArrData(arr)[key];
	return lValD(val);
}

lVal *lnfArrSet(lClosure *c, lVal *v){
	lVal *arr = lEval(c,lCar(v));
	if((arr == NULL) || (arr->type != ltArray) || (v == NULL)){return NULL;}
	v = lCdr(v);
	lVal *t = lEval(c, lCar(v));
	if(t == NULL){return NULL;}
	if((t->type != ltInt) && (t->type != ltFloat)){return NULL;}
	const lVal *lkey = lnfInt(c,t);
	if(lkey == NULL){return NULL;}
	int key = lkey->vInt;
	if((key < 0) || (key >= lArrLength(arr))){return NULL;}
	v = lCdr(v);
	forEach(cur,v){
		lVal *cv = lEval(c,lCar(cur));
		lArrData(arr)[key++] = cv == NULL ? 0 : lValI(cv);
		if(key >= lArrLength(arr)){return NULL;}
	}
	int val = lArrData(arr)[key];
	return lValD(val);
}

lVal *lnfArrNew(lClosure *c, lVal *v){
	lVal *t = lnfInt(c,v);
	if((t == NULL) || (t->type != ltInt)){return NULL;}
	lVal *r = lValAlloc();
	r->type = ltArray;
	r->vCdr = lArrayAlloc();
	lArrLength(r) = t->vInt;
	lArrData(r) = malloc(t->vInt * sizeof(*lArrData(r)));
	if(lArrData(r) == NULL){
		lArrLength(r) = 0;
		return NULL;
	}
	memset(lArrData(r),0,lArrLength(r) * sizeof(*lArrData(r)));
	return r;
}

lVal *lnfArr(lClosure *c, lVal *v){
	if((c == NULL) || (v == NULL)){return NULL;}
	lVal *vals = lApply(c,v,lEval);;
	int length = lListLength(vals);
	lVal *r = lValAlloc();
	r->type = ltArray;
	r->vCdr = lArrayAlloc();
	if(r->vCdr == 0){return NULL;}
	lArray *arr = &lArr(r);
	arr->length = length;
	arr->data = malloc(length * sizeof(*arr->data));
	if(arr->data == NULL){
		arr->length = 0;
		lValFree(r);
		return NULL;
	}
	memset(lArrData(r),0,lArrLength(r) * sizeof(*arr->data));
	int key = 0;
	forEach(cur,vals){
		lArrData(r)[key++] = lValI(lCar(cur));
	}
	return r;
}

lVal *lnfArrPred(lClosure *c, lVal *v){
	lVal *arr = lEval(c,lCar(v));
	if((arr == NULL) || (arr->type != ltArray)){return lValBool(false);}
	return lValBool(true);
}

void lAddArrayFuncs(lClosure *c){
	lAddNativeFunc(c,"arr-length", "[array]",    "Return length of ARRAY",                          lnfArrLength);
	lAddNativeFunc(c,"arr-ref",    "[array index]",  "Return value of ARRAY at position INDEX",     lnfArrRef);
	lAddNativeFunc(c,"arr-set!",   "[array index &...values]","Set ARRAY at INDEX to &...VALUES",   lnfArrSet);
	lAddNativeFunc(c,"arr-new",    "[size]",     "Allocate a new array of SIZE",                    lnfArrNew);
	lAddNativeFunc(c,"arr",        "[...args]",  "Create a new array from ...ARGS",                 lnfArr);
	lAddNativeFunc(c,"array? arr?","[val]",     "Return #t if VAL is an array",                     lnfArrPred);
}