diff options
| author | Felix S. Klock II <pnkfelix@pnkfx.org> | 2015-02-19 15:14:48 +0100 |
|---|---|---|
| committer | Felix S. Klock II <pnkfelix@pnkfx.org> | 2015-03-03 12:10:57 +0100 |
| commit | c8db89aa82573b89481fde598da6e54371f266cb (patch) | |
| tree | bf3fda792aca94eeca3c413b64c0837a896bf448 /src/libcore/num | |
| parent | 4394720dae12c119a9b1aed492b1b24ee089d808 (diff) | |
| download | rust-c8db89aa82573b89481fde598da6e54371f266cb.tar.gz rust-c8db89aa82573b89481fde598da6e54371f266cb.zip | |
Accommodate arith-overflow in `core::num`, `std::num`, `coretest::num`.
* `core::num`: adjust `UnsignedInt::is_power_of_two`, `UnsignedInt::next_power_of_two`, `Int::pow`. In particular for `Int::pow`: (1.) do not panic when `base` overflows if `acc` never observes the overflowed `base`, and (2.) if `acc` does observe the overflowed `base`, make sure we only panic if we would have otherwise (e.g. during a computation of `base * base`). * also in `core::num`: avoid underflow during computation of `uint::MAX`. * `std::num`: adjust tests `uint::test_uint_from_str_overflow`, `uint::test_uint_to_str_overflow`, `strconv` * `coretest::num`: adjust `test::test_int_from_str_overflow`.
Diffstat (limited to 'src/libcore/num')
| -rw-r--r-- | src/libcore/num/mod.rs | 26 | ||||
| -rw-r--r-- | src/libcore/num/uint_macros.rs | 2 |
2 files changed, 22 insertions, 6 deletions
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 3ed059520b1..92cdd84160b 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -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}; @@ -51,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 @@ -379,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 @@ -694,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`. @@ -709,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 diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index 330f0b91bf1..d0c4885ad00 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -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; ) } |
