diff --git a/corelib/src/integer.cairo b/corelib/src/integer.cairo index d1f6ebdc4ad..d9ceabd36b7 100644 --- a/corelib/src/integer.cairo +++ b/corelib/src/integer.cairo @@ -2754,3 +2754,105 @@ impl I128One of core::num::traits::One { !self.is_one() } } + +// OverflowingAdd implementations +impl U8OverflowingAdd of core::num::traits::OverflowingAdd { + fn overflowing_add(self: u8, v: u8) -> (u8, bool) { + match u8_overflowing_add(self, v) { + Result::Ok(x) => (x, false), + Result::Err(x) => (x, true) + } + } +} + +impl U16OverflowingAdd of core::num::traits::OverflowingAdd { + fn overflowing_add(self: u16, v: u16) -> (u16, bool) { + match u16_overflowing_add(self, v) { + Result::Ok(x) => (x, false), + Result::Err(x) => (x, true) + } + } +} + +impl U32OverflowingAdd of core::num::traits::OverflowingAdd { + fn overflowing_add(self: u32, v: u32) -> (u32, bool) { + match u32_overflowing_add(self, v) { + Result::Ok(x) => (x, false), + Result::Err(x) => (x, true) + } + } +} + +impl U64OverflowingAdd of core::num::traits::OverflowingAdd { + fn overflowing_add(self: u64, v: u64) -> (u64, bool) { + match u64_overflowing_add(self, v) { + Result::Ok(x) => (x, false), + Result::Err(x) => (x, true) + } + } +} + +impl U128OverflowingAdd of core::num::traits::OverflowingAdd { + fn overflowing_add(self: u128, v: u128) -> (u128, bool) { + match u128_overflowing_add(self, v) { + Result::Ok(x) => (x, false), + Result::Err(x) => (x, true) + } + } +} + +impl U256OverflowingAdd of core::num::traits::OverflowingAdd { + fn overflowing_add(self: u256, v: u256) -> (u256, bool) { + u256_overflowing_add(self, v) + } +} + +impl I8OverflowingAdd of core::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 core::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 core::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 core::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 core::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), + } + } +} diff --git a/corelib/src/num/traits.cairo b/corelib/src/num/traits.cairo index 75f57a4e3ac..0635fd8bbf5 100644 --- a/corelib/src/num/traits.cairo +++ b/corelib/src/num/traits.cairo @@ -6,3 +6,6 @@ pub use one::One; pub mod bit_size; pub use bit_size::BitSize; + +pub mod ops; +pub use ops::{OverflowingAdd}; diff --git a/corelib/src/num/traits/ops.cairo b/corelib/src/num/traits/ops.cairo new file mode 100644 index 00000000000..0fc00cd8396 --- /dev/null +++ b/corelib/src/num/traits/ops.cairo @@ -0,0 +1,2 @@ +pub mod overflowing; +pub use overflowing::{OverflowingAdd}; diff --git a/corelib/src/num/traits/ops/overflowing.cairo b/corelib/src/num/traits/ops/overflowing.cairo new file mode 100644 index 00000000000..fef37ce0023 --- /dev/null +++ b/corelib/src/num/traits/ops/overflowing.cairo @@ -0,0 +1,7 @@ +/// Performs addition with a flag for overflow. +pub trait OverflowingAdd { + /// Returns a tuple of the sum along with a boolean indicating whether an arithmetic overflow + /// would occur. + /// If an overflow would have occurred then the wrapped value is returned. + fn overflowing_add(self: T, v: T) -> (T, bool); +} diff --git a/corelib/src/test/num_test.cairo b/corelib/src/test/num_test.cairo index bdd43579177..d89725ec750 100644 --- a/corelib/src/test/num_test.cairo +++ b/corelib/src/test/num_test.cairo @@ -1,4 +1,7 @@ use core::num::traits::BitSize; +use core::num::traits::OverflowingAdd; +use core::integer::BoundedInt; + #[test] fn test_bit_size() { @@ -15,3 +18,51 @@ fn test_bit_size() { assert!(BitSize::::bits() == 128); assert!(BitSize::::bits() == 248); } + +#[test] +fn tests_overflowing_add_unsigned_integers() { + assert_eq!(1_u8.overflowing_add(2), (3, false)); + assert_eq!(BoundedInt::::max().overflowing_add(1), (0, true)); + assert_eq!(1_u16.overflowing_add(2), (3, false)); + assert_eq!(BoundedInt::::max().overflowing_add(1), (0, true)); + assert_eq!(1_u32.overflowing_add(2), (3, false)); + assert_eq!(BoundedInt::::max().overflowing_add(1), (0, true)); + assert_eq!(1_u64.overflowing_add(2), (3, false)); + assert_eq!(BoundedInt::::max().overflowing_add(1), (0, true)); + assert_eq!(1_u128.overflowing_add(2), (3, false)); + assert_eq!(BoundedInt::::max().overflowing_add(1), (0, true)); + assert_eq!(1_u256.overflowing_add(2), (3, false)); + assert_eq!(BoundedInt::::max().overflowing_add(1), (0, true)); +} + +#[test] +fn test_overflowing_add_positive_signed_integers() { + assert!(1_i8.overflowing_add(2) == (3, false)); + assert!(BoundedInt::::max().overflowing_add(1) == (-0x80, true)); + assert!(1_i16.overflowing_add(2) == (3, false)); + assert!(BoundedInt::::max().overflowing_add(1) == (-0x8000, true)); + assert!(1_i32.overflowing_add(2) == (3, false)); + assert!(BoundedInt::::max().overflowing_add(1) == (-0x80000000, true)); + assert!(1_i64.overflowing_add(2) == (3, false)); + assert!(BoundedInt::::max().overflowing_add(1) == (-0x8000000000000000, true)); + assert!(1_i128.overflowing_add(2) == (3, false)); + assert!( + BoundedInt::::max().overflowing_add(1) == (-0x80000000000000000000000000000000, true) + ); +} + +#[test] +fn test_overflowing_add_negative_signed_integers() { + assert!((-1_i8).overflowing_add(-2) == (-3, false)); + assert!(BoundedInt::::min().overflowing_add(-1) == (0x7f, true)); + assert!((-1_i16).overflowing_add(-2) == (-3, false)); + assert!(BoundedInt::::min().overflowing_add(-1) == (0x7fff, true)); + assert!((-1_i32).overflowing_add(-2) == (-3, false)); + assert!(BoundedInt::::min().overflowing_add(-1) == (0x7fffffff, true)); + assert!((-1_i64).overflowing_add(-2) == (-3, false)); + assert!(BoundedInt::::min().overflowing_add(-1) == (0x7fffffffffffffff, true)); + assert!((-1_i128).overflowing_add(-2) == (-3, false)); + assert!( + BoundedInt::::min().overflowing_add(-1) == (0x7fffffffffffffffffffffffffffffff, true) + ); +}