Skip to content

Commit 0c78e9d

Browse files
authoredOct 6, 2021
Rollup merge of rust-lang#87601 - a1phyr:feature_uint_add_signed, r=kennytm
Add functions to add unsigned and signed integers This PR adds methods to unsigned integers to add signed integers with good overflow semantics under `#![feature(mixed_integer_ops)]`. The added API is: ```rust // `uX` is `u8`, `u16`, `u32`, `u64`,`u128`, `usize` impl uX { pub const fn checked_add_signed(self, iX) -> Option<Self>; pub const fn overflowing_add_signed(self, iX) -> (Self, bool); pub const fn saturating_add_signed(self, iX) -> Self; pub const fn wrapping_add_signed(self, iX) -> Self; } impl iX { pub const fn checked_add_unsigned(self, uX) -> Option<Self>; pub const fn overflowing_add_unsigned(self, uX) -> (Self, bool); pub const fn saturating_add_unsigned(self, uX) -> Self; pub const fn wrapping_add_unsigned(self, uX) -> Self; pub const fn checked_sub_unsigned(self, uX) -> Option<Self>; pub const fn overflowing_sub_unsigned(self, uX) -> (Self, bool); pub const fn saturating_sub_unsigned(self, uX) -> Self; pub const fn wrapping_sub_unsigned(self, uX) -> Self; } ``` Maybe it would be interesting to also have `add_signed` that panics in debug and wraps in release ?
2 parents 98a5a98 + 47edde1 commit 0c78e9d

File tree

6 files changed

+304
-15
lines changed

6 files changed

+304
-15
lines changed
 

‎library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@
142142
#![feature(link_llvm_intrinsics)]
143143
#![feature(llvm_asm)]
144144
#![feature(min_specialization)]
145+
#![feature(mixed_integer_ops)]
145146
#![cfg_attr(not(bootstrap), feature(must_not_suspend))]
146147
#![feature(negative_impls)]
147148
#![feature(never_type)]

‎library/core/src/num/int_macros.rs

+192
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,28 @@ macro_rules! int_impl {
433433
unsafe { intrinsics::unchecked_add(self, rhs) }
434434
}
435435

436+
/// Checked addition with an unsigned integer. Computes `self + rhs`,
437+
/// returning `None` if overflow occurred.
438+
///
439+
/// # Examples
440+
///
441+
/// Basic usage:
442+
///
443+
/// ```
444+
/// # #![feature(mixed_integer_ops)]
445+
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_unsigned(2), Some(3));")]
446+
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_unsigned(3), None);")]
447+
/// ```
448+
#[unstable(feature = "mixed_integer_ops", issue = "87840")]
449+
#[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
450+
#[must_use = "this returns the result of the operation, \
451+
without modifying the original"]
452+
#[inline]
453+
pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option<Self> {
454+
let (a, b) = self.overflowing_add_unsigned(rhs);
455+
if unlikely!(b) {None} else {Some(a)}
456+
}
457+
436458
/// Checked integer subtraction. Computes `self - rhs`, returning `None` if
437459
/// overflow occurred.
438460
///
@@ -479,6 +501,28 @@ macro_rules! int_impl {
479501
unsafe { intrinsics::unchecked_sub(self, rhs) }
480502
}
481503

504+
/// Checked subtraction with an unsigned integer. Computes `self - rhs`,
505+
/// returning `None` if overflow occurred.
506+
///
507+
/// # Examples
508+
///
509+
/// Basic usage:
510+
///
511+
/// ```
512+
/// # #![feature(mixed_integer_ops)]
513+
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_unsigned(2), Some(-1));")]
514+
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub_unsigned(3), None);")]
515+
/// ```
516+
#[unstable(feature = "mixed_integer_ops", issue = "87840")]
517+
#[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
518+
#[must_use = "this returns the result of the operation, \
519+
without modifying the original"]
520+
#[inline]
521+
pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option<Self> {
522+
let (a, b) = self.overflowing_sub_unsigned(rhs);
523+
if unlikely!(b) {None} else {Some(a)}
524+
}
525+
482526
/// Checked integer multiplication. Computes `self * rhs`, returning `None` if
483527
/// overflow occurred.
484528
///
@@ -826,6 +870,32 @@ macro_rules! int_impl {
826870
intrinsics::saturating_add(self, rhs)
827871
}
828872

873+
/// Saturating addition with an unsigned integer. Computes `self + rhs`,
874+
/// saturating at the numeric bounds instead of overflowing.
875+
///
876+
/// # Examples
877+
///
878+
/// Basic usage:
879+
///
880+
/// ```
881+
/// # #![feature(mixed_integer_ops)]
882+
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_unsigned(2), 3);")]
883+
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add_unsigned(100), ", stringify!($SelfT), "::MAX);")]
884+
/// ```
885+
#[unstable(feature = "mixed_integer_ops", issue = "87840")]
886+
#[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
887+
#[must_use = "this returns the result of the operation, \
888+
without modifying the original"]
889+
#[inline]
890+
pub const fn saturating_add_unsigned(self, rhs: $UnsignedT) -> Self {
891+
// Overflow can only happen at the upper bound
892+
// We cannot use `unwrap_or` here because it is not `const`
893+
match self.checked_add_unsigned(rhs) {
894+
Some(x) => x,
895+
None => Self::MAX,
896+
}
897+
}
898+
829899
/// Saturating integer subtraction. Computes `self - rhs`, saturating at the
830900
/// numeric bounds instead of overflowing.
831901
///
@@ -847,6 +917,32 @@ macro_rules! int_impl {
847917
intrinsics::saturating_sub(self, rhs)
848918
}
849919

920+
/// Saturating subtraction with an unsigned integer. Computes `self - rhs`,
921+
/// saturating at the numeric bounds instead of overflowing.
922+
///
923+
/// # Examples
924+
///
925+
/// Basic usage:
926+
///
927+
/// ```
928+
/// # #![feature(mixed_integer_ops)]
929+
#[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub_unsigned(127), -27);")]
930+
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub_unsigned(100), ", stringify!($SelfT), "::MIN);")]
931+
/// ```
932+
#[unstable(feature = "mixed_integer_ops", issue = "87840")]
933+
#[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
934+
#[must_use = "this returns the result of the operation, \
935+
without modifying the original"]
936+
#[inline]
937+
pub const fn saturating_sub_unsigned(self, rhs: $UnsignedT) -> Self {
938+
// Overflow can only happen at the lower bound
939+
// We cannot use `unwrap_or` here because it is not `const`
940+
match self.checked_sub_unsigned(rhs) {
941+
Some(x) => x,
942+
None => Self::MIN,
943+
}
944+
}
945+
850946
/// Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN`
851947
/// instead of overflowing.
852948
///
@@ -1002,6 +1098,27 @@ macro_rules! int_impl {
10021098
intrinsics::wrapping_add(self, rhs)
10031099
}
10041100

1101+
/// Wrapping (modular) addition with an unsigned integer. Computes
1102+
/// `self + rhs`, wrapping around at the boundary of the type.
1103+
///
1104+
/// # Examples
1105+
///
1106+
/// Basic usage:
1107+
///
1108+
/// ```
1109+
/// # #![feature(mixed_integer_ops)]
1110+
#[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_add_unsigned(27), 127);")]
1111+
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add_unsigned(2), ", stringify!($SelfT), "::MIN + 1);")]
1112+
/// ```
1113+
#[unstable(feature = "mixed_integer_ops", issue = "87840")]
1114+
#[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
1115+
#[must_use = "this returns the result of the operation, \
1116+
without modifying the original"]
1117+
#[inline(always)]
1118+
pub const fn wrapping_add_unsigned(self, rhs: $UnsignedT) -> Self {
1119+
self.wrapping_add(rhs as Self)
1120+
}
1121+
10051122
/// Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the
10061123
/// boundary of the type.
10071124
///
@@ -1022,6 +1139,27 @@ macro_rules! int_impl {
10221139
intrinsics::wrapping_sub(self, rhs)
10231140
}
10241141

1142+
/// Wrapping (modular) subtraction with an unsigned integer. Computes
1143+
/// `self - rhs`, wrapping around at the boundary of the type.
1144+
///
1145+
/// # Examples
1146+
///
1147+
/// Basic usage:
1148+
///
1149+
/// ```
1150+
/// # #![feature(mixed_integer_ops)]
1151+
#[doc = concat!("assert_eq!(0", stringify!($SelfT), ".wrapping_sub_unsigned(127), -127);")]
1152+
#[doc = concat!("assert_eq!((-2", stringify!($SelfT), ").wrapping_sub_unsigned(", stringify!($UnsignedT), "::MAX), -1);")]
1153+
/// ```
1154+
#[unstable(feature = "mixed_integer_ops", issue = "87840")]
1155+
#[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
1156+
#[must_use = "this returns the result of the operation, \
1157+
without modifying the original"]
1158+
#[inline(always)]
1159+
pub const fn wrapping_sub_unsigned(self, rhs: $UnsignedT) -> Self {
1160+
self.wrapping_sub(rhs as Self)
1161+
}
1162+
10251163
/// Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at
10261164
/// the boundary of the type.
10271165
///
@@ -1372,6 +1510,33 @@ macro_rules! int_impl {
13721510
(sum as $SelfT, carry)
13731511
}
13741512

1513+
/// Calculates `self` + `rhs` with an unsigned `rhs`
1514+
///
1515+
/// Returns a tuple of the addition along with a boolean indicating
1516+
/// whether an arithmetic overflow would occur. If an overflow would
1517+
/// have occurred then the wrapped value is returned.
1518+
///
1519+
/// # Examples
1520+
///
1521+
/// Basic usage:
1522+
///
1523+
/// ```
1524+
/// # #![feature(mixed_integer_ops)]
1525+
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_unsigned(2), (3, false));")]
1526+
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN).overflowing_add_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MAX, false));")]
1527+
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_unsigned(3), (", stringify!($SelfT), "::MIN, true));")]
1528+
/// ```
1529+
#[unstable(feature = "mixed_integer_ops", issue = "87840")]
1530+
#[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
1531+
#[must_use = "this returns the result of the operation, \
1532+
without modifying the original"]
1533+
#[inline]
1534+
pub const fn overflowing_add_unsigned(self, rhs: $UnsignedT) -> (Self, bool) {
1535+
let rhs = rhs as Self;
1536+
let (res, overflowed) = self.overflowing_add(rhs);
1537+
(res, overflowed ^ (rhs < 0))
1538+
}
1539+
13751540
/// Calculates `self` - `rhs`
13761541
///
13771542
/// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow
@@ -1423,6 +1588,33 @@ macro_rules! int_impl {
14231588
(sum as $SelfT, borrow)
14241589
}
14251590

1591+
/// Calculates `self` - `rhs` with an unsigned `rhs`
1592+
///
1593+
/// Returns a tuple of the subtraction along with a boolean indicating
1594+
/// whether an arithmetic overflow would occur. If an overflow would
1595+
/// have occurred then the wrapped value is returned.
1596+
///
1597+
/// # Examples
1598+
///
1599+
/// Basic usage:
1600+
///
1601+
/// ```
1602+
/// # #![feature(mixed_integer_ops)]
1603+
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_unsigned(2), (-1, false));")]
1604+
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX).overflowing_sub_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MIN, false));")]
1605+
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).overflowing_sub_unsigned(3), (", stringify!($SelfT), "::MAX, true));")]
1606+
/// ```
1607+
#[unstable(feature = "mixed_integer_ops", issue = "87840")]
1608+
#[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
1609+
#[must_use = "this returns the result of the operation, \
1610+
without modifying the original"]
1611+
#[inline]
1612+
pub const fn overflowing_sub_unsigned(self, rhs: $UnsignedT) -> (Self, bool) {
1613+
let rhs = rhs as Self;
1614+
let (res, overflowed) = self.overflowing_sub(rhs);
1615+
(res, overflowed ^ (rhs < 0))
1616+
}
1617+
14261618
/// Calculates the multiplication of `self` and `rhs`.
14271619
///
14281620
/// Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow

‎library/core/src/num/mod.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ const ASCII_CASE_MASK: u8 = 0b0010_0000;
245245
#[lang = "u8"]
246246
impl u8 {
247247
widening_impl! { u8, u16, 8 }
248-
uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
248+
uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
249249
"[0x12]", "", "" }
250250

251251
/// Checks if the value is within the ASCII range.
@@ -779,21 +779,21 @@ impl u8 {
779779
#[lang = "u16"]
780780
impl u16 {
781781
widening_impl! { u16, u32, 16 }
782-
uint_impl! { u16, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
782+
uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
783783
"[0x34, 0x12]", "[0x12, 0x34]", "", "" }
784784
}
785785

786786
#[lang = "u32"]
787787
impl u32 {
788788
widening_impl! { u32, u64, 32 }
789-
uint_impl! { u32, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
789+
uint_impl! { u32, u32, i32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
790790
"0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
791791
}
792792

793793
#[lang = "u64"]
794794
impl u64 {
795795
widening_impl! { u64, u128, 64 }
796-
uint_impl! { u64, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
796+
uint_impl! { u64, u64, i64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
797797
"0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
798798
"[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
799799
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
@@ -802,7 +802,7 @@ impl u64 {
802802

803803
#[lang = "u128"]
804804
impl u128 {
805-
uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, 16,
805+
uint_impl! { u128, u128, i128, 128, 340282366920938463463374607431768211455, 16,
806806
"0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
807807
"0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
808808
"[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
@@ -816,15 +816,15 @@ impl u128 {
816816
#[lang = "usize"]
817817
impl usize {
818818
widening_impl! { usize, u32, 16 }
819-
uint_impl! { usize, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
819+
uint_impl! { usize, u16, isize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
820820
"[0x34, 0x12]", "[0x12, 0x34]",
821821
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
822822
}
823823
#[cfg(target_pointer_width = "32")]
824824
#[lang = "usize"]
825825
impl usize {
826826
widening_impl! { usize, u64, 32 }
827-
uint_impl! { usize, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
827+
uint_impl! { usize, u32, isize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
828828
"0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]",
829829
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
830830
}
@@ -833,7 +833,7 @@ impl usize {
833833
#[lang = "usize"]
834834
impl usize {
835835
widening_impl! { usize, u128, 64 }
836-
uint_impl! { usize, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
836+
uint_impl! { usize, u64, isize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
837837
"0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
838838
"[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
839839
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",

0 commit comments

Comments
 (0)
Please sign in to comment.