diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 96302acb8d9..1f5ef6be0bc 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -4375,95 +4375,6 @@ impl Iterator for StepBy> where } } -/// An iterator over the range [start, stop] -#[derive(Clone)] -#[unstable(feature = "range_inclusive", - reason = "likely to be replaced by range notation and adapters", - issue = "27777")] -#[rustc_deprecated(since = "1.5.0", reason = "replaced with ... syntax")] -#[allow(deprecated)] -pub struct RangeInclusive { - range: ops::Range, - done: bool, -} - -/// Returns an iterator over the range [start, stop]. -#[inline] -#[unstable(feature = "range_inclusive", - reason = "likely to be replaced by range notation and adapters", - issue = "27777")] -#[rustc_deprecated(since = "1.5.0", reason = "replaced with ... syntax")] -#[allow(deprecated)] -pub fn range_inclusive(start: A, stop: A) -> RangeInclusive - where A: Step + One + Clone -{ - RangeInclusive { - range: start..stop, - done: false, - } -} - -#[unstable(feature = "range_inclusive", - reason = "likely to be replaced by range notation and adapters", - issue = "27777")] -#[rustc_deprecated(since = "1.5.0", reason = "replaced with ... syntax")] -#[allow(deprecated)] -impl Iterator for RangeInclusive where - A: PartialEq + Step + One + Clone, - for<'a> &'a A: Add<&'a A, Output = A> -{ - type Item = A; - - #[inline] - fn next(&mut self) -> Option { - self.range.next().or_else(|| { - if !self.done && self.range.start == self.range.end { - self.done = true; - Some(self.range.end.clone()) - } else { - None - } - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (lo, hi) = self.range.size_hint(); - if self.done { - (lo, hi) - } else { - let lo = lo.saturating_add(1); - let hi = hi.and_then(|x| x.checked_add(1)); - (lo, hi) - } - } -} - -#[unstable(feature = "range_inclusive", - reason = "likely to be replaced by range notation and adapters", - issue = "27777")] -#[rustc_deprecated(since = "1.5.0", reason = "replaced with ... syntax")] -#[allow(deprecated)] -impl DoubleEndedIterator for RangeInclusive where - A: PartialEq + Step + One + Clone, - for<'a> &'a A: Add<&'a A, Output = A>, - for<'a> &'a A: Sub -{ - #[inline] - fn next_back(&mut self) -> Option { - if self.range.end > self.range.start { - let result = self.range.end.clone(); - self.range.end = &self.range.end - &A::one(); - Some(result) - } else if !self.done && self.range.start == self.range.end { - self.done = true; - Some(self.range.end.clone()) - } else { - None - } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for StepBy> { type Item = A; @@ -4505,6 +4416,9 @@ macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for ops::Range<$t> { } + + #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] + impl ExactSizeIterator for ops::RangeInclusive<$t> { } )*) } @@ -4568,6 +4482,99 @@ impl Iterator for ops::RangeFrom where } } +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl Iterator for ops::RangeInclusive where + for<'a> &'a A: Add<&'a A, Output = A> +{ + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + use ops::RangeInclusive::*; + + // this function has a sort of odd structure due to borrowck issues + // we may need to replace self, so borrows of self.start and self.end need to end early + + let (finishing, n) = match *self { + Empty { .. } => (None, None), // empty iterators yield no values + + NonEmpty { ref mut start, ref mut end } => { + let one = A::one(); + if start <= end { + let mut n = &*start + &one; + mem::swap(&mut n, start); + + // if the iterator is done iterating, it will change from NonEmpty to Empty + // to avoid unnecessary drops or clones, we'll reuse either start or end + // (they are equal now, so it doesn't matter which) + // to pull out end, we need to swap something back in -- use the previously + // created A::one() as a dummy value + + (if n == *end { Some(mem::replace(end, one)) } else { None }, + // ^ are we done yet? + Some(n)) // < the value to output + } else { + (Some(mem::replace(start, one)), None) + } + } + }; + + // turn into an empty iterator if this is the last value + if let Some(end) = finishing { + *self = Empty { at: end }; + } + + n + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + use ops::RangeInclusive::*; + + match *self { + Empty { .. } => (0, Some(0)), + + NonEmpty { ref start, ref end } => + match Step::steps_between(start, end, &A::one()) { + Some(hint) => (hint.saturating_add(1), hint.checked_add(1)), + None => (0, None), + } + } + } +} + +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl DoubleEndedIterator for ops::RangeInclusive where + for<'a> &'a A: Add<&'a A, Output = A>, + for<'a> &'a A: Sub<&'a A, Output = A> +{ + #[inline] + fn next_back(&mut self) -> Option { + use ops::RangeInclusive::*; + + // see Iterator::next for comments + + let (finishing, n) = match *self { + Empty { .. } => return None, + + NonEmpty { ref mut start, ref mut end } => { + let one = A::one(); + let mut n = &*end - &one; + mem::swap(&mut n, end); + + (if n == *start { Some(mem::replace(start, one)) } else { None }, + n) + } + }; + + if let Some(start) = finishing { + *self = Empty { at: start }; + } + + Some(n) + } +} + /// An iterator that repeats an element endlessly. /// /// This `struct` is created by the [`repeat()`] function. See its documentation for more. diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index d1c5b175bb0..cf8f4279a1d 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -67,8 +67,11 @@ #![stable(feature = "rust1", since = "1.0.0")] -use marker::{Sized, Unsize}; +use cmp::PartialOrd; use fmt; +use convert::From; +use marker::{Sized, Unsize}; +use num::One; /// The `Drop` trait is used to run some code when a value goes out of scope. /// This is sometimes called a 'destructor'. @@ -1530,6 +1533,73 @@ impl fmt::Debug for RangeTo { } } +/// An inclusive range which is bounded at both ends. +#[derive(Copy, Clone, PartialEq, Eq)] +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +pub enum RangeInclusive { + /// Empty range (iteration has finished) + Empty { + /// The point at which iteration finished + at: Idx + }, + /// Non-empty range (iteration will yield value(s)) + NonEmpty { + /// The lower bound of the range (inclusive). + start: Idx, + /// The upper bound of the range (inclusive). + end: Idx, + }, +} + +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl fmt::Debug for RangeInclusive { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + use self::RangeInclusive::*; + + match *self { + Empty { ref at } => write!(fmt, "[empty range @ {:?}]", at), + NonEmpty { ref start, ref end } => write!(fmt, "{:?}...{:?}", start, end), + } + } +} + +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl> From> for RangeInclusive { + fn from(range: Range) -> RangeInclusive { + use self::RangeInclusive::*; + + if range.start < range.end { + NonEmpty { + start: range.start, + end: range.end - Idx::one() // can't underflow because end > start >= MIN + } + } else { + Empty { + at: range.start + } + } + } +} + +/// An inclusive range which is only bounded above. +#[derive(Copy, Clone, PartialEq, Eq)] +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +pub struct RangeToInclusive { + /// The upper bound of the range (inclusive) + #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] + pub end: Idx, +} + +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl fmt::Debug for RangeToInclusive { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "...{:?}", self.end) + } +} + +// RangeToInclusive cannot impl From> +// because underflow would be possible with (..0).into() + /// The `Deref` trait is used to specify the functionality of dereferencing /// operations, like `*v`. /// diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f9e7c1fede2..dd84cba370c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -247,7 +247,6 @@ #![feature(optin_builtin_traits)] #![feature(placement_in_syntax)] #![feature(rand)] -#![feature(range_inclusive)] #![feature(raw)] #![feature(repr_simd)] #![feature(reflect_marker)]