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:
parent
f1e191c0b9
commit
c5d58de665
3 changed files with 167 additions and 91 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue