Implement owned ops for HashSet and BTreeSet#109402
Implement owned ops for HashSet and BTreeSet#109402WaffleLapkin wants to merge 3 commits intorust-lang:masterfrom
HashSet and BTreeSet#109402Conversation
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. |
|
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: Clonebounds (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
selfowned (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