From bcaf7f25f42b21067a26895e097ada73765ba7d5 Mon Sep 17 00:00:00 2001 From: Peter Mikkelsen Date: Wed, 26 Jan 2022 09:40:50 +0000 Subject: Implement a new "mixed" type which can be either of the three scalar types: int, float, rune. This allows scalar arrays with mixed scalar types --- apl9.h | 14 ++++++++++ array.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++-------------- eval.c | 4 ++- print.c | 38 ++++++++++++++----------- quadnames.c | 35 +++++++++++++++++++++++ 5 files changed, 145 insertions(+), 38 deletions(-) diff --git a/apl9.h b/apl9.h index b15b7e6..9004636 100644 --- a/apl9.h +++ b/apl9.h @@ -22,6 +22,7 @@ typedef enum AtypeInt, AtypeFloat, AtypeRune, + AtypeMixed, AtypeArray, } arrayDataType; @@ -57,6 +58,7 @@ typedef enum } errorCodes; /* Data types */ +typedef struct Mixed Mixed; typedef struct Array Array; typedef struct Statement Statement; typedef struct Operator Operator; @@ -69,6 +71,16 @@ typedef struct QuadnameDef QuadnameDef; typedef struct ErrorHandler ErrorHandler; typedef struct DfnFrame DfnFrame; +struct Mixed +{ + int type; + union { + vlong i; + double f; + Rune r; + }; +}; + struct Array { arrayDataType type; @@ -82,6 +94,7 @@ struct Array vlong *intdata; double *floatdata; Rune *runedata; + Mixed *mixeddata; Array **arraydata; }; }; @@ -222,6 +235,7 @@ Array *arrayitem(Array *, int); Array *simplifyarray(Array *); int comparearray(Array *, Array *, int); Array *fillelement(Array *); +uvlong arrayspaceused(Array *); /* eval.c */ Datum *eval(Statement *, int); diff --git a/array.c b/array.c index b6bc87b..1ae2125 100644 --- a/array.c +++ b/array.c @@ -10,6 +10,7 @@ int datasizes[] = { [AtypeInt] = sizeof(vlong), [AtypeFloat] = sizeof(double), [AtypeRune] = sizeof(Rune), + [AtypeMixed] = sizeof(Mixed), [AtypeArray] = sizeof(Array *) }; @@ -63,6 +64,7 @@ duparrayshape(Array *a, int type) { Array *b = allocarray(type, a->rank, a->size); memcpy(b->shape, a->shape, sizeof(int) * a->rank); + b->stranded = a->stranded; return b; } @@ -174,13 +176,21 @@ arrayitem(Array *a, int index) case AtypeRune: res = mkscalarrune(a->runedata[index]); break; + case AtypeMixed: + switch(a->mixeddata[index].type){ + case AtypeInt: res = mkscalarint(a->mixeddata[index].i); break; + case AtypeFloat: res = mkscalarfloat(a->mixeddata[index].f); break; + case AtypeRune: res = mkscalarrune(a->mixeddata[index].r); break; + default: + throwerror(L"Unhandled case in arrayitem", ENotImplemented); + } + break; case AtypeArray: res = a->arraydata[index]; incref(res); break; default: - print("Unhandled case in arrayitem()\n"); - exits(nil); + throwerror(L"Unhandled case in arrayitem", ENotImplemented); } return res; } @@ -189,30 +199,40 @@ Array * simplifyarray(Array *a) { /* simplify an array if possible. */ - if(a->type != AtypeArray || a->size == 0) + if((a->type != AtypeArray && a->type != AtypeMixed) || a->size == 0) return fnSame(a); - int type = a->arraydata[0]->type; + int nested = a->type == AtypeArray; + int type = nested ? a->arraydata[0]->type : a->mixeddata[0].type; int canfloat = type == AtypeFloat || type == AtypeInt; int sametype = 1; + int canmix = 1; int i; for(i = 0; i < a->size; i++){ - int t = a->arraydata[i]->type; + int t = nested ? a->arraydata[i]->type : a->mixeddata[i].type; canfloat = canfloat && (t == AtypeFloat || t == AtypeInt); sametype = sametype && (t == type); - if(a->arraydata[i]->rank != 0) + canmix = canmix && (t != AtypeArray); + if(nested && a->arraydata[i]->rank != 0) return fnSame(a); /* cannot be simplified */ } if(sametype){ - Array *b = allocarray(type, a->rank, a->size); - b->stranded = a->stranded; - for(i = 0; i < a->rank; i++) - b->shape[i] = a->shape[i]; + Array *b = duparrayshape(a, type); for(i = 0; i < a->size; i++){ - memcpy(b->rawdata + i * datasizes[type], a->arraydata[i]->rawdata, datasizes[type]); - if(b->type == AtypeArray) - incref(b->arraydata[i]); + if(nested){ + memcpy(b->rawdata + i * datasizes[type], a->arraydata[i]->rawdata, datasizes[type]); + if(b->type == AtypeArray) + incref(b->arraydata[i]); + }else{ + switch(b->type){ + case AtypeInt: b->intdata[i] = a->mixeddata[i].i; break; + case AtypeFloat: b->floatdata[i] = a->mixeddata[i].f; break; + case AtypeRune: b->runedata[i] = a->mixeddata[i].r; break; + default: + throwerror(L"Missing case in simplifyarray", ENotImplemented); + } + } } if(b->type == AtypeArray){ Array *tmp = b; @@ -221,15 +241,32 @@ simplifyarray(Array *a) } return b; }else if(canfloat){ - Array *b = allocarray(AtypeFloat, a->rank, a->size); - b->stranded = a->stranded; - for(i = 0; i < a->rank; i++) - b->shape[i] = a->shape[i]; + Array *b = duparrayshape(a, AtypeFloat); for(i = 0; i < a->size; i++){ - if(a->arraydata[i]->type == AtypeFloat) - b->floatdata[i] = a->arraydata[i]->floatdata[0]; - else - b->floatdata[i] = a->arraydata[i]->intdata[0]; + if(nested){ + if(a->arraydata[i]->type == AtypeFloat) + b->floatdata[i] = a->arraydata[i]->floatdata[0]; + else + b->floatdata[i] = a->arraydata[i]->intdata[0]; + }else{ + if(a->mixeddata[i].type == AtypeFloat) + b->floatdata[i] = a->mixeddata[i].f; + else + b->floatdata[i] = a->mixeddata[i].i; + } + } + return b; + }else if(canmix && nested){ + Array *b = duparrayshape(a, AtypeMixed); + for(i = 0; i < a->size; i++){ + b->mixeddata[i].type = a->arraydata[i]->type; + switch(b->mixeddata[i].type){ + case AtypeInt: b->mixeddata[i].i = a->arraydata[i]->intdata[0]; break; + case AtypeFloat: b->mixeddata[i].f = a->arraydata[i]->floatdata[0]; break; + case AtypeRune: b->mixeddata[i].r = a->arraydata[i]->runedata[0]; break; + default: + throwerror(L"Missing case in simplifyarray", ENotImplemented); + } } return b; }else @@ -304,4 +341,17 @@ fillelement(Array *a) exits(nil); return 0; } +} + +uvlong +arrayspaceused(Array *a) +{ + uvlong size = 0; + size += sizeof(*a); + size += sizeof(int) * a->rank; + size += datasizes[a->type] * a->size; + + for(int i = 0; i < a->size && a->type == AtypeArray; i++) + size += arrayspaceused(a->arraydata[i]); + return size; } \ No newline at end of file diff --git a/eval.c b/eval.c index aff3f73..e33c3b5 100644 --- a/eval.c +++ b/eval.c @@ -164,9 +164,11 @@ strand(Datum left, Datum right) result.shy = 0; Array *leftarr = left.array->stranded ? fnSame(left.array) : fnEnclose(left.array); Array *rightarr = right.array->stranded ? fnSame(right.array) : fnEnclose(right.array); + Array *tmp = fnCatenateFirst(leftarr, rightarr); result.tag = ArrayTag; - result.array = fnCatenateFirst(leftarr, rightarr); + result.array = simplifyarray(tmp); result.array->stranded = 1; + freearray(tmp); freearray(leftarr); freearray(rightarr); return result; diff --git a/print.c b/print.c index e46866c..3c119dd 100644 --- a/print.c +++ b/print.c @@ -63,24 +63,30 @@ pparray(Array *a) Rune *arrstr = pparray(a->arraydata[i]); elemstrs[i] = runesmprint("%S", arrstr); free(arrstr); - }else if(a->type == AtypeInt) - elemstrs[i] = runesmprint("%lld", a->intdata[i]); - else if(a->type == AtypeRune) - elemstrs[i] = runesmprint("%C", a->runedata[i]); - else if(a->type == AtypeFloat){ - char *fmt = smprint("%%.%df", printprecision); - elemstrs[i] = runesmprint(fmt, a->floatdata[i]); - free(fmt); - Rune *p = &elemstrs[i][runestrlen(elemstrs[i])-1]; - int done = 0; - while((*p == '0' || *p == '.') && !done){ - if(*p == '.') - done = 1; - *p-- = 0; /* remove trailing 0's */ + }else{ + Array *e = arrayitem(a, i); /* a scalar */ + if(e->type == AtypeInt) + elemstrs[i] = runesmprint("%lld", e->intdata[0]); + else if(e->type == AtypeRune) + elemstrs[i] = runesmprint("%C", e->runedata[0]); + else if(e->type == AtypeFloat){ + char *fmt = smprint("%%.%df", printprecision); + elemstrs[i] = runesmprint(fmt, e->floatdata[0]); + free(fmt); + Rune *p = &elemstrs[i][runestrlen(elemstrs[i])-1]; + int done = 0; + while((*p == '0' || *p == '.') && !done){ + if(*p == '.') + done = 1; + *p-- = 0; /* remove trailing 0's */ + } } + + if(elemstrs[i][0] == '-' && (e->type == AtypeInt || e->type == AtypeFloat)) + elemstrs[i][0] = L'¯'; + freearray(e); } - if(elemstrs[i][0] == '-' && (a->type == AtypeInt || a->type == AtypeFloat)) - elemstrs[i][0] = L'¯'; + } int lastdim = a->rank ? a->shape[a->rank-1] : 1; diff --git a/quadnames.c b/quadnames.c index 8ce54e1..2646840 100644 --- a/quadnames.c +++ b/quadnames.c @@ -16,6 +16,7 @@ void setdiv(Datum); Array *runfile(Array *); Array *quadthrow1(Array *); Array *quadthrow2(Array *, Array *); +Array *quadinfo(Array *); QuadnameDef quadnames[] = { {L"⎕", NameTag, getquad, setquad, nil, nil}, @@ -24,6 +25,7 @@ QuadnameDef quadnames[] = { {L"⎕DIV", NameTag, getdiv, setdiv, nil, nil}, {L"⎕RUN", FunctionTag, nil, nil, runfile, nil}, {L"⎕THROW", FunctionTag, nil, nil, quadthrow1, quadthrow2}, + {L"⎕INFO", FunctionTag, nil, nil, quadinfo, nil}, {nil, 0, nil, nil, nil, nil} /* MUST BE LAST */ }; @@ -190,4 +192,37 @@ quadthrow2(Array *msg, Array *code) throwerror(nil, ERank); throwerror(pparray(msg), code->intdata[0]); return nil; +} + +/* ⎕INFO */ +Array * +quadinfo(Array *a) +{ + if(a->type != AtypeRune) + throwerror(nil, EType); + Rune *code = pparray(a); + Datum *res = evalline(code, nil, 0); + Rune *info; + switch(res->tag){ + case ArrayTag:{ + char *typestring = "?"; + switch(res->array->type){ + case AtypeInt: typestring = "int"; break; + case AtypeFloat: typestring = "float"; break; + case AtypeRune: typestring = "rune"; break; + case AtypeMixed: typestring = "mixed"; break; + case AtypeArray: typestring = "array"; break; + } + uvlong size = arrayspaceused(res->array); + info = runesmprint("Type = %s, size in bytes = %ulld", typestring, size); + break; + } + default: + info = runesmprint("Can't show info for datum tag %d", res->tag); + } + Array *infoarr = mkrunearray(info); + free(code); + free(res); + free(info); + return infoarr; } \ No newline at end of file -- cgit v1.2.3