Skip to content
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

Add method .remove_index(axis, index) #967

Merged
merged 6 commits into from
Apr 9, 2021
Merged

Add method .remove_index(axis, index) #967

merged 6 commits into from
Apr 9, 2021

Conversation

bluss
Copy link
Member

@bluss bluss commented Apr 4, 2021

Add method to remove the indexth entry along all lanes of axis.
The method doesn't change the number of initialized elements, just like slicing in place works
(this could be confusing, w.r.t remove semantics).

Fixes #931

@bluss
Copy link
Member Author

bluss commented Apr 4, 2021

This is my approach. Safe version (commit 1) and optimized (commit 2) are not so far apart, and they should be pretty good and remarkably simple as a first approach. They don't change the number of initialized elements, just like slicing in place works.

Copy link
Member

@jturner314 jturner314 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swapping along lanes like this is a nice solution, and the temporary variable to avoid unnecessary writes is nice, too.

src/impl_methods.rs Outdated Show resolved Hide resolved
let mut slot = MaybeUninit::<A>::uninit();
unsafe {
slot.as_mut_ptr().copy_from_nonoverlapping(dst, 1);
for elt in lane_iter {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If lane_iter.next() panics, then an element will be dropped twice, and, less importantly, the element in slot won't be dropped. I don't think the current implementation can panic, but this still makes me uncomfortable. I'd feel more comfortable with getting a raw pointer to the start of the lane, the stride for the axis, and then .offset()ting the pointer by the stride on each iteration, because this would be easier to audit for potential panics.

Copy link
Member Author

@bluss bluss Apr 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I know this is a no-panic section and it should be marked. I was comfortable apparently, but I had a thought to maybe leave an "abort on panic" guard here to make it entirely visible. (What do you think?)

As for a simpler iteration, in that case we should implement a special 1D iterator that does just that (even though Zip is already doing about the same job). I don't want to write out a raw pointer loop, ndarray probably needs a bit more use of higher level abstractions, not less 🙂

src/impl_methods.rs Outdated Show resolved Hide resolved
src/impl_methods.rs Outdated Show resolved Hide resolved
let mut slot = MaybeUninit::<A>::uninit();
unsafe {
slot.as_mut_ptr().copy_from_nonoverlapping(dst, 1);
for elt in lane_iter {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, src would be a clearer name than elt.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm matter of taste that I haven't addressed

src/impl_methods.rs Show resolved Hide resolved
// use swap to keep all elements initialized (as required by owned storage)
Zip::from(tail.lanes_mut(axis)).for_each(|mut lane| {
let mut lane_iter = lane.iter_mut();
let mut dst = if let Some(dst) = lane_iter.next() { dst } else { return };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we panic on the index == self.len_of(axis) case as I suggested above, the None case cannot occur.

Copy link
Member Author

@bluss bluss Apr 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Type system wise the existing code is neat enough, don't know if anything else is worthwhile?

src/impl_methods.rs Outdated Show resolved Hide resolved
@bluss bluss added this to the 0.15.2 milestone Apr 5, 2021
@bluss bluss changed the title Add method .shift_remove_index(axis, index) Add method .remove_index(axis, index) Apr 5, 2021
@bluss bluss force-pushed the shift-remove branch 2 times, most recently from 497169e to 5b6b215 Compare April 9, 2021 16:33
bluss and others added 6 commits April 9, 2021 21:17
Removing the index-past-the end does not make sense (it's an ok split
index, so the previous code passed through without action).
It's a critical section where we can't panic. Mark the reason in the
guard and message.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Method to remove index along axis
2 participants