core: add inclusive ranges to core::ops

Since it removes the old iter::{range_inclusive, RangeInclusive} which
were unstable and deprecated, this is a [breaking-change] on nightly.
This commit is contained in:
Alex Burka 2016-01-13 16:48:58 -05:00
parent f1e191c0b9
commit c5d58de665
3 changed files with 167 additions and 91 deletions

View file

@ -4375,95 +4375,6 @@ impl<A> Iterator for StepBy<A, RangeFrom<A>> 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<A> {
range: ops::Range<A>,
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<A>(start: A, stop: A) -> RangeInclusive<A>
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<A> Iterator for RangeInclusive<A> where
A: PartialEq + Step + One + Clone,
for<'a> &'a A: Add<&'a A, Output = A>
{
type Item = A;
#[inline]
fn next(&mut self) -> Option<A> {
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<usize>) {
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<A> DoubleEndedIterator for RangeInclusive<A> where
A: PartialEq + Step + One + Clone,
for<'a> &'a A: Add<&'a A, Output = A>,
for<'a> &'a A: Sub<Output=A>
{
#[inline]
fn next_back(&mut self) -> Option<A> {
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<A: Step + Zero + Clone> Iterator for StepBy<A, ops::Range<A>> {
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<A: Step + One> Iterator for ops::RangeFrom<A> where
}
}
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<A: Step + One> Iterator for ops::RangeInclusive<A> where
for<'a> &'a A: Add<&'a A, Output = A>
{
type Item = A;
#[inline]
fn next(&mut self) -> Option<A> {
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<usize>) {
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<A: Step + One> DoubleEndedIterator for ops::RangeInclusive<A> 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<A> {
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.

View file

@ -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<Idx: fmt::Debug> fmt::Debug for RangeTo<Idx> {
}
}
/// 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<Idx> {
/// 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<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
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<Idx: PartialOrd + One + Sub<Output=Idx>> From<Range<Idx>> for RangeInclusive<Idx> {
fn from(range: Range<Idx>) -> RangeInclusive<Idx> {
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<Idx> {
/// 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<Idx: fmt::Debug> fmt::Debug for RangeToInclusive<Idx> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "...{:?}", self.end)
}
}
// RangeToInclusive<Idx> cannot impl From<RangeTo<Idx>>
// because underflow would be possible with (..0).into()
/// The `Deref` trait is used to specify the functionality of dereferencing
/// operations, like `*v`.
///

View file

@ -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)]