From 454d1b072d085b9f4a4f023df48dbcbba7aa9334 Mon Sep 17 00:00:00 2001 From: dzaima Date: Sun, 25 May 2025 21:18:41 +0300 Subject: [PATCH] =?UTF-8?q?move=20arr=E2=8C=BE(m=E2=8A=B8/)=F0=9D=95=A9=20?= =?UTF-8?q?over=20to=20new=20DirectArr=20thing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/builtins/slash.c | 85 +++++++++++++++++++++++--------------------- src/utils/mut.c | 34 ++++++++++++++---- src/utils/mut.h | 20 ++++++++--- test/cases/under.bqn | 1 + 4 files changed, 89 insertions(+), 51 deletions(-) diff --git a/src/builtins/slash.c b/src/builtins/slash.c index e43199c0..9e835aec 100644 --- a/src/builtins/slash.c +++ b/src/builtins/slash.c @@ -1036,34 +1036,29 @@ B slash_im(B t, B x) { extern INIT_GLOBAL BlendArrScalarFn* blendArrScalarFns; #endif -typedef struct { B b; void* data; } AnyArr; -AnyArr cpyElTypeArr(u8 re, B x) { // consumes x; returns new array with the given element type, with data & shape from x - Arr* a; - switch (re) { default: UD; - case el_bit: a = cpyBitArr(x); goto tyarr; - case el_i8: a = cpyI8Arr(x); goto tyarr; - case el_i16: a = cpyI16Arr(x); goto tyarr; - case el_i32: a = cpyI32Arr(x); goto tyarr; - case el_f64: a = cpyF64Arr(x); goto tyarr; - case el_c8: a = cpyC8Arr(x); goto tyarr; - case el_c16: a = cpyC16Arr(x); goto tyarr; - case el_c32: a = cpyC32Arr(x); goto tyarr; - case el_B: - a = cpyHArr(x); - return (AnyArr){taga(a), harrv_ptr(a)}; - } - tyarr: - return (AnyArr){taga(a), tyarrv_ptr((TyArr*)a)}; + +#define BY_MASK(F, ELTS, C) ({ \ + u64 c = (C); \ + B* elts_ = (ELTS); \ + while (c) { \ + F(elts_[CTZ(c)]); \ + c&=c-1; \ + } \ +}) + +static void decByMask(u64* mask, B* elts, ux ia, bool inv) { + u64 xor = inv? U64_MAX : 0; + ux e = ia>>6; + for (ux i=0; i>6; + for (ux i=0; im1) != n_each) goto notConstEach; @@ -1104,26 +1098,37 @@ B slash_ucw(B t, B o, B w, B x) { } u8 ce = selfElType(c); - u8 re = el_or(ce,xe); // can be el_B + u8 re = el_or(ce,xe); - B r; + u64 sum = U64_MAX; if (isVal(c)) { - u64 sum = usum(w); + sum = bit_sum(bitany_ptr(w), ia); if (sum==0) decG(c); // TODO could return x; fills? else incByG(c, sum-1); } - void* rp; + DirectArr r; void* xp; if (re != xe) { - AnyArr a = cpyElTypeArr(re, x); - x = r = incG(a.b); - xp = rp = a.data; + assert(xe != el_B); + r = toEltypeArr(x, re); + x = incG(r.obj); + xp = r.data; } else { - AnyArr a = m_anyarrc(re, x); - r = a.b; - rp = a.data; - xp = tyany_ptr(x); + if (xe==el_B) { + r = potentiallyReuse(x); + if (r.obj.u == x.u) { + xp = r.data; + decByMask(bitany_ptr(w), xp, ia, 0); + } else { + TO_BPTR(x); + xp = arr_bptrG(x); + incByMask(bitany_ptr(w), xp, ia, 1); + } + } else { + r = potentiallyReuse(x); + xp = tyany_ptr(x); + } } u64 cv; @@ -1134,10 +1139,10 @@ B slash_ucw(B t, B o, B w, B x) { cv = re==el_f64? r_f64u(o2fG(c)) : r_Bu(c); } - blendArrScalarFns[elwBitLog(re)](rp, xp, cv, bitany_ptr(w), IA(x)); + blendArrScalarFns[elwBitLog(re)](r.data, xp, cv, bitany_ptr(w), ia); NOGC_E; decG(w); decG(x); - return r; + return r.obj; } #endif goto notConstEach; notConstEach:; diff --git a/src/utils/mut.c b/src/utils/mut.c index 67f8afb2..062edbd7 100644 --- a/src/utils/mut.c +++ b/src/utils/mut.c @@ -799,7 +799,7 @@ static NOINLINE DirectArr toFillArr(B x, B fill) { static void* reusableArr_ptr(Arr* t, u8 el) { return el==el_B? (void*)(PTY(t)==t_fillarr? fillarrv_ptr(t) : harrv_ptr(t)) : tyarrv_ptr((TyArr*)t); } -DirectArr toEltypeArr(B x, u8 re) { // consumes x; returns an array with eltype==re, with same shape/elements/fill as x, and its data pointer +DirectArr toEltypeArr(B x, u8 re) { assert(isArr(x)); if (reusable(x) && re==reuseElType[TY(x)]) { x = REUSE(x); @@ -818,16 +818,38 @@ DirectArr toEltypeArr(B x, u8 re) { // consumes x; returns an array with eltype= case el_c32: tyarr = cpyC32Arr(x); goto tyarr; case el_B:; B fill = getFillR(x); - if (noFill(fill)) { - Arr* r = cpyHArr(x); - return (DirectArr){taga(r), harrv_ptr(r)}; - } - return toFillArr(x, fill); + if (!noFill(fill)) return toFillArr(x, fill); + + Arr* r = cpyHArr(x); + return (DirectArr){taga(r), harrv_ptr(r)}; } tyarr: return (DirectArr){taga(tyarr), tyarrv_ptr((TyArr*) tyarr)}; } +static NOINLINE DirectArr m_fillarrAs(B x, B fill) { + Arr* r = arr_shCopy(m_fillarrp(IA(x)), x); + fillarr_setFill(r, fill); + return (DirectArr){taga(r), fillarrv_ptr(r)}; +} +DirectArr potentiallyReuse(B x) { + assert(isArr(x)); + u8 xe = TI(x,elType); + if (reusable(x) && xe == reuseElType[TY(x)]) { + x = REUSE(x); + return (DirectArr){incG(x), reusableArr_ptr(a(x), xe)}; + } + if (xe==el_B) { + B fill = getFillR(x); + if (!noFill(fill)) return m_fillarrAs(x, fill); + + HArr_p r = m_harrUc(x); + return (DirectArr) {r.b, r.a}; + } + B r; + void* rp = m_tyarrlbc(&r, elwBitLog(xe), x, el2t(xe)); + return (DirectArr) {r, rp}; +} B directGetU_bit(void* data, ux i) { return m_f64(bitp_get(data,i));} void directSet_bit(void* data, ux i, B v) { bitp_set(data, i, o2bG(v)); } B directGetU_i8 (void* data, ux i) { return m_f64((( i8*)data)[i]); } void directSet_i8 (void* data, ux i, B v) { (( i8*)data)[i] = o2iG(v); } diff --git a/src/utils/mut.h b/src/utils/mut.h index 16c12aa4..f9443898 100644 --- a/src/utils/mut.h +++ b/src/utils/mut.h @@ -287,13 +287,23 @@ typedef void (*DirectSetRange)(void* data, ux rs, B x, ux xs, ux l); extern INIT_GLOBAL DirectGet directGetU[el_MAX]; extern INIT_GLOBAL DirectSet directSet[el_MAX]; extern INIT_GLOBAL DirectSetRange directSetRange[el_MAX]; + +// consumes x; returns an array with eltype==re, with same shape/elements/fill as x, and its data pointer DirectArr toEltypeArr(B x, u8 re); + +// doesn't consume; returns array with same shape & fill as x, returning x itself if possible (iif so, x.u==obj.u). +// If reused, the object is untouched besides having its refcount incremented and flags cleared. +// As such, if an el_B array is reused, all elements effectively have 1 more refcount than they should as x's elements never get freed +// Otherwise, functionality is the same as if a regular new array was made +// May start NOGC +DirectArr potentiallyReuse(B x); + #define DIRECTARR_COPY(R, RE, X) \ - u8 R##_elt = RE; \ - DirectArr R = toEltypeArr(X, R##_elt); \ - DirectGet R##_getU = directGetU[R##_elt]; \ - DirectSet R##_set = directSet[R##_elt]; \ - DirectSetRange R##_setRange = directSetRange[R##_elt]; + u8 R##_elt = RE; \ + MAYBE_UNUSED DirectArr R = toEltypeArr(X, R##_elt); \ + MAYBE_UNUSED DirectGet R##_getU = directGetU[R##_elt]; \ + MAYBE_UNUSED DirectSet R##_set = directSet[R##_elt]; \ + MAYBE_UNUSED DirectSetRange R##_setRange = directSetRange[R##_elt]; #define DIRECTARR_RM(R, I) if (R##_elt == el_B) dec(((B*)R.data)[I]); #define DIRECTARR_GETU(R, I) R##_getU(R.data, I) diff --git a/test/cases/under.bqn b/test/cases/under.bqn index 74cab646..43c13020 100644 --- a/test/cases/under.bqn +++ b/test/cases/under.bqn @@ -175,6 +175,7 @@ n←500 ⋄ a←↕n ⋄ i←(-n)+↕2×n ⋄ r←⌽(2×n)⥊a ⋄ ! (⌽a) ≡ 1⊸+⌾((↕10)⊸/) ↕10 %% ×⊸+ ↕10 %USE eqvar ⋄ <‿≥‿> {𝕨⌾(1‿0‿0‿1‿1⊸/) 𝕩}_eqvar +‿-‿×‿÷‿⋆ %% <‿-‿×‿≥‿> %USE eqvar ⋄ ["wx"‿"WX","yz"‿"YZ"] {𝕨⌾(1‿0‿0‿1⊸/) 𝕩}_eqvar (<"aA")+↕4‿2 %% 4‿2⥊⟨"wx","WX","bA","bB","cA","cB","yz","YZ"⟩ +{m←𝕩•rand.Range 2 ⋄ ! (m{𝕨?"huh";⥊'a'+𝕩}¨↕𝕩) ≡ "huh"¨⌾(m⊸/) 'a'+↕⋈𝕩}¨ ↕100 !"Integer out of range: 3.68934881474191e19" % 1¨⌾(a⊸/) a←100⥊2⋆65 !"Expected non-negative integer, got ¯10" % %USE evar ⋄ 1¨⌾(a⊸/)_evar a←¯10⌾(50⊸⊑) 100⥊10