You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Sorting/NaturalStringComparer.cs:21 defines CreateNaturalChunkRegex() => new(@"(\d+)|(\D+)"). Compare calls it on every comparison (around line 55), then copies both match collections into arrays.
The SYSLIB1045 ("use GeneratedRegex") warning is suppressed with Justification = "<Pending>". That suggests the fix was intended and never made.
A sort makes O(n log n) comparisons. Each one pays for:
constructing and parsing a Regex
two MatchCollections plus their Match objects
two array copies
Measured impact
Release build, sorting 50,000 file names with List.Sort(new NaturalStringComparer()), about 857k comparisons:
Variant
Time
Allocated per compare
Current (new Regex per compare)
4.43 s
≈7.6 KB
Cached static Regex, nothing else changed
3.22 s
≈3.5 KB
A comparer that walks the chunks directly, with no Regex and no Match objects, should do much better again. The comparer is used for things like file lists and UI tables, where multi-second sorts are noticeable.
Suggested fix / acceptance criteria
At minimum, replace the per-call construction with a [GeneratedRegex] / static instance, and remove the <Pending> suppression.
Preferably, replace the Regex with a character scanner that walks both strings chunk by chunk using char.IsDigit. This keeps the current semantics, including the leading-zero and very-long-digit-run handling, and allocates nothing per compare.
Add a benchmark or a coarse perf test, and keep all existing ordering tests passing.
What's wrong
Sorting/NaturalStringComparer.cs:21definesCreateNaturalChunkRegex() => new(@"(\d+)|(\D+)").Comparecalls it on every comparison (around line 55), then copies both match collections into arrays.The
SYSLIB1045("use GeneratedRegex") warning is suppressed withJustification = "<Pending>". That suggests the fix was intended and never made.A sort makes O(n log n) comparisons. Each one pays for:
MatchCollections plus theirMatchobjectsMeasured impact
Release build, sorting 50,000 file names with
List.Sort(new NaturalStringComparer()), about 857k comparisons:A comparer that walks the chunks directly, with no Regex and no
Matchobjects, should do much better again. The comparer is used for things like file lists and UI tables, where multi-second sorts are noticeable.Suggested fix / acceptance criteria
[GeneratedRegex]/ static instance, and remove the<Pending>suppression.char.IsDigit. This keeps the current semantics, including the leading-zero and very-long-digit-run handling, and allocates nothing per compare.