Skip to content

Commit

Permalink
Non-generic StringComparer conversion for dict and hashset (#49608)
Browse files Browse the repository at this point in the history
  • Loading branch information
benaadams authored Mar 15, 2021
1 parent db0a5dd commit 5ef6a06
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,28 +54,20 @@ 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;
}

// 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.

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))
IEqualityComparer<string>? stringComparer = NonRandomizedStringEqualityComparer.GetStringComparer(_comparer);
if (stringComparer is not null)
{
_comparer = (IEqualityComparer<TKey>)NonRandomizedStringEqualityComparer.WrappedAroundStringComparerOrdinalIgnoreCase;
_comparer = (IEqualityComparer<TKey>?)stringComparer;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,28 +54,20 @@ 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;
}

// 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.

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))
IEqualityComparer<string>? stringComparer = NonRandomizedStringEqualityComparer.GetStringComparer(_comparer);
if (stringComparer is not null)
{
_comparer = (IEqualityComparer<T>)NonRandomizedStringEqualityComparer.WrappedAroundStringComparerOrdinalIgnoreCase;
_comparer = (IEqualityComparer<T>?)stringComparer;
}
}
}
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 @@ -20,9 +18,9 @@ public class NonRandomizedStringEqualityComparer : IEqualityComparer<string?>, I
// 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 NonRandomizedStringEqualityComparer WrappedAroundDefaultComparer = new OrdinalComparer(EqualityComparer<string?>.Default);
private static readonly NonRandomizedStringEqualityComparer WrappedAroundStringComparerOrdinal = new OrdinalComparer(StringComparer.Ordinal);
private static readonly NonRandomizedStringEqualityComparer WrappedAroundStringComparerOrdinalIgnoreCase = new OrdinalIgnoreCaseComparer(StringComparer.OrdinalIgnoreCase);

private readonly IEqualityComparer<string?> _underlyingComparer;

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

public static IEqualityComparer<string>? GetStringComparer(object? 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.
if (comparer is null)
{
return WrappedAroundDefaultComparer;
}
else if (ReferenceEquals(comparer, StringComparer.Ordinal))
{
return WrappedAroundStringComparerOrdinal;
}
else if (ReferenceEquals(comparer, StringComparer.OrdinalIgnoreCase))
{
return WrappedAroundStringComparerOrdinalIgnoreCase;
}

return null;
}
}
}

0 comments on commit 5ef6a06

Please sign in to comment.