-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Tracking Issue for get_many_mut #104642
Comments
Is there a reason that |
Since fn get_many_check_valid<const N: usize>(indices: &[usize; N], len: usize) -> bool {
let mut valid = true;
if N <= 10 {
// NB: The optimzer should inline the loops into a sequence
// of instructions without additional branching.
for (i, &idx) in indices.iter().enumerate() {
valid &= idx < len;
for &idx2 in &indices[..i] {
valid &= idx != idx2;
}
}
} else {
let mut sorted = *indices;
sorted.sort_unstable();
for i in 1..N {
valid &= sorted[i-1] < sorted[i];
}
valid &= sorted[N-1] < len;
}
valid
} On another note, perhaps we should have a |
I also like the idea of DisjointedIndices for this. And since a pair of indices is likely a common use case for this, perhaps something that could be available would be something like disjoint_pair(lhs: usize, rhs: usize) -> DisjointIndices<2> (panics if lhs == rhs). |
I've tried to use this a few times now. The fact that the current placeholder error type doesn't distinguish out-of-bounds vs duplicate indices makes it hard to even test in something resembling a real use case. For example, if you wanted to implement slice::swap via slice::get_many_mut (not saying you should), you'd want the duplicate index case to be a nop, but you'd still want the out-of-bounds case to panic. A lot of my hypothetical use cases for get_many_mut have this "multi-object transaction" flavor to them. Related: Would it make sense to have an implementation of IndexMut for [usize; N] that panics in the duplicates case? The duplicate indices issue seems like it falls into the same bucket of dynamic borrow conflicts you have with RefCell::borrow/borrow_mut (which panics unlike try_borrow/try_borrow_mut), so it seems like a reasonable behavior when you have an upstream invariant that is expected to guarantee uniqueness but you still need the dynamic check for safety. Splitting the duplicate checking via a DisjointIndices type seems to help with some of these issues as well. In the case of get_many_mut, it means you only have one type of error (out of bounds) as with the plain get method. And if we eventually end up with all these related APIs (e.g. Index and IndexMut can be implemented for DisjointIndices), the stage separation of disjoint index handling helps to eliminate redundancy in both the implementation and interfaces (e.g. error types). And in the aforementioned case where you have upstream invariants that guarantee uniqueness, it means you can propagate that invariant using a DisjointIndices value as a proof witness. (The proof witness idea also works for bounds checking. It doesn't make much sense for a singular index with a known bound since that known bound must still be checked against the slice length, but once you have multiple indices packaged together with a known bound it means you can get away with only one bounds check against the slice length instead of one for each index.) |
For embedded use cases, I'd strongly prefer we limit the number of panics added by this feature, limiting it only to out-of-bounds as it is today.
There's not really a way to implement The same applies to |
There is also this crate that introduces some macros and methods for retrieving multiple mutable indices from a mutable slice https://crates.io/crates/indices . It uses insertion sort so more optimized towards a small number of indices and near sorted indices. It also has macros that assume the input is already sorted, requiring no sorting at all. |
If there isn't any specific reason not to do this, I think we should change to an interface based on fn get_many_mut<I, const N: usize>(
&mut self,
indices: [I; N],
) -> Result<[&mut <I as SliceIndex<[T]>>::Output; N], GetManyMutError<N>>
where
// If we switch to using `DisjointIndices` as suggested above, `Ord` is not
// needed here.
I: SliceIndex<[T]> + Ord
{ /* ... */ } Cc @ChayimFriedman2 since you have a stabilization PR up. |
If it's going to go through a trait, should it perhaps be That would leave space open to also allow things like |
I make a POC to experiment with this idea. |
We discussed this in the libs-api meeting yesterday and concluded that we are mostly happy with the shape that the API has today. We would like it to be extended to support any index that implements |
Attempting to answer this based on what I half-remember from the meeting: The 99% case here is 2 (or maybe 3) indices. As such, there's should not be a requirement that they're sorted, and there's no need to do optimizations for many-index cases. Someone looking to use a more complicated scenario -- which wants to pre-check disjointness or sortedness of indices, say -- is expected to make their own wrapper around |
@Amanieu Is the team interested in adding range support now, or deferring it? Also, it may cause inference problems later if we make it generic. |
Yes, we would like to add range support now. |
|
@Amanieu Did you discuss whether the error should include more details? |
I'll nominate that for discussion in our next meeting. |
We discussed this in today's @rust-lang/libs-api meeting. We'd like to stabilize this, using the signature that accepts an array of SliceIndex types. The error should be a two-variant enum (one variant for overlaps and one variant for out-of-bounds) that doesn't carry any data and doesn't have a generic parameter. @rfcbot merge |
Team member @joshtriplett has proposed to merge this. The next step is review by the rest of the tagged team members: Concerns: Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
Ah, I thought we were talking about a |
Rollup merge of rust-lang#133136 - ChayimFriedman2:get-many-mut, r=Amanieu Support ranges in `<[T]>::get_many_mut()` As per T-libs-api decision in rust-lang#104642. I implemented that with a separate trait and not within `SliceIndex`, because doing that via `SliceIndex` requires adding support for range types that are (almost) always overlapping e.g. `RangeFrom`, and also adding fake support code for `impl SliceIndex<str>`. An inconvenience that I ran into was that slice indexing takes the index by value, but I only have it by reference. I could change slice indexing to take by ref, but this is pretty much the hottest code ever so I'm afraid to touch it. Instead I added a requirement for `Clone` (which all index types implement anyway) and cloned. This is an internal requirement the user won't see and the clone should always be optimized away. I also implemented `Clone`, `PartialEq` and `Eq` for the error type, since I noticed it does not do that when writing the tests and other errors in std seem to implement them. I didn't implement `Copy` because maybe we will want to put something non-`Copy` there.
I agree that |
|
I personally prefer the current |
Another alternative is |
What about:
This way, developers can find both |
We discussed this in the libs-api meeting today and decided to change the name to @rfcbot cancel |
@Amanieu proposal cancelled. |
@rfcbot merge |
Team member @Amanieu has proposed to merge this. The next step is review by the rest of the tagged team members: Concerns:
Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
Also note that the error type still needs to be changed as we decided in a previous meeting. |
Was something like |
In |
@rfcbot concern Consider |
We discussed this in the libs-api meeting and most of the team preferred @rfcbot cancel |
@Amanieu proposal cancelled. |
@rfcbot merge |
Team member @Amanieu has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
Feature gate:
#![feature(get_many_mut)]
This is a tracking issue for
get_many_mut
andget_many_unchecked_mut
, which provide&mut T
access to multiple distinct slice elements.Public API
Steps / History
Unresolved Questions
get_many_mut([0..3, 4..6])
)?O(n^2)
time?Footnotes
https://std-dev-guide.rust-lang.org/feature-lifecycle/stabilization.html ↩
The text was updated successfully, but these errors were encountered: