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

Tracking Issue for map_many_mut #97601

Closed
4 tasks done
Urgau opened this issue May 31, 2022 · 33 comments · Fixed by #136152
Closed
4 tasks done

Tracking Issue for map_many_mut #97601

Urgau opened this issue May 31, 2022 · 33 comments · Fixed by #136152
Labels
C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@Urgau
Copy link
Member

Urgau commented May 31, 2022

Feature gate: #![feature(map_many_mut)]

This is a tracking issue for the HashMap::get_disjoint{,_unchecked}_mut functions (previously get_many_mut and get_many_unchecked_mut).

Attempts to get mutable references to N values in the map at once.

Public API

// in HashMap

pub fn get_disjoint_mut<Q: ?Sized, const N: usize>(
    &mut self,
    ks: [&Q; N]
) -> [Option<&'_ mut V>; N]
where
    K: Borrow<Q>,
    Q: Hash + Eq;

pub unsafe fn get_disjoint_unchecked_mut<Q: ?Sized, const N: usize>(
    &mut self,
    ks: [&Q; N],
) -> [Option<&'_ mut V>; N]
where
    K: Borrow<Q>,
    Q: Hash + Eq;

Steps / History

Unresolved Questions

@Urgau Urgau added C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels May 31, 2022
@ibraheemdev
Copy link
Member

Would it be better for this to return Result<[Option<&mut V>; N], DuplicateKeys>?

@Urgau
Copy link
Member Author

Urgau commented Jun 6, 2022

Would it be better for this to return Result<[Option<&mut V>; N], DuplicateKeys>?

I don't think so, returning a Result<_, DuplicateKeys> would different from any other get methods on HashMap; they all return Option<_> of something; And returning a individual Option for every entry would completely change the semantic of the function and make things more difficult for peoples who wants all or nothing to achieve it.

@Arnavion
Copy link

And returning a individual Option for every entry would completely change the semantic of the function and make things more difficult for peoples who wants all or nothing to achieve it.

Sure, but the current implementation makes things more difficult for people who want to do multiple lookups in parallel and then do some mutations based on which keys exist and don't exist.

Returning [Option<&mut>] would not only provide strictly more information, but can be converted to Option<[&mut]> using result.try_map(std::convert::identity) (as suggested by AstrallyForged on IRC).


If I follow the history correctly, the libstd implementation returns Option<[&mut]> because hashbrown's does. hashbrown's implementation originally returned [Result<&mut>] but this was then changed to Option<[&mut]> to align with libstd's [T]::get_many_mut. So perhaps we need to start there.

bors added a commit to rust-lang-ci/rust that referenced this issue Jun 21, 2022
Use get_many_mut to reduce the cost of setting up check cfg values

This PR use the newly added [`get_many_mut`](rust-lang#97601) function in [`HashMap`](https://doc.rust-lang.org/nightly/std/collections/hash_map/struct.HashMap.html#method.get_many_mut) to reduce the cost of setting up the initial check cfg values.

cc `@petrochenkov`
@workingjubilee
Copy link
Member

Bikesheddy note: this is very similar to the notion of a "gather" (a la Simd::gather_*) and that term is used extensively in similar interfaces (though it is also called something like "indexed vector load" in some cases).

@forrestli74
Copy link

This seems very restrictive on the number of elements at the same time. Would be nice to have a version that supports Vec or Iterator of some sort. We don't have to support the general form now, but should think about how to design the API that adding general form is easy.

@mqudsi
Copy link
Contributor

mqudsi commented Dec 1, 2022

Are there any performance benefits to this other than eliminating a for loop caller-side? Can someone explain the motivation or a use-case for this, given that the code this replaces is rather short and to-the-point?

@smarnach
Copy link
Contributor

smarnach commented Dec 5, 2022

@mqudsi It's currently impossible in safe code to get simultaneous mutable references to different values in a HashMap, and the unsafe code needed to do this in a sound way is not straightforward at all. You can easily get shared references to multiple values, which is why there is only get_many_mut() and no get_many(), but for multiple mutable references the new function is helpful.

@Uriopass
Copy link
Contributor

What about BTreeMap ? Would it be possible to have get_many_mut and get_many_unchecked_mut there too ?

@Darksonn
Copy link
Contributor

and the unsafe code needed to do this in a sound way is not straightforward at all

Can it be done at all?

@nagisa
Copy link
Member

nagisa commented May 18, 2023

Rather than returning references to values, could this be an entry-based API instead? That would forgo the questions about people wanting to potentially make multiple lookups without them necessarily failing if some of them are missing. The current proposed function could easily be built on top of an entry-based API, but vice-versa is not possible.

@Arnavion
Copy link

Does it work to have multiple Entrys in flight simultaneously? Changing one of them from Vacant to Occupied might require reallocation which would invalidate the other Occupieds.

tamird added a commit to aya-rs/aya that referenced this issue Aug 11, 2023
Store programs in a `hashbrown::HashMap` and expose `get_many_mut`. We
can revisit this dependency when
rust-lang/rust#97601 is resolved.
@JustForFun88
Copy link

This seems very restrictive on the number of elements at the same time. Would be nice to have a version that supports Vec or Iterator of some sort...

I implemented a similar thing in this pull request: rust-lang/hashbrown#408

@ilyvion
Copy link

ilyvion commented Nov 11, 2023

This seems very restrictive on the number of elements at the same time. Would be nice to have a version that supports Vec or Iterator of some sort...

I implemented a similar thing in this pull request: rust-lang/hashbrown#408

I don't see how that does what was requested. As far as I can tell based on that PR, your changes still require a const N: usize, i.e. it's a decided-at-compile-time number of queries and results, not a decided-at-runtime number of queries and results like Vec or a non-array-based iterator could support.

@DrAlta
Copy link

DrAlta commented Mar 16, 2024

What about BTreeMap ? Would it be possible to have get_many_mut and get_many_unchecked_mut there too ?

I assume they are waiting for this to reach stable for HashMaps before bringing it to BTreeMap.

But if you just want something that works

https://github.com/DrAlta/rust_quality_of_life.git

implements .get_many_mut() for BTreeMap in the GetManyMut trait

Thou it doesn't go poking around the innards of the BTreeMap it just iters over it and returns the wanted bits.

@Urgau Urgau added the I-libs-api-nominated Nominated for discussion during a libs-api team meeting. label Sep 17, 2024
@joshtriplett
Copy link
Member

We just had a very long conversation about this in today's @rust-lang/libs-api method.

The outcome of that discussion was that we'd like to change the signatures to:

// in HashMap

/// # Panics
///
/// Panics if the same index was passed more than once.
pub fn get_many_mut<Q: ?Sized, const N: usize>(
    &mut self,
    ks: [&Q; N]
) -> [Option<&'_ mut V>; N]
where
    K: Borrow<Q>,
    Q: Hash + Eq;

/// UB if the same index was passed more than once.
pub unsafe fn get_many_unchecked_mut<Q: ?Sized, const N: usize>(
    &mut self,
    ks: [&Q; N],
) -> [Option<&'_ mut V>; N]
where
    K: Borrow<Q>,
    Q: Hash + Eq;

The two changes here are 1) panicking on duplicate indexes and 2) returning an array of Option rather than an Option of array.

Our rationales for both of these are based on an expected usage model of either having an array of N keys that are statically known at compile time or having an array of most commonly 2 or perhaps 3 keys that are dynamically supplied by the user.

Rationale for 1: In the static case you know there aren't duplicates, and in the dynamic case you have few enough items that you can easily if k1 == k2 (or if src_key == dest_key) and that you probably want to check that case in advance to give a better error and avoid doing the lookups.

Rationale for 2: In the dynamic case, we expect the common case to be 2 keys, and it's extremely easy to let [Some(v1), Some(v2)] = map.get_many_mut([k1, k2]) else { ... }, or use a match if you want to be able to handle those cases. We expect that people will commonly want to report "source doesn't exist" vs "destination doesn't exist", or handle those cases such as by creating the missing value. In the static case, you might want the unchecked variant for performance if you know every item will exist, or you might want to call .expect, but it'd be trivial to provide a helper method .transpose() that turns array-of-Option into Option-of-array (and we think that method should exist; it already does for array-of-MaybeUninit).

@rfcbot rfcbot removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Dec 4, 2024
@Amanieu
Copy link
Member

Amanieu commented Dec 4, 2024

@rfcbot merge

@rfcbot
Copy link

rfcbot commented Dec 4, 2024

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.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Dec 4, 2024
@Amanieu
Copy link
Member

Amanieu commented Dec 10, 2024

We discussed this in the libs-api meeting and most of the team preferred get_disjoint_mut for both slices and HashMap. Restarting the FCP again!

@rfcbot cancel

@rfcbot
Copy link

rfcbot commented Dec 10, 2024

@Amanieu proposal cancelled.

@rfcbot rfcbot removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Dec 10, 2024
@Amanieu
Copy link
Member

Amanieu commented Dec 10, 2024

@rfcbot merge

@rfcbot
Copy link

rfcbot commented Dec 10, 2024

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.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Dec 10, 2024
@Urgau
Copy link
Member Author

Urgau commented Jan 20, 2025

@joshtriplett @m-ou-se @BurntSushi could one of you take a look at the FCP above, there is only one checkbox missing.

@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Jan 27, 2025
@rfcbot
Copy link

rfcbot commented Jan 27, 2025

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. to-announce Announce this issue on triage meeting and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Feb 6, 2025
@rfcbot
Copy link

rfcbot commented Feb 6, 2025

The final comment period, with a disposition to merge, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

This will be merged soon.

@BurntSushi
Copy link
Member

Noting that #136152 has the name change suggested about (get_disjoint_mut).

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Feb 6, 2025
…shtriplett

Stabilize `map_many_mut` feature

This PR stabilize `HashMap::get_many_mut` as `HashMap::get_disjoint_mut` and `HashMap::get_many_unchecked_mut` as `HashMap::get_disjoint_unchecked_mut` per FCP.

FCP at rust-lang#97601 (comment)
Fixes rust-lang#97601
r? libs
@bors bors closed this as completed in 0fb72ee Feb 7, 2025
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Feb 7, 2025
Rollup merge of rust-lang#136152 - Urgau:stabilize-map_many_mut, r=joshtriplett

Stabilize `map_many_mut` feature

This PR stabilize `HashMap::get_many_mut` as `HashMap::get_disjoint_mut` and `HashMap::get_many_unchecked_mut` as `HashMap::get_disjoint_unchecked_mut` per FCP.

FCP at rust-lang#97601 (comment)
Fixes rust-lang#97601
r? libs
@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Feb 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.