osu/osu.Game/Utils/OrdinalSortByCaseStringComp...

50 lines
2.2 KiB
C#

// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
namespace osu.Game.Utils
{
/// <summary>
/// This string comparer is something of a cross-over between <see cref="StringComparer.Ordinal"/> and <see cref="StringComparer.OrdinalIgnoreCase"/>.
/// <see cref="StringComparer.OrdinalIgnoreCase"/> is used first, but <see cref="StringComparer.Ordinal"/> is used as a tie-breaker.
/// </summary>
/// <remarks>
/// This comparer's behaviour somewhat emulates <see cref="StringComparer.InvariantCulture"/>,
/// but non-ordinal comparers - both culture-aware and culture-invariant - have huge performance overheads due to i18n factors (up to 5x slower).
/// </remarks>
/// <example>
/// Given the following strings to sort: <c>[A, B, C, D, a, b, c, d, A]</c> and a stable sorting algorithm:
/// <list type="bullet">
/// <item>
/// <see cref="StringComparer.Ordinal"/> would return <c>[A, A, B, C, D, a, b, c, d]</c>.
/// This is undesirable as letters are interleaved.
/// </item>
/// <item>
/// <see cref="StringComparer.OrdinalIgnoreCase"/> would return <c>[A, a, A, B, b, C, c, D, d]</c>.
/// Different letters are not interleaved, but because case is ignored, the As are left in arbitrary order.
/// </item>
/// </list>
/// <item>
/// <see cref="OrdinalSortByCaseStringComparer"/> would return <c>[a, A, A, b, B, c, C, d, D]</c>, which is the expected behaviour.
/// </item>
/// </example>
public class OrdinalSortByCaseStringComparer : IComparer<string>
{
public static readonly OrdinalSortByCaseStringComparer DEFAULT = new OrdinalSortByCaseStringComparer();
private OrdinalSortByCaseStringComparer()
{
}
public int Compare(string? a, string? b)
{
int result = StringComparer.OrdinalIgnoreCase.Compare(a, b);
if (result == 0)
result = -StringComparer.Ordinal.Compare(a, b); // negative to place lowercase letters before uppercase.
return result;
}
}
}