uCBQN/src/utils/each.c
2023-04-29 17:39:13 +03:00

131 lines
4.7 KiB
C

#include "../core.h"
#include "each.h"
static inline B mv(B* p, usz n) { B r = p [n]; p [n] = m_f64(0); return r; }
static inline B hmv(HArr_p p, usz n) { B r = p.a[n]; p.a[n] = m_f64(0); return r; }
B eachd_fn(B fo, B w, B x, FC2 f) {
ur wr, xr; // if rank is 0, respective w/x will be disclosed
if (isArr(w)) { wr=RNK(w); if (wr==0) { B c=IGet(w, 0); decG(w); w=c; } } else wr=0;
if (isArr(x)) { xr=RNK(x); if (xr==0) { B c=IGet(x, 0); decG(x); x=c; } } else xr=0;
bool wg = wr>xr;
ur rM = wg? wr : xr;
ur rm = wg? xr : wr;
if (rM==0) return m_funit(f(fo, w, x));
if (rm && !eqShPart(SH(w), SH(x), rm)) thrF("Mapping: Expected equal shape prefix (%H ≡ ≢𝕨, %H ≡ ≢𝕩)", w, x);
bool rw = rM==wr && reusable(w) && TY(w)==t_harr; // dereferencing is safe as rank>0 from rM==
bool rx = rM==xr && reusable(x) && TY(x)==t_harr;
if (rw|rx && (wr==xr | rm==0)) {
HArr_p r = harr_parts(REUSE(rw? w : x));
usz ria = r.c->ia;
if (ria>0) {
if (wr==0) { incBy(w, ria-1); for(usz i=0; i<ria; i++) r.a[i] = f(fo, w, hmv(r,i)); }
else if (xr==0) { incBy(x, ria-1); for(usz i=0; i<ria; i++) r.a[i] = f(fo, hmv(r,i), x ); }
else {
assert(wr==xr);
if (rw) { SGet(x) for (usz i = 0; i < ria; i++) r.a[i] = f(fo, hmv(r,i), Get(x,i)); }
else { SGet(w) for (usz i = 0; i < ria; i++) r.a[i] = f(fo, Get(w,i), hmv(r,i)); }
decG(rw? x : w);
}
} else {
dec(rw? x : w);
}
return any_squeeze(r.b);
}
B bo = wg? w : x;
usz ria = IA(bo);
B rb;
if (ria==0) {
rb = rM==1? emptyHVec() : m_harrUc(bo).b;
} else {
M_HARR(r, ria)
if (wr==xr) { SGet(x) SGet(w) for(usz ri=0; ri<ria; ri++) HARR_ADD(r, ri, f(fo, Get(w,ri), Get(x,ri))); }
else if (wr==0) { incBy(w, ria); SGet(x) for(usz ri=0; ri<ria; ri++) HARR_ADD(r, ri, f(fo, w , Get(x,ri))); }
else if (xr==0) { incBy(x, ria); SGet(w) for(usz ri=0; ri<ria; ri++) HARR_ADD(r, ri, f(fo, Get(w,ri), x )); }
else {
usz min = wg? IA(x) : IA(w);
usz ext = ria / min;
SGet(w) SGet(x)
if (wg) for (usz i = 0; i < min; i++) { B c=incBy(Get(x,i), ext-1); for (usz j=0; j<ext; j++) HARR_ADDA(r, f(fo, Get(w,HARR_I(r)), c)); }
else for (usz i = 0; i < min; i++) { B c=incBy(Get(w,i), ext-1); for (usz j=0; j<ext; j++) HARR_ADDA(r, f(fo, c, Get(x,HARR_I(r)))); }
}
rb = any_squeeze(HARR_FC(r, bo));
}
dec(w); dec(x);
return rb;
}
B eachm_fn(B fo, B x, FC1 f) {
usz ia = IA(x);
usz i = 0;
if (ia==0) return x;
if (reusable(x)) {
B* xp;
re_reuse:
switch (v(x)->type) {
case t_fillarr: {
dec(c(FillArr,x)->fill);
c(FillArr,x)->fill = bi_noFill;
xp = fillarr_ptr(a(x));
break;
}
case t_harr: {
xp = harr_ptr(x);
break;
}
case t_fillslice: {
FillSlice* s = c(FillSlice,x);
Arr* p = s->p;
if (p->refc==1 && (p->type==t_fillarr || p->type==t_harr) && ((FillArr*)p)->a == s->a && PIA(p)==ia) {
ur sr = PRNK(s);
if (sr<=1) {
arr_shErase(p, sr);
} else {
usz* ssh = PSH(s);
if (ssh != PSH(p)) arr_shReplace(p, sr, ptr_inc(shObjS(ssh)));
}
x = taga(ptr_inc(p));
value_free((Value*)s);
goto re_reuse;
} else goto base;
}
default: goto base;
}
REUSE(x);
for (; i < ia; i++) xp[i] = f(fo, mv(xp, i));
return any_squeeze(x);
}
base:;
M_HARR(r, ia)
void* xp = tyany_ptr(x);
switch(TI(x,elType)) { default: UD;
case el_B: { SGet(x);
{ for (; i<ia; i++) HARR_ADD(r, i, f(fo, Get(x,i))); } break; }
case el_bit: for (; i<ia; i++) HARR_ADD(r, i, f(fo, m_i32(bitp_get(xp,i)))); break;
case el_i8: for (; i<ia; i++) HARR_ADD(r, i, f(fo, m_i32(((i8* )xp)[i]))); break;
case el_i16: for (; i<ia; i++) HARR_ADD(r, i, f(fo, m_i32(((i16*)xp)[i]))); break;
case el_i32: for (; i<ia; i++) HARR_ADD(r, i, f(fo, m_i32(((i32*)xp)[i]))); break;
case el_f64: for (; i<ia; i++) HARR_ADD(r, i, f(fo, m_f64(((f64*)xp)[i]))); break;
case el_c8: for (; i<ia; i++) HARR_ADD(r, i, f(fo, m_c32(((u8* )xp)[i]))); break;
case el_c16: for (; i<ia; i++) HARR_ADD(r, i, f(fo, m_c32(((u16*)xp)[i]))); break;
case el_c32: for (; i<ia; i++) HARR_ADD(r, i, f(fo, m_c32(((u32*)xp)[i]))); break;
}
return any_squeeze(HARR_FCD(r, x));
}
#if CATCH_ERRORS
B arith_recd(FC2 f, B w, B x) {
B fx = getFillQ(x);
if (noFill(fx)) return eachd_fn(bi_N, w, x, f);
B fw = getFillQ(w);
B r = eachd_fn(bi_N, w, x, f);
if (noFill(fw)) { dec(fx); return r; }
if (CATCH) { freeThrown(); return r; }
B fr = f(bi_N, fw, fx);
popCatch();
return withFill(r, asFill(fr));
}
#endif