-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Avoid SmallVec::collect
#64949
Avoid SmallVec::collect
#64949
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2848,8 +2848,29 @@ impl<'a, T, R> InternIteratorElement<T, R> for &'a T | |
|
||
impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> { | ||
type Output = Result<R, E>; | ||
fn intern_with<I: Iterator<Item=Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output { | ||
Ok(f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?)) | ||
fn intern_with<I: Iterator<Item=Self>, F: FnOnce(&[T]) -> R>(mut iter: I, f: F) | ||
-> Self::Output { | ||
// This code is hot enough that it's worth specializing for the most | ||
// common length lists, to avoid the overhead of `SmallVec` creation. | ||
// The match arms are in order of frequency. The 1, 2, and 0 cases are | ||
// typically hit in ~95% of cases. We assume that if the upper and | ||
// lower bounds from `size_hint` agree they are correct. | ||
Ok(match iter.size_hint() { | ||
(1, Some(1)) => { | ||
f(&[iter.next().unwrap()?]) | ||
} | ||
(2, Some(2)) => { | ||
let t0 = iter.next().unwrap()?; | ||
let t1 = iter.next().unwrap()?; | ||
f(&[t0, t1]) | ||
} | ||
(0, Some(0)) => { | ||
f(&[]) | ||
} | ||
_ => { | ||
f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the small cases are already taken care of above, could it be a win to just collect to Vec here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I haven't measured, but I suspect Also, this collect-into- |
||
} | ||
}) | ||
} | ||
} | ||
|
||
|
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.
Is this assumption OK? It seems to run counter to the
Iterator
docs -- In particular, are you sure that nounsafe
code in the compiler relies on the correctness of collecting? You could specialize forTrustedLen
in which case this assumption is definitely OK.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.
First I tried adding blanket
TrustedLen
requirements, but some of the iterators that feed into this method don't implementTrustedLen
.Then I tried to use specialization but failed. The problem is that we have this function:
And we want one behaviour if
I
implementsTrustedLen
, and another behaviour if it doesn't. But you can't do that with an argument. This function appears within animpl
block forResult<T, E>
, i.e.I
isn't part of theimpl
type.As for the existing code... if the iterator gives fewer elements than the size hint (e.g. 1 when the hint was
(2, Some(2))
) then anunwrap
will safely fail within the function. If the iterator gives more elements than the size hint (e.g. 2 when the hint was(1, Some(1))
) then the wrong value will be interned. This could certainly cause correctness issues. It seems unlikely it could lead to unsafety, though I can't guarantee it. Also, it seems unlikely that an iterator would erroneously claim an exact size hint (i.e. where the lower bound and the upper bound match).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 can't say that reasoning based on probability makes me very confident in the safety of this change. :/
How bad/expensive would it be to
assert!
that callingnext()
again yieldsNone
?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 see any unsafe code here, and
size_hint
is required to produce conservative lower and upper bounds. If the bounds are the same, we know the size exactly.