//sl_v //sl_*_any(sl_v *args, u32int nargs) // input: ACCUM_DEFAULT ARITH_OP(a,b) MP_OP ARITH_OVERFLOW // add: 0 a+b mpadd sadd_overflow_64 // mul: 1 a*b mpmul smul_overflow_64 mpint *Maccum = nil, *m = nil; s64int Saccum = ACCUM_DEFAULT, x; double Faccum = ACCUM_DEFAULT; u64int u64; bool inexact = false; int forcetype = -1; sl_v arg; sl_numtype pt; void *a; sl_cv *cv; u32int i, j; FOR_ARGS(i, 0, arg, args){ if(isfixnum(arg)) x = numval(arg); else{ if(isubnum(arg)){ pt = ubnumtype(arg); u64 = ubnumval(arg); a = ubnumptr(u64, pt); }else if(iscvalue(arg)){ cv = ptr(sl_cv, arg); a = cv_data(cv); pt = cv_numtype(cv); }else{ typeerr: mpfree(Maccum); mpfree(m); cthrow(type_error(nil, "num", arg), args); } switch(pt){ case T_F64: Faccum = ARITH_OP(Faccum, *(double*)a); inexact = true; continue; case T_F32: Faccum = ARITH_OP(Faccum, *(float*)a); inexact = true; continue; case T_S8: x = *(s8int*)a; break; case T_U8: x = *(u8int*)a; break; case T_S16: x = *(s16int*)a; break; case T_U16: x = *(u16int*)a; break; case T_S32: x = *(s32int*)a; break; #if !defined(ARITH_NOPTR) case T_P32: if(forcetype < T_P32) forcetype = T_P32; sl_fallthrough; #endif case T_U32: x = *(u32int*)a; break; case T_S64: x = *(s64int*)a; break; #if !defined(ARITH_NOPTR) case T_P64: if(forcetype < T_P64) forcetype = T_P64; sl_fallthrough; #endif case T_U64: u64 = *(u64int*)a; if(u64 > INT64_MAX){ x = ACCUM_DEFAULT; goto overflow; } x = u64; break; case T_BIG: x = ACCUM_DEFAULT; u64 = ACCUM_DEFAULT; m = mpcopy(*(mpint**)a); goto overflow; default: goto typeerr; } } s64int accu; if(ARITH_OVERFLOW(Saccum, x, &accu)){ u64 = ACCUM_DEFAULT; goto overflow; } Saccum = accu; } if(sl_unlikely(forcetype >= 0)){ forcedptr: if(inexact) cthrow(error(sl_errarg, "arithmetic on a mix of ptr and inexact types"), args); switch(forcetype){ case T_P32: return mk_p32(Saccum); case T_P64: return mk_p64(Saccum); default: abort(); } } if(sl_unlikely(inexact)) return mk_f64(ARITH_OP(Faccum, (double)Saccum)); if(sl_likely(fits_fixnum(Saccum))) return fixnum((sl_fx)Saccum); u64 = ACCUM_DEFAULT; x = ACCUM_DEFAULT; overflow: i++; if(sl_likely(Maccum == nil)) Maccum = vtomp(Saccum, nil); if(sl_unlikely(m == nil)) m = u64 != ACCUM_DEFAULT ? uvtomp(u64, nil) : vtomp(x, nil); MP_OP(Maccum, m, Maccum); FOR_ARGS(j, i, arg, args){ if(isfixnum(arg)){ vtomp(numval(arg), m); MP_OP(Maccum, m, Maccum); continue; } if(isubnum(arg)){ pt = ubnumtype(arg); u64 = ubnumval(arg); a = ubnumptr(u64, pt); }else if(iscvalue(arg)){ cv = ptr(sl_cv, arg); a = cv_data(cv); pt = cv_numtype(cv); }else{ goto typeerr; } switch(pt){ case T_F64: Faccum = ARITH_OP(Faccum, *(double*)a); inexact = true; continue; case T_F32: Faccum = ARITH_OP(Faccum, *(float*)a); inexact = true; continue; case T_S8: x = *(s8int*)a; break; case T_U8: x = *(u8int*)a; break; case T_S16: x = *(s16int*)a; break; case T_U16: x = *(u16int*)a; break; case T_S32: x = *(s32int*)a; break; #if !defined(ARITH_NOPTR) case T_P32: if(forcetype < T_P32) forcetype = T_P32; sl_fallthrough; #endif case T_U32: x = *(u32int*)a; break; case T_S64: x = *(s64int*)a; break; #if !defined(ARITH_NOPTR) case T_P64: if(forcetype < T_P64) forcetype = T_P64; sl_fallthrough; #endif case T_U64: uvtomp(*(u64int*)a, m); MP_OP(Maccum, m, Maccum); continue; case T_BIG: MP_OP(Maccum, *(mpint**)a, Maccum); continue; default: goto typeerr; } vtomp(x, m); MP_OP(Maccum, m, Maccum); } if(forcetype >= 0){ Saccum = mptouv(Maccum); goto forcedptr; } int n = mpsignif(Maccum); if(n >= FIXNUM_BITS){ if(inexact){ dtomp(Faccum, m); MP_OP(Maccum, m, Maccum); n = mpsignif(Maccum); if(n < FIXNUM_BITS){ inexact = false; goto down; } } mpfree(m); return mk_bignum(Maccum); } down: mpfree(m); Saccum = mptov(Maccum); mpfree(Maccum); if(inexact) return mk_f64(ARITH_OP(Faccum, (double)Saccum)); assert(fits_fixnum(Saccum)); return fixnum((sl_fx)Saccum); #undef ACCUM_DEFAULT #undef ARITH_OP #undef MP_OP #undef ARITH_OVERFLOW #undef ARITH_NOPTR