-
Notifications
You must be signed in to change notification settings - Fork 114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve performance characteristics of Vector iterators to better match Vec iterators #104
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just passing by and I noticed what I believe to be multiple bugs in this implementation. All my comments apply to both the Iterator
and DoubleEndedIterator
implementations for all the mutability variants.
if n >= self.len() { | ||
None | ||
} else { | ||
self.front_index += n; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if this overflows?
|
||
fn nth(&mut self, n: usize) -> Option<Self::Item> { | ||
if n >= self.len() { | ||
None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe this shortcut is correct. It introduces a bug.
Before this change, this works:
let vec = vector![1, 2, 3];
let mut iter = vec.iter();
assert_eq!(iter.nth(3), None);
assert_eq!(iter.next(), None);
Afterwards, it panics because the call to next()
returns Some(1)
.
Since the implementation of next()
already has a check for exhaustion, I would remove this if
altogether and replace it with its else
case.
impl<'a, A: Clone> ExactSizeIterator for Iter<'a, A> {} | ||
impl<'a, A: Clone> ExactSizeIterator for Iter<'a, A> { | ||
fn len(&self) -> usize { | ||
self.back_index - self.front_index |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if this underflows?
self.back_index - self.front_index | |
self.back_index.saturating_sub(self.front_index) |
impl<'a, A: Clone> ExactSizeIterator for IterMut<'a, A> {} | ||
impl<'a, A: Clone> ExactSizeIterator for IterMut<'a, A> { | ||
fn len(&self) -> usize { | ||
self.back_index - self.front_index |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.back_index - self.front_index | |
self.back_index.saturing_sub(self.front_index) |
|
||
impl<'a, A: Clone> ExactSizeIterator for Chunks<'a, A> { | ||
fn len(&self) -> usize { | ||
self.back_index - self.front_index |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.back_index - self.front_index | |
self.back_index.saturing_sub(self.front_index) |
|
||
impl<'a, A: Clone> ExactSizeIterator for ChunksMut<'a, A> { | ||
fn len(&self) -> usize { | ||
self.back_index - self.front_index |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.back_index - self.front_index | |
self.back_index.saturing_sub(self.front_index) |
In particular provided implementations of
len
,count
,nth
, andnth_back
forIter
,IterMut
,Chunks
,ChunksMut
that make use offront_index
andback_index
to improve performance.Similar work might also be useful for
ConsumingIter
, but I couldn't easily trace that code to see where/if such improvements would make sense.