Thanks to visit codestin.com
Credit goes to github.com

Skip to content
111 changes: 91 additions & 20 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -882,17 +882,37 @@ $EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[cfg(stage0)]
pub fn saturating_add(self, rhs: Self) -> Self {
#[cfg(stage0)]
match self.checked_add(rhs) {
Some(x) => x,
None if rhs >= 0 => Self::max_value(),
None => Self::min_value(),
}
#[cfg(not(stage0))]
{
intrinsics::saturating_add(self, rhs)
}
}

}

doc_comment! {
concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric
bounds instead of overflowing.

# Examples

Basic usage:

```
", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);
assert_eq!(", stringify!($SelfT), "::max_value().saturating_add(100), ", stringify!($SelfT),
"::max_value());",
$EndFeature, "
```"),

#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[cfg(not(stage0))]
pub const fn saturating_add(self, rhs: Self) -> Self {
intrinsics::saturating_add(self, rhs)
}
}

Expand All @@ -912,17 +932,35 @@ $EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[cfg(stage0)]
pub fn saturating_sub(self, rhs: Self) -> Self {
#[cfg(stage0)]
match self.checked_sub(rhs) {
Some(x) => x,
None if rhs >= 0 => Self::min_value(),
None => Self::max_value(),
}
#[cfg(not(stage0))]
{
intrinsics::saturating_sub(self, rhs)
}
}
}

doc_comment! {
concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the
numeric bounds instead of overflowing.

# Examples

Basic usage:

```
", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27);
assert_eq!(", stringify!($SelfT), "::min_value().saturating_sub(100), ", stringify!($SelfT),
"::min_value());",
$EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[cfg(not(stage0))]
pub const fn saturating_sub(self, rhs: Self) -> Self {
intrinsics::saturating_sub(self, rhs)
}
}

Expand Down Expand Up @@ -2753,16 +2791,33 @@ assert_eq!(200u8.saturating_add(127), 255);", $EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[cfg(stage0)]
pub fn saturating_add(self, rhs: Self) -> Self {
#[cfg(stage0)]
match self.checked_add(rhs) {
Some(x) => x,
None => Self::max_value(),
}
#[cfg(not(stage0))]
{
intrinsics::saturating_add(self, rhs)
}
}
}

doc_comment! {
concat!("Saturating integer addition. Computes `self + rhs`, saturating at
the numeric bounds instead of overflowing.

# Examples

Basic usage:

```
", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);
assert_eq!(200u8.saturating_add(127), 255);", $EndFeature, "
```"),

#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[cfg(not(stage0))]
pub const fn saturating_add(self, rhs: Self) -> Self {
intrinsics::saturating_add(self, rhs)
}
}

Expand All @@ -2780,16 +2835,32 @@ assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[cfg(stage0)]
pub fn saturating_sub(self, rhs: Self) -> Self {
#[cfg(stage0)]
match self.checked_sub(rhs) {
Some(x) => x,
None => Self::min_value(),
}
#[cfg(not(stage0))]
{
intrinsics::saturating_sub(self, rhs)
}
}
}

doc_comment! {
concat!("Saturating integer subtraction. Computes `self - rhs`, saturating
at the numeric bounds instead of overflowing.

# Examples

Basic usage:

```
", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73);
assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[cfg(not(stage0))]
pub const fn saturating_sub(self, rhs: Self) -> Self {
intrinsics::saturating_sub(self, rhs)
}
}

Expand Down
52 changes: 51 additions & 1 deletion src/librustc_mir/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use syntax::symbol::Symbol;
use rustc::ty;
use rustc::ty::layout::{LayoutOf, Primitive};
use rustc::ty::layout::{LayoutOf, Primitive, Size};
use rustc::mir::BinOp;
use rustc::mir::interpret::{
EvalResult, EvalErrorKind, Scalar,
Expand Down Expand Up @@ -122,6 +122,56 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
self.binop_with_overflow(bin_op, lhs, rhs, dest)?;
}
}
"saturating_add" => {
let l = self.read_immediate(args[0])?;
let r = self.read_immediate(args[1])?;
let (val, overflowed) = self.binary_op_imm(BinOp::Add, l, r)?;
if overflowed {
let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
let num_bits = l.layout.size.bits();
let val = if l.layout.abi.is_signed() {
// For signed addition the saturated value depends on the
// sign of either term
if first_term & (1 << (num_bits-1)) == 0 { // signed term is positive
Scalar::from_uint((1u128 << (num_bits - 1)) - 1,
Size::from_bits(num_bits))
} else { // signed term is negative
Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
}
} else {
Scalar::from_uint(u128::max_value() >> (128 - num_bits),
Size::from_bits(num_bits))
};
self.write_scalar(val, dest)?;
} else {
self.write_scalar(val, dest)?;
}
}
"saturating_sub" => {
let l = self.read_immediate(args[0])?;
let r = self.read_immediate(args[1])?;
let (val, overflowed) = self.binary_op_imm(BinOp::Sub, l, r)?;
if overflowed {
let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
let num_bits = l.layout.size.bits();
let val = if l.layout.abi.is_signed() {
if first_term & (1 << (num_bits-1)) == 0 { // first term is positive
// so overflow is positive
Scalar::from_uint((1u128 << (num_bits - 1)) - 1,
Size::from_bits(num_bits))
} else {
// if first term negative, overflow must be negative
Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
}
} else {
// unsigned underflow saturates to 0
Scalar::from_uint(0u128, Size::from_bits(num_bits))
};
self.write_scalar(val, dest)?;
} else {
self.write_scalar(val, dest)?;
}
}
"unchecked_shl" | "unchecked_shr" => {
let l = self.read_immediate(args[0])?;
let r = self.read_immediate(args[1])?;
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_mir/transform/qualify_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
| "add_with_overflow"
| "sub_with_overflow"
| "mul_with_overflow"
| "saturating_add"
| "saturating_sub"
// no need to check feature gates, intrinsics are only callable
// from the libstd or with forever unstable feature gates
=> is_const_fn = true,
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_mir/transform/qualify_min_const_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,8 @@ fn is_intrinsic_whitelisted(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool
| "overflowing_add" // ~> .wrapping_add
| "overflowing_sub" // ~> .wrapping_sub
| "overflowing_mul" // ~> .wrapping_mul
| "saturating_add" // ~> .saturating_add
| "saturating_sub" // ~> .saturating_sub
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @rust-lang/lang

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm also

| "unchecked_shl" // ~> .wrapping_shl
| "unchecked_shr" // ~> .wrapping_shr
| "rotate_left" // ~> .rotate_left
Expand Down
31 changes: 31 additions & 0 deletions src/test/run-pass/const-int-saturating-arith.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const INT_U32_NO: u32 = (42 as u32).saturating_add(2);
const INT_U32: u32 = u32::max_value().saturating_add(1);
const INT_U128: u128 = u128::max_value().saturating_add(1);
const INT_I128: i128 = i128::max_value().saturating_add(1);
const INT_I128_NEG: i128 = i128::min_value().saturating_add(-1);

const INT_U32_NO_SUB: u32 = (42 as u32).saturating_sub(2);
const INT_U32_SUB: u32 = (1 as u32).saturating_sub(2);
const INT_I32_NO_SUB: i32 = (-42 as i32).saturating_sub(2);
const INT_I32_NEG_SUB: i32 = i32::min_value().saturating_sub(1);
const INT_I32_POS_SUB: i32 = i32::max_value().saturating_sub(-1);
const INT_U128_SUB: u128 = (0 as u128).saturating_sub(1);
const INT_I128_NEG_SUB: i128 = i128::min_value().saturating_sub(1);
const INT_I128_POS_SUB: i128 = i128::max_value().saturating_sub(-1);

fn main() {
assert_eq!(INT_U32_NO, 44);
assert_eq!(INT_U32, u32::max_value());
assert_eq!(INT_U128, u128::max_value());
assert_eq!(INT_I128, i128::max_value());
assert_eq!(INT_I128_NEG, i128::min_value());

assert_eq!(INT_U32_NO_SUB, 40);
assert_eq!(INT_U32_SUB, 0);
assert_eq!(INT_I32_NO_SUB, -44);
assert_eq!(INT_I32_NEG_SUB, i32::min_value());
assert_eq!(INT_I32_POS_SUB, i32::max_value());
assert_eq!(INT_U128_SUB, 0);
assert_eq!(INT_I128_NEG_SUB, i128::min_value());
assert_eq!(INT_I128_POS_SUB, i128::max_value());
}