-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Add Iterator::collect_into<E: Extend>(e: E)
?
#45840
Comments
The problem is that Another possibility is You can also do this -- but note that type SizeHint = (usize, Option<usize>);
struct OverrideSizeHint<I>(I, SizeHint);
extension_trait! {
<I: Iterator> SizeHintExt<I> for I {
fn override_size_hint(self, hint: SizeHint) -> OverrideSizeHint<I> {
OverrideSizeHint(self, hint)
}
}
}
impl<I: Iterator> Iterator for OverrideSizeHint<I> {
type Item = I::Item;
fn next(&mut self) -> Option<I::Item> {
self.0.next()
}
fn size_hint(&self) -> SizeHint {
self.1
}
}
fn collect_hint(ratio: u8, chars: &[char]) -> Vec<char> {
chars.iter().enumerate().filter_map(|(i, c)| {
if filter(ratio, i) {
Some(*c)
} else {
None
}
}).override_size_hint((chars.len(), Some(chars.len()))).collect()
} |
Hmm, what about
|
@scottmcm : I like that alternative as well. |
I noticed the other day that unzip has a similar problem. It always just extends with |
collect_with_size_hint
?Iterator::collect_into<E: Extend>(e: E)
?
Updated description/title to apply @scottmcm 's |
Do any trait Iterator {
/* ... */
fn collect_into<E: Extend<Self::Item>>(self, e: E) -> E {
e.extend(self);
e
}
} As I understand it, the following are always equivalent right? let vec = whatever.into_iter().etc(...).collect_into(Vec::with_capacity(N)); let mut vec = Vec::with_capacity(N);
vec.extend(whatever.into_iter().etc(...)); Is the advantage of |
Yes... and avoiding the mutable local variable is nice as well. Finally, the symmetry with |
I love the idea of collecting into an existing collection, but for another reason: ergonomics. I've proposed something similar on Rust user and internals forums. I think, that the function ( |
We might also consider Also, FWIW rayon already has |
I feel that @stuhood I've included your motivation, are you OK with that? |
Try to guess a smarter initial capacity in Vec::from_iter > Another possibility is collect could look at the upper bound and be smarter about what capacity to use? ~ #45840 (comment) This is obviously good for hints like `(60, Some(61))` where today we allocate space for 60, then double it should the additional element show up, and it'd be much better to just always allocate 61. More nuanced are hints like `(0, Some(150))`, where today the code uses just the `0`, and thus starts at a capacity of `1`, but with this change will start at `10` instead. This can undeniably increase memory pressure over where it is today, so I expect at least some controversy 🙂 It does use `try_reserve` for the allocation that's more than the lower bound, and thus shouldn't introduce new aborts, at least. And the starting point grows by the root, keeping things fairly contained: even with an hint of `(0, Some(1_000_000_000))` it'll only start at `30_517`. cc @ljedrz cc #48994
Were there any further developments? @CodeSandwich your RFC link seems to be out of date. |
As of now it's dead 😆 It was too small for an RFC, so I was asked to implement it, but it was rejected #48597 |
Hey gang.
As originally determined in https://twitter.com/kot_2010/status/927119253324619776, building a pre-size-hinted mutable
Vec
as the output of a loop (even for very smalln
) can occasionally be more than twice as fast ascollect
ing into aVec
. As demonstrated here https://github.com/stuhood/rust-vec-bench, usingextend
into a pre-size-hintedVec
closes most of the gap.Focusing on improving
Iterator::size_hint
implementations so that they suggest better sizes forcollect
would likely help reduce this gap. But there are diminishing returns to heuristics, and in many cases users should be able to give better explicit hints.This issue initially proposed adding an
Iterator::collect_with_size_hint
method, but @scottmcm 's suggestion to addIterator::collect_into<E: Extend>(e: E) -> E
seems more general, and suggests a useful analogue inunzip_into<E1: Extend, E2: Extend>(e1: E1, e2: E2) -> (E1, E2)
.The text was updated successfully, but these errors were encountered: