-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #27292 from bdach/carousel-sorting-again
Fix beatmap carousel string carousel not matching expectations
- Loading branch information
Showing
4 changed files
with
116 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence. | ||
// See the LICENCE file in the repository root for full licence text. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using BenchmarkDotNet.Attributes; | ||
using osu.Game.Utils; | ||
|
||
namespace osu.Game.Benchmarks | ||
{ | ||
public class BenchmarkStringComparison | ||
{ | ||
private string[] strings = null!; | ||
|
||
[GlobalSetup] | ||
public void GlobalSetUp() | ||
{ | ||
strings = new string[10000]; | ||
|
||
for (int i = 0; i < strings.Length; ++i) | ||
strings[i] = Guid.NewGuid().ToString(); | ||
|
||
for (int i = 0; i < strings.Length; ++i) | ||
{ | ||
if (i % 2 == 0) | ||
strings[i] = strings[i].ToUpperInvariant(); | ||
} | ||
} | ||
|
||
[Benchmark] | ||
public void OrdinalIgnoreCase() => compare(StringComparer.OrdinalIgnoreCase); | ||
|
||
[Benchmark] | ||
public void OrdinalSortByCase() => compare(OrdinalSortByCaseStringComparer.DEFAULT); | ||
|
||
[Benchmark] | ||
public void InvariantCulture() => compare(StringComparer.InvariantCulture); | ||
|
||
private void compare(IComparer<string> comparer) | ||
{ | ||
for (int i = 0; i < strings.Length; ++i) | ||
{ | ||
for (int j = i + 1; j < strings.Length; ++j) | ||
_ = comparer.Compare(strings[i], strings[j]); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// Copyright (c) ppy Pty Ltd <[email protected]>. 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; | ||
} | ||
} | ||
} |