Moves generic comparers to shared CoreLib (dotnet/coreclr#21649)
authorMarek Safar <marek.safar@gmail.com>
Sun, 30 Dec 2018 07:38:06 +0000 (08:38 +0100)
committerJan Kotas <jkotas@microsoft.com>
Sun, 30 Dec 2018 07:38:06 +0000 (21:38 -1000)
* Moves generic comparer to shared CoreLib

* Keep Index/LastIndexOf optimizations in CoreCLR only

* Moved runtime-specific enum helper to runtime-specific partial type

Commit migrated from https://github.com/dotnet/coreclr/commit/3b5782fa0aa4086ee72904b6052f21cba693bcf7

src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj
src/coreclr/src/System.Private.CoreLib/src/System/Collections/Generic/Comparer.CoreCLR.cs [new file with mode: 0644]
src/coreclr/src/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.CoreCLR.cs [new file with mode: 0644]
src/coreclr/src/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs [deleted file]
src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Comparer.cs [moved from src/coreclr/src/System.Private.CoreLib/src/System/Collections/Generic/Comparer.cs with 79% similarity]
src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs [new file with mode: 0644]

index 6e6e453..8e98367 100644 (file)
     <Compile Include="$(BclSourcesRoot)\System\CLRConfig.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Collections\EmptyReadOnlyDictionaryInternal.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Collections\Generic\ArraySortHelper.CoreCLR.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Collections\Generic\Comparer.cs" />
+    <Compile Include="$(BclSourcesRoot)\System\Collections\Generic\Comparer.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Collections\Generic\ComparerHelpers.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\Collections\Generic\EqualityComparer.cs" />
+    <Compile Include="$(BclSourcesRoot)\System\Collections\Generic\EqualityComparer.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Collections\ObjectModel\ReadOnlyDictionary.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Currency.cs" />
     <Compile Include="$(BclSourcesRoot)\System\DefaultBinder.CanConvert.cs" />
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Collections/Generic/Comparer.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Collections/Generic/Comparer.CoreCLR.cs
new file mode 100644 (file)
index 0000000..b06fe7e
--- /dev/null
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+using System.Runtime;
+using System.Runtime.CompilerServices;
+
+namespace System.Collections.Generic
+{
+    [TypeDependencyAttribute("System.Collections.Generic.ObjectComparer`1")]
+    public abstract partial class Comparer<T> : IComparer, IComparer<T>
+    {
+        // To minimize generic instantiation overhead of creating the comparer per type, we keep the generic portion of the code as small
+        // as possible and define most of the creation logic in a non-generic class.
+        public static Comparer<T> Default { get; } = (Comparer<T>)ComparerHelpers.CreateDefaultComparer(typeof(T));
+    }
+
+    internal sealed partial class EnumComparer<T> : Comparer<T> where T : struct, Enum
+    {
+        public override int Compare(T x, T y)
+        {
+            return System.Runtime.CompilerServices.JitHelpers.EnumCompareTo(x, y);
+        }
+    }
+}
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.CoreCLR.cs
new file mode 100644 (file)
index 0000000..8ef6818
--- /dev/null
@@ -0,0 +1,213 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime;
+using System.Runtime.CompilerServices;
+using System.Diagnostics;
+
+namespace System.Collections.Generic
+{
+    [TypeDependencyAttribute("System.Collections.Generic.ObjectEqualityComparer`1")]
+    public abstract partial class EqualityComparer<T> : IEqualityComparer, IEqualityComparer<T>
+    {
+        // To minimize generic instantiation overhead of creating the comparer per type, we keep the generic portion of the code as small
+        // as possible and define most of the creation logic in a non-generic class.
+        public static EqualityComparer<T> Default { [Intrinsic] get; } = (EqualityComparer<T>)ComparerHelpers.CreateDefaultEqualityComparer(typeof(T));
+
+        internal virtual int IndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex + count;
+            for (int i = startIndex; i < endIndex; i++)
+            {
+                if (Equals(array[i], value)) return i;
+            }
+            return -1;
+        }
+
+        internal virtual int LastIndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex - count + 1;
+            for (int i = startIndex; i >= endIndex; i--)
+            {
+                if (Equals(array[i], value)) return i;
+            }
+            return -1;
+        }
+    }
+
+    public sealed partial class GenericEqualityComparer<T> : EqualityComparer<T> where T : IEquatable<T>
+    {
+        internal override int IndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex + count;
+            if (value == null)
+            {
+                for (int i = startIndex; i < endIndex; i++)
+                {
+                    if (array[i] == null) return i;
+                }
+            }
+            else
+            {
+                for (int i = startIndex; i < endIndex; i++)
+                {
+                    if (array[i] != null && array[i].Equals(value)) return i;
+                }
+            }
+            return -1;
+        }
+
+        internal override int LastIndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex - count + 1;
+            if (value == null)
+            {
+                for (int i = startIndex; i >= endIndex; i--)
+                {
+                    if (array[i] == null) return i;
+                }
+            }
+            else
+            {
+                for (int i = startIndex; i >= endIndex; i--)
+                {
+                    if (array[i] != null && array[i].Equals(value)) return i;
+                }
+            }
+            return -1;
+        }
+    }
+
+    public sealed partial class NullableEqualityComparer<T> : EqualityComparer<T?> where T : struct, IEquatable<T>
+    {
+        internal override int IndexOf(T?[] array, T? value, int startIndex, int count)
+        {
+            int endIndex = startIndex + count;
+            if (!value.HasValue)
+            {
+                for (int i = startIndex; i < endIndex; i++)
+                {
+                    if (!array[i].HasValue) return i;
+                }
+            }
+            else
+            {
+                for (int i = startIndex; i < endIndex; i++)
+                {
+                    if (array[i].HasValue && array[i].value.Equals(value.value)) return i;
+                }
+            }
+            return -1;
+        }
+
+        internal override int LastIndexOf(T?[] array, T? value, int startIndex, int count)
+        {
+            int endIndex = startIndex - count + 1;
+            if (!value.HasValue)
+            {
+                for (int i = startIndex; i >= endIndex; i--)
+                {
+                    if (!array[i].HasValue) return i;
+                }
+            }
+            else
+            {
+                for (int i = startIndex; i >= endIndex; i--)
+                {
+                    if (array[i].HasValue && array[i].value.Equals(value.value)) return i;
+                }
+            }
+            return -1;
+        }
+    }
+
+    public sealed partial class ObjectEqualityComparer<T> : EqualityComparer<T>
+    {
+        internal override int IndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex + count;
+            if (value == null)
+            {
+                for (int i = startIndex; i < endIndex; i++)
+                {
+                    if (array[i] == null) return i;
+                }
+            }
+            else
+            {
+                for (int i = startIndex; i < endIndex; i++)
+                {
+                    if (array[i] != null && array[i].Equals(value)) return i;
+                }
+            }
+            return -1;
+        }
+
+        internal override int LastIndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex - count + 1;
+            if (value == null)
+            {
+                for (int i = startIndex; i >= endIndex; i--)
+                {
+                    if (array[i] == null) return i;
+                }
+            }
+            else
+            {
+                for (int i = startIndex; i >= endIndex; i--)
+                {
+                    if (array[i] != null && array[i].Equals(value)) return i;
+                }
+            }
+            return -1;
+        }
+    }
+
+    public sealed partial class ByteEqualityComparer : EqualityComparer<byte>
+    {
+#if DEBUG
+        internal override int IndexOf(byte[] array, byte value, int startIndex, int count)
+        {
+             Debug.Fail("Should not get here.");
+             return -1;
+        }
+
+        internal override int LastIndexOf(byte[] array, byte value, int startIndex, int count)
+        {
+             Debug.Fail("Should not get here.");
+             return -1;
+        }
+#endif
+    }
+
+    public sealed partial class EnumEqualityComparer<T> : EqualityComparer<T> where T : struct, Enum
+    {
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public override bool Equals(T x, T y)
+        {
+            return System.Runtime.CompilerServices.JitHelpers.EnumEquals(x, y);
+        }
+
+        internal override int IndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex + count;
+            for (int i = startIndex; i < endIndex; i++)
+            {
+                if (System.Runtime.CompilerServices.JitHelpers.EnumEquals(array[i], value)) return i;
+            }
+            return -1;
+        }
+
+        internal override int LastIndexOf(T[] array, T value, int startIndex, int count)
+        {
+            int endIndex = startIndex - count + 1;
+            for (int i = startIndex; i >= endIndex; i--)
+            {
+                if (System.Runtime.CompilerServices.JitHelpers.EnumEquals(array[i], value)) return i;
+            }
+            return -1;
+        }
+    }
+}
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs
deleted file mode 100644 (file)
index 82051af..0000000
+++ /dev/null
@@ -1,372 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Security;
-
-using System.Globalization;
-using System.Runtime;
-using System.Runtime.CompilerServices;
-using System.Runtime.Serialization;
-using System.Diagnostics;
-
-namespace System.Collections.Generic
-{
-    [Serializable]
-    [TypeDependencyAttribute("System.Collections.Generic.ObjectEqualityComparer`1")]
-    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] 
-    public abstract class EqualityComparer<T> : IEqualityComparer, IEqualityComparer<T>
-    {
-        // To minimize generic instantiation overhead of creating the comparer per type, we keep the generic portion of the code as small
-        // as possible and define most of the creation logic in a non-generic class.
-        public static EqualityComparer<T> Default { [Intrinsic] get; } = (EqualityComparer<T>)ComparerHelpers.CreateDefaultEqualityComparer(typeof(T));
-
-        public abstract bool Equals(T x, T y);
-        public abstract int GetHashCode(T obj);
-
-        internal virtual int IndexOf(T[] array, T value, int startIndex, int count)
-        {
-            int endIndex = startIndex + count;
-            for (int i = startIndex; i < endIndex; i++)
-            {
-                if (Equals(array[i], value)) return i;
-            }
-            return -1;
-        }
-
-        internal virtual int LastIndexOf(T[] array, T value, int startIndex, int count)
-        {
-            int endIndex = startIndex - count + 1;
-            for (int i = startIndex; i >= endIndex; i--)
-            {
-                if (Equals(array[i], value)) return i;
-            }
-            return -1;
-        }
-
-        int IEqualityComparer.GetHashCode(object obj)
-        {
-            if (obj == null) return 0;
-            if (obj is T) return GetHashCode((T)obj);
-            ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArgumentForComparison);
-            return 0;
-        }
-
-        bool IEqualityComparer.Equals(object x, object y)
-        {
-            if (x == y) return true;
-            if (x == null || y == null) return false;
-            if ((x is T) && (y is T)) return Equals((T)x, (T)y);
-            ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArgumentForComparison);
-            return false;
-        }
-    }
-
-    // The methods in this class look identical to the inherited methods, but the calls
-    // to Equal bind to IEquatable<T>.Equals(T) instead of Object.Equals(Object)
-    [Serializable]
-    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    // Needs to be public to support binary serialization compatibility
-    public sealed class GenericEqualityComparer<T> : EqualityComparer<T> where T : IEquatable<T>
-    {
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public override bool Equals(T x, T y)
-        {
-            if (x != null)
-            {
-                if (y != null) return x.Equals(y);
-                return false;
-            }
-            if (y != null) return false;
-            return true;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public override int GetHashCode(T obj) => obj?.GetHashCode() ?? 0;
-
-        internal override int IndexOf(T[] array, T value, int startIndex, int count)
-        {
-            int endIndex = startIndex + count;
-            if (value == null)
-            {
-                for (int i = startIndex; i < endIndex; i++)
-                {
-                    if (array[i] == null) return i;
-                }
-            }
-            else
-            {
-                for (int i = startIndex; i < endIndex; i++)
-                {
-                    if (array[i] != null && array[i].Equals(value)) return i;
-                }
-            }
-            return -1;
-        }
-
-        internal override int LastIndexOf(T[] array, T value, int startIndex, int count)
-        {
-            int endIndex = startIndex - count + 1;
-            if (value == null)
-            {
-                for (int i = startIndex; i >= endIndex; i--)
-                {
-                    if (array[i] == null) return i;
-                }
-            }
-            else
-            {
-                for (int i = startIndex; i >= endIndex; i--)
-                {
-                    if (array[i] != null && array[i].Equals(value)) return i;
-                }
-            }
-            return -1;
-        }
-
-        // Equals method for the comparer itself.
-        // If in the future this type is made sealed, change the is check to obj != null && GetType() == obj.GetType().
-        public override bool Equals(object obj) =>
-            obj is GenericEqualityComparer<T>;
-
-        // If in the future this type is made sealed, change typeof(...) to GetType().
-        public override int GetHashCode() =>
-            typeof(GenericEqualityComparer<T>).GetHashCode();
-    }
-
-    [Serializable]
-    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    // Needs to be public to support binary serialization compatibility
-    public sealed class NullableEqualityComparer<T> : EqualityComparer<T?> where T : struct, IEquatable<T>
-    {
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public override bool Equals(T? x, T? y)
-        {
-            if (x.HasValue)
-            {
-                if (y.HasValue) return x.value.Equals(y.value);
-                return false;
-            }
-            if (y.HasValue) return false;
-            return true;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public override int GetHashCode(T? obj) => obj.GetHashCode();
-
-        internal override int IndexOf(T?[] array, T? value, int startIndex, int count)
-        {
-            int endIndex = startIndex + count;
-            if (!value.HasValue)
-            {
-                for (int i = startIndex; i < endIndex; i++)
-                {
-                    if (!array[i].HasValue) return i;
-                }
-            }
-            else
-            {
-                for (int i = startIndex; i < endIndex; i++)
-                {
-                    if (array[i].HasValue && array[i].value.Equals(value.value)) return i;
-                }
-            }
-            return -1;
-        }
-
-        internal override int LastIndexOf(T?[] array, T? value, int startIndex, int count)
-        {
-            int endIndex = startIndex - count + 1;
-            if (!value.HasValue)
-            {
-                for (int i = startIndex; i >= endIndex; i--)
-                {
-                    if (!array[i].HasValue) return i;
-                }
-            }
-            else
-            {
-                for (int i = startIndex; i >= endIndex; i--)
-                {
-                    if (array[i].HasValue && array[i].value.Equals(value.value)) return i;
-                }
-            }
-            return -1;
-        }
-
-        // Equals method for the comparer itself.
-        public override bool Equals(object obj) =>
-            obj != null && GetType() == obj.GetType();
-
-        public override int GetHashCode() =>
-            GetType().GetHashCode();
-    }
-
-    [Serializable]
-    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    // Needs to be public to support binary serialization compatibility
-    public sealed class ObjectEqualityComparer<T> : EqualityComparer<T>
-    {
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public override bool Equals(T x, T y)
-        {
-            if (x != null)
-            {
-                if (y != null) return x.Equals(y);
-                return false;
-            }
-            if (y != null) return false;
-            return true;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public override int GetHashCode(T obj) => obj?.GetHashCode() ?? 0;
-
-        internal override int IndexOf(T[] array, T value, int startIndex, int count)
-        {
-            int endIndex = startIndex + count;
-            if (value == null)
-            {
-                for (int i = startIndex; i < endIndex; i++)
-                {
-                    if (array[i] == null) return i;
-                }
-            }
-            else
-            {
-                for (int i = startIndex; i < endIndex; i++)
-                {
-                    if (array[i] != null && array[i].Equals(value)) return i;
-                }
-            }
-            return -1;
-        }
-
-        internal override int LastIndexOf(T[] array, T value, int startIndex, int count)
-        {
-            int endIndex = startIndex - count + 1;
-            if (value == null)
-            {
-                for (int i = startIndex; i >= endIndex; i--)
-                {
-                    if (array[i] == null) return i;
-                }
-            }
-            else
-            {
-                for (int i = startIndex; i >= endIndex; i--)
-                {
-                    if (array[i] != null && array[i].Equals(value)) return i;
-                }
-            }
-            return -1;
-        }
-
-        // Equals method for the comparer itself.
-        public override bool Equals(object obj) =>
-            obj != null && GetType() == obj.GetType();
-
-        public override int GetHashCode() =>
-            GetType().GetHashCode();
-    }
-
-    [Serializable]
-    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    // Needs to be public to support binary serialization compatibility
-    public sealed class ByteEqualityComparer : EqualityComparer<byte>
-    {
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public override bool Equals(byte x, byte y)
-        {
-            return x == y;
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public override int GetHashCode(byte b)
-        {
-            return b.GetHashCode();
-        }
-
-#if DEBUG
-        internal override int IndexOf(byte[] array, byte value, int startIndex, int count)
-        {
-             Debug.Fail("Should not get here.");
-             return -1;
-        }
-
-        internal override int LastIndexOf(byte[] array, byte value, int startIndex, int count)
-        {
-             Debug.Fail("Should not get here.");
-             return -1;
-        }
-#endif
-
-        // Equals method for the comparer itself.
-        public override bool Equals(object obj) =>
-            obj != null && GetType() == obj.GetType();
-
-        public override int GetHashCode() =>
-            GetType().GetHashCode();
-    }
-
-    [Serializable]
-    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    // Needs to be public to support binary serialization compatibility
-    public sealed class EnumEqualityComparer<T> : EqualityComparer<T>, ISerializable where T : struct, Enum
-    {
-        internal EnumEqualityComparer() { }
-
-        // This is used by the serialization engine.
-        private EnumEqualityComparer(SerializationInfo information, StreamingContext context) { }
-
-        public void GetObjectData(SerializationInfo info, StreamingContext context)
-        {
-            // For back-compat we need to serialize the comparers for enums with underlying types other than int as ObjectEqualityComparer 
-            if (Type.GetTypeCode(Enum.GetUnderlyingType(typeof(T))) != TypeCode.Int32) {
-                info.SetType(typeof(ObjectEqualityComparer<T>));
-            }
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public override bool Equals(T x, T y)
-        {
-            return System.Runtime.CompilerServices.JitHelpers.EnumEquals(x, y);
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public override int GetHashCode(T obj)
-        {
-            return obj.GetHashCode();
-        }
-
-        // Equals method for the comparer itself.
-        public override bool Equals(object obj) =>
-            obj != null && GetType() == obj.GetType();
-
-        public override int GetHashCode() =>
-            GetType().GetHashCode();
-
-        internal override int IndexOf(T[] array, T value, int startIndex, int count)
-        {
-            int endIndex = startIndex + count;
-            for (int i = startIndex; i < endIndex; i++)
-            {
-                if (System.Runtime.CompilerServices.JitHelpers.EnumEquals(array[i], value)) return i;
-            }
-            return -1;
-        }
-
-        internal override int LastIndexOf(T[] array, T value, int startIndex, int count)
-        {
-            int endIndex = startIndex - count + 1;
-            for (int i = startIndex; i >= endIndex; i--)
-            {
-                if (System.Runtime.CompilerServices.JitHelpers.EnumEquals(array[i], value)) return i;
-            }
-            return -1;
-        }
-    }
-}
index 923100d..3e52944 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)System\Collections\Concurrent\IProducerConsumerCollectionDebugView.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Collections\DictionaryEntry.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\ArraySortHelper.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\Comparer.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\Dictionary.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\EqualityComparer.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\IAsyncEnumerable.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\IAsyncEnumerator.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\ICollection.cs" />
@@ -10,13 +10,10 @@ using System.Runtime.Serialization;
 namespace System.Collections.Generic
 {
     [Serializable]
-    [TypeDependencyAttribute("System.Collections.Generic.ObjectComparer`1")]
     [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] 
-    public abstract class Comparer<T> : IComparer, IComparer<T>
+    public abstract partial class Comparer<T> : IComparer, IComparer<T>
     {
-        // To minimize generic instantiation overhead of creating the comparer per type, we keep the generic portion of the code as small
-        // as possible and define most of the creation logic in a non-generic class.
-        public static Comparer<T> Default { get; } = (Comparer<T>)ComparerHelpers.CreateDefaultComparer(typeof(T));
+        // public static Comparer<T> Default is runtime-specific
 
         public static Comparer<T> Create(Comparison<T> comparison)
         {
@@ -38,6 +35,21 @@ namespace System.Collections.Generic
         }
     }
 
+    internal sealed class ComparisonComparer<T> : Comparer<T>
+    {
+        private readonly Comparison<T> _comparison;
+
+        public ComparisonComparer(Comparison<T> comparison)
+        {
+            _comparison = comparison;
+        }
+
+        public override int Compare(T x, T y)
+        {
+            return _comparison(x, y);
+        }
+    }
+
     // Note: although there is a lot of shared code in the following
     // comparers, we do not incorporate it into a base class for perf
     // reasons. Adding another base class (even one with no fields)
@@ -46,7 +58,7 @@ namespace System.Collections.Generic
     [Serializable]
     [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
     // Needs to be public to support binary serialization compatibility
-    public sealed class GenericComparer<T> : Comparer<T> where T : IComparable<T>
+    public sealed partial class GenericComparer<T> : Comparer<T> where T : IComparable<T>
     {
         public override int Compare(T x, T y)
         {
@@ -70,7 +82,7 @@ namespace System.Collections.Generic
     [Serializable]
     [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
     // Needs to be public to support binary serialization compatibility
-    public sealed class NullableComparer<T> : Comparer<T?> where T : struct, IComparable<T>
+    public sealed partial class NullableComparer<T> : Comparer<T?> where T : struct, IComparable<T>
     {
         public override int Compare(T? x, T? y)
         {
@@ -94,7 +106,7 @@ namespace System.Collections.Generic
     [Serializable]
     [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
     // Needs to be public to support binary serialization compatibility
-    public sealed class ObjectComparer<T> : Comparer<T>
+    public sealed partial class ObjectComparer<T> : Comparer<T>
     {
         public override int Compare(T x, T y)
         {
@@ -109,38 +121,15 @@ namespace System.Collections.Generic
             GetType().GetHashCode();
     }
 
-    internal sealed class ComparisonComparer<T> : Comparer<T>
-    {
-        private readonly Comparison<T> _comparison;
-
-        public ComparisonComparer(Comparison<T> comparison)
-        {
-            _comparison = comparison;
-        }
-
-        public override int Compare(T x, T y)
-        {
-            return _comparison(x, y);
-        }
-    }
-
-    // Enum comparers (specialized to avoid boxing)
-    // NOTE: Each of these needs to implement ISerializable
-    // and have a SerializationInfo/StreamingContext ctor,
-    // since we want to serialize as ObjectComparer for
-    // back-compat reasons (see below).
     [Serializable]
-    internal sealed class EnumComparer<T> : Comparer<T>, ISerializable where T : struct, Enum
+    internal sealed partial class EnumComparer<T> : Comparer<T>, ISerializable where T : struct, Enum
     {
         internal EnumComparer() { }
 
         // Used by the serialization engine.
         private EnumComparer(SerializationInfo info, StreamingContext context) { }
 
-        public override int Compare(T x, T y)
-        {
-            return System.Runtime.CompilerServices.JitHelpers.EnumCompareTo(x, y);
-        }
+        // public override int Compare(T x, T y) is runtime-specific
 
         // Equals method for the comparer itself. 
         public override bool Equals(object obj) =>
diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs
new file mode 100644 (file)
index 0000000..c04f121
--- /dev/null
@@ -0,0 +1,185 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime;
+using System.Runtime.CompilerServices;
+using System.Runtime.Serialization;
+using System.Diagnostics;
+
+namespace System.Collections.Generic
+{
+    [Serializable]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] 
+    public abstract partial class EqualityComparer<T> : IEqualityComparer, IEqualityComparer<T>
+    {
+        // public static EqualityComparer<T> Default is runtime-specific
+
+        public abstract bool Equals(T x, T y);
+        public abstract int GetHashCode(T obj);
+
+        int IEqualityComparer.GetHashCode(object obj)
+        {
+            if (obj == null) return 0;
+            if (obj is T) return GetHashCode((T)obj);
+            ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArgumentForComparison);
+            return 0;
+        }
+
+        bool IEqualityComparer.Equals(object x, object y)
+        {
+            if (x == y) return true;
+            if (x == null || y == null) return false;
+            if ((x is T) && (y is T)) return Equals((T)x, (T)y);
+            ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArgumentForComparison);
+            return false;
+        }
+    }
+
+    // The methods in this class look identical to the inherited methods, but the calls
+    // to Equal bind to IEquatable<T>.Equals(T) instead of Object.Equals(Object)
+    [Serializable]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    // Needs to be public to support binary serialization compatibility
+    public sealed partial class GenericEqualityComparer<T> : EqualityComparer<T> where T : IEquatable<T>
+    {
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public override bool Equals(T x, T y)
+        {
+            if (x != null)
+            {
+                if (y != null) return x.Equals(y);
+                return false;
+            }
+            if (y != null) return false;
+            return true;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public override int GetHashCode(T obj) => obj?.GetHashCode() ?? 0;
+
+        // Equals method for the comparer itself.
+        // If in the future this type is made sealed, change the is check to obj != null && GetType() == obj.GetType().
+        public override bool Equals(object obj) =>
+            obj is GenericEqualityComparer<T>;
+
+        // If in the future this type is made sealed, change typeof(...) to GetType().
+        public override int GetHashCode() =>
+            typeof(GenericEqualityComparer<T>).GetHashCode();
+    }
+
+    [Serializable]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    // Needs to be public to support binary serialization compatibility
+    public sealed partial class NullableEqualityComparer<T> : EqualityComparer<T?> where T : struct, IEquatable<T>
+    {
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public override bool Equals(T? x, T? y)
+        {
+            if (x.HasValue)
+            {
+                if (y.HasValue) return x.value.Equals(y.value);
+                return false;
+            }
+            if (y.HasValue) return false;
+            return true;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public override int GetHashCode(T? obj) => obj.GetHashCode();
+
+        // Equals method for the comparer itself.
+        public override bool Equals(object obj) =>
+            obj != null && GetType() == obj.GetType();
+
+        public override int GetHashCode() =>
+            GetType().GetHashCode();
+    }
+
+    [Serializable]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    // Needs to be public to support binary serialization compatibility
+    public sealed partial class ObjectEqualityComparer<T> : EqualityComparer<T>
+    {
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public override bool Equals(T x, T y)
+        {
+            if (x != null)
+            {
+                if (y != null) return x.Equals(y);
+                return false;
+            }
+            if (y != null) return false;
+            return true;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public override int GetHashCode(T obj) => obj?.GetHashCode() ?? 0;
+
+        // Equals method for the comparer itself.
+        public override bool Equals(object obj) =>
+            obj != null && GetType() == obj.GetType();
+
+        public override int GetHashCode() =>
+            GetType().GetHashCode();
+    }
+
+    [Serializable]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    // Needs to be public to support binary serialization compatibility
+    public sealed partial class ByteEqualityComparer : EqualityComparer<byte>
+    {
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public override bool Equals(byte x, byte y)
+        {
+            return x == y;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public override int GetHashCode(byte b)
+        {
+            return b.GetHashCode();
+        }
+
+        // Equals method for the comparer itself.
+        public override bool Equals(object obj) =>
+            obj != null && GetType() == obj.GetType();
+
+        public override int GetHashCode() =>
+            GetType().GetHashCode();
+    }
+
+    [Serializable]
+    [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+    // Needs to be public to support binary serialization compatibility
+    public sealed partial class EnumEqualityComparer<T> : EqualityComparer<T>, ISerializable where T : struct, Enum
+    {
+        internal EnumEqualityComparer() { }
+
+        // This is used by the serialization engine.
+        private EnumEqualityComparer(SerializationInfo information, StreamingContext context) { }
+
+        public void GetObjectData(SerializationInfo info, StreamingContext context)
+        {
+            // For back-compat we need to serialize the comparers for enums with underlying types other than int as ObjectEqualityComparer 
+            if (Type.GetTypeCode(Enum.GetUnderlyingType(typeof(T))) != TypeCode.Int32) {
+                info.SetType(typeof(ObjectEqualityComparer<T>));
+            }
+        }
+
+        // public override bool Equals(T x, T y) is runtime-specific
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public override int GetHashCode(T obj)
+        {
+            return obj.GetHashCode();
+        }
+
+        // Equals method for the comparer itself.
+        public override bool Equals(object obj) =>
+            obj != null && GetType() == obj.GetType();
+
+        public override int GetHashCode() =>
+            GetType().GetHashCode();
+    }
+}