diff options
| author | Dan Schatzberg <schatzberg.dan@gmail.com> | 2014-09-04 15:25:23 -0400 |
|---|---|---|
| committer | Dan Schatzberg <schatzberg.dan@gmail.com> | 2014-10-02 11:22:05 -0400 |
| commit | 4184396f28d5612520f7b30718df9fff6918d239 (patch) | |
| tree | d3cf8319d19246c4a59be7c9ce558f6c67f15a20 | |
| parent | b419e9e7396852d698602c10216051fa9f3ec2b8 (diff) | |
| download | rust-4184396f28d5612520f7b30718df9fff6918d239.tar.gz rust-4184396f28d5612520f7b30718df9fff6918d239.zip | |
Add lifetime bounds on Items and MutItems.
This also requires a fix for Vec's MoveItems. This resolves issue #16941
| -rw-r--r-- | src/libcollections/vec.rs | 56 | ||||
| -rw-r--r-- | src/libcore/slice.rs | 4 |
2 files changed, 44 insertions, 16 deletions
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 9dc122cfc7d..6fdf2fce0a2 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -845,11 +845,12 @@ impl<T> Vec<T> { #[inline] pub fn into_iter(self) -> MoveItems<T> { unsafe { - let iter = mem::transmute(self.as_slice().iter()); let ptr = self.ptr; let cap = self.cap; + let begin = self.ptr as *const T; + let end = (self.ptr as uint + self.len()) as *const T; mem::forget(self); - MoveItems { allocation: ptr, cap: cap, iter: iter } + MoveItems { allocation: ptr, cap: cap, ptr: begin, end: end } } } @@ -1773,7 +1774,8 @@ impl<T> MutableSeq<T> for Vec<T> { pub struct MoveItems<T> { allocation: *mut T, // the block of memory allocated for the vector cap: uint, // the capacity of the vector - iter: Items<'static, T> + ptr: *const T, + end: *const T } impl<T> MoveItems<T> { @@ -1793,17 +1795,33 @@ impl<T> Iterator<T> for MoveItems<T> { #[inline] fn next<'a>(&'a mut self) -> Option<T> { unsafe { - // Unsafely transmute from Items<'static, T> to Items<'a, - // T> because otherwise the type checker requires that T - // be bounded by 'static. - let iter: &mut Items<'a, T> = mem::transmute(&mut self.iter); - iter.next().map(|x| ptr::read(x)) + if self.ptr == self.end { + None + } else { + if mem::size_of::<T>() == 0 { + // purposefully don't use 'ptr.offset' because for + // vectors with 0-size elements this would return the + // same pointer. + self.ptr = mem::transmute(self.ptr as uint + 1); + + // Use a non-null pointer value + Some(ptr::read(mem::transmute(1u))) + } else { + let old = self.ptr; + self.ptr = self.ptr.offset(1); + + Some(ptr::read(old)) + } + } } } #[inline] fn size_hint(&self) -> (uint, Option<uint>) { - self.iter.size_hint() + let diff = (self.end as uint) - (self.ptr as uint); + let size = mem::size_of::<T>(); + let exact = diff / (if size == 0 {1} else {size}); + (exact, Some(exact)) } } @@ -1811,11 +1829,21 @@ impl<T> DoubleEndedIterator<T> for MoveItems<T> { #[inline] fn next_back<'a>(&'a mut self) -> Option<T> { unsafe { - // Unsafely transmute from Items<'static, T> to Items<'a, - // T> because otherwise the type checker requires that T - // be bounded by 'static. - let iter: &mut Items<'a, T> = mem::transmute(&mut self.iter); - iter.next_back().map(|x| ptr::read(x)) + if self.end == self.ptr { + None + } else { + if mem::size_of::<T>() == 0 { + // See above for why 'ptr.offset' isn't used + self.end = mem::transmute(self.end as uint - 1); + + // Use a non-null pointer value + Some(ptr::read(mem::transmute(1u))) + } else { + self.end = self.end.offset(-1); + + Some(ptr::read(mem::transmute(self.end))) + } + } } } } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index a8becb315b2..6a8bea001bf 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1163,7 +1163,7 @@ macro_rules! iterator { /// Immutable slice iterator #[experimental = "needs review"] -pub struct Items<'a, T> { +pub struct Items<'a, T: 'a> { ptr: *const T, end: *const T, marker: marker::ContravariantLifetime<'a> @@ -1206,7 +1206,7 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> { /// Mutable slice iterator. #[experimental = "needs review"] -pub struct MutItems<'a, T> { +pub struct MutItems<'a, T: 'a> { ptr: *mut T, end: *mut T, marker: marker::ContravariantLifetime<'a>, |
