]> git.lizzy.rs Git - rust.git/commitdiff
Make Vec::clone and slice::to_owned failure-safe
authorJames Miller <james@aatch.net>
Wed, 16 Apr 2014 02:29:36 +0000 (14:29 +1200)
committerJames Miller <james@aatch.net>
Wed, 16 Apr 2014 02:29:36 +0000 (14:29 +1200)
src/libstd/slice.rs
src/libstd/vec.rs

index f4f97ea8c9202f7511b873e917f2966b61e16e28..153e21c780c098cf69e4b8031502fa4186b61fd1 100644 (file)
@@ -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
     }
index 034d53aa78bdb76533783c2c2ca1bd0c8cbca506..96cbac8869ef212d4452c59900ed436e3a9345bd 100644 (file)
@@ -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