Auto merge of #41771 - clarcharr:resize_default, r=nikomatsakis

Add Vec::resize_default.

As suggested by #41758.
This commit is contained in:
bors 2017-05-16 08:14:29 +00:00
commit 4d09a0eb5d
3 changed files with 105 additions and 35 deletions

View File

@ -217,6 +217,7 @@
- [unique](library-features/unique.md) - [unique](library-features/unique.md)
- [unsize](library-features/unsize.md) - [unsize](library-features/unsize.md)
- [utf8_error_error_len](library-features/utf8-error-error-len.md) - [utf8_error_error_len](library-features/utf8-error-error-len.md)
- [vec_resize_default](library-features/vec-resize-default.md)
- [vec_remove_item](library-features/vec-remove-item.md) - [vec_remove_item](library-features/vec-remove-item.md)
- [windows_c](library-features/windows-c.md) - [windows_c](library-features/windows-c.md)
- [windows_handle](library-features/windows-handle.md) - [windows_handle](library-features/windows-handle.md)

View File

@ -0,0 +1,7 @@
# `vec_resize_default`
The tracking issue for this feature is: [#41758]
[#41758]: https://github.com/rust-lang/rust/issues/41758
------------------------

View File

@ -1220,11 +1220,14 @@ impl<T> Vec<T> {
} }
impl<T: Clone> Vec<T> { impl<T: Clone> Vec<T> {
/// Resizes the `Vec` in-place so that `len()` is equal to `new_len`. /// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
/// ///
/// If `new_len` is greater than `len()`, the `Vec` is extended by the /// If `new_len` is greater than `len`, the `Vec` is extended by the
/// difference, with each additional slot filled with `value`. /// difference, with each additional slot filled with `value`.
/// If `new_len` is less than `len()`, the `Vec` is simply truncated. /// If `new_len` is less than `len`, the `Vec` is simply truncated.
///
/// This method requires `Clone` to clone the passed value. If you'd
/// rather create a value with `Default` instead, see [`resize_default`].
/// ///
/// # Examples /// # Examples
/// ///
@ -1237,46 +1240,19 @@ impl<T: Clone> Vec<T> {
/// vec.resize(2, 0); /// vec.resize(2, 0);
/// assert_eq!(vec, [1, 2]); /// assert_eq!(vec, [1, 2]);
/// ``` /// ```
///
/// [`resize_default`]: #method.resize_default
#[stable(feature = "vec_resize", since = "1.5.0")] #[stable(feature = "vec_resize", since = "1.5.0")]
pub fn resize(&mut self, new_len: usize, value: T) { pub fn resize(&mut self, new_len: usize, value: T) {
let len = self.len(); let len = self.len();
if new_len > len { if new_len > len {
self.extend_with_element(new_len - len, value); self.extend_with(new_len - len, ExtendElement(value))
} else { } else {
self.truncate(new_len); self.truncate(new_len);
} }
} }
/// Extend the vector by `n` additional clones of `value`.
fn extend_with_element(&mut self, n: usize, value: T) {
self.reserve(n);
unsafe {
let mut ptr = self.as_mut_ptr().offset(self.len() as isize);
// Use SetLenOnDrop to work around bug where compiler
// may not realize the store through `ptr` through self.set_len()
// don't alias.
let mut local_len = SetLenOnDrop::new(&mut self.len);
// Write all elements except the last one
for _ in 1..n {
ptr::write(ptr, value.clone());
ptr = ptr.offset(1);
// Increment the length in every step in case clone() panics
local_len.increment_len(1);
}
if n > 0 {
// We can write the last element directly without cloning needlessly
ptr::write(ptr, value);
local_len.increment_len(1);
}
// len set by scope guard
}
}
/// Clones and appends all elements in a slice to the `Vec`. /// Clones and appends all elements in a slice to the `Vec`.
/// ///
/// Iterates over the slice `other`, clones each element, and then appends /// Iterates over the slice `other`, clones each element, and then appends
@ -1300,6 +1276,92 @@ impl<T: Clone> Vec<T> {
} }
} }
impl<T: Default> Vec<T> {
/// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
///
/// If `new_len` is greater than `len`, the `Vec` is extended by the
/// difference, with each additional slot filled with `Default::default()`.
/// If `new_len` is less than `len`, the `Vec` is simply truncated.
///
/// This method uses `Default` to create new values on every push. If
/// you'd rather `Clone` a given value, use [`resize`].
///
///
/// # Examples
///
/// ```
/// #![feature(vec_resize_default)]
///
/// let mut vec = vec![1, 2, 3];
/// vec.resize_default(5);
/// assert_eq!(vec, [1, 2, 3, 0, 0]);
///
/// let mut vec = vec![1, 2, 3, 4];
/// vec.resize_default(2);
/// assert_eq!(vec, [1, 2]);
/// ```
///
/// [`resize`]: #method.resize
#[unstable(feature = "vec_resize_default", issue = "41758")]
pub fn resize_default(&mut self, new_len: usize) {
let len = self.len();
if new_len > len {
self.extend_with(new_len - len, ExtendDefault);
} else {
self.truncate(new_len);
}
}
}
// This code generalises `extend_with_{element,default}`.
trait ExtendWith<T> {
fn next(&self) -> T;
fn last(self) -> T;
}
struct ExtendElement<T>(T);
impl<T: Clone> ExtendWith<T> for ExtendElement<T> {
fn next(&self) -> T { self.0.clone() }
fn last(self) -> T { self.0 }
}
struct ExtendDefault;
impl<T: Default> ExtendWith<T> for ExtendDefault {
fn next(&self) -> T { Default::default() }
fn last(self) -> T { Default::default() }
}
impl<T> Vec<T> {
/// Extend the vector by `n` values, using the given generator.
fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, value: E) {
self.reserve(n);
unsafe {
let mut ptr = self.as_mut_ptr().offset(self.len() as isize);
// Use SetLenOnDrop to work around bug where compiler
// may not realize the store through `ptr` through self.set_len()
// don't alias.
let mut local_len = SetLenOnDrop::new(&mut self.len);
// Write all elements except the last one
for _ in 1..n {
ptr::write(ptr, value.next());
ptr = ptr.offset(1);
// Increment the length in every step in case next() panics
local_len.increment_len(1);
}
if n > 0 {
// We can write the last element directly without cloning needlessly
ptr::write(ptr, value.last());
local_len.increment_len(1);
}
// len set by scope guard
}
}
}
// Set the length of the vec when the `SetLenOnDrop` value goes out of scope. // Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
// //
// The idea is: The length field in SetLenOnDrop is a local variable // The idea is: The length field in SetLenOnDrop is a local variable
@ -1389,7 +1451,7 @@ trait SpecFromElem: Sized {
impl<T: Clone> SpecFromElem for T { impl<T: Clone> SpecFromElem for T {
default fn from_elem(elem: Self, n: usize) -> Vec<Self> { default fn from_elem(elem: Self, n: usize) -> Vec<Self> {
let mut v = Vec::with_capacity(n); let mut v = Vec::with_capacity(n);
v.extend_with_element(n, elem); v.extend_with(n, ExtendElement(elem));
v v
} }
} }
@ -1424,7 +1486,7 @@ macro_rules! impl_spec_from_elem {
} }
} }
let mut v = Vec::with_capacity(n); let mut v = Vec::with_capacity(n);
v.extend_with_element(n, elem); v.extend_with(n, ExtendElement(elem));
v v
} }
} }