]> git.lizzy.rs Git - rust.git/commitdiff
std: Fix iteration over vectors of 0-size values
authorAlex Crichton <alex@alexcrichton.com>
Fri, 11 Apr 2014 21:34:21 +0000 (14:34 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Fri, 11 Apr 2014 22:12:56 +0000 (15:12 -0700)
Previously, all slices derived from a vector whose values were of size 0 had a
null pointer as the 'data' pointer on the slice. This caused first pointer to be
yielded during iteration to always be the null pointer. Due to the null pointer
optimization, this meant that the first return value was None, instead of
Some(&T).

This commit changes slice construction from a Vec instance to use a base pointer
of 1 if the values have zero size. This means that the iterator will never
return null, and the iteration will proceed appropriately.

Closes #13467

src/libstd/vec.rs

index da0e0d73feddccdf21709947991f659a2d4e6ebf..a69120de00f7d6dfc60c3660074c1d08143490aa 100644 (file)
@@ -598,7 +598,12 @@ pub fn truncate(&mut self, len: uint) {
     /// ```
     #[inline]
     pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
-        let slice = Slice { data: self.ptr as *T, len: self.len };
+        // See the comment in as_slice() for what's going on here.
+        let slice = if mem::size_of::<T>() == 0 {
+            Slice { data: 1 as *T, len: self.len }
+        } else {
+            Slice { data: self.ptr as *T, len: self.len }
+        };
         unsafe { transmute(slice) }
     }
 
@@ -1335,7 +1340,15 @@ impl<T> Vector<T> for Vec<T> {
     /// ```
     #[inline]
     fn as_slice<'a>(&'a self) -> &'a [T] {
-        let slice = Slice { data: self.ptr as *T, len: self.len };
+        // If we have a 0-sized vector, then the base pointer should not be NULL
+        // because an iterator over the slice will attempt to yield the base
+        // pointer as the first element in the vector, but this will end up
+        // being Some(NULL) which is optimized to None.
+        let slice = if mem::size_of::<T>() == 0 {
+            Slice { data: 1 as *T, len: self.len }
+        } else {
+            Slice { data: self.ptr as *T, len: self.len }
+        };
         unsafe { transmute(slice) }
     }
 }
@@ -1588,4 +1601,35 @@ fn test_retain() {
         vec.retain(|x| x%2 == 0);
         assert!(vec == Vec::from_slice([2u, 4]));
     }
+
+    #[test]
+    fn zero_sized_values() {
+        let mut v = Vec::new();
+        assert_eq!(v.len(), 0);
+        v.push(());
+        assert_eq!(v.len(), 1);
+        v.push(());
+        assert_eq!(v.len(), 2);
+        assert_eq!(v.pop(), Some(()));
+        assert_eq!(v.pop(), Some(()));
+        assert_eq!(v.pop(), None);
+
+        assert_eq!(v.iter().len(), 0);
+        v.push(());
+        assert_eq!(v.iter().len(), 1);
+        v.push(());
+        assert_eq!(v.iter().len(), 2);
+
+        for &() in v.iter() {}
+
+        assert_eq!(v.mut_iter().len(), 2);
+        v.push(());
+        assert_eq!(v.mut_iter().len(), 3);
+        v.push(());
+        assert_eq!(v.mut_iter().len(), 4);
+
+        for &() in v.mut_iter() {}
+        unsafe { v.set_len(0); }
+        assert_eq!(v.mut_iter().len(), 0);
+    }
 }