Auto merge of #22532 - pnkfelix:arith-overflow, r=pnkfelix,eddyb
Rebase and follow-through on work done by @cmr and @aatch. Implements most of rust-lang/rfcs#560. Errors encountered from the checks during building were fixed. The checks for division, remainder and bit-shifting have not been implemented yet. See also PR #20795 cc @Aatch ; cc @nikomatsakis
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
|
||||
use prelude::*;
|
||||
use default::Default;
|
||||
|
||||
use num::wrapping::WrappingOps;
|
||||
use super::Hasher;
|
||||
|
||||
/// An implementation of SipHash 2-4.
|
||||
@@ -71,17 +71,17 @@ macro_rules! u8to64_le {
|
||||
|
||||
macro_rules! rotl {
|
||||
($x:expr, $b:expr) =>
|
||||
(($x << $b) | ($x >> (64 - $b)))
|
||||
(($x << $b) | ($x >> (64.wrapping_sub($b))))
|
||||
}
|
||||
|
||||
macro_rules! compress {
|
||||
($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
|
||||
({
|
||||
$v0 += $v1; $v1 = rotl!($v1, 13); $v1 ^= $v0;
|
||||
$v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0;
|
||||
$v0 = rotl!($v0, 32);
|
||||
$v2 += $v3; $v3 = rotl!($v3, 16); $v3 ^= $v2;
|
||||
$v0 += $v3; $v3 = rotl!($v3, 21); $v3 ^= $v0;
|
||||
$v2 += $v1; $v1 = rotl!($v1, 17); $v1 ^= $v2;
|
||||
$v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2;
|
||||
$v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0;
|
||||
$v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2;
|
||||
$v2 = rotl!($v2, 32);
|
||||
})
|
||||
}
|
||||
|
||||
@@ -546,3 +546,14 @@ extern "rust-intrinsic" {
|
||||
/// Performs checked `u64` multiplication.
|
||||
pub fn u64_mul_with_overflow(x: u64, y: u64) -> (u64, bool);
|
||||
}
|
||||
|
||||
// SNAP 880fb89
|
||||
#[cfg(not(stage0))]
|
||||
extern "rust-intrinsic" {
|
||||
/// Returns (a + b) mod 2^N, where N is the width of N in bits.
|
||||
pub fn overflowing_add<T>(a: T, b: T) -> T;
|
||||
/// Returns (a - b) mod 2^N, where N is the width of N in bits.
|
||||
pub fn overflowing_sub<T>(a: T, b: T) -> T;
|
||||
/// Returns (a * b) mod 2^N, where N is the width of N in bits.
|
||||
pub fn overflowing_mul<T>(a: T, b: T) -> T;
|
||||
}
|
||||
|
||||
@@ -728,10 +728,11 @@ pub trait IteratorExt: Iterator + Sized {
|
||||
P: FnMut(Self::Item) -> bool,
|
||||
Self: ExactSizeIterator + DoubleEndedIterator
|
||||
{
|
||||
let mut i = self.len() - 1;
|
||||
let mut i = self.len();
|
||||
|
||||
while let Some(v) = self.next_back() {
|
||||
if predicate(v) {
|
||||
return Some(i);
|
||||
return Some(i - 1);
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
@@ -1129,7 +1130,11 @@ impl<I> RandomAccessIterator for Rev<I> where I: DoubleEndedIterator + RandomAcc
|
||||
#[inline]
|
||||
fn idx(&mut self, index: usize) -> Option<<I as Iterator>::Item> {
|
||||
let amt = self.indexable();
|
||||
self.iter.idx(amt - index - 1)
|
||||
if amt > index {
|
||||
self.iter.idx(amt - index - 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(concat_idents)]
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use self::wrapping::{OverflowingOps, WrappingOps};
|
||||
|
||||
use char::CharExt;
|
||||
use clone::Clone;
|
||||
use cmp::{PartialEq, Eq, PartialOrd, Ord};
|
||||
@@ -30,6 +32,9 @@ use option::Option::{self, Some, None};
|
||||
use result::Result::{self, Ok, Err};
|
||||
use str::{FromStr, StrExt};
|
||||
|
||||
#[unstable(feature = "core", reason = "may be removed or relocated")]
|
||||
pub mod wrapping;
|
||||
|
||||
/// A built-in signed or unsigned integer.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Int
|
||||
@@ -48,6 +53,8 @@ pub trait Int
|
||||
+ BitXor<Output=Self>
|
||||
+ Shl<uint, Output=Self>
|
||||
+ Shr<uint, Output=Self>
|
||||
+ WrappingOps
|
||||
+ OverflowingOps
|
||||
{
|
||||
/// Returns the `0` value of this integer type.
|
||||
// FIXME (#5527): Should be an associated constant
|
||||
@@ -376,11 +383,23 @@ pub trait Int
|
||||
let mut base = self;
|
||||
let mut acc: Self = Int::one();
|
||||
|
||||
let mut prev_base = self;
|
||||
let mut base_oflo = false;
|
||||
while exp > 0 {
|
||||
if (exp & 1) == 1 {
|
||||
acc = acc * base;
|
||||
if base_oflo {
|
||||
// ensure overflow occurs in the same manner it
|
||||
// would have otherwise (i.e. signal any exception
|
||||
// it would have otherwise).
|
||||
acc = acc * (prev_base * prev_base);
|
||||
} else {
|
||||
acc = acc * base;
|
||||
}
|
||||
}
|
||||
base = base * base;
|
||||
prev_base = base;
|
||||
let (new_base, new_base_oflo) = base.overflowing_mul(base);
|
||||
base = new_base;
|
||||
base_oflo = new_base_oflo;
|
||||
exp /= 2;
|
||||
}
|
||||
acc
|
||||
@@ -691,12 +710,12 @@ signed_int_impl! { int }
|
||||
|
||||
/// A built-in unsigned integer.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait UnsignedInt: Int {
|
||||
pub trait UnsignedInt: Int + WrappingOps {
|
||||
/// Returns `true` iff `self == 2^k` for some `k`.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
fn is_power_of_two(self) -> bool {
|
||||
(self - Int::one()) & self == Int::zero() && !(self == Int::zero())
|
||||
(self.wrapping_sub(Int::one())) & self == Int::zero() && !(self == Int::zero())
|
||||
}
|
||||
|
||||
/// Returns the smallest power of two greater than or equal to `self`.
|
||||
@@ -706,7 +725,7 @@ pub trait UnsignedInt: Int {
|
||||
fn next_power_of_two(self) -> Self {
|
||||
let bits = size_of::<Self>() * 8;
|
||||
let one: Self = Int::one();
|
||||
one << ((bits - (self - one).leading_zeros() as usize) % bits)
|
||||
one << ((bits - self.wrapping_sub(one).leading_zeros() as usize) % bits)
|
||||
}
|
||||
|
||||
/// Returns the smallest power of two greater than or equal to `n`. If the
|
||||
|
||||
@@ -20,6 +20,6 @@ pub const BYTES : u32 = ($bits / 8);
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub const MIN: $T = 0 as $T;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub const MAX: $T = 0 as $T - 1 as $T;
|
||||
pub const MAX: $T = !0 as $T;
|
||||
|
||||
) }
|
||||
|
||||
300
src/libcore/num/wrapping.rs
Normal file
300
src/libcore/num/wrapping.rs
Normal file
@@ -0,0 +1,300 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use ops::*;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
use intrinsics::{overflowing_add, overflowing_sub, overflowing_mul};
|
||||
|
||||
use intrinsics::{i8_add_with_overflow, u8_add_with_overflow};
|
||||
use intrinsics::{i16_add_with_overflow, u16_add_with_overflow};
|
||||
use intrinsics::{i32_add_with_overflow, u32_add_with_overflow};
|
||||
use intrinsics::{i64_add_with_overflow, u64_add_with_overflow};
|
||||
use intrinsics::{i8_sub_with_overflow, u8_sub_with_overflow};
|
||||
use intrinsics::{i16_sub_with_overflow, u16_sub_with_overflow};
|
||||
use intrinsics::{i32_sub_with_overflow, u32_sub_with_overflow};
|
||||
use intrinsics::{i64_sub_with_overflow, u64_sub_with_overflow};
|
||||
use intrinsics::{i8_mul_with_overflow, u8_mul_with_overflow};
|
||||
use intrinsics::{i16_mul_with_overflow, u16_mul_with_overflow};
|
||||
use intrinsics::{i32_mul_with_overflow, u32_mul_with_overflow};
|
||||
use intrinsics::{i64_mul_with_overflow, u64_mul_with_overflow};
|
||||
|
||||
pub trait WrappingOps {
|
||||
fn wrapping_add(self, rhs: Self) -> Self;
|
||||
fn wrapping_sub(self, rhs: Self) -> Self;
|
||||
fn wrapping_mul(self, rhs: Self) -> Self;
|
||||
}
|
||||
|
||||
#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
|
||||
pub trait OverflowingOps {
|
||||
fn overflowing_add(self, rhs: Self) -> (Self, bool);
|
||||
fn overflowing_sub(self, rhs: Self) -> (Self, bool);
|
||||
fn overflowing_mul(self, rhs: Self) -> (Self, bool);
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
macro_rules! wrapping_impl {
|
||||
($($t:ty)*) => ($(
|
||||
impl WrappingOps for $t {
|
||||
#[inline(always)]
|
||||
fn wrapping_add(self, rhs: $t) -> $t {
|
||||
unsafe {
|
||||
overflowing_add(self, rhs)
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn wrapping_sub(self, rhs: $t) -> $t {
|
||||
unsafe {
|
||||
overflowing_sub(self, rhs)
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn wrapping_mul(self, rhs: $t) -> $t {
|
||||
unsafe {
|
||||
overflowing_mul(self, rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
macro_rules! wrapping_impl {
|
||||
($($t:ty)*) => ($(
|
||||
impl WrappingOps for $t {
|
||||
#[inline(always)]
|
||||
fn wrapping_add(self, rhs: $t) -> $t {
|
||||
self + rhs
|
||||
}
|
||||
#[inline(always)]
|
||||
fn wrapping_sub(self, rhs: $t) -> $t {
|
||||
self - rhs
|
||||
}
|
||||
#[inline(always)]
|
||||
fn wrapping_mul(self, rhs: $t) -> $t {
|
||||
self * rhs
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
wrapping_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 }
|
||||
|
||||
#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
|
||||
#[derive(PartialEq,Eq,PartialOrd,Ord,Clone,Copy)]
|
||||
pub struct Wrapping<T>(pub T);
|
||||
|
||||
impl<T:WrappingOps> Add for Wrapping<T> {
|
||||
type Output = Wrapping<T>;
|
||||
|
||||
#[inline(always)]
|
||||
fn add(self, other: Wrapping<T>) -> Wrapping<T> {
|
||||
Wrapping(self.0.wrapping_add(other.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:WrappingOps> Sub for Wrapping<T> {
|
||||
type Output = Wrapping<T>;
|
||||
|
||||
#[inline(always)]
|
||||
fn sub(self, other: Wrapping<T>) -> Wrapping<T> {
|
||||
Wrapping(self.0.wrapping_sub(other.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:WrappingOps> Mul for Wrapping<T> {
|
||||
type Output = Wrapping<T>;
|
||||
|
||||
#[inline(always)]
|
||||
fn mul(self, other: Wrapping<T>) -> Wrapping<T> {
|
||||
Wrapping(self.0.wrapping_mul(other.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:WrappingOps+Not<Output=T>> Not for Wrapping<T> {
|
||||
type Output = Wrapping<T>;
|
||||
|
||||
fn not(self) -> Wrapping<T> {
|
||||
Wrapping(!self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:WrappingOps+BitXor<Output=T>> BitXor for Wrapping<T> {
|
||||
type Output = Wrapping<T>;
|
||||
|
||||
#[inline(always)]
|
||||
fn bitxor(self, other: Wrapping<T>) -> Wrapping<T> {
|
||||
Wrapping(self.0 ^ other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:WrappingOps+BitOr<Output=T>> BitOr for Wrapping<T> {
|
||||
type Output = Wrapping<T>;
|
||||
|
||||
#[inline(always)]
|
||||
fn bitor(self, other: Wrapping<T>) -> Wrapping<T> {
|
||||
Wrapping(self.0 | other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:WrappingOps+BitAnd<Output=T>> BitAnd for Wrapping<T> {
|
||||
type Output = Wrapping<T>;
|
||||
|
||||
#[inline(always)]
|
||||
fn bitand(self, other: Wrapping<T>) -> Wrapping<T> {
|
||||
Wrapping(self.0 & other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:WrappingOps+Shl<uint,Output=T>> Shl<uint> for Wrapping<T> {
|
||||
type Output = Wrapping<T>;
|
||||
|
||||
#[inline(always)]
|
||||
fn shl(self, other: uint) -> Wrapping<T> {
|
||||
Wrapping(self.0 << other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:WrappingOps+Shr<uint,Output=T>> Shr<uint> for Wrapping<T> {
|
||||
type Output = Wrapping<T>;
|
||||
|
||||
#[inline(always)]
|
||||
fn shr(self, other: uint) -> Wrapping<T> {
|
||||
Wrapping(self.0 >> other)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! overflowing_impl {
|
||||
($($t:ident)*) => ($(
|
||||
impl OverflowingOps for $t {
|
||||
#[inline(always)]
|
||||
fn overflowing_add(self, rhs: $t) -> ($t, bool) {
|
||||
unsafe {
|
||||
concat_idents!($t, _add_with_overflow)(self, rhs)
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn overflowing_sub(self, rhs: $t) -> ($t, bool) {
|
||||
unsafe {
|
||||
concat_idents!($t, _sub_with_overflow)(self, rhs)
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn overflowing_mul(self, rhs: $t) -> ($t, bool) {
|
||||
unsafe {
|
||||
concat_idents!($t, _mul_with_overflow)(self, rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
overflowing_impl! { u8 u16 u32 u64 i8 i16 i32 i64 }
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
impl OverflowingOps for usize {
|
||||
#[inline(always)]
|
||||
fn overflowing_add(self, rhs: usize) -> (usize, bool) {
|
||||
unsafe {
|
||||
let res = u64_add_with_overflow(self as u64, rhs as u64);
|
||||
(res.0 as usize, res.1)
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn overflowing_sub(self, rhs: usize) -> (usize, bool) {
|
||||
unsafe {
|
||||
let res = u64_sub_with_overflow(self as u64, rhs as u64);
|
||||
(res.0 as usize, res.1)
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn overflowing_mul(self, rhs: usize) -> (usize, bool) {
|
||||
unsafe {
|
||||
let res = u64_mul_with_overflow(self as u64, rhs as u64);
|
||||
(res.0 as usize, res.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
impl OverflowingOps for usize {
|
||||
#[inline(always)]
|
||||
fn overflowing_add(self, rhs: usize) -> (usize, bool) {
|
||||
unsafe {
|
||||
let res = u32_add_with_overflow(self as u32, rhs as u32);
|
||||
(res.0 as usize, res.1)
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn overflowing_sub(self, rhs: usize) -> (usize, bool) {
|
||||
unsafe {
|
||||
let res = u32_sub_with_overflow(self as u32, rhs as u32);
|
||||
(res.0 as usize, res.1)
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn overflowing_mul(self, rhs: usize) -> (usize, bool) {
|
||||
unsafe {
|
||||
let res = u32_mul_with_overflow(self as u32, rhs as u32);
|
||||
(res.0 as usize, res.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
impl OverflowingOps for isize {
|
||||
#[inline(always)]
|
||||
fn overflowing_add(self, rhs: isize) -> (isize, bool) {
|
||||
unsafe {
|
||||
let res = i64_add_with_overflow(self as i64, rhs as i64);
|
||||
(res.0 as isize, res.1)
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn overflowing_sub(self, rhs: isize) -> (isize, bool) {
|
||||
unsafe {
|
||||
let res = i64_sub_with_overflow(self as i64, rhs as i64);
|
||||
(res.0 as isize, res.1)
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn overflowing_mul(self, rhs: isize) -> (isize, bool) {
|
||||
unsafe {
|
||||
let res = i64_mul_with_overflow(self as i64, rhs as i64);
|
||||
(res.0 as isize, res.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
impl OverflowingOps for isize {
|
||||
#[inline(always)]
|
||||
fn overflowing_add(self, rhs: isize) -> (isize, bool) {
|
||||
unsafe {
|
||||
let res = i32_add_with_overflow(self as i32, rhs as i32);
|
||||
(res.0 as isize, res.1)
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn overflowing_sub(self, rhs: isize) -> (isize, bool) {
|
||||
unsafe {
|
||||
let res = i32_sub_with_overflow(self as i32, rhs as i32);
|
||||
(res.0 as isize, res.1)
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn overflowing_mul(self, rhs: isize) -> (isize, bool) {
|
||||
unsafe {
|
||||
let res = i32_mul_with_overflow(self as i32, rhs as i32);
|
||||
(res.0 as isize, res.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -841,6 +841,7 @@ impl TwoWaySearcher {
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) {
|
||||
use num::wrapping::WrappingOps;
|
||||
let mut left = -1; // Corresponds to i in the paper
|
||||
let mut right = 0; // Corresponds to j in the paper
|
||||
let mut offset = 1; // Corresponds to k in the paper
|
||||
@@ -850,17 +851,17 @@ impl TwoWaySearcher {
|
||||
let a;
|
||||
let b;
|
||||
if reversed {
|
||||
a = arr[left + offset];
|
||||
a = arr[left.wrapping_add(offset)];
|
||||
b = arr[right + offset];
|
||||
} else {
|
||||
a = arr[right + offset];
|
||||
b = arr[left + offset];
|
||||
b = arr[left.wrapping_add(offset)];
|
||||
}
|
||||
if a < b {
|
||||
// Suffix is smaller, period is entire prefix so far.
|
||||
right += offset;
|
||||
offset = 1;
|
||||
period = right - left;
|
||||
period = right.wrapping_sub(left);
|
||||
} else if a == b {
|
||||
// Advance through repetition of the current period.
|
||||
if offset == period {
|
||||
@@ -877,7 +878,7 @@ impl TwoWaySearcher {
|
||||
period = 1;
|
||||
}
|
||||
}
|
||||
(left + 1, period)
|
||||
(left.wrapping_add(1), period)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user