cksac
March 18, 2022, 9:36am
1
Given:
pub struct Children<'a> {
tape: &'a mut [Slot],
cursors: Vec<usize>, // some non-overlapping indexes within tape
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Slot> {
// Failed:
// self.cursors.iter().filter_map(|c| self.tape.get_mut(*c))
// Ok:
self.tape
.iter_mut()
.enumerate()
.filter(|(i, _)| self.cursors.contains(&i))
.map(|(_, s)| s)
}
Any idea to not loop all item in self.tape?
1 Like
alice
March 18, 2022, 10:09am
2
If your indexes are sorted, then you could probably get it to with a split_at_mut
thing, but otherwise you can only do it with unsafe or by looping through everything with iter_mut
.
1 Like
cksac
March 18, 2022, 10:44am
3
unsafe version, should be ok if make sure self.cursors is non-overlapping ?
self.cursors.iter().map(|c| unsafe {
let ptr = self.tape.get_unchecked_mut(*c) as *mut Slot;
&mut *ptr
})
alice
March 18, 2022, 10:48am
4
Well, it's a bit complicated because the full slice will overlap with the previously returned mutable references, so touching the full slice again invalidates those previous references. It's better to use a raw pointer like this:
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Slot> {
let ptr = self.tape.as_mut_ptr();
self.cursors.iter().map(move |c| unsafe {
let elem_ptr = ptr.add(*c);
&mut *elem_ptr
})
}
Obviously, the above code is only correct if you know up-front that all indexes are in-bounds and that they are all distinct.
2 Likes
Safe version, assuming cursors
is sorted:
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Slot> {
let mut next_idx = 0;
let mut tape = self.tape.iter_mut();
self.cursors
.iter()
.filter_map(move |&idx| {
let value = tape.nth(idx - next_idx);
next_idx = idx + 1;
value
})
}
5 Likes
system
Closed
June 16, 2022, 10:55am
6
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.