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

Non-generic StringComparer conversion for dict and hashset #49608

Merged
merged 5 commits into from
Mar 15, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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 @@ -54,7 +54,7 @@ public Dictionary(int capacity, IEqualityComparer<TKey>? comparer)
Initialize(capacity);
}

if (comparer != null && comparer != EqualityComparer<TKey>.Default) // first check for null to avoid forcing default comparer instantiation unnecessarily
if (comparer is not null && comparer != EqualityComparer<TKey>.Default) // first check for null to avoid forcing default comparer instantiation unnecessarily
{
_comparer = comparer;
}
Expand All @@ -65,18 +65,7 @@ public Dictionary(int capacity, IEqualityComparer<TKey>? comparer)

if (typeof(TKey) == typeof(string))
{
if (_comparer is null)
{
_comparer = (IEqualityComparer<TKey>)NonRandomizedStringEqualityComparer.WrappedAroundDefaultComparer;
}
else if (ReferenceEquals(_comparer, StringComparer.Ordinal))
{
_comparer = (IEqualityComparer<TKey>)NonRandomizedStringEqualityComparer.WrappedAroundStringComparerOrdinal;
}
else if (ReferenceEquals(_comparer, StringComparer.OrdinalIgnoreCase))
{
_comparer = (IEqualityComparer<TKey>)NonRandomizedStringEqualityComparer.WrappedAroundStringComparerOrdinalIgnoreCase;
}
_comparer = (IEqualityComparer<TKey>?)NonRandomizedStringEqualityComparer.GetStringComparer((IEqualityComparer<string>?)_comparer);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public HashSet() : this((IEqualityComparer<T>?)null) { }

public HashSet(IEqualityComparer<T>? comparer)
{
if (comparer != null && comparer != EqualityComparer<T>.Default) // first check for null to avoid forcing default comparer instantiation unnecessarily
if (comparer is not null && comparer != EqualityComparer<T>.Default) // first check for null to avoid forcing default comparer instantiation unnecessarily
{
_comparer = comparer;
}
Expand All @@ -65,18 +65,7 @@ public HashSet(IEqualityComparer<T>? comparer)

if (typeof(T) == typeof(string))
{
if (_comparer is null)
{
_comparer = (IEqualityComparer<T>)NonRandomizedStringEqualityComparer.WrappedAroundDefaultComparer;
}
else if (ReferenceEquals(_comparer, StringComparer.Ordinal))
{
_comparer = (IEqualityComparer<T>)NonRandomizedStringEqualityComparer.WrappedAroundStringComparerOrdinal;
}
else if (ReferenceEquals(_comparer, StringComparer.OrdinalIgnoreCase))
{
_comparer = (IEqualityComparer<T>)NonRandomizedStringEqualityComparer.WrappedAroundStringComparerOrdinalIgnoreCase;
}
_comparer = (IEqualityComparer<T>?)NonRandomizedStringEqualityComparer.GetStringComparer((IEqualityComparer<string>?)_comparer);
benaadams marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Globalization;
using System.Runtime.Serialization;
using Internal.Runtime.CompilerServices;

namespace System.Collections.Generic
{
Expand All @@ -16,13 +14,7 @@ namespace System.Collections.Generic
// Needs to be public to support binary serialization compatibility
public class NonRandomizedStringEqualityComparer : IEqualityComparer<string?>, IInternalStringEqualityComparer, ISerializable
{
// Dictionary<...>.Comparer and similar methods need to return the original IEqualityComparer
// that was passed in to the ctor. The caller chooses one of these singletons so that the
// GetUnderlyingEqualityComparer method can return the correct value.

internal static readonly NonRandomizedStringEqualityComparer WrappedAroundDefaultComparer = new OrdinalComparer(EqualityComparer<string?>.Default);
internal static readonly NonRandomizedStringEqualityComparer WrappedAroundStringComparerOrdinal = new OrdinalComparer(StringComparer.Ordinal);
internal static readonly NonRandomizedStringEqualityComparer WrappedAroundStringComparerOrdinalIgnoreCase = new OrdinalIgnoreCaseComparer(StringComparer.OrdinalIgnoreCase);
private static readonly StringComparers s_stringComparers = new StringComparers();
benaadams marked this conversation as resolved.
Show resolved Hide resolved

private readonly IEqualityComparer<string?> _underlyingComparer;

Expand Down Expand Up @@ -109,5 +101,37 @@ internal override RandomizedStringEqualityComparer GetRandomizedEqualityComparer
return RandomizedStringEqualityComparer.Create(_underlyingComparer, ignoreCase: true);
}
}

public static IEqualityComparer<string> GetStringComparer(IEqualityComparer<string>? comparer)
{
// Special-case EqualityComparer<string>.Default, StringComparer.Ordinal, and StringComparer.OrdinalIgnoreCase.
// We use a non-randomized comparer for improved perf, falling back to a randomized comparer if the
// hash buckets become unbalanced.
StringComparers stringComparers = s_stringComparers;
if (comparer is null)
{
return stringComparers.WrappedAroundDefaultComparer;
}
else if (ReferenceEquals(comparer, StringComparer.Ordinal))
{
return stringComparers.WrappedAroundStringComparerOrdinal;
}
else if (ReferenceEquals(comparer, StringComparer.OrdinalIgnoreCase))
{
return stringComparers.WrappedAroundStringComparerOrdinalIgnoreCase;
}

return comparer;
}

private class StringComparers
{
// Dictionary<...>.Comparer and similar methods need to return the original IEqualityComparer
// that was passed in to the ctor. The caller chooses one of these singletons so that the
// GetUnderlyingEqualityComparer method can return the correct value.
public readonly NonRandomizedStringEqualityComparer WrappedAroundDefaultComparer = new OrdinalComparer(EqualityComparer<string?>.Default);
public readonly NonRandomizedStringEqualityComparer WrappedAroundStringComparerOrdinal = new OrdinalComparer(StringComparer.Ordinal);
public readonly NonRandomizedStringEqualityComparer WrappedAroundStringComparerOrdinalIgnoreCase = new OrdinalIgnoreCaseComparer(StringComparer.OrdinalIgnoreCase);
}
}
}