// First Cell and Select (⊏) // First Cell is just a slice // Complications in Select mostly come from range checks and negative 𝕨 // Atom or enclosed atom 𝕨 and rank-1 𝕩: make new array // Atom or enclosed atom 𝕨 and high-rank 𝕩: slice // Empty 𝕨: no selection // Float or generic 𝕨: attempt to squeeze, go generic cell size path if stays float // High-rank 𝕩 & boolean 𝕨: either widens 𝕨 to i8, or goes generic cell path // SHOULD go a bit select path for small cells // SHOULD reshape for 1=≠𝕩 // Boolean 𝕩 (cell size = 1 bit): // 𝕨 larger than 𝕩: convert 𝕩 to i8, select, convert back // Otherwise: select/shift bytes, reversed for fast writing // TRIED pext, doesn't seem faster (mask built with shifts anyway) // 𝕩 with cell sizes of 1, 2, 4, or 8 bytes: // Small 𝕩 and i8 𝕨 with Singeli: use shuffles // Boolean 𝕨: use bit_sel for blend or similar // Integer 𝕨 with Singeli: fused wrap, range-check, and gather // COULD try selecting from boolean with gather // COULD detect = 4) { \ switch(xl) { default:UD; CASEW(3,u8); CASEW(4,u16); CASEW(5,u32); CASEW(6,u64); } \ } else { \ W* wt = NULL; \ for (usz bl=(1<<14)/sizeof(W), i0=0, i1=0; i0wia) i1=wia; \ W min=wp[i0], max=min; for (usz i=i0+1; imax) max=e; if (e=(i64)xn) thrF("⊏: Indexing out-of-bounds (%iβˆŠπ•¨, %s≑≠𝕩)", max, xn); \ W* ip=wp; usz off=xn; \ if (max>=0) { off=0; if (RARE(min<0)) { \ if (RARE(xn > (1ULL<<(sizeof(W)*8-1)))) { w=taga(NEXT(w)); mm_free((Value*)r); return C2(select, w, x); } \ if (!wt) {wt=TALLOCP(W,i1-i0);} ip=wt-i0;\ for (usz i=i0; i=256 : wia>=4) && csz<128) { // test widen/narrow on bitarr input // ShArr* sh = RNK(x)==1? NULL : ptr_inc(shObj(x)); // B t = C2(select, w, widenBitArr(x, 1)); // B r = narrowWidenedBitArr(t, wr, xr-1, sh==NULL? &xn : sh->a+1); // if (sh!=NULL) ptr_dec(sh); // return r; if (csz==1) { if (wia/4>=xia) return taga(cpyBitArr(C2(select, w, taga(cpyI8Arr(x))))); } else if (csz>64? wia/2>=xn : wia>=xn/2) { ShArr* sh = ptr_inc(shObj(x)); B t = C2(select, w, widenBitArr(x, 1)); B r = narrowWidenedBitArr(t, wr, xr-1, sh->a+1); ptr_dec(sh); return r; } } #define TYPE(W, NEXT) { W* wp = W##any_ptr(w); \ if (xl==0) { u64* xp=bitarr_ptr(x); \ u64* rp; r = m_bitarrp(&rp, ria); \ BOOL_SPECIAL(W) \ u64 b=0; \ for (usz i = wia; ; ) { \ i--; \ usz n = WRAP(wp[i], xn, thrF("⊏: Indexing out-of-bounds (%iβˆŠπ•¨, %s≑≠𝕩)", wp[i], xn)); \ b = 2*b + ((((u8*)xp)[n/8] >> (n%8)) & 1); \ if (i%64 == 0) { rp[i/64]=b; if (!i) break; } \ } \ goto setsh; \ } \ if (xe!=el_B) { \ if (xl<3 || xl==7) goto generic_l; \ void* rp = m_tyarrlp(&r, xl-3, ria, arrNewType(TY(x))); \ void* xp = tyany_ptr(x); \ CPUSEL(W, NEXT) \ goto setsh; \ } \ if (xl!=6) goto generic_l; \ M_HARR(ra, wia); B* xp = arr_bptr(x); \ SLOWIF(xp==NULL) SLOW2("π•¨βŠπ•©", w, x); \ if (xp!=NULL) { for (usz i=0; i=xn) { badw=c; goto bad1; } cf_call(f, rm->a, ri, xp, c*f.mul); ri+= f.mul; } // TODO something better case el_i8: for (; ia, ri, xp, c*f.mul); ri+= f.mul; } case el_i16: for (; ia, ri, xp, c*f.mul); ri+= f.mul; } case el_i32: for (; ia, ri, xp, c*f.mul); ri+= f.mul; } } assert(!isVal(xf)); r = a(mut_fv(rm)); } else { MUTG_INIT(rm); for (; i < wia; i++) { B cw = GetU(w, i); // assumed number from previous squeeze usz c = WRAP(o2i64(cw), xn, { badw=o2fG(cw); goto bad1; }); mut_copyG(rm, i*csz, x, csz*c, csz); } r = a(withFill(mut_fv(rm), xf)); } goto setsh; bad1:; mut_pfree(rm, i*csz); thrF("⊏: Indexing out-of-bounds (%fβˆŠπ•¨, %H≑≒𝕩)", badw, x); } setsh: if (rr>1) { if (rr > UR_MAX) thrF("⊏: Result rank too large (%i≑=𝕨, %i≑=𝕩)", wr, xr); ShArr* sh = m_shArr(rr); shcpy(sh->a, SH(w), wr); shcpy(sh->a+wr, SH(x)+1, xr-1); arr_shSetU(r, rr, sh); } else { arr_shVec(r); } dec_ret:; decG(w); decG(x); return taga(r); } B select_ucw(B t, B o, B w, B x) { if (isAtm(x) || RNK(x)!=1 || isAtm(w)) return def_fn_ucw(t, o, w, x); usz xia = IA(x); usz wia = IA(w); SGetU(w) if (TI(w,elType)!=el_i32) for (usz i = 0; i < wia; i++) if (!q_i64(GetU(w,i))) return def_fn_ucw(t, o, w, x); B arg = select_c2(t, inc(w), inc(x)); B rep = c1(o, arg); if (isAtm(rep) || !eqShape(w, rep)) thrF("π”½βŒΎ(a⊸⊏)𝕩: Result of 𝔽 must have the same shape as 'a' (expected %H, got %H)", w, rep); #if CHECK_VALID TALLOC(bool, set, xia); bool sparse = wia < xia/64; if (!sparse) for (i64 i = 0; i < xia; i++) set[i] = false; #define SPARSE_INIT(WI) \ if (sparse) for (usz i = 0; i < wia; i++) { \ i64 cw = WI; if (RARE(cw<0)) cw+= (i64)xia; set[cw] = false; \ } #define EQ(F) if (set[cw] && (F)) thrM("π”½βŒΎ(a⊸⊏): Incompatible result elements"); set[cw] = true; #define FREE_CHECK TFREE(set) SLOWIF(xia>100 && wia100 && wiare?xe:re; bool reuse = reusable(x); if (me==el_i32) { I32Arr* xn = reuse? toI32Arr(REUSE(x)) : (I32Arr*)cpyI32Arr(x); i32* xp = i32arrv_ptr(xn); rep = toI32Any(rep); i32* rp = i32any_ptr(rep); for (usz i = 0; i < wia; i++) { i64 cw = wp[i]; if (RARE(cw<0)) cw+= (i64)xia; // we're free to assume w is valid i32 cr = rp[i]; EQ(cr != xp[cw]); xp[cw] = cr; } decG(w); decG(rep); FREE_CHECK; return taga(xn); } else if (me==el_i8) { I8Arr* xn = reuse? toI8Arr(REUSE(x)) : (I8Arr*)cpyI8Arr(x); i8* xp = i8arrv_ptr(xn); rep = toI8Any(rep); i8* rp = i8any_ptr(rep); for (usz i = 0; i < wia; i++) { i64 cw = wp[i]; if (RARE(cw<0)) cw+= (i64)xia; i8 cr = rp[i]; EQ(cr != xp[cw]); xp[cw] = cr; } decG(w); decG(rep); FREE_CHECK; return taga(xn); } else if (me==el_i16) { I16Arr* xn = reuse? toI16Arr(REUSE(x)) : (I16Arr*)cpyI16Arr(x); i16* xp = i16arrv_ptr(xn); rep = toI16Any(rep); i16* rp = i16any_ptr(rep); for (usz i = 0; i < wia; i++) { i64 cw = wp[i]; if (RARE(cw<0)) cw+= (i64)xia; i16 cr = rp[i]; EQ(cr != xp[cw]); xp[cw] = cr; } decG(w); decG(rep); FREE_CHECK; return taga(xn); } else if (me==el_bit) { BitArr* xn = reuse? toBitArr(REUSE(x)) : (BitArr*)cpyBitArr(x); u64* xp = bitarrv_ptr(xn); rep = taga(toBitArr(rep)); u64* rp = bitarr_ptr(rep); for (usz i = 0; i < wia; i++) { i64 cw = wp[i]; if (RARE(cw<0)) cw+= (i64)xia; bool cr = bitp_get(rp, i); EQ(cr != bitp_get(xp,cw)); bitp_set(xp,cw,cr); } decG(w); decG(rep); FREE_CHECK; return taga(xn); } else if (me==el_f64) { F64Arr* xn = reuse? toF64Arr(REUSE(x)) : (F64Arr*)cpyF64Arr(x); f64* xp = f64arrv_ptr(xn); rep = toF64Any(rep); f64* rp = f64any_ptr(rep); for (usz i = 0; i < wia; i++) { i64 cw = wp[i]; if (RARE(cw<0)) cw+= (i64)xia; f64 cr = rp[i]; EQ(cr != xp[cw]); xp[cw] = cr; } decG(w); decG(rep); FREE_CHECK; return taga(xn); } else UD; } if (reusable(x) && xe==re) { if (TY(x)==t_harr) { B* xp = harr_ptr(REUSE(x)); SGet(rep) for (usz i = 0; i < wia; i++) { i64 cw = wp[i]; if (RARE(cw<0)) cw+= (i64)xia; B cr = Get(rep, i); EQ(!equal(cr,xp[cw])); dec(xp[cw]); xp[cw] = cr; } decG(w); decG(rep); FREE_CHECK; return x; } } MAKE_MUT_INIT(r, xia, el_or(xe, re)); MUTG_INIT(r); mut_copyG(r, 0, x, 0, xia); SGet(rep) for (usz i = 0; i < wia; i++) { i64 cw = wp[i]; if (RARE(cw<0)) cw+= (i64)xia; B cr = Get(rep, i); EQ(!equal(mut_getU(r, cw), cr)); mut_rm(r, cw); mut_setG(r, cw, cr); } decG(w); decG(rep); FREE_CHECK; return mut_fcd(r, x); } MAKE_MUT_INIT(r, xia, el_or(xe, re)); MUTG_INIT(r); mut_copyG(r, 0, x, 0, xia); SGet(rep) SPARSE_INIT(o2i64G(GetU(w, i))) for (usz i = 0; i < wia; i++) { i64 cw = o2i64G(GetU(w, i)); if (RARE(cw<0)) cw+= (i64)xia; B cr = Get(rep, i); EQ(!equal(mut_getU(r, cw), cr)); mut_rm(r, cw); mut_setG(r, cw, cr); } decG(w); decG(rep); FREE_CHECK; return mut_fcd(r, x); #undef SPARSE_INIT #undef EQ #undef FREE_CHECK }