File: Utilities\SortComparer`1.cs
Web Access
Project: src\src\roslyn\src\Razor\src\Shared\Microsoft.AspNetCore.Razor.Utilities.Shared\Microsoft.AspNetCore.Razor.Utilities.Shared.csproj (Microsoft.AspNetCore.Razor.Utilities.Shared)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

namespace Microsoft.AspNetCore.Razor.Utilities;

internal abstract class SortComparer<T> : IComparer<SortKey<T>>
{
    public static IComparer<SortKey<T>> GetOrCreate(IComparer<T> comparer, bool descending)
    {
        if (ReferenceEquals(comparer, Comparer<T>.Default))
        {
            return descending
                ? DescendingComparer.Default
                : AscendingComparer.Default;
        }

        return descending
            ? new DescendingComparer(comparer)
            : new AscendingComparer(comparer);
    }

    public static IComparer<SortKey<T>> Create(Comparison<T> comparison, bool descending)
        => descending
            ? new DescendingComparison(comparison)
            : new AscendingComparison(comparison);

    private SortComparer()
    {
    }

    protected abstract int CompareValues(T x, T y);

    public int Compare(SortKey<T> x, SortKey<T> y)
        => CompareValues(x.Value, y.Value) switch
        {
            // If the values are equal, use their indices to ensure stability.
            0 => x.Index - y.Index,
            var result => result
        };

    private sealed class AscendingComparer(IComparer<T> comparer) : SortComparer<T>
    {
        private static SortComparer<T>? s_default;

        public static SortComparer<T> Default
            => s_default ?? InterlockedOperations.Initialize(ref s_default, new AscendingComparer(Comparer<T>.Default));

        protected override int CompareValues(T x, T y)
            => comparer.Compare(x, y);
    }

    private sealed class DescendingComparer(IComparer<T> comparer) : SortComparer<T>
    {
        private static SortComparer<T>? s_default;

        public static SortComparer<T> Default
            => s_default ?? InterlockedOperations.Initialize(ref s_default, new DescendingComparer(Comparer<T>.Default));

        protected override int CompareValues(T x, T y)
            => comparer.Compare(y, x);
    }

    private sealed class AscendingComparison(Comparison<T> comparison) : SortComparer<T>
    {
        protected override int CompareValues(T x, T y)
            => comparison(x, y);
    }

    private sealed class DescendingComparison(Comparison<T> comparison) : SortComparer<T>
    {
        protected override int CompareValues(T x, T y)
            => comparison(y, x);
    }
}