Skip to content

Commit

Permalink
Optimize Iterator::last() for PyList & PyTuple and `Iterator::c…
Browse files Browse the repository at this point in the history
…ount()` for `PyDict`, `PyList`, `PyTuple` & `PySet` (#4878)

* Optimize `Iterator::last()` for `PyList` & `PyTuple`

* Optimize `Iterator::count()` for `PyDict`, `PyList`, `PyTuple` & `PySet`
  • Loading branch information
bschoenmaeckers authored Feb 19, 2025
1 parent f2f30f3 commit da3e37e
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 0 deletions.
2 changes: 2 additions & 0 deletions newsfragments/4878.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Optimizes `last` for `BoundListIterator`, `BoundTupleIterator` and `BorrowedTupleIterator`
- Optimizes `Iterator::count()` for `PyDict`, `PyList`, `PyTuple` & `PySet`
24 changes: 24 additions & 0 deletions src/types/dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,14 @@ impl<'py> Iterator for BoundDictIterator<'py> {
(len, Some(len))
}

#[inline]
fn count(self) -> usize
where
Self: Sized,
{
self.len()
}

#[inline]
#[cfg(Py_GIL_DISABLED)]
fn fold<B, F>(mut self, init: B, mut f: F) -> B
Expand Down Expand Up @@ -736,6 +744,14 @@ mod borrowed_iter {
let len = self.len();
(len, Some(len))
}

#[inline]
fn count(self) -> usize
where
Self: Sized,
{
self.len()
}
}

impl ExactSizeIterator for BorrowedDictIter<'_, '_> {
Expand Down Expand Up @@ -1657,4 +1673,12 @@ mod tests {
.is_err());
});
}

#[test]
fn test_iter_count() {
Python::with_gil(|py| {
let dict = [(1, 1), (2, 2), (3, 3)].into_py_dict(py).unwrap();
assert_eq!(dict.iter().count(), 3);
})
}
}
16 changes: 16 additions & 0 deletions src/types/frozenset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,14 @@ impl<'py> Iterator for BoundFrozenSetIterator<'py> {
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}

#[inline]
fn count(self) -> usize
where
Self: Sized,
{
self.len()
}
}

impl ExactSizeIterator for BoundFrozenSetIterator<'_> {
Expand Down Expand Up @@ -358,4 +366,12 @@ mod tests {
assert!(!set.contains(3).unwrap());
});
}

#[test]
fn test_iter_count() {
Python::with_gil(|py| {
let set = PyFrozenSet::new(py, vec![1, 2, 3]).unwrap();
assert_eq!(set.iter().count(), 3);
})
}
}
33 changes: 33 additions & 0 deletions src/types/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,22 @@ impl<'py> Iterator for BoundListIterator<'py> {
(len, Some(len))
}

#[inline]
fn count(self) -> usize
where
Self: Sized,
{
self.len()
}

#[inline]
fn last(mut self) -> Option<Self::Item>
where
Self: Sized,
{
self.next_back()
}

#[inline]
#[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
fn fold<B, F>(mut self, init: B, mut f: F) -> B
Expand Down Expand Up @@ -1778,4 +1794,21 @@ mod tests {
assert_eq!(iter4.next_back().unwrap().extract::<i32>().unwrap(), 5);
})
}

#[test]
fn test_iter_last() {
Python::with_gil(|py| {
let list = PyList::new(py, vec![1, 2, 3]).unwrap();
let last = list.iter().last();
assert_eq!(last.unwrap().extract::<i32>().unwrap(), 3);
})
}

#[test]
fn test_iter_count() {
Python::with_gil(|py| {
let list = PyList::new(py, vec![1, 2, 3]).unwrap();
assert_eq!(list.iter().count(), 3);
})
}
}
16 changes: 16 additions & 0 deletions src/types/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,14 @@ impl<'py> Iterator for BoundSetIterator<'py> {
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}

#[inline]
fn count(self) -> usize
where
Self: Sized,
{
self.len()
}
}

impl ExactSizeIterator for BoundSetIterator<'_> {
Expand Down Expand Up @@ -479,4 +487,12 @@ mod tests {
assert_eq!(iter.size_hint(), (0, Some(0)));
});
}

#[test]
fn test_iter_count() {
Python::with_gil(|py| {
let set = PySet::new(py, vec![1, 2, 3]).unwrap();
assert_eq!(set.iter().count(), 3);
})
}
}
49 changes: 49 additions & 0 deletions src/types/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,22 @@ impl<'py> Iterator for BoundTupleIterator<'py> {
(len, Some(len))
}

#[inline]
fn count(self) -> usize
where
Self: Sized,
{
self.len()
}

#[inline]
fn last(mut self) -> Option<Self::Item>
where
Self: Sized,
{
self.next_back()
}

#[inline]
#[cfg(not(feature = "nightly"))]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
Expand Down Expand Up @@ -548,6 +564,22 @@ impl<'a, 'py> Iterator for BorrowedTupleIterator<'a, 'py> {
let len = self.len();
(len, Some(len))
}

#[inline]
fn count(self) -> usize
where
Self: Sized,
{
self.len()
}

#[inline]
fn last(mut self) -> Option<Self::Item>
where
Self: Sized,
{
self.next_back()
}
}

impl DoubleEndedIterator for BorrowedTupleIterator<'_, '_> {
Expand Down Expand Up @@ -1728,4 +1760,21 @@ mod tests {
assert_eq!(iter4.next_back().unwrap().extract::<i32>().unwrap(), 5);
})
}

#[test]
fn test_iter_last() {
Python::with_gil(|py| {
let tuple = PyTuple::new(py, vec![1, 2, 3]).unwrap();
let last = tuple.iter().last();
assert_eq!(last.unwrap().extract::<i32>().unwrap(), 3);
})
}

#[test]
fn test_iter_count() {
Python::with_gil(|py| {
let tuple = PyTuple::new(py, vec![1, 2, 3]).unwrap();
assert_eq!(tuple.iter().count(), 3);
})
}
}

0 comments on commit da3e37e

Please sign in to comment.