working i8/i16-arrs

This commit is contained in:
dzaima 2021-09-05 16:06:13 +03:00
parent 80be141968
commit 21ba88751a
13 changed files with 183 additions and 203 deletions

View File

@ -80,9 +80,7 @@ Extra functions for converting types:
o2cu(x) // B → c32, assumes is valid
o2fu(x) // B → f64, assumes is valid
o2b(x) // B → bool, throw if impossible
q_i32(x) // query if x is convertible to i32
q_i64(x) // query if x is convertible to i64
q_f64(x) // query if x is convertible to f64 (equivalent to isF64)
q_TYPE(x) // query if x is convertible to TYPE (see definitions in h.h)
q_N(x) // query if x is · (≡ bi_N)
noFill(x) // if x represents undefined fill (returned by getFill*; ≡ bi_noFill)
tag(x,*_TAG) // pointer → B

View File

@ -29,13 +29,23 @@ void ud_rec(B** p, usz d, usz r, i32* pos, usz* sh) {
B ud_c1(B t, B x) {
if (isAtm(x)) {
usz xu = o2s(x);
if (RARE(xu>=I32_MAX)) {
f64* rp; B r = m_f64arrv(&rp, xu);
if (LIKELY(xu<=I8_MAX)) {
if (RARE(xu==0)) return emptyIVec();
i8* rp; B r = m_i8arrv(&rp, xu);
for (usz i = 0; i < xu; i++) rp[i] = i;
return r;
}
if (xu==0) return emptyIVec();
i32* rp; B r = m_i32arrv(&rp, xu);
if (xu<=I16_MAX) {
i16* rp; B r = m_i16arrv(&rp, xu);
for (usz i = 0; i < xu; i++) rp[i] = i;
return r;
}
if (xu<=I32_MAX) {
i32* rp; B r = m_i32arrv(&rp, xu);
for (usz i = 0; i < xu; i++) rp[i] = i;
return r;
}
f64* rp; B r = m_f64arrv(&rp, xu);
for (usz i = 0; i < xu; i++) rp[i] = i;
return r;
}

View File

@ -26,9 +26,21 @@
#define TYARR_SZ(T,IA) fsizeof(T##Arr, a, T##Atom, IA)
#define TYARR_SZ2(T,IA) TYARR_SZ(T,IA)
#define TU I8
#define TP(W,X) W##i8##X
#include "core/tyarrTemplate.h"
#define TU I16
#define TP(W,X) W##i16##X
#include "core/tyarrTemplate.h"
#define TU I32
#define TP(W,X) W##i32##X
#include "core/tyarrTemplate.h"
#define TU C8
#define TP(W,X) W##c8##X
#include "core/tyarrTemplate.h"
#define TU C16
#define TP(W,X) W##c16##X
#include "core/tyarrTemplate.h"
#define TU C32
#define TP(W,X) W##c32##X
#include "core/tyarrTemplate.h"

View File

@ -29,8 +29,8 @@ static bool fillEqual(B w, B x) {
static B getFillR(B x) { // doesn't consume; can return bi_noFill
if (isArr(x)) {
switch(TI(x,elType)) { default: UD;
case el_f64: case el_i32: return m_i32(0);
case el_c32: return m_c32(' ');
case el_i8: case el_i16: case el_i32: case el_f64: return m_i32(0);
case el_c8: case el_c16: case el_c32: return m_c32(' ');
case el_B:;
u8 t = v(x)->type;
if (t==t_fillarr ) return inc(c(FillArr,x )->fill);

View File

@ -355,7 +355,7 @@ NOINLINE bool equal(B w, B x) { // doesn't consume
usz ia = a(x)->ia;
u8 we = TI(w,elType);
u8 xe = TI(x,elType);
if (we<=el_f64 && xe<=el_f64) { assert(we==el_i32|we==el_f64); assert(xe==el_i32|xe==el_f64);
if (((we==el_f64 | we==el_i32) && (xe==el_f64 | xe==el_i32))) {
if (we==el_i32) { i32* wp = i32any_ptr(w);
if(xe==el_i32) { i32* xp = i32any_ptr(x); for (usz i = 0; i < ia; i++) if(wp[i]!=xp[i]) return false; }
else { f64* xp = f64any_ptr(x); for (usz i = 0; i < ia; i++) if(wp[i]!=xp[i]) return false; }
@ -439,8 +439,12 @@ char* format_type(u8 u) {
case t_md2BI:return"builtin md2"; case t_md2_block:return"md2 block";
case t_fork:return"fork"; case t_atop:return"atop";
case t_md1D:return"md1D"; case t_md2D:return"md2D"; case t_md2H:return"md2H";
case t_harr :return"harr" ; case t_i8arr :return"i8arr" ; case t_i32arr :return"i32arr" ; case t_fillarr :return"fillarr" ; case t_c32arr :return"c32arr" ; case t_f64arr :return"f64arr" ;
case t_hslice:return"hslice"; case t_i8slice:return"i8slice"; case t_i32slice:return"i32slice"; case t_fillslice:return"fillslice"; case t_c32slice:return"c32slice"; case t_f64slice:return"f64slice";
case t_i8arr :return"i8arr" ; case t_i16arr :return"i16arr" ; case t_i32arr :return"i32arr" ;
case t_i8slice:return"i8slice"; case t_i16slice:return"i16slice"; case t_i32slice:return"i32slice";
case t_c8arr :return"c8arr" ; case t_c16arr :return"c16arr" ; case t_c32arr :return"c32arr" ;
case t_c8slice:return"c8slice"; case t_c16slice:return"c16slice"; case t_c32slice:return"c32slice";
case t_harr :return"harr" ; case t_fillarr :return"fillarr" ; case t_f64arr :return"f64arr" ;
case t_hslice:return"hslice"; case t_fillslice:return"fillslice"; case t_f64slice:return"f64slice";
case t_comp:return"comp"; case t_block:return"block"; case t_body:return"body"; case t_scope:return"scope"; case t_scopeExt:return"scope extension"; case t_blBlocks: return "block list";
case t_ns:return"ns"; case t_nsDesc:return"nsDesc"; case t_fldAlias:return"alias"; case t_hashmap:return"hashmap"; case t_temp:return"temporary"; case t_nfn:return"nfn"; case t_nfnDesc:return"nfnDesc";
case t_freed:return"(freed by GC)"; case t_harrPartial:return"partHarr";

View File

@ -1,13 +1,27 @@
#include "../core.h"
#define TU F64
#define TP(W,X) W##f64##X
B m_i8(i8 x) { return m_i32(x); } B m_i16(i16 x) { return m_i32(x); }
B m_c8(i8 x) { return m_c32(x); } B m_c16(i16 x) { return m_c32(x); }
#define TU I8
#define TP(W,X) W##i8##X
#include "tyarrTemplate.c"
#define TU I16
#define TP(W,X) W##i16##X
#include "tyarrTemplate.c"
#define TU I32
#define TP(W,X) W##i32##X
#include "tyarrTemplate.c"
#define TU C8
#define TP(W,X) W##c8##X
#include "tyarrTemplate.c"
#define TU C16
#define TP(W,X) W##c16##X
#include "tyarrTemplate.c"
#define TU C32
#define TP(W,X) W##c32##X
#include "tyarrTemplate.c"
#define TU I32
#define TP(W,X) W##i32##X
#define TU F64
#define TP(W,X) W##f64##X
#include "tyarrTemplate.c"
NOINLINE B m_caf64(usz sz, f64* a) { f64* rp; B r = m_f64arrv(&rp, sz); for (usz i = 0; i < sz; i++) rp[i] = a[i]; return r; }
@ -22,6 +36,9 @@ NOINLINE B m_str32(u32* s) {
}
void tyarr_init() {
i8arr_init(); i16arr_init(); i32arr_init();
c8arr_init(); c16arr_init(); c32arr_init(); f64arr_init();
{ i32* tmp; bi_emptyIVec = m_i32arrv(&tmp, 0); gc_add(bi_emptyIVec); }
{ u32* tmp; bi_emptyCVec = m_c32arrv(&tmp, 0); gc_add(bi_emptyCVec); }

View File

@ -17,7 +17,7 @@ static B TP(,arr_get) (B x, usz n) { VTY(x,T_ARR ); return TP(m_,) (c(TArr ,
static B TP(,slice_get) (B x, usz n) { VTY(x,T_SLICE); return TP(m_,) (c(TSlice,x)->a[n]); }
static bool TP(,arr_canStore) (B x) { return TP(q_,) (x); }
void TP(,arr_init)() {
static void TP(,arr_init)() {
TIi(T_ARR,get) = TP(,arr_get); TIi(T_SLICE,get) = TP(,slice_get);
TIi(T_ARR,getU) = TP(,arr_get); TIi(T_SLICE,getU) = TP(,slice_get);
TIi(T_ARR,slice) = TP(,arr_slice); TIi(T_SLICE,slice) = TP(,slice_slice);

25
src/h.h
View File

@ -100,6 +100,10 @@
#define i64 int64_t
#define u64 uint64_t
#define f64 double
#define I8_MAX 127
#define I16_MAX 65535
#define I8_MIN (-128)
#define I16_MIN (-65536)
#define I32_MAX ((i32)((1LL<<31)-1))
#define I32_MIN ((i32)(-(1LL<<31)))
#define I64_MIN ((i64)(1ULL<<63))
@ -174,8 +178,8 @@ enum Type {
/* 8*/ t_fork, t_atop,
/*10*/ t_md1D, t_md2D, t_md2H,
/*13*/ t_harr , t_i8arr , t_i32arr , t_fillarr , t_c32arr , t_f64arr ,
/*19*/ t_hslice, t_i8slice, t_i32slice, t_fillslice, t_c32slice, t_f64slice,
/*13*/ t_i8arr , t_i16arr , t_i32arr , t_c8arr , t_c16arr , t_c32arr , t_f64arr , t_harr , t_fillarr ,
/*19*/ t_i8slice, t_i16slice, t_i32slice, t_c8slice, t_c16slice, t_c32slice, t_f64slice, t_hslice, t_fillslice,
/*25*/ t_comp, t_block, t_body, t_scope, t_scopeExt, t_blBlocks,
/*31*/ t_ns, t_nsDesc, t_fldAlias, t_vfyObj, t_hashmap, t_temp, t_nfn, t_nfnDesc,
@ -187,11 +191,18 @@ enum Type {
};
enum ElType { // a⌈b shall return the type that can store both, if possible; any x<=el_f64 is an integer type
el_i32=0,
el_f64=1,
el_c32=2,
el_B =3,
el_MAX=4 // also used for incomplete in mut.c
el_bit=0, // unused; just here for completeness of ElType
el_i8 =1,
el_i16=2,
el_i32=3,
el_f64=4,
el_c8 =5,
el_c16=6,
el_c32=7,
el_B =8,
el_MAX=9 // also used for incomplete in mut.c
};

View File

@ -5,7 +5,7 @@
#include "utils/file.h"
#include "utils/builtins.h"
#define FOR_INIT(F) F(base) F(harr) F(fillarr) F(i32arr) F(c32arr) F(f64arr) F(tyarr) F(hash) F(sfns) F(fns) F(arith) F(md1) F(md2) F(derv) F(comp) F(rtWrap) F(ns) F(nfn) F(sysfn) F(load) F(sysfnPost)
#define FOR_INIT(F) F(base) F(harr) F(mutF) F(fillarr) F(tyarr) F(hash) F(sfns) F(fns) F(arith) F(md1) F(md2) F(derv) F(comp) F(rtWrap) F(ns) F(nfn) F(sysfn) F(load) F(sysfnPost)
#define F(X) void X##_init(void);
FOR_INIT(F)
#undef F
@ -227,7 +227,6 @@ void load_init() { // very last init function
#ifndef NO_RT
B provide[] = {bi_type,bi_fill,bi_log,bi_grLen,bi_grOrd,bi_asrt,bi_add,bi_sub,bi_mul,bi_div,bi_pow,bi_floor,bi_eq,bi_le,bi_fne,bi_shape,bi_pick,bi_ud,bi_tbl,bi_scan,bi_fillBy,bi_val,bi_catch};
#ifndef ALL_R0
B runtime_0[] = {bi_floor,bi_ceil,bi_stile,bi_lt,bi_gt,bi_ne,bi_ge,bi_rtack,bi_ltack,bi_join,bi_take,bi_drop,bi_select,bi_const,bi_swap,bi_each,bi_fold,bi_atop,bi_over,bi_before,bi_after,bi_cond,bi_repeat};
#else

View File

@ -24,6 +24,6 @@
#include "../ns.c"
#include "../nfns.c"
#include "../rtwrap.c"
#include "../jit/nvm.c"
#include "../load.c"
#include "../main.c"
#include "../jit/nvm.c"

View File

@ -7,7 +7,7 @@
/* sfns.c*/A(shape,"") A(pick,"") A(pair,"{𝕨‿𝕩}") A(select,"") A(slash,"/") A(join,"") A(couple,"") A(shiftb,"»") A(shifta,"«") A(take,"") A(drop,"") A(group,"") A(reverse,"") \
/* sort.c*/A(gradeUp,"") A(gradeDown,"") \
/* everything before the definition of •Type is defined to be pure, and everything after is not */ \
/* sysfn.c*/M(type,"•Type") M(decp,"•Decompose") M(primInd,"•PrimInd") M(glyph,"•Glyph") A(fill,"•FillFn") M(sys,"•getsys") A(grLen,"•GroupLen") D(grOrd,"groupOrd") \
/* sysfn.c*/M(type,"•Type") M(decp,"•Decompose") M(primInd,"•PrimInd") M(glyph,"•Glyph") A(fill,"•FillFn") M(sys,"•getsys") A(grLen,"•GroupLen") D(grOrd,"GroupOrd") \
/* sysfn.c*/M(repr,"•Repr") M(fmt,"•Fmt") A(asrt,"!") A(casrt,"!") M(out,"•Out") M(show,"•Show") M(bqn,"•BQN") M(sh,"•SH") M(fromUtf8,"•FromUTF8") \
/* sysfn.c*/D(cmp,"•Cmp") A(hash,"•Hash") M(unixTime,"•UnixTime") M(monoTime,"•MonoTime") M(delay,"•Delay") M(makeRand,"•MakeRand") M(reBQN,"•ReBQN") M(exit,"•Exit") M(getLine,"•GetLine") \
/*internal.c*/M(itype,"•internal.Type") M(refc,"•internal.Refc") M(squeeze,"•internal.Squeeze") M(isPure,"•internal.IsPure") A(info,"•internal.Info") \

View File

@ -42,3 +42,17 @@ NOINLINE void mut_pfree(Mut* m, usz n) { // free the first n elements
if (m->type==el_B) harr_pfree(taga(m->val), n);
else mm_free((Value*) m->val);
}
u8 el_orArr[el_MAX*16 + el_MAX];
void mutF_init() {
for (u8 i = 0; i <= el_MAX; i++) {
for (u8 j = 0; j <= el_MAX; j++) {
u8 el;
if (i==el_MAX|j==el_MAX) el = i>j?j:i;
else if (i<=el_f64 && j<=el_f64) el = i>j?i:j;
else if (i>=el_c8 && i<=el_c32 && j>=el_c8 && j<=el_c32) el = i>j?i:j;
else el = el_B;
el_orArr[i*16 + j] = el;
}
}
}

View File

@ -18,9 +18,9 @@ typedef struct Mut {
usz ia;
Arr* val;
union {
i32* ai32;
i8* ai8; i16* ai16; i32* ai32;
u8* ac8; u16* ac16; u32* ac32;
f64* af64;
u32* ac32;
B* aB;
};
} Mut;
@ -33,9 +33,13 @@ static void mut_init(Mut* m, u8 n) {
usz sz;
// hack around inlining of the allocator too many times
switch(n) { default: UD;
case el_i8: ty = t_i8arr ; sz = TYARR_SZ(I8, ia); break;
case el_i16: ty = t_i16arr; sz = TYARR_SZ(I16,ia); break;
case el_i32: ty = t_i32arr; sz = TYARR_SZ(I32,ia); break;
case el_f64: ty = t_f64arr; sz = TYARR_SZ(F64,ia); break;
case el_c8: ty = t_c8arr ; sz = TYARR_SZ(C8, ia); break;
case el_c16: ty = t_c16arr; sz = TYARR_SZ(C16,ia); break;
case el_c32: ty = t_c32arr; sz = TYARR_SZ(C32,ia); break;
case el_f64: ty = t_f64arr; sz = TYARR_SZ(F64,ia); break;
case el_B:;
HArr_p t = m_harrUp(ia);
m->val = (Arr*)t.c;
@ -45,9 +49,9 @@ static void mut_init(Mut* m, u8 n) {
Arr* a = m_arr(sz, ty, ia);
m->val = a;
switch(n) { default: UD; // gcc generates horrible code for this (which should just be two instructions), but that's what gcc does
case el_i32: m->ai32 = ((I32Arr*)a)->a; break;
case el_i8: m->ai8 = ((I8Arr*)a)->a; break; case el_i16: m->ai16 = ((I16Arr*)a)->a; break; case el_i32: m->ai32 = ((I32Arr*)a)->a; break;
case el_c8: m->ac8 = ((C8Arr*)a)->a; break; case el_c16: m->ac16 = ((C16Arr*)a)->a; break; case el_c32: m->ac32 = ((C32Arr*)a)->a; break;
case el_f64: m->af64 = ((F64Arr*)a)->a; break;
case el_c32: m->ac32 = ((C32Arr*)a)->a; break;
}
}
void mut_to(Mut* m, u8 n);
@ -73,16 +77,9 @@ static Arr* mut_fp(Mut* m) { assert(m->type!=el_MAX);
return m->val;
}
extern u8 el_orArr[];
static u8 el_or(u8 a, u8 b) {
#define M(X) if(b==X) return a>X?a:X;
switch (a) { default: UD;
case el_c32: M(el_c32); return el_B;
case el_i32: M(el_i32); M(el_f64); return el_B;
case el_f64: M(el_i32); M(el_f64); return el_B;
case el_B: return el_B;
case el_MAX: return b;
}
#undef M
return el_orArr[a*16 + b];
}
void mut_pfree(Mut* m, usz n);
@ -151,70 +148,15 @@ static B mut_getU(Mut* m, usz ms) {
}
}
// doesn't consume; fills m[ms…ms+l] with x
static void mut_fill(Mut* m, usz ms, B x, usz l) {
again:;
u8 nty;
switch(m->type) { default: UD;
case el_MAX:
nty = isF64(x)? (q_i32(x)? el_i32 : el_f64) : (isC32(x)? el_c32 : el_B);
goto change;
case el_i32: {
if (RARE(!q_i32(x))) { nty = isF64(x)? el_f64 : el_B; goto change; }
i32* p = m->ai32+ms;
i32 v = o2iu(x);
for (usz i = 0; i < l; i++) p[i] = v;
return;
}
case el_c32: {
if (RARE(!isC32(x))) { nty = el_B; goto change; }
u32* p = m->ac32+ms;
u32 v = o2cu(x);
for (usz i = 0; i < l; i++) p[i] = v;
return;
}
case el_f64: {
if (RARE(!isF64(x))) { nty = el_B; goto change; }
f64* p = m->af64+ms;
f64 v = o2fu(x);
for (usz i = 0; i < l; i++) p[i] = v;
return;
}
case el_B: {
B* p = m->aB+ms;
for (usz i = 0; i < l; i++) p[i] = x;
if (isVal(x)) for (usz i = 0; i < l; i++) inc(x);
return;
}
}
change:
mut_to(m, nty);
goto again;
}
static void mut_fillG(Mut* m, usz ms, B x, usz l) { // doesn't consume x
switch(m->type) { default: UD;
case el_i32: {
assert(q_i32(x));
i32* p = m->ai32+ms;
i32 v = o2iu(x);
for (usz i = 0; i < l; i++) p[i] = v;
return;
}
case el_c32: {
assert(isC32(x));
u32* p = m->ac32+ms;
u32 v = o2cu(x);
for (usz i = 0; i < l; i++) p[i] = v;
return;
}
case el_f64: {
assert(isF64(x));
f64* p = m->af64+ms;
f64 v = o2fu(x);
for (usz i = 0; i < l; i++) p[i] = v;
return;
}
case el_i8: { assert(q_i8 (x)); i8* p = m->ai8 +ms; i8 v = o2iu(x); for (usz i = 0; i < l; i++) p[i] = v; return; }
case el_i16: { assert(q_i16(x)); i16* p = m->ai16+ms; i16 v = o2iu(x); for (usz i = 0; i < l; i++) p[i] = v; return; }
case el_i32: { assert(q_i32(x)); i32* p = m->ai32+ms; i32 v = o2iu(x); for (usz i = 0; i < l; i++) p[i] = v; return; }
case el_c8: { assert(q_c8 (x)); u8* p = m->ac8 +ms; u8 v = o2cu(x); for (usz i = 0; i < l; i++) p[i] = v; return; }
case el_c16: { assert(q_c16(x)); u16* p = m->ac16+ms; u16 v = o2cu(x); for (usz i = 0; i < l; i++) p[i] = v; return; }
case el_c32: { assert(q_c32(x)); u32* p = m->ac32+ms; u32 v = o2cu(x); for (usz i = 0; i < l; i++) p[i] = v; return; }
case el_f64: { assert(isF64(x)); f64* p = m->af64+ms; f64 v = o2fu(x); for (usz i = 0; i < l; i++) p[i] = v; return; }
case el_B: {
B* p = m->aB+ms;
for (usz i = 0; i < l; i++) p[i] = x;
@ -224,110 +166,83 @@ static void mut_fillG(Mut* m, usz ms, B x, usz l) { // doesn't consume x
}
}
// doesn't consume; fills m[ms…ms+l] with x
static void mut_fill(Mut* m, usz ms, B x, usz l) {
u8 nmt = el_or(m->type, selfElType(x));
if (nmt!=m->type) mut_to(m, nmt);
mut_fillG(m, ms, x, l);
}
// mut_copy but x is guaranteed to be a subtype of m
static void mut_copyG(Mut* m, usz ms, B x, usz xs, usz l) { assert(isArr(x));
// printf("mut_%d[%d…%d] ← %s[%d…%d]\n", m->type, ms, ms+l, format_type(xt), xs, xs+l); fflush(stdout);
u8 xt = v(x)->type;
switch(m->type) { default: UD;
case el_i8: { i8* rp = m->ai8+ms; i8* xp = i8any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
case el_i16: { i16* rp = m->ai16+ms;
switch (xt) { default: UD;
case t_i8arr: case t_i8slice: { i8* xp = i8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
case t_i16arr: case t_i16slice: { i16* xp = i16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
}
}
case el_i32: { i32* rp = m->ai32+ms;
switch (xt) { default: UD;
case t_i8arr: case t_i8slice: { i8* xp = i8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
case t_i16arr: case t_i16slice: { i16* xp = i16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
case t_i32arr: case t_i32slice: { i32* xp = i32any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
}
}
case el_c8: { u8* rp = m->ac8+ms; u8* xp = c8any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
case el_c16: { u16* rp = m->ac16+ms;
switch (xt) { default: UD;
case t_c8arr: case t_c8slice: { u8* xp = c8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
case t_c16arr: case t_c16slice: { u16* xp = c16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
}
}
case el_c32: { u32* rp = m->ac32+ms;
switch (xt) { default: UD;
case t_c8arr: case t_c8slice: { u8* xp = c8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
case t_c16arr: case t_c16slice: { u16* xp = c16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
case t_c32arr: case t_c32slice: { u32* xp = c32any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
}
}
case el_f64: {
f64* rp = m->af64+ms;
switch (xt) { default: UD;
case t_i8arr: case t_i8slice: { i8* xp = i8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
case t_i16arr: case t_i16slice: { i16* xp = i16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
case t_i32arr: case t_i32slice: { i32* xp = i32any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
case t_f64arr: case t_f64slice: { f64* xp = f64any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }
}
}
case el_B: {
B* mpo = m->aB+ms;
B* xp;
if (xt==t_harr) xp = harr_ptr(x);
else if (xt==t_hslice) xp = c(HSlice,x)->a;
else if (xt==t_fillarr) xp = c(FillArr,x)->a;
else {
BS2B xget = TIi(xt,get);
for (usz i = 0; i < l; i++) mpo[i] = xget(x,i+xs);
return;
}
memcpy(mpo, xp+xs, l*sizeof(B*));
for (usz i = 0; i < l; i++) inc(mpo[i]);
return;
}
}
}
// expects x to be an array, each position must be written to precisely once
// doesn't consume x
static void mut_copy(Mut* m, usz ms, B x, usz xs, usz l) { // TODO try harder to not bump type
assert(isArr(x));
u8 xt = v(x)->type;
u8 xe = TIi(xt,elType);
// printf("mut_%d[%d…%d] ← %s[%d…%d]\n", m->type, ms, ms+l, format_type(xt), xs, xs+l); fflush(stdout);
again:
switch(m->type) { default: UD;
case el_MAX: goto change;
case el_i32: {
if (RARE(xt!=t_i32arr & xt!=t_i32slice)) goto change;
i32* xp = i32any_ptr(x);
memcpy(m->ai32+ms, xp+xs, l*4);
return;
}
case el_c32: {
if (RARE(xt!=t_c32arr & xt!=t_c32slice)) goto change;
u32* xp = c32any_ptr(x);
memcpy(m->ac32+ms, xp+xs, l*4);
return;
}
case el_f64: {
f64* xp;
if (xt==t_f64arr) xp = f64arr_ptr(x);
else if (xt==t_f64slice) xp = c(F64Slice,x)->a;
else if (LIKELY(xt==t_i32arr|xt==t_i32slice)) {
i32* xp = i32any_ptr(x);
f64* rp = m->af64+ms;
for (usz i = 0; i < l; i++) rp[i] = xp[i+xs];
return;
}
else goto change;
memcpy(m->af64+ms, xp+xs, l*8);
return;
}
case el_B: {
B* mpo = m->aB+ms;
B* xp;
if (xt==t_harr) xp = harr_ptr(x);
else if (xt==t_hslice) xp = c(HSlice,x)->a;
else if (xt==t_fillarr) xp = c(FillArr,x)->a;
else {
BS2B xget = TIi(xt,get);
for (usz i = 0; i < l; i++) mpo[i] = xget(x,i+xs);
return;
}
memcpy(mpo, xp+xs, l*sizeof(B*));
for (usz i = 0; i < l; i++) inc(mpo[i]);
return;
}
}
change:
mut_to(m, el_or(m->type, xe));
goto again;
}
static void mut_copyG(Mut* m, usz ms, B x, usz xs, usz l) { // mut_copy but x is guaranteed to be a subtype of m
assert(isArr(x));
u8 xt = v(x)->type;
switch(m->type) { default: UD;
case el_i32: {
i32* xp = i32any_ptr(x);
memcpy(m->ai32+ms, xp+xs, l*4);
return;
}
case el_c32: {
u32* xp = c32any_ptr(x);
memcpy(m->ac32+ms, xp+xs, l*4);
return;
}
case el_f64: {
f64* xp;
if (xt==t_f64arr) xp = f64arr_ptr(x);
else if (xt==t_f64slice) xp = c(F64Slice,x)->a;
else {
assert(TIi(xt,elType)==el_i32);
i32* xp = i32any_ptr(x);
f64* rp = m->af64+ms;
for (usz i = 0; i < l; i++) rp[i] = xp[i+xs];
return;
}
memcpy(m->af64+ms, xp+xs, l*8);
return;
}
case el_B: {
B* mpo = m->aB+ms;
B* xp;
if (xt==t_harr) xp = harr_ptr(x);
else if (xt==t_hslice) xp = c(HSlice,x)->a;
else if (xt==t_fillarr) xp = c(FillArr,x)->a;
else {
BS2B xget = TIi(xt,get);
for (usz i = 0; i < l; i++) mpo[i] = xget(x,i+xs);
return;
}
memcpy(mpo, xp+xs, l*sizeof(B*));
for (usz i = 0; i < l; i++) inc(mpo[i]);
return;
}
}
static void mut_copy(Mut* m, usz ms, B x, usz xs, usz l) { assert(isArr(x));
u8 nmt = el_or(m->type, TI(x,elType));
if (nmt!=m->type) mut_to(m, nmt);
mut_copyG(m, ms, x, xs, l);
}
static B vec_join(B w, B x) { // consumes both
usz wia = a(w)->ia;
usz xia = a(x)->ia;