-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Implement owned ops for HashSet
and BTreeSet
#109402
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
@rust-lang/libs-api: This adds the following binary operator impls shown in bold below. There is a pre-existing more restrictive impl corresponding to each one; the additional bounds required by the pre-existing impls are noted below. All of the following require
All of the following require
|
Team member @dtolnay 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. |
Add `minmax{,_by,_by_key}` functions to `core::cmp` This PR adds the following functions: ```rust // mod core::cmp #![unstable(feature = "cmp_minmax")] pub fn minmax<T>(v1: T, v2: T) -> [T; 2] where T: Ord; pub fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2] where F: FnOnce(&T, &T) -> Ordering; pub fn minmax_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> [T; 2] where F: FnMut(&T) -> K, K: Ord; ``` (they are also `const` under `#[feature(const_cmp)]`, I've omitted `const` stuff for simplicity/readability) ---- Semantically these functions are equivalent to `{ let mut arr = [v1, v2]; arr.sort(); arr }`, but since they operate on 2 elements only, they are implemented as a single comparison. Even though that's basically a sort, I think "sort 2 elements" operation is useful on it's own in many cases. Namely, it's a common pattern when you have 2 things, and need to know which one is smaller/bigger to operate on them differently. I've wanted such functions countless times, most recently in rust-lang#109402, so I thought I'd propose them. ---- r? libs-api
Rollup merge of rust-lang#109409 - WaffleLapkin:progamer, r=dtolnay Add `minmax{,_by,_by_key}` functions to `core::cmp` This PR adds the following functions: ```rust // mod core::cmp #![unstable(feature = "cmp_minmax")] pub fn minmax<T>(v1: T, v2: T) -> [T; 2] where T: Ord; pub fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2] where F: FnOnce(&T, &T) -> Ordering; pub fn minmax_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> [T; 2] where F: FnMut(&T) -> K, K: Ord; ``` (they are also `const` under `#[feature(const_cmp)]`, I've omitted `const` stuff for simplicity/readability) ---- Semantically these functions are equivalent to `{ let mut arr = [v1, v2]; arr.sort(); arr }`, but since they operate on 2 elements only, they are implemented as a single comparison. Even though that's basically a sort, I think "sort 2 elements" operation is useful on it's own in many cases. Namely, it's a common pattern when you have 2 things, and need to know which one is smaller/bigger to operate on them differently. I've wanted such functions countless times, most recently in rust-lang#109402, so I thought I'd propose them. ---- r? libs-api
It's going to be a small but weird asymmetry and an ergonomics papercut if some operators can take owned arguments and others cannot. Adding all the combinations would also fix the issue that code like |
☔ The latest upstream changes (presumably #128672) made this pull request unmergeable. Please resolve the merge conflicts. |
Approving this, but also, please do update the PR to support |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
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. |
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.
Thank you!
I rebased to fix a trivial conflict with #128309 in library/alloc/src/collections/btree/set.rs.
|
I am on board with those new impls, but it'll need another FCP with the team so let's leave this to a followup PR. |
@bors r+ |
The job Click to see the possible cause of the failure (guessed by this bot)
|
@bors r- |
Method syntax like use std::collections::BTreeSet;
use std::ops::BitAnd;
fn f(a: BTreeSet<i32>, b: BTreeSet<i32>) {
let a = (a,);
let _ = a.0.bitand(&b);
drop(a.0);
} error[E0382]: use of moved value: `a.0`
--> src/main.rs:7:10
|
6 | let _ = a.0.bitand(&b);
| ---------- `a.0` moved due to this method call
7 | drop(a.0);
| ^^^ value used here after move
|
note: `bitand` takes ownership of the receiver `self`, which moves `a.0`
--> /git/rust/library/core/src/ops/bit.rs:161:15
|
161 | fn bitand(self, rhs: Rhs) -> Self::Output;
| ^^^^
= note: move occurs because `a.0` has type `BTreeSet<i32>`, which does not implement the `Copy` trait
help: you can `clone` the value and consume it, but this might not be your desired behavior
|
6 | let _ = a.0.clone().bitand(&b);
| ++++++++ |
Unfortunate that this happens, but ig there is nothing to do. Closing since this introduces a regression. |
This PR implements
ops::{BitAnd, BitOr, BitXor, Sub}
where one, or both arguments are owned (previously we only had impls for references to sets).The main advantage of these impls is lifted
T: Clone
bounds (and, in case ofHashSet
, liftedS: Default
). The secondary one is being able to reuse allocations. Lastly, they may (or may not) be more performant.Added public APIs (insta-stable):
I only added the "important" impls, i.e. such that allow lifting the bounds. Thus union-like ops (or, xor) have both arguments owned (because they need elements from both sets), while difference-like ops (sub, and) have only
self
owned (that's sufficient to not clone elements).Other potentially interesting implementations (in the order of most to least interesting according to myself):
BitAnd<Set<T, ...>> for Set<T, ...>
— optimization potential (can keep either allocation/iterate either set)BitOr<&Set<T, ...>> for Set<T, ...>
andBitOr<&Set<T, ...>> for Set<T, ...>
— still requireT: Clone
, but can keep the allocation/hasherBitOr<Set<T, ...>> for &Set<T, ...>
andBitOr<Set<T, ...>> for &Set<T, ...>
could be added for completenessBitAnd<Set<T, ...>> for &Set<T, ...>
— symmetry for completenessSub<Set<T, ...>> for Set<T, ...>
andSub<Set<T, ...>> for &Set<T, ...>
— completeness (no bounds lifting/optimization gains)r? libs-api