diff --git a/src/builtins/cells.c b/src/builtins/cells.c index 68d36f30..f7a0cd35 100644 --- a/src/builtins/cells.c +++ b/src/builtins/cells.c @@ -7,10 +7,18 @@ B fne_c1(B, B); B shape_c2(B, B, B); B transp_c2(B, B, B); -B fold_rows(Md1D* d, B x); // from fold.c -B fold_rows_bit(Md1D* d, B x, usz n, usz m); // from fold.c +B take_c2(B, B, B); +B join_c2(B, B, B); + +// from fold.c: +B fold_rows(Md1D* d, B x, usz n, usz m); +B fold_rows_bit(Md1D* d, B x, usz n, usz m); +B insert_cells_join(B x, usz* xsh, ur cr, ur k); +B insert_cells_identity(B x, B f, usz* xsh, ur xr, ur k, u8 rtid); + B scan_rows_bit(u8, B x, usz m); // from scan.c B takedrop_highrank(bool take, B w, B x); // from sfns.c +B rotate_highrank(bool inv, B w, B x); // from sfns.c B try_interleave_cells(B w, B x, ur xr, ur xk, usz* xsh); // from transpose.c // X - variable name; XSH - its shape; K - number of leading axes that get iterated over; SLN - number of slices that will be made; DX - additional refcount count to add to x @@ -165,7 +173,7 @@ NOINLINE B leading_axis_arith(FC2 fc2, B w, B x, usz* wsh, usz* xsh, ur mr) { // if (mr==wr) w=s; else x=s; return fc2(m_f64(0), w, x); } else { - M_APD_SH(r, mr, bsh); + M_APD_SH_N(r, mr, bsh, cam); S_KSLICES(b, bsh, mr, cam, 1) usz bp=0; if (mr==wr) { SGetU(w); for (usz i=0; i1 && k=7 || (xl<3 && xl>0)) { // generic case + MAKE_MUT_INIT(rm, ria, TI(x,elType)); MUTG_INIT(rm); + usz jump = l * csz; + usz xi = take*ind; + usz ri = 0; + for (usz i = 0; i < cam; i++) { + mut_copyG(rm, ri, x, xi, take); + xi+= jump; + ri+= take; + } + ra = mut_fp(rm); + } else if (xe==el_B) { + assert(take == 1); SGet(x) - HArr_p rp = m_harrUv(cam); - for (usz i = 0; i < cam; i++) rp.a[i] = Get(x, i*jump+n); + HArr_p rp = m_harrUv(ria); + for (usz i = 0; i < cam; i++) rp.a[i] = Get(x, i*l+ind); NOGC_E; ra = (Arr*)rp.c; } else { - void* rp = m_tyarrlbp(&ra, elwBitLog(xe), cam, el2t(xe)); + void* rp = m_tyarrlbp(&ra, ewl, ria, el2t(xe)); void* xp = tyany_ptr(x); - switch(xe) { - case el_bit: + switch(xl) { + case 0: #if SINGELI - if (jump < 64) si_select_cells_bit_lt64(xp, rp, cam, jump, n); + if (l < 64) si_select_cells_bit_lt64(xp, rp, cam, l, ind); else #endif - for (usz i=0; im1->flags-1; - if (rtid==n_const) { f=fd->f; goto const_f; } - usz *sh = SH(x); - if (((rtid==n_fold && cr==1) || rtid==n_insert) && TI(x,elType)!=el_B - && isFun(fd->f) && 1==shProd(sh, k+1, xr) && sh[k] > 0) { - usz m = sh[k]; - u8 frtid = v(fd->f)->flags-1; - if (m==1 || frtid==n_ltack) return select_cells(0 , x, cam, k, false); - if ( frtid==n_rtack) return select_cells(m-1, x, cam, k, false); - if (isPervasiveDyExt(fd->f)) { - if (TI(x,elType)==el_bit) { - incG(x); // keep shape alive - B r = fold_rows_bit(fd, x, shProd(sh, 0, k), m); - if (!q_N(r)) { - if (xr > 2) { - usz* rsh = arr_shAlloc(a(r), xr-1); - shcpy(rsh, sh, k); - shcpy(rsh+k, sh+k+1, xr-1-k); - } - decG(x); return r; + switch(rtid) { + case n_const: f=fd->f; goto const_f; + case n_cell: cr-= cr>0; return for_cells_c1(fd->f, xr, cr, xr-cr, x, U'˘'); + case n_fold: if (cr != 1) break; // else fall through + case n_insert: if (cr>0 && isFun(fd->f)) { + u8 frtid = v(fd->f)->flags-1; + if (frtid==n_join && rtid==n_insert) return insert_cells_join(x, xsh, cr, k); + usz m = xsh[k]; + if (m==0) return insert_cells_identity(x, fd->f, xsh, xr, k, rtid); + if (TI(x,elType)==el_B) break; + if (m==1 || frtid==n_ltack) return select_cells(0 , x, cam, k, false); + if ( frtid==n_rtack) return select_cells(m-1, x, cam, k, false); + if (isPervasiveDyExt(fd->f) && 1==shProd(xsh, k+1, xr)) { + B r; + // special cases always return rank 1 + // incG(x) preserves the shape to restore afterwards if needed + if (TI(x,elType)==el_bit) { + incG(x); r = fold_rows_bit(fd, x, cam, m); + if (q_N(r)) decG(x); // will try fold_rows + else goto finish_fold; } - decG(x); + if (m<=64 && m 2) { + usz* rsh = arr_shAlloc(a(r), xr-1); + shcpy(rsh, xsh, k); + shcpy(rsh+k, xsh+k+1, xr-1-k); + } + decG(x); return r; } - // TODO extend to any rank - if (xr==2 && k==1 && m<=64 && mf)) goto base; - u8 frtid = v(fd->f)->flags-1; - if (frtid==n_rtack) return x; - if (TI(x,elType)==el_bit && (isPervasiveDyExt(fd->f)||frtid==n_ltack) - && 1==shProd(sh, k+1, xr)) { - B r = scan_rows_bit(frtid, x, m); if (!q_N(r)) return r; + } break; + case n_scan: { + if (cr==0) break; + usz m = xsh[k]; + if (m<=1 || IA(x)==0) return x; + if (!isFun(fd->f)) break; + u8 frtid = v(fd->f)->flags-1; + if (frtid==n_rtack) return x; + if (TI(x,elType)==el_bit && (isPervasiveDyExt(fd->f)||frtid==n_ltack) + && 1==shProd(xsh, k+1, xr)) { + B r = scan_rows_bit(frtid, x, m); if (!q_N(r)) return r; + } + break; } } } else if (TY(f) == t_md2D) { @@ -531,7 +576,7 @@ B for_cells_c1(B f, u32 xr, u32 cr, u32 k, B x, u32 chr) { // F⎉cr x, with arr base:; - M_APD_SH(r, k, xsh); + M_APD_SH_N(r, k, xsh, cam); S_KSLICES(x, xsh, k, cam, 1); FC1 fc1 = c1fn(f); for (usz i=0,xp=0; iflags-1; - if (rtid==n_rtack) { dec(w); return x; } - if (rtid==n_ltack) return const_cells(x, xk, xsh, w, chr); - if (rtid==n_select && xk==1 && isF64(w) && xr==2) return select_cells(WRAP(o2i64(w), SH(x)[1], thrF("⊏: Indexing out-of-bounds (𝕨≡%R, %s≡≠𝕩)", w, cam)), x, cam, 1, false); - if (rtid==n_pick && xk==1 && TI(x,arrD1) && xr==2 && isF64(w)) return select_cells(WRAP(o2i64(w), SH(x)[1], thrF("⊑: Indexing out-of-bounds (𝕨≡%R, %s≡≠𝕩)", w, cam)), x, cam, 1, true); - if ((rtid==n_shifta || rtid==n_shiftb) && xk==1 && xr==2 && isAtm(w)) { - if (isArr(w)) { B w0=w; w = IGet(w,0); decG(w0); } - return shift_cells(w, x, SH(x)[0], SH(x)[1], el_or(TI(x,elType), selfElType(w)), rtid); - } - if (rtid==n_take || rtid==n_drop) { - if (xcr==0 || !isF64(w)) goto generic; - bool take = rtid==n_take; - f64* ap; - B a = m_f64arrv(&ap, xk+1); - if (!take) { FILL_TO(ap, el_f64, 0, m_f64(0), xk); } - else { usz* xsh=SH(x); PLAINLOOP for (usz i=0; i(2048*8)>>arrTypeBitsLog(TY(w)) && IA(w)!=IA(x))) goto generic; - return c2(f, C2(shape, C1(fne, incG(x)), w), x); + switch(rtid) { + case n_rtack: dec(w); return x; + case n_ltack: return const_cells(x, xk, xsh, w, chr); + case n_select: if (isF64(w) && xcr>=1) { + usz l = xsh[xk]; + return select_cells(WRAP(o2i64(w), l, thrF("⊏: Indexing out-of-bounds (𝕨≡%R, %s≡≠𝕩)", w, l)), x, cam, xk, false); + } break; + case n_pick: if (isF64(w) && xcr==1 && TI(x,arrD1)) { + usz l = xsh[xk]; + return select_cells(WRAP(o2i64(w), l, thrF("⊑: Indexing out-of-bounds (𝕨≡%R, %s≡≠𝕩)", w, l)), x, cam, xk, true); + } break; + case n_shifta: case n_shiftb: if (isAtm(w)) { + if (IA(x)==0) return x; + if (xcr!=1) { + if (xcr==0) break; + if (!(xsh[xk]==1 || shProd(xsh, xk+1, xr)==1)) break; + } + if (isArr(w)) { B w0=w; w = IGet(w,0); decG(w0); } + return shift_cells(w, x, cam, xsh[xk], el_or(TI(x,elType), selfElType(w)), rtid); + } break; + case n_take: case n_drop: { + bool take = rtid==n_take; + B a; + if (isF64(w)) { + if (xcr < 1) break; + f64* ap; + a = m_f64arrv(&ap, xk+1); + if (!take) { FILL_TO(ap, el_f64, 0, m_f64(0), xk); } + else { PLAINLOOP for (usz i=0; i1) break; + usz wia = IA(w); + if (xcr < wia) break; // needs rank extension in the middle of x's shape + if (!take) a = C2(take, m_f64(-(i32)(xk+wia)), w); + else a = C2(join, C2(take, m_f64(xk), C1(fne, incG(x))), w); // (k↑≢𝕩)∾𝕨 + } + return takedrop_highrank(take, a, x); + } break; + case n_reverse: { + B a; + if (isF64(w)) { + if (xcr < 1) break; + f64* ap; + a = m_f64arrv(&ap, xk+1); + FILL_TO(ap, el_f64, 0, m_f64(0), xk); + ap[xk] = o2fG(w); + } else { + if (!isArr(w) || RNK(w)>1) break; + usz wia = IA(w); + if (xcr < wia) break; + a = C2(take, m_f64(-(i32)(xk+wia)), w); + } + return rotate_highrank(0, a, x); + } + case n_transp: + if (q_usz(w)) { usz a=o2sG(w); if (a(2048*8)>>arrTypeBitsLog(TY(w)) && IA(w)!=IA(x))) break; + return c2(f, C2(shape, C1(fne, incG(x)), w), x); + } } } else if (!isMd(f)) { dec(w); return const_cells(x, xk, xsh, inc(f), chr); } - generic:; S_KSLICES(x, xsh, xk, cam, 1) incBy(w, cam-1); - M_APD_SH(r, xk, xsh); FC2 fc2 = c2fn(f); + M_APD_SH_N(r, xk, xsh, cam); FC2 fc2 = c2fn(f); for (usz i=0,xp=0; if; - if (isAtm(x) || RNK(x)==0) thrM("˝: 𝕩 must have rank at least 1"); + ur xr; + if (isAtm(x) || (xr=RNK(x))==0) thrM("˝: 𝕩 must have rank at least 1"); usz len = *SH(x); - if (len==0) { SLOW2("!𝕎˝𝕩", f, x); return m1c1(rt_insert, f, x); } + if (len==0) { + if (isFun(f)) { + B id = TI(f,identity)(f); + if (!q_N(id)) { + if (isArr(id)) { decG(x); return id; } // arithmetic with table + usz* xsh = SH(x); + Arr* r = reshape_one(shProd(xsh, 1, xr), id); + if (xr == 2) arr_shVec(r); else { + usz* rsh = arr_shAlloc(r, xr-1); + shcpy(rsh, xsh+1, xr-1); + } + decG(x); return taga(r); + } else if (v(f)->flags == n_join+1) { + if (xr <= 1) thrM("˝: Identity does not exist"); + goto join; + } + } + thrM("˝: Identity not found"); + } if (len==1) return C1(select, x); if (RARE(!isFun(f))) { decG(x); if (isMd(f)) thrM("Calling a modifier"); return inc(f); } - ur xr = RNK(x); - if (xr==1 && isPervasiveDyExt(f)) return m_unit(fold_c1(d, x)); + if (isPervasiveDyExt(f)) { + if (xr==1) return m_unit(fold_c1(d, x)); + if (len==IA(x)) { + B r = m_vec1(fold_c1(d, C1(shape, x))); + ur rr = xr - 1; + if (rr > 1) { + ShArr* rsh = m_shArr(rr); + PLAINLOOP for (ur i=0; ia[i] = 1; + arr_shReplace(a(r), rr, rsh); + } + return r; + } + } if (v(f)->flags) { u8 rtid = v(f)->flags-1; if (rtid==n_ltack) return C1(select, x); if (rtid==n_rtack) return C2(select, m_f64(-1), x); - if (rtid==n_join) { + if (rtid==n_join) { join:; if (xr==1) return x; ShArr* rsh; if (xr>2) { @@ -414,17 +445,32 @@ B insert_c1(Md1D* d, B x) { B f = d->f; return insert_base(f, x, 0, m_f64(0)); } B insert_c2(Md1D* d, B w, B x) { B f = d->f; - if (isAtm(x) || RNK(x)==0) thrM("˝: 𝕩 must have rank at least 1"); - if (*SH(x)==0) { decG(x); return w; } + ur xr; + if (isAtm(x) || (xr=RNK(x))==0) thrM("˝: 𝕩 must have rank at least 1"); + usz len = *SH(x); + if (len==0) { decG(x); return w; } if (RARE(!isFun(f))) { dec(w); decG(x); if (isMd(f)) thrM("Calling a modifier"); return inc(f); } - if (RNK(x)==1 && isPervasiveDyExt(f)) { - if (isAtm(w)) { - to_fold: return m_unit(fold_c2(d, w, x)); - } - if (RNK(w)==0) { + if (isPervasiveDyExt(f) && len==IA(x)) { + // 1-element arrays are always conformable + // final rank is higher of w, cell rank of x + ur rr = xr - 1; + if (isArr(w)) { + if (IA(w) != 1) goto skip; + ur wr = RNK(w); if (wr>rr) rr = wr; B w0=w; w = IGet(w,0); decG(w0); - goto to_fold; } + if (xr > 1) x = C1(shape, x); + B r = m_unit(fold_c2(d, w, x)); + if (rr > 0) { + if (rr == 1) arr_shVec(a(r)); + else { + ShArr* rsh = m_shArr(rr); + PLAINLOOP for (ur i=0; ia[i] = 1; + arr_shReplace(a(r), rr, rsh); + } + } + return r; + skip:; } if (v(f)->flags) { u8 rtid = v(f)->flags-1; @@ -434,19 +480,56 @@ B insert_c2(Md1D* d, B w, B x) { B f = d->f; return insert_base(f, x, 1, w); } -// Arithmetic fold/insert on rows of flat rank-2 array x +B insert_cells_join(B x, usz* xsh, ur cr, ur k) { + assert(k > 0); + if (cr <= 1) { + if (xsh[k]==0) thrM("˝: Identity does not exist"); + return x; + } + ur rr = k+cr-1; // result rank (>1) + ShArr* rsh; + rsh = m_shArr(rr); + shcpy(rsh->a, xsh, k); + rsh->a[k] = xsh[k] * xsh[k+1]; + shcpy(rsh->a+k+1, xsh+k+2, cr-2); + Arr* r = TI(x,slice)(x, 0, IA(x)); + arr_shSetUG(r, rr, rsh); + decG(x); return taga(r); +} +B insert_cells_identity(B x, B f, usz* xsh, ur xr, ur k, u8 rtid) { + B id; + if (!isFun(f) || q_N(id = TI(f,identity)(f))) thrF("%c: Identity not found", rtid==n_fold? U'´' : U'˝'); + bool cs = !isArr(id); // if x cell shape is used (not table) + usz ria = shProd(xsh, 0, k); + if (cs) ria*= shProd(xsh, k+1, xr); + Arr* r = reshape_one(ria, id); + ur rr = cs? xr-1 : k; + if (rr == 1) arr_shVec(r); else { + usz* rsh = arr_shAlloc(r, rr); + shcpy(rsh, xsh, k); + if (cs) shcpy(rsh+k, xsh+k+1, rr-k); + } + decG(x); return taga(r); +} + +// Arithmetic fold/insert on -k-cells of flat array x +// Return a vector regardless of argument shape B transp_c1(B, B); -B join_c2(B, B, B); -B fold_rows(Md1D* fd, B x) { - assert(isArr(x) && RNK(x)==2); +B fold_rows(Md1D* fd, B x, usz n, usz m) { + assert(isArr(x) && IA(x)==n*m); // Target block size trying to avoid power-of-two lengths, from: // {𝕩/˜⌊´⊸= +˝˘ +˝¬∨`2|>⌊∘÷⟜2⍟(↕12) ⌊0.5+32÷˜𝕩÷⌜1+↕64} +⟜↕2⋆16 u64 block = (116053*8) >> arrTypeBitsLog(TY(x)); if (TI(x,elType)==el_bit || IA(x)/2 <= block) { + if (RNK(x) > 2) { + Arr* xc = cpyWithShape(x); + ShArr* sh = m_shArr(2); + sh->a[0] = n; sh->a[1] = m; + x = taga(arr_shReplace(xc, 2, sh)); + } x = C1(transp, x); return insert_c1(fd, x); } else { - usz *sh = SH(x); usz n = sh[0]; usz m = sh[1]; usz b = (block + m - 1) / m; // Normal block length usz b_max = b + b/4; // Last block max length MAKE_MUT(r, n); MUT_APPEND_INIT(r); diff --git a/src/builtins/sfns.c b/src/builtins/sfns.c index 72e157db..69b28400 100644 --- a/src/builtins/sfns.c +++ b/src/builtins/sfns.c @@ -998,7 +998,10 @@ B shiftb_c1(B t, B x) { if (ia==0) return x; B xf = getFillE(x); usz csz = arr_csz(x); - + if (ia==csz) { // length 1 + Arr* r = arr_shCopy(reshape_one(ia, xf), x); + decG(x); return taga(r); + } MAKE_MUT_INIT(r, ia, el_or(TI(x,elType), selfElType(xf))); MUTG_INIT(r); mut_copyG(r, csz, x, 0, ia-csz); mut_fillG(r, 0, xf, csz); @@ -1025,6 +1028,10 @@ B shifta_c1(B t, B x) { if (ia==0) return x; B xf = getFillE(x); usz csz = arr_csz(x); + if (ia==csz) { // length 1 + Arr* r = arr_shCopy(reshape_one(ia, xf), x); + decG(x); return taga(r); + } MAKE_MUT_INIT(r, ia, el_or(TI(x,elType), selfElType(xf))); MUTG_INIT(r); mut_copyG(r, 0, x, csz, ia-csz); mut_fillG(r, ia-csz, xf, csz); @@ -1059,7 +1066,7 @@ static u64 bit_reverse(u64 x) { B reverse_c1(B t, B x) { if (isAtm(x) || RNK(x)==0) thrM("⌽: Argument cannot be a unit"); usz n = *SH(x); - if (n==0) return x; + if (n<=1) return x; u8 xl = cellWidthLog(x); u8 xt = arrNewType(TY(x)); if (xl<=6 && (xl>=3 || xl==0)) { @@ -1115,7 +1122,7 @@ B reverse_c1(B t, B x) { B reverse_c2(B t, B w, B x); #define WRAP_ROT(V, L) ({ i64 v_ = (V); usz l_ = (L); if ((u64)v_ >= (u64)l_) { v_%= (i64)l_; if(v_<0) v_+= l_; } v_; }) -static NOINLINE B rotate_highrank(bool inv, B w, B x) { +NOINLINE B rotate_highrank(bool inv, B w, B x) { #define INV (inv? "⁼" : "") if (RNK(w)>1) thrF("⌽%U: 𝕨 must have rank at most 1 (%H ≡ ≢𝕨)", INV, w); B r; diff --git a/src/core/arrFns.h b/src/core/arrFns.h index 1257c9e0..b020be2c 100644 --- a/src/core/arrFns.h +++ b/src/core/arrFns.h @@ -73,11 +73,15 @@ SHOULD_INLINE void arr_check_size(u64 sz, u8 type, usz ia) { #endif } // Log of width in bits: max of 7, and also return 7 if not power of 2 -SHOULD_INLINE u8 cellWidthLog(B x) { +SHOULD_INLINE u8 multWidthLog(usz n, u8 lw) { // Of n elements, 1<>lw); // Max of 7; also handle n==0 +} +SHOULD_INLINE u8 kCellWidthLog(B x, ur k) { assert(isArr(x) && RNK(x)>=1); u8 lw = arrTypeBitsLog(TY(x)); - if (LIKELY(RNK(x)==1)) return lw; - usz csz = arr_csz(x); - if (csz & (csz-1)) return 7; // Not power of 2 - return lw + CTZ(csz | 128>>lw); // Max of 7; also handle csz==0 + ur xr = RNK(x); + if (LIKELY(xr <= k)) return lw; + return multWidthLog(shProd(SH(x), k, xr), lw); } +SHOULD_INLINE u8 cellWidthLog(B x) { return kCellWidthLog(x, 1); } diff --git a/src/core/stuff.c b/src/core/stuff.c index 79dd5fba..7ac11122 100644 --- a/src/core/stuff.c +++ b/src/core/stuff.c @@ -460,7 +460,7 @@ B bqn_merge(B x, u32 type) { return taga(r); } - M_APD_SH(r, xr, SH(x)); + M_APD_SH_N(r, xr, SH(x), xia); SGetU(x) for (usz i = 0; i < xia; i++) APD(r, GetU(x, i)); decG(x); diff --git a/src/load.c b/src/load.c index 5df99209..2d8ace52 100644 --- a/src/load.c +++ b/src/load.c @@ -129,7 +129,7 @@ NOINLINE B load_fullpath(B path, B name) { GLOBAL HArr* comps_curr; -GLOBAL B rt_undo, rt_select, rt_slash, rt_insert, rt_depth, +GLOBAL B rt_undo, rt_select, rt_slash, rt_depth, rt_group, rt_under, rt_find; Block* load_buildBlock(B x, B src, B path, B name, Scope* sc, i32 nsResult) { // consumes x,src B fullpath = load_fullpath(path, name); @@ -500,7 +500,6 @@ void load_init() { // very last init function gc_add(rt_under = Get(rtObjRaw, n_under )); gc_add(rt_find = Get(rtObjRaw, n_find )); gc_add(rt_depth = Get(rtObjRaw, n_depth )); - gc_add(rt_insert = Get(rtObjRaw, n_insert)); for (usz i = 0; i < RT_LEN; i++) { #ifdef RT_WRAP @@ -542,7 +541,7 @@ void load_init() { // very last init function load_rt = frtObj; rt_select = rt_slash = rt_group = rt_find = bi_invalidFn; - rt_undo = rt_insert = bi_invalidMd1; + rt_undo = bi_invalidMd1; rt_under = rt_depth = bi_invalidMd2; rt_invFnRegFn = rt_invFnSwapFn = invalidFn_c1; diff --git a/src/utils/mut.c b/src/utils/mut.c index cfbce2d6..d391ee41 100644 --- a/src/utils/mut.c +++ b/src/utils/mut.c @@ -665,6 +665,37 @@ NOINLINE void apd_sh_init(ApdMut* m, B x) { else m->apd(m, x); if (xe==el_B) NOGC_E; } +// used if this is the only append: only need to add leading 1s to shape +NOINLINE void apd_reshape(ApdMut* m, B x) { + ur rr0 = m->rr0; // need to be read before union fields are written + for (ur i=0; irsh0[i] == 1); + + inc(x); + if (isAtm(x)) x = m_unit(x); + + if (rr0 > 0) { + ur xr = RNK(x); + if (rr0 + xr > UR_MAX) { + m->failEl = x; + m->end = apd_rnk_err; + return; + } + ur rr = rr0 + xr; + Arr* r = cpyWithShape(x); + if (rr <= 1) { + arr_shErase(r, rr); + } else { + usz* xsh = PSH(r); + ShArr* rsh = m_shArr(rr); + PLAINLOOP for (ur i=0; ia[i] = 1; + shcpy(rsh->a + rr0, xsh, xr); + arr_shReplace(r, rr, rsh); + } + x = taga(r); + } + m->obj = a(x); + m->end = apd_ret_end; +} NOINLINE void apd_widen(ApdMut* m, B x, ApdFn* const* fns) { u8 xe = isArr(x)? TI(x,elType) : selfElType(x); diff --git a/src/utils/mut.h b/src/utils/mut.h index ebeef513..701f6dd1 100644 --- a/src/utils/mut.h +++ b/src/utils/mut.h @@ -265,7 +265,7 @@ struct ApdMut { }; }; -ApdFn apd_tot_init, apd_sh_init; +ApdFn apd_tot_init, apd_sh_init, apd_reshape; #if DEBUG ApdFn apd_dbg_apd; ApdEnd apd_dbg_end; @@ -275,6 +275,7 @@ ApdFn apd_tot_init, apd_sh_init; #endif #define M_APD_TOT(M, IA) M_APD_BASE(M) M.apd = apd_tot_init; M.ia0 = (IA); // end gives uninitialized shape #define M_APD_SH(M, RR, RSH) M_APD_BASE(M) M.apd = apd_sh_init; M.rsh0 = (RSH); M.rr0 = (RR); // end gives full shape; will error on invalid at the end; rsh must be alive until at least the first APD call +#define M_APD_SH_N(M, RR, RSH, N) M_APD_BASE(M) M.apd = N==1? apd_reshape : apd_sh_init; M.rsh0 = (RSH); M.rr0 = (RR); // same, with known number of appends #define M_APD_SH1(M, RIA) usz M##_sh0 = (RIA); M_APD_SH(M, 1, &M##_sh0); #define APD(M, A) M.apd(&M, A) // doesn't consume A #define APDD(M, A) ({ B av_ = (A); M.apd(&M, av_); dec(av_); }) // consumes A diff --git a/test/cases/cells.bqn b/test/cases/cells.bqn index 260e9c42..50819073 100644 --- a/test/cases/cells.bqn +++ b/test/cases/cells.bqn @@ -21,6 +21,51 @@ !"˘: Argument frames don't agree (⟨3⟩ ≡ ≢𝕨, ⟨2⟩ ≡ ≢𝕩, common frame of 1 axes)" % "abc" ⊢˘ "ab" ! ∧´{𝕊: ! (∾≡{𝕨∾𝕩}´) (<•rand.Range∘≠⊸⊑ ⟨"ab",1‿2,⟨⟩,↕0,""⟩) ∾˜ (4•rand.Range≠)⊸⊏ ⟨1, {⇐}, 'a', <'a', <{⇐}, "ab", ↕0, ""⟩}¨↕10000 +# error cases that could be affected by special code +!"∧: Argument cannot have rank 0" % ∧˘↕2 +!"∨: Argument cannot have rank 0" % ∨˘"a" +!"Expected non-negative integer, got ¯3" % 2‿¯3/⎉1 6‿2⥊0 +!"/: Lengths of components of 𝕨 must match 𝕩 (3 ≠ 4)" % 1‿2‿3⊸/˘≍4‿5‿6‿7 +!"/: Simple 𝕨 must have rank 0 or 1 (2≡=𝕨)" % (2‿3‿1⥊↕4) /˘ ↕2 +!"𝕨/𝕩: Length of compound 𝕨 must be at most rank of 𝕩" % (<↕0)/˘○(5⊸⥊)<"ab" +!"⊏: Indexing out-of-bounds (24∊𝕨, 4≡≠𝕩)" % 1‿24⊏⎉1↕4‿4 +!"⊏: Indexing out-of-bounds (4∊𝕨, 4≡≠𝕩)" % ⊏⎉1˜6‿4⥊↕24 +!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such arrays" % 0‿@‿¯1⊏⎉1 5‿2⥊0.5 +!"Expected integer, got ¯5.25" % ¯5.25⊏˘∘‿4⥊↕24 +!"⊏: Indexing out-of-bounds (1∊𝕨, 1≡≠𝕩)" % 0‿0‿1 ⊏˘○(≍˘) 10000×↕3 +!"⊏: 𝕩 cannot be a unit" % 0⊏˘5⥊<"a" +!"⊏: 𝕩 cannot be a unit" % (3‿0⥊⟨⟩)⊏˘↕3 +!"Expected integer, got 0.1" % 0.1⊑˘3‿5⥊↕15 +!"⊑: 𝕩 must be a list when 𝕨 is a number (3‿4 ≡ ≢𝕩)" % 5⊑˘↕2‿3‿4 +!">: Result rank too large (80 ≡ =𝕩, 205 ≡ =⊑𝕩)" % >⎉80 (200⥊1)⥊<(205⥊1)⥊1 +!"⎉: Result rank too large (195 ≡ =𝕩, 210 ≡ =𝔽v)" % >⎉5 (200⥊1)⥊<(205⥊1)⥊1 +!"∾: Lengths not matchable (⟨6⟩ ≡ ≢𝕨, 1‿1 ≡ ≢𝕩)" % ("abc"∾"def")∾˘○(3/≍)≍"a" +!"∾: Argument ranks must differ by 1 or less (0≡=𝕨, 2≡=𝕩)" % 1∾˘↕3‿3‿3 +!"∾: Lengths not matchable (4‿2 ≡ ≢𝕨, 3‿3 ≡ ≢𝕩)" % (3‿4‿2⥊4)∾˘3‿3‿3⥊5 +!"≍: 𝕨 and 𝕩 must have equal shapes (3‿4 ≡ ≢𝕨, 3‿3 ≡ ≢𝕩)" % (↕3‿4)≍⎉2 2‿3‿3⥊↕18 +!"≍: Result rank too large (255≡=𝕩)" % ≍⎉∞ 0⥊˜255⥊1 +!"shift: Lengths not matchable (⟨6⟩ ≡ ≢𝕨, 1‿1 ≡ ≢𝕩)" % ("abc"∾"def")«˘○(3/≍)≍"a" +!"shift: =𝕨 must be =𝕩 or ¯1+=𝕩 (0≡=𝕨, 2≡=𝕩)" % 1«˘↕2‿2‿2 +!"»: Argument cannot be a scalar" % »⎉0 2‿3‿1⥊↕6 +!"⌽: Argument cannot be a unit" % ⌽˘↕10 +!"Expected integer, got 1.5" % 1.5↑˘↕2‿3‿2 +!"↑: 𝕨 must have rank at most 1 (1‿2 ≡ ≢𝕨)" % (≍1‿2)⊸↑˘↕2‿3‿2 +!"↓: 𝕨 must have rank at most 1 (4‿2 ≡ ≢𝕨)" % (4‿2⥊↕8)↓˘○≍@ +!"Integer out of range: 1e20" % 1e20⌽˘3‿10⥊10 +!"Expected number" % 3‿4‿@⌽˘↕3‿4 +!"Expected integer, got 0.5" % 0.5⊸⌽˘4‿3⥊↕12 +!"↑: Argument must have rank at least 1" % ↑˘↕2 +!"↓: Argument must have rank at least 1" % ↓⎉0 2‿1⥊0 +!"⊐: 𝕩 cannot have rank 0" % ⊐˘"abcd" +!"⊒: Argument cannot have rank 0" % ⊒˘"abcd" +!"∊: Argument cannot have rank 0" % ∊˘"abcd" +!"⍋: 𝕨 must be sorted" % 0‿2‿1⊸⍋˘ 3‿4⥊↕12 +!"`: Shape of 𝕨 must match the cell of 𝕩 (⟨2⟩ ≡ ≢𝕨, 2‿3 ≡ ≢𝕩)" % (2‿2⥊1)+`˘2‿2‿3⥊0.4 +!"`: Shape of 𝕨 must match the cell of 𝕩 (⟨⟩ ≡ ≢𝕨, 3‿3 ≡ ≢𝕩)" % 2+`˘↕3‿3‿3 +!"´: Argument must be a list (3‿3 ≡ ≢𝕩)" % +´˘2‿3‿3⥊↕18 +!"´: 𝕩 must be a list (3‿3 ≡ ≢𝕩)" % 1+´˘2‿3‿3⥊↕18 +!"˝: 𝕩 must have rank at least 1" % +˝˘˘10‿10⥊↕100 + %USE tcc ⋄ ⟨2, 20, ¯2, ¯20, 0⟩ {𝕨 ↑_tcc 𝕩 ⋄ 𝕨 ↓_tcc 𝕩}⌜ ⟨<4, ↕5, 4‿5⥊↕20, 4‿5‿6⥊↕120⟩ %USE tcc ⋄ ⟨<, ≍, ⊏, ⥊⟩ {𝕎 _tcc 𝕩}⌜ ⟨<4, ↕5, 4‿5⥊↕20, 4‿5‿6⥊↕120, 2‿3‿4‿5⥊↕120⟩ %USE tcc ⋄ ⟨<, ≍, ⥊⟩ {𝕎 _tcc 𝕩}⌜ ⟨<4, ↕5, 4‿5⥊↕20, 4‿5‿6⥊↕120, 2‿3‿4‿5⥊↕120⟩