Skip to content

Commit d0c084a

Browse files
authored
Rollup merge of rust-lang#57043 - ssomers:master, r=alexcrichton
Fix poor worst case performance of set intersection Specifically, intersection of asymmetrically sized sets when the large set is on the left. See also the [latest answer on stackoverflow](https://stackoverflow.com/questions/35439376/python-set-intersection-is-faster-then-rust-hashset-intersection). Also applied to the union member, where the effect is much less but still measurable. Formatted the changed code only, does not increase the error count reported by tidy check, and tried to adhere to the spirit of the unit tests.
2 parents d106808 + cef2e2f commit d0c084a

File tree

1 file changed

+60
-7
lines changed
  • src/libstd/collections/hash

1 file changed

+60
-7
lines changed

src/libstd/collections/hash/set.rs

+60-7
Original file line numberDiff line numberDiff line change
@@ -410,9 +410,16 @@ impl<T, S> HashSet<T, S>
410410
/// ```
411411
#[stable(feature = "rust1", since = "1.0.0")]
412412
pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a, T, S> {
413-
Intersection {
414-
iter: self.iter(),
415-
other,
413+
if self.len() <= other.len() {
414+
Intersection {
415+
iter: self.iter(),
416+
other,
417+
}
418+
} else {
419+
Intersection {
420+
iter: other.iter(),
421+
other: self,
422+
}
416423
}
417424
}
418425

@@ -436,7 +443,15 @@ impl<T, S> HashSet<T, S>
436443
/// ```
437444
#[stable(feature = "rust1", since = "1.0.0")]
438445
pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> {
439-
Union { iter: self.iter().chain(other.difference(self)) }
446+
if self.len() <= other.len() {
447+
Union {
448+
iter: self.iter().chain(other.difference(self)),
449+
}
450+
} else {
451+
Union {
452+
iter: other.iter().chain(self.difference(other)),
453+
}
454+
}
440455
}
441456

442457
/// Returns the number of elements in the set.
@@ -584,7 +599,11 @@ impl<T, S> HashSet<T, S>
584599
/// ```
585600
#[stable(feature = "rust1", since = "1.0.0")]
586601
pub fn is_disjoint(&self, other: &HashSet<T, S>) -> bool {
587-
self.iter().all(|v| !other.contains(v))
602+
if self.len() <= other.len() {
603+
self.iter().all(|v| !other.contains(v))
604+
} else {
605+
other.iter().all(|v| !self.contains(v))
606+
}
588607
}
589608

590609
/// Returns `true` if the set is a subset of another,
@@ -1494,6 +1513,7 @@ mod test_set {
14941513
fn test_intersection() {
14951514
let mut a = HashSet::new();
14961515
let mut b = HashSet::new();
1516+
assert!(a.intersection(&b).next().is_none());
14971517

14981518
assert!(a.insert(11));
14991519
assert!(a.insert(1));
@@ -1518,6 +1538,22 @@ mod test_set {
15181538
i += 1
15191539
}
15201540
assert_eq!(i, expected.len());
1541+
1542+
assert!(a.insert(9)); // make a bigger than b
1543+
1544+
i = 0;
1545+
for x in a.intersection(&b) {
1546+
assert!(expected.contains(x));
1547+
i += 1
1548+
}
1549+
assert_eq!(i, expected.len());
1550+
1551+
i = 0;
1552+
for x in b.intersection(&a) {
1553+
assert!(expected.contains(x));
1554+
i += 1
1555+
}
1556+
assert_eq!(i, expected.len());
15211557
}
15221558

15231559
#[test]
@@ -1573,11 +1609,11 @@ mod test_set {
15731609
fn test_union() {
15741610
let mut a = HashSet::new();
15751611
let mut b = HashSet::new();
1612+
assert!(a.union(&b).next().is_none());
1613+
assert!(b.union(&a).next().is_none());
15761614

15771615
assert!(a.insert(1));
15781616
assert!(a.insert(3));
1579-
assert!(a.insert(5));
1580-
assert!(a.insert(9));
15811617
assert!(a.insert(11));
15821618
assert!(a.insert(16));
15831619
assert!(a.insert(19));
@@ -1597,6 +1633,23 @@ mod test_set {
15971633
i += 1
15981634
}
15991635
assert_eq!(i, expected.len());
1636+
1637+
assert!(a.insert(9)); // make a bigger than b
1638+
assert!(a.insert(5));
1639+
1640+
i = 0;
1641+
for x in a.union(&b) {
1642+
assert!(expected.contains(x));
1643+
i += 1
1644+
}
1645+
assert_eq!(i, expected.len());
1646+
1647+
i = 0;
1648+
for x in b.union(&a) {
1649+
assert!(expected.contains(x));
1650+
i += 1
1651+
}
1652+
assert_eq!(i, expected.len());
16001653
}
16011654

16021655
#[test]

0 commit comments

Comments
 (0)