Skip to content

Commit a2df222

Browse files
committed
Add implementations of ops for HashSet that keep ownership
1 parent 777b15f commit a2df222

File tree

1 file changed

+133
-0
lines changed
  • library/std/src/collections/hash

1 file changed

+133
-0
lines changed

library/std/src/collections/hash/set.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,38 @@ where
11471147
}
11481148
}
11491149

1150+
#[stable(feature = "set_owned_ops", since = "CURRENT_RUSTC_VERSION")]
1151+
impl<T, S> BitOr<HashSet<T, S>> for HashSet<T, S>
1152+
where
1153+
T: Eq + Hash,
1154+
S: BuildHasher,
1155+
{
1156+
type Output = HashSet<T, S>;
1157+
1158+
/// Returns the union of `self` and `rhs` as a new `HashSet<T, S>`.
1159+
///
1160+
/// # Examples
1161+
///
1162+
/// ```
1163+
/// use std::collections::HashSet;
1164+
///
1165+
/// let a = HashSet::from([1, 2, 3]);
1166+
/// let b = HashSet::from([3, 4, 5]);
1167+
///
1168+
/// let result = a | b;
1169+
/// assert_eq!(result, HashSet::from([1, 2, 3, 4, 5]));
1170+
/// ```
1171+
fn bitor(self, rhs: HashSet<T, S>) -> HashSet<T, S> {
1172+
// Try to avoid allocations by keeping set with the bigger capacity,
1173+
// try to avoid unnecessary moves, by keeping set with the bigger length
1174+
let [a, mut b] = minmax_by_key(self, rhs, |set| (set.capacity(), set.len()));
1175+
1176+
b.extend(a);
1177+
1178+
b
1179+
}
1180+
}
1181+
11501182
#[stable(feature = "rust1", since = "1.0.0")]
11511183
impl<T, S> BitAnd<&HashSet<T, S>> for &HashSet<T, S>
11521184
where
@@ -1173,6 +1205,33 @@ where
11731205
}
11741206
}
11751207

1208+
#[stable(feature = "set_owned_ops", since = "CURRENT_RUSTC_VERSION")]
1209+
impl<T, S> BitAnd<&HashSet<T, S>> for HashSet<T, S>
1210+
where
1211+
T: Eq + Hash,
1212+
S: BuildHasher,
1213+
{
1214+
type Output = HashSet<T, S>;
1215+
1216+
/// Returns the intersection of `self` and `rhs` as a new `HashSet<T, S>`.
1217+
///
1218+
/// # Examples
1219+
///
1220+
/// ```
1221+
/// use std::collections::HashSet;
1222+
///
1223+
/// let a = HashSet::from([1, 2, 3]);
1224+
/// let b = HashSet::from([2, 3, 4]);
1225+
///
1226+
/// let result = a & &b;
1227+
/// assert_eq!(result, HashSet::from([2, 3]));
1228+
/// ```
1229+
fn bitand(mut self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
1230+
self.retain(|e| rhs.contains(e));
1231+
self
1232+
}
1233+
}
1234+
11761235
#[stable(feature = "rust1", since = "1.0.0")]
11771236
impl<T, S> BitXor<&HashSet<T, S>> for &HashSet<T, S>
11781237
where
@@ -1199,6 +1258,41 @@ where
11991258
}
12001259
}
12011260

1261+
#[stable(feature = "set_owned_ops", since = "CURRENT_RUSTC_VERSION")]
1262+
impl<T, S> BitXor<HashSet<T, S>> for HashSet<T, S>
1263+
where
1264+
T: Eq + Hash,
1265+
S: BuildHasher,
1266+
{
1267+
type Output = HashSet<T, S>;
1268+
1269+
/// Returns the symmetric difference of `self` and `rhs` as a new `HashSet<T, S>`.
1270+
///
1271+
/// # Examples
1272+
///
1273+
/// ```
1274+
/// use std::collections::HashSet;
1275+
///
1276+
/// let a = HashSet::from([1, 2, 3]);
1277+
/// let b = HashSet::from([3, 4, 5]);
1278+
///
1279+
/// let result = a ^ b;
1280+
/// assert_eq!(result, HashSet::from([1, 2, 4, 5]));
1281+
/// ```
1282+
fn bitxor(self, rhs: HashSet<T, S>) -> HashSet<T, S> {
1283+
// Iterate through the smaller set
1284+
let [mut a, mut b] = minmax_by_key(self, rhs, HashSet::len);
1285+
1286+
// This is essentially
1287+
// a = a - b (retain elements that are *not* in b)
1288+
// b = b - a (remove all elements that are in a)
1289+
a.retain(|e| !b.remove(e));
1290+
1291+
// Union of the differences
1292+
a | b
1293+
}
1294+
}
1295+
12021296
#[stable(feature = "rust1", since = "1.0.0")]
12031297
impl<T, S> Sub<&HashSet<T, S>> for &HashSet<T, S>
12041298
where
@@ -1225,6 +1319,41 @@ where
12251319
}
12261320
}
12271321

1322+
#[stable(feature = "set_owned_ops", since = "CURRENT_RUSTC_VERSION")]
1323+
impl<T, S> Sub<&HashSet<T, S>> for HashSet<T, S>
1324+
where
1325+
T: Eq + Hash,
1326+
S: BuildHasher,
1327+
{
1328+
type Output = HashSet<T, S>;
1329+
1330+
/// Returns the difference of `self` and `rhs` as a new `HashSet<T, S>`.
1331+
///
1332+
/// # Examples
1333+
///
1334+
/// ```
1335+
/// use std::collections::HashSet;
1336+
///
1337+
/// let a = HashSet::from([1, 2, 3]);
1338+
/// let b = HashSet::from([3, 4, 5]);
1339+
///
1340+
/// let result = a - &b;
1341+
/// assert_eq!(result, HashSet::from([1, 2]));
1342+
/// ```
1343+
fn sub(mut self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
1344+
// Iterate the smaller set, removing elements that are in `rhs` from `self`
1345+
if self.len() <= rhs.len() {
1346+
self.retain(|e| !rhs.contains(e));
1347+
} else {
1348+
rhs.iter().for_each(|e| {
1349+
self.remove(e);
1350+
})
1351+
}
1352+
1353+
self
1354+
}
1355+
}
1356+
12281357
/// An iterator over the items of a `HashSet`.
12291358
///
12301359
/// This `struct` is created by the [`iter`] method on [`HashSet`].
@@ -1885,3 +2014,7 @@ fn assert_covariance() {
18852014
d
18862015
}
18872016
}
2017+
2018+
fn minmax_by_key<T, K: Ord>(a: T, b: T, k: impl Fn(&T) -> K) -> [T; 2] {
2019+
if k(&a) <= k(&b) { [a, b] } else { [b, a] }
2020+
}

0 commit comments

Comments
 (0)