implement advance_(back_)_by on more iterators

This commit is contained in:
The8472
2021-07-12 21:40:38 +02:00
parent 6dc08b909b
commit 2c6e67105e
15 changed files with 375 additions and 2 deletions

View File

@@ -521,10 +521,12 @@ trait RangeIteratorImpl {
// Iterator
fn spec_next(&mut self) -> Option<Self::Item>;
fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
fn spec_advance_by(&mut self, n: usize) -> Result<(), usize>;
// DoubleEndedIterator
fn spec_next_back(&mut self) -> Option<Self::Item>;
fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>;
fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize>;
}
impl<A: Step> RangeIteratorImpl for ops::Range<A> {
@@ -555,6 +557,22 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
None
}
#[inline]
default fn spec_advance_by(&mut self, n: usize) -> Result<(), usize> {
let available = if self.start <= self.end {
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
} else {
0
};
let taken = available.min(n);
self.start =
Step::forward_checked(self.start.clone(), taken).expect("`Step` invariants not upheld");
if taken < n { Err(taken) } else { Ok(()) }
}
#[inline]
default fn spec_next_back(&mut self) -> Option<A> {
if self.start < self.end {
@@ -579,6 +597,22 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
self.end = self.start.clone();
None
}
#[inline]
default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize> {
let available = if self.start <= self.end {
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
} else {
0
};
let taken = available.min(n);
self.end =
Step::backward_checked(self.end.clone(), taken).expect("`Step` invariants not upheld");
if taken < n { Err(taken) } else { Ok(()) }
}
}
impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
@@ -607,6 +641,25 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
None
}
#[inline]
fn spec_advance_by(&mut self, n: usize) -> Result<(), usize> {
let available = if self.start <= self.end {
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
} else {
0
};
let taken = available.min(n);
// SAFETY: the conditions above ensure that the count is in bounds. If start <= end
// then steps_between either returns a bound to which we clamp or returns None which
// together with the initial inequality implies more than usize::MAX steps.
// Otherwise 0 is returned which always safe to use.
self.start = unsafe { Step::forward_unchecked(self.start.clone(), taken) };
if taken < n { Err(taken) } else { Ok(()) }
}
#[inline]
fn spec_next_back(&mut self) -> Option<T> {
if self.start < self.end {
@@ -631,6 +684,22 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
self.end = self.start.clone();
None
}
#[inline]
fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize> {
let available = if self.start <= self.end {
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
} else {
0
};
let taken = available.min(n);
// SAFETY: same as the spec_advance_by() implementation
self.end = unsafe { Step::backward_unchecked(self.end.clone(), taken) };
if taken < n { Err(taken) } else { Ok(()) }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -677,6 +746,11 @@ impl<A: Step> Iterator for ops::Range<A> {
true
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
self.spec_advance_by(n)
}
#[inline]
#[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
@@ -750,6 +824,11 @@ impl<A: Step> DoubleEndedIterator for ops::Range<A> {
fn nth_back(&mut self, n: usize) -> Option<A> {
self.spec_nth_back(n)
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
self.spec_advance_back_by(n)
}
}
// Safety: