diff options
Diffstat (limited to 'src/mscorlib/src/System/Collections/Generic/Comparer.cs')
-rw-r--r-- | src/mscorlib/src/System/Collections/Generic/Comparer.cs | 127 |
1 files changed, 35 insertions, 92 deletions
diff --git a/src/mscorlib/src/System/Collections/Generic/Comparer.cs b/src/mscorlib/src/System/Collections/Generic/Comparer.cs index 056843a606..a9b4b3f0dd 100644 --- a/src/mscorlib/src/System/Collections/Generic/Comparer.cs +++ b/src/mscorlib/src/System/Collections/Generic/Comparer.cs @@ -15,19 +15,14 @@ using System.Security; using System.Runtime.Serialization; namespace System.Collections.Generic -{ +{ [Serializable] - [TypeDependencyAttribute("System.Collections.Generic.ObjectComparer`1")] + [TypeDependencyAttribute("System.Collections.Generic.ObjectComparer`1")] public abstract class Comparer<T> : IComparer, IComparer<T> { - static readonly Comparer<T> defaultComparer = CreateComparer(); - - public static Comparer<T> Default { - get { - Contract.Ensures(Contract.Result<Comparer<T>>() != null); - return defaultComparer; - } - } + // 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> Create(Comparison<T> comparison) { @@ -39,69 +34,10 @@ namespace System.Collections.Generic return new ComparisonComparer<T>(comparison); } - // - // Note that logic in this method is replicated in vm\compile.cpp to ensure that NGen - // saves the right instantiations - // - private static Comparer<T> CreateComparer() - { - object result = null; - RuntimeType t = (RuntimeType)typeof(T); - - // If T implements IComparable<T> return a GenericComparer<T> - if (typeof(IComparable<T>).IsAssignableFrom(t)) - { - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericComparer<int>), t); - } - else if (default(T) == null) - { - // If T is a Nullable<U> where U implements IComparable<U> return a NullableComparer<U> - if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) { - RuntimeType u = (RuntimeType)t.GetGenericArguments()[0]; - if (typeof(IComparable<>).MakeGenericType(u).IsAssignableFrom(u)) { - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableComparer<int>), u); - } - } - } - else if (t.IsEnum) - { - // Explicitly call Enum.GetUnderlyingType here. Although GetTypeCode - // ends up doing this anyway, we end up avoiding an unnecessary P/Invoke - // and virtual method call. - TypeCode underlyingTypeCode = Type.GetTypeCode(Enum.GetUnderlyingType(t)); - - // Depending on the enum type, we need to special case the comparers so that we avoid boxing - // Specialize differently for signed/unsigned types so we avoid problems with large numbers - switch (underlyingTypeCode) - { - case TypeCode.SByte: - case TypeCode.Int16: - case TypeCode.Int32: - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(Int32EnumComparer<int>), t); - break; - case TypeCode.Byte: - case TypeCode.UInt16: - case TypeCode.UInt32: - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(UInt32EnumComparer<uint>), t); - break; - // 64-bit enums: use UnsafeEnumCastLong - case TypeCode.Int64: - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(Int64EnumComparer<long>), t); - break; - case TypeCode.UInt64: - result = RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(UInt64EnumComparer<ulong>), t); - break; - } - } - - return result != null ? - (Comparer<T>)result : - new ObjectComparer<T>(); // Fallback to ObjectComparer, which uses boxing - } - public abstract int Compare(T x, T y); - int IComparer.Compare(object x, object y) { + int IComparer.Compare(object x, object y) + { if (x == null) return y == null ? 0 : -1; if (y == null) return 1; if (x is T && y is T) return Compare((T)x, (T)y); @@ -109,18 +45,20 @@ namespace System.Collections.Generic return 0; } } - + // 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) // means another generic instantiation, which can be costly esp. // for value types. - + [Serializable] internal sealed class GenericComparer<T> : Comparer<T> where T : IComparable<T> - { - public override int Compare(T x, T y) { - if (x != null) { + { + public override int Compare(T x, T y) + { + if (x != null) + { if (y != null) return x.CompareTo(y); return 1; } @@ -139,8 +77,10 @@ namespace System.Collections.Generic [Serializable] internal sealed class NullableComparer<T> : Comparer<T?> where T : struct, IComparable<T> { - public override int Compare(T? x, T? y) { - if (x.HasValue) { + public override int Compare(T? x, T? y) + { + if (x.HasValue) + { if (y.HasValue) return x.value.CompareTo(y.value); return 1; } @@ -159,7 +99,8 @@ namespace System.Collections.Generic [Serializable] internal sealed class ObjectComparer<T> : Comparer<T> { - public override int Compare(T x, T y) { + public override int Compare(T x, T y) + { return System.Collections.Comparer.Default.Compare(x, y); } @@ -176,11 +117,13 @@ namespace System.Collections.Generic { private readonly Comparison<T> _comparison; - public ComparisonComparer(Comparison<T> comparison) { + public ComparisonComparer(Comparison<T> comparison) + { _comparison = comparison; } - public override int Compare(T x, T y) { + public override int Compare(T x, T y) + { return _comparison(x, y); } } @@ -196,12 +139,12 @@ namespace System.Collections.Generic { public Int32EnumComparer() { - Debug.Assert(typeof(T).IsEnum, "This type is only intended to be used to compare enums!"); + Debug.Assert(typeof(T).IsEnum); } - + // Used by the serialization engine. private Int32EnumComparer(SerializationInfo info, StreamingContext context) { } - + public override int Compare(T x, T y) { int ix = JitHelpers.UnsafeEnumCast(x); @@ -231,12 +174,12 @@ namespace System.Collections.Generic { public UInt32EnumComparer() { - Debug.Assert(typeof(T).IsEnum, "This type is only intended to be used to compare enums!"); + Debug.Assert(typeof(T).IsEnum); } - + // Used by the serialization engine. private UInt32EnumComparer(SerializationInfo info, StreamingContext context) { } - + public override int Compare(T x, T y) { uint ix = (uint)JitHelpers.UnsafeEnumCast(x); @@ -262,9 +205,9 @@ namespace System.Collections.Generic { public Int64EnumComparer() { - Debug.Assert(typeof(T).IsEnum, "This type is only intended to be used to compare enums!"); + Debug.Assert(typeof(T).IsEnum); } - + public override int Compare(T x, T y) { long lx = JitHelpers.UnsafeEnumCastLong(x); @@ -290,12 +233,12 @@ namespace System.Collections.Generic { public UInt64EnumComparer() { - Debug.Assert(typeof(T).IsEnum, "This type is only intended to be used to compare enums!"); + Debug.Assert(typeof(T).IsEnum); } - + // Used by the serialization engine. private UInt64EnumComparer(SerializationInfo info, StreamingContext context) { } - + public override int Compare(T x, T y) { ulong lx = (ulong)JitHelpers.UnsafeEnumCastLong(x); |