more proper eltype copying helper

fixes c¨⌾(m⊸/)genericlist arr_bptr==NULL path copying input during noAlloc
This commit is contained in:
dzaima 2025-05-26 23:01:00 +03:00
parent 7e3e4a031f
commit 9e47ce066a
3 changed files with 82 additions and 44 deletions

View File

@ -1084,7 +1084,7 @@ B slash_ucw(B t, B o, B w, B x) {
// (c ; C˙)¨⌾(w⊸/) x
#if SINGELI_SIMD
if (isFun(o) && TY(o)==t_md1D) {
if (MAY_F(isFun(o) && TY(o)==t_md1D)) {
u8 xe = TI(x,elType);
Md1D* od = c(Md1D,o);
@ -1109,28 +1109,12 @@ B slash_ucw(B t, B o, B w, B x) {
else incByG(c, sum-1);
}
DirectArr r;
void* xp;
if (re != xe) {
assert(xe != el_B);
r = toEltypeArr(x, re);
x = incG(r.obj);
xp = r.data;
} else {
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);
}
ConvArr r = toEltypeArrX(x, re);
assert((xe==el_B) == (r.refState!=0));
if (r.refState != 0) {
assert(re == el_B);
if (r.refState == 1) decByMask(bitany_ptr(w), r.xp, ia, 0);
else incByMask(bitany_ptr(w), r.xp, ia, 1);
}
u64 cv;
@ -1141,10 +1125,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)](r.data, xp, cv, bitany_ptr(w), ia);
blendArrScalarFns[elwBitLog(re)](r.rp, r.xp, cv, bitany_ptr(w), ia);
NOGC_E;
decG(w); decG(x);
return r.obj;
return r.res;
}
#endif
goto notConstEach; notConstEach:;

View File

@ -799,12 +799,14 @@ 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) {
assert(isArr(x));
if (reusable(x) && re==reuseElType[TY(x)]) {
static DirectArr doReuse(B x, u8 xe) { // consumes (i.e. transfers x to result)
assert(TI(x,elType)==xe);
x = REUSE(x);
return (DirectArr){x, reusableArr_ptr(a(x), re)};
}
return (DirectArr){x, reusableArr_ptr(a(x), xe)};
}
DirectArr toEltypeArr(B x, u8 re) { // consumes
assert(isArr(x));
if (reusable(x) && re==reuseElType[TY(x)]) return doReuse(x, re);
Arr* tyarr;
switch (re) { default: UD;
@ -827,18 +829,15 @@ DirectArr toEltypeArr(B x, u8 re) {
tyarr:
return (DirectArr){taga(tyarr), tyarrv_ptr((TyArr*) tyarr)};
}
static NOINLINE DirectArr m_fillarrAs(B x, B fill) {
static NOINLINE DirectArr m_fillarrAs(B x, B fill) { // doesn't consume
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)};
}
static DirectArr m_directarrAs(B x, u8 xe) { // doesn't consume
if (xe==el_B) {
B fill = getFillR(x);
if (!noFill(fill)) return m_fillarrAs(x, fill);
@ -850,6 +849,48 @@ DirectArr potentiallyReuse(B x) {
void* rp = m_tyarrlbc(&r, elwBitLog(xe), x, el2t(xe));
return (DirectArr) {r, rp};
}
static bool canReuse(B x, u8 xe) {
return reusable(x) && xe == reuseElType[TY(x)];
}
DirectArr potentiallyReuse(B x) { // doesn't consume
assert(isArr(x));
u8 xe = TI(x,elType);
return canReuse(x, xe)? doReuse(incG(x), xe) : m_directarrAs(x, xe);
}
ConvArr toEltypeArrX(B x, u8 re) { // doesn't consume
debug_assert(isArr(x) && el_or(re,TI(x,elType))==re);
u8 xe = TI(x,elType);
u8 refState = 0;
DirectArr dr;
if (re == xe) {
if (canReuse(x, xe)) {
refState = xe==el_B? 1 : 0;
dr = doReuse(incG(x), xe);
goto ret_dr;
} else {
void* xp;
if (xe == el_B) {
xp = arr_bptr(x);
if (xp == NULL) {
refState = 1;
goto toEltype;
}
refState = 2;
} else {
xp = tyany_ptr(x);
}
DirectArr r = m_directarrAs(x, re);
return (ConvArr){r.obj, r.data, xp, refState};
}
} else {
assert(xe != el_B);
toEltype:;
dr = toEltypeArr(incG(x), re);
ret_dr:
return (ConvArr){dr.obj, dr.data, dr.data, refState};
}
}
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); }

View File

@ -288,15 +288,28 @@ 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);
// returns an array with eltype==re, with same shape/elements/fill as x, and its data pointer
DirectArr toEltypeArr(B x, u8 re); // consumes
// doesn't consume; returns array with same shape & fill as x, returning x itself if possible (iif so, x.u==obj.u).
// 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);
// Otherwise, functionality is the same as if a regular new array was made (i.e. uninitialized elements, may start NOGC)
DirectArr potentiallyReuse(B x); // doesn't consume
typedef struct {
B res;
void* rp;
void* xp;
u8 refState;
} ConvArr;
// gives TI(res,elType)==re to write in via rp, and a pointer to x's data in eltype==re representation, from either x, or rp
// TI(x,elType)==el_B needs special handling based on result.refState:
// 0: elements aren't reference-counted (is so iif TI(x,elType)!=el_B)
// 1: xp==rp, elements not desired to be copied from x must be decremented
// 2: result is a fresh array, so elements desired to be copied from x must be incremented
ConvArr toEltypeArrX(B x, u8 re); // doesn't consume; x must stay alive for xp to remain valid
#define DIRECTARR_COPY(R, RE, X) \
u8 R##_elt = RE; \