Skip to content

Commit c09d35d

Browse files
committed
Add implementations of ops for HashSet that keep ownership
1 parent b70c88e commit c09d35d

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

+133
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,38 @@ where
11461146
}
11471147
}
11481148

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

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

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

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

0 commit comments

Comments
 (0)