Skip to content

Add lifetime bounds on Items and MutItems. #16993

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 3, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/libcollections/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ struct AbsEntries<T> {
}

/// An iterator over a BTreeMap's entries.
pub struct Entries<'a, K, V> {
pub struct Entries<'a, K: 'a, V: 'a> {
inner: AbsEntries<Traversal<'a, K, V>>
}

/// A mutable iterator over a BTreeMap's entries.
pub struct MutEntries<'a, K, V> {
pub struct MutEntries<'a, K: 'a, V: 'a> {
inner: AbsEntries<MutTraversal<'a, K, V>>
}

Expand Down
92 changes: 77 additions & 15 deletions src/libcollections/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,11 +845,16 @@ 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 = if mem::size_of::<T>() == 0 {
(ptr as uint + self.len()) as *const T
} else {
ptr.offset(self.len() as int) as *const T
};
mem::forget(self);
MoveItems { allocation: ptr, cap: cap, iter: iter }
MoveItems { allocation: ptr, cap: cap, ptr: begin, end: end }
}
}

Expand Down Expand Up @@ -1773,7 +1778,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> {
Expand All @@ -1782,7 +1788,7 @@ impl<T> MoveItems<T> {
pub fn unwrap(mut self) -> Vec<T> {
unsafe {
for _x in self { }
let MoveItems { allocation, cap, iter: _iter } = self;
let MoveItems { allocation, cap, ptr: _ptr, end: _end } = self;
mem::forget(self);
Vec { ptr: allocation, cap: cap, len: 0 }
}
Expand All @@ -1793,29 +1799,55 @@ 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))
}
}

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)))
}
}
}
}
}
Expand Down Expand Up @@ -2533,6 +2565,36 @@ mod tests {
assert_eq!(v.map_in_place(|_| ZeroSized).as_slice(), [ZeroSized, ZeroSized].as_slice());
}

#[test]
fn test_move_items() {
let mut vec = vec!(1i, 2, 3);
let mut vec2 : Vec<int> = vec!();
for i in vec.into_iter() {
vec2.push(i);
}
assert!(vec2 == vec!(1i, 2, 3));
}

#[test]
fn test_move_items_reverse() {
let mut vec = vec!(1i, 2, 3);
let mut vec2 : Vec<int> = vec!();
for i in vec.into_iter().rev() {
vec2.push(i);
}
assert!(vec2 == vec!(3i, 2, 1));
}

#[test]
fn test_move_items_zero_sized() {
let mut vec = vec!((), (), ());
let mut vec2 : Vec<()> = vec!();
for i in vec.into_iter() {
vec2.push(i);
}
assert!(vec2 == vec!((), (), ()));
}

#[bench]
fn bench_new(b: &mut Bencher) {
b.iter(|| {
Expand Down
4 changes: 2 additions & 2 deletions src/libcore/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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>,
Expand Down