Skip to content
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

Smarter default implementation of Extend::extend_reserve #88761

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions library/core/src/iter/traits/collect.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::marker::PhantomData;

/// Conversion from an [`Iterator`].
///
/// By implementing `FromIterator` for a type, you define how it will be
Expand Down Expand Up @@ -346,10 +348,37 @@ pub trait Extend<A> {

/// Reserves capacity in a collection for the given number of additional elements.
///
/// The default implementation does nothing.
/// The default implementation forwards to `extend` with an iterator having
/// the given requested capacity as `size_hint`, which has the effect of
/// reserving if `extend` takes into account its argument's size hint in
/// order to reserve capacity.
#[unstable(feature = "extend_one", issue = "72631")]
fn extend_reserve(&mut self, additional: usize) {
let _ = additional;
struct ReserveHint<A> {
additional: usize,
item: PhantomData<A>,
}

// DO NOT implement TrustedLen, because the real len is actually 0.
impl<A> Iterator for ReserveHint<A> {
type Item = A;

fn next(&mut self) -> Option<Self::Item> {
None
}

fn size_hint(&self) -> (usize, Option<usize>) {
(self.additional, Some(self.additional))
}
}

impl<A> ExactSizeIterator for ReserveHint<A> {
fn len(&self) -> usize {
self.additional
}
}

self.extend(ReserveHint { additional, item: PhantomData })
}
}

Expand Down
27 changes: 27 additions & 0 deletions library/core/tests/iter/traits/collect.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#[test]
fn test_extend_reserve() {
struct Collection {
len: usize,
capacity: usize,
}

impl Extend<i32> for Collection {
fn extend<I: IntoIterator<Item = i32>>(&mut self, elements: I) {
let iter = elements.into_iter();
let (lower_bound, _) = iter.size_hint();
let expected_len = self.len.saturating_add(lower_bound);
if self.capacity < expected_len {
// do the reserve
self.capacity = expected_len;
}
// do the extend
iter.into_iter().for_each(drop);
}

// no custom implementation of extend_reserve
}

let mut collection = Collection { len: 0, capacity: 0 };
collection.extend_reserve(5);
assert_eq!(collection.capacity, 5);
}
1 change: 1 addition & 0 deletions library/core/tests/iter/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod accum;
mod collect;
mod double_ended;
mod iterator;
mod step;
1 change: 1 addition & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#![feature(duration_consts_2)]
#![feature(duration_constants)]
#![feature(exact_size_is_empty)]
#![feature(extend_one)]
#![feature(extern_types)]
#![feature(flt2dec)]
#![feature(fmt_internals)]
Expand Down