From 2bf553c3e018025e9fe7e85216aafd7ba047db71 Mon Sep 17 00:00:00 2001 From: Markus Siemens Date: Tue, 17 Feb 2015 17:44:46 +0100 Subject: [PATCH] Implement `Vec::from_elem` (RFC 832) Implement `Vec::from_elem` by making the `vec![element; len]` macro more powerful (see RFC 832). Closes #22414 --- src/libcollections/macros.rs | 28 ++++++++++++++++++++++++--- src/libcollections/vec.rs | 24 +++++++++++++++++++++++ src/test/run-pass/vec-macro-repeat.rs | 5 +++++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/libcollections/macros.rs b/src/libcollections/macros.rs index 79c86a846f1b9..ebcfb8d1cf84e 100644 --- a/src/libcollections/macros.rs +++ b/src/libcollections/macros.rs @@ -9,12 +9,34 @@ // except according to those terms. /// Creates a `Vec` containing the arguments. +/// +/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions. +/// There are two forms of this macro: +/// +/// - Create a `Vec` containing a given list of elements: +/// +/// ``` +/// let v = vec![1, 2, 3]; +/// assert_eq!(v[0], 1); +/// assert_eq!(v[1], 2); +/// assert_eq!(v[2], 3); +/// ``` +/// +/// - Create a `Vec` from a given element and size: +/// +/// ``` +/// let v = vec![1; 3]; +/// assert_eq!(v, vec![1, 1, 1]); +/// ``` +/// +/// Note that unlike array expressions this syntax supports all elements +/// which implement `Clone` and the number of elements doesn't have to be +/// a constant. #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! vec { - ($x:expr; $y:expr) => ( - <[_] as $crate::slice::SliceExt>::into_vec( - $crate::boxed::Box::new([$x; $y])) + ($elem:expr; $n:expr) => ( + $crate::vec::from_elem($elem, $n) ); ($($x:expr),*) => ( <[_] as $crate::slice::SliceExt>::into_vec( diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index f294dd3c3e0f6..dcb63aa19391a 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1252,6 +1252,30 @@ unsafe fn dealloc(ptr: *mut T, len: usize) { } } +#[doc(hidden)] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn from_elem(elem: T, n: usize) -> Vec { + unsafe { + let mut v = Vec::with_capacity(n); + let mut ptr = v.as_mut_ptr(); + + // Write all elements except the last one + for i in 1..n { + ptr::write(ptr, Clone::clone(&elem)); + ptr = ptr.offset(1); + v.set_len(i); // Increment the length in every step in case Clone::clone() panics + } + + if n > 0 { + // We can write the last element directly without cloning needlessly + ptr::write(ptr, elem); + v.set_len(n); + } + + v + } +} + //////////////////////////////////////////////////////////////////////////////// // Common trait implementations for Vec //////////////////////////////////////////////////////////////////////////////// diff --git a/src/test/run-pass/vec-macro-repeat.rs b/src/test/run-pass/vec-macro-repeat.rs index 9e69ecfce4fbe..76e7b92ea046b 100644 --- a/src/test/run-pass/vec-macro-repeat.rs +++ b/src/test/run-pass/vec-macro-repeat.rs @@ -14,4 +14,9 @@ pub fn main() { assert_eq!(vec![1; 2], vec![1, 1]); assert_eq!(vec![1; 1], vec![1]); assert_eq!(vec![1; 0], vec![]); + + // from_elem syntax (see RFC 832) + let el = Box::new(1); + let n = 3; + assert_eq!(vec![el; n], vec![Box::new(1), Box::new(1), Box::new(1)]); }