-
Notifications
You must be signed in to change notification settings - Fork 321
Add support for slicing with subviews #369
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
Conversation
The same assertion occurs in `self.islice()`, so this one is redundant.
I think it looks great. I don't always have time during the week to give so much feedback, not if I want it to be well thought out 😄 (Yes serialization for IxDyn was implemented in a half sedated state.) I think I'll only have minor comments and curious questions through out |
src/impl_methods.rs
Outdated
pub fn slice<I, T, Do>(&self, info: I) -> ArrayView<A, Do> | ||
where | ||
I: Borrow<SliceInfo<T, Do>>, | ||
T: Borrow<D::SliceArg>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I would like to avoid the T parameter and simplify the types here, ideally using
SliceInfo<D::SliceArg, ...
, but I see that it's not exactly easy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... Removing the T
parameter is difficult because s!
always returns a SliceInfo<T, D>
where T
is a fixed-length array. The constraint could be I: Borrow<SliceInfo<D::SliceArg, Do>>
for Ix0
to Ix6
, but this wouldn't work for IxDyn
because IxDyn::SliceArg = [SliceOrIndex]
. There are a few possible alternatives:
slice()
could be implemented separately for each dimensionD
, so forIx0
toIx6
, theT
parameter wouldn't be necessary.- I think it would be possible to change the constraint to
&'a I: Into<SliceInfo<&'b D::SliceArg, Do>>
, but that adds lifetime parameters, which IMHO are worse than a type parameter. - If
IxDyn::SliceArg = Vec<SliceOrIndex>
, then I think it would be possible to change the constraint toI: Into<SliceInfo<D::SliceArg, Do>>
, but that would mean thatslice()
would take ownership of theinfo
parameter, which is not desirable. - If
IxDyn::SliceArg = Vec<SliceOrIndex>
, then I think it would be possible to change the constraint to&'a I: Into<SliceInfo<D::SliceArg, Do>>
, but that would require theinfo
argument to be a reference, which is not really desirable (see below).
It would be possible to remove the I
parameter and instead make the signature pub fn slice<T, Do>(&self, info: &SliceInfo<T, Do>) -> ArrayView<A, Do>
. However, that would mean that info
has to be a reference, which would make usage with the s!
macro less clean: arr.slice(&s![1..4, 3])
. (It would be possible to make the s!
macro to return &SliceInfo
instead of SliceInfo
, but as far as I know, then the &SliceInfo
couldn't leave the scope where it was created, so it couldn't be returned from a function.)
In conclusion, in my limited Rust knowledge, the best options are requiring slice(&s![])
or requiring the extra I
parameter. If you'd like me to remove I
and require slice(&s![])
, or if you have any other ideas, please let me know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will look at this in detail late. Looks possible to use &SliceInfo< [SliceorIndex]>
for the ixdyn case, as long as the macro makes that but a fixed size array instead.
src/impl_methods.rs
Outdated
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) | ||
pub fn islice<I>(&mut self, info: I) | ||
where | ||
I: AsRef<[SliceOrIndex]>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method loses the static length check this way. It would be ideal to keep it, but it's a less used method so not that important.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. I just pushed a fix to keep compile-type length checking.
src/impl_methods.rs
Outdated
/// | ||
/// **Panics** if an index is out of bounds or stride is zero.<br> | ||
/// **Panics** if `axis` is out of bounds. | ||
pub fn slice_axis(&self, axis: Axis, indices: &Si) -> ArrayView<A, D> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great little methods, they are overdue! -- Si is a simple copy type, so I'd pass it by reference or remodel the argument here (break into its parts, or?).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean pass-by-value instead of pass-by-reference? If so, I just pushed a commit to change it to pass-by-value. Keeping the argument as Si
instead of breaking it into parts is nice because there are convenient From<Range*> for Si
implementations.
I understand, no worries. :) Thanks for looking at it today!
Since you like the approach, I'll work on updating the documentation and adding more tests. |
Minor note, we don't have to worry too much about Rust < 1.21. We have promised in our docs to jump to newer rust versions to advance the library, and Rust 1.21 brings the needs_drop function which will be a great help to us. |
This also adds `.is_slice()` and `is_index()` methods to `SliceOrIndex`.
I successfully removed the Edit: I'm a little uncomfortable about the Edit2: It turns out I can replace the |
Looks cool! The now we can make the final transition to |
@bluss I'm working on cleaning up this PR in preparation for merging. I have a few questions:
|
|
I think the current version of the implementation is pretty good, although I'm somewhat unsatisfied about the need to call |
We can change islice like that later. I think we've achieved a pretty good interface here. It may be hard for me to avoid tinkering with it after merging, I'd primarily see if there is a neater way to build the phantom dimension type. For now, I'd put #[repr(C)] on the SliceInfo struct, should make the raw pointer cast we do even less problematic. |
Naming of the slice methods. This may be too much of brainstorming, don't know if it works.
drawback: pretty breaking |
We could also try |
Regarding naming, I think I prefer your first suggestion:
For Another option is Another option is
which makes it easy for users to update their code. The |
Yet another option is
I think my favorite option so far is:
|
Let's go with that. One concern is that |
This maintains consistency with .slice_move().
Can we keep into_subview? |
Sure; I just assumed that you'd want it to name it like |
This reverts commit 5bc5cd3.
I also renamed |
@jturner314 Yeah I think that's a good call, |
Should the third member of |
step size sounds good, it doesn't mix the concepts. It's a multiplicative stride I guess? If we have a row stride of 12 and slice with step size 2, the new stride is 24. |
Thanks a lot for working on this cool feature. Please update PR description and rebase & squash the commits so that we are ready to merge. I think it's ready, what do you think? |
Oh that said, maybe I should look over if there are any non-breaking changes I can merge first. |
I cleaned up the commit history and created a new ready-to-merge PR #377. I edited the history to try and make it as easy as possible to read (primarily by minimizing the size of the commit that adds |
Please don't merge this PR immediately. It needs some refinement, including updated documentation and more tests.
This is an implementation of #215, adding support for taking subviews while slicing. A few of the changes are:
s!
macro can take individual indices (to indicate subviews) in addition to ranges.s!
macro returns an ownedSliceInfo
instance instead of just a reference, so the caller can easily pass it around between methods.*slice*()
methods now take aSliceInfo
instance (or reference).slice_into()
method. Note that ideally we'd come up with a better name thanslice_into
because there's already aninto_slice()
method.ArrayBase
now has three additional methods*slice_axis*()
that slice along a single axis.The primary disadvantage of this change is that it's not easy to create a
SliceInfo
instance without thes!
macro. If that's an important feature, it would be possible to do any (or all) of the following:impl<'a> From<&'a [SliceOrIndex]> for SliceInfo<Vec<SliceOrIndex>, IxDyn>
.[SliceOrIndex; n]
intoSliceInfo<[SliceOrIndex; n], D>
, whereD
is determined at compile time.[SliceOrIndex; n]
intoSliceInfo<[SliceOrIndex; n], D>
, where the caller would have to specifyD
, andD
would be checked at runtime.Note that this PR is a breaking change.
Will you please let me know what you think?