about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSteven Allen <steven@stebalien.com>2015-04-22 18:44:17 -0400
committerSteven Allen <steven@stebalien.com>2015-04-22 19:19:54 -0400
commit50c6c6ca9038223226a36d9ceb15b6f37254959c (patch)
treebb066fd6090473b6d0f59a11cd518d97dd3b8cda
parentde8c79a53532c4a6de61b0dcde6ed9b133afa752 (diff)
downloadrust-50c6c6ca9038223226a36d9ceb15b6f37254959c.tar.gz
rust-50c6c6ca9038223226a36d9ceb15b6f37254959c.zip
Address comments.
1. Use next_back for last.
2. Use slices for computing nth. It might be possible to use the same
code for both the mut/const case but I don't know how that will play
with compiler optimizations.
-rw-r--r--src/libcore/slice.rs88
1 files changed, 46 insertions, 42 deletions
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index e2bb881921d..7bed0ef6daa 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -674,51 +674,13 @@ macro_rules! iterator {
 
             #[inline]
             fn nth(&mut self, n: usize) -> Option<$elem> {
-                // could be implemented with slices, but this avoids bounds checks
-                unsafe {
-                    ::intrinsics::assume(!self.ptr.is_null());
-                    ::intrinsics::assume(!self.end.is_null());
-                    // There should be some way to use offset and optimize this to LEA but I don't
-                    // know how to do that AND detect overflow...
-                    let size = mem::size_of::<T>();
-                    if size == 0 {
-                        if let Some(new_ptr) = (self.ptr as usize).checked_add(n) {
-                            if new_ptr < (self.end as usize) {
-                                self.ptr = transmute(new_ptr + 1);
-                                return Some(&mut *(1 as *mut _))
-                            }
-                        }
-                    } else {
-                        if let Some(new_ptr) = n.checked_mul(size).and_then(|offset| {
-                            (self.ptr as usize).checked_add(offset)
-                        }) {
-                            if new_ptr < (self.end as usize) {
-                                self.ptr = transmute(new_ptr + size);
-                                return Some(transmute(new_ptr))
-                            }
-                        }
-                    }
-                    None
-                }
+                // Call helper method. Can't put the definition here because mut versus const.
+                self.iter_nth(n)
             }
 
             #[inline]
-            fn last(self) -> Option<$elem> {
-                // We could just call next_back but this avoids the memory write.
-                unsafe {
-                    ::intrinsics::assume(!self.ptr.is_null());
-                    ::intrinsics::assume(!self.end.is_null());
-                    if self.end == self.ptr {
-                        None
-                    } else {
-                        if mem::size_of::<T>() == 0 {
-                            // Use a non-null pointer value
-                            Some(&mut *(1 as *mut _))
-                        } else {
-                            Some(transmute(self.end.offset(-1)))
-                        }
-                    }
-                }
+            fn last(mut self) -> Option<$elem> {
+                self.next_back()
             }
         }
 
@@ -839,6 +801,27 @@ impl<'a, T> Iter<'a, T> {
     pub fn as_slice(&self) -> &'a [T] {
         make_slice!(T => &'a [T]: self.ptr, self.end)
     }
+
+    // Helper function for Iter::nth
+    fn iter_nth(&mut self, n: usize) -> Option<&'a T> {
+        match self.as_slice().get(n) {
+            Some(elem_ref) => if mem::size_of::<T>() == 0 {
+                unsafe {
+                    self.ptr = transmute((elem_ref as *const _) as usize + 1);
+                    Some(& *(1 as *const _))
+                }
+            } else {
+                unsafe {
+                    self.ptr = (elem_ref as *const _).offset(1);
+                    Some(elem_ref)
+                }
+            },
+            None => {
+                self.ptr = self.end;
+                None
+            }
+        }
+    }
 }
 
 iterator!{struct Iter -> *const T, &'a T}
@@ -968,6 +951,27 @@ impl<'a, T> IterMut<'a, T> {
     pub fn into_slice(self) -> &'a mut [T] {
         make_mut_slice!(T => &'a mut [T]: self.ptr, self.end)
     }
+
+    // Helper function for IterMut::nth
+    fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> {
+        match make_mut_slice!(T => &'a mut [T]: self.ptr, self.end).get_mut(n) {
+            Some(elem_ref) => if mem::size_of::<T>() == 0 {
+                unsafe {
+                    self.ptr = transmute((elem_ref as *mut _) as usize + 1);
+                    Some(&mut *(1 as *mut _))
+                }
+            } else {
+                unsafe {
+                    self.ptr = (elem_ref as *mut _).offset(1);
+                    Some(elem_ref)
+                }
+            },
+            None => {
+                self.ptr = self.end;
+                None
+            }
+        }
+    }
 }
 
 iterator!{struct IterMut -> *mut T, &'a mut T}