summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorJames Miller <james@aatch.net>2014-04-16 11:35:18 +1200
committerJames Miller <james@aatch.net>2014-04-16 11:35:31 +1200
commit42b39924d87739f2dcda3e788c6e8655d310954f (patch)
tree25b6b5fabb3b1ed9aef4f2373b9354f099c660b4 /src/libstd
parent10f94e3fe5859fe7fc001cf26f4fa401d9a2ee2e (diff)
downloadrust-42b39924d87739f2dcda3e788c6e8655d310954f.tar.gz
rust-42b39924d87739f2dcda3e788c6e8655d310954f.zip
Improve the copying code for slices and Vec
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/slice.rs20
-rw-r--r--src/libstd/vec.rs21
2 files changed, 36 insertions, 5 deletions
diff --git a/src/libstd/slice.rs b/src/libstd/slice.rs
index aedaa5b3c15..f4f97ea8c92 100644
--- a/src/libstd/slice.rs
+++ b/src/libstd/slice.rs
@@ -760,9 +760,20 @@ impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
     /// Returns a copy of `v`.
     #[inline]
     fn to_owned(&self) -> ~[T] {
-        let mut result = with_capacity(self.len());
-        for e in self.iter() {
-            result.push((*e).clone());
+        let len = self.len();
+        let mut result = with_capacity(len);
+        unsafe {
+            // Unsafe code so this can be optimised to a memcpy (or something
+            // similarly fast) when T is Copy. LLVM is easily confused, so any
+            // extra operations during the loop can prevent this optimisation
+            result.set_len(len);
+            let mut i = 0;
+            while i < len {
+                mem::move_val_init(
+                    result.unsafe_mut_ref(i),
+                    self.unsafe_ref(i).clone());
+                i = i + 1;
+            }
         }
         result
     }
@@ -2584,7 +2595,8 @@ pub mod bytes {
 impl<A: Clone> Clone for ~[A] {
     #[inline]
     fn clone(&self) -> ~[A] {
-        self.iter().map(|item| item.clone()).collect()
+        // Use the fast to_owned on &[A] for cloning
+        self.as_slice().to_owned()
     }
 
     fn clone_from(&mut self, source: &~[A]) {
diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs
index a69120de00f..034d53aa78b 100644
--- a/src/libstd/vec.rs
+++ b/src/libstd/vec.rs
@@ -311,7 +311,26 @@ impl<T: Clone> Vec<T> {
 
 impl<T:Clone> Clone for Vec<T> {
     fn clone(&self) -> Vec<T> {
-        self.iter().map(|x| x.clone()).collect()
+        let len = self.len;
+        let mut vector = Vec::with_capacity(len);
+        vector.len = len;
+        // Unsafe code so this can be optimised to a memcpy (or something
+        // similarly fast) when T is Copy. LLVM is easily confused, so any
+        // extra operations during the loop can prevent this optimisation
+        {
+            let slice = vector.as_mut_slice();
+            let this_slice = self.as_slice();
+            let mut i = 0;
+            while i < len {
+                unsafe {
+                    mem::move_val_init(
+                        slice.unsafe_mut_ref(i),
+                        this_slice.unsafe_ref(i).clone());
+                }
+                i = i + 1;
+            }
+        }
+        vector
     }
 
     fn clone_from(&mut self, other: &Vec<T>) {