// First Cell and Select (⊏) // First Cell is just a slice // Complications in Select mostly come from range checks and negative 𝕨 // Atom 𝕨 and any rank 𝕩: slice // Rank-1 𝕩: // Empty 𝕨: no selection // Small 𝕩 with Singeli: use shuffles // Boolean 𝕨: use bit_sel for blend or similar // Boolean 𝕩 and larger 𝕨: convert to i8, select, convert back // Boolean 𝕩 otherwise: select/shift bytes, reversed for fast writing // TRIED pext, doesn't seem faster (mask built with shifts anyway) // SHOULD squeeze 𝕨 if not ≀i32 to get to optimized cases // Integer 𝕨 with Singeli: fused wrap, range-check, and gather // COULD try selecting from boolean with gather // COULD detect = 4) { \ switch(xw) { default:UD; CASEW(1,u8); CASEW(2,u16); CASEW(4,u32); CASEW(8,f64); } \ } 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)xia) thrF("⊏: Indexing out-of-bounds (%iβˆŠπ•¨, %s≑≠𝕩)", max, xia); \ W* ip=wp; usz off=xia; \ if (max>=0) { off=0; if (RARE(min<0)) { \ if (RARE(xia > (1ULL<<(sizeof(W)*8-1)))) { w=taga(NEXT(w)); mm_free(v(r)); return select_c2(m_f64(0), w, x); } \ if (!wt) {wt=TALLOCP(W,i1-i0);} ip=wt-i0; \ for (usz i=i0; i> (n%8)) & 1); \ if (i%64 == 0) { rp[i/64]=b; if (!i) break; } \ } \ goto dec_ret; \ } \ if (xe!=el_B) { \ usz xw = elWidth(xe); \ void* rp = m_tyarrc(&r, xw, w, el2t(xe)); \ void* xp = tyany_ptr(x); \ CPUSEL(W, NEXT) \ goto dec_ret; \ } \ M_HARR(r, wia); \ if (TY(x)==t_harr || TY(x)==t_hslice) { \ B* xp = hany_ptr(x); \ for (usz i=0; i < wia; i++) HARR_ADD(r, i, inc(xp[WRAP(wp[i], xia, thrF("⊏: Indexing out-of-bounds (%iβˆŠπ•¨, %s≑≠𝕩)", wp[i], xia))])); \ decG(x); return HARR_FCD(r, w); \ } SLOW2("π•¨βŠπ•©", w, x); \ for (usz i=0; i < wia; i++) HARR_ADD(r, i, Get(x, WRAP(wp[i], xia, thrF("⊏: Indexing out-of-bounds (%iβˆŠπ•¨, %s≑≠𝕩)", wp[i], xia)))); \ decG(x); return withFill(HARR_FCD(r,w),xf); \ } if (xe==el_bit && wia>=256 && !BOOL_USE_SIMD && wia/4>=xia && we!=el_bit) { return taga(cpyBitArr(select_c2(m_f64(0), w, taga(cpyI8Arr(x))))); } if (we==el_bit) { SGetU(x) B x0 = GetU(x, 0); B x1; if (xia<2) { u64* wp=bitarr_ptr(w); usz i; for (i=0; iUR_MAX) thrF("⊏: Result rank too large (%i≑=𝕨, %i≑=𝕩)", wr, xr); usz csz = arr_csz(x); usz cam = SH(x)[0]; MAKE_MUT(r, wia*csz); mut_init(r, TI(x,elType)); MUTG_INIT(r); for (usz i = 0; i < wia; i++) { B cw = GetU(w, i); // assumed number from previous squeeze usz c = WRAP(o2i64(cw), cam, { mut_pfree(r, i*csz); thrF("⊏: Indexing out-of-bounds (%RβˆŠπ•¨, %s≑≠𝕩)", cw, cam); }); mut_copyG(r, i*csz, x, csz*c, csz); } Arr* ra = mut_fp(r); usz* rsh = arr_shAlloc(ra, rr); if (rsh) { shcpy(rsh , SH(w) , wr ); shcpy(rsh+wr, SH(x)+1, xr-1); } decG(w); decG(x); return withFill(taga(ra),xf); } base:; dec(xf); return c2rt(select, w, x); dec_ret:; decG(w); decG(x); return 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)) : 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)) : 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)) : 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)) : 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)) : 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(r, xia); mut_init(r, 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(r, xia); mut_init(r, 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 }