1
Fork 0

Move checked arithmetic operators into Int trait

This commit is contained in:
Brendan Zabarauskas 2014-11-10 00:11:28 +11:00
parent 7e57cd843c
commit e51cc089da
20 changed files with 324 additions and 371 deletions

View file

@ -97,7 +97,7 @@ syn keyword rustTrait FromIterator IntoIterator Extend ExactSize
syn keyword rustTrait Iterator DoubleEndedIterator syn keyword rustTrait Iterator DoubleEndedIterator
syn keyword rustTrait RandomAccessIterator CloneableIterator syn keyword rustTrait RandomAccessIterator CloneableIterator
syn keyword rustTrait OrdIterator MutableDoubleEndedIterator syn keyword rustTrait OrdIterator MutableDoubleEndedIterator
syn keyword rustTrait Num NumCast CheckedAdd CheckedSub CheckedMul CheckedDiv syn keyword rustTrait Num NumCast
syn keyword rustTrait Signed Unsigned Primitive Int Float syn keyword rustTrait Signed Unsigned Primitive Int Float
syn keyword rustTrait FloatMath ToPrimitive FromPrimitive syn keyword rustTrait FloatMath ToPrimitive FromPrimitive
syn keyword rustTrait Box syn keyword rustTrait Box

View file

@ -132,7 +132,7 @@ impl Drop for Arena {
#[inline] #[inline]
fn round_up(base: uint, align: uint) -> uint { fn round_up(base: uint, align: uint) -> uint {
(base.checked_add(&(align - 1))).unwrap() & !(align - 1) (base.checked_add(align - 1)).unwrap() & !(align - 1)
} }
// Walk down a chunk, running the destructors for any objects stored // Walk down a chunk, running the destructors for any objects stored
@ -376,8 +376,8 @@ fn calculate_size<T>(capacity: uint) -> uint {
let mut size = mem::size_of::<TypedArenaChunk<T>>(); let mut size = mem::size_of::<TypedArenaChunk<T>>();
size = round_up(size, mem::min_align_of::<T>()); size = round_up(size, mem::min_align_of::<T>());
let elem_size = mem::size_of::<T>(); let elem_size = mem::size_of::<T>();
let elems_size = elem_size.checked_mul(&capacity).unwrap(); let elems_size = elem_size.checked_mul(capacity).unwrap();
size = size.checked_add(&elems_size).unwrap(); size = size.checked_add(elems_size).unwrap();
size size
} }
@ -432,7 +432,7 @@ impl<T> TypedArenaChunk<T> {
#[inline] #[inline]
fn end(&self) -> *const u8 { fn end(&self) -> *const u8 {
unsafe { unsafe {
let size = mem::size_of::<T>().checked_mul(&self.capacity).unwrap(); let size = mem::size_of::<T>().checked_mul(self.capacity).unwrap();
self.start().offset(size as int) self.start().offset(size as int)
} }
} }
@ -481,7 +481,7 @@ impl<T> TypedArena<T> {
fn grow(&self) { fn grow(&self) {
unsafe { unsafe {
let chunk = *self.first.borrow_mut(); let chunk = *self.first.borrow_mut();
let new_capacity = (*chunk).capacity.checked_mul(&2).unwrap(); let new_capacity = (*chunk).capacity.checked_mul(2).unwrap();
let chunk = TypedArenaChunk::<T>::new(chunk, new_capacity); let chunk = TypedArenaChunk::<T>::new(chunk, new_capacity);
self.ptr.set((*chunk).start() as *const T); self.ptr.set((*chunk).start() as *const T);
self.end.set((*chunk).end() as *const T); self.end.set((*chunk).end() as *const T);

View file

@ -161,7 +161,7 @@ impl<T> Vec<T> {
} else if capacity == 0 { } else if capacity == 0 {
Vec::new() Vec::new()
} else { } else {
let size = capacity.checked_mul(&mem::size_of::<T>()) let size = capacity.checked_mul(mem::size_of::<T>())
.expect("capacity overflow"); .expect("capacity overflow");
let ptr = unsafe { allocate(size, mem::min_align_of::<T>()) }; let ptr = unsafe { allocate(size, mem::min_align_of::<T>()) };
Vec { ptr: ptr as *mut T, len: 0, cap: capacity } Vec { ptr: ptr as *mut T, len: 0, cap: capacity }
@ -601,7 +601,7 @@ impl<T> Vec<T> {
#[unstable = "matches collection reform specification, waiting for dust to settle"] #[unstable = "matches collection reform specification, waiting for dust to settle"]
pub fn reserve(&mut self, additional: uint) { pub fn reserve(&mut self, additional: uint) {
if self.cap - self.len < additional { if self.cap - self.len < additional {
match self.len.checked_add(&additional) { match self.len.checked_add(additional) {
None => panic!("Vec::reserve: `uint` overflow"), None => panic!("Vec::reserve: `uint` overflow"),
// if the checked_add // if the checked_add
Some(new_cap) => { Some(new_cap) => {
@ -638,7 +638,7 @@ impl<T> Vec<T> {
#[unstable = "matches collection reform specification, waiting for dust to settle"] #[unstable = "matches collection reform specification, waiting for dust to settle"]
pub fn reserve_exact(&mut self, additional: uint) { pub fn reserve_exact(&mut self, additional: uint) {
if self.cap - self.len < additional { if self.cap - self.len < additional {
match self.len.checked_add(&additional) { match self.len.checked_add(additional) {
None => panic!("Vec::reserve: `uint` overflow"), None => panic!("Vec::reserve: `uint` overflow"),
Some(new_cap) => self.grow_capacity(new_cap) Some(new_cap) => self.grow_capacity(new_cap)
} }
@ -971,7 +971,7 @@ impl<T> Vec<T> {
pub fn push(&mut self, value: T) { pub fn push(&mut self, value: T) {
if mem::size_of::<T>() == 0 { if mem::size_of::<T>() == 0 {
// zero-size types consume no memory, so we can't rely on the address space running out // zero-size types consume no memory, so we can't rely on the address space running out
self.len = self.len.checked_add(&1).expect("length overflow"); self.len = self.len.checked_add(1).expect("length overflow");
unsafe { mem::forget(value); } unsafe { mem::forget(value); }
return return
} }
@ -1064,7 +1064,7 @@ impl<T> Vec<T> {
if mem::size_of::<T>() == 0 { return } if mem::size_of::<T>() == 0 { return }
if capacity > self.cap { if capacity > self.cap {
let size = capacity.checked_mul(&mem::size_of::<T>()) let size = capacity.checked_mul(mem::size_of::<T>())
.expect("capacity overflow"); .expect("capacity overflow");
unsafe { unsafe {
self.ptr = alloc_or_realloc(self.ptr, self.cap * mem::size_of::<T>(), size); self.ptr = alloc_or_realloc(self.ptr, self.cap * mem::size_of::<T>(), size);

View file

@ -60,9 +60,9 @@ This `for` loop syntax can be applied to any iterator over any type.
use clone::Clone; use clone::Clone;
use cmp; use cmp;
use cmp::{PartialEq, PartialOrd, Ord}; use cmp::{PartialOrd, Ord};
use mem; use mem;
use num::{Zero, One, CheckedAdd, CheckedSub, ToPrimitive, Int}; use num::{Zero, One, ToPrimitive, Int};
use ops::{Add, Mul, Sub}; use ops::{Add, Mul, Sub};
use option::{Option, Some, None}; use option::{Option, Some, None};
use uint; use uint;
@ -1093,7 +1093,7 @@ impl<A, T: Iterator<A>, U: Iterator<A>> Iterator<A> for Chain<T, U> {
let lower = a_lower.saturating_add(b_lower); let lower = a_lower.saturating_add(b_lower);
let upper = match (a_upper, b_upper) { let upper = match (a_upper, b_upper) {
(Some(x), Some(y)) => x.checked_add(&y), (Some(x), Some(y)) => x.checked_add(y),
_ => None _ => None
}; };
@ -1415,7 +1415,7 @@ impl<A, T: Iterator<A>> Iterator<A> for Peekable<A, T> {
if self.peeked.is_some() { if self.peeked.is_some() {
let lo = lo.saturating_add(1); let lo = lo.saturating_add(1);
let hi = match hi { let hi = match hi {
Some(x) => x.checked_add(&1), Some(x) => x.checked_add(1),
None => None None => None
}; };
(lo, hi) (lo, hi)
@ -1680,7 +1680,7 @@ impl<'a, A, T: Iterator<A>, B, U: Iterator<B>> Iterator<B> for FlatMap<'a, A, T,
let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), |it| it.size_hint()); let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), |it| it.size_hint());
let lo = flo.saturating_add(blo); let lo = flo.saturating_add(blo);
match (self.iter.size_hint(), fhi, bhi) { match (self.iter.size_hint(), fhi, bhi) {
((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(&b)), ((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)),
_ => (lo, None) _ => (lo, None)
} }
} }
@ -1946,7 +1946,7 @@ impl<A: Add<A, A> + PartialOrd + Clone + ToPrimitive> Iterator<A> for Range<A> {
// the i64/u64 might lie within their range. // the i64/u64 might lie within their range.
let bound = match self.state.to_i64() { let bound = match self.state.to_i64() {
Some(a) => { Some(a) => {
let sz = self.stop.to_i64().map(|b| b.checked_sub(&a)); let sz = self.stop.to_i64().map(|b| b.checked_sub(a));
match sz { match sz {
Some(Some(bound)) => bound.to_uint(), Some(Some(bound)) => bound.to_uint(),
_ => None, _ => None,
@ -1954,7 +1954,7 @@ impl<A: Add<A, A> + PartialOrd + Clone + ToPrimitive> Iterator<A> for Range<A> {
}, },
None => match self.state.to_u64() { None => match self.state.to_u64() {
Some(a) => { Some(a) => {
let sz = self.stop.to_u64().map(|b| b.checked_sub(&a)); let sz = self.stop.to_u64().map(|b| b.checked_sub(a));
match sz { match sz {
Some(Some(bound)) => bound.to_uint(), Some(Some(bound)) => bound.to_uint(),
_ => None _ => None
@ -2024,7 +2024,7 @@ impl<A: Add<A, A> + PartialOrd + Clone + ToPrimitive> Iterator<A> for RangeInclu
} else { } else {
let lo = lo.saturating_add(1); let lo = lo.saturating_add(1);
let hi = match hi { let hi = match hi {
Some(x) => x.checked_add(&1), Some(x) => x.checked_add(1),
None => None None => None
}; };
(lo, hi) (lo, hi)
@ -2060,18 +2060,17 @@ pub struct RangeStep<A> {
/// Return an iterator over the range [start, stop) by `step`. It handles overflow by stopping. /// Return an iterator over the range [start, stop) by `step`. It handles overflow by stopping.
#[inline] #[inline]
pub fn range_step<A: CheckedAdd + PartialOrd + pub fn range_step<A: Int>(start: A, stop: A, step: A) -> RangeStep<A> {
Clone + Zero>(start: A, stop: A, step: A) -> RangeStep<A> {
let rev = step < Zero::zero(); let rev = step < Zero::zero();
RangeStep{state: start, stop: stop, step: step, rev: rev} RangeStep{state: start, stop: stop, step: step, rev: rev}
} }
impl<A: CheckedAdd + PartialOrd + Clone> Iterator<A> for RangeStep<A> { impl<A: Int> Iterator<A> for RangeStep<A> {
#[inline] #[inline]
fn next(&mut self) -> Option<A> { fn next(&mut self) -> Option<A> {
if (self.rev && self.state > self.stop) || (!self.rev && self.state < self.stop) { if (self.rev && self.state > self.stop) || (!self.rev && self.state < self.stop) {
let result = self.state.clone(); let result = self.state;
match self.state.checked_add(&self.step) { match self.state.checked_add(self.step) {
Some(x) => self.state = x, Some(x) => self.state = x,
None => self.state = self.stop.clone() None => self.state = self.stop.clone()
} }
@ -2094,19 +2093,18 @@ pub struct RangeStepInclusive<A> {
/// Return an iterator over the range [start, stop] by `step`. It handles overflow by stopping. /// Return an iterator over the range [start, stop] by `step`. It handles overflow by stopping.
#[inline] #[inline]
pub fn range_step_inclusive<A: CheckedAdd + PartialOrd + Clone + Zero>(start: A, stop: A, pub fn range_step_inclusive<A: Int>(start: A, stop: A, step: A) -> RangeStepInclusive<A> {
step: A) -> RangeStepInclusive<A> {
let rev = step < Zero::zero(); let rev = step < Zero::zero();
RangeStepInclusive{state: start, stop: stop, step: step, rev: rev, done: false} RangeStepInclusive{state: start, stop: stop, step: step, rev: rev, done: false}
} }
impl<A: CheckedAdd + PartialOrd + Clone + PartialEq> Iterator<A> for RangeStepInclusive<A> { impl<A: Int> Iterator<A> for RangeStepInclusive<A> {
#[inline] #[inline]
fn next(&mut self) -> Option<A> { fn next(&mut self) -> Option<A> {
if !self.done && ((self.rev && self.state >= self.stop) || if !self.done && ((self.rev && self.state >= self.stop) ||
(!self.rev && self.state <= self.stop)) { (!self.rev && self.state <= self.stop)) {
let result = self.state.clone(); let result = self.state;
match self.state.checked_add(&self.step) { match self.state.checked_add(self.step) {
Some(x) => self.state = x, Some(x) => self.state = x,
None => self.done = true None => self.done = true
} }

View file

@ -348,10 +348,6 @@ trait_impl!(Primitive for uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64)
/// operators, bit counting methods, and endian conversion functions. /// operators, bit counting methods, and endian conversion functions.
pub trait Int: Primitive pub trait Int: Primitive
+ Ord + Ord
+ CheckedAdd
+ CheckedSub
+ CheckedMul
+ CheckedDiv
+ Bounded + Bounded
+ Not<Self> + Not<Self>
+ BitAnd<Self,Self> + BitAnd<Self,Self>
@ -526,11 +522,65 @@ pub trait Int: Primitive
if cfg!(target_endian = "little") { self } else { self.swap_bytes() } if cfg!(target_endian = "little") { self } else { self.swap_bytes() }
} }
/// Adds two numbers, checking for overflow. If overflow occurs, `None` is
/// returned.
///
/// # Example
///
/// ```rust
/// use std::num::Int;
///
/// assert_eq!(5u16.checked_add(65530), Some(65535));
/// assert_eq!(6u16.checked_add(65530), None);
/// ```
fn checked_add(self, other: Self) -> Option<Self>;
/// Subtracts two numbers, checking for underflow. If underflow occurs,
/// `None` is returned.
///
/// # Example
///
/// ```rust
/// use std::num::Int;
///
/// assert_eq!((-127i8).checked_sub(1), Some(-128));
/// assert_eq!((-128i8).checked_sub(1), None);
/// ```
fn checked_sub(self, other: Self) -> Option<Self>;
/// Multiplies two numbers, checking for underflow or overflow. If underflow
/// or overflow occurs, `None` is returned.
///
/// # Example
///
/// ```rust
/// use std::num::Int;
///
/// assert_eq!(5u8.checked_mul(51), Some(255));
/// assert_eq!(5u8.checked_mul(52), None);
/// ```
fn checked_mul(self, other: Self) -> Option<Self>;
/// Divides two numbers, checking for underflow, overflow and division by
/// zero. If underflow occurs, `None` is returned.
///
/// # Example
///
/// ```rust
/// use std::num::Int;
///
/// assert_eq!((-127i8).checked_div(-1), Some(127));
/// assert_eq!((-128i8).checked_div(-1), None);
/// assert_eq!((1i8).checked_div(0), None);
/// ```
#[inline]
fn checked_div(self, other: Self) -> Option<Self>;
/// Saturating addition. Returns `self + other`, saturating at the /// Saturating addition. Returns `self + other`, saturating at the
/// numeric bounds instead of overflowing. /// numeric bounds instead of overflowing.
#[inline] #[inline]
fn saturating_add(self, other: Self) -> Self { fn saturating_add(self, other: Self) -> Self {
match self.checked_add(&other) { match self.checked_add(other) {
Some(x) => x, Some(x) => x,
None if other >= Zero::zero() => Bounded::max_value(), None if other >= Zero::zero() => Bounded::max_value(),
None => Bounded::min_value(), None => Bounded::min_value(),
@ -541,7 +591,7 @@ pub trait Int: Primitive
/// numeric bounds instead of overflowing. /// numeric bounds instead of overflowing.
#[inline] #[inline]
fn saturating_sub(self, other: Self) -> Self { fn saturating_sub(self, other: Self) -> Self {
match self.checked_sub(&other) { match self.checked_sub(other) {
Some(x) => x, Some(x) => x,
None if other >= Zero::zero() => Bounded::min_value(), None if other >= Zero::zero() => Bounded::min_value(),
None => Bounded::max_value(), None => Bounded::max_value(),
@ -549,9 +599,22 @@ pub trait Int: Primitive
} }
} }
macro_rules! checked_op {
($T:ty, $U:ty, $op:path, $x:expr, $y:expr) => {{
let (result, overflowed) = unsafe { $op($x as $U, $y as $U) };
if overflowed { None } else { Some(result as $T) }
}}
}
macro_rules! uint_impl { macro_rules! uint_impl {
($T:ty, $ActualT:ty, $BITS:expr, ($T:ty = $ActualT:ty, $BITS:expr,
$ctpop:path, $ctlz:path, $cttz:path, $bswap:path) => { $ctpop:path,
$ctlz:path,
$cttz:path,
$bswap:path,
$add_with_overflow:path,
$sub_with_overflow:path,
$mul_with_overflow:path) => {
impl Int for $T { impl Int for $T {
#[inline] #[inline]
fn count_ones(self) -> uint { unsafe { $ctpop(self as $ActualT) as uint } } fn count_ones(self) -> uint { unsafe { $ctpop(self as $ActualT) as uint } }
@ -578,6 +641,29 @@ macro_rules! uint_impl {
#[inline] #[inline]
fn swap_bytes(self) -> $T { unsafe { $bswap(self as $ActualT) as $T } } fn swap_bytes(self) -> $T { unsafe { $bswap(self as $ActualT) as $T } }
#[inline]
fn checked_add(self, other: $T) -> Option<$T> {
checked_op!($T, $ActualT, $add_with_overflow, self, other)
}
#[inline]
fn checked_sub(self, other: $T) -> Option<$T> {
checked_op!($T, $ActualT, $sub_with_overflow, self, other)
}
#[inline]
fn checked_mul(self, other: $T) -> Option<$T> {
checked_op!($T, $ActualT, $mul_with_overflow, self, other)
}
#[inline]
fn checked_div(self, v: $T) -> Option<$T> {
match v {
0 => None,
v => Some(self / v),
}
}
} }
} }
} }
@ -586,74 +672,145 @@ macro_rules! uint_impl {
/// consistency with the other `bswap` intrinsics. /// consistency with the other `bswap` intrinsics.
unsafe fn bswap8(x: u8) -> u8 { x } unsafe fn bswap8(x: u8) -> u8 { x }
uint_impl!(u8, u8, 8, uint_impl!(u8 = u8, 8,
intrinsics::ctpop8, intrinsics::ctpop8,
intrinsics::ctlz8, intrinsics::ctlz8,
intrinsics::cttz8, intrinsics::cttz8,
bswap8) bswap8,
intrinsics::u8_add_with_overflow,
intrinsics::u8_sub_with_overflow,
intrinsics::u8_mul_with_overflow)
uint_impl!(u16, u16, 16, uint_impl!(u16 = u16, 16,
intrinsics::ctpop16, intrinsics::ctpop16,
intrinsics::ctlz16, intrinsics::ctlz16,
intrinsics::cttz16, intrinsics::cttz16,
intrinsics::bswap16) intrinsics::bswap16,
intrinsics::u16_add_with_overflow,
intrinsics::u16_sub_with_overflow,
intrinsics::u16_mul_with_overflow)
uint_impl!(u32, u32, 32, uint_impl!(u32 = u32, 32,
intrinsics::ctpop32, intrinsics::ctpop32,
intrinsics::ctlz32, intrinsics::ctlz32,
intrinsics::cttz32, intrinsics::cttz32,
intrinsics::bswap32) intrinsics::bswap32,
intrinsics::u32_add_with_overflow,
intrinsics::u32_sub_with_overflow,
intrinsics::u32_mul_with_overflow)
uint_impl!(u64, u64, 64, uint_impl!(u64 = u64, 64,
intrinsics::ctpop64, intrinsics::ctpop64,
intrinsics::ctlz64, intrinsics::ctlz64,
intrinsics::cttz64, intrinsics::cttz64,
intrinsics::bswap64) intrinsics::bswap64,
intrinsics::u64_add_with_overflow,
intrinsics::u64_sub_with_overflow,
intrinsics::u64_mul_with_overflow)
#[cfg(target_word_size = "32")] #[cfg(target_word_size = "32")]
uint_impl!(uint, u32, 32, uint_impl!(uint = u32, 32,
intrinsics::ctpop32, intrinsics::ctpop32,
intrinsics::ctlz32, intrinsics::ctlz32,
intrinsics::cttz32, intrinsics::cttz32,
intrinsics::bswap32) intrinsics::bswap32,
intrinsics::u32_add_with_overflow,
intrinsics::u32_sub_with_overflow,
intrinsics::u32_mul_with_overflow)
#[cfg(target_word_size = "64")] #[cfg(target_word_size = "64")]
uint_impl!(uint, u64, 64, uint_impl!(uint = u64, 64,
intrinsics::ctpop64, intrinsics::ctpop64,
intrinsics::ctlz64, intrinsics::ctlz64,
intrinsics::cttz64, intrinsics::cttz64,
intrinsics::bswap64) intrinsics::bswap64,
intrinsics::u64_add_with_overflow,
intrinsics::u64_sub_with_overflow,
intrinsics::u64_mul_with_overflow)
macro_rules! int_impl { macro_rules! int_impl {
($T:ty, $U:ty) => { ($T:ty = $ActualT:ty, $UnsignedT:ty,
$add_with_overflow:path,
$sub_with_overflow:path,
$mul_with_overflow:path) => {
impl Int for $T { impl Int for $T {
#[inline] #[inline]
fn count_ones(self) -> uint { (self as $U).count_ones() } fn count_ones(self) -> uint { (self as $UnsignedT).count_ones() }
#[inline] #[inline]
fn leading_zeros(self) -> uint { (self as $U).leading_zeros() } fn leading_zeros(self) -> uint { (self as $UnsignedT).leading_zeros() }
#[inline] #[inline]
fn trailing_zeros(self) -> uint { (self as $U).trailing_zeros() } fn trailing_zeros(self) -> uint { (self as $UnsignedT).trailing_zeros() }
#[inline] #[inline]
fn rotate_left(self, n: uint) -> $T { (self as $U).rotate_left(n) as $T } fn rotate_left(self, n: uint) -> $T { (self as $UnsignedT).rotate_left(n) as $T }
#[inline] #[inline]
fn rotate_right(self, n: uint) -> $T { (self as $U).rotate_right(n) as $T } fn rotate_right(self, n: uint) -> $T { (self as $UnsignedT).rotate_right(n) as $T }
#[inline] #[inline]
fn swap_bytes(self) -> $T { (self as $U).swap_bytes() as $T } fn swap_bytes(self) -> $T { (self as $UnsignedT).swap_bytes() as $T }
#[inline]
fn checked_add(self, other: $T) -> Option<$T> {
checked_op!($T, $ActualT, $add_with_overflow, self, other)
}
#[inline]
fn checked_sub(self, other: $T) -> Option<$T> {
checked_op!($T, $ActualT, $sub_with_overflow, self, other)
}
#[inline]
fn checked_mul(self, other: $T) -> Option<$T> {
checked_op!($T, $ActualT, $mul_with_overflow, self, other)
}
#[inline]
fn checked_div(self, v: $T) -> Option<$T> {
match v {
0 => None,
-1 if self == Bounded::min_value()
=> None,
v => Some(self / v),
}
}
} }
} }
} }
int_impl!(i8, u8) int_impl!(i8 = i8, u8,
int_impl!(i16, u16) intrinsics::i8_add_with_overflow,
int_impl!(i32, u32) intrinsics::i8_sub_with_overflow,
int_impl!(i64, u64) intrinsics::i8_mul_with_overflow)
#[cfg(target_word_size = "32")] int_impl!(int, u32)
#[cfg(target_word_size = "64")] int_impl!(int, u64) int_impl!(i16 = i16, u16,
intrinsics::i16_add_with_overflow,
intrinsics::i16_sub_with_overflow,
intrinsics::i16_mul_with_overflow)
int_impl!(i32 = i32, u32,
intrinsics::i32_add_with_overflow,
intrinsics::i32_sub_with_overflow,
intrinsics::i32_mul_with_overflow)
int_impl!(i64 = i64, u64,
intrinsics::i64_add_with_overflow,
intrinsics::i64_sub_with_overflow,
intrinsics::i64_mul_with_overflow)
#[cfg(target_word_size = "32")]
int_impl!(int = i32, u32,
intrinsics::i32_add_with_overflow,
intrinsics::i32_sub_with_overflow,
intrinsics::i32_mul_with_overflow)
#[cfg(target_word_size = "64")]
int_impl!(int = i64, u64,
intrinsics::i64_add_with_overflow,
intrinsics::i64_sub_with_overflow,
intrinsics::i64_mul_with_overflow)
/// Unsigned integers /// Unsigned integers
pub trait UnsignedInt: Int { pub trait UnsignedInt: Int {
@ -686,7 +843,7 @@ pub trait UnsignedInt: Int {
tmp = tmp | (tmp >> shift); tmp = tmp | (tmp >> shift);
shift = shift << 1u; shift = shift << 1u;
} }
tmp.checked_add(&one()) tmp.checked_add(one())
} }
} }
@ -1184,192 +1341,6 @@ impl_num_cast!(int, to_int)
impl_num_cast!(f32, to_f32) impl_num_cast!(f32, to_f32)
impl_num_cast!(f64, to_f64) impl_num_cast!(f64, to_f64)
/// Performs addition that returns `None` instead of wrapping around on overflow.
pub trait CheckedAdd: Add<Self, Self> {
/// Adds two numbers, checking for overflow. If overflow happens, `None` is returned.
///
/// # Example
///
/// ```rust
/// use std::num::CheckedAdd;
/// assert_eq!(5u16.checked_add(&65530), Some(65535));
/// assert_eq!(6u16.checked_add(&65530), None);
/// ```
fn checked_add(&self, v: &Self) -> Option<Self>;
}
macro_rules! checked_impl(
($trait_name:ident, $method:ident, $t:ty, $op:path) => {
impl $trait_name for $t {
#[inline]
fn $method(&self, v: &$t) -> Option<$t> {
unsafe {
let (x, y) = $op(*self, *v);
if y { None } else { Some(x) }
}
}
}
}
)
macro_rules! checked_cast_impl(
($trait_name:ident, $method:ident, $t:ty, $cast:ty, $op:path) => {
impl $trait_name for $t {
#[inline]
fn $method(&self, v: &$t) -> Option<$t> {
unsafe {
let (x, y) = $op(*self as $cast, *v as $cast);
if y { None } else { Some(x as $t) }
}
}
}
}
)
#[cfg(target_word_size = "32")]
checked_cast_impl!(CheckedAdd, checked_add, uint, u32, intrinsics::u32_add_with_overflow)
#[cfg(target_word_size = "64")]
checked_cast_impl!(CheckedAdd, checked_add, uint, u64, intrinsics::u64_add_with_overflow)
checked_impl!(CheckedAdd, checked_add, u8, intrinsics::u8_add_with_overflow)
checked_impl!(CheckedAdd, checked_add, u16, intrinsics::u16_add_with_overflow)
checked_impl!(CheckedAdd, checked_add, u32, intrinsics::u32_add_with_overflow)
checked_impl!(CheckedAdd, checked_add, u64, intrinsics::u64_add_with_overflow)
#[cfg(target_word_size = "32")]
checked_cast_impl!(CheckedAdd, checked_add, int, i32, intrinsics::i32_add_with_overflow)
#[cfg(target_word_size = "64")]
checked_cast_impl!(CheckedAdd, checked_add, int, i64, intrinsics::i64_add_with_overflow)
checked_impl!(CheckedAdd, checked_add, i8, intrinsics::i8_add_with_overflow)
checked_impl!(CheckedAdd, checked_add, i16, intrinsics::i16_add_with_overflow)
checked_impl!(CheckedAdd, checked_add, i32, intrinsics::i32_add_with_overflow)
checked_impl!(CheckedAdd, checked_add, i64, intrinsics::i64_add_with_overflow)
/// Performs subtraction that returns `None` instead of wrapping around on underflow.
pub trait CheckedSub: Sub<Self, Self> {
/// Subtracts two numbers, checking for underflow. If underflow happens, `None` is returned.
///
/// # Example
///
/// ```rust
/// use std::num::CheckedSub;
/// assert_eq!((-127i8).checked_sub(&1), Some(-128));
/// assert_eq!((-128i8).checked_sub(&1), None);
/// ```
fn checked_sub(&self, v: &Self) -> Option<Self>;
}
#[cfg(target_word_size = "32")]
checked_cast_impl!(CheckedSub, checked_sub, uint, u32, intrinsics::u32_sub_with_overflow)
#[cfg(target_word_size = "64")]
checked_cast_impl!(CheckedSub, checked_sub, uint, u64, intrinsics::u64_sub_with_overflow)
checked_impl!(CheckedSub, checked_sub, u8, intrinsics::u8_sub_with_overflow)
checked_impl!(CheckedSub, checked_sub, u16, intrinsics::u16_sub_with_overflow)
checked_impl!(CheckedSub, checked_sub, u32, intrinsics::u32_sub_with_overflow)
checked_impl!(CheckedSub, checked_sub, u64, intrinsics::u64_sub_with_overflow)
#[cfg(target_word_size = "32")]
checked_cast_impl!(CheckedSub, checked_sub, int, i32, intrinsics::i32_sub_with_overflow)
#[cfg(target_word_size = "64")]
checked_cast_impl!(CheckedSub, checked_sub, int, i64, intrinsics::i64_sub_with_overflow)
checked_impl!(CheckedSub, checked_sub, i8, intrinsics::i8_sub_with_overflow)
checked_impl!(CheckedSub, checked_sub, i16, intrinsics::i16_sub_with_overflow)
checked_impl!(CheckedSub, checked_sub, i32, intrinsics::i32_sub_with_overflow)
checked_impl!(CheckedSub, checked_sub, i64, intrinsics::i64_sub_with_overflow)
/// Performs multiplication that returns `None` instead of wrapping around on underflow or
/// overflow.
pub trait CheckedMul: Mul<Self, Self> {
/// Multiplies two numbers, checking for underflow or overflow. If underflow or overflow
/// happens, `None` is returned.
///
/// # Example
///
/// ```rust
/// use std::num::CheckedMul;
/// assert_eq!(5u8.checked_mul(&51), Some(255));
/// assert_eq!(5u8.checked_mul(&52), None);
/// ```
fn checked_mul(&self, v: &Self) -> Option<Self>;
}
#[cfg(target_word_size = "32")]
checked_cast_impl!(CheckedMul, checked_mul, uint, u32, intrinsics::u32_mul_with_overflow)
#[cfg(target_word_size = "64")]
checked_cast_impl!(CheckedMul, checked_mul, uint, u64, intrinsics::u64_mul_with_overflow)
checked_impl!(CheckedMul, checked_mul, u8, intrinsics::u8_mul_with_overflow)
checked_impl!(CheckedMul, checked_mul, u16, intrinsics::u16_mul_with_overflow)
checked_impl!(CheckedMul, checked_mul, u32, intrinsics::u32_mul_with_overflow)
checked_impl!(CheckedMul, checked_mul, u64, intrinsics::u64_mul_with_overflow)
#[cfg(target_word_size = "32")]
checked_cast_impl!(CheckedMul, checked_mul, int, i32, intrinsics::i32_mul_with_overflow)
#[cfg(target_word_size = "64")]
checked_cast_impl!(CheckedMul, checked_mul, int, i64, intrinsics::i64_mul_with_overflow)
checked_impl!(CheckedMul, checked_mul, i8, intrinsics::i8_mul_with_overflow)
checked_impl!(CheckedMul, checked_mul, i16, intrinsics::i16_mul_with_overflow)
checked_impl!(CheckedMul, checked_mul, i32, intrinsics::i32_mul_with_overflow)
checked_impl!(CheckedMul, checked_mul, i64, intrinsics::i64_mul_with_overflow)
/// Performs division that returns `None` instead of panicking on division by zero and instead of
/// wrapping around on underflow and overflow.
pub trait CheckedDiv: Div<Self, Self> {
/// Divides two numbers, checking for underflow, overflow and division by zero. If any of that
/// happens, `None` is returned.
///
/// # Example
///
/// ```rust
/// use std::num::CheckedDiv;
/// assert_eq!((-127i8).checked_div(&-1), Some(127));
/// assert_eq!((-128i8).checked_div(&-1), None);
/// assert_eq!((1i8).checked_div(&0), None);
/// ```
fn checked_div(&self, v: &Self) -> Option<Self>;
}
macro_rules! checkeddiv_int_impl(
($t:ty, $min:expr) => {
impl CheckedDiv for $t {
#[inline]
fn checked_div(&self, v: &$t) -> Option<$t> {
if *v == 0 || (*self == $min && *v == -1) {
None
} else {
Some(*self / *v)
}
}
}
}
)
checkeddiv_int_impl!(int, int::MIN)
checkeddiv_int_impl!(i8, i8::MIN)
checkeddiv_int_impl!(i16, i16::MIN)
checkeddiv_int_impl!(i32, i32::MIN)
checkeddiv_int_impl!(i64, i64::MIN)
macro_rules! checkeddiv_uint_impl(
($($t:ty)*) => ($(
impl CheckedDiv for $t {
#[inline]
fn checked_div(&self, v: &$t) -> Option<$t> {
if *v == 0 {
None
} else {
Some(*self / *v)
}
}
}
)*)
)
checkeddiv_uint_impl!(uint u8 u16 u32 u64)
/// Used for representing the classification of floating point numbers /// Used for representing the classification of floating point numbers
#[deriving(PartialEq, Show)] #[deriving(PartialEq, Show)]
pub enum FPCategory { pub enum FPCategory {

View file

@ -51,7 +51,7 @@ pub use cmp::{Ordering, Less, Equal, Greater, Equiv};
pub use iter::{FromIterator, Extend}; pub use iter::{FromIterator, Extend};
pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, CloneableIterator}; pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, CloneableIterator};
pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize}; pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize};
pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul}; pub use num::{Num, NumCast};
pub use num::{Signed, Unsigned, Float}; pub use num::{Signed, Unsigned, Float};
pub use num::{Primitive, Int, ToPrimitive, FromPrimitive}; pub use num::{Primitive, Int, ToPrimitive, FromPrimitive};
pub use option::{Option, Some, None}; pub use option::{Option, Some, None};

View file

@ -40,7 +40,7 @@ use cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering, Less, Equal, Greater, Equiv}
use cmp; use cmp;
use default::Default; use default::Default;
use iter::*; use iter::*;
use num::{CheckedAdd, Int, div_rem}; use num::{Int, div_rem};
use ops; use ops;
use option::{None, Option, Some}; use option::{None, Option, Some};
use ptr; use ptr;
@ -1346,7 +1346,7 @@ impl<'a, T> Iterator<&'a [T]> for Windows<'a, T> {
(0, Some(0)) (0, Some(0))
} else { } else {
let x = self.v.len() - self.size; let x = self.v.len() - self.size;
(x.saturating_add(1), x.checked_add(&1u)) (x.saturating_add(1), x.checked_add(1u))
} }
} }
} }

View file

@ -25,7 +25,7 @@ use iter::{Map, Iterator};
use iter::{DoubleEndedIterator, ExactSize}; use iter::{DoubleEndedIterator, ExactSize};
use iter::range; use iter::range;
use kinds::Sized; use kinds::Sized;
use num::{CheckedMul, Int}; use num::Int;
use option::{Option, None, Some}; use option::{Option, None, Some};
use raw::Repr; use raw::Repr;
use slice::{mod, SlicePrelude}; use slice::{mod, SlicePrelude};
@ -750,7 +750,7 @@ impl<'a> Iterator<u16> for Utf16CodeUnits<'a> {
// every char gets either one u16 or two u16, // every char gets either one u16 or two u16,
// so this iterator is between 1 or 2 times as // so this iterator is between 1 or 2 times as
// long as the underlying iterator. // long as the underlying iterator.
(low, high.and_then(|n| n.checked_mul(&2))) (low, high.and_then(|n| n.checked_mul(2)))
} }
} }

View file

@ -16,7 +16,6 @@ mod tests {
use core::$T_i::*; use core::$T_i::*;
use core::int; use core::int;
use num; use num;
use core::num::CheckedDiv;
#[test] #[test]
fn test_overflows() { fn test_overflows() {
@ -152,9 +151,9 @@ mod tests {
#[test] #[test]
fn test_signed_checked_div() { fn test_signed_checked_div() {
assert!(10i.checked_div(&2) == Some(5)); assert!(10i.checked_div(2) == Some(5));
assert!(5i.checked_div(&0) == None); assert!(5i.checked_div(0) == None);
assert!(int::MIN.checked_div(&-1) == None); assert!(int::MIN.checked_div(-1) == None);
} }
} }

View file

@ -15,7 +15,6 @@ macro_rules! uint_module (($T:ty, $T_i:ident) => (
mod tests { mod tests {
use core::$T_i::*; use core::$T_i::*;
use num; use num;
use core::num::CheckedDiv;
#[test] #[test]
fn test_overflows() { fn test_overflows() {
@ -120,8 +119,8 @@ mod tests {
#[test] #[test]
fn test_unsigned_checked_div() { fn test_unsigned_checked_div() {
assert!(10u.checked_div(&2) == Some(5)); assert!(10u.checked_div(2) == Some(5));
assert!(5u.checked_div(&0) == None); assert!(5u.checked_div(0) == None);
} }
} }
)) ))

View file

@ -126,7 +126,7 @@ impl<'a, T: Clone> WeightedChoice<'a, T> {
// weights so we can binary search. This *could* drop elements // weights so we can binary search. This *could* drop elements
// with weight == 0 as an optimisation. // with weight == 0 as an optimisation.
for item in items.iter_mut() { for item in items.iter_mut() {
running_total = match running_total.checked_add(&item.weight) { running_total = match running_total.checked_add(item.weight) {
Some(n) => n, Some(n) => n,
None => panic!("WeightedChoice::new called with a total weight \ None => panic!("WeightedChoice::new called with a total weight \
larger than a uint can contain") larger than a uint can contain")

View file

@ -24,15 +24,13 @@ use middle::trans::type_::Type;
use syntax::abi; use syntax::abi;
use syntax::ast; use syntax::ast;
use std::num::CheckedMul;
// LLVM doesn't like objects that are too big. Issue #17913 // LLVM doesn't like objects that are too big. Issue #17913
fn ensure_array_fits_in_address_space(ccx: &CrateContext, fn ensure_array_fits_in_address_space(ccx: &CrateContext,
llet: Type, llet: Type,
size: machine::llsize, size: machine::llsize,
scapegoat: ty::t) { scapegoat: ty::t) {
let esz = machine::llsize_of_alloc(ccx, llet); let esz = machine::llsize_of_alloc(ccx, llet);
match esz.checked_mul(&size) { match esz.checked_mul(size) {
Some(n) if n < ccx.max_obj_size() => {} Some(n) if n < ccx.max_obj_size() => {}
_ => { ccx.report_overbig_object(scapegoat) } _ => { ccx.report_overbig_object(scapegoat) }
} }

View file

@ -61,14 +61,14 @@ impl ToBits for u64 {
/// Adds the specified number of bytes to the bit count. panic!() if this would cause numeric /// Adds the specified number of bytes to the bit count. panic!() if this would cause numeric
/// overflow. /// overflow.
fn add_bytes_to_bits<T: Int + CheckedAdd + ToBits>(bits: T, bytes: T) -> T { fn add_bytes_to_bits<T: Int + ToBits>(bits: T, bytes: T) -> T {
let (new_high_bits, new_low_bits) = bytes.to_bits(); let (new_high_bits, new_low_bits) = bytes.to_bits();
if new_high_bits > Zero::zero() { if new_high_bits > Zero::zero() {
panic!("numeric overflow occurred.") panic!("numeric overflow occurred.")
} }
match bits.checked_add(&new_low_bits) { match bits.checked_add(new_low_bits) {
Some(x) => return x, Some(x) => return x,
None => panic!("numeric overflow occurred.") None => panic!("numeric overflow occurred.")
} }

View file

@ -609,7 +609,7 @@ impl<'a> PrettyEncoder<'a> {
/// This is safe to set during encoding. /// This is safe to set during encoding.
pub fn set_indent<'a>(&mut self, indent: uint) { pub fn set_indent<'a>(&mut self, indent: uint) {
// self.indent very well could be 0 so we need to use checked division. // self.indent very well could be 0 so we need to use checked division.
let level = self.curr_indent.checked_div(&self.indent).unwrap_or(0); let level = self.curr_indent.checked_div(self.indent).unwrap_or(0);
self.indent = indent; self.indent = indent;
self.curr_indent = level * self.indent; self.curr_indent = level * self.indent;
} }

View file

@ -17,7 +17,7 @@ use iter::{Iterator, count};
use kinds::{Sized, marker}; use kinds::{Sized, marker};
use mem::{min_align_of, size_of}; use mem::{min_align_of, size_of};
use mem; use mem;
use num::{CheckedAdd, CheckedMul, UnsignedInt}; use num::{Int, UnsignedInt};
use ops::{Deref, DerefMut, Drop}; use ops::{Deref, DerefMut, Drop};
use option::{Some, None, Option}; use option::{Some, None, Option};
use ptr::{RawPtr, copy_nonoverlapping_memory, zero_memory}; use ptr::{RawPtr, copy_nonoverlapping_memory, zero_memory};
@ -604,9 +604,9 @@ impl<K, V> RawTable<K, V> {
vals_size, min_align_of::< V >()); vals_size, min_align_of::< V >());
// One check for overflow that covers calculation and rounding of size. // One check for overflow that covers calculation and rounding of size.
let size_of_bucket = size_of::<u64>().checked_add(&size_of::<K>()).unwrap() let size_of_bucket = size_of::<u64>().checked_add(size_of::<K>()).unwrap()
.checked_add(&size_of::<V>()).unwrap(); .checked_add(size_of::<V>()).unwrap();
assert!(size >= capacity.checked_mul(&size_of_bucket) assert!(size >= capacity.checked_mul(size_of_bucket)
.expect("capacity overflow"), .expect("capacity overflow"),
"capacity overflow"); "capacity overflow");

View file

@ -24,7 +24,6 @@ pub use core::num::{Num, div_rem, Zero, zero, One, one};
pub use core::num::{Signed, abs, signum}; pub use core::num::{Signed, abs, signum};
pub use core::num::{Unsigned, pow, Bounded}; pub use core::num::{Unsigned, pow, Bounded};
pub use core::num::{Primitive, Int, UnsignedInt}; pub use core::num::{Primitive, Int, UnsignedInt};
pub use core::num::{CheckedAdd, CheckedSub, CheckedMul, CheckedDiv};
pub use core::num::{cast, FromPrimitive, NumCast, ToPrimitive}; pub use core::num::{cast, FromPrimitive, NumCast, ToPrimitive};
pub use core::num::{next_power_of_two, is_power_of_two}; pub use core::num::{next_power_of_two, is_power_of_two};
pub use core::num::{checked_next_power_of_two}; pub use core::num::{checked_next_power_of_two};
@ -636,36 +635,36 @@ mod tests {
#[test] #[test]
fn test_checked_add() { fn test_checked_add() {
let five_less = uint::MAX - 5; let five_less = uint::MAX - 5;
assert_eq!(five_less.checked_add(&0), Some(uint::MAX - 5)); assert_eq!(five_less.checked_add(0), Some(uint::MAX - 5));
assert_eq!(five_less.checked_add(&1), Some(uint::MAX - 4)); assert_eq!(five_less.checked_add(1), Some(uint::MAX - 4));
assert_eq!(five_less.checked_add(&2), Some(uint::MAX - 3)); assert_eq!(five_less.checked_add(2), Some(uint::MAX - 3));
assert_eq!(five_less.checked_add(&3), Some(uint::MAX - 2)); assert_eq!(five_less.checked_add(3), Some(uint::MAX - 2));
assert_eq!(five_less.checked_add(&4), Some(uint::MAX - 1)); assert_eq!(five_less.checked_add(4), Some(uint::MAX - 1));
assert_eq!(five_less.checked_add(&5), Some(uint::MAX)); assert_eq!(five_less.checked_add(5), Some(uint::MAX));
assert_eq!(five_less.checked_add(&6), None); assert_eq!(five_less.checked_add(6), None);
assert_eq!(five_less.checked_add(&7), None); assert_eq!(five_less.checked_add(7), None);
} }
#[test] #[test]
fn test_checked_sub() { fn test_checked_sub() {
assert_eq!(5u.checked_sub(&0), Some(5)); assert_eq!(5u.checked_sub(0), Some(5));
assert_eq!(5u.checked_sub(&1), Some(4)); assert_eq!(5u.checked_sub(1), Some(4));
assert_eq!(5u.checked_sub(&2), Some(3)); assert_eq!(5u.checked_sub(2), Some(3));
assert_eq!(5u.checked_sub(&3), Some(2)); assert_eq!(5u.checked_sub(3), Some(2));
assert_eq!(5u.checked_sub(&4), Some(1)); assert_eq!(5u.checked_sub(4), Some(1));
assert_eq!(5u.checked_sub(&5), Some(0)); assert_eq!(5u.checked_sub(5), Some(0));
assert_eq!(5u.checked_sub(&6), None); assert_eq!(5u.checked_sub(6), None);
assert_eq!(5u.checked_sub(&7), None); assert_eq!(5u.checked_sub(7), None);
} }
#[test] #[test]
fn test_checked_mul() { fn test_checked_mul() {
let third = uint::MAX / 3; let third = uint::MAX / 3;
assert_eq!(third.checked_mul(&0), Some(0)); assert_eq!(third.checked_mul(0), Some(0));
assert_eq!(third.checked_mul(&1), Some(third)); assert_eq!(third.checked_mul(1), Some(third));
assert_eq!(third.checked_mul(&2), Some(third * 2)); assert_eq!(third.checked_mul(2), Some(third * 2));
assert_eq!(third.checked_mul(&3), Some(third * 3)); assert_eq!(third.checked_mul(3), Some(third * 3));
assert_eq!(third.checked_mul(&4), None); assert_eq!(third.checked_mul(4), None);
} }
macro_rules! test_next_power_of_two( macro_rules! test_next_power_of_two(

View file

@ -601,11 +601,11 @@ pub fn from_str_radix_int<T: Int>(src: &str, radix: uint) -> Option<T> {
Some(x) => x, Some(x) => x,
None => return None, None => return None,
}; };
result = match result.checked_mul(&radix) { result = match result.checked_mul(radix) {
Some(result) => result, Some(result) => result,
None => return None, None => return None,
}; };
result = match result.checked_add(&x) { result = match result.checked_add(x) {
Some(result) => result, Some(result) => result,
None => return None, None => return None,
}; };
@ -616,11 +616,11 @@ pub fn from_str_radix_int<T: Int>(src: &str, radix: uint) -> Option<T> {
Some(x) => x, Some(x) => x,
None => return None, None => return None,
}; };
result = match result.checked_mul(&radix) { result = match result.checked_mul(radix) {
Some(result) => result, Some(result) => result,
None => return None, None => return None,
}; };
result = match result.checked_sub(&x) { result = match result.checked_sub(x) {
Some(result) => result, Some(result) => result,
None => return None, None => return None,
}; };

View file

@ -67,7 +67,7 @@
#[doc(no_inline)] pub use iter::{Iterator, DoubleEndedIterator}; #[doc(no_inline)] pub use iter::{Iterator, DoubleEndedIterator};
#[doc(no_inline)] pub use iter::{RandomAccessIterator, CloneableIterator}; #[doc(no_inline)] pub use iter::{RandomAccessIterator, CloneableIterator};
#[doc(no_inline)] pub use iter::{OrdIterator, MutableDoubleEndedIterator}; #[doc(no_inline)] pub use iter::{OrdIterator, MutableDoubleEndedIterator};
#[doc(no_inline)] pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv}; #[doc(no_inline)] pub use num::{Num, NumCast};
#[doc(no_inline)] pub use num::{Signed, Unsigned, Primitive, Int, Float}; #[doc(no_inline)] pub use num::{Signed, Unsigned, Primitive, Int, Float};
#[doc(no_inline)] pub use num::{FloatMath, ToPrimitive, FromPrimitive}; #[doc(no_inline)] pub use num::{FloatMath, ToPrimitive, FromPrimitive};
#[doc(no_inline)] pub use boxed::Box; #[doc(no_inline)] pub use boxed::Box;

View file

@ -15,8 +15,7 @@
use {fmt, i64}; use {fmt, i64};
use ops::{Add, Sub, Mul, Div, Neg}; use ops::{Add, Sub, Mul, Div, Neg};
use option::{Option, Some, None}; use option::{Option, Some, None};
use num; use num::Int;
use num::{CheckedAdd, CheckedMul};
use result::{Result, Ok, Err}; use result::{Result, Ok, Err};
/// The number of nanoseconds in a microsecond. /// The number of nanoseconds in a microsecond.
@ -69,7 +68,7 @@ impl Duration {
/// Fails when the duration is out of bounds. /// Fails when the duration is out of bounds.
#[inline] #[inline]
pub fn weeks(weeks: i64) -> Duration { pub fn weeks(weeks: i64) -> Duration {
let secs = weeks.checked_mul(&SECS_PER_WEEK).expect("Duration::weeks out of bounds"); let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds");
Duration::seconds(secs) Duration::seconds(secs)
} }
@ -78,7 +77,7 @@ impl Duration {
/// Fails when the duration is out of bounds. /// Fails when the duration is out of bounds.
#[inline] #[inline]
pub fn days(days: i64) -> Duration { pub fn days(days: i64) -> Duration {
let secs = days.checked_mul(&SECS_PER_DAY).expect("Duration::days out of bounds"); let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds");
Duration::seconds(secs) Duration::seconds(secs)
} }
@ -87,7 +86,7 @@ impl Duration {
/// Fails when the duration is out of bounds. /// Fails when the duration is out of bounds.
#[inline] #[inline]
pub fn hours(hours: i64) -> Duration { pub fn hours(hours: i64) -> Duration {
let secs = hours.checked_mul(&SECS_PER_HOUR).expect("Duration::hours ouf of bounds"); let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds");
Duration::seconds(secs) Duration::seconds(secs)
} }
@ -96,7 +95,7 @@ impl Duration {
/// Fails when the duration is out of bounds. /// Fails when the duration is out of bounds.
#[inline] #[inline]
pub fn minutes(minutes: i64) -> Duration { pub fn minutes(minutes: i64) -> Duration {
let secs = minutes.checked_mul(&SECS_PER_MINUTE).expect("Duration::minutes out of bounds"); let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds");
Duration::seconds(secs) Duration::seconds(secs)
} }
@ -191,33 +190,64 @@ impl Duration {
/// Returns the total number of whole microseconds in the duration, /// Returns the total number of whole microseconds in the duration,
/// or `None` on overflow (exceeding 2^63 microseconds in either direction). /// or `None` on overflow (exceeding 2^63 microseconds in either direction).
pub fn num_microseconds(&self) -> Option<i64> { pub fn num_microseconds(&self) -> Option<i64> {
let secs_part = try_opt!(self.num_seconds().checked_mul(&MICROS_PER_SEC)); let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC));
let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO; let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO;
secs_part.checked_add(&(nanos_part as i64)) secs_part.checked_add(nanos_part as i64)
} }
/// Returns the total number of whole nanoseconds in the duration, /// Returns the total number of whole nanoseconds in the duration,
/// or `None` on overflow (exceeding 2^63 nanoseconds in either direction). /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
pub fn num_nanoseconds(&self) -> Option<i64> { pub fn num_nanoseconds(&self) -> Option<i64> {
let secs_part = try_opt!(self.num_seconds().checked_mul(&(NANOS_PER_SEC as i64))); let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64));
let nanos_part = self.nanos_mod_sec(); let nanos_part = self.nanos_mod_sec();
secs_part.checked_add(&(nanos_part as i64)) secs_part.checked_add(nanos_part as i64)
} }
}
impl num::Bounded for Duration { /// Add two durations, returning `None` if overflow occured.
#[inline] fn min_value() -> Duration { MIN } pub fn checked_add(&self, rhs: &Duration) -> Option<Duration> {
#[inline] fn max_value() -> Duration { MAX } let mut secs = try_opt!(self.secs.checked_add(rhs.secs));
} let mut nanos = self.nanos + rhs.nanos;
if nanos >= NANOS_PER_SEC {
nanos -= NANOS_PER_SEC;
secs = try_opt!(secs.checked_add(1));
}
let d = Duration { secs: secs, nanos: nanos };
// Even if d is within the bounds of i64 seconds,
// it might still overflow i64 milliseconds.
if d < MIN || d > MAX { None } else { Some(d) }
}
impl num::Zero for Duration { /// Subtract two durations, returning `None` if overflow occured.
pub fn checked_sub(&self, rhs: &Duration) -> Option<Duration> {
let mut secs = try_opt!(self.secs.checked_sub(rhs.secs));
let mut nanos = self.nanos - rhs.nanos;
if nanos < 0 {
nanos += NANOS_PER_SEC;
secs = try_opt!(secs.checked_sub(1));
}
let d = Duration { secs: secs, nanos: nanos };
// Even if d is within the bounds of i64 seconds,
// it might still overflow i64 milliseconds.
if d < MIN || d > MAX { None } else { Some(d) }
}
/// The minimum possible `Duration`: `i64::MIN` milliseconds.
#[inline] #[inline]
fn zero() -> Duration { pub fn min_value() -> Duration { MIN }
/// The maximum possible `Duration`: `i64::MAX` milliseconds.
#[inline]
pub fn max_value() -> Duration { MAX }
/// A duration where the stored seconds and nanoseconds are equal to zero.
#[inline]
pub fn zero() -> Duration {
Duration { secs: 0, nanos: 0 } Duration { secs: 0, nanos: 0 }
} }
/// Returns `true` if the duration equals `Duration::zero()`.
#[inline] #[inline]
fn is_zero(&self) -> bool { pub fn is_zero(&self) -> bool {
self.secs == 0 && self.nanos == 0 self.secs == 0 && self.nanos == 0
} }
} }
@ -245,21 +275,6 @@ impl Add<Duration,Duration> for Duration {
} }
} }
impl num::CheckedAdd for Duration {
fn checked_add(&self, rhs: &Duration) -> Option<Duration> {
let mut secs = try_opt!(self.secs.checked_add(&rhs.secs));
let mut nanos = self.nanos + rhs.nanos;
if nanos >= NANOS_PER_SEC {
nanos -= NANOS_PER_SEC;
secs = try_opt!(secs.checked_add(&1));
}
let d = Duration { secs: secs, nanos: nanos };
// Even if d is within the bounds of i64 seconds,
// it might still overflow i64 milliseconds.
if d < MIN || d > MAX { None } else { Some(d) }
}
}
impl Sub<Duration,Duration> for Duration { impl Sub<Duration,Duration> for Duration {
fn sub(&self, rhs: &Duration) -> Duration { fn sub(&self, rhs: &Duration) -> Duration {
let mut secs = self.secs - rhs.secs; let mut secs = self.secs - rhs.secs;
@ -272,21 +287,6 @@ impl Sub<Duration,Duration> for Duration {
} }
} }
impl num::CheckedSub for Duration {
fn checked_sub(&self, rhs: &Duration) -> Option<Duration> {
let mut secs = try_opt!(self.secs.checked_sub(&rhs.secs));
let mut nanos = self.nanos - rhs.nanos;
if nanos < 0 {
nanos += NANOS_PER_SEC;
secs = try_opt!(secs.checked_sub(&1));
}
let d = Duration { secs: secs, nanos: nanos };
// Even if d is within the bounds of i64 seconds,
// it might still overflow i64 milliseconds.
if d < MIN || d > MAX { None } else { Some(d) }
}
}
impl Mul<i32,Duration> for Duration { impl Mul<i32,Duration> for Duration {
fn mul(&self, rhs: &i32) -> Duration { fn mul(&self, rhs: &i32) -> Duration {
// Multiply nanoseconds as i64, because it cannot overflow that way. // Multiply nanoseconds as i64, because it cannot overflow that way.
@ -379,15 +379,12 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
mod tests { mod tests {
use super::{Duration, MIN, MAX}; use super::{Duration, MIN, MAX};
use {i32, i64}; use {i32, i64};
use num::{Zero, CheckedAdd, CheckedSub};
use option::{Some, None}; use option::{Some, None};
use to_string::ToString; use to_string::ToString;
#[test] #[test]
fn test_duration() { fn test_duration() {
let d: Duration = Zero::zero(); assert!(Duration::seconds(1) != Duration::zero());
assert_eq!(d, Zero::zero());
assert!(Duration::seconds(1) != Zero::zero());
assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3)); assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3));
assert_eq!(Duration::seconds(86399) + Duration::seconds(4), assert_eq!(Duration::seconds(86399) + Duration::seconds(4),
Duration::days(1) + Duration::seconds(3)); Duration::days(1) + Duration::seconds(3));
@ -403,8 +400,7 @@ mod tests {
#[test] #[test]
fn test_duration_num_days() { fn test_duration_num_days() {
let d: Duration = Zero::zero(); assert_eq!(Duration::zero().num_days(), 0);
assert_eq!(d.num_days(), 0);
assert_eq!(Duration::days(1).num_days(), 1); assert_eq!(Duration::days(1).num_days(), 1);
assert_eq!(Duration::days(-1).num_days(), -1); assert_eq!(Duration::days(-1).num_days(), -1);
assert_eq!(Duration::seconds(86399).num_days(), 0); assert_eq!(Duration::seconds(86399).num_days(), 0);
@ -417,8 +413,7 @@ mod tests {
#[test] #[test]
fn test_duration_num_seconds() { fn test_duration_num_seconds() {
let d: Duration = Zero::zero(); assert_eq!(Duration::zero().num_seconds(), 0);
assert_eq!(d.num_seconds(), 0);
assert_eq!(Duration::seconds(1).num_seconds(), 1); assert_eq!(Duration::seconds(1).num_seconds(), 1);
assert_eq!(Duration::seconds(-1).num_seconds(), -1); assert_eq!(Duration::seconds(-1).num_seconds(), -1);
assert_eq!(Duration::milliseconds(999).num_seconds(), 0); assert_eq!(Duration::milliseconds(999).num_seconds(), 0);
@ -429,8 +424,7 @@ mod tests {
#[test] #[test]
fn test_duration_num_milliseconds() { fn test_duration_num_milliseconds() {
let d: Duration = Zero::zero(); assert_eq!(Duration::zero().num_milliseconds(), 0);
assert_eq!(d.num_milliseconds(), 0);
assert_eq!(Duration::milliseconds(1).num_milliseconds(), 1); assert_eq!(Duration::milliseconds(1).num_milliseconds(), 1);
assert_eq!(Duration::milliseconds(-1).num_milliseconds(), -1); assert_eq!(Duration::milliseconds(-1).num_milliseconds(), -1);
assert_eq!(Duration::microseconds(999).num_milliseconds(), 0); assert_eq!(Duration::microseconds(999).num_milliseconds(), 0);
@ -445,8 +439,7 @@ mod tests {
#[test] #[test]
fn test_duration_num_microseconds() { fn test_duration_num_microseconds() {
let d: Duration = Zero::zero(); assert_eq!(Duration::zero().num_microseconds(), Some(0));
assert_eq!(d.num_microseconds(), Some(0));
assert_eq!(Duration::microseconds(1).num_microseconds(), Some(1)); assert_eq!(Duration::microseconds(1).num_microseconds(), Some(1));
assert_eq!(Duration::microseconds(-1).num_microseconds(), Some(-1)); assert_eq!(Duration::microseconds(-1).num_microseconds(), Some(-1));
assert_eq!(Duration::nanoseconds(999).num_microseconds(), Some(0)); assert_eq!(Duration::nanoseconds(999).num_microseconds(), Some(0));
@ -470,8 +463,7 @@ mod tests {
#[test] #[test]
fn test_duration_num_nanoseconds() { fn test_duration_num_nanoseconds() {
let d: Duration = Zero::zero(); assert_eq!(Duration::zero().num_nanoseconds(), Some(0));
assert_eq!(d.num_nanoseconds(), Some(0));
assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1)); assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1));
assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1)); assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1));
assert_eq!(Duration::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX)); assert_eq!(Duration::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX));
@ -504,10 +496,9 @@ mod tests {
#[test] #[test]
fn test_duration_mul() { fn test_duration_mul() {
let d: Duration = Zero::zero(); assert_eq!(Duration::zero() * i32::MAX, Duration::zero());
assert_eq!(d * i32::MAX, d); assert_eq!(Duration::zero() * i32::MIN, Duration::zero());
assert_eq!(d * i32::MIN, d); assert_eq!(Duration::nanoseconds(1) * 0, Duration::zero());
assert_eq!(Duration::nanoseconds(1) * 0, Zero::zero());
assert_eq!(Duration::nanoseconds(1) * 1, Duration::nanoseconds(1)); assert_eq!(Duration::nanoseconds(1) * 1, Duration::nanoseconds(1));
assert_eq!(Duration::nanoseconds(1) * 1_000_000_000, Duration::seconds(1)); assert_eq!(Duration::nanoseconds(1) * 1_000_000_000, Duration::seconds(1));
assert_eq!(Duration::nanoseconds(1) * -1_000_000_000, -Duration::seconds(1)); assert_eq!(Duration::nanoseconds(1) * -1_000_000_000, -Duration::seconds(1));
@ -522,9 +513,8 @@ mod tests {
#[test] #[test]
fn test_duration_div() { fn test_duration_div() {
let d: Duration = Zero::zero(); assert_eq!(Duration::zero() / i32::MAX, Duration::zero());
assert_eq!(d / i32::MAX, d); assert_eq!(Duration::zero() / i32::MIN, Duration::zero());
assert_eq!(d / i32::MIN, d);
assert_eq!(Duration::nanoseconds(123_456_789) / 1, Duration::nanoseconds(123_456_789)); assert_eq!(Duration::nanoseconds(123_456_789) / 1, Duration::nanoseconds(123_456_789));
assert_eq!(Duration::nanoseconds(123_456_789) / -1, -Duration::nanoseconds(123_456_789)); assert_eq!(Duration::nanoseconds(123_456_789) / -1, -Duration::nanoseconds(123_456_789));
assert_eq!(-Duration::nanoseconds(123_456_789) / -1, Duration::nanoseconds(123_456_789)); assert_eq!(-Duration::nanoseconds(123_456_789) / -1, Duration::nanoseconds(123_456_789));
@ -540,8 +530,7 @@ mod tests {
#[test] #[test]
fn test_duration_fmt() { fn test_duration_fmt() {
let d: Duration = Zero::zero(); assert_eq!(Duration::zero().to_string(), "PT0S".to_string());
assert_eq!(d.to_string(), "PT0S".to_string());
assert_eq!(Duration::days(42).to_string(), "P42D".to_string()); assert_eq!(Duration::days(42).to_string(), "P42D".to_string());
assert_eq!(Duration::days(-42).to_string(), "-P42D".to_string()); assert_eq!(Duration::days(-42).to_string(), "-P42D".to_string());
assert_eq!(Duration::seconds(42).to_string(), "PT42S".to_string()); assert_eq!(Duration::seconds(42).to_string(), "PT42S".to_string());

View file

@ -63,7 +63,7 @@ impl ParseSess {
pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId { pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId {
let v = self.node_id.get(); let v = self.node_id.get();
match v.checked_add(&count) { match v.checked_add(count) {
Some(next) => { self.node_id.set(next); } Some(next) => { self.node_id.set(next); }
None => panic!("Input too large, ran out of node ids!") None => panic!("Input too large, ran out of node ids!")
} }