about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorJames Miller <james@aatch.net>2014-04-16 14:29:36 +1200
committerJames Miller <james@aatch.net>2014-04-16 14:29:36 +1200
commitbe334d582435a05ea56c1ca7fcb2e512cfc51f24 (patch)
tree900da71bc36964d4cbe260b94db3d1163b74f48a /src/libstd
parent42b39924d87739f2dcda3e788c6e8655d310954f (diff)
downloadrust-be334d582435a05ea56c1ca7fcb2e512cfc51f24.tar.gz
rust-be334d582435a05ea56c1ca7fcb2e512cfc51f24.zip
Make Vec::clone and slice::to_owned failure-safe
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/slice.rs25
-rw-r--r--src/libstd/vec.rs11
2 files changed, 19 insertions, 17 deletions
diff --git a/src/libstd/slice.rs b/src/libstd/slice.rs
index f4f97ea8c92..153e21c780c 100644
--- a/src/libstd/slice.rs
+++ b/src/libstd/slice.rs
@@ -762,18 +762,23 @@ impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
     fn to_owned(&self) -> ~[T] {
         let len = self.len();
         let mut result = with_capacity(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
         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;
-            }
+            let p = result.as_mut_ptr();
+            // Use try_finally here otherwise the write to length
+            // inside the loop stops LLVM from optimising this.
+            try_finally(
+                &mut i, (),
+                |i, ()| while *i < len {
+                    mem::move_val_init(
+                        &mut(*p.offset(*i as int)),
+                        self.unsafe_ref(*i).clone());
+                    *i += 1;
+                },
+                |i| result.set_len(*i));
         }
         result
     }
diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs
index 034d53aa78b..96cbac8869e 100644
--- a/src/libstd/vec.rs
+++ b/src/libstd/vec.rs
@@ -313,21 +313,18 @@ impl<T:Clone> Clone for Vec<T> {
     fn clone(&self) -> Vec<T> {
         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 {
+            while vector.len < len {
                 unsafe {
                     mem::move_val_init(
-                        slice.unsafe_mut_ref(i),
-                        this_slice.unsafe_ref(i).clone());
+                        vector.as_mut_slice().unsafe_mut_ref(vector.len),
+                        this_slice.unsafe_ref(vector.len).clone());
                 }
-                i = i + 1;
+                vector.len += 1;
             }
         }
         vector