diff --git a/corelib/src/integer.cairo b/corelib/src/integer.cairo index a4233c03b3b..669f9c64139 100644 --- a/corelib/src/integer.cairo +++ b/corelib/src/integer.cairo @@ -1566,6 +1566,201 @@ enum SignedIntegerResult { } impl SignedIntegerResultDrop> of Drop>; +/// Impls for signed int addition and subtraction. +mod signed_int_impls { + use super::SignedIntegerResult; + + /// Helper trait for calling the libfuncs per signed int type. + trait SignedIntegerHelper { + /// The wrapper for the addition libfunc. + fn add(lhs: T, rhs: T) -> SignedIntegerResult nopanic; + /// The wrapper for the subtraction libfunc. + fn sub(lhs: T, rhs: T) -> SignedIntegerResult nopanic; + } + + impl SignedIntegerHelperI8 of SignedIntegerHelper { + fn add(lhs: i8, rhs: i8) -> SignedIntegerResult nopanic { + super::i8_overflowing_add_impl(lhs, rhs) + } + fn sub(lhs: i8, rhs: i8) -> SignedIntegerResult nopanic { + super::i8_overflowing_sub_impl(lhs, rhs) + } + } + impl SignedIntegerHelperI16 of SignedIntegerHelper { + fn add(lhs: i16, rhs: i16) -> SignedIntegerResult nopanic { + super::i16_overflowing_add_impl(lhs, rhs) + } + fn sub(lhs: i16, rhs: i16) -> SignedIntegerResult nopanic { + super::i16_overflowing_sub_impl(lhs, rhs) + } + } + impl SignedIntegerHelperI32 of SignedIntegerHelper { + fn add(lhs: i32, rhs: i32) -> SignedIntegerResult nopanic { + super::i32_overflowing_add_impl(lhs, rhs) + } + fn sub(lhs: i32, rhs: i32) -> SignedIntegerResult nopanic { + super::i32_overflowing_sub_impl(lhs, rhs) + } + } + impl SignedIntegerHelperI64 of SignedIntegerHelper { + fn add(lhs: i64, rhs: i64) -> SignedIntegerResult nopanic { + super::i64_overflowing_add_impl(lhs, rhs) + } + fn sub(lhs: i64, rhs: i64) -> SignedIntegerResult nopanic { + super::i64_overflowing_sub_impl(lhs, rhs) + } + } + impl SignedIntegerHelperI128 of SignedIntegerHelper { + fn add(lhs: i128, rhs: i128) -> SignedIntegerResult nopanic { + super::i128_overflowing_add_impl(lhs, rhs) + } + fn sub(lhs: i128, rhs: i128) -> SignedIntegerResult nopanic { + super::i128_overflowing_sub_impl(lhs, rhs) + } + } + /// Impl for `CheckedAdd` based on `SignedIntegerHelper`. + pub impl CheckedAddImpl< + T, impl H: SignedIntegerHelper, +Drop + > of crate::num::traits::CheckedAdd { + fn checked_add(self: T, v: T) -> Option { + as_checked(H::add(self, v)) + } + } + /// Impl for `CheckedSub` based on `SignedIntegerHelper`. + pub impl CheckedSubImpl< + T, impl H: SignedIntegerHelper, +Drop + > of crate::num::traits::CheckedSub { + fn checked_sub(self: T, v: T) -> Option { + as_checked(H::sub(self, v)) + } + } + /// Converts `SignedIntegerResult` to an `Option::Some` if in range and to `Option::None` + /// otherwise. + fn as_checked>(result: SignedIntegerResult) -> Option { + match result { + SignedIntegerResult::InRange(result) => Option::Some(result), + SignedIntegerResult::Underflow(_) | SignedIntegerResult::Overflow(_) => Option::None, + } + } + /// Impl for `SaturatingAdd` based on `SignedIntegerHelper`. + pub impl SaturatingAddImpl< + T, impl H: SignedIntegerHelper, +Drop, +crate::num::traits::Bounded + > of crate::num::traits::SaturatingAdd { + fn saturating_add(self: T, other: T) -> T { + as_saturating(H::add(self, other)) + } + } + /// Impl for `SaturatingSub` based on `SignedIntegerHelper`. + pub impl SaturatingSubImpl< + T, impl H: SignedIntegerHelper, +Drop, +crate::num::traits::Bounded + > of crate::num::traits::SaturatingSub { + fn saturating_sub(self: T, other: T) -> T { + as_saturating(H::sub(self, other)) + } + } + /// Converts `SignedIntegerResult` to a saturated value. + fn as_saturating, impl B: crate::num::traits::Bounded>( + result: SignedIntegerResult + ) -> T { + match result { + SignedIntegerResult::InRange(result) => result, + SignedIntegerResult::Underflow(_) => B::MIN, + SignedIntegerResult::Overflow(_) => B::MAX, + } + } + /// Impl for `OverflowingAdd` based on `SignedIntegerHelper`. + pub impl OverflowingAddImpl< + T, impl H: SignedIntegerHelper, +Drop + > of crate::num::traits::OverflowingAdd { + fn overflowing_add(self: T, v: T) -> (T, bool) { + as_overflowing(H::add(self, v)) + } + } + /// Impl for `OverflowingSub` based on `SignedIntegerHelper`. + pub impl OverflowingSubImpl< + T, impl H: SignedIntegerHelper, +Drop + > of crate::num::traits::OverflowingSub { + fn overflowing_sub(self: T, v: T) -> (T, bool) { + as_overflowing(H::sub(self, v)) + } + } + /// Converts `SignedIntegerResult` to a tuple of the result and a boolean indicating overflow. + fn as_overflowing(result: SignedIntegerResult) -> (T, bool) { + match result { + SignedIntegerResult::InRange(result) => (result, false), + SignedIntegerResult::Underflow(result) | + SignedIntegerResult::Overflow(result) => (result, true), + } + } + /// Impl for `WrappingAdd` based on `SignedIntegerHelper`. + pub impl WrappingAddImpl< + T, impl H: SignedIntegerHelper, +Drop + > of crate::num::traits::WrappingAdd { + fn wrapping_add(self: T, v: T) -> T { + as_wrapping(H::add(self, v)) + } + } + /// Impl for `WrappingSub` based on `SignedIntegerHelper`. + pub impl WrappingSubImpl< + T, impl H: SignedIntegerHelper, +Drop + > of crate::num::traits::WrappingSub { + fn wrapping_sub(self: T, v: T) -> T { + as_wrapping(H::sub(self, v)) + } + } + /// Converts `SignedIntegerResult` to a wrapping value. + fn as_wrapping(result: SignedIntegerResult) -> T { + match result { + SignedIntegerResult::InRange(result) | SignedIntegerResult::Underflow(result) | + SignedIntegerResult::Overflow(result) => result, + } + } +} +impl I8CheckedAdd = signed_int_impls::CheckedAddImpl; +impl I8CheckedSub = signed_int_impls::CheckedSubImpl; +impl I8SaturatingAdd = signed_int_impls::SaturatingAddImpl; +impl I8SaturatingSub = signed_int_impls::SaturatingSubImpl; +impl I8OverflowingAdd = signed_int_impls::OverflowingAddImpl; +impl I8OverflowingSub = signed_int_impls::OverflowingSubImpl; +impl I8WrappingAdd = signed_int_impls::WrappingAddImpl; +impl I8WrappingSub = signed_int_impls::WrappingSubImpl; + +impl I16CheckedAdd = signed_int_impls::CheckedAddImpl; +impl I16CheckedSub = signed_int_impls::CheckedSubImpl; +impl I16SaturatingAdd = signed_int_impls::SaturatingAddImpl; +impl I16SaturatingSub = signed_int_impls::SaturatingSubImpl; +impl I16OverflowingAdd = signed_int_impls::OverflowingAddImpl; +impl I16OverflowingSub = signed_int_impls::OverflowingSubImpl; +impl I16WrappingAdd = signed_int_impls::WrappingAddImpl; +impl I16WrappingSub = signed_int_impls::WrappingSubImpl; + +impl I32CheckedAdd = signed_int_impls::CheckedAddImpl; +impl I32CheckedSub = signed_int_impls::CheckedSubImpl; +impl I32SaturatingAdd = signed_int_impls::SaturatingAddImpl; +impl I32SaturatingSub = signed_int_impls::SaturatingSubImpl; +impl I32OverflowingAdd = signed_int_impls::OverflowingAddImpl; +impl I32OverflowingSub = signed_int_impls::OverflowingSubImpl; +impl I32WrappingAdd = signed_int_impls::WrappingAddImpl; +impl I32WrappingSub = signed_int_impls::WrappingSubImpl; + +impl I64CheckedAdd = signed_int_impls::CheckedAddImpl; +impl I64CheckedSub = signed_int_impls::CheckedSubImpl; +impl I64SaturatingAdd = signed_int_impls::SaturatingAddImpl; +impl I64SaturatingSub = signed_int_impls::SaturatingSubImpl; +impl I64OverflowingAdd = signed_int_impls::OverflowingAddImpl; +impl I64OverflowingSub = signed_int_impls::OverflowingSubImpl; +impl I64WrappingAdd = signed_int_impls::WrappingAddImpl; +impl I64WrappingSub = signed_int_impls::WrappingSubImpl; + +impl I128CheckedAdd = signed_int_impls::CheckedAddImpl; +impl I128CheckedSub = signed_int_impls::CheckedSubImpl; +impl I128SaturatingAdd = signed_int_impls::SaturatingAddImpl; +impl I128SaturatingSub = signed_int_impls::SaturatingSubImpl; +impl I128OverflowingAdd = signed_int_impls::OverflowingAddImpl; +impl I128OverflowingSub = signed_int_impls::OverflowingSubImpl; +impl I128WrappingAdd = signed_int_impls::WrappingAddImpl; +impl I128WrappingSub = signed_int_impls::WrappingSubImpl; + #[derive(Copy, Drop)] pub extern type i8; impl NumericLiterali8 of NumericLiteral; @@ -2631,56 +2826,6 @@ impl U256OverflowingAdd of crate::num::traits::OverflowingAdd { } } -impl I8OverflowingAdd of crate::num::traits::OverflowingAdd { - fn overflowing_add(self: i8, v: i8) -> (i8, bool) { - match i8_overflowing_add_impl(self, v) { - SignedIntegerResult::InRange(x) => (x, false), - SignedIntegerResult::Underflow(x) => (x, true), - SignedIntegerResult::Overflow(x) => (x, true), - } - } -} - -impl I16OverflowingAdd of crate::num::traits::OverflowingAdd { - fn overflowing_add(self: i16, v: i16) -> (i16, bool) { - match i16_overflowing_add_impl(self, v) { - SignedIntegerResult::InRange(x) => (x, false), - SignedIntegerResult::Underflow(x) => (x, true), - SignedIntegerResult::Overflow(x) => (x, true), - } - } -} - -impl I32OverflowingAdd of crate::num::traits::OverflowingAdd { - fn overflowing_add(self: i32, v: i32) -> (i32, bool) { - match i32_overflowing_add_impl(self, v) { - SignedIntegerResult::InRange(x) => (x, false), - SignedIntegerResult::Underflow(x) => (x, true), - SignedIntegerResult::Overflow(x) => (x, true), - } - } -} - -impl I64OverflowingAdd of crate::num::traits::OverflowingAdd { - fn overflowing_add(self: i64, v: i64) -> (i64, bool) { - match i64_overflowing_add_impl(self, v) { - SignedIntegerResult::InRange(x) => (x, false), - SignedIntegerResult::Underflow(x) => (x, true), - SignedIntegerResult::Overflow(x) => (x, true), - } - } -} - -impl I128OverflowingAdd of crate::num::traits::OverflowingAdd { - fn overflowing_add(self: i128, v: i128) -> (i128, bool) { - match i128_overflowing_add_impl(self, v) { - SignedIntegerResult::InRange(x) => (x, false), - SignedIntegerResult::Underflow(x) => (x, true), - SignedIntegerResult::Overflow(x) => (x, true), - } - } -} - // OverflowingSub implementations impl U8OverflowingSub of crate::num::traits::OverflowingSub { fn overflowing_sub(self: u8, v: u8) -> (u8, bool) { @@ -2733,56 +2878,6 @@ impl U256OverflowingSub of crate::num::traits::OverflowingSub { } } -impl I8OverflowingSub of crate::num::traits::OverflowingSub { - fn overflowing_sub(self: i8, v: i8) -> (i8, bool) { - match i8_overflowing_sub_impl(self, v) { - SignedIntegerResult::InRange(x) => (x, false), - SignedIntegerResult::Underflow(x) => (x, true), - SignedIntegerResult::Overflow(x) => (x, true), - } - } -} - -impl I16OverflowingSub of crate::num::traits::OverflowingSub { - fn overflowing_sub(self: i16, v: i16) -> (i16, bool) { - match i16_overflowing_sub_impl(self, v) { - SignedIntegerResult::InRange(x) => (x, false), - SignedIntegerResult::Underflow(x) => (x, true), - SignedIntegerResult::Overflow(x) => (x, true), - } - } -} - -impl I32OverflowingSub of crate::num::traits::OverflowingSub { - fn overflowing_sub(self: i32, v: i32) -> (i32, bool) { - match i32_overflowing_sub_impl(self, v) { - SignedIntegerResult::InRange(x) => (x, false), - SignedIntegerResult::Underflow(x) => (x, true), - SignedIntegerResult::Overflow(x) => (x, true), - } - } -} - -impl I64OverflowingSub of crate::num::traits::OverflowingSub { - fn overflowing_sub(self: i64, v: i64) -> (i64, bool) { - match i64_overflowing_sub_impl(self, v) { - SignedIntegerResult::InRange(x) => (x, false), - SignedIntegerResult::Underflow(x) => (x, true), - SignedIntegerResult::Overflow(x) => (x, true), - } - } -} - -impl I128OverflowingSub of crate::num::traits::OverflowingSub { - fn overflowing_sub(self: i128, v: i128) -> (i128, bool) { - match i128_overflowing_sub_impl(self, v) { - SignedIntegerResult::InRange(x) => (x, false), - SignedIntegerResult::Underflow(x) => (x, true), - SignedIntegerResult::Overflow(x) => (x, true), - } - } -} - // OverflowingMul implementations impl U8OverflowingMul of crate::num::traits::OverflowingMul { fn overflowing_mul(self: u8, v: u8) -> (u8, bool) { @@ -2839,11 +2934,6 @@ impl U32WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappi impl U64WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappingAdd; impl U128WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappingAdd; impl U256WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappingAdd; -impl I8WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappingAdd; -impl I16WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappingAdd; -impl I32WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappingAdd; -impl I64WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappingAdd; -impl I128WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappingAdd; /// WrappingSub implementations impl U8WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; @@ -2852,11 +2942,6 @@ impl U32WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappi impl U64WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; impl U128WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; impl U256WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; -impl I8WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; -impl I16WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; -impl I32WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; -impl I64WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; -impl I128WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; /// WrappingMul implementations impl U8WrappingMul = crate::num::traits::ops::wrapping::overflow_based::TWrappingMul; @@ -2903,12 +2988,6 @@ impl U256CheckedAdd of crate::num::traits::CheckedAdd { } } -impl I8CheckedAdd = crate::num::traits::ops::checked::overflow_based::TCheckedAdd; -impl I16CheckedAdd = crate::num::traits::ops::checked::overflow_based::TCheckedAdd; -impl I32CheckedAdd = crate::num::traits::ops::checked::overflow_based::TCheckedAdd; -impl I64CheckedAdd = crate::num::traits::ops::checked::overflow_based::TCheckedAdd; -impl I128CheckedAdd = crate::num::traits::ops::checked::overflow_based::TCheckedAdd; - // CheckedSub implementations impl U8CheckedSub of crate::num::traits::CheckedSub { fn checked_sub(self: u8, v: u8) -> Option { @@ -2946,12 +3025,6 @@ impl U256CheckedSub of crate::num::traits::CheckedSub { } } -impl I8CheckedSub = crate::num::traits::ops::checked::overflow_based::TCheckedSub; -impl I16CheckedSub = crate::num::traits::ops::checked::overflow_based::TCheckedSub; -impl I32CheckedSub = crate::num::traits::ops::checked::overflow_based::TCheckedSub; -impl I64CheckedSub = crate::num::traits::ops::checked::overflow_based::TCheckedSub; -impl I128CheckedSub = crate::num::traits::ops::checked::overflow_based::TCheckedSub; - // CheckedMul implementations impl U8CheckedMul = crate::num::traits::ops::checked::overflow_based::TCheckedMul; impl U16CheckedMul = crate::num::traits::ops::checked::overflow_based::TCheckedMul; @@ -2968,11 +3041,6 @@ impl U32SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSa impl U64SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSaturatingAdd; impl U128SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSaturatingAdd; impl U256SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSaturatingAdd; -impl I8SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSaturatingAdd; -impl I16SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSaturatingAdd; -impl I32SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSaturatingAdd; -impl I64SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSaturatingAdd; -impl I128SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSaturatingAdd; // SaturatingSub implementations impl U8SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; @@ -2981,11 +3049,6 @@ impl U32SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSa impl U64SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; impl U128SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; impl U256SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; -impl I8SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; -impl I16SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; -impl I32SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; -impl I64SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; -impl I128SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; // SaturatingMul implementations impl U8SaturatingMul = crate::num::traits::ops::saturating::overflow_based::TSaturatingMul; diff --git a/corelib/src/test/num_test.cairo b/corelib/src/test/num_test.cairo index cc425ab57e9..3fdeb295190 100644 --- a/corelib/src/test/num_test.cairo +++ b/corelib/src/test/num_test.cairo @@ -368,6 +368,20 @@ fn test_saturating_add_signed_integers() { assert_eq!(Bounded::::MAX.saturating_add(1), Bounded::::MAX); } +#[test] +fn test_saturating_add_signed_negative_integers() { + assert_eq!(Bounded::::MIN.saturating_add(-1), Bounded::::MIN); + assert_eq!((-1_i8).saturating_add(-2), -3); + assert_eq!(Bounded::::MIN.saturating_add(-1), Bounded::::MIN); + assert_eq!((-1_i16).saturating_add(-2), -3); + assert_eq!(Bounded::::MIN.saturating_add(-1), Bounded::::MIN); + assert_eq!((-1_i32).saturating_add(-2), -3); + assert_eq!(Bounded::::MIN.saturating_add(-1), Bounded::::MIN); + assert_eq!((-1_i64).saturating_add(-2), -3); + assert_eq!(Bounded::::MIN.saturating_add(-1), Bounded::::MIN); + assert_eq!((-1_i128).saturating_add(-2), -3); +} + #[test] fn test_saturating_sub_unsigned_integers() { assert_eq!(3_u8.saturating_sub(2), 1); @@ -398,6 +412,20 @@ fn test_saturating_sub_signed_integers() { assert_eq!(Bounded::::MIN.saturating_sub(1), Bounded::::MIN); } +#[test] +fn test_saturating_sub_signed_negative_integers() { + assert_eq!(1_i8.saturating_sub(-2), 3); + assert_eq!(Bounded::::MAX.saturating_sub(-1), Bounded::::MAX); + assert_eq!(1_i16.saturating_sub(-2), 3); + assert_eq!(Bounded::::MAX.saturating_sub(-1), Bounded::::MAX); + assert_eq!(1_i32.saturating_sub(-2), 3); + assert_eq!(Bounded::::MAX.saturating_sub(-1), Bounded::::MAX); + assert_eq!(1_i64.saturating_sub(-2), 3); + assert_eq!(Bounded::::MAX.saturating_sub(-1), Bounded::::MAX); + assert_eq!(1_i128.saturating_sub(-2), 3); + assert_eq!(Bounded::::MAX.saturating_sub(-1), Bounded::::MAX); +} + #[test] fn test_saturating_mul_unsigned_integers() { assert_eq!(2_u8.saturating_mul(3), 6);