// 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 && TI(w,arrD1)) { // 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 if (!q_i64(cw)) { bad_cw: badw=o2fG(cw); goto bad1; } usz c = WRAP(o2i64G(cw), xn, goto bad_cw; ); mut_copyG(rm, i*csz, x, csz*c, csz); } r = a(withFill(mut_fv(rm), xf)); } goto setsh; bad1:; mut_pfree(rm, i*csz); if (!q_fi64(badw)) expI_f64(badw); thrF("⊏: Indexing out-of-bounds (%fβˆŠπ•¨, %s≑≠𝕩)", badw, xn); } 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_shSetUG(r, rr, sh); } else { arr_shVec(r); } dec_ret:; decG(w); decG(x); return taga(r); } extern INIT_GLOBAL u8 reuseElType[t_COUNT]; B select_replace(u32 chr, B w, B x, B rep, usz wia, usz cam, usz csz) { // consumes all; (β₯Šrep)⌾(β₯Šw⊏camβ€Ώcszβ₯ŠβŠ’) x; assumes csz>0, that w is a typed (elNum) list of valid indices (squeeze already attempted on el_f64), and that rep has the proper element count assert(csz > 0); #if CHECK_VALID TALLOC(bool, set, cam); bool sparse = wia < cam/64; if (!sparse) for (i64 i = 0; i < cam; 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)cam; set[cw] = false; \ } #define EQ(ITER,F) if (set[cw]) ITER if (F) thrF("π”½βŒΎ(a⊸%c): Incompatible result elements", chr); set[cw] = true; #define EQ1(F) EQ(,F) #define FREE_CHECK TFREE(set) #else #define SPARSE_INIT(GET) #define EQ(ITER,F) #define EQ1(F) #define FREE_CHECK #endif #define READ_W(N,I) i64 N = (i64)wp[I]; if (RARE(N<0)) N+= (i64)cam u8 we = TI(w,elType); assert(elNum(we)); u8 xe = TI(x,elType); u8 re = el_or(xe, TI(rep,elType)); Arr* ra; // w = taga(cpyF64Arr(w)); we = el_f64; // test the float path if (we==el_f64) { f64* wp = f64any_ptr(w); SPARSE_INIT((i64)wp[i]) MAKE_MUT(r, cam*csz); mut_init_copy(r, x, re); NOGC_E; MUTG_INIT(r); SGet(rep) if (csz==1) { for (usz i = 0; i < wia; i++) { READ_W(cw, i); B cn = Get(rep, i); EQ1(!equal(mut_getU(r, cw), cn)); mut_rm(r, cw); mut_setG(r, cw, cn); } } else { for (usz i = 0; i < wia; i++) { READ_W(cw, i); EQ(for (usz j = 0; j < csz; j++), !equal(mut_getU(r, cw*csz + j), Get(rep, i*csz + j))); for (usz j = 0; j < csz; j++) mut_rm(r, cw*csz + j); mut_copyG(r, cw*csz, rep, i*csz, csz); } } ra = mut_fp(r); goto dec_ret_ra; } assert(elInt(we)); w = toI32Any(w); i32* wp = i32any_ptr(w); SPARSE_INIT(wp[i]) bool reuse = reusable(x) && re==reuseElType[TY(x)]; SLOWIF(!reuse && cam>100 && wiaa; if (csz==1) { for (usz i = 0; i < wia; i++) { READ_W(cw, i); bool cn = bitp_get(np, i); EQ1(cn != bitp_get(rp, cw)); bitp_set(rp, cw, cn); } } else { for (usz i = 0; i < wia; i++) { READ_W(cw, i); EQ(for (usz j = 0; j < csz; j++), bitp_get(np, i*csz + j) != bitp_get(rp, cw*csz + j)); COPY_TO(rp, el_bit, cw*csz, rep, i*csz, csz); } } goto dec_ret_ra; } case el_B: { ra = reuse? a(REUSE(x)) : cpyHArr(x); B* rp = harrP_parts((HArr*)ra).a; SGet(rep) if (csz==1) { for (usz i = 0; i < wia; i++) { READ_W(cw, i); B cn = Get(rep, i); EQ1(!equal(cn,rp[cw])); dec(rp[cw]); rp[cw] = cn; } } else { for (usz i = 0; i < wia; i++) { READ_W(cw, i); EQ(for (usz j = 0; j < csz; j++), !equal(Get(rep, i*csz + j), rp[cw*csz + j])); for (usz j = 0; j < csz; j++) dec(rp[cw*csz + j]); COPY_TO(rp, el_B, cw*csz, rep, i*csz, csz); } } goto dec_ret_ra; } } #define IMPL(T) do { \ if (csz!=1) goto do_tycell; \ T* rp = (void*)((TyArr*)ra)->a; \ T* np = tyany_ptr(rep); \ for (usz i = 0; i < wia; i++) { \ READ_W(cw, i); \ T cn = np[i]; \ EQ1(cn != rp[cw]); \ rp[cw] = cn; \ } \ goto dec_ret_ra; \ } while(0) do_u8: IMPL(u8); do_u16: IMPL(u16); do_u32: IMPL(u32); do_u64: IMPL(u64); #undef IMPL do_tycell:; u8 cwidth = csz * elWidth(re); u8* rp = (u8*) ((TyArr*)ra)->a; u8* np = tyany_ptr(rep); EqFnObj eq = EQFN_GET(re,re); for (usz i = 0; i < wia; i++) { READ_W(cw, i); EQ1(!EQFN_CALL(eq, rp + cw*cwidth, np + i*cwidth, csz)); COPY_TO(rp, re, cw*csz, rep, i*csz, csz); } goto dec_ret_ra; dec_ret_ra:; decG(w); decG(rep); FREE_CHECK; return taga(ra); #undef SPARSE_INIT #undef EQ #undef EQ1 #undef FREE_CHECK } B select_ucw(B t, B o, B w, B x) { if (isAtm(x) || isAtm(w)) { def: return def_fn_ucw(t, o, w, x); } usz xia = IA(x); usz wia = IA(w); u8 we = TI(w,elType); if (!elInt(we) && IA(w)!=0) { w = num_squeezeChk(w); we = TI(w,elType); if (!elNum(we)) goto def; } B rep; if (isArr(o) && RNK(x)>0) { i64 buf[2]; if (wia!=0 && (!getRange_fns[we](tyany_ptr(w), buf, wia) || buf[0]<-(i64)xia || buf[1]>=xia)) thrF("π”½βŒΎ(a⊸⊏)𝕩: Indexing out-of-bounds (%l∊a, %H≑≒𝕩)", buf[1]>=xia?buf[1]:buf[0], x); rep = incG(o); } else { rep = c1(o, C2(select, incG(w), incG(x))); } usz xr = RNK(x); usz wr = RNK(w); usz rr = RNK(rep); bool ok = !isAtm(rep) && xr+wr==rr+1 && eqShPart(SH(w),SH(rep),wr) && eqShPart(SH(x)+1,SH(rep)+wr,xr-1); if (!ok) thrF("π”½βŒΎ(a⊸⊏)𝕩: 𝔽 must return an array with the same shape as its input (%H ≑ shape of a, %2H ≑ shape of βŠπ•©, %H ≑ shape of result of 𝔽)", w, xr-1, SH(x)+1, rep); usz csz = arr_csz(x); if (csz == 0) { decG(rep); decG(w); return x; } return select_replace(U'⊏', w, x, rep, wia, *SH(x), csz); }