Skip to content

Commit

Permalink
Specialize len for ExactSizeIterator with unmistakable size_hint
Browse files Browse the repository at this point in the history
  • Loading branch information
ssomers committed Jun 21, 2022
1 parent dc80ca7 commit 84125b2
Show file tree
Hide file tree
Showing 15 changed files with 286 additions and 89 deletions.
24 changes: 22 additions & 2 deletions library/alloc/src/collections/binary_heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,10 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for Iter<'_, T> {
fn len(&self) -> usize {
self.iter.len()
}

fn is_empty(&self) -> bool {
self.iter.is_empty()
}
Expand Down Expand Up @@ -1395,6 +1399,10 @@ impl<T> DoubleEndedIterator for IntoIter<T> {

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for IntoIter<T> {
fn len(&self) -> usize {
self.iter.len()
}

fn is_empty(&self) -> bool {
self.iter.is_empty()
}
Expand Down Expand Up @@ -1452,7 +1460,11 @@ impl<T: Ord> Iterator for IntoIterSorted<T> {
}

#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
impl<T: Ord> ExactSizeIterator for IntoIterSorted<T> {}
impl<T: Ord> ExactSizeIterator for IntoIterSorted<T> {
fn len(&self) -> usize {
self.inner.len()
}
}

#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
impl<T: Ord> FusedIterator for IntoIterSorted<T> {}
Expand Down Expand Up @@ -1497,6 +1509,10 @@ impl<T> DoubleEndedIterator for Drain<'_, T> {

#[stable(feature = "drain", since = "1.6.0")]
impl<T> ExactSizeIterator for Drain<'_, T> {
fn len(&self) -> usize {
self.iter.len()
}

fn is_empty(&self) -> bool {
self.iter.is_empty()
}
Expand Down Expand Up @@ -1554,7 +1570,11 @@ impl<T: Ord> Iterator for DrainSorted<'_, T> {
}

#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
impl<T: Ord> ExactSizeIterator for DrainSorted<'_, T> {}
impl<T: Ord> ExactSizeIterator for DrainSorted<'_, T> {
fn len(&self) -> usize {
self.inner.len()
}
}

#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
impl<T: Ord> FusedIterator for DrainSorted<'_, T> {}
Expand Down
19 changes: 16 additions & 3 deletions library/alloc/src/collections/linked_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,12 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for Iter<'_, T> {}
impl<T> ExactSizeIterator for Iter<'_, T> {
#[inline]
fn len(&self) -> usize {
self.len
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<T> FusedIterator for Iter<'_, T> {}
Expand Down Expand Up @@ -1124,7 +1129,11 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for IterMut<'_, T> {}
impl<T> ExactSizeIterator for IterMut<'_, T> {
fn len(&self) -> usize {
self.len
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<T> FusedIterator for IterMut<'_, T> {}
Expand Down Expand Up @@ -1803,7 +1812,11 @@ impl<T> DoubleEndedIterator for IntoIter<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for IntoIter<T> {}
impl<T> ExactSizeIterator for IntoIter<T> {
fn len(&self) -> usize {
self.list.len
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<T> FusedIterator for IntoIter<T> {}
Expand Down
9 changes: 8 additions & 1 deletion library/alloc/src/collections/vec_deque/drain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,14 @@ impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
}

#[stable(feature = "drain", since = "1.6.0")]
impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {}
impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {
#[inline]
fn len(&self) -> usize {
let n = self.iter.len();
debug_assert_eq!(self.size_hint(), (n, Some(n)));
n
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
5 changes: 5 additions & 0 deletions library/alloc/src/collections/vec_deque/into_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {
#[inline]
fn len(&self) -> usize {
self.inner.len()
}

fn is_empty(&self) -> bool {
self.inner.is_empty()
}
Expand Down
9 changes: 7 additions & 2 deletions library/alloc/src/collections/vec_deque/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl<'a, T> Iterator for Iter<'a, T> {

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = count(self.tail, self.head, self.ring.len());
let len = self.len();
(len, Some(len))
}

Expand Down Expand Up @@ -113,7 +113,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
}

fn nth(&mut self, n: usize) -> Option<Self::Item> {
if n >= count(self.tail, self.head, self.ring.len()) {
if n >= self.len() {
self.tail = self.head;
None
} else {
Expand Down Expand Up @@ -197,6 +197,11 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for Iter<'_, T> {
#[inline]
fn len(&self) -> usize {
count(self.tail, self.head, self.ring.len())
}

fn is_empty(&self) -> bool {
self.head == self.tail
}
Expand Down
9 changes: 7 additions & 2 deletions library/alloc/src/collections/vec_deque/iter_mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl<'a, T> Iterator for IterMut<'a, T> {

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = count(self.tail, self.head, self.ring.len());
let len = self.len();
(len, Some(len))
}

Expand All @@ -85,7 +85,7 @@ impl<'a, T> Iterator for IterMut<'a, T> {
}

fn nth(&mut self, n: usize) -> Option<Self::Item> {
if n >= count(self.tail, self.head, self.ring.len()) {
if n >= self.len() {
self.tail = self.head;
None
} else {
Expand Down Expand Up @@ -140,6 +140,11 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for IterMut<'_, T> {
#[inline]
fn len(&self) -> usize {
count(self.tail, self.head, self.ring.len())
}

fn is_empty(&self) -> bool {
self.head == self.tail
}
Expand Down
4 changes: 4 additions & 0 deletions library/alloc/src/vec/drain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {

#[stable(feature = "drain", since = "1.6.0")]
impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {
fn len(&self) -> usize {
self.iter.len()
}

fn is_empty(&self) -> bool {
self.iter.is_empty()
}
Expand Down
15 changes: 10 additions & 5 deletions library/alloc/src/vec/into_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let exact = if mem::size_of::<T>() == 0 {
self.end.addr().wrapping_sub(self.ptr.addr())
} else {
unsafe { self.end.sub_ptr(self.ptr) }
};
let exact = self.len();
(exact, Some(exact))
}

Expand Down Expand Up @@ -265,6 +261,15 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {
#[inline]
fn len(&self) -> usize {
if mem::size_of::<T>() == 0 {
self.end.addr().wrapping_sub(self.ptr.addr())
} else {
unsafe { self.end.sub_ptr(self.ptr) }
}
}

fn is_empty(&self) -> bool {
self.ptr == self.end
}
Expand Down
8 changes: 7 additions & 1 deletion library/alloc/src/vec/splice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,13 @@ impl<I: Iterator, A: Allocator> DoubleEndedIterator for Splice<'_, I, A> {
}

#[stable(feature = "vec_splice", since = "1.21.0")]
impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {}
impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {
fn len(&self) -> usize {
let n = self.drain.len();
debug_assert_eq!(self.size_hint(), (n, Some(n)));
n
}
}

#[stable(feature = "vec_splice", since = "1.21.0")]
impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
Expand Down
6 changes: 5 additions & 1 deletion library/core/src/ascii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,11 @@ impl DoubleEndedIterator for EscapeDefault {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ExactSizeIterator for EscapeDefault {}
impl ExactSizeIterator for EscapeDefault {
fn len(&self) -> usize {
self.range.len()
}
}
#[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for EscapeDefault {}

Expand Down
36 changes: 30 additions & 6 deletions library/core/src/char/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,13 @@ impl Iterator for EscapeDebug {
}

#[stable(feature = "char_escape_debug", since = "1.20.0")]
impl ExactSizeIterator for EscapeDebug {}
impl ExactSizeIterator for EscapeDebug {
fn len(&self) -> usize {
let n = self.0.len();
debug_assert_eq!(self.size_hint(), (n, Some(n)));
n
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for EscapeDebug {}
Expand Down Expand Up @@ -430,7 +436,13 @@ impl DoubleEndedIterator for ToLowercase {
impl FusedIterator for ToLowercase {}

#[stable(feature = "exact_size_case_mapping_iter", since = "1.35.0")]
impl ExactSizeIterator for ToLowercase {}
impl ExactSizeIterator for ToLowercase {
fn len(&self) -> usize {
let n = self.0.len();
debug_assert_eq!(self.size_hint(), (n, Some(n)));
n
}
}

/// Returns an iterator that yields the uppercase equivalent of a `char`.
///
Expand Down Expand Up @@ -464,7 +476,13 @@ impl DoubleEndedIterator for ToUppercase {
impl FusedIterator for ToUppercase {}

#[stable(feature = "exact_size_case_mapping_iter", since = "1.35.0")]
impl ExactSizeIterator for ToUppercase {}
impl ExactSizeIterator for ToUppercase {
fn len(&self) -> usize {
let n = self.0.len();
debug_assert_eq!(self.size_hint(), (n, Some(n)));
n
}
}

#[derive(Debug, Clone)]
enum CaseMappingIter {
Expand Down Expand Up @@ -509,13 +527,19 @@ impl Iterator for CaseMappingIter {
}

fn size_hint(&self) -> (usize, Option<usize>) {
let size = match self {
let size = self.len();
(size, Some(size))
}
}

impl CaseMappingIter {
fn len(&self) -> usize {
match self {
CaseMappingIter::Three(..) => 3,
CaseMappingIter::Two(..) => 2,
CaseMappingIter::One(_) => 1,
CaseMappingIter::Zero => 0,
};
(size, Some(size))
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions library/core/src/iter/traits/exact_size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ pub trait ExactSizeIterator: Iterator {
fn len(&self) -> usize {
let (lower, upper) = self.size_hint();
// Note: This assertion is overly defensive, but it checks the invariant
// guaranteed by the trait. If this trait were rust-internal,
// we could use debug_assert!; assert_eq! will check all Rust user
// implementations too.
// guaranteed by the trait in all Rust user implementations too.
// If this trait were rust-internal, we could use debug_assert!, but
// any implementation for which it matters can override `len`.
assert_eq!(upper, Some(lower));
lower
}
Expand Down

0 comments on commit 84125b2

Please sign in to comment.