// Ported from Hare's math::checked saturating siblings // (ref/hare/math/checked/saturating.ha). Part of the same `checked` // module as checked.ww. Each sat_* clamps to the type's range on // overflow instead of wrapping. // // Three ww adaptations vs Hare, all forced by language differences, none // behavioral: // - no if-as-expression (N_IF is statement-only, see strings.ww), so // Hare's `return if (c) X else Y` becomes an if-statement. // - unsigned overflow tests rely on inline wraparound in Hare; ww // truncates sub-word arithmetic only on store to a typed lvalue, so // the wrap is forced through a typed `res`. // - the mul overflow compares need an explicit widening cast (no // implicit promotion in ww). // // Deferred (faithful subset, Hare splits per type): sat_*z (no `size` // type, #85); sat_muli64/sat_mulu64/sat_muli/sat_mulu (need // math::mulu64); int/uint native-width sat_* (ww int is 64-bit — a width // divergence in the overflow boundary). package checked; import types; export fn sat_addi8(a: i8, b: i8) i8 = { let res: i8 = a + b; if (a < 0 == b < 0 && a < 0 != res < 0) { if (res < 0) { return types.I8_MAX; }; return types.I8_MIN; }; return res; }; export fn sat_addi16(a: i16, b: i16) i16 = { let res: i16 = a + b; if (a < 0 == b < 0 && a < 0 != res < 0) { if (res < 0) { return types.I16_MAX; }; return types.I16_MIN; }; return res; }; export fn sat_addi32(a: i32, b: i32) i32 = { let res: i32 = a + b; if (a < 0 == b < 0 && a < 0 != res < 0) { if (res < 0) { return types.I32_MAX; }; return types.I32_MIN; }; return res; }; export fn sat_addi64(a: i64, b: i64) i64 = { let res: i64 = a + b; if (a < 0 == b < 0 && a < 0 != res < 0) { if (res < 0) { return types.I64_MAX; }; return types.I64_MIN; }; return res; }; export fn sat_addu8(a: u8, b: u8) u8 = { let res: u8 = a + b; if (res < a) { return types.U8_MAX; }; return res; }; export fn sat_addu16(a: u16, b: u16) u16 = { let res: u16 = a + b; if (res < a) { return types.U16_MAX; }; return res; }; export fn sat_addu32(a: u32, b: u32) u32 = { let res: u32 = a + b; if (res < a) { return types.U32_MAX; }; return res; }; export fn sat_addu64(a: u64, b: u64) u64 = { let res: u64 = a + b; if (res < a) { return types.U64_MAX; }; return res; }; export fn sat_subi8(a: i8, b: i8) i8 = { let res: i8 = a - b; if (a < 0 != b < 0 && a < 0 != res < 0) { if (res < 0) { return types.I8_MAX; }; return types.I8_MIN; }; return res; }; export fn sat_subi16(a: i16, b: i16) i16 = { let res: i16 = a - b; if (a < 0 != b < 0 && a < 0 != res < 0) { if (res < 0) { return types.I16_MAX; }; return types.I16_MIN; }; return res; }; export fn sat_subi32(a: i32, b: i32) i32 = { let res: i32 = a - b; if (a < 0 != b < 0 && a < 0 != res < 0) { if (res < 0) { return types.I32_MAX; }; return types.I32_MIN; }; return res; }; export fn sat_subi64(a: i64, b: i64) i64 = { let res: i64 = a - b; if (a < 0 != b < 0 && a < 0 != res < 0) { if (res < 0) { return types.I64_MAX; }; return types.I64_MIN; }; return res; }; export fn sat_subu8(a: u8, b: u8) u8 = { let res: u8 = a - b; if (res > a) { return types.U8_MIN; }; return res; }; export fn sat_subu16(a: u16, b: u16) u16 = { let res: u16 = a - b; if (res > a) { return types.U16_MIN; }; return res; }; export fn sat_subu32(a: u32, b: u32) u32 = { let res: u32 = a - b; if (res > a) { return types.U32_MIN; }; return res; }; export fn sat_subu64(a: u64, b: u64) u64 = { let res: u64 = a - b; if (res > a) { return types.U64_MIN; }; return res; }; export fn sat_muli8(a: i8, b: i8) i8 = { let fullres: int = a: int * b: int; let res: i8 = fullres: i8; if (res: int != fullres) { if (res < 0) { return types.I8_MAX; }; return types.I8_MIN; }; return res; }; export fn sat_muli16(a: i16, b: i16) i16 = { let fullres: int = a: int * b: int; let res: i16 = fullres: i16; if (res: int != fullres) { if (res < 0) { return types.I16_MAX; }; return types.I16_MIN; }; return res; }; export fn sat_muli32(a: i32, b: i32) i32 = { let fullres: i64 = a: i64 * b: i64; let res: i32 = fullres: i32; if (res: i64 != fullres) { if (res < 0) { return types.I32_MAX; }; return types.I32_MIN; }; return res; }; export fn sat_mulu8(a: u8, b: u8) u8 = { let res: uint = a: uint * b: uint; if (res > (types.U8_MAX): uint) { return types.U8_MAX; }; return res: u8; }; export fn sat_mulu16(a: u16, b: u16) u16 = { let res: uint = a: uint * b: uint; if (res > (types.U16_MAX): uint) { return types.U16_MAX; }; return res: u16; }; export fn sat_mulu32(a: u32, b: u32) u32 = { let res: u64 = a: u64 * b: u64; if (res > (types.U32_MAX): u64) { return types.U32_MAX; }; return res: u32; };