Skip to content

Commit

Permalink
Auto merge of #531 - ToMe25:optimize_is_disjoint, r=Amanieu
Browse files Browse the repository at this point in the history
Optimize Set is_disjoint

By using the `Intersection` iterator in `HashSet::is_Disjoint` its performance can be significantly improved in some cases.
This is because `intersection()` always uses the shorter set as its iterator.

It would also be possible to replicate this "Iterate over the smaller set and check in the larger set" logic in the is_disjoint method.
However in my benchmarks the approach I chose is faster than that.

This change only causes a significant improvement when called on the larger of two disjoint sets.

My benchmark results:

Name | Before | After | Diff (%)
-- | -- | -- | --
disjoint_is_disjoint_large_small | 1,147.43 | 535.25 | -53,35 %
disjoint_is_disjoint_small_large | 535.66 | 527.59 | -1,51 %
subset_is_disjoint | 9.90 | 10.44 | 5,45 %
superset_is_disjoint | 9.80 | 10.43 | 6,43 %
  • Loading branch information
bors committed Jun 11, 2024
2 parents 2310a95 + 4b6e11d commit e25e6bb
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 3 deletions.
9 changes: 7 additions & 2 deletions src/raw/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4439,11 +4439,13 @@ impl<T, A: Allocator> FusedIterator for RawDrain<'_, T, A> {}
/// created will be yielded by that iterator.
/// - The order in which the iterator yields buckets is unspecified and may
/// change in the future.
#[cfg(feature = "raw")]
pub struct RawIterHash<T> {
inner: RawIterHashInner,
_marker: PhantomData<T>,
}

#[cfg(feature = "raw")]
struct RawIterHashInner {
// See `RawTableInner`'s corresponding fields for details.
// We can't store a `*const RawTableInner` as it would get
Expand All @@ -4463,19 +4465,20 @@ struct RawIterHashInner {
bitmask: BitMaskIter,
}

#[cfg(feature = "raw")]
impl<T> RawIterHash<T> {
#[cfg_attr(feature = "inline-more", inline)]
#[cfg(feature = "raw")]
unsafe fn new<A: Allocator>(table: &RawTable<T, A>, hash: u64) -> Self {
RawIterHash {
inner: RawIterHashInner::new(&table.table, hash),
_marker: PhantomData,
}
}
}

#[cfg(feature = "raw")]
impl RawIterHashInner {
#[cfg_attr(feature = "inline-more", inline)]
#[cfg(feature = "raw")]
unsafe fn new(table: &RawTableInner, hash: u64) -> Self {
let h2_hash = h2(hash);
let probe_seq = table.probe_seq(hash);
Expand All @@ -4493,6 +4496,7 @@ impl RawIterHashInner {
}
}

#[cfg(feature = "raw")]
impl<T> Iterator for RawIterHash<T> {
type Item = Bucket<T>;

Expand All @@ -4512,6 +4516,7 @@ impl<T> Iterator for RawIterHash<T> {
}
}

#[cfg(feature = "raw")]
impl Iterator for RawIterHashInner {
type Item = usize;

Expand Down
2 changes: 1 addition & 1 deletion src/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1044,7 +1044,7 @@ where
/// assert_eq!(a.is_disjoint(&b), false);
/// ```
pub fn is_disjoint(&self, other: &Self) -> bool {
self.iter().all(|v| !other.contains(v))
self.intersection(other).next().is_none()
}

/// Returns `true` if the set is a subset of another,
Expand Down

0 comments on commit e25e6bb

Please sign in to comment.