diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index e7efd9728b94a..aefed1890fef8 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -68,11 +68,9 @@ macro_rules! step_impl_unsigned { issue = "42168")] impl Step for $t { #[inline] - #[allow(trivial_numeric_casts)] fn steps_between(start: &$t, end: &$t) -> Option { if *start < *end { - // Note: We assume $t <= usize here - Some((*end - *start) as usize) + usize::try_from(*end - *start).ok() } else { Some(0) } @@ -98,13 +96,11 @@ macro_rules! step_impl_signed { issue = "42168")] impl Step for $t { #[inline] - #[allow(trivial_numeric_casts)] fn steps_between(start: &$t, end: &$t) -> Option { if *start < *end { - // Note: We assume $t <= isize here - // Use .wrapping_sub and cast to usize to compute the - // difference that may not fit inside the range of isize. - Some((*end as isize).wrapping_sub(*start as isize) as usize) + // Use .wrapping_sub and cast to unsigned to compute the + // difference that may not fit inside the range of $t. + usize::try_from(end.wrapping_sub(*start) as $unsigned).ok() } else { Some(0) } @@ -134,46 +130,9 @@ macro_rules! step_impl_signed { )*) } -macro_rules! step_impl_no_between { - ($($t:ty)*) => ($( - #[unstable(feature = "step_trait", - reason = "likely to be replaced by finer-grained traits", - issue = "42168")] - impl Step for $t { - #[inline] - fn steps_between(_start: &Self, _end: &Self) -> Option { - None - } - - #[inline] - fn add_usize(&self, n: usize) -> Option { - self.checked_add(n as $t) - } - - step_identical_methods!(); - } - )*) -} - -step_impl_unsigned!(usize u8 u16); -#[cfg(not(target_pointer_width = "16"))] -step_impl_unsigned!(u32); -#[cfg(target_pointer_width = "16")] -step_impl_no_between!(u32); +step_impl_unsigned!(usize u8 u16 u32 u64 u128); step_impl_signed!([isize: usize] [i8: u8] [i16: u16]); -#[cfg(not(target_pointer_width = "16"))] -step_impl_signed!([i32: u32]); -#[cfg(target_pointer_width = "16")] -step_impl_no_between!(i32); -#[cfg(target_pointer_width = "64")] -step_impl_unsigned!(u64); -#[cfg(target_pointer_width = "64")] -step_impl_signed!([i64: u64]); -// If the target pointer width is not 64-bits, we -// assume here that it is less than 64-bits. -#[cfg(not(target_pointer_width = "64"))] -step_impl_no_between!(u64 i64); -step_impl_no_between!(u128 i128); +step_impl_signed!([i32: u32] [i64: u64] [i128: u128]); macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( @@ -229,7 +188,7 @@ impl Iterator for ops::Range { fn size_hint(&self) -> (usize, Option) { match Step::steps_between(&self.start, &self.end) { Some(hint) => (hint, Some(hint)), - None => (0, None) + None => (usize::MAX, None) } } @@ -273,8 +232,8 @@ range_incl_exact_iter_impl!(u8 u16 i8 i16); // // They need to guarantee that .size_hint() is either exact, or that // the upper bound is None when it does not fit the type limits. -range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64); -range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64); +range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 u64 i64 u128 i128); +range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 u64 i64 u128 i128); #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for ops::Range { @@ -350,7 +309,7 @@ impl Iterator for ops::RangeInclusive { match Step::steps_between(&self.start, &self.end) { Some(hint) => (hint.saturating_add(1), hint.checked_add(1)), - None => (0, None), + None => (usize::MAX, None), } } diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index a3f0b02e2fe33..d5b581d336d2f 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1,4 +1,5 @@ use core::cell::Cell; +use core::convert::TryFrom; use core::iter::*; use core::{i8, i16, isize}; use core::usize; @@ -1800,6 +1801,66 @@ fn test_range_inclusive_folds() { assert!(it.is_empty()); } +#[test] +fn test_range_size_hint() { + use core::usize::MAX as UMAX; + assert_eq!((0..0usize).size_hint(), (0, Some(0))); + assert_eq!((0..100usize).size_hint(), (100, Some(100))); + assert_eq!((0..UMAX).size_hint(), (UMAX, Some(UMAX))); + + let umax = u128::try_from(UMAX).unwrap(); + assert_eq!((0..0u128).size_hint(), (0, Some(0))); + assert_eq!((0..100u128).size_hint(), (100, Some(100))); + assert_eq!((0..umax).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((0..umax + 1).size_hint(), (UMAX, None)); + + use core::isize::{MAX as IMAX, MIN as IMIN}; + assert_eq!((0..0isize).size_hint(), (0, Some(0))); + assert_eq!((-100..100isize).size_hint(), (200, Some(200))); + assert_eq!((IMIN..IMAX).size_hint(), (UMAX, Some(UMAX))); + + let imin = i128::try_from(IMIN).unwrap(); + let imax = i128::try_from(IMAX).unwrap(); + assert_eq!((0..0i128).size_hint(), (0, Some(0))); + assert_eq!((-100..100i128).size_hint(), (200, Some(200))); + assert_eq!((imin..imax).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((imin..imax + 1).size_hint(), (UMAX, None)); +} + +#[test] +fn test_range_inclusive_size_hint() { + use core::usize::MAX as UMAX; + assert_eq!((1..=0usize).size_hint(), (0, Some(0))); + assert_eq!((0..=0usize).size_hint(), (1, Some(1))); + assert_eq!((0..=100usize).size_hint(), (101, Some(101))); + assert_eq!((0..=UMAX - 1).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((0..=UMAX).size_hint(), (UMAX, None)); + + let umax = u128::try_from(UMAX).unwrap(); + assert_eq!((1..=0u128).size_hint(), (0, Some(0))); + assert_eq!((0..=0u128).size_hint(), (1, Some(1))); + assert_eq!((0..=100u128).size_hint(), (101, Some(101))); + assert_eq!((0..=umax - 1).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((0..=umax).size_hint(), (UMAX, None)); + assert_eq!((0..=umax + 1).size_hint(), (UMAX, None)); + + use core::isize::{MAX as IMAX, MIN as IMIN}; + assert_eq!((0..=-1isize).size_hint(), (0, Some(0))); + assert_eq!((0..=0isize).size_hint(), (1, Some(1))); + assert_eq!((-100..=100isize).size_hint(), (201, Some(201))); + assert_eq!((IMIN..=IMAX - 1).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((IMIN..=IMAX).size_hint(), (UMAX, None)); + + let imin = i128::try_from(IMIN).unwrap(); + let imax = i128::try_from(IMAX).unwrap(); + assert_eq!((0..=-1i128).size_hint(), (0, Some(0))); + assert_eq!((0..=0i128).size_hint(), (1, Some(1))); + assert_eq!((-100..=100i128).size_hint(), (201, Some(201))); + assert_eq!((imin..=imax - 1).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((imin..=imax).size_hint(), (UMAX, None)); + assert_eq!((imin..=imax + 1).size_hint(), (UMAX, None)); +} + #[test] fn test_repeat() { let mut it = repeat(42);