File: Internal\IntrinsicSupport\ComparerHelpers.cs
Web Access
Project: src\src\runtime\src\coreclr\nativeaot\System.Private.CoreLib\src\System.Private.CoreLib.csproj (System.Private.CoreLib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// The algoritm to choose the default comparer is duplicated in the IL compiler. The compiler will replace the code within
// Comparer<T>.Create method with more specific implementation based on what sort of type is being compared where possible.

using System;
using System.Collections.Generic;
using System.Runtime;
using System.Runtime.CompilerServices;

using Internal.Runtime;
using Internal.Runtime.Augments;

namespace Internal.IntrinsicSupport
{
    internal static class ComparerHelpers
    {
        private static unsafe bool ImplementsIComparable(RuntimeTypeHandle t)
        {
            MethodTable* objectType = t.ToMethodTable();
            MethodTable* icomparableType = typeof(IComparable<>).TypeHandle.ToMethodTable();
            int interfaceCount = objectType->NumInterfaces;
            for (int i = 0; i < interfaceCount; i++)
            {
                MethodTable* interfaceType = objectType->InterfaceMap[i];

                if (!interfaceType->IsGeneric)
                    continue;

                if (interfaceType->GenericDefinition == icomparableType)
                {
                    if (interfaceType->GenericArity != 1)
                        continue;

                    if (objectType->IsValueType)
                    {
                        if (interfaceType->GenericArguments[0] == objectType)
                        {
                            return true;
                        }
                    }
                    else if (RuntimeImports.AreTypesAssignable(objectType, interfaceType->GenericArguments[0]))
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        internal static object GetComparer(RuntimeTypeHandle t)
        {
            RuntimeTypeHandle comparerType;
            RuntimeTypeHandle openComparerType = default(RuntimeTypeHandle);
            RuntimeTypeHandle comparerTypeArgument = default(RuntimeTypeHandle);

            if (RuntimeAugments.IsNullable(t))
            {
                RuntimeTypeHandle nullableType = RuntimeAugments.GetNullableType(t);
                openComparerType = typeof(NullableComparer<>).TypeHandle;
                comparerTypeArgument = nullableType;
            }
            if (EqualityComparerHelpers.IsEnum(t))
            {
                openComparerType = typeof(EnumComparer<>).TypeHandle;
                comparerTypeArgument = t;
            }

            if (openComparerType.Equals(default(RuntimeTypeHandle)))
            {
                if (ImplementsIComparable(t))
                {
                    openComparerType = typeof(GenericComparer<>).TypeHandle;
                    comparerTypeArgument = t;
                }
                else
                {
                    openComparerType = typeof(ObjectComparer<>).TypeHandle;
                    comparerTypeArgument = t;
                }
            }

            bool success = RuntimeAugments.TypeLoaderCallbacks.TryGetConstructedGenericTypeForComponents(openComparerType, new RuntimeTypeHandle[] { comparerTypeArgument }, out comparerType);
            if (!success)
            {
                Environment.FailFast("Unable to create comparer");
            }

            return RuntimeAugments.RawNewObject(comparerType);
        }

        // This one is an intrinsic that is used to make enum comparisons more efficient.
        [Intrinsic]
        internal static int EnumOnlyCompare<T>(T x, T y) where T : struct, Enum
        {
            return x.CompareTo(y);
        }
    }
}