From fe11483afa90628106971993049b4fd2f0dae6fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Thu, 29 Jul 2021 19:39:56 +0200 Subject: [PATCH 1/7] Add functions to add unsigned and signed integers --- library/core/src/lib.rs | 1 + library/core/src/num/mod.rs | 16 ++--- library/core/src/num/uint_macros.rs | 102 +++++++++++++++++++++++++++- library/std/src/io/cursor.rs | 7 +- library/std/src/lib.rs | 1 + 5 files changed, 112 insertions(+), 15 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 4408b5a3d2088..2e419625d14f6 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -159,6 +159,7 @@ #![feature(trait_alias)] #![feature(transparent_unions)] #![feature(try_blocks)] +#![feature(uint_add_signed)] #![feature(unboxed_closures)] #![feature(unsized_fn_params)] // diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 59b68cbe9c0ce..8966a9c11d2b4 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -245,7 +245,7 @@ const ASCII_CASE_MASK: u8 = 0b0010_0000; #[lang = "u8"] impl u8 { widening_impl! { u8, u16, 8 } - uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", + uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", "[0x12]", "", "" } /// Checks if the value is within the ASCII range. @@ -779,21 +779,21 @@ impl u8 { #[lang = "u16"] impl u16 { widening_impl! { u16, u32, 16 } - uint_impl! { u16, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", + uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } } #[lang = "u32"] impl u32 { widening_impl! { u32, u64, 32 } - uint_impl! { u32, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", + uint_impl! { u32, u32, i32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" } } #[lang = "u64"] impl u64 { widening_impl! { u64, u128, 64 } - uint_impl! { u64, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", + uint_impl! { u64, u64, i64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", @@ -802,7 +802,7 @@ impl u64 { #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, 16, + uint_impl! { u128, u128, i128, 128, 340282366920938463463374607431768211455, 16, "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012", "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48", "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \ @@ -816,7 +816,7 @@ impl u128 { #[lang = "usize"] impl usize { widening_impl! { usize, u32, 16 } - uint_impl! { usize, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", + uint_impl! { usize, u16, isize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } @@ -824,7 +824,7 @@ impl usize { #[lang = "usize"] impl usize { widening_impl! { usize, u64, 32 } - uint_impl! { usize, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", + uint_impl! { usize, u32, isize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } @@ -833,7 +833,7 @@ impl usize { #[lang = "usize"] impl usize { widening_impl! { usize, u128, 64 } - uint_impl! { usize, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", + uint_impl! { usize, u64, isize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 8ce8266263091..67d72a171350b 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1,5 +1,5 @@ macro_rules! uint_impl { - ($SelfT:ty, $ActualT:ident, $BITS:expr, $MaxV:expr, + ($SelfT:ty, $ActualT:ident, $SignedT:ident, $BITS:expr, $MaxV:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, $reversed:expr, $le_bytes:expr, $be_bytes:expr, $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { @@ -442,6 +442,29 @@ macro_rules! uint_impl { unsafe { intrinsics::unchecked_add(self, rhs) } } + /// Checked addition with a signed integer. Computes `self + rhs`, + /// returning `None` if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(uint_add_signed)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(2), Some(3));")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(-2), None);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);")] + /// ``` + #[unstable(feature = "uint_add_signed", issue = "none")] + #[rustc_const_unstable(feature = "uint_add_signed", issue = "none")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_add_signed(self, rhs: $SignedT) -> Option { + let (a, b) = self.overflowing_add_signed(rhs); + if unlikely!(b) {None} else {Some(a)} + } + /// Checked integer subtraction. Computes `self - rhs`, returning /// `None` if overflow occurred. /// @@ -995,6 +1018,32 @@ macro_rules! uint_impl { intrinsics::saturating_add(self, rhs) } + /// Saturating addition with a signed integer. Computes `self + rhs`, + /// saturating at the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(uint_add_signed)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(2), 3);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(-2), 0);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).saturating_add_signed(4), ", stringify!($SelfT), "::MAX);")] + /// ``` + #[unstable(feature = "uint_add_signed", issue = "none")] + #[rustc_const_unstable(feature = "uint_add_signed", issue = "none")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_add_signed(self, rhs: $SignedT) -> Self { + if rhs >= 0 { + self.saturating_add(rhs as Self) + } else { + self.saturating_sub(rhs.unsigned_abs()) + } + } + /// Saturating integer subtraction. Computes `self - rhs`, saturating /// at the numeric bounds instead of overflowing. /// @@ -1111,6 +1160,28 @@ macro_rules! uint_impl { intrinsics::wrapping_add(self, rhs) } + /// Wrapping (modular) addition with a signed integer. Computes + /// `self + rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(uint_add_signed)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(2), 3);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(-2), ", stringify!($SelfT), "::MAX);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).wrapping_add_signed(4), 1);")] + /// ``` + #[unstable(feature = "uint_add_signed", issue = "none")] + #[rustc_const_unstable(feature = "uint_add_signed", issue = "none")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_add_signed(self, rhs: $SignedT) -> Self { + self.wrapping_add(rhs as Self) + } + /// Wrapping (modular) subtraction. Computes `self - rhs`, /// wrapping around at the boundary of the type. /// @@ -1435,6 +1506,35 @@ macro_rules! uint_impl { (c, b | d) } + /// Calculates `self` + `rhs` with a signed `rhs` + /// + /// Returns a tuple of the addition along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would + /// have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(uint_add_signed)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(2), (3, false));")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(-2), (", stringify!($SelfT), "::MAX, true));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_signed(4), (1, true));")] + /// ``` + #[unstable(feature = "uint_add_signed", issue = "none")] + #[rustc_const_unstable(feature = "uint_add_signed", issue = "none")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_add_signed(self, rhs: $SignedT) -> (Self, bool) { + if rhs >= 0 { + self.overflowing_add(rhs as Self) + } else { + self.overflowing_sub(rhs.unsigned_abs()) + } + } + /// Calculates `self` - `rhs` /// /// Returns a tuple of the subtraction along with a boolean indicating diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 25cc5e67ad14e..980b2531192e8 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -292,12 +292,7 @@ where SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n), SeekFrom::Current(n) => (self.pos, n), }; - let new_pos = if offset >= 0 { - base_pos.checked_add(offset as u64) - } else { - base_pos.checked_sub((offset.wrapping_neg()) as u64) - }; - match new_pos { + match base_pos.checked_add_signed(offset) { Some(n) => { self.pos = n; Ok(self.pos) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index b33a3c5d22fe1..e9a1aa41a63db 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -333,6 +333,7 @@ #![feature(try_blocks)] #![feature(try_reserve)] #![feature(try_reserve_kind)] +#![feature(uint_add_signed)] #![feature(unboxed_closures)] #![feature(unwrap_infallible)] #![feature(vec_into_raw_parts)] From ab9f8a0b593a832f98188cd755bd467eeb9416d4 Mon Sep 17 00:00:00 2001 From: Alphyr <47725341+a1phyr@users.noreply.github.com> Date: Fri, 30 Jul 2021 12:11:18 +0200 Subject: [PATCH 2/7] Apply suggestion for `overflowing_add_signed` Co-authored-by: kennytm --- library/core/src/num/uint_macros.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 67d72a171350b..2c4097a30a1e1 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1528,11 +1528,8 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn overflowing_add_signed(self, rhs: $SignedT) -> (Self, bool) { - if rhs >= 0 { - self.overflowing_add(rhs as Self) - } else { - self.overflowing_sub(rhs.unsigned_abs()) - } + let (res, overflowed) = self.overflowing_add(rhs as Self); + (res, overflowed ^ (rhs < 0)) } /// Calculates `self` - `rhs` From b5dd5227ee7785174f006a5281622c52533c6075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Sat, 7 Aug 2021 11:26:34 +0200 Subject: [PATCH 3/7] Fix doc test --- library/core/src/num/uint_macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 2c4097a30a1e1..e6c675edabcc3 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -453,7 +453,7 @@ macro_rules! uint_impl { /// # #![feature(uint_add_signed)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(2), Some(3));")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(-2), None);")] - #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_signed(3), None);")] /// ``` #[unstable(feature = "uint_add_signed", issue = "none")] #[rustc_const_unstable(feature = "uint_add_signed", issue = "none")] From 9faf6213558c0f0158eff5f2a911dbd6ab804605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Sat, 7 Aug 2021 12:11:59 +0200 Subject: [PATCH 4/7] Add methods to add/sub `uX` to/from `iX` --- library/core/src/lib.rs | 2 +- library/core/src/num/int_macros.rs | 190 ++++++++++++++++++++++++++++ library/core/src/num/uint_macros.rs | 24 ++-- library/std/src/lib.rs | 2 +- 4 files changed, 204 insertions(+), 14 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 2e419625d14f6..f41eeae9cc1fa 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -142,6 +142,7 @@ #![feature(link_llvm_intrinsics)] #![feature(llvm_asm)] #![feature(min_specialization)] +#![feature(mixed_integer_ops)] #![cfg_attr(not(bootstrap), feature(must_not_suspend))] #![feature(negative_impls)] #![feature(never_type)] @@ -159,7 +160,6 @@ #![feature(trait_alias)] #![feature(transparent_unions)] #![feature(try_blocks)] -#![feature(uint_add_signed)] #![feature(unboxed_closures)] #![feature(unsized_fn_params)] // diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index daef5c98967cc..5f299687780ef 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -433,6 +433,28 @@ macro_rules! int_impl { unsafe { intrinsics::unchecked_add(self, rhs) } } + /// Checked addition with an unsigned integer. Computes `self + rhs`, + /// returning `None` if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_unsigned(2), Some(3));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_unsigned(3), None);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option { + let (a, b) = self.overflowing_add_unsigned(rhs); + if unlikely!(b) {None} else {Some(a)} + } + /// Checked integer subtraction. Computes `self - rhs`, returning `None` if /// overflow occurred. /// @@ -479,6 +501,28 @@ macro_rules! int_impl { unsafe { intrinsics::unchecked_sub(self, rhs) } } + /// Checked addition with an unsigned integer. Computes `self + rhs`, + /// returning `None` if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_unsigned(2), Some(-1));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub_unsigned(3), None);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option { + let (a, b) = self.overflowing_sub_unsigned(rhs); + if unlikely!(b) {None} else {Some(a)} + } + /// Checked integer multiplication. Computes `self * rhs`, returning `None` if /// overflow occurred. /// @@ -822,6 +866,31 @@ macro_rules! int_impl { intrinsics::saturating_add(self, rhs) } + /// Saturating addition with an unsigned integer. Computes `self + rhs`, + /// saturating at the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_unsigned(2), 3);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add_unsigned(100), ", stringify!($SelfT), "::MAX);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_add_unsigned(self, rhs: $UnsignedT) -> Self { + // Overflow can only happen at the upper bound + match self.checked_add_unsigned(rhs) { + Some(x) => x, + None => Self::MAX, + } + } + /// Saturating integer subtraction. Computes `self - rhs`, saturating at the /// numeric bounds instead of overflowing. /// @@ -843,6 +912,31 @@ macro_rules! int_impl { intrinsics::saturating_sub(self, rhs) } + /// Saturating substraction with an unsigned integer. Computes `self - rhs`, + /// saturating at the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub_unsigned(127), -27);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub_unsigned(100), ", stringify!($SelfT), "::MIN);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_sub_unsigned(self, rhs: $UnsignedT) -> Self { + // Overflow can only happen at the lower bound + match self.checked_sub_unsigned(rhs) { + Some(x) => x, + None => Self::MIN, + } + } + /// Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` /// instead of overflowing. /// @@ -998,6 +1092,27 @@ macro_rules! int_impl { intrinsics::wrapping_add(self, rhs) } + /// Wrapping (modular) addition with an unsigned integer. Computes + /// `self + rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_add_unsigned(27), 127);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add_unsigned(2), ", stringify!($SelfT), "::MIN + 1);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn wrapping_add_unsigned(self, rhs: $UnsignedT) -> Self { + self.wrapping_add(rhs as Self) + } + /// Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the /// boundary of the type. /// @@ -1018,6 +1133,27 @@ macro_rules! int_impl { intrinsics::wrapping_sub(self, rhs) } + /// Wrapping (modular) substraction with an unsigned integer. Computes + /// `self - rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".wrapping_sub_unsigned(127), -127);")] + #[doc = concat!("assert_eq!((-2", stringify!($SelfT), ").wrapping_sub_unsigned(", stringify!($UnsignedT), "::MAX), -1);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn wrapping_sub_unsigned(self, rhs: $UnsignedT) -> Self { + self.wrapping_sub(rhs as Self) + } + /// Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at /// the boundary of the type. /// @@ -1368,6 +1504,33 @@ macro_rules! int_impl { (sum as $SelfT, carry) } + /// Calculates `self` + `rhs` with an unsigned `rhs` + /// + /// Returns a tuple of the addition along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would + /// have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_unsigned(2), (3, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN).overflowing_add_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MAX, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_unsigned(3), (", stringify!($SelfT), "::MIN, true));")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_add_unsigned(self, rhs: $UnsignedT) -> (Self, bool) { + let rhs = rhs as Self; + let (res, overflowed) = self.overflowing_add(rhs); + (res, overflowed ^ (rhs < 0)) + } + /// Calculates `self` - `rhs` /// /// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow @@ -1419,6 +1582,33 @@ macro_rules! int_impl { (sum as $SelfT, borrow) } + /// Calculates `self` - `rhs` with an unsigned `rhs` + /// + /// Returns a tuple of the substraction along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would + /// have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_unsigned(2), (-1, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX).overflowing_sub_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MIN, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).overflowing_sub_unsigned(3), (", stringify!($SelfT), "::MAX, true));")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_sub_unsigned(self, rhs: $UnsignedT) -> (Self, bool) { + let rhs = rhs as Self; + let (res, overflowed) = self.overflowing_sub(rhs); + (res, overflowed ^ (rhs < 0)) + } + /// Calculates the multiplication of `self` and `rhs`. /// /// Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index e6c675edabcc3..5a65f77a87993 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -450,13 +450,13 @@ macro_rules! uint_impl { /// Basic usage: /// /// ``` - /// # #![feature(uint_add_signed)] + /// # #![feature(mixed_integer_ops)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(2), Some(3));")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(-2), None);")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_signed(3), None);")] /// ``` - #[unstable(feature = "uint_add_signed", issue = "none")] - #[rustc_const_unstable(feature = "uint_add_signed", issue = "none")] + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1026,13 +1026,13 @@ macro_rules! uint_impl { /// Basic usage: /// /// ``` - /// # #![feature(uint_add_signed)] + /// # #![feature(mixed_integer_ops)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(2), 3);")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(-2), 0);")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).saturating_add_signed(4), ", stringify!($SelfT), "::MAX);")] /// ``` - #[unstable(feature = "uint_add_signed", issue = "none")] - #[rustc_const_unstable(feature = "uint_add_signed", issue = "none")] + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1168,13 +1168,13 @@ macro_rules! uint_impl { /// Basic usage: /// /// ``` - /// # #![feature(uint_add_signed)] + /// # #![feature(mixed_integer_ops)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(2), 3);")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(-2), ", stringify!($SelfT), "::MAX);")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).wrapping_add_signed(4), 1);")] /// ``` - #[unstable(feature = "uint_add_signed", issue = "none")] - #[rustc_const_unstable(feature = "uint_add_signed", issue = "none")] + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1517,13 +1517,13 @@ macro_rules! uint_impl { /// Basic usage: /// /// ``` - /// # #![feature(uint_add_signed)] + /// # #![feature(mixed_integer_ops)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(2), (3, false));")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(-2), (", stringify!($SelfT), "::MAX, true));")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_signed(4), (1, true));")] /// ``` - #[unstable(feature = "uint_add_signed", issue = "none")] - #[rustc_const_unstable(feature = "uint_add_signed", issue = "none")] + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index e9a1aa41a63db..1781a3cb7c402 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -297,6 +297,7 @@ #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(min_specialization)] +#![feature(mixed_integer_ops)] #![cfg_attr(not(bootstrap), feature(must_not_suspend))] #![feature(needs_panic_runtime)] #![feature(negative_impls)] @@ -333,7 +334,6 @@ #![feature(try_blocks)] #![feature(try_reserve)] #![feature(try_reserve_kind)] -#![feature(uint_add_signed)] #![feature(unboxed_closures)] #![feature(unwrap_infallible)] #![feature(vec_into_raw_parts)] From 70e55a8938bb84542f73a127edd5c91f2c8bd0aa Mon Sep 17 00:00:00 2001 From: Alphyr <47725341+a1phyr@users.noreply.github.com> Date: Sun, 3 Oct 2021 22:44:07 +0200 Subject: [PATCH 5/7] Apply suggestions Co-authored-by: kennytm --- library/core/src/num/int_macros.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 5f299687780ef..540b7d36625af 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -501,7 +501,7 @@ macro_rules! int_impl { unsafe { intrinsics::unchecked_sub(self, rhs) } } - /// Checked addition with an unsigned integer. Computes `self + rhs`, + /// Checked subtraction with an unsigned integer. Computes `self - rhs`, /// returning `None` if overflow occurred. /// /// # Examples @@ -885,10 +885,7 @@ macro_rules! int_impl { #[inline] pub const fn saturating_add_unsigned(self, rhs: $UnsignedT) -> Self { // Overflow can only happen at the upper bound - match self.checked_add_unsigned(rhs) { - Some(x) => x, - None => Self::MAX, - } + self.checked_add_unsigned(rhs).unwrap_or(Self::MAX) } /// Saturating integer subtraction. Computes `self - rhs`, saturating at the @@ -912,7 +909,7 @@ macro_rules! int_impl { intrinsics::saturating_sub(self, rhs) } - /// Saturating substraction with an unsigned integer. Computes `self - rhs`, + /// Saturating subtraction with an unsigned integer. Computes `self - rhs`, /// saturating at the numeric bounds instead of overflowing. /// /// # Examples @@ -931,10 +928,7 @@ macro_rules! int_impl { #[inline] pub const fn saturating_sub_unsigned(self, rhs: $UnsignedT) -> Self { // Overflow can only happen at the lower bound - match self.checked_sub_unsigned(rhs) { - Some(x) => x, - None => Self::MIN, - } + self.checked_sub_unsigned(rhs).unwrap_or(Self::MIN) } /// Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` @@ -1133,7 +1127,7 @@ macro_rules! int_impl { intrinsics::wrapping_sub(self, rhs) } - /// Wrapping (modular) substraction with an unsigned integer. Computes + /// Wrapping (modular) subtraction with an unsigned integer. Computes /// `self - rhs`, wrapping around at the boundary of the type. /// /// # Examples @@ -1584,7 +1578,7 @@ macro_rules! int_impl { /// Calculates `self` - `rhs` with an unsigned `rhs` /// - /// Returns a tuple of the substraction along with a boolean indicating + /// Returns a tuple of the subtraction along with a boolean indicating /// whether an arithmetic overflow would occur. If an overflow would /// have occurred then the wrapped value is returned. /// From 4846fd92c0cc82545c5fd33c9ab3007f03f0f9f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Sun, 3 Oct 2021 22:56:34 +0200 Subject: [PATCH 6/7] Revert suggested use of `unwrap_or` --- library/core/src/num/int_macros.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 540b7d36625af..5bdb6ed91761f 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -885,7 +885,11 @@ macro_rules! int_impl { #[inline] pub const fn saturating_add_unsigned(self, rhs: $UnsignedT) -> Self { // Overflow can only happen at the upper bound - self.checked_add_unsigned(rhs).unwrap_or(Self::MAX) + // We cannot use `unwrap_or` here because it is not `const` + match self.checked_add_unsigned(rhs) { + Some(x) => x, + None => Self::MAX, + } } /// Saturating integer subtraction. Computes `self - rhs`, saturating at the @@ -928,7 +932,11 @@ macro_rules! int_impl { #[inline] pub const fn saturating_sub_unsigned(self, rhs: $UnsignedT) -> Self { // Overflow can only happen at the lower bound - self.checked_sub_unsigned(rhs).unwrap_or(Self::MIN) + // We cannot use `unwrap_or` here because it is not `const` + match self.checked_sub_unsigned(rhs) { + Some(x) => x, + None => Self::MIN, + } } /// Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` From 47edde1086412b36e9efd6098b191ec15a2a760a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Mon, 4 Oct 2021 18:52:17 +0200 Subject: [PATCH 7/7] Optimize `saturating_add_signed` --- library/core/src/num/uint_macros.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 5a65f77a87993..96375b82582ed 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1037,10 +1037,13 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn saturating_add_signed(self, rhs: $SignedT) -> Self { - if rhs >= 0 { - self.saturating_add(rhs as Self) + let (res, overflow) = self.overflowing_add(rhs as Self); + if overflow == (rhs < 0) { + res + } else if overflow { + Self::MAX } else { - self.saturating_sub(rhs.unsigned_abs()) + 0 } }