uCBQN/src/builtins/squeeze.c
2025-05-15 00:43:53 +03:00

315 lines
10 KiB
C

#include "../core.h"
#define SQFN_START assert(xa == a(x) && ia==IA(x) && ia>0 && TY(x)==type && a(x)==xa)
typedef B (*SqueezeFn)(B x, Arr* xa, u8 type, ux ia);
static B squeeze_smallest(B x, Arr* xa, u8 type, ux ia) {
SQFN_START;
assert(TI(x,elType)==el_bit || TI(x,elType)==el_c8);
FLV_SET(xa, fl_squoze);
return x;
}
static B squeeze_nope(B x, Arr* xa, u8 type, ux ia) {
SQFN_START;
return x;
}
#define SQFN_NUM_RET \
mostI32:MAYBE_UNUSED; if(or>I16_MAX) goto r_i32; \
mostI16:MAYBE_UNUSED; if(or>I8_MAX ) goto r_i16; \
mostI8: MAYBE_UNUSED; if(or>0 ) goto r_i8; \
mostBit:MAYBE_UNUSED; goto r_bit; \
r_f64:MAYBE_UNUSED; xa = cpyF64Arr(x); goto tag; \
r_i32: xa = cpyI32Arr(x); goto tag; \
r_i16: xa = cpyI16Arr(x); goto tag; \
r_i8: xa = cpyI8Arr (x); goto tag; \
r_bit: xa = cpyBitArr(x); goto tag; \
tag: x = taga(xa); \
squeezed: FLV_SET(xa, fl_squoze); \
return x;
#define SQFN_CHR_RET \
r_c32:MAYBE_UNUSED; xa = cpyC32Arr(x); goto tag; \
r_c16:MAYBE_UNUSED; xa = cpyC16Arr(x); goto tag; \
r_c8: MAYBE_UNUSED; xa = cpyC8Arr (x); goto tag; \
tag: x = taga(xa); \
squeezed: FLV_SET(xa, fl_squoze); \
return x;
#define SQFN_NUM(T, CORE) static B squeeze_##T(B x, Arr* xa, u8 type, ux ia) { \
SQFN_START; \
u32 or=0; CORE; \
SQFN_NUM_RET; \
}
#define SQFN_CHR(T, CORE) static B squeeze_##T(B x, Arr* xa, u8 type, ux ia) { \
SQFN_START; \
CORE; \
SQFN_CHR_RET; \
}
#if SINGELI_SIMD
#define SINGELI_FILE squeeze
#include "../utils/includeSingeli.h"
SQFN_NUM(i8, or = si_squeeze_i8 ( i8anyv_ptr(xa), ia); if(or> 1) goto squeezed; else goto mostBit;)
SQFN_NUM(i16, or = si_squeeze_i16(i16anyv_ptr(xa), ia); if(or> I8_MAX) goto squeezed; else goto mostI8;)
SQFN_NUM(i32, or = si_squeeze_i32(i32anyv_ptr(xa), ia); if(or> I16_MAX) goto squeezed; else goto mostI16;)
SQFN_NUM(f64, or = si_squeeze_f64(f64anyv_ptr(xa), ia); if(-1==(u32)or) goto squeezed; else goto mostI32;)
SQFN_CHR(c16, u32 t = si_squeeze_c16(c16anyv_ptr(xa), ia); if (t==0) goto r_c8; else goto squeezed;)
SQFN_CHR(c32, u32 t = si_squeeze_c32(c32anyv_ptr(xa), ia); if (t==0) goto r_c8; else if (t==1) goto r_c16; else if (t==2) goto squeezed; else UD;)
#else
SQFN_NUM(i8, i8* xp = i8anyv_ptr (xa); for (ux i=0; i<ia; i++) { i32 c = xp[i]; or|= (u8)c; } if(or> 1) goto squeezed; goto mostBit;)
SQFN_NUM(i16, i16* xp = i16anyv_ptr(xa); for (ux i=0; i<ia; i++) { i32 c = xp[i]; or|= ((u32)c & ~1) ^ (u32)(c>>31); } if(or> I8_MAX) goto squeezed; goto mostI8;)
SQFN_NUM(i32, i32* xp = i32anyv_ptr(xa); for (ux i=0; i<ia; i++) { i32 c = xp[i]; or|= ((u32)c & ~1) ^ (u32)(c>>31); } if(or>I16_MAX) goto squeezed; goto mostI16;)
SQFN_NUM(f64,
f64* xp = f64anyv_ptr(xa);
for (ux i = 0; i < ia; i++) {
f64 cf = xp[i];
i32 c = (i32)cf;
if (c!=cf) goto squeezed;
or|= ((u32)c & ~1) ^ (u32)(c>>31);
}
goto mostI32;
)
SQFN_CHR(c16,
u16* xp = c16anyv_ptr(xa);
for (ux i = 0; i < ia; i++) if (xp[i] != (u8)xp[i]) goto squeezed;
goto r_c8;
)
SQFN_CHR(c32,
u32* xp = c32anyv_ptr(xa);
bool c8 = true;
for (ux i = 0; i < ia; i++) {
if (xp[i] != (u16)xp[i]) goto squeezed;
if (xp[i] != (u8 )xp[i]) c8 = false;
}
if (c8) goto r_c8;
else goto r_c16;
)
#endif
#define SQUEEZE_NUM_B_LOOP(GET) \
u32 or = 0; \
for (ux i = 0; i < ia; i++) { \
B c = GET; \
if (RARE(!q_i32(c))) { \
while (i<ia) { if (!isF64(GET)) goto not_num; i++; } \
goto r_f64; \
} \
i32 ci = o2iG(c); \
or|= ((u32)ci & ~1) ^ (u32)(ci>>31); \
} \
goto mostI32;
#define SQFN_NUM_B \
not_num: \
if (notChar) goto squeezed; \
else return x; \
SQFN_NUM_RET;
NOINLINE B squeeze_B_numSlow(B x, Arr* xa, u8 type, usz ia, bool notChar) {
SQFN_START;
SGetU(x)
SQUEEZE_NUM_B_LOOP(GetU(x,i))
SQFN_NUM_B;
}
SHOULD_INLINE B squeeze_BV_numImpl(B x, Arr* xa, u8 type, ux ia, B* xp, bool notChar) {
SQFN_START;
#if SINGELI_SIMD
u32 or = si_squeeze_numB(xp, ia);
if (-2==(i32)or) goto not_num;
if (-1==(i32)or) goto r_f64;
goto mostI32;
#else
SQUEEZE_NUM_B_LOOP(xp[i])
#endif
SQFN_NUM_B;
}
#define SQFN_CHR_B \
if (or>U16_MAX) goto r_c32; \
if (or>U8_MAX ) goto r_c16; \
goto r_c8; \
not_chr: \
if (notNum) goto squeezed; \
else return x; \
SQFN_CHR_RET;
NOINLINE B squeeze_B_chrSlow(B x, Arr* xa, u8 type, usz ia, bool notNum) {
SQFN_START;
u32 or = 0;
SGetU(x)
for (ux i = 0; i < ia; i++) {
B cr = GetU(x,i);
if (!isC32(cr)) goto not_chr;
or|= o2cG(cr);
}
SQFN_CHR_B;
}
SHOULD_INLINE B squeeze_BV_chrImpl(B x, Arr* xa, u8 type, usz ia, B* xp, bool notNum) {
SQFN_START;
u32 or = 0;
#if SINGELI_SIMD
u32 t = si_squeeze_chrB(xp, ia);
if (t==0) goto r_c8;
else if (t==1) goto r_c16;
else if (t==2) goto r_c32;
else if (t==3) goto not_chr;
else UD;
#else
for (ux i = 0; i < ia; i++) {
if (!isC32(xp[i])) goto not_chr;
or|= o2cG(xp[i]);
}
#endif
SQFN_CHR_B;
}
SHOULD_INLINE B squeeze_B_chrImpl(B x, Arr* xa, u8 type, ux ia, bool notNum) {
B* xp = arrv_bptr(xa);
if (xp!=NULL) return squeeze_BV_chrImpl(x, xa, type, ia, xp, notNum);
else return squeeze_B_chrSlow(x, xa, type, ia, notNum);
}
SHOULD_INLINE B squeeze_B_numImpl(B x, Arr* xa, u8 type, ux ia, bool notNum) {
B* xp = arrv_bptr(xa);
if (xp!=NULL) return squeeze_BV_numImpl(x, xa, type, ia, xp, notNum);
else return squeeze_B_numSlow(x, xa, type, ia, notNum);
}
static B squeeze_B_numMaybe(B x, Arr* xa, u8 type, ux ia) { return squeeze_B_numImpl(x, xa, type, ia, false); }
static B squeeze_B_chrMaybe(B x, Arr* xa, u8 type, ux ia) { return squeeze_B_chrImpl(x, xa, type, ia, false); }
NOINLINE B squeeze_BGeneric(B x, Arr* xa, u8 type, ux ia) {
SQFN_START;
B x0 = IGetU(x,0);
if (isNum(x0)) return squeeze_B_numSlow(x, xa, type, ia, true);
if (isC32(x0)) return squeeze_B_chrSlow(x, xa, type, ia, true);
FLV_SET(xa, fl_squoze);
return x;
}
static B squeeze_B(B x, Arr* xa, u8 type, ux ia) {
SQFN_START;
B* xp = arrv_bptr(xa);
if (xp == NULL) return squeeze_BGeneric(x, xa, type, ia);
B x0 = xp[0];
if (isNum(x0)) return squeeze_BV_numImpl(x, xa, type, ia, xp, true);
if (isC32(x0)) return squeeze_BV_chrImpl(x, xa, type, ia, xp, true);
FLV_SET(xa, fl_squoze);
return x;
}
// el_bit el_i8 el_i16 el_i32 el_f64 el_c8 el_c16 el_c32 el_B
SqueezeFn squeeze_numFns[el_MAX] = {squeeze_smallest, squeeze_i8, squeeze_i16, squeeze_i32, squeeze_f64, squeeze_smallest, squeeze_nope, squeeze_nope, squeeze_B_numMaybe};
SqueezeFn squeeze_chrFns[el_MAX] = {squeeze_smallest, squeeze_nope, squeeze_nope, squeeze_nope, squeeze_nope, squeeze_smallest, squeeze_c16, squeeze_c32, squeeze_B_chrMaybe};
SqueezeFn squeeze_anyFns[el_MAX] = {squeeze_smallest, squeeze_i8, squeeze_i16, squeeze_i32, squeeze_f64, squeeze_smallest, squeeze_c16, squeeze_c32, squeeze_B};
NOINLINE B int_squeeze_sorted(B x, Arr* xa, u8 type, ux ia) {
SQFN_START;
assert(elInt(TI(x,elType)));
if (ia==0) {
squeezed:
return FL_SET(x, fl_squoze);
}
u8 xe = TI(x,elType);
i32 x0v, x1v;
void* xp = tyanyv_ptr(xa);
ux last = ia-1;
switch (xe) { default: UD;
case el_bit: goto squeezed;
case el_i8: x0v = ((i8* )xp)[0]; x1v = ((i8* )xp)[last]; break;
case el_i16: x0v = ((i16*)xp)[0]; x1v = ((i16*)xp)[last]; break;
case el_i32: x0v = ((i32*)xp)[0]; x1v = ((i32*)xp)[last]; break;
}
u8 x0e = selfElType_i32(x0v);
u8 x1e = selfElType_i32(x1v);
u8 re = x0e>x1e? x0e : x1e;
if (xe == re) goto squeezed;
u8 flags = FLV_GET(xa) | fl_squoze;
Arr* ra;
switch (re) { default: UD;
case el_i16: ra = cpyI16Arr(x); break;
case el_i8: ra = cpyI8Arr (x); break;
case el_bit: ra = cpyBitArr(x); break;
}
debug_assert(!FLV_HAS(ra, fl_asc|fl_dsc)); // if cpy*Arr starts preserving flags, this should be changed to not do so itself
return taga(FLV_SET(ra, flags));
}
#define SQ_FAST(RET) if (FL_HAS(x, fl_squoze)) { RET; }
#define SQ_FAST_EXT(NEW, RET) \
if (FL_HAS(x, fl_squoze|fl_asc|fl_dsc)) { \
SQ_FAST(RET) \
if (elInt(TI(x,elType))) { x = int_squeeze_sorted(x, a(x), TY(x), ia); NEW; RET; } \
} // could check for sorted character arrays (even from a TI(x,el_B) input) but sorted character arrays aren't worth it
#define SQ_READ \
assert(isArr(x)); \
u8 xe = TI(x,elType); \
usz ia = IA(x);
NOINLINE B squeeze_any(B x) {
SQ_READ;
SQ_FAST_EXT(, return x);
if (ia==0) return FL_SET(x, fl_squoze); // TODO return a version of the smallest type?
return squeeze_anyFns[xe](x, a(x), TY(x), ia);
}
NOINLINE B squeeze_numNew(B x) {
SQ_READ;
if (ia==0) return xe==el_bit? x : emptyNumsWithShape(x);
return squeeze_numFns[xe](x,a(x),TY(x),ia);
}
NOINLINE B squeeze_chrNew(B x) {
SQ_READ;
if (ia==0) return xe==el_c8? x : emptyChrsWithShape(x);
return squeeze_chrFns[xe](x,a(x),TY(x),ia);
}
SqRes squeeze_numTryImpl(B x) {
SQ_READ;
if (ia==0) return (SqRes){xe==el_bit? x : emptyNumsWithShape(x), el_bit};
SQ_FAST_EXT(xe=TI(x,elType), return ((SqRes){x, xe}));
x = squeeze_numFns[xe](x,a(x),TY(x),ia);
return (SqRes){x, TI(x,elType)};
}
SqRes squeeze_chrTryImpl(B x) {
SQ_READ;
SQ_FAST(return ((SqRes){x, xe}));
if (ia==0) return (SqRes){xe==el_c8? x : emptyChrsWithShape(x), el_c8};
x = squeeze_chrFns[xe](x,a(x),TY(x),ia);
return (SqRes){x, TI(x,elType)};
}
B squeeze_numOut(B x) { return squeeze_numTryImpl(x).r; }
B squeeze_chrOut(B x) { return squeeze_chrTryImpl(x).r; }
B squeeze_deep(B x) {
if (!isArr(x)) return x;
x = squeeze_any(x);
if (TI(x,elType)!=el_B) return x;
usz ia = IA(x);
M_HARR(r, ia)
B* xp = arr_bptr(x);
B xf = getFillR(x);
if (xp!=NULL) {
for (ux i=0; i<ia; i++) { HARR_ADD(r, i, squeeze_deep(inc(xp[i]))); }
} else {
SGet(x);
for (ux i=0; i<ia; i++) { HARR_ADD(r, i, squeeze_deep(Get(x,i))); }
}
return squeeze_any(qWithFill(HARR_FCD(r, x), xf));
}