Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve early returns for HashSet SubSet and SetEquals methods #102758

Merged
merged 2 commits into from
Jul 10, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -879,25 +879,26 @@ public bool IsSubsetOf(IEnumerable<T> other)
}

// The empty set is a subset of any set, and a set is a subset of itself.
// Set is always a subset of itself
// Set is always a subset of itself.
if (Count == 0 || other == this)
{
return true;
}

// Faster if other has unique elements according to this equality comparer; so check
// that other is a hashset using the same equality comparer.
if (other is HashSet<T> otherAsSet && EqualityComparersAreEqual(this, otherAsSet))
if (other is ICollection<T> otherAsCollection)
{
// if this has more elements then it can't be a subset
if (Count > otherAsSet.Count)
// If this has more elements then it can't be a subset.
if (Count > otherAsCollection.Count)
{
return false;
}

// already checked that we're using same equality comparer. simply check that
// each element in this is contained in other.
return IsSubsetOfHashSetWithSameComparer(otherAsSet);
// Faster if other has unique elements according to this equality comparer; so check
// that other is a hashset using the same equality comparer.
if (other is HashSet<T> otherAsSet && EqualityComparersAreEqual(this, otherAsSet))
{
return IsSubsetOfHashSetWithSameComparer(otherAsSet);
}
}

(int uniqueCount, int unfoundCount) = CheckUniqueAndUnfoundElements(other, returnIfUnfound: false);
Expand All @@ -922,26 +923,22 @@ public bool IsProperSubsetOf(IEnumerable<T> other)

if (other is ICollection<T> otherAsCollection)
{
// No set is a proper subset of an empty set.
if (otherAsCollection.Count == 0)
// No set is a proper subset of a set with less or equal number of elements.
if (otherAsCollection.Count <= Count)
{
return false;
}

// The empty set is a proper subset of anything but the empty set.
if (Count == 0)
{
return otherAsCollection.Count > 0;
// Based on check above, other is not empty when Count == 0.
return true;
}

// Faster if other is a hashset (and we're using same equality comparer).
if (other is HashSet<T> otherAsSet && EqualityComparersAreEqual(this, otherAsSet))
{
if (Count >= otherAsSet.Count)
{
return false;
}

// This has strictly less than number of items in other, so the following
// check suffices for proper subset.
return IsSubsetOfHashSetWithSameComparer(otherAsSet);
Expand Down Expand Up @@ -1088,33 +1085,38 @@ public bool SetEquals(IEnumerable<T> other)
return true;
}

// Faster if other is a hashset and we're using same equality comparer.
if (other is HashSet<T> otherAsSet && EqualityComparersAreEqual(this, otherAsSet))
if (other is ICollection<T> otherAsCollection)
{
// Attempt to return early: since both contain unique elements, if they have
// different counts, then they can't be equal.
if (Count != otherAsSet.Count)
// If this is empty, they are equal iff other is empty.
if (Count == 0)
{
return false;
return otherAsCollection.Count == 0;
}

// Already confirmed that the sets have the same number of distinct elements, so if
// one is a subset of the other then they must be equal.
return IsSubsetOfHashSetWithSameComparer(otherAsSet);
}
else
{
// If this count is 0 but other contains at least one element, they can't be equal.
if (Count == 0 &&
other is ICollection<T> otherAsCollection &&
otherAsCollection.Count > 0)
// Faster if other is a hashset and we're using same equality comparer.
if (other is HashSet<T> otherAsSet && EqualityComparersAreEqual(this, otherAsSet))
{
return false;
// Attempt to return early: since both contain unique elements, if they have
// different counts, then they can't be equal.
if (Count != otherAsSet.Count)
{
return false;
}

// Already confirmed that the sets have the same number of distinct elements, so if
// one is a subset of the other then they must be equal.
return IsSubsetOfHashSetWithSameComparer(otherAsSet);
}

(int uniqueCount, int unfoundCount) = CheckUniqueAndUnfoundElements(other, returnIfUnfound: true);
return uniqueCount == Count && unfoundCount == 0;
// Can't be equal if other set contains fewer elements than this.
if (Count > otherAsCollection.Count)
{
return false;
}
}

(int uniqueCount, int unfoundCount) = CheckUniqueAndUnfoundElements(other, returnIfUnfound: true);
return uniqueCount == Count && unfoundCount == 0;
}

public void CopyTo(T[] array) => CopyTo(array, 0, Count);
Expand Down
Loading