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 // (c ; C˙)¨⌾(w⊸/) x
#if SINGELI_SIMD #if SINGELI_SIMD
if (isFun(o) && TY(o)==t_md1D) { if (MAY_F(isFun(o) && TY(o)==t_md1D)) {
u8 xe = TI(x,elType); u8 xe = TI(x,elType);
Md1D* od = c(Md1D,o); 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); else incByG(c, sum-1);
} }
DirectArr r; ConvArr r = toEltypeArrX(x, re);
void* xp; assert((xe==el_B) == (r.refState!=0));
if (re != xe) { if (r.refState != 0) {
assert(xe != el_B); assert(re == el_B);
r = toEltypeArr(x, re); if (r.refState == 1) decByMask(bitany_ptr(w), r.xp, ia, 0);
x = incG(r.obj); else incByMask(bitany_ptr(w), r.xp, ia, 1);
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);
}
} }
u64 cv; 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); 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; NOGC_E;
decG(w); decG(x); decG(w); decG(x);
return r.obj; return r.res;
} }
#endif #endif
goto notConstEach; notConstEach:; 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) { 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); 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) { 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), xe)};
}
DirectArr toEltypeArr(B x, u8 re) { // consumes
assert(isArr(x)); assert(isArr(x));
if (reusable(x) && re==reuseElType[TY(x)]) { if (reusable(x) && re==reuseElType[TY(x)]) return doReuse(x, re);
x = REUSE(x);
return (DirectArr){x, reusableArr_ptr(a(x), re)};
}
Arr* tyarr; Arr* tyarr;
switch (re) { default: UD; switch (re) { default: UD;
@ -827,18 +829,15 @@ DirectArr toEltypeArr(B x, u8 re) {
tyarr: tyarr:
return (DirectArr){taga(tyarr), tyarrv_ptr((TyArr*) 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); Arr* r = arr_shCopy(m_fillarrp(IA(x)), x);
fillarr_setFill(r, fill); fillarr_setFill(r, fill);
return (DirectArr){taga(r), fillarrv_ptr(r)}; return (DirectArr){taga(r), fillarrv_ptr(r)};
} }
DirectArr potentiallyReuse(B x) { static DirectArr m_directarrAs(B x, u8 xe) { // doesn't consume
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) { if (xe==el_B) {
B fill = getFillR(x); B fill = getFillR(x);
if (!noFill(fill)) return m_fillarrAs(x, fill); 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)); void* rp = m_tyarrlbc(&r, elwBitLog(xe), x, el2t(xe));
return (DirectArr) {r, rp}; 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_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); } 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 DirectSet directSet[el_MAX];
extern INIT_GLOBAL DirectSetRange directSetRange[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 // returns an array with eltype==re, with same shape/elements/fill as x, and its data pointer
DirectArr toEltypeArr(B x, u8 re); 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. // 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 // 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 // Otherwise, functionality is the same as if a regular new array was made (i.e. uninitialized elements, may start NOGC)
// May start NOGC DirectArr potentiallyReuse(B x); // doesn't consume
DirectArr potentiallyReuse(B x);
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) \ #define DIRECTARR_COPY(R, RE, X) \
u8 R##_elt = RE; \ u8 R##_elt = RE; \